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