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