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