174462Salfred/* $NetBSD: lockd.c,v 1.7 2000/08/12 18:08:44 thorpej Exp $ */ 274462Salfred/* $FreeBSD: stable/11/usr.sbin/rpc.lockd/lockd.c 355368 2019-12-03 22:54:24Z rpokala $ */ 374462Salfred 4331722Seadler/* 514123Speter * Copyright (c) 1995 614123Speter * A.R. Gordon (andrew.gordon@net-tel.co.uk). All rights reserved. 714123Speter * 814123Speter * Redistribution and use in source and binary forms, with or without 914123Speter * modification, are permitted provided that the following conditions 1014123Speter * are met: 1114123Speter * 1. Redistributions of source code must retain the above copyright 1214123Speter * notice, this list of conditions and the following disclaimer. 1314123Speter * 2. Redistributions in binary form must reproduce the above copyright 1414123Speter * notice, this list of conditions and the following disclaimer in the 1514123Speter * documentation and/or other materials provided with the distribution. 1614123Speter * 3. All advertising materials mentioning features or use of this software 1714123Speter * must display the following acknowledgement: 1814123Speter * This product includes software developed for the FreeBSD project 1914123Speter * 4. Neither the name of the author nor the names of any co-contributors 2014123Speter * may be used to endorse or promote products derived from this software 2114123Speter * without specific prior written permission. 2214123Speter * 2314123Speter * THIS SOFTWARE IS PROVIDED BY ANDREW GORDON AND CONTRIBUTORS ``AS IS'' AND 2414123Speter * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2514123Speter * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2614123Speter * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2714123Speter * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2814123Speter * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2914123Speter * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3014123Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3114123Speter * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3214123Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3314123Speter * SUCH DAMAGE. 3414123Speter * 3514123Speter */ 3614123Speter 3774462Salfred#include <sys/cdefs.h> 3830376Scharnier#ifndef lint 3974462Salfred__RCSID("$NetBSD: lockd.c,v 1.7 2000/08/12 18:08:44 thorpej Exp $"); 4074462Salfred#endif 4114123Speter 4274462Salfred/* 4374462Salfred * main() function for NFS lock daemon. Most of the code in this 4474462Salfred * file was generated by running rpcgen /usr/include/rpcsvc/nlm_prot.x. 4574462Salfred * 4674462Salfred * The actual program logic is in the file lock_proc.c 4774462Salfred */ 4814123Speter 49177662Sdfr#include <sys/param.h> 50177662Sdfr#include <sys/linker.h> 51177662Sdfr#include <sys/module.h> 5274462Salfred#include <sys/socket.h> 53177633Sdfr#include <sys/stat.h> 5474462Salfred 55173281Smatteo#include <netinet/in.h> 56173281Smatteo#include <arpa/inet.h> 57173281Smatteo 5830376Scharnier#include <err.h> 5974462Salfred#include <stdio.h> 6030376Scharnier#include <stdlib.h> 6174462Salfred#include <errno.h> 6274462Salfred#include <syslog.h> 6374462Salfred#include <signal.h> 6430376Scharnier#include <string.h> 6574462Salfred#include <unistd.h> 6674462Salfred#include <libutil.h> 6774462Salfred#include <netconfig.h> 68173281Smatteo#include <netdb.h> 6974462Salfred 7030376Scharnier#include <rpc/rpc.h> 71109363Smbr#include <rpc/rpc_com.h> 7274462Salfred#include <rpcsvc/sm_inter.h> 7374462Salfred 7414123Speter#include "lockd.h" 7574462Salfred#include <rpcsvc/nlm_prot.h> 7614123Speter 77222624Srmacklem#define GETPORT_MAXTRY 20 /* Max tries to get a port # */ 78222624Srmacklem 7974462Salfredint debug_level = 0; /* 0 = no debugging syslog() calls */ 8074462Salfredint _rpcsvcdirty = 0; 8114123Speter 8274462Salfredint grace_expired; 8375631Salfredint nsm_state; 84177633Sdfrint kernel_lockd; 85180025Sdfrint kernel_lockd_client; 8675631Salfredpid_t client_pid; 8775631Salfredstruct mon mon_host; 88173281Smatteochar **hosts, *svcport_str = NULL; 89222624Srmacklemstatic int mallocd_svcport = 0; 90222624Srmacklemstatic int *sock_fd; 91222624Srmacklemstatic int sock_fdcnt; 92222624Srmacklemstatic int sock_fdpos; 93173281Smatteoint nhosts = 0; 94173281Smatteoint xcreated = 0; 95177633Sdfrchar **addrs; /* actually (netid, uaddr) pairs */ 96177633Sdfrint naddrs; /* count of how many (netid, uaddr) pairs */ 97216603Suqschar localhost[] = "localhost"; 9814123Speter 99222624Srmacklemstatic int create_service(struct netconfig *nconf); 100222624Srmacklemstatic void complete_service(struct netconfig *nconf, char *port_str); 101222624Srmacklemstatic void clearout_service(void); 102320217Sdelphijstatic void out_of_mem(void) __dead2; 10375631Salfredvoid init_nsm(void); 10492909Salfredvoid usage(void); 10574462Salfred 10692909Salfredvoid sigalarm_handler(void); 10774462Salfred 108177633Sdfr/* 109177633Sdfr * XXX move to some header file. 110177633Sdfr */ 111177633Sdfr#define _PATH_RPCLOCKDSOCK "/var/run/rpclockd.sock" 112177633Sdfr 11330376Scharnierint 114173281Smatteomain(int argc, char **argv) 11514123Speter{ 116173281Smatteo int ch, i, s; 117173281Smatteo void *nc_handle; 118173281Smatteo char *endptr, **hosts_bak; 11987096Salfred struct sigaction sigalarm; 12074462Salfred int grace_period = 30; 121355368Srpokala int foreground = 0; 12274462Salfred struct netconfig *nconf; 123173281Smatteo int have_v6 = 1; 124109363Smbr int maxrec = RPC_MAXDATASIZE; 125168324Smatteo in_port_t svcport = 0; 126222624Srmacklem int attempt_cnt, port_len, port_pos, ret; 127222624Srmacklem char **port_list; 12814123Speter 129355368Srpokala while ((ch = getopt(argc, argv, "d:Fg:h:p:")) != (-1)) { 13074462Salfred switch (ch) { 13174462Salfred case 'd': 13274462Salfred debug_level = atoi(optarg); 13374462Salfred if (!debug_level) { 13474462Salfred usage(); 13574462Salfred /* NOTREACHED */ 13674462Salfred } 13774462Salfred break; 138355368Srpokala case 'F': 139355368Srpokala foreground = 1; 140355368Srpokala break; 14174462Salfred case 'g': 14274462Salfred grace_period = atoi(optarg); 14374462Salfred if (!grace_period) { 14474462Salfred usage(); 14574462Salfred /* NOTREACHED */ 14674462Salfred } 14774462Salfred break; 148173281Smatteo case 'h': 149173281Smatteo ++nhosts; 150173281Smatteo hosts_bak = realloc(hosts, nhosts * sizeof(char *)); 151173281Smatteo if (hosts_bak == NULL) { 152173281Smatteo if (hosts != NULL) { 153173281Smatteo for (i = 0; i < nhosts; i++) 154173281Smatteo free(hosts[i]); 155173281Smatteo free(hosts); 156173281Smatteo out_of_mem(); 157173281Smatteo } 158173281Smatteo } 159173281Smatteo hosts = hosts_bak; 160173281Smatteo hosts[nhosts - 1] = strdup(optarg); 161173281Smatteo if (hosts[nhosts - 1] == NULL) { 162173281Smatteo for (i = 0; i < (nhosts - 1); i++) 163173281Smatteo free(hosts[i]); 164173281Smatteo free(hosts); 165173281Smatteo out_of_mem(); 166173281Smatteo } 167173281Smatteo break; 168168324Smatteo case 'p': 169168324Smatteo endptr = NULL; 170168324Smatteo svcport = (in_port_t)strtoul(optarg, &endptr, 10); 171168324Smatteo if (endptr == NULL || *endptr != '\0' || 172168324Smatteo svcport == 0 || svcport >= IPPORT_MAX) 173168324Smatteo usage(); 174173281Smatteo svcport_str = strdup(optarg); 175168324Smatteo break; 17674462Salfred default: 17774462Salfred usage(); 17874462Salfred /* NOTREACHED */ 17974462Salfred } 18074462Salfred } 18174462Salfred if (geteuid()) { /* This command allowed only to root */ 18274462Salfred fprintf(stderr, "Sorry. You are not superuser\n"); 18374462Salfred exit(1); 18474462Salfred } 18514123Speter 186177662Sdfr kernel_lockd = FALSE; 187180025Sdfr kernel_lockd_client = FALSE; 188177662Sdfr if (modfind("nfslockd") < 0) { 189177662Sdfr if (kldload("nfslockd") < 0) { 190177662Sdfr fprintf(stderr, "Can't find or load kernel support for rpc.lockd - using non-kernel implementation\n"); 191178066Sdfr } else { 192178066Sdfr kernel_lockd = TRUE; 193177662Sdfr } 194177662Sdfr } else { 195177662Sdfr kernel_lockd = TRUE; 196177662Sdfr } 197180025Sdfr if (kernel_lockd) { 198180025Sdfr if (getosreldate() >= 800040) 199180025Sdfr kernel_lockd_client = TRUE; 200180025Sdfr } 201177662Sdfr 20274462Salfred (void)rpcb_unset(NLM_PROG, NLM_SM, NULL); 20374462Salfred (void)rpcb_unset(NLM_PROG, NLM_VERS, NULL); 20474462Salfred (void)rpcb_unset(NLM_PROG, NLM_VERSX, NULL); 20574462Salfred (void)rpcb_unset(NLM_PROG, NLM_VERS4, NULL); 20614123Speter 20774462Salfred /* 20874462Salfred * Check if IPv6 support is present. 20974462Salfred */ 21074462Salfred s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP); 21174462Salfred if (s < 0) 212173281Smatteo have_v6 = 0; 213173281Smatteo else 21474462Salfred close(s); 21514123Speter 216173281Smatteo rpc_control(RPC_SVC_CONNMAXREC_SET, &maxrec); 217168324Smatteo 218173281Smatteo /* 219173281Smatteo * If no hosts were specified, add a wildcard entry to bind to 220173281Smatteo * INADDR_ANY. Otherwise make sure 127.0.0.1 and ::1 are added to the 221173281Smatteo * list. 222173281Smatteo */ 223173281Smatteo if (nhosts == 0) { 224292864Suqs hosts = malloc(sizeof(char *)); 225173281Smatteo if (hosts == NULL) 226173281Smatteo out_of_mem(); 227168324Smatteo 228260251Sdelphij hosts[0] = strdup("*"); 229173281Smatteo nhosts = 1; 230173281Smatteo } else { 231173281Smatteo if (have_v6) { 232173281Smatteo hosts_bak = realloc(hosts, (nhosts + 2) * 233173281Smatteo sizeof(char *)); 234173281Smatteo if (hosts_bak == NULL) { 235173281Smatteo for (i = 0; i < nhosts; i++) 236173281Smatteo free(hosts[i]); 237173281Smatteo free(hosts); 238173281Smatteo out_of_mem(); 239173281Smatteo } else 240173281Smatteo hosts = hosts_bak; 241109363Smbr 242173281Smatteo nhosts += 2; 243260251Sdelphij hosts[nhosts - 2] = strdup("::1"); 244173281Smatteo } else { 245173281Smatteo hosts_bak = realloc(hosts, (nhosts + 1) * sizeof(char *)); 246173281Smatteo if (hosts_bak == NULL) { 247173281Smatteo for (i = 0; i < nhosts; i++) 248173281Smatteo free(hosts[i]); 24914123Speter 250173281Smatteo free(hosts); 251173281Smatteo out_of_mem(); 252173281Smatteo } else { 253173281Smatteo nhosts += 1; 254173281Smatteo hosts = hosts_bak; 255168324Smatteo } 256168324Smatteo } 257260251Sdelphij hosts[nhosts - 1] = strdup("127.0.0.1"); 258173281Smatteo } 259168324Smatteo 260177633Sdfr if (kernel_lockd) { 261180025Sdfr if (!kernel_lockd_client) { 262180025Sdfr /* 263180025Sdfr * For the case where we have a kernel lockd but it 264180025Sdfr * doesn't provide client locking, we run a cut-down 265180025Sdfr * RPC service on a local-domain socket. The kernel's 266180025Sdfr * RPC server will pass what it can't handle (mainly 267180025Sdfr * client replies) down to us. 268180025Sdfr */ 269180025Sdfr struct sockaddr_un sun; 270180025Sdfr int fd, oldmask; 271180025Sdfr SVCXPRT *xprt; 272177633Sdfr 273180025Sdfr memset(&sun, 0, sizeof sun); 274180025Sdfr sun.sun_family = AF_LOCAL; 275180025Sdfr unlink(_PATH_RPCLOCKDSOCK); 276180025Sdfr strcpy(sun.sun_path, _PATH_RPCLOCKDSOCK); 277180025Sdfr sun.sun_len = SUN_LEN(&sun); 278180025Sdfr fd = socket(AF_LOCAL, SOCK_STREAM, 0); 279180025Sdfr if (!fd) { 280180025Sdfr err(1, "Can't create local lockd socket"); 281180025Sdfr } 282180025Sdfr oldmask = umask(S_IXUSR|S_IRWXG|S_IRWXO); 283180025Sdfr if (bind(fd, (struct sockaddr *) &sun, sun.sun_len) < 0) { 284180025Sdfr err(1, "Can't bind local lockd socket"); 285180025Sdfr } 286180025Sdfr umask(oldmask); 287180025Sdfr if (listen(fd, SOMAXCONN) < 0) { 288180025Sdfr err(1, "Can't listen on local lockd socket"); 289180025Sdfr } 290180025Sdfr xprt = svc_vc_create(fd, RPC_MAXDATASIZE, RPC_MAXDATASIZE); 291180025Sdfr if (!xprt) { 292180025Sdfr err(1, "Can't create transport for local lockd socket"); 293180025Sdfr } 294180025Sdfr if (!svc_reg(xprt, NLM_PROG, NLM_VERS4, nlm_prog_4, NULL)) { 295180025Sdfr err(1, "Can't register service for local lockd socket"); 296180025Sdfr } 297177633Sdfr } 298177633Sdfr 299177633Sdfr /* 300177633Sdfr * We need to look up the addresses so that we can 301177633Sdfr * hand uaddrs (ascii encoded address+port strings) to 302177633Sdfr * the kernel. 303177633Sdfr */ 304177633Sdfr nc_handle = setnetconfig(); 305177633Sdfr while ((nconf = getnetconfig(nc_handle))) { 306177633Sdfr /* We want to listen only on udp6, tcp6, udp, tcp transports */ 307177633Sdfr if (nconf->nc_flag & NC_VISIBLE) { 308177633Sdfr /* Skip if there's no IPv6 support */ 309177633Sdfr if (have_v6 == 0 && strcmp(nconf->nc_protofmly, "inet6") == 0) { 310177633Sdfr /* DO NOTHING */ 311177633Sdfr } else { 312320217Sdelphij create_service(nconf); 313177633Sdfr } 314173281Smatteo } 31574462Salfred } 316177633Sdfr endnetconfig(nc_handle); 317177633Sdfr } else { 318222624Srmacklem attempt_cnt = 1; 319222624Srmacklem sock_fdcnt = 0; 320222624Srmacklem sock_fd = NULL; 321222624Srmacklem port_list = NULL; 322222624Srmacklem port_len = 0; 323177633Sdfr nc_handle = setnetconfig(); 324177633Sdfr while ((nconf = getnetconfig(nc_handle))) { 325177633Sdfr /* We want to listen only on udp6, tcp6, udp, tcp transports */ 326177633Sdfr if (nconf->nc_flag & NC_VISIBLE) { 327177633Sdfr /* Skip if there's no IPv6 support */ 328177633Sdfr if (have_v6 == 0 && strcmp(nconf->nc_protofmly, "inet6") == 0) { 329177633Sdfr /* DO NOTHING */ 330177633Sdfr } else { 331222624Srmacklem ret = create_service(nconf); 332222624Srmacklem if (ret == 1) 333222624Srmacklem /* Ignore this call */ 334222624Srmacklem continue; 335222624Srmacklem if (ret < 0) { 336222624Srmacklem /* 337222624Srmacklem * Failed to bind port, so close 338222624Srmacklem * off all sockets created and 339222624Srmacklem * try again if the port# was 340222624Srmacklem * dynamically assigned via 341222624Srmacklem * bind(2). 342222624Srmacklem */ 343222624Srmacklem clearout_service(); 344222624Srmacklem if (mallocd_svcport != 0 && 345222624Srmacklem attempt_cnt < 346222624Srmacklem GETPORT_MAXTRY) { 347222624Srmacklem free(svcport_str); 348222624Srmacklem svcport_str = NULL; 349222624Srmacklem mallocd_svcport = 0; 350222624Srmacklem } else { 351222624Srmacklem errno = EADDRINUSE; 352222624Srmacklem syslog(LOG_ERR, 353222624Srmacklem "bindresvport_sa: %m"); 354222624Srmacklem exit(1); 355222624Srmacklem } 356222624Srmacklem 357222624Srmacklem /* 358222624Srmacklem * Start over at the first 359222624Srmacklem * service. 360222624Srmacklem */ 361222624Srmacklem free(sock_fd); 362222624Srmacklem sock_fdcnt = 0; 363222624Srmacklem sock_fd = NULL; 364222624Srmacklem nc_handle = setnetconfig(); 365222624Srmacklem attempt_cnt++; 366222624Srmacklem } else if (mallocd_svcport != 0 && 367222624Srmacklem attempt_cnt == GETPORT_MAXTRY) { 368222624Srmacklem /* 369222624Srmacklem * For the last attempt, allow 370222624Srmacklem * different port #s for each 371222624Srmacklem * nconf by saving the 372222624Srmacklem * svcport_str and setting it 373222624Srmacklem * back to NULL. 374222624Srmacklem */ 375222624Srmacklem port_list = realloc(port_list, 376222624Srmacklem (port_len + 1) * 377222624Srmacklem sizeof(char *)); 378222624Srmacklem if (port_list == NULL) 379222624Srmacklem out_of_mem(); 380222624Srmacklem port_list[port_len++] = 381222624Srmacklem svcport_str; 382222624Srmacklem svcport_str = NULL; 383222624Srmacklem mallocd_svcport = 0; 384222624Srmacklem } 385177633Sdfr } 386177633Sdfr } 387177633Sdfr } 388222624Srmacklem 389222624Srmacklem /* 390222624Srmacklem * Successfully bound the ports, so call complete_service() to 391222624Srmacklem * do the rest of the setup on the service(s). 392222624Srmacklem */ 393222624Srmacklem sock_fdpos = 0; 394222624Srmacklem port_pos = 0; 395222624Srmacklem nc_handle = setnetconfig(); 396222624Srmacklem while ((nconf = getnetconfig(nc_handle))) { 397222624Srmacklem /* We want to listen only on udp6, tcp6, udp, tcp transports */ 398222624Srmacklem if (nconf->nc_flag & NC_VISIBLE) { 399222624Srmacklem /* Skip if there's no IPv6 support */ 400222624Srmacklem if (have_v6 == 0 && strcmp(nconf->nc_protofmly, "inet6") == 0) { 401222624Srmacklem /* DO NOTHING */ 402222624Srmacklem } else if (port_list != NULL) { 403222624Srmacklem if (port_pos >= port_len) { 404222624Srmacklem syslog(LOG_ERR, 405222624Srmacklem "too many port#s"); 406222624Srmacklem exit(1); 407222624Srmacklem } 408222624Srmacklem complete_service(nconf, 409222624Srmacklem port_list[port_pos++]); 410222624Srmacklem } else 411222624Srmacklem complete_service(nconf, svcport_str); 412222624Srmacklem } 413222624Srmacklem } 414177633Sdfr endnetconfig(nc_handle); 415222624Srmacklem free(sock_fd); 416222624Srmacklem if (port_list != NULL) { 417222624Srmacklem for (port_pos = 0; port_pos < port_len; port_pos++) 418222624Srmacklem free(port_list[port_pos]); 419222624Srmacklem free(port_list); 420222624Srmacklem } 42174462Salfred } 42214123Speter 42374462Salfred /* 42474462Salfred * Note that it is NOT sensible to run this program from inetd - the 42574462Salfred * protocol assumes that it will run immediately at boot time. 42674462Salfred */ 427355368Srpokala if ((foreground == 0) && daemon(0, debug_level > 0)) { 42874462Salfred err(1, "cannot fork"); 42974462Salfred /* NOTREACHED */ 43074462Salfred } 43174462Salfred 43274462Salfred openlog("rpc.lockd", 0, LOG_DAEMON); 43374462Salfred if (debug_level) 43474462Salfred syslog(LOG_INFO, "Starting, debug level %d", debug_level); 43574462Salfred else 43674462Salfred syslog(LOG_INFO, "Starting"); 43774462Salfred 43886319Salfred sigalarm.sa_handler = (sig_t) sigalarm_handler; 43974462Salfred sigemptyset(&sigalarm.sa_mask); 44074462Salfred sigalarm.sa_flags = SA_RESETHAND; /* should only happen once */ 44174462Salfred sigalarm.sa_flags |= SA_RESTART; 44274462Salfred if (sigaction(SIGALRM, &sigalarm, NULL) != 0) { 44374462Salfred syslog(LOG_WARNING, "sigaction(SIGALRM) failed: %s", 44474462Salfred strerror(errno)); 44574462Salfred exit(1); 44674462Salfred } 44774462Salfred 448177633Sdfr if (kernel_lockd) { 449180025Sdfr if (!kernel_lockd_client) { 450180025Sdfr init_nsm(); 451180025Sdfr client_pid = client_request(); 45275631Salfred 453180025Sdfr /* 454180025Sdfr * Create a child process to enter the kernel and then 455180025Sdfr * wait for RPCs on our local domain socket. 456180025Sdfr */ 457180025Sdfr if (!fork()) 458180025Sdfr nlm_syscall(debug_level, grace_period, 459180025Sdfr naddrs, addrs); 460180025Sdfr else 461180025Sdfr svc_run(); 462180025Sdfr } else { 463180025Sdfr /* 464180025Sdfr * The kernel lockd implementation provides 465180025Sdfr * both client and server so we don't need to 466180025Sdfr * do anything else. 467180025Sdfr */ 468177633Sdfr nlm_syscall(debug_level, grace_period, naddrs, addrs); 469180025Sdfr } 470177633Sdfr } else { 471177633Sdfr grace_expired = 0; 472177633Sdfr alarm(grace_period); 47375631Salfred 474177633Sdfr init_nsm(); 475177633Sdfr 476177633Sdfr client_pid = client_request(); 477177633Sdfr 478177633Sdfr svc_run(); /* Should never return */ 479177633Sdfr } 48074462Salfred exit(1); 48114123Speter} 48230376Scharnier 483173281Smatteo/* 484173281Smatteo * This routine creates and binds sockets on the appropriate 485320217Sdelphij * addresses if lockd for user NLM, or perform a lookup of 486320217Sdelphij * addresses for the kernel to create transports. 487320217Sdelphij * 488320217Sdelphij * It gets called one time for each transport. 489320217Sdelphij * 490222624Srmacklem * It returns 0 upon success, 1 for ingore the call and -1 to indicate 491222624Srmacklem * bind failed with EADDRINUSE. 492320217Sdelphij * 493222624Srmacklem * Any file descriptors that have been created are stored in sock_fd and 494222624Srmacklem * the total count of them is maintained in sock_fdcnt. 495173281Smatteo */ 496222624Srmacklemstatic int 497173281Smatteocreate_service(struct netconfig *nconf) 498173281Smatteo{ 499173281Smatteo struct addrinfo hints, *res = NULL; 500173281Smatteo struct sockaddr_in *sin; 501173281Smatteo struct sockaddr_in6 *sin6; 502173281Smatteo struct __rpc_sockinfo si; 503173281Smatteo int aicode; 504173281Smatteo int fd; 505173281Smatteo int nhostsbak; 506173281Smatteo int r; 507173281Smatteo u_int32_t host_addr[4]; /* IPv4 or IPv6 */ 508222624Srmacklem int mallocd_res; 509173281Smatteo 510173281Smatteo if ((nconf->nc_semantics != NC_TPI_CLTS) && 511173281Smatteo (nconf->nc_semantics != NC_TPI_COTS) && 512173281Smatteo (nconf->nc_semantics != NC_TPI_COTS_ORD)) 513222624Srmacklem return (1); /* not my type */ 514173281Smatteo 515173281Smatteo /* 516173281Smatteo * XXX - using RPC library internal functions. 517173281Smatteo */ 518173281Smatteo if (!__rpc_nconf2sockinfo(nconf, &si)) { 519173281Smatteo syslog(LOG_ERR, "cannot get information for %s", 520173281Smatteo nconf->nc_netid); 521222624Srmacklem return (1); 522173281Smatteo } 523173281Smatteo 524173281Smatteo /* Get rpc.statd's address on this transport */ 525173281Smatteo memset(&hints, 0, sizeof hints); 526173281Smatteo hints.ai_family = si.si_af; 527173281Smatteo hints.ai_socktype = si.si_socktype; 528173281Smatteo hints.ai_protocol = si.si_proto; 529173281Smatteo 530173281Smatteo /* 531173281Smatteo * Bind to specific IPs if asked to 532173281Smatteo */ 533173281Smatteo nhostsbak = nhosts; 534173281Smatteo while (nhostsbak > 0) { 535173281Smatteo --nhostsbak; 536222624Srmacklem mallocd_res = 0; 537277352Srstone hints.ai_flags = AI_PASSIVE; 538173281Smatteo 539320217Sdelphij if (!kernel_lockd) { 540320217Sdelphij sock_fd = realloc(sock_fd, (sock_fdcnt + 1) * sizeof(int)); 541320217Sdelphij if (sock_fd == NULL) 542320217Sdelphij out_of_mem(); 543320217Sdelphij sock_fd[sock_fdcnt++] = -1; /* Set invalid for now. */ 544320217Sdelphij 545320217Sdelphij /* 546320217Sdelphij * XXX - using RPC library internal functions. 547320217Sdelphij */ 548320217Sdelphij if ((fd = __rpc_nconf2fd(nconf)) < 0) { 549320217Sdelphij syslog(LOG_ERR, "cannot create socket for %s", 550320217Sdelphij nconf->nc_netid); 551320217Sdelphij continue; 552320217Sdelphij } 553173281Smatteo } 554173281Smatteo 555173281Smatteo switch (hints.ai_family) { 556173281Smatteo case AF_INET: 557173281Smatteo if (inet_pton(AF_INET, hosts[nhostsbak], 558173281Smatteo host_addr) == 1) { 559222624Srmacklem hints.ai_flags |= AI_NUMERICHOST; 560173281Smatteo } else { 561173281Smatteo /* 562173281Smatteo * Skip if we have an AF_INET6 address. 563173281Smatteo */ 564173281Smatteo if (inet_pton(AF_INET6, hosts[nhostsbak], 565173281Smatteo host_addr) == 1) { 566320217Sdelphij if (!kernel_lockd) 567320217Sdelphij close(fd); 568173281Smatteo continue; 569173281Smatteo } 570173281Smatteo } 571173281Smatteo break; 572173281Smatteo case AF_INET6: 573173281Smatteo if (inet_pton(AF_INET6, hosts[nhostsbak], 574173281Smatteo host_addr) == 1) { 575222624Srmacklem hints.ai_flags |= AI_NUMERICHOST; 576173281Smatteo } else { 577173281Smatteo /* 578173281Smatteo * Skip if we have an AF_INET address. 579173281Smatteo */ 580173281Smatteo if (inet_pton(AF_INET, hosts[nhostsbak], 581173281Smatteo host_addr) == 1) { 582320217Sdelphij if (!kernel_lockd) 583320217Sdelphij close(fd); 584173281Smatteo continue; 585173281Smatteo } 586173281Smatteo } 587173281Smatteo break; 588173281Smatteo default: 589173281Smatteo break; 590173281Smatteo } 591173281Smatteo 592173281Smatteo /* 593173281Smatteo * If no hosts were specified, just bind to INADDR_ANY 594173281Smatteo */ 595173281Smatteo if (strcmp("*", hosts[nhostsbak]) == 0) { 596173281Smatteo if (svcport_str == NULL) { 597320217Sdelphij if ((res = malloc(sizeof(struct addrinfo))) == NULL) 598173281Smatteo out_of_mem(); 599222624Srmacklem mallocd_res = 1; 600173281Smatteo res->ai_flags = hints.ai_flags; 601173281Smatteo res->ai_family = hints.ai_family; 602173281Smatteo res->ai_protocol = hints.ai_protocol; 603173281Smatteo switch (res->ai_family) { 604173281Smatteo case AF_INET: 605173281Smatteo sin = malloc(sizeof(struct sockaddr_in)); 606173281Smatteo if (sin == NULL) 607173281Smatteo out_of_mem(); 608173281Smatteo sin->sin_family = AF_INET; 609173281Smatteo sin->sin_port = htons(0); 610173281Smatteo sin->sin_addr.s_addr = htonl(INADDR_ANY); 611173281Smatteo res->ai_addr = (struct sockaddr*) sin; 612173281Smatteo res->ai_addrlen = (socklen_t) 613222624Srmacklem sizeof(struct sockaddr_in); 614173281Smatteo break; 615173281Smatteo case AF_INET6: 616173281Smatteo sin6 = malloc(sizeof(struct sockaddr_in6)); 617173411Smatteo if (sin6 == NULL) 618173281Smatteo out_of_mem(); 619173281Smatteo sin6->sin6_family = AF_INET6; 620173281Smatteo sin6->sin6_port = htons(0); 621173281Smatteo sin6->sin6_addr = in6addr_any; 622173281Smatteo res->ai_addr = (struct sockaddr*) sin6; 623222624Srmacklem res->ai_addrlen = (socklen_t) 624222624Srmacklem sizeof(struct sockaddr_in6); 625173281Smatteo break; 626173281Smatteo default: 627222624Srmacklem syslog(LOG_ERR, 628320217Sdelphij "bad address family %d", 629222624Srmacklem res->ai_family); 630222624Srmacklem exit(1); 631173281Smatteo } 632173281Smatteo } else { 633173281Smatteo if ((aicode = getaddrinfo(NULL, svcport_str, 634173281Smatteo &hints, &res)) != 0) { 635173281Smatteo syslog(LOG_ERR, 636173281Smatteo "cannot get local address for %s: %s", 637173281Smatteo nconf->nc_netid, 638173281Smatteo gai_strerror(aicode)); 639320217Sdelphij if (!kernel_lockd) 640320217Sdelphij close(fd); 641173281Smatteo continue; 642173281Smatteo } 643173281Smatteo } 644173281Smatteo } else { 645173281Smatteo if ((aicode = getaddrinfo(hosts[nhostsbak], svcport_str, 646173281Smatteo &hints, &res)) != 0) { 647173281Smatteo syslog(LOG_ERR, 648173281Smatteo "cannot get local address for %s: %s", 649173281Smatteo nconf->nc_netid, gai_strerror(aicode)); 650320217Sdelphij if (!kernel_lockd) 651320217Sdelphij close(fd); 652173281Smatteo continue; 653173281Smatteo } 654173281Smatteo } 655173281Smatteo 656320217Sdelphij if (kernel_lockd) { 657320217Sdelphij struct netbuf servaddr; 658320217Sdelphij char *uaddr; 659222624Srmacklem 660320217Sdelphij /* 661320217Sdelphij * Look up addresses for the kernel to create transports for. 662320217Sdelphij */ 663320217Sdelphij servaddr.len = servaddr.maxlen = res->ai_addrlen; 664320217Sdelphij servaddr.buf = res->ai_addr; 665320217Sdelphij uaddr = taddr2uaddr(nconf, &servaddr); 666222624Srmacklem 667320217Sdelphij addrs = realloc(addrs, 2 * (naddrs + 1) * sizeof(char *)); 668320217Sdelphij if (!addrs) 669320217Sdelphij out_of_mem(); 670320217Sdelphij addrs[2 * naddrs] = strdup(nconf->nc_netid); 671320217Sdelphij addrs[2 * naddrs + 1] = uaddr; 672320217Sdelphij naddrs++; 673320217Sdelphij } else { 674320217Sdelphij /* Store the fd. */ 675320217Sdelphij sock_fd[sock_fdcnt - 1] = fd; 676320217Sdelphij 677320217Sdelphij /* Now, attempt the bind. */ 678320217Sdelphij r = bindresvport_sa(fd, res->ai_addr); 679320217Sdelphij if (r != 0) { 680320217Sdelphij if (errno == EADDRINUSE && mallocd_svcport != 0) { 681320217Sdelphij if (mallocd_res != 0) { 682320217Sdelphij free(res->ai_addr); 683320217Sdelphij free(res); 684320217Sdelphij } else 685320217Sdelphij freeaddrinfo(res); 686320217Sdelphij return (-1); 687320217Sdelphij } 688320217Sdelphij syslog(LOG_ERR, "bindresvport_sa: %m"); 689320217Sdelphij exit(1); 690222624Srmacklem } 691173281Smatteo 692320217Sdelphij if (svcport_str == NULL) { 693320217Sdelphij svcport_str = malloc(NI_MAXSERV * sizeof(char)); 694320217Sdelphij if (svcport_str == NULL) 695320217Sdelphij out_of_mem(); 696320217Sdelphij mallocd_svcport = 1; 697222624Srmacklem 698320217Sdelphij if (getnameinfo(res->ai_addr, 699320217Sdelphij res->ai_addr->sa_len, NULL, NI_MAXHOST, 700320217Sdelphij svcport_str, NI_MAXSERV * sizeof(char), 701320217Sdelphij NI_NUMERICHOST | NI_NUMERICSERV)) 702320217Sdelphij errx(1, "Cannot get port number"); 703320217Sdelphij } 704222624Srmacklem } 705320217Sdelphij 706222624Srmacklem if (mallocd_res != 0) { 707222624Srmacklem free(res->ai_addr); 708222624Srmacklem free(res); 709222624Srmacklem } else 710222624Srmacklem freeaddrinfo(res); 711222624Srmacklem res = NULL; 712222624Srmacklem } 713222624Srmacklem return (0); 714222624Srmacklem} 715222624Srmacklem 716222624Srmacklem/* 717222624Srmacklem * Called after all the create_service() calls have succeeded, to complete 718222624Srmacklem * the setup and registration. 719222624Srmacklem */ 720222624Srmacklemstatic void 721222624Srmacklemcomplete_service(struct netconfig *nconf, char *port_str) 722222624Srmacklem{ 723222624Srmacklem struct addrinfo hints, *res = NULL; 724222624Srmacklem struct __rpc_sockinfo si; 725222624Srmacklem struct netbuf servaddr; 726222624Srmacklem SVCXPRT *transp = NULL; 727222624Srmacklem int aicode, fd, nhostsbak; 728222624Srmacklem int registered = 0; 729222624Srmacklem 730222624Srmacklem if ((nconf->nc_semantics != NC_TPI_CLTS) && 731222624Srmacklem (nconf->nc_semantics != NC_TPI_COTS) && 732222624Srmacklem (nconf->nc_semantics != NC_TPI_COTS_ORD)) 733222624Srmacklem return; /* not my type */ 734222624Srmacklem 735222624Srmacklem /* 736222624Srmacklem * XXX - using RPC library internal functions. 737222624Srmacklem */ 738222624Srmacklem if (!__rpc_nconf2sockinfo(nconf, &si)) { 739222624Srmacklem syslog(LOG_ERR, "cannot get information for %s", 740222624Srmacklem nconf->nc_netid); 741222624Srmacklem return; 742222624Srmacklem } 743222624Srmacklem 744222624Srmacklem nhostsbak = nhosts; 745222624Srmacklem while (nhostsbak > 0) { 746222624Srmacklem --nhostsbak; 747222624Srmacklem if (sock_fdpos >= sock_fdcnt) { 748222624Srmacklem /* Should never happen. */ 749222624Srmacklem syslog(LOG_ERR, "Ran out of socket fd's"); 750222624Srmacklem return; 751222624Srmacklem } 752222624Srmacklem fd = sock_fd[sock_fdpos++]; 753222624Srmacklem if (fd < 0) 754222624Srmacklem continue; 755222624Srmacklem 756177950Sdfr if (nconf->nc_semantics != NC_TPI_CLTS) 757177950Sdfr listen(fd, SOMAXCONN); 758177950Sdfr 759173281Smatteo transp = svc_tli_create(fd, nconf, NULL, 760173281Smatteo RPC_MAXDATASIZE, RPC_MAXDATASIZE); 761173281Smatteo 762173281Smatteo if (transp != (SVCXPRT *) NULL) { 763173281Smatteo if (!svc_reg(transp, NLM_PROG, NLM_SM, nlm_prog_0, 764173281Smatteo NULL)) 765173281Smatteo syslog(LOG_ERR, 766173281Smatteo "can't register %s NLM_PROG, NLM_SM service", 767173281Smatteo nconf->nc_netid); 768173281Smatteo 769173281Smatteo if (!svc_reg(transp, NLM_PROG, NLM_VERS, nlm_prog_1, 770173281Smatteo NULL)) 771173281Smatteo syslog(LOG_ERR, 772173281Smatteo "can't register %s NLM_PROG, NLM_VERS service", 773173281Smatteo nconf->nc_netid); 774173281Smatteo 775173281Smatteo if (!svc_reg(transp, NLM_PROG, NLM_VERSX, nlm_prog_3, 776173281Smatteo NULL)) 777173281Smatteo syslog(LOG_ERR, 778173281Smatteo "can't register %s NLM_PROG, NLM_VERSX service", 779173281Smatteo nconf->nc_netid); 780173281Smatteo 781173281Smatteo if (!svc_reg(transp, NLM_PROG, NLM_VERS4, nlm_prog_4, 782173281Smatteo NULL)) 783173281Smatteo syslog(LOG_ERR, 784173281Smatteo "can't register %s NLM_PROG, NLM_VERS4 service", 785173281Smatteo nconf->nc_netid); 786173281Smatteo 787173281Smatteo } else 788173281Smatteo syslog(LOG_WARNING, "can't create %s services", 789173281Smatteo nconf->nc_netid); 790173281Smatteo 791173281Smatteo if (registered == 0) { 792173281Smatteo registered = 1; 793173281Smatteo memset(&hints, 0, sizeof hints); 794173281Smatteo hints.ai_flags = AI_PASSIVE; 795173281Smatteo hints.ai_family = si.si_af; 796173281Smatteo hints.ai_socktype = si.si_socktype; 797173281Smatteo hints.ai_protocol = si.si_proto; 798173281Smatteo 799222624Srmacklem if ((aicode = getaddrinfo(NULL, port_str, &hints, 800173281Smatteo &res)) != 0) { 801173281Smatteo syslog(LOG_ERR, "cannot get local address: %s", 802173281Smatteo gai_strerror(aicode)); 803173281Smatteo exit(1); 804173281Smatteo } 805173281Smatteo 806173281Smatteo servaddr.buf = malloc(res->ai_addrlen); 807173281Smatteo memcpy(servaddr.buf, res->ai_addr, res->ai_addrlen); 808173281Smatteo servaddr.len = res->ai_addrlen; 809173281Smatteo 810173281Smatteo rpcb_set(NLM_PROG, NLM_SM, nconf, &servaddr); 811173281Smatteo rpcb_set(NLM_PROG, NLM_VERS, nconf, &servaddr); 812173281Smatteo rpcb_set(NLM_PROG, NLM_VERSX, nconf, &servaddr); 813173281Smatteo rpcb_set(NLM_PROG, NLM_VERS4, nconf, &servaddr); 814173281Smatteo 815173281Smatteo xcreated++; 816173281Smatteo freeaddrinfo(res); 817173281Smatteo } 818173281Smatteo } /* end while */ 819173281Smatteo} 820173281Smatteo 821177633Sdfr/* 822222624Srmacklem * Clear out sockets after a failure to bind one of them, so that the 823222624Srmacklem * cycle of socket creation/binding can start anew. 824222624Srmacklem */ 825222624Srmacklemstatic void 826222624Srmacklemclearout_service(void) 827222624Srmacklem{ 828222624Srmacklem int i; 829222624Srmacklem 830222624Srmacklem for (i = 0; i < sock_fdcnt; i++) { 831222624Srmacklem if (sock_fd[i] >= 0) { 832222624Srmacklem shutdown(sock_fd[i], SHUT_RDWR); 833222624Srmacklem close(sock_fd[i]); 834222624Srmacklem } 835222624Srmacklem } 836222624Srmacklem} 837222624Srmacklem 838173281Smatteovoid 83986319Salfredsigalarm_handler(void) 84074462Salfred{ 84186319Salfred 84274462Salfred grace_expired = 1; 84374462Salfred} 84474462Salfred 84574462Salfredvoid 84630376Scharnierusage() 84730376Scharnier{ 848177666Sdfr errx(1, "usage: rpc.lockd [-d <debuglevel>]" 849355368Srpokala " [-F] [-g <grace period>] [-h <bindip>] [-p <port>]"); 85030376Scharnier} 85175631Salfred 85275631Salfred/* 85375631Salfred * init_nsm -- 85475631Salfred * Reset the NSM state-of-the-world and acquire its state. 85575631Salfred */ 85675631Salfredvoid 85775631Salfredinit_nsm(void) 85875631Salfred{ 85975631Salfred enum clnt_stat ret; 86075631Salfred my_id id; 86175631Salfred sm_stat stat; 86292978Salfred char name[] = "NFS NLM"; 86375631Salfred 86475631Salfred /* 86575631Salfred * !!! 86675631Salfred * The my_id structure isn't used by the SM_UNMON_ALL call, as far 86775631Salfred * as I know. Leave it empty for now. 86875631Salfred */ 86975631Salfred memset(&id, 0, sizeof(id)); 87092978Salfred id.my_name = name; 87175631Salfred 87275631Salfred /* 87375631Salfred * !!! 87475631Salfred * The statd program must already be registered when lockd runs. 87575631Salfred */ 87675631Salfred do { 87775631Salfred ret = callrpc("localhost", SM_PROG, SM_VERS, SM_UNMON_ALL, 878121558Speter (xdrproc_t)xdr_my_id, &id, (xdrproc_t)xdr_sm_stat, &stat); 87975631Salfred if (ret == RPC_PROGUNAVAIL) { 880113971Sghelmer syslog(LOG_WARNING, "%lu %s", SM_PROG, 881113971Sghelmer clnt_sperrno(ret)); 88275631Salfred sleep(2); 88375631Salfred continue; 88475631Salfred } 88575631Salfred break; 88675631Salfred } while (0); 88775631Salfred 88875631Salfred if (ret != 0) { 889113971Sghelmer syslog(LOG_ERR, "%lu %s", SM_PROG, clnt_sperrno(ret)); 890113971Sghelmer exit(1); 89175631Salfred } 89275631Salfred 89375631Salfred nsm_state = stat.state; 89475631Salfred 89575631Salfred /* setup constant data for SM_MON calls */ 89692978Salfred mon_host.mon_id.my_id.my_name = localhost; 89775631Salfred mon_host.mon_id.my_id.my_prog = NLM_PROG; 89875631Salfred mon_host.mon_id.my_id.my_vers = NLM_SM; 89975631Salfred mon_host.mon_id.my_id.my_proc = NLM_SM_NOTIFY; /* bsdi addition */ 90075631Salfred} 901173281Smatteo 902173281Smatteo/* 903173281Smatteo * Out of memory, fatal 904173281Smatteo */ 905173281Smatteovoid out_of_mem() 906173281Smatteo{ 907173281Smatteo syslog(LOG_ERR, "out of memory"); 908173281Smatteo exit(2); 909173281Smatteo} 910