1 /* $NetBSD: lockd.c,v 1.7 2000/08/12 18:08:44 thorpej Exp $ */ 2 /* $FreeBSD$ */ 3 4 /* 5 * Copyright (c) 1995 6 * A.R. Gordon (andrew.gordon@net-tel.co.uk). All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed for the FreeBSD project 19 * 4. Neither the name of the author nor the names of any co-contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY ANDREW GORDON AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 * 35 */ 36 37 #include <sys/cdefs.h> 38 #ifndef lint 39 __RCSID("$NetBSD: lockd.c,v 1.7 2000/08/12 18:08:44 thorpej Exp $"); 40 #endif 41 42 /* 43 * main() function for NFS lock daemon. Most of the code in this 44 * file was generated by running rpcgen /usr/include/rpcsvc/nlm_prot.x. 45 * 46 * The actual program logic is in the file lock_proc.c 47 */ 48 49 #include <sys/param.h> 50 #include <sys/linker.h> 51 #include <sys/module.h> 52 #include <sys/socket.h> 53 #include <sys/stat.h> 54 55 #include <netinet/in.h> 56 #include <arpa/inet.h> 57 58 #include <err.h> 59 #include <stdio.h> 60 #include <stdlib.h> 61 #include <errno.h> 62 #include <syslog.h> 63 #include <signal.h> 64 #include <string.h> 65 #include <unistd.h> 66 #include <libutil.h> 67 #include <netconfig.h> 68 #include <netdb.h> 69 70 #include <rpc/rpc.h> 71 #include <rpc/rpc_com.h> 72 #include <rpcsvc/sm_inter.h> 73 74 #include "lockd.h" 75 #include <rpcsvc/nlm_prot.h> 76 77 int debug_level = 0; /* 0 = no debugging syslog() calls */ 78 int _rpcsvcdirty = 0; 79 80 int grace_expired; 81 int nsm_state; 82 int kernel_lockd; 83 int kernel_lockd_client; 84 pid_t client_pid; 85 struct mon mon_host; 86 char **hosts, *svcport_str = NULL; 87 int nhosts = 0; 88 int xcreated = 0; 89 char **addrs; /* actually (netid, uaddr) pairs */ 90 int naddrs; /* count of how many (netid, uaddr) pairs */ 91 92 void create_service(struct netconfig *nconf); 93 void lookup_addresses(struct netconfig *nconf); 94 void init_nsm(void); 95 void nlm_prog_0(struct svc_req *, SVCXPRT *); 96 void nlm_prog_1(struct svc_req *, SVCXPRT *); 97 void nlm_prog_3(struct svc_req *, SVCXPRT *); 98 void nlm_prog_4(struct svc_req *, SVCXPRT *); 99 void out_of_mem(void); 100 void usage(void); 101 102 void sigalarm_handler(void); 103 104 /* 105 * XXX move to some header file. 106 */ 107 #define _PATH_RPCLOCKDSOCK "/var/run/rpclockd.sock" 108 109 int 110 main(int argc, char **argv) 111 { 112 int ch, i, s; 113 void *nc_handle; 114 char *endptr, **hosts_bak; 115 struct sigaction sigalarm; 116 int grace_period = 30; 117 struct netconfig *nconf; 118 int have_v6 = 1; 119 int maxrec = RPC_MAXDATASIZE; 120 in_port_t svcport = 0; 121 122 while ((ch = getopt(argc, argv, "d:g:h:p:")) != (-1)) { 123 switch (ch) { 124 case 'd': 125 debug_level = atoi(optarg); 126 if (!debug_level) { 127 usage(); 128 /* NOTREACHED */ 129 } 130 break; 131 case 'g': 132 grace_period = atoi(optarg); 133 if (!grace_period) { 134 usage(); 135 /* NOTREACHED */ 136 } 137 break; 138 case 'h': 139 ++nhosts; 140 hosts_bak = hosts; 141 hosts_bak = realloc(hosts, nhosts * sizeof(char *)); 142 if (hosts_bak == NULL) { 143 if (hosts != NULL) { 144 for (i = 0; i < nhosts; i++) 145 free(hosts[i]); 146 free(hosts); 147 out_of_mem(); 148 } 149 } 150 hosts = hosts_bak; 151 hosts[nhosts - 1] = strdup(optarg); 152 if (hosts[nhosts - 1] == NULL) { 153 for (i = 0; i < (nhosts - 1); i++) 154 free(hosts[i]); 155 free(hosts); 156 out_of_mem(); 157 } 158 break; 159 case 'p': 160 endptr = NULL; 161 svcport = (in_port_t)strtoul(optarg, &endptr, 10); 162 if (endptr == NULL || *endptr != '\0' || 163 svcport == 0 || svcport >= IPPORT_MAX) 164 usage(); 165 svcport_str = strdup(optarg); 166 break; 167 default: 168 case '?': 169 usage(); 170 /* NOTREACHED */ 171 } 172 } 173 if (geteuid()) { /* This command allowed only to root */ 174 fprintf(stderr, "Sorry. You are not superuser\n"); 175 exit(1); 176 } 177 178 kernel_lockd = FALSE; 179 kernel_lockd_client = FALSE; 180 if (modfind("nfslockd") < 0) { 181 if (kldload("nfslockd") < 0) { 182 fprintf(stderr, "Can't find or load kernel support for rpc.lockd - using non-kernel implementation\n"); 183 } else { 184 kernel_lockd = TRUE; 185 } 186 } else { 187 kernel_lockd = TRUE; 188 } 189 if (kernel_lockd) { 190 if (getosreldate() >= 800040) 191 kernel_lockd_client = TRUE; 192 } 193 194 (void)rpcb_unset(NLM_PROG, NLM_SM, NULL); 195 (void)rpcb_unset(NLM_PROG, NLM_VERS, NULL); 196 (void)rpcb_unset(NLM_PROG, NLM_VERSX, NULL); 197 (void)rpcb_unset(NLM_PROG, NLM_VERS4, NULL); 198 199 /* 200 * Check if IPv6 support is present. 201 */ 202 s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); 203 if (s < 0) 204 have_v6 = 0; 205 else 206 close(s); 207 208 rpc_control(RPC_SVC_CONNMAXREC_SET, &maxrec); 209 210 /* 211 * If no hosts were specified, add a wildcard entry to bind to 212 * INADDR_ANY. Otherwise make sure 127.0.0.1 and ::1 are added to the 213 * list. 214 */ 215 if (nhosts == 0) { 216 hosts = malloc(sizeof(char**)); 217 if (hosts == NULL) 218 out_of_mem(); 219 220 hosts[0] = "*"; 221 nhosts = 1; 222 } else { 223 hosts_bak = hosts; 224 if (have_v6) { 225 hosts_bak = realloc(hosts, (nhosts + 2) * 226 sizeof(char *)); 227 if (hosts_bak == NULL) { 228 for (i = 0; i < nhosts; i++) 229 free(hosts[i]); 230 free(hosts); 231 out_of_mem(); 232 } else 233 hosts = hosts_bak; 234 235 nhosts += 2; 236 hosts[nhosts - 2] = "::1"; 237 } else { 238 hosts_bak = realloc(hosts, (nhosts + 1) * sizeof(char *)); 239 if (hosts_bak == NULL) { 240 for (i = 0; i < nhosts; i++) 241 free(hosts[i]); 242 243 free(hosts); 244 out_of_mem(); 245 } else { 246 nhosts += 1; 247 hosts = hosts_bak; 248 } 249 } 250 hosts[nhosts - 1] = "127.0.0.1"; 251 } 252 253 if (kernel_lockd) { 254 if (!kernel_lockd_client) { 255 /* 256 * For the case where we have a kernel lockd but it 257 * doesn't provide client locking, we run a cut-down 258 * RPC service on a local-domain socket. The kernel's 259 * RPC server will pass what it can't handle (mainly 260 * client replies) down to us. 261 */ 262 struct sockaddr_un sun; 263 int fd, oldmask; 264 SVCXPRT *xprt; 265 266 memset(&sun, 0, sizeof sun); 267 sun.sun_family = AF_LOCAL; 268 unlink(_PATH_RPCLOCKDSOCK); 269 strcpy(sun.sun_path, _PATH_RPCLOCKDSOCK); 270 sun.sun_len = SUN_LEN(&sun); 271 fd = socket(AF_LOCAL, SOCK_STREAM, 0); 272 if (!fd) { 273 err(1, "Can't create local lockd socket"); 274 } 275 oldmask = umask(S_IXUSR|S_IRWXG|S_IRWXO); 276 if (bind(fd, (struct sockaddr *) &sun, sun.sun_len) < 0) { 277 err(1, "Can't bind local lockd socket"); 278 } 279 umask(oldmask); 280 if (listen(fd, SOMAXCONN) < 0) { 281 err(1, "Can't listen on local lockd socket"); 282 } 283 xprt = svc_vc_create(fd, RPC_MAXDATASIZE, RPC_MAXDATASIZE); 284 if (!xprt) { 285 err(1, "Can't create transport for local lockd socket"); 286 } 287 if (!svc_reg(xprt, NLM_PROG, NLM_VERS4, nlm_prog_4, NULL)) { 288 err(1, "Can't register service for local lockd socket"); 289 } 290 } 291 292 /* 293 * We need to look up the addresses so that we can 294 * hand uaddrs (ascii encoded address+port strings) to 295 * the kernel. 296 */ 297 nc_handle = setnetconfig(); 298 while ((nconf = getnetconfig(nc_handle))) { 299 /* We want to listen only on udp6, tcp6, udp, tcp transports */ 300 if (nconf->nc_flag & NC_VISIBLE) { 301 /* Skip if there's no IPv6 support */ 302 if (have_v6 == 0 && strcmp(nconf->nc_protofmly, "inet6") == 0) { 303 /* DO NOTHING */ 304 } else { 305 lookup_addresses(nconf); 306 } 307 } 308 } 309 endnetconfig(nc_handle); 310 } else { 311 nc_handle = setnetconfig(); 312 while ((nconf = getnetconfig(nc_handle))) { 313 /* We want to listen only on udp6, tcp6, udp, tcp transports */ 314 if (nconf->nc_flag & NC_VISIBLE) { 315 /* Skip if there's no IPv6 support */ 316 if (have_v6 == 0 && strcmp(nconf->nc_protofmly, "inet6") == 0) { 317 /* DO NOTHING */ 318 } else { 319 create_service(nconf); 320 } 321 } 322 } 323 endnetconfig(nc_handle); 324 } 325 326 /* 327 * Note that it is NOT sensible to run this program from inetd - the 328 * protocol assumes that it will run immediately at boot time. 329 */ 330 if (daemon(0, debug_level > 0)) { 331 err(1, "cannot fork"); 332 /* NOTREACHED */ 333 } 334 335 openlog("rpc.lockd", 0, LOG_DAEMON); 336 if (debug_level) 337 syslog(LOG_INFO, "Starting, debug level %d", debug_level); 338 else 339 syslog(LOG_INFO, "Starting"); 340 341 sigalarm.sa_handler = (sig_t) sigalarm_handler; 342 sigemptyset(&sigalarm.sa_mask); 343 sigalarm.sa_flags = SA_RESETHAND; /* should only happen once */ 344 sigalarm.sa_flags |= SA_RESTART; 345 if (sigaction(SIGALRM, &sigalarm, NULL) != 0) { 346 syslog(LOG_WARNING, "sigaction(SIGALRM) failed: %s", 347 strerror(errno)); 348 exit(1); 349 } 350 351 if (kernel_lockd) { 352 if (!kernel_lockd_client) { 353 init_nsm(); 354 client_pid = client_request(); 355 356 /* 357 * Create a child process to enter the kernel and then 358 * wait for RPCs on our local domain socket. 359 */ 360 if (!fork()) 361 nlm_syscall(debug_level, grace_period, 362 naddrs, addrs); 363 else 364 svc_run(); 365 } else { 366 /* 367 * The kernel lockd implementation provides 368 * both client and server so we don't need to 369 * do anything else. 370 */ 371 nlm_syscall(debug_level, grace_period, naddrs, addrs); 372 } 373 } else { 374 grace_expired = 0; 375 alarm(grace_period); 376 377 init_nsm(); 378 379 client_pid = client_request(); 380 381 svc_run(); /* Should never return */ 382 } 383 exit(1); 384 } 385 386 /* 387 * This routine creates and binds sockets on the appropriate 388 * addresses. It gets called one time for each transport and 389 * registrates the service with rpcbind on that trasport. 390 */ 391 void 392 create_service(struct netconfig *nconf) 393 { 394 struct addrinfo hints, *res = NULL; 395 struct sockaddr_in *sin; 396 struct sockaddr_in6 *sin6; 397 struct __rpc_sockinfo si; 398 struct netbuf servaddr; 399 SVCXPRT *transp = NULL; 400 int aicode; 401 int fd; 402 int nhostsbak; 403 int r; 404 int registered = 0; 405 u_int32_t host_addr[4]; /* IPv4 or IPv6 */ 406 407 if ((nconf->nc_semantics != NC_TPI_CLTS) && 408 (nconf->nc_semantics != NC_TPI_COTS) && 409 (nconf->nc_semantics != NC_TPI_COTS_ORD)) 410 return; /* not my type */ 411 412 /* 413 * XXX - using RPC library internal functions. 414 */ 415 if (!__rpc_nconf2sockinfo(nconf, &si)) { 416 syslog(LOG_ERR, "cannot get information for %s", 417 nconf->nc_netid); 418 return; 419 } 420 421 /* Get rpc.statd's address on this transport */ 422 memset(&hints, 0, sizeof hints); 423 hints.ai_flags = AI_PASSIVE; 424 hints.ai_family = si.si_af; 425 hints.ai_socktype = si.si_socktype; 426 hints.ai_protocol = si.si_proto; 427 428 /* 429 * Bind to specific IPs if asked to 430 */ 431 nhostsbak = nhosts; 432 while (nhostsbak > 0) { 433 --nhostsbak; 434 435 /* 436 * XXX - using RPC library internal functions. 437 */ 438 if ((fd = __rpc_nconf2fd(nconf)) < 0) { 439 syslog(LOG_ERR, "cannot create socket for %s", 440 nconf->nc_netid); 441 continue; 442 } 443 444 switch (hints.ai_family) { 445 case AF_INET: 446 if (inet_pton(AF_INET, hosts[nhostsbak], 447 host_addr) == 1) { 448 hints.ai_flags &= AI_NUMERICHOST; 449 } else { 450 /* 451 * Skip if we have an AF_INET6 address. 452 */ 453 if (inet_pton(AF_INET6, hosts[nhostsbak], 454 host_addr) == 1) { 455 close(fd); 456 continue; 457 } 458 } 459 break; 460 case AF_INET6: 461 if (inet_pton(AF_INET6, hosts[nhostsbak], 462 host_addr) == 1) { 463 hints.ai_flags &= AI_NUMERICHOST; 464 } else { 465 /* 466 * Skip if we have an AF_INET address. 467 */ 468 if (inet_pton(AF_INET, hosts[nhostsbak], 469 host_addr) == 1) { 470 close(fd); 471 continue; 472 } 473 } 474 break; 475 default: 476 break; 477 } 478 479 /* 480 * If no hosts were specified, just bind to INADDR_ANY 481 */ 482 if (strcmp("*", hosts[nhostsbak]) == 0) { 483 if (svcport_str == NULL) { 484 res = malloc(sizeof(struct addrinfo)); 485 if (res == NULL) 486 out_of_mem(); 487 res->ai_flags = hints.ai_flags; 488 res->ai_family = hints.ai_family; 489 res->ai_protocol = hints.ai_protocol; 490 switch (res->ai_family) { 491 case AF_INET: 492 sin = malloc(sizeof(struct sockaddr_in)); 493 if (sin == NULL) 494 out_of_mem(); 495 sin->sin_family = AF_INET; 496 sin->sin_port = htons(0); 497 sin->sin_addr.s_addr = htonl(INADDR_ANY); 498 res->ai_addr = (struct sockaddr*) sin; 499 res->ai_addrlen = (socklen_t) 500 sizeof(res->ai_addr); 501 break; 502 case AF_INET6: 503 sin6 = malloc(sizeof(struct sockaddr_in6)); 504 if (sin6 == NULL) 505 out_of_mem(); 506 sin6->sin6_family = AF_INET6; 507 sin6->sin6_port = htons(0); 508 sin6->sin6_addr = in6addr_any; 509 res->ai_addr = (struct sockaddr*) sin6; 510 res->ai_addrlen = (socklen_t) sizeof(res->ai_addr); 511 break; 512 default: 513 break; 514 } 515 } else { 516 if ((aicode = getaddrinfo(NULL, svcport_str, 517 &hints, &res)) != 0) { 518 syslog(LOG_ERR, 519 "cannot get local address for %s: %s", 520 nconf->nc_netid, 521 gai_strerror(aicode)); 522 continue; 523 } 524 } 525 } else { 526 if ((aicode = getaddrinfo(hosts[nhostsbak], svcport_str, 527 &hints, &res)) != 0) { 528 syslog(LOG_ERR, 529 "cannot get local address for %s: %s", 530 nconf->nc_netid, gai_strerror(aicode)); 531 continue; 532 } 533 } 534 535 r = bindresvport_sa(fd, res->ai_addr); 536 if (r != 0) { 537 syslog(LOG_ERR, "bindresvport_sa: %m"); 538 exit(1); 539 } 540 541 if (nconf->nc_semantics != NC_TPI_CLTS) 542 listen(fd, SOMAXCONN); 543 544 transp = svc_tli_create(fd, nconf, NULL, 545 RPC_MAXDATASIZE, RPC_MAXDATASIZE); 546 547 if (transp != (SVCXPRT *) NULL) { 548 if (!svc_reg(transp, NLM_PROG, NLM_SM, nlm_prog_0, 549 NULL)) 550 syslog(LOG_ERR, 551 "can't register %s NLM_PROG, NLM_SM service", 552 nconf->nc_netid); 553 554 if (!svc_reg(transp, NLM_PROG, NLM_VERS, nlm_prog_1, 555 NULL)) 556 syslog(LOG_ERR, 557 "can't register %s NLM_PROG, NLM_VERS service", 558 nconf->nc_netid); 559 560 if (!svc_reg(transp, NLM_PROG, NLM_VERSX, nlm_prog_3, 561 NULL)) 562 syslog(LOG_ERR, 563 "can't register %s NLM_PROG, NLM_VERSX service", 564 nconf->nc_netid); 565 566 if (!svc_reg(transp, NLM_PROG, NLM_VERS4, nlm_prog_4, 567 NULL)) 568 syslog(LOG_ERR, 569 "can't register %s NLM_PROG, NLM_VERS4 service", 570 nconf->nc_netid); 571 572 } else 573 syslog(LOG_WARNING, "can't create %s services", 574 nconf->nc_netid); 575 576 if (registered == 0) { 577 registered = 1; 578 memset(&hints, 0, sizeof hints); 579 hints.ai_flags = AI_PASSIVE; 580 hints.ai_family = si.si_af; 581 hints.ai_socktype = si.si_socktype; 582 hints.ai_protocol = si.si_proto; 583 584 if (svcport_str == NULL) { 585 svcport_str = malloc(NI_MAXSERV * sizeof(char)); 586 if (svcport_str == NULL) 587 out_of_mem(); 588 589 if (getnameinfo(res->ai_addr, 590 res->ai_addr->sa_len, NULL, NI_MAXHOST, 591 svcport_str, NI_MAXSERV * sizeof(char), 592 NI_NUMERICHOST | NI_NUMERICSERV)) 593 errx(1, "Cannot get port number"); 594 } 595 596 if((aicode = getaddrinfo(NULL, svcport_str, &hints, 597 &res)) != 0) { 598 syslog(LOG_ERR, "cannot get local address: %s", 599 gai_strerror(aicode)); 600 exit(1); 601 } 602 603 servaddr.buf = malloc(res->ai_addrlen); 604 memcpy(servaddr.buf, res->ai_addr, res->ai_addrlen); 605 servaddr.len = res->ai_addrlen; 606 607 rpcb_set(NLM_PROG, NLM_SM, nconf, &servaddr); 608 rpcb_set(NLM_PROG, NLM_VERS, nconf, &servaddr); 609 rpcb_set(NLM_PROG, NLM_VERSX, nconf, &servaddr); 610 rpcb_set(NLM_PROG, NLM_VERS4, nconf, &servaddr); 611 612 xcreated++; 613 freeaddrinfo(res); 614 } 615 } /* end while */ 616 } 617 618 /* 619 * Look up addresses for the kernel to create transports for. 620 */ 621 void 622 lookup_addresses(struct netconfig *nconf) 623 { 624 struct addrinfo hints, *res = NULL; 625 struct sockaddr_in *sin; 626 struct sockaddr_in6 *sin6; 627 struct __rpc_sockinfo si; 628 struct netbuf servaddr; 629 SVCXPRT *transp = NULL; 630 int aicode; 631 int nhostsbak; 632 int r; 633 int registered = 0; 634 u_int32_t host_addr[4]; /* IPv4 or IPv6 */ 635 char *uaddr; 636 637 if ((nconf->nc_semantics != NC_TPI_CLTS) && 638 (nconf->nc_semantics != NC_TPI_COTS) && 639 (nconf->nc_semantics != NC_TPI_COTS_ORD)) 640 return; /* not my type */ 641 642 /* 643 * XXX - using RPC library internal functions. 644 */ 645 if (!__rpc_nconf2sockinfo(nconf, &si)) { 646 syslog(LOG_ERR, "cannot get information for %s", 647 nconf->nc_netid); 648 return; 649 } 650 651 /* Get rpc.statd's address on this transport */ 652 memset(&hints, 0, sizeof hints); 653 hints.ai_flags = AI_PASSIVE; 654 hints.ai_family = si.si_af; 655 hints.ai_socktype = si.si_socktype; 656 hints.ai_protocol = si.si_proto; 657 658 /* 659 * Bind to specific IPs if asked to 660 */ 661 nhostsbak = nhosts; 662 while (nhostsbak > 0) { 663 --nhostsbak; 664 665 switch (hints.ai_family) { 666 case AF_INET: 667 if (inet_pton(AF_INET, hosts[nhostsbak], 668 host_addr) == 1) { 669 hints.ai_flags &= AI_NUMERICHOST; 670 } else { 671 /* 672 * Skip if we have an AF_INET6 address. 673 */ 674 if (inet_pton(AF_INET6, hosts[nhostsbak], 675 host_addr) == 1) { 676 continue; 677 } 678 } 679 break; 680 case AF_INET6: 681 if (inet_pton(AF_INET6, hosts[nhostsbak], 682 host_addr) == 1) { 683 hints.ai_flags &= AI_NUMERICHOST; 684 } else { 685 /* 686 * Skip if we have an AF_INET address. 687 */ 688 if (inet_pton(AF_INET, hosts[nhostsbak], 689 host_addr) == 1) { 690 continue; 691 } 692 } 693 break; 694 default: 695 break; 696 } 697 698 /* 699 * If no hosts were specified, just bind to INADDR_ANY 700 */ 701 if (strcmp("*", hosts[nhostsbak]) == 0) { 702 if (svcport_str == NULL) { 703 res = malloc(sizeof(struct addrinfo)); 704 if (res == NULL) 705 out_of_mem(); 706 res->ai_flags = hints.ai_flags; 707 res->ai_family = hints.ai_family; 708 res->ai_protocol = hints.ai_protocol; 709 switch (res->ai_family) { 710 case AF_INET: 711 sin = malloc(sizeof(struct sockaddr_in)); 712 if (sin == NULL) 713 out_of_mem(); 714 sin->sin_family = AF_INET; 715 sin->sin_port = htons(0); 716 sin->sin_addr.s_addr = htonl(INADDR_ANY); 717 res->ai_addr = (struct sockaddr*) sin; 718 res->ai_addrlen = (socklen_t) 719 sizeof(res->ai_addr); 720 break; 721 case AF_INET6: 722 sin6 = malloc(sizeof(struct sockaddr_in6)); 723 if (sin6 == NULL) 724 out_of_mem(); 725 sin6->sin6_family = AF_INET6; 726 sin6->sin6_port = htons(0); 727 sin6->sin6_addr = in6addr_any; 728 res->ai_addr = (struct sockaddr*) sin6; 729 res->ai_addrlen = (socklen_t) sizeof(res->ai_addr); 730 break; 731 default: 732 break; 733 } 734 } else { 735 if ((aicode = getaddrinfo(NULL, svcport_str, 736 &hints, &res)) != 0) { 737 syslog(LOG_ERR, 738 "cannot get local address for %s: %s", 739 nconf->nc_netid, 740 gai_strerror(aicode)); 741 continue; 742 } 743 } 744 } else { 745 if ((aicode = getaddrinfo(hosts[nhostsbak], svcport_str, 746 &hints, &res)) != 0) { 747 syslog(LOG_ERR, 748 "cannot get local address for %s: %s", 749 nconf->nc_netid, gai_strerror(aicode)); 750 continue; 751 } 752 } 753 754 servaddr.len = servaddr.maxlen = res->ai_addr->sa_len; 755 servaddr.buf = res->ai_addr; 756 uaddr = taddr2uaddr(nconf, &servaddr); 757 758 addrs = realloc(addrs, 2 * (naddrs + 1) * sizeof(char *)); 759 if (!addrs) 760 out_of_mem(); 761 addrs[2 * naddrs] = strdup(nconf->nc_netid); 762 addrs[2 * naddrs + 1] = uaddr; 763 naddrs++; 764 } /* end while */ 765 } 766 767 void 768 sigalarm_handler(void) 769 { 770 771 grace_expired = 1; 772 } 773 774 void 775 usage() 776 { 777 errx(1, "usage: rpc.lockd [-d <debuglevel>]" 778 " [-g <grace period>] [-h <bindip>] [-p <port>]"); 779 } 780 781 /* 782 * init_nsm -- 783 * Reset the NSM state-of-the-world and acquire its state. 784 */ 785 void 786 init_nsm(void) 787 { 788 enum clnt_stat ret; 789 my_id id; 790 sm_stat stat; 791 char name[] = "NFS NLM"; 792 char localhost[] = "localhost"; 793 794 /* 795 * !!! 796 * The my_id structure isn't used by the SM_UNMON_ALL call, as far 797 * as I know. Leave it empty for now. 798 */ 799 memset(&id, 0, sizeof(id)); 800 id.my_name = name; 801 802 /* 803 * !!! 804 * The statd program must already be registered when lockd runs. 805 */ 806 do { 807 ret = callrpc("localhost", SM_PROG, SM_VERS, SM_UNMON_ALL, 808 (xdrproc_t)xdr_my_id, &id, (xdrproc_t)xdr_sm_stat, &stat); 809 if (ret == RPC_PROGUNAVAIL) { 810 syslog(LOG_WARNING, "%lu %s", SM_PROG, 811 clnt_sperrno(ret)); 812 sleep(2); 813 continue; 814 } 815 break; 816 } while (0); 817 818 if (ret != 0) { 819 syslog(LOG_ERR, "%lu %s", SM_PROG, clnt_sperrno(ret)); 820 exit(1); 821 } 822 823 nsm_state = stat.state; 824 825 /* setup constant data for SM_MON calls */ 826 mon_host.mon_id.my_id.my_name = localhost; 827 mon_host.mon_id.my_id.my_prog = NLM_PROG; 828 mon_host.mon_id.my_id.my_vers = NLM_SM; 829 mon_host.mon_id.my_id.my_proc = NLM_SM_NOTIFY; /* bsdi addition */ 830 } 831 832 /* 833 * Out of memory, fatal 834 */ 835 void out_of_mem() 836 { 837 syslog(LOG_ERR, "out of memory"); 838 exit(2); 839 } 840