1 /* 2 * Copyright (c) 1995 3 * A.R. Gordon (andrew.gordon@net-tel.co.uk). All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed for the FreeBSD project 16 * 4. Neither the name of the author nor the names of any co-contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY ANDREW GORDON AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 * 32 * $NetBSD: lockd.c,v 1.7 2000/08/12 18:08:44 thorpej Exp $ 33 * $FreeBSD: src/usr.sbin/rpc.lockd/lockd.c,v 1.6 2001/03/19 12:50:09 alfred Exp $ 34 */ 35 36 /* 37 * main() function for NFS lock daemon. Most of the code in this 38 * file was generated by running rpcgen /usr/include/rpcsvc/nlm_prot.x. 39 * 40 * The actual program logic is in the file lock_proc.c 41 */ 42 43 #include <sys/types.h> 44 #include <sys/socket.h> 45 46 #include <netinet/in.h> 47 #include <arpa/inet.h> 48 49 #include <err.h> 50 #include <stdio.h> 51 #include <stdlib.h> 52 #include <errno.h> 53 #include <syslog.h> 54 #include <signal.h> 55 #include <string.h> 56 #include <unistd.h> 57 #include <libutil.h> 58 #include <netconfig.h> 59 #include <netdb.h> 60 61 #include <rpc/rpc.h> 62 #include <rpc/rpc_com.h> 63 #include <rpcsvc/sm_inter.h> 64 65 #include "lockd.h" 66 #include <rpcsvc/nlm_prot.h> 67 68 int debug_level = 0; /* 0 = no debugging syslog() calls */ 69 int _rpcsvcdirty = 0; 70 71 int grace_expired; 72 char **hosts, *svcport_str = NULL; 73 int nhosts = 0; 74 int xcreated = 0; 75 76 #ifndef IPPORT_MAX 77 #define IPPORT_MAX 65535 78 #endif 79 80 void create_service(struct netconfig *); 81 82 void nlm_prog_0(struct svc_req *, SVCXPRT *); 83 void nlm_prog_1(struct svc_req *, SVCXPRT *); 84 void nlm_prog_3(struct svc_req *, SVCXPRT *); 85 void nlm_prog_4(struct svc_req *, SVCXPRT *); 86 void out_of_mem(void) __dead2; 87 88 static void usage(void) __dead2; 89 90 void sigalarm_handler(void); 91 92 int 93 main(int argc, char **argv) 94 { 95 int ch, i, s; 96 void *nc_handle; 97 char *endptr, **hosts_bak; 98 struct sigaction sigalarm; 99 int grace_period = 30; 100 struct netconfig *nconf; 101 int have_v6 = 1; 102 int maxrec = RPC_MAXDATASIZE; 103 in_port_t svcport = 0; 104 105 while ((ch = getopt(argc, argv, "d:g:h:p:")) != (-1)) { 106 switch (ch) { 107 case 'd': 108 debug_level = atoi(optarg); 109 if (!debug_level) { 110 usage(); 111 /* NOTREACHED */ 112 } 113 break; 114 case 'g': 115 grace_period = atoi(optarg); 116 if (!grace_period) { 117 usage(); 118 /* NOTREACHED */ 119 } 120 break; 121 case 'h': 122 ++nhosts; 123 hosts_bak = hosts; 124 hosts_bak = realloc(hosts, nhosts * sizeof(char *)); 125 if (hosts_bak == NULL) { 126 if (hosts != NULL) { 127 for (i = 0; i < nhosts; i++) 128 free(hosts[i]); 129 free(hosts); 130 out_of_mem(); 131 } 132 } 133 hosts = hosts_bak; 134 hosts[nhosts - 1] = strdup(optarg); 135 if (hosts[nhosts - 1] == NULL) { 136 for (i = 0; i < (nhosts - 1); i++) 137 free(hosts[i]); 138 free(hosts); 139 out_of_mem(); 140 } 141 break; 142 case 'p': 143 endptr = NULL; 144 svcport = (in_port_t)strtoul(optarg, &endptr, 10); 145 if (endptr == NULL || *endptr != '\0' || 146 svcport == 0 || svcport >= IPPORT_MAX) 147 usage(); 148 svcport_str = strdup(optarg); 149 break; 150 default: 151 case '?': 152 usage(); 153 /* NOTREACHED */ 154 } 155 } 156 if (geteuid()) { /* This command allowed only to root */ 157 fprintf(stderr, "Sorry. You are not superuser\n"); 158 exit(1); 159 } 160 161 rpcb_unset(NLM_PROG, NLM_SM, NULL); 162 rpcb_unset(NLM_PROG, NLM_VERS, NULL); 163 rpcb_unset(NLM_PROG, NLM_VERSX, NULL); 164 rpcb_unset(NLM_PROG, NLM_VERS4, NULL); 165 166 /* 167 * Check if IPv6 support is present. 168 */ 169 s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); 170 if (s < 0) 171 have_v6 = 0; 172 else 173 close(s); 174 175 rpc_control(RPC_SVC_CONNMAXREC_SET, &maxrec); 176 177 /* 178 * If no hosts were specified, add a wildcard entry to bind to 179 * INADDR_ANY. Otherwise make sure 127.0.0.1 and ::1 are added to the 180 * list. 181 */ 182 if (nhosts == 0) { 183 hosts = malloc(sizeof(char**)); 184 if (hosts == NULL) 185 out_of_mem(); 186 187 hosts[0] = "*"; 188 nhosts = 1; 189 } else { 190 hosts_bak = hosts; 191 if (have_v6) { 192 hosts_bak = realloc(hosts, (nhosts + 2) * 193 sizeof(char *)); 194 if (hosts_bak == NULL) { 195 for (i = 0; i < nhosts; i++) 196 free(hosts[i]); 197 free(hosts); 198 out_of_mem(); 199 } else 200 hosts = hosts_bak; 201 202 nhosts += 2; 203 hosts[nhosts - 2] = "::1"; 204 } else { 205 hosts_bak = realloc(hosts, (nhosts + 1) * sizeof(char *)); 206 if (hosts_bak == NULL) { 207 for (i = 0; i < nhosts; i++) 208 free(hosts[i]); 209 210 free(hosts); 211 out_of_mem(); 212 } else { 213 nhosts += 1; 214 hosts = hosts_bak; 215 } 216 } 217 hosts[nhosts - 1] = "127.0.0.1"; 218 } 219 220 nc_handle = setnetconfig(); 221 while ((nconf = getnetconfig(nc_handle))) { 222 /* We want to listen only on udp6, tcp6, udp, tcp transports */ 223 if (nconf->nc_flag & NC_VISIBLE) { 224 /* Skip if there's no IPv6 support */ 225 if (have_v6 == 0 && strcmp(nconf->nc_protofmly, "inet6") == 0) { 226 /* DO NOTHING */ 227 } else { 228 create_service(nconf); 229 } 230 } 231 } 232 endnetconfig(nc_handle); 233 234 /* 235 * Note that it is NOT sensible to run this program from inetd - the 236 * protocol assumes that it will run immediately at boot time. 237 */ 238 if (daemon(0, debug_level > 0)) { 239 err(1, "cannot fork"); 240 /* NOTREACHED */ 241 } 242 243 openlog("rpc.lockd", 0, LOG_DAEMON); 244 if (debug_level) 245 syslog(LOG_INFO, "Starting, debug level %d", debug_level); 246 else 247 syslog(LOG_INFO, "Starting"); 248 249 sigalarm.sa_handler = (sig_t) sigalarm_handler; 250 sigemptyset(&sigalarm.sa_mask); 251 sigalarm.sa_flags = SA_RESETHAND; /* should only happen once */ 252 sigalarm.sa_flags |= SA_RESTART; 253 if (sigaction(SIGALRM, &sigalarm, NULL) != 0) { 254 syslog(LOG_WARNING, "sigaction(SIGALRM) failed: %s", 255 strerror(errno)); 256 exit(1); 257 } 258 grace_expired = 0; 259 alarm(grace_period); 260 261 svc_run(); /* Should never return */ 262 exit(1); 263 } 264 265 /* 266 * This routine creates and binds sockets on the appropriate 267 * addresses. It gets called one time for each transport and 268 * registrates the service with rpcbind on that trasport. 269 */ 270 void 271 create_service(struct netconfig *nconf) 272 { 273 struct addrinfo hints, *res = NULL; 274 struct sockaddr_in *sin; 275 struct sockaddr_in6 *sin6; 276 struct __rpc_sockinfo si; 277 struct netbuf servaddr; 278 SVCXPRT *transp = NULL; 279 int aicode; 280 int fd; 281 int nhostsbak; 282 int r; 283 int registered = 0; 284 u_int32_t host_addr[4]; /* IPv4 or IPv6 */ 285 286 if ((nconf->nc_semantics != NC_TPI_CLTS) && 287 (nconf->nc_semantics != NC_TPI_COTS) && 288 (nconf->nc_semantics != NC_TPI_COTS_ORD)) 289 return; /* not my type */ 290 291 /* 292 * XXX - using RPC library internal functions. 293 */ 294 if (!__rpc_nconf2sockinfo(nconf, &si)) { 295 syslog(LOG_ERR, "cannot get information for %s", 296 nconf->nc_netid); 297 return; 298 } 299 300 /* Get rpc.statd's address on this transport */ 301 memset(&hints, 0, sizeof hints); 302 hints.ai_flags = AI_PASSIVE; 303 hints.ai_family = si.si_af; 304 hints.ai_socktype = si.si_socktype; 305 hints.ai_protocol = si.si_proto; 306 307 /* 308 * Bind to specific IPs if asked to 309 */ 310 nhostsbak = nhosts; 311 while (nhostsbak > 0) { 312 --nhostsbak; 313 314 /* 315 * XXX - using RPC library internal functions. 316 */ 317 if ((fd = __rpc_nconf2fd(nconf)) < 0) { 318 syslog(LOG_ERR, "cannot create socket for %s", 319 nconf->nc_netid); 320 continue; 321 } 322 323 switch (hints.ai_family) { 324 case AF_INET: 325 if (inet_pton(AF_INET, hosts[nhostsbak], 326 host_addr) == 1) { 327 hints.ai_flags &= AI_NUMERICHOST; 328 } else { 329 /* 330 * Skip if we have an AF_INET6 address. 331 */ 332 if (inet_pton(AF_INET6, hosts[nhostsbak], 333 host_addr) == 1) { 334 close(fd); 335 continue; 336 } 337 } 338 break; 339 case AF_INET6: 340 if (inet_pton(AF_INET6, hosts[nhostsbak], 341 host_addr) == 1) { 342 hints.ai_flags &= AI_NUMERICHOST; 343 } else { 344 /* 345 * Skip if we have an AF_INET address. 346 */ 347 if (inet_pton(AF_INET, hosts[nhostsbak], 348 host_addr) == 1) { 349 close(fd); 350 continue; 351 } 352 } 353 break; 354 default: 355 break; 356 } 357 358 /* 359 * If no hosts were specified, just bind to INADDR_ANY 360 */ 361 if (strcmp("*", hosts[nhostsbak]) == 0) { 362 if (svcport_str == NULL) { 363 res = malloc(sizeof(struct addrinfo)); 364 if (res == NULL) 365 out_of_mem(); 366 res->ai_flags = hints.ai_flags; 367 res->ai_family = hints.ai_family; 368 res->ai_protocol = hints.ai_protocol; 369 switch (res->ai_family) { 370 case AF_INET: 371 sin = malloc(sizeof(struct sockaddr_in)); 372 if (sin == NULL) 373 out_of_mem(); 374 sin->sin_family = AF_INET; 375 sin->sin_port = htons(0); 376 sin->sin_addr.s_addr = htonl(INADDR_ANY); 377 res->ai_addr = (struct sockaddr*) sin; 378 res->ai_addrlen = (socklen_t) 379 sizeof(res->ai_addr); 380 break; 381 case AF_INET6: 382 sin6 = malloc(sizeof(struct sockaddr_in6)); 383 if (sin6 == NULL) 384 out_of_mem(); 385 sin6->sin6_family = AF_INET6; 386 sin6->sin6_port = htons(0); 387 sin6->sin6_addr = in6addr_any; 388 res->ai_addr = (struct sockaddr*) sin6; 389 res->ai_addrlen = (socklen_t) sizeof(res->ai_addr); 390 break; 391 default: 392 break; 393 } 394 } else { 395 if ((aicode = getaddrinfo(NULL, svcport_str, 396 &hints, &res)) != 0) { 397 syslog(LOG_ERR, 398 "cannot get local address for %s: %s", 399 nconf->nc_netid, 400 gai_strerror(aicode)); 401 continue; 402 } 403 } 404 } else { 405 if ((aicode = getaddrinfo(hosts[nhostsbak], svcport_str, 406 &hints, &res)) != 0) { 407 syslog(LOG_ERR, 408 "cannot get local address for %s: %s", 409 nconf->nc_netid, gai_strerror(aicode)); 410 continue; 411 } 412 } 413 414 r = bindresvport_sa(fd, res->ai_addr); 415 if (r != 0) { 416 syslog(LOG_ERR, "bindresvport_sa: %m"); 417 exit(1); 418 } 419 420 transp = svc_tli_create(fd, nconf, NULL, 421 RPC_MAXDATASIZE, RPC_MAXDATASIZE); 422 423 if (transp != NULL) { 424 if (!svc_reg(transp, NLM_PROG, NLM_SM, nlm_prog_0, 425 NULL)) 426 syslog(LOG_ERR, 427 "can't register %s NLM_PROG, NLM_SM service", 428 nconf->nc_netid); 429 430 if (!svc_reg(transp, NLM_PROG, NLM_VERS, nlm_prog_1, 431 NULL)) 432 syslog(LOG_ERR, 433 "can't register %s NLM_PROG, NLM_VERS service", 434 nconf->nc_netid); 435 436 if (!svc_reg(transp, NLM_PROG, NLM_VERSX, nlm_prog_3, 437 NULL)) 438 syslog(LOG_ERR, 439 "can't register %s NLM_PROG, NLM_VERSX service", 440 nconf->nc_netid); 441 442 if (!svc_reg(transp, NLM_PROG, NLM_VERS4, nlm_prog_4, 443 NULL)) 444 syslog(LOG_ERR, 445 "can't register %s NLM_PROG, NLM_VERS4 service", 446 nconf->nc_netid); 447 448 } else 449 syslog(LOG_WARNING, "can't create %s services", 450 nconf->nc_netid); 451 452 if (registered == 0) { 453 registered = 1; 454 memset(&hints, 0, sizeof hints); 455 hints.ai_flags = AI_PASSIVE; 456 hints.ai_family = si.si_af; 457 hints.ai_socktype = si.si_socktype; 458 hints.ai_protocol = si.si_proto; 459 460 if (svcport_str == NULL) { 461 svcport_str = malloc(NI_MAXSERV * sizeof(char)); 462 if (svcport_str == NULL) 463 out_of_mem(); 464 465 if (getnameinfo(res->ai_addr, 466 res->ai_addr->sa_len, NULL, NI_MAXHOST, 467 svcport_str, NI_MAXSERV * sizeof(char), 468 NI_NUMERICHOST | NI_NUMERICSERV)) 469 errx(1, "Cannot get port number"); 470 } 471 472 if((aicode = getaddrinfo(NULL, svcport_str, &hints, 473 &res)) != 0) { 474 syslog(LOG_ERR, "cannot get local address: %s", 475 gai_strerror(aicode)); 476 exit(1); 477 } 478 479 servaddr.buf = malloc(res->ai_addrlen); 480 memcpy(servaddr.buf, res->ai_addr, res->ai_addrlen); 481 servaddr.len = res->ai_addrlen; 482 483 rpcb_set(NLM_PROG, NLM_SM, nconf, &servaddr); 484 rpcb_set(NLM_PROG, NLM_VERS, nconf, &servaddr); 485 rpcb_set(NLM_PROG, NLM_VERSX, nconf, &servaddr); 486 rpcb_set(NLM_PROG, NLM_VERS4, nconf, &servaddr); 487 488 xcreated++; 489 freeaddrinfo(res); 490 } 491 } /* end while */ 492 } 493 494 void 495 sigalarm_handler(void) 496 { 497 498 grace_expired = 1; 499 } 500 501 static void 502 usage(void) 503 { 504 errx(1, "usage: rpc.lockd [-d <debuglevel>]" 505 " [-g <grace period>] [-h <bindip>] [-p <port>]"); 506 } 507 508 /* 509 * Out of memory, fatal 510 */ 511 void 512 out_of_mem(void) 513 { 514 syslog(LOG_ERR, "out of memory"); 515 exit(2); 516 } 517