lockd.c revision 177633
174462Salfred/*	$NetBSD: lockd.c,v 1.7 2000/08/12 18:08:44 thorpej Exp $	*/
274462Salfred/*	$FreeBSD: head/usr.sbin/rpc.lockd/lockd.c 177633 2008-03-26 15:23:12Z 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
4974462Salfred#include <sys/types.h>
5074462Salfred#include <sys/socket.h>
51177633Sdfr#include <sys/stat.h>
5274462Salfred
53173281Smatteo#include <netinet/in.h>
54173281Smatteo#include <arpa/inet.h>
55173281Smatteo
5630376Scharnier#include <err.h>
5774462Salfred#include <stdio.h>
5830376Scharnier#include <stdlib.h>
5974462Salfred#include <errno.h>
6074462Salfred#include <syslog.h>
6174462Salfred#include <signal.h>
6230376Scharnier#include <string.h>
6374462Salfred#include <unistd.h>
6474462Salfred#include <libutil.h>
6574462Salfred#include <netconfig.h>
66173281Smatteo#include <netdb.h>
6774462Salfred
6830376Scharnier#include <rpc/rpc.h>
69109363Smbr#include <rpc/rpc_com.h>
7074462Salfred#include <rpcsvc/sm_inter.h>
7174462Salfred
7214123Speter#include "lockd.h"
7374462Salfred#include <rpcsvc/nlm_prot.h>
7414123Speter
7574462Salfredint		debug_level = 0;	/* 0 = no debugging syslog() calls */
7674462Salfredint		_rpcsvcdirty = 0;
7714123Speter
7874462Salfredint grace_expired;
7975631Salfredint nsm_state;
80177633Sdfrint kernel_lockd;
8175631Salfredpid_t client_pid;
8275631Salfredstruct mon mon_host;
83173281Smatteochar **hosts, *svcport_str = NULL;
84173281Smatteoint nhosts = 0;
85173281Smatteoint xcreated = 0;
86177633Sdfrchar **addrs;			/* actually (netid, uaddr) pairs */
87177633Sdfrint naddrs;			/* count of how many (netid, uaddr) pairs */
8814123Speter
89173281Smatteovoid 	create_service(struct netconfig *nconf);
90177633Sdfrvoid 	lookup_addresses(struct netconfig *nconf);
9175631Salfredvoid	init_nsm(void);
9292909Salfredvoid	nlm_prog_0(struct svc_req *, SVCXPRT *);
9392909Salfredvoid	nlm_prog_1(struct svc_req *, SVCXPRT *);
9492909Salfredvoid	nlm_prog_3(struct svc_req *, SVCXPRT *);
9592909Salfredvoid	nlm_prog_4(struct svc_req *, SVCXPRT *);
96173281Smatteovoid	out_of_mem(void);
9792909Salfredvoid	usage(void);
9874462Salfred
9992909Salfredvoid sigalarm_handler(void);
10074462Salfred
101177633Sdfr/*
102177633Sdfr * XXX move to some header file.
103177633Sdfr */
104177633Sdfr#define _PATH_RPCLOCKDSOCK	"/var/run/rpclockd.sock"
105177633Sdfr
10630376Scharnierint
107173281Smatteomain(int argc, char **argv)
10814123Speter{
109173281Smatteo	int ch, i, s;
110173281Smatteo	void *nc_handle;
111173281Smatteo	char *endptr, **hosts_bak;
11287096Salfred	struct sigaction sigalarm;
11374462Salfred	int grace_period = 30;
11474462Salfred	struct netconfig *nconf;
115173281Smatteo	int have_v6 = 1;
116109363Smbr	int maxrec = RPC_MAXDATASIZE;
117168324Smatteo	in_port_t svcport = 0;
11814123Speter
119177633Sdfr	while ((ch = getopt(argc, argv, "d:g:h:kp:")) != (-1)) {
12074462Salfred		switch (ch) {
12174462Salfred		case 'd':
12274462Salfred			debug_level = atoi(optarg);
12374462Salfred			if (!debug_level) {
12474462Salfred				usage();
12574462Salfred				/* NOTREACHED */
12674462Salfred			}
12774462Salfred			break;
12874462Salfred		case 'g':
12974462Salfred			grace_period = atoi(optarg);
13074462Salfred			if (!grace_period) {
13174462Salfred				usage();
13274462Salfred				/* NOTREACHED */
13374462Salfred			}
13474462Salfred			break;
135173281Smatteo		case 'h':
136173281Smatteo			++nhosts;
137173281Smatteo			hosts_bak = hosts;
138173281Smatteo			hosts_bak = realloc(hosts, nhosts * sizeof(char *));
139173281Smatteo			if (hosts_bak == NULL) {
140173281Smatteo				if (hosts != NULL) {
141173281Smatteo					for (i = 0; i < nhosts; i++)
142173281Smatteo						free(hosts[i]);
143173281Smatteo					free(hosts);
144173281Smatteo					out_of_mem();
145173281Smatteo				}
146173281Smatteo			}
147173281Smatteo			hosts = hosts_bak;
148173281Smatteo			hosts[nhosts - 1] = strdup(optarg);
149173281Smatteo			if (hosts[nhosts - 1] == NULL) {
150173281Smatteo				for (i = 0; i < (nhosts - 1); i++)
151173281Smatteo					free(hosts[i]);
152173281Smatteo				free(hosts);
153173281Smatteo				out_of_mem();
154173281Smatteo			}
155173281Smatteo			break;
156177633Sdfr		case 'k':
157177633Sdfr			kernel_lockd = TRUE;
158177633Sdfr			break;
159168324Smatteo		case 'p':
160168324Smatteo			endptr = NULL;
161168324Smatteo			svcport = (in_port_t)strtoul(optarg, &endptr, 10);
162168324Smatteo			if (endptr == NULL || *endptr != '\0' ||
163168324Smatteo			    svcport == 0 || svcport >= IPPORT_MAX)
164168324Smatteo				usage();
165173281Smatteo			svcport_str = strdup(optarg);
166168324Smatteo			break;
16774462Salfred		default:
16874462Salfred		case '?':
16974462Salfred			usage();
17074462Salfred			/* NOTREACHED */
17174462Salfred		}
17274462Salfred	}
17374462Salfred	if (geteuid()) { /* This command allowed only to root */
17474462Salfred		fprintf(stderr, "Sorry. You are not superuser\n");
17574462Salfred		exit(1);
17674462Salfred        }
17714123Speter
17874462Salfred	(void)rpcb_unset(NLM_PROG, NLM_SM, NULL);
17974462Salfred	(void)rpcb_unset(NLM_PROG, NLM_VERS, NULL);
18074462Salfred	(void)rpcb_unset(NLM_PROG, NLM_VERSX, NULL);
18174462Salfred	(void)rpcb_unset(NLM_PROG, NLM_VERS4, NULL);
18214123Speter
18374462Salfred	/*
18474462Salfred	 * Check if IPv6 support is present.
18574462Salfred	 */
18674462Salfred	s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
18774462Salfred	if (s < 0)
188173281Smatteo		have_v6 = 0;
189173281Smatteo	else
19074462Salfred		close(s);
19114123Speter
192173281Smatteo	rpc_control(RPC_SVC_CONNMAXREC_SET, &maxrec);
193168324Smatteo
194173281Smatteo	/*
195173281Smatteo	 * If no hosts were specified, add a wildcard entry to bind to
196173281Smatteo	 * INADDR_ANY. Otherwise make sure 127.0.0.1 and ::1 are added to the
197173281Smatteo	 * list.
198173281Smatteo	 */
199173281Smatteo	if (nhosts == 0) {
200173281Smatteo		hosts = malloc(sizeof(char**));
201173281Smatteo		if (hosts == NULL)
202173281Smatteo			out_of_mem();
203168324Smatteo
204173281Smatteo		hosts[0] = "*";
205173281Smatteo		nhosts = 1;
206173281Smatteo	} else {
207173281Smatteo		hosts_bak = hosts;
208173281Smatteo		if (have_v6) {
209173281Smatteo			hosts_bak = realloc(hosts, (nhosts + 2) *
210173281Smatteo			    sizeof(char *));
211173281Smatteo			if (hosts_bak == NULL) {
212173281Smatteo				for (i = 0; i < nhosts; i++)
213173281Smatteo					free(hosts[i]);
214173281Smatteo				free(hosts);
215173281Smatteo				out_of_mem();
216173281Smatteo			} else
217173281Smatteo				hosts = hosts_bak;
218109363Smbr
219173281Smatteo			nhosts += 2;
220173281Smatteo			hosts[nhosts - 2] = "::1";
221173281Smatteo		} else {
222173281Smatteo			hosts_bak = realloc(hosts, (nhosts + 1) * sizeof(char *));
223173281Smatteo			if (hosts_bak == NULL) {
224173281Smatteo				for (i = 0; i < nhosts; i++)
225173281Smatteo					free(hosts[i]);
22614123Speter
227173281Smatteo				free(hosts);
228173281Smatteo				out_of_mem();
229173281Smatteo			} else {
230173281Smatteo				nhosts += 1;
231173281Smatteo				hosts = hosts_bak;
232168324Smatteo			}
233168324Smatteo		}
234173281Smatteo		hosts[nhosts - 1] = "127.0.0.1";
235173281Smatteo	}
236168324Smatteo
237177633Sdfr	if (kernel_lockd) {
238177633Sdfr		/*
239177633Sdfr		 * For the kernel lockd case, we run a cut-down RPC
240177633Sdfr		 * service on a local-domain socket. The kernel's RPC
241177633Sdfr		 * server will pass what it can't handle (mainly
242177633Sdfr		 * client replies) down to us. This can go away
243177633Sdfr		 * entirely if/when we move the client side of NFS
244177633Sdfr		 * locking into the kernel.
245177633Sdfr		 */
246177633Sdfr		struct sockaddr_un sun;
247177633Sdfr		int fd, oldmask;
248177633Sdfr		SVCXPRT *xprt;
249177633Sdfr
250177633Sdfr		memset(&sun, 0, sizeof sun);
251177633Sdfr		sun.sun_family = AF_LOCAL;
252177633Sdfr		unlink(_PATH_RPCLOCKDSOCK);
253177633Sdfr		strcpy(sun.sun_path, _PATH_RPCLOCKDSOCK);
254177633Sdfr		sun.sun_len = SUN_LEN(&sun);
255177633Sdfr		fd = socket(AF_LOCAL, SOCK_STREAM, 0);
256177633Sdfr		if (!fd) {
257177633Sdfr			err(1, "Can't create local lockd socket");
258177633Sdfr		}
259177633Sdfr		oldmask = umask(S_IXUSR|S_IRWXG|S_IRWXO);
260177633Sdfr		if (bind(fd, (struct sockaddr *) &sun, sun.sun_len) < 0) {
261177633Sdfr			err(1, "Can't bind local lockd socket");
262177633Sdfr		}
263177633Sdfr		umask(oldmask);
264177633Sdfr		if (listen(fd, SOMAXCONN) < 0) {
265177633Sdfr			err(1, "Can't listen on local lockd socket");
266177633Sdfr		}
267177633Sdfr		xprt = svc_vc_create(fd, RPC_MAXDATASIZE, RPC_MAXDATASIZE);
268177633Sdfr		if (!xprt) {
269177633Sdfr			err(1, "Can't create transport for local lockd socket");
270177633Sdfr		}
271177633Sdfr		if (!svc_reg(xprt, NLM_PROG, NLM_VERS4, nlm_prog_4, NULL)) {
272177633Sdfr			err(1, "Can't register service for local lockd socket");
273177633Sdfr		}
274177633Sdfr
275177633Sdfr		/*
276177633Sdfr		 * We need to look up the addresses so that we can
277177633Sdfr		 * hand uaddrs (ascii encoded address+port strings) to
278177633Sdfr		 * the kernel.
279177633Sdfr		 */
280177633Sdfr		nc_handle = setnetconfig();
281177633Sdfr		while ((nconf = getnetconfig(nc_handle))) {
282177633Sdfr			/* We want to listen only on udp6, tcp6, udp, tcp transports */
283177633Sdfr			if (nconf->nc_flag & NC_VISIBLE) {
284177633Sdfr				/* Skip if there's no IPv6 support */
285177633Sdfr				if (have_v6 == 0 && strcmp(nconf->nc_protofmly, "inet6") == 0) {
286177633Sdfr					/* DO NOTHING */
287177633Sdfr				} else {
288177633Sdfr					lookup_addresses(nconf);
289177633Sdfr				}
290173281Smatteo			}
29174462Salfred		}
292177633Sdfr		endnetconfig(nc_handle);
293177633Sdfr	} else {
294177633Sdfr		nc_handle = setnetconfig();
295177633Sdfr		while ((nconf = getnetconfig(nc_handle))) {
296177633Sdfr			/* We want to listen only on udp6, tcp6, udp, tcp transports */
297177633Sdfr			if (nconf->nc_flag & NC_VISIBLE) {
298177633Sdfr				/* Skip if there's no IPv6 support */
299177633Sdfr				if (have_v6 == 0 && strcmp(nconf->nc_protofmly, "inet6") == 0) {
300177633Sdfr					/* DO NOTHING */
301177633Sdfr				} else {
302177633Sdfr					create_service(nconf);
303177633Sdfr				}
304177633Sdfr			}
305177633Sdfr		}
306177633Sdfr		endnetconfig(nc_handle);
30774462Salfred	}
30814123Speter
30974462Salfred	/*
31074462Salfred	 * Note that it is NOT sensible to run this program from inetd - the
31174462Salfred	 * protocol assumes that it will run immediately at boot time.
31274462Salfred	 */
313132254Smr	if (daemon(0, debug_level > 0)) {
31474462Salfred		err(1, "cannot fork");
31574462Salfred		/* NOTREACHED */
31674462Salfred	}
31774462Salfred
31874462Salfred	openlog("rpc.lockd", 0, LOG_DAEMON);
31974462Salfred	if (debug_level)
32074462Salfred		syslog(LOG_INFO, "Starting, debug level %d", debug_level);
32174462Salfred	else
32274462Salfred		syslog(LOG_INFO, "Starting");
32374462Salfred
32486319Salfred	sigalarm.sa_handler = (sig_t) sigalarm_handler;
32574462Salfred	sigemptyset(&sigalarm.sa_mask);
32674462Salfred	sigalarm.sa_flags = SA_RESETHAND; /* should only happen once */
32774462Salfred	sigalarm.sa_flags |= SA_RESTART;
32874462Salfred	if (sigaction(SIGALRM, &sigalarm, NULL) != 0) {
32974462Salfred		syslog(LOG_WARNING, "sigaction(SIGALRM) failed: %s",
33074462Salfred		    strerror(errno));
33174462Salfred		exit(1);
33274462Salfred	}
33374462Salfred
334177633Sdfr	if (kernel_lockd) {
335177633Sdfr		client_pid = client_request();
33675631Salfred
337177633Sdfr		/*
338177633Sdfr		 * Create a child process to enter the kernel and then
339177633Sdfr		 * wait for RPCs on our local domain socket.
340177633Sdfr		 */
341177633Sdfr		if (!fork())
342177633Sdfr			nlm_syscall(debug_level, grace_period, naddrs, addrs);
343177633Sdfr		else
344177633Sdfr			svc_run();
345177633Sdfr	} else {
346177633Sdfr		grace_expired = 0;
347177633Sdfr		alarm(grace_period);
34875631Salfred
349177633Sdfr		init_nsm();
350177633Sdfr
351177633Sdfr		client_pid = client_request();
352177633Sdfr
353177633Sdfr		svc_run();		/* Should never return */
354177633Sdfr	}
35574462Salfred	exit(1);
35614123Speter}
35730376Scharnier
358173281Smatteo/*
359173281Smatteo * This routine creates and binds sockets on the appropriate
360173281Smatteo * addresses. It gets called one time for each transport and
361173281Smatteo * registrates the service with rpcbind on that trasport.
362173281Smatteo */
36374462Salfredvoid
364173281Smatteocreate_service(struct netconfig *nconf)
365173281Smatteo{
366173281Smatteo	struct addrinfo hints, *res = NULL;
367173281Smatteo	struct sockaddr_in *sin;
368173281Smatteo	struct sockaddr_in6 *sin6;
369173281Smatteo	struct __rpc_sockinfo si;
370173281Smatteo	struct netbuf servaddr;
371173281Smatteo	SVCXPRT	*transp = NULL;
372173281Smatteo	int aicode;
373173281Smatteo	int fd;
374173281Smatteo	int nhostsbak;
375173281Smatteo	int r;
376173281Smatteo	int registered = 0;
377173281Smatteo	u_int32_t host_addr[4];  /* IPv4 or IPv6 */
378173281Smatteo
379173281Smatteo	if ((nconf->nc_semantics != NC_TPI_CLTS) &&
380173281Smatteo	    (nconf->nc_semantics != NC_TPI_COTS) &&
381173281Smatteo	    (nconf->nc_semantics != NC_TPI_COTS_ORD))
382173281Smatteo		return;	/* not my type */
383173281Smatteo
384173281Smatteo	/*
385173281Smatteo	 * XXX - using RPC library internal functions.
386173281Smatteo	 */
387173281Smatteo	if (!__rpc_nconf2sockinfo(nconf, &si)) {
388173281Smatteo		syslog(LOG_ERR, "cannot get information for %s",
389173281Smatteo		    nconf->nc_netid);
390173281Smatteo		return;
391173281Smatteo	}
392173281Smatteo
393173281Smatteo	/* Get rpc.statd's address on this transport */
394173281Smatteo	memset(&hints, 0, sizeof hints);
395173281Smatteo	hints.ai_flags = AI_PASSIVE;
396173281Smatteo	hints.ai_family = si.si_af;
397173281Smatteo	hints.ai_socktype = si.si_socktype;
398173281Smatteo	hints.ai_protocol = si.si_proto;
399173281Smatteo
400173281Smatteo	/*
401173281Smatteo	 * Bind to specific IPs if asked to
402173281Smatteo	 */
403173281Smatteo	nhostsbak = nhosts;
404173281Smatteo	while (nhostsbak > 0) {
405173281Smatteo		--nhostsbak;
406173281Smatteo
407173281Smatteo		/*
408173281Smatteo		 * XXX - using RPC library internal functions.
409173281Smatteo		 */
410173281Smatteo		if ((fd = __rpc_nconf2fd(nconf)) < 0) {
411173281Smatteo			syslog(LOG_ERR, "cannot create socket for %s",
412173281Smatteo			    nconf->nc_netid);
413173281Smatteo			continue;
414173281Smatteo		}
415173281Smatteo
416173281Smatteo		switch (hints.ai_family) {
417173281Smatteo			case AF_INET:
418173281Smatteo				if (inet_pton(AF_INET, hosts[nhostsbak],
419173281Smatteo				    host_addr) == 1) {
420173281Smatteo					hints.ai_flags &= AI_NUMERICHOST;
421173281Smatteo				} else {
422173281Smatteo					/*
423173281Smatteo					 * Skip if we have an AF_INET6 address.
424173281Smatteo					 */
425173281Smatteo					if (inet_pton(AF_INET6, hosts[nhostsbak],
426173281Smatteo					    host_addr) == 1) {
427173281Smatteo						close(fd);
428173281Smatteo						continue;
429173281Smatteo					}
430173281Smatteo				}
431173281Smatteo				break;
432173281Smatteo			case AF_INET6:
433173281Smatteo				if (inet_pton(AF_INET6, hosts[nhostsbak],
434173281Smatteo				    host_addr) == 1) {
435173281Smatteo					hints.ai_flags &= AI_NUMERICHOST;
436173281Smatteo				} else {
437173281Smatteo					/*
438173281Smatteo					 * Skip if we have an AF_INET address.
439173281Smatteo					 */
440173281Smatteo					if (inet_pton(AF_INET, hosts[nhostsbak],
441173281Smatteo					    host_addr) == 1) {
442173281Smatteo						close(fd);
443173281Smatteo						continue;
444173281Smatteo					}
445173281Smatteo				}
446173281Smatteo				break;
447173281Smatteo			default:
448173281Smatteo				break;
449173281Smatteo		}
450173281Smatteo
451173281Smatteo		/*
452173281Smatteo		 * If no hosts were specified, just bind to INADDR_ANY
453173281Smatteo		 */
454173281Smatteo		if (strcmp("*", hosts[nhostsbak]) == 0) {
455173281Smatteo			if (svcport_str == NULL) {
456173281Smatteo				res = malloc(sizeof(struct addrinfo));
457173281Smatteo				if (res == NULL)
458173281Smatteo					out_of_mem();
459173281Smatteo				res->ai_flags = hints.ai_flags;
460173281Smatteo				res->ai_family = hints.ai_family;
461173281Smatteo				res->ai_protocol = hints.ai_protocol;
462173281Smatteo				switch (res->ai_family) {
463173281Smatteo					case AF_INET:
464173281Smatteo						sin = malloc(sizeof(struct sockaddr_in));
465173281Smatteo						if (sin == NULL)
466173281Smatteo							out_of_mem();
467173281Smatteo						sin->sin_family = AF_INET;
468173281Smatteo						sin->sin_port = htons(0);
469173281Smatteo						sin->sin_addr.s_addr = htonl(INADDR_ANY);
470173281Smatteo						res->ai_addr = (struct sockaddr*) sin;
471173281Smatteo						res->ai_addrlen = (socklen_t)
472173281Smatteo						    sizeof(res->ai_addr);
473173281Smatteo						break;
474173281Smatteo					case AF_INET6:
475173281Smatteo						sin6 = malloc(sizeof(struct sockaddr_in6));
476173411Smatteo						if (sin6 == NULL)
477173281Smatteo							out_of_mem();
478173281Smatteo						sin6->sin6_family = AF_INET6;
479173281Smatteo						sin6->sin6_port = htons(0);
480173281Smatteo						sin6->sin6_addr = in6addr_any;
481173281Smatteo						res->ai_addr = (struct sockaddr*) sin6;
482173281Smatteo						res->ai_addrlen = (socklen_t) sizeof(res->ai_addr);
483173281Smatteo						break;
484173281Smatteo					default:
485173281Smatteo						break;
486173281Smatteo				}
487173281Smatteo			} else {
488173281Smatteo				if ((aicode = getaddrinfo(NULL, svcport_str,
489173281Smatteo				    &hints, &res)) != 0) {
490173281Smatteo					syslog(LOG_ERR,
491173281Smatteo					    "cannot get local address for %s: %s",
492173281Smatteo					    nconf->nc_netid,
493173281Smatteo					    gai_strerror(aicode));
494173281Smatteo					continue;
495173281Smatteo				}
496173281Smatteo			}
497173281Smatteo		} else {
498173281Smatteo			if ((aicode = getaddrinfo(hosts[nhostsbak], svcport_str,
499173281Smatteo			    &hints, &res)) != 0) {
500173281Smatteo				syslog(LOG_ERR,
501173281Smatteo				    "cannot get local address for %s: %s",
502173281Smatteo				    nconf->nc_netid, gai_strerror(aicode));
503173281Smatteo				continue;
504173281Smatteo			}
505173281Smatteo		}
506173281Smatteo
507173281Smatteo		r = bindresvport_sa(fd, res->ai_addr);
508173281Smatteo		if (r != 0) {
509173281Smatteo			syslog(LOG_ERR, "bindresvport_sa: %m");
510173281Smatteo			exit(1);
511173281Smatteo		}
512173281Smatteo
513173281Smatteo		transp = svc_tli_create(fd, nconf, NULL,
514173281Smatteo		    RPC_MAXDATASIZE, RPC_MAXDATASIZE);
515173281Smatteo
516173281Smatteo		if (transp != (SVCXPRT *) NULL) {
517173281Smatteo			if (!svc_reg(transp, NLM_PROG, NLM_SM, nlm_prog_0,
518173281Smatteo			    NULL))
519173281Smatteo				syslog(LOG_ERR,
520173281Smatteo				    "can't register %s NLM_PROG, NLM_SM service",
521173281Smatteo				    nconf->nc_netid);
522173281Smatteo
523173281Smatteo			if (!svc_reg(transp, NLM_PROG, NLM_VERS, nlm_prog_1,
524173281Smatteo			    NULL))
525173281Smatteo				syslog(LOG_ERR,
526173281Smatteo				    "can't register %s NLM_PROG, NLM_VERS service",
527173281Smatteo				    nconf->nc_netid);
528173281Smatteo
529173281Smatteo			if (!svc_reg(transp, NLM_PROG, NLM_VERSX, nlm_prog_3,
530173281Smatteo			    NULL))
531173281Smatteo				syslog(LOG_ERR,
532173281Smatteo				    "can't register %s NLM_PROG, NLM_VERSX service",
533173281Smatteo				    nconf->nc_netid);
534173281Smatteo
535173281Smatteo			if (!svc_reg(transp, NLM_PROG, NLM_VERS4, nlm_prog_4,
536173281Smatteo			    NULL))
537173281Smatteo				syslog(LOG_ERR,
538173281Smatteo				    "can't register %s NLM_PROG, NLM_VERS4 service",
539173281Smatteo				    nconf->nc_netid);
540173281Smatteo
541173281Smatteo		} else
542173281Smatteo			syslog(LOG_WARNING, "can't create %s services",
543173281Smatteo			    nconf->nc_netid);
544173281Smatteo
545173281Smatteo		if (registered == 0) {
546173281Smatteo			registered = 1;
547173281Smatteo			memset(&hints, 0, sizeof hints);
548173281Smatteo			hints.ai_flags = AI_PASSIVE;
549173281Smatteo			hints.ai_family = si.si_af;
550173281Smatteo			hints.ai_socktype = si.si_socktype;
551173281Smatteo			hints.ai_protocol = si.si_proto;
552173281Smatteo
553173281Smatteo			if (svcport_str == NULL) {
554173281Smatteo				svcport_str = malloc(NI_MAXSERV * sizeof(char));
555173281Smatteo				if (svcport_str == NULL)
556173281Smatteo					out_of_mem();
557173281Smatteo
558173281Smatteo				if (getnameinfo(res->ai_addr,
559173281Smatteo				    res->ai_addr->sa_len, NULL, NI_MAXHOST,
560173281Smatteo				    svcport_str, NI_MAXSERV * sizeof(char),
561173281Smatteo				    NI_NUMERICHOST | NI_NUMERICSERV))
562173281Smatteo					errx(1, "Cannot get port number");
563173281Smatteo			}
564173281Smatteo
565173281Smatteo			if((aicode = getaddrinfo(NULL, svcport_str, &hints,
566173281Smatteo			    &res)) != 0) {
567173281Smatteo				syslog(LOG_ERR, "cannot get local address: %s",
568173281Smatteo				    gai_strerror(aicode));
569173281Smatteo				exit(1);
570173281Smatteo			}
571173281Smatteo
572173281Smatteo			servaddr.buf = malloc(res->ai_addrlen);
573173281Smatteo			memcpy(servaddr.buf, res->ai_addr, res->ai_addrlen);
574173281Smatteo			servaddr.len = res->ai_addrlen;
575173281Smatteo
576173281Smatteo			rpcb_set(NLM_PROG, NLM_SM, nconf, &servaddr);
577173281Smatteo			rpcb_set(NLM_PROG, NLM_VERS, nconf, &servaddr);
578173281Smatteo			rpcb_set(NLM_PROG, NLM_VERSX, nconf, &servaddr);
579173281Smatteo			rpcb_set(NLM_PROG, NLM_VERS4, nconf, &servaddr);
580173281Smatteo
581173281Smatteo			xcreated++;
582173281Smatteo			freeaddrinfo(res);
583173281Smatteo		}
584173281Smatteo	} /* end while */
585173281Smatteo}
586173281Smatteo
587177633Sdfr/*
588177633Sdfr * Look up addresses for the kernel to create transports for.
589177633Sdfr */
590173281Smatteovoid
591177633Sdfrlookup_addresses(struct netconfig *nconf)
592177633Sdfr{
593177633Sdfr	struct addrinfo hints, *res = NULL;
594177633Sdfr	struct sockaddr_in *sin;
595177633Sdfr	struct sockaddr_in6 *sin6;
596177633Sdfr	struct __rpc_sockinfo si;
597177633Sdfr	struct netbuf servaddr;
598177633Sdfr	SVCXPRT	*transp = NULL;
599177633Sdfr	int aicode;
600177633Sdfr	int nhostsbak;
601177633Sdfr	int r;
602177633Sdfr	int registered = 0;
603177633Sdfr	u_int32_t host_addr[4];  /* IPv4 or IPv6 */
604177633Sdfr	char *uaddr;
605177633Sdfr
606177633Sdfr	if ((nconf->nc_semantics != NC_TPI_CLTS) &&
607177633Sdfr	    (nconf->nc_semantics != NC_TPI_COTS) &&
608177633Sdfr	    (nconf->nc_semantics != NC_TPI_COTS_ORD))
609177633Sdfr		return;	/* not my type */
610177633Sdfr
611177633Sdfr	/*
612177633Sdfr	 * XXX - using RPC library internal functions.
613177633Sdfr	 */
614177633Sdfr	if (!__rpc_nconf2sockinfo(nconf, &si)) {
615177633Sdfr		syslog(LOG_ERR, "cannot get information for %s",
616177633Sdfr		    nconf->nc_netid);
617177633Sdfr		return;
618177633Sdfr	}
619177633Sdfr
620177633Sdfr	/* Get rpc.statd's address on this transport */
621177633Sdfr	memset(&hints, 0, sizeof hints);
622177633Sdfr	hints.ai_flags = AI_PASSIVE;
623177633Sdfr	hints.ai_family = si.si_af;
624177633Sdfr	hints.ai_socktype = si.si_socktype;
625177633Sdfr	hints.ai_protocol = si.si_proto;
626177633Sdfr
627177633Sdfr	/*
628177633Sdfr	 * Bind to specific IPs if asked to
629177633Sdfr	 */
630177633Sdfr	nhostsbak = nhosts;
631177633Sdfr	while (nhostsbak > 0) {
632177633Sdfr		--nhostsbak;
633177633Sdfr
634177633Sdfr		switch (hints.ai_family) {
635177633Sdfr			case AF_INET:
636177633Sdfr				if (inet_pton(AF_INET, hosts[nhostsbak],
637177633Sdfr				    host_addr) == 1) {
638177633Sdfr					hints.ai_flags &= AI_NUMERICHOST;
639177633Sdfr				} else {
640177633Sdfr					/*
641177633Sdfr					 * Skip if we have an AF_INET6 address.
642177633Sdfr					 */
643177633Sdfr					if (inet_pton(AF_INET6, hosts[nhostsbak],
644177633Sdfr					    host_addr) == 1) {
645177633Sdfr						continue;
646177633Sdfr					}
647177633Sdfr				}
648177633Sdfr				break;
649177633Sdfr			case AF_INET6:
650177633Sdfr				if (inet_pton(AF_INET6, hosts[nhostsbak],
651177633Sdfr				    host_addr) == 1) {
652177633Sdfr					hints.ai_flags &= AI_NUMERICHOST;
653177633Sdfr				} else {
654177633Sdfr					/*
655177633Sdfr					 * Skip if we have an AF_INET address.
656177633Sdfr					 */
657177633Sdfr					if (inet_pton(AF_INET, hosts[nhostsbak],
658177633Sdfr					    host_addr) == 1) {
659177633Sdfr						continue;
660177633Sdfr					}
661177633Sdfr				}
662177633Sdfr				break;
663177633Sdfr			default:
664177633Sdfr				break;
665177633Sdfr		}
666177633Sdfr
667177633Sdfr		/*
668177633Sdfr		 * If no hosts were specified, just bind to INADDR_ANY
669177633Sdfr		 */
670177633Sdfr		if (strcmp("*", hosts[nhostsbak]) == 0) {
671177633Sdfr			if (svcport_str == NULL) {
672177633Sdfr				res = malloc(sizeof(struct addrinfo));
673177633Sdfr				if (res == NULL)
674177633Sdfr					out_of_mem();
675177633Sdfr				res->ai_flags = hints.ai_flags;
676177633Sdfr				res->ai_family = hints.ai_family;
677177633Sdfr				res->ai_protocol = hints.ai_protocol;
678177633Sdfr				switch (res->ai_family) {
679177633Sdfr					case AF_INET:
680177633Sdfr						sin = malloc(sizeof(struct sockaddr_in));
681177633Sdfr						if (sin == NULL)
682177633Sdfr							out_of_mem();
683177633Sdfr						sin->sin_family = AF_INET;
684177633Sdfr						sin->sin_port = htons(0);
685177633Sdfr						sin->sin_addr.s_addr = htonl(INADDR_ANY);
686177633Sdfr						res->ai_addr = (struct sockaddr*) sin;
687177633Sdfr						res->ai_addrlen = (socklen_t)
688177633Sdfr						    sizeof(res->ai_addr);
689177633Sdfr						break;
690177633Sdfr					case AF_INET6:
691177633Sdfr						sin6 = malloc(sizeof(struct sockaddr_in6));
692177633Sdfr						if (sin6 == NULL)
693177633Sdfr							out_of_mem();
694177633Sdfr						sin6->sin6_family = AF_INET6;
695177633Sdfr						sin6->sin6_port = htons(0);
696177633Sdfr						sin6->sin6_addr = in6addr_any;
697177633Sdfr						res->ai_addr = (struct sockaddr*) sin6;
698177633Sdfr						res->ai_addrlen = (socklen_t) sizeof(res->ai_addr);
699177633Sdfr						break;
700177633Sdfr					default:
701177633Sdfr						break;
702177633Sdfr				}
703177633Sdfr			} else {
704177633Sdfr				if ((aicode = getaddrinfo(NULL, svcport_str,
705177633Sdfr				    &hints, &res)) != 0) {
706177633Sdfr					syslog(LOG_ERR,
707177633Sdfr					    "cannot get local address for %s: %s",
708177633Sdfr					    nconf->nc_netid,
709177633Sdfr					    gai_strerror(aicode));
710177633Sdfr					continue;
711177633Sdfr				}
712177633Sdfr			}
713177633Sdfr		} else {
714177633Sdfr			if ((aicode = getaddrinfo(hosts[nhostsbak], svcport_str,
715177633Sdfr			    &hints, &res)) != 0) {
716177633Sdfr				syslog(LOG_ERR,
717177633Sdfr				    "cannot get local address for %s: %s",
718177633Sdfr				    nconf->nc_netid, gai_strerror(aicode));
719177633Sdfr				continue;
720177633Sdfr			}
721177633Sdfr		}
722177633Sdfr
723177633Sdfr		servaddr.len = servaddr.maxlen = res->ai_addr->sa_len;
724177633Sdfr		servaddr.buf = res->ai_addr;
725177633Sdfr		uaddr = taddr2uaddr(nconf, &servaddr);
726177633Sdfr
727177633Sdfr		addrs = realloc(addrs, 2 * (naddrs + 1) * sizeof(char *));
728177633Sdfr		if (!addrs)
729177633Sdfr			out_of_mem();
730177633Sdfr		addrs[2 * naddrs] = strdup(nconf->nc_netid);
731177633Sdfr		addrs[2 * naddrs + 1] = uaddr;
732177633Sdfr		naddrs++;
733177633Sdfr	} /* end while */
734177633Sdfr}
735177633Sdfr
736177633Sdfrvoid
73786319Salfredsigalarm_handler(void)
73874462Salfred{
73986319Salfred
74074462Salfred	grace_expired = 1;
74174462Salfred}
74274462Salfred
74374462Salfredvoid
74430376Scharnierusage()
74530376Scharnier{
746177633Sdfr	errx(1, "usage: rpc.lockd [-k] [-d <debuglevel>]"
747173281Smatteo	    " [-g <grace period>] [-h <bindip>] [-p <port>]");
74830376Scharnier}
74975631Salfred
75075631Salfred/*
75175631Salfred * init_nsm --
75275631Salfred *	Reset the NSM state-of-the-world and acquire its state.
75375631Salfred */
75475631Salfredvoid
75575631Salfredinit_nsm(void)
75675631Salfred{
75775631Salfred	enum clnt_stat ret;
75875631Salfred	my_id id;
75975631Salfred	sm_stat stat;
76092978Salfred	char name[] = "NFS NLM";
76192978Salfred	char localhost[] = "localhost";
76275631Salfred
76375631Salfred	/*
76475631Salfred	 * !!!
76575631Salfred	 * The my_id structure isn't used by the SM_UNMON_ALL call, as far
76675631Salfred	 * as I know.  Leave it empty for now.
76775631Salfred	 */
76875631Salfred	memset(&id, 0, sizeof(id));
76992978Salfred	id.my_name = name;
77075631Salfred
77175631Salfred	/*
77275631Salfred	 * !!!
77375631Salfred	 * The statd program must already be registered when lockd runs.
77475631Salfred	 */
77575631Salfred	do {
77675631Salfred		ret = callrpc("localhost", SM_PROG, SM_VERS, SM_UNMON_ALL,
777121558Speter		    (xdrproc_t)xdr_my_id, &id, (xdrproc_t)xdr_sm_stat, &stat);
77875631Salfred		if (ret == RPC_PROGUNAVAIL) {
779113971Sghelmer			syslog(LOG_WARNING, "%lu %s", SM_PROG,
780113971Sghelmer			    clnt_sperrno(ret));
78175631Salfred			sleep(2);
78275631Salfred			continue;
78375631Salfred		}
78475631Salfred		break;
78575631Salfred	} while (0);
78675631Salfred
78775631Salfred	if (ret != 0) {
788113971Sghelmer		syslog(LOG_ERR, "%lu %s", SM_PROG, clnt_sperrno(ret));
789113971Sghelmer		exit(1);
79075631Salfred	}
79175631Salfred
79275631Salfred	nsm_state = stat.state;
79375631Salfred
79475631Salfred	/* setup constant data for SM_MON calls */
79592978Salfred	mon_host.mon_id.my_id.my_name = localhost;
79675631Salfred	mon_host.mon_id.my_id.my_prog = NLM_PROG;
79775631Salfred	mon_host.mon_id.my_id.my_vers = NLM_SM;
79875631Salfred	mon_host.mon_id.my_id.my_proc = NLM_SM_NOTIFY;  /* bsdi addition */
79975631Salfred}
800173281Smatteo
801173281Smatteo/*
802173281Smatteo * Out of memory, fatal
803173281Smatteo */
804173281Smatteovoid out_of_mem()
805173281Smatteo{
806173281Smatteo	syslog(LOG_ERR, "out of memory");
807173281Smatteo	exit(2);
808173281Smatteo}
809