xref: /original-bsd/usr.sbin/inetd/inetd.c (revision e8eb2810)
1 /*
2  * Copyright (c) 1983, 1991, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  */
7 
8 #ifndef lint
9 static char copyright[] =
10 "@(#) Copyright (c) 1983, 1991, 1993\n\
11 	The Regents of the University of California.  All rights reserved.\n";
12 #endif /* not lint */
13 
14 #ifndef lint
15 static char sccsid[] = "@(#)inetd.c	8.1 (Berkeley) 06/06/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_family = AF_INET;
501 			sep->se_ctrladdr.sin_port = sp->s_port;
502 			if (sep->se_fd >= 0)
503 				close_sep(sep);
504 		}
505 		if (sep->se_fd == -1)
506 			setup(sep);
507 	}
508 	endconfig();
509 	/*
510 	 * Purge anything not looked at above.
511 	 */
512 	omask = sigblock(SIGBLOCK);
513 	sepp = &servtab;
514 	while (sep = *sepp) {
515 		if (sep->se_checked) {
516 			sepp = &sep->se_next;
517 			continue;
518 		}
519 		*sepp = sep->se_next;
520 		if (sep->se_fd >= 0)
521 			close_sep(sep);
522 		if (debug)
523 			print_service("FREE", sep);
524 		freeconfig(sep);
525 		free((char *)sep);
526 	}
527 	(void) sigsetmask(omask);
528 }
529 
530 void
531 retry()
532 {
533 	register struct servtab *sep;
534 
535 	timingout = 0;
536 	for (sep = servtab; sep; sep = sep->se_next)
537 		if (sep->se_fd == -1)
538 			setup(sep);
539 }
540 
541 setup(sep)
542 	register struct servtab *sep;
543 {
544 	int on = 1;
545 
546 	if ((sep->se_fd = socket(AF_INET, sep->se_socktype, 0)) < 0) {
547 		if (debug)
548 			fprintf(stderr, "socket failed on %s/%s: %s\n",
549 				sep->se_service, sep->se_proto,
550 				strerror(errno));
551 		syslog(LOG_ERR, "%s/%s: socket: %m",
552 		    sep->se_service, sep->se_proto);
553 		return;
554 	}
555 #define	turnon(fd, opt) \
556 setsockopt(fd, SOL_SOCKET, opt, (char *)&on, sizeof (on))
557 	if (strcmp(sep->se_proto, "tcp") == 0 && (options & SO_DEBUG) &&
558 	    turnon(sep->se_fd, SO_DEBUG) < 0)
559 		syslog(LOG_ERR, "setsockopt (SO_DEBUG): %m");
560 	if (turnon(sep->se_fd, SO_REUSEADDR) < 0)
561 		syslog(LOG_ERR, "setsockopt (SO_REUSEADDR): %m");
562 #undef turnon
563 	if (bind(sep->se_fd, (struct sockaddr *)&sep->se_ctrladdr,
564 	    sizeof (sep->se_ctrladdr)) < 0) {
565 		if (debug)
566 			fprintf(stderr, "bind failed on %s/%s: %s\n",
567 				sep->se_service, sep->se_proto,
568 				strerror(errno));
569 		syslog(LOG_ERR, "%s/%s: bind: %m",
570 		    sep->se_service, sep->se_proto);
571 		(void) close(sep->se_fd);
572 		sep->se_fd = -1;
573 		if (!timingout) {
574 			timingout = 1;
575 			alarm(RETRYTIME);
576 		}
577 		return;
578 	}
579 	if (sep->se_socktype == SOCK_STREAM)
580 		listen(sep->se_fd, 10);
581 	FD_SET(sep->se_fd, &allsock);
582 	nsock++;
583 	if (sep->se_fd > maxsock)
584 		maxsock = sep->se_fd;
585 	if (debug) {
586 		fprintf(stderr, "registered %s on %d\n",
587 			sep->se_server, sep->se_fd);
588 	}
589 }
590 
591 /*
592  * Finish with a service and its socket.
593  */
594 close_sep(sep)
595 	register struct servtab *sep;
596 {
597 	if (sep->se_fd >= 0) {
598 		nsock--;
599 		FD_CLR(sep->se_fd, &allsock);
600 		(void) close(sep->se_fd);
601 		sep->se_fd = -1;
602 	}
603 	sep->se_count = 0;
604 	/*
605 	 * Don't keep the pid of this running deamon: when reapchild()
606 	 * reaps this pid, it would erroneously increment nsock.
607 	 */
608 	if (sep->se_wait > 1)
609 		sep->se_wait = 1;
610 }
611 
612 struct servtab *
613 enter(cp)
614 	struct servtab *cp;
615 {
616 	register struct servtab *sep;
617 	long omask;
618 
619 	sep = (struct servtab *)malloc(sizeof (*sep));
620 	if (sep == (struct servtab *)0) {
621 		syslog(LOG_ERR, "Out of memory.");
622 		exit(-1);
623 	}
624 	*sep = *cp;
625 	sep->se_fd = -1;
626 	omask = sigblock(SIGBLOCK);
627 	sep->se_next = servtab;
628 	servtab = sep;
629 	sigsetmask(omask);
630 	return (sep);
631 }
632 
633 FILE	*fconfig = NULL;
634 struct	servtab serv;
635 char	line[256];
636 char	*sskip(), *skip(), *nextline();
637 
638 setconfig()
639 {
640 
641 	if (fconfig != NULL) {
642 		fseek(fconfig, 0L, SEEK_SET);
643 		return (1);
644 	}
645 	fconfig = fopen(CONFIG, "r");
646 	return (fconfig != NULL);
647 }
648 
649 endconfig()
650 {
651 	if (fconfig) {
652 		(void) fclose(fconfig);
653 		fconfig = NULL;
654 	}
655 }
656 
657 struct servtab *
658 getconfigent()
659 {
660 	register struct servtab *sep = &serv;
661 	int argc;
662 	char *cp, *arg, *newstr();
663 	static char TCPMUX_TOKEN[] = "tcpmux/";
664 #define MUX_LEN		(sizeof(TCPMUX_TOKEN)-1)
665 
666 more:
667 	while ((cp = nextline(fconfig)) && (*cp == '#' || *cp == '\0'))
668 		;
669 	if (cp == NULL)
670 		return ((struct servtab *)0);
671 	/*
672 	 * clear the static buffer, since some fields (se_ctrladdr,
673 	 * for example) don't get initialized here.
674 	 */
675 	bzero((caddr_t)sep, sizeof *sep);
676 	arg = skip(&cp);
677 	if (cp == NULL) {
678 		/* got an empty line containing just blanks/tabs. */
679 		goto more;
680 	}
681 	if (strncmp(arg, TCPMUX_TOKEN, MUX_LEN) == 0) {
682 		char *c = arg + MUX_LEN;
683 		if (*c == '+') {
684 			sep->se_type = MUXPLUS_TYPE;
685 			c++;
686 		} else
687 			sep->se_type = MUX_TYPE;
688 		sep->se_service = newstr(c);
689 	} else {
690 		sep->se_service = newstr(arg);
691 		sep->se_type = NORM_TYPE;
692 	}
693 	arg = sskip(&cp);
694 	if (strcmp(arg, "stream") == 0)
695 		sep->se_socktype = SOCK_STREAM;
696 	else if (strcmp(arg, "dgram") == 0)
697 		sep->se_socktype = SOCK_DGRAM;
698 	else if (strcmp(arg, "rdm") == 0)
699 		sep->se_socktype = SOCK_RDM;
700 	else if (strcmp(arg, "seqpacket") == 0)
701 		sep->se_socktype = SOCK_SEQPACKET;
702 	else if (strcmp(arg, "raw") == 0)
703 		sep->se_socktype = SOCK_RAW;
704 	else
705 		sep->se_socktype = -1;
706 	sep->se_proto = newstr(sskip(&cp));
707 	arg = sskip(&cp);
708 	sep->se_wait = strcmp(arg, "wait") == 0;
709 	if (ISMUX(sep)) {
710 		/*
711 		 * Silently enforce "nowait" for TCPMUX services since
712 		 * they don't have an assigned port to listen on.
713 		 */
714 		sep->se_wait = 0;
715 
716 		if (strcmp(sep->se_proto, "tcp")) {
717 			syslog(LOG_ERR,
718 				"%s: bad protocol for tcpmux service %s",
719 				CONFIG, sep->se_service);
720 			goto more;
721 		}
722 		if (sep->se_socktype != SOCK_STREAM) {
723 			syslog(LOG_ERR,
724 				"%s: bad socket type for tcpmux service %s",
725 				CONFIG, sep->se_service);
726 			goto more;
727 		}
728 	}
729 	sep->se_user = newstr(sskip(&cp));
730 	sep->se_server = newstr(sskip(&cp));
731 	if (strcmp(sep->se_server, "internal") == 0) {
732 		register struct biltin *bi;
733 
734 		for (bi = biltins; bi->bi_service; bi++)
735 			if (bi->bi_socktype == sep->se_socktype &&
736 			    strcmp(bi->bi_service, sep->se_service) == 0)
737 				break;
738 		if (bi->bi_service == 0) {
739 			syslog(LOG_ERR, "internal service %s unknown",
740 				sep->se_service);
741 			goto more;
742 		}
743 		sep->se_bi = bi;
744 		sep->se_wait = bi->bi_wait;
745 	} else
746 		sep->se_bi = NULL;
747 	argc = 0;
748 	for (arg = skip(&cp); cp; arg = skip(&cp))
749 		if (argc < MAXARGV)
750 			sep->se_argv[argc++] = newstr(arg);
751 	while (argc <= MAXARGV)
752 		sep->se_argv[argc++] = NULL;
753 	return (sep);
754 }
755 
756 freeconfig(cp)
757 	register struct servtab *cp;
758 {
759 	int i;
760 
761 	if (cp->se_service)
762 		free(cp->se_service);
763 	if (cp->se_proto)
764 		free(cp->se_proto);
765 	if (cp->se_user)
766 		free(cp->se_user);
767 	if (cp->se_server)
768 		free(cp->se_server);
769 	for (i = 0; i < MAXARGV; i++)
770 		if (cp->se_argv[i])
771 			free(cp->se_argv[i]);
772 }
773 
774 
775 /*
776  * Safe skip - if skip returns null, log a syntax error in the
777  * configuration file and exit.
778  */
779 char *
780 sskip(cpp)
781 	char **cpp;
782 {
783 	register char *cp;
784 
785 	cp = skip(cpp);
786 	if (cp == NULL) {
787 		syslog(LOG_ERR, "%s: syntax error", CONFIG);
788 		exit(-1);
789 	}
790 	return (cp);
791 }
792 
793 char *
794 skip(cpp)
795 	char **cpp;
796 {
797 	register char *cp = *cpp;
798 	char *start;
799 
800 again:
801 	while (*cp == ' ' || *cp == '\t')
802 		cp++;
803 	if (*cp == '\0') {
804 		int c;
805 
806 		c = getc(fconfig);
807 		(void) ungetc(c, fconfig);
808 		if (c == ' ' || c == '\t')
809 			if (cp = nextline(fconfig))
810 				goto again;
811 		*cpp = (char *)0;
812 		return ((char *)0);
813 	}
814 	start = cp;
815 	while (*cp && *cp != ' ' && *cp != '\t')
816 		cp++;
817 	if (*cp != '\0')
818 		*cp++ = '\0';
819 	*cpp = cp;
820 	return (start);
821 }
822 
823 char *
824 nextline(fd)
825 	FILE *fd;
826 {
827 	char *cp;
828 
829 	if (fgets(line, sizeof (line), fd) == NULL)
830 		return ((char *)0);
831 	cp = index(line, '\n');
832 	if (cp)
833 		*cp = '\0';
834 	return (line);
835 }
836 
837 char *
838 newstr(cp)
839 	char *cp;
840 {
841 	if (cp = strdup(cp ? cp : ""))
842 		return(cp);
843 	syslog(LOG_ERR, "strdup: %m");
844 	exit(-1);
845 }
846 
847 setproctitle(a, s)
848 	char *a;
849 	int s;
850 {
851 	int size;
852 	register char *cp;
853 	struct sockaddr_in sin;
854 	char buf[80];
855 
856 	cp = Argv[0];
857 	size = sizeof(sin);
858 	if (getpeername(s, (struct sockaddr *)&sin, &size) == 0)
859 		(void) sprintf(buf, "-%s [%s]", a, inet_ntoa(sin.sin_addr));
860 	else
861 		(void) sprintf(buf, "-%s", a);
862 	strncpy(cp, buf, LastArg - cp);
863 	cp += strlen(cp);
864 	while (cp < LastArg)
865 		*cp++ = ' ';
866 }
867 
868 /*
869  * Internet services provided internally by inetd:
870  */
871 #define	BUFSIZE	8192
872 
873 /* ARGSUSED */
874 echo_stream(s, sep)		/* Echo service -- echo data back */
875 	int s;
876 	struct servtab *sep;
877 {
878 	char buffer[BUFSIZE];
879 	int i;
880 
881 	setproctitle(sep->se_service, s);
882 	while ((i = read(s, buffer, sizeof(buffer))) > 0 &&
883 	    write(s, buffer, i) > 0)
884 		;
885 	exit(0);
886 }
887 
888 /* ARGSUSED */
889 echo_dg(s, sep)			/* Echo service -- echo data back */
890 	int s;
891 	struct servtab *sep;
892 {
893 	char buffer[BUFSIZE];
894 	int i, size;
895 	struct sockaddr sa;
896 
897 	size = sizeof(sa);
898 	if ((i = recvfrom(s, buffer, sizeof(buffer), 0, &sa, &size)) < 0)
899 		return;
900 	(void) sendto(s, buffer, i, 0, &sa, sizeof(sa));
901 }
902 
903 /* ARGSUSED */
904 discard_stream(s, sep)		/* Discard service -- ignore data */
905 	int s;
906 	struct servtab *sep;
907 {
908 	int ret;
909 	char buffer[BUFSIZE];
910 
911 	setproctitle(sep->se_service, s);
912 	while (1) {
913 		while ((ret = read(s, buffer, sizeof(buffer))) > 0)
914 			;
915 		if (ret == 0 || errno != EINTR)
916 			break;
917 	}
918 	exit(0);
919 }
920 
921 /* ARGSUSED */
922 discard_dg(s, sep)		/* Discard service -- ignore data */
923 	int s;
924 	struct servtab *sep;
925 {
926 	char buffer[BUFSIZE];
927 
928 	(void) read(s, buffer, sizeof(buffer));
929 }
930 
931 #include <ctype.h>
932 #define LINESIZ 72
933 char ring[128];
934 char *endring;
935 
936 initring()
937 {
938 	register int i;
939 
940 	endring = ring;
941 
942 	for (i = 0; i <= 128; ++i)
943 		if (isprint(i))
944 			*endring++ = i;
945 }
946 
947 /* ARGSUSED */
948 chargen_stream(s, sep)		/* Character generator */
949 	int s;
950 	struct servtab *sep;
951 {
952 	register char *rs;
953 	int len;
954 	char text[LINESIZ+2];
955 
956 	setproctitle(sep->se_service, s);
957 
958 	if (!endring) {
959 		initring();
960 		rs = ring;
961 	}
962 
963 	text[LINESIZ] = '\r';
964 	text[LINESIZ + 1] = '\n';
965 	for (rs = ring;;) {
966 		if ((len = endring - rs) >= LINESIZ)
967 			bcopy(rs, text, LINESIZ);
968 		else {
969 			bcopy(rs, text, len);
970 			bcopy(ring, text + len, LINESIZ - len);
971 		}
972 		if (++rs == endring)
973 			rs = ring;
974 		if (write(s, text, sizeof(text)) != sizeof(text))
975 			break;
976 	}
977 	exit(0);
978 }
979 
980 /* ARGSUSED */
981 chargen_dg(s, sep)		/* Character generator */
982 	int s;
983 	struct servtab *sep;
984 {
985 	struct sockaddr sa;
986 	static char *rs;
987 	int len, size;
988 	char text[LINESIZ+2];
989 
990 	if (endring == 0) {
991 		initring();
992 		rs = ring;
993 	}
994 
995 	size = sizeof(sa);
996 	if (recvfrom(s, text, sizeof(text), 0, &sa, &size) < 0)
997 		return;
998 
999 	if ((len = endring - rs) >= LINESIZ)
1000 		bcopy(rs, text, LINESIZ);
1001 	else {
1002 		bcopy(rs, text, len);
1003 		bcopy(ring, text + len, LINESIZ - len);
1004 	}
1005 	if (++rs == endring)
1006 		rs = ring;
1007 	text[LINESIZ] = '\r';
1008 	text[LINESIZ + 1] = '\n';
1009 	(void) sendto(s, text, sizeof(text), 0, &sa, sizeof(sa));
1010 }
1011 
1012 /*
1013  * Return a machine readable date and time, in the form of the
1014  * number of seconds since midnight, Jan 1, 1900.  Since gettimeofday
1015  * returns the number of seconds since midnight, Jan 1, 1970,
1016  * we must add 2208988800 seconds to this figure to make up for
1017  * some seventy years Bell Labs was asleep.
1018  */
1019 
1020 long
1021 machtime()
1022 {
1023 	struct timeval tv;
1024 
1025 	if (gettimeofday(&tv, (struct timezone *)0) < 0) {
1026 		if (debug)
1027 			fprintf(stderr, "Unable to get time of day\n");
1028 		return (0L);
1029 	}
1030 #define	OFFSET ((u_long)25567 * 24*60*60)
1031 	return (htonl((long)(tv.tv_sec + OFFSET)));
1032 #undef OFFSET
1033 }
1034 
1035 /* ARGSUSED */
1036 machtime_stream(s, sep)
1037 	int s;
1038 	struct servtab *sep;
1039 {
1040 	long result;
1041 
1042 	result = machtime();
1043 	(void) write(s, (char *) &result, sizeof(result));
1044 }
1045 
1046 /* ARGSUSED */
1047 machtime_dg(s, sep)
1048 	int s;
1049 	struct servtab *sep;
1050 {
1051 	long result;
1052 	struct sockaddr sa;
1053 	int size;
1054 
1055 	size = sizeof(sa);
1056 	if (recvfrom(s, (char *)&result, sizeof(result), 0, &sa, &size) < 0)
1057 		return;
1058 	result = machtime();
1059 	(void) sendto(s, (char *) &result, sizeof(result), 0, &sa, sizeof(sa));
1060 }
1061 
1062 /* ARGSUSED */
1063 daytime_stream(s, sep)		/* Return human-readable time of day */
1064 	int s;
1065 	struct servtab *sep;
1066 {
1067 	char buffer[256];
1068 	time_t clock;
1069 
1070 	clock = time((time_t *) 0);
1071 
1072 	(void) sprintf(buffer, "%.24s\r\n", ctime(&clock));
1073 	(void) write(s, buffer, strlen(buffer));
1074 }
1075 
1076 /* ARGSUSED */
1077 daytime_dg(s, sep)		/* Return human-readable time of day */
1078 	int s;
1079 	struct servtab *sep;
1080 {
1081 	char buffer[256];
1082 	time_t clock;
1083 	struct sockaddr sa;
1084 	int size;
1085 
1086 	clock = time((time_t *) 0);
1087 
1088 	size = sizeof(sa);
1089 	if (recvfrom(s, buffer, sizeof(buffer), 0, &sa, &size) < 0)
1090 		return;
1091 	(void) sprintf(buffer, "%.24s\r\n", ctime(&clock));
1092 	(void) sendto(s, buffer, strlen(buffer), 0, &sa, sizeof(sa));
1093 }
1094 
1095 /*
1096  * print_service:
1097  *	Dump relevant information to stderr
1098  */
1099 print_service(action, sep)
1100 	char *action;
1101 	struct servtab *sep;
1102 {
1103 	fprintf(stderr,
1104 	    "%s: %s proto=%s, wait=%d, user=%s builtin=%x server=%s\n",
1105 	    action, sep->se_service, sep->se_proto,
1106 	    sep->se_wait, sep->se_user, (int)sep->se_bi, sep->se_server);
1107 }
1108 
1109 /*
1110  *  Based on TCPMUX.C by Mark K. Lottor November 1988
1111  *  sri-nic::ps:<mkl>tcpmux.c
1112  */
1113 
1114 
1115 static int		/* # of characters upto \r,\n or \0 */
1116 getline(fd, buf, len)
1117 	int fd;
1118 	char *buf;
1119 	int len;
1120 {
1121 	int count = 0, n;
1122 
1123 	do {
1124 		n = read(fd, buf, len-count);
1125 		if (n == 0)
1126 			return count;
1127 		if (n < 0)
1128 			return (-1);
1129 		while (--n >= 0) {
1130 			if (*buf == '\r' || *buf == '\n' || *buf == '\0')
1131 				return count;
1132 			count++;
1133 			buf++;
1134 		}
1135 	} while (count < len);
1136 	return (count);
1137 }
1138 
1139 #define MAX_SERV_LEN	(256+2)		/* 2 bytes for \r\n */
1140 
1141 #define strwrite(fd, buf)	(void) write(fd, buf, sizeof(buf)-1)
1142 
1143 struct servtab *
1144 tcpmux(s)
1145 	int s;
1146 {
1147 	register struct servtab *sep;
1148 	char service[MAX_SERV_LEN+1];
1149 	int len;
1150 
1151 	/* Get requested service name */
1152 	if ((len = getline(s, service, MAX_SERV_LEN)) < 0) {
1153 	    strwrite(s, "-Error reading service name\r\n");
1154 	    return(NULL);
1155 	}
1156 	service[len] = '\0';
1157 
1158 	if (debug)
1159 	    fprintf(stderr, "tcpmux: someone wants %s\n", service);
1160 
1161 	/*
1162 	 * Help is a required command, and lists available services,
1163 	 * one per line.
1164 	 */
1165 	if (!strcasecmp(service,"help")) {
1166 	    for (sep = servtab; sep; sep = sep->se_next) {
1167 		if (!ISMUX(sep))
1168 		    continue;
1169 		(void) write(s, sep->se_service, strlen(sep->se_service));
1170 		strwrite(s, "\r\n");
1171 	    }
1172 	    return(NULL);
1173 	}
1174 
1175 	/* Try matching a service in inetd.conf with the request */
1176 	for (sep = servtab; sep; sep = sep->se_next) {
1177 	    if (!ISMUX(sep))
1178 		continue;
1179 	    if (!strcasecmp(service,sep->se_service)) {
1180 		if (ISMUXPLUS(sep)) {
1181 		    strwrite(s, "+Go\r\n");
1182 		}
1183 		return(sep);
1184 	    }
1185 	}
1186 	strwrite(s, "-Service not available\r\n");
1187 	return(NULL);
1188 }
1189