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