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