xref: /freebsd/usr.sbin/rpc.lockd/lockd.c (revision 44e72c6e2e6bcfa2cba89afb92fa05f6ac4d5660)
14945c132SAlfred Perlstein /*	$NetBSD: lockd.c,v 1.7 2000/08/12 18:08:44 thorpej Exp $	*/
24945c132SAlfred Perlstein 
3df57947fSPedro F. Giffuni /*-
4df57947fSPedro F. Giffuni  * SPDX-License-Identifier: BSD-4-Clause
5df57947fSPedro F. Giffuni  *
64945c132SAlfred Perlstein  * Copyright (c) 1995
74945c132SAlfred Perlstein  *	A.R. Gordon (andrew.gordon@net-tel.co.uk).  All rights reserved.
84945c132SAlfred Perlstein  *
94945c132SAlfred Perlstein  * Redistribution and use in source and binary forms, with or without
104945c132SAlfred Perlstein  * modification, are permitted provided that the following conditions
114945c132SAlfred Perlstein  * are met:
124945c132SAlfred Perlstein  * 1. Redistributions of source code must retain the above copyright
134945c132SAlfred Perlstein  *    notice, this list of conditions and the following disclaimer.
144945c132SAlfred Perlstein  * 2. Redistributions in binary form must reproduce the above copyright
154945c132SAlfred Perlstein  *    notice, this list of conditions and the following disclaimer in the
164945c132SAlfred Perlstein  *    documentation and/or other materials provided with the distribution.
174945c132SAlfred Perlstein  * 3. All advertising materials mentioning features or use of this software
184945c132SAlfred Perlstein  *    must display the following acknowledgement:
194945c132SAlfred Perlstein  *	This product includes software developed for the FreeBSD project
204945c132SAlfred Perlstein  * 4. Neither the name of the author nor the names of any co-contributors
214945c132SAlfred Perlstein  *    may be used to endorse or promote products derived from this software
224945c132SAlfred Perlstein  *    without specific prior written permission.
234945c132SAlfred Perlstein  *
244945c132SAlfred Perlstein  * THIS SOFTWARE IS PROVIDED BY ANDREW GORDON AND CONTRIBUTORS ``AS IS'' AND
254945c132SAlfred Perlstein  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
264945c132SAlfred Perlstein  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
274945c132SAlfred Perlstein  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
284945c132SAlfred Perlstein  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
294945c132SAlfred Perlstein  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
304945c132SAlfred Perlstein  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
314945c132SAlfred Perlstein  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
324945c132SAlfred Perlstein  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
334945c132SAlfred Perlstein  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
344945c132SAlfred Perlstein  * SUCH DAMAGE.
354945c132SAlfred Perlstein  *
364945c132SAlfred Perlstein  */
374945c132SAlfred Perlstein 
384945c132SAlfred Perlstein #include <sys/cdefs.h>
394945c132SAlfred Perlstein #ifndef lint
404945c132SAlfred Perlstein __RCSID("$NetBSD: lockd.c,v 1.7 2000/08/12 18:08:44 thorpej Exp $");
414945c132SAlfred Perlstein #endif
424945c132SAlfred Perlstein 
434945c132SAlfred Perlstein /*
444945c132SAlfred Perlstein  * main() function for NFS lock daemon.  Most of the code in this
454945c132SAlfred Perlstein  * file was generated by running rpcgen /usr/include/rpcsvc/nlm_prot.x.
464945c132SAlfred Perlstein  *
474945c132SAlfred Perlstein  * The actual program logic is in the file lock_proc.c
484945c132SAlfred Perlstein  */
494945c132SAlfred Perlstein 
50fa9d9930SDoug Rabson #include <sys/param.h>
51fa9d9930SDoug Rabson #include <sys/linker.h>
52fa9d9930SDoug Rabson #include <sys/module.h>
534945c132SAlfred Perlstein #include <sys/socket.h>
54dfdcada3SDoug Rabson #include <sys/stat.h>
554945c132SAlfred Perlstein 
56e56fbc5aSMatteo Riondato #include <netinet/in.h>
57e56fbc5aSMatteo Riondato #include <arpa/inet.h>
58e56fbc5aSMatteo Riondato 
594945c132SAlfred Perlstein #include <err.h>
604945c132SAlfred Perlstein #include <stdio.h>
614945c132SAlfred Perlstein #include <stdlib.h>
624945c132SAlfred Perlstein #include <errno.h>
634945c132SAlfred Perlstein #include <syslog.h>
644945c132SAlfred Perlstein #include <signal.h>
654945c132SAlfred Perlstein #include <string.h>
664945c132SAlfred Perlstein #include <unistd.h>
674945c132SAlfred Perlstein #include <libutil.h>
684945c132SAlfred Perlstein #include <netconfig.h>
69e56fbc5aSMatteo Riondato #include <netdb.h>
704945c132SAlfred Perlstein 
714945c132SAlfred Perlstein #include <rpc/rpc.h>
72bcb53b16SMartin Blapp #include <rpc/rpc_com.h>
734945c132SAlfred Perlstein #include <rpcsvc/sm_inter.h>
744945c132SAlfred Perlstein 
754945c132SAlfred Perlstein #include "lockd.h"
764945c132SAlfred Perlstein #include <rpcsvc/nlm_prot.h>
774945c132SAlfred Perlstein 
78795b2dc0SRick Macklem #define	GETPORT_MAXTRY	20	/* Max tries to get a port # */
79795b2dc0SRick Macklem 
804945c132SAlfred Perlstein int		debug_level = 0;	/* 0 = no debugging syslog() calls */
814945c132SAlfred Perlstein int		_rpcsvcdirty = 0;
824945c132SAlfred Perlstein 
834945c132SAlfred Perlstein int grace_expired;
844945c132SAlfred Perlstein int nsm_state;
85dfdcada3SDoug Rabson int kernel_lockd;
86c675522fSDoug Rabson int kernel_lockd_client;
874945c132SAlfred Perlstein pid_t client_pid;
884945c132SAlfred Perlstein struct mon mon_host;
89e56fbc5aSMatteo Riondato char **hosts, *svcport_str = NULL;
90795b2dc0SRick Macklem static int	mallocd_svcport = 0;
91795b2dc0SRick Macklem static int	*sock_fd;
92795b2dc0SRick Macklem static int	sock_fdcnt;
93795b2dc0SRick Macklem static int	sock_fdpos;
94e56fbc5aSMatteo Riondato int nhosts = 0;
95e56fbc5aSMatteo Riondato int xcreated = 0;
96dfdcada3SDoug Rabson char **addrs;			/* actually (netid, uaddr) pairs */
97dfdcada3SDoug Rabson int naddrs;			/* count of how many (netid, uaddr) pairs */
98091c4c86SUlrich Spörlein char localhost[] = "localhost";
994945c132SAlfred Perlstein 
100795b2dc0SRick Macklem static int	create_service(struct netconfig *nconf);
101795b2dc0SRick Macklem static void	complete_service(struct netconfig *nconf, char *port_str);
102795b2dc0SRick Macklem static void	clearout_service(void);
1038a3cd533SXin LI static void	out_of_mem(void) __dead2;
1044945c132SAlfred Perlstein void	init_nsm(void);
10533314abeSAlfred Perlstein void	usage(void);
1064945c132SAlfred Perlstein 
10733314abeSAlfred Perlstein void sigalarm_handler(void);
1084945c132SAlfred Perlstein 
109dfdcada3SDoug Rabson /*
110dfdcada3SDoug Rabson  * XXX move to some header file.
111dfdcada3SDoug Rabson  */
112dfdcada3SDoug Rabson #define _PATH_RPCLOCKDSOCK	"/var/run/rpclockd.sock"
113dfdcada3SDoug Rabson 
1144945c132SAlfred Perlstein int
main(int argc,char ** argv)115e56fbc5aSMatteo Riondato main(int argc, char **argv)
1164945c132SAlfred Perlstein {
117e56fbc5aSMatteo Riondato 	int ch, i, s;
118e56fbc5aSMatteo Riondato 	void *nc_handle;
119e56fbc5aSMatteo Riondato 	char *endptr, **hosts_bak;
1204945c132SAlfred Perlstein 	struct sigaction sigalarm;
1214945c132SAlfred Perlstein 	int grace_period = 30;
12290e43b44SRavi Pokala 	int foreground = 0;
1234945c132SAlfred Perlstein 	struct netconfig *nconf;
124e56fbc5aSMatteo Riondato 	int have_v6 = 1;
125bcb53b16SMartin Blapp 	int maxrec = RPC_MAXDATASIZE;
12669f129c9SMatteo Riondato 	in_port_t svcport = 0;
127795b2dc0SRick Macklem 	int attempt_cnt, port_len, port_pos, ret;
128795b2dc0SRick Macklem 	char **port_list;
1294945c132SAlfred Perlstein 
13090e43b44SRavi Pokala 	while ((ch = getopt(argc, argv, "d:Fg:h:p:")) != (-1)) {
1314945c132SAlfred Perlstein 		switch (ch) {
1324945c132SAlfred Perlstein 		case 'd':
1334945c132SAlfred Perlstein 			debug_level = atoi(optarg);
1344945c132SAlfred Perlstein 			if (!debug_level) {
1354945c132SAlfred Perlstein 				usage();
1364945c132SAlfred Perlstein 				/* NOTREACHED */
1374945c132SAlfred Perlstein 			}
1384945c132SAlfred Perlstein 			break;
13990e43b44SRavi Pokala 		case 'F':
14090e43b44SRavi Pokala 			foreground = 1;
14190e43b44SRavi Pokala 			break;
1424945c132SAlfred Perlstein 		case 'g':
1434945c132SAlfred Perlstein 			grace_period = atoi(optarg);
1444945c132SAlfred Perlstein 			if (!grace_period) {
1454945c132SAlfred Perlstein 				usage();
1464945c132SAlfred Perlstein 				/* NOTREACHED */
1474945c132SAlfred Perlstein 			}
1484945c132SAlfred Perlstein 			break;
149e56fbc5aSMatteo Riondato 		case 'h':
150e56fbc5aSMatteo Riondato 			++nhosts;
151e56fbc5aSMatteo Riondato 			hosts_bak = realloc(hosts, nhosts * sizeof(char *));
152e56fbc5aSMatteo Riondato 			if (hosts_bak == NULL) {
153e56fbc5aSMatteo Riondato 				if (hosts != NULL) {
154e56fbc5aSMatteo Riondato 					for (i = 0; i < nhosts; i++)
155e56fbc5aSMatteo Riondato 						free(hosts[i]);
156e56fbc5aSMatteo Riondato 					free(hosts);
157e56fbc5aSMatteo Riondato 					out_of_mem();
158e56fbc5aSMatteo Riondato 				}
159e56fbc5aSMatteo Riondato 			}
160e56fbc5aSMatteo Riondato 			hosts = hosts_bak;
161e56fbc5aSMatteo Riondato 			hosts[nhosts - 1] = strdup(optarg);
162e56fbc5aSMatteo Riondato 			if (hosts[nhosts - 1] == NULL) {
163e56fbc5aSMatteo Riondato 				for (i = 0; i < (nhosts - 1); i++)
164e56fbc5aSMatteo Riondato 					free(hosts[i]);
165e56fbc5aSMatteo Riondato 				free(hosts);
166e56fbc5aSMatteo Riondato 				out_of_mem();
167e56fbc5aSMatteo Riondato 			}
168e56fbc5aSMatteo Riondato 			break;
16969f129c9SMatteo Riondato 		case 'p':
17069f129c9SMatteo Riondato 			endptr = NULL;
17169f129c9SMatteo Riondato 			svcport = (in_port_t)strtoul(optarg, &endptr, 10);
17269f129c9SMatteo Riondato 			if (endptr == NULL || *endptr != '\0' ||
17369f129c9SMatteo Riondato 			    svcport == 0 || svcport >= IPPORT_MAX)
17469f129c9SMatteo Riondato 				usage();
175e56fbc5aSMatteo Riondato 			svcport_str = strdup(optarg);
17669f129c9SMatteo Riondato 			break;
1774945c132SAlfred Perlstein 		default:
1784945c132SAlfred Perlstein 			usage();
1794945c132SAlfred Perlstein 			/* NOTREACHED */
1804945c132SAlfred Perlstein 		}
1814945c132SAlfred Perlstein 	}
1824945c132SAlfred Perlstein 	if (geteuid()) { /* This command allowed only to root */
1834945c132SAlfred Perlstein 		fprintf(stderr, "Sorry. You are not superuser\n");
1844945c132SAlfred Perlstein 		exit(1);
1854945c132SAlfred Perlstein         }
1864945c132SAlfred Perlstein 
187fa9d9930SDoug Rabson 	kernel_lockd = FALSE;
188c675522fSDoug Rabson 	kernel_lockd_client = FALSE;
189fa9d9930SDoug Rabson 	if (modfind("nfslockd") < 0) {
190fa9d9930SDoug Rabson 		if (kldload("nfslockd") < 0) {
191*44e72c6eSDag-Erling Smørgrav 			fprintf(stderr, "Unable to load nfslockd(4), "
192*44e72c6eSDag-Erling Smørgrav 			    "using userland implementation\n");
1933cba562fSDoug Rabson 		} else {
194fa9d9930SDoug Rabson 			kernel_lockd = TRUE;
1953cba562fSDoug Rabson 		}
196fa9d9930SDoug Rabson 	} else {
197fa9d9930SDoug Rabson 		kernel_lockd = TRUE;
198fa9d9930SDoug Rabson 	}
199c675522fSDoug Rabson 	if (kernel_lockd) {
200c675522fSDoug Rabson 		if (getosreldate() >= 800040)
201c675522fSDoug Rabson 			kernel_lockd_client = TRUE;
202c675522fSDoug Rabson 	}
203fa9d9930SDoug Rabson 
2044945c132SAlfred Perlstein 	(void)rpcb_unset(NLM_PROG, NLM_SM, NULL);
2054945c132SAlfred Perlstein 	(void)rpcb_unset(NLM_PROG, NLM_VERS, NULL);
2064945c132SAlfred Perlstein 	(void)rpcb_unset(NLM_PROG, NLM_VERSX, NULL);
2074945c132SAlfred Perlstein 	(void)rpcb_unset(NLM_PROG, NLM_VERS4, NULL);
2084945c132SAlfred Perlstein 
2094945c132SAlfred Perlstein 	/*
2104945c132SAlfred Perlstein 	 * Check if IPv6 support is present.
2114945c132SAlfred Perlstein 	 */
2124945c132SAlfred Perlstein 	s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
2134945c132SAlfred Perlstein 	if (s < 0)
214e56fbc5aSMatteo Riondato 		have_v6 = 0;
215e56fbc5aSMatteo Riondato 	else
2164945c132SAlfred Perlstein 		close(s);
21769f129c9SMatteo Riondato 
218bcb53b16SMartin Blapp 	rpc_control(RPC_SVC_CONNMAXREC_SET, &maxrec);
219bcb53b16SMartin Blapp 
220e56fbc5aSMatteo Riondato 	/*
221e56fbc5aSMatteo Riondato 	 * If no hosts were specified, add a wildcard entry to bind to
222e56fbc5aSMatteo Riondato 	 * INADDR_ANY. Otherwise make sure 127.0.0.1 and ::1 are added to the
223e56fbc5aSMatteo Riondato 	 * list.
224e56fbc5aSMatteo Riondato 	 */
225e56fbc5aSMatteo Riondato 	if (nhosts == 0) {
226c9e1c304SUlrich Spörlein 		hosts = malloc(sizeof(char *));
227e56fbc5aSMatteo Riondato 		if (hosts == NULL)
228e56fbc5aSMatteo Riondato 			out_of_mem();
2294945c132SAlfred Perlstein 
230146ff0f4SXin LI 		hosts[0] = strdup("*");
231e56fbc5aSMatteo Riondato 		nhosts = 1;
23269f129c9SMatteo Riondato 	} else {
233e56fbc5aSMatteo Riondato 		if (have_v6) {
234e56fbc5aSMatteo Riondato 			hosts_bak = realloc(hosts, (nhosts + 2) *
235e56fbc5aSMatteo Riondato 			    sizeof(char *));
236e56fbc5aSMatteo Riondato 			if (hosts_bak == NULL) {
237e56fbc5aSMatteo Riondato 				for (i = 0; i < nhosts; i++)
238e56fbc5aSMatteo Riondato 					free(hosts[i]);
239e56fbc5aSMatteo Riondato 				free(hosts);
240e56fbc5aSMatteo Riondato 				out_of_mem();
241e56fbc5aSMatteo Riondato 			} else
242e56fbc5aSMatteo Riondato 				hosts = hosts_bak;
243e56fbc5aSMatteo Riondato 
244e56fbc5aSMatteo Riondato 			nhosts += 2;
245146ff0f4SXin LI 			hosts[nhosts - 2] = strdup("::1");
246e56fbc5aSMatteo Riondato 		} else {
247e56fbc5aSMatteo Riondato 			hosts_bak = realloc(hosts, (nhosts + 1) * sizeof(char *));
248e56fbc5aSMatteo Riondato 			if (hosts_bak == NULL) {
249e56fbc5aSMatteo Riondato 				for (i = 0; i < nhosts; i++)
250e56fbc5aSMatteo Riondato 					free(hosts[i]);
251e56fbc5aSMatteo Riondato 
252e56fbc5aSMatteo Riondato 				free(hosts);
253e56fbc5aSMatteo Riondato 				out_of_mem();
254e56fbc5aSMatteo Riondato 			} else {
255e56fbc5aSMatteo Riondato 				nhosts += 1;
256e56fbc5aSMatteo Riondato 				hosts = hosts_bak;
257e56fbc5aSMatteo Riondato 			}
258e56fbc5aSMatteo Riondato 		}
259146ff0f4SXin LI 		hosts[nhosts - 1] = strdup("127.0.0.1");
26069f129c9SMatteo Riondato 	}
26169f129c9SMatteo Riondato 
262dfdcada3SDoug Rabson 	if (kernel_lockd) {
263c675522fSDoug Rabson 		if (!kernel_lockd_client) {
264dfdcada3SDoug Rabson 			/*
265c675522fSDoug Rabson 			 * For the case where we have a kernel lockd but it
266c675522fSDoug Rabson 			 * doesn't provide client locking, we run a cut-down
267c675522fSDoug Rabson 			 * RPC service on a local-domain socket. The kernel's
268c675522fSDoug Rabson 			 * RPC server will pass what it can't handle (mainly
269c675522fSDoug Rabson 			 * client replies) down to us.
270dfdcada3SDoug Rabson 			 */
271dfdcada3SDoug Rabson 			struct sockaddr_un sun;
272dfdcada3SDoug Rabson 			int fd, oldmask;
273dfdcada3SDoug Rabson 			SVCXPRT *xprt;
274dfdcada3SDoug Rabson 
275dfdcada3SDoug Rabson 			memset(&sun, 0, sizeof sun);
276dfdcada3SDoug Rabson 			sun.sun_family = AF_LOCAL;
277dfdcada3SDoug Rabson 			unlink(_PATH_RPCLOCKDSOCK);
278dfdcada3SDoug Rabson 			strcpy(sun.sun_path, _PATH_RPCLOCKDSOCK);
279dfdcada3SDoug Rabson 			sun.sun_len = SUN_LEN(&sun);
280dfdcada3SDoug Rabson 			fd = socket(AF_LOCAL, SOCK_STREAM, 0);
281dfdcada3SDoug Rabson 			if (!fd) {
282dfdcada3SDoug Rabson 				err(1, "Can't create local lockd socket");
283dfdcada3SDoug Rabson 			}
284dfdcada3SDoug Rabson 			oldmask = umask(S_IXUSR|S_IRWXG|S_IRWXO);
285dfdcada3SDoug Rabson 			if (bind(fd, (struct sockaddr *) &sun, sun.sun_len) < 0) {
286dfdcada3SDoug Rabson 				err(1, "Can't bind local lockd socket");
287dfdcada3SDoug Rabson 			}
288dfdcada3SDoug Rabson 			umask(oldmask);
289dfdcada3SDoug Rabson 			if (listen(fd, SOMAXCONN) < 0) {
290dfdcada3SDoug Rabson 				err(1, "Can't listen on local lockd socket");
291dfdcada3SDoug Rabson 			}
292dfdcada3SDoug Rabson 			xprt = svc_vc_create(fd, RPC_MAXDATASIZE, RPC_MAXDATASIZE);
293dfdcada3SDoug Rabson 			if (!xprt) {
294dfdcada3SDoug Rabson 				err(1, "Can't create transport for local lockd socket");
295dfdcada3SDoug Rabson 			}
296dfdcada3SDoug Rabson 			if (!svc_reg(xprt, NLM_PROG, NLM_VERS4, nlm_prog_4, NULL)) {
297dfdcada3SDoug Rabson 				err(1, "Can't register service for local lockd socket");
298dfdcada3SDoug Rabson 			}
299c675522fSDoug Rabson 		}
300dfdcada3SDoug Rabson 
301dfdcada3SDoug Rabson 		/*
302dfdcada3SDoug Rabson 		 * We need to look up the addresses so that we can
303dfdcada3SDoug Rabson 		 * hand uaddrs (ascii encoded address+port strings) to
304dfdcada3SDoug Rabson 		 * the kernel.
305dfdcada3SDoug Rabson 		 */
306dfdcada3SDoug Rabson 		nc_handle = setnetconfig();
307dfdcada3SDoug Rabson 		while ((nconf = getnetconfig(nc_handle))) {
308dfdcada3SDoug Rabson 			/* We want to listen only on udp6, tcp6, udp, tcp transports */
309dfdcada3SDoug Rabson 			if (nconf->nc_flag & NC_VISIBLE) {
310dfdcada3SDoug Rabson 				/* Skip if there's no IPv6 support */
311dfdcada3SDoug Rabson 				if (have_v6 == 0 && strcmp(nconf->nc_protofmly, "inet6") == 0) {
312dfdcada3SDoug Rabson 					/* DO NOTHING */
313dfdcada3SDoug Rabson 				} else {
3148a3cd533SXin LI 					create_service(nconf);
315dfdcada3SDoug Rabson 				}
316dfdcada3SDoug Rabson 			}
317dfdcada3SDoug Rabson 		}
318dfdcada3SDoug Rabson 		endnetconfig(nc_handle);
319dfdcada3SDoug Rabson 	} else {
320795b2dc0SRick Macklem 		attempt_cnt = 1;
321795b2dc0SRick Macklem 		sock_fdcnt = 0;
322795b2dc0SRick Macklem 		sock_fd = NULL;
323795b2dc0SRick Macklem 		port_list = NULL;
324795b2dc0SRick Macklem 		port_len = 0;
325e56fbc5aSMatteo Riondato 		nc_handle = setnetconfig();
326e56fbc5aSMatteo Riondato 		while ((nconf = getnetconfig(nc_handle))) {
327e56fbc5aSMatteo Riondato 			/* We want to listen only on udp6, tcp6, udp, tcp transports */
328e56fbc5aSMatteo Riondato 			if (nconf->nc_flag & NC_VISIBLE) {
329e56fbc5aSMatteo Riondato 				/* Skip if there's no IPv6 support */
330e56fbc5aSMatteo Riondato 				if (have_v6 == 0 && strcmp(nconf->nc_protofmly, "inet6") == 0) {
331e56fbc5aSMatteo Riondato 					/* DO NOTHING */
332e56fbc5aSMatteo Riondato 				} else {
333795b2dc0SRick Macklem 					ret = create_service(nconf);
334795b2dc0SRick Macklem 					if (ret == 1)
335795b2dc0SRick Macklem 						/* Ignore this call */
336795b2dc0SRick Macklem 						continue;
337795b2dc0SRick Macklem 					if (ret < 0) {
338795b2dc0SRick Macklem 						/*
339795b2dc0SRick Macklem 						 * Failed to bind port, so close
340795b2dc0SRick Macklem 						 * off all sockets created and
341795b2dc0SRick Macklem 						 * try again if the port# was
342795b2dc0SRick Macklem 						 * dynamically assigned via
343795b2dc0SRick Macklem 						 * bind(2).
344795b2dc0SRick Macklem 						 */
345795b2dc0SRick Macklem 						clearout_service();
346795b2dc0SRick Macklem 						if (mallocd_svcport != 0 &&
347795b2dc0SRick Macklem 						    attempt_cnt <
348795b2dc0SRick Macklem 						    GETPORT_MAXTRY) {
349795b2dc0SRick Macklem 							free(svcport_str);
350795b2dc0SRick Macklem 							svcport_str = NULL;
351795b2dc0SRick Macklem 							mallocd_svcport = 0;
352795b2dc0SRick Macklem 						} else {
353795b2dc0SRick Macklem 							errno = EADDRINUSE;
354795b2dc0SRick Macklem 							syslog(LOG_ERR,
355795b2dc0SRick Macklem 							 "bindresvport_sa: %m");
356795b2dc0SRick Macklem 							exit(1);
3574945c132SAlfred Perlstein 						}
358795b2dc0SRick Macklem 
359795b2dc0SRick Macklem 						/*
360795b2dc0SRick Macklem 						 * Start over at the first
361795b2dc0SRick Macklem 						 * service.
362795b2dc0SRick Macklem 						 */
363795b2dc0SRick Macklem 						free(sock_fd);
364795b2dc0SRick Macklem 						sock_fdcnt = 0;
365795b2dc0SRick Macklem 						sock_fd = NULL;
366795b2dc0SRick Macklem 						nc_handle = setnetconfig();
367795b2dc0SRick Macklem 						attempt_cnt++;
368795b2dc0SRick Macklem 					} else if (mallocd_svcport != 0 &&
369795b2dc0SRick Macklem 					    attempt_cnt == GETPORT_MAXTRY) {
370795b2dc0SRick Macklem 						/*
371795b2dc0SRick Macklem 						 * For the last attempt, allow
372795b2dc0SRick Macklem 						 * different port #s for each
373795b2dc0SRick Macklem 						 * nconf by saving the
374795b2dc0SRick Macklem 						 * svcport_str and setting it
375795b2dc0SRick Macklem 						 * back to NULL.
376795b2dc0SRick Macklem 						 */
377795b2dc0SRick Macklem 						port_list = realloc(port_list,
378795b2dc0SRick Macklem 						    (port_len + 1) *
379795b2dc0SRick Macklem 						    sizeof(char *));
380795b2dc0SRick Macklem 						if (port_list == NULL)
381795b2dc0SRick Macklem 							out_of_mem();
382795b2dc0SRick Macklem 						port_list[port_len++] =
383795b2dc0SRick Macklem 						    svcport_str;
384795b2dc0SRick Macklem 						svcport_str = NULL;
385795b2dc0SRick Macklem 						mallocd_svcport = 0;
386795b2dc0SRick Macklem 					}
387795b2dc0SRick Macklem 				}
388795b2dc0SRick Macklem 			}
389795b2dc0SRick Macklem 		}
390795b2dc0SRick Macklem 
391795b2dc0SRick Macklem 		/*
392795b2dc0SRick Macklem 		 * Successfully bound the ports, so call complete_service() to
393795b2dc0SRick Macklem 		 * do the rest of the setup on the service(s).
394795b2dc0SRick Macklem 		 */
395795b2dc0SRick Macklem 		sock_fdpos = 0;
396795b2dc0SRick Macklem 		port_pos = 0;
397795b2dc0SRick Macklem 		nc_handle = setnetconfig();
398795b2dc0SRick Macklem 		while ((nconf = getnetconfig(nc_handle))) {
399795b2dc0SRick Macklem 			/* We want to listen only on udp6, tcp6, udp, tcp transports */
400795b2dc0SRick Macklem 			if (nconf->nc_flag & NC_VISIBLE) {
401795b2dc0SRick Macklem 				/* Skip if there's no IPv6 support */
402795b2dc0SRick Macklem 				if (have_v6 == 0 && strcmp(nconf->nc_protofmly, "inet6") == 0) {
403795b2dc0SRick Macklem 					/* DO NOTHING */
404795b2dc0SRick Macklem 				} else if (port_list != NULL) {
405795b2dc0SRick Macklem 					if (port_pos >= port_len) {
406795b2dc0SRick Macklem 						syslog(LOG_ERR,
407795b2dc0SRick Macklem 						    "too many port#s");
408795b2dc0SRick Macklem 						exit(1);
409795b2dc0SRick Macklem 					}
410795b2dc0SRick Macklem 					complete_service(nconf,
411795b2dc0SRick Macklem 					    port_list[port_pos++]);
412795b2dc0SRick Macklem 				} else
413795b2dc0SRick Macklem 					complete_service(nconf, svcport_str);
4144945c132SAlfred Perlstein 			}
4154945c132SAlfred Perlstein 		}
416e56fbc5aSMatteo Riondato 		endnetconfig(nc_handle);
417795b2dc0SRick Macklem 		free(sock_fd);
418795b2dc0SRick Macklem 		if (port_list != NULL) {
419795b2dc0SRick Macklem 			for (port_pos = 0; port_pos < port_len; port_pos++)
420795b2dc0SRick Macklem 				free(port_list[port_pos]);
421795b2dc0SRick Macklem 			free(port_list);
422795b2dc0SRick Macklem 		}
423dfdcada3SDoug Rabson 	}
4244945c132SAlfred Perlstein 
4254945c132SAlfred Perlstein 	/*
4264945c132SAlfred Perlstein 	 * Note that it is NOT sensible to run this program from inetd - the
4274945c132SAlfred Perlstein 	 * protocol assumes that it will run immediately at boot time.
4284945c132SAlfred Perlstein 	 */
429badcfbacSCaleb St. John 	if ((foreground == 0) && daemon(0, 0)) {
4304945c132SAlfred Perlstein 		err(1, "cannot fork");
4314945c132SAlfred Perlstein 		/* NOTREACHED */
4324945c132SAlfred Perlstein 	}
4334945c132SAlfred Perlstein 
4344945c132SAlfred Perlstein 	openlog("rpc.lockd", 0, LOG_DAEMON);
4354945c132SAlfred Perlstein 	if (debug_level)
4364945c132SAlfred Perlstein 		syslog(LOG_INFO, "Starting, debug level %d", debug_level);
4374945c132SAlfred Perlstein 	else
4384945c132SAlfred Perlstein 		syslog(LOG_INFO, "Starting");
4394945c132SAlfred Perlstein 
4404945c132SAlfred Perlstein 	sigalarm.sa_handler = (sig_t) sigalarm_handler;
4414945c132SAlfred Perlstein 	sigemptyset(&sigalarm.sa_mask);
4424945c132SAlfred Perlstein 	sigalarm.sa_flags = SA_RESETHAND; /* should only happen once */
4434945c132SAlfred Perlstein 	sigalarm.sa_flags |= SA_RESTART;
4444945c132SAlfred Perlstein 	if (sigaction(SIGALRM, &sigalarm, NULL) != 0) {
4454945c132SAlfred Perlstein 		syslog(LOG_WARNING, "sigaction(SIGALRM) failed: %s",
4464945c132SAlfred Perlstein 		    strerror(errno));
4474945c132SAlfred Perlstein 		exit(1);
4484945c132SAlfred Perlstein 	}
449dfdcada3SDoug Rabson 
450dfdcada3SDoug Rabson 	if (kernel_lockd) {
451c675522fSDoug Rabson 		if (!kernel_lockd_client) {
452bbf7dc4cSDoug Rabson 			init_nsm();
453dfdcada3SDoug Rabson 			client_pid = client_request();
454dfdcada3SDoug Rabson 
455dfdcada3SDoug Rabson 			/*
456dfdcada3SDoug Rabson 			 * Create a child process to enter the kernel and then
457dfdcada3SDoug Rabson 			 * wait for RPCs on our local domain socket.
458dfdcada3SDoug Rabson 			 */
459dfdcada3SDoug Rabson 			if (!fork())
460c675522fSDoug Rabson 				nlm_syscall(debug_level, grace_period,
461c675522fSDoug Rabson 				    naddrs, addrs);
462dfdcada3SDoug Rabson 			else
463dfdcada3SDoug Rabson 				svc_run();
464dfdcada3SDoug Rabson 		} else {
465c675522fSDoug Rabson 			/*
466c675522fSDoug Rabson 			 * The kernel lockd implementation provides
467c675522fSDoug Rabson 			 * both client and server so we don't need to
468c675522fSDoug Rabson 			 * do anything else.
469c675522fSDoug Rabson 			 */
470c675522fSDoug Rabson 			nlm_syscall(debug_level, grace_period, naddrs, addrs);
471c675522fSDoug Rabson 		}
472c675522fSDoug Rabson 	} else {
4734945c132SAlfred Perlstein 		grace_expired = 0;
47435a64c9fSThomas Quinot 		alarm(grace_period);
4754945c132SAlfred Perlstein 
4764945c132SAlfred Perlstein 		init_nsm();
4774945c132SAlfred Perlstein 
4784945c132SAlfred Perlstein 		client_pid = client_request();
4794945c132SAlfred Perlstein 
4804945c132SAlfred Perlstein 		svc_run();		/* Should never return */
481dfdcada3SDoug Rabson 	}
4824945c132SAlfred Perlstein 	exit(1);
4834945c132SAlfred Perlstein }
4844945c132SAlfred Perlstein 
485e56fbc5aSMatteo Riondato /*
486e56fbc5aSMatteo Riondato  * This routine creates and binds sockets on the appropriate
4878a3cd533SXin LI  * addresses if lockd for user NLM, or perform a lookup of
4888a3cd533SXin LI  * addresses for the kernel to create transports.
4898a3cd533SXin LI  *
4908a3cd533SXin LI  * It gets called one time for each transport.
4918a3cd533SXin LI  *
49272e70904SGordon Bergling  * It returns 0 upon success, 1 for ignore the call and -1 to indicate
493795b2dc0SRick Macklem  * bind failed with EADDRINUSE.
4948a3cd533SXin LI  *
495795b2dc0SRick Macklem  * Any file descriptors that have been created are stored in sock_fd and
496795b2dc0SRick Macklem  * the total count of them is maintained in sock_fdcnt.
497e56fbc5aSMatteo Riondato  */
498795b2dc0SRick Macklem static int
create_service(struct netconfig * nconf)499e56fbc5aSMatteo Riondato create_service(struct netconfig *nconf)
500e56fbc5aSMatteo Riondato {
501e56fbc5aSMatteo Riondato 	struct addrinfo hints, *res = NULL;
502e56fbc5aSMatteo Riondato 	struct sockaddr_in *sin;
503e56fbc5aSMatteo Riondato 	struct sockaddr_in6 *sin6;
504e56fbc5aSMatteo Riondato 	struct __rpc_sockinfo si;
505e56fbc5aSMatteo Riondato 	int aicode;
506e56fbc5aSMatteo Riondato 	int fd;
507e56fbc5aSMatteo Riondato 	int nhostsbak;
508e56fbc5aSMatteo Riondato 	int r;
509e56fbc5aSMatteo Riondato 	u_int32_t host_addr[4];  /* IPv4 or IPv6 */
510795b2dc0SRick Macklem 	int mallocd_res;
511e56fbc5aSMatteo Riondato 
512e56fbc5aSMatteo Riondato 	if ((nconf->nc_semantics != NC_TPI_CLTS) &&
513e56fbc5aSMatteo Riondato 	    (nconf->nc_semantics != NC_TPI_COTS) &&
514e56fbc5aSMatteo Riondato 	    (nconf->nc_semantics != NC_TPI_COTS_ORD))
515795b2dc0SRick Macklem 		return (1);	/* not my type */
516e56fbc5aSMatteo Riondato 
517e56fbc5aSMatteo Riondato 	/*
518e56fbc5aSMatteo Riondato 	 * XXX - using RPC library internal functions.
519e56fbc5aSMatteo Riondato 	 */
520e56fbc5aSMatteo Riondato 	if (!__rpc_nconf2sockinfo(nconf, &si)) {
521e56fbc5aSMatteo Riondato 		syslog(LOG_ERR, "cannot get information for %s",
522e56fbc5aSMatteo Riondato 		    nconf->nc_netid);
523795b2dc0SRick Macklem 		return (1);
524e56fbc5aSMatteo Riondato 	}
525e56fbc5aSMatteo Riondato 
526e56fbc5aSMatteo Riondato 	/* Get rpc.statd's address on this transport */
527e56fbc5aSMatteo Riondato 	memset(&hints, 0, sizeof hints);
528e56fbc5aSMatteo Riondato 	hints.ai_family = si.si_af;
529e56fbc5aSMatteo Riondato 	hints.ai_socktype = si.si_socktype;
530e56fbc5aSMatteo Riondato 	hints.ai_protocol = si.si_proto;
531e56fbc5aSMatteo Riondato 
532e56fbc5aSMatteo Riondato 	/*
533e56fbc5aSMatteo Riondato 	 * Bind to specific IPs if asked to
534e56fbc5aSMatteo Riondato 	 */
535e56fbc5aSMatteo Riondato 	nhostsbak = nhosts;
536e56fbc5aSMatteo Riondato 	while (nhostsbak > 0) {
537e56fbc5aSMatteo Riondato 		--nhostsbak;
5388a3cd533SXin LI 		mallocd_res = 0;
5398a3cd533SXin LI 		hints.ai_flags = AI_PASSIVE;
5408a3cd533SXin LI 
5418a3cd533SXin LI 		if (!kernel_lockd) {
542795b2dc0SRick Macklem 			sock_fd = realloc(sock_fd, (sock_fdcnt + 1) * sizeof(int));
543795b2dc0SRick Macklem 			if (sock_fd == NULL)
544795b2dc0SRick Macklem 				out_of_mem();
545795b2dc0SRick Macklem 			sock_fd[sock_fdcnt++] = -1;	/* Set invalid for now. */
546e56fbc5aSMatteo Riondato 
547e56fbc5aSMatteo Riondato 			/*
548e56fbc5aSMatteo Riondato 			* XXX - using RPC library internal functions.
549e56fbc5aSMatteo Riondato 			*/
550e56fbc5aSMatteo Riondato 			if ((fd = __rpc_nconf2fd(nconf)) < 0) {
551e56fbc5aSMatteo Riondato 				syslog(LOG_ERR, "cannot create socket for %s",
552e56fbc5aSMatteo Riondato 					nconf->nc_netid);
553e56fbc5aSMatteo Riondato 				continue;
554e56fbc5aSMatteo Riondato 			}
5558a3cd533SXin LI 		}
556e56fbc5aSMatteo Riondato 
557e56fbc5aSMatteo Riondato 		switch (hints.ai_family) {
558e56fbc5aSMatteo Riondato 			case AF_INET:
559e56fbc5aSMatteo Riondato 				if (inet_pton(AF_INET, hosts[nhostsbak],
560e56fbc5aSMatteo Riondato 				    host_addr) == 1) {
561795b2dc0SRick Macklem 					hints.ai_flags |= AI_NUMERICHOST;
562e56fbc5aSMatteo Riondato 				} else {
563e56fbc5aSMatteo Riondato 					/*
564e56fbc5aSMatteo Riondato 					 * Skip if we have an AF_INET6 address.
565e56fbc5aSMatteo Riondato 					 */
566e56fbc5aSMatteo Riondato 					if (inet_pton(AF_INET6, hosts[nhostsbak],
567e56fbc5aSMatteo Riondato 					    host_addr) == 1) {
5688a3cd533SXin LI 						if (!kernel_lockd)
569e56fbc5aSMatteo Riondato 							close(fd);
570e56fbc5aSMatteo Riondato 						continue;
571e56fbc5aSMatteo Riondato 					}
572e56fbc5aSMatteo Riondato 				}
573e56fbc5aSMatteo Riondato 				break;
574e56fbc5aSMatteo Riondato 			case AF_INET6:
575e56fbc5aSMatteo Riondato 				if (inet_pton(AF_INET6, hosts[nhostsbak],
576e56fbc5aSMatteo Riondato 				    host_addr) == 1) {
577795b2dc0SRick Macklem 					hints.ai_flags |= AI_NUMERICHOST;
578e56fbc5aSMatteo Riondato 				} else {
579e56fbc5aSMatteo Riondato 					/*
580e56fbc5aSMatteo Riondato 					 * Skip if we have an AF_INET address.
581e56fbc5aSMatteo Riondato 					 */
582e56fbc5aSMatteo Riondato 					if (inet_pton(AF_INET, hosts[nhostsbak],
583e56fbc5aSMatteo Riondato 					    host_addr) == 1) {
5848a3cd533SXin LI 						if (!kernel_lockd)
585e56fbc5aSMatteo Riondato 							close(fd);
586e56fbc5aSMatteo Riondato 						continue;
587e56fbc5aSMatteo Riondato 					}
588e56fbc5aSMatteo Riondato 				}
589e56fbc5aSMatteo Riondato 				break;
590e56fbc5aSMatteo Riondato 			default:
591e56fbc5aSMatteo Riondato 				break;
592e56fbc5aSMatteo Riondato 		}
593e56fbc5aSMatteo Riondato 
594e56fbc5aSMatteo Riondato 		/*
595e56fbc5aSMatteo Riondato 		 * If no hosts were specified, just bind to INADDR_ANY
596e56fbc5aSMatteo Riondato 		 */
597e56fbc5aSMatteo Riondato 		if (strcmp("*", hosts[nhostsbak]) == 0) {
598e56fbc5aSMatteo Riondato 			if (svcport_str == NULL) {
5998a3cd533SXin LI 				if ((res = malloc(sizeof(struct addrinfo))) == NULL)
600e56fbc5aSMatteo Riondato 					out_of_mem();
601795b2dc0SRick Macklem 				mallocd_res = 1;
602e56fbc5aSMatteo Riondato 				res->ai_flags = hints.ai_flags;
603e56fbc5aSMatteo Riondato 				res->ai_family = hints.ai_family;
604e56fbc5aSMatteo Riondato 				res->ai_protocol = hints.ai_protocol;
605e56fbc5aSMatteo Riondato 				switch (res->ai_family) {
606e56fbc5aSMatteo Riondato 					case AF_INET:
607e56fbc5aSMatteo Riondato 						sin = malloc(sizeof(struct sockaddr_in));
608e56fbc5aSMatteo Riondato 						if (sin == NULL)
609e56fbc5aSMatteo Riondato 							out_of_mem();
610e56fbc5aSMatteo Riondato 						sin->sin_family = AF_INET;
611e56fbc5aSMatteo Riondato 						sin->sin_port = htons(0);
612e56fbc5aSMatteo Riondato 						sin->sin_addr.s_addr = htonl(INADDR_ANY);
613e56fbc5aSMatteo Riondato 						res->ai_addr = (struct sockaddr*) sin;
614e56fbc5aSMatteo Riondato 						res->ai_addrlen = (socklen_t)
615795b2dc0SRick Macklem 						    sizeof(struct sockaddr_in);
616e56fbc5aSMatteo Riondato 						break;
617e56fbc5aSMatteo Riondato 					case AF_INET6:
618e56fbc5aSMatteo Riondato 						sin6 = malloc(sizeof(struct sockaddr_in6));
61996e460ecSMatteo Riondato 						if (sin6 == NULL)
620e56fbc5aSMatteo Riondato 							out_of_mem();
621e56fbc5aSMatteo Riondato 						sin6->sin6_family = AF_INET6;
622e56fbc5aSMatteo Riondato 						sin6->sin6_port = htons(0);
623e56fbc5aSMatteo Riondato 						sin6->sin6_addr = in6addr_any;
624e56fbc5aSMatteo Riondato 						res->ai_addr = (struct sockaddr*) sin6;
625795b2dc0SRick Macklem 						res->ai_addrlen = (socklen_t)
626795b2dc0SRick Macklem 						    sizeof(struct sockaddr_in6);
627e56fbc5aSMatteo Riondato 						break;
628e56fbc5aSMatteo Riondato 					default:
629795b2dc0SRick Macklem 						syslog(LOG_ERR,
6308a3cd533SXin LI 						    "bad address family %d",
631795b2dc0SRick Macklem 						    res->ai_family);
632795b2dc0SRick Macklem 						exit(1);
633e56fbc5aSMatteo Riondato 				}
634e56fbc5aSMatteo Riondato 			} else {
635e56fbc5aSMatteo Riondato 				if ((aicode = getaddrinfo(NULL, svcport_str,
636e56fbc5aSMatteo Riondato 				    &hints, &res)) != 0) {
637e56fbc5aSMatteo Riondato 					syslog(LOG_ERR,
638e56fbc5aSMatteo Riondato 					    "cannot get local address for %s: %s",
639e56fbc5aSMatteo Riondato 					    nconf->nc_netid,
640e56fbc5aSMatteo Riondato 					    gai_strerror(aicode));
6418a3cd533SXin LI 					if (!kernel_lockd)
642795b2dc0SRick Macklem 						close(fd);
643e56fbc5aSMatteo Riondato 					continue;
644e56fbc5aSMatteo Riondato 				}
645e56fbc5aSMatteo Riondato 			}
646e56fbc5aSMatteo Riondato 		} else {
647e56fbc5aSMatteo Riondato 			if ((aicode = getaddrinfo(hosts[nhostsbak], svcport_str,
648e56fbc5aSMatteo Riondato 			    &hints, &res)) != 0) {
649e56fbc5aSMatteo Riondato 				syslog(LOG_ERR,
650e56fbc5aSMatteo Riondato 				    "cannot get local address for %s: %s",
651e56fbc5aSMatteo Riondato 				    nconf->nc_netid, gai_strerror(aicode));
6528a3cd533SXin LI 				if (!kernel_lockd)
653795b2dc0SRick Macklem 					close(fd);
654e56fbc5aSMatteo Riondato 				continue;
655e56fbc5aSMatteo Riondato 			}
656e56fbc5aSMatteo Riondato 		}
657e56fbc5aSMatteo Riondato 
6588a3cd533SXin LI 		if (kernel_lockd) {
6598a3cd533SXin LI 			struct netbuf servaddr;
6608a3cd533SXin LI 			char *uaddr;
661795b2dc0SRick Macklem 
6628a3cd533SXin LI 			/*
6638a3cd533SXin LI 			 * Look up addresses for the kernel to create transports for.
6648a3cd533SXin LI 			 */
6658a3cd533SXin LI 			servaddr.len = servaddr.maxlen = res->ai_addrlen;
6668a3cd533SXin LI 			servaddr.buf = res->ai_addr;
6678a3cd533SXin LI 			uaddr = taddr2uaddr(nconf, &servaddr);
6688a3cd533SXin LI 
6698a3cd533SXin LI 			addrs = realloc(addrs, 2 * (naddrs + 1) * sizeof(char *));
6708a3cd533SXin LI 			if (!addrs)
6718a3cd533SXin LI 				out_of_mem();
6728a3cd533SXin LI 			addrs[2 * naddrs] = strdup(nconf->nc_netid);
6738a3cd533SXin LI 			addrs[2 * naddrs + 1] = uaddr;
6748a3cd533SXin LI 			naddrs++;
6758a3cd533SXin LI 		} else {
676795b2dc0SRick Macklem 			/* Store the fd. */
677795b2dc0SRick Macklem 			sock_fd[sock_fdcnt - 1] = fd;
678795b2dc0SRick Macklem 
679795b2dc0SRick Macklem 			/* Now, attempt the bind. */
680e56fbc5aSMatteo Riondato 			r = bindresvport_sa(fd, res->ai_addr);
681e56fbc5aSMatteo Riondato 			if (r != 0) {
682795b2dc0SRick Macklem 				if (errno == EADDRINUSE && mallocd_svcport != 0) {
683795b2dc0SRick Macklem 					if (mallocd_res != 0) {
684795b2dc0SRick Macklem 						free(res->ai_addr);
685795b2dc0SRick Macklem 						free(res);
686795b2dc0SRick Macklem 					} else
687795b2dc0SRick Macklem 						freeaddrinfo(res);
688795b2dc0SRick Macklem 					return (-1);
689795b2dc0SRick Macklem 				}
690e56fbc5aSMatteo Riondato 				syslog(LOG_ERR, "bindresvport_sa: %m");
691e56fbc5aSMatteo Riondato 				exit(1);
692e56fbc5aSMatteo Riondato 			}
693e56fbc5aSMatteo Riondato 
694795b2dc0SRick Macklem 			if (svcport_str == NULL) {
695795b2dc0SRick Macklem 				svcport_str = malloc(NI_MAXSERV * sizeof(char));
696795b2dc0SRick Macklem 				if (svcport_str == NULL)
697795b2dc0SRick Macklem 					out_of_mem();
698795b2dc0SRick Macklem 				mallocd_svcport = 1;
699795b2dc0SRick Macklem 
700795b2dc0SRick Macklem 				if (getnameinfo(res->ai_addr,
701795b2dc0SRick Macklem 				res->ai_addr->sa_len, NULL, NI_MAXHOST,
702795b2dc0SRick Macklem 				svcport_str, NI_MAXSERV * sizeof(char),
703795b2dc0SRick Macklem 				NI_NUMERICHOST | NI_NUMERICSERV))
704795b2dc0SRick Macklem 					errx(1, "Cannot get port number");
705795b2dc0SRick Macklem 			}
7068a3cd533SXin LI 		}
7078a3cd533SXin LI 
708795b2dc0SRick Macklem 		if (mallocd_res != 0) {
709795b2dc0SRick Macklem 			free(res->ai_addr);
710795b2dc0SRick Macklem 			free(res);
711795b2dc0SRick Macklem 		} else
712795b2dc0SRick Macklem 			freeaddrinfo(res);
713795b2dc0SRick Macklem 		res = NULL;
714795b2dc0SRick Macklem 	}
715795b2dc0SRick Macklem 	return (0);
716795b2dc0SRick Macklem }
717795b2dc0SRick Macklem 
718795b2dc0SRick Macklem /*
719795b2dc0SRick Macklem  * Called after all the create_service() calls have succeeded, to complete
720795b2dc0SRick Macklem  * the setup and registration.
721795b2dc0SRick Macklem  */
722795b2dc0SRick Macklem static void
complete_service(struct netconfig * nconf,char * port_str)723795b2dc0SRick Macklem complete_service(struct netconfig *nconf, char *port_str)
724795b2dc0SRick Macklem {
725795b2dc0SRick Macklem 	struct addrinfo hints, *res = NULL;
726795b2dc0SRick Macklem 	struct __rpc_sockinfo si;
727795b2dc0SRick Macklem 	struct netbuf servaddr;
728795b2dc0SRick Macklem 	SVCXPRT	*transp = NULL;
729795b2dc0SRick Macklem 	int aicode, fd, nhostsbak;
730795b2dc0SRick Macklem 	int registered = 0;
731795b2dc0SRick Macklem 
732795b2dc0SRick Macklem 	if ((nconf->nc_semantics != NC_TPI_CLTS) &&
733795b2dc0SRick Macklem 	    (nconf->nc_semantics != NC_TPI_COTS) &&
734795b2dc0SRick Macklem 	    (nconf->nc_semantics != NC_TPI_COTS_ORD))
735795b2dc0SRick Macklem 		return;	/* not my type */
736795b2dc0SRick Macklem 
737795b2dc0SRick Macklem 	/*
738795b2dc0SRick Macklem 	 * XXX - using RPC library internal functions.
739795b2dc0SRick Macklem 	 */
740795b2dc0SRick Macklem 	if (!__rpc_nconf2sockinfo(nconf, &si)) {
741795b2dc0SRick Macklem 		syslog(LOG_ERR, "cannot get information for %s",
742795b2dc0SRick Macklem 		    nconf->nc_netid);
743795b2dc0SRick Macklem 		return;
744795b2dc0SRick Macklem 	}
745795b2dc0SRick Macklem 
746795b2dc0SRick Macklem 	nhostsbak = nhosts;
747795b2dc0SRick Macklem 	while (nhostsbak > 0) {
748795b2dc0SRick Macklem 		--nhostsbak;
749795b2dc0SRick Macklem 		if (sock_fdpos >= sock_fdcnt) {
750795b2dc0SRick Macklem 			/* Should never happen. */
751795b2dc0SRick Macklem 			syslog(LOG_ERR, "Ran out of socket fd's");
752795b2dc0SRick Macklem 			return;
753795b2dc0SRick Macklem 		}
754795b2dc0SRick Macklem 		fd = sock_fd[sock_fdpos++];
755795b2dc0SRick Macklem 		if (fd < 0)
756795b2dc0SRick Macklem 			continue;
757795b2dc0SRick Macklem 
7580e7cce13SDoug Rabson 		if (nconf->nc_semantics != NC_TPI_CLTS)
7590e7cce13SDoug Rabson 		    listen(fd, SOMAXCONN);
7600e7cce13SDoug Rabson 
761e56fbc5aSMatteo Riondato 		transp = svc_tli_create(fd, nconf, NULL,
762e56fbc5aSMatteo Riondato 		    RPC_MAXDATASIZE, RPC_MAXDATASIZE);
763e56fbc5aSMatteo Riondato 
764e56fbc5aSMatteo Riondato 		if (transp != (SVCXPRT *) NULL) {
765e56fbc5aSMatteo Riondato 			if (!svc_reg(transp, NLM_PROG, NLM_SM, nlm_prog_0,
766e56fbc5aSMatteo Riondato 			    NULL))
767e56fbc5aSMatteo Riondato 				syslog(LOG_ERR,
768e56fbc5aSMatteo Riondato 				    "can't register %s NLM_PROG, NLM_SM service",
769e56fbc5aSMatteo Riondato 				    nconf->nc_netid);
770e56fbc5aSMatteo Riondato 
771e56fbc5aSMatteo Riondato 			if (!svc_reg(transp, NLM_PROG, NLM_VERS, nlm_prog_1,
772e56fbc5aSMatteo Riondato 			    NULL))
773e56fbc5aSMatteo Riondato 				syslog(LOG_ERR,
774e56fbc5aSMatteo Riondato 				    "can't register %s NLM_PROG, NLM_VERS service",
775e56fbc5aSMatteo Riondato 				    nconf->nc_netid);
776e56fbc5aSMatteo Riondato 
777e56fbc5aSMatteo Riondato 			if (!svc_reg(transp, NLM_PROG, NLM_VERSX, nlm_prog_3,
778e56fbc5aSMatteo Riondato 			    NULL))
779e56fbc5aSMatteo Riondato 				syslog(LOG_ERR,
780e56fbc5aSMatteo Riondato 				    "can't register %s NLM_PROG, NLM_VERSX service",
781e56fbc5aSMatteo Riondato 				    nconf->nc_netid);
782e56fbc5aSMatteo Riondato 
783e56fbc5aSMatteo Riondato 			if (!svc_reg(transp, NLM_PROG, NLM_VERS4, nlm_prog_4,
784e56fbc5aSMatteo Riondato 			    NULL))
785e56fbc5aSMatteo Riondato 				syslog(LOG_ERR,
786e56fbc5aSMatteo Riondato 				    "can't register %s NLM_PROG, NLM_VERS4 service",
787e56fbc5aSMatteo Riondato 				    nconf->nc_netid);
788e56fbc5aSMatteo Riondato 
789e56fbc5aSMatteo Riondato 		} else
790e56fbc5aSMatteo Riondato 			syslog(LOG_WARNING, "can't create %s services",
791e56fbc5aSMatteo Riondato 			    nconf->nc_netid);
792e56fbc5aSMatteo Riondato 
793e56fbc5aSMatteo Riondato 		if (registered == 0) {
794e56fbc5aSMatteo Riondato 			registered = 1;
795e56fbc5aSMatteo Riondato 			memset(&hints, 0, sizeof hints);
796e56fbc5aSMatteo Riondato 			hints.ai_flags = AI_PASSIVE;
797e56fbc5aSMatteo Riondato 			hints.ai_family = si.si_af;
798e56fbc5aSMatteo Riondato 			hints.ai_socktype = si.si_socktype;
799e56fbc5aSMatteo Riondato 			hints.ai_protocol = si.si_proto;
800e56fbc5aSMatteo Riondato 
801795b2dc0SRick Macklem 			if ((aicode = getaddrinfo(NULL, port_str, &hints,
802e56fbc5aSMatteo Riondato 			    &res)) != 0) {
803e56fbc5aSMatteo Riondato 				syslog(LOG_ERR, "cannot get local address: %s",
804e56fbc5aSMatteo Riondato 				    gai_strerror(aicode));
805e56fbc5aSMatteo Riondato 				exit(1);
806e56fbc5aSMatteo Riondato 			}
807e56fbc5aSMatteo Riondato 
808e56fbc5aSMatteo Riondato 			servaddr.buf = malloc(res->ai_addrlen);
809e56fbc5aSMatteo Riondato 			memcpy(servaddr.buf, res->ai_addr, res->ai_addrlen);
810e56fbc5aSMatteo Riondato 			servaddr.len = res->ai_addrlen;
811e56fbc5aSMatteo Riondato 
812e56fbc5aSMatteo Riondato 			rpcb_set(NLM_PROG, NLM_SM, nconf, &servaddr);
813e56fbc5aSMatteo Riondato 			rpcb_set(NLM_PROG, NLM_VERS, nconf, &servaddr);
814e56fbc5aSMatteo Riondato 			rpcb_set(NLM_PROG, NLM_VERSX, nconf, &servaddr);
815e56fbc5aSMatteo Riondato 			rpcb_set(NLM_PROG, NLM_VERS4, nconf, &servaddr);
816e56fbc5aSMatteo Riondato 
817e56fbc5aSMatteo Riondato 			xcreated++;
818e56fbc5aSMatteo Riondato 			freeaddrinfo(res);
819e56fbc5aSMatteo Riondato 		}
820e56fbc5aSMatteo Riondato 	} /* end while */
821e56fbc5aSMatteo Riondato }
822e56fbc5aSMatteo Riondato 
823dfdcada3SDoug Rabson /*
824795b2dc0SRick Macklem  * Clear out sockets after a failure to bind one of them, so that the
825795b2dc0SRick Macklem  * cycle of socket creation/binding can start anew.
826795b2dc0SRick Macklem  */
827795b2dc0SRick Macklem static void
clearout_service(void)828795b2dc0SRick Macklem clearout_service(void)
829795b2dc0SRick Macklem {
830795b2dc0SRick Macklem 	int i;
831795b2dc0SRick Macklem 
832795b2dc0SRick Macklem 	for (i = 0; i < sock_fdcnt; i++) {
833795b2dc0SRick Macklem 		if (sock_fd[i] >= 0) {
834795b2dc0SRick Macklem 			shutdown(sock_fd[i], SHUT_RDWR);
835795b2dc0SRick Macklem 			close(sock_fd[i]);
836795b2dc0SRick Macklem 		}
837795b2dc0SRick Macklem 	}
838795b2dc0SRick Macklem }
839795b2dc0SRick Macklem 
8404945c132SAlfred Perlstein void
sigalarm_handler(void)8414945c132SAlfred Perlstein sigalarm_handler(void)
8424945c132SAlfred Perlstein {
8434945c132SAlfred Perlstein 
8444945c132SAlfred Perlstein 	grace_expired = 1;
8454945c132SAlfred Perlstein }
8464945c132SAlfred Perlstein 
8474945c132SAlfred Perlstein void
usage(void)8487b043ce5SJohn Baldwin usage(void)
8494945c132SAlfred Perlstein {
8503efa83dcSDoug Rabson 	errx(1, "usage: rpc.lockd [-d <debuglevel>]"
85190e43b44SRavi Pokala 	    " [-F] [-g <grace period>] [-h <bindip>] [-p <port>]");
8524945c132SAlfred Perlstein }
8534945c132SAlfred Perlstein 
8544945c132SAlfred Perlstein /*
8554945c132SAlfred Perlstein  * init_nsm --
8564945c132SAlfred Perlstein  *	Reset the NSM state-of-the-world and acquire its state.
8574945c132SAlfred Perlstein  */
8584945c132SAlfred Perlstein void
init_nsm(void)8594945c132SAlfred Perlstein init_nsm(void)
8604945c132SAlfred Perlstein {
8614945c132SAlfred Perlstein 	enum clnt_stat ret;
8624945c132SAlfred Perlstein 	my_id id;
8634945c132SAlfred Perlstein 	sm_stat stat;
864e4b0fedeSAlfred Perlstein 	char name[] = "NFS NLM";
8654945c132SAlfred Perlstein 
8664945c132SAlfred Perlstein 	/*
8674945c132SAlfred Perlstein 	 * !!!
8684945c132SAlfred Perlstein 	 * The my_id structure isn't used by the SM_UNMON_ALL call, as far
8694945c132SAlfred Perlstein 	 * as I know.  Leave it empty for now.
8704945c132SAlfred Perlstein 	 */
8714945c132SAlfred Perlstein 	memset(&id, 0, sizeof(id));
872e4b0fedeSAlfred Perlstein 	id.my_name = name;
8734945c132SAlfred Perlstein 
8744945c132SAlfred Perlstein 	/*
8754945c132SAlfred Perlstein 	 * !!!
8764945c132SAlfred Perlstein 	 * The statd program must already be registered when lockd runs.
8774945c132SAlfred Perlstein 	 */
8784945c132SAlfred Perlstein 	do {
8794945c132SAlfred Perlstein 		ret = callrpc("localhost", SM_PROG, SM_VERS, SM_UNMON_ALL,
88075e40e46SPeter Wemm 		    (xdrproc_t)xdr_my_id, &id, (xdrproc_t)xdr_sm_stat, &stat);
8814945c132SAlfred Perlstein 		if (ret == RPC_PROGUNAVAIL) {
8828ebcf97eSGuy Helmer 			syslog(LOG_WARNING, "%lu %s", SM_PROG,
8838ebcf97eSGuy Helmer 			    clnt_sperrno(ret));
8844945c132SAlfred Perlstein 			sleep(2);
8854945c132SAlfred Perlstein 			continue;
8864945c132SAlfred Perlstein 		}
8874945c132SAlfred Perlstein 		break;
8884945c132SAlfred Perlstein 	} while (0);
8894945c132SAlfred Perlstein 
8904945c132SAlfred Perlstein 	if (ret != 0) {
8918ebcf97eSGuy Helmer 		syslog(LOG_ERR, "%lu %s", SM_PROG, clnt_sperrno(ret));
8928ebcf97eSGuy Helmer 		exit(1);
8934945c132SAlfred Perlstein 	}
8944945c132SAlfred Perlstein 
8954945c132SAlfred Perlstein 	nsm_state = stat.state;
8964945c132SAlfred Perlstein 
8974945c132SAlfred Perlstein 	/* setup constant data for SM_MON calls */
898e4b0fedeSAlfred Perlstein 	mon_host.mon_id.my_id.my_name = localhost;
8994945c132SAlfred Perlstein 	mon_host.mon_id.my_id.my_prog = NLM_PROG;
9004945c132SAlfred Perlstein 	mon_host.mon_id.my_id.my_vers = NLM_SM;
9014945c132SAlfred Perlstein 	mon_host.mon_id.my_id.my_proc = NLM_SM_NOTIFY;  /* bsdi addition */
9024945c132SAlfred Perlstein }
903e56fbc5aSMatteo Riondato 
904e56fbc5aSMatteo Riondato /*
905e56fbc5aSMatteo Riondato  * Out of memory, fatal
906e56fbc5aSMatteo Riondato  */
9077b043ce5SJohn Baldwin void
out_of_mem(void)9087b043ce5SJohn Baldwin out_of_mem(void)
909e56fbc5aSMatteo Riondato {
910e56fbc5aSMatteo Riondato 	syslog(LOG_ERR, "out of memory");
911e56fbc5aSMatteo Riondato 	exit(2);
912e56fbc5aSMatteo Riondato }
913