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