xref: /openbsd/usr.sbin/inetd/inetd.c (revision 1c33b230)
1 /*	$OpenBSD: inetd.c,v 1.165 2023/09/03 22:01:00 bluhm Exp $	*/
2 
3 /*
4  * Copyright (c) 1983,1991 The Regents of the University of California.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. Neither the name of the University nor the names of its contributors
16  *    may be used to endorse or promote products derived from this software
17  *    without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31 
32 /*
33  * Inetd - Internet super-server
34  *
35  * This program invokes all internet services as needed.
36  * connection-oriented services are invoked each time a
37  * connection is made, by creating a process.  This process
38  * is passed the connection as file descriptor 0 and is
39  * expected to do a getpeername to find out the source host
40  * and port.
41  *
42  * Datagram oriented services are invoked when a datagram
43  * arrives; a process is created and passed a pending message
44  * on file descriptor 0.  Datagram servers may either connect
45  * to their peer, freeing up the original socket for inetd
46  * to receive further messages on, or ``take over the socket'',
47  * processing all arriving datagrams and, eventually, timing
48  * out.	 The first type of server is said to be ``multi-threaded'';
49  * the second type of server ``single-threaded''.
50  *
51  * Inetd uses a configuration file which is read at startup
52  * and, possibly, at some later time in response to a hangup signal.
53  * The configuration file is ``free format'' with fields given in the
54  * order shown below.  Continuation lines for an entry must begin with
55  * a space or tab.  All fields must be present in each entry.
56  *
57  *	service name			must be in /etc/services
58  *	socket type			stream/dgram
59  *	protocol			must be in /etc/protocols
60  *	wait/nowait[.max]		single-threaded/multi-threaded, max #
61  *	user[.group] or user[:group]	user/group to run daemon as
62  *	server program			full path name
63  *	server program arguments	maximum of MAXARGS (20)
64  *
65  * For RPC services
66  *      service name/version            must be in /etc/rpc
67  *	socket type			stream/dgram
68  *	protocol			must be in /etc/protocols
69  *	wait/nowait[.max]		single-threaded/multi-threaded
70  *	user[.group] or user[:group]	user to run daemon as
71  *	server program			full path name
72  *	server program arguments	maximum of MAXARGS (20)
73  *
74  * For non-RPC services, the "service name" can be of the form
75  * hostaddress:servicename, in which case the hostaddress is used
76  * as the host portion of the address to listen on.  If hostaddress
77  * consists of a single `*' character, INADDR_ANY is used.
78  *
79  * A line can also consist of just
80  *      hostaddress:
81  * where hostaddress is as in the preceding paragraph.  Such a line must
82  * have no further fields; the specified hostaddress is remembered and
83  * used for all further lines that have no hostaddress specified,
84  * until the next such line (or EOF).  (This is why * is provided to
85  * allow explicit specification of INADDR_ANY.)  A line
86  *      *:
87  * is implicitly in effect at the beginning of the file.
88  *
89  * The hostaddress specifier may (and often will) contain dots;
90  * the service name must not.
91  *
92  * For RPC services, host-address specifiers are accepted and will
93  * work to some extent; however, because of limitations in the
94  * portmapper interface, it will not work to try to give more than
95  * one line for any given RPC service, even if the host-address
96  * specifiers are different.
97  *
98  * Comment lines are indicated by a `#' in column 1.
99  */
100 
101 /*
102  * Here's the scoop concerning the user[.:]group feature:
103  *
104  * 1) set-group-option off.
105  *
106  *	a) user = root:	NO setuid() or setgid() is done
107  *
108  *	b) other:	setgid(primary group as found in passwd)
109  *			initgroups(name, primary group)
110  *			setuid()
111  *
112  * 2) set-group-option on.
113  *
114  *	a) user = root:	setgid(specified group)
115  *			NO initgroups()
116  *			NO setuid()
117  *
118  *	b) other:	setgid(specified group)
119  *			initgroups(name, specified group)
120  *			setuid()
121  *
122  */
123 
124 #include <sys/stat.h>
125 #include <sys/socket.h>
126 #include <sys/un.h>
127 #include <sys/wait.h>
128 #include <sys/time.h>
129 #include <sys/resource.h>
130 
131 #include <net/if.h>
132 #include <netinet/in.h>
133 #include <arpa/inet.h>
134 
135 #include <err.h>
136 #include <errno.h>
137 #include <ctype.h>
138 #include <signal.h>
139 #include <netdb.h>
140 #include <syslog.h>
141 #include <pwd.h>
142 #include <grp.h>
143 #include <stdio.h>
144 #include <stdlib.h>
145 #include <unistd.h>
146 #include <limits.h>
147 #include <string.h>
148 #include <login_cap.h>
149 #include <ifaddrs.h>
150 #include <rpc/rpc.h>
151 #include <rpc/pmap_clnt.h>
152 #include <rpcsvc/nfs_prot.h>
153 #include <event.h>
154 #include "pathnames.h"
155 
156 #define MINIMUM(a, b)	(((a) < (b)) ? (a) : (b))
157 
158 #define	TOOMANY		256		/* don't start more than TOOMANY */
159 #define	CNT_INTVL	60		/* servers in CNT_INTVL sec. */
160 #define	RETRYTIME	(60*10)		/* retry after bind or server fail */
161 
162 int	 debug = 0;
163 int	 maxsock;
164 int	 toomany = TOOMANY;
165 int	 timingout;
166 struct	 servent *sp;
167 uid_t	 uid;
168 
169 #ifndef OPEN_MAX
170 #define OPEN_MAX	64
171 #endif
172 
173 /* Reserve some descriptors, 3 stdio + at least: 1 log, 1 conf. file */
174 #define FD_MARGIN	(8)
175 rlim_t	rlim_nofile_cur = OPEN_MAX;
176 
177 struct rlimit	rlim_nofile;
178 
179 struct	servtab {
180 	char	*se_hostaddr;		/* host address to listen on */
181 	char	*se_service;		/* name of service */
182 	int	se_socktype;		/* type of socket to use */
183 	int	se_family;		/* address family */
184 	char	*se_proto;		/* protocol used */
185 	int	se_rpcprog;		/* rpc program number */
186 	int	se_rpcversl;		/* rpc program lowest version */
187 	int	se_rpcversh;		/* rpc program highest version */
188 #define isrpcservice(sep)	((sep)->se_rpcversl != 0)
189 	pid_t	se_wait;		/* single threaded server */
190 	short	se_checked;		/* looked at during merge */
191 	char	*se_user;		/* user name to run as */
192 	char	*se_group;		/* group name to run as */
193 	struct	biltin *se_bi;		/* if built-in, description */
194 	char	*se_server;		/* server program */
195 #define	MAXARGV 20
196 	char	*se_argv[MAXARGV+1];	/* program arguments */
197 	int	se_fd;			/* open descriptor */
198 	union {
199 		struct	sockaddr se_un_ctrladdr;
200 		struct	sockaddr_in se_un_ctrladdr_in;
201 		struct	sockaddr_in6 se_un_ctrladdr_in6;
202 		struct	sockaddr_un se_un_ctrladdr_un;
203 		struct	sockaddr_storage se_un_ctrladdr_storage;
204 	} se_un;			/* bound address */
205 #define se_ctrladdr	se_un.se_un_ctrladdr
206 #define se_ctrladdr_in	se_un.se_un_ctrladdr_in
207 #define se_ctrladdr_in6	se_un.se_un_ctrladdr_in6
208 #define se_ctrladdr_un	se_un.se_un_ctrladdr_un
209 #define se_ctrladdr_storage	se_un.se_un_ctrladdr_storage
210 	int	se_ctrladdr_size;
211 	int	se_max;			/* max # of instances of this service */
212 	int	se_count;		/* number started since se_time */
213 	struct	timeval se_time;	/* start of se_count */
214 	struct	servtab *se_next;
215 	struct	event se_event;
216 } *servtab;
217 
218 void echo_stream(int, struct servtab *);
219 void discard_stream(int, struct servtab *);
220 void machtime_stream(int, struct servtab *);
221 void daytime_stream(int, struct servtab *);
222 void chargen_stream(int, struct servtab *);
223 void echo_dg(int, struct servtab *);
224 void discard_dg(int, struct servtab *);
225 void machtime_dg(int, struct servtab *);
226 void daytime_dg(int, struct servtab *);
227 void chargen_dg(int, struct servtab *);
228 
229 struct biltin {
230 	char	*bi_service;		/* internally provided service name */
231 	int	bi_socktype;		/* type of socket supported */
232 	short	bi_fork;		/* 1 if should fork before call */
233 	short	bi_wait;		/* 1 if should wait for child */
234 	void	(*bi_fn)(int, struct servtab *);
235 } biltins[] = {
236 	/* Echo received data */
237 	{ "echo",	SOCK_STREAM,	1, 0,	echo_stream },
238 	{ "echo",	SOCK_DGRAM,	0, 0,	echo_dg },
239 
240 	/* Internet /dev/null */
241 	{ "discard",	SOCK_STREAM,	1, 0,	discard_stream },
242 	{ "discard",	SOCK_DGRAM,	0, 0,	discard_dg },
243 
244 	/* Return 32 bit time since 1900 */
245 	{ "time",	SOCK_STREAM,	0, 0,	machtime_stream },
246 	{ "time",	SOCK_DGRAM,	0, 0,	machtime_dg },
247 
248 	/* Return human-readable time */
249 	{ "daytime",	SOCK_STREAM,	0, 0,	daytime_stream },
250 	{ "daytime",	SOCK_DGRAM,	0, 0,	daytime_dg },
251 
252 	/* Familiar character generator */
253 	{ "chargen",	SOCK_STREAM,	1, 0,	chargen_stream },
254 	{ "chargen",	SOCK_DGRAM,	0, 0,	chargen_dg },
255 
256 	{ 0 }
257 };
258 
259 struct event evsig_alrm;
260 struct event evsig_hup;
261 struct event evsig_chld;
262 struct event evsig_term;
263 struct event evsig_int;
264 
265 void	config(int, short, void *);
266 void	reap(int, short, void *);
267 void	retry(int, short, void *);
268 void	die(int, short, void *);
269 
270 void	spawn(int, short, void *);
271 void	gettcp(int, short, void *);
272 int	setconfig(void);
273 void	endconfig(void);
274 void	register_rpc(struct servtab *);
275 void	unregister_rpc(struct servtab *);
276 void	freeconfig(struct servtab *);
277 void	print_service(char *, struct servtab *);
278 void	setup(struct servtab *);
279 struct servtab *getconfigent(void);
280 int	bump_nofile(void);
281 struct servtab *enter(struct servtab *);
282 int	matchconf(struct servtab *, struct servtab *);
283 int	dg_broadcast(struct in_addr *in);
284 
285 #define NUMINT	(sizeof(intab) / sizeof(struct inent))
286 char	*CONFIG = _PATH_INETDCONF;
287 
288 int		dg_badinput(struct sockaddr *sa);
289 void		inetd_setproctitle(char *a, int s);
290 void		initring(void);
291 u_int32_t	machtime(void);
292 
293 int
main(int argc,char * argv[])294 main(int argc, char *argv[])
295 {
296 	int ch;
297 
298 	while ((ch = getopt(argc, argv, "dR:")) != -1)
299 		switch (ch) {
300 		case 'd':
301 			debug = 1;
302 			break;
303 		case 'R': {	/* invocation rate */
304 			char *p;
305 			int val;
306 
307 			val = strtoul(optarg, &p, 0);
308 			if (val >= 1 && *p == '\0') {
309 				toomany = val;
310 				break;
311 			}
312 			syslog(LOG_ERR,
313 			    "-R %s: bad value for service invocation rate",
314 			    optarg);
315 			break;
316 		}
317 		default:
318 			fprintf(stderr,
319 			    "usage: inetd [-d] [-R rate] [configuration_file]\n");
320 			exit(1);
321 		}
322 	argc -= optind;
323 	argv += optind;
324 
325 	uid = getuid();
326 	if (uid != 0)
327 		CONFIG = NULL;
328 	if (argc > 0)
329 		CONFIG = argv[0];
330 	if (CONFIG == NULL) {
331 		fprintf(stderr, "inetd: non-root must specify a config file\n");
332 		exit(1);
333 	}
334 	if (argc > 1) {
335 		fprintf(stderr, "inetd: more than one argument specified\n");
336 		exit(1);
337 	}
338 
339 	umask(022);
340 	if (debug == 0) {
341 		daemon(0, 0);
342 		if (uid == 0)
343 			(void) setlogin("");
344 	}
345 
346 	if (pledge("stdio rpath cpath getpw dns inet unix proc exec id", NULL) == -1)
347 		err(1, "pledge");
348 
349 	if (uid == 0) {
350 		gid_t gid = getgid();
351 
352 		/* If run by hand, ensure groups vector gets trashed */
353 		setgroups(1, &gid);
354 	}
355 
356 	openlog("inetd", LOG_PID | LOG_NOWAIT, LOG_DAEMON);
357 
358 	if (getrlimit(RLIMIT_NOFILE, &rlim_nofile) == -1) {
359 		syslog(LOG_ERR, "getrlimit: %m");
360 	} else {
361 		rlim_nofile_cur = rlim_nofile.rlim_cur;
362 		if (rlim_nofile_cur == RLIM_INFINITY)	/* ! */
363 			rlim_nofile_cur = OPEN_MAX;
364 	}
365 
366 	event_init();
367 
368 	signal_set(&evsig_alrm, SIGALRM, retry, NULL);
369 	signal_add(&evsig_alrm, NULL);
370 
371 	config(0, 0, NULL);
372 
373 	signal_set(&evsig_hup, SIGHUP, config, NULL);
374 	signal_add(&evsig_hup, NULL);
375 	signal_set(&evsig_chld, SIGCHLD, reap, NULL);
376 	signal_add(&evsig_chld, NULL);
377 	signal_set(&evsig_term, SIGTERM, die, NULL);
378 	signal_add(&evsig_term, NULL);
379 	signal_set(&evsig_int, SIGINT, die, NULL);
380 	signal_add(&evsig_int, NULL);
381 
382 	signal(SIGPIPE, SIG_IGN);
383 
384 	event_dispatch();
385 
386 	return (0);
387 }
388 
389 void
gettcp(int fd,short events,void * xsep)390 gettcp(int fd, short events, void *xsep)
391 {
392 	struct servtab *sep = xsep;
393 	int ctrl;
394 
395 	if (debug)
396 		fprintf(stderr, "someone wants %s\n", sep->se_service);
397 
398 	ctrl = accept(sep->se_fd, NULL, NULL);
399 	if (debug)
400 		fprintf(stderr, "accept, ctrl %d\n", ctrl);
401 	if (ctrl == -1) {
402 		if (errno != EWOULDBLOCK && errno != EINTR &&
403 		    errno != ECONNABORTED)
404 			syslog(LOG_WARNING, "accept (for %s): %m",
405 			    sep->se_service);
406 		return;
407 	}
408 	if ((sep->se_family == AF_INET || sep->se_family == AF_INET6) &&
409 	    sep->se_socktype == SOCK_STREAM) {
410 		struct sockaddr_storage peer;
411 		socklen_t plen = sizeof(peer);
412 		char sbuf[NI_MAXSERV];
413 
414 		if (getpeername(ctrl, (struct sockaddr *)&peer, &plen) == -1) {
415 			syslog(LOG_WARNING, "could not getpeername");
416 			close(ctrl);
417 			return;
418 		}
419 		if (getnameinfo((struct sockaddr *)&peer, plen, NULL, 0,
420 		    sbuf, sizeof(sbuf), NI_NUMERICSERV) == 0 &&
421 		    strtonum(sbuf, 1, USHRT_MAX, NULL) == 20) {
422 			/*
423 			 * ignore things that look like ftp bounce
424 			 */
425 			close(ctrl);
426 			return;
427 		}
428 	}
429 
430 	spawn(ctrl, 0, sep);
431 }
432 
433 int
dg_badinput(struct sockaddr * sa)434 dg_badinput(struct sockaddr *sa)
435 {
436 	struct in_addr in;
437 	struct in6_addr *in6;
438 	u_int16_t port;
439 
440 	switch (sa->sa_family) {
441 	case AF_INET:
442 		in.s_addr = ntohl(((struct sockaddr_in *)sa)->sin_addr.s_addr);
443 		port = ntohs(((struct sockaddr_in *)sa)->sin_port);
444 		if (IN_MULTICAST(in.s_addr))
445 			goto bad;
446 		switch ((in.s_addr & 0xff000000) >> 24) {
447 		case 0: case 255:
448 			goto bad;
449 		}
450 		if (dg_broadcast(&in))
451 			goto bad;
452 		break;
453 	case AF_INET6:
454 		in6 = &((struct sockaddr_in6 *)sa)->sin6_addr;
455 		port = ntohs(((struct sockaddr_in6 *)sa)->sin6_port);
456 		if (IN6_IS_ADDR_MULTICAST(in6) || IN6_IS_ADDR_UNSPECIFIED(in6))
457 			goto bad;
458 		/*
459 		 * OpenBSD does not support IPv4-mapped and
460 		 * IPv4-compatible IPv6 addresses (RFC2553). We should
461 		 * drop the packet.
462 		 */
463 		if (IN6_IS_ADDR_V4MAPPED(in6) || IN6_IS_ADDR_V4COMPAT(in6))
464 			goto bad;
465 		break;
466 	default:
467 		/* Unsupported AF */
468 		goto bad;
469 	}
470 
471 	if (port < IPPORT_RESERVED || port == NFS_PORT)
472 		goto bad;
473 
474 	return (0);
475 
476 bad:
477 	return (1);
478 }
479 
480 int
dg_broadcast(struct in_addr * in)481 dg_broadcast(struct in_addr *in)
482 {
483 	struct ifaddrs *ifa, *ifap;
484 	struct sockaddr_in *sin;
485 
486 	if (getifaddrs(&ifap) == -1)
487 		return (0);
488 	for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
489 		if (ifa->ifa_addr == NULL ||
490 		    ifa->ifa_addr->sa_family != AF_INET ||
491 		    (ifa->ifa_flags & IFF_BROADCAST) == 0)
492 			continue;
493 		sin = (struct sockaddr_in *)ifa->ifa_broadaddr;
494 		if (sin->sin_addr.s_addr == in->s_addr) {
495 			freeifaddrs(ifap);
496 			return (1);
497 		}
498 	}
499 	freeifaddrs(ifap);
500 	return (0);
501 }
502 
503 void
reap(int sig,short event,void * arg)504 reap(int sig, short event, void *arg)
505 {
506 	struct servtab *sep;
507 	int status;
508 	pid_t pid;
509 
510 	if (debug)
511 		fprintf(stderr, "reaping asked for\n");
512 
513 	for (;;) {
514 		if ((pid = wait3(&status, WNOHANG, NULL)) <= 0) {
515 			if (pid == -1 && errno == EINTR)
516 				continue;
517 			break;
518 		}
519 		if (debug)
520 			fprintf(stderr, "%ld reaped, status %x\n",
521 			    (long)pid, status);
522 		for (sep = servtab; sep; sep = sep->se_next)
523 			if (sep->se_wait == pid) {
524 				if (WIFEXITED(status) && WEXITSTATUS(status))
525 					syslog(LOG_WARNING,
526 					    "%s: exit status %d",
527 					    sep->se_server, WEXITSTATUS(status));
528 				else if (WIFSIGNALED(status))
529 					syslog(LOG_WARNING,
530 					    "%s: exit signal %d",
531 					    sep->se_server, WTERMSIG(status));
532 				sep->se_wait = 1;
533 				event_add(&sep->se_event, NULL);
534 				if (debug)
535 					fprintf(stderr, "restored %s, fd %d\n",
536 					    sep->se_service, sep->se_fd);
537 			}
538 	}
539 }
540 
541 void
config(int sig,short event,void * arg)542 config(int sig, short event, void *arg)
543 {
544 	struct servtab *sep, *cp, **sepp;
545 	int add;
546 	char protoname[11];
547 
548 	if (!setconfig()) {
549 		syslog(LOG_ERR, "%s: %m", CONFIG);
550 		exit(1);
551 	}
552 	for (sep = servtab; sep; sep = sep->se_next)
553 		sep->se_checked = 0;
554 	cp = getconfigent();
555 	while (cp != NULL) {
556 		for (sep = servtab; sep; sep = sep->se_next)
557 			if (matchconf(sep, cp))
558 				break;
559 		add = 0;
560 		if (sep != NULL) {
561 			int i;
562 
563 #define SWAP(type, a, b) {type c=(type)a; a=(type)b; b=(type)c;}
564 
565 			/*
566 			 * sep->se_wait may be holding the pid of a daemon
567 			 * that we're waiting for.  If so, don't overwrite
568 			 * it unless the config file explicitly says don't
569 			 * wait.
570 			 */
571 			if (cp->se_bi == 0 &&
572 			    (sep->se_wait == 1 || cp->se_wait == 0))
573 				sep->se_wait = cp->se_wait;
574 			SWAP(int, cp->se_max, sep->se_max);
575 			SWAP(char *, sep->se_user, cp->se_user);
576 			SWAP(char *, sep->se_group, cp->se_group);
577 			SWAP(char *, sep->se_server, cp->se_server);
578 			for (i = 0; i < MAXARGV; i++)
579 				SWAP(char *, sep->se_argv[i], cp->se_argv[i]);
580 #undef SWAP
581 			if (isrpcservice(sep))
582 				unregister_rpc(sep);
583 			sep->se_rpcversl = cp->se_rpcversl;
584 			sep->se_rpcversh = cp->se_rpcversh;
585 			freeconfig(cp);
586 			add = 1;
587 		} else {
588 			sep = enter(cp);
589 		}
590 		sep->se_checked = 1;
591 
592 		switch (sep->se_family) {
593 		case AF_UNIX:
594 			if (sep->se_fd != -1)
595 				break;
596 			sep->se_ctrladdr_size =
597 			    strlcpy(sep->se_ctrladdr_un.sun_path,
598 			    sep->se_service,
599 			    sizeof sep->se_ctrladdr_un.sun_path);
600 			if (sep->se_ctrladdr_size >=
601 			    sizeof sep->se_ctrladdr_un.sun_path) {
602 				syslog(LOG_WARNING, "%s/%s: UNIX domain socket "
603 				    "path too long", sep->se_service,
604 				    sep->se_proto);
605 				goto serv_unknown;
606 			}
607 			sep->se_ctrladdr_un.sun_family = AF_UNIX;
608 			sep->se_ctrladdr_size +=
609 			    1 + sizeof sep->se_ctrladdr_un.sun_family;
610 			(void)unlink(sep->se_service);
611 			setup(sep);
612 			break;
613 		case AF_INET:
614 			sep->se_ctrladdr_in.sin_family = AF_INET;
615 			/* se_ctrladdr_in was set in getconfigent */
616 			sep->se_ctrladdr_size = sizeof sep->se_ctrladdr_in;
617 
618 			if (isrpcservice(sep)) {
619 				struct rpcent *rp;
620 
621 				sep->se_rpcprog = strtonum(sep->se_service,
622 				    1, USHRT_MAX, NULL);
623 				if (sep->se_rpcprog == 0) {
624 					rp = getrpcbyname(sep->se_service);
625 					if (rp == 0) {
626 						syslog(LOG_ERR,
627 						    "%s: unknown rpc service",
628 						    sep->se_service);
629 						goto serv_unknown;
630 					}
631 					sep->se_rpcprog = rp->r_number;
632 				}
633 				if (sep->se_fd == -1)
634 					setup(sep);
635 				if (sep->se_fd != -1)
636 					register_rpc(sep);
637 			} else {
638 				u_short port = htons(strtonum(sep->se_service,
639 				    1, USHRT_MAX, NULL));
640 
641 				if (!port) {
642 					(void)strlcpy(protoname, sep->se_proto,
643 					    sizeof(protoname));
644 					if (isdigit((unsigned char)
645 					    protoname[strlen(protoname) - 1]))
646 						protoname[strlen(protoname) - 1] = '\0';
647 					sp = getservbyname(sep->se_service,
648 					    protoname);
649 					if (sp == 0) {
650 						syslog(LOG_ERR,
651 						    "%s/%s: unknown service",
652 						    sep->se_service, sep->se_proto);
653 						goto serv_unknown;
654 					}
655 					port = sp->s_port;
656 				}
657 				if (port != sep->se_ctrladdr_in.sin_port) {
658 					sep->se_ctrladdr_in.sin_port = port;
659 					if (sep->se_fd != -1) {
660 						event_del(&sep->se_event);
661 						(void) close(sep->se_fd);
662 					}
663 					sep->se_fd = -1;
664 				}
665 				if (sep->se_fd == -1)
666 					setup(sep);
667 			}
668 			break;
669 		case AF_INET6:
670 			sep->se_ctrladdr_in6.sin6_family = AF_INET6;
671 			/* se_ctrladdr_in was set in getconfigent */
672 			sep->se_ctrladdr_size = sizeof sep->se_ctrladdr_in6;
673 
674 			if (isrpcservice(sep)) {
675 				struct rpcent *rp;
676 
677 				sep->se_rpcprog = strtonum(sep->se_service,
678 				    1, USHRT_MAX, NULL);
679 				if (sep->se_rpcprog == 0) {
680 					rp = getrpcbyname(sep->se_service);
681 					if (rp == 0) {
682 						syslog(LOG_ERR,
683 						    "%s: unknown rpc service",
684 						    sep->se_service);
685 						goto serv_unknown;
686 					}
687 					sep->se_rpcprog = rp->r_number;
688 				}
689 				if (sep->se_fd == -1)
690 					setup(sep);
691 				if (sep->se_fd != -1)
692 					register_rpc(sep);
693 			} else {
694 				u_short port = htons(strtonum(sep->se_service,
695 				    1, USHRT_MAX, NULL));
696 
697 				if (!port) {
698 					(void)strlcpy(protoname, sep->se_proto,
699 					    sizeof(protoname));
700 					if (isdigit((unsigned char)
701 					    protoname[strlen(protoname) - 1]))
702 						protoname[strlen(protoname) - 1] = '\0';
703 					sp = getservbyname(sep->se_service,
704 					    protoname);
705 					if (sp == 0) {
706 						syslog(LOG_ERR,
707 						    "%s/%s: unknown service",
708 						    sep->se_service, sep->se_proto);
709 						goto serv_unknown;
710 					}
711 					port = sp->s_port;
712 				}
713 				if (port != sep->se_ctrladdr_in6.sin6_port) {
714 					sep->se_ctrladdr_in6.sin6_port = port;
715 					if (sep->se_fd != -1) {
716 						event_del(&sep->se_event);
717 						(void) close(sep->se_fd);
718 					}
719 					sep->se_fd = -1;
720 				}
721 				if (sep->se_fd == -1)
722 					setup(sep);
723 			}
724 			break;
725 		}
726 	serv_unknown:
727 		if (cp->se_next != NULL) {
728 			struct servtab *tmp = cp;
729 
730 			cp = cp->se_next;
731 			free(tmp);
732 		} else {
733 			free(cp);
734 			cp = getconfigent();
735 		}
736 		if (debug)
737 			print_service(add ? "REDO" : "ADD", sep);
738 	}
739 	endconfig();
740 	/*
741 	 * Purge anything not looked at above.
742 	 */
743 	sepp = &servtab;
744 	while ((sep = *sepp)) {
745 		if (sep->se_checked) {
746 			sepp = &sep->se_next;
747 			continue;
748 		}
749 		*sepp = sep->se_next;
750 		if (sep->se_fd != -1) {
751 			event_del(&sep->se_event);
752 			(void) close(sep->se_fd);
753 		}
754 		if (isrpcservice(sep))
755 			unregister_rpc(sep);
756 		if (sep->se_family == AF_UNIX)
757 			(void)unlink(sep->se_service);
758 		if (debug)
759 			print_service("FREE", sep);
760 		freeconfig(sep);
761 		free(sep);
762 	}
763 }
764 
765 void
retry(int sig,short events,void * arg)766 retry(int sig, short events, void *arg)
767 {
768 	struct servtab *sep;
769 
770 	timingout = 0;
771 	for (sep = servtab; sep; sep = sep->se_next) {
772 		if (sep->se_fd == -1) {
773 			switch (sep->se_family) {
774 			case AF_UNIX:
775 			case AF_INET:
776 			case AF_INET6:
777 				setup(sep);
778 				if (sep->se_fd != -1 && isrpcservice(sep))
779 					register_rpc(sep);
780 				break;
781 			}
782 		}
783 	}
784 }
785 
786 void
die(int sig,short events,void * arg)787 die(int sig, short events, void *arg)
788 {
789 	struct servtab *sep;
790 
791 	for (sep = servtab; sep; sep = sep->se_next) {
792 		if (sep->se_fd == -1)
793 			continue;
794 
795 		switch (sep->se_family) {
796 		case AF_UNIX:
797 			(void)unlink(sep->se_service);
798 			break;
799 		case AF_INET:
800 		case AF_INET6:
801 			if (sep->se_wait == 1 && isrpcservice(sep))
802 				unregister_rpc(sep);
803 			break;
804 		}
805 		(void)close(sep->se_fd);
806 	}
807 	exit(0);
808 }
809 
810 void
setup(struct servtab * sep)811 setup(struct servtab *sep)
812 {
813 	int on = 1;
814 	int r;
815 	mode_t mask = 0;
816 
817 	if ((sep->se_fd = socket(sep->se_family, sep->se_socktype, 0)) == -1) {
818 		syslog(LOG_ERR, "%s/%s: socket: %m",
819 		    sep->se_service, sep->se_proto);
820 		return;
821 	}
822 #define	turnon(fd, opt) \
823 setsockopt(fd, SOL_SOCKET, opt, &on, sizeof (on))
824 	if (strncmp(sep->se_proto, "tcp", 3) == 0 && debug &&
825 	    turnon(sep->se_fd, SO_DEBUG) < 0)
826 		syslog(LOG_ERR, "setsockopt (SO_DEBUG): %m");
827 	if (turnon(sep->se_fd, SO_REUSEADDR) < 0)
828 		syslog(LOG_ERR, "setsockopt (SO_REUSEADDR): %m");
829 #undef turnon
830 	if (isrpcservice(sep)) {
831 		struct passwd *pwd;
832 
833 		/*
834 		 * for RPC services, attempt to use a reserved port
835 		 * if they are going to be running as root.
836 		 *
837 		 * Also, zero out the port for all RPC services; let bind()
838 		 * find one.
839 		 */
840 		sep->se_ctrladdr_in.sin_port = 0;
841 		if (sep->se_user && (pwd = getpwnam(sep->se_user)) &&
842 		    pwd->pw_uid == 0 && uid == 0)
843 			r = bindresvport(sep->se_fd, &sep->se_ctrladdr_in);
844 		else {
845 			r = bind(sep->se_fd, &sep->se_ctrladdr,
846 			    sep->se_ctrladdr_size);
847 			if (r == 0) {
848 				socklen_t len = sep->se_ctrladdr_size;
849 				int saveerrno = errno;
850 
851 				/* update se_ctrladdr_in.sin_port */
852 				r = getsockname(sep->se_fd, &sep->se_ctrladdr,
853 				    &len);
854 				if (r <= 0)
855 					errno = saveerrno;
856 			}
857 		}
858 	} else {
859 		if (sep->se_family == AF_UNIX)
860 			mask = umask(0111);
861 		r = bind(sep->se_fd, &sep->se_ctrladdr, sep->se_ctrladdr_size);
862 		if (sep->se_family == AF_UNIX)
863 			umask(mask);
864 	}
865 	if (r == -1) {
866 		syslog(LOG_ERR, "%s/%s: bind: %m",
867 		    sep->se_service, sep->se_proto);
868 		(void) close(sep->se_fd);
869 		sep->se_fd = -1;
870 		if (!timingout) {
871 			timingout = 1;
872 			alarm(RETRYTIME);
873 		}
874 		return;
875 	}
876 	if (sep->se_socktype == SOCK_STREAM)
877 		listen(sep->se_fd, 10);
878 
879 	if (!sep->se_wait && sep->se_socktype == SOCK_STREAM) {
880 		event_set(&sep->se_event, sep->se_fd, EV_READ|EV_PERSIST,
881 		    gettcp, sep);
882 	} else {
883 		event_set(&sep->se_event, sep->se_fd, EV_READ|EV_PERSIST,
884 		    spawn, sep);
885 	}
886 
887 	event_add(&sep->se_event, NULL);
888 
889 	if (sep->se_fd > maxsock) {
890 		maxsock = sep->se_fd;
891 		if (maxsock > rlim_nofile_cur - FD_MARGIN)
892 			bump_nofile();
893 	}
894 }
895 
896 void
register_rpc(struct servtab * sep)897 register_rpc(struct servtab *sep)
898 {
899 	socklen_t n;
900 	struct sockaddr_in sin;
901 	struct protoent *pp;
902 
903 	if ((pp = getprotobyname(sep->se_proto+4)) == NULL) {
904 		syslog(LOG_ERR, "%s: getproto: %m",
905 		    sep->se_proto);
906 		return;
907 	}
908 	n = sizeof sin;
909 	if (getsockname(sep->se_fd, (struct sockaddr *)&sin, &n) == -1) {
910 		syslog(LOG_ERR, "%s/%s: getsockname: %m",
911 		    sep->se_service, sep->se_proto);
912 		return;
913 	}
914 
915 	for (n = sep->se_rpcversl; n <= sep->se_rpcversh; n++) {
916 		if (debug)
917 			fprintf(stderr, "pmap_set: %u %u %u %u\n",
918 			    sep->se_rpcprog, n, pp->p_proto,
919 			    ntohs(sin.sin_port));
920 		(void)pmap_unset(sep->se_rpcprog, n);
921 		if (!pmap_set(sep->se_rpcprog, n, pp->p_proto, ntohs(sin.sin_port)))
922 			syslog(LOG_ERR, "%s %s: pmap_set: %u %u %u %u: %m",
923 			    sep->se_service, sep->se_proto,
924 			    sep->se_rpcprog, n, pp->p_proto,
925 			    ntohs(sin.sin_port));
926 	}
927 }
928 
929 void
unregister_rpc(struct servtab * sep)930 unregister_rpc(struct servtab *sep)
931 {
932 	int n;
933 
934 	for (n = sep->se_rpcversl; n <= sep->se_rpcversh; n++) {
935 		if (debug)
936 			fprintf(stderr, "pmap_unset(%u, %u)\n",
937 			    sep->se_rpcprog, n);
938 		if (!pmap_unset(sep->se_rpcprog, n))
939 			syslog(LOG_ERR, "pmap_unset(%u, %u)",
940 			    sep->se_rpcprog, n);
941 	}
942 }
943 
944 
945 struct servtab *
enter(struct servtab * cp)946 enter(struct servtab *cp)
947 {
948 	struct servtab *sep;
949 
950 	sep = malloc(sizeof (*sep));
951 	if (sep == NULL) {
952 		syslog(LOG_ERR, "Out of memory.");
953 		exit(1);
954 	}
955 	*sep = *cp;
956 	sep->se_fd = -1;
957 	sep->se_rpcprog = -1;
958 	sep->se_next = servtab;
959 	servtab = sep;
960 	return (sep);
961 }
962 
963 int
matchconf(struct servtab * old,struct servtab * new)964 matchconf(struct servtab *old, struct servtab *new)
965 {
966 	if (strcmp(old->se_service, new->se_service) != 0)
967 		return (0);
968 
969 	if (strcmp(old->se_hostaddr, new->se_hostaddr) != 0)
970 		return (0);
971 
972 	if (strcmp(old->se_proto, new->se_proto) != 0)
973 		return (0);
974 
975 	/*
976 	 * If the new servtab is bound to a specific address, check that the
977 	 * old servtab is bound to the same entry. If the new service is not
978 	 * bound to a specific address then the check of se_hostaddr above
979 	 * is sufficient.
980 	 */
981 
982 	if (old->se_family == AF_INET && new->se_family == AF_INET &&
983 	    bcmp(&old->se_ctrladdr_in.sin_addr,
984 	    &new->se_ctrladdr_in.sin_addr,
985 	    sizeof(new->se_ctrladdr_in.sin_addr)) != 0)
986 		return (0);
987 
988 	if (old->se_family == AF_INET6 && new->se_family == AF_INET6 &&
989 	    bcmp(&old->se_ctrladdr_in6.sin6_addr,
990 	    &new->se_ctrladdr_in6.sin6_addr,
991 	    sizeof(new->se_ctrladdr_in6.sin6_addr)) != 0)
992 		return (0);
993 	if (old->se_family == AF_INET6 && new->se_family == AF_INET6 &&
994 	    old->se_ctrladdr_in6.sin6_scope_id !=
995 	    new->se_ctrladdr_in6.sin6_scope_id)
996 		return (0);
997 
998 	return (1);
999 }
1000 
1001 FILE		*fconfig = NULL;
1002 char		line[1024];
1003 char		*defhost;
1004 char		*skip(char **, int);
1005 char		*nextline(FILE *);
1006 char		*newstr(char *);
1007 struct servtab	*dupconfig(struct servtab *);
1008 
1009 int
setconfig(void)1010 setconfig(void)
1011 {
1012 	free(defhost);
1013 	defhost = newstr("*");
1014 	if (fconfig != NULL) {
1015 		fseek(fconfig, 0L, SEEK_SET);
1016 		return (1);
1017 	}
1018 	fconfig = fopen(CONFIG, "r");
1019 	return (fconfig != NULL);
1020 }
1021 
1022 void
endconfig(void)1023 endconfig(void)
1024 {
1025 	if (fconfig) {
1026 		(void) fclose(fconfig);
1027 		fconfig = NULL;
1028 	}
1029 	if (defhost) {
1030 		free(defhost);
1031 		defhost = 0;
1032 	}
1033 }
1034 
1035 struct servtab *
getconfigent(void)1036 getconfigent(void)
1037 {
1038 	struct servtab *sep, *tsep;
1039 	char *arg, *cp, *hostdelim, *s;
1040 	int argc;
1041 
1042 	sep = calloc(1, sizeof(struct servtab));
1043 	if (sep == NULL) {
1044 		syslog(LOG_ERR, "calloc: %m");
1045 		exit(1);
1046 	}
1047 more:
1048 	freeconfig(sep);
1049 
1050 	while ((cp = nextline(fconfig)) && *cp == '#')
1051 		;
1052 	if (cp == NULL) {
1053 		free(sep);
1054 		return (NULL);
1055 	}
1056 
1057 	memset(sep, 0, sizeof *sep);
1058 	arg = skip(&cp, 0);
1059 	if (arg == NULL) {
1060 		/* A blank line. */
1061 		goto more;
1062 	}
1063 
1064 	/* Check for a host name. */
1065 	hostdelim = strrchr(arg, ':');
1066 	if (hostdelim) {
1067 		*hostdelim = '\0';
1068 		if (arg[0] == '[' && hostdelim > arg && hostdelim[-1] == ']') {
1069 			hostdelim[-1] = '\0';
1070 			sep->se_hostaddr = newstr(arg + 1);
1071 		} else if (hostdelim == arg)
1072 			sep->se_hostaddr = newstr("*");
1073 		else
1074 			sep->se_hostaddr = newstr(arg);
1075 		arg = hostdelim + 1;
1076 		/*
1077 		 * If the line is of the form `host:', then just change the
1078 		 * default host for the following lines.
1079 		 */
1080 		if (*arg == '\0') {
1081 			arg = skip(&cp, 0);
1082 			if (cp == NULL) {
1083 				free(defhost);
1084 				defhost = newstr(sep->se_hostaddr);
1085 				goto more;
1086 			}
1087 		}
1088 	} else
1089 		sep->se_hostaddr = newstr(defhost);
1090 
1091 	sep->se_service = newstr(arg);
1092 	if ((arg = skip(&cp, 1)) == NULL)
1093 		goto more;
1094 
1095 	if (strcmp(arg, "stream") == 0)
1096 		sep->se_socktype = SOCK_STREAM;
1097 	else if (strcmp(arg, "dgram") == 0)
1098 		sep->se_socktype = SOCK_DGRAM;
1099 	else
1100 		sep->se_socktype = -1;
1101 
1102 	if ((arg = skip(&cp, 1)) == NULL)
1103 		goto more;
1104 
1105 	sep->se_proto = newstr(arg);
1106 
1107 	if (strcmp(sep->se_proto, "unix") == 0) {
1108 		sep->se_family = AF_UNIX;
1109 	} else {
1110 		int s;
1111 
1112 		sep->se_family = AF_INET;
1113 		if (sep->se_proto[strlen(sep->se_proto) - 1] == '6')
1114 			sep->se_family = AF_INET6;
1115 
1116 		/* check if the family is supported */
1117 		s = socket(sep->se_family, SOCK_DGRAM, 0);
1118 		if (s == -1) {
1119 			syslog(LOG_WARNING, "%s/%s: %s: the address family is "
1120 			    "not supported by the kernel", sep->se_service,
1121 			    sep->se_proto, sep->se_hostaddr);
1122 			goto more;
1123 		}
1124 		close(s);
1125 
1126 		if (strncmp(sep->se_proto, "rpc/", 4) == 0) {
1127 			char *cp, *ccp;
1128 			long l;
1129 
1130 			cp = strchr(sep->se_service, '/');
1131 			if (cp == 0) {
1132 				syslog(LOG_ERR, "%s: no rpc version",
1133 				    sep->se_service);
1134 				goto more;
1135 			}
1136 			*cp++ = '\0';
1137 			l = strtol(cp, &ccp, 0);
1138 			if (ccp == cp || l < 0 || l > INT_MAX) {
1139 		badafterall:
1140 				syslog(LOG_ERR, "%s/%s: bad rpc version",
1141 				    sep->se_service, cp);
1142 				goto more;
1143 			}
1144 			sep->se_rpcversl = sep->se_rpcversh = l;
1145 			if (*ccp == '-') {
1146 				cp = ccp + 1;
1147 				l = strtol(cp, &ccp, 0);
1148 				if (ccp == cp || l < 0 || l > INT_MAX ||
1149 				    l < sep->se_rpcversl || *ccp)
1150 					goto badafterall;
1151 				sep->se_rpcversh = l;
1152 			} else if (*ccp != '\0')
1153 				goto badafterall;
1154 		}
1155 	}
1156 	arg = skip(&cp, 1);
1157 	if (arg == NULL)
1158 		goto more;
1159 
1160 	s = strchr(arg, '.');
1161 	if (s) {
1162 		char *p;
1163 
1164 		*s++ = '\0';
1165 		sep->se_max = strtoul(s, &p, 0);
1166 		if (sep->se_max < 1 || *p) {
1167 			syslog(LOG_ERR,
1168 			    "%s: illegal max field \"%s\", setting to %d",
1169 			    sep->se_service, s, toomany);
1170 			sep->se_max = toomany;
1171 		}
1172 	} else
1173 		sep->se_max = toomany;
1174 
1175 	sep->se_wait = strcmp(arg, "wait") == 0;
1176 	if ((arg = skip(&cp, 1)) == NULL)
1177 		goto more;
1178 	sep->se_user = newstr(arg);
1179 	arg = strchr(sep->se_user, '.');
1180 	if (arg == NULL)
1181 		arg = strchr(sep->se_user, ':');
1182 	if (arg) {
1183 		*arg++ = '\0';
1184 		sep->se_group = newstr(arg);
1185 	}
1186 	if ((arg = skip(&cp, 1)) == NULL)
1187 		goto more;
1188 
1189 	sep->se_server = newstr(arg);
1190 	if (strcmp(sep->se_server, "internal") == 0) {
1191 		struct biltin *bi;
1192 
1193 		for (bi = biltins; bi->bi_service; bi++)
1194 			if (bi->bi_socktype == sep->se_socktype &&
1195 			    strcmp(bi->bi_service, sep->se_service) == 0)
1196 				break;
1197 		if (bi->bi_service == 0) {
1198 			syslog(LOG_ERR, "internal service %s unknown",
1199 			    sep->se_service);
1200 			goto more;
1201 		}
1202 		sep->se_bi = bi;
1203 		sep->se_wait = bi->bi_wait;
1204 	} else
1205 		sep->se_bi = NULL;
1206 	argc = 0;
1207 	for (arg = skip(&cp, 0); cp; arg = skip(&cp, 0)) {
1208 		if (argc < MAXARGV)
1209 			sep->se_argv[argc++] = newstr(arg);
1210 	}
1211 	if (argc == 0 && sep->se_bi == NULL) {
1212 		if ((arg = strrchr(sep->se_server, '/')) != NULL)
1213 			arg++;
1214 		else
1215 			arg = sep->se_server;
1216 		sep->se_argv[argc++] = newstr(arg);
1217 	}
1218 	while (argc <= MAXARGV)
1219 		sep->se_argv[argc++] = NULL;
1220 
1221 	/*
1222 	 * Resolve each hostname in the se_hostaddr list (if any)
1223 	 * and create a new entry for each resolved address.
1224 	 */
1225 	if (sep->se_hostaddr != NULL && strcmp(sep->se_proto, "unix") != 0) {
1226 		struct addrinfo hints, *res0, *res;
1227 		char *host, *hostlist0, *hostlist, *port;
1228 		int error;
1229 
1230 		hostlist = hostlist0 = sep->se_hostaddr;
1231 		sep->se_hostaddr = NULL;
1232 		sep->se_checked = -1;
1233 		while ((host = strsep(&hostlist, ",")) != NULL) {
1234 			if (*host == '\0')
1235 				continue;
1236 
1237 			memset(&hints, 0, sizeof(hints));
1238 			hints.ai_family = sep->se_family;
1239 			hints.ai_socktype = sep->se_socktype;
1240 			hints.ai_flags = AI_PASSIVE;
1241 			port = "0";
1242 			error = getaddrinfo(strcmp(host, "*") ? host : NULL,
1243 			    port, &hints, &res0);
1244 			if (error) {
1245 				syslog(LOG_ERR, "%s/%s: %s: %s",
1246 				    sep->se_service, sep->se_proto,
1247 				    host, gai_strerror(error));
1248 				continue;
1249 			}
1250 			for (res = res0; res; res = res->ai_next) {
1251 				/*
1252 				 * If sep is unused, store host in there.
1253 				 * Otherwise, dup a new entry and prepend it.
1254 				 */
1255 				if (sep->se_checked == -1) {
1256 					sep->se_checked = 0;
1257 				} else {
1258 					tsep = dupconfig(sep);
1259 					tsep->se_next = sep;
1260 					sep = tsep;
1261 				}
1262 				sep->se_hostaddr = newstr(host);
1263 				memcpy(&sep->se_ctrladdr_storage,
1264 				    res->ai_addr, res->ai_addrlen);
1265 				sep->se_ctrladdr_size = res->ai_addrlen;
1266 			}
1267 			freeaddrinfo(res0);
1268 		}
1269 		free(hostlist0);
1270 		if (sep->se_checked == -1)
1271 			goto more;	/* no resolvable names/addresses */
1272 	}
1273 
1274 	return (sep);
1275 }
1276 
1277 void
freeconfig(struct servtab * cp)1278 freeconfig(struct servtab *cp)
1279 {
1280 	int i;
1281 
1282 	free(cp->se_hostaddr);
1283 	cp->se_hostaddr = NULL;
1284 	free(cp->se_service);
1285 	cp->se_service = NULL;
1286 	free(cp->se_proto);
1287 	cp->se_proto = NULL;
1288 	free(cp->se_user);
1289 	cp->se_user = NULL;
1290 	free(cp->se_group);
1291 	cp->se_group = NULL;
1292 	free(cp->se_server);
1293 	cp->se_server = NULL;
1294 	for (i = 0; i < MAXARGV; i++) {
1295 		free(cp->se_argv[i]);
1296 		cp->se_argv[i] = NULL;
1297 	}
1298 }
1299 
1300 char *
skip(char ** cpp,int report)1301 skip(char **cpp, int report)
1302 {
1303 	char *cp = *cpp;
1304 	char *start;
1305 
1306 erp:
1307 	if (*cpp == NULL) {
1308 		if (report)
1309 			syslog(LOG_ERR, "syntax error in inetd config file");
1310 		return (NULL);
1311 	}
1312 
1313 again:
1314 	while (*cp == ' ' || *cp == '\t')
1315 		cp++;
1316 	if (*cp == '\0') {
1317 		int c;
1318 
1319 		c = getc(fconfig);
1320 		(void) ungetc(c, fconfig);
1321 		if (c == ' ' || c == '\t')
1322 			if ((cp = nextline(fconfig)))
1323 				goto again;
1324 		*cpp = NULL;
1325 		goto erp;
1326 	}
1327 	start = cp;
1328 	while (*cp && *cp != ' ' && *cp != '\t')
1329 		cp++;
1330 	if (*cp != '\0')
1331 		*cp++ = '\0';
1332 	if ((*cpp = cp) == NULL)
1333 		goto erp;
1334 
1335 	return (start);
1336 }
1337 
1338 char *
nextline(FILE * fd)1339 nextline(FILE *fd)
1340 {
1341 	if (fgets(line, sizeof (line), fd) == NULL)
1342 		return (NULL);
1343 	line[strcspn(line, "\n")] = '\0';
1344 	return (line);
1345 }
1346 
1347 char *
newstr(char * cp)1348 newstr(char *cp)
1349 {
1350 	if ((cp = strdup(cp ? cp : "")))
1351 		return(cp);
1352 	syslog(LOG_ERR, "strdup: %m");
1353 	exit(1);
1354 }
1355 
1356 struct servtab *
dupconfig(struct servtab * sep)1357 dupconfig(struct servtab *sep)
1358 {
1359 	struct servtab *newtab;
1360 	int argc;
1361 
1362 	newtab = calloc(1, sizeof(struct servtab));
1363 
1364 	if (newtab == NULL) {
1365 		syslog(LOG_ERR, "calloc: %m");
1366 		exit(1);
1367 	}
1368 
1369 	newtab->se_service = sep->se_service ? newstr(sep->se_service) : NULL;
1370 	newtab->se_socktype = sep->se_socktype;
1371 	newtab->se_family = sep->se_family;
1372 	newtab->se_proto = sep->se_proto ? newstr(sep->se_proto) : NULL;
1373 	newtab->se_rpcprog = sep->se_rpcprog;
1374 	newtab->se_rpcversl = sep->se_rpcversl;
1375 	newtab->se_rpcversh = sep->se_rpcversh;
1376 	newtab->se_wait = sep->se_wait;
1377 	newtab->se_user = sep->se_user ? newstr(sep->se_user) : NULL;
1378 	newtab->se_group = sep->se_group ? newstr(sep->se_group) : NULL;
1379 	newtab->se_bi = sep->se_bi;
1380 	newtab->se_server = sep->se_server ? newstr(sep->se_server) : 0;
1381 
1382 	for (argc = 0; argc <= MAXARGV; argc++)
1383 		newtab->se_argv[argc] = sep->se_argv[argc] ?
1384 		    newstr(sep->se_argv[argc]) : NULL;
1385 	newtab->se_max = sep->se_max;
1386 
1387 	return (newtab);
1388 }
1389 
1390 void
inetd_setproctitle(char * a,int s)1391 inetd_setproctitle(char *a, int s)
1392 {
1393 	socklen_t size;
1394 	struct sockaddr_storage ss;
1395 	char hbuf[NI_MAXHOST];
1396 
1397 	size = sizeof(ss);
1398 	if (getpeername(s, (struct sockaddr *)&ss, &size) == 0) {
1399 		if (getnameinfo((struct sockaddr *)&ss, size, hbuf,
1400 		    sizeof(hbuf), NULL, 0, NI_NUMERICHOST) == 0)
1401 			setproctitle("-%s [%s]", a, hbuf);
1402 		else
1403 			setproctitle("-%s [?]", a);
1404 	} else
1405 		setproctitle("-%s", a);
1406 }
1407 
1408 int
bump_nofile(void)1409 bump_nofile(void)
1410 {
1411 #define FD_CHUNK	32
1412 
1413 	struct rlimit rl;
1414 
1415 	if (getrlimit(RLIMIT_NOFILE, &rl) == -1) {
1416 		syslog(LOG_ERR, "getrlimit: %m");
1417 		return -1;
1418 	}
1419 	rl.rlim_cur = MINIMUM(rl.rlim_max, rl.rlim_cur + FD_CHUNK);
1420 	rl.rlim_cur = MINIMUM(FD_SETSIZE, rl.rlim_cur + FD_CHUNK);
1421 	if (rl.rlim_cur <= rlim_nofile_cur) {
1422 		syslog(LOG_ERR,
1423 		    "bump_nofile: cannot extend file limit, max = %d",
1424 		    (int)rl.rlim_cur);
1425 		return -1;
1426 	}
1427 
1428 	if (setrlimit(RLIMIT_NOFILE, &rl) == -1) {
1429 		syslog(LOG_ERR, "setrlimit: %m");
1430 		return -1;
1431 	}
1432 
1433 	rlim_nofile_cur = rl.rlim_cur;
1434 	return 0;
1435 }
1436 
1437 /*
1438  * Internet services provided internally by inetd:
1439  */
1440 #define	BUFSIZE	4096
1441 
1442 void
echo_stream(int s,struct servtab * sep)1443 echo_stream(int s, struct servtab *sep)
1444 {
1445 	char buffer[BUFSIZE];
1446 	int i;
1447 
1448 	inetd_setproctitle(sep->se_service, s);
1449 	while ((i = read(s, buffer, sizeof(buffer))) > 0 &&
1450 	    write(s, buffer, i) > 0)
1451 		;
1452 	exit(0);
1453 }
1454 
1455 void
echo_dg(int s,struct servtab * sep)1456 echo_dg(int s, struct servtab *sep)
1457 {
1458 	char buffer[BUFSIZE];
1459 	int i;
1460 	socklen_t size;
1461 	struct sockaddr_storage ss;
1462 
1463 	size = sizeof(ss);
1464 	if ((i = recvfrom(s, buffer, sizeof(buffer), 0,
1465 	    (struct sockaddr *)&ss, &size)) == -1)
1466 		return;
1467 	if (dg_badinput((struct sockaddr *)&ss))
1468 		return;
1469 	(void) sendto(s, buffer, i, 0, (struct sockaddr *)&ss, size);
1470 }
1471 
1472 void
discard_stream(int s,struct servtab * sep)1473 discard_stream(int s, struct servtab *sep)
1474 {
1475 	char buffer[BUFSIZE];
1476 
1477 	inetd_setproctitle(sep->se_service, s);
1478 	while ((errno = 0, read(s, buffer, sizeof(buffer)) > 0) ||
1479 	    errno == EINTR)
1480 		;
1481 	exit(0);
1482 }
1483 
1484 void
discard_dg(int s,struct servtab * sep)1485 discard_dg(int s, struct servtab *sep)
1486 {
1487 	char buffer[BUFSIZE];
1488 
1489 	(void) read(s, buffer, sizeof(buffer));
1490 }
1491 
1492 #define LINESIZ 72
1493 char ring[128];
1494 char *endring;
1495 
1496 void
initring(void)1497 initring(void)
1498 {
1499 	int i;
1500 
1501 	endring = ring;
1502 
1503 	for (i = 0; i <= sizeof ring; ++i)
1504 		if (isprint((unsigned char)i))
1505 			*endring++ = i;
1506 }
1507 
1508 void
chargen_stream(int s,struct servtab * sep)1509 chargen_stream(int s, struct servtab *sep)
1510 {
1511 	char *rs;
1512 	int len;
1513 	char text[LINESIZ+2];
1514 
1515 	inetd_setproctitle(sep->se_service, s);
1516 
1517 	if (!endring) {
1518 		initring();
1519 		rs = ring;
1520 	}
1521 
1522 	text[LINESIZ] = '\r';
1523 	text[LINESIZ + 1] = '\n';
1524 	for (rs = ring;;) {
1525 		if ((len = endring - rs) >= LINESIZ)
1526 			memmove(text, rs, LINESIZ);
1527 		else {
1528 			memmove(text, rs, len);
1529 			memmove(text + len, ring, LINESIZ - len);
1530 		}
1531 		if (++rs == endring)
1532 			rs = ring;
1533 		if (write(s, text, sizeof(text)) != sizeof(text))
1534 			break;
1535 	}
1536 	exit(0);
1537 }
1538 
1539 void
chargen_dg(int s,struct servtab * sep)1540 chargen_dg(int s, struct servtab *sep)
1541 {
1542 	struct sockaddr_storage ss;
1543 	static char *rs;
1544 	int len;
1545 	socklen_t size;
1546 	char text[LINESIZ+2];
1547 
1548 	if (endring == 0) {
1549 		initring();
1550 		rs = ring;
1551 	}
1552 
1553 	size = sizeof(ss);
1554 	if (recvfrom(s, text, sizeof(text), 0, (struct sockaddr *)&ss,
1555 	    &size) == -1)
1556 		return;
1557 	if (dg_badinput((struct sockaddr *)&ss))
1558 		return;
1559 
1560 	if ((len = endring - rs) >= LINESIZ)
1561 		memmove(text, rs, LINESIZ);
1562 	else {
1563 		memmove(text, rs, len);
1564 		memmove(text + len, ring, LINESIZ - len);
1565 	}
1566 	if (++rs == endring)
1567 		rs = ring;
1568 	text[LINESIZ] = '\r';
1569 	text[LINESIZ + 1] = '\n';
1570 	(void) sendto(s, text, sizeof(text), 0, (struct sockaddr *)&ss, size);
1571 }
1572 
1573 /*
1574  * Return a machine readable date and time, in the form of the
1575  * number of seconds since midnight, Jan 1, 1900.  Since gettimeofday
1576  * returns the number of seconds since midnight, Jan 1, 1970,
1577  * we must add 2208988800 seconds to this figure to make up for
1578  * some seventy years Bell Labs was asleep.
1579  */
1580 u_int32_t
machtime(void)1581 machtime(void)
1582 {
1583 	struct timeval tv;
1584 
1585 	if (gettimeofday(&tv, NULL) == -1)
1586 		return (0L);
1587 
1588 	return (htonl((u_int32_t)tv.tv_sec + 2208988800UL));
1589 }
1590 
1591 void
machtime_stream(int s,struct servtab * sep)1592 machtime_stream(int s, struct servtab *sep)
1593 {
1594 	u_int32_t result;
1595 
1596 	result = machtime();
1597 	(void) write(s, &result, sizeof(result));
1598 }
1599 
1600 void
machtime_dg(int s,struct servtab * sep)1601 machtime_dg(int s, struct servtab *sep)
1602 {
1603 	u_int32_t result;
1604 	struct sockaddr_storage ss;
1605 	socklen_t size;
1606 
1607 	size = sizeof(ss);
1608 	if (recvfrom(s, &result, sizeof(result), 0,
1609 	    (struct sockaddr *)&ss, &size) == -1)
1610 		return;
1611 	if (dg_badinput((struct sockaddr *)&ss))
1612 		return;
1613 	result = machtime();
1614 	(void) sendto(s, &result, sizeof(result), 0,
1615 	    (struct sockaddr *)&ss, size);
1616 }
1617 
1618 /* Return human-readable time of day */
1619 void
daytime_stream(int s,struct servtab * sep)1620 daytime_stream(int s, struct servtab *sep)
1621 {
1622 	char buffer[256];
1623 	time_t clock;
1624 
1625 	clock = time(NULL);
1626 
1627 	(void) snprintf(buffer, sizeof buffer, "%.24s\r\n", ctime(&clock));
1628 	(void) write(s, buffer, strlen(buffer));
1629 }
1630 
1631 /* Return human-readable time of day */
1632 void
daytime_dg(int s,struct servtab * sep)1633 daytime_dg(int s, struct servtab *sep)
1634 {
1635 	char buffer[256];
1636 	time_t clock;
1637 	struct sockaddr_storage ss;
1638 	socklen_t size;
1639 
1640 	clock = time(NULL);
1641 
1642 	size = sizeof(ss);
1643 	if (recvfrom(s, buffer, sizeof(buffer), 0, (struct sockaddr *)&ss,
1644 	    &size) == -1)
1645 		return;
1646 	if (dg_badinput((struct sockaddr *)&ss))
1647 		return;
1648 	(void) snprintf(buffer, sizeof buffer, "%.24s\r\n", ctime(&clock));
1649 	(void) sendto(s, buffer, strlen(buffer), 0, (struct sockaddr *)&ss,
1650 	    size);
1651 }
1652 
1653 /*
1654  * print_service:
1655  *	Dump relevant information to stderr
1656  */
1657 void
print_service(char * action,struct servtab * sep)1658 print_service(char *action, struct servtab *sep)
1659 {
1660 	if (strcmp(sep->se_hostaddr, "*") == 0)
1661 		fprintf(stderr, "%s: %s ", action, sep->se_service);
1662 	else
1663 		fprintf(stderr, "%s: %s:%s ", action, sep->se_hostaddr,
1664 		    sep->se_service);
1665 
1666 	if (isrpcservice(sep))
1667 		fprintf(stderr, "rpcprog=%d, rpcvers=%d/%d, proto=%s,",
1668 		    sep->se_rpcprog, sep->se_rpcversh,
1669 		    sep->se_rpcversl, sep->se_proto);
1670 	else
1671 		fprintf(stderr, "proto=%s,", sep->se_proto);
1672 
1673 	fprintf(stderr,
1674 	    " wait.max=%d.%d user:group=%s:%s builtin=%lx server=%s\n",
1675 	    sep->se_wait, sep->se_max, sep->se_user,
1676 	    sep->se_group ? sep->se_group : "wheel",
1677 	    (long)sep->se_bi, sep->se_server);
1678 }
1679 
1680 void
spawn(int ctrl,short events,void * xsep)1681 spawn(int ctrl, short events, void *xsep)
1682 {
1683 	struct servtab *sep = xsep;
1684 	struct passwd *pwd;
1685 	int tmpint, dofork;
1686 	struct group *grp = NULL;
1687 	char buf[50];
1688 	pid_t pid;
1689 
1690 	if (debug)
1691 		fprintf(stderr, "someone wants %s\n", sep->se_service);
1692 
1693 	pid = 0;
1694 	dofork = (sep->se_bi == 0 || sep->se_bi->bi_fork);
1695 	if (dofork) {
1696 		if (sep->se_count++ == 0)
1697 		    (void)gettimeofday(&sep->se_time, NULL);
1698 		else if (sep->se_count >= sep->se_max) {
1699 			struct timeval now;
1700 
1701 			(void)gettimeofday(&now, NULL);
1702 			if (now.tv_sec - sep->se_time.tv_sec >
1703 			    CNT_INTVL) {
1704 				sep->se_time = now;
1705 				sep->se_count = 1;
1706 			} else {
1707 				if (!sep->se_wait &&
1708 				    sep->se_socktype == SOCK_STREAM)
1709 					close(ctrl);
1710 				if (sep->se_family == AF_INET &&
1711 				    ntohs(sep->se_ctrladdr_in.sin_port) >=
1712 				    IPPORT_RESERVED) {
1713 					/*
1714 					 * Cannot close it -- there are
1715 					 * thieves on the system.
1716 					 * Simply ignore the connection.
1717 					 */
1718 					--sep->se_count;
1719 					return;
1720 				}
1721 				syslog(LOG_ERR,
1722 				    "%s/%s server failing (looping), service terminated",
1723 				    sep->se_service, sep->se_proto);
1724 				if (!sep->se_wait &&
1725 				    sep->se_socktype == SOCK_STREAM)
1726 					close(ctrl);
1727 				event_del(&sep->se_event);
1728 				(void) close(sep->se_fd);
1729 
1730 				sep->se_fd = -1;
1731 				sep->se_count = 0;
1732 				if (!timingout) {
1733 					timingout = 1;
1734 					alarm(RETRYTIME);
1735 				}
1736 				return;
1737 			}
1738 		}
1739 		pid = fork();
1740 	}
1741 	if (pid == -1) {
1742 		syslog(LOG_ERR, "fork: %m");
1743 		if (!sep->se_wait && sep->se_socktype == SOCK_STREAM)
1744 			close(ctrl);
1745 		sleep(1);
1746 		return;
1747 	}
1748 
1749 	if (pid && sep->se_wait) {
1750 		sep->se_wait = pid;
1751 		event_del(&sep->se_event);
1752 	}
1753 	if (pid == 0) {
1754 		if (sep->se_bi) {
1755 			if (dofork && pledge("stdio inet", NULL) == -1)
1756 				err(1, "pledge");
1757 			(*sep->se_bi->bi_fn)(ctrl, sep);
1758 		} else {
1759 			if ((pwd = getpwnam(sep->se_user)) == NULL) {
1760 				syslog(LOG_ERR,
1761 				    "getpwnam: %s: No such user",
1762 				    sep->se_user);
1763 				if (sep->se_socktype != SOCK_STREAM)
1764 					recv(0, buf, sizeof (buf), 0);
1765 				exit(1);
1766 			}
1767 			if (setsid() <0)
1768 				syslog(LOG_ERR, "%s: setsid: %m",
1769 				    sep->se_service);
1770 			if (sep->se_group &&
1771 			    (grp = getgrnam(sep->se_group)) == NULL) {
1772 				syslog(LOG_ERR,
1773 				    "getgrnam: %s: No such group",
1774 				    sep->se_group);
1775 				if (sep->se_socktype != SOCK_STREAM)
1776 					recv(0, buf, sizeof (buf), 0);
1777 				exit(1);
1778 			}
1779 			if (uid != 0) {
1780 				/* a user running private inetd */
1781 				if (uid != pwd->pw_uid)
1782 					exit(1);
1783 			} else {
1784 				tmpint = LOGIN_SETALL &
1785 				    ~(LOGIN_SETGROUP|LOGIN_SETLOGIN);
1786 				if (pwd->pw_uid)
1787 					tmpint |= LOGIN_SETGROUP|LOGIN_SETLOGIN;
1788 				if (sep->se_group) {
1789 					pwd->pw_gid = grp->gr_gid;
1790 					tmpint |= LOGIN_SETGROUP;
1791 				}
1792 				if (setusercontext(NULL, pwd, pwd->pw_uid,
1793 				    tmpint) == -1) {
1794 					syslog(LOG_ERR,
1795 					    "%s/%s: setusercontext: %m",
1796 					    sep->se_service, sep->se_proto);
1797 					exit(1);
1798 				}
1799 			}
1800 			if (debug)
1801 				fprintf(stderr, "%ld execv %s\n",
1802 				    (long)getpid(), sep->se_server);
1803 			if (ctrl != STDIN_FILENO) {
1804 				dup2(ctrl, STDIN_FILENO);
1805 				close(ctrl);
1806 			}
1807 			dup2(STDIN_FILENO, STDOUT_FILENO);
1808 			dup2(STDIN_FILENO, STDERR_FILENO);
1809 			closelog();
1810 			closefrom(3);
1811 			signal(SIGPIPE, SIG_DFL);
1812 			execv(sep->se_server, sep->se_argv);
1813 			if (sep->se_socktype != SOCK_STREAM)
1814 				recv(0, buf, sizeof (buf), 0);
1815 			syslog(LOG_ERR, "execv %s: %m", sep->se_server);
1816 			exit(1);
1817 		}
1818 	}
1819 	if (!sep->se_wait && sep->se_socktype == SOCK_STREAM)
1820 		close(ctrl);
1821 }
1822