1/*	$NetBSD: rpcbind.c,v 1.2 2010/07/28 15:11:30 pooka Exp $	*/
2
3/*
4 * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
5 * unrestricted use provided that this legend is included on all tape
6 * media and as a part of the software program in whole or part.  Users
7 * may copy or modify Sun RPC without charge, but are not authorized
8 * to license or distribute it to anyone else except as part of a product or
9 * program developed by the user.
10 *
11 * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
12 * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
13 * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
14 *
15 * Sun RPC is provided with no support and without any obligation on the
16 * part of Sun Microsystems, Inc. to assist in its use, correction,
17 * modification or enhancement.
18 *
19 * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
20 * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
21 * OR ANY PART THEREOF.
22 *
23 * In no event will Sun Microsystems, Inc. be liable for any lost revenue
24 * or profits or other special, indirect and consequential damages, even if
25 * Sun has been advised of the possibility of such damages.
26 *
27 * Sun Microsystems, Inc.
28 * 2550 Garcia Avenue
29 * Mountain View, California  94043
30 */
31/*
32 * Copyright (c) 1984 - 1991 by Sun Microsystems, Inc.
33 */
34
35/* #ident	"@(#)rpcbind.c	1.19	94/04/25 SMI" */
36
37#if 0
38#ifndef lint
39static	char sccsid[] = "@(#)rpcbind.c 1.35 89/04/21 Copyr 1984 Sun Micro";
40#endif
41#endif
42
43/*
44 * rpcbind.c
45 * Implements the program, version to address mapping for rpc.
46 *
47 */
48
49#include <sys/types.h>
50#include <sys/stat.h>
51#include <sys/errno.h>
52#include <sys/time.h>
53#include <sys/resource.h>
54#include <sys/wait.h>
55#include <sys/signal.h>
56#include <sys/socket.h>
57#include <sys/un.h>
58#include <rpc/rpc.h>
59#ifdef PORTMAP
60#include <netinet/in.h>
61#endif
62#include <netdb.h>
63#include <stdio.h>
64#include <netconfig.h>
65#include <stdlib.h>
66#include <unistd.h>
67#include <syslog.h>
68#include <err.h>
69#include <util.h>
70#include <pwd.h>
71#include <semaphore.h>
72#include <string.h>
73#include <errno.h>
74#include "rpcbind.h"
75
76#include <rump/rump.h>
77#include <rump/rump_syscalls.h>
78
79/* Global variables */
80int debugging = 1;	/* 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#include "svc_fdset.h"
85
86/* who to suid to if -s is given */
87#define RUN_AS  "daemon"
88
89int runasdaemon = 0;
90int insecure = 0;
91int oldstyle_local = 0;
92int verboselog = 0;
93
94#ifdef WARMSTART
95/* Local Variable */
96static int warmstart = 0;	/* Grab a old copy of registrations */
97#endif
98
99#ifdef PORTMAP
100struct pmaplist *list_pml;	/* A list of version 2 rpcbind services */
101const char *udptrans;		/* Name of UDP transport */
102const char *tcptrans;		/* Name of TCP transport */
103const char *udp_uaddr;		/* Universal UDP address */
104const char *tcp_uaddr;		/* Universal TCP address */
105#endif
106static const char servname[] = "sunrpc";
107
108const char rpcbind_superuser[] = "superuser";
109const char rpcbind_unknown[] = "unknown";
110
111static int init_transport(struct netconfig *);
112static void rbllist_add(rpcprog_t, rpcvers_t, struct netconfig *,
113    struct netbuf *);
114static void terminate(int);
115#if 0
116static void parseargs(int, char *[]);
117#endif
118
119int rpcbind_main(void *);
120int
121rpcbind_main(void *arg)
122{
123	struct netconfig *nconf;
124	void *nc_handle;	/* Net config handle */
125	struct rlimit rl;
126	int maxrec = RPC_MAXDATASIZE;
127	extern sem_t gensem;
128
129#if 0
130	parseargs(argc, argv);
131#endif
132
133	alloc_fdset();
134
135	getrlimit(RLIMIT_NOFILE, &rl);
136	if (rl.rlim_cur < 128) {
137		if (rl.rlim_max <= 128)
138			rl.rlim_cur = rl.rlim_max;
139		else
140			rl.rlim_cur = 128;
141		setrlimit(RLIMIT_NOFILE, &rl);
142	}
143#if 0
144	if (geteuid()) /* This command allowed only to root */
145		errx(1, "Sorry. You are not superuser");
146#endif
147	nc_handle = setnetconfig(); 	/* open netconfig file */
148	if (nc_handle == NULL)
149		errx(1, "could not read /etc/netconfig");
150#ifdef PORTMAP
151	udptrans = "";
152	tcptrans = "";
153#endif
154
155	nconf = getnetconfigent("local");
156	if (nconf == NULL)
157		errx(1, "can't find local transport");
158
159	rpc_control(RPC_SVC_CONNMAXREC_SET, &maxrec);
160
161	init_transport(nconf);
162
163	while ((nconf = getnetconfig(nc_handle))) {
164		if (nconf->nc_flag & NC_VISIBLE)
165			init_transport(nconf);
166	}
167	endnetconfig(nc_handle);
168
169	/* catch the usual termination signals for graceful exit */
170	(void) signal(SIGCHLD, reap);
171	(void) signal(SIGINT, terminate);
172	(void) signal(SIGTERM, terminate);
173	(void) signal(SIGQUIT, terminate);
174	/* ignore others that could get sent */
175	(void) signal(SIGPIPE, SIG_IGN);
176	//(void) signal(SIGHUP, SIG_IGN); used by mountd
177	(void) signal(SIGUSR1, SIG_IGN);
178	(void) signal(SIGUSR2, SIG_IGN);
179#ifdef WARMSTART
180	if (warmstart) {
181		read_warmstart();
182	}
183#endif
184	if (debugging) {
185		printf("rpcbind debugging enabled.");
186		if (doabort) {
187			printf("  Will abort on errors!\n");
188		} else {
189			printf("\n");
190		}
191	} else {
192		if (daemon(0, 0))
193			err(1, "fork failed");
194	}
195
196	openlog("rpcbind", 0, LOG_DAEMON);
197	pidfile(NULL);
198
199	if (runasdaemon) {
200		struct passwd *p;
201
202		if((p = getpwnam(RUN_AS)) == NULL) {
203			syslog(LOG_ERR, "cannot get uid of daemon: %m");
204			exit(1);
205		}
206		if (setuid(p->pw_uid) == -1) {
207			syslog(LOG_ERR, "setuid to daemon failed: %m");
208			exit(1);
209		}
210	}
211
212	network_init();
213
214	sem_post(&gensem);
215	my_svc_run();
216	syslog(LOG_ERR, "svc_run returned unexpectedly");
217	rpcbind_abort();
218	/* NOTREACHED */
219
220	return 0;
221}
222
223/*
224 * Adds the entry into the rpcbind database.
225 * If PORTMAP, then for UDP and TCP, it adds the entries for version 2 also
226 * Returns 0 if succeeds, else fails
227 */
228static int
229init_transport(struct netconfig *nconf)
230{
231	int fd;
232	struct t_bind taddr;
233	struct addrinfo hints, *res = NULL;
234	struct __rpc_sockinfo si;
235	SVCXPRT	*my_xprt;
236	int status;	/* bound checking ? */
237	int aicode;
238	int addrlen;
239	struct sockaddr *sa;
240	struct sockaddr_un sun;
241	const int one = 1;
242
243	if ((nconf->nc_semantics != NC_TPI_CLTS) &&
244		(nconf->nc_semantics != NC_TPI_COTS) &&
245		(nconf->nc_semantics != NC_TPI_COTS_ORD))
246		return 1;	/* not my type */
247#ifdef RPCBIND_DEBUG
248	if (debugging) {
249		int i;
250		char **s;
251
252		(void)fprintf(stderr, "%s: %ld lookup routines :\n",
253		    nconf->nc_netid, nconf->nc_nlookups);
254		for (i = 0, s = nconf->nc_lookups; i < nconf->nc_nlookups;
255		     i++, s++)
256			(void)fprintf(stderr, "[%d] - %s\n", i, *s);
257	}
258#endif
259
260	/*
261	 * XXX - using RPC library internal functions.
262	 */
263	if ((fd = __rpc_nconf2fd(nconf)) < 0) {
264		if (errno == EAFNOSUPPORT)
265			return 1;
266		warn("Cannot create socket for `%s'", nconf->nc_netid);
267		return 1;
268	}
269
270	if (!__rpc_nconf2sockinfo(nconf, &si)) {
271		warnx("Cannot get information for `%s'", nconf->nc_netid);
272		return 1;
273	}
274
275	if (si.si_af == AF_INET6) {
276		/*
277		 * We're doing host-based access checks here, so don't allow
278		 * v4-in-v6 to confuse things.
279		 */
280		if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &one,
281		    sizeof one) < 0) {
282			warn("Can't make socket ipv6 only");
283			return 1;
284		}
285	}
286
287
288	if (!strcmp(nconf->nc_netid, "local")) {
289		(void)memset(&sun, 0, sizeof sun);
290		sun.sun_family = AF_LOCAL;
291		(void)rump_sys_unlink(_PATH_RPCBINDSOCK);
292		(void)strlcpy(sun.sun_path, _PATH_RPCBINDSOCK,
293		    sizeof(sun.sun_path));
294		sun.sun_len = SUN_LEN(&sun);
295		addrlen = sizeof(struct sockaddr_un);
296		sa = (struct sockaddr *)&sun;
297	} else {
298		/* Get rpcbind's address on this transport */
299
300		(void)memset(&hints, 0, sizeof hints);
301		hints.ai_flags = AI_PASSIVE;
302		hints.ai_family = si.si_af;
303		hints.ai_socktype = si.si_socktype;
304		hints.ai_protocol = si.si_proto;
305		if ((aicode = getaddrinfo(NULL, servname, &hints, &res)) != 0) {
306			warnx("Cannot get local address for `%s' (%s)",
307			    nconf->nc_netid, gai_strerror(aicode));
308			return 1;
309		}
310		addrlen = res->ai_addrlen;
311		sa = (struct sockaddr *)res->ai_addr;
312	}
313
314	if (bind(fd, sa, addrlen) < 0) {
315		warn("Cannot bind `%s'", nconf->nc_netid);
316		if (res != NULL)
317			freeaddrinfo(res);
318		return 1;
319	}
320#if 0
321	if (sa->sa_family == AF_LOCAL)
322		if (rump_sys_chmod(sun.sun_path, S_IRWXU|S_IRWXG|S_IRWXO) == -1)
323			warn("Cannot chmod `%s'", sun.sun_path);
324#endif
325
326	/* Copy the address */
327	taddr.addr.len = taddr.addr.maxlen = addrlen;
328	taddr.addr.buf = malloc(addrlen);
329	if (taddr.addr.buf == NULL) {
330		warn("Cannot allocate memory for `%s' address",
331		    nconf->nc_netid);
332		if (res != NULL)
333			freeaddrinfo(res);
334		return 1;
335	}
336	(void)memcpy(taddr.addr.buf, sa, addrlen);
337#ifdef RPCBIND_DEBUG
338	if (debugging) {
339		/* for debugging print out our universal address */
340		char *uaddr;
341		struct netbuf nb;
342
343		nb.buf = sa;
344		nb.len = nb.maxlen = sa->sa_len;
345		uaddr = taddr2uaddr(nconf, &nb);
346		(void)fprintf(stderr, "rpcbind: my address is %s\n", uaddr);
347		(void)free(uaddr);
348	}
349#endif
350
351	if (res != NULL)
352		freeaddrinfo(res);
353
354	if (nconf->nc_semantics != NC_TPI_CLTS)
355		listen(fd, SOMAXCONN);
356
357	my_xprt = (SVCXPRT *)svc_tli_create(fd, nconf, &taddr, RPC_MAXDATASIZE,
358	    RPC_MAXDATASIZE);
359	if (my_xprt == NULL) {
360		warnx("Could not create service for `%s'", nconf->nc_netid);
361		goto error;
362	}
363
364#ifdef PORTMAP
365	/*
366	 * Register both the versions for tcp/ip, udp/ip and local.
367	 */
368	if ((strcmp(nconf->nc_protofmly, NC_INET) == 0 &&
369		(strcmp(nconf->nc_proto, NC_TCP) == 0 ||
370		strcmp(nconf->nc_proto, NC_UDP) == 0)) ||
371		strcmp(nconf->nc_netid, "local") == 0) {
372		struct pmaplist *pml;
373
374		if (!svc_register(my_xprt, PMAPPROG, PMAPVERS,
375			pmap_service, 0)) {
376			warn("Could not register on `%s'", nconf->nc_netid);
377			goto error;
378		}
379		pml = malloc(sizeof (struct pmaplist));
380		if (pml == NULL) {
381			warn("Cannot allocate memory");
382			goto error;
383		}
384		pml->pml_map.pm_prog = PMAPPROG;
385		pml->pml_map.pm_vers = PMAPVERS;
386		pml->pml_map.pm_port = PMAPPORT;
387		if (strcmp(nconf->nc_proto, NC_TCP) == 0) {
388			if (tcptrans[0]) {
389				warnx(
390				    "Cannot have more than one TCP transport");
391				free(pml);
392				goto error;
393			}
394			tcptrans = strdup(nconf->nc_netid);
395			if (tcptrans == NULL) {
396				free(pml);
397				warn("Cannot allocate memory");
398				goto error;
399			}
400			pml->pml_map.pm_prot = IPPROTO_TCP;
401
402			/* Let's snarf the universal address */
403			/* "h1.h2.h3.h4.p1.p2" */
404			tcp_uaddr = taddr2uaddr(nconf, &taddr.addr);
405		} else if (strcmp(nconf->nc_proto, NC_UDP) == 0) {
406			if (udptrans[0]) {
407				free(pml);
408				warnx(
409				"Cannot have more than one UDP transport");
410				goto error;
411			}
412			udptrans = strdup(nconf->nc_netid);
413			if (udptrans == NULL) {
414				free(pml);
415				warn("Cannot allocate memory");
416				goto error;
417			}
418			pml->pml_map.pm_prot = IPPROTO_UDP;
419
420			/* Let's snarf the universal address */
421			/* "h1.h2.h3.h4.p1.p2" */
422			udp_uaddr = taddr2uaddr(nconf, &taddr.addr);
423		}
424		pml->pml_next = list_pml;
425		list_pml = pml;
426
427		/* Add version 3 information */
428		pml = malloc(sizeof (struct pmaplist));
429		if (pml == NULL) {
430			warn("Cannot allocate memory");
431			goto error;
432		}
433		pml->pml_map = list_pml->pml_map;
434		pml->pml_map.pm_vers = RPCBVERS;
435		pml->pml_next = list_pml;
436		list_pml = pml;
437
438		/* Add version 4 information */
439		pml = malloc(sizeof (struct pmaplist));
440		if (pml == NULL) {
441			warn("Cannot allocate memory");
442			goto error;
443		}
444		pml->pml_map = list_pml->pml_map;
445		pml->pml_map.pm_vers = RPCBVERS4;
446		pml->pml_next = list_pml;
447		list_pml = pml;
448
449		/* Also add version 2 stuff to rpcbind list */
450		rbllist_add(PMAPPROG, PMAPVERS, nconf, &taddr.addr);
451	}
452#endif
453
454	/* version 3 registration */
455	if (!svc_reg(my_xprt, RPCBPROG, RPCBVERS, rpcb_service_3, NULL)) {
456		warn("Could not register %s version 3", nconf->nc_netid);
457		goto error;
458	}
459	rbllist_add(RPCBPROG, RPCBVERS, nconf, &taddr.addr);
460
461	/* version 4 registration */
462	if (!svc_reg(my_xprt, RPCBPROG, RPCBVERS4, rpcb_service_4, NULL)) {
463		warn("Could not register %s version 4", nconf->nc_netid);
464		goto error;
465	}
466	rbllist_add(RPCBPROG, RPCBVERS4, nconf, &taddr.addr);
467
468	/* decide if bound checking works for this transport */
469	status = add_bndlist(nconf, &taddr.addr);
470#ifdef RPCBIND_DEBUG
471	if (debugging) {
472		if (status < 0) {
473			fprintf(stderr, "Error in finding bind status for %s\n",
474				nconf->nc_netid);
475		} else if (status == 0) {
476			fprintf(stderr, "check binding for %s\n",
477				nconf->nc_netid);
478		} else if (status > 0) {
479			fprintf(stderr, "No check binding for %s\n",
480				nconf->nc_netid);
481		}
482	}
483#endif
484	/*
485	 * rmtcall only supported on CLTS transports for now.
486	 */
487	if (nconf->nc_semantics == NC_TPI_CLTS) {
488		status = create_rmtcall_fd(nconf);
489
490#ifdef RPCBIND_DEBUG
491		if (debugging) {
492			if (status < 0) {
493				fprintf(stderr,
494				    "Could not create rmtcall fd for %s\n",
495					nconf->nc_netid);
496			} else {
497				fprintf(stderr, "rmtcall fd for %s is %d\n",
498					nconf->nc_netid, status);
499			}
500		}
501#endif
502	}
503	return (0);
504error:
505	(void)rump_sys_close(fd);
506	return (1);
507}
508
509static void
510rbllist_add(rpcprog_t prog, rpcvers_t vers, struct netconfig *nconf,
511	    struct netbuf *addr)
512{
513	rpcblist_ptr rbl;
514
515	rbl = malloc(sizeof(rpcblist));
516	if (rbl == NULL) {
517		warn("Out of memory");
518		return;
519	}
520
521	rbl->rpcb_map.r_prog = prog;
522	rbl->rpcb_map.r_vers = vers;
523	rbl->rpcb_map.r_netid = strdup(nconf->nc_netid);
524	rbl->rpcb_map.r_addr = taddr2uaddr(nconf, addr);
525	rbl->rpcb_map.r_owner = strdup(rpcbind_superuser);
526	rbl->rpcb_next = list_rbl;	/* Attach to global list */
527	list_rbl = rbl;
528}
529
530/*
531 * Catch the signal and die
532 */
533static void
534terminate(int dummy)
535{
536#ifdef WARMSTART
537	syslog(LOG_ERR,
538		"rpcbind terminating on signal. Restart with \"rpcbind -w\"");
539	write_warmstart();	/* Dump yourself */
540#endif
541	exit(2);
542}
543
544void
545rpcbind_abort()
546{
547#ifdef WARMSTART
548	write_warmstart();	/* Dump yourself */
549#endif
550	abort();
551}
552
553#if 0
554/* get command line options */
555static void
556parseargs(int argc, char *argv[])
557{
558	int c;
559
560	while ((c = getopt(argc, argv, "dwailLs")) != -1) {
561		switch (c) {
562		case 'a':
563			doabort = 1;	/* when debugging, do an abort on */
564			break;		/* errors; for rpcbind developers */
565					/* only! */
566		case 'd':
567			debugging = 1;
568			break;
569		case 'i':
570			insecure = 1;
571			break;
572		case 'L':
573			oldstyle_local = 1;
574			break;
575		case 'l':
576			verboselog = 1;
577			break;
578		case 's':
579			runasdaemon = 1;
580			break;
581#ifdef WARMSTART
582		case 'w':
583			warmstart = 1;
584			break;
585#endif
586		default:	/* error */
587			fprintf(stderr,	"usage: rpcbind [-Idwils]\n");
588			exit (1);
589		}
590	}
591	if (doabort && !debugging) {
592	    fprintf(stderr,
593		"-a (abort) specified without -d (debugging) -- ignored.\n");
594	    doabort = 0;
595	}
596}
597#endif
598
599void
600reap(int dummy)
601{
602	int save_errno = errno;
603
604	while (wait3(NULL, WNOHANG, NULL) > 0)
605		;
606	errno = save_errno;
607}
608
609void
610toggle_verboselog(int dummy)
611{
612	verboselog = !verboselog;
613}
614