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