xref: /original-bsd/usr.sbin/inetd/inetd.c (revision 8c7fbc72)
1 /*
2  * Copyright (c) 1983, 1991, 1993 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  */
7 
8 #ifndef lint
9 char copyright[] =
10 "@(#) Copyright (c) 1983, 1991, 1993 Regents of the University of California.\n\
11  All rights reserved.\n";
12 #endif /* not lint */
13 
14 #ifndef lint
15 static char sccsid[] = "@(#)inetd.c	5.32 (Berkeley) 05/16/93";
16 #endif /* not lint */
17 
18 /*
19  * Inetd - Internet super-server
20  *
21  * This program invokes all internet services as needed.  Connection-oriented
22  * services are invoked each time a connection is made, by creating a process.
23  * This process is passed the connection as file descriptor 0 and is expected
24  * to do a getpeername to find out the source host and port.
25  *
26  * Datagram oriented services are invoked when a datagram
27  * arrives; a process is created and passed a pending message
28  * on file descriptor 0.  Datagram servers may either connect
29  * to their peer, freeing up the original socket for inetd
30  * to receive further messages on, or ``take over the socket'',
31  * processing all arriving datagrams and, eventually, timing
32  * out.	 The first type of server is said to be ``multi-threaded'';
33  * the second type of server ``single-threaded''.
34  *
35  * Inetd uses a configuration file which is read at startup
36  * and, possibly, at some later time in response to a hangup signal.
37  * The configuration file is ``free format'' with fields given in the
38  * order shown below.  Continuation lines for an entry must being with
39  * a space or tab.  All fields must be present in each entry.
40  *
41  *	service name			must be in /etc/services or must
42  *					name a tcpmux service
43  *	socket type			stream/dgram/raw/rdm/seqpacket
44  *	protocol			must be in /etc/protocols
45  *	wait/nowait			single-threaded/multi-threaded
46  *	user				user to run daemon as
47  *	server program			full path name
48  *	server program arguments	maximum of MAXARGS (20)
49  *
50  * TCP services without official port numbers are handled with the
51  * RFC1078-based tcpmux internal service. Tcpmux listens on port 1 for
52  * requests. When a connection is made from a foreign host, the service
53  * requested is passed to tcpmux, which looks it up in the servtab list
54  * and returns the proper entry for the service. Tcpmux returns a
55  * negative reply if the service doesn't exist, otherwise the invoked
56  * server is expected to return the positive reply if the service type in
57  * inetd.conf file has the prefix "tcpmux/". If the service type has the
58  * prefix "tcpmux/+", tcpmux will return the positive reply for the
59  * process; this is for compatibility with older server code, and also
60  * allows you to invoke programs that use stdin/stdout without putting any
61  * special server code in them. Services that use tcpmux are "nowait"
62  * because they do not have a well-known port and hence cannot listen
63  * for new requests.
64  *
65  * Comment lines are indicated by a `#' in column 1.
66  */
67 #include <sys/param.h>
68 #include <sys/stat.h>
69 #include <sys/ioctl.h>
70 #include <sys/socket.h>
71 #include <sys/wait.h>
72 #include <sys/time.h>
73 #include <sys/resource.h>
74 
75 #include <netinet/in.h>
76 #include <arpa/inet.h>
77 
78 #include <errno.h>
79 #include <fcntl.h>
80 #include <netdb.h>
81 #include <pwd.h>
82 #include <signal.h>
83 #include <stdio.h>
84 #include <stdlib.h>
85 #include <string.h>
86 #include <syslog.h>
87 #include <unistd.h>
88 
89 #include "pathnames.h"
90 
91 #define	TOOMANY		40		/* don't start more than TOOMANY */
92 #define	CNT_INTVL	60		/* servers in CNT_INTVL sec. */
93 #define	RETRYTIME	(60*10)		/* retry after bind or server fail */
94 
95 #define	SIGBLOCK	(sigmask(SIGCHLD)|sigmask(SIGHUP)|sigmask(SIGALRM))
96 
97 
98 void	config(), reapchild(), retry();
99 
100 int	debug = 0;
101 int	nsock, maxsock;
102 fd_set	allsock;
103 int	options;
104 int	timingout;
105 int	toomany = TOOMANY;
106 struct	servent *sp;
107 
108 struct	servtab {
109 	char	*se_service;		/* name of service */
110 	int	se_socktype;		/* type of socket to use */
111 	char	*se_proto;		/* protocol used */
112 	short	se_wait;		/* single threaded server */
113 	short	se_checked;		/* looked at during merge */
114 	char	*se_user;		/* user name to run as */
115 	struct	biltin *se_bi;		/* if built-in, description */
116 	char	*se_server;		/* server program */
117 #define	MAXARGV 20
118 	char	*se_argv[MAXARGV+1];	/* program arguments */
119 	int	se_fd;			/* open descriptor */
120 	int	se_type;		/* type */
121 	struct	sockaddr_in se_ctrladdr;/* bound address */
122 	int	se_count;		/* number started since se_time */
123 	struct	timeval se_time;	/* start of se_count */
124 	struct	servtab *se_next;
125 } *servtab;
126 
127 #define NORM_TYPE	0
128 #define MUX_TYPE	1
129 #define MUXPLUS_TYPE	2
130 #define ISMUX(sep)	(((sep)->se_type == MUX_TYPE) || \
131 			 ((sep)->se_type == MUXPLUS_TYPE))
132 #define ISMUXPLUS(sep)	((sep)->se_type == MUXPLUS_TYPE)
133 
134 int echo_stream(), discard_stream(), machtime_stream();
135 int daytime_stream(), chargen_stream();
136 int echo_dg(), discard_dg(), machtime_dg(), daytime_dg(), chargen_dg();
137 struct servtab *tcpmux();
138 
139 struct biltin {
140 	char	*bi_service;		/* internally provided service name */
141 	int	bi_socktype;		/* type of socket supported */
142 	short	bi_fork;		/* 1 if should fork before call */
143 	short	bi_wait;		/* 1 if should wait for child */
144 	int	(*bi_fn)();		/* function which performs it */
145 } biltins[] = {
146 	/* Echo received data */
147 	"echo",		SOCK_STREAM,	1, 0,	echo_stream,
148 	"echo",		SOCK_DGRAM,	0, 0,	echo_dg,
149 
150 	/* Internet /dev/null */
151 	"discard",	SOCK_STREAM,	1, 0,	discard_stream,
152 	"discard",	SOCK_DGRAM,	0, 0,	discard_dg,
153 
154 	/* Return 32 bit time since 1970 */
155 	"time",		SOCK_STREAM,	0, 0,	machtime_stream,
156 	"time",		SOCK_DGRAM,	0, 0,	machtime_dg,
157 
158 	/* Return human-readable time */
159 	"daytime",	SOCK_STREAM,	0, 0,	daytime_stream,
160 	"daytime",	SOCK_DGRAM,	0, 0,	daytime_dg,
161 
162 	/* Familiar character generator */
163 	"chargen",	SOCK_STREAM,	1, 0,	chargen_stream,
164 	"chargen",	SOCK_DGRAM,	0, 0,	chargen_dg,
165 
166 	"tcpmux",	SOCK_STREAM,	1, 0,	(int (*)())tcpmux,
167 
168 	NULL
169 };
170 
171 #define NUMINT	(sizeof(intab) / sizeof(struct inent))
172 char	*CONFIG = _PATH_INETDCONF;
173 char	**Argv;
174 char 	*LastArg;
175 
176 main(argc, argv, envp)
177 	int argc;
178 	char *argv[], *envp[];
179 {
180 	register struct servtab *sep;
181 	register struct passwd *pwd;
182 	register int tmpint;
183 	struct sigvec sv;
184 	int ch, pid, dofork;
185 	char buf[50];
186 
187 	Argv = argv;
188 	if (envp == 0 || *envp == 0)
189 		envp = argv;
190 	while (*envp)
191 		envp++;
192 	LastArg = envp[-1] + strlen(envp[-1]);
193 
194 	openlog("inetd", LOG_PID | LOG_NOWAIT, LOG_DAEMON);
195 
196 	while ((ch = getopt(argc, argv, "dR:")) != EOF)
197 		switch(ch) {
198 		case 'd':
199 			debug = 1;
200 			options |= SO_DEBUG;
201 			break;
202 		case 'R': {	/* invocation rate */
203 			char *p;
204 
205 			tmpint = strtol(optarg, &p, 0);
206 			if (tmpint < 1 || *p)
207 				syslog(LOG_ERR,
208 			         "-R %s: bad value for service invocation rate",
209 					optarg);
210 			else
211 				toomany = tmpint;
212 			break;
213 		}
214 		case '?':
215 		default:
216 			syslog(LOG_ERR,
217 				"usage: inetd [-d] [-R rate] [conf-file]");
218 			exit(1);
219 		}
220 	argc -= optind;
221 	argv += optind;
222 
223 	if (argc > 0)
224 		CONFIG = argv[0];
225 	if (debug == 0) {
226 		daemon(0, 0);
227 	}
228 	bzero(&sv, sizeof(sv));
229 	sv.sv_mask = SIGBLOCK;
230 	sv.sv_handler = retry;
231 	sigvec(SIGALRM, &sv, (struct sigvec *)0);
232 	config();
233 	sv.sv_handler = config;
234 	sigvec(SIGHUP, &sv, (struct sigvec *)0);
235 	sv.sv_handler = reapchild;
236 	sigvec(SIGCHLD, &sv, (struct sigvec *)0);
237 
238 	{
239 		/* space for daemons to overwrite environment for ps */
240 #define	DUMMYSIZE	100
241 		char dummy[DUMMYSIZE];
242 
243 		(void)memset(dummy, 'x', sizeof(DUMMYSIZE) - 1);
244 		dummy[DUMMYSIZE - 1] = '\0';
245 		(void)setenv("inetd_dummy", dummy, 1);
246 	}
247 
248 	for (;;) {
249 	    int n, ctrl;
250 	    fd_set readable;
251 
252 	    if (nsock == 0) {
253 		(void) sigblock(SIGBLOCK);
254 		while (nsock == 0)
255 		    sigpause(0L);
256 		(void) sigsetmask(0L);
257 	    }
258 	    readable = allsock;
259 	    if ((n = select(maxsock + 1, &readable, (fd_set *)0,
260 		(fd_set *)0, (struct timeval *)0)) <= 0) {
261 		    if (n < 0 && errno != EINTR)
262 			syslog(LOG_WARNING, "select: %m");
263 		    sleep(1);
264 		    continue;
265 	    }
266 	    for (sep = servtab; n && sep; sep = sep->se_next)
267 	        if (sep->se_fd != -1 && FD_ISSET(sep->se_fd, &readable)) {
268 		    n--;
269 		    if (debug)
270 			    fprintf(stderr, "someone wants %s\n",
271 				sep->se_service);
272 		    if (sep->se_socktype == SOCK_STREAM) {
273 			    ctrl = accept(sep->se_fd, (struct sockaddr *)0,
274 				(int *)0);
275 			    if (debug)
276 				    fprintf(stderr, "accept, ctrl %d\n", ctrl);
277 			    if (ctrl < 0) {
278 				    if (errno != EINTR)
279 					    syslog(LOG_WARNING,
280 						"accept (for %s): %m",
281 						sep->se_service);
282 				    continue;
283 			    }
284 			    /*
285 			     * Call tcpmux to find the real service to exec.
286 			     */
287 			    if (sep->se_bi &&
288 				sep->se_bi->bi_fn == (int (*)()) tcpmux) {
289 				    sep = tcpmux(ctrl);
290 				    if (sep == NULL) {
291 					    close(ctrl);
292 					    continue;
293 				    }
294 			    }
295 		    } else
296 			    ctrl = sep->se_fd;
297 		    (void) sigblock(SIGBLOCK);
298 		    pid = 0;
299 		    dofork = (sep->se_bi == 0 || sep->se_bi->bi_fork);
300 		    if (dofork) {
301 			    if (sep->se_count++ == 0)
302 				(void)gettimeofday(&sep->se_time,
303 				    (struct timezone *)0);
304 			    else if (sep->se_count >= toomany) {
305 				struct timeval now;
306 
307 				(void)gettimeofday(&now, (struct timezone *)0);
308 				if (now.tv_sec - sep->se_time.tv_sec >
309 				    CNT_INTVL) {
310 					sep->se_time = now;
311 					sep->se_count = 1;
312 				} else {
313 					syslog(LOG_ERR,
314 			"%s/%s server failing (looping), service terminated",
315 					    sep->se_service, sep->se_proto);
316 					close_sep(sep);
317 					sigsetmask(0L);
318 					if (!timingout) {
319 						timingout = 1;
320 						alarm(RETRYTIME);
321 					}
322 					continue;
323 				}
324 			    }
325 			    pid = fork();
326 		    }
327 		    if (pid < 0) {
328 			    syslog(LOG_ERR, "fork: %m");
329 			    if (sep->se_socktype == SOCK_STREAM)
330 				    close(ctrl);
331 			    sigsetmask(0L);
332 			    sleep(1);
333 			    continue;
334 		    }
335 		    if (pid && sep->se_wait) {
336 			    sep->se_wait = pid;
337 			    if (sep->se_fd >= 0) {
338 				FD_CLR(sep->se_fd, &allsock);
339 			        nsock--;
340 			    }
341 		    }
342 		    sigsetmask(0L);
343 		    if (pid == 0) {
344 			    if (debug && dofork)
345 				setsid();
346 			    if (dofork) {
347 				if (debug)
348 					fprintf(stderr, "+ Closing from %d\n",
349 						maxsock);
350 				for (tmpint = maxsock; tmpint > 2; tmpint--)
351 					if (tmpint != ctrl)
352 						close(tmpint);
353 			    }
354 			    if (sep->se_bi)
355 				(*sep->se_bi->bi_fn)(ctrl, sep);
356 			    else {
357 				if (debug)
358 					fprintf(stderr, "%d execl %s\n",
359 					    getpid(), sep->se_server);
360 				dup2(ctrl, 0);
361 				close(ctrl);
362 				dup2(0, 1);
363 				dup2(0, 2);
364 				if ((pwd = getpwnam(sep->se_user)) == NULL) {
365 					syslog(LOG_ERR,
366 					    "%s/%s: %s: No such user",
367 						sep->se_service, sep->se_proto,
368 						sep->se_user);
369 					if (sep->se_socktype != SOCK_STREAM)
370 						recv(0, buf, sizeof (buf), 0);
371 					_exit(1);
372 				}
373 				if (pwd->pw_uid) {
374 					if (setgid(pwd->pw_gid) < 0) {
375 						syslog(LOG_ERR,
376 						  "%s: can't set gid %d: %m",
377 						  sep->se_service, pwd->pw_gid);
378 						_exit(1);
379 					}
380 					(void) initgroups(pwd->pw_name,
381 							pwd->pw_gid);
382 					if (setuid(pwd->pw_uid) < 0) {
383 						syslog(LOG_ERR,
384 						  "%s: can't set uid %d: %m",
385 						  sep->se_service, pwd->pw_uid);
386 						_exit(1);
387 					}
388 				}
389 				execv(sep->se_server, sep->se_argv);
390 				if (sep->se_socktype != SOCK_STREAM)
391 					recv(0, buf, sizeof (buf), 0);
392 				syslog(LOG_ERR,
393 				    "cannot execute %s: %m", sep->se_server);
394 				_exit(1);
395 			    }
396 		    }
397 		    if (sep->se_socktype == SOCK_STREAM)
398 			    close(ctrl);
399 		}
400 	}
401 }
402 
403 void
404 reapchild()
405 {
406 	int status;
407 	int pid;
408 	register struct servtab *sep;
409 
410 	for (;;) {
411 		pid = wait3(&status, WNOHANG, (struct rusage *)0);
412 		if (pid <= 0)
413 			break;
414 		if (debug)
415 			fprintf(stderr, "%d reaped, status %#x\n",
416 				pid, status);
417 		for (sep = servtab; sep; sep = sep->se_next)
418 			if (sep->se_wait == pid) {
419 				if (status)
420 					syslog(LOG_WARNING,
421 					    "%s: exit status 0x%x",
422 					    sep->se_server, status);
423 				if (debug)
424 					fprintf(stderr, "restored %s, fd %d\n",
425 					    sep->se_service, sep->se_fd);
426 				FD_SET(sep->se_fd, &allsock);
427 				nsock++;
428 				sep->se_wait = 1;
429 			}
430 	}
431 }
432 
433 void
434 config()
435 {
436 	register struct servtab *sep, *cp, **sepp;
437 	struct servtab *getconfigent(), *enter();
438 	struct passwd *pwd;
439 	long omask;
440 
441 	if (!setconfig()) {
442 		syslog(LOG_ERR, "%s: %m", CONFIG);
443 		return;
444 	}
445 	for (sep = servtab; sep; sep = sep->se_next)
446 		sep->se_checked = 0;
447 	while (cp = getconfigent()) {
448 		if ((pwd = getpwnam(cp->se_user)) == NULL) {
449 			syslog(LOG_ERR,
450 				"%s/%s: No such user '%s', service ignored",
451 				cp->se_service, cp->se_proto, cp->se_user);
452 			continue;
453 		}
454 		for (sep = servtab; sep; sep = sep->se_next)
455 			if (strcmp(sep->se_service, cp->se_service) == 0 &&
456 			    strcmp(sep->se_proto, cp->se_proto) == 0)
457 				break;
458 		if (sep != 0) {
459 			int i;
460 
461 			omask = sigblock(SIGBLOCK);
462 			/*
463 			 * sep->se_wait may be holding the pid of a daemon
464 			 * that we're waiting for.  If so, don't overwrite
465 			 * it unless the config file explicitly says don't
466 			 * wait.
467 			 */
468 			if (cp->se_bi == 0 &&
469 			    (sep->se_wait == 1 || cp->se_wait == 0))
470 				sep->se_wait = cp->se_wait;
471 #define SWAP(a, b) { char *c = a; a = b; b = c; }
472 			if (cp->se_user)
473 				SWAP(sep->se_user, cp->se_user);
474 			if (cp->se_server)
475 				SWAP(sep->se_server, cp->se_server);
476 			for (i = 0; i < MAXARGV; i++)
477 				SWAP(sep->se_argv[i], cp->se_argv[i]);
478 			sigsetmask(omask);
479 			freeconfig(cp);
480 			if (debug)
481 				print_service("REDO", sep);
482 		} else {
483 			sep = enter(cp);
484 			if (debug)
485 				print_service("ADD ", sep);
486 		}
487 		sep->se_checked = 1;
488 		if (ISMUX(sep)) {
489 			sep->se_fd = -1;
490 			continue;
491 		}
492 		sp = getservbyname(sep->se_service, sep->se_proto);
493 		if (sp == 0) {
494 			syslog(LOG_ERR, "%s/%s: unknown service",
495 			    sep->se_service, sep->se_proto);
496 			sep->se_checked = 0;
497 			continue;
498 		}
499 		if (sp->s_port != sep->se_ctrladdr.sin_port) {
500 			sep->se_ctrladdr.sin_port = sp->s_port;
501 			if (sep->se_fd >= 0)
502 				close_sep(sep);
503 		}
504 		if (sep->se_fd == -1)
505 			setup(sep);
506 	}
507 	endconfig();
508 	/*
509 	 * Purge anything not looked at above.
510 	 */
511 	omask = sigblock(SIGBLOCK);
512 	sepp = &servtab;
513 	while (sep = *sepp) {
514 		if (sep->se_checked) {
515 			sepp = &sep->se_next;
516 			continue;
517 		}
518 		*sepp = sep->se_next;
519 		if (sep->se_fd >= 0)
520 			close_sep(sep);
521 		if (debug)
522 			print_service("FREE", sep);
523 		freeconfig(sep);
524 		free((char *)sep);
525 	}
526 	(void) sigsetmask(omask);
527 }
528 
529 void
530 retry()
531 {
532 	register struct servtab *sep;
533 
534 	timingout = 0;
535 	for (sep = servtab; sep; sep = sep->se_next)
536 		if (sep->se_fd == -1)
537 			setup(sep);
538 }
539 
540 setup(sep)
541 	register struct servtab *sep;
542 {
543 	int on = 1;
544 
545 	if ((sep->se_fd = socket(AF_INET, sep->se_socktype, 0)) < 0) {
546 		if (debug)
547 			fprintf(stderr, "socket failed on %s/%s: %s\n",
548 				sep->se_service, sep->se_proto,
549 				strerror(errno));
550 		syslog(LOG_ERR, "%s/%s: socket: %m",
551 		    sep->se_service, sep->se_proto);
552 		return;
553 	}
554 #define	turnon(fd, opt) \
555 setsockopt(fd, SOL_SOCKET, opt, (char *)&on, sizeof (on))
556 	if (strcmp(sep->se_proto, "tcp") == 0 && (options & SO_DEBUG) &&
557 	    turnon(sep->se_fd, SO_DEBUG) < 0)
558 		syslog(LOG_ERR, "setsockopt (SO_DEBUG): %m");
559 	if (turnon(sep->se_fd, SO_REUSEADDR) < 0)
560 		syslog(LOG_ERR, "setsockopt (SO_REUSEADDR): %m");
561 #undef turnon
562 	if (bind(sep->se_fd, (struct sockaddr *)&sep->se_ctrladdr,
563 	    sizeof (sep->se_ctrladdr)) < 0) {
564 		if (debug)
565 			fprintf(stderr, "bind failed on %s/%s: %s\n",
566 				sep->se_service, sep->se_proto,
567 				strerror(errno));
568 		syslog(LOG_ERR, "%s/%s: bind: %m",
569 		    sep->se_service, sep->se_proto);
570 		(void) close(sep->se_fd);
571 		sep->se_fd = -1;
572 		if (!timingout) {
573 			timingout = 1;
574 			alarm(RETRYTIME);
575 		}
576 		return;
577 	}
578 	if (sep->se_socktype == SOCK_STREAM)
579 		listen(sep->se_fd, 10);
580 	FD_SET(sep->se_fd, &allsock);
581 	nsock++;
582 	if (sep->se_fd > maxsock)
583 		maxsock = sep->se_fd;
584 	if (debug) {
585 		fprintf(stderr, "registered %s on %d\n",
586 			sep->se_server, sep->se_fd);
587 	}
588 }
589 
590 /*
591  * Finish with a service and its socket.
592  */
593 close_sep(sep)
594 	register struct servtab *sep;
595 {
596 	if (sep->se_fd >= 0) {
597 		nsock--;
598 		FD_CLR(sep->se_fd, &allsock);
599 		(void) close(sep->se_fd);
600 		sep->se_fd = -1;
601 	}
602 	sep->se_count = 0;
603 	/*
604 	 * Don't keep the pid of this running deamon: when reapchild()
605 	 * reaps this pid, it would erroneously increment nsock.
606 	 */
607 	if (sep->se_wait > 1)
608 		sep->se_wait = 1;
609 }
610 
611 struct servtab *
612 enter(cp)
613 	struct servtab *cp;
614 {
615 	register struct servtab *sep;
616 	long omask;
617 
618 	sep = (struct servtab *)malloc(sizeof (*sep));
619 	if (sep == (struct servtab *)0) {
620 		syslog(LOG_ERR, "Out of memory.");
621 		exit(-1);
622 	}
623 	*sep = *cp;
624 	sep->se_fd = -1;
625 	omask = sigblock(SIGBLOCK);
626 	sep->se_next = servtab;
627 	servtab = sep;
628 	sigsetmask(omask);
629 	return (sep);
630 }
631 
632 FILE	*fconfig = NULL;
633 struct	servtab serv;
634 char	line[256];
635 char	*sskip(), *skip(), *nextline();
636 
637 setconfig()
638 {
639 
640 	if (fconfig != NULL) {
641 		fseek(fconfig, 0L, SEEK_SET);
642 		return (1);
643 	}
644 	fconfig = fopen(CONFIG, "r");
645 	return (fconfig != NULL);
646 }
647 
648 endconfig()
649 {
650 	if (fconfig) {
651 		(void) fclose(fconfig);
652 		fconfig = NULL;
653 	}
654 }
655 
656 struct servtab *
657 getconfigent()
658 {
659 	register struct servtab *sep = &serv;
660 	int argc;
661 	char *cp, *arg, *newstr();
662 	static char TCPMUX_TOKEN[] = "tcpmux/";
663 #define MUX_LEN		(sizeof(TCPMUX_TOKEN)-1)
664 
665 more:
666 	while ((cp = nextline(fconfig)) && (*cp == '#' || *cp == '\0'))
667 		;
668 	if (cp == NULL)
669 		return ((struct servtab *)0);
670 	/*
671 	 * clear the static buffer, since some fields (se_ctrladdr,
672 	 * for example) don't get initialized here.
673 	 */
674 	bzero((caddr_t)sep, sizeof *sep);
675 	arg = skip(&cp);
676 	if (cp == NULL) {
677 		/* got an empty line containing just blanks/tabs. */
678 		goto more;
679 	}
680 	if (strncmp(arg, TCPMUX_TOKEN, MUX_LEN) == 0) {
681 		char *c = arg + MUX_LEN;
682 		if (*c == '+') {
683 			sep->se_type = MUXPLUS_TYPE;
684 			c++;
685 		} else
686 			sep->se_type = MUX_TYPE;
687 		sep->se_service = newstr(c);
688 	} else {
689 		sep->se_service = newstr(arg);
690 		sep->se_type = NORM_TYPE;
691 	}
692 	arg = sskip(&cp);
693 	if (strcmp(arg, "stream") == 0)
694 		sep->se_socktype = SOCK_STREAM;
695 	else if (strcmp(arg, "dgram") == 0)
696 		sep->se_socktype = SOCK_DGRAM;
697 	else if (strcmp(arg, "rdm") == 0)
698 		sep->se_socktype = SOCK_RDM;
699 	else if (strcmp(arg, "seqpacket") == 0)
700 		sep->se_socktype = SOCK_SEQPACKET;
701 	else if (strcmp(arg, "raw") == 0)
702 		sep->se_socktype = SOCK_RAW;
703 	else
704 		sep->se_socktype = -1;
705 	sep->se_proto = newstr(sskip(&cp));
706 	arg = sskip(&cp);
707 	sep->se_wait = strcmp(arg, "wait") == 0;
708 	if (ISMUX(sep)) {
709 		/*
710 		 * Silently enforce "nowait" for TCPMUX services since
711 		 * they don't have an assigned port to listen on.
712 		 */
713 		sep->se_wait = 0;
714 
715 		if (strcmp(sep->se_proto, "tcp")) {
716 			syslog(LOG_ERR,
717 				"%s: bad protocol for tcpmux service %s",
718 				CONFIG, sep->se_service);
719 			goto more;
720 		}
721 		if (sep->se_socktype != SOCK_STREAM) {
722 			syslog(LOG_ERR,
723 				"%s: bad socket type for tcpmux service %s",
724 				CONFIG, sep->se_service);
725 			goto more;
726 		}
727 	}
728 	sep->se_user = newstr(sskip(&cp));
729 	sep->se_server = newstr(sskip(&cp));
730 	if (strcmp(sep->se_server, "internal") == 0) {
731 		register struct biltin *bi;
732 
733 		for (bi = biltins; bi->bi_service; bi++)
734 			if (bi->bi_socktype == sep->se_socktype &&
735 			    strcmp(bi->bi_service, sep->se_service) == 0)
736 				break;
737 		if (bi->bi_service == 0) {
738 			syslog(LOG_ERR, "internal service %s unknown",
739 				sep->se_service);
740 			goto more;
741 		}
742 		sep->se_bi = bi;
743 		sep->se_wait = bi->bi_wait;
744 	} else
745 		sep->se_bi = NULL;
746 	argc = 0;
747 	for (arg = skip(&cp); cp; arg = skip(&cp))
748 		if (argc < MAXARGV)
749 			sep->se_argv[argc++] = newstr(arg);
750 	while (argc <= MAXARGV)
751 		sep->se_argv[argc++] = NULL;
752 	return (sep);
753 }
754 
755 freeconfig(cp)
756 	register struct servtab *cp;
757 {
758 	int i;
759 
760 	if (cp->se_service)
761 		free(cp->se_service);
762 	if (cp->se_proto)
763 		free(cp->se_proto);
764 	if (cp->se_user)
765 		free(cp->se_user);
766 	if (cp->se_server)
767 		free(cp->se_server);
768 	for (i = 0; i < MAXARGV; i++)
769 		if (cp->se_argv[i])
770 			free(cp->se_argv[i]);
771 }
772 
773 
774 /*
775  * Safe skip - if skip returns null, log a syntax error in the
776  * configuration file and exit.
777  */
778 char *
779 sskip(cpp)
780 	char **cpp;
781 {
782 	register char *cp;
783 
784 	cp = skip(cpp);
785 	if (cp == NULL) {
786 		syslog(LOG_ERR, "%s: syntax error", CONFIG);
787 		exit(-1);
788 	}
789 	return (cp);
790 }
791 
792 char *
793 skip(cpp)
794 	char **cpp;
795 {
796 	register char *cp = *cpp;
797 	char *start;
798 
799 again:
800 	while (*cp == ' ' || *cp == '\t')
801 		cp++;
802 	if (*cp == '\0') {
803 		int c;
804 
805 		c = getc(fconfig);
806 		(void) ungetc(c, fconfig);
807 		if (c == ' ' || c == '\t')
808 			if (cp = nextline(fconfig))
809 				goto again;
810 		*cpp = (char *)0;
811 		return ((char *)0);
812 	}
813 	start = cp;
814 	while (*cp && *cp != ' ' && *cp != '\t')
815 		cp++;
816 	if (*cp != '\0')
817 		*cp++ = '\0';
818 	*cpp = cp;
819 	return (start);
820 }
821 
822 char *
823 nextline(fd)
824 	FILE *fd;
825 {
826 	char *cp;
827 
828 	if (fgets(line, sizeof (line), fd) == NULL)
829 		return ((char *)0);
830 	cp = index(line, '\n');
831 	if (cp)
832 		*cp = '\0';
833 	return (line);
834 }
835 
836 char *
837 newstr(cp)
838 	char *cp;
839 {
840 	if (cp = strdup(cp ? cp : ""))
841 		return(cp);
842 	syslog(LOG_ERR, "strdup: %m");
843 	exit(-1);
844 }
845 
846 setproctitle(a, s)
847 	char *a;
848 	int s;
849 {
850 	int size;
851 	register char *cp;
852 	struct sockaddr_in sin;
853 	char buf[80];
854 
855 	cp = Argv[0];
856 	size = sizeof(sin);
857 	if (getpeername(s, (struct sockaddr *)&sin, &size) == 0)
858 		(void) sprintf(buf, "-%s [%s]", a, inet_ntoa(sin.sin_addr));
859 	else
860 		(void) sprintf(buf, "-%s", a);
861 	strncpy(cp, buf, LastArg - cp);
862 	cp += strlen(cp);
863 	while (cp < LastArg)
864 		*cp++ = ' ';
865 }
866 
867 /*
868  * Internet services provided internally by inetd:
869  */
870 #define	BUFSIZE	8192
871 
872 /* ARGSUSED */
873 echo_stream(s, sep)		/* Echo service -- echo data back */
874 	int s;
875 	struct servtab *sep;
876 {
877 	char buffer[BUFSIZE];
878 	int i;
879 
880 	setproctitle(sep->se_service, s);
881 	while ((i = read(s, buffer, sizeof(buffer))) > 0 &&
882 	    write(s, buffer, i) > 0)
883 		;
884 	exit(0);
885 }
886 
887 /* ARGSUSED */
888 echo_dg(s, sep)			/* Echo service -- echo data back */
889 	int s;
890 	struct servtab *sep;
891 {
892 	char buffer[BUFSIZE];
893 	int i, size;
894 	struct sockaddr sa;
895 
896 	size = sizeof(sa);
897 	if ((i = recvfrom(s, buffer, sizeof(buffer), 0, &sa, &size)) < 0)
898 		return;
899 	(void) sendto(s, buffer, i, 0, &sa, sizeof(sa));
900 }
901 
902 /* ARGSUSED */
903 discard_stream(s, sep)		/* Discard service -- ignore data */
904 	int s;
905 	struct servtab *sep;
906 {
907 	int ret;
908 	char buffer[BUFSIZE];
909 
910 	setproctitle(sep->se_service, s);
911 	while (1) {
912 		while ((ret = read(s, buffer, sizeof(buffer))) > 0)
913 			;
914 		if (ret == 0 || errno != EINTR)
915 			break;
916 	}
917 	exit(0);
918 }
919 
920 /* ARGSUSED */
921 discard_dg(s, sep)		/* Discard service -- ignore data */
922 	int s;
923 	struct servtab *sep;
924 {
925 	char buffer[BUFSIZE];
926 
927 	(void) read(s, buffer, sizeof(buffer));
928 }
929 
930 #include <ctype.h>
931 #define LINESIZ 72
932 char ring[128];
933 char *endring;
934 
935 initring()
936 {
937 	register int i;
938 
939 	endring = ring;
940 
941 	for (i = 0; i <= 128; ++i)
942 		if (isprint(i))
943 			*endring++ = i;
944 }
945 
946 /* ARGSUSED */
947 chargen_stream(s, sep)		/* Character generator */
948 	int s;
949 	struct servtab *sep;
950 {
951 	register char *rs;
952 	int len;
953 	char text[LINESIZ+2];
954 
955 	setproctitle(sep->se_service, s);
956 
957 	if (!endring) {
958 		initring();
959 		rs = ring;
960 	}
961 
962 	text[LINESIZ] = '\r';
963 	text[LINESIZ + 1] = '\n';
964 	for (rs = ring;;) {
965 		if ((len = endring - rs) >= LINESIZ)
966 			bcopy(rs, text, LINESIZ);
967 		else {
968 			bcopy(rs, text, len);
969 			bcopy(ring, text + len, LINESIZ - len);
970 		}
971 		if (++rs == endring)
972 			rs = ring;
973 		if (write(s, text, sizeof(text)) != sizeof(text))
974 			break;
975 	}
976 	exit(0);
977 }
978 
979 /* ARGSUSED */
980 chargen_dg(s, sep)		/* Character generator */
981 	int s;
982 	struct servtab *sep;
983 {
984 	struct sockaddr sa;
985 	static char *rs;
986 	int len, size;
987 	char text[LINESIZ+2];
988 
989 	if (endring == 0) {
990 		initring();
991 		rs = ring;
992 	}
993 
994 	size = sizeof(sa);
995 	if (recvfrom(s, text, sizeof(text), 0, &sa, &size) < 0)
996 		return;
997 
998 	if ((len = endring - rs) >= LINESIZ)
999 		bcopy(rs, text, LINESIZ);
1000 	else {
1001 		bcopy(rs, text, len);
1002 		bcopy(ring, text + len, LINESIZ - len);
1003 	}
1004 	if (++rs == endring)
1005 		rs = ring;
1006 	text[LINESIZ] = '\r';
1007 	text[LINESIZ + 1] = '\n';
1008 	(void) sendto(s, text, sizeof(text), 0, &sa, sizeof(sa));
1009 }
1010 
1011 /*
1012  * Return a machine readable date and time, in the form of the
1013  * number of seconds since midnight, Jan 1, 1900.  Since gettimeofday
1014  * returns the number of seconds since midnight, Jan 1, 1970,
1015  * we must add 2208988800 seconds to this figure to make up for
1016  * some seventy years Bell Labs was asleep.
1017  */
1018 
1019 long
1020 machtime()
1021 {
1022 	struct timeval tv;
1023 
1024 	if (gettimeofday(&tv, (struct timezone *)0) < 0) {
1025 		if (debug)
1026 			fprintf(stderr, "Unable to get time of day\n");
1027 		return (0L);
1028 	}
1029 #define	OFFSET ((u_long)25567 * 24*60*60)
1030 	return (htonl((long)(tv.tv_sec + OFFSET)));
1031 #undef OFFSET
1032 }
1033 
1034 /* ARGSUSED */
1035 machtime_stream(s, sep)
1036 	int s;
1037 	struct servtab *sep;
1038 {
1039 	long result;
1040 
1041 	result = machtime();
1042 	(void) write(s, (char *) &result, sizeof(result));
1043 }
1044 
1045 /* ARGSUSED */
1046 machtime_dg(s, sep)
1047 	int s;
1048 	struct servtab *sep;
1049 {
1050 	long result;
1051 	struct sockaddr sa;
1052 	int size;
1053 
1054 	size = sizeof(sa);
1055 	if (recvfrom(s, (char *)&result, sizeof(result), 0, &sa, &size) < 0)
1056 		return;
1057 	result = machtime();
1058 	(void) sendto(s, (char *) &result, sizeof(result), 0, &sa, sizeof(sa));
1059 }
1060 
1061 /* ARGSUSED */
1062 daytime_stream(s, sep)		/* Return human-readable time of day */
1063 	int s;
1064 	struct servtab *sep;
1065 {
1066 	char buffer[256];
1067 	time_t clock;
1068 
1069 	clock = time((time_t *) 0);
1070 
1071 	(void) sprintf(buffer, "%.24s\r\n", ctime(&clock));
1072 	(void) write(s, buffer, strlen(buffer));
1073 }
1074 
1075 /* ARGSUSED */
1076 daytime_dg(s, sep)		/* Return human-readable time of day */
1077 	int s;
1078 	struct servtab *sep;
1079 {
1080 	char buffer[256];
1081 	time_t clock;
1082 	struct sockaddr sa;
1083 	int size;
1084 
1085 	clock = time((time_t *) 0);
1086 
1087 	size = sizeof(sa);
1088 	if (recvfrom(s, buffer, sizeof(buffer), 0, &sa, &size) < 0)
1089 		return;
1090 	(void) sprintf(buffer, "%.24s\r\n", ctime(&clock));
1091 	(void) sendto(s, buffer, strlen(buffer), 0, &sa, sizeof(sa));
1092 }
1093 
1094 /*
1095  * print_service:
1096  *	Dump relevant information to stderr
1097  */
1098 print_service(action, sep)
1099 	char *action;
1100 	struct servtab *sep;
1101 {
1102 	fprintf(stderr,
1103 	    "%s: %s proto=%s, wait=%d, user=%s builtin=%x server=%s\n",
1104 	    action, sep->se_service, sep->se_proto,
1105 	    sep->se_wait, sep->se_user, (int)sep->se_bi, sep->se_server);
1106 }
1107 
1108 /*
1109  *  Based on TCPMUX.C by Mark K. Lottor November 1988
1110  *  sri-nic::ps:<mkl>tcpmux.c
1111  */
1112 
1113 
1114 static int		/* # of characters upto \r,\n or \0 */
1115 getline(fd, buf, len)
1116 	int fd;
1117 	char *buf;
1118 	int len;
1119 {
1120 	int count = 0, n;
1121 
1122 	do {
1123 		n = read(fd, buf, len-count);
1124 		if (n == 0)
1125 			return count;
1126 		if (n < 0)
1127 			return (-1);
1128 		while (--n >= 0) {
1129 			if (*buf == '\r' || *buf == '\n' || *buf == '\0')
1130 				return count;
1131 			count++;
1132 			buf++;
1133 		}
1134 	} while (count < len);
1135 	return (count);
1136 }
1137 
1138 #define MAX_SERV_LEN	(256+2)		/* 2 bytes for \r\n */
1139 
1140 #define strwrite(fd, buf)	(void) write(fd, buf, sizeof(buf)-1)
1141 
1142 struct servtab *
1143 tcpmux(s)
1144 	int s;
1145 {
1146 	register struct servtab *sep;
1147 	char service[MAX_SERV_LEN+1];
1148 	int len;
1149 
1150 	/* Get requested service name */
1151 	if ((len = getline(s, service, MAX_SERV_LEN)) < 0) {
1152 	    strwrite(s, "-Error reading service name\r\n");
1153 	    return(NULL);
1154 	}
1155 	service[len] = '\0';
1156 
1157 	if (debug)
1158 	    fprintf(stderr, "tcpmux: someone wants %s\n", service);
1159 
1160 	/*
1161 	 * Help is a required command, and lists available services,
1162 	 * one per line.
1163 	 */
1164 	if (!strcasecmp(service,"help")) {
1165 	    for (sep = servtab; sep; sep = sep->se_next) {
1166 		if (!ISMUX(sep))
1167 		    continue;
1168 		(void) write(s, sep->se_service, strlen(sep->se_service));
1169 		strwrite(s, "\r\n");
1170 	    }
1171 	    return(NULL);
1172 	}
1173 
1174 	/* Try matching a service in inetd.conf with the request */
1175 	for (sep = servtab; sep; sep = sep->se_next) {
1176 	    if (!ISMUX(sep))
1177 		continue;
1178 	    if (!strcasecmp(service,sep->se_service)) {
1179 		if (ISMUXPLUS(sep)) {
1180 		    strwrite(s, "+Go\r\n");
1181 		}
1182 		return(sep);
1183 	    }
1184 	}
1185 	strwrite(s, "-Service not available\r\n");
1186 	return(NULL);
1187 }
1188