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