xref: /freebsd/usr.sbin/inetd/inetd.c (revision 5129159789cc9d7bc514e4546b88e3427695002d)
1 /*
2  * Copyright (c) 1983, 1991, 1993, 1994
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *	This product includes software developed by the University of
16  *	California, Berkeley and its contributors.
17  * 4. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33 
34 #ifndef lint
35 static const char copyright[] =
36 "@(#) Copyright (c) 1983, 1991, 1993, 1994\n\
37 	The Regents of the University of California.  All rights reserved.\n";
38 #endif /* not lint */
39 
40 #ifndef lint
41 #if 0
42 static char sccsid[] = "@(#)from: inetd.c	8.4 (Berkeley) 4/13/94";
43 #endif
44 static const char rcsid[] =
45   "$FreeBSD$";
46 #endif /* not lint */
47 
48 /*
49  * Inetd - Internet super-server
50  *
51  * This program invokes all internet services as needed.  Connection-oriented
52  * services are invoked each time a connection is made, by creating a process.
53  * This process is passed the connection as file descriptor 0 and is expected
54  * to do a getpeername to find out the source host and port.
55  *
56  * Datagram oriented services are invoked when a datagram
57  * arrives; a process is created and passed a pending message
58  * on file descriptor 0.  Datagram servers may either connect
59  * to their peer, freeing up the original socket for inetd
60  * to receive further messages on, or ``take over the socket'',
61  * processing all arriving datagrams and, eventually, timing
62  * out.	 The first type of server is said to be ``multi-threaded'';
63  * the second type of server ``single-threaded''.
64  *
65  * Inetd uses a configuration file which is read at startup
66  * and, possibly, at some later time in response to a hangup signal.
67  * The configuration file is ``free format'' with fields given in the
68  * order shown below.  Continuation lines for an entry must being with
69  * a space or tab.  All fields must be present in each entry.
70  *
71  *	service name			must be in /etc/services or must
72  *					name a tcpmux service
73  *	socket type			stream/dgram/raw/rdm/seqpacket
74  *	protocol			must be in /etc/protocols
75  *	wait/nowait			single-threaded/multi-threaded
76  *	user				user to run daemon as
77  *	server program			full path name
78  *	server program arguments	maximum of MAXARGS (20)
79  *
80  * TCP services without official port numbers are handled with the
81  * RFC1078-based tcpmux internal service. Tcpmux listens on port 1 for
82  * requests. When a connection is made from a foreign host, the service
83  * requested is passed to tcpmux, which looks it up in the servtab list
84  * and returns the proper entry for the service. Tcpmux returns a
85  * negative reply if the service doesn't exist, otherwise the invoked
86  * server is expected to return the positive reply if the service type in
87  * inetd.conf file has the prefix "tcpmux/". If the service type has the
88  * prefix "tcpmux/+", tcpmux will return the positive reply for the
89  * process; this is for compatibility with older server code, and also
90  * allows you to invoke programs that use stdin/stdout without putting any
91  * special server code in them. Services that use tcpmux are "nowait"
92  * because they do not have a well-known port and hence cannot listen
93  * for new requests.
94  *
95  * For RPC services
96  *	service name/version		must be in /etc/rpc
97  *	socket type			stream/dgram/raw/rdm/seqpacket
98  *	protocol			must be in /etc/protocols
99  *	wait/nowait			single-threaded/multi-threaded
100  *	user				user to run daemon as
101  *	server program			full path name
102  *	server program arguments	maximum of MAXARGS
103  *
104  * Comment lines are indicated by a `#' in column 1.
105  */
106 #include <sys/param.h>
107 #include <sys/ioctl.h>
108 #include <sys/wait.h>
109 #include <sys/time.h>
110 #include <sys/resource.h>
111 
112 #include <netinet/in.h>
113 #include <netinet/tcp.h>
114 #include <arpa/inet.h>
115 #include <rpc/rpc.h>
116 #include <rpc/pmap_clnt.h>
117 
118 #include <errno.h>
119 #include <err.h>
120 #include <fcntl.h>
121 #include <grp.h>
122 #include <netdb.h>
123 #include <pwd.h>
124 #include <signal.h>
125 #include <stdio.h>
126 #include <stdlib.h>
127 #include <string.h>
128 #include <syslog.h>
129 #include <tcpd.h>
130 #include <unistd.h>
131 #include <libutil.h>
132 #include <sysexits.h>
133 
134 #include "inetd.h"
135 #include "pathnames.h"
136 
137 #ifndef LIBWRAP_ALLOW_FACILITY
138 # define LIBWRAP_ALLOW_FACILITY LOG_AUTH
139 #endif
140 #ifndef LIBWRAP_ALLOW_SEVERITY
141 # define LIBWRAP_ALLOW_SEVERITY LOG_INFO
142 #endif
143 #ifndef LIBWRAP_DENY_FACILITY
144 # define LIBWRAP_DENY_FACILITY LOG_AUTH
145 #endif
146 #ifndef LIBWRAP_DENY_SEVERITY
147 # define LIBWRAP_DENY_SEVERITY LOG_WARNING
148 #endif
149 
150 #define ISWRAP(sep)	\
151 	   ( ((wrap_ex && !(sep)->se_bi) || (wrap_bi && (sep)->se_bi)) \
152 	&& ( ((sep)->se_accept && (sep)->se_socktype == SOCK_STREAM) \
153 	    || (sep)->se_socktype == SOCK_DGRAM))
154 
155 #ifdef LOGIN_CAP
156 #include <login_cap.h>
157 
158 /* see init.c */
159 #define RESOURCE_RC "daemon"
160 
161 #endif
162 
163 #ifndef	MAXCHILD
164 #define	MAXCHILD	-1		/* maximum number of this service
165 					   < 0 = no limit */
166 #endif
167 
168 #ifndef	MAXCPM
169 #define	MAXCPM		-1		/* rate limit invocations from a
170 					   single remote address,
171 					   < 0 = no limit */
172 #endif
173 
174 #define	TOOMANY		256		/* don't start more than TOOMANY */
175 #define	CNT_INTVL	60		/* servers in CNT_INTVL sec. */
176 #define	RETRYTIME	(60*10)		/* retry after bind or server fail */
177 #define MAX_MAXCHLD	32767		/* max allowable max children */
178 
179 #define	SIGBLOCK	(sigmask(SIGCHLD)|sigmask(SIGHUP)|sigmask(SIGALRM))
180 
181 int	allow_severity;
182 int	deny_severity;
183 int	wrap_ex = 0;
184 int	wrap_bi = 0;
185 int	debug = 0;
186 int	log = 0;
187 int	maxsock;			/* highest-numbered descriptor */
188 fd_set	allsock;
189 int	options;
190 int	timingout;
191 int	toomany = TOOMANY;
192 int	maxchild = MAXCHILD;
193 int	maxcpm = MAXCPM;
194 struct	servent *sp;
195 struct	rpcent *rpc;
196 struct	in_addr bind_address;
197 int	signalpipe[2];
198 #ifdef SANITY_CHECK
199 int	nsock;
200 #endif
201 
202 struct	servtab *servtab;
203 
204 extern struct biltin biltins[];
205 
206 #define NUMINT	(sizeof(intab) / sizeof(struct inent))
207 char	*CONFIG = _PATH_INETDCONF;
208 char	*pid_file = _PATH_INETDPID;
209 
210 #ifdef OLD_SETPROCTITLE
211 char	**Argv;
212 char 	*LastArg;
213 #endif
214 
215 int
216 getvalue(arg, value, whine)
217 	char *arg, *whine;
218 	int  *value;
219 {
220 	int  tmp;
221 	char *p;
222 
223 	tmp = strtol(arg, &p, 0);
224 	if (tmp < 1 || *p) {
225 		syslog(LOG_ERR, whine, arg);
226 		return 1;			/* failure */
227 	}
228 	*value = tmp;
229 	return 0;				/* success */
230 }
231 
232 int
233 main(argc, argv, envp)
234 	int argc;
235 	char *argv[], *envp[];
236 {
237 	struct servtab *sep;
238 	struct passwd *pwd;
239 	struct group *grp;
240 	struct sigaction sa, saalrm, sachld, sahup, sapipe;
241 	int tmpint, ch, dofork;
242 	pid_t pid;
243 	char buf[50];
244 #ifdef LOGIN_CAP
245 	login_cap_t *lc = NULL;
246 #endif
247 	struct request_info req;
248 	int denied;
249 	char *service = NULL;
250 	char *pnm;
251 	struct  sockaddr_in peer;
252 	int i;
253 
254 
255 #ifdef OLD_SETPROCTITLE
256 	Argv = argv;
257 	if (envp == 0 || *envp == 0)
258 		envp = argv;
259 	while (*envp)
260 		envp++;
261 	LastArg = envp[-1] + strlen(envp[-1]);
262 #endif
263 
264 	openlog("inetd", LOG_PID | LOG_NOWAIT, LOG_DAEMON);
265 
266 	bind_address.s_addr = htonl(INADDR_ANY);
267 	while ((ch = getopt(argc, argv, "dlwWR:a:c:C:p:")) != -1)
268 		switch(ch) {
269 		case 'd':
270 			debug = 1;
271 			options |= SO_DEBUG;
272 			break;
273 		case 'l':
274 			log = 1;
275 			break;
276 		case 'R':
277 			getvalue(optarg, &toomany,
278 				"-R %s: bad value for service invocation rate");
279 			break;
280 		case 'c':
281 			getvalue(optarg, &maxchild,
282 				"-c %s: bad value for maximum children");
283 			break;
284 		case 'C':
285 			getvalue(optarg, &maxcpm,
286 				"-C %s: bad value for maximum children/minute");
287 			break;
288 		case 'a':
289 			if (!inet_aton(optarg, &bind_address)) {
290 				syslog(LOG_ERR,
291 			         "-a %s: invalid IP address", optarg);
292 				exit(EX_USAGE);
293 			}
294 			break;
295 		case 'p':
296 			pid_file = optarg;
297 			break;
298 		case 'w':
299 			wrap_ex++;
300 			break;
301 		case 'W':
302 			wrap_bi++;
303 			break;
304 		case '?':
305 		default:
306 			syslog(LOG_ERR,
307 				"usage: inetd [-dlwW] [-a address] [-R rate]"
308 				" [-c maximum] [-C rate]"
309 				" [-p pidfile] [conf-file]");
310 			exit(EX_USAGE);
311 		}
312 	argc -= optind;
313 	argv += optind;
314 
315 	if (argc > 0)
316 		CONFIG = argv[0];
317 	if (debug == 0) {
318 		FILE *fp;
319 		if (daemon(0, 0) < 0) {
320 			syslog(LOG_WARNING, "daemon(0,0) failed: %m");
321 		}
322 		/*
323 		 * In case somebody has started inetd manually, we need to
324 		 * clear the logname, so that old servers run as root do not
325 		 * get the user's logname..
326 		 */
327 		if (setlogin("") < 0) {
328 			syslog(LOG_WARNING, "cannot clear logname: %m");
329 			/* no big deal if it fails.. */
330 		}
331 		pid = getpid();
332 		fp = fopen(pid_file, "w");
333 		if (fp) {
334 			fprintf(fp, "%ld\n", (long)pid);
335 			fclose(fp);
336 		} else {
337 			syslog(LOG_WARNING, "%s: %m", pid_file);
338 		}
339 	}
340 	sa.sa_flags = 0;
341 	sigemptyset(&sa.sa_mask);
342 	sigaddset(&sa.sa_mask, SIGALRM);
343 	sigaddset(&sa.sa_mask, SIGCHLD);
344 	sigaddset(&sa.sa_mask, SIGHUP);
345 	sa.sa_handler = flag_retry;
346 	sigaction(SIGALRM, &sa, &saalrm);
347 	config();
348 	sa.sa_handler = flag_config;
349 	sigaction(SIGHUP, &sa, &sahup);
350 	sa.sa_handler = flag_reapchild;
351 	sigaction(SIGCHLD, &sa, &sachld);
352 	sa.sa_handler = SIG_IGN;
353 	sigaction(SIGPIPE, &sa, &sapipe);
354 
355 	{
356 		/* space for daemons to overwrite environment for ps */
357 #define	DUMMYSIZE	100
358 		char dummy[DUMMYSIZE];
359 
360 		(void)memset(dummy, 'x', DUMMYSIZE - 1);
361 		dummy[DUMMYSIZE - 1] = '\0';
362 		(void)setenv("inetd_dummy", dummy, 1);
363 	}
364 
365 	if (pipe(signalpipe) != 0) {
366 		syslog(LOG_ERR, "pipe: %m");
367 		exit(EX_OSERR);
368 	}
369 	FD_SET(signalpipe[0], &allsock);
370 #ifdef SANITY_CHECK
371 	nsock++;
372 #endif
373 	if (signalpipe[0] > maxsock)
374 	    maxsock = signalpipe[0];
375 	if (signalpipe[1] > maxsock)
376 	    maxsock = signalpipe[1];
377 
378 	for (;;) {
379 	    int n, ctrl;
380 	    fd_set readable;
381 
382 #ifdef SANITY_CHECK
383 	    if (nsock == 0) {
384 		syslog(LOG_ERR, "%s: nsock=0", __FUNCTION__);
385 		exit(EX_SOFTWARE);
386 	    }
387 #endif
388 	    readable = allsock;
389 	    if ((n = select(maxsock + 1, &readable, (fd_set *)0,
390 		(fd_set *)0, (struct timeval *)0)) <= 0) {
391 		    if (n < 0 && errno != EINTR) {
392 			syslog(LOG_WARNING, "select: %m");
393 			sleep(1);
394 		    }
395 		    continue;
396 	    }
397 	    /* handle any queued signal flags */
398 	    if (FD_ISSET(signalpipe[0], &readable)) {
399 		int n;
400 		if (ioctl(signalpipe[0], FIONREAD, &n) != 0) {
401 		    syslog(LOG_ERR, "ioctl: %m");
402 		    exit(EX_OSERR);
403 		}
404 		while (--n >= 0) {
405 		    char c;
406 		    if (read(signalpipe[0], &c, 1) != 1) {
407 			syslog(LOG_ERR, "read: %m");
408 			exit(EX_OSERR);
409 		    }
410 		    if (debug)
411 			warnx("Handling signal flag %c", c);
412 		    switch(c) {
413 		    case 'A': /* sigalrm */
414 			retry();
415 			break;
416 		    case 'C': /* sigchld */
417 			reapchild();
418 			break;
419 		    case 'H': /* sighup */
420 			config();
421 			break;
422 		    }
423 		}
424 	    }
425 	    for (sep = servtab; n && sep; sep = sep->se_next)
426 	        if (sep->se_fd != -1 && FD_ISSET(sep->se_fd, &readable)) {
427 		    n--;
428 		    if (debug)
429 			    warnx("someone wants %s", sep->se_service);
430 		    if (sep->se_accept && sep->se_socktype == SOCK_STREAM) {
431 			    i = 1;
432 			    if (ioctl(sep->se_fd, FIONBIO, &i) < 0)
433 				    syslog(LOG_ERR, "ioctl (FIONBIO, 1): %m");
434 			    ctrl = accept(sep->se_fd, (struct sockaddr *)0,
435 				(int *)0);
436 			    if (debug)
437 				    warnx("accept, ctrl %d", ctrl);
438 			    if (ctrl < 0) {
439 				    if (errno != EINTR)
440 					    syslog(LOG_WARNING,
441 						"accept (for %s): %m",
442 						sep->se_service);
443                                       if (sep->se_accept &&
444                                           sep->se_socktype == SOCK_STREAM)
445                                               close(ctrl);
446 				    continue;
447 			    }
448 			    i = 0;
449 			    if (ioctl(sep->se_fd, FIONBIO, &i) < 0)
450 				    syslog(LOG_ERR, "ioctl1(FIONBIO, 0): %m");
451 			    if (ioctl(ctrl, FIONBIO, &i) < 0)
452 				    syslog(LOG_ERR, "ioctl2(FIONBIO, 0): %m");
453 			    if (cpmip(sep, ctrl) < 0) {
454 				close(ctrl);
455 				continue;
456 			    }
457 		    } else
458 			    ctrl = sep->se_fd;
459 		    if (log && !ISWRAP(sep)) {
460 			    pnm = "unknown";
461 			    i = sizeof peer;
462 			    if (getpeername(ctrl, (struct sockaddr *)
463 					    &peer, &i)) {
464 				    i = sizeof peer;
465 				    if (recvfrom(ctrl, buf, sizeof(buf),
466 					MSG_PEEK,
467 					(struct sockaddr *)&peer, &i) >= 0)
468 					    pnm = inet_ntoa(peer.sin_addr);
469 			    }
470 			    else
471 				    pnm = inet_ntoa(peer.sin_addr);
472 			    syslog(LOG_INFO,"%s from %s", sep->se_service, pnm);
473 		    }
474 		    (void) sigblock(SIGBLOCK);
475 		    pid = 0;
476 		    /*
477 		     * Fork for all external services, builtins which need to
478 		     * fork and anything we're wrapping (as wrapping might
479 		     * block or use hosts_options(5) twist).
480 		     */
481 		    dofork = !sep->se_bi || sep->se_bi->bi_fork || ISWRAP(sep);
482 		    if (dofork) {
483 			    if (sep->se_count++ == 0)
484 				(void)gettimeofday(&sep->se_time, (struct timezone *)NULL);
485 			    else if (sep->se_count >= toomany) {
486 				struct timeval now;
487 
488 				(void)gettimeofday(&now, (struct timezone *)NULL);
489 				if (now.tv_sec - sep->se_time.tv_sec >
490 				    CNT_INTVL) {
491 					sep->se_time = now;
492 					sep->se_count = 1;
493 				} else {
494 					syslog(LOG_ERR,
495 			"%s/%s server failing (looping), service terminated",
496 					    sep->se_service, sep->se_proto);
497 					close_sep(sep);
498 					sigsetmask(0L);
499 					if (!timingout) {
500 						timingout = 1;
501 						alarm(RETRYTIME);
502 					}
503 					continue;
504 				}
505 			    }
506 			    pid = fork();
507 		    }
508 		    if (pid < 0) {
509 			    syslog(LOG_ERR, "fork: %m");
510 			    if (sep->se_accept &&
511 				sep->se_socktype == SOCK_STREAM)
512 				    close(ctrl);
513 			    sigsetmask(0L);
514 			    sleep(1);
515 			    continue;
516 		    }
517 		    if (pid)
518 			addchild(sep, pid);
519 		    sigsetmask(0L);
520 		    if (pid == 0) {
521 			    if (dofork) {
522 				if (debug)
523 					warnx("+ closing from %d", maxsock);
524 				for (tmpint = maxsock; tmpint > 2; tmpint--)
525 					if (tmpint != ctrl)
526 						(void) close(tmpint);
527 				sigaction(SIGALRM, &saalrm, (struct sigaction *)0);
528 				sigaction(SIGCHLD, &sachld, (struct sigaction *)0);
529 				sigaction(SIGHUP, &sahup, (struct sigaction *)0);
530 				/* SIGPIPE reset before exec */
531 			    }
532 			    /*
533 			     * Call tcpmux to find the real service to exec.
534 			     */
535 			    if (sep->se_bi &&
536 				sep->se_bi->bi_fn == (void (*)()) tcpmux) {
537 				    sep = tcpmux(ctrl);
538 				    if (sep == NULL) {
539 					    close(ctrl);
540 					    _exit(0);
541 				    }
542 			    }
543 			    if (ISWRAP(sep)) {
544 				inetd_setproctitle("wrapping", ctrl);
545 				service = sep->se_server_name ?
546 				    sep->se_server_name : sep->se_service;
547 				request_init(&req, RQ_DAEMON, service, RQ_FILE, ctrl, NULL);
548 				fromhost(&req);
549 				deny_severity = LIBWRAP_DENY_FACILITY|LIBWRAP_DENY_SEVERITY;
550 				allow_severity = LIBWRAP_ALLOW_FACILITY|LIBWRAP_ALLOW_SEVERITY;
551 				denied = !hosts_access(&req);
552 				if (denied) {
553 				    syslog(deny_severity,
554 				        "refused connection from %.500s, service %s (%s)",
555 				        eval_client(&req), service, sep->se_proto);
556 				    if (sep->se_socktype != SOCK_STREAM)
557 					recv(ctrl, buf, sizeof (buf), 0);
558 				    if (dofork)
559 					_exit(0);
560 				}
561 				if (log) {
562 				    syslog(allow_severity,
563 				        "connection from %.500s, service %s (%s)",
564 					eval_client(&req), service, sep->se_proto);
565 				}
566 			    }
567 			    if (sep->se_bi) {
568 				(*sep->se_bi->bi_fn)(ctrl, sep);
569 			    } else {
570 				if (debug)
571 					warnx("%d execl %s",
572 						getpid(), sep->se_server);
573 				dup2(ctrl, 0);
574 				close(ctrl);
575 				dup2(0, 1);
576 				dup2(0, 2);
577 				if ((pwd = getpwnam(sep->se_user)) == NULL) {
578 					syslog(LOG_ERR,
579 					    "%s/%s: %s: No such user",
580 						sep->se_service, sep->se_proto,
581 						sep->se_user);
582 					if (sep->se_socktype != SOCK_STREAM)
583 						recv(0, buf, sizeof (buf), 0);
584 					_exit(EX_NOUSER);
585 				}
586 				grp = NULL;
587 				if (   sep->se_group != NULL
588 				    && (grp = getgrnam(sep->se_group)) == NULL
589 				   ) {
590 					syslog(LOG_ERR,
591 					    "%s/%s: %s: No such group",
592 						sep->se_service, sep->se_proto,
593 						sep->se_group);
594 					if (sep->se_socktype != SOCK_STREAM)
595 						recv(0, buf, sizeof (buf), 0);
596 					_exit(EX_NOUSER);
597 				}
598 				if (grp != NULL)
599 					pwd->pw_gid = grp->gr_gid;
600 #ifdef LOGIN_CAP
601 				if ((lc = login_getclass(sep->se_class)) == NULL) {
602 					/* error syslogged by getclass */
603 					syslog(LOG_ERR,
604 					    "%s/%s: %s: login class error",
605 						sep->se_service, sep->se_proto,
606 						sep->se_class);
607 					if (sep->se_socktype != SOCK_STREAM)
608 						recv(0, buf, sizeof (buf), 0);
609 					_exit(EX_NOUSER);
610 				}
611 #endif
612 				if (setsid() < 0) {
613 					syslog(LOG_ERR,
614 						"%s: can't setsid(): %m",
615 						 sep->se_service);
616 					/* _exit(EX_OSERR); not fatal yet */
617 				}
618 #ifdef LOGIN_CAP
619 				if (setusercontext(lc, pwd, pwd->pw_uid,
620 				    LOGIN_SETALL) != 0) {
621 					syslog(LOG_ERR,
622 					 "%s: can't setusercontext(..%s..): %m",
623 					 sep->se_service, sep->se_user);
624 					_exit(EX_OSERR);
625 				}
626 #else
627 				if (pwd->pw_uid) {
628 					if (setlogin(sep->se_user) < 0) {
629 						syslog(LOG_ERR,
630 						 "%s: can't setlogin(%s): %m",
631 						 sep->se_service, sep->se_user);
632 						/* _exit(EX_OSERR); not yet */
633 					}
634 					if (setgid(pwd->pw_gid) < 0) {
635 						syslog(LOG_ERR,
636 						  "%s: can't set gid %d: %m",
637 						  sep->se_service, pwd->pw_gid);
638 						_exit(EX_OSERR);
639 					}
640 					(void) initgroups(pwd->pw_name,
641 							pwd->pw_gid);
642 					if (setuid(pwd->pw_uid) < 0) {
643 						syslog(LOG_ERR,
644 						  "%s: can't set uid %d: %m",
645 						  sep->se_service, pwd->pw_uid);
646 						_exit(EX_OSERR);
647 					}
648 				}
649 #endif
650 				sigaction(SIGPIPE, &sapipe,
651 				    (struct sigaction *)0);
652 				execv(sep->se_server, sep->se_argv);
653 				syslog(LOG_ERR,
654 				    "cannot execute %s: %m", sep->se_server);
655 				if (sep->se_socktype != SOCK_STREAM)
656 					recv(0, buf, sizeof (buf), 0);
657 			    }
658 			    if (dofork)
659 				_exit(0);
660 		    }
661 		    if (sep->se_accept && sep->se_socktype == SOCK_STREAM)
662 			    close(ctrl);
663 		}
664 	}
665 }
666 
667 /*
668  * Add a signal flag to the signal flag queue for later handling
669  */
670 
671 void flag_signal(c)
672     char c;
673 {
674 	if (write(signalpipe[1], &c, 1) != 1) {
675 		syslog(LOG_ERR, "write: %m");
676 		_exit(EX_OSERR);
677 	}
678 }
679 
680 /*
681  * Record a new child pid for this service. If we've reached the
682  * limit on children, then stop accepting incoming requests.
683  */
684 
685 void
686 addchild(struct servtab *sep, pid_t pid)
687 {
688 #ifdef SANITY_CHECK
689 	if (sep->se_numchild >= sep->se_maxchild) {
690 		syslog(LOG_ERR, "%s: %d >= %d",
691 		    __FUNCTION__, sep->se_numchild, sep->se_maxchild);
692 		exit(EX_SOFTWARE);
693 	}
694 #endif
695 	if (sep->se_maxchild == 0)
696 		return;
697 	sep->se_pids[sep->se_numchild++] = pid;
698 	if (sep->se_numchild == sep->se_maxchild)
699 		disable(sep);
700 }
701 
702 /*
703  * Some child process has exited. See if it's on somebody's list.
704  */
705 
706 void
707 flag_reapchild(signo)
708 	int signo;
709 {
710 	flag_signal('C');
711 }
712 
713 void
714 reapchild()
715 {
716 	int k, status;
717 	pid_t pid;
718 	struct servtab *sep;
719 
720 	for (;;) {
721 		pid = wait3(&status, WNOHANG, (struct rusage *)0);
722 		if (pid <= 0)
723 			break;
724 		if (debug)
725 			warnx("%d reaped, status %#x", pid, status);
726 		for (sep = servtab; sep; sep = sep->se_next) {
727 			for (k = 0; k < sep->se_numchild; k++)
728 				if (sep->se_pids[k] == pid)
729 					break;
730 			if (k == sep->se_numchild)
731 				continue;
732 			if (sep->se_numchild == sep->se_maxchild)
733 				enable(sep);
734 			sep->se_pids[k] = sep->se_pids[--sep->se_numchild];
735 			if (status)
736 				syslog(LOG_WARNING,
737 				    "%s[%d]: exit status 0x%x",
738 				    sep->se_server, pid, status);
739 			break;
740 		}
741 	}
742 }
743 
744 void
745 flag_config(signo)
746 	int signo;
747 {
748 	flag_signal('H');
749 }
750 
751 void config()
752 {
753 	struct servtab *sep, *new, **sepp;
754 	long omask;
755 
756 	if (!setconfig()) {
757 		syslog(LOG_ERR, "%s: %m", CONFIG);
758 		return;
759 	}
760 	for (sep = servtab; sep; sep = sep->se_next)
761 		sep->se_checked = 0;
762 	while ((new = getconfigent())) {
763 		if (getpwnam(new->se_user) == NULL) {
764 			syslog(LOG_ERR,
765 				"%s/%s: No such user '%s', service ignored",
766 				new->se_service, new->se_proto, new->se_user);
767 			continue;
768 		}
769 		if (new->se_group && getgrnam(new->se_group) == NULL) {
770 			syslog(LOG_ERR,
771 				"%s/%s: No such group '%s', service ignored",
772 				new->se_service, new->se_proto, new->se_group);
773 			continue;
774 		}
775 #ifdef LOGIN_CAP
776 		if (login_getclass(new->se_class) == NULL) {
777 			/* error syslogged by getclass */
778 			syslog(LOG_ERR,
779 				"%s/%s: %s: login class error, service ignored",
780 				new->se_service, new->se_proto, new->se_class);
781 			continue;
782 		}
783 #endif
784 		for (sep = servtab; sep; sep = sep->se_next)
785 			if (strcmp(sep->se_service, new->se_service) == 0 &&
786 			    strcmp(sep->se_proto, new->se_proto) == 0)
787 				break;
788 		if (sep != 0) {
789 			int i;
790 
791 #define SWAP(a, b) { typeof(a) c = a; a = b; b = c; }
792 			omask = sigblock(SIGBLOCK);
793 			/* copy over outstanding child pids */
794 			if (sep->se_maxchild && new->se_maxchild) {
795 				new->se_numchild = sep->se_numchild;
796 				if (new->se_numchild > new->se_maxchild)
797 					new->se_numchild = new->se_maxchild;
798 				memcpy(new->se_pids, sep->se_pids,
799 				    new->se_numchild * sizeof(*new->se_pids));
800 			}
801 			SWAP(sep->se_pids, new->se_pids);
802 			sep->se_maxchild = new->se_maxchild;
803 			sep->se_numchild = new->se_numchild;
804 			sep->se_maxcpm = new->se_maxcpm;
805 			/* might need to turn on or off service now */
806 			if (sep->se_fd >= 0) {
807 			      if (sep->se_maxchild
808 				  && sep->se_numchild == sep->se_maxchild) {
809 				      if (FD_ISSET(sep->se_fd, &allsock))
810 					  disable(sep);
811 			      } else {
812 				      if (!FD_ISSET(sep->se_fd, &allsock))
813 					  enable(sep);
814 			      }
815 			}
816 			sep->se_accept = new->se_accept;
817 			SWAP(sep->se_user, new->se_user);
818 			SWAP(sep->se_group, new->se_group);
819 #ifdef LOGIN_CAP
820 			SWAP(sep->se_class, new->se_class);
821 #endif
822 			SWAP(sep->se_server, new->se_server);
823 			SWAP(sep->se_server_name, new->se_server_name);
824 			for (i = 0; i < MAXARGV; i++)
825 				SWAP(sep->se_argv[i], new->se_argv[i]);
826 			sigsetmask(omask);
827 			freeconfig(new);
828 			if (debug)
829 				print_service("REDO", sep);
830 		} else {
831 			sep = enter(new);
832 			if (debug)
833 				print_service("ADD ", sep);
834 		}
835 		sep->se_checked = 1;
836 		if (ISMUX(sep)) {
837 			sep->se_fd = -1;
838 			continue;
839 		}
840 		if (!sep->se_rpc) {
841 			sp = getservbyname(sep->se_service, sep->se_proto);
842 			if (sp == 0) {
843 				syslog(LOG_ERR, "%s/%s: unknown service",
844 			    	sep->se_service, sep->se_proto);
845 				sep->se_checked = 0;
846 				continue;
847 			}
848 			if (sp->s_port != sep->se_ctrladdr.sin_port) {
849 				sep->se_ctrladdr.sin_family = AF_INET;
850 				sep->se_ctrladdr.sin_addr = bind_address;
851 				sep->se_ctrladdr.sin_port = sp->s_port;
852 				if (sep->se_fd >= 0)
853 					close_sep(sep);
854 			}
855 		} else {
856 			rpc = getrpcbyname(sep->se_service);
857 			if (rpc == 0) {
858 				syslog(LOG_ERR, "%s/%s unknown RPC service",
859 					sep->se_service, sep->se_proto);
860 				if (sep->se_fd != -1)
861 					(void) close(sep->se_fd);
862 				sep->se_fd = -1;
863 					continue;
864 			}
865 			if (rpc->r_number != sep->se_rpc_prog) {
866 				if (sep->se_rpc_prog)
867 					unregisterrpc(sep);
868 				sep->se_rpc_prog = rpc->r_number;
869 				if (sep->se_fd != -1)
870 					(void) close(sep->se_fd);
871 				sep->se_fd = -1;
872 			}
873 		}
874 		if (sep->se_fd == -1)
875 			setup(sep);
876 	}
877 	endconfig();
878 	/*
879 	 * Purge anything not looked at above.
880 	 */
881 	omask = sigblock(SIGBLOCK);
882 	sepp = &servtab;
883 	while ((sep = *sepp)) {
884 		if (sep->se_checked) {
885 			sepp = &sep->se_next;
886 			continue;
887 		}
888 		*sepp = sep->se_next;
889 		if (sep->se_fd >= 0)
890 			close_sep(sep);
891 		if (debug)
892 			print_service("FREE", sep);
893 		if (sep->se_rpc && sep->se_rpc_prog > 0)
894 			unregisterrpc(sep);
895 		freeconfig(sep);
896 		free((char *)sep);
897 	}
898 	(void) sigsetmask(omask);
899 }
900 
901 void
902 unregisterrpc(sep)
903 	struct servtab *sep;
904 {
905         int i;
906         struct servtab *sepp;
907 	long omask;
908 
909 	omask = sigblock(SIGBLOCK);
910         for (sepp = servtab; sepp; sepp = sepp->se_next) {
911                 if (sepp == sep)
912                         continue;
913 		if (sep->se_checked == 0 ||
914                     !sepp->se_rpc ||
915                     sep->se_rpc_prog != sepp->se_rpc_prog)
916 			continue;
917                 return;
918         }
919         if (debug)
920                 print_service("UNREG", sep);
921         for (i = sep->se_rpc_lowvers; i <= sep->se_rpc_highvers; i++)
922                 pmap_unset(sep->se_rpc_prog, i);
923         if (sep->se_fd != -1)
924                 (void) close(sep->se_fd);
925         sep->se_fd = -1;
926 	(void) sigsetmask(omask);
927 }
928 
929 void
930 flag_retry(signo)
931 	int signo;
932 {
933 	flag_signal('A');
934 }
935 
936 void
937 retry()
938 {
939 	struct servtab *sep;
940 
941 	timingout = 0;
942 	for (sep = servtab; sep; sep = sep->se_next)
943 		if (sep->se_fd == -1 && !ISMUX(sep))
944 			setup(sep);
945 }
946 
947 void
948 setup(sep)
949 	struct servtab *sep;
950 {
951 	int on = 1;
952 
953 	if ((sep->se_fd = socket(AF_INET, sep->se_socktype, 0)) < 0) {
954 		if (debug)
955 			warn("socket failed on %s/%s",
956 				sep->se_service, sep->se_proto);
957 		syslog(LOG_ERR, "%s/%s: socket: %m",
958 		    sep->se_service, sep->se_proto);
959 		return;
960 	}
961 #define	turnon(fd, opt) \
962 setsockopt(fd, SOL_SOCKET, opt, (char *)&on, sizeof (on))
963 	if (strcmp(sep->se_proto, "tcp") == 0 && (options & SO_DEBUG) &&
964 	    turnon(sep->se_fd, SO_DEBUG) < 0)
965 		syslog(LOG_ERR, "setsockopt (SO_DEBUG): %m");
966 	if (turnon(sep->se_fd, SO_REUSEADDR) < 0)
967 		syslog(LOG_ERR, "setsockopt (SO_REUSEADDR): %m");
968 #ifdef SO_PRIVSTATE
969 	if (turnon(sep->se_fd, SO_PRIVSTATE) < 0)
970 		syslog(LOG_ERR, "setsockopt (SO_PRIVSTATE): %m");
971 #endif
972 #undef turnon
973 	if (sep->se_type == TTCP_TYPE)
974 		if (setsockopt(sep->se_fd, IPPROTO_TCP, TCP_NOPUSH,
975 		    (char *)&on, sizeof (on)) < 0)
976 			syslog(LOG_ERR, "setsockopt (TCP_NOPUSH): %m");
977 	if (bind(sep->se_fd, (struct sockaddr *)&sep->se_ctrladdr,
978 	    sizeof (sep->se_ctrladdr)) < 0) {
979 		if (debug)
980 			warn("bind failed on %s/%s",
981 				sep->se_service, sep->se_proto);
982 		syslog(LOG_ERR, "%s/%s: bind: %m",
983 		    sep->se_service, sep->se_proto);
984 		(void) close(sep->se_fd);
985 		sep->se_fd = -1;
986 		if (!timingout) {
987 			timingout = 1;
988 			alarm(RETRYTIME);
989 		}
990 		return;
991 	}
992         if (sep->se_rpc) {
993                 int i, len = sizeof(struct sockaddr);
994 
995                 if (getsockname(sep->se_fd,
996 				(struct sockaddr*)&sep->se_ctrladdr, &len) < 0){
997                         syslog(LOG_ERR, "%s/%s: getsockname: %m",
998                                sep->se_service, sep->se_proto);
999                         (void) close(sep->se_fd);
1000                         sep->se_fd = -1;
1001                         return;
1002                 }
1003                 if (debug)
1004                         print_service("REG ", sep);
1005                 for (i = sep->se_rpc_lowvers; i <= sep->se_rpc_highvers; i++) {
1006                         pmap_unset(sep->se_rpc_prog, i);
1007                         pmap_set(sep->se_rpc_prog, i,
1008                                  (sep->se_socktype == SOCK_DGRAM)
1009                                  ? IPPROTO_UDP : IPPROTO_TCP,
1010                                  ntohs(sep->se_ctrladdr.sin_port));
1011                 }
1012 
1013         }
1014 	if (sep->se_socktype == SOCK_STREAM)
1015 		listen(sep->se_fd, 64);
1016 	enable(sep);
1017 	if (debug) {
1018 		warnx("registered %s on %d",
1019 			sep->se_server, sep->se_fd);
1020 	}
1021 }
1022 
1023 /*
1024  * Finish with a service and its socket.
1025  */
1026 void
1027 close_sep(sep)
1028 	struct servtab *sep;
1029 {
1030 	if (sep->se_fd >= 0) {
1031 		if (FD_ISSET(sep->se_fd, &allsock))
1032 			disable(sep);
1033 		(void) close(sep->se_fd);
1034 		sep->se_fd = -1;
1035 	}
1036 	sep->se_count = 0;
1037 	sep->se_numchild = 0;	/* forget about any existing children */
1038 }
1039 
1040 int
1041 matchservent(name1, name2, proto)
1042 	char *name1, *name2, *proto;
1043 {
1044 	char **alias;
1045 	struct servent *se;
1046 
1047 	if (strcmp(name1, name2) == 0)
1048 		return(1);
1049 	if ((se = getservbyname(name1, proto)) != NULL) {
1050 		if (strcmp(name2, se->s_name) == 0)
1051 			return(1);
1052 		for (alias = se->s_aliases; *alias; alias++)
1053 			if (strcmp(name2, *alias) == 0)
1054 				return(1);
1055 	}
1056 	return(0);
1057 }
1058 
1059 struct servtab *
1060 enter(cp)
1061 	struct servtab *cp;
1062 {
1063 	struct servtab *sep;
1064 	long omask;
1065 
1066 	sep = (struct servtab *)malloc(sizeof (*sep));
1067 	if (sep == (struct servtab *)0) {
1068 		syslog(LOG_ERR, "malloc: %m");
1069 		exit(EX_OSERR);
1070 	}
1071 	*sep = *cp;
1072 	sep->se_fd = -1;
1073 	omask = sigblock(SIGBLOCK);
1074 	sep->se_next = servtab;
1075 	servtab = sep;
1076 	sigsetmask(omask);
1077 	return (sep);
1078 }
1079 
1080 void
1081 enable(struct servtab *sep)
1082 {
1083 	if (debug)
1084 		warnx(
1085 		    "enabling %s, fd %d", sep->se_service, sep->se_fd);
1086 #ifdef SANITY_CHECK
1087 	if (sep->se_fd < 0) {
1088 		syslog(LOG_ERR,
1089 		    "%s: %s: bad fd", __FUNCTION__, sep->se_service);
1090 		exit(EX_SOFTWARE);
1091 	}
1092 	if (ISMUX(sep)) {
1093 		syslog(LOG_ERR,
1094 		    "%s: %s: is mux", __FUNCTION__, sep->se_service);
1095 		exit(EX_SOFTWARE);
1096 	}
1097 	if (FD_ISSET(sep->se_fd, &allsock)) {
1098 		syslog(LOG_ERR,
1099 		    "%s: %s: not off", __FUNCTION__, sep->se_service);
1100 		exit(EX_SOFTWARE);
1101 	}
1102 	nsock++;
1103 #endif
1104 	FD_SET(sep->se_fd, &allsock);
1105 	if (sep->se_fd > maxsock)
1106 		maxsock = sep->se_fd;
1107 }
1108 
1109 void
1110 disable(struct servtab *sep)
1111 {
1112 	if (debug)
1113 		warnx(
1114 		    "disabling %s, fd %d", sep->se_service, sep->se_fd);
1115 #ifdef SANITY_CHECK
1116 	if (sep->se_fd < 0) {
1117 		syslog(LOG_ERR,
1118 		    "%s: %s: bad fd", __FUNCTION__, sep->se_service);
1119 		exit(EX_SOFTWARE);
1120 	}
1121 	if (ISMUX(sep)) {
1122 		syslog(LOG_ERR,
1123 		    "%s: %s: is mux", __FUNCTION__, sep->se_service);
1124 		exit(EX_SOFTWARE);
1125 	}
1126 	if (!FD_ISSET(sep->se_fd, &allsock)) {
1127 		syslog(LOG_ERR,
1128 		    "%s: %s: not on", __FUNCTION__, sep->se_service);
1129 		exit(EX_SOFTWARE);
1130 	}
1131 	if (nsock == 0) {
1132 		syslog(LOG_ERR, "%s: nsock=0", __FUNCTION__);
1133 		exit(EX_SOFTWARE);
1134 	}
1135 	nsock--;
1136 #endif
1137 	FD_CLR(sep->se_fd, &allsock);
1138 	if (sep->se_fd == maxsock)
1139 		maxsock--;
1140 }
1141 
1142 FILE	*fconfig = NULL;
1143 struct	servtab serv;
1144 char	line[LINE_MAX];
1145 
1146 int
1147 setconfig()
1148 {
1149 
1150 	if (fconfig != NULL) {
1151 		fseek(fconfig, 0L, SEEK_SET);
1152 		return (1);
1153 	}
1154 	fconfig = fopen(CONFIG, "r");
1155 	return (fconfig != NULL);
1156 }
1157 
1158 void
1159 endconfig()
1160 {
1161 	if (fconfig) {
1162 		(void) fclose(fconfig);
1163 		fconfig = NULL;
1164 	}
1165 }
1166 
1167 struct servtab *
1168 getconfigent()
1169 {
1170 	struct servtab *sep = &serv;
1171 	int argc;
1172 	char *cp, *arg, *s;
1173 	char *versp;
1174 	static char TCPMUX_TOKEN[] = "tcpmux/";
1175 #define MUX_LEN		(sizeof(TCPMUX_TOKEN)-1)
1176 
1177 more:
1178 	while ((cp = nextline(fconfig)) && (*cp == '#' || *cp == '\0'))
1179 		;
1180 	if (cp == NULL)
1181 		return ((struct servtab *)0);
1182 	/*
1183 	 * clear the static buffer, since some fields (se_ctrladdr,
1184 	 * for example) don't get initialized here.
1185 	 */
1186 	memset((caddr_t)sep, 0, sizeof *sep);
1187 	arg = skip(&cp);
1188 	if (cp == NULL) {
1189 		/* got an empty line containing just blanks/tabs. */
1190 		goto more;
1191 	}
1192 	if (strncmp(arg, TCPMUX_TOKEN, MUX_LEN) == 0) {
1193 		char *c = arg + MUX_LEN;
1194 		if (*c == '+') {
1195 			sep->se_type = MUXPLUS_TYPE;
1196 			c++;
1197 		} else
1198 			sep->se_type = MUX_TYPE;
1199 		sep->se_service = newstr(c);
1200 	} else {
1201 		sep->se_service = newstr(arg);
1202 		sep->se_type = NORM_TYPE;
1203 	}
1204 	arg = sskip(&cp);
1205 	if (strcmp(arg, "stream") == 0)
1206 		sep->se_socktype = SOCK_STREAM;
1207 	else if (strcmp(arg, "dgram") == 0)
1208 		sep->se_socktype = SOCK_DGRAM;
1209 	else if (strcmp(arg, "rdm") == 0)
1210 		sep->se_socktype = SOCK_RDM;
1211 	else if (strcmp(arg, "seqpacket") == 0)
1212 		sep->se_socktype = SOCK_SEQPACKET;
1213 	else if (strcmp(arg, "raw") == 0)
1214 		sep->se_socktype = SOCK_RAW;
1215 	else
1216 		sep->se_socktype = -1;
1217 
1218 	arg = sskip(&cp);
1219 	if (strcmp(arg, "tcp/ttcp") == 0) {
1220 		sep->se_type = TTCP_TYPE;
1221 		sep->se_proto = newstr("tcp");
1222 	} else {
1223 		sep->se_proto = newstr(arg);
1224 	}
1225         if (strncmp(sep->se_proto, "rpc/", 4) == 0) {
1226                 memmove(sep->se_proto, sep->se_proto + 4,
1227                     strlen(sep->se_proto) + 1 - 4);
1228                 sep->se_rpc = 1;
1229                 sep->se_rpc_prog = sep->se_rpc_lowvers =
1230 			sep->se_rpc_lowvers = 0;
1231                 sep->se_ctrladdr.sin_family = AF_INET;
1232                 sep->se_ctrladdr.sin_port = 0;
1233                 sep->se_ctrladdr.sin_addr = bind_address;
1234                 if ((versp = rindex(sep->se_service, '/'))) {
1235                         *versp++ = '\0';
1236                         switch (sscanf(versp, "%d-%d",
1237                                        &sep->se_rpc_lowvers,
1238                                        &sep->se_rpc_highvers)) {
1239                         case 2:
1240                                 break;
1241                         case 1:
1242                                 sep->se_rpc_highvers =
1243                                         sep->se_rpc_lowvers;
1244                                 break;
1245                         default:
1246                                 syslog(LOG_ERR,
1247 					"bad RPC version specifier; %s",
1248 					sep->se_service);
1249                                 freeconfig(sep);
1250                                 goto more;
1251                         }
1252                 }
1253                 else {
1254                         sep->se_rpc_lowvers =
1255                                 sep->se_rpc_highvers = 1;
1256                 }
1257         }
1258 	arg = sskip(&cp);
1259 	if (!strncmp(arg, "wait", 4))
1260 		sep->se_accept = 0;
1261 	else if (!strncmp(arg, "nowait", 6))
1262 		sep->se_accept = 1;
1263 	else {
1264 		syslog(LOG_ERR,
1265 			"%s: bad wait/nowait for service %s",
1266 			CONFIG, sep->se_service);
1267 		goto more;
1268 	}
1269 	sep->se_maxchild = -1;
1270 	sep->se_maxcpm = -1;
1271 	if ((s = strchr(arg, '/')) != NULL) {
1272 		char *eptr;
1273 		u_long val;
1274 
1275 		val = strtoul(s + 1, &eptr, 10);
1276 		if (eptr == s + 1 || val > MAX_MAXCHLD) {
1277 			syslog(LOG_ERR,
1278 				"%s: bad max-child for service %s",
1279 				CONFIG, sep->se_service);
1280 			goto more;
1281 		}
1282 		if (debug)
1283 			if (!sep->se_accept && val != 1)
1284 				warnx("maxchild=%lu for wait service %s"
1285 				    " not recommended", val, sep->se_service);
1286 		sep->se_maxchild = val;
1287 		if (*eptr == '/')
1288 			sep->se_maxcpm = strtol(eptr + 1, &eptr, 10);
1289 		/*
1290 		 * explicitly do not check for \0 for future expansion /
1291 		 * backwards compatibility
1292 		 */
1293 	}
1294 	if (ISMUX(sep)) {
1295 		/*
1296 		 * Silently enforce "nowait" mode for TCPMUX services
1297 		 * since they don't have an assigned port to listen on.
1298 		 */
1299 		sep->se_accept = 1;
1300 		if (strcmp(sep->se_proto, "tcp")) {
1301 			syslog(LOG_ERR,
1302 				"%s: bad protocol for tcpmux service %s",
1303 				CONFIG, sep->se_service);
1304 			goto more;
1305 		}
1306 		if (sep->se_socktype != SOCK_STREAM) {
1307 			syslog(LOG_ERR,
1308 				"%s: bad socket type for tcpmux service %s",
1309 				CONFIG, sep->se_service);
1310 			goto more;
1311 		}
1312 	}
1313 	sep->se_user = newstr(sskip(&cp));
1314 #ifdef LOGIN_CAP
1315 	if ((s = strrchr(sep->se_user, '/')) != NULL) {
1316 		*s = '\0';
1317 		sep->se_class = newstr(s + 1);
1318 	} else
1319 		sep->se_class = newstr(RESOURCE_RC);
1320 #endif
1321 	if ((s = strrchr(sep->se_user, ':')) != NULL) {
1322 		*s = '\0';
1323 		sep->se_group = newstr(s + 1);
1324 	} else
1325 		sep->se_group = NULL;
1326 	sep->se_server = newstr(sskip(&cp));
1327 	if ((sep->se_server_name = rindex(sep->se_server, '/')))
1328 		sep->se_server_name++;
1329 	if (strcmp(sep->se_server, "internal") == 0) {
1330 		struct biltin *bi;
1331 
1332 		for (bi = biltins; bi->bi_service; bi++)
1333 			if (bi->bi_socktype == sep->se_socktype &&
1334 			    matchservent(bi->bi_service, sep->se_service,
1335 			    sep->se_proto))
1336 				break;
1337 		if (bi->bi_service == 0) {
1338 			syslog(LOG_ERR, "internal service %s unknown",
1339 				sep->se_service);
1340 			goto more;
1341 		}
1342 		sep->se_accept = 1;	/* force accept mode for built-ins */
1343 		sep->se_bi = bi;
1344 	} else
1345 		sep->se_bi = NULL;
1346 	if (sep->se_maxcpm < 0)
1347 		sep->se_maxcpm = maxcpm;
1348 	if (sep->se_maxchild < 0) {	/* apply default max-children */
1349 		if (sep->se_bi && sep->se_bi->bi_maxchild >= 0)
1350 			sep->se_maxchild = sep->se_bi->bi_maxchild;
1351 		else if (sep->se_accept)
1352 			sep->se_maxchild = maxchild > 0 ? maxchild : 0;
1353 		else
1354 			sep->se_maxchild = 1;
1355 	}
1356 	if (sep->se_maxchild) {
1357 		sep->se_pids = malloc(sep->se_maxchild * sizeof(*sep->se_pids));
1358 		if (sep->se_pids == NULL) {
1359 			syslog(LOG_ERR, "malloc: %m");
1360 			exit(EX_OSERR);
1361 		}
1362 	}
1363 	argc = 0;
1364 	for (arg = skip(&cp); cp; arg = skip(&cp))
1365 		if (argc < MAXARGV) {
1366 			sep->se_argv[argc++] = newstr(arg);
1367 		} else {
1368 			syslog(LOG_ERR,
1369 				"%s: too many arguments for service %s",
1370 				CONFIG, sep->se_service);
1371 			goto more;
1372 		}
1373 	while (argc <= MAXARGV)
1374 		sep->se_argv[argc++] = NULL;
1375 	return (sep);
1376 }
1377 
1378 void
1379 freeconfig(cp)
1380 	struct servtab *cp;
1381 {
1382 	int i;
1383 
1384 	if (cp->se_service)
1385 		free(cp->se_service);
1386 	if (cp->se_proto)
1387 		free(cp->se_proto);
1388 	if (cp->se_user)
1389 		free(cp->se_user);
1390 	if (cp->se_group)
1391 		free(cp->se_group);
1392 #ifdef LOGIN_CAP
1393 	if (cp->se_class)
1394 		free(cp->se_class);
1395 #endif
1396 	if (cp->se_server)
1397 		free(cp->se_server);
1398 	if (cp->se_pids)
1399 		free(cp->se_pids);
1400 	for (i = 0; i < MAXARGV; i++)
1401 		if (cp->se_argv[i])
1402 			free(cp->se_argv[i]);
1403 }
1404 
1405 
1406 /*
1407  * Safe skip - if skip returns null, log a syntax error in the
1408  * configuration file and exit.
1409  */
1410 char *
1411 sskip(cpp)
1412 	char **cpp;
1413 {
1414 	char *cp;
1415 
1416 	cp = skip(cpp);
1417 	if (cp == NULL) {
1418 		syslog(LOG_ERR, "%s: syntax error", CONFIG);
1419 		exit(EX_DATAERR);
1420 	}
1421 	return (cp);
1422 }
1423 
1424 char *
1425 skip(cpp)
1426 	char **cpp;
1427 {
1428 	char *cp = *cpp;
1429 	char *start;
1430 	char quote = '\0';
1431 
1432 again:
1433 	while (*cp == ' ' || *cp == '\t')
1434 		cp++;
1435 	if (*cp == '\0') {
1436 		int c;
1437 
1438 		c = getc(fconfig);
1439 		(void) ungetc(c, fconfig);
1440 		if (c == ' ' || c == '\t')
1441 			if ((cp = nextline(fconfig)))
1442 				goto again;
1443 		*cpp = (char *)0;
1444 		return ((char *)0);
1445 	}
1446 	if (*cp == '"' || *cp == '\'')
1447 		quote = *cp++;
1448 	start = cp;
1449 	if (quote)
1450 		while (*cp && *cp != quote)
1451 			cp++;
1452 	else
1453 		while (*cp && *cp != ' ' && *cp != '\t')
1454 			cp++;
1455 	if (*cp != '\0')
1456 		*cp++ = '\0';
1457 	*cpp = cp;
1458 	return (start);
1459 }
1460 
1461 char *
1462 nextline(fd)
1463 	FILE *fd;
1464 {
1465 	char *cp;
1466 
1467 	if (fgets(line, sizeof (line), fd) == NULL)
1468 		return ((char *)0);
1469 	cp = strchr(line, '\n');
1470 	if (cp)
1471 		*cp = '\0';
1472 	return (line);
1473 }
1474 
1475 char *
1476 newstr(cp)
1477 	char *cp;
1478 {
1479 	if ((cp = strdup(cp ? cp : "")))
1480 		return (cp);
1481 	syslog(LOG_ERR, "strdup: %m");
1482 	exit(EX_OSERR);
1483 }
1484 
1485 #ifdef OLD_SETPROCTITLE
1486 void
1487 inetd_setproctitle(a, s)
1488 	char *a;
1489 	int s;
1490 {
1491 	int size;
1492 	char *cp;
1493 	struct sockaddr_in sin;
1494 	char buf[80];
1495 
1496 	cp = Argv[0];
1497 	size = sizeof(sin);
1498 	if (getpeername(s, (struct sockaddr *)&sin, &size) == 0)
1499 		(void) sprintf(buf, "-%s [%s]", a, inet_ntoa(sin.sin_addr));
1500 	else
1501 		(void) sprintf(buf, "-%s", a);
1502 	strncpy(cp, buf, LastArg - cp);
1503 	cp += strlen(cp);
1504 	while (cp < LastArg)
1505 		*cp++ = ' ';
1506 }
1507 #else
1508 void
1509 inetd_setproctitle(a, s)
1510 	char *a;
1511 	int s;
1512 {
1513 	int size;
1514 	struct sockaddr_in sin;
1515 	char buf[80];
1516 
1517 	size = sizeof(sin);
1518 	if (getpeername(s, (struct sockaddr *)&sin, &size) == 0)
1519 		(void) sprintf(buf, "%s [%s]", a, inet_ntoa(sin.sin_addr));
1520 	else
1521 		(void) sprintf(buf, "%s", a);
1522 	setproctitle("%s", buf);
1523 }
1524 #endif
1525 
1526 
1527 /*
1528  * Internet services provided internally by inetd:
1529  */
1530 
1531 int check_loop(sin, sep)
1532 	struct sockaddr_in *sin;
1533 	struct servtab *sep;
1534 {
1535 	struct servtab *se2;
1536 
1537 	for (se2 = servtab; se2; se2 = se2->se_next) {
1538 		if (!se2->se_bi || se2->se_socktype != SOCK_DGRAM)
1539 			continue;
1540 
1541 		if (sin->sin_port == se2->se_ctrladdr.sin_port) {
1542 			syslog(LOG_WARNING,
1543 			       "%s/%s:%s/%s loop request REFUSED from %s",
1544 			       sep->se_service, sep->se_proto,
1545 			       se2->se_service, se2->se_proto,
1546 			       inet_ntoa(sin->sin_addr));
1547 			return 1;
1548 		}
1549 	}
1550 	return 0;
1551 }
1552 
1553 /*
1554  * print_service:
1555  *	Dump relevant information to stderr
1556  */
1557 void
1558 print_service(action, sep)
1559 	char *action;
1560 	struct servtab *sep;
1561 {
1562 	fprintf(stderr,
1563 #ifdef LOGIN_CAP
1564 	    "%s: %s proto=%s accept=%d max=%d user=%s group=%s class=%s builtin=%p server=%s\n",
1565 #else
1566 	    "%s: %s proto=%s accept=%d max=%d user=%s group=%s builtin=%p server=%s\n",
1567 #endif
1568 	    action, sep->se_service, sep->se_proto,
1569 	    sep->se_accept, sep->se_maxchild, sep->se_user, sep->se_group,
1570 #ifdef LOGIN_CAP
1571 	    sep->se_class,
1572 #endif
1573 	    (void *) sep->se_bi, sep->se_server);
1574 }
1575 
1576 #define CPMHSIZE	256
1577 #define CPMHMASK	(CPMHSIZE-1)
1578 #define CHTGRAN		10
1579 #define CHTSIZE		6
1580 
1581 typedef struct CTime {
1582 	unsigned long 	ct_Ticks;
1583 	int		ct_Count;
1584 } CTime;
1585 
1586 typedef struct CHash {
1587 	struct in_addr	ch_Addr;
1588 	time_t		ch_LTime;
1589 	char		*ch_Service;
1590 	CTime		ch_Times[CHTSIZE];
1591 } CHash;
1592 
1593 CHash	CHashAry[CPMHSIZE];
1594 
1595 int
1596 cpmip(sep, ctrl)
1597 	struct servtab *sep;
1598 	int ctrl;
1599 {
1600 	struct sockaddr_in rsin;
1601 	int rsinLen = sizeof(rsin);
1602 	int r = 0;
1603 
1604 	/*
1605 	 * If getpeername() fails, just let it through (if logging is
1606 	 * enabled the condition is caught elsewhere)
1607 	 */
1608 
1609 	if (sep->se_maxcpm > 0 &&
1610 	    getpeername(ctrl, (struct sockaddr *)&rsin, &rsinLen) == 0 ) {
1611 		time_t t = time(NULL);
1612 		int hv = 0xABC3D20F;
1613 		int i;
1614 		int cnt = 0;
1615 		CHash *chBest = NULL;
1616 		unsigned int ticks = t / CHTGRAN;
1617 
1618 		{
1619 			char *p;
1620 			int i;
1621 
1622 			for (i = 0, p = (char *)&rsin.sin_addr;
1623 			    i < sizeof(rsin.sin_addr);
1624 			    ++i, ++p) {
1625 				hv = (hv << 5) ^ (hv >> 23) ^ *p;
1626 			}
1627 			hv = (hv ^ (hv >> 16));
1628 		}
1629 		for (i = 0; i < 5; ++i) {
1630 			CHash *ch = &CHashAry[(hv + i) & CPMHMASK];
1631 
1632 			if (rsin.sin_addr.s_addr == ch->ch_Addr.s_addr &&
1633 			    ch->ch_Service && strcmp(sep->se_service,
1634 			    ch->ch_Service) == 0) {
1635 				chBest = ch;
1636 				break;
1637 			}
1638 			if (chBest == NULL || ch->ch_LTime == 0 ||
1639 			    ch->ch_LTime < chBest->ch_LTime) {
1640 				chBest = ch;
1641 			}
1642 		}
1643 		if (rsin.sin_addr.s_addr != chBest->ch_Addr.s_addr ||
1644 		    chBest->ch_Service == NULL ||
1645 		    strcmp(sep->se_service, chBest->ch_Service) != 0) {
1646 			chBest->ch_Addr = rsin.sin_addr;
1647 			if (chBest->ch_Service)
1648 				free(chBest->ch_Service);
1649 			chBest->ch_Service = strdup(sep->se_service);
1650 			bzero(chBest->ch_Times, sizeof(chBest->ch_Times));
1651 		}
1652 		chBest->ch_LTime = t;
1653 		{
1654 			CTime *ct = &chBest->ch_Times[ticks % CHTSIZE];
1655 			if (ct->ct_Ticks != ticks) {
1656 				ct->ct_Ticks = ticks;
1657 				ct->ct_Count = 0;
1658 			}
1659 			++ct->ct_Count;
1660 		}
1661 		for (i = 0; i < CHTSIZE; ++i) {
1662 			CTime *ct = &chBest->ch_Times[i];
1663 			if (ct->ct_Ticks <= ticks &&
1664 			    ct->ct_Ticks >= ticks - CHTSIZE) {
1665 				cnt += ct->ct_Count;
1666 			}
1667 		}
1668 		if (cnt * (CHTSIZE * CHTGRAN) / 60 > sep->se_maxcpm) {
1669 			r = -1;
1670 			syslog(LOG_ERR,
1671 			    "%s from %s exceeded counts/min (limit %d/min)",
1672 			    sep->se_service, inet_ntoa(rsin.sin_addr),
1673 			    sep->se_maxcpm);
1674 		}
1675 	}
1676 	return(r);
1677 }
1678