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