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