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