1 /* $NetBSD: lockd.c,v 1.7 2000/08/12 18:08:44 thorpej Exp $ */ 2 3 /*- 4 * SPDX-License-Identifier: BSD-4-Clause 5 * 6 * Copyright (c) 1995 7 * A.R. Gordon (andrew.gordon@net-tel.co.uk). All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. All advertising materials mentioning features or use of this software 18 * must display the following acknowledgement: 19 * This product includes software developed for the FreeBSD project 20 * 4. Neither the name of the author nor the names of any co-contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY ANDREW GORDON AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 * 36 */ 37 38 #include <sys/cdefs.h> 39 #ifndef lint 40 __RCSID("$NetBSD: lockd.c,v 1.7 2000/08/12 18:08:44 thorpej Exp $"); 41 #endif 42 43 /* 44 * main() function for NFS lock daemon. Most of the code in this 45 * file was generated by running rpcgen /usr/include/rpcsvc/nlm_prot.x. 46 * 47 * The actual program logic is in the file lock_proc.c 48 */ 49 50 #include <sys/param.h> 51 #include <sys/linker.h> 52 #include <sys/module.h> 53 #include <sys/socket.h> 54 #include <sys/stat.h> 55 56 #include <netinet/in.h> 57 #include <arpa/inet.h> 58 59 #include <err.h> 60 #include <stdio.h> 61 #include <stdlib.h> 62 #include <errno.h> 63 #include <syslog.h> 64 #include <signal.h> 65 #include <string.h> 66 #include <unistd.h> 67 #include <libutil.h> 68 #include <netconfig.h> 69 #include <netdb.h> 70 71 #include <rpc/rpc.h> 72 #include <rpc/rpc_com.h> 73 #include <rpcsvc/sm_inter.h> 74 75 #include "lockd.h" 76 #include <rpcsvc/nlm_prot.h> 77 78 #define GETPORT_MAXTRY 20 /* Max tries to get a port # */ 79 80 int debug_level = 0; /* 0 = no debugging syslog() calls */ 81 int _rpcsvcdirty = 0; 82 83 int grace_expired; 84 int nsm_state; 85 int kernel_lockd; 86 int kernel_lockd_client; 87 pid_t client_pid; 88 struct mon mon_host; 89 char **hosts, *svcport_str = NULL; 90 static int mallocd_svcport = 0; 91 static int *sock_fd; 92 static int sock_fdcnt; 93 static int sock_fdpos; 94 int nhosts = 0; 95 int xcreated = 0; 96 char **addrs; /* actually (netid, uaddr) pairs */ 97 int naddrs; /* count of how many (netid, uaddr) pairs */ 98 char localhost[] = "localhost"; 99 100 static int create_service(struct netconfig *nconf); 101 static void complete_service(struct netconfig *nconf, char *port_str); 102 static void clearout_service(void); 103 static void out_of_mem(void) __dead2; 104 void init_nsm(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 int foreground = 0; 123 struct netconfig *nconf; 124 int have_v6 = 1; 125 int maxrec = RPC_MAXDATASIZE; 126 in_port_t svcport = 0; 127 int attempt_cnt, port_len, port_pos, ret; 128 char **port_list; 129 130 while ((ch = getopt(argc, argv, "d:Fg:h:p:")) != (-1)) { 131 switch (ch) { 132 case 'd': 133 debug_level = atoi(optarg); 134 if (!debug_level) { 135 usage(); 136 /* NOTREACHED */ 137 } 138 break; 139 case 'F': 140 foreground = 1; 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 = realloc(hosts, nhosts * sizeof(char *)); 152 if (hosts_bak == NULL) { 153 if (hosts != NULL) { 154 for (i = 0; i < nhosts; i++) 155 free(hosts[i]); 156 free(hosts); 157 out_of_mem(); 158 } 159 } 160 hosts = hosts_bak; 161 hosts[nhosts - 1] = strdup(optarg); 162 if (hosts[nhosts - 1] == NULL) { 163 for (i = 0; i < (nhosts - 1); i++) 164 free(hosts[i]); 165 free(hosts); 166 out_of_mem(); 167 } 168 break; 169 case 'p': 170 endptr = NULL; 171 svcport = (in_port_t)strtoul(optarg, &endptr, 10); 172 if (endptr == NULL || *endptr != '\0' || 173 svcport == 0 || svcport >= IPPORT_MAX) 174 usage(); 175 svcport_str = strdup(optarg); 176 break; 177 default: 178 usage(); 179 /* NOTREACHED */ 180 } 181 } 182 if (geteuid()) { /* This command allowed only to root */ 183 fprintf(stderr, "Sorry. You are not superuser\n"); 184 exit(1); 185 } 186 187 kernel_lockd = FALSE; 188 kernel_lockd_client = FALSE; 189 if (modfind("nfslockd") < 0) { 190 if (kldload("nfslockd") < 0) { 191 fprintf(stderr, "Unable to load nfslockd(4), " 192 "using userland 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