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