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