xref: /titanic_41/usr/src/cmd/rpcbind/rpcbind.c (revision 70025d765b044c6d8594bb965a2247a61e991a99)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
27 /* All Rights Reserved */
28 /*
29  * University Copyright- Copyright (c) 1982, 1986, 1988
30  * The Regents of the University of California
31  * All Rights Reserved
32  *
33  * University Acknowledgment- Portions of this document are derived from
34  * software developed by the University of California, Berkeley, and its
35  * contributors.
36  */
37 
38 #pragma ident	"%Z%%M%	%I%	%E% SMI"
39 
40 /*
41  * rpcbind.c
42  * Implements the program, version to address mapping for rpc.
43  *
44  */
45 
46 #include <dlfcn.h>
47 #include <stdio.h>
48 #include <sys/types.h>
49 #include <unistd.h>
50 #include <stdlib.h>
51 #include <string.h>
52 #include <rpc/rpc.h>
53 #include <netconfig.h>
54 #include <netdir.h>
55 #include <errno.h>
56 #include <sys/wait.h>
57 #include <signal.h>
58 #include <string.h>
59 #include <stdlib.h>
60 #include <thread.h>
61 #include <synch.h>
62 #include <deflt.h>
63 #include <stdarg.h>
64 #ifdef PORTMAP
65 #include <netinet/in.h>
66 #endif
67 #include <arpa/inet.h>
68 #include <sys/termios.h>
69 #include "rpcbind.h"
70 #include <sys/syslog.h>
71 #include <sys/stat.h>
72 #include <syslog.h>
73 #include <string.h>
74 #include <sys/time.h>
75 #include <sys/resource.h>
76 #include <rpcsvc/daemon_utils.h>
77 #include <priv_utils.h>
78 #include <libscf.h>
79 
80 #ifdef PORTMAP
81 extern void pmap_service(struct svc_req *, SVCXPRT *xprt);
82 #endif
83 extern void rpcb_service_3(struct svc_req *, SVCXPRT *xprt);
84 extern void rpcb_service_4(struct svc_req *, SVCXPRT *xprt);
85 extern void read_warmstart(void);
86 extern void write_warmstart(void);
87 extern int Is_ipv6present(void);
88 
89 #define	MAX_FILEDESC_LIMIT	1023
90 
91 static void terminate(int);
92 static void detachfromtty(void);
93 static void parseargs(int, char *[]);
94 static void rbllist_add(ulong_t, ulong_t, struct netconfig *, struct netbuf *);
95 static int init_transport(struct netconfig *);
96 static int check_netconfig(void);
97 
98 static boolean_t check_hostserv(struct netconfig *, const char *, const char *);
99 static void rpcb_check_init(void);
100 
101 
102 /* Global variables */
103 #ifdef ND_DEBUG
104 int debugging = 1;	/* Tell me what's going on */
105 #else
106 int debugging = 0;	/* Tell me what's going on */
107 #endif
108 static int ipv6flag = 0;
109 int doabort = 0;	/* When debugging, do an abort on errors */
110 static int listen_backlog = 64;
111 rpcblist_ptr list_rbl;	/* A list of version 3/4 rpcbind services */
112 char *loopback_dg;	/* Datagram loopback transport, for set and unset */
113 char *loopback_vc;	/* COTS loopback transport, for set and unset */
114 char *loopback_vc_ord;	/* COTS_ORD loopback transport, for set and unset */
115 
116 boolean_t verboselog = B_FALSE;
117 boolean_t wrap_enabled = B_FALSE;
118 boolean_t allow_indirect = B_TRUE;
119 
120 /* Local Variable */
121 static int warmstart = 0;	/* Grab a old copy of registrations */
122 
123 #ifdef PORTMAP
124 PMAPLIST *list_pml;	/* A list of version 2 rpcbind services */
125 char *udptrans;		/* Name of UDP transport */
126 char *tcptrans;		/* Name of TCP transport */
127 char *udp_uaddr;	/* Universal UDP address */
128 char *tcp_uaddr;	/* Universal TCP address */
129 #endif
130 static char servname[] = "rpcbind";
131 static char superuser[] = "superuser";
132 
133 static const char daemon_dir[] = DAEMON_DIR;
134 
135 int
136 main(int argc, char *argv[])
137 {
138 	struct netconfig *nconf;
139 	void *nc_handle;	/* Net config handle */
140 	struct rlimit rl;
141 	int maxrecsz = RPC_MAXDATASIZE;
142 
143 	parseargs(argc, argv);
144 
145 	getrlimit(RLIMIT_NOFILE, &rl);
146 
147 	if (rl.rlim_cur < MAX_FILEDESC_LIMIT) {
148 		if (rl.rlim_max <= MAX_FILEDESC_LIMIT)
149 			rl.rlim_cur = rl.rlim_max;
150 		else
151 			rl.rlim_cur = MAX_FILEDESC_LIMIT;
152 		setrlimit(RLIMIT_NOFILE, &rl);
153 	}
154 	openlog("rpcbind", LOG_CONS, LOG_DAEMON);
155 
156 	/*
157 	 * Create the daemon directory in /var/run
158 	 */
159 	if (mkdir(daemon_dir, DAEMON_DIR_MODE) == 0 || errno == EEXIST) {
160 		chmod(daemon_dir, DAEMON_DIR_MODE);
161 		chown(daemon_dir, DAEMON_UID, DAEMON_GID);
162 	} else {
163 		syslog(LOG_ERR, "failed to create \"%s\": %m", daemon_dir);
164 	}
165 
166 	/*
167 	 * These privileges are required for the t_bind check rpcbind uses
168 	 * to determine whether a service is still live or not.
169 	 */
170 	if (__init_daemon_priv(PU_RESETGROUPS|PU_CLEARLIMITSET, DAEMON_UID,
171 	    DAEMON_GID, PRIV_NET_PRIVADDR, PRIV_SYS_NFS, (char *)NULL) == -1) {
172 		fprintf(stderr, "Insufficient privileges\n");
173 		exit(1);
174 	}
175 
176 	/*
177 	 * Enable non-blocking mode and maximum record size checks for
178 	 * connection oriented transports.
179 	 */
180 	if (!rpc_control(RPC_SVC_CONNMAXREC_SET, &maxrecsz)) {
181 		syslog(LOG_INFO, "unable to set RPC max record size");
182 	}
183 
184 	nc_handle = setnetconfig(); 	/* open netconfig file */
185 	if (nc_handle == NULL) {
186 		syslog(LOG_ERR, "could not read /etc/netconfig");
187 		exit(1);
188 	}
189 	loopback_dg = "";
190 	loopback_vc = "";
191 	loopback_vc_ord = "";
192 #ifdef PORTMAP
193 	udptrans = "";
194 	tcptrans = "";
195 #endif
196 
197 	{
198 		/*
199 		 * rpcbind is the first application to encounter the
200 		 * various netconfig files.  check_netconfig() verifies
201 		 * that they are set up correctly and complains loudly
202 		 * if not.
203 		 */
204 		int trouble;
205 
206 		trouble = check_netconfig();
207 		if (trouble) {
208 			syslog(LOG_ERR,
209 	"%s: found %d errors with network configuration files. Exiting.",
210 				argv[0], trouble);
211 			fprintf(stderr,
212 	"%s: found %d errors with network configuration files. Exiting.\n",
213 				argv[0], trouble);
214 			exit(1);
215 		}
216 	}
217 	ipv6flag = Is_ipv6present();
218 	rpcb_check_init();
219 	while (nconf = getnetconfig(nc_handle)) {
220 		if (nconf->nc_flag & NC_VISIBLE)
221 			init_transport(nconf);
222 	}
223 	endnetconfig(nc_handle);
224 
225 	if ((loopback_dg[0] == NULL) && (loopback_vc[0] == NULL) &&
226 		(loopback_vc_ord[0] == NULL)) {
227 		syslog(LOG_ERR, "could not find loopback transports");
228 		exit(1);
229 	}
230 
231 	/* catch the usual termination signals for graceful exit */
232 	(void) signal(SIGINT, terminate);
233 	(void) signal(SIGTERM, terminate);
234 	(void) signal(SIGQUIT, terminate);
235 	/* ignore others that could get sent */
236 	(void) signal(SIGHUP, SIG_IGN);
237 	(void) signal(SIGUSR1, SIG_IGN);
238 	(void) signal(SIGUSR2, SIG_IGN);
239 	if (warmstart) {
240 		read_warmstart();
241 	}
242 	if (debugging) {
243 		printf("rpcbind debugging enabled.");
244 		if (doabort) {
245 			printf("  Will abort on errors!\n");
246 		} else {
247 			printf("\n");
248 		}
249 	} else {
250 		detachfromtty();
251 	}
252 
253 	/* These are basic privileges we do not need */
254 	__fini_daemon_priv(PRIV_PROC_EXEC, PRIV_PROC_SESSION,
255 	    PRIV_FILE_LINK_ANY, PRIV_PROC_INFO, (char *)NULL);
256 
257 	my_svc_run();
258 	syslog(LOG_ERR, "svc_run returned unexpectedly");
259 	rpcbind_abort();
260 	/* NOTREACHED */
261 }
262 
263 /*
264  * Increments a counter each time a problem is found with the network
265  * configuration information.
266  */
267 static int
268 check_netconfig(void)
269 {
270 	void	*nc;
271 	void	*dlcookie;
272 	int	busted = 0;
273 	int	i;
274 	int	lo_clts_found = 0, lo_cots_found = 0, lo_cotsord_found = 0;
275 	struct netconfig	*nconf, *np;
276 	struct stat	sb;
277 
278 	nc = setnetconfig();
279 	if (nc == NULL) {
280 		if (debugging)
281 			fprintf(stderr,
282 				"setnetconfig() failed:  %s\n", nc_sperror());
283 		syslog(LOG_ALERT, "setnetconfig() failed:  %s", nc_sperror());
284 		return (1);
285 	}
286 	while (np = getnetconfig(nc)) {
287 		if ((np->nc_flag & NC_VISIBLE) == 0)
288 			continue;
289 		if (debugging)
290 			fprintf(stderr, "checking netid \"%s\"\n",
291 				np->nc_netid);
292 		if (strcmp(np->nc_protofmly, NC_LOOPBACK) == 0)
293 			switch (np->nc_semantics) {
294 			case NC_TPI_CLTS:
295 				lo_clts_found = 1;
296 				break;
297 
298 			case NC_TPI_COTS:
299 				lo_cots_found = 1;
300 				break;
301 
302 			case NC_TPI_COTS_ORD:
303 				lo_cotsord_found = 1;
304 				break;
305 			}
306 		if (stat(np->nc_device, &sb) == -1 && errno == ENOENT) {
307 			if (debugging)
308 				fprintf(stderr, "\tdevice %s does not exist\n",
309 					np->nc_device);
310 			syslog(LOG_ERR, "netid %s:  device %s does not exist",
311 				np->nc_netid, np->nc_device);
312 			busted++;
313 		} else
314 			if (debugging)
315 				fprintf(stderr, "\tdevice %s present\n",
316 					np->nc_device);
317 		for (i = 0; i < np->nc_nlookups; i++) {
318 			char	*libname = np->nc_lookups[i];
319 
320 			if ((dlcookie = dlopen(libname, RTLD_LAZY)) == NULL) {
321 				char *dlerrstr;
322 
323 				dlerrstr = dlerror();
324 				if (debugging) {
325 					fprintf(stderr,
326 	"\tnetid %s: dlopen of name-to-address library %s failed\ndlerror: %s",
327 	np->nc_netid, libname, dlerrstr ? dlerrstr : "");
328 				}
329 				syslog(LOG_ERR,
330 	"netid %s:  dlopen of name-to-address library %s failed",
331 						np->nc_netid, libname);
332 				if (dlerrstr)
333 					syslog(LOG_ERR, "%s", dlerrstr);
334 				busted++;
335 			} else {
336 				if (debugging)
337 					fprintf(stderr,
338 	"\tdlopen of name-to-address library %s succeeded\n", libname);
339 				(void) dlclose(dlcookie);
340 			}
341 		}
342 		nconf = getnetconfigent(np->nc_netid);
343 
344 		if (!check_hostserv(nconf, HOST_SELF, ""))
345 			busted++;
346 		if (!check_hostserv(nconf, HOST_SELF_CONNECT, ""))
347 			busted++;
348 		if (!check_hostserv(nconf, HOST_SELF, "rpcbind"))
349 			busted++;
350 		if (!check_hostserv(nconf, HOST_SELF_CONNECT, "rpcbind"))
351 			busted++;
352 
353 		freenetconfigent(nconf);
354 	}
355 	endnetconfig(nc);
356 
357 	if (lo_clts_found) {
358 		if (debugging)
359 			fprintf(stderr, "Found CLTS loopback transport\n");
360 	} else {
361 		syslog(LOG_ALERT, "no CLTS loopback transport found\n");
362 		if (debugging)
363 			fprintf(stderr, "no CLTS loopback transport found\n");
364 	}
365 	if (lo_cots_found) {
366 		if (debugging)
367 			fprintf(stderr, "Found COTS loopback transport\n");
368 	} else {
369 		syslog(LOG_ALERT, "no COTS loopback transport found\n");
370 		if (debugging)
371 			fprintf(stderr, "no COTS loopback transport found\n");
372 	}
373 	if (lo_cotsord_found) {
374 		if (debugging)
375 			fprintf(stderr, "Found COTS ORD loopback transport\n");
376 	} else {
377 		syslog(LOG_ALERT, "no COTS ORD loopback transport found\n");
378 		if (debugging)
379 			fprintf(stderr,
380 				"no COTS ORD loopback transport found\n");
381 	}
382 
383 	return (busted);
384 }
385 
386 /*
387  * Adds the entry into the rpcbind database.
388  * If PORTMAP, then for UDP and TCP, it adds the entries for version 2 also
389  * Returns 0 if succeeds, else fails
390  */
391 static int
392 init_transport(struct netconfig *nconf)
393 {
394 	int fd;
395 	struct t_bind *taddr, *baddr;
396 	SVCXPRT	*my_xprt;
397 	struct nd_addrlist *nas;
398 	struct nd_hostserv hs;
399 	int status;	/* bound checking ? */
400 	static int msgprt = 0;
401 
402 	static int setopt_reuseaddr(int);
403 	static int setup_callit(int);
404 
405 	if ((nconf->nc_semantics != NC_TPI_CLTS) &&
406 		(nconf->nc_semantics != NC_TPI_COTS) &&
407 		(nconf->nc_semantics != NC_TPI_COTS_ORD))
408 		return (1);	/* not my type */
409 
410 	if ((strcmp(nconf->nc_protofmly, NC_INET6) == 0) && !ipv6flag) {
411 		if (!msgprt)
412 			syslog(LOG_DEBUG,
413 "/etc/netconfig has IPv6 entries but IPv6 is not configured");
414 		msgprt++;
415 		return (1);
416 	}
417 #ifdef ND_DEBUG
418 	{
419 	int i;
420 	char **s;
421 
422 	(void) fprintf(stderr, "%s: %d lookup routines :\n",
423 		nconf->nc_netid, nconf->nc_nlookups);
424 	for (i = 0, s = nconf->nc_lookups; i < nconf->nc_nlookups; i++, s++)
425 		fprintf(stderr, "[%d] - %s\n", i, *s);
426 	}
427 #endif
428 
429 	if ((fd = t_open(nconf->nc_device, O_RDWR, NULL)) < 0) {
430 		syslog(LOG_ERR, "%s: cannot open connection: %s",
431 				nconf->nc_netid, t_errlist[t_errno]);
432 		return (1);
433 	}
434 
435 	/*
436 	 * Negotiate for returning the ucred of the caller. This should
437 	 * done before enabling the endpoint for service via
438 	 * t_bind() so that requests to rpcbind contain the uid.
439 	 */
440 	svc_fd_negotiate_ucred(fd);
441 
442 	taddr = (struct t_bind *)t_alloc(fd, T_BIND, T_ADDR);
443 	baddr = (struct t_bind *)t_alloc(fd, T_BIND, T_ADDR);
444 	if ((baddr == NULL) || (taddr == NULL)) {
445 		syslog(LOG_ERR, "%s: cannot allocate netbuf: %s",
446 				nconf->nc_netid, t_errlist[t_errno]);
447 		exit(1);
448 	}
449 
450 	/* Get rpcbind's address on this transport */
451 	hs.h_host = HOST_SELF;
452 	hs.h_serv = servname;
453 	if (netdir_getbyname(nconf, &hs, &nas))
454 		goto error;
455 
456 	/* Copy the address */
457 	taddr->addr.len = nas->n_addrs->len;
458 	memcpy(taddr->addr.buf, nas->n_addrs->buf, (int)nas->n_addrs->len);
459 #ifdef ND_DEBUG
460 	{
461 	/* for debugging print out our universal address */
462 	char *uaddr;
463 
464 	uaddr = taddr2uaddr(nconf, nas->n_addrs);
465 	(void) fprintf(stderr, "rpcbind : my address is %s\n", uaddr);
466 	(void) free(uaddr);
467 	}
468 #endif
469 	netdir_free((char *)nas, ND_ADDRLIST);
470 
471 	if (nconf->nc_semantics == NC_TPI_CLTS)
472 		taddr->qlen = 0;
473 	else
474 		taddr->qlen = listen_backlog;
475 
476 	if (strcmp(nconf->nc_proto, NC_TCP) == 0) {
477 		/*
478 		 * Sm: If we are running then set SO_REUSEADDR option
479 		 * so that we can bind to our preferred address even if
480 		 * previous connections are in FIN_WAIT state
481 		 */
482 #ifdef ND_DEBUG
483 		fprintf(stdout, "Setting SO_REUSEADDR.\n");
484 #endif
485 		if (setopt_reuseaddr(fd) == -1) {
486 			syslog(LOG_ERR, "Couldn't set SO_REUSEADDR option");
487 		}
488 	}
489 
490 	if (t_bind(fd, taddr, baddr) != 0) {
491 		syslog(LOG_ERR, "%s: cannot bind: %s",
492 			nconf->nc_netid, t_errlist[t_errno]);
493 		goto error;
494 	}
495 
496 
497 	if (memcmp(taddr->addr.buf, baddr->addr.buf, (int)baddr->addr.len)) {
498 		syslog(LOG_ERR, "%s: address in use", nconf->nc_netid);
499 		goto error;
500 	}
501 
502 	my_xprt = (SVCXPRT *)svc_tli_create(fd, nconf, baddr, 0, 0);
503 	if (my_xprt == (SVCXPRT *)NULL) {
504 		syslog(LOG_ERR, "%s: could not create service",
505 				nconf->nc_netid);
506 		goto error;
507 	}
508 
509 	/* set up multicast address for RPC CALL_IT, IPv6 */
510 
511 	if ((strcmp(nconf->nc_protofmly, NC_INET6) == 0) &&
512 	    (strcmp(nconf->nc_proto, NC_UDP) == 0)) {
513 		if (setup_callit(fd) < 0) {
514 			syslog(LOG_ERR, "Unable to join IPv6 multicast group \
515 for rpc broadcast %s", RPCB_MULTICAST_ADDR);
516 		}
517 	}
518 
519 	if (strcmp(nconf->nc_proto, NC_TCP) == 0) {
520 			svc_control(my_xprt, SVCSET_KEEPALIVE, (void *) TRUE);
521 	}
522 
523 #ifdef PORTMAP
524 	/*
525 	 * Register both the versions for tcp/ip and udp/ip
526 	 */
527 	if ((strcmp(nconf->nc_protofmly, NC_INET) == 0) &&
528 		((strcmp(nconf->nc_proto, NC_TCP) == 0) ||
529 		(strcmp(nconf->nc_proto, NC_UDP) == 0))) {
530 		PMAPLIST *pml;
531 
532 		if (!svc_register(my_xprt, PMAPPROG, PMAPVERS,
533 			pmap_service, NULL)) {
534 			syslog(LOG_ERR, "could not register on %s",
535 					nconf->nc_netid);
536 			goto error;
537 		}
538 		pml = (PMAPLIST *)malloc((uint_t)sizeof (PMAPLIST));
539 		if (pml == (PMAPLIST *)NULL) {
540 			syslog(LOG_ERR, "no memory!");
541 			exit(1);
542 		}
543 		pml->pml_map.pm_prog = PMAPPROG;
544 		pml->pml_map.pm_vers = PMAPVERS;
545 		pml->pml_map.pm_port = PMAPPORT;
546 		if (strcmp(nconf->nc_proto, NC_TCP) == 0) {
547 			if (tcptrans[0]) {
548 				syslog(LOG_ERR,
549 				"cannot have more than one TCP transport");
550 				goto error;
551 			}
552 			tcptrans = strdup(nconf->nc_netid);
553 			pml->pml_map.pm_prot = IPPROTO_TCP;
554 
555 			/* Let's snarf the universal address */
556 			/* "h1.h2.h3.h4.p1.p2" */
557 			tcp_uaddr = taddr2uaddr(nconf, &baddr->addr);
558 		} else {
559 			if (udptrans[0]) {
560 				syslog(LOG_ERR,
561 				"cannot have more than one UDP transport");
562 				goto error;
563 			}
564 			udptrans = strdup(nconf->nc_netid);
565 			pml->pml_map.pm_prot = IPPROTO_UDP;
566 
567 			/* Let's snarf the universal address */
568 			/* "h1.h2.h3.h4.p1.p2" */
569 			udp_uaddr = taddr2uaddr(nconf, &baddr->addr);
570 		}
571 		pml->pml_next = list_pml;
572 		list_pml = pml;
573 
574 		/* Add version 3 information */
575 		pml = (PMAPLIST *)malloc((uint_t)sizeof (PMAPLIST));
576 		if (pml == (PMAPLIST *)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 = RPCBVERS;
582 		pml->pml_next = list_pml;
583 		list_pml = pml;
584 
585 		/* Add version 4 information */
586 		pml = (PMAPLIST *)malloc((uint_t)sizeof (PMAPLIST));
587 		if (pml == (PMAPLIST *)NULL) {
588 			syslog(LOG_ERR, "no memory!");
589 			exit(1);
590 		}
591 		pml->pml_map = list_pml->pml_map;
592 		pml->pml_map.pm_vers = RPCBVERS4;
593 		pml->pml_next = list_pml;
594 		list_pml = pml;
595 
596 		/* Also add version 2 stuff to rpcbind list */
597 		rbllist_add(PMAPPROG, PMAPVERS, nconf, &baddr->addr);
598 	}
599 #endif
600 
601 	/* version 3 registration */
602 	if (!svc_reg(my_xprt, RPCBPROG, RPCBVERS, rpcb_service_3, NULL)) {
603 		syslog(LOG_ERR, "could not register %s version 3",
604 				nconf->nc_netid);
605 		goto error;
606 	}
607 	rbllist_add(RPCBPROG, RPCBVERS, nconf, &baddr->addr);
608 
609 	/* version 4 registration */
610 	if (!svc_reg(my_xprt, RPCBPROG, RPCBVERS4, rpcb_service_4, NULL)) {
611 		syslog(LOG_ERR, "could not register %s version 4",
612 				nconf->nc_netid);
613 		goto error;
614 	}
615 	rbllist_add(RPCBPROG, RPCBVERS4, nconf, &baddr->addr);
616 
617 	if (strcmp(nconf->nc_protofmly, NC_LOOPBACK) == 0) {
618 		if (nconf->nc_semantics == NC_TPI_CLTS)
619 			loopback_dg = strdup(nconf->nc_netid);
620 		else if (nconf->nc_semantics == NC_TPI_COTS)
621 			loopback_vc = strdup(nconf->nc_netid);
622 		else if (nconf->nc_semantics == NC_TPI_COTS_ORD)
623 			loopback_vc_ord = strdup(nconf->nc_netid);
624 	}
625 
626 	/* decide if bound checking works for this transport */
627 	status = add_bndlist(nconf, taddr, baddr);
628 #ifdef BIND_DEBUG
629 	if (status < 0) {
630 		fprintf(stderr, "Error in finding bind status for %s\n",
631 			nconf->nc_netid);
632 	} else if (status == 0) {
633 		fprintf(stderr, "check binding for %s\n",
634 			nconf->nc_netid);
635 	} else if (status > 0) {
636 		fprintf(stderr, "No check binding for %s\n",
637 			nconf->nc_netid);
638 	}
639 #endif
640 	/*
641 	 * rmtcall only supported on CLTS transports for now.
642 	 * only needed when we are allowing indirect calls
643 	 */
644 	if (allow_indirect && nconf->nc_semantics == NC_TPI_CLTS) {
645 		status = create_rmtcall_fd(nconf);
646 
647 #ifdef BIND_DEBUG
648 		if (status < 0) {
649 			fprintf(stderr, "Could not create rmtcall fd for %s\n",
650 				nconf->nc_netid);
651 		} else {
652 			fprintf(stderr, "rmtcall fd for %s is %d\n",
653 				nconf->nc_netid, status);
654 		}
655 #endif
656 	}
657 	(void) t_free((char *)taddr, T_BIND);
658 	(void) t_free((char *)baddr, T_BIND);
659 	return (0);
660 error:
661 	(void) t_free((char *)taddr, T_BIND);
662 	(void) t_free((char *)baddr, T_BIND);
663 	(void) t_close(fd);
664 	return (1);
665 }
666 
667 static void
668 rbllist_add(ulong_t prog, ulong_t vers, struct netconfig *nconf,
669 	struct netbuf *addr)
670 {
671 	rpcblist_ptr rbl;
672 
673 	rbl = (rpcblist_ptr)malloc((uint_t)sizeof (rpcblist));
674 	if (rbl == (rpcblist_ptr)NULL) {
675 		syslog(LOG_ERR, "no memory!");
676 		exit(1);
677 	}
678 
679 	rbl->rpcb_map.r_prog = prog;
680 	rbl->rpcb_map.r_vers = vers;
681 	rbl->rpcb_map.r_netid = strdup(nconf->nc_netid);
682 	rbl->rpcb_map.r_addr = taddr2uaddr(nconf, addr);
683 	rbl->rpcb_map.r_owner = strdup(superuser);
684 	rbl->rpcb_next = list_rbl;	/* Attach to global list */
685 	list_rbl = rbl;
686 }
687 
688 /*
689  * Catch the signal and die
690  */
691 /* ARGSUSED */
692 static void
693 terminate(int sig)
694 {
695 	syslog(LOG_ERR, "rpcbind terminating on signal.");
696 	write_warmstart();	/* Dump yourself */
697 	exit(2);
698 }
699 
700 void
701 rpcbind_abort(void)
702 {
703 	write_warmstart();	/* Dump yourself */
704 	abort();
705 }
706 
707 /*
708  * detach from tty
709  */
710 static void
711 detachfromtty(void)
712 {
713 	close(0);
714 	close(1);
715 	close(2);
716 	switch (forkall()) {
717 	case (pid_t)-1:
718 		perror("fork");
719 		break;
720 	case 0:
721 		break;
722 	default:
723 		exit(0);
724 	}
725 	setsid();
726 	(void) open("/dev/null", O_RDWR, 0);
727 	dup(0);
728 	dup(0);
729 }
730 
731 /* get command line options */
732 static void
733 parseargs(int argc, char *argv[])
734 {
735 	int c;
736 	int tmp;
737 
738 	while ((c = getopt(argc, argv, "dwal:")) != EOF) {
739 		switch (c) {
740 		case 'd':
741 			debugging = 1;
742 			break;
743 		case 'a':
744 			doabort = 1;	/* when debugging, do an abort on */
745 			break;		/* errors; for rpcbind developers */
746 					/* only! */
747 		case 'w':
748 			warmstart = 1;
749 			break;
750 
751 		case 'l':
752 			if (sscanf(optarg, "%d", &tmp)) {
753 				if (tmp > listen_backlog) {
754 					listen_backlog = tmp;
755 				}
756 			}
757 			break;
758 		default:	/* error */
759 			fprintf(stderr,
760 			"usage: rpcbind [-d] [-w] [-l listen_backlog]\n");
761 			exit(1);
762 		}
763 	}
764 	if (doabort && !debugging) {
765 	    fprintf(stderr,
766 		"-a (abort) specified without -d (debugging) -- ignored.\n");
767 	    doabort = 0;
768 	}
769 }
770 
771 static int
772 setopt_reuseaddr(int fd)
773 {
774 	struct t_optmgmt req, resp;
775 	struct opthdr *opt;
776 	char reqbuf[128];
777 	int *ip;
778 
779 	opt = (struct opthdr *)reqbuf;
780 	opt->level = SOL_SOCKET;
781 	opt->name = SO_REUSEADDR;
782 	opt->len = sizeof (int);
783 
784 	ip = (int *)&reqbuf[sizeof (struct opthdr)];
785 	*ip = 1;
786 
787 	req.flags = T_NEGOTIATE;
788 	req.opt.len = sizeof (struct opthdr) + opt->len;
789 	req.opt.buf = (char *)opt;
790 
791 	resp.flags = 0;
792 	resp.opt.buf = reqbuf;
793 	resp.opt.maxlen = sizeof (reqbuf);
794 
795 	if (t_optmgmt(fd, &req, &resp) < 0 || resp.flags != T_SUCCESS) {
796 		t_error("t_optmgmt");
797 		return (-1);
798 	}
799 	return (0);
800 }
801 
802 static int
803 setup_callit(int fd)
804 {
805 	struct ipv6_mreq mreq;
806 	struct t_optmgmt req, resp;
807 	struct opthdr *opt;
808 	char reqbuf[ sizeof (struct ipv6_mreq) + 24];
809 	struct ipv6_mreq *pmreq;
810 
811 	opt = (struct opthdr *)reqbuf;
812 
813 	opt->level = IPPROTO_IPV6;
814 	opt->name = IPV6_ADD_MEMBERSHIP;
815 	opt->len = sizeof (struct ipv6_mreq);
816 
817 	/* multicast address */
818 	(void) inet_pton(AF_INET6, RPCB_MULTICAST_ADDR,
819 		mreq.ipv6mr_multiaddr.s6_addr);
820 	mreq.ipv6mr_interface = 0;
821 
822 	/* insert it into opt */
823 	pmreq = (struct ipv6_mreq *)&reqbuf[sizeof (struct opthdr)];
824 	memcpy(pmreq, &mreq, sizeof (struct ipv6_mreq));
825 
826 	req.flags = T_NEGOTIATE;
827 	req.opt.len = sizeof (struct opthdr) + opt->len;
828 	req.opt.buf = (char *)opt;
829 
830 	resp.flags = 0;
831 	resp.opt.buf = reqbuf;
832 	resp.opt.maxlen = sizeof (reqbuf);
833 
834 	if (t_optmgmt(fd, &req, &resp) < 0 || resp.flags != T_SUCCESS) {
835 		t_error("t_optmgmt");
836 		return (-1);
837 	}
838 	return (0);
839 }
840 
841 static boolean_t
842 check_hostserv(struct netconfig *nconf, const char *host, const char *serv)
843 {
844 	struct nd_hostserv nh;
845 	struct nd_addrlist *na;
846 	const char *hostname = host;
847 	const char *servname = serv;
848 	int retval;
849 
850 	if (strcmp(host, HOST_SELF) == 0)
851 		hostname = "HOST_SELF";
852 	else if (strcmp(host, HOST_SELF_CONNECT) == 0)
853 		hostname = "HOST_SELF_CONNECT";
854 
855 	if (serv[0] == '\0')
856 		servname = "<any>";
857 
858 	nh.h_host = (char *)host;
859 	nh.h_serv = (char *)serv;
860 
861 	retval = netdir_getbyname(nconf, &nh, &na);
862 	if (retval != ND_OK || na->n_cnt == 0) {
863 		if (retval == ND_OK)
864 			netdir_free(na, ND_ADDRLIST);
865 
866 		syslog(LOG_ALERT, "netid %s: cannot find an address for host "
867 		    "%s, service \"%s\"", nconf->nc_netid, hostname, servname);
868 		if (debugging) {
869 			(void) fprintf(stderr, "\tnetdir_getbyname for %s, "
870 			    "service \"%s\" failed\n", hostname, servname);
871 		}
872 		return (B_FALSE);
873 	}
874 	netdir_free(na, ND_ADDRLIST);
875 
876 	if (debugging) {
877 		(void) fprintf(stderr, "\tnetdir_getbyname for %s, service "
878 		    "service \"%s\" succeeded\n", hostname, servname);
879 	}
880 	return (B_TRUE);
881 }
882 
883 #define	DEFRPCBIND	"/etc/default/rpcbind"
884 
885 /* Maximum outstanding syslog requests */
886 #define	MAXLOG		100
887 /* Maximum length: the messages generated are fairly short; no hostnames. */
888 #define	MAXMSG		128
889 
890 typedef struct logmsg {
891 	struct logmsg	*log_next;
892 	int		log_pri;
893 	char		log_msg[MAXMSG];
894 } logmsg;
895 
896 static logmsg *loghead = NULL;
897 static logmsg **logtailp = &loghead;
898 static mutex_t logmutex = DEFAULTMUTEX;
899 static cond_t logcond = DEFAULTCV;
900 static int logcount = 0;
901 
902 /*ARGSUSED*/
903 static void *
904 logthread(void *arg)
905 {
906 	while (1) {
907 		logmsg *msg;
908 		(void) mutex_lock(&logmutex);
909 		while ((msg = loghead) == NULL)
910 			(void) cond_wait(&logcond, &logmutex);
911 
912 		loghead = msg->log_next;
913 		logcount--;
914 		if (loghead == NULL) {
915 			logtailp = &loghead;
916 			logcount = 0;
917 		}
918 		(void) mutex_unlock(&logmutex);
919 		syslog(msg->log_pri, "%s", msg->log_msg);
920 		free(msg);
921 	}
922 	/* NOTREACHED */
923 }
924 
925 /*
926  * Initialize: read the configuration parameters from the default file.
927  */
928 static void
929 rpcb_check_init(void)
930 {
931 	thread_t tid;
932 	scf_simple_prop_t *prop;
933 	uint8_t	*bool;
934 
935 	if ((prop = scf_simple_prop_get(NULL, NULL, "config",
936 	    "enable_tcpwrappers")) != NULL) {
937 
938 		if ((bool = scf_simple_prop_next_boolean(prop)) != NULL) {
939 			wrap_enabled = (*bool == 0) ? B_FALSE : B_TRUE;
940 		} else {
941 			syslog(LOG_ALERT, "enable_tcpwrappers no value %s",
942 			    scf_strerror(scf_error()));
943 		}
944 		scf_simple_prop_free(prop);
945 	} else {
946 		syslog(LOG_ALERT, "unable to get enable_tcpwrappers %s",
947 		    scf_strerror(scf_error()));
948 	}
949 	if ((prop = scf_simple_prop_get(NULL, NULL, "config",
950 	    "verbose_logging")) != NULL) {
951 
952 		if ((bool = scf_simple_prop_next_boolean(prop)) != NULL) {
953 			verboselog = (*bool == 0) ? B_FALSE : B_TRUE;
954 		} else {
955 			syslog(LOG_ALERT, "verboselog no value %s",
956 			    scf_strerror(scf_error()));
957 		}
958 		scf_simple_prop_free(prop);
959 	} else {
960 		syslog(LOG_ALERT, "unable to get verbose_logging %s",
961 		    scf_strerror(scf_error()));
962 	}
963 	if ((prop = scf_simple_prop_get(NULL, NULL, "config",
964 	    "allow_indirect")) != NULL) {
965 
966 		if ((bool = scf_simple_prop_next_boolean(prop)) != NULL) {
967 			allow_indirect = (*bool == 0) ? B_FALSE : B_TRUE;
968 		} else {
969 			syslog(LOG_ALERT, "allow_indirect no value %s",
970 			    scf_strerror(scf_error()));
971 		}
972 		scf_simple_prop_free(prop);
973 	} else {
974 		syslog(LOG_ALERT, "unable to get allow_indirect %s",
975 		    scf_strerror(scf_error()));
976 	}
977 
978 	if (wrap_enabled)
979 		(void) thr_create(NULL, 0, logthread, NULL, THR_DETACHED, &tid);
980 }
981 
982 /*
983  * qsyslog() - queue a request for syslog(); if syslog blocks, the other
984  * thread blocks; we make sure we don't run out of memory by allowing
985  * only a limited number of outstandig syslog() requests.
986  */
987 void
988 qsyslog(int pri, const char *fmt, ...)
989 {
990 	logmsg *msg = malloc(sizeof (*msg));
991 	int oldcount;
992 	va_list ap;
993 
994 	if (msg == NULL)
995 		return;
996 
997 	msg->log_pri = pri;
998 
999 	va_start(ap, fmt);
1000 	(void) vsnprintf(msg->log_msg, sizeof (msg->log_msg), fmt, ap);
1001 	va_end(ap);
1002 
1003 	msg->log_next = NULL;
1004 
1005 	(void) mutex_lock(&logmutex);
1006 	oldcount = logcount;
1007 	if (logcount < MAXLOG) {
1008 		logcount++;
1009 		*logtailp = msg;
1010 		logtailp = &msg->log_next;
1011 	} else {
1012 		free(msg);
1013 	}
1014 	(void) mutex_unlock(&logmutex);
1015 	if (oldcount == 0)
1016 		(void) cond_signal(&logcond);
1017 }
1018