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