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