xref: /freebsd/usr.sbin/inetd/inetd.c (revision 33b77e2decd50e53798014b70bf7ca3bdc4c0c7e)
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 	"$Id: inetd.c,v 1.28 1997/10/28 13:46:52 ache Exp $";
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/stat.h>
108 #include <sys/ioctl.h>
109 #include <sys/socket.h>
110 #include <sys/wait.h>
111 #include <sys/time.h>
112 #include <sys/resource.h>
113 
114 #include <netinet/in.h>
115 #include <arpa/inet.h>
116 #include <rpc/rpc.h>
117 #include <rpc/pmap_clnt.h>
118 
119 #include <errno.h>
120 #include <err.h>
121 #include <fcntl.h>
122 #include <grp.h>
123 #include <netdb.h>
124 #include <pwd.h>
125 #include <signal.h>
126 #include <stdio.h>
127 #include <stdlib.h>
128 #include <string.h>
129 #include <syslog.h>
130 #include <unistd.h>
131 #include <libutil.h>
132 #include <sysexits.h>
133 
134 #ifdef LOGIN_CAP
135 #include <login_cap.h>
136 
137 /* see init.c */
138 #define RESOURCE_RC "daemon"
139 
140 #endif
141 
142 #include "pathnames.h"
143 
144 #define	TOOMANY		256		/* don't start more than TOOMANY */
145 #define	CNT_INTVL	60		/* servers in CNT_INTVL sec. */
146 #define	RETRYTIME	(60*10)		/* retry after bind or server fail */
147 #define MAX_MAXCHLD	32767		/* max allowable max children */
148 
149 #define	SIGBLOCK	(sigmask(SIGCHLD)|sigmask(SIGHUP)|sigmask(SIGALRM))
150 
151 int	debug = 0;
152 int	log = 0;
153 int	nsock, maxsock;
154 fd_set	allsock;
155 int	options;
156 int	timingout;
157 int	toomany = TOOMANY;
158 struct	servent *sp;
159 struct	rpcent *rpc;
160 struct	in_addr bind_address;
161 
162 struct	servtab {
163 	char	*se_service;		/* name of service */
164 	int	se_socktype;		/* type of socket to use */
165 	char	*se_proto;		/* protocol used */
166 	int	se_maxchild;		/* max number of children */
167 	int	se_maxcpm;		/* max connects per IP per minute */
168 	int	se_numchild;		/* current number of children */
169 	pid_t	*se_pids;		/* array of child pids */
170 	char	*se_user;		/* user name to run as */
171 	char    *se_group;              /* group name to run as */
172 #ifdef  LOGIN_CAP
173 	char    *se_class;              /* login class name to run with */
174 #endif
175 	struct	biltin *se_bi;		/* if built-in, description */
176 	char	*se_server;		/* server program */
177 #define	MAXARGV 20
178 	char	*se_argv[MAXARGV+1];	/* program arguments */
179 	int	se_fd;			/* open descriptor */
180 	struct	sockaddr_in se_ctrladdr;/* bound address */
181 	u_char	se_type;		/* type: normal, mux, or mux+ */
182 	u_char	se_checked;		/* looked at during merge */
183 	u_char	se_accept;		/* i.e., wait/nowait mode */
184 	u_char	se_rpc;			/* ==1 if RPC service */
185 	int	se_rpc_prog;		/* RPC program number */
186 	u_int	se_rpc_lowvers;		/* RPC low version */
187 	u_int	se_rpc_highvers;	/* RPC high version */
188 	int	se_count;		/* number started since se_time */
189 	struct	timeval se_time;	/* start of se_count */
190 	struct	servtab *se_next;
191 } *servtab;
192 
193 #define NORM_TYPE	0
194 #define MUX_TYPE	1
195 #define MUXPLUS_TYPE	2
196 #define ISMUX(sep)	(((sep)->se_type == MUX_TYPE) || \
197 			 ((sep)->se_type == MUXPLUS_TYPE))
198 #define ISMUXPLUS(sep)	((sep)->se_type == MUXPLUS_TYPE)
199 
200 
201 void		chargen_dg __P((int, struct servtab *));
202 void		chargen_stream __P((int, struct servtab *));
203 void		close_sep __P((struct servtab *));
204 void		config __P((int));
205 void		daytime_dg __P((int, struct servtab *));
206 void		daytime_stream __P((int, struct servtab *));
207 void		discard_dg __P((int, struct servtab *));
208 void		discard_stream __P((int, struct servtab *));
209 void		echo_dg __P((int, struct servtab *));
210 void		echo_stream __P((int, struct servtab *));
211 void		endconfig __P((void));
212 struct servtab *enter __P((struct servtab *));
213 void		freeconfig __P((struct servtab *));
214 struct servtab *getconfigent __P((void));
215 void		machtime_dg __P((int, struct servtab *));
216 void		machtime_stream __P((int, struct servtab *));
217 char	       *newstr __P((char *));
218 char	       *nextline __P((FILE *));
219 void		print_service __P((char *, struct servtab *));
220 void		addchild __P((struct servtab *, int));
221 void		reapchild __P((int));
222 void		enable __P((struct servtab *));
223 void		disable __P((struct servtab *));
224 void		retry __P((int));
225 int		setconfig __P((void));
226 void		setup __P((struct servtab *));
227 char	       *sskip __P((char **));
228 char	       *skip __P((char **));
229 struct servtab *tcpmux __P((int));
230 int		cpmip __P((struct servtab *, int));
231 
232 void		unregisterrpc __P((register struct servtab *sep));
233 
234 struct biltin {
235 	char	*bi_service;		/* internally provided service name */
236 	int	bi_socktype;		/* type of socket supported */
237 	short	bi_fork;		/* 1 if should fork before call */
238 	int	bi_maxchild;		/* max number of children (default) */
239 	void	(*bi_fn)();		/* function which performs it */
240 } biltins[] = {
241 	/* Echo received data */
242 	{ "echo",	SOCK_STREAM,	1, 0,	echo_stream },
243 	{ "echo",	SOCK_DGRAM,	0, 0,	echo_dg },
244 
245 	/* Internet /dev/null */
246 	{ "discard",	SOCK_STREAM,	1, 0,	discard_stream },
247 	{ "discard",	SOCK_DGRAM,	0, 0,	discard_dg },
248 
249 	/* Return 32 bit time since 1970 */
250 	{ "time",	SOCK_STREAM,	0, 0,	machtime_stream },
251 	{ "time",	SOCK_DGRAM,	0, 0,	machtime_dg },
252 
253 	/* Return human-readable time */
254 	{ "daytime",	SOCK_STREAM,	0, 0,	daytime_stream },
255 	{ "daytime",	SOCK_DGRAM,	0, 0,	daytime_dg },
256 
257 	/* Familiar character generator */
258 	{ "chargen",	SOCK_STREAM,	1, 0,	chargen_stream },
259 	{ "chargen",	SOCK_DGRAM,	0, 0,	chargen_dg },
260 
261 	{ "tcpmux",	SOCK_STREAM,	1, 0,	(void (*)())tcpmux },
262 
263 	{ NULL }
264 };
265 
266 #define NUMINT	(sizeof(intab) / sizeof(struct inent))
267 char	*CONFIG = _PATH_INETDCONF;
268 char	*pid_file = _PATH_INETDPID;
269 
270 #ifdef OLD_SETPROCTITLE
271 char	**Argv;
272 char 	*LastArg;
273 #endif
274 
275 int
276 main(argc, argv, envp)
277 	int argc;
278 	char *argv[], *envp[];
279 {
280 	struct servtab *sep;
281 	struct passwd *pwd;
282 	struct group *grp;
283 	struct sigvec sv;
284 	int tmpint, ch, dofork;
285 	pid_t pid;
286 	char buf[50];
287 	struct  sockaddr_in peer;
288 	int i;
289 #ifdef LOGIN_CAP
290 	login_cap_t *lc = NULL;
291 #endif
292 
293 
294 #ifdef OLD_SETPROCTITLE
295 	Argv = argv;
296 	if (envp == 0 || *envp == 0)
297 		envp = argv;
298 	while (*envp)
299 		envp++;
300 	LastArg = envp[-1] + strlen(envp[-1]);
301 #endif
302 
303 	openlog("inetd", LOG_PID | LOG_NOWAIT, LOG_DAEMON);
304 
305 	bind_address.s_addr = htonl(INADDR_ANY);
306 	while ((ch = getopt(argc, argv, "dlR:a:p:")) != -1)
307 		switch(ch) {
308 		case 'd':
309 			debug = 1;
310 			options |= SO_DEBUG;
311 			break;
312 		case 'l':
313 			log = 1;
314 			break;
315 		case 'R': {	/* invocation rate */
316 			char *p;
317 
318 			tmpint = strtol(optarg, &p, 0);
319 			if (tmpint < 1 || *p)
320 				syslog(LOG_ERR,
321 			         "-R %s: bad value for service invocation rate",
322 					optarg);
323 			else
324 				toomany = tmpint;
325 			break;
326 		}
327 		case 'a':
328 			if (!inet_aton(optarg, &bind_address)) {
329 				syslog(LOG_ERR,
330 			         "-a %s: invalid IP address", optarg);
331 				exit(EX_USAGE);
332 			}
333 			break;
334 		case 'p':
335 			pid_file = optarg;
336 			break;
337 		case '?':
338 		default:
339 			syslog(LOG_ERR,
340 				"usage: inetd [-dl] [-a address] [-R rate]"
341 				" [-p pidfile] [conf-file]");
342 			exit(EX_USAGE);
343 		}
344 	argc -= optind;
345 	argv += optind;
346 
347 	if (argc > 0)
348 		CONFIG = argv[0];
349 	if (debug == 0) {
350 		FILE *fp;
351 		if (daemon(0, 0) < 0) {
352 			syslog(LOG_WARNING, "daemon(0,0) failed: %m");
353 		}
354 		/*
355 		 * In case somebody has started inetd manually, we need to
356 		 * clear the logname, so that old servers run as root do not
357 		 * get the user's logname..
358 		 */
359 		if (setlogin("") < 0) {
360 			syslog(LOG_WARNING, "cannot clear logname: %m");
361 			/* no big deal if it fails.. */
362 		}
363 		pid = getpid();
364 		fp = fopen(pid_file, "w");
365 		if (fp) {
366 			fprintf(fp, "%ld\n", (long)pid);
367 			fclose(fp);
368 		} else {
369 			syslog(LOG_WARNING, "%s: %m", pid_file);
370 		}
371 	}
372 	memset(&sv, 0, sizeof(sv));
373 	sv.sv_mask = SIGBLOCK;
374 	sv.sv_handler = retry;
375 	sigvec(SIGALRM, &sv, (struct sigvec *)0);
376 	config(SIGHUP);
377 	sv.sv_handler = config;
378 	sigvec(SIGHUP, &sv, (struct sigvec *)0);
379 	sv.sv_handler = reapchild;
380 	sigvec(SIGCHLD, &sv, (struct sigvec *)0);
381 
382 	{
383 		/* space for daemons to overwrite environment for ps */
384 #define	DUMMYSIZE	100
385 		char dummy[DUMMYSIZE];
386 
387 		(void)memset(dummy, 'x', DUMMYSIZE - 1);
388 		dummy[DUMMYSIZE - 1] = '\0';
389 		(void)setenv("inetd_dummy", dummy, 1);
390 	}
391 
392 	for (;;) {
393 	    int n, ctrl;
394 	    fd_set readable;
395 
396 	    if (nsock == 0) {
397 		(void) sigblock(SIGBLOCK);
398 		while (nsock == 0)
399 		    sigpause(0L);
400 		(void) sigsetmask(0L);
401 	    }
402 	    readable = allsock;
403 	    if ((n = select(maxsock + 1, &readable, (fd_set *)0,
404 		(fd_set *)0, (struct timeval *)0)) <= 0) {
405 		    if (n < 0 && errno != EINTR) {
406 			syslog(LOG_WARNING, "select: %m");
407 			sleep(1);
408 		    }
409 		    continue;
410 	    }
411 	    for (sep = servtab; n && sep; sep = sep->se_next)
412 	        if (sep->se_fd != -1 && FD_ISSET(sep->se_fd, &readable)) {
413 		    n--;
414 		    if (debug)
415 			    warnx("someone wants %s", sep->se_service);
416 		    if (sep->se_accept && sep->se_socktype == SOCK_STREAM) {
417 			    ctrl = accept(sep->se_fd, (struct sockaddr *)0,
418 				(int *)0);
419 			    if (debug)
420 				    warnx("accept, ctrl %d", ctrl);
421 			    if (ctrl < 0) {
422 				    if (errno != EINTR)
423 					    syslog(LOG_WARNING,
424 						"accept (for %s): %m",
425 						sep->se_service);
426 				    continue;
427 			    }
428 			    if (cpmip(sep, ctrl) < 0) {
429 				close(ctrl);
430 				continue;
431 			    }
432 			    if (log) {
433 				i = sizeof peer;
434 				if (getpeername(ctrl, (struct sockaddr *)
435 						&peer, &i)) {
436 					syslog(LOG_WARNING,
437 						"getpeername(for %s): %m",
438 						sep->se_service);
439 					close(ctrl);
440 					continue;
441 				}
442 				syslog(LOG_INFO,"%s from %s",
443 					sep->se_service,
444 					inet_ntoa(peer.sin_addr));
445 			    }
446 			    /*
447 			     * Call tcpmux to find the real service to exec.
448 			     */
449 			    if (sep->se_bi &&
450 				sep->se_bi->bi_fn == (void (*)()) tcpmux) {
451 				    struct servtab *tsep;
452 
453 				    tsep = tcpmux(ctrl);
454 				    if (tsep == NULL) {
455 					    close(ctrl);
456 					    continue;
457 				    }
458 				    sep = tsep;
459 			    }
460 		    } else
461 			    ctrl = sep->se_fd;
462 		    (void) sigblock(SIGBLOCK);
463 		    pid = 0;
464 		    dofork = (sep->se_bi == 0 || sep->se_bi->bi_fork);
465 		    if (dofork) {
466 			    if (sep->se_count++ == 0)
467 				(void)gettimeofday(&sep->se_time,
468 				    (struct timezone *)0);
469 			    else if (sep->se_count >= toomany) {
470 				struct timeval now;
471 
472 				(void)gettimeofday(&now, (struct timezone *)0);
473 				if (now.tv_sec - sep->se_time.tv_sec >
474 				    CNT_INTVL) {
475 					sep->se_time = now;
476 					sep->se_count = 1;
477 				} else {
478 					syslog(LOG_ERR,
479 			"%s/%s server failing (looping), service terminated",
480 					    sep->se_service, sep->se_proto);
481 					close_sep(sep);
482 					sigsetmask(0L);
483 					if (!timingout) {
484 						timingout = 1;
485 						alarm(RETRYTIME);
486 					}
487 					continue;
488 				}
489 			    }
490 			    pid = fork();
491 		    }
492 		    if (pid < 0) {
493 			    syslog(LOG_ERR, "fork: %m");
494 			    if (sep->se_accept &&
495 				sep->se_socktype == SOCK_STREAM)
496 				    close(ctrl);
497 			    sigsetmask(0L);
498 			    sleep(1);
499 			    continue;
500 		    }
501 		    if (pid)
502 			addchild(sep, pid);
503 		    sigsetmask(0L);
504 		    if (pid == 0) {
505 			    if (dofork) {
506 				if (debug)
507 					warnx("+ closing from %d", maxsock);
508 				for (tmpint = maxsock; tmpint > 2; tmpint--)
509 					if (tmpint != ctrl)
510 						(void) close(tmpint);
511 			    }
512 			    if (sep->se_bi) {
513 				(*sep->se_bi->bi_fn)(ctrl, sep);
514 				/* NOTREACHED */
515 			    } else {
516 				if (debug)
517 					warnx("%d execl %s",
518 						getpid(), sep->se_server);
519 				dup2(ctrl, 0);
520 				close(ctrl);
521 				dup2(0, 1);
522 				dup2(0, 2);
523 				if ((pwd = getpwnam(sep->se_user)) == NULL) {
524 					syslog(LOG_ERR,
525 					    "%s/%s: %s: No such user",
526 						sep->se_service, sep->se_proto,
527 						sep->se_user);
528 					if (sep->se_socktype != SOCK_STREAM)
529 						recv(0, buf, sizeof (buf), 0);
530 					_exit(EX_NOUSER);
531 				}
532 				grp = NULL;
533 				if (   sep->se_group != NULL
534 				    && (grp = getgrnam(sep->se_group)) == NULL
535 				   ) {
536 					syslog(LOG_ERR,
537 					    "%s/%s: %s: No such group",
538 						sep->se_service, sep->se_proto,
539 						sep->se_group);
540 					if (sep->se_socktype != SOCK_STREAM)
541 						recv(0, buf, sizeof (buf), 0);
542 					_exit(EX_NOUSER);
543 				}
544 				if (grp != NULL)
545 					pwd->pw_gid = grp->gr_gid;
546 #ifdef LOGIN_CAP
547 				if ((lc = login_getclass(sep->se_class)) == NULL) {
548 					/* error syslogged by getclass */
549 					syslog(LOG_ERR,
550 					    "%s/%s: %s: login class error",
551 						sep->se_service, sep->se_proto);
552 					if (sep->se_socktype != SOCK_STREAM)
553 						recv(0, buf, sizeof (buf), 0);
554 					_exit(EX_NOUSER);
555 				}
556 #endif
557 				if (setsid() < 0) {
558 					syslog(LOG_ERR,
559 						"%s: can't setsid(): %m",
560 						 sep->se_service);
561 					/* _exit(EX_OSERR); not fatal yet */
562 				}
563 #ifdef LOGIN_CAP
564 				if (setusercontext(lc, pwd, pwd->pw_uid,
565 				    LOGIN_SETALL) != 0) {
566 					syslog(LOG_ERR,
567 					 "%s: can't setusercontext(..%s..): %m",
568 					 sep->se_service, sep->se_user);
569 					_exit(EX_OSERR);
570 				}
571 #else
572 				if (pwd->pw_uid) {
573 					if (setlogin(sep->se_user) < 0) {
574 						syslog(LOG_ERR,
575 						 "%s: can't setlogin(%s): %m",
576 						 sep->se_service, sep->se_user);
577 						/* _exit(EX_OSERR); not yet */
578 					}
579 					if (setgid(pwd->pw_gid) < 0) {
580 						syslog(LOG_ERR,
581 						  "%s: can't set gid %d: %m",
582 						  sep->se_service, pwd->pw_gid);
583 						_exit(EX_OSERR);
584 					}
585 					(void) initgroups(pwd->pw_name,
586 							pwd->pw_gid);
587 					if (setuid(pwd->pw_uid) < 0) {
588 						syslog(LOG_ERR,
589 						  "%s: can't set uid %d: %m",
590 						  sep->se_service, pwd->pw_uid);
591 						_exit(EX_OSERR);
592 					}
593 				}
594 #endif
595 				execv(sep->se_server, sep->se_argv);
596 				if (sep->se_socktype != SOCK_STREAM)
597 					recv(0, buf, sizeof (buf), 0);
598 				syslog(LOG_ERR,
599 				    "cannot execute %s: %m", sep->se_server);
600 				_exit(EX_OSERR);
601 			    }
602 		    }
603 		    if (sep->se_accept && sep->se_socktype == SOCK_STREAM)
604 			    close(ctrl);
605 		}
606 	}
607 }
608 
609 /*
610  * Record a new child pid for this service. If we've reached the
611  * limit on children, then stop accepting incoming requests.
612  */
613 
614 void
615 addchild(struct servtab *sep, pid_t pid)
616 {
617 #ifdef SANITY_CHECK
618 	if (sep->se_numchild >= sep->se_maxchild) {
619 		syslog(LOG_ERR, "%s: %d >= %d",
620 		    __FUNCTION__, sep->se_numchild, sep->se_maxchild);
621 		exit(EX_SOFTWARE);
622 	}
623 #endif
624 	if (sep->se_maxchild == 0)
625 		return;
626 	sep->se_pids[sep->se_numchild++] = pid;
627 	if (sep->se_numchild == sep->se_maxchild)
628 		disable(sep);
629 }
630 
631 /*
632  * Some child process has exited. See if it's on somebody's list.
633  */
634 
635 void
636 reapchild(signo)
637 	int signo;
638 {
639 	int k, status;
640 	pid_t pid;
641 	struct servtab *sep;
642 
643 	for (;;) {
644 		pid = wait3(&status, WNOHANG, (struct rusage *)0);
645 		if (pid <= 0)
646 			break;
647 		if (debug)
648 			warnx("%d reaped, status %#x", pid, status);
649 		for (sep = servtab; sep; sep = sep->se_next) {
650 			for (k = 0; k < sep->se_numchild; k++)
651 				if (sep->se_pids[k] == pid)
652 					break;
653 			if (k == sep->se_numchild)
654 				continue;
655 			if (sep->se_numchild == sep->se_maxchild)
656 				enable(sep);
657 			sep->se_pids[k] = sep->se_pids[--sep->se_numchild];
658 			if (status)
659 				syslog(LOG_WARNING,
660 				    "%s[%d]: exit status 0x%x",
661 				    sep->se_server, pid, status);
662 			break;
663 		}
664 	}
665 }
666 
667 void
668 config(signo)
669 	int signo;
670 {
671 	struct servtab *sep, *new, **sepp;
672 	long omask;
673 
674 	if (!setconfig()) {
675 		syslog(LOG_ERR, "%s: %m", CONFIG);
676 		return;
677 	}
678 	for (sep = servtab; sep; sep = sep->se_next)
679 		sep->se_checked = 0;
680 	while ((new = getconfigent())) {
681 		if (getpwnam(new->se_user) == NULL) {
682 			syslog(LOG_ERR,
683 				"%s/%s: No such user '%s', service ignored",
684 				new->se_service, new->se_proto, new->se_user);
685 			continue;
686 		}
687 		if (new->se_group && getgrnam(new->se_group) == NULL) {
688 			syslog(LOG_ERR,
689 				"%s/%s: No such group '%s', service ignored",
690 				new->se_service, new->se_proto, new->se_group);
691 			continue;
692 		}
693 #ifdef LOGIN_CAP
694 		if (login_getclass(new->se_class) == NULL) {
695 			/* error syslogged by getclass */
696 			syslog(LOG_ERR,
697 				"%s/%s: login class error, service ignored",
698 				new->se_service, new->se_proto);
699 			continue;
700 		}
701 #endif
702 		for (sep = servtab; sep; sep = sep->se_next)
703 			if (strcmp(sep->se_service, new->se_service) == 0 &&
704 			    strcmp(sep->se_proto, new->se_proto) == 0)
705 				break;
706 		if (sep != 0) {
707 			int i;
708 
709 #define SWAP(a, b) { typeof(a) c = a; a = b; b = c; }
710 			omask = sigblock(SIGBLOCK);
711 			/* copy over outstanding child pids */
712 			if (sep->se_maxchild && new->se_maxchild) {
713 				new->se_numchild = sep->se_numchild;
714 				if (new->se_numchild > new->se_maxchild)
715 					new->se_numchild = new->se_maxchild;
716 				memcpy(new->se_pids, sep->se_pids,
717 				    new->se_numchild * sizeof(*new->se_pids));
718 			}
719 			SWAP(sep->se_pids, new->se_pids);
720 			sep->se_maxchild = new->se_maxchild;
721 			sep->se_numchild = new->se_numchild;
722 			sep->se_maxcpm = new->se_maxcpm;
723 			/* might need to turn on or off service now */
724 			if (sep->se_fd >= 0) {
725 			      if (sep->se_maxchild
726 				  && sep->se_numchild == sep->se_maxchild) {
727 				      if (FD_ISSET(sep->se_fd, &allsock))
728 					  disable(sep);
729 			      } else {
730 				      if (!FD_ISSET(sep->se_fd, &allsock))
731 					  enable(sep);
732 			      }
733 			}
734 			sep->se_accept = new->se_accept;
735 			SWAP(sep->se_user, new->se_user);
736 			SWAP(sep->se_group, new->se_group);
737 #ifdef LOGIN_CAP
738 			SWAP(sep->se_class, new->se_class);
739 #endif
740 			SWAP(sep->se_server, new->se_server);
741 			for (i = 0; i < MAXARGV; i++)
742 				SWAP(sep->se_argv[i], new->se_argv[i]);
743 			sigsetmask(omask);
744 			freeconfig(new);
745 			if (debug)
746 				print_service("REDO", sep);
747 		} else {
748 			sep = enter(new);
749 			if (debug)
750 				print_service("ADD ", sep);
751 		}
752 		sep->se_checked = 1;
753 		if (ISMUX(sep)) {
754 			sep->se_fd = -1;
755 			continue;
756 		}
757 		if (!sep->se_rpc) {
758 			sp = getservbyname(sep->se_service, sep->se_proto);
759 			if (sp == 0) {
760 				syslog(LOG_ERR, "%s/%s: unknown service",
761 			    	sep->se_service, sep->se_proto);
762 				sep->se_checked = 0;
763 				continue;
764 			}
765 			if (sp->s_port != sep->se_ctrladdr.sin_port) {
766 				sep->se_ctrladdr.sin_family = AF_INET;
767 				sep->se_ctrladdr.sin_addr = bind_address;
768 				sep->se_ctrladdr.sin_port = sp->s_port;
769 				if (sep->se_fd >= 0)
770 					close_sep(sep);
771 			}
772 		} else {
773 			rpc = getrpcbyname(sep->se_service);
774 			if (rpc == 0) {
775 				syslog(LOG_ERR, "%s/%s unknown RPC service.",
776 					sep->se_service, sep->se_proto);
777 				if (sep->se_fd != -1)
778 					(void) close(sep->se_fd);
779 				sep->se_fd = -1;
780 					continue;
781 			}
782 			if (rpc->r_number != sep->se_rpc_prog) {
783 				if (sep->se_rpc_prog)
784 					unregisterrpc(sep);
785 				sep->se_rpc_prog = rpc->r_number;
786 				if (sep->se_fd != -1)
787 					(void) close(sep->se_fd);
788 				sep->se_fd = -1;
789 			}
790 		}
791 		if (sep->se_fd == -1)
792 			setup(sep);
793 	}
794 	endconfig();
795 	/*
796 	 * Purge anything not looked at above.
797 	 */
798 	omask = sigblock(SIGBLOCK);
799 	sepp = &servtab;
800 	while ((sep = *sepp)) {
801 		if (sep->se_checked) {
802 			sepp = &sep->se_next;
803 			continue;
804 		}
805 		*sepp = sep->se_next;
806 		if (sep->se_fd >= 0)
807 			close_sep(sep);
808 		if (debug)
809 			print_service("FREE", sep);
810 		if (sep->se_rpc && sep->se_rpc_prog > 0)
811 			unregisterrpc(sep);
812 		freeconfig(sep);
813 		free((char *)sep);
814 	}
815 	(void) sigsetmask(omask);
816 }
817 
818 void
819 unregisterrpc(sep)
820 	struct servtab *sep;
821 {
822         int i;
823         struct servtab *sepp;
824 	long omask;
825 
826 	omask = sigblock(SIGBLOCK);
827         for (sepp = servtab; sepp; sepp = sepp->se_next) {
828                 if (sepp == sep)
829                         continue;
830 		if (sep->se_checked == 0 ||
831                     !sepp->se_rpc ||
832                     sep->se_rpc_prog != sepp->se_rpc_prog)
833 			continue;
834                 return;
835         }
836         if (debug)
837                 print_service("UNREG", sep);
838         for (i = sep->se_rpc_lowvers; i <= sep->se_rpc_highvers; i++)
839                 pmap_unset(sep->se_rpc_prog, i);
840         if (sep->se_fd != -1)
841                 (void) close(sep->se_fd);
842         sep->se_fd = -1;
843 	(void) sigsetmask(omask);
844 }
845 
846 void
847 retry(signo)
848 	int signo;
849 {
850 	struct servtab *sep;
851 
852 	timingout = 0;
853 	for (sep = servtab; sep; sep = sep->se_next)
854 		if (sep->se_fd == -1 && !ISMUX(sep))
855 			setup(sep);
856 }
857 
858 void
859 setup(sep)
860 	struct servtab *sep;
861 {
862 	int on = 1;
863 
864 	if ((sep->se_fd = socket(AF_INET, sep->se_socktype, 0)) < 0) {
865 		if (debug)
866 			warn("socket failed on %s/%s",
867 				sep->se_service, sep->se_proto);
868 		syslog(LOG_ERR, "%s/%s: socket: %m",
869 		    sep->se_service, sep->se_proto);
870 		return;
871 	}
872 #define	turnon(fd, opt) \
873 setsockopt(fd, SOL_SOCKET, opt, (char *)&on, sizeof (on))
874 	if (strcmp(sep->se_proto, "tcp") == 0 && (options & SO_DEBUG) &&
875 	    turnon(sep->se_fd, SO_DEBUG) < 0)
876 		syslog(LOG_ERR, "setsockopt (SO_DEBUG): %m");
877 	if (turnon(sep->se_fd, SO_REUSEADDR) < 0)
878 		syslog(LOG_ERR, "setsockopt (SO_REUSEADDR): %m");
879 #ifdef SO_PRIVSTATE
880 	if (turnon(sep->se_fd, SO_PRIVSTATE) < 0)
881 		syslog(LOG_ERR, "setsockopt (SO_PRIVSTATE): %m");
882 #endif
883 #undef turnon
884 	if (bind(sep->se_fd, (struct sockaddr *)&sep->se_ctrladdr,
885 	    sizeof (sep->se_ctrladdr)) < 0) {
886 		if (debug)
887 			warn("bind failed on %s/%s",
888 				sep->se_service, sep->se_proto);
889 		syslog(LOG_ERR, "%s/%s: bind: %m",
890 		    sep->se_service, sep->se_proto);
891 		(void) close(sep->se_fd);
892 		sep->se_fd = -1;
893 		if (!timingout) {
894 			timingout = 1;
895 			alarm(RETRYTIME);
896 		}
897 		return;
898 	}
899         if (sep->se_rpc) {
900                 int i, len = sizeof(struct sockaddr);
901 
902                 if (getsockname(sep->se_fd,
903 				(struct sockaddr*)&sep->se_ctrladdr, &len) < 0){
904                         syslog(LOG_ERR, "%s/%s: getsockname: %m",
905                                sep->se_service, sep->se_proto);
906                         (void) close(sep->se_fd);
907                         sep->se_fd = -1;
908                         return;
909                 }
910                 if (debug)
911                         print_service("REG ", sep);
912                 for (i = sep->se_rpc_lowvers; i <= sep->se_rpc_highvers; i++) {
913                         pmap_unset(sep->se_rpc_prog, i);
914                         pmap_set(sep->se_rpc_prog, i,
915                                  (sep->se_socktype == SOCK_DGRAM)
916                                  ? IPPROTO_UDP : IPPROTO_TCP,
917                                  ntohs(sep->se_ctrladdr.sin_port));
918                 }
919 
920         }
921 	if (sep->se_socktype == SOCK_STREAM)
922 		listen(sep->se_fd, 64);
923 	enable(sep);
924 	if (debug) {
925 		warnx("registered %s on %d",
926 			sep->se_server, sep->se_fd);
927 	}
928 }
929 
930 /*
931  * Finish with a service and its socket.
932  */
933 void
934 close_sep(sep)
935 	struct servtab *sep;
936 {
937 	if (sep->se_fd >= 0) {
938 		if (FD_ISSET(sep->se_fd, &allsock))
939 			disable(sep);
940 		(void) close(sep->se_fd);
941 		sep->se_fd = -1;
942 	}
943 	sep->se_count = 0;
944 	sep->se_numchild = 0;	/* forget about any existing children */
945 }
946 
947 struct servtab *
948 enter(cp)
949 	struct servtab *cp;
950 {
951 	struct servtab *sep;
952 	long omask;
953 
954 	sep = (struct servtab *)malloc(sizeof (*sep));
955 	if (sep == (struct servtab *)0) {
956 		syslog(LOG_ERR, "Out of memory.");
957 		exit(EX_OSERR);
958 	}
959 	*sep = *cp;
960 	sep->se_fd = -1;
961 	omask = sigblock(SIGBLOCK);
962 	sep->se_next = servtab;
963 	servtab = sep;
964 	sigsetmask(omask);
965 	return (sep);
966 }
967 
968 void
969 enable(struct servtab *sep)
970 {
971 	if (debug)
972 		warnx(
973 		    "enabling %s, fd %d", sep->se_service, sep->se_fd);
974 #ifdef SANITY_CHECK
975 	if (sep->se_fd < 0) {
976 		syslog(LOG_ERR,
977 		    "%s: %s: bad fd", __FUNCTION__, sep->se_service);
978 		exit(EX_SOFTWARE);
979 	}
980 	if (ISMUX(sep)) {
981 		syslog(LOG_ERR,
982 		    "%s: %s: is mux", __FUNCTION__, sep->se_service);
983 		exit(EX_SOFTWARE);
984 	}
985 	if (FD_ISSET(sep->se_fd, &allsock)) {
986 		syslog(LOG_ERR,
987 		    "%s: %s: not off", __FUNCTION__, sep->se_service);
988 		exit(EX_SOFTWARE);
989 	}
990 #endif
991 	FD_SET(sep->se_fd, &allsock);
992 	nsock++;
993 	if (sep->se_fd > maxsock)
994 		maxsock = sep->se_fd;
995 }
996 
997 void
998 disable(struct servtab *sep)
999 {
1000 	if (debug)
1001 		warnx(
1002 		    "disabling %s, fd %d", sep->se_service, sep->se_fd);
1003 #ifdef SANITY_CHECK
1004 	if (sep->se_fd < 0) {
1005 		syslog(LOG_ERR,
1006 		    "%s: %s: bad fd", __FUNCTION__, sep->se_service);
1007 		exit(EX_SOFTWARE);
1008 	}
1009 	if (ISMUX(sep)) {
1010 		syslog(LOG_ERR,
1011 		    "%s: %s: is mux", __FUNCTION__, sep->se_service);
1012 		exit(EX_SOFTWARE);
1013 	}
1014 	if (!FD_ISSET(sep->se_fd, &allsock)) {
1015 		syslog(LOG_ERR,
1016 		    "%s: %s: not on", __FUNCTION__, sep->se_service);
1017 		exit(EX_SOFTWARE);
1018 	}
1019 	if (nsock == 0) {
1020 		syslog(LOG_ERR, "%s: nsock=0", __FUNCTION__);
1021 		exit(EX_SOFTWARE);
1022 	}
1023 #endif
1024 	FD_CLR(sep->se_fd, &allsock);
1025 	nsock--;
1026 	if (sep->se_fd == maxsock)
1027 		maxsock--;
1028 }
1029 
1030 FILE	*fconfig = NULL;
1031 struct	servtab serv;
1032 char	line[LINE_MAX];
1033 
1034 int
1035 setconfig()
1036 {
1037 
1038 	if (fconfig != NULL) {
1039 		fseek(fconfig, 0L, SEEK_SET);
1040 		return (1);
1041 	}
1042 	fconfig = fopen(CONFIG, "r");
1043 	return (fconfig != NULL);
1044 }
1045 
1046 void
1047 endconfig()
1048 {
1049 	if (fconfig) {
1050 		(void) fclose(fconfig);
1051 		fconfig = NULL;
1052 	}
1053 }
1054 
1055 struct servtab *
1056 getconfigent()
1057 {
1058 	struct servtab *sep = &serv;
1059 	int argc;
1060 	char *cp, *arg, *s;
1061 	char *versp;
1062 	static char TCPMUX_TOKEN[] = "tcpmux/";
1063 #define MUX_LEN		(sizeof(TCPMUX_TOKEN)-1)
1064 
1065 more:
1066 	while ((cp = nextline(fconfig)) && (*cp == '#' || *cp == '\0'))
1067 		;
1068 	if (cp == NULL)
1069 		return ((struct servtab *)0);
1070 	/*
1071 	 * clear the static buffer, since some fields (se_ctrladdr,
1072 	 * for example) don't get initialized here.
1073 	 */
1074 	memset((caddr_t)sep, 0, sizeof *sep);
1075 	arg = skip(&cp);
1076 	if (cp == NULL) {
1077 		/* got an empty line containing just blanks/tabs. */
1078 		goto more;
1079 	}
1080 	if (strncmp(arg, TCPMUX_TOKEN, MUX_LEN) == 0) {
1081 		char *c = arg + MUX_LEN;
1082 		if (*c == '+') {
1083 			sep->se_type = MUXPLUS_TYPE;
1084 			c++;
1085 		} else
1086 			sep->se_type = MUX_TYPE;
1087 		sep->se_service = newstr(c);
1088 	} else {
1089 		sep->se_service = newstr(arg);
1090 		sep->se_type = NORM_TYPE;
1091 	}
1092 	arg = sskip(&cp);
1093 	if (strcmp(arg, "stream") == 0)
1094 		sep->se_socktype = SOCK_STREAM;
1095 	else if (strcmp(arg, "dgram") == 0)
1096 		sep->se_socktype = SOCK_DGRAM;
1097 	else if (strcmp(arg, "rdm") == 0)
1098 		sep->se_socktype = SOCK_RDM;
1099 	else if (strcmp(arg, "seqpacket") == 0)
1100 		sep->se_socktype = SOCK_SEQPACKET;
1101 	else if (strcmp(arg, "raw") == 0)
1102 		sep->se_socktype = SOCK_RAW;
1103 	else
1104 		sep->se_socktype = -1;
1105 	sep->se_proto = newstr(sskip(&cp));
1106         if (strncmp(sep->se_proto, "rpc/", 4) == 0) {
1107                 memmove(sep->se_proto, sep->se_proto + 4,
1108                     strlen(sep->se_proto) + 1 - 4);
1109                 sep->se_rpc = 1;
1110                 sep->se_rpc_prog = sep->se_rpc_lowvers =
1111 			sep->se_rpc_lowvers = 0;
1112                 sep->se_ctrladdr.sin_family = AF_INET;
1113                 sep->se_ctrladdr.sin_port = 0;
1114                 sep->se_ctrladdr.sin_addr = bind_address;
1115                 if ((versp = rindex(sep->se_service, '/'))) {
1116                         *versp++ = '\0';
1117                         switch (sscanf(versp, "%d-%d",
1118                                        &sep->se_rpc_lowvers,
1119                                        &sep->se_rpc_highvers)) {
1120                         case 2:
1121                                 break;
1122                         case 1:
1123                                 sep->se_rpc_highvers =
1124                                         sep->se_rpc_lowvers;
1125                                 break;
1126                         default:
1127                                 syslog(LOG_ERR,
1128 					"bad RPC version specifier; %s\n",
1129 					sep->se_service);
1130                                 freeconfig(sep);
1131                                 goto more;
1132                         }
1133                 }
1134                 else {
1135                         sep->se_rpc_lowvers =
1136                                 sep->se_rpc_highvers = 1;
1137                 }
1138         }
1139 	arg = sskip(&cp);
1140 	if (!strncmp(arg, "wait", 4))
1141 		sep->se_accept = 0;
1142 	else if (!strncmp(arg, "nowait", 6))
1143 		sep->se_accept = 1;
1144 	else {
1145 		syslog(LOG_ERR,
1146 			"%s: bad wait/nowait for service %s",
1147 			CONFIG, sep->se_service);
1148 		goto more;
1149 	}
1150 	sep->se_maxchild = -1;
1151 	sep->se_maxcpm = -1;
1152 	if ((s = strchr(arg, '/')) != NULL) {
1153 		char *eptr;
1154 		u_long val;
1155 
1156 		val = strtoul(s + 1, &eptr, 10);
1157 		if (eptr == s + 1 || val > MAX_MAXCHLD) {
1158 			syslog(LOG_ERR,
1159 				"%s: bad max-child for service %s",
1160 				CONFIG, sep->se_service);
1161 			goto more;
1162 		}
1163 		sep->se_maxchild = val;
1164 		if (*eptr == '/')
1165 			sep->se_maxcpm = strtol(eptr + 1, &eptr, 10);
1166 		/*
1167 		 * explicitly do not check for \0 for future expansion /
1168 		 * backwards compatibility
1169 		 */
1170 	}
1171 	if (ISMUX(sep)) {
1172 		/*
1173 		 * Silently enforce "nowait" mode for TCPMUX services
1174 		 * since they don't have an assigned port to listen on.
1175 		 */
1176 		sep->se_accept = 1;
1177 		if (strcmp(sep->se_proto, "tcp")) {
1178 			syslog(LOG_ERR,
1179 				"%s: bad protocol for tcpmux service %s",
1180 				CONFIG, sep->se_service);
1181 			goto more;
1182 		}
1183 		if (sep->se_socktype != SOCK_STREAM) {
1184 			syslog(LOG_ERR,
1185 				"%s: bad socket type for tcpmux service %s",
1186 				CONFIG, sep->se_service);
1187 			goto more;
1188 		}
1189 	}
1190 	sep->se_user = newstr(sskip(&cp));
1191 #ifdef LOGIN_CAP
1192 	if ((s = strrchr(sep->se_user, '/')) != NULL) {
1193 		*s = '\0';
1194 		sep->se_class = newstr(s + 1);
1195 	} else
1196 		sep->se_class = newstr(RESOURCE_RC);
1197 #endif
1198 	if ((s = strrchr(sep->se_user, ':')) != NULL) {
1199 		*s = '\0';
1200 		sep->se_group = newstr(s + 1);
1201 	} else
1202 		sep->se_group = NULL;
1203 	sep->se_server = newstr(sskip(&cp));
1204 	if (strcmp(sep->se_server, "internal") == 0) {
1205 		struct biltin *bi;
1206 
1207 		for (bi = biltins; bi->bi_service; bi++)
1208 			if (bi->bi_socktype == sep->se_socktype &&
1209 			    strcmp(bi->bi_service, sep->se_service) == 0)
1210 				break;
1211 		if (bi->bi_service == 0) {
1212 			syslog(LOG_ERR, "internal service %s unknown",
1213 				sep->se_service);
1214 			goto more;
1215 		}
1216 		sep->se_accept = 1;	/* force accept mode for built-ins */
1217 		sep->se_bi = bi;
1218 	} else
1219 		sep->se_bi = NULL;
1220 	if (sep->se_maxchild < 0)	/* apply default max-children */
1221 		if (sep->se_bi)
1222 			sep->se_maxchild = sep->se_bi->bi_maxchild;
1223 		else
1224 			sep->se_maxchild = sep->se_accept ? 0 : 1;
1225 	if (sep->se_maxchild) {
1226 		sep->se_pids = malloc(sep->se_maxchild * sizeof(*sep->se_pids));
1227 		if (sep->se_pids == NULL) {
1228 			syslog(LOG_ERR, "Out of memory.");
1229 			exit(EX_OSERR);
1230 		}
1231 	}
1232 	argc = 0;
1233 	for (arg = skip(&cp); cp; arg = skip(&cp))
1234 		if (argc < MAXARGV) {
1235 			sep->se_argv[argc++] = newstr(arg);
1236 		} else {
1237 			syslog(LOG_ERR,
1238 				"%s: too many arguments for service %s",
1239 				CONFIG, sep->se_service);
1240 			goto more;
1241 		}
1242 	while (argc <= MAXARGV)
1243 		sep->se_argv[argc++] = NULL;
1244 	return (sep);
1245 }
1246 
1247 void
1248 freeconfig(cp)
1249 	struct servtab *cp;
1250 {
1251 	int i;
1252 
1253 	if (cp->se_service)
1254 		free(cp->se_service);
1255 	if (cp->se_proto)
1256 		free(cp->se_proto);
1257 	if (cp->se_user)
1258 		free(cp->se_user);
1259 	if (cp->se_group)
1260 		free(cp->se_group);
1261 #ifdef LOGIN_CAP
1262 	if (cp->se_class)
1263 		free(cp->se_class);
1264 #endif
1265 	if (cp->se_server)
1266 		free(cp->se_server);
1267 	if (cp->se_pids)
1268 		free(cp->se_pids);
1269 	for (i = 0; i < MAXARGV; i++)
1270 		if (cp->se_argv[i])
1271 			free(cp->se_argv[i]);
1272 }
1273 
1274 
1275 /*
1276  * Safe skip - if skip returns null, log a syntax error in the
1277  * configuration file and exit.
1278  */
1279 char *
1280 sskip(cpp)
1281 	char **cpp;
1282 {
1283 	char *cp;
1284 
1285 	cp = skip(cpp);
1286 	if (cp == NULL) {
1287 		syslog(LOG_ERR, "%s: syntax error", CONFIG);
1288 		exit(EX_DATAERR);
1289 	}
1290 	return (cp);
1291 }
1292 
1293 char *
1294 skip(cpp)
1295 	char **cpp;
1296 {
1297 	char *cp = *cpp;
1298 	char *start;
1299 	char quote = '\0';
1300 
1301 again:
1302 	while (*cp == ' ' || *cp == '\t')
1303 		cp++;
1304 	if (*cp == '\0') {
1305 		int c;
1306 
1307 		c = getc(fconfig);
1308 		(void) ungetc(c, fconfig);
1309 		if (c == ' ' || c == '\t')
1310 			if ((cp = nextline(fconfig)))
1311 				goto again;
1312 		*cpp = (char *)0;
1313 		return ((char *)0);
1314 	}
1315 	if (*cp == '"' || *cp == '\'')
1316 		quote = *cp++;
1317 	start = cp;
1318 	if (quote)
1319 		while (*cp && *cp != quote)
1320 			cp++;
1321 	else
1322 		while (*cp && *cp != ' ' && *cp != '\t')
1323 			cp++;
1324 	if (*cp != '\0')
1325 		*cp++ = '\0';
1326 	*cpp = cp;
1327 	return (start);
1328 }
1329 
1330 char *
1331 nextline(fd)
1332 	FILE *fd;
1333 {
1334 	char *cp;
1335 
1336 	if (fgets(line, sizeof (line), fd) == NULL)
1337 		return ((char *)0);
1338 	cp = strchr(line, '\n');
1339 	if (cp)
1340 		*cp = '\0';
1341 	return (line);
1342 }
1343 
1344 char *
1345 newstr(cp)
1346 	char *cp;
1347 {
1348 	if ((cp = strdup(cp ? cp : "")))
1349 		return (cp);
1350 	syslog(LOG_ERR, "strdup: %m");
1351 	exit(EX_OSERR);
1352 }
1353 
1354 #ifdef OLD_SETPROCTITLE
1355 void
1356 inetd_setproctitle(a, s)
1357 	char *a;
1358 	int s;
1359 {
1360 	int size;
1361 	char *cp;
1362 	struct sockaddr_in sin;
1363 	char buf[80];
1364 
1365 	cp = Argv[0];
1366 	size = sizeof(sin);
1367 	if (getpeername(s, (struct sockaddr *)&sin, &size) == 0)
1368 		(void) sprintf(buf, "-%s [%s]", a, inet_ntoa(sin.sin_addr));
1369 	else
1370 		(void) sprintf(buf, "-%s", a);
1371 	strncpy(cp, buf, LastArg - cp);
1372 	cp += strlen(cp);
1373 	while (cp < LastArg)
1374 		*cp++ = ' ';
1375 }
1376 #else
1377 void
1378 inetd_setproctitle(a, s)
1379 	char *a;
1380 	int s;
1381 {
1382 	int size;
1383 	struct sockaddr_in sin;
1384 	char buf[80];
1385 
1386 	size = sizeof(sin);
1387 	if (getpeername(s, (struct sockaddr *)&sin, &size) == 0)
1388 		(void) sprintf(buf, "%s [%s]", a, inet_ntoa(sin.sin_addr));
1389 	else
1390 		(void) sprintf(buf, "%s", a);
1391 	setproctitle("%s", buf);
1392 }
1393 #endif
1394 
1395 
1396 /*
1397  * Internet services provided internally by inetd:
1398  */
1399 #define	BUFSIZE	8192
1400 
1401 /* ARGSUSED */
1402 void
1403 echo_stream(s, sep)		/* Echo service -- echo data back */
1404 	int s;
1405 	struct servtab *sep;
1406 {
1407 	char buffer[BUFSIZE];
1408 	int i;
1409 
1410 	inetd_setproctitle(sep->se_service, s);
1411 	while ((i = read(s, buffer, sizeof(buffer))) > 0 &&
1412 	    write(s, buffer, i) > 0)
1413 		;
1414 	exit(0);
1415 }
1416 
1417 int check_loop(sin, sep)
1418 	struct sockaddr_in *sin;
1419 	struct servtab *sep;
1420 {
1421 	struct servtab *se2;
1422 
1423 	for (se2 = servtab; se2; se2 = se2->se_next) {
1424 		if (!se2->se_bi || se2->se_socktype != SOCK_DGRAM)
1425 			continue;
1426 
1427 		if (sin->sin_port == se2->se_ctrladdr.sin_port) {
1428 			syslog(LOG_WARNING,
1429 			       "%s/%s:%s/%s loop request REFUSED from %s",
1430 			       sep->se_service, sep->se_proto,
1431 			       se2->se_service, se2->se_proto,
1432 			       inet_ntoa(sin->sin_addr));
1433 			return 1;
1434 		}
1435 	}
1436 	return 0;
1437 }
1438 
1439 /* ARGSUSED */
1440 void
1441 echo_dg(s, sep)			/* Echo service -- echo data back */
1442 	int s;
1443 	struct servtab *sep;
1444 {
1445 	char buffer[BUFSIZE];
1446 	int i, size;
1447 	struct sockaddr_in sin;
1448 
1449 	size = sizeof(sin);
1450 	if ((i = recvfrom(s, buffer, sizeof(buffer), 0,
1451 			  (struct sockaddr *)&sin, &size)) < 0)
1452 		return;
1453 
1454 	if (check_loop(&sin, sep))
1455 		return;
1456 
1457 	(void) sendto(s, buffer, i, 0, (struct sockaddr *)&sin,
1458 		      sizeof(sin));
1459 }
1460 
1461 /* ARGSUSED */
1462 void
1463 discard_stream(s, sep)		/* Discard service -- ignore data */
1464 	int s;
1465 	struct servtab *sep;
1466 {
1467 	int ret;
1468 	char buffer[BUFSIZE];
1469 
1470 	inetd_setproctitle(sep->se_service, s);
1471 	while (1) {
1472 		while ((ret = read(s, buffer, sizeof(buffer))) > 0)
1473 			;
1474 		if (ret == 0 || errno != EINTR)
1475 			break;
1476 	}
1477 	exit(0);
1478 }
1479 
1480 /* ARGSUSED */
1481 void
1482 discard_dg(s, sep)		/* Discard service -- ignore data */
1483 	int s;
1484 	struct servtab *sep;
1485 {
1486 	char buffer[BUFSIZE];
1487 
1488 	(void) read(s, buffer, sizeof(buffer));
1489 }
1490 
1491 #include <ctype.h>
1492 #define LINESIZ 72
1493 char ring[128];
1494 char *endring;
1495 
1496 void
1497 initring()
1498 {
1499 	int i;
1500 
1501 	endring = ring;
1502 
1503 	for (i = 0; i <= 128; ++i)
1504 		if (isprint(i))
1505 			*endring++ = i;
1506 }
1507 
1508 /* ARGSUSED */
1509 void
1510 chargen_stream(s, sep)		/* Character generator */
1511 	int s;
1512 	struct servtab *sep;
1513 {
1514 	int len;
1515 	char *rs, text[LINESIZ+2];
1516 
1517 	inetd_setproctitle(sep->se_service, s);
1518 
1519 	if (!endring) {
1520 		initring();
1521 		rs = ring;
1522 	}
1523 
1524 	text[LINESIZ] = '\r';
1525 	text[LINESIZ + 1] = '\n';
1526 	for (rs = ring;;) {
1527 		if ((len = endring - rs) >= LINESIZ)
1528 			memmove(text, rs, LINESIZ);
1529 		else {
1530 			memmove(text, rs, len);
1531 			memmove(text + len, ring, LINESIZ - len);
1532 		}
1533 		if (++rs == endring)
1534 			rs = ring;
1535 		if (write(s, text, sizeof(text)) != sizeof(text))
1536 			break;
1537 	}
1538 	exit(0);
1539 }
1540 
1541 /* ARGSUSED */
1542 void
1543 chargen_dg(s, sep)		/* Character generator */
1544 	int s;
1545 	struct servtab *sep;
1546 {
1547 	struct sockaddr_in sin;
1548 	static char *rs;
1549 	int len, size;
1550 	char text[LINESIZ+2];
1551 
1552 	if (endring == 0) {
1553 		initring();
1554 		rs = ring;
1555 	}
1556 
1557 	size = sizeof(sin);
1558 	if (recvfrom(s, text, sizeof(text), 0,
1559 		     (struct sockaddr *)&sin, &size) < 0)
1560 		return;
1561 
1562 	if (check_loop(&sin, sep))
1563 		return;
1564 
1565 	if ((len = endring - rs) >= LINESIZ)
1566 		memmove(text, rs, LINESIZ);
1567 	else {
1568 		memmove(text, rs, len);
1569 		memmove(text + len, ring, LINESIZ - len);
1570 	}
1571 	if (++rs == endring)
1572 		rs = ring;
1573 	text[LINESIZ] = '\r';
1574 	text[LINESIZ + 1] = '\n';
1575 	(void) sendto(s, text, sizeof(text), 0,
1576 		      (struct sockaddr *)&sin, sizeof(sin));
1577 }
1578 
1579 /*
1580  * Return a machine readable date and time, in the form of the
1581  * number of seconds since midnight, Jan 1, 1900.  Since gettimeofday
1582  * returns the number of seconds since midnight, Jan 1, 1970,
1583  * we must add 2208988800 seconds to this figure to make up for
1584  * some seventy years Bell Labs was asleep.
1585  */
1586 
1587 long
1588 machtime()
1589 {
1590 	struct timeval tv;
1591 
1592 	if (gettimeofday(&tv, (struct timezone *)0) < 0) {
1593 		if (debug)
1594 			warnx("unable to get time of day");
1595 		return (0L);
1596 	}
1597 #define	OFFSET ((u_long)25567 * 24*60*60)
1598 	return (htonl((long)(tv.tv_sec + OFFSET)));
1599 #undef OFFSET
1600 }
1601 
1602 /* ARGSUSED */
1603 void
1604 machtime_stream(s, sep)
1605 	int s;
1606 	struct servtab *sep;
1607 {
1608 	long result;
1609 
1610 	result = machtime();
1611 	(void) write(s, (char *) &result, sizeof(result));
1612 }
1613 
1614 /* ARGSUSED */
1615 void
1616 machtime_dg(s, sep)
1617 	int s;
1618 	struct servtab *sep;
1619 {
1620 	long result;
1621 	struct sockaddr_in sin;
1622 	int size;
1623 
1624 	size = sizeof(sin);
1625 	if (recvfrom(s, (char *)&result, sizeof(result), 0,
1626 		     (struct sockaddr *)&sin, &size) < 0)
1627 		return;
1628 
1629 	if (check_loop(&sin, sep))
1630 		return;
1631 
1632 	result = machtime();
1633 	(void) sendto(s, (char *) &result, sizeof(result), 0,
1634 		      (struct sockaddr *)&sin, sizeof(sin));
1635 }
1636 
1637 /* ARGSUSED */
1638 void
1639 daytime_stream(s, sep)		/* Return human-readable time of day */
1640 	int s;
1641 	struct servtab *sep;
1642 {
1643 	char buffer[256];
1644 	time_t clock;
1645 
1646 	clock = time((time_t *) 0);
1647 
1648 	(void) sprintf(buffer, "%.24s\r\n", ctime(&clock));
1649 	(void) write(s, buffer, strlen(buffer));
1650 }
1651 
1652 /* ARGSUSED */
1653 void
1654 daytime_dg(s, sep)		/* Return human-readable time of day */
1655 	int s;
1656 	struct servtab *sep;
1657 {
1658 	char buffer[256];
1659 	time_t clock;
1660 	struct sockaddr_in sin;
1661 	int size;
1662 
1663 	clock = time((time_t *) 0);
1664 
1665 	size = sizeof(sin);
1666 	if (recvfrom(s, buffer, sizeof(buffer), 0,
1667 		     (struct sockaddr *)&sin, &size) < 0)
1668 		return;
1669 
1670 	if (check_loop(&sin, sep))
1671 		return;
1672 
1673 	(void) sprintf(buffer, "%.24s\r\n", ctime(&clock));
1674 	(void) sendto(s, buffer, strlen(buffer), 0,
1675 		      (struct sockaddr *)&sin, sizeof(sin));
1676 }
1677 
1678 /*
1679  * print_service:
1680  *	Dump relevant information to stderr
1681  */
1682 void
1683 print_service(action, sep)
1684 	char *action;
1685 	struct servtab *sep;
1686 {
1687 	fprintf(stderr,
1688 #ifdef LOGIN_CAP
1689 	    "%s: %s proto=%s accept=%d max=%d user=%s group=%s class=%s builtin=%x server=%s\n",
1690 #else
1691 	    "%s: %s proto=%s accept=%d max=%d user=%s group=%s builtin=%x server=%s\n",
1692 #endif
1693 	    action, sep->se_service, sep->se_proto,
1694 	    sep->se_accept, sep->se_maxchild, sep->se_user, sep->se_group,
1695 #ifdef LOGIN_CAP
1696 	    sep->se_class,
1697 #endif
1698 	    (int)sep->se_bi, sep->se_server);
1699 }
1700 
1701 /*
1702  *  Based on TCPMUX.C by Mark K. Lottor November 1988
1703  *  sri-nic::ps:<mkl>tcpmux.c
1704  */
1705 
1706 
1707 static int		/* # of characters upto \r,\n or \0 */
1708 getline(fd, buf, len)
1709 	int fd;
1710 	char *buf;
1711 	int len;
1712 {
1713 	int count = 0, n;
1714 
1715 	do {
1716 		n = read(fd, buf, len-count);
1717 		if (n == 0)
1718 			return (count);
1719 		if (n < 0)
1720 			return (-1);
1721 		while (--n >= 0) {
1722 			if (*buf == '\r' || *buf == '\n' || *buf == '\0')
1723 				return (count);
1724 			count++;
1725 			buf++;
1726 		}
1727 	} while (count < len);
1728 	return (count);
1729 }
1730 
1731 #define MAX_SERV_LEN	(256+2)		/* 2 bytes for \r\n */
1732 
1733 #define strwrite(fd, buf)	(void) write(fd, buf, sizeof(buf)-1)
1734 
1735 struct servtab *
1736 tcpmux(s)
1737 	int s;
1738 {
1739 	struct servtab *sep;
1740 	char service[MAX_SERV_LEN+1];
1741 	int len;
1742 
1743 	/* Get requested service name */
1744 	if ((len = getline(s, service, MAX_SERV_LEN)) < 0) {
1745 		strwrite(s, "-Error reading service name\r\n");
1746 		return (NULL);
1747 	}
1748 	service[len] = '\0';
1749 
1750 	if (debug)
1751 		warnx("tcpmux: someone wants %s", service);
1752 
1753 	/*
1754 	 * Help is a required command, and lists available services,
1755 	 * one per line.
1756 	 */
1757 	if (!strcasecmp(service, "help")) {
1758 		for (sep = servtab; sep; sep = sep->se_next) {
1759 			if (!ISMUX(sep))
1760 				continue;
1761 			(void)write(s,sep->se_service,strlen(sep->se_service));
1762 			strwrite(s, "\r\n");
1763 		}
1764 		return (NULL);
1765 	}
1766 
1767 	/* Try matching a service in inetd.conf with the request */
1768 	for (sep = servtab; sep; sep = sep->se_next) {
1769 		if (!ISMUX(sep))
1770 			continue;
1771 		if (!strcasecmp(service, sep->se_service)) {
1772 			if (ISMUXPLUS(sep)) {
1773 				strwrite(s, "+Go\r\n");
1774 			}
1775 			return (sep);
1776 		}
1777 	}
1778 	strwrite(s, "-Service not available\r\n");
1779 	return (NULL);
1780 }
1781 
1782 #define CPMHSIZE	256
1783 #define CPMHMASK	(CPMHSIZE-1)
1784 #define CHTGRAN		10
1785 #define CHTSIZE		6
1786 
1787 typedef struct CTime {
1788 	unsigned long 	ct_Ticks;
1789 	int		ct_Count;
1790 } CTime;
1791 
1792 typedef struct CHash {
1793 	struct in_addr	ch_Addr;
1794 	time_t		ch_LTime;
1795 	char		*ch_Service;
1796 	CTime		ch_Times[CHTSIZE];
1797 } CHash;
1798 
1799 CHash	CHashAry[CPMHSIZE];
1800 
1801 int
1802 cpmip(sep, ctrl)
1803 	struct servtab *sep;
1804 	int ctrl;
1805 {
1806 	struct sockaddr_in rsin;
1807 	int rsinLen = sizeof(rsin);
1808 	int r = 0;
1809 
1810 	/*
1811 	 * If getpeername() fails, just let it through (if logging is
1812 	 * enabled the condition is caught elsewhere)
1813 	 */
1814 
1815 	if (sep->se_maxcpm > 0 &&
1816 	    getpeername(ctrl, (struct sockaddr *)&rsin, &rsinLen) == 0 ) {
1817 		time_t t = time(NULL);
1818 		int hv = 0xABC3D20F;
1819 		int i;
1820 		int cnt = 0;
1821 		CHash *chBest = NULL;
1822 		unsigned int ticks = t / CHTGRAN;
1823 
1824 		{
1825 			char *p;
1826 			int i;
1827 
1828 			for (i = 0, p = (char *)&rsin.sin_addr;
1829 			    i < sizeof(rsin.sin_addr);
1830 			    ++i, ++p) {
1831 				hv = (hv << 5) ^ (hv >> 23) ^ *p;
1832 			}
1833 			hv = (hv ^ (hv >> 16));
1834 		}
1835 		for (i = 0; i < 5; ++i) {
1836 			CHash *ch = &CHashAry[(hv + i) & CPMHMASK];
1837 
1838 			if (rsin.sin_addr.s_addr == ch->ch_Addr.s_addr &&
1839 			    ch->ch_Service && strcmp(sep->se_service,
1840 			    ch->ch_Service) == 0) {
1841 				chBest = ch;
1842 				break;
1843 			}
1844 			if (chBest == NULL || ch->ch_LTime == 0 ||
1845 			    ch->ch_LTime < chBest->ch_LTime) {
1846 				chBest = ch;
1847 			}
1848 		}
1849 		if (rsin.sin_addr.s_addr != chBest->ch_Addr.s_addr ||
1850 		    chBest->ch_Service == NULL ||
1851 		    strcmp(sep->se_service, chBest->ch_Service) != 0) {
1852 			chBest->ch_Addr = rsin.sin_addr;
1853 			if (chBest->ch_Service)
1854 				free(chBest->ch_Service);
1855 			chBest->ch_Service = strdup(sep->se_service);
1856 			bzero(chBest->ch_Times, sizeof(chBest->ch_Times));
1857 		}
1858 		chBest->ch_LTime = t;
1859 		{
1860 			CTime *ct = &chBest->ch_Times[ticks % CHTSIZE];
1861 			if (ct->ct_Ticks != ticks) {
1862 				ct->ct_Ticks = ticks;
1863 				ct->ct_Count = 0;
1864 			}
1865 			++ct->ct_Count;
1866 		}
1867 		for (i = 0; i < CHTSIZE; ++i) {
1868 			CTime *ct = &chBest->ch_Times[i];
1869 			if (ct->ct_Ticks <= ticks &&
1870 			    ct->ct_Ticks >= ticks - CHTSIZE) {
1871 				cnt += ct->ct_Count;
1872 			}
1873 		}
1874 		if (cnt * (CHTSIZE * CHTGRAN) / 60 > sep->se_maxcpm) {
1875 			r = -1;
1876 			syslog(LOG_ERR,
1877 			    "%s from %s exceeded counts/min limit %d/%d",
1878 			    sep->se_service, inet_ntoa(rsin.sin_addr), cnt,
1879 			    sep->se_maxcpm );
1880 		}
1881 	}
1882 	return(r);
1883 }
1884