rpcbind.c revision 104592
1205859Sjoel/*	$NetBSD: rpcbind.c,v 1.1 2000/06/02 23:15:42 fvdl Exp $	*/
2162874Snetchild/*	$FreeBSD: head/usr.sbin/rpcbind/rpcbind.c 104592 2002-10-07 02:56:59Z alfred $ */
3159687Snetchild
4159687Snetchild/*
5159687Snetchild * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
6159687Snetchild * unrestricted use provided that this legend is included on all tape
7159687Snetchild * media and as a part of the software program in whole or part.  Users
8159687Snetchild * may copy or modify Sun RPC without charge, but are not authorized
9159687Snetchild * to license or distribute it to anyone else except as part of a product or
10159687Snetchild * program developed by the user.
11159687Snetchild *
12159687Snetchild * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
13159687Snetchild * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
14159687Snetchild * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
15159687Snetchild *
16159687Snetchild * Sun RPC is provided with no support and without any obligation on the
17159687Snetchild * part of Sun Microsystems, Inc. to assist in its use, correction,
18159687Snetchild * modification or enhancement.
19159687Snetchild *
20159687Snetchild * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
21159687Snetchild * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
22159687Snetchild * OR ANY PART THEREOF.
23159687Snetchild *
24159687Snetchild * In no event will Sun Microsystems, Inc. be liable for any lost revenue
25159687Snetchild * or profits or other special, indirect and consequential damages, even if
26159687Snetchild * Sun has been advised of the possibility of such damages.
27159687Snetchild *
28159687Snetchild * Sun Microsystems, Inc.
29159687Snetchild * 2550 Garcia Avenue
30193640Sariff * Mountain View, California  94043
31193640Sariff */
32193640Sariff/*
33193640Sariff * Copyright (c) 1984 - 1991 by Sun Microsystems, Inc.
34159687Snetchild */
35159687Snetchild
36162874Snetchild/* #ident	"@(#)rpcbind.c	1.19	94/04/25 SMI" */
37159687Snetchild
38227293Sed#if 0
39159687Snetchild#ifndef lint
40162874Snetchildstatic	char sccsid[] = "@(#)rpcbind.c 1.35 89/04/21 Copyr 1984 Sun Micro";
41162874Snetchild#endif
42159687Snetchild#endif
43162874Snetchild
44159687Snetchild/*
45159687Snetchild * rpcbind.c
46159687Snetchild * Implements the program, version to address mapping for rpc.
47159687Snetchild *
48159687Snetchild */
49159687Snetchild
50159687Snetchild#include <sys/types.h>
51162874Snetchild#include <sys/stat.h>
52166713Sariff#include <sys/errno.h>
53159687Snetchild#include <sys/time.h>
54159687Snetchild#include <sys/resource.h>
55159687Snetchild#include <sys/wait.h>
56162874Snetchild#include <sys/signal.h>
57159687Snetchild#include <sys/socket.h>
58159687Snetchild#include <sys/un.h>
59159687Snetchild#include <rpc/rpc.h>
60159687Snetchild#ifdef PORTMAP
61159687Snetchild#include <netinet/in.h>
62159687Snetchild#endif
63159687Snetchild#include <arpa/inet.h>
64159687Snetchild#include <netdb.h>
65159687Snetchild#include <stdio.h>
66159687Snetchild#include <netconfig.h>
67159687Snetchild#include <stdlib.h>
68159687Snetchild#include <unistd.h>
69159687Snetchild#include <syslog.h>
70159687Snetchild#include <err.h>
71159687Snetchild#include <libutil.h>
72159687Snetchild#include <pwd.h>
73159687Snetchild#include <string.h>
74159687Snetchild#include <errno.h>
75159687Snetchild#include "rpcbind.h"
76162874Snetchild
77159687Snetchild/* Global variables */
78159687Snetchildint debugging = 0;	/* Tell me what's going on */
79159687Snetchildint doabort = 0;	/* When debugging, do an abort on errors */
80159687Snetchildrpcblist_ptr list_rbl;	/* A list of version 3/4 rpcbind services */
81162874Snetchild
82159687Snetchild/* who to suid to if -s is given */
83159687Snetchild#define RUN_AS  "daemon"
84159687Snetchild
85159687Snetchildint runasdaemon = 0;
86159687Snetchildint insecure = 0;
87159687Snetchildint oldstyle_local = 0;
88159687Snetchildint verboselog = 0;
89162874Snetchild
90162874Snetchildchar **hosts = NULL;
91162874Snetchildint nhosts = 0;
92162874Snetchildint on = 1;
93162874Snetchild
94162874Snetchild#ifdef WARMSTART
95170031Sjoel/* Local Variable */
96170031Sjoelstatic int warmstart = 0;	/* Grab a old copy of registrations */
97170031Sjoel#endif
98170031Sjoel
99170031Sjoel#ifdef PORTMAP
100170031Sjoelstruct pmaplist *list_pml;	/* A list of version 2 rpcbind services */
101162874Snetchildchar *udptrans;		/* Name of UDP transport */
102159687Snetchildchar *tcptrans;		/* Name of TCP transport */
103162874Snetchildchar *udp_uaddr;	/* Universal UDP address */
104162874Snetchildchar *tcp_uaddr;	/* Universal TCP address */
105162874Snetchild#endif
106159687Snetchildstatic char servname[] = "rpcbind";
107162874Snetchildstatic char superuser[] = "superuser";
108159687Snetchild
109159687Snetchildint main __P((int, char *[]));
110162874Snetchild
111159687Snetchildstatic int init_transport __P((struct netconfig *));
112159687Snetchildstatic void rbllist_add __P((rpcprog_t, rpcvers_t, struct netconfig *,
113162874Snetchild			     struct netbuf *));
114159687Snetchildstatic void terminate __P((int));
115159687Snetchildstatic void parseargs __P((int, char *[]));
116162874Snetchild
117162874Snetchildint
118162874Snetchildmain(int argc, char *argv[])
119162874Snetchild{
120162874Snetchild	struct netconfig *nconf;
121162874Snetchild	void *nc_handle;	/* Net config handle */
122162874Snetchild	struct rlimit rl;
123162874Snetchild
124162874Snetchild	parseargs(argc, argv);
125162874Snetchild
126162874Snetchild	getrlimit(RLIMIT_NOFILE, &rl);
127159687Snetchild	if (rl.rlim_cur < 128) {
128159687Snetchild		if (rl.rlim_max <= 128)
129159687Snetchild			rl.rlim_cur = rl.rlim_max;
130159687Snetchild		else
131159687Snetchild			rl.rlim_cur = 128;
132159687Snetchild		setrlimit(RLIMIT_NOFILE, &rl);
133159687Snetchild	}
134159687Snetchild	openlog("rpcbind", LOG_CONS, LOG_DAEMON);
135159687Snetchild	if (geteuid()) { /* This command allowed only to root */
136159687Snetchild		fprintf(stderr, "Sorry. You are not superuser\n");
137159687Snetchild		exit(1);
138159687Snetchild	}
139162874Snetchild	nc_handle = setnetconfig(); 	/* open netconfig file */
140162874Snetchild	if (nc_handle == NULL) {
141159687Snetchild		syslog(LOG_ERR, "could not read /etc/netconfig");
142162874Snetchild		exit(1);
143159687Snetchild	}
144159687Snetchild#ifdef PORTMAP
145162874Snetchild	udptrans = "";
146159687Snetchild	tcptrans = "";
147162874Snetchild#endif
148159687Snetchild
149159687Snetchild	nconf = getnetconfigent("unix");
150159687Snetchild	if (nconf == NULL) {
151162874Snetchild		syslog(LOG_ERR, "%s: can't find local transport\n", argv[0]);
152159689Snetchild		exit(1);
153159687Snetchild	}
154159687Snetchild	init_transport(nconf);
155159687Snetchild
156159687Snetchild	while ((nconf = getnetconfig(nc_handle))) {
157162874Snetchild		if (nconf->nc_flag & NC_VISIBLE)
158159687Snetchild			init_transport(nconf);
159159687Snetchild	}
160159687Snetchild	endnetconfig(nc_handle);
161159687Snetchild
162159687Snetchild	/* catch the usual termination signals for graceful exit */
163159687Snetchild	(void) signal(SIGCHLD, reap);
164159687Snetchild	(void) signal(SIGINT, terminate);
165159687Snetchild	(void) signal(SIGTERM, terminate);
166162874Snetchild	(void) signal(SIGQUIT, terminate);
167159687Snetchild	/* ignore others that could get sent */
168159687Snetchild	(void) signal(SIGPIPE, SIG_IGN);
169162874Snetchild	(void) signal(SIGHUP, SIG_IGN);
170159687Snetchild	(void) signal(SIGUSR1, SIG_IGN);
171159687Snetchild	(void) signal(SIGUSR2, SIG_IGN);
172159687Snetchild#ifdef WARMSTART
173162874Snetchild	if (warmstart) {
174159687Snetchild		read_warmstart();
175159687Snetchild	}
176159687Snetchild#endif
177159687Snetchild	if (debugging) {
178159687Snetchild		printf("rpcbind debugging enabled.");
179159687Snetchild		if (doabort) {
180159687Snetchild			printf("  Will abort on errors!\n");
181162874Snetchild		} else {
182159687Snetchild			printf("\n");
183159687Snetchild		}
184159687Snetchild	} else {
185159687Snetchild		if (daemon(0, 0))
186159687Snetchild			err(1, "fork failed");
187159687Snetchild	}
188159687Snetchild
189162874Snetchild	if (runasdaemon) {
190159687Snetchild		struct passwd *p;
191159687Snetchild
192159687Snetchild		if((p = getpwnam(RUN_AS)) == NULL) {
193159687Snetchild			syslog(LOG_ERR, "cannot get uid of daemon: %m");
194159687Snetchild			exit(1);
195159687Snetchild		}
196159687Snetchild		if (setuid(p->pw_uid) == -1) {
197162874Snetchild			syslog(LOG_ERR, "setuid to daemon failed: %m");
198159687Snetchild			exit(1);
199159687Snetchild		}
200159689Snetchild	}
201159687Snetchild
202159687Snetchild	network_init();
203159687Snetchild
204159687Snetchild	my_svc_run();
205162874Snetchild	syslog(LOG_ERR, "svc_run returned unexpectedly");
206159687Snetchild	rpcbind_abort();
207159687Snetchild	/* NOTREACHED */
208162874Snetchild
209159687Snetchild	return 0;
210159687Snetchild}
211162874Snetchild
212162874Snetchild/*
213159687Snetchild * Adds the entry into the rpcbind database.
214162874Snetchild * If PORTMAP, then for UDP and TCP, it adds the entries for version 2 also
215159687Snetchild * Returns 0 if succeeds, else fails
216162874Snetchild */
217162874Snetchildstatic int
218159687Snetchildinit_transport(struct netconfig *nconf)
219162874Snetchild{
220159687Snetchild	int fd;
221162874Snetchild	struct t_bind taddr;
222162874Snetchild	struct addrinfo hints, *res = NULL;
223162874Snetchild	struct __rpc_sockinfo si;
224162874Snetchild	SVCXPRT	*my_xprt;
225162874Snetchild	int status;	/* bound checking ? */
226162874Snetchild	int aicode;
227162874Snetchild	int addrlen;
228162874Snetchild	int nhostsbak;
229162874Snetchild	int checkbind;
230162874Snetchild	struct sockaddr *sa;
231162874Snetchild	u_int32_t host_addr[4];  /* IPv4 or IPv6 */
232162874Snetchild	struct sockaddr_un sun;
233162874Snetchild	mode_t oldmask;
234162874Snetchild
235162874Snetchild	if ((nconf->nc_semantics != NC_TPI_CLTS) &&
236162874Snetchild		(nconf->nc_semantics != NC_TPI_COTS) &&
237162874Snetchild		(nconf->nc_semantics != NC_TPI_COTS_ORD))
238162874Snetchild		return (1);	/* not my type */
239162874Snetchild#ifdef ND_DEBUG
240162874Snetchild	if (debugging) {
241188480Snetchild		int i;
242170031Sjoel		char **s;
243170031Sjoel
244159687Snetchild		(void) fprintf(stderr, "%s: %ld lookup routines :\n",
245159687Snetchild			nconf->nc_netid, nconf->nc_nlookups);
246159687Snetchild		for (i = 0, s = nconf->nc_lookups; i < nconf->nc_nlookups;
247159687Snetchild		     i++, s++)
248162874Snetchild			fprintf(stderr, "[%d] - %s\n", i, *s);
249159687Snetchild	}
250159687Snetchild#endif
251162874Snetchild
252159687Snetchild	/*
253162874Snetchild	 * XXX - using RPC library internal functions. For NC_TPI_CLTS
254159687Snetchild	 * we call this later, for each socket we like to bind.
255162874Snetchild	 */
256162874Snetchild	if (nconf->nc_semantics != NC_TPI_CLTS) {
257159687Snetchild		if ((fd = __rpc_nconf2fd(nconf)) < 0) {
258162874Snetchild			syslog(LOG_ERR, "cannot create socket for %s",
259162874Snetchild			    nconf->nc_netid);
260162874Snetchild			return (1);
261162874Snetchild		}
262162874Snetchild	}
263162874Snetchild
264162874Snetchild	if (!__rpc_nconf2sockinfo(nconf, &si)) {
265159687Snetchild		syslog(LOG_ERR, "cannot get information for %s",
266159687Snetchild		    nconf->nc_netid);
267159687Snetchild		return (1);
268159687Snetchild	}
269162874Snetchild
270159687Snetchild	if (!strcmp(nconf->nc_netid, "unix")) {
271159687Snetchild		memset(&sun, 0, sizeof sun);
272162874Snetchild		sun.sun_family = AF_LOCAL;
273159687Snetchild		unlink(_PATH_RPCBINDSOCK);
274159687Snetchild		strcpy(sun.sun_path, _PATH_RPCBINDSOCK);
275159687Snetchild		sun.sun_len = SUN_LEN(&sun);
276170031Sjoel		addrlen = sizeof (struct sockaddr_un);
277170031Sjoel		sa = (struct sockaddr *)&sun;
278162874Snetchild	} else {
279162874Snetchild		/* Get rpcbind's address on this transport */
280162874Snetchild
281159687Snetchild		memset(&hints, 0, sizeof hints);
282162874Snetchild		hints.ai_flags = AI_PASSIVE;
283162874Snetchild		hints.ai_family = si.si_af;
284162874Snetchild		hints.ai_socktype = si.si_socktype;
285162874Snetchild		hints.ai_protocol = si.si_proto;
286213779Srpaulo	}
287213779Srpaulo	if (nconf->nc_semantics == NC_TPI_CLTS) {
288162874Snetchild		/*
289162874Snetchild		 * If no hosts were specified, just bind to INADDR_ANY.  Otherwise
290162874Snetchild		 * make sure 127.0.0.1 is added to the list.
291162874Snetchild		 */
292162874Snetchild		nhostsbak = nhosts;
293159687Snetchild		nhostsbak++;
294170031Sjoel		hosts = realloc(hosts, nhostsbak * sizeof(char *));
295170031Sjoel		if (nhostsbak == 1)
296162874Snetchild			hosts[0] = "*";
297162874Snetchild		else {
298162874Snetchild			if (hints.ai_family == AF_INET) {
299159687Snetchild				hosts[nhostsbak - 1] = "127.0.0.1";
300162874Snetchild			} else if (hints.ai_family == AF_INET6) {
301162874Snetchild				hosts[nhostsbak - 1] = "::1";
302162874Snetchild			} else
303162874Snetchild				return 1;
304188480Snetchild		}
305188480Snetchild
306162874Snetchild	       /*
307162874Snetchild		* Bind to specific IPs if asked to
308162874Snetchild		*/
309162874Snetchild		checkbind = 1;
310162874Snetchild		while (nhostsbak > 0) {
311162874Snetchild			--nhostsbak;
312159687Snetchild			/*
313162874Snetchild			 * XXX - using RPC library internal functions.
314159687Snetchild			 */
315162874Snetchild			if ((fd = __rpc_nconf2fd(nconf)) < 0) {
316162874Snetchild				syslog(LOG_ERR, "cannot create socket for %s",
317159687Snetchild				    nconf->nc_netid);
318162874Snetchild				return (1);
319159687Snetchild			}
320162874Snetchild			switch (hints.ai_family) {
321159687Snetchild			case AF_INET:
322162874Snetchild				if (inet_pton(AF_INET, hosts[nhostsbak],
323162874Snetchild				    host_addr) == 1) {
324159687Snetchild					hints.ai_flags &= AI_NUMERICHOST;
325162874Snetchild				} else {
326159687Snetchild					/*
327162874Snetchild					 * Skip if we have a AF_INET6 adress
328159687Snetchild					 */
329162874Snetchild					if (inet_pton(AF_INET6,
330162874Snetchild					    hosts[nhostsbak], host_addr) == 1)
331159687Snetchild						continue;
332162874Snetchild				}
333162874Snetchild				break;
334162874Snetchild			case AF_INET6:
335162874Snetchild				if (inet_pton(AF_INET6, hosts[nhostsbak],
336162874Snetchild				    host_addr) == 1) {
337162874Snetchild					hints.ai_flags &= AI_NUMERICHOST;
338162874Snetchild				} else {
339162874Snetchild					/*
340162874Snetchild					 * Skip if we have a AF_INET adress
341162874Snetchild					 */
342162874Snetchild					if (inet_pton(AF_INET, hosts[nhostsbak],
343162874Snetchild					    host_addr) == 1)
344162874Snetchild						continue;
345162874Snetchild				}
346162874Snetchild				if (setsockopt(fd, IPPROTO_IPV6,
347162874Snetchild                                    IPV6_V6ONLY, &on, sizeof on) < 0) {
348162874Snetchild                                        syslog(LOG_ERR,
349162874Snetchild					    "can't set v6-only binding for "
350162874Snetchild                                            "udp6 socket: %m");
351162874Snetchild					continue;
352162874Snetchild				}
353162874Snetchild				break;
354170031Sjoel			default:
355170031Sjoel				break;
356170031Sjoel			}
357170031Sjoel
358170031Sjoel			/*
359170031Sjoel			 * If no hosts were specified, just bind to INADDR_ANY
360170031Sjoel			 */
361170031Sjoel			if (strcmp("*", hosts[nhostsbak]) == 0)
362159687Snetchild				hosts[nhostsbak] = NULL;
363159687Snetchild
364159687Snetchild			if ((aicode = getaddrinfo(hosts[nhostsbak],
365162874Snetchild			    servname, &hints, &res)) != 0) {
366162874Snetchild				syslog(LOG_ERR,
367				    "cannot get local address for %s: %s",
368				    nconf->nc_netid, gai_strerror(aicode));
369				continue;
370			}
371			addrlen = res->ai_addrlen;
372			sa = (struct sockaddr *)res->ai_addr;
373			oldmask = umask(S_IXUSR|S_IXGRP|S_IXOTH);
374			if (bind(fd, sa, addrlen) != 0) {
375				syslog(LOG_ERR, "cannot bind %s on %s: %m",
376					(hosts[nhostsbak] == NULL) ? "*" :
377					hosts[nhostsbak], nconf->nc_netid);
378				if (res != NULL)
379					freeaddrinfo(res);
380				continue;
381			} else
382				checkbind++;
383			(void) umask(oldmask);
384
385			/* Copy the address */
386			taddr.addr.len = taddr.addr.maxlen = addrlen;
387			taddr.addr.buf = malloc(addrlen);
388			if (taddr.addr.buf == NULL) {
389				syslog(LOG_ERR,
390				    "cannot allocate memory for %s address",
391				    nconf->nc_netid);
392				if (res != NULL)
393					freeaddrinfo(res);
394				return 1;
395			}
396			memcpy(taddr.addr.buf, sa, addrlen);
397#ifdef ND_DEBUG
398			if (debugging) {
399				/*
400				 * for debugging print out our universal
401				 * address
402				 */
403				char *uaddr;
404				struct netbuf nb;
405
406				nb.buf = sa;
407				nb.len = nb.maxlen = sa->sa_len;
408				uaddr = taddr2uaddr(nconf, &nb);
409				(void) fprintf(stderr,
410				    "rpcbind : my address is %s\n", uaddr);
411				(void) free(uaddr);
412			}
413#endif
414
415			if (nconf->nc_semantics != NC_TPI_CLTS)
416				listen(fd, SOMAXCONN);
417
418			my_xprt = (SVCXPRT *)svc_tli_create(fd, nconf, &taddr,
419			    0, 0);
420			if (my_xprt == (SVCXPRT *)NULL) {
421				syslog(LOG_ERR, "%s: could not create service",
422					nconf->nc_netid);
423				goto error;
424			}
425		}
426		if (!checkbind)
427			return 1;
428	} else {
429		if (strcmp(nconf->nc_netid, "unix") != 0) {
430			if ((aicode = getaddrinfo(NULL, servname, &hints, &res))
431			    != 0) {
432				syslog(LOG_ERR,
433				    "cannot get local address for %s: %s",
434				    nconf->nc_netid, gai_strerror(aicode));
435				return 1;
436			}
437			addrlen = res->ai_addrlen;
438			sa = (struct sockaddr *)res->ai_addr;
439		}
440		oldmask = umask(S_IXUSR|S_IXGRP|S_IXOTH);
441		if (bind(fd, sa, addrlen) < 0) {
442			syslog(LOG_ERR, "cannot bind %s: %m", nconf->nc_netid);
443			if (res != NULL)
444				freeaddrinfo(res);
445			return 1;
446		}
447		(void) umask(oldmask);
448
449		/* Copy the address */
450		taddr.addr.len = taddr.addr.maxlen = addrlen;
451		taddr.addr.buf = malloc(addrlen);
452		if (taddr.addr.buf == NULL) {
453			syslog(LOG_ERR, "cannot allocate memory for %s address",
454			    nconf->nc_netid);
455			if (res != NULL)
456				freeaddrinfo(res);
457			return 1;
458		}
459		memcpy(taddr.addr.buf, sa, addrlen);
460#ifdef ND_DEBUG
461		if (debugging) {
462			/* for debugging print out our universal address */
463			char *uaddr;
464			struct netbuf nb;
465
466			nb.buf = sa;
467			nb.len = nb.maxlen = sa->sa_len;
468			uaddr = taddr2uaddr(nconf, &nb);
469			(void) fprintf(stderr, "rpcbind : my address is %s\n",
470			    uaddr);
471			(void) free(uaddr);
472		}
473#endif
474
475		if (nconf->nc_semantics != NC_TPI_CLTS)
476			listen(fd, SOMAXCONN);
477
478		my_xprt = (SVCXPRT *)svc_tli_create(fd, nconf, &taddr, 0, 0);
479		if (my_xprt == (SVCXPRT *)NULL) {
480			syslog(LOG_ERR, "%s: could not create service",
481					nconf->nc_netid);
482			goto error;
483		}
484	}
485
486#ifdef PORTMAP
487	/*
488	 * Register both the versions for tcp/ip, udp/ip and local.
489	 */
490	if ((strcmp(nconf->nc_protofmly, NC_INET) == 0 &&
491		(strcmp(nconf->nc_proto, NC_TCP) == 0 ||
492		strcmp(nconf->nc_proto, NC_UDP) == 0)) ||
493		strcmp(nconf->nc_netid, "unix") == 0) {
494		struct pmaplist *pml;
495
496		if (!svc_register(my_xprt, PMAPPROG, PMAPVERS,
497			pmap_service, NULL)) {
498			syslog(LOG_ERR, "could not register on %s",
499					nconf->nc_netid);
500			goto error;
501		}
502		pml = malloc(sizeof (struct pmaplist));
503		if (pml == NULL) {
504			syslog(LOG_ERR, "no memory!");
505			exit(1);
506		}
507		pml->pml_map.pm_prog = PMAPPROG;
508		pml->pml_map.pm_vers = PMAPVERS;
509		pml->pml_map.pm_port = PMAPPORT;
510		if (strcmp(nconf->nc_proto, NC_TCP) == 0) {
511			if (tcptrans[0]) {
512				syslog(LOG_ERR,
513				"cannot have more than one TCP transport");
514				goto error;
515			}
516			tcptrans = strdup(nconf->nc_netid);
517			pml->pml_map.pm_prot = IPPROTO_TCP;
518
519			/* Let's snarf the universal address */
520			/* "h1.h2.h3.h4.p1.p2" */
521			tcp_uaddr = taddr2uaddr(nconf, &taddr.addr);
522		} else if (strcmp(nconf->nc_proto, NC_UDP) == 0) {
523			if (udptrans[0]) {
524				syslog(LOG_ERR,
525				"cannot have more than one UDP transport");
526				goto error;
527			}
528			udptrans = strdup(nconf->nc_netid);
529			pml->pml_map.pm_prot = IPPROTO_UDP;
530
531			/* Let's snarf the universal address */
532			/* "h1.h2.h3.h4.p1.p2" */
533			udp_uaddr = taddr2uaddr(nconf, &taddr.addr);
534		} else if (strcmp(nconf->nc_netid, "unix") == 0)
535			pml->pml_map.pm_prot = IPPROTO_ST;
536		pml->pml_next = list_pml;
537		list_pml = pml;
538
539		/* Add version 3 information */
540		pml = malloc(sizeof (struct pmaplist));
541		if (pml == NULL) {
542			syslog(LOG_ERR, "no memory!");
543			exit(1);
544		}
545		pml->pml_map = list_pml->pml_map;
546		pml->pml_map.pm_vers = RPCBVERS;
547		pml->pml_next = list_pml;
548		list_pml = pml;
549
550		/* Add version 4 information */
551		pml = malloc (sizeof (struct pmaplist));
552		if (pml == NULL) {
553			syslog(LOG_ERR, "no memory!");
554			exit(1);
555		}
556		pml->pml_map = list_pml->pml_map;
557		pml->pml_map.pm_vers = RPCBVERS4;
558		pml->pml_next = list_pml;
559		list_pml = pml;
560
561		/* Also add version 2 stuff to rpcbind list */
562		rbllist_add(PMAPPROG, PMAPVERS, nconf, &taddr.addr);
563	}
564#endif
565
566	/* version 3 registration */
567	if (!svc_reg(my_xprt, RPCBPROG, RPCBVERS, rpcb_service_3, NULL)) {
568		syslog(LOG_ERR, "could not register %s version 3",
569				nconf->nc_netid);
570		goto error;
571	}
572	rbllist_add(RPCBPROG, RPCBVERS, nconf, &taddr.addr);
573
574	/* version 4 registration */
575	if (!svc_reg(my_xprt, RPCBPROG, RPCBVERS4, rpcb_service_4, NULL)) {
576		syslog(LOG_ERR, "could not register %s version 4",
577				nconf->nc_netid);
578		goto error;
579	}
580	rbllist_add(RPCBPROG, RPCBVERS4, nconf, &taddr.addr);
581
582	/* decide if bound checking works for this transport */
583	status = add_bndlist(nconf, &taddr.addr);
584#ifdef BIND_DEBUG
585	if (debugging) {
586		if (status < 0) {
587			fprintf(stderr, "Error in finding bind status for %s\n",
588				nconf->nc_netid);
589		} else if (status == 0) {
590			fprintf(stderr, "check binding for %s\n",
591				nconf->nc_netid);
592		} else if (status > 0) {
593			fprintf(stderr, "No check binding for %s\n",
594				nconf->nc_netid);
595		}
596	}
597#endif
598	/*
599	 * rmtcall only supported on CLTS transports for now.
600	 */
601	if (nconf->nc_semantics == NC_TPI_CLTS) {
602		status = create_rmtcall_fd(nconf);
603
604#ifdef BIND_DEBUG
605		if (debugging) {
606			if (status < 0) {
607				fprintf(stderr,
608				    "Could not create rmtcall fd for %s\n",
609					nconf->nc_netid);
610			} else {
611				fprintf(stderr, "rmtcall fd for %s is %d\n",
612					nconf->nc_netid, status);
613			}
614		}
615#endif
616	}
617	return (0);
618error:
619	close(fd);
620	return (1);
621}
622
623static void
624rbllist_add(rpcprog_t prog, rpcvers_t vers, struct netconfig *nconf,
625	    struct netbuf *addr)
626{
627	rpcblist_ptr rbl;
628
629	rbl = malloc(sizeof (rpcblist));
630	if (rbl == NULL) {
631		syslog(LOG_ERR, "no memory!");
632		exit(1);
633	}
634
635	rbl->rpcb_map.r_prog = prog;
636	rbl->rpcb_map.r_vers = vers;
637	rbl->rpcb_map.r_netid = strdup(nconf->nc_netid);
638	rbl->rpcb_map.r_addr = taddr2uaddr(nconf, addr);
639	rbl->rpcb_map.r_owner = strdup(superuser);
640	rbl->rpcb_next = list_rbl;	/* Attach to global list */
641	list_rbl = rbl;
642}
643
644/*
645 * Catch the signal and die
646 */
647static void
648terminate(int dummy __unused)
649{
650#ifdef WARMSTART
651	syslog(LOG_ERR,
652		"rpcbind terminating on signal. Restart with \"rpcbind -w\"");
653	write_warmstart();	/* Dump yourself */
654#endif
655	exit(2);
656}
657
658void
659rpcbind_abort()
660{
661#ifdef WARMSTART
662	write_warmstart();	/* Dump yourself */
663#endif
664	abort();
665}
666
667/* get command line options */
668static void
669parseargs(int argc, char *argv[])
670{
671	int c;
672
673	while ((c = getopt(argc, argv, "dwah:ilLs")) != -1) {
674		switch (c) {
675		case 'a':
676			doabort = 1;	/* when debugging, do an abort on */
677			break;		/* errors; for rpcbind developers */
678					/* only! */
679		case 'd':
680			debugging = 1;
681			break;
682		case 'h':
683			++nhosts;
684			hosts = realloc(hosts, nhosts * sizeof(char *));
685			if (hosts == NULL)
686				errx(1, "Out of memory");
687			hosts[nhosts - 1] = strdup(optarg);
688			if (hosts[nhosts - 1] == NULL)
689				errx(1, "Out of memory");
690			break;
691		case 'i':
692			insecure = 1;
693			break;
694		case 'L':
695			oldstyle_local = 1;
696			break;
697		case 'l':
698			verboselog = 1;
699			break;
700		case 's':
701			runasdaemon = 1;
702			break;
703#ifdef WARMSTART
704		case 'w':
705			warmstart = 1;
706			break;
707#endif
708		default:	/* error */
709			fprintf(stderr,	"usage: rpcbind [-Idwils]\n");
710			exit (1);
711		}
712	}
713	if (doabort && !debugging) {
714	    fprintf(stderr,
715		"-a (abort) specified without -d (debugging) -- ignored.\n");
716	    doabort = 0;
717	}
718}
719
720void
721reap(int dummy __unused)
722{
723	int save_errno = errno;
724
725	while (wait3(NULL, WNOHANG, NULL) > 0)
726		;
727	errno = save_errno;
728}
729
730void
731toggle_verboselog(int dummy __unused)
732{
733	verboselog = !verboselog;
734}
735