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