rpcbind.c revision 121657
124374Speter/*	$NetBSD: rpcbind.c,v 1.3 2002/11/08 00:16:40 fvdl Exp $	*/
224374Speter/*	$FreeBSD: head/usr.sbin/rpcbind/rpcbind.c 121657 2003-10-29 09:31:41Z mbr $ */
350477Speter
424374Speter/*
524374Speter * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
6155359Srwatson * unrestricted use provided that this legend is included on all tape
724374Speter * media and as a part of the software program in whole or part.  Users
868157Sobrien * may copy or modify Sun RPC without charge, but are not authorized
968157Sobrien * to license or distribute it to anyone else except as part of a product or
1024374Speter * program developed by the user.
1124374Speter *
1224374Speter * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
1324374Speter * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
1424374Speter * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
1524374Speter *
1624374Speter * Sun RPC is provided with no support and without any obligation on the
1768157Sobrien * part of Sun Microsystems, Inc. to assist in its use, correction,
1868157Sobrien * modification or enhancement.
1924374Speter *
2024374Speter * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
2124374Speter * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
2224374Speter * OR ANY PART THEREOF.
2324374Speter *
2424374Speter * In no event will Sun Microsystems, Inc. be liable for any lost revenue
2568157Sobrien * or profits or other special, indirect and consequential damages, even if
2668157Sobrien * Sun has been advised of the possibility of such damages.
2724374Speter *
2824374Speter * Sun Microsystems, Inc.
2924374Speter * 2550 Garcia Avenue
3024374Speter * Mountain View, California  94043
3124374Speter */
3224374Speter/*
33 * Copyright (c) 1984 - 1991 by Sun Microsystems, Inc.
34 */
35
36/* #ident	"@(#)rpcbind.c	1.19	94/04/25 SMI" */
37
38#if 0
39#ifndef lint
40static	char sccsid[] = "@(#)rpcbind.c 1.35 89/04/21 Copyr 1984 Sun Micro";
41#endif
42#endif
43
44/*
45 * rpcbind.c
46 * Implements the program, version to address mapping for rpc.
47 *
48 */
49
50#include <sys/types.h>
51#include <sys/stat.h>
52#include <sys/errno.h>
53#include <sys/time.h>
54#include <sys/resource.h>
55#include <sys/wait.h>
56#include <sys/signal.h>
57#include <sys/socket.h>
58#include <sys/un.h>
59#include <rpc/rpc.h>
60#include <rpc/rpc_com.h>
61#ifdef PORTMAP
62#include <netinet/in.h>
63#endif
64#include <arpa/inet.h>
65#include <fcntl.h>
66#include <netdb.h>
67#include <stdio.h>
68#include <netconfig.h>
69#include <stdlib.h>
70#include <unistd.h>
71#include <syslog.h>
72#include <err.h>
73#include <libutil.h>
74#include <pwd.h>
75#include <string.h>
76#include <errno.h>
77#include "rpcbind.h"
78
79/* Global variables */
80int debugging = 0;	/* Tell me what's going on */
81int doabort = 0;	/* When debugging, do an abort on errors */
82rpcblist_ptr list_rbl;	/* A list of version 3/4 rpcbind services */
83
84/* who to suid to if -s is given */
85#define RUN_AS  "daemon"
86
87#define RPCBINDDLOCK "/var/run/rpcbind.lock"
88
89int runasdaemon = 0;
90int insecure = 0;
91int oldstyle_local = 0;
92int verboselog = 0;
93
94char **hosts = NULL;
95int nhosts = 0;
96int on = 1;
97int rpcbindlockfd;
98
99#ifdef WARMSTART
100/* Local Variable */
101static int warmstart = 0;	/* Grab an old copy of registrations. */
102#endif
103
104#ifdef PORTMAP
105struct pmaplist *list_pml;	/* A list of version 2 rpcbind services */
106char *udptrans;		/* Name of UDP transport */
107char *tcptrans;		/* Name of TCP transport */
108char *udp_uaddr;	/* Universal UDP address */
109char *tcp_uaddr;	/* Universal TCP address */
110#endif
111static char servname[] = "rpcbind";
112static char superuser[] = "superuser";
113
114int main __P((int, char *[]));
115
116static int init_transport __P((struct netconfig *));
117static void rbllist_add __P((rpcprog_t, rpcvers_t, struct netconfig *,
118			     struct netbuf *));
119static void terminate __P((int));
120static void parseargs __P((int, char *[]));
121
122int
123main(int argc, char *argv[])
124{
125	struct netconfig *nconf;
126	void *nc_handle;	/* Net config handle */
127	struct rlimit rl;
128	int maxrec = RPC_MAXDATASIZE;
129
130	parseargs(argc, argv);
131
132	/* Check that another rpcbind isn't already running. */
133	if ((rpcbindlockfd = (open(RPCBINDDLOCK,
134	    O_RDONLY|O_CREAT, 0444))) == -1)
135		err(1, "%s", RPCBINDDLOCK);
136
137	if(flock(rpcbindlockfd, LOCK_EX|LOCK_NB) == -1 && errno == EWOULDBLOCK)
138		errx(1, "another rpcbind is already running. Aborting");
139
140	getrlimit(RLIMIT_NOFILE, &rl);
141	if (rl.rlim_cur < 128) {
142		if (rl.rlim_max <= 128)
143			rl.rlim_cur = rl.rlim_max;
144		else
145			rl.rlim_cur = 128;
146		setrlimit(RLIMIT_NOFILE, &rl);
147	}
148	openlog("rpcbind", LOG_CONS, LOG_DAEMON);
149	if (geteuid()) { /* This command allowed only to root */
150		fprintf(stderr, "Sorry. You are not superuser\n");
151		exit(1);
152	}
153	nc_handle = setnetconfig(); 	/* open netconfig file */
154	if (nc_handle == NULL) {
155		syslog(LOG_ERR, "could not read /etc/netconfig");
156		exit(1);
157	}
158#ifdef PORTMAP
159	udptrans = "";
160	tcptrans = "";
161#endif
162
163	nconf = getnetconfigent("local");
164	if (nconf == NULL)
165		nconf = getnetconfigent("unix");
166	if (nconf == NULL) {
167		syslog(LOG_ERR, "%s: can't find local transport\n", argv[0]);
168		exit(1);
169	}
170
171	rpc_control(RPC_SVC_CONNMAXREC_SET, &maxrec);
172
173	init_transport(nconf);
174
175	while ((nconf = getnetconfig(nc_handle))) {
176		if (nconf->nc_flag & NC_VISIBLE)
177			init_transport(nconf);
178	}
179	endnetconfig(nc_handle);
180
181	/* catch the usual termination signals for graceful exit */
182	(void) signal(SIGCHLD, reap);
183	(void) signal(SIGINT, terminate);
184	(void) signal(SIGTERM, terminate);
185	(void) signal(SIGQUIT, terminate);
186	/* ignore others that could get sent */
187	(void) signal(SIGPIPE, SIG_IGN);
188	(void) signal(SIGHUP, SIG_IGN);
189	(void) signal(SIGUSR1, SIG_IGN);
190	(void) signal(SIGUSR2, SIG_IGN);
191#ifdef WARMSTART
192	if (warmstart) {
193		read_warmstart();
194	}
195#endif
196	if (debugging) {
197		printf("rpcbind debugging enabled.");
198		if (doabort) {
199			printf("  Will abort on errors!\n");
200		} else {
201			printf("\n");
202		}
203	} else {
204		if (daemon(0, 0))
205			err(1, "fork failed");
206	}
207
208	if (runasdaemon) {
209		struct passwd *p;
210
211		if((p = getpwnam(RUN_AS)) == NULL) {
212			syslog(LOG_ERR, "cannot get uid of daemon: %m");
213			exit(1);
214		}
215		if (setuid(p->pw_uid) == -1) {
216			syslog(LOG_ERR, "setuid to daemon failed: %m");
217			exit(1);
218		}
219	}
220
221	network_init();
222
223	my_svc_run();
224	syslog(LOG_ERR, "svc_run returned unexpectedly");
225	rpcbind_abort();
226	/* NOTREACHED */
227
228	return 0;
229}
230
231/*
232 * Adds the entry into the rpcbind database.
233 * If PORTMAP, then for UDP and TCP, it adds the entries for version 2 also
234 * Returns 0 if succeeds, else fails
235 */
236static int
237init_transport(struct netconfig *nconf)
238{
239	int fd;
240	struct t_bind taddr;
241	struct addrinfo hints, *res = NULL;
242	struct __rpc_sockinfo si;
243	SVCXPRT	*my_xprt;
244	int status;	/* bound checking ? */
245	int aicode;
246	int addrlen;
247	int nhostsbak;
248	int checkbind;
249	struct sockaddr *sa;
250	u_int32_t host_addr[4];  /* IPv4 or IPv6 */
251	struct sockaddr_un sun;
252	mode_t oldmask;
253
254	if ((nconf->nc_semantics != NC_TPI_CLTS) &&
255		(nconf->nc_semantics != NC_TPI_COTS) &&
256		(nconf->nc_semantics != NC_TPI_COTS_ORD))
257		return (1);	/* not my type */
258#ifdef ND_DEBUG
259	if (debugging) {
260		int i;
261		char **s;
262
263		(void) fprintf(stderr, "%s: %ld lookup routines :\n",
264			nconf->nc_netid, nconf->nc_nlookups);
265		for (i = 0, s = nconf->nc_lookups; i < nconf->nc_nlookups;
266		     i++, s++)
267			fprintf(stderr, "[%d] - %s\n", i, *s);
268	}
269#endif
270
271	/*
272	 * XXX - using RPC library internal functions. For NC_TPI_CLTS
273	 * we call this later, for each socket we like to bind.
274	 */
275	if (nconf->nc_semantics != NC_TPI_CLTS) {
276		if ((fd = __rpc_nconf2fd(nconf)) < 0) {
277			syslog(LOG_ERR, "cannot create socket for %s",
278			    nconf->nc_netid);
279			return (1);
280		}
281	}
282
283	if (!__rpc_nconf2sockinfo(nconf, &si)) {
284		syslog(LOG_ERR, "cannot get information for %s",
285		    nconf->nc_netid);
286		return (1);
287	}
288
289	if ((strcmp(nconf->nc_netid, "local") == 0) ||
290	    (strcmp(nconf->nc_netid, "unix") == 0)) {
291		memset(&sun, 0, sizeof sun);
292		sun.sun_family = AF_LOCAL;
293		unlink(_PATH_RPCBINDSOCK);
294		strcpy(sun.sun_path, _PATH_RPCBINDSOCK);
295		sun.sun_len = SUN_LEN(&sun);
296		addrlen = sizeof (struct sockaddr_un);
297		sa = (struct sockaddr *)&sun;
298	} else {
299		/* Get rpcbind's address on this transport */
300
301		memset(&hints, 0, sizeof hints);
302		hints.ai_flags = AI_PASSIVE;
303		hints.ai_family = si.si_af;
304		hints.ai_socktype = si.si_socktype;
305		hints.ai_protocol = si.si_proto;
306	}
307	if (nconf->nc_semantics == NC_TPI_CLTS) {
308		/*
309		 * If no hosts were specified, just bind to INADDR_ANY.  Otherwise
310		 * make sure 127.0.0.1 is added to the list.
311		 */
312		nhostsbak = nhosts;
313		nhostsbak++;
314		hosts = realloc(hosts, nhostsbak * sizeof(char *));
315		if (nhostsbak == 1)
316			hosts[0] = "*";
317		else {
318			if (hints.ai_family == AF_INET) {
319				hosts[nhostsbak - 1] = "127.0.0.1";
320			} else if (hints.ai_family == AF_INET6) {
321				hosts[nhostsbak - 1] = "::1";
322			} else
323				return 1;
324		}
325
326	       /*
327		* Bind to specific IPs if asked to
328		*/
329		checkbind = 1;
330		while (nhostsbak > 0) {
331			--nhostsbak;
332			/*
333			 * XXX - using RPC library internal functions.
334			 */
335			if ((fd = __rpc_nconf2fd(nconf)) < 0) {
336				syslog(LOG_ERR, "cannot create socket for %s",
337				    nconf->nc_netid);
338				return (1);
339			}
340			switch (hints.ai_family) {
341			case AF_INET:
342				if (inet_pton(AF_INET, hosts[nhostsbak],
343				    host_addr) == 1) {
344					hints.ai_flags &= AI_NUMERICHOST;
345				} else {
346					/*
347					 * Skip if we have an AF_INET6 adress.
348					 */
349					if (inet_pton(AF_INET6,
350					    hosts[nhostsbak], host_addr) == 1)
351						continue;
352				}
353				break;
354			case AF_INET6:
355				if (inet_pton(AF_INET6, hosts[nhostsbak],
356				    host_addr) == 1) {
357					hints.ai_flags &= AI_NUMERICHOST;
358				} else {
359					/*
360					 * Skip if we have an AF_INET adress.
361					 */
362					if (inet_pton(AF_INET, hosts[nhostsbak],
363					    host_addr) == 1)
364						continue;
365				}
366				if (setsockopt(fd, IPPROTO_IPV6,
367                                    IPV6_V6ONLY, &on, sizeof on) < 0) {
368                                        syslog(LOG_ERR,
369					    "can't set v6-only binding for "
370                                            "udp6 socket: %m");
371					continue;
372				}
373				break;
374			default:
375				break;
376			}
377
378			/*
379			 * If no hosts were specified, just bind to INADDR_ANY
380			 */
381			if (strcmp("*", hosts[nhostsbak]) == 0)
382				hosts[nhostsbak] = NULL;
383
384			if ((aicode = getaddrinfo(hosts[nhostsbak],
385			    servname, &hints, &res)) != 0) {
386				syslog(LOG_ERR,
387				    "cannot get local address for %s: %s",
388				    nconf->nc_netid, gai_strerror(aicode));
389				continue;
390			}
391			addrlen = res->ai_addrlen;
392			sa = (struct sockaddr *)res->ai_addr;
393			oldmask = umask(S_IXUSR|S_IXGRP|S_IXOTH);
394			if (bind(fd, sa, addrlen) != 0) {
395				syslog(LOG_ERR, "cannot bind %s on %s: %m",
396					(hosts[nhostsbak] == NULL) ? "*" :
397					hosts[nhostsbak], nconf->nc_netid);
398				if (res != NULL)
399					freeaddrinfo(res);
400				continue;
401			} else
402				checkbind++;
403			(void) umask(oldmask);
404
405			/* Copy the address */
406			taddr.addr.len = taddr.addr.maxlen = addrlen;
407			taddr.addr.buf = malloc(addrlen);
408			if (taddr.addr.buf == NULL) {
409				syslog(LOG_ERR,
410				    "cannot allocate memory for %s address",
411				    nconf->nc_netid);
412				if (res != NULL)
413					freeaddrinfo(res);
414				return 1;
415			}
416			memcpy(taddr.addr.buf, sa, addrlen);
417#ifdef ND_DEBUG
418			if (debugging) {
419				/*
420				 * for debugging print out our universal
421				 * address
422				 */
423				char *uaddr;
424				struct netbuf nb;
425
426				nb.buf = sa;
427				nb.len = nb.maxlen = sa->sa_len;
428				uaddr = taddr2uaddr(nconf, &nb);
429				(void) fprintf(stderr,
430				    "rpcbind : my address is %s\n", uaddr);
431				(void) free(uaddr);
432			}
433#endif
434
435			if (nconf->nc_semantics != NC_TPI_CLTS)
436				listen(fd, SOMAXCONN);
437
438			my_xprt = (SVCXPRT *)svc_tli_create(fd, nconf, &taddr,
439			    RPC_MAXDATASIZE, RPC_MAXDATASIZE);
440			if (my_xprt == (SVCXPRT *)NULL) {
441				syslog(LOG_ERR, "%s: could not create service",
442					nconf->nc_netid);
443				goto error;
444			}
445		}
446		if (!checkbind)
447			return 1;
448	} else {
449		if ((strcmp(nconf->nc_netid, "local") != 0) &&
450		    (strcmp(nconf->nc_netid, "unix") != 0)) {
451			if ((aicode = getaddrinfo(NULL, servname, &hints, &res))
452			    != 0) {
453				syslog(LOG_ERR,
454				    "cannot get local address for %s: %s",
455				    nconf->nc_netid, gai_strerror(aicode));
456				return 1;
457			}
458			addrlen = res->ai_addrlen;
459			sa = (struct sockaddr *)res->ai_addr;
460		}
461		oldmask = umask(S_IXUSR|S_IXGRP|S_IXOTH);
462		if (bind(fd, sa, addrlen) < 0) {
463			syslog(LOG_ERR, "cannot bind %s: %m", nconf->nc_netid);
464			if (res != NULL)
465				freeaddrinfo(res);
466			return 1;
467		}
468		(void) umask(oldmask);
469
470		/* Copy the address */
471		taddr.addr.len = taddr.addr.maxlen = addrlen;
472		taddr.addr.buf = malloc(addrlen);
473		if (taddr.addr.buf == NULL) {
474			syslog(LOG_ERR, "cannot allocate memory for %s address",
475			    nconf->nc_netid);
476			if (res != NULL)
477				freeaddrinfo(res);
478			return 1;
479		}
480		memcpy(taddr.addr.buf, sa, addrlen);
481#ifdef ND_DEBUG
482		if (debugging) {
483			/* for debugging print out our universal address */
484			char *uaddr;
485			struct netbuf nb;
486
487			nb.buf = sa;
488			nb.len = nb.maxlen = sa->sa_len;
489			uaddr = taddr2uaddr(nconf, &nb);
490			(void) fprintf(stderr, "rpcbind : my address is %s\n",
491			    uaddr);
492			(void) free(uaddr);
493		}
494#endif
495
496		if (nconf->nc_semantics != NC_TPI_CLTS)
497			listen(fd, SOMAXCONN);
498
499		my_xprt = (SVCXPRT *)svc_tli_create(fd, nconf, &taddr, RPC_MAXDATASIZE, RPC_MAXDATASIZE);
500		if (my_xprt == (SVCXPRT *)NULL) {
501			syslog(LOG_ERR, "%s: could not create service",
502					nconf->nc_netid);
503			goto error;
504		}
505	}
506
507#ifdef PORTMAP
508	/*
509	 * Register both the versions for tcp/ip, udp/ip and local.
510	 */
511	if ((strcmp(nconf->nc_protofmly, NC_INET) == 0 &&
512		(strcmp(nconf->nc_proto, NC_TCP) == 0 ||
513		strcmp(nconf->nc_proto, NC_UDP) == 0)) ||
514		(strcmp(nconf->nc_netid, "unix") == 0) ||
515		(strcmp(nconf->nc_netid, "local") == 0)) {
516		struct pmaplist *pml;
517
518		if (!svc_register(my_xprt, PMAPPROG, PMAPVERS,
519			pmap_service, 0)) {
520			syslog(LOG_ERR, "could not register on %s",
521					nconf->nc_netid);
522			goto error;
523		}
524		pml = malloc(sizeof (struct pmaplist));
525		if (pml == NULL) {
526			syslog(LOG_ERR, "no memory!");
527			exit(1);
528		}
529		pml->pml_map.pm_prog = PMAPPROG;
530		pml->pml_map.pm_vers = PMAPVERS;
531		pml->pml_map.pm_port = PMAPPORT;
532		if (strcmp(nconf->nc_proto, NC_TCP) == 0) {
533			if (tcptrans[0]) {
534				syslog(LOG_ERR,
535				"cannot have more than one TCP transport");
536				goto error;
537			}
538			tcptrans = strdup(nconf->nc_netid);
539			pml->pml_map.pm_prot = IPPROTO_TCP;
540
541			/* Let's snarf the universal address */
542			/* "h1.h2.h3.h4.p1.p2" */
543			tcp_uaddr = taddr2uaddr(nconf, &taddr.addr);
544		} else if (strcmp(nconf->nc_proto, NC_UDP) == 0) {
545			if (udptrans[0]) {
546				syslog(LOG_ERR,
547				"cannot have more than one UDP transport");
548				goto error;
549			}
550			udptrans = strdup(nconf->nc_netid);
551			pml->pml_map.pm_prot = IPPROTO_UDP;
552
553			/* Let's snarf the universal address */
554			/* "h1.h2.h3.h4.p1.p2" */
555			udp_uaddr = taddr2uaddr(nconf, &taddr.addr);
556		} else if (strcmp(nconf->nc_netid, "local") == 0)
557			pml->pml_map.pm_prot = IPPROTO_ST;
558		else if (strcmp(nconf->nc_netid, "unix") == 0)
559			pml->pml_map.pm_prot = IPPROTO_ST;
560		pml->pml_next = list_pml;
561		list_pml = pml;
562
563		/* Add version 3 information */
564		pml = malloc(sizeof (struct pmaplist));
565		if (pml == NULL) {
566			syslog(LOG_ERR, "no memory!");
567			exit(1);
568		}
569		pml->pml_map = list_pml->pml_map;
570		pml->pml_map.pm_vers = RPCBVERS;
571		pml->pml_next = list_pml;
572		list_pml = pml;
573
574		/* Add version 4 information */
575		pml = malloc (sizeof (struct pmaplist));
576		if (pml == NULL) {
577			syslog(LOG_ERR, "no memory!");
578			exit(1);
579		}
580		pml->pml_map = list_pml->pml_map;
581		pml->pml_map.pm_vers = RPCBVERS4;
582		pml->pml_next = list_pml;
583		list_pml = pml;
584
585		/* Also add version 2 stuff to rpcbind list */
586		rbllist_add(PMAPPROG, PMAPVERS, nconf, &taddr.addr);
587	}
588#endif
589
590	/* version 3 registration */
591	if (!svc_reg(my_xprt, RPCBPROG, RPCBVERS, rpcb_service_3, NULL)) {
592		syslog(LOG_ERR, "could not register %s version 3",
593				nconf->nc_netid);
594		goto error;
595	}
596	rbllist_add(RPCBPROG, RPCBVERS, nconf, &taddr.addr);
597
598	/* version 4 registration */
599	if (!svc_reg(my_xprt, RPCBPROG, RPCBVERS4, rpcb_service_4, NULL)) {
600		syslog(LOG_ERR, "could not register %s version 4",
601				nconf->nc_netid);
602		goto error;
603	}
604	rbllist_add(RPCBPROG, RPCBVERS4, nconf, &taddr.addr);
605
606	/* decide if bound checking works for this transport */
607	status = add_bndlist(nconf, &taddr.addr);
608#ifdef BIND_DEBUG
609	if (debugging) {
610		if (status < 0) {
611			fprintf(stderr, "Error in finding bind status for %s\n",
612				nconf->nc_netid);
613		} else if (status == 0) {
614			fprintf(stderr, "check binding for %s\n",
615				nconf->nc_netid);
616		} else if (status > 0) {
617			fprintf(stderr, "No check binding for %s\n",
618				nconf->nc_netid);
619		}
620	}
621#endif
622	/*
623	 * rmtcall only supported on CLTS transports for now.
624	 */
625	if (nconf->nc_semantics == NC_TPI_CLTS) {
626		status = create_rmtcall_fd(nconf);
627
628#ifdef BIND_DEBUG
629		if (debugging) {
630			if (status < 0) {
631				fprintf(stderr,
632				    "Could not create rmtcall fd for %s\n",
633					nconf->nc_netid);
634			} else {
635				fprintf(stderr, "rmtcall fd for %s is %d\n",
636					nconf->nc_netid, status);
637			}
638		}
639#endif
640	}
641	return (0);
642error:
643	close(fd);
644	return (1);
645}
646
647static void
648rbllist_add(rpcprog_t prog, rpcvers_t vers, struct netconfig *nconf,
649	    struct netbuf *addr)
650{
651	rpcblist_ptr rbl;
652
653	rbl = malloc(sizeof (rpcblist));
654	if (rbl == NULL) {
655		syslog(LOG_ERR, "no memory!");
656		exit(1);
657	}
658
659	rbl->rpcb_map.r_prog = prog;
660	rbl->rpcb_map.r_vers = vers;
661	rbl->rpcb_map.r_netid = strdup(nconf->nc_netid);
662	rbl->rpcb_map.r_addr = taddr2uaddr(nconf, addr);
663	rbl->rpcb_map.r_owner = strdup(superuser);
664	rbl->rpcb_next = list_rbl;	/* Attach to global list */
665	list_rbl = rbl;
666}
667
668/*
669 * Catch the signal and die
670 */
671static void
672terminate(int dummy __unused)
673{
674	close(rpcbindlockfd);
675#ifdef WARMSTART
676	syslog(LOG_ERR,
677		"rpcbind terminating on signal. Restart with \"rpcbind -w\"");
678	write_warmstart();	/* Dump yourself */
679#endif
680	exit(2);
681}
682
683void
684rpcbind_abort()
685{
686#ifdef WARMSTART
687	write_warmstart();	/* Dump yourself */
688#endif
689	abort();
690}
691
692/* get command line options */
693static void
694parseargs(int argc, char *argv[])
695{
696	int c;
697
698	while ((c = getopt(argc, argv, "dwah:ilLs")) != -1) {
699		switch (c) {
700		case 'a':
701			doabort = 1;	/* when debugging, do an abort on */
702			break;		/* errors; for rpcbind developers */
703					/* only! */
704		case 'd':
705			debugging = 1;
706			break;
707		case 'h':
708			++nhosts;
709			hosts = realloc(hosts, nhosts * sizeof(char *));
710			if (hosts == NULL)
711				errx(1, "Out of memory");
712			hosts[nhosts - 1] = strdup(optarg);
713			if (hosts[nhosts - 1] == NULL)
714				errx(1, "Out of memory");
715			break;
716		case 'i':
717			insecure = 1;
718			break;
719		case 'L':
720			oldstyle_local = 1;
721			break;
722		case 'l':
723			verboselog = 1;
724			break;
725		case 's':
726			runasdaemon = 1;
727			break;
728#ifdef WARMSTART
729		case 'w':
730			warmstart = 1;
731			break;
732#endif
733		default:	/* error */
734			fprintf(stderr,	"usage: rpcbind [-Idwils]\n");
735			exit (1);
736		}
737	}
738	if (doabort && !debugging) {
739	    fprintf(stderr,
740		"-a (abort) specified without -d (debugging) -- ignored.\n");
741	    doabort = 0;
742	}
743}
744
745void
746reap(int dummy __unused)
747{
748	int save_errno = errno;
749
750	while (wait3(NULL, WNOHANG, NULL) > 0)
751		;
752	errno = save_errno;
753}
754
755void
756toggle_verboselog(int dummy __unused)
757{
758	verboselog = !verboselog;
759}
760