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