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