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