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