xref: /freebsd/usr.sbin/rpcbind/rpcbind.c (revision 8a0a413e)
1 /*	$NetBSD: rpcbind.c,v 1.3 2002/11/08 00:16:40 fvdl Exp $	*/
2 /*	$FreeBSD$ */
3 
4 /*-
5  * SPDX-License-Identifier: BSD-3-Clause
6  *
7  * Copyright (c) 2009, Sun Microsystems, Inc.
8  * All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions are met:
12  * - Redistributions of source code must retain the above copyright notice,
13  *   this list of conditions and the following disclaimer.
14  * - Redistributions in binary form must reproduce the above copyright notice,
15  *   this list of conditions and the following disclaimer in the documentation
16  *   and/or other materials provided with the distribution.
17  * - Neither the name of Sun Microsystems, Inc. nor the names of its
18  *   contributors may be used to endorse or promote products derived
19  *   from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
25  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31  * POSSIBILITY OF SUCH DAMAGE.
32  */
33 /*
34  * Copyright (c) 1984 - 1991 by Sun Microsystems, Inc.
35  */
36 
37 /* #ident	"@(#)rpcbind.c	1.19	94/04/25 SMI" */
38 
39 #if 0
40 #ifndef lint
41 static	char sccsid[] = "@(#)rpcbind.c 1.35 89/04/21 Copyr 1984 Sun Micro";
42 #endif
43 #endif
44 
45 /*
46  * rpcbind.c
47  * Implements the program, version to address mapping for rpc.
48  *
49  */
50 
51 #include <sys/types.h>
52 #include <sys/stat.h>
53 #include <sys/errno.h>
54 #include <sys/time.h>
55 #include <sys/resource.h>
56 #include <sys/wait.h>
57 #include <sys/signal.h>
58 #include <sys/socket.h>
59 #include <sys/un.h>
60 #include <rpc/rpc.h>
61 #include <rpc/rpc_com.h>
62 #ifdef PORTMAP
63 #include <netinet/in.h>
64 #endif
65 #include <arpa/inet.h>
66 #include <fcntl.h>
67 #include <netdb.h>
68 #include <stdio.h>
69 #include <netconfig.h>
70 #include <stdlib.h>
71 #include <unistd.h>
72 #include <syslog.h>
73 #include <err.h>
74 #include <libutil.h>
75 #include <pwd.h>
76 #include <string.h>
77 #include <errno.h>
78 #include "rpcbind.h"
79 
80 /* Global variables */
81 int debugging = 0;	/* Tell me what's going on */
82 int doabort = 0;	/* When debugging, do an abort on errors */
83 rpcblist_ptr list_rbl;	/* A list of version 3/4 rpcbind services */
84 
85 /* who to suid to if -s is given */
86 #define RUN_AS  "daemon"
87 
88 #define RPCBINDDLOCK "/var/run/rpcbind.lock"
89 
90 static int runasdaemon = 0;
91 int insecure = 0;
92 int oldstyle_local = 0;
93 #ifdef LIBWRAP
94 int libwrap = 0;
95 #endif
96 int verboselog = 0;
97 
98 static char **hosts = NULL;
99 static struct sockaddr **bound_sa;
100 static int ipv6_only = 0;
101 static int nhosts = 0;
102 static int on = 1;
103 static int rpcbindlockfd;
104 
105 #ifdef WARMSTART
106 /* Local Variable */
107 static int warmstart = 0;	/* Grab an old copy of registrations. */
108 #endif
109 
110 #ifdef PORTMAP
111 struct pmaplist *list_pml;	/* A list of version 2 rpcbind services */
112 char *udptrans;		/* Name of UDP transport */
113 char *tcptrans;		/* Name of TCP transport */
114 char *udp_uaddr;	/* Universal UDP address */
115 char *tcp_uaddr;	/* Universal TCP address */
116 #endif
117 static char servname[] = "rpcbind";
118 static char superuser[] = "superuser";
119 
120 int main(int, char *[]);
121 
122 static int init_transport(struct netconfig *);
123 static void rbllist_add(rpcprog_t, rpcvers_t, struct netconfig *,
124 			     struct netbuf *);
125 static void terminate(int);
126 static void parseargs(int, char *[]);
127 static void update_bound_sa(void);
128 
129 int
130 main(int argc, char *argv[])
131 {
132 	struct netconfig *nconf;
133 	void *nc_handle;	/* Net config handle */
134 	struct rlimit rl;
135 	int maxrec = RPC_MAXDATASIZE;
136 
137 	parseargs(argc, argv);
138 
139 	update_bound_sa();
140 
141 	/* Check that another rpcbind isn't already running. */
142 	if ((rpcbindlockfd = (open(RPCBINDDLOCK,
143 	    O_RDONLY|O_CREAT, 0444))) == -1)
144 		err(1, "%s", RPCBINDDLOCK);
145 
146 	if(flock(rpcbindlockfd, LOCK_EX|LOCK_NB) == -1 && errno == EWOULDBLOCK)
147 		errx(1, "another rpcbind is already running. Aborting");
148 
149 	getrlimit(RLIMIT_NOFILE, &rl);
150 	if (rl.rlim_cur < 128) {
151 		if (rl.rlim_max <= 128)
152 			rl.rlim_cur = rl.rlim_max;
153 		else
154 			rl.rlim_cur = 128;
155 		setrlimit(RLIMIT_NOFILE, &rl);
156 	}
157 	openlog("rpcbind", LOG_CONS, LOG_DAEMON);
158 	if (geteuid()) { /* This command allowed only to root */
159 		fprintf(stderr, "Sorry. You are not superuser\n");
160 		exit(1);
161 	}
162 	nc_handle = setnetconfig(); 	/* open netconfig file */
163 	if (nc_handle == NULL) {
164 		syslog(LOG_ERR, "could not read /etc/netconfig");
165 		exit(1);
166 	}
167 #ifdef PORTMAP
168 	udptrans = "";
169 	tcptrans = "";
170 #endif
171 
172 	nconf = getnetconfigent("local");
173 	if (nconf == NULL)
174 		nconf = getnetconfigent("unix");
175 	if (nconf == NULL) {
176 		syslog(LOG_ERR, "%s: can't find local transport\n", argv[0]);
177 		exit(1);
178 	}
179 
180 	rpc_control(RPC_SVC_CONNMAXREC_SET, &maxrec);
181 
182 	init_transport(nconf);
183 
184 	while ((nconf = getnetconfig(nc_handle))) {
185 	    if (nconf->nc_flag & NC_VISIBLE) {
186 	    	if (ipv6_only == 1 && strcmp(nconf->nc_protofmly,
187 		    "inet") == 0) {
188 		    /* DO NOTHING */
189 		} else
190 		    init_transport(nconf);
191 	    }
192 	}
193 	endnetconfig(nc_handle);
194 
195 	/* catch the usual termination signals for graceful exit */
196 	(void) signal(SIGCHLD, reap);
197 	(void) signal(SIGINT, terminate);
198 	(void) signal(SIGTERM, terminate);
199 	(void) signal(SIGQUIT, terminate);
200 	/* ignore others that could get sent */
201 	(void) signal(SIGPIPE, SIG_IGN);
202 	(void) signal(SIGHUP, SIG_IGN);
203 	(void) signal(SIGUSR1, SIG_IGN);
204 	(void) signal(SIGUSR2, SIG_IGN);
205 #ifdef WARMSTART
206 	if (warmstart) {
207 		read_warmstart();
208 	}
209 #endif
210 	if (debugging) {
211 		printf("rpcbind debugging enabled.");
212 		if (doabort) {
213 			printf("  Will abort on errors!\n");
214 		} else {
215 			printf("\n");
216 		}
217 	} else {
218 		if (daemon(0, 0))
219 			err(1, "fork failed");
220 	}
221 
222 	if (runasdaemon) {
223 		struct passwd *p;
224 
225 		if((p = getpwnam(RUN_AS)) == NULL) {
226 			syslog(LOG_ERR, "cannot get uid of daemon: %m");
227 			exit(1);
228 		}
229 		if (setuid(p->pw_uid) == -1) {
230 			syslog(LOG_ERR, "setuid to daemon failed: %m");
231 			exit(1);
232 		}
233 	}
234 
235 	network_init();
236 
237 	my_svc_run();
238 	syslog(LOG_ERR, "svc_run returned unexpectedly");
239 	rpcbind_abort();
240 	/* NOTREACHED */
241 
242 	return 0;
243 }
244 
245 /*
246  * Adds the entry into the rpcbind database.
247  * If PORTMAP, then for UDP and TCP, it adds the entries for version 2 also
248  * Returns 0 if succeeds, else fails
249  */
250 static int
251 init_transport(struct netconfig *nconf)
252 {
253 	int fd;
254 	struct t_bind taddr;
255 	struct addrinfo hints, *res = NULL;
256 	struct __rpc_sockinfo si;
257 	SVCXPRT	*my_xprt;
258 	int status;	/* bound checking ? */
259 	int aicode;
260 	int addrlen;
261 	int nhostsbak;
262 	int bound;
263 	struct sockaddr *sa;
264 	u_int32_t host_addr[4];  /* IPv4 or IPv6 */
265 	struct sockaddr_un sun;
266 	mode_t oldmask;
267 
268 	if ((nconf->nc_semantics != NC_TPI_CLTS) &&
269 	    (nconf->nc_semantics != NC_TPI_COTS) &&
270 	    (nconf->nc_semantics != NC_TPI_COTS_ORD))
271 	    return (1);	/* not my type */
272 #ifdef ND_DEBUG
273 	if (debugging) {
274 	    int i;
275 	    char **s;
276 
277 	    (void)fprintf(stderr, "%s: %ld lookup routines :\n",
278 		nconf->nc_netid, nconf->nc_nlookups);
279 	    for (i = 0, s = nconf->nc_lookups; i < nconf->nc_nlookups;
280 		i++, s++)
281 		fprintf(stderr, "[%d] - %s\n", i, *s);
282 	}
283 #endif
284 
285 	/*
286 	 * XXX - using RPC library internal functions.
287 	 */
288 	if ((strcmp(nconf->nc_netid, "local") == 0) ||
289 	    (strcmp(nconf->nc_netid, "unix") == 0)) {
290 	    /*
291 	     * For other transports we call this later, for each socket we
292 	     * like to bind.
293 	     */
294 	    if ((fd = __rpc_nconf2fd(nconf)) < 0) {
295 		int non_fatal = 0;
296 		if (errno == EAFNOSUPPORT)
297 		    non_fatal = 1;
298 		syslog(non_fatal?LOG_DEBUG:LOG_ERR, "cannot create socket for %s",
299 		    nconf->nc_netid);
300 		return (1);
301 	    }
302 	}
303 
304 	if (!__rpc_nconf2sockinfo(nconf, &si)) {
305 	    syslog(LOG_ERR, "cannot get information for %s",
306 		nconf->nc_netid);
307 	    return (1);
308 	}
309 
310 	if ((strcmp(nconf->nc_netid, "local") == 0) ||
311 	    (strcmp(nconf->nc_netid, "unix") == 0)) {
312 	    memset(&sun, 0, sizeof sun);
313 	    sun.sun_family = AF_LOCAL;
314 	    unlink(_PATH_RPCBINDSOCK);
315 	    strcpy(sun.sun_path, _PATH_RPCBINDSOCK);
316 	    sun.sun_len = SUN_LEN(&sun);
317 	    addrlen = sizeof (struct sockaddr_un);
318 	    sa = (struct sockaddr *)&sun;
319 	} else {
320 	    /* Get rpcbind's address on this transport */
321 
322 	    memset(&hints, 0, sizeof hints);
323 	    hints.ai_flags = AI_PASSIVE;
324 	    hints.ai_family = si.si_af;
325 	    hints.ai_socktype = si.si_socktype;
326 	    hints.ai_protocol = si.si_proto;
327 	}
328 
329 	if ((strcmp(nconf->nc_netid, "local") != 0) &&
330 	    (strcmp(nconf->nc_netid, "unix") != 0)) {
331 	    /*
332 	     * If no hosts were specified, just bind to INADDR_ANY.
333 	     * Otherwise  make sure 127.0.0.1 is added to the list.
334 	     */
335 	    nhostsbak = nhosts + 1;
336 	    hosts = realloc(hosts, nhostsbak * sizeof(char *));
337 	    if (nhostsbak == 1)
338 	        hosts[0] = "*";
339 	    else {
340 		if (hints.ai_family == AF_INET) {
341 		    hosts[nhostsbak - 1] = "127.0.0.1";
342 		} else if (hints.ai_family == AF_INET6) {
343 		    hosts[nhostsbak - 1] = "::1";
344 		} else
345 		    return 1;
346 	    }
347 
348 	    /*
349 	     * Bind to specific IPs if asked to
350 	     */
351 	    bound = 0;
352 	    while (nhostsbak > 0) {
353 		--nhostsbak;
354 		/*
355 		 * XXX - using RPC library internal functions.
356 		 */
357 		if ((fd = __rpc_nconf2fd(nconf)) < 0) {
358 		    int non_fatal = 0;
359 		    if (errno == EAFNOSUPPORT &&
360 			nconf->nc_semantics != NC_TPI_CLTS)
361 			non_fatal = 1;
362 		    syslog(non_fatal ? LOG_DEBUG : LOG_ERR,
363 			"cannot create socket for %s", nconf->nc_netid);
364 		    return (1);
365 		}
366 		switch (hints.ai_family) {
367 		case AF_INET:
368 		    if (inet_pton(AF_INET, hosts[nhostsbak],
369 			host_addr) == 1) {
370 			hints.ai_flags &= AI_NUMERICHOST;
371 		    } else {
372 			/*
373 			 * Skip if we have an AF_INET6 address.
374 			 */
375 			if (inet_pton(AF_INET6,
376 			    hosts[nhostsbak], host_addr) == 1) {
377 			    close(fd);
378 			    continue;
379 			}
380 		    }
381 		    break;
382 		case AF_INET6:
383 		    if (inet_pton(AF_INET6, hosts[nhostsbak],
384 			host_addr) == 1) {
385 			hints.ai_flags &= AI_NUMERICHOST;
386 		    } else {
387 			/*
388 			 * Skip if we have an AF_INET address.
389 			 */
390 			if (inet_pton(AF_INET, hosts[nhostsbak],
391 			    host_addr) == 1) {
392 				close(fd);
393 				continue;
394 			}
395 		    }
396 		    if (setsockopt(fd, IPPROTO_IPV6,
397 			IPV6_V6ONLY, &on, sizeof on) < 0) {
398 			syslog(LOG_ERR,
399 			    "can't set v6-only binding for "
400 			    "ipv6 socket: %m");
401 			continue;
402 		    }
403 		    break;
404 		default:
405 		    break;
406 		}
407 
408 		/*
409 		 * If no hosts were specified, just bind to INADDR_ANY
410 		 */
411 		if (strcmp("*", hosts[nhostsbak]) == 0)
412 		    hosts[nhostsbak] = NULL;
413 		if ((strcmp(nconf->nc_netid, "local") != 0) &&
414 		    (strcmp(nconf->nc_netid, "unix") != 0)) {
415 		    if ((aicode = getaddrinfo(hosts[nhostsbak],
416 			servname, &hints, &res)) != 0) {
417 			syslog(LOG_ERR,
418 			    "cannot get local address for %s: %s",
419 			    nconf->nc_netid, gai_strerror(aicode));
420 			continue;
421 		    }
422 		    addrlen = res->ai_addrlen;
423 		    sa = (struct sockaddr *)res->ai_addr;
424 		}
425 		oldmask = umask(S_IXUSR|S_IXGRP|S_IXOTH);
426 		if (bind(fd, sa, addrlen) != 0) {
427 		    syslog(LOG_ERR, "cannot bind %s on %s: %m",
428 			(hosts[nhostsbak] == NULL) ? "*" :
429 			    hosts[nhostsbak], nconf->nc_netid);
430 		    if (res != NULL)
431 			freeaddrinfo(res);
432 		    continue;
433 		} else
434 		    bound = 1;
435 		(void)umask(oldmask);
436 
437 		/* Copy the address */
438 		taddr.addr.len = taddr.addr.maxlen = addrlen;
439 		taddr.addr.buf = malloc(addrlen);
440 		if (taddr.addr.buf == NULL) {
441 		    syslog(LOG_ERR,
442 			"cannot allocate memory for %s address",
443 			nconf->nc_netid);
444 		    if (res != NULL)
445 			freeaddrinfo(res);
446 		    return 1;
447 		}
448 		memcpy(taddr.addr.buf, sa, addrlen);
449 #ifdef ND_DEBUG
450 		if (debugging) {
451 		    /*
452 		     * for debugging print out our universal
453 		     * address
454 		     */
455 		    char *uaddr;
456 		    struct netbuf nb;
457 
458 		    nb.buf = sa;
459 		    nb.len = nb.maxlen = sa->sa_len;
460 		    uaddr = taddr2uaddr(nconf, &nb);
461 		    (void)fprintf(stderr,
462 			"rpcbind : my address is %s\n", uaddr);
463 		    (void)free(uaddr);
464 		}
465 #endif
466 
467 		if (nconf->nc_semantics != NC_TPI_CLTS)
468 		    listen(fd, SOMAXCONN);
469 
470 		my_xprt = (SVCXPRT *)svc_tli_create(fd, nconf, &taddr,
471 		    RPC_MAXDATASIZE, RPC_MAXDATASIZE);
472 		if (my_xprt == (SVCXPRT *)NULL) {
473 		    syslog(LOG_ERR, "%s: could not create service",
474 			nconf->nc_netid);
475 		    goto error;
476 		}
477 	    }
478 	    if (!bound)
479 		return 1;
480 	} else {
481 	    oldmask = umask(S_IXUSR|S_IXGRP|S_IXOTH);
482 	    if (bind(fd, sa, addrlen) < 0) {
483 		syslog(LOG_ERR, "cannot bind %s: %m", nconf->nc_netid);
484 		if (res != NULL)
485 		    freeaddrinfo(res);
486 		return 1;
487 	    }
488 	    (void) umask(oldmask);
489 
490 	    /* Copy the address */
491 	    taddr.addr.len = taddr.addr.maxlen = addrlen;
492 	    taddr.addr.buf = malloc(addrlen);
493 	    if (taddr.addr.buf == NULL) {
494 		syslog(LOG_ERR, "cannot allocate memory for %s address",
495 		    nconf->nc_netid);
496 		if (res != NULL)
497 		    freeaddrinfo(res);
498 		return 1;
499 	    }
500 	    memcpy(taddr.addr.buf, sa, addrlen);
501 #ifdef ND_DEBUG
502 	    if (debugging) {
503 		/* for debugging print out our universal address */
504 		char *uaddr;
505 		struct netbuf nb;
506 
507 		nb.buf = sa;
508 		nb.len = nb.maxlen = sa->sa_len;
509 		uaddr = taddr2uaddr(nconf, &nb);
510 		(void) fprintf(stderr, "rpcbind : my address is %s\n",
511 		    uaddr);
512 		(void) free(uaddr);
513 	    }
514 #endif
515 
516 	    if (nconf->nc_semantics != NC_TPI_CLTS)
517 		listen(fd, SOMAXCONN);
518 
519 	    my_xprt = (SVCXPRT *)svc_tli_create(fd, nconf, &taddr,
520 		RPC_MAXDATASIZE, RPC_MAXDATASIZE);
521 	    if (my_xprt == (SVCXPRT *)NULL) {
522 		syslog(LOG_ERR, "%s: could not create service",
523 		    nconf->nc_netid);
524 		goto error;
525 	    }
526 	}
527 
528 #ifdef PORTMAP
529 	/*
530 	 * Register both the versions for tcp/ip, udp/ip and local.
531 	 */
532 	if ((strcmp(nconf->nc_protofmly, NC_INET) == 0 &&
533 		(strcmp(nconf->nc_proto, NC_TCP) == 0 ||
534 		strcmp(nconf->nc_proto, NC_UDP) == 0)) ||
535 		(strcmp(nconf->nc_netid, "unix") == 0) ||
536 		(strcmp(nconf->nc_netid, "local") == 0)) {
537 		struct pmaplist *pml;
538 
539 		if (!svc_register(my_xprt, PMAPPROG, PMAPVERS,
540 			pmap_service, 0)) {
541 			syslog(LOG_ERR, "could not register on %s",
542 					nconf->nc_netid);
543 			goto error;
544 		}
545 		pml = malloc(sizeof (struct pmaplist));
546 		if (pml == NULL) {
547 			syslog(LOG_ERR, "no memory!");
548 			exit(1);
549 		}
550 		pml->pml_map.pm_prog = PMAPPROG;
551 		pml->pml_map.pm_vers = PMAPVERS;
552 		pml->pml_map.pm_port = PMAPPORT;
553 		if (strcmp(nconf->nc_proto, NC_TCP) == 0) {
554 			if (tcptrans[0]) {
555 				syslog(LOG_ERR,
556 				"cannot have more than one TCP transport");
557 				goto error;
558 			}
559 			tcptrans = strdup(nconf->nc_netid);
560 			pml->pml_map.pm_prot = IPPROTO_TCP;
561 
562 			/* Let's snarf the universal address */
563 			/* "h1.h2.h3.h4.p1.p2" */
564 			tcp_uaddr = taddr2uaddr(nconf, &taddr.addr);
565 		} else if (strcmp(nconf->nc_proto, NC_UDP) == 0) {
566 			if (udptrans[0]) {
567 				syslog(LOG_ERR,
568 				"cannot have more than one UDP transport");
569 				goto error;
570 			}
571 			udptrans = strdup(nconf->nc_netid);
572 			pml->pml_map.pm_prot = IPPROTO_UDP;
573 
574 			/* Let's snarf the universal address */
575 			/* "h1.h2.h3.h4.p1.p2" */
576 			udp_uaddr = taddr2uaddr(nconf, &taddr.addr);
577 		} else if (strcmp(nconf->nc_netid, "local") == 0)
578 			pml->pml_map.pm_prot = IPPROTO_ST;
579 		else if (strcmp(nconf->nc_netid, "unix") == 0)
580 			pml->pml_map.pm_prot = IPPROTO_ST;
581 		pml->pml_next = list_pml;
582 		list_pml = pml;
583 
584 		/* Add version 3 information */
585 		pml = malloc(sizeof (struct pmaplist));
586 		if (pml == NULL) {
587 			syslog(LOG_ERR, "no memory!");
588 			exit(1);
589 		}
590 		pml->pml_map = list_pml->pml_map;
591 		pml->pml_map.pm_vers = RPCBVERS;
592 		pml->pml_next = list_pml;
593 		list_pml = pml;
594 
595 		/* Add version 4 information */
596 		pml = malloc (sizeof (struct pmaplist));
597 		if (pml == NULL) {
598 			syslog(LOG_ERR, "no memory!");
599 			exit(1);
600 		}
601 		pml->pml_map = list_pml->pml_map;
602 		pml->pml_map.pm_vers = RPCBVERS4;
603 		pml->pml_next = list_pml;
604 		list_pml = pml;
605 
606 		/* Also add version 2 stuff to rpcbind list */
607 		rbllist_add(PMAPPROG, PMAPVERS, nconf, &taddr.addr);
608 	}
609 #endif
610 
611 	/* version 3 registration */
612 	if (!svc_reg(my_xprt, RPCBPROG, RPCBVERS, rpcb_service_3, NULL)) {
613 		syslog(LOG_ERR, "could not register %s version 3",
614 				nconf->nc_netid);
615 		goto error;
616 	}
617 	rbllist_add(RPCBPROG, RPCBVERS, nconf, &taddr.addr);
618 
619 	/* version 4 registration */
620 	if (!svc_reg(my_xprt, RPCBPROG, RPCBVERS4, rpcb_service_4, NULL)) {
621 		syslog(LOG_ERR, "could not register %s version 4",
622 				nconf->nc_netid);
623 		goto error;
624 	}
625 	rbllist_add(RPCBPROG, RPCBVERS4, nconf, &taddr.addr);
626 
627 	/* decide if bound checking works for this transport */
628 	status = add_bndlist(nconf, &taddr.addr);
629 #ifdef BIND_DEBUG
630 	if (debugging) {
631 		if (status < 0) {
632 			fprintf(stderr, "Error in finding bind status for %s\n",
633 				nconf->nc_netid);
634 		} else if (status == 0) {
635 			fprintf(stderr, "check binding for %s\n",
636 				nconf->nc_netid);
637 		} else if (status > 0) {
638 			fprintf(stderr, "No check binding for %s\n",
639 				nconf->nc_netid);
640 		}
641 	}
642 #endif
643 	/*
644 	 * rmtcall only supported on CLTS transports for now.
645 	 */
646 	if (nconf->nc_semantics == NC_TPI_CLTS) {
647 		status = create_rmtcall_fd(nconf);
648 
649 #ifdef BIND_DEBUG
650 		if (debugging) {
651 			if (status < 0) {
652 				fprintf(stderr,
653 				    "Could not create rmtcall fd for %s\n",
654 					nconf->nc_netid);
655 			} else {
656 				fprintf(stderr, "rmtcall fd for %s is %d\n",
657 					nconf->nc_netid, status);
658 			}
659 		}
660 #endif
661 	}
662 	return (0);
663 error:
664 	close(fd);
665 	return (1);
666 }
667 
668 /*
669  * Create the list of addresses that we're bound to.  Normally, this
670  * list is empty because we're listening on the wildcard address
671  * (nhost == 0).  If -h is specified on the command line, then
672  * bound_sa will have a list of the addresses that the program binds
673  * to specifically.  This function takes that list and converts them to
674  * struct sockaddr * and stores them in bound_sa.
675  */
676 static void
677 update_bound_sa(void)
678 {
679 	struct addrinfo hints, *res = NULL;
680 	int i;
681 
682 	if (nhosts == 0)
683 		return;
684 	bound_sa = malloc(sizeof(*bound_sa) * nhosts);
685 	memset(&hints, 0, sizeof(hints));
686 	hints.ai_family = PF_UNSPEC;
687 	for (i = 0; i < nhosts; i++)  {
688 		if (getaddrinfo(hosts[i], NULL, &hints, &res) != 0)
689 			continue;
690 		bound_sa[i] = malloc(res->ai_addrlen);
691 		memcpy(bound_sa[i], res->ai_addr, res->ai_addrlen);
692 	}
693 }
694 
695 /*
696  * Match the sa against the list of addresses we've bound to.  If
697  * we've not specifically bound to anything, we match everything.
698  * Otherwise, if the IPv4 or IPv6 address matches one of the addresses
699  * in bound_sa, we return true.  If not, we return false.
700  */
701 int
702 listen_addr(const struct sockaddr *sa)
703 {
704 	int i;
705 
706 	/*
707 	 * If nhosts == 0, then there were no -h options on the
708 	 * command line, so all addresses are addresses we're
709 	 * listening to.
710 	 */
711 	if (nhosts == 0)
712 		return 1;
713 	for (i = 0; i < nhosts; i++) {
714 		if (bound_sa[i] == NULL ||
715 		    sa->sa_family != bound_sa[i]->sa_family)
716 			continue;
717 		switch (sa->sa_family) {
718 		case AF_INET:
719 		  	if (memcmp(&SA2SINADDR(sa), &SA2SINADDR(bound_sa[i]),
720 			    sizeof(struct in_addr)) == 0)
721 				return (1);
722 			break;
723 #ifdef INET6
724 		case AF_INET6:
725 		  	if (memcmp(&SA2SIN6ADDR(sa), &SA2SIN6ADDR(bound_sa[i]),
726 			    sizeof(struct in6_addr)) == 0)
727 				return (1);
728 			break;
729 #endif
730 		default:
731 			break;
732 		}
733 	}
734 	return (0);
735 }
736 
737 static void
738 rbllist_add(rpcprog_t prog, rpcvers_t vers, struct netconfig *nconf,
739 	    struct netbuf *addr)
740 {
741 	rpcblist_ptr rbl;
742 
743 	rbl = malloc(sizeof (rpcblist));
744 	if (rbl == NULL) {
745 		syslog(LOG_ERR, "no memory!");
746 		exit(1);
747 	}
748 
749 	rbl->rpcb_map.r_prog = prog;
750 	rbl->rpcb_map.r_vers = vers;
751 	rbl->rpcb_map.r_netid = strdup(nconf->nc_netid);
752 	rbl->rpcb_map.r_addr = taddr2uaddr(nconf, addr);
753 	rbl->rpcb_map.r_owner = strdup(superuser);
754 	rbl->rpcb_next = list_rbl;	/* Attach to global list */
755 	list_rbl = rbl;
756 }
757 
758 /*
759  * Catch the signal and die
760  */
761 static void
762 terminate(int signum __unused)
763 {
764 	close(rpcbindlockfd);
765 #ifdef WARMSTART
766 	syslog(LOG_ERR,
767 	    "rpcbind terminating on signal %d. Restart with \"rpcbind -w\"",
768 	    signum);
769 	write_warmstart();	/* Dump yourself */
770 #endif
771 	exit(2);
772 }
773 
774 void
775 rpcbind_abort(void)
776 {
777 #ifdef WARMSTART
778 	write_warmstart();	/* Dump yourself */
779 #endif
780 	abort();
781 }
782 
783 /* get command line options */
784 static void
785 parseargs(int argc, char *argv[])
786 {
787 	int c;
788 
789 #ifdef WARMSTART
790 #define	WSOP	"w"
791 #else
792 #define	WSOP	""
793 #endif
794 #ifdef LIBWRAP
795 #define WRAPOP	"W"
796 #else
797 #define WRAPOP	""
798 #endif
799 	while ((c = getopt(argc, argv, "6adh:iLls" WRAPOP WSOP)) != -1) {
800 		switch (c) {
801 		case '6':
802 			ipv6_only = 1;
803 			break;
804 		case 'a':
805 			doabort = 1;	/* when debugging, do an abort on */
806 			break;		/* errors; for rpcbind developers */
807 					/* only! */
808 		case 'd':
809 			debugging = 1;
810 			break;
811 		case 'h':
812 			++nhosts;
813 			hosts = realloc(hosts, nhosts * sizeof(char *));
814 			if (hosts == NULL)
815 				errx(1, "Out of memory");
816 			hosts[nhosts - 1] = strdup(optarg);
817 			if (hosts[nhosts - 1] == NULL)
818 				errx(1, "Out of memory");
819 			break;
820 		case 'i':
821 			insecure = 1;
822 			break;
823 		case 'L':
824 			oldstyle_local = 1;
825 			break;
826 		case 'l':
827 			verboselog = 1;
828 			break;
829 		case 's':
830 			runasdaemon = 1;
831 			break;
832 #ifdef LIBWRAP
833 		case 'W':
834 			libwrap = 1;
835 			break;
836 #endif
837 #ifdef WARMSTART
838 		case 'w':
839 			warmstart = 1;
840 			break;
841 #endif
842 		default:	/* error */
843 			fprintf(stderr,
844 			    "usage: rpcbind [-6adiLls%s%s] [-h bindip]\n",
845 			    WRAPOP, WSOP);
846 			exit (1);
847 		}
848 	}
849 	if (doabort && !debugging) {
850 	    fprintf(stderr,
851 		"-a (abort) specified without -d (debugging) -- ignored.\n");
852 	    doabort = 0;
853 	}
854 #undef WSOP
855 }
856 
857 void
858 reap(int dummy __unused)
859 {
860 	int save_errno = errno;
861 
862 	while (wait3(NULL, WNOHANG, NULL) > 0)
863 		;
864 	errno = save_errno;
865 }
866 
867 void
868 toggle_verboselog(int dummy __unused)
869 {
870 	verboselog = !verboselog;
871 }
872