xref: /freebsd/usr.sbin/rpc.lockd/lockd.c (revision bbf7dc4c)
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 		init_nsm();
346 		client_pid = client_request();
347 
348 		/*
349 		 * Create a child process to enter the kernel and then
350 		 * wait for RPCs on our local domain socket.
351 		 */
352 		if (!fork())
353 			nlm_syscall(debug_level, grace_period, naddrs, addrs);
354 		else
355 			svc_run();
356 	} else {
357 		grace_expired = 0;
358 		alarm(grace_period);
359 
360 		init_nsm();
361 
362 		client_pid = client_request();
363 
364 		svc_run();		/* Should never return */
365 	}
366 	exit(1);
367 }
368 
369 /*
370  * This routine creates and binds sockets on the appropriate
371  * addresses. It gets called one time for each transport and
372  * registrates the service with rpcbind on that trasport.
373  */
374 void
375 create_service(struct netconfig *nconf)
376 {
377 	struct addrinfo hints, *res = NULL;
378 	struct sockaddr_in *sin;
379 	struct sockaddr_in6 *sin6;
380 	struct __rpc_sockinfo si;
381 	struct netbuf servaddr;
382 	SVCXPRT	*transp = NULL;
383 	int aicode;
384 	int fd;
385 	int nhostsbak;
386 	int r;
387 	int registered = 0;
388 	u_int32_t host_addr[4];  /* IPv4 or IPv6 */
389 
390 	if ((nconf->nc_semantics != NC_TPI_CLTS) &&
391 	    (nconf->nc_semantics != NC_TPI_COTS) &&
392 	    (nconf->nc_semantics != NC_TPI_COTS_ORD))
393 		return;	/* not my type */
394 
395 	/*
396 	 * XXX - using RPC library internal functions.
397 	 */
398 	if (!__rpc_nconf2sockinfo(nconf, &si)) {
399 		syslog(LOG_ERR, "cannot get information for %s",
400 		    nconf->nc_netid);
401 		return;
402 	}
403 
404 	/* Get rpc.statd's address on this transport */
405 	memset(&hints, 0, sizeof hints);
406 	hints.ai_flags = AI_PASSIVE;
407 	hints.ai_family = si.si_af;
408 	hints.ai_socktype = si.si_socktype;
409 	hints.ai_protocol = si.si_proto;
410 
411 	/*
412 	 * Bind to specific IPs if asked to
413 	 */
414 	nhostsbak = nhosts;
415 	while (nhostsbak > 0) {
416 		--nhostsbak;
417 
418 		/*
419 		 * XXX - using RPC library internal functions.
420 		 */
421 		if ((fd = __rpc_nconf2fd(nconf)) < 0) {
422 			syslog(LOG_ERR, "cannot create socket for %s",
423 			    nconf->nc_netid);
424 			continue;
425 		}
426 
427 		switch (hints.ai_family) {
428 			case AF_INET:
429 				if (inet_pton(AF_INET, hosts[nhostsbak],
430 				    host_addr) == 1) {
431 					hints.ai_flags &= AI_NUMERICHOST;
432 				} else {
433 					/*
434 					 * Skip if we have an AF_INET6 address.
435 					 */
436 					if (inet_pton(AF_INET6, hosts[nhostsbak],
437 					    host_addr) == 1) {
438 						close(fd);
439 						continue;
440 					}
441 				}
442 				break;
443 			case AF_INET6:
444 				if (inet_pton(AF_INET6, hosts[nhostsbak],
445 				    host_addr) == 1) {
446 					hints.ai_flags &= AI_NUMERICHOST;
447 				} else {
448 					/*
449 					 * Skip if we have an AF_INET address.
450 					 */
451 					if (inet_pton(AF_INET, hosts[nhostsbak],
452 					    host_addr) == 1) {
453 						close(fd);
454 						continue;
455 					}
456 				}
457 				break;
458 			default:
459 				break;
460 		}
461 
462 		/*
463 		 * If no hosts were specified, just bind to INADDR_ANY
464 		 */
465 		if (strcmp("*", hosts[nhostsbak]) == 0) {
466 			if (svcport_str == NULL) {
467 				res = malloc(sizeof(struct addrinfo));
468 				if (res == NULL)
469 					out_of_mem();
470 				res->ai_flags = hints.ai_flags;
471 				res->ai_family = hints.ai_family;
472 				res->ai_protocol = hints.ai_protocol;
473 				switch (res->ai_family) {
474 					case AF_INET:
475 						sin = malloc(sizeof(struct sockaddr_in));
476 						if (sin == NULL)
477 							out_of_mem();
478 						sin->sin_family = AF_INET;
479 						sin->sin_port = htons(0);
480 						sin->sin_addr.s_addr = htonl(INADDR_ANY);
481 						res->ai_addr = (struct sockaddr*) sin;
482 						res->ai_addrlen = (socklen_t)
483 						    sizeof(res->ai_addr);
484 						break;
485 					case AF_INET6:
486 						sin6 = malloc(sizeof(struct sockaddr_in6));
487 						if (sin6 == NULL)
488 							out_of_mem();
489 						sin6->sin6_family = AF_INET6;
490 						sin6->sin6_port = htons(0);
491 						sin6->sin6_addr = in6addr_any;
492 						res->ai_addr = (struct sockaddr*) sin6;
493 						res->ai_addrlen = (socklen_t) sizeof(res->ai_addr);
494 						break;
495 					default:
496 						break;
497 				}
498 			} else {
499 				if ((aicode = getaddrinfo(NULL, svcport_str,
500 				    &hints, &res)) != 0) {
501 					syslog(LOG_ERR,
502 					    "cannot get local address for %s: %s",
503 					    nconf->nc_netid,
504 					    gai_strerror(aicode));
505 					continue;
506 				}
507 			}
508 		} else {
509 			if ((aicode = getaddrinfo(hosts[nhostsbak], svcport_str,
510 			    &hints, &res)) != 0) {
511 				syslog(LOG_ERR,
512 				    "cannot get local address for %s: %s",
513 				    nconf->nc_netid, gai_strerror(aicode));
514 				continue;
515 			}
516 		}
517 
518 		r = bindresvport_sa(fd, res->ai_addr);
519 		if (r != 0) {
520 			syslog(LOG_ERR, "bindresvport_sa: %m");
521 			exit(1);
522 		}
523 
524 		if (nconf->nc_semantics != NC_TPI_CLTS)
525 		    listen(fd, SOMAXCONN);
526 
527 		transp = svc_tli_create(fd, nconf, NULL,
528 		    RPC_MAXDATASIZE, RPC_MAXDATASIZE);
529 
530 		if (transp != (SVCXPRT *) NULL) {
531 			if (!svc_reg(transp, NLM_PROG, NLM_SM, nlm_prog_0,
532 			    NULL))
533 				syslog(LOG_ERR,
534 				    "can't register %s NLM_PROG, NLM_SM service",
535 				    nconf->nc_netid);
536 
537 			if (!svc_reg(transp, NLM_PROG, NLM_VERS, nlm_prog_1,
538 			    NULL))
539 				syslog(LOG_ERR,
540 				    "can't register %s NLM_PROG, NLM_VERS service",
541 				    nconf->nc_netid);
542 
543 			if (!svc_reg(transp, NLM_PROG, NLM_VERSX, nlm_prog_3,
544 			    NULL))
545 				syslog(LOG_ERR,
546 				    "can't register %s NLM_PROG, NLM_VERSX service",
547 				    nconf->nc_netid);
548 
549 			if (!svc_reg(transp, NLM_PROG, NLM_VERS4, nlm_prog_4,
550 			    NULL))
551 				syslog(LOG_ERR,
552 				    "can't register %s NLM_PROG, NLM_VERS4 service",
553 				    nconf->nc_netid);
554 
555 		} else
556 			syslog(LOG_WARNING, "can't create %s services",
557 			    nconf->nc_netid);
558 
559 		if (registered == 0) {
560 			registered = 1;
561 			memset(&hints, 0, sizeof hints);
562 			hints.ai_flags = AI_PASSIVE;
563 			hints.ai_family = si.si_af;
564 			hints.ai_socktype = si.si_socktype;
565 			hints.ai_protocol = si.si_proto;
566 
567 			if (svcport_str == NULL) {
568 				svcport_str = malloc(NI_MAXSERV * sizeof(char));
569 				if (svcport_str == NULL)
570 					out_of_mem();
571 
572 				if (getnameinfo(res->ai_addr,
573 				    res->ai_addr->sa_len, NULL, NI_MAXHOST,
574 				    svcport_str, NI_MAXSERV * sizeof(char),
575 				    NI_NUMERICHOST | NI_NUMERICSERV))
576 					errx(1, "Cannot get port number");
577 			}
578 
579 			if((aicode = getaddrinfo(NULL, svcport_str, &hints,
580 			    &res)) != 0) {
581 				syslog(LOG_ERR, "cannot get local address: %s",
582 				    gai_strerror(aicode));
583 				exit(1);
584 			}
585 
586 			servaddr.buf = malloc(res->ai_addrlen);
587 			memcpy(servaddr.buf, res->ai_addr, res->ai_addrlen);
588 			servaddr.len = res->ai_addrlen;
589 
590 			rpcb_set(NLM_PROG, NLM_SM, nconf, &servaddr);
591 			rpcb_set(NLM_PROG, NLM_VERS, nconf, &servaddr);
592 			rpcb_set(NLM_PROG, NLM_VERSX, nconf, &servaddr);
593 			rpcb_set(NLM_PROG, NLM_VERS4, nconf, &servaddr);
594 
595 			xcreated++;
596 			freeaddrinfo(res);
597 		}
598 	} /* end while */
599 }
600 
601 /*
602  * Look up addresses for the kernel to create transports for.
603  */
604 void
605 lookup_addresses(struct netconfig *nconf)
606 {
607 	struct addrinfo hints, *res = NULL;
608 	struct sockaddr_in *sin;
609 	struct sockaddr_in6 *sin6;
610 	struct __rpc_sockinfo si;
611 	struct netbuf servaddr;
612 	SVCXPRT	*transp = NULL;
613 	int aicode;
614 	int nhostsbak;
615 	int r;
616 	int registered = 0;
617 	u_int32_t host_addr[4];  /* IPv4 or IPv6 */
618 	char *uaddr;
619 
620 	if ((nconf->nc_semantics != NC_TPI_CLTS) &&
621 	    (nconf->nc_semantics != NC_TPI_COTS) &&
622 	    (nconf->nc_semantics != NC_TPI_COTS_ORD))
623 		return;	/* not my type */
624 
625 	/*
626 	 * XXX - using RPC library internal functions.
627 	 */
628 	if (!__rpc_nconf2sockinfo(nconf, &si)) {
629 		syslog(LOG_ERR, "cannot get information for %s",
630 		    nconf->nc_netid);
631 		return;
632 	}
633 
634 	/* Get rpc.statd's address on this transport */
635 	memset(&hints, 0, sizeof hints);
636 	hints.ai_flags = AI_PASSIVE;
637 	hints.ai_family = si.si_af;
638 	hints.ai_socktype = si.si_socktype;
639 	hints.ai_protocol = si.si_proto;
640 
641 	/*
642 	 * Bind to specific IPs if asked to
643 	 */
644 	nhostsbak = nhosts;
645 	while (nhostsbak > 0) {
646 		--nhostsbak;
647 
648 		switch (hints.ai_family) {
649 			case AF_INET:
650 				if (inet_pton(AF_INET, hosts[nhostsbak],
651 				    host_addr) == 1) {
652 					hints.ai_flags &= AI_NUMERICHOST;
653 				} else {
654 					/*
655 					 * Skip if we have an AF_INET6 address.
656 					 */
657 					if (inet_pton(AF_INET6, hosts[nhostsbak],
658 					    host_addr) == 1) {
659 						continue;
660 					}
661 				}
662 				break;
663 			case AF_INET6:
664 				if (inet_pton(AF_INET6, hosts[nhostsbak],
665 				    host_addr) == 1) {
666 					hints.ai_flags &= AI_NUMERICHOST;
667 				} else {
668 					/*
669 					 * Skip if we have an AF_INET address.
670 					 */
671 					if (inet_pton(AF_INET, hosts[nhostsbak],
672 					    host_addr) == 1) {
673 						continue;
674 					}
675 				}
676 				break;
677 			default:
678 				break;
679 		}
680 
681 		/*
682 		 * If no hosts were specified, just bind to INADDR_ANY
683 		 */
684 		if (strcmp("*", hosts[nhostsbak]) == 0) {
685 			if (svcport_str == NULL) {
686 				res = malloc(sizeof(struct addrinfo));
687 				if (res == NULL)
688 					out_of_mem();
689 				res->ai_flags = hints.ai_flags;
690 				res->ai_family = hints.ai_family;
691 				res->ai_protocol = hints.ai_protocol;
692 				switch (res->ai_family) {
693 					case AF_INET:
694 						sin = malloc(sizeof(struct sockaddr_in));
695 						if (sin == NULL)
696 							out_of_mem();
697 						sin->sin_family = AF_INET;
698 						sin->sin_port = htons(0);
699 						sin->sin_addr.s_addr = htonl(INADDR_ANY);
700 						res->ai_addr = (struct sockaddr*) sin;
701 						res->ai_addrlen = (socklen_t)
702 						    sizeof(res->ai_addr);
703 						break;
704 					case AF_INET6:
705 						sin6 = malloc(sizeof(struct sockaddr_in6));
706 						if (sin6 == NULL)
707 							out_of_mem();
708 						sin6->sin6_family = AF_INET6;
709 						sin6->sin6_port = htons(0);
710 						sin6->sin6_addr = in6addr_any;
711 						res->ai_addr = (struct sockaddr*) sin6;
712 						res->ai_addrlen = (socklen_t) sizeof(res->ai_addr);
713 						break;
714 					default:
715 						break;
716 				}
717 			} else {
718 				if ((aicode = getaddrinfo(NULL, svcport_str,
719 				    &hints, &res)) != 0) {
720 					syslog(LOG_ERR,
721 					    "cannot get local address for %s: %s",
722 					    nconf->nc_netid,
723 					    gai_strerror(aicode));
724 					continue;
725 				}
726 			}
727 		} else {
728 			if ((aicode = getaddrinfo(hosts[nhostsbak], svcport_str,
729 			    &hints, &res)) != 0) {
730 				syslog(LOG_ERR,
731 				    "cannot get local address for %s: %s",
732 				    nconf->nc_netid, gai_strerror(aicode));
733 				continue;
734 			}
735 		}
736 
737 		servaddr.len = servaddr.maxlen = res->ai_addr->sa_len;
738 		servaddr.buf = res->ai_addr;
739 		uaddr = taddr2uaddr(nconf, &servaddr);
740 
741 		addrs = realloc(addrs, 2 * (naddrs + 1) * sizeof(char *));
742 		if (!addrs)
743 			out_of_mem();
744 		addrs[2 * naddrs] = strdup(nconf->nc_netid);
745 		addrs[2 * naddrs + 1] = uaddr;
746 		naddrs++;
747 	} /* end while */
748 }
749 
750 void
751 sigalarm_handler(void)
752 {
753 
754 	grace_expired = 1;
755 }
756 
757 void
758 usage()
759 {
760 	errx(1, "usage: rpc.lockd [-d <debuglevel>]"
761 	    " [-g <grace period>] [-h <bindip>] [-p <port>]");
762 }
763 
764 /*
765  * init_nsm --
766  *	Reset the NSM state-of-the-world and acquire its state.
767  */
768 void
769 init_nsm(void)
770 {
771 	enum clnt_stat ret;
772 	my_id id;
773 	sm_stat stat;
774 	char name[] = "NFS NLM";
775 	char localhost[] = "localhost";
776 
777 	/*
778 	 * !!!
779 	 * The my_id structure isn't used by the SM_UNMON_ALL call, as far
780 	 * as I know.  Leave it empty for now.
781 	 */
782 	memset(&id, 0, sizeof(id));
783 	id.my_name = name;
784 
785 	/*
786 	 * !!!
787 	 * The statd program must already be registered when lockd runs.
788 	 */
789 	do {
790 		ret = callrpc("localhost", SM_PROG, SM_VERS, SM_UNMON_ALL,
791 		    (xdrproc_t)xdr_my_id, &id, (xdrproc_t)xdr_sm_stat, &stat);
792 		if (ret == RPC_PROGUNAVAIL) {
793 			syslog(LOG_WARNING, "%lu %s", SM_PROG,
794 			    clnt_sperrno(ret));
795 			sleep(2);
796 			continue;
797 		}
798 		break;
799 	} while (0);
800 
801 	if (ret != 0) {
802 		syslog(LOG_ERR, "%lu %s", SM_PROG, clnt_sperrno(ret));
803 		exit(1);
804 	}
805 
806 	nsm_state = stat.state;
807 
808 	/* setup constant data for SM_MON calls */
809 	mon_host.mon_id.my_id.my_name = localhost;
810 	mon_host.mon_id.my_id.my_prog = NLM_PROG;
811 	mon_host.mon_id.my_id.my_vers = NLM_SM;
812 	mon_host.mon_id.my_id.my_proc = NLM_SM_NOTIFY;  /* bsdi addition */
813 }
814 
815 /*
816  * Out of memory, fatal
817  */
818 void out_of_mem()
819 {
820 	syslog(LOG_ERR, "out of memory");
821 	exit(2);
822 }
823