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