xref: /freebsd/usr.sbin/inetd/inetd.c (revision 4cf49a43559ed9fdad601bdcccd2c55963008675)
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 			    ctrl = accept(sep->se_fd, (struct sockaddr *)0,
432 				(int *)0);
433 			    if (debug)
434 				    warnx("accept, ctrl %d", ctrl);
435 			    if (ctrl < 0) {
436 				    if (errno != EINTR)
437 					    syslog(LOG_WARNING,
438 						"accept (for %s): %m",
439 						sep->se_service);
440                                       if (sep->se_accept &&
441                                           sep->se_socktype == SOCK_STREAM)
442                                               close(ctrl);
443 				    continue;
444 			    }
445 			    if (cpmip(sep, ctrl) < 0) {
446 				close(ctrl);
447 				continue;
448 			    }
449 		    } else
450 			    ctrl = sep->se_fd;
451 		    if (log && !ISWRAP(sep)) {
452 			    pnm = "unknown";
453 			    i = sizeof peer;
454 			    if (getpeername(ctrl, (struct sockaddr *)
455 					    &peer, &i)) {
456 				    i = sizeof peer;
457 				    if (recvfrom(ctrl, buf, sizeof(buf),
458 					MSG_PEEK,
459 					(struct sockaddr *)&peer, &i) >= 0)
460 					    pnm = inet_ntoa(peer.sin_addr);
461 			    }
462 			    else
463 				    pnm = inet_ntoa(peer.sin_addr);
464 			    syslog(LOG_INFO,"%s from %s", sep->se_service, pnm);
465 		    }
466 		    (void) sigblock(SIGBLOCK);
467 		    pid = 0;
468 		    /*
469 		     * Fork for all external services, builtins which need to
470 		     * fork and anything we're wrapping (as wrapping might
471 		     * block or use hosts_options(5) twist).
472 		     */
473 		    dofork = !sep->se_bi || sep->se_bi->bi_fork || ISWRAP(sep);
474 		    if (dofork) {
475 			    if (sep->se_count++ == 0)
476 				(void)gettimeofday(&sep->se_time, (struct timezone *)NULL);
477 			    else if (sep->se_count >= toomany) {
478 				struct timeval now;
479 
480 				(void)gettimeofday(&now, (struct timezone *)NULL);
481 				if (now.tv_sec - sep->se_time.tv_sec >
482 				    CNT_INTVL) {
483 					sep->se_time = now;
484 					sep->se_count = 1;
485 				} else {
486 					syslog(LOG_ERR,
487 			"%s/%s server failing (looping), service terminated",
488 					    sep->se_service, sep->se_proto);
489 					close_sep(sep);
490 					sigsetmask(0L);
491 					if (!timingout) {
492 						timingout = 1;
493 						alarm(RETRYTIME);
494 					}
495 					continue;
496 				}
497 			    }
498 			    pid = fork();
499 		    }
500 		    if (pid < 0) {
501 			    syslog(LOG_ERR, "fork: %m");
502 			    if (sep->se_accept &&
503 				sep->se_socktype == SOCK_STREAM)
504 				    close(ctrl);
505 			    sigsetmask(0L);
506 			    sleep(1);
507 			    continue;
508 		    }
509 		    if (pid)
510 			addchild(sep, pid);
511 		    sigsetmask(0L);
512 		    if (pid == 0) {
513 			    if (dofork) {
514 				if (debug)
515 					warnx("+ closing from %d", maxsock);
516 				for (tmpint = maxsock; tmpint > 2; tmpint--)
517 					if (tmpint != ctrl)
518 						(void) close(tmpint);
519 				sigaction(SIGALRM, &saalrm, (struct sigaction *)0);
520 				sigaction(SIGCHLD, &sachld, (struct sigaction *)0);
521 				sigaction(SIGHUP, &sahup, (struct sigaction *)0);
522 				/* SIGPIPE reset before exec */
523 			    }
524 			    /*
525 			     * Call tcpmux to find the real service to exec.
526 			     */
527 			    if (sep->se_bi &&
528 				sep->se_bi->bi_fn == (void (*)()) tcpmux) {
529 				    sep = tcpmux(ctrl);
530 				    if (sep == NULL) {
531 					    close(ctrl);
532 					    _exit(0);
533 				    }
534 			    }
535 			    if (ISWRAP(sep)) {
536 				inetd_setproctitle("wrapping", ctrl);
537 				service = sep->se_server_name ?
538 				    sep->se_server_name : sep->se_service;
539 				request_init(&req, RQ_DAEMON, service, RQ_FILE, ctrl, NULL);
540 				fromhost(&req);
541 				deny_severity = LIBWRAP_DENY_FACILITY|LIBWRAP_DENY_SEVERITY;
542 				allow_severity = LIBWRAP_ALLOW_FACILITY|LIBWRAP_ALLOW_SEVERITY;
543 				denied = !hosts_access(&req);
544 				if (denied) {
545 				    syslog(deny_severity,
546 				        "refused connection from %.500s, service %s (%s)",
547 				        eval_client(&req), service, sep->se_proto);
548 				    if (sep->se_socktype != SOCK_STREAM)
549 					recv(ctrl, buf, sizeof (buf), 0);
550 				    if (dofork)
551 					_exit(0);
552 				}
553 				if (log) {
554 				    syslog(allow_severity,
555 				        "connection from %.500s, service %s (%s)",
556 					eval_client(&req), service, sep->se_proto);
557 				}
558 			    }
559 			    if (sep->se_bi) {
560 				(*sep->se_bi->bi_fn)(ctrl, sep);
561 			    } else {
562 				if (debug)
563 					warnx("%d execl %s",
564 						getpid(), sep->se_server);
565 				dup2(ctrl, 0);
566 				close(ctrl);
567 				dup2(0, 1);
568 				dup2(0, 2);
569 				if ((pwd = getpwnam(sep->se_user)) == NULL) {
570 					syslog(LOG_ERR,
571 					    "%s/%s: %s: No such user",
572 						sep->se_service, sep->se_proto,
573 						sep->se_user);
574 					if (sep->se_socktype != SOCK_STREAM)
575 						recv(0, buf, sizeof (buf), 0);
576 					_exit(EX_NOUSER);
577 				}
578 				grp = NULL;
579 				if (   sep->se_group != NULL
580 				    && (grp = getgrnam(sep->se_group)) == NULL
581 				   ) {
582 					syslog(LOG_ERR,
583 					    "%s/%s: %s: No such group",
584 						sep->se_service, sep->se_proto,
585 						sep->se_group);
586 					if (sep->se_socktype != SOCK_STREAM)
587 						recv(0, buf, sizeof (buf), 0);
588 					_exit(EX_NOUSER);
589 				}
590 				if (grp != NULL)
591 					pwd->pw_gid = grp->gr_gid;
592 #ifdef LOGIN_CAP
593 				if ((lc = login_getclass(sep->se_class)) == NULL) {
594 					/* error syslogged by getclass */
595 					syslog(LOG_ERR,
596 					    "%s/%s: %s: login class error",
597 						sep->se_service, sep->se_proto,
598 						sep->se_class);
599 					if (sep->se_socktype != SOCK_STREAM)
600 						recv(0, buf, sizeof (buf), 0);
601 					_exit(EX_NOUSER);
602 				}
603 #endif
604 				if (setsid() < 0) {
605 					syslog(LOG_ERR,
606 						"%s: can't setsid(): %m",
607 						 sep->se_service);
608 					/* _exit(EX_OSERR); not fatal yet */
609 				}
610 #ifdef LOGIN_CAP
611 				if (setusercontext(lc, pwd, pwd->pw_uid,
612 				    LOGIN_SETALL) != 0) {
613 					syslog(LOG_ERR,
614 					 "%s: can't setusercontext(..%s..): %m",
615 					 sep->se_service, sep->se_user);
616 					_exit(EX_OSERR);
617 				}
618 #else
619 				if (pwd->pw_uid) {
620 					if (setlogin(sep->se_user) < 0) {
621 						syslog(LOG_ERR,
622 						 "%s: can't setlogin(%s): %m",
623 						 sep->se_service, sep->se_user);
624 						/* _exit(EX_OSERR); not yet */
625 					}
626 					if (setgid(pwd->pw_gid) < 0) {
627 						syslog(LOG_ERR,
628 						  "%s: can't set gid %d: %m",
629 						  sep->se_service, pwd->pw_gid);
630 						_exit(EX_OSERR);
631 					}
632 					(void) initgroups(pwd->pw_name,
633 							pwd->pw_gid);
634 					if (setuid(pwd->pw_uid) < 0) {
635 						syslog(LOG_ERR,
636 						  "%s: can't set uid %d: %m",
637 						  sep->se_service, pwd->pw_uid);
638 						_exit(EX_OSERR);
639 					}
640 				}
641 #endif
642 				sigaction(SIGPIPE, &sapipe,
643 				    (struct sigaction *)0);
644 				execv(sep->se_server, sep->se_argv);
645 				syslog(LOG_ERR,
646 				    "cannot execute %s: %m", sep->se_server);
647 				if (sep->se_socktype != SOCK_STREAM)
648 					recv(0, buf, sizeof (buf), 0);
649 			    }
650 			    if (dofork)
651 				_exit(0);
652 		    }
653 		    if (sep->se_accept && sep->se_socktype == SOCK_STREAM)
654 			    close(ctrl);
655 		}
656 	}
657 }
658 
659 /*
660  * Add a signal flag to the signal flag queue for later handling
661  */
662 
663 void flag_signal(c)
664     char c;
665 {
666 	if (write(signalpipe[1], &c, 1) != 1) {
667 		syslog(LOG_ERR, "write: %m");
668 		_exit(EX_OSERR);
669 	}
670 }
671 
672 /*
673  * Record a new child pid for this service. If we've reached the
674  * limit on children, then stop accepting incoming requests.
675  */
676 
677 void
678 addchild(struct servtab *sep, pid_t pid)
679 {
680 #ifdef SANITY_CHECK
681 	if (sep->se_numchild >= sep->se_maxchild) {
682 		syslog(LOG_ERR, "%s: %d >= %d",
683 		    __FUNCTION__, sep->se_numchild, sep->se_maxchild);
684 		exit(EX_SOFTWARE);
685 	}
686 #endif
687 	if (sep->se_maxchild == 0)
688 		return;
689 	sep->se_pids[sep->se_numchild++] = pid;
690 	if (sep->se_numchild == sep->se_maxchild)
691 		disable(sep);
692 }
693 
694 /*
695  * Some child process has exited. See if it's on somebody's list.
696  */
697 
698 void
699 flag_reapchild(signo)
700 	int signo;
701 {
702 	flag_signal('C');
703 }
704 
705 void
706 reapchild()
707 {
708 	int k, status;
709 	pid_t pid;
710 	struct servtab *sep;
711 
712 	for (;;) {
713 		pid = wait3(&status, WNOHANG, (struct rusage *)0);
714 		if (pid <= 0)
715 			break;
716 		if (debug)
717 			warnx("%d reaped, status %#x", pid, status);
718 		for (sep = servtab; sep; sep = sep->se_next) {
719 			for (k = 0; k < sep->se_numchild; k++)
720 				if (sep->se_pids[k] == pid)
721 					break;
722 			if (k == sep->se_numchild)
723 				continue;
724 			if (sep->se_numchild == sep->se_maxchild)
725 				enable(sep);
726 			sep->se_pids[k] = sep->se_pids[--sep->se_numchild];
727 			if (status)
728 				syslog(LOG_WARNING,
729 				    "%s[%d]: exit status 0x%x",
730 				    sep->se_server, pid, status);
731 			break;
732 		}
733 	}
734 }
735 
736 void
737 flag_config(signo)
738 	int signo;
739 {
740 	flag_signal('H');
741 }
742 
743 void config()
744 {
745 	struct servtab *sep, *new, **sepp;
746 	long omask;
747 
748 	if (!setconfig()) {
749 		syslog(LOG_ERR, "%s: %m", CONFIG);
750 		return;
751 	}
752 	for (sep = servtab; sep; sep = sep->se_next)
753 		sep->se_checked = 0;
754 	while ((new = getconfigent())) {
755 		if (getpwnam(new->se_user) == NULL) {
756 			syslog(LOG_ERR,
757 				"%s/%s: No such user '%s', service ignored",
758 				new->se_service, new->se_proto, new->se_user);
759 			continue;
760 		}
761 		if (new->se_group && getgrnam(new->se_group) == NULL) {
762 			syslog(LOG_ERR,
763 				"%s/%s: No such group '%s', service ignored",
764 				new->se_service, new->se_proto, new->se_group);
765 			continue;
766 		}
767 #ifdef LOGIN_CAP
768 		if (login_getclass(new->se_class) == NULL) {
769 			/* error syslogged by getclass */
770 			syslog(LOG_ERR,
771 				"%s/%s: %s: login class error, service ignored",
772 				new->se_service, new->se_proto, new->se_class);
773 			continue;
774 		}
775 #endif
776 		for (sep = servtab; sep; sep = sep->se_next)
777 			if (strcmp(sep->se_service, new->se_service) == 0 &&
778 			    strcmp(sep->se_proto, new->se_proto) == 0)
779 				break;
780 		if (sep != 0) {
781 			int i;
782 
783 #define SWAP(a, b) { typeof(a) c = a; a = b; b = c; }
784 			omask = sigblock(SIGBLOCK);
785 			/* copy over outstanding child pids */
786 			if (sep->se_maxchild && new->se_maxchild) {
787 				new->se_numchild = sep->se_numchild;
788 				if (new->se_numchild > new->se_maxchild)
789 					new->se_numchild = new->se_maxchild;
790 				memcpy(new->se_pids, sep->se_pids,
791 				    new->se_numchild * sizeof(*new->se_pids));
792 			}
793 			SWAP(sep->se_pids, new->se_pids);
794 			sep->se_maxchild = new->se_maxchild;
795 			sep->se_numchild = new->se_numchild;
796 			sep->se_maxcpm = new->se_maxcpm;
797 			/* might need to turn on or off service now */
798 			if (sep->se_fd >= 0) {
799 			      if (sep->se_maxchild
800 				  && sep->se_numchild == sep->se_maxchild) {
801 				      if (FD_ISSET(sep->se_fd, &allsock))
802 					  disable(sep);
803 			      } else {
804 				      if (!FD_ISSET(sep->se_fd, &allsock))
805 					  enable(sep);
806 			      }
807 			}
808 			sep->se_accept = new->se_accept;
809 			SWAP(sep->se_user, new->se_user);
810 			SWAP(sep->se_group, new->se_group);
811 #ifdef LOGIN_CAP
812 			SWAP(sep->se_class, new->se_class);
813 #endif
814 			SWAP(sep->se_server, new->se_server);
815 			SWAP(sep->se_server_name, new->se_server_name);
816 			for (i = 0; i < MAXARGV; i++)
817 				SWAP(sep->se_argv[i], new->se_argv[i]);
818 			sigsetmask(omask);
819 			freeconfig(new);
820 			if (debug)
821 				print_service("REDO", sep);
822 		} else {
823 			sep = enter(new);
824 			if (debug)
825 				print_service("ADD ", sep);
826 		}
827 		sep->se_checked = 1;
828 		if (ISMUX(sep)) {
829 			sep->se_fd = -1;
830 			continue;
831 		}
832 		if (!sep->se_rpc) {
833 			sp = getservbyname(sep->se_service, sep->se_proto);
834 			if (sp == 0) {
835 				syslog(LOG_ERR, "%s/%s: unknown service",
836 			    	sep->se_service, sep->se_proto);
837 				sep->se_checked = 0;
838 				continue;
839 			}
840 			if (sp->s_port != sep->se_ctrladdr.sin_port) {
841 				sep->se_ctrladdr.sin_family = AF_INET;
842 				sep->se_ctrladdr.sin_addr = bind_address;
843 				sep->se_ctrladdr.sin_port = sp->s_port;
844 				if (sep->se_fd >= 0)
845 					close_sep(sep);
846 			}
847 		} else {
848 			rpc = getrpcbyname(sep->se_service);
849 			if (rpc == 0) {
850 				syslog(LOG_ERR, "%s/%s unknown RPC service",
851 					sep->se_service, sep->se_proto);
852 				if (sep->se_fd != -1)
853 					(void) close(sep->se_fd);
854 				sep->se_fd = -1;
855 					continue;
856 			}
857 			if (rpc->r_number != sep->se_rpc_prog) {
858 				if (sep->se_rpc_prog)
859 					unregisterrpc(sep);
860 				sep->se_rpc_prog = rpc->r_number;
861 				if (sep->se_fd != -1)
862 					(void) close(sep->se_fd);
863 				sep->se_fd = -1;
864 			}
865 		}
866 		if (sep->se_fd == -1)
867 			setup(sep);
868 	}
869 	endconfig();
870 	/*
871 	 * Purge anything not looked at above.
872 	 */
873 	omask = sigblock(SIGBLOCK);
874 	sepp = &servtab;
875 	while ((sep = *sepp)) {
876 		if (sep->se_checked) {
877 			sepp = &sep->se_next;
878 			continue;
879 		}
880 		*sepp = sep->se_next;
881 		if (sep->se_fd >= 0)
882 			close_sep(sep);
883 		if (debug)
884 			print_service("FREE", sep);
885 		if (sep->se_rpc && sep->se_rpc_prog > 0)
886 			unregisterrpc(sep);
887 		freeconfig(sep);
888 		free((char *)sep);
889 	}
890 	(void) sigsetmask(omask);
891 }
892 
893 void
894 unregisterrpc(sep)
895 	struct servtab *sep;
896 {
897         int i;
898         struct servtab *sepp;
899 	long omask;
900 
901 	omask = sigblock(SIGBLOCK);
902         for (sepp = servtab; sepp; sepp = sepp->se_next) {
903                 if (sepp == sep)
904                         continue;
905 		if (sep->se_checked == 0 ||
906                     !sepp->se_rpc ||
907                     sep->se_rpc_prog != sepp->se_rpc_prog)
908 			continue;
909                 return;
910         }
911         if (debug)
912                 print_service("UNREG", sep);
913         for (i = sep->se_rpc_lowvers; i <= sep->se_rpc_highvers; i++)
914                 pmap_unset(sep->se_rpc_prog, i);
915         if (sep->se_fd != -1)
916                 (void) close(sep->se_fd);
917         sep->se_fd = -1;
918 	(void) sigsetmask(omask);
919 }
920 
921 void
922 flag_retry(signo)
923 	int signo;
924 {
925 	flag_signal('A');
926 }
927 
928 void
929 retry()
930 {
931 	struct servtab *sep;
932 
933 	timingout = 0;
934 	for (sep = servtab; sep; sep = sep->se_next)
935 		if (sep->se_fd == -1 && !ISMUX(sep))
936 			setup(sep);
937 }
938 
939 void
940 setup(sep)
941 	struct servtab *sep;
942 {
943 	int on = 1;
944 
945 	if ((sep->se_fd = socket(AF_INET, sep->se_socktype, 0)) < 0) {
946 		if (debug)
947 			warn("socket failed on %s/%s",
948 				sep->se_service, sep->se_proto);
949 		syslog(LOG_ERR, "%s/%s: socket: %m",
950 		    sep->se_service, sep->se_proto);
951 		return;
952 	}
953 #define	turnon(fd, opt) \
954 setsockopt(fd, SOL_SOCKET, opt, (char *)&on, sizeof (on))
955 	if (strcmp(sep->se_proto, "tcp") == 0 && (options & SO_DEBUG) &&
956 	    turnon(sep->se_fd, SO_DEBUG) < 0)
957 		syslog(LOG_ERR, "setsockopt (SO_DEBUG): %m");
958 	if (turnon(sep->se_fd, SO_REUSEADDR) < 0)
959 		syslog(LOG_ERR, "setsockopt (SO_REUSEADDR): %m");
960 #ifdef SO_PRIVSTATE
961 	if (turnon(sep->se_fd, SO_PRIVSTATE) < 0)
962 		syslog(LOG_ERR, "setsockopt (SO_PRIVSTATE): %m");
963 #endif
964 #undef turnon
965 	if (sep->se_type == TTCP_TYPE)
966 		if (setsockopt(sep->se_fd, IPPROTO_TCP, TCP_NOPUSH,
967 		    (char *)&on, sizeof (on)) < 0)
968 			syslog(LOG_ERR, "setsockopt (TCP_NOPUSH): %m");
969 	if (bind(sep->se_fd, (struct sockaddr *)&sep->se_ctrladdr,
970 	    sizeof (sep->se_ctrladdr)) < 0) {
971 		if (debug)
972 			warn("bind failed on %s/%s",
973 				sep->se_service, sep->se_proto);
974 		syslog(LOG_ERR, "%s/%s: bind: %m",
975 		    sep->se_service, sep->se_proto);
976 		(void) close(sep->se_fd);
977 		sep->se_fd = -1;
978 		if (!timingout) {
979 			timingout = 1;
980 			alarm(RETRYTIME);
981 		}
982 		return;
983 	}
984         if (sep->se_rpc) {
985                 int i, len = sizeof(struct sockaddr);
986 
987                 if (getsockname(sep->se_fd,
988 				(struct sockaddr*)&sep->se_ctrladdr, &len) < 0){
989                         syslog(LOG_ERR, "%s/%s: getsockname: %m",
990                                sep->se_service, sep->se_proto);
991                         (void) close(sep->se_fd);
992                         sep->se_fd = -1;
993                         return;
994                 }
995                 if (debug)
996                         print_service("REG ", sep);
997                 for (i = sep->se_rpc_lowvers; i <= sep->se_rpc_highvers; i++) {
998                         pmap_unset(sep->se_rpc_prog, i);
999                         pmap_set(sep->se_rpc_prog, i,
1000                                  (sep->se_socktype == SOCK_DGRAM)
1001                                  ? IPPROTO_UDP : IPPROTO_TCP,
1002                                  ntohs(sep->se_ctrladdr.sin_port));
1003                 }
1004 
1005         }
1006 	if (sep->se_socktype == SOCK_STREAM)
1007 		listen(sep->se_fd, 64);
1008 	enable(sep);
1009 	if (debug) {
1010 		warnx("registered %s on %d",
1011 			sep->se_server, sep->se_fd);
1012 	}
1013 }
1014 
1015 /*
1016  * Finish with a service and its socket.
1017  */
1018 void
1019 close_sep(sep)
1020 	struct servtab *sep;
1021 {
1022 	if (sep->se_fd >= 0) {
1023 		if (FD_ISSET(sep->se_fd, &allsock))
1024 			disable(sep);
1025 		(void) close(sep->se_fd);
1026 		sep->se_fd = -1;
1027 	}
1028 	sep->se_count = 0;
1029 	sep->se_numchild = 0;	/* forget about any existing children */
1030 }
1031 
1032 int
1033 matchservent(name1, name2, proto)
1034 	char *name1, *name2, *proto;
1035 {
1036 	char **alias;
1037 	struct servent *se;
1038 
1039 	if (strcmp(name1, name2) == 0)
1040 		return(1);
1041 	if ((se = getservbyname(name1, proto)) != NULL) {
1042 		if (strcmp(name2, se->s_name) == 0)
1043 			return(1);
1044 		for (alias = se->s_aliases; *alias; alias++)
1045 			if (strcmp(name2, *alias) == 0)
1046 				return(1);
1047 	}
1048 	return(0);
1049 }
1050 
1051 struct servtab *
1052 enter(cp)
1053 	struct servtab *cp;
1054 {
1055 	struct servtab *sep;
1056 	long omask;
1057 
1058 	sep = (struct servtab *)malloc(sizeof (*sep));
1059 	if (sep == (struct servtab *)0) {
1060 		syslog(LOG_ERR, "malloc: %m");
1061 		exit(EX_OSERR);
1062 	}
1063 	*sep = *cp;
1064 	sep->se_fd = -1;
1065 	omask = sigblock(SIGBLOCK);
1066 	sep->se_next = servtab;
1067 	servtab = sep;
1068 	sigsetmask(omask);
1069 	return (sep);
1070 }
1071 
1072 void
1073 enable(struct servtab *sep)
1074 {
1075 	if (debug)
1076 		warnx(
1077 		    "enabling %s, fd %d", sep->se_service, sep->se_fd);
1078 #ifdef SANITY_CHECK
1079 	if (sep->se_fd < 0) {
1080 		syslog(LOG_ERR,
1081 		    "%s: %s: bad fd", __FUNCTION__, sep->se_service);
1082 		exit(EX_SOFTWARE);
1083 	}
1084 	if (ISMUX(sep)) {
1085 		syslog(LOG_ERR,
1086 		    "%s: %s: is mux", __FUNCTION__, sep->se_service);
1087 		exit(EX_SOFTWARE);
1088 	}
1089 	if (FD_ISSET(sep->se_fd, &allsock)) {
1090 		syslog(LOG_ERR,
1091 		    "%s: %s: not off", __FUNCTION__, sep->se_service);
1092 		exit(EX_SOFTWARE);
1093 	}
1094 	nsock++;
1095 #endif
1096 	FD_SET(sep->se_fd, &allsock);
1097 	if (sep->se_fd > maxsock)
1098 		maxsock = sep->se_fd;
1099 }
1100 
1101 void
1102 disable(struct servtab *sep)
1103 {
1104 	if (debug)
1105 		warnx(
1106 		    "disabling %s, fd %d", sep->se_service, sep->se_fd);
1107 #ifdef SANITY_CHECK
1108 	if (sep->se_fd < 0) {
1109 		syslog(LOG_ERR,
1110 		    "%s: %s: bad fd", __FUNCTION__, sep->se_service);
1111 		exit(EX_SOFTWARE);
1112 	}
1113 	if (ISMUX(sep)) {
1114 		syslog(LOG_ERR,
1115 		    "%s: %s: is mux", __FUNCTION__, sep->se_service);
1116 		exit(EX_SOFTWARE);
1117 	}
1118 	if (!FD_ISSET(sep->se_fd, &allsock)) {
1119 		syslog(LOG_ERR,
1120 		    "%s: %s: not on", __FUNCTION__, sep->se_service);
1121 		exit(EX_SOFTWARE);
1122 	}
1123 	if (nsock == 0) {
1124 		syslog(LOG_ERR, "%s: nsock=0", __FUNCTION__);
1125 		exit(EX_SOFTWARE);
1126 	}
1127 	nsock--;
1128 #endif
1129 	FD_CLR(sep->se_fd, &allsock);
1130 	if (sep->se_fd == maxsock)
1131 		maxsock--;
1132 }
1133 
1134 FILE	*fconfig = NULL;
1135 struct	servtab serv;
1136 char	line[LINE_MAX];
1137 
1138 int
1139 setconfig()
1140 {
1141 
1142 	if (fconfig != NULL) {
1143 		fseek(fconfig, 0L, SEEK_SET);
1144 		return (1);
1145 	}
1146 	fconfig = fopen(CONFIG, "r");
1147 	return (fconfig != NULL);
1148 }
1149 
1150 void
1151 endconfig()
1152 {
1153 	if (fconfig) {
1154 		(void) fclose(fconfig);
1155 		fconfig = NULL;
1156 	}
1157 }
1158 
1159 struct servtab *
1160 getconfigent()
1161 {
1162 	struct servtab *sep = &serv;
1163 	int argc;
1164 	char *cp, *arg, *s;
1165 	char *versp;
1166 	static char TCPMUX_TOKEN[] = "tcpmux/";
1167 #define MUX_LEN		(sizeof(TCPMUX_TOKEN)-1)
1168 
1169 more:
1170 	while ((cp = nextline(fconfig)) && (*cp == '#' || *cp == '\0'))
1171 		;
1172 	if (cp == NULL)
1173 		return ((struct servtab *)0);
1174 	/*
1175 	 * clear the static buffer, since some fields (se_ctrladdr,
1176 	 * for example) don't get initialized here.
1177 	 */
1178 	memset((caddr_t)sep, 0, sizeof *sep);
1179 	arg = skip(&cp);
1180 	if (cp == NULL) {
1181 		/* got an empty line containing just blanks/tabs. */
1182 		goto more;
1183 	}
1184 	if (strncmp(arg, TCPMUX_TOKEN, MUX_LEN) == 0) {
1185 		char *c = arg + MUX_LEN;
1186 		if (*c == '+') {
1187 			sep->se_type = MUXPLUS_TYPE;
1188 			c++;
1189 		} else
1190 			sep->se_type = MUX_TYPE;
1191 		sep->se_service = newstr(c);
1192 	} else {
1193 		sep->se_service = newstr(arg);
1194 		sep->se_type = NORM_TYPE;
1195 	}
1196 	arg = sskip(&cp);
1197 	if (strcmp(arg, "stream") == 0)
1198 		sep->se_socktype = SOCK_STREAM;
1199 	else if (strcmp(arg, "dgram") == 0)
1200 		sep->se_socktype = SOCK_DGRAM;
1201 	else if (strcmp(arg, "rdm") == 0)
1202 		sep->se_socktype = SOCK_RDM;
1203 	else if (strcmp(arg, "seqpacket") == 0)
1204 		sep->se_socktype = SOCK_SEQPACKET;
1205 	else if (strcmp(arg, "raw") == 0)
1206 		sep->se_socktype = SOCK_RAW;
1207 	else
1208 		sep->se_socktype = -1;
1209 
1210 	arg = sskip(&cp);
1211 	if (strcmp(arg, "tcp/ttcp") == 0) {
1212 		sep->se_type = TTCP_TYPE;
1213 		sep->se_proto = newstr("tcp");
1214 	} else {
1215 		sep->se_proto = newstr(arg);
1216 	}
1217         if (strncmp(sep->se_proto, "rpc/", 4) == 0) {
1218                 memmove(sep->se_proto, sep->se_proto + 4,
1219                     strlen(sep->se_proto) + 1 - 4);
1220                 sep->se_rpc = 1;
1221                 sep->se_rpc_prog = sep->se_rpc_lowvers =
1222 			sep->se_rpc_lowvers = 0;
1223                 sep->se_ctrladdr.sin_family = AF_INET;
1224                 sep->se_ctrladdr.sin_port = 0;
1225                 sep->se_ctrladdr.sin_addr = bind_address;
1226                 if ((versp = rindex(sep->se_service, '/'))) {
1227                         *versp++ = '\0';
1228                         switch (sscanf(versp, "%d-%d",
1229                                        &sep->se_rpc_lowvers,
1230                                        &sep->se_rpc_highvers)) {
1231                         case 2:
1232                                 break;
1233                         case 1:
1234                                 sep->se_rpc_highvers =
1235                                         sep->se_rpc_lowvers;
1236                                 break;
1237                         default:
1238                                 syslog(LOG_ERR,
1239 					"bad RPC version specifier; %s",
1240 					sep->se_service);
1241                                 freeconfig(sep);
1242                                 goto more;
1243                         }
1244                 }
1245                 else {
1246                         sep->se_rpc_lowvers =
1247                                 sep->se_rpc_highvers = 1;
1248                 }
1249         }
1250 	arg = sskip(&cp);
1251 	if (!strncmp(arg, "wait", 4))
1252 		sep->se_accept = 0;
1253 	else if (!strncmp(arg, "nowait", 6))
1254 		sep->se_accept = 1;
1255 	else {
1256 		syslog(LOG_ERR,
1257 			"%s: bad wait/nowait for service %s",
1258 			CONFIG, sep->se_service);
1259 		goto more;
1260 	}
1261 	sep->se_maxchild = -1;
1262 	sep->se_maxcpm = -1;
1263 	if ((s = strchr(arg, '/')) != NULL) {
1264 		char *eptr;
1265 		u_long val;
1266 
1267 		val = strtoul(s + 1, &eptr, 10);
1268 		if (eptr == s + 1 || val > MAX_MAXCHLD) {
1269 			syslog(LOG_ERR,
1270 				"%s: bad max-child for service %s",
1271 				CONFIG, sep->se_service);
1272 			goto more;
1273 		}
1274 		if (debug)
1275 			if (!sep->se_accept && val != 1)
1276 				warnx("maxchild=%lu for wait service %s"
1277 				    " not recommended", val, sep->se_service);
1278 		sep->se_maxchild = val;
1279 		if (*eptr == '/')
1280 			sep->se_maxcpm = strtol(eptr + 1, &eptr, 10);
1281 		/*
1282 		 * explicitly do not check for \0 for future expansion /
1283 		 * backwards compatibility
1284 		 */
1285 	}
1286 	if (ISMUX(sep)) {
1287 		/*
1288 		 * Silently enforce "nowait" mode for TCPMUX services
1289 		 * since they don't have an assigned port to listen on.
1290 		 */
1291 		sep->se_accept = 1;
1292 		if (strcmp(sep->se_proto, "tcp")) {
1293 			syslog(LOG_ERR,
1294 				"%s: bad protocol for tcpmux service %s",
1295 				CONFIG, sep->se_service);
1296 			goto more;
1297 		}
1298 		if (sep->se_socktype != SOCK_STREAM) {
1299 			syslog(LOG_ERR,
1300 				"%s: bad socket type for tcpmux service %s",
1301 				CONFIG, sep->se_service);
1302 			goto more;
1303 		}
1304 	}
1305 	sep->se_user = newstr(sskip(&cp));
1306 #ifdef LOGIN_CAP
1307 	if ((s = strrchr(sep->se_user, '/')) != NULL) {
1308 		*s = '\0';
1309 		sep->se_class = newstr(s + 1);
1310 	} else
1311 		sep->se_class = newstr(RESOURCE_RC);
1312 #endif
1313 	if ((s = strrchr(sep->se_user, ':')) != NULL) {
1314 		*s = '\0';
1315 		sep->se_group = newstr(s + 1);
1316 	} else
1317 		sep->se_group = NULL;
1318 	sep->se_server = newstr(sskip(&cp));
1319 	if ((sep->se_server_name = rindex(sep->se_server, '/')))
1320 		sep->se_server_name++;
1321 	if (strcmp(sep->se_server, "internal") == 0) {
1322 		struct biltin *bi;
1323 
1324 		for (bi = biltins; bi->bi_service; bi++)
1325 			if (bi->bi_socktype == sep->se_socktype &&
1326 			    matchservent(bi->bi_service, sep->se_service,
1327 			    sep->se_proto))
1328 				break;
1329 		if (bi->bi_service == 0) {
1330 			syslog(LOG_ERR, "internal service %s unknown",
1331 				sep->se_service);
1332 			goto more;
1333 		}
1334 		sep->se_accept = 1;	/* force accept mode for built-ins */
1335 		sep->se_bi = bi;
1336 	} else
1337 		sep->se_bi = NULL;
1338 	if (sep->se_maxcpm < 0)
1339 		sep->se_maxcpm = maxcpm;
1340 	if (sep->se_maxchild < 0) {	/* apply default max-children */
1341 		if (sep->se_bi && sep->se_bi->bi_maxchild >= 0)
1342 			sep->se_maxchild = sep->se_bi->bi_maxchild;
1343 		else if (sep->se_accept)
1344 			sep->se_maxchild = maxchild > 0 ? maxchild : 0;
1345 		else
1346 			sep->se_maxchild = 1;
1347 	}
1348 	if (sep->se_maxchild) {
1349 		sep->se_pids = malloc(sep->se_maxchild * sizeof(*sep->se_pids));
1350 		if (sep->se_pids == NULL) {
1351 			syslog(LOG_ERR, "malloc: %m");
1352 			exit(EX_OSERR);
1353 		}
1354 	}
1355 	argc = 0;
1356 	for (arg = skip(&cp); cp; arg = skip(&cp))
1357 		if (argc < MAXARGV) {
1358 			sep->se_argv[argc++] = newstr(arg);
1359 		} else {
1360 			syslog(LOG_ERR,
1361 				"%s: too many arguments for service %s",
1362 				CONFIG, sep->se_service);
1363 			goto more;
1364 		}
1365 	while (argc <= MAXARGV)
1366 		sep->se_argv[argc++] = NULL;
1367 	return (sep);
1368 }
1369 
1370 void
1371 freeconfig(cp)
1372 	struct servtab *cp;
1373 {
1374 	int i;
1375 
1376 	if (cp->se_service)
1377 		free(cp->se_service);
1378 	if (cp->se_proto)
1379 		free(cp->se_proto);
1380 	if (cp->se_user)
1381 		free(cp->se_user);
1382 	if (cp->se_group)
1383 		free(cp->se_group);
1384 #ifdef LOGIN_CAP
1385 	if (cp->se_class)
1386 		free(cp->se_class);
1387 #endif
1388 	if (cp->se_server)
1389 		free(cp->se_server);
1390 	if (cp->se_pids)
1391 		free(cp->se_pids);
1392 	for (i = 0; i < MAXARGV; i++)
1393 		if (cp->se_argv[i])
1394 			free(cp->se_argv[i]);
1395 }
1396 
1397 
1398 /*
1399  * Safe skip - if skip returns null, log a syntax error in the
1400  * configuration file and exit.
1401  */
1402 char *
1403 sskip(cpp)
1404 	char **cpp;
1405 {
1406 	char *cp;
1407 
1408 	cp = skip(cpp);
1409 	if (cp == NULL) {
1410 		syslog(LOG_ERR, "%s: syntax error", CONFIG);
1411 		exit(EX_DATAERR);
1412 	}
1413 	return (cp);
1414 }
1415 
1416 char *
1417 skip(cpp)
1418 	char **cpp;
1419 {
1420 	char *cp = *cpp;
1421 	char *start;
1422 	char quote = '\0';
1423 
1424 again:
1425 	while (*cp == ' ' || *cp == '\t')
1426 		cp++;
1427 	if (*cp == '\0') {
1428 		int c;
1429 
1430 		c = getc(fconfig);
1431 		(void) ungetc(c, fconfig);
1432 		if (c == ' ' || c == '\t')
1433 			if ((cp = nextline(fconfig)))
1434 				goto again;
1435 		*cpp = (char *)0;
1436 		return ((char *)0);
1437 	}
1438 	if (*cp == '"' || *cp == '\'')
1439 		quote = *cp++;
1440 	start = cp;
1441 	if (quote)
1442 		while (*cp && *cp != quote)
1443 			cp++;
1444 	else
1445 		while (*cp && *cp != ' ' && *cp != '\t')
1446 			cp++;
1447 	if (*cp != '\0')
1448 		*cp++ = '\0';
1449 	*cpp = cp;
1450 	return (start);
1451 }
1452 
1453 char *
1454 nextline(fd)
1455 	FILE *fd;
1456 {
1457 	char *cp;
1458 
1459 	if (fgets(line, sizeof (line), fd) == NULL)
1460 		return ((char *)0);
1461 	cp = strchr(line, '\n');
1462 	if (cp)
1463 		*cp = '\0';
1464 	return (line);
1465 }
1466 
1467 char *
1468 newstr(cp)
1469 	char *cp;
1470 {
1471 	if ((cp = strdup(cp ? cp : "")))
1472 		return (cp);
1473 	syslog(LOG_ERR, "strdup: %m");
1474 	exit(EX_OSERR);
1475 }
1476 
1477 #ifdef OLD_SETPROCTITLE
1478 void
1479 inetd_setproctitle(a, s)
1480 	char *a;
1481 	int s;
1482 {
1483 	int size;
1484 	char *cp;
1485 	struct sockaddr_in sin;
1486 	char buf[80];
1487 
1488 	cp = Argv[0];
1489 	size = sizeof(sin);
1490 	if (getpeername(s, (struct sockaddr *)&sin, &size) == 0)
1491 		(void) sprintf(buf, "-%s [%s]", a, inet_ntoa(sin.sin_addr));
1492 	else
1493 		(void) sprintf(buf, "-%s", a);
1494 	strncpy(cp, buf, LastArg - cp);
1495 	cp += strlen(cp);
1496 	while (cp < LastArg)
1497 		*cp++ = ' ';
1498 }
1499 #else
1500 void
1501 inetd_setproctitle(a, s)
1502 	char *a;
1503 	int s;
1504 {
1505 	int size;
1506 	struct sockaddr_in sin;
1507 	char buf[80];
1508 
1509 	size = sizeof(sin);
1510 	if (getpeername(s, (struct sockaddr *)&sin, &size) == 0)
1511 		(void) sprintf(buf, "%s [%s]", a, inet_ntoa(sin.sin_addr));
1512 	else
1513 		(void) sprintf(buf, "%s", a);
1514 	setproctitle("%s", buf);
1515 }
1516 #endif
1517 
1518 
1519 /*
1520  * Internet services provided internally by inetd:
1521  */
1522 
1523 int check_loop(sin, sep)
1524 	struct sockaddr_in *sin;
1525 	struct servtab *sep;
1526 {
1527 	struct servtab *se2;
1528 
1529 	for (se2 = servtab; se2; se2 = se2->se_next) {
1530 		if (!se2->se_bi || se2->se_socktype != SOCK_DGRAM)
1531 			continue;
1532 
1533 		if (sin->sin_port == se2->se_ctrladdr.sin_port) {
1534 			syslog(LOG_WARNING,
1535 			       "%s/%s:%s/%s loop request REFUSED from %s",
1536 			       sep->se_service, sep->se_proto,
1537 			       se2->se_service, se2->se_proto,
1538 			       inet_ntoa(sin->sin_addr));
1539 			return 1;
1540 		}
1541 	}
1542 	return 0;
1543 }
1544 
1545 /*
1546  * print_service:
1547  *	Dump relevant information to stderr
1548  */
1549 void
1550 print_service(action, sep)
1551 	char *action;
1552 	struct servtab *sep;
1553 {
1554 	fprintf(stderr,
1555 #ifdef LOGIN_CAP
1556 	    "%s: %s proto=%s accept=%d max=%d user=%s group=%s class=%s builtin=%p server=%s\n",
1557 #else
1558 	    "%s: %s proto=%s accept=%d max=%d user=%s group=%s builtin=%p server=%s\n",
1559 #endif
1560 	    action, sep->se_service, sep->se_proto,
1561 	    sep->se_accept, sep->se_maxchild, sep->se_user, sep->se_group,
1562 #ifdef LOGIN_CAP
1563 	    sep->se_class,
1564 #endif
1565 	    (void *) sep->se_bi, sep->se_server);
1566 }
1567 
1568 #define CPMHSIZE	256
1569 #define CPMHMASK	(CPMHSIZE-1)
1570 #define CHTGRAN		10
1571 #define CHTSIZE		6
1572 
1573 typedef struct CTime {
1574 	unsigned long 	ct_Ticks;
1575 	int		ct_Count;
1576 } CTime;
1577 
1578 typedef struct CHash {
1579 	struct in_addr	ch_Addr;
1580 	time_t		ch_LTime;
1581 	char		*ch_Service;
1582 	CTime		ch_Times[CHTSIZE];
1583 } CHash;
1584 
1585 CHash	CHashAry[CPMHSIZE];
1586 
1587 int
1588 cpmip(sep, ctrl)
1589 	struct servtab *sep;
1590 	int ctrl;
1591 {
1592 	struct sockaddr_in rsin;
1593 	int rsinLen = sizeof(rsin);
1594 	int r = 0;
1595 
1596 	/*
1597 	 * If getpeername() fails, just let it through (if logging is
1598 	 * enabled the condition is caught elsewhere)
1599 	 */
1600 
1601 	if (sep->se_maxcpm > 0 &&
1602 	    getpeername(ctrl, (struct sockaddr *)&rsin, &rsinLen) == 0 ) {
1603 		time_t t = time(NULL);
1604 		int hv = 0xABC3D20F;
1605 		int i;
1606 		int cnt = 0;
1607 		CHash *chBest = NULL;
1608 		unsigned int ticks = t / CHTGRAN;
1609 
1610 		{
1611 			char *p;
1612 			int i;
1613 
1614 			for (i = 0, p = (char *)&rsin.sin_addr;
1615 			    i < sizeof(rsin.sin_addr);
1616 			    ++i, ++p) {
1617 				hv = (hv << 5) ^ (hv >> 23) ^ *p;
1618 			}
1619 			hv = (hv ^ (hv >> 16));
1620 		}
1621 		for (i = 0; i < 5; ++i) {
1622 			CHash *ch = &CHashAry[(hv + i) & CPMHMASK];
1623 
1624 			if (rsin.sin_addr.s_addr == ch->ch_Addr.s_addr &&
1625 			    ch->ch_Service && strcmp(sep->se_service,
1626 			    ch->ch_Service) == 0) {
1627 				chBest = ch;
1628 				break;
1629 			}
1630 			if (chBest == NULL || ch->ch_LTime == 0 ||
1631 			    ch->ch_LTime < chBest->ch_LTime) {
1632 				chBest = ch;
1633 			}
1634 		}
1635 		if (rsin.sin_addr.s_addr != chBest->ch_Addr.s_addr ||
1636 		    chBest->ch_Service == NULL ||
1637 		    strcmp(sep->se_service, chBest->ch_Service) != 0) {
1638 			chBest->ch_Addr = rsin.sin_addr;
1639 			if (chBest->ch_Service)
1640 				free(chBest->ch_Service);
1641 			chBest->ch_Service = strdup(sep->se_service);
1642 			bzero(chBest->ch_Times, sizeof(chBest->ch_Times));
1643 		}
1644 		chBest->ch_LTime = t;
1645 		{
1646 			CTime *ct = &chBest->ch_Times[ticks % CHTSIZE];
1647 			if (ct->ct_Ticks != ticks) {
1648 				ct->ct_Ticks = ticks;
1649 				ct->ct_Count = 0;
1650 			}
1651 			++ct->ct_Count;
1652 		}
1653 		for (i = 0; i < CHTSIZE; ++i) {
1654 			CTime *ct = &chBest->ch_Times[i];
1655 			if (ct->ct_Ticks <= ticks &&
1656 			    ct->ct_Ticks >= ticks - CHTSIZE) {
1657 				cnt += ct->ct_Count;
1658 			}
1659 		}
1660 		if (cnt * (CHTSIZE * CHTGRAN) / 60 > sep->se_maxcpm) {
1661 			r = -1;
1662 			syslog(LOG_ERR,
1663 			    "%s from %s exceeded counts/min (limit %d/min)",
1664 			    sep->se_service, inet_ntoa(rsin.sin_addr),
1665 			    sep->se_maxcpm);
1666 		}
1667 	}
1668 	return(r);
1669 }
1670