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