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