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