1 /* $NetBSD: lockd.c,v 1.7 2000/08/12 18:08:44 thorpej Exp $ */ 2 /* $FreeBSD$ */ 3 4 /*- 5 * SPDX-License-Identifier: BSD-4-Clause 6 * 7 * Copyright (c) 1995 8 * A.R. Gordon (andrew.gordon@net-tel.co.uk). All rights reserved. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed for the FreeBSD project 21 * 4. Neither the name of the author nor the names of any co-contributors 22 * may be used to endorse or promote products derived from this software 23 * without specific prior written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY ANDREW GORDON AND CONTRIBUTORS ``AS IS'' AND 26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35 * SUCH DAMAGE. 36 * 37 */ 38 39 #include <sys/cdefs.h> 40 #ifndef lint 41 __RCSID("$NetBSD: lockd.c,v 1.7 2000/08/12 18:08:44 thorpej Exp $"); 42 #endif 43 44 /* 45 * main() function for NFS lock daemon. Most of the code in this 46 * file was generated by running rpcgen /usr/include/rpcsvc/nlm_prot.x. 47 * 48 * The actual program logic is in the file lock_proc.c 49 */ 50 51 #include <sys/param.h> 52 #include <sys/linker.h> 53 #include <sys/module.h> 54 #include <sys/socket.h> 55 #include <sys/stat.h> 56 57 #include <netinet/in.h> 58 #include <arpa/inet.h> 59 60 #include <err.h> 61 #include <stdio.h> 62 #include <stdlib.h> 63 #include <errno.h> 64 #include <syslog.h> 65 #include <signal.h> 66 #include <string.h> 67 #include <unistd.h> 68 #include <libutil.h> 69 #include <netconfig.h> 70 #include <netdb.h> 71 72 #include <rpc/rpc.h> 73 #include <rpc/rpc_com.h> 74 #include <rpcsvc/sm_inter.h> 75 76 #include "lockd.h" 77 #include <rpcsvc/nlm_prot.h> 78 79 #define GETPORT_MAXTRY 20 /* Max tries to get a port # */ 80 81 int debug_level = 0; /* 0 = no debugging syslog() calls */ 82 int _rpcsvcdirty = 0; 83 84 int grace_expired; 85 int nsm_state; 86 int kernel_lockd; 87 int kernel_lockd_client; 88 pid_t client_pid; 89 struct mon mon_host; 90 char **hosts, *svcport_str = NULL; 91 static int mallocd_svcport = 0; 92 static int *sock_fd; 93 static int sock_fdcnt; 94 static int sock_fdpos; 95 int nhosts = 0; 96 int xcreated = 0; 97 char **addrs; /* actually (netid, uaddr) pairs */ 98 int naddrs; /* count of how many (netid, uaddr) pairs */ 99 char localhost[] = "localhost"; 100 101 static int create_service(struct netconfig *nconf); 102 static void complete_service(struct netconfig *nconf, char *port_str); 103 static void clearout_service(void); 104 static void out_of_mem(void) __dead2; 105 void init_nsm(void); 106 void usage(void); 107 108 void sigalarm_handler(void); 109 110 /* 111 * XXX move to some header file. 112 */ 113 #define _PATH_RPCLOCKDSOCK "/var/run/rpclockd.sock" 114 115 int 116 main(int argc, char **argv) 117 { 118 int ch, i, s; 119 void *nc_handle; 120 char *endptr, **hosts_bak; 121 struct sigaction sigalarm; 122 int grace_period = 30; 123 int foreground = 0; 124 struct netconfig *nconf; 125 int have_v6 = 1; 126 int maxrec = RPC_MAXDATASIZE; 127 in_port_t svcport = 0; 128 int attempt_cnt, port_len, port_pos, ret; 129 char **port_list; 130 131 while ((ch = getopt(argc, argv, "d:Fg:h:p:")) != (-1)) { 132 switch (ch) { 133 case 'd': 134 debug_level = atoi(optarg); 135 if (!debug_level) { 136 usage(); 137 /* NOTREACHED */ 138 } 139 break; 140 case 'F': 141 foreground = 1; 142 break; 143 case 'g': 144 grace_period = atoi(optarg); 145 if (!grace_period) { 146 usage(); 147 /* NOTREACHED */ 148 } 149 break; 150 case 'h': 151 ++nhosts; 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 usage(); 180 /* NOTREACHED */ 181 } 182 } 183 if (geteuid()) { /* This command allowed only to root */ 184 fprintf(stderr, "Sorry. You are not superuser\n"); 185 exit(1); 186 } 187 188 kernel_lockd = FALSE; 189 kernel_lockd_client = FALSE; 190 if (modfind("nfslockd") < 0) { 191 if (kldload("nfslockd") < 0) { 192 fprintf(stderr, "Can't find or load kernel support for rpc.lockd - using non-kernel implementation\n"); 193 } else { 194 kernel_lockd = TRUE; 195 } 196 } else { 197 kernel_lockd = TRUE; 198 } 199 if (kernel_lockd) { 200 if (getosreldate() >= 800040) 201 kernel_lockd_client = TRUE; 202 } 203 204 (void)rpcb_unset(NLM_PROG, NLM_SM, NULL); 205 (void)rpcb_unset(NLM_PROG, NLM_VERS, NULL); 206 (void)rpcb_unset(NLM_PROG, NLM_VERSX, NULL); 207 (void)rpcb_unset(NLM_PROG, NLM_VERS4, NULL); 208 209 /* 210 * Check if IPv6 support is present. 211 */ 212 s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); 213 if (s < 0) 214 have_v6 = 0; 215 else 216 close(s); 217 218 rpc_control(RPC_SVC_CONNMAXREC_SET, &maxrec); 219 220 /* 221 * If no hosts were specified, add a wildcard entry to bind to 222 * INADDR_ANY. Otherwise make sure 127.0.0.1 and ::1 are added to the 223 * list. 224 */ 225 if (nhosts == 0) { 226 hosts = malloc(sizeof(char *)); 227 if (hosts == NULL) 228 out_of_mem(); 229 230 hosts[0] = strdup("*"); 231 nhosts = 1; 232 } else { 233 if (have_v6) { 234 hosts_bak = realloc(hosts, (nhosts + 2) * 235 sizeof(char *)); 236 if (hosts_bak == NULL) { 237 for (i = 0; i < nhosts; i++) 238 free(hosts[i]); 239 free(hosts); 240 out_of_mem(); 241 } else 242 hosts = hosts_bak; 243 244 nhosts += 2; 245 hosts[nhosts - 2] = strdup("::1"); 246 } else { 247 hosts_bak = realloc(hosts, (nhosts + 1) * sizeof(char *)); 248 if (hosts_bak == NULL) { 249 for (i = 0; i < nhosts; i++) 250 free(hosts[i]); 251 252 free(hosts); 253 out_of_mem(); 254 } else { 255 nhosts += 1; 256 hosts = hosts_bak; 257 } 258 } 259 hosts[nhosts - 1] = strdup("127.0.0.1"); 260 } 261 262 if (kernel_lockd) { 263 if (!kernel_lockd_client) { 264 /* 265 * For the case where we have a kernel lockd but it 266 * doesn't provide client locking, we run a cut-down 267 * RPC service on a local-domain socket. The kernel's 268 * RPC server will pass what it can't handle (mainly 269 * client replies) down to us. 270 */ 271 struct sockaddr_un sun; 272 int fd, oldmask; 273 SVCXPRT *xprt; 274 275 memset(&sun, 0, sizeof sun); 276 sun.sun_family = AF_LOCAL; 277 unlink(_PATH_RPCLOCKDSOCK); 278 strcpy(sun.sun_path, _PATH_RPCLOCKDSOCK); 279 sun.sun_len = SUN_LEN(&sun); 280 fd = socket(AF_LOCAL, SOCK_STREAM, 0); 281 if (!fd) { 282 err(1, "Can't create local lockd socket"); 283 } 284 oldmask = umask(S_IXUSR|S_IRWXG|S_IRWXO); 285 if (bind(fd, (struct sockaddr *) &sun, sun.sun_len) < 0) { 286 err(1, "Can't bind local lockd socket"); 287 } 288 umask(oldmask); 289 if (listen(fd, SOMAXCONN) < 0) { 290 err(1, "Can't listen on local lockd socket"); 291 } 292 xprt = svc_vc_create(fd, RPC_MAXDATASIZE, RPC_MAXDATASIZE); 293 if (!xprt) { 294 err(1, "Can't create transport for local lockd socket"); 295 } 296 if (!svc_reg(xprt, NLM_PROG, NLM_VERS4, nlm_prog_4, NULL)) { 297 err(1, "Can't register service for local lockd socket"); 298 } 299 } 300 301 /* 302 * We need to look up the addresses so that we can 303 * hand uaddrs (ascii encoded address+port strings) to 304 * the kernel. 305 */ 306 nc_handle = setnetconfig(); 307 while ((nconf = getnetconfig(nc_handle))) { 308 /* We want to listen only on udp6, tcp6, udp, tcp transports */ 309 if (nconf->nc_flag & NC_VISIBLE) { 310 /* Skip if there's no IPv6 support */ 311 if (have_v6 == 0 && strcmp(nconf->nc_protofmly, "inet6") == 0) { 312 /* DO NOTHING */ 313 } else { 314 create_service(nconf); 315 } 316 } 317 } 318 endnetconfig(nc_handle); 319 } else { 320 attempt_cnt = 1; 321 sock_fdcnt = 0; 322 sock_fd = NULL; 323 port_list = NULL; 324 port_len = 0; 325 nc_handle = setnetconfig(); 326 while ((nconf = getnetconfig(nc_handle))) { 327 /* We want to listen only on udp6, tcp6, udp, tcp transports */ 328 if (nconf->nc_flag & NC_VISIBLE) { 329 /* Skip if there's no IPv6 support */ 330 if (have_v6 == 0 && strcmp(nconf->nc_protofmly, "inet6") == 0) { 331 /* DO NOTHING */ 332 } else { 333 ret = create_service(nconf); 334 if (ret == 1) 335 /* Ignore this call */ 336 continue; 337 if (ret < 0) { 338 /* 339 * Failed to bind port, so close 340 * off all sockets created and 341 * try again if the port# was 342 * dynamically assigned via 343 * bind(2). 344 */ 345 clearout_service(); 346 if (mallocd_svcport != 0 && 347 attempt_cnt < 348 GETPORT_MAXTRY) { 349 free(svcport_str); 350 svcport_str = NULL; 351 mallocd_svcport = 0; 352 } else { 353 errno = EADDRINUSE; 354 syslog(LOG_ERR, 355 "bindresvport_sa: %m"); 356 exit(1); 357 } 358 359 /* 360 * Start over at the first 361 * service. 362 */ 363 free(sock_fd); 364 sock_fdcnt = 0; 365 sock_fd = NULL; 366 nc_handle = setnetconfig(); 367 attempt_cnt++; 368 } else if (mallocd_svcport != 0 && 369 attempt_cnt == GETPORT_MAXTRY) { 370 /* 371 * For the last attempt, allow 372 * different port #s for each 373 * nconf by saving the 374 * svcport_str and setting it 375 * back to NULL. 376 */ 377 port_list = realloc(port_list, 378 (port_len + 1) * 379 sizeof(char *)); 380 if (port_list == NULL) 381 out_of_mem(); 382 port_list[port_len++] = 383 svcport_str; 384 svcport_str = NULL; 385 mallocd_svcport = 0; 386 } 387 } 388 } 389 } 390 391 /* 392 * Successfully bound the ports, so call complete_service() to 393 * do the rest of the setup on the service(s). 394 */ 395 sock_fdpos = 0; 396 port_pos = 0; 397 nc_handle = setnetconfig(); 398 while ((nconf = getnetconfig(nc_handle))) { 399 /* We want to listen only on udp6, tcp6, udp, tcp transports */ 400 if (nconf->nc_flag & NC_VISIBLE) { 401 /* Skip if there's no IPv6 support */ 402 if (have_v6 == 0 && strcmp(nconf->nc_protofmly, "inet6") == 0) { 403 /* DO NOTHING */ 404 } else if (port_list != NULL) { 405 if (port_pos >= port_len) { 406 syslog(LOG_ERR, 407 "too many port#s"); 408 exit(1); 409 } 410 complete_service(nconf, 411 port_list[port_pos++]); 412 } else 413 complete_service(nconf, svcport_str); 414 } 415 } 416 endnetconfig(nc_handle); 417 free(sock_fd); 418 if (port_list != NULL) { 419 for (port_pos = 0; port_pos < port_len; port_pos++) 420 free(port_list[port_pos]); 421 free(port_list); 422 } 423 } 424 425 /* 426 * Note that it is NOT sensible to run this program from inetd - the 427 * protocol assumes that it will run immediately at boot time. 428 */ 429 if ((foreground == 0) && daemon(0, 0)) { 430 err(1, "cannot fork"); 431 /* NOTREACHED */ 432 } 433 434 openlog("rpc.lockd", 0, LOG_DAEMON); 435 if (debug_level) 436 syslog(LOG_INFO, "Starting, debug level %d", debug_level); 437 else 438 syslog(LOG_INFO, "Starting"); 439 440 sigalarm.sa_handler = (sig_t) sigalarm_handler; 441 sigemptyset(&sigalarm.sa_mask); 442 sigalarm.sa_flags = SA_RESETHAND; /* should only happen once */ 443 sigalarm.sa_flags |= SA_RESTART; 444 if (sigaction(SIGALRM, &sigalarm, NULL) != 0) { 445 syslog(LOG_WARNING, "sigaction(SIGALRM) failed: %s", 446 strerror(errno)); 447 exit(1); 448 } 449 450 if (kernel_lockd) { 451 if (!kernel_lockd_client) { 452 init_nsm(); 453 client_pid = client_request(); 454 455 /* 456 * Create a child process to enter the kernel and then 457 * wait for RPCs on our local domain socket. 458 */ 459 if (!fork()) 460 nlm_syscall(debug_level, grace_period, 461 naddrs, addrs); 462 else 463 svc_run(); 464 } else { 465 /* 466 * The kernel lockd implementation provides 467 * both client and server so we don't need to 468 * do anything else. 469 */ 470 nlm_syscall(debug_level, grace_period, naddrs, addrs); 471 } 472 } else { 473 grace_expired = 0; 474 alarm(grace_period); 475 476 init_nsm(); 477 478 client_pid = client_request(); 479 480 svc_run(); /* Should never return */ 481 } 482 exit(1); 483 } 484 485 /* 486 * This routine creates and binds sockets on the appropriate 487 * addresses if lockd for user NLM, or perform a lookup of 488 * addresses for the kernel to create transports. 489 * 490 * It gets called one time for each transport. 491 * 492 * It returns 0 upon success, 1 for ignore the call and -1 to indicate 493 * bind failed with EADDRINUSE. 494 * 495 * Any file descriptors that have been created are stored in sock_fd and 496 * the total count of them is maintained in sock_fdcnt. 497 */ 498 static int 499 create_service(struct netconfig *nconf) 500 { 501 struct addrinfo hints, *res = NULL; 502 struct sockaddr_in *sin; 503 struct sockaddr_in6 *sin6; 504 struct __rpc_sockinfo si; 505 int aicode; 506 int fd; 507 int nhostsbak; 508 int r; 509 u_int32_t host_addr[4]; /* IPv4 or IPv6 */ 510 int mallocd_res; 511 512 if ((nconf->nc_semantics != NC_TPI_CLTS) && 513 (nconf->nc_semantics != NC_TPI_COTS) && 514 (nconf->nc_semantics != NC_TPI_COTS_ORD)) 515 return (1); /* not my type */ 516 517 /* 518 * XXX - using RPC library internal functions. 519 */ 520 if (!__rpc_nconf2sockinfo(nconf, &si)) { 521 syslog(LOG_ERR, "cannot get information for %s", 522 nconf->nc_netid); 523 return (1); 524 } 525 526 /* Get rpc.statd's address on this transport */ 527 memset(&hints, 0, sizeof hints); 528 hints.ai_family = si.si_af; 529 hints.ai_socktype = si.si_socktype; 530 hints.ai_protocol = si.si_proto; 531 532 /* 533 * Bind to specific IPs if asked to 534 */ 535 nhostsbak = nhosts; 536 while (nhostsbak > 0) { 537 --nhostsbak; 538 mallocd_res = 0; 539 hints.ai_flags = AI_PASSIVE; 540 541 if (!kernel_lockd) { 542 sock_fd = realloc(sock_fd, (sock_fdcnt + 1) * sizeof(int)); 543 if (sock_fd == NULL) 544 out_of_mem(); 545 sock_fd[sock_fdcnt++] = -1; /* Set invalid for now. */ 546 547 /* 548 * XXX - using RPC library internal functions. 549 */ 550 if ((fd = __rpc_nconf2fd(nconf)) < 0) { 551 syslog(LOG_ERR, "cannot create socket for %s", 552 nconf->nc_netid); 553 continue; 554 } 555 } 556 557 switch (hints.ai_family) { 558 case AF_INET: 559 if (inet_pton(AF_INET, hosts[nhostsbak], 560 host_addr) == 1) { 561 hints.ai_flags |= AI_NUMERICHOST; 562 } else { 563 /* 564 * Skip if we have an AF_INET6 address. 565 */ 566 if (inet_pton(AF_INET6, hosts[nhostsbak], 567 host_addr) == 1) { 568 if (!kernel_lockd) 569 close(fd); 570 continue; 571 } 572 } 573 break; 574 case AF_INET6: 575 if (inet_pton(AF_INET6, hosts[nhostsbak], 576 host_addr) == 1) { 577 hints.ai_flags |= AI_NUMERICHOST; 578 } else { 579 /* 580 * Skip if we have an AF_INET address. 581 */ 582 if (inet_pton(AF_INET, hosts[nhostsbak], 583 host_addr) == 1) { 584 if (!kernel_lockd) 585 close(fd); 586 continue; 587 } 588 } 589 break; 590 default: 591 break; 592 } 593 594 /* 595 * If no hosts were specified, just bind to INADDR_ANY 596 */ 597 if (strcmp("*", hosts[nhostsbak]) == 0) { 598 if (svcport_str == NULL) { 599 if ((res = malloc(sizeof(struct addrinfo))) == NULL) 600 out_of_mem(); 601 mallocd_res = 1; 602 res->ai_flags = hints.ai_flags; 603 res->ai_family = hints.ai_family; 604 res->ai_protocol = hints.ai_protocol; 605 switch (res->ai_family) { 606 case AF_INET: 607 sin = malloc(sizeof(struct sockaddr_in)); 608 if (sin == NULL) 609 out_of_mem(); 610 sin->sin_family = AF_INET; 611 sin->sin_port = htons(0); 612 sin->sin_addr.s_addr = htonl(INADDR_ANY); 613 res->ai_addr = (struct sockaddr*) sin; 614 res->ai_addrlen = (socklen_t) 615 sizeof(struct sockaddr_in); 616 break; 617 case AF_INET6: 618 sin6 = malloc(sizeof(struct sockaddr_in6)); 619 if (sin6 == NULL) 620 out_of_mem(); 621 sin6->sin6_family = AF_INET6; 622 sin6->sin6_port = htons(0); 623 sin6->sin6_addr = in6addr_any; 624 res->ai_addr = (struct sockaddr*) sin6; 625 res->ai_addrlen = (socklen_t) 626 sizeof(struct sockaddr_in6); 627 break; 628 default: 629 syslog(LOG_ERR, 630 "bad address family %d", 631 res->ai_family); 632 exit(1); 633 } 634 } else { 635 if ((aicode = getaddrinfo(NULL, svcport_str, 636 &hints, &res)) != 0) { 637 syslog(LOG_ERR, 638 "cannot get local address for %s: %s", 639 nconf->nc_netid, 640 gai_strerror(aicode)); 641 if (!kernel_lockd) 642 close(fd); 643 continue; 644 } 645 } 646 } else { 647 if ((aicode = getaddrinfo(hosts[nhostsbak], svcport_str, 648 &hints, &res)) != 0) { 649 syslog(LOG_ERR, 650 "cannot get local address for %s: %s", 651 nconf->nc_netid, gai_strerror(aicode)); 652 if (!kernel_lockd) 653 close(fd); 654 continue; 655 } 656 } 657 658 if (kernel_lockd) { 659 struct netbuf servaddr; 660 char *uaddr; 661 662 /* 663 * Look up addresses for the kernel to create transports for. 664 */ 665 servaddr.len = servaddr.maxlen = res->ai_addrlen; 666 servaddr.buf = res->ai_addr; 667 uaddr = taddr2uaddr(nconf, &servaddr); 668 669 addrs = realloc(addrs, 2 * (naddrs + 1) * sizeof(char *)); 670 if (!addrs) 671 out_of_mem(); 672 addrs[2 * naddrs] = strdup(nconf->nc_netid); 673 addrs[2 * naddrs + 1] = uaddr; 674 naddrs++; 675 } else { 676 /* Store the fd. */ 677 sock_fd[sock_fdcnt - 1] = fd; 678 679 /* Now, attempt the bind. */ 680 r = bindresvport_sa(fd, res->ai_addr); 681 if (r != 0) { 682 if (errno == EADDRINUSE && mallocd_svcport != 0) { 683 if (mallocd_res != 0) { 684 free(res->ai_addr); 685 free(res); 686 } else 687 freeaddrinfo(res); 688 return (-1); 689 } 690 syslog(LOG_ERR, "bindresvport_sa: %m"); 691 exit(1); 692 } 693 694 if (svcport_str == NULL) { 695 svcport_str = malloc(NI_MAXSERV * sizeof(char)); 696 if (svcport_str == NULL) 697 out_of_mem(); 698 mallocd_svcport = 1; 699 700 if (getnameinfo(res->ai_addr, 701 res->ai_addr->sa_len, NULL, NI_MAXHOST, 702 svcport_str, NI_MAXSERV * sizeof(char), 703 NI_NUMERICHOST | NI_NUMERICSERV)) 704 errx(1, "Cannot get port number"); 705 } 706 } 707 708 if (mallocd_res != 0) { 709 free(res->ai_addr); 710 free(res); 711 } else 712 freeaddrinfo(res); 713 res = NULL; 714 } 715 return (0); 716 } 717 718 /* 719 * Called after all the create_service() calls have succeeded, to complete 720 * the setup and registration. 721 */ 722 static void 723 complete_service(struct netconfig *nconf, char *port_str) 724 { 725 struct addrinfo hints, *res = NULL; 726 struct __rpc_sockinfo si; 727 struct netbuf servaddr; 728 SVCXPRT *transp = NULL; 729 int aicode, fd, nhostsbak; 730 int registered = 0; 731 732 if ((nconf->nc_semantics != NC_TPI_CLTS) && 733 (nconf->nc_semantics != NC_TPI_COTS) && 734 (nconf->nc_semantics != NC_TPI_COTS_ORD)) 735 return; /* not my type */ 736 737 /* 738 * XXX - using RPC library internal functions. 739 */ 740 if (!__rpc_nconf2sockinfo(nconf, &si)) { 741 syslog(LOG_ERR, "cannot get information for %s", 742 nconf->nc_netid); 743 return; 744 } 745 746 nhostsbak = nhosts; 747 while (nhostsbak > 0) { 748 --nhostsbak; 749 if (sock_fdpos >= sock_fdcnt) { 750 /* Should never happen. */ 751 syslog(LOG_ERR, "Ran out of socket fd's"); 752 return; 753 } 754 fd = sock_fd[sock_fdpos++]; 755 if (fd < 0) 756 continue; 757 758 if (nconf->nc_semantics != NC_TPI_CLTS) 759 listen(fd, SOMAXCONN); 760 761 transp = svc_tli_create(fd, nconf, NULL, 762 RPC_MAXDATASIZE, RPC_MAXDATASIZE); 763 764 if (transp != (SVCXPRT *) NULL) { 765 if (!svc_reg(transp, NLM_PROG, NLM_SM, nlm_prog_0, 766 NULL)) 767 syslog(LOG_ERR, 768 "can't register %s NLM_PROG, NLM_SM service", 769 nconf->nc_netid); 770 771 if (!svc_reg(transp, NLM_PROG, NLM_VERS, nlm_prog_1, 772 NULL)) 773 syslog(LOG_ERR, 774 "can't register %s NLM_PROG, NLM_VERS service", 775 nconf->nc_netid); 776 777 if (!svc_reg(transp, NLM_PROG, NLM_VERSX, nlm_prog_3, 778 NULL)) 779 syslog(LOG_ERR, 780 "can't register %s NLM_PROG, NLM_VERSX service", 781 nconf->nc_netid); 782 783 if (!svc_reg(transp, NLM_PROG, NLM_VERS4, nlm_prog_4, 784 NULL)) 785 syslog(LOG_ERR, 786 "can't register %s NLM_PROG, NLM_VERS4 service", 787 nconf->nc_netid); 788 789 } else 790 syslog(LOG_WARNING, "can't create %s services", 791 nconf->nc_netid); 792 793 if (registered == 0) { 794 registered = 1; 795 memset(&hints, 0, sizeof hints); 796 hints.ai_flags = AI_PASSIVE; 797 hints.ai_family = si.si_af; 798 hints.ai_socktype = si.si_socktype; 799 hints.ai_protocol = si.si_proto; 800 801 if ((aicode = getaddrinfo(NULL, port_str, &hints, 802 &res)) != 0) { 803 syslog(LOG_ERR, "cannot get local address: %s", 804 gai_strerror(aicode)); 805 exit(1); 806 } 807 808 servaddr.buf = malloc(res->ai_addrlen); 809 memcpy(servaddr.buf, res->ai_addr, res->ai_addrlen); 810 servaddr.len = res->ai_addrlen; 811 812 rpcb_set(NLM_PROG, NLM_SM, nconf, &servaddr); 813 rpcb_set(NLM_PROG, NLM_VERS, nconf, &servaddr); 814 rpcb_set(NLM_PROG, NLM_VERSX, nconf, &servaddr); 815 rpcb_set(NLM_PROG, NLM_VERS4, nconf, &servaddr); 816 817 xcreated++; 818 freeaddrinfo(res); 819 } 820 } /* end while */ 821 } 822 823 /* 824 * Clear out sockets after a failure to bind one of them, so that the 825 * cycle of socket creation/binding can start anew. 826 */ 827 static void 828 clearout_service(void) 829 { 830 int i; 831 832 for (i = 0; i < sock_fdcnt; i++) { 833 if (sock_fd[i] >= 0) { 834 shutdown(sock_fd[i], SHUT_RDWR); 835 close(sock_fd[i]); 836 } 837 } 838 } 839 840 void 841 sigalarm_handler(void) 842 { 843 844 grace_expired = 1; 845 } 846 847 void 848 usage(void) 849 { 850 errx(1, "usage: rpc.lockd [-d <debuglevel>]" 851 " [-F] [-g <grace period>] [-h <bindip>] [-p <port>]"); 852 } 853 854 /* 855 * init_nsm -- 856 * Reset the NSM state-of-the-world and acquire its state. 857 */ 858 void 859 init_nsm(void) 860 { 861 enum clnt_stat ret; 862 my_id id; 863 sm_stat stat; 864 char name[] = "NFS NLM"; 865 866 /* 867 * !!! 868 * The my_id structure isn't used by the SM_UNMON_ALL call, as far 869 * as I know. Leave it empty for now. 870 */ 871 memset(&id, 0, sizeof(id)); 872 id.my_name = name; 873 874 /* 875 * !!! 876 * The statd program must already be registered when lockd runs. 877 */ 878 do { 879 ret = callrpc("localhost", SM_PROG, SM_VERS, SM_UNMON_ALL, 880 (xdrproc_t)xdr_my_id, &id, (xdrproc_t)xdr_sm_stat, &stat); 881 if (ret == RPC_PROGUNAVAIL) { 882 syslog(LOG_WARNING, "%lu %s", SM_PROG, 883 clnt_sperrno(ret)); 884 sleep(2); 885 continue; 886 } 887 break; 888 } while (0); 889 890 if (ret != 0) { 891 syslog(LOG_ERR, "%lu %s", SM_PROG, clnt_sperrno(ret)); 892 exit(1); 893 } 894 895 nsm_state = stat.state; 896 897 /* setup constant data for SM_MON calls */ 898 mon_host.mon_id.my_id.my_name = localhost; 899 mon_host.mon_id.my_id.my_prog = NLM_PROG; 900 mon_host.mon_id.my_id.my_vers = NLM_SM; 901 mon_host.mon_id.my_id.my_proc = NLM_SM_NOTIFY; /* bsdi addition */ 902 } 903 904 /* 905 * Out of memory, fatal 906 */ 907 void 908 out_of_mem(void) 909 { 910 syslog(LOG_ERR, "out of memory"); 911 exit(2); 912 } 913