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