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