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