xref: /freebsd/usr.sbin/rpc.lockd/lockd.c (revision 2be1a816b9ff69588e55be0a84cbe2a31efc0f2f)
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 int		debug_level = 0;	/* 0 = no debugging syslog() calls */
78 int		_rpcsvcdirty = 0;
79 
80 int grace_expired;
81 int nsm_state;
82 int kernel_lockd;
83 pid_t client_pid;
84 struct mon mon_host;
85 char **hosts, *svcport_str = NULL;
86 int nhosts = 0;
87 int xcreated = 0;
88 char **addrs;			/* actually (netid, uaddr) pairs */
89 int naddrs;			/* count of how many (netid, uaddr) pairs */
90 
91 void 	create_service(struct netconfig *nconf);
92 void 	lookup_addresses(struct netconfig *nconf);
93 void	init_nsm(void);
94 void	nlm_prog_0(struct svc_req *, SVCXPRT *);
95 void	nlm_prog_1(struct svc_req *, SVCXPRT *);
96 void	nlm_prog_3(struct svc_req *, SVCXPRT *);
97 void	nlm_prog_4(struct svc_req *, SVCXPRT *);
98 void	out_of_mem(void);
99 void	usage(void);
100 
101 void sigalarm_handler(void);
102 
103 /*
104  * XXX move to some header file.
105  */
106 #define _PATH_RPCLOCKDSOCK	"/var/run/rpclockd.sock"
107 
108 int
109 main(int argc, char **argv)
110 {
111 	int ch, i, s;
112 	void *nc_handle;
113 	char *endptr, **hosts_bak;
114 	struct sigaction sigalarm;
115 	int grace_period = 30;
116 	struct netconfig *nconf;
117 	int have_v6 = 1;
118 	int maxrec = RPC_MAXDATASIZE;
119 	in_port_t svcport = 0;
120 
121 	while ((ch = getopt(argc, argv, "d:g:h:p:")) != (-1)) {
122 		switch (ch) {
123 		case 'd':
124 			debug_level = atoi(optarg);
125 			if (!debug_level) {
126 				usage();
127 				/* NOTREACHED */
128 			}
129 			break;
130 		case 'g':
131 			grace_period = atoi(optarg);
132 			if (!grace_period) {
133 				usage();
134 				/* NOTREACHED */
135 			}
136 			break;
137 		case 'h':
138 			++nhosts;
139 			hosts_bak = hosts;
140 			hosts_bak = realloc(hosts, nhosts * sizeof(char *));
141 			if (hosts_bak == NULL) {
142 				if (hosts != NULL) {
143 					for (i = 0; i < nhosts; i++)
144 						free(hosts[i]);
145 					free(hosts);
146 					out_of_mem();
147 				}
148 			}
149 			hosts = hosts_bak;
150 			hosts[nhosts - 1] = strdup(optarg);
151 			if (hosts[nhosts - 1] == NULL) {
152 				for (i = 0; i < (nhosts - 1); i++)
153 					free(hosts[i]);
154 				free(hosts);
155 				out_of_mem();
156 			}
157 			break;
158 		case 'p':
159 			endptr = NULL;
160 			svcport = (in_port_t)strtoul(optarg, &endptr, 10);
161 			if (endptr == NULL || *endptr != '\0' ||
162 			    svcport == 0 || svcport >= IPPORT_MAX)
163 				usage();
164 			svcport_str = strdup(optarg);
165 			break;
166 		default:
167 		case '?':
168 			usage();
169 			/* NOTREACHED */
170 		}
171 	}
172 	if (geteuid()) { /* This command allowed only to root */
173 		fprintf(stderr, "Sorry. You are not superuser\n");
174 		exit(1);
175         }
176 
177 	kernel_lockd = FALSE;
178 	if (modfind("nfslockd") < 0) {
179 		if (kldload("nfslockd") < 0) {
180 			fprintf(stderr, "Can't find or load kernel support for rpc.lockd - using non-kernel implementation\n");
181 		} else {
182 			kernel_lockd = TRUE;
183 		}
184 	} else {
185 		kernel_lockd = TRUE;
186 	}
187 
188 	(void)rpcb_unset(NLM_PROG, NLM_SM, NULL);
189 	(void)rpcb_unset(NLM_PROG, NLM_VERS, NULL);
190 	(void)rpcb_unset(NLM_PROG, NLM_VERSX, NULL);
191 	(void)rpcb_unset(NLM_PROG, NLM_VERS4, NULL);
192 
193 	/*
194 	 * Check if IPv6 support is present.
195 	 */
196 	s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
197 	if (s < 0)
198 		have_v6 = 0;
199 	else
200 		close(s);
201 
202 	rpc_control(RPC_SVC_CONNMAXREC_SET, &maxrec);
203 
204 	/*
205 	 * If no hosts were specified, add a wildcard entry to bind to
206 	 * INADDR_ANY. Otherwise make sure 127.0.0.1 and ::1 are added to the
207 	 * list.
208 	 */
209 	if (nhosts == 0) {
210 		hosts = malloc(sizeof(char**));
211 		if (hosts == NULL)
212 			out_of_mem();
213 
214 		hosts[0] = "*";
215 		nhosts = 1;
216 	} else {
217 		hosts_bak = hosts;
218 		if (have_v6) {
219 			hosts_bak = realloc(hosts, (nhosts + 2) *
220 			    sizeof(char *));
221 			if (hosts_bak == NULL) {
222 				for (i = 0; i < nhosts; i++)
223 					free(hosts[i]);
224 				free(hosts);
225 				out_of_mem();
226 			} else
227 				hosts = hosts_bak;
228 
229 			nhosts += 2;
230 			hosts[nhosts - 2] = "::1";
231 		} else {
232 			hosts_bak = realloc(hosts, (nhosts + 1) * sizeof(char *));
233 			if (hosts_bak == NULL) {
234 				for (i = 0; i < nhosts; i++)
235 					free(hosts[i]);
236 
237 				free(hosts);
238 				out_of_mem();
239 			} else {
240 				nhosts += 1;
241 				hosts = hosts_bak;
242 			}
243 		}
244 		hosts[nhosts - 1] = "127.0.0.1";
245 	}
246 
247 	if (kernel_lockd) {
248 		/*
249 		 * For the kernel lockd case, we run a cut-down RPC
250 		 * service on a local-domain socket. The kernel's RPC
251 		 * server will pass what it can't handle (mainly
252 		 * client replies) down to us. This can go away
253 		 * entirely if/when we move the client side of NFS
254 		 * locking into the kernel.
255 		 */
256 		struct sockaddr_un sun;
257 		int fd, oldmask;
258 		SVCXPRT *xprt;
259 
260 		memset(&sun, 0, sizeof sun);
261 		sun.sun_family = AF_LOCAL;
262 		unlink(_PATH_RPCLOCKDSOCK);
263 		strcpy(sun.sun_path, _PATH_RPCLOCKDSOCK);
264 		sun.sun_len = SUN_LEN(&sun);
265 		fd = socket(AF_LOCAL, SOCK_STREAM, 0);
266 		if (!fd) {
267 			err(1, "Can't create local lockd socket");
268 		}
269 		oldmask = umask(S_IXUSR|S_IRWXG|S_IRWXO);
270 		if (bind(fd, (struct sockaddr *) &sun, sun.sun_len) < 0) {
271 			err(1, "Can't bind local lockd socket");
272 		}
273 		umask(oldmask);
274 		if (listen(fd, SOMAXCONN) < 0) {
275 			err(1, "Can't listen on local lockd socket");
276 		}
277 		xprt = svc_vc_create(fd, RPC_MAXDATASIZE, RPC_MAXDATASIZE);
278 		if (!xprt) {
279 			err(1, "Can't create transport for local lockd socket");
280 		}
281 		if (!svc_reg(xprt, NLM_PROG, NLM_VERS4, nlm_prog_4, NULL)) {
282 			err(1, "Can't register service for local lockd socket");
283 		}
284 
285 		/*
286 		 * We need to look up the addresses so that we can
287 		 * hand uaddrs (ascii encoded address+port strings) to
288 		 * the kernel.
289 		 */
290 		nc_handle = setnetconfig();
291 		while ((nconf = getnetconfig(nc_handle))) {
292 			/* We want to listen only on udp6, tcp6, udp, tcp transports */
293 			if (nconf->nc_flag & NC_VISIBLE) {
294 				/* Skip if there's no IPv6 support */
295 				if (have_v6 == 0 && strcmp(nconf->nc_protofmly, "inet6") == 0) {
296 					/* DO NOTHING */
297 				} else {
298 					lookup_addresses(nconf);
299 				}
300 			}
301 		}
302 		endnetconfig(nc_handle);
303 	} else {
304 		nc_handle = setnetconfig();
305 		while ((nconf = getnetconfig(nc_handle))) {
306 			/* We want to listen only on udp6, tcp6, udp, tcp transports */
307 			if (nconf->nc_flag & NC_VISIBLE) {
308 				/* Skip if there's no IPv6 support */
309 				if (have_v6 == 0 && strcmp(nconf->nc_protofmly, "inet6") == 0) {
310 					/* DO NOTHING */
311 				} else {
312 					create_service(nconf);
313 				}
314 			}
315 		}
316 		endnetconfig(nc_handle);
317 	}
318 
319 	/*
320 	 * Note that it is NOT sensible to run this program from inetd - the
321 	 * protocol assumes that it will run immediately at boot time.
322 	 */
323 	if (daemon(0, debug_level > 0)) {
324 		err(1, "cannot fork");
325 		/* NOTREACHED */
326 	}
327 
328 	openlog("rpc.lockd", 0, LOG_DAEMON);
329 	if (debug_level)
330 		syslog(LOG_INFO, "Starting, debug level %d", debug_level);
331 	else
332 		syslog(LOG_INFO, "Starting");
333 
334 	sigalarm.sa_handler = (sig_t) sigalarm_handler;
335 	sigemptyset(&sigalarm.sa_mask);
336 	sigalarm.sa_flags = SA_RESETHAND; /* should only happen once */
337 	sigalarm.sa_flags |= SA_RESTART;
338 	if (sigaction(SIGALRM, &sigalarm, NULL) != 0) {
339 		syslog(LOG_WARNING, "sigaction(SIGALRM) failed: %s",
340 		    strerror(errno));
341 		exit(1);
342 	}
343 
344 	if (kernel_lockd) {
345 		client_pid = client_request();
346 
347 		/*
348 		 * Create a child process to enter the kernel and then
349 		 * wait for RPCs on our local domain socket.
350 		 */
351 		if (!fork())
352 			nlm_syscall(debug_level, grace_period, naddrs, addrs);
353 		else
354 			svc_run();
355 	} else {
356 		grace_expired = 0;
357 		alarm(grace_period);
358 
359 		init_nsm();
360 
361 		client_pid = client_request();
362 
363 		svc_run();		/* Should never return */
364 	}
365 	exit(1);
366 }
367 
368 /*
369  * This routine creates and binds sockets on the appropriate
370  * addresses. It gets called one time for each transport and
371  * registrates the service with rpcbind on that trasport.
372  */
373 void
374 create_service(struct netconfig *nconf)
375 {
376 	struct addrinfo hints, *res = NULL;
377 	struct sockaddr_in *sin;
378 	struct sockaddr_in6 *sin6;
379 	struct __rpc_sockinfo si;
380 	struct netbuf servaddr;
381 	SVCXPRT	*transp = NULL;
382 	int aicode;
383 	int fd;
384 	int nhostsbak;
385 	int r;
386 	int registered = 0;
387 	u_int32_t host_addr[4];  /* IPv4 or IPv6 */
388 
389 	if ((nconf->nc_semantics != NC_TPI_CLTS) &&
390 	    (nconf->nc_semantics != NC_TPI_COTS) &&
391 	    (nconf->nc_semantics != NC_TPI_COTS_ORD))
392 		return;	/* not my type */
393 
394 	/*
395 	 * XXX - using RPC library internal functions.
396 	 */
397 	if (!__rpc_nconf2sockinfo(nconf, &si)) {
398 		syslog(LOG_ERR, "cannot get information for %s",
399 		    nconf->nc_netid);
400 		return;
401 	}
402 
403 	/* Get rpc.statd's address on this transport */
404 	memset(&hints, 0, sizeof hints);
405 	hints.ai_flags = AI_PASSIVE;
406 	hints.ai_family = si.si_af;
407 	hints.ai_socktype = si.si_socktype;
408 	hints.ai_protocol = si.si_proto;
409 
410 	/*
411 	 * Bind to specific IPs if asked to
412 	 */
413 	nhostsbak = nhosts;
414 	while (nhostsbak > 0) {
415 		--nhostsbak;
416 
417 		/*
418 		 * XXX - using RPC library internal functions.
419 		 */
420 		if ((fd = __rpc_nconf2fd(nconf)) < 0) {
421 			syslog(LOG_ERR, "cannot create socket for %s",
422 			    nconf->nc_netid);
423 			continue;
424 		}
425 
426 		switch (hints.ai_family) {
427 			case AF_INET:
428 				if (inet_pton(AF_INET, hosts[nhostsbak],
429 				    host_addr) == 1) {
430 					hints.ai_flags &= AI_NUMERICHOST;
431 				} else {
432 					/*
433 					 * Skip if we have an AF_INET6 address.
434 					 */
435 					if (inet_pton(AF_INET6, hosts[nhostsbak],
436 					    host_addr) == 1) {
437 						close(fd);
438 						continue;
439 					}
440 				}
441 				break;
442 			case AF_INET6:
443 				if (inet_pton(AF_INET6, hosts[nhostsbak],
444 				    host_addr) == 1) {
445 					hints.ai_flags &= AI_NUMERICHOST;
446 				} else {
447 					/*
448 					 * Skip if we have an AF_INET address.
449 					 */
450 					if (inet_pton(AF_INET, hosts[nhostsbak],
451 					    host_addr) == 1) {
452 						close(fd);
453 						continue;
454 					}
455 				}
456 				break;
457 			default:
458 				break;
459 		}
460 
461 		/*
462 		 * If no hosts were specified, just bind to INADDR_ANY
463 		 */
464 		if (strcmp("*", hosts[nhostsbak]) == 0) {
465 			if (svcport_str == NULL) {
466 				res = malloc(sizeof(struct addrinfo));
467 				if (res == NULL)
468 					out_of_mem();
469 				res->ai_flags = hints.ai_flags;
470 				res->ai_family = hints.ai_family;
471 				res->ai_protocol = hints.ai_protocol;
472 				switch (res->ai_family) {
473 					case AF_INET:
474 						sin = malloc(sizeof(struct sockaddr_in));
475 						if (sin == NULL)
476 							out_of_mem();
477 						sin->sin_family = AF_INET;
478 						sin->sin_port = htons(0);
479 						sin->sin_addr.s_addr = htonl(INADDR_ANY);
480 						res->ai_addr = (struct sockaddr*) sin;
481 						res->ai_addrlen = (socklen_t)
482 						    sizeof(res->ai_addr);
483 						break;
484 					case AF_INET6:
485 						sin6 = malloc(sizeof(struct sockaddr_in6));
486 						if (sin6 == NULL)
487 							out_of_mem();
488 						sin6->sin6_family = AF_INET6;
489 						sin6->sin6_port = htons(0);
490 						sin6->sin6_addr = in6addr_any;
491 						res->ai_addr = (struct sockaddr*) sin6;
492 						res->ai_addrlen = (socklen_t) sizeof(res->ai_addr);
493 						break;
494 					default:
495 						break;
496 				}
497 			} else {
498 				if ((aicode = getaddrinfo(NULL, svcport_str,
499 				    &hints, &res)) != 0) {
500 					syslog(LOG_ERR,
501 					    "cannot get local address for %s: %s",
502 					    nconf->nc_netid,
503 					    gai_strerror(aicode));
504 					continue;
505 				}
506 			}
507 		} else {
508 			if ((aicode = getaddrinfo(hosts[nhostsbak], svcport_str,
509 			    &hints, &res)) != 0) {
510 				syslog(LOG_ERR,
511 				    "cannot get local address for %s: %s",
512 				    nconf->nc_netid, gai_strerror(aicode));
513 				continue;
514 			}
515 		}
516 
517 		r = bindresvport_sa(fd, res->ai_addr);
518 		if (r != 0) {
519 			syslog(LOG_ERR, "bindresvport_sa: %m");
520 			exit(1);
521 		}
522 
523 		if (nconf->nc_semantics != NC_TPI_CLTS)
524 		    listen(fd, SOMAXCONN);
525 
526 		transp = svc_tli_create(fd, nconf, NULL,
527 		    RPC_MAXDATASIZE, RPC_MAXDATASIZE);
528 
529 		if (transp != (SVCXPRT *) NULL) {
530 			if (!svc_reg(transp, NLM_PROG, NLM_SM, nlm_prog_0,
531 			    NULL))
532 				syslog(LOG_ERR,
533 				    "can't register %s NLM_PROG, NLM_SM service",
534 				    nconf->nc_netid);
535 
536 			if (!svc_reg(transp, NLM_PROG, NLM_VERS, nlm_prog_1,
537 			    NULL))
538 				syslog(LOG_ERR,
539 				    "can't register %s NLM_PROG, NLM_VERS service",
540 				    nconf->nc_netid);
541 
542 			if (!svc_reg(transp, NLM_PROG, NLM_VERSX, nlm_prog_3,
543 			    NULL))
544 				syslog(LOG_ERR,
545 				    "can't register %s NLM_PROG, NLM_VERSX service",
546 				    nconf->nc_netid);
547 
548 			if (!svc_reg(transp, NLM_PROG, NLM_VERS4, nlm_prog_4,
549 			    NULL))
550 				syslog(LOG_ERR,
551 				    "can't register %s NLM_PROG, NLM_VERS4 service",
552 				    nconf->nc_netid);
553 
554 		} else
555 			syslog(LOG_WARNING, "can't create %s services",
556 			    nconf->nc_netid);
557 
558 		if (registered == 0) {
559 			registered = 1;
560 			memset(&hints, 0, sizeof hints);
561 			hints.ai_flags = AI_PASSIVE;
562 			hints.ai_family = si.si_af;
563 			hints.ai_socktype = si.si_socktype;
564 			hints.ai_protocol = si.si_proto;
565 
566 			if (svcport_str == NULL) {
567 				svcport_str = malloc(NI_MAXSERV * sizeof(char));
568 				if (svcport_str == NULL)
569 					out_of_mem();
570 
571 				if (getnameinfo(res->ai_addr,
572 				    res->ai_addr->sa_len, NULL, NI_MAXHOST,
573 				    svcport_str, NI_MAXSERV * sizeof(char),
574 				    NI_NUMERICHOST | NI_NUMERICSERV))
575 					errx(1, "Cannot get port number");
576 			}
577 
578 			if((aicode = getaddrinfo(NULL, svcport_str, &hints,
579 			    &res)) != 0) {
580 				syslog(LOG_ERR, "cannot get local address: %s",
581 				    gai_strerror(aicode));
582 				exit(1);
583 			}
584 
585 			servaddr.buf = malloc(res->ai_addrlen);
586 			memcpy(servaddr.buf, res->ai_addr, res->ai_addrlen);
587 			servaddr.len = res->ai_addrlen;
588 
589 			rpcb_set(NLM_PROG, NLM_SM, nconf, &servaddr);
590 			rpcb_set(NLM_PROG, NLM_VERS, nconf, &servaddr);
591 			rpcb_set(NLM_PROG, NLM_VERSX, nconf, &servaddr);
592 			rpcb_set(NLM_PROG, NLM_VERS4, nconf, &servaddr);
593 
594 			xcreated++;
595 			freeaddrinfo(res);
596 		}
597 	} /* end while */
598 }
599 
600 /*
601  * Look up addresses for the kernel to create transports for.
602  */
603 void
604 lookup_addresses(struct netconfig *nconf)
605 {
606 	struct addrinfo hints, *res = NULL;
607 	struct sockaddr_in *sin;
608 	struct sockaddr_in6 *sin6;
609 	struct __rpc_sockinfo si;
610 	struct netbuf servaddr;
611 	SVCXPRT	*transp = NULL;
612 	int aicode;
613 	int nhostsbak;
614 	int r;
615 	int registered = 0;
616 	u_int32_t host_addr[4];  /* IPv4 or IPv6 */
617 	char *uaddr;
618 
619 	if ((nconf->nc_semantics != NC_TPI_CLTS) &&
620 	    (nconf->nc_semantics != NC_TPI_COTS) &&
621 	    (nconf->nc_semantics != NC_TPI_COTS_ORD))
622 		return;	/* not my type */
623 
624 	/*
625 	 * XXX - using RPC library internal functions.
626 	 */
627 	if (!__rpc_nconf2sockinfo(nconf, &si)) {
628 		syslog(LOG_ERR, "cannot get information for %s",
629 		    nconf->nc_netid);
630 		return;
631 	}
632 
633 	/* Get rpc.statd's address on this transport */
634 	memset(&hints, 0, sizeof hints);
635 	hints.ai_flags = AI_PASSIVE;
636 	hints.ai_family = si.si_af;
637 	hints.ai_socktype = si.si_socktype;
638 	hints.ai_protocol = si.si_proto;
639 
640 	/*
641 	 * Bind to specific IPs if asked to
642 	 */
643 	nhostsbak = nhosts;
644 	while (nhostsbak > 0) {
645 		--nhostsbak;
646 
647 		switch (hints.ai_family) {
648 			case AF_INET:
649 				if (inet_pton(AF_INET, hosts[nhostsbak],
650 				    host_addr) == 1) {
651 					hints.ai_flags &= AI_NUMERICHOST;
652 				} else {
653 					/*
654 					 * Skip if we have an AF_INET6 address.
655 					 */
656 					if (inet_pton(AF_INET6, hosts[nhostsbak],
657 					    host_addr) == 1) {
658 						continue;
659 					}
660 				}
661 				break;
662 			case AF_INET6:
663 				if (inet_pton(AF_INET6, hosts[nhostsbak],
664 				    host_addr) == 1) {
665 					hints.ai_flags &= AI_NUMERICHOST;
666 				} else {
667 					/*
668 					 * Skip if we have an AF_INET address.
669 					 */
670 					if (inet_pton(AF_INET, hosts[nhostsbak],
671 					    host_addr) == 1) {
672 						continue;
673 					}
674 				}
675 				break;
676 			default:
677 				break;
678 		}
679 
680 		/*
681 		 * If no hosts were specified, just bind to INADDR_ANY
682 		 */
683 		if (strcmp("*", hosts[nhostsbak]) == 0) {
684 			if (svcport_str == NULL) {
685 				res = malloc(sizeof(struct addrinfo));
686 				if (res == NULL)
687 					out_of_mem();
688 				res->ai_flags = hints.ai_flags;
689 				res->ai_family = hints.ai_family;
690 				res->ai_protocol = hints.ai_protocol;
691 				switch (res->ai_family) {
692 					case AF_INET:
693 						sin = malloc(sizeof(struct sockaddr_in));
694 						if (sin == NULL)
695 							out_of_mem();
696 						sin->sin_family = AF_INET;
697 						sin->sin_port = htons(0);
698 						sin->sin_addr.s_addr = htonl(INADDR_ANY);
699 						res->ai_addr = (struct sockaddr*) sin;
700 						res->ai_addrlen = (socklen_t)
701 						    sizeof(res->ai_addr);
702 						break;
703 					case AF_INET6:
704 						sin6 = malloc(sizeof(struct sockaddr_in6));
705 						if (sin6 == NULL)
706 							out_of_mem();
707 						sin6->sin6_family = AF_INET6;
708 						sin6->sin6_port = htons(0);
709 						sin6->sin6_addr = in6addr_any;
710 						res->ai_addr = (struct sockaddr*) sin6;
711 						res->ai_addrlen = (socklen_t) sizeof(res->ai_addr);
712 						break;
713 					default:
714 						break;
715 				}
716 			} else {
717 				if ((aicode = getaddrinfo(NULL, svcport_str,
718 				    &hints, &res)) != 0) {
719 					syslog(LOG_ERR,
720 					    "cannot get local address for %s: %s",
721 					    nconf->nc_netid,
722 					    gai_strerror(aicode));
723 					continue;
724 				}
725 			}
726 		} else {
727 			if ((aicode = getaddrinfo(hosts[nhostsbak], svcport_str,
728 			    &hints, &res)) != 0) {
729 				syslog(LOG_ERR,
730 				    "cannot get local address for %s: %s",
731 				    nconf->nc_netid, gai_strerror(aicode));
732 				continue;
733 			}
734 		}
735 
736 		servaddr.len = servaddr.maxlen = res->ai_addr->sa_len;
737 		servaddr.buf = res->ai_addr;
738 		uaddr = taddr2uaddr(nconf, &servaddr);
739 
740 		addrs = realloc(addrs, 2 * (naddrs + 1) * sizeof(char *));
741 		if (!addrs)
742 			out_of_mem();
743 		addrs[2 * naddrs] = strdup(nconf->nc_netid);
744 		addrs[2 * naddrs + 1] = uaddr;
745 		naddrs++;
746 	} /* end while */
747 }
748 
749 void
750 sigalarm_handler(void)
751 {
752 
753 	grace_expired = 1;
754 }
755 
756 void
757 usage()
758 {
759 	errx(1, "usage: rpc.lockd [-d <debuglevel>]"
760 	    " [-g <grace period>] [-h <bindip>] [-p <port>]");
761 }
762 
763 /*
764  * init_nsm --
765  *	Reset the NSM state-of-the-world and acquire its state.
766  */
767 void
768 init_nsm(void)
769 {
770 	enum clnt_stat ret;
771 	my_id id;
772 	sm_stat stat;
773 	char name[] = "NFS NLM";
774 	char localhost[] = "localhost";
775 
776 	/*
777 	 * !!!
778 	 * The my_id structure isn't used by the SM_UNMON_ALL call, as far
779 	 * as I know.  Leave it empty for now.
780 	 */
781 	memset(&id, 0, sizeof(id));
782 	id.my_name = name;
783 
784 	/*
785 	 * !!!
786 	 * The statd program must already be registered when lockd runs.
787 	 */
788 	do {
789 		ret = callrpc("localhost", SM_PROG, SM_VERS, SM_UNMON_ALL,
790 		    (xdrproc_t)xdr_my_id, &id, (xdrproc_t)xdr_sm_stat, &stat);
791 		if (ret == RPC_PROGUNAVAIL) {
792 			syslog(LOG_WARNING, "%lu %s", SM_PROG,
793 			    clnt_sperrno(ret));
794 			sleep(2);
795 			continue;
796 		}
797 		break;
798 	} while (0);
799 
800 	if (ret != 0) {
801 		syslog(LOG_ERR, "%lu %s", SM_PROG, clnt_sperrno(ret));
802 		exit(1);
803 	}
804 
805 	nsm_state = stat.state;
806 
807 	/* setup constant data for SM_MON calls */
808 	mon_host.mon_id.my_id.my_name = localhost;
809 	mon_host.mon_id.my_id.my_prog = NLM_PROG;
810 	mon_host.mon_id.my_id.my_vers = NLM_SM;
811 	mon_host.mon_id.my_id.my_proc = NLM_SM_NOTIFY;  /* bsdi addition */
812 }
813 
814 /*
815  * Out of memory, fatal
816  */
817 void out_of_mem()
818 {
819 	syslog(LOG_ERR, "out of memory");
820 	exit(2);
821 }
822