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