lockd.c revision 178066
174462Salfred/*	$NetBSD: lockd.c,v 1.7 2000/08/12 18:08:44 thorpej Exp $	*/
274462Salfred/*	$FreeBSD: head/usr.sbin/rpc.lockd/lockd.c 178066 2008-04-10 12:54:53Z dfr $ */
374462Salfred
414123Speter/*
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
7774462Salfredint		debug_level = 0;	/* 0 = no debugging syslog() calls */
7874462Salfredint		_rpcsvcdirty = 0;
7914123Speter
8074462Salfredint grace_expired;
8175631Salfredint nsm_state;
82177633Sdfrint kernel_lockd;
8375631Salfredpid_t client_pid;
8475631Salfredstruct mon mon_host;
85173281Smatteochar **hosts, *svcport_str = NULL;
86173281Smatteoint nhosts = 0;
87173281Smatteoint xcreated = 0;
88177633Sdfrchar **addrs;			/* actually (netid, uaddr) pairs */
89177633Sdfrint naddrs;			/* count of how many (netid, uaddr) pairs */
9014123Speter
91173281Smatteovoid 	create_service(struct netconfig *nconf);
92177633Sdfrvoid 	lookup_addresses(struct netconfig *nconf);
9375631Salfredvoid	init_nsm(void);
9492909Salfredvoid	nlm_prog_0(struct svc_req *, SVCXPRT *);
9592909Salfredvoid	nlm_prog_1(struct svc_req *, SVCXPRT *);
9692909Salfredvoid	nlm_prog_3(struct svc_req *, SVCXPRT *);
9792909Salfredvoid	nlm_prog_4(struct svc_req *, SVCXPRT *);
98173281Smatteovoid	out_of_mem(void);
9992909Salfredvoid	usage(void);
10074462Salfred
10192909Salfredvoid sigalarm_handler(void);
10274462Salfred
103177633Sdfr/*
104177633Sdfr * XXX move to some header file.
105177633Sdfr */
106177633Sdfr#define _PATH_RPCLOCKDSOCK	"/var/run/rpclockd.sock"
107177633Sdfr
10830376Scharnierint
109173281Smatteomain(int argc, char **argv)
11014123Speter{
111173281Smatteo	int ch, i, s;
112173281Smatteo	void *nc_handle;
113173281Smatteo	char *endptr, **hosts_bak;
11487096Salfred	struct sigaction sigalarm;
11574462Salfred	int grace_period = 30;
11674462Salfred	struct netconfig *nconf;
117173281Smatteo	int have_v6 = 1;
118109363Smbr	int maxrec = RPC_MAXDATASIZE;
119168324Smatteo	in_port_t svcport = 0;
12014123Speter
121177662Sdfr	while ((ch = getopt(argc, argv, "d:g:h:p:")) != (-1)) {
12274462Salfred		switch (ch) {
12374462Salfred		case 'd':
12474462Salfred			debug_level = atoi(optarg);
12574462Salfred			if (!debug_level) {
12674462Salfred				usage();
12774462Salfred				/* NOTREACHED */
12874462Salfred			}
12974462Salfred			break;
13074462Salfred		case 'g':
13174462Salfred			grace_period = atoi(optarg);
13274462Salfred			if (!grace_period) {
13374462Salfred				usage();
13474462Salfred				/* NOTREACHED */
13574462Salfred			}
13674462Salfred			break;
137173281Smatteo		case 'h':
138173281Smatteo			++nhosts;
139173281Smatteo			hosts_bak = hosts;
140173281Smatteo			hosts_bak = realloc(hosts, nhosts * sizeof(char *));
141173281Smatteo			if (hosts_bak == NULL) {
142173281Smatteo				if (hosts != NULL) {
143173281Smatteo					for (i = 0; i < nhosts; i++)
144173281Smatteo						free(hosts[i]);
145173281Smatteo					free(hosts);
146173281Smatteo					out_of_mem();
147173281Smatteo				}
148173281Smatteo			}
149173281Smatteo			hosts = hosts_bak;
150173281Smatteo			hosts[nhosts - 1] = strdup(optarg);
151173281Smatteo			if (hosts[nhosts - 1] == NULL) {
152173281Smatteo				for (i = 0; i < (nhosts - 1); i++)
153173281Smatteo					free(hosts[i]);
154173281Smatteo				free(hosts);
155173281Smatteo				out_of_mem();
156173281Smatteo			}
157173281Smatteo			break;
158168324Smatteo		case 'p':
159168324Smatteo			endptr = NULL;
160168324Smatteo			svcport = (in_port_t)strtoul(optarg, &endptr, 10);
161168324Smatteo			if (endptr == NULL || *endptr != '\0' ||
162168324Smatteo			    svcport == 0 || svcport >= IPPORT_MAX)
163168324Smatteo				usage();
164173281Smatteo			svcport_str = strdup(optarg);
165168324Smatteo			break;
16674462Salfred		default:
16774462Salfred		case '?':
16874462Salfred			usage();
16974462Salfred			/* NOTREACHED */
17074462Salfred		}
17174462Salfred	}
17274462Salfred	if (geteuid()) { /* This command allowed only to root */
17374462Salfred		fprintf(stderr, "Sorry. You are not superuser\n");
17474462Salfred		exit(1);
17574462Salfred        }
17614123Speter
177177662Sdfr	kernel_lockd = FALSE;
178177662Sdfr	if (modfind("nfslockd") < 0) {
179177662Sdfr		if (kldload("nfslockd") < 0) {
180177662Sdfr			fprintf(stderr, "Can't find or load kernel support for rpc.lockd - using non-kernel implementation\n");
181178066Sdfr		} else {
182178066Sdfr			kernel_lockd = TRUE;
183177662Sdfr		}
184177662Sdfr	} else {
185177662Sdfr		kernel_lockd = TRUE;
186177662Sdfr	}
187177662Sdfr
18874462Salfred	(void)rpcb_unset(NLM_PROG, NLM_SM, NULL);
18974462Salfred	(void)rpcb_unset(NLM_PROG, NLM_VERS, NULL);
19074462Salfred	(void)rpcb_unset(NLM_PROG, NLM_VERSX, NULL);
19174462Salfred	(void)rpcb_unset(NLM_PROG, NLM_VERS4, NULL);
19214123Speter
19374462Salfred	/*
19474462Salfred	 * Check if IPv6 support is present.
19574462Salfred	 */
19674462Salfred	s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
19774462Salfred	if (s < 0)
198173281Smatteo		have_v6 = 0;
199173281Smatteo	else
20074462Salfred		close(s);
20114123Speter
202173281Smatteo	rpc_control(RPC_SVC_CONNMAXREC_SET, &maxrec);
203168324Smatteo
204173281Smatteo	/*
205173281Smatteo	 * If no hosts were specified, add a wildcard entry to bind to
206173281Smatteo	 * INADDR_ANY. Otherwise make sure 127.0.0.1 and ::1 are added to the
207173281Smatteo	 * list.
208173281Smatteo	 */
209173281Smatteo	if (nhosts == 0) {
210173281Smatteo		hosts = malloc(sizeof(char**));
211173281Smatteo		if (hosts == NULL)
212173281Smatteo			out_of_mem();
213168324Smatteo
214173281Smatteo		hosts[0] = "*";
215173281Smatteo		nhosts = 1;
216173281Smatteo	} else {
217173281Smatteo		hosts_bak = hosts;
218173281Smatteo		if (have_v6) {
219173281Smatteo			hosts_bak = realloc(hosts, (nhosts + 2) *
220173281Smatteo			    sizeof(char *));
221173281Smatteo			if (hosts_bak == NULL) {
222173281Smatteo				for (i = 0; i < nhosts; i++)
223173281Smatteo					free(hosts[i]);
224173281Smatteo				free(hosts);
225173281Smatteo				out_of_mem();
226173281Smatteo			} else
227173281Smatteo				hosts = hosts_bak;
228109363Smbr
229173281Smatteo			nhosts += 2;
230173281Smatteo			hosts[nhosts - 2] = "::1";
231173281Smatteo		} else {
232173281Smatteo			hosts_bak = realloc(hosts, (nhosts + 1) * sizeof(char *));
233173281Smatteo			if (hosts_bak == NULL) {
234173281Smatteo				for (i = 0; i < nhosts; i++)
235173281Smatteo					free(hosts[i]);
23614123Speter
237173281Smatteo				free(hosts);
238173281Smatteo				out_of_mem();
239173281Smatteo			} else {
240173281Smatteo				nhosts += 1;
241173281Smatteo				hosts = hosts_bak;
242168324Smatteo			}
243168324Smatteo		}
244173281Smatteo		hosts[nhosts - 1] = "127.0.0.1";
245173281Smatteo	}
246168324Smatteo
247177633Sdfr	if (kernel_lockd) {
248177633Sdfr		/*
249177633Sdfr		 * For the kernel lockd case, we run a cut-down RPC
250177633Sdfr		 * service on a local-domain socket. The kernel's RPC
251177633Sdfr		 * server will pass what it can't handle (mainly
252177633Sdfr		 * client replies) down to us. This can go away
253177633Sdfr		 * entirely if/when we move the client side of NFS
254177633Sdfr		 * locking into the kernel.
255177633Sdfr		 */
256177633Sdfr		struct sockaddr_un sun;
257177633Sdfr		int fd, oldmask;
258177633Sdfr		SVCXPRT *xprt;
259177633Sdfr
260177633Sdfr		memset(&sun, 0, sizeof sun);
261177633Sdfr		sun.sun_family = AF_LOCAL;
262177633Sdfr		unlink(_PATH_RPCLOCKDSOCK);
263177633Sdfr		strcpy(sun.sun_path, _PATH_RPCLOCKDSOCK);
264177633Sdfr		sun.sun_len = SUN_LEN(&sun);
265177633Sdfr		fd = socket(AF_LOCAL, SOCK_STREAM, 0);
266177633Sdfr		if (!fd) {
267177633Sdfr			err(1, "Can't create local lockd socket");
268177633Sdfr		}
269177633Sdfr		oldmask = umask(S_IXUSR|S_IRWXG|S_IRWXO);
270177633Sdfr		if (bind(fd, (struct sockaddr *) &sun, sun.sun_len) < 0) {
271177633Sdfr			err(1, "Can't bind local lockd socket");
272177633Sdfr		}
273177633Sdfr		umask(oldmask);
274177633Sdfr		if (listen(fd, SOMAXCONN) < 0) {
275177633Sdfr			err(1, "Can't listen on local lockd socket");
276177633Sdfr		}
277177633Sdfr		xprt = svc_vc_create(fd, RPC_MAXDATASIZE, RPC_MAXDATASIZE);
278177633Sdfr		if (!xprt) {
279177633Sdfr			err(1, "Can't create transport for local lockd socket");
280177633Sdfr		}
281177633Sdfr		if (!svc_reg(xprt, NLM_PROG, NLM_VERS4, nlm_prog_4, NULL)) {
282177633Sdfr			err(1, "Can't register service for local lockd socket");
283177633Sdfr		}
284177633Sdfr
285177633Sdfr		/*
286177633Sdfr		 * We need to look up the addresses so that we can
287177633Sdfr		 * hand uaddrs (ascii encoded address+port strings) to
288177633Sdfr		 * the kernel.
289177633Sdfr		 */
290177633Sdfr		nc_handle = setnetconfig();
291177633Sdfr		while ((nconf = getnetconfig(nc_handle))) {
292177633Sdfr			/* We want to listen only on udp6, tcp6, udp, tcp transports */
293177633Sdfr			if (nconf->nc_flag & NC_VISIBLE) {
294177633Sdfr				/* Skip if there's no IPv6 support */
295177633Sdfr				if (have_v6 == 0 && strcmp(nconf->nc_protofmly, "inet6") == 0) {
296177633Sdfr					/* DO NOTHING */
297177633Sdfr				} else {
298177633Sdfr					lookup_addresses(nconf);
299177633Sdfr				}
300173281Smatteo			}
30174462Salfred		}
302177633Sdfr		endnetconfig(nc_handle);
303177633Sdfr	} else {
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 {
312177633Sdfr					create_service(nconf);
313177633Sdfr				}
314177633Sdfr			}
315177633Sdfr		}
316177633Sdfr		endnetconfig(nc_handle);
31774462Salfred	}
31814123Speter
31974462Salfred	/*
32074462Salfred	 * Note that it is NOT sensible to run this program from inetd - the
32174462Salfred	 * protocol assumes that it will run immediately at boot time.
32274462Salfred	 */
323132254Smr	if (daemon(0, debug_level > 0)) {
32474462Salfred		err(1, "cannot fork");
32574462Salfred		/* NOTREACHED */
32674462Salfred	}
32774462Salfred
32874462Salfred	openlog("rpc.lockd", 0, LOG_DAEMON);
32974462Salfred	if (debug_level)
33074462Salfred		syslog(LOG_INFO, "Starting, debug level %d", debug_level);
33174462Salfred	else
33274462Salfred		syslog(LOG_INFO, "Starting");
33374462Salfred
33486319Salfred	sigalarm.sa_handler = (sig_t) sigalarm_handler;
33574462Salfred	sigemptyset(&sigalarm.sa_mask);
33674462Salfred	sigalarm.sa_flags = SA_RESETHAND; /* should only happen once */
33774462Salfred	sigalarm.sa_flags |= SA_RESTART;
33874462Salfred	if (sigaction(SIGALRM, &sigalarm, NULL) != 0) {
33974462Salfred		syslog(LOG_WARNING, "sigaction(SIGALRM) failed: %s",
34074462Salfred		    strerror(errno));
34174462Salfred		exit(1);
34274462Salfred	}
34374462Salfred
344177633Sdfr	if (kernel_lockd) {
345177633Sdfr		client_pid = client_request();
34675631Salfred
347177633Sdfr		/*
348177633Sdfr		 * Create a child process to enter the kernel and then
349177633Sdfr		 * wait for RPCs on our local domain socket.
350177633Sdfr		 */
351177633Sdfr		if (!fork())
352177633Sdfr			nlm_syscall(debug_level, grace_period, naddrs, addrs);
353177633Sdfr		else
354177633Sdfr			svc_run();
355177633Sdfr	} else {
356177633Sdfr		grace_expired = 0;
357177633Sdfr		alarm(grace_period);
35875631Salfred
359177633Sdfr		init_nsm();
360177633Sdfr
361177633Sdfr		client_pid = client_request();
362177633Sdfr
363177633Sdfr		svc_run();		/* Should never return */
364177633Sdfr	}
36574462Salfred	exit(1);
36614123Speter}
36730376Scharnier
368173281Smatteo/*
369173281Smatteo * This routine creates and binds sockets on the appropriate
370173281Smatteo * addresses. It gets called one time for each transport and
371173281Smatteo * registrates the service with rpcbind on that trasport.
372173281Smatteo */
37374462Salfredvoid
374173281Smatteocreate_service(struct netconfig *nconf)
375173281Smatteo{
376173281Smatteo	struct addrinfo hints, *res = NULL;
377173281Smatteo	struct sockaddr_in *sin;
378173281Smatteo	struct sockaddr_in6 *sin6;
379173281Smatteo	struct __rpc_sockinfo si;
380173281Smatteo	struct netbuf servaddr;
381173281Smatteo	SVCXPRT	*transp = NULL;
382173281Smatteo	int aicode;
383173281Smatteo	int fd;
384173281Smatteo	int nhostsbak;
385173281Smatteo	int r;
386173281Smatteo	int registered = 0;
387173281Smatteo	u_int32_t host_addr[4];  /* IPv4 or IPv6 */
388173281Smatteo
389173281Smatteo	if ((nconf->nc_semantics != NC_TPI_CLTS) &&
390173281Smatteo	    (nconf->nc_semantics != NC_TPI_COTS) &&
391173281Smatteo	    (nconf->nc_semantics != NC_TPI_COTS_ORD))
392173281Smatteo		return;	/* not my type */
393173281Smatteo
394173281Smatteo	/*
395173281Smatteo	 * XXX - using RPC library internal functions.
396173281Smatteo	 */
397173281Smatteo	if (!__rpc_nconf2sockinfo(nconf, &si)) {
398173281Smatteo		syslog(LOG_ERR, "cannot get information for %s",
399173281Smatteo		    nconf->nc_netid);
400173281Smatteo		return;
401173281Smatteo	}
402173281Smatteo
403173281Smatteo	/* Get rpc.statd's address on this transport */
404173281Smatteo	memset(&hints, 0, sizeof hints);
405173281Smatteo	hints.ai_flags = AI_PASSIVE;
406173281Smatteo	hints.ai_family = si.si_af;
407173281Smatteo	hints.ai_socktype = si.si_socktype;
408173281Smatteo	hints.ai_protocol = si.si_proto;
409173281Smatteo
410173281Smatteo	/*
411173281Smatteo	 * Bind to specific IPs if asked to
412173281Smatteo	 */
413173281Smatteo	nhostsbak = nhosts;
414173281Smatteo	while (nhostsbak > 0) {
415173281Smatteo		--nhostsbak;
416173281Smatteo
417173281Smatteo		/*
418173281Smatteo		 * XXX - using RPC library internal functions.
419173281Smatteo		 */
420173281Smatteo		if ((fd = __rpc_nconf2fd(nconf)) < 0) {
421173281Smatteo			syslog(LOG_ERR, "cannot create socket for %s",
422173281Smatteo			    nconf->nc_netid);
423173281Smatteo			continue;
424173281Smatteo		}
425173281Smatteo
426173281Smatteo		switch (hints.ai_family) {
427173281Smatteo			case AF_INET:
428173281Smatteo				if (inet_pton(AF_INET, hosts[nhostsbak],
429173281Smatteo				    host_addr) == 1) {
430173281Smatteo					hints.ai_flags &= AI_NUMERICHOST;
431173281Smatteo				} else {
432173281Smatteo					/*
433173281Smatteo					 * Skip if we have an AF_INET6 address.
434173281Smatteo					 */
435173281Smatteo					if (inet_pton(AF_INET6, hosts[nhostsbak],
436173281Smatteo					    host_addr) == 1) {
437173281Smatteo						close(fd);
438173281Smatteo						continue;
439173281Smatteo					}
440173281Smatteo				}
441173281Smatteo				break;
442173281Smatteo			case AF_INET6:
443173281Smatteo				if (inet_pton(AF_INET6, hosts[nhostsbak],
444173281Smatteo				    host_addr) == 1) {
445173281Smatteo					hints.ai_flags &= AI_NUMERICHOST;
446173281Smatteo				} else {
447173281Smatteo					/*
448173281Smatteo					 * Skip if we have an AF_INET address.
449173281Smatteo					 */
450173281Smatteo					if (inet_pton(AF_INET, hosts[nhostsbak],
451173281Smatteo					    host_addr) == 1) {
452173281Smatteo						close(fd);
453173281Smatteo						continue;
454173281Smatteo					}
455173281Smatteo				}
456173281Smatteo				break;
457173281Smatteo			default:
458173281Smatteo				break;
459173281Smatteo		}
460173281Smatteo
461173281Smatteo		/*
462173281Smatteo		 * If no hosts were specified, just bind to INADDR_ANY
463173281Smatteo		 */
464173281Smatteo		if (strcmp("*", hosts[nhostsbak]) == 0) {
465173281Smatteo			if (svcport_str == NULL) {
466173281Smatteo				res = malloc(sizeof(struct addrinfo));
467173281Smatteo				if (res == NULL)
468173281Smatteo					out_of_mem();
469173281Smatteo				res->ai_flags = hints.ai_flags;
470173281Smatteo				res->ai_family = hints.ai_family;
471173281Smatteo				res->ai_protocol = hints.ai_protocol;
472173281Smatteo				switch (res->ai_family) {
473173281Smatteo					case AF_INET:
474173281Smatteo						sin = malloc(sizeof(struct sockaddr_in));
475173281Smatteo						if (sin == NULL)
476173281Smatteo							out_of_mem();
477173281Smatteo						sin->sin_family = AF_INET;
478173281Smatteo						sin->sin_port = htons(0);
479173281Smatteo						sin->sin_addr.s_addr = htonl(INADDR_ANY);
480173281Smatteo						res->ai_addr = (struct sockaddr*) sin;
481173281Smatteo						res->ai_addrlen = (socklen_t)
482173281Smatteo						    sizeof(res->ai_addr);
483173281Smatteo						break;
484173281Smatteo					case AF_INET6:
485173281Smatteo						sin6 = malloc(sizeof(struct sockaddr_in6));
486173411Smatteo						if (sin6 == NULL)
487173281Smatteo							out_of_mem();
488173281Smatteo						sin6->sin6_family = AF_INET6;
489173281Smatteo						sin6->sin6_port = htons(0);
490173281Smatteo						sin6->sin6_addr = in6addr_any;
491173281Smatteo						res->ai_addr = (struct sockaddr*) sin6;
492173281Smatteo						res->ai_addrlen = (socklen_t) sizeof(res->ai_addr);
493173281Smatteo						break;
494173281Smatteo					default:
495173281Smatteo						break;
496173281Smatteo				}
497173281Smatteo			} else {
498173281Smatteo				if ((aicode = getaddrinfo(NULL, svcport_str,
499173281Smatteo				    &hints, &res)) != 0) {
500173281Smatteo					syslog(LOG_ERR,
501173281Smatteo					    "cannot get local address for %s: %s",
502173281Smatteo					    nconf->nc_netid,
503173281Smatteo					    gai_strerror(aicode));
504173281Smatteo					continue;
505173281Smatteo				}
506173281Smatteo			}
507173281Smatteo		} else {
508173281Smatteo			if ((aicode = getaddrinfo(hosts[nhostsbak], svcport_str,
509173281Smatteo			    &hints, &res)) != 0) {
510173281Smatteo				syslog(LOG_ERR,
511173281Smatteo				    "cannot get local address for %s: %s",
512173281Smatteo				    nconf->nc_netid, gai_strerror(aicode));
513173281Smatteo				continue;
514173281Smatteo			}
515173281Smatteo		}
516173281Smatteo
517173281Smatteo		r = bindresvport_sa(fd, res->ai_addr);
518173281Smatteo		if (r != 0) {
519173281Smatteo			syslog(LOG_ERR, "bindresvport_sa: %m");
520173281Smatteo			exit(1);
521173281Smatteo		}
522173281Smatteo
523177950Sdfr		if (nconf->nc_semantics != NC_TPI_CLTS)
524177950Sdfr		    listen(fd, SOMAXCONN);
525177950Sdfr
526173281Smatteo		transp = svc_tli_create(fd, nconf, NULL,
527173281Smatteo		    RPC_MAXDATASIZE, RPC_MAXDATASIZE);
528173281Smatteo
529173281Smatteo		if (transp != (SVCXPRT *) NULL) {
530173281Smatteo			if (!svc_reg(transp, NLM_PROG, NLM_SM, nlm_prog_0,
531173281Smatteo			    NULL))
532173281Smatteo				syslog(LOG_ERR,
533173281Smatteo				    "can't register %s NLM_PROG, NLM_SM service",
534173281Smatteo				    nconf->nc_netid);
535173281Smatteo
536173281Smatteo			if (!svc_reg(transp, NLM_PROG, NLM_VERS, nlm_prog_1,
537173281Smatteo			    NULL))
538173281Smatteo				syslog(LOG_ERR,
539173281Smatteo				    "can't register %s NLM_PROG, NLM_VERS service",
540173281Smatteo				    nconf->nc_netid);
541173281Smatteo
542173281Smatteo			if (!svc_reg(transp, NLM_PROG, NLM_VERSX, nlm_prog_3,
543173281Smatteo			    NULL))
544173281Smatteo				syslog(LOG_ERR,
545173281Smatteo				    "can't register %s NLM_PROG, NLM_VERSX service",
546173281Smatteo				    nconf->nc_netid);
547173281Smatteo
548173281Smatteo			if (!svc_reg(transp, NLM_PROG, NLM_VERS4, nlm_prog_4,
549173281Smatteo			    NULL))
550173281Smatteo				syslog(LOG_ERR,
551173281Smatteo				    "can't register %s NLM_PROG, NLM_VERS4 service",
552173281Smatteo				    nconf->nc_netid);
553173281Smatteo
554173281Smatteo		} else
555173281Smatteo			syslog(LOG_WARNING, "can't create %s services",
556173281Smatteo			    nconf->nc_netid);
557173281Smatteo
558173281Smatteo		if (registered == 0) {
559173281Smatteo			registered = 1;
560173281Smatteo			memset(&hints, 0, sizeof hints);
561173281Smatteo			hints.ai_flags = AI_PASSIVE;
562173281Smatteo			hints.ai_family = si.si_af;
563173281Smatteo			hints.ai_socktype = si.si_socktype;
564173281Smatteo			hints.ai_protocol = si.si_proto;
565173281Smatteo
566173281Smatteo			if (svcport_str == NULL) {
567173281Smatteo				svcport_str = malloc(NI_MAXSERV * sizeof(char));
568173281Smatteo				if (svcport_str == NULL)
569173281Smatteo					out_of_mem();
570173281Smatteo
571173281Smatteo				if (getnameinfo(res->ai_addr,
572173281Smatteo				    res->ai_addr->sa_len, NULL, NI_MAXHOST,
573173281Smatteo				    svcport_str, NI_MAXSERV * sizeof(char),
574173281Smatteo				    NI_NUMERICHOST | NI_NUMERICSERV))
575173281Smatteo					errx(1, "Cannot get port number");
576173281Smatteo			}
577173281Smatteo
578173281Smatteo			if((aicode = getaddrinfo(NULL, svcport_str, &hints,
579173281Smatteo			    &res)) != 0) {
580173281Smatteo				syslog(LOG_ERR, "cannot get local address: %s",
581173281Smatteo				    gai_strerror(aicode));
582173281Smatteo				exit(1);
583173281Smatteo			}
584173281Smatteo
585173281Smatteo			servaddr.buf = malloc(res->ai_addrlen);
586173281Smatteo			memcpy(servaddr.buf, res->ai_addr, res->ai_addrlen);
587173281Smatteo			servaddr.len = res->ai_addrlen;
588173281Smatteo
589173281Smatteo			rpcb_set(NLM_PROG, NLM_SM, nconf, &servaddr);
590173281Smatteo			rpcb_set(NLM_PROG, NLM_VERS, nconf, &servaddr);
591173281Smatteo			rpcb_set(NLM_PROG, NLM_VERSX, nconf, &servaddr);
592173281Smatteo			rpcb_set(NLM_PROG, NLM_VERS4, nconf, &servaddr);
593173281Smatteo
594173281Smatteo			xcreated++;
595173281Smatteo			freeaddrinfo(res);
596173281Smatteo		}
597173281Smatteo	} /* end while */
598173281Smatteo}
599173281Smatteo
600177633Sdfr/*
601177633Sdfr * Look up addresses for the kernel to create transports for.
602177633Sdfr */
603173281Smatteovoid
604177633Sdfrlookup_addresses(struct netconfig *nconf)
605177633Sdfr{
606177633Sdfr	struct addrinfo hints, *res = NULL;
607177633Sdfr	struct sockaddr_in *sin;
608177633Sdfr	struct sockaddr_in6 *sin6;
609177633Sdfr	struct __rpc_sockinfo si;
610177633Sdfr	struct netbuf servaddr;
611177633Sdfr	SVCXPRT	*transp = NULL;
612177633Sdfr	int aicode;
613177633Sdfr	int nhostsbak;
614177633Sdfr	int r;
615177633Sdfr	int registered = 0;
616177633Sdfr	u_int32_t host_addr[4];  /* IPv4 or IPv6 */
617177633Sdfr	char *uaddr;
618177633Sdfr
619177633Sdfr	if ((nconf->nc_semantics != NC_TPI_CLTS) &&
620177633Sdfr	    (nconf->nc_semantics != NC_TPI_COTS) &&
621177633Sdfr	    (nconf->nc_semantics != NC_TPI_COTS_ORD))
622177633Sdfr		return;	/* not my type */
623177633Sdfr
624177633Sdfr	/*
625177633Sdfr	 * XXX - using RPC library internal functions.
626177633Sdfr	 */
627177633Sdfr	if (!__rpc_nconf2sockinfo(nconf, &si)) {
628177633Sdfr		syslog(LOG_ERR, "cannot get information for %s",
629177633Sdfr		    nconf->nc_netid);
630177633Sdfr		return;
631177633Sdfr	}
632177633Sdfr
633177633Sdfr	/* Get rpc.statd's address on this transport */
634177633Sdfr	memset(&hints, 0, sizeof hints);
635177633Sdfr	hints.ai_flags = AI_PASSIVE;
636177633Sdfr	hints.ai_family = si.si_af;
637177633Sdfr	hints.ai_socktype = si.si_socktype;
638177633Sdfr	hints.ai_protocol = si.si_proto;
639177633Sdfr
640177633Sdfr	/*
641177633Sdfr	 * Bind to specific IPs if asked to
642177633Sdfr	 */
643177633Sdfr	nhostsbak = nhosts;
644177633Sdfr	while (nhostsbak > 0) {
645177633Sdfr		--nhostsbak;
646177633Sdfr
647177633Sdfr		switch (hints.ai_family) {
648177633Sdfr			case AF_INET:
649177633Sdfr				if (inet_pton(AF_INET, hosts[nhostsbak],
650177633Sdfr				    host_addr) == 1) {
651177633Sdfr					hints.ai_flags &= AI_NUMERICHOST;
652177633Sdfr				} else {
653177633Sdfr					/*
654177633Sdfr					 * Skip if we have an AF_INET6 address.
655177633Sdfr					 */
656177633Sdfr					if (inet_pton(AF_INET6, hosts[nhostsbak],
657177633Sdfr					    host_addr) == 1) {
658177633Sdfr						continue;
659177633Sdfr					}
660177633Sdfr				}
661177633Sdfr				break;
662177633Sdfr			case AF_INET6:
663177633Sdfr				if (inet_pton(AF_INET6, hosts[nhostsbak],
664177633Sdfr				    host_addr) == 1) {
665177633Sdfr					hints.ai_flags &= AI_NUMERICHOST;
666177633Sdfr				} else {
667177633Sdfr					/*
668177633Sdfr					 * Skip if we have an AF_INET address.
669177633Sdfr					 */
670177633Sdfr					if (inet_pton(AF_INET, hosts[nhostsbak],
671177633Sdfr					    host_addr) == 1) {
672177633Sdfr						continue;
673177633Sdfr					}
674177633Sdfr				}
675177633Sdfr				break;
676177633Sdfr			default:
677177633Sdfr				break;
678177633Sdfr		}
679177633Sdfr
680177633Sdfr		/*
681177633Sdfr		 * If no hosts were specified, just bind to INADDR_ANY
682177633Sdfr		 */
683177633Sdfr		if (strcmp("*", hosts[nhostsbak]) == 0) {
684177633Sdfr			if (svcport_str == NULL) {
685177633Sdfr				res = malloc(sizeof(struct addrinfo));
686177633Sdfr				if (res == NULL)
687177633Sdfr					out_of_mem();
688177633Sdfr				res->ai_flags = hints.ai_flags;
689177633Sdfr				res->ai_family = hints.ai_family;
690177633Sdfr				res->ai_protocol = hints.ai_protocol;
691177633Sdfr				switch (res->ai_family) {
692177633Sdfr					case AF_INET:
693177633Sdfr						sin = malloc(sizeof(struct sockaddr_in));
694177633Sdfr						if (sin == NULL)
695177633Sdfr							out_of_mem();
696177633Sdfr						sin->sin_family = AF_INET;
697177633Sdfr						sin->sin_port = htons(0);
698177633Sdfr						sin->sin_addr.s_addr = htonl(INADDR_ANY);
699177633Sdfr						res->ai_addr = (struct sockaddr*) sin;
700177633Sdfr						res->ai_addrlen = (socklen_t)
701177633Sdfr						    sizeof(res->ai_addr);
702177633Sdfr						break;
703177633Sdfr					case AF_INET6:
704177633Sdfr						sin6 = malloc(sizeof(struct sockaddr_in6));
705177633Sdfr						if (sin6 == NULL)
706177633Sdfr							out_of_mem();
707177633Sdfr						sin6->sin6_family = AF_INET6;
708177633Sdfr						sin6->sin6_port = htons(0);
709177633Sdfr						sin6->sin6_addr = in6addr_any;
710177633Sdfr						res->ai_addr = (struct sockaddr*) sin6;
711177633Sdfr						res->ai_addrlen = (socklen_t) sizeof(res->ai_addr);
712177633Sdfr						break;
713177633Sdfr					default:
714177633Sdfr						break;
715177633Sdfr				}
716177633Sdfr			} else {
717177633Sdfr				if ((aicode = getaddrinfo(NULL, svcport_str,
718177633Sdfr				    &hints, &res)) != 0) {
719177633Sdfr					syslog(LOG_ERR,
720177633Sdfr					    "cannot get local address for %s: %s",
721177633Sdfr					    nconf->nc_netid,
722177633Sdfr					    gai_strerror(aicode));
723177633Sdfr					continue;
724177633Sdfr				}
725177633Sdfr			}
726177633Sdfr		} else {
727177633Sdfr			if ((aicode = getaddrinfo(hosts[nhostsbak], svcport_str,
728177633Sdfr			    &hints, &res)) != 0) {
729177633Sdfr				syslog(LOG_ERR,
730177633Sdfr				    "cannot get local address for %s: %s",
731177633Sdfr				    nconf->nc_netid, gai_strerror(aicode));
732177633Sdfr				continue;
733177633Sdfr			}
734177633Sdfr		}
735177633Sdfr
736177633Sdfr		servaddr.len = servaddr.maxlen = res->ai_addr->sa_len;
737177633Sdfr		servaddr.buf = res->ai_addr;
738177633Sdfr		uaddr = taddr2uaddr(nconf, &servaddr);
739177633Sdfr
740177633Sdfr		addrs = realloc(addrs, 2 * (naddrs + 1) * sizeof(char *));
741177633Sdfr		if (!addrs)
742177633Sdfr			out_of_mem();
743177633Sdfr		addrs[2 * naddrs] = strdup(nconf->nc_netid);
744177633Sdfr		addrs[2 * naddrs + 1] = uaddr;
745177633Sdfr		naddrs++;
746177633Sdfr	} /* end while */
747177633Sdfr}
748177633Sdfr
749177633Sdfrvoid
75086319Salfredsigalarm_handler(void)
75174462Salfred{
75286319Salfred
75374462Salfred	grace_expired = 1;
75474462Salfred}
75574462Salfred
75674462Salfredvoid
75730376Scharnierusage()
75830376Scharnier{
759177666Sdfr	errx(1, "usage: rpc.lockd [-d <debuglevel>]"
760173281Smatteo	    " [-g <grace period>] [-h <bindip>] [-p <port>]");
76130376Scharnier}
76275631Salfred
76375631Salfred/*
76475631Salfred * init_nsm --
76575631Salfred *	Reset the NSM state-of-the-world and acquire its state.
76675631Salfred */
76775631Salfredvoid
76875631Salfredinit_nsm(void)
76975631Salfred{
77075631Salfred	enum clnt_stat ret;
77175631Salfred	my_id id;
77275631Salfred	sm_stat stat;
77392978Salfred	char name[] = "NFS NLM";
77492978Salfred	char localhost[] = "localhost";
77575631Salfred
77675631Salfred	/*
77775631Salfred	 * !!!
77875631Salfred	 * The my_id structure isn't used by the SM_UNMON_ALL call, as far
77975631Salfred	 * as I know.  Leave it empty for now.
78075631Salfred	 */
78175631Salfred	memset(&id, 0, sizeof(id));
78292978Salfred	id.my_name = name;
78375631Salfred
78475631Salfred	/*
78575631Salfred	 * !!!
78675631Salfred	 * The statd program must already be registered when lockd runs.
78775631Salfred	 */
78875631Salfred	do {
78975631Salfred		ret = callrpc("localhost", SM_PROG, SM_VERS, SM_UNMON_ALL,
790121558Speter		    (xdrproc_t)xdr_my_id, &id, (xdrproc_t)xdr_sm_stat, &stat);
79175631Salfred		if (ret == RPC_PROGUNAVAIL) {
792113971Sghelmer			syslog(LOG_WARNING, "%lu %s", SM_PROG,
793113971Sghelmer			    clnt_sperrno(ret));
79475631Salfred			sleep(2);
79575631Salfred			continue;
79675631Salfred		}
79775631Salfred		break;
79875631Salfred	} while (0);
79975631Salfred
80075631Salfred	if (ret != 0) {
801113971Sghelmer		syslog(LOG_ERR, "%lu %s", SM_PROG, clnt_sperrno(ret));
802113971Sghelmer		exit(1);
80375631Salfred	}
80475631Salfred
80575631Salfred	nsm_state = stat.state;
80675631Salfred
80775631Salfred	/* setup constant data for SM_MON calls */
80892978Salfred	mon_host.mon_id.my_id.my_name = localhost;
80975631Salfred	mon_host.mon_id.my_id.my_prog = NLM_PROG;
81075631Salfred	mon_host.mon_id.my_id.my_vers = NLM_SM;
81175631Salfred	mon_host.mon_id.my_id.my_proc = NLM_SM_NOTIFY;  /* bsdi addition */
81275631Salfred}
813173281Smatteo
814173281Smatteo/*
815173281Smatteo * Out of memory, fatal
816173281Smatteo */
817173281Smatteovoid out_of_mem()
818173281Smatteo{
819173281Smatteo	syslog(LOG_ERR, "out of memory");
820173281Smatteo	exit(2);
821173281Smatteo}
822