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