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