xref: /original-bsd/usr.sbin/inetd/inetd.c (revision e58c8952)
1 /*
2  * Copyright (c) 1983, 1991, 1993, 1994
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, 1994\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.4 (Berkeley) 04/13/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_wait && 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_wait &&
352 				sep->se_socktype == SOCK_STREAM)
353 				    close(ctrl);
354 			    sigsetmask(0L);
355 			    sleep(1);
356 			    continue;
357 		    }
358 		    if (pid && sep->se_wait) {
359 			    sep->se_wait = pid;
360 			    if (sep->se_fd >= 0) {
361 				FD_CLR(sep->se_fd, &allsock);
362 			        nsock--;
363 			    }
364 		    }
365 		    sigsetmask(0L);
366 		    if (pid == 0) {
367 			    if (debug && dofork)
368 				setsid();
369 			    if (dofork) {
370 				if (debug)
371 					fprintf(stderr, "+ Closing from %d\n",
372 						maxsock);
373 				for (tmpint = maxsock; tmpint > 2; tmpint--)
374 					if (tmpint != ctrl)
375 						close(tmpint);
376 			    }
377 			    if (sep->se_bi)
378 				(*sep->se_bi->bi_fn)(ctrl, sep);
379 			    else {
380 				if (debug)
381 					fprintf(stderr, "%d execl %s\n",
382 					    getpid(), sep->se_server);
383 				dup2(ctrl, 0);
384 				close(ctrl);
385 				dup2(0, 1);
386 				dup2(0, 2);
387 				if ((pwd = getpwnam(sep->se_user)) == NULL) {
388 					syslog(LOG_ERR,
389 					    "%s/%s: %s: No such user",
390 						sep->se_service, sep->se_proto,
391 						sep->se_user);
392 					if (sep->se_socktype != SOCK_STREAM)
393 						recv(0, buf, sizeof (buf), 0);
394 					_exit(1);
395 				}
396 				if (pwd->pw_uid) {
397 					if (setgid(pwd->pw_gid) < 0) {
398 						syslog(LOG_ERR,
399 						  "%s: can't set gid %d: %m",
400 						  sep->se_service, pwd->pw_gid);
401 						_exit(1);
402 					}
403 					(void) initgroups(pwd->pw_name,
404 							pwd->pw_gid);
405 					if (setuid(pwd->pw_uid) < 0) {
406 						syslog(LOG_ERR,
407 						  "%s: can't set uid %d: %m",
408 						  sep->se_service, pwd->pw_uid);
409 						_exit(1);
410 					}
411 				}
412 				execv(sep->se_server, sep->se_argv);
413 				if (sep->se_socktype != SOCK_STREAM)
414 					recv(0, buf, sizeof (buf), 0);
415 				syslog(LOG_ERR,
416 				    "cannot execute %s: %m", sep->se_server);
417 				_exit(1);
418 			    }
419 		    }
420 		    if (!sep->se_wait && sep->se_socktype == SOCK_STREAM)
421 			    close(ctrl);
422 		}
423 	}
424 }
425 
426 void
427 reapchild(signo)
428 	int signo;
429 {
430 	int status;
431 	pid_t pid;
432 	struct servtab *sep;
433 
434 	for (;;) {
435 		pid = wait3(&status, WNOHANG, (struct rusage *)0);
436 		if (pid <= 0)
437 			break;
438 		if (debug)
439 			fprintf(stderr, "%d reaped, status %#x\n",
440 				pid, status);
441 		for (sep = servtab; sep; sep = sep->se_next)
442 			if (sep->se_wait == pid) {
443 				if (status)
444 					syslog(LOG_WARNING,
445 					    "%s: exit status 0x%x",
446 					    sep->se_server, status);
447 				if (debug)
448 					fprintf(stderr, "restored %s, fd %d\n",
449 					    sep->se_service, sep->se_fd);
450 				FD_SET(sep->se_fd, &allsock);
451 				nsock++;
452 				sep->se_wait = 1;
453 			}
454 	}
455 }
456 
457 void
458 config(signo)
459 	int signo;
460 {
461 	struct servtab *sep, *cp, **sepp;
462 	struct passwd *pwd;
463 	long omask;
464 
465 	if (!setconfig()) {
466 		syslog(LOG_ERR, "%s: %m", CONFIG);
467 		return;
468 	}
469 	for (sep = servtab; sep; sep = sep->se_next)
470 		sep->se_checked = 0;
471 	while (cp = getconfigent()) {
472 		if ((pwd = getpwnam(cp->se_user)) == NULL) {
473 			syslog(LOG_ERR,
474 				"%s/%s: No such user '%s', service ignored",
475 				cp->se_service, cp->se_proto, cp->se_user);
476 			continue;
477 		}
478 		for (sep = servtab; sep; sep = sep->se_next)
479 			if (strcmp(sep->se_service, cp->se_service) == 0 &&
480 			    strcmp(sep->se_proto, cp->se_proto) == 0)
481 				break;
482 		if (sep != 0) {
483 			int i;
484 
485 			omask = sigblock(SIGBLOCK);
486 			/*
487 			 * sep->se_wait may be holding the pid of a daemon
488 			 * that we're waiting for.  If so, don't overwrite
489 			 * it unless the config file explicitly says don't
490 			 * wait.
491 			 */
492 			if (cp->se_bi == 0 &&
493 			    (sep->se_wait == 1 || cp->se_wait == 0))
494 				sep->se_wait = cp->se_wait;
495 #define SWAP(a, b) { char *c = a; a = b; b = c; }
496 			if (cp->se_user)
497 				SWAP(sep->se_user, cp->se_user);
498 			if (cp->se_server)
499 				SWAP(sep->se_server, cp->se_server);
500 			for (i = 0; i < MAXARGV; i++)
501 				SWAP(sep->se_argv[i], cp->se_argv[i]);
502 			sigsetmask(omask);
503 			freeconfig(cp);
504 			if (debug)
505 				print_service("REDO", sep);
506 		} else {
507 			sep = enter(cp);
508 			if (debug)
509 				print_service("ADD ", sep);
510 		}
511 		sep->se_checked = 1;
512 		if (ISMUX(sep)) {
513 			sep->se_fd = -1;
514 			continue;
515 		}
516 		sp = getservbyname(sep->se_service, sep->se_proto);
517 		if (sp == 0) {
518 			syslog(LOG_ERR, "%s/%s: unknown service",
519 			    sep->se_service, sep->se_proto);
520 			sep->se_checked = 0;
521 			continue;
522 		}
523 		if (sp->s_port != sep->se_ctrladdr.sin_port) {
524 			sep->se_ctrladdr.sin_family = AF_INET;
525 			sep->se_ctrladdr.sin_port = sp->s_port;
526 			if (sep->se_fd >= 0)
527 				close_sep(sep);
528 		}
529 		if (sep->se_fd == -1)
530 			setup(sep);
531 	}
532 	endconfig();
533 	/*
534 	 * Purge anything not looked at above.
535 	 */
536 	omask = sigblock(SIGBLOCK);
537 	sepp = &servtab;
538 	while (sep = *sepp) {
539 		if (sep->se_checked) {
540 			sepp = &sep->se_next;
541 			continue;
542 		}
543 		*sepp = sep->se_next;
544 		if (sep->se_fd >= 0)
545 			close_sep(sep);
546 		if (debug)
547 			print_service("FREE", sep);
548 		freeconfig(sep);
549 		free((char *)sep);
550 	}
551 	(void) sigsetmask(omask);
552 }
553 
554 void
555 retry(signo)
556 	int signo;
557 {
558 	struct servtab *sep;
559 
560 	timingout = 0;
561 	for (sep = servtab; sep; sep = sep->se_next)
562 		if (sep->se_fd == -1)
563 			setup(sep);
564 }
565 
566 void
567 setup(sep)
568 	struct servtab *sep;
569 {
570 	int on = 1;
571 
572 	if ((sep->se_fd = socket(AF_INET, sep->se_socktype, 0)) < 0) {
573 		if (debug)
574 			fprintf(stderr, "socket failed on %s/%s: %s\n",
575 				sep->se_service, sep->se_proto,
576 				strerror(errno));
577 		syslog(LOG_ERR, "%s/%s: socket: %m",
578 		    sep->se_service, sep->se_proto);
579 		return;
580 	}
581 #define	turnon(fd, opt) \
582 setsockopt(fd, SOL_SOCKET, opt, (char *)&on, sizeof (on))
583 	if (strcmp(sep->se_proto, "tcp") == 0 && (options & SO_DEBUG) &&
584 	    turnon(sep->se_fd, SO_DEBUG) < 0)
585 		syslog(LOG_ERR, "setsockopt (SO_DEBUG): %m");
586 	if (turnon(sep->se_fd, SO_REUSEADDR) < 0)
587 		syslog(LOG_ERR, "setsockopt (SO_REUSEADDR): %m");
588 #undef turnon
589 	if (bind(sep->se_fd, (struct sockaddr *)&sep->se_ctrladdr,
590 	    sizeof (sep->se_ctrladdr)) < 0) {
591 		if (debug)
592 			fprintf(stderr, "bind failed on %s/%s: %s\n",
593 				sep->se_service, sep->se_proto,
594 				strerror(errno));
595 		syslog(LOG_ERR, "%s/%s: bind: %m",
596 		    sep->se_service, sep->se_proto);
597 		(void) close(sep->se_fd);
598 		sep->se_fd = -1;
599 		if (!timingout) {
600 			timingout = 1;
601 			alarm(RETRYTIME);
602 		}
603 		return;
604 	}
605 	if (sep->se_socktype == SOCK_STREAM)
606 		listen(sep->se_fd, 10);
607 	FD_SET(sep->se_fd, &allsock);
608 	nsock++;
609 	if (sep->se_fd > maxsock)
610 		maxsock = sep->se_fd;
611 	if (debug) {
612 		fprintf(stderr, "registered %s on %d\n",
613 			sep->se_server, sep->se_fd);
614 	}
615 }
616 
617 /*
618  * Finish with a service and its socket.
619  */
620 void
621 close_sep(sep)
622 	struct servtab *sep;
623 {
624 	if (sep->se_fd >= 0) {
625 		nsock--;
626 		FD_CLR(sep->se_fd, &allsock);
627 		(void) close(sep->se_fd);
628 		sep->se_fd = -1;
629 	}
630 	sep->se_count = 0;
631 	/*
632 	 * Don't keep the pid of this running deamon: when reapchild()
633 	 * reaps this pid, it would erroneously increment nsock.
634 	 */
635 	if (sep->se_wait > 1)
636 		sep->se_wait = 1;
637 }
638 
639 struct servtab *
640 enter(cp)
641 	struct servtab *cp;
642 {
643 	struct servtab *sep;
644 	long omask;
645 
646 	sep = (struct servtab *)malloc(sizeof (*sep));
647 	if (sep == (struct servtab *)0) {
648 		syslog(LOG_ERR, "Out of memory.");
649 		exit(-1);
650 	}
651 	*sep = *cp;
652 	sep->se_fd = -1;
653 	omask = sigblock(SIGBLOCK);
654 	sep->se_next = servtab;
655 	servtab = sep;
656 	sigsetmask(omask);
657 	return (sep);
658 }
659 
660 FILE	*fconfig = NULL;
661 struct	servtab serv;
662 char	line[LINE_MAX];
663 
664 int
665 setconfig()
666 {
667 
668 	if (fconfig != NULL) {
669 		fseek(fconfig, 0L, SEEK_SET);
670 		return (1);
671 	}
672 	fconfig = fopen(CONFIG, "r");
673 	return (fconfig != NULL);
674 }
675 
676 void
677 endconfig()
678 {
679 	if (fconfig) {
680 		(void) fclose(fconfig);
681 		fconfig = NULL;
682 	}
683 }
684 
685 struct servtab *
686 getconfigent()
687 {
688 	struct servtab *sep = &serv;
689 	int argc;
690 	char *cp, *arg;
691 	static char TCPMUX_TOKEN[] = "tcpmux/";
692 #define MUX_LEN		(sizeof(TCPMUX_TOKEN)-1)
693 
694 more:
695 	while ((cp = nextline(fconfig)) && (*cp == '#' || *cp == '\0'))
696 		;
697 	if (cp == NULL)
698 		return ((struct servtab *)0);
699 	/*
700 	 * clear the static buffer, since some fields (se_ctrladdr,
701 	 * for example) don't get initialized here.
702 	 */
703 	memset((caddr_t)sep, 0, sizeof *sep);
704 	arg = skip(&cp);
705 	if (cp == NULL) {
706 		/* got an empty line containing just blanks/tabs. */
707 		goto more;
708 	}
709 	if (strncmp(arg, TCPMUX_TOKEN, MUX_LEN) == 0) {
710 		char *c = arg + MUX_LEN;
711 		if (*c == '+') {
712 			sep->se_type = MUXPLUS_TYPE;
713 			c++;
714 		} else
715 			sep->se_type = MUX_TYPE;
716 		sep->se_service = newstr(c);
717 	} else {
718 		sep->se_service = newstr(arg);
719 		sep->se_type = NORM_TYPE;
720 	}
721 	arg = sskip(&cp);
722 	if (strcmp(arg, "stream") == 0)
723 		sep->se_socktype = SOCK_STREAM;
724 	else if (strcmp(arg, "dgram") == 0)
725 		sep->se_socktype = SOCK_DGRAM;
726 	else if (strcmp(arg, "rdm") == 0)
727 		sep->se_socktype = SOCK_RDM;
728 	else if (strcmp(arg, "seqpacket") == 0)
729 		sep->se_socktype = SOCK_SEQPACKET;
730 	else if (strcmp(arg, "raw") == 0)
731 		sep->se_socktype = SOCK_RAW;
732 	else
733 		sep->se_socktype = -1;
734 	sep->se_proto = newstr(sskip(&cp));
735 	arg = sskip(&cp);
736 	sep->se_wait = strcmp(arg, "wait") == 0;
737 	if (ISMUX(sep)) {
738 		/*
739 		 * Silently enforce "nowait" for TCPMUX services since
740 		 * they don't have an assigned port to listen on.
741 		 */
742 		sep->se_wait = 0;
743 
744 		if (strcmp(sep->se_proto, "tcp")) {
745 			syslog(LOG_ERR,
746 				"%s: bad protocol for tcpmux service %s",
747 				CONFIG, sep->se_service);
748 			goto more;
749 		}
750 		if (sep->se_socktype != SOCK_STREAM) {
751 			syslog(LOG_ERR,
752 				"%s: bad socket type for tcpmux service %s",
753 				CONFIG, sep->se_service);
754 			goto more;
755 		}
756 	}
757 	sep->se_user = newstr(sskip(&cp));
758 	sep->se_server = newstr(sskip(&cp));
759 	if (strcmp(sep->se_server, "internal") == 0) {
760 		struct biltin *bi;
761 
762 		for (bi = biltins; bi->bi_service; bi++)
763 			if (bi->bi_socktype == sep->se_socktype &&
764 			    strcmp(bi->bi_service, sep->se_service) == 0)
765 				break;
766 		if (bi->bi_service == 0) {
767 			syslog(LOG_ERR, "internal service %s unknown",
768 				sep->se_service);
769 			goto more;
770 		}
771 		sep->se_bi = bi;
772 		sep->se_wait = bi->bi_wait;
773 	} else
774 		sep->se_bi = NULL;
775 	argc = 0;
776 	for (arg = skip(&cp); cp; arg = skip(&cp))
777 		if (argc < MAXARGV)
778 			sep->se_argv[argc++] = newstr(arg);
779 	while (argc <= MAXARGV)
780 		sep->se_argv[argc++] = NULL;
781 	return (sep);
782 }
783 
784 void
785 freeconfig(cp)
786 	struct servtab *cp;
787 {
788 	int i;
789 
790 	if (cp->se_service)
791 		free(cp->se_service);
792 	if (cp->se_proto)
793 		free(cp->se_proto);
794 	if (cp->se_user)
795 		free(cp->se_user);
796 	if (cp->se_server)
797 		free(cp->se_server);
798 	for (i = 0; i < MAXARGV; i++)
799 		if (cp->se_argv[i])
800 			free(cp->se_argv[i]);
801 }
802 
803 
804 /*
805  * Safe skip - if skip returns null, log a syntax error in the
806  * configuration file and exit.
807  */
808 char *
809 sskip(cpp)
810 	char **cpp;
811 {
812 	char *cp;
813 
814 	cp = skip(cpp);
815 	if (cp == NULL) {
816 		syslog(LOG_ERR, "%s: syntax error", CONFIG);
817 		exit(-1);
818 	}
819 	return (cp);
820 }
821 
822 char *
823 skip(cpp)
824 	char **cpp;
825 {
826 	char *cp = *cpp;
827 	char *start;
828 
829 again:
830 	while (*cp == ' ' || *cp == '\t')
831 		cp++;
832 	if (*cp == '\0') {
833 		int c;
834 
835 		c = getc(fconfig);
836 		(void) ungetc(c, fconfig);
837 		if (c == ' ' || c == '\t')
838 			if (cp = nextline(fconfig))
839 				goto again;
840 		*cpp = (char *)0;
841 		return ((char *)0);
842 	}
843 	start = cp;
844 	while (*cp && *cp != ' ' && *cp != '\t')
845 		cp++;
846 	if (*cp != '\0')
847 		*cp++ = '\0';
848 	*cpp = cp;
849 	return (start);
850 }
851 
852 char *
853 nextline(fd)
854 	FILE *fd;
855 {
856 	char *cp;
857 
858 	if (fgets(line, sizeof (line), fd) == NULL)
859 		return ((char *)0);
860 	cp = strchr(line, '\n');
861 	if (cp)
862 		*cp = '\0';
863 	return (line);
864 }
865 
866 char *
867 newstr(cp)
868 	char *cp;
869 {
870 	if (cp = strdup(cp ? cp : ""))
871 		return (cp);
872 	syslog(LOG_ERR, "strdup: %m");
873 	exit(-1);
874 }
875 
876 void
877 setproctitle(a, s)
878 	char *a;
879 	int s;
880 {
881 	int size;
882 	char *cp;
883 	struct sockaddr_in sin;
884 	char buf[80];
885 
886 	cp = Argv[0];
887 	size = sizeof(sin);
888 	if (getpeername(s, (struct sockaddr *)&sin, &size) == 0)
889 		(void) sprintf(buf, "-%s [%s]", a, inet_ntoa(sin.sin_addr));
890 	else
891 		(void) sprintf(buf, "-%s", a);
892 	strncpy(cp, buf, LastArg - cp);
893 	cp += strlen(cp);
894 	while (cp < LastArg)
895 		*cp++ = ' ';
896 }
897 
898 /*
899  * Internet services provided internally by inetd:
900  */
901 #define	BUFSIZE	8192
902 
903 /* ARGSUSED */
904 void
905 echo_stream(s, sep)		/* Echo service -- echo data back */
906 	int s;
907 	struct servtab *sep;
908 {
909 	char buffer[BUFSIZE];
910 	int i;
911 
912 	setproctitle(sep->se_service, s);
913 	while ((i = read(s, buffer, sizeof(buffer))) > 0 &&
914 	    write(s, buffer, i) > 0)
915 		;
916 	exit(0);
917 }
918 
919 /* ARGSUSED */
920 void
921 echo_dg(s, sep)			/* Echo service -- echo data back */
922 	int s;
923 	struct servtab *sep;
924 {
925 	char buffer[BUFSIZE];
926 	int i, size;
927 	struct sockaddr sa;
928 
929 	size = sizeof(sa);
930 	if ((i = recvfrom(s, buffer, sizeof(buffer), 0, &sa, &size)) < 0)
931 		return;
932 	(void) sendto(s, buffer, i, 0, &sa, sizeof(sa));
933 }
934 
935 /* ARGSUSED */
936 void
937 discard_stream(s, sep)		/* Discard service -- ignore data */
938 	int s;
939 	struct servtab *sep;
940 {
941 	int ret;
942 	char buffer[BUFSIZE];
943 
944 	setproctitle(sep->se_service, s);
945 	while (1) {
946 		while ((ret = read(s, buffer, sizeof(buffer))) > 0)
947 			;
948 		if (ret == 0 || errno != EINTR)
949 			break;
950 	}
951 	exit(0);
952 }
953 
954 /* ARGSUSED */
955 void
956 discard_dg(s, sep)		/* Discard service -- ignore data */
957 	int s;
958 	struct servtab *sep;
959 {
960 	char buffer[BUFSIZE];
961 
962 	(void) read(s, buffer, sizeof(buffer));
963 }
964 
965 #include <ctype.h>
966 #define LINESIZ 72
967 char ring[128];
968 char *endring;
969 
970 void
971 initring()
972 {
973 	int i;
974 
975 	endring = ring;
976 
977 	for (i = 0; i <= 128; ++i)
978 		if (isprint(i))
979 			*endring++ = i;
980 }
981 
982 /* ARGSUSED */
983 void
984 chargen_stream(s, sep)		/* Character generator */
985 	int s;
986 	struct servtab *sep;
987 {
988 	int len;
989 	char *rs, text[LINESIZ+2];
990 
991 	setproctitle(sep->se_service, s);
992 
993 	if (!endring) {
994 		initring();
995 		rs = ring;
996 	}
997 
998 	text[LINESIZ] = '\r';
999 	text[LINESIZ + 1] = '\n';
1000 	for (rs = ring;;) {
1001 		if ((len = endring - rs) >= LINESIZ)
1002 			memmove(text, rs, LINESIZ);
1003 		else {
1004 			memmove(text, rs, len);
1005 			memmove(text + len, ring, LINESIZ - len);
1006 		}
1007 		if (++rs == endring)
1008 			rs = ring;
1009 		if (write(s, text, sizeof(text)) != sizeof(text))
1010 			break;
1011 	}
1012 	exit(0);
1013 }
1014 
1015 /* ARGSUSED */
1016 void
1017 chargen_dg(s, sep)		/* Character generator */
1018 	int s;
1019 	struct servtab *sep;
1020 {
1021 	struct sockaddr sa;
1022 	static char *rs;
1023 	int len, size;
1024 	char text[LINESIZ+2];
1025 
1026 	if (endring == 0) {
1027 		initring();
1028 		rs = ring;
1029 	}
1030 
1031 	size = sizeof(sa);
1032 	if (recvfrom(s, text, sizeof(text), 0, &sa, &size) < 0)
1033 		return;
1034 
1035 	if ((len = endring - rs) >= LINESIZ)
1036 		memmove(text, rs, LINESIZ);
1037 	else {
1038 		memmove(text, rs, len);
1039 		memmove(text + len, ring, LINESIZ - len);
1040 	}
1041 	if (++rs == endring)
1042 		rs = ring;
1043 	text[LINESIZ] = '\r';
1044 	text[LINESIZ + 1] = '\n';
1045 	(void) sendto(s, text, sizeof(text), 0, &sa, sizeof(sa));
1046 }
1047 
1048 /*
1049  * Return a machine readable date and time, in the form of the
1050  * number of seconds since midnight, Jan 1, 1900.  Since gettimeofday
1051  * returns the number of seconds since midnight, Jan 1, 1970,
1052  * we must add 2208988800 seconds to this figure to make up for
1053  * some seventy years Bell Labs was asleep.
1054  */
1055 
1056 long
1057 machtime()
1058 {
1059 	struct timeval tv;
1060 
1061 	if (gettimeofday(&tv, (struct timezone *)0) < 0) {
1062 		if (debug)
1063 			fprintf(stderr, "Unable to get time of day\n");
1064 		return (0L);
1065 	}
1066 #define	OFFSET ((u_long)25567 * 24*60*60)
1067 	return (htonl((long)(tv.tv_sec + OFFSET)));
1068 #undef OFFSET
1069 }
1070 
1071 /* ARGSUSED */
1072 void
1073 machtime_stream(s, sep)
1074 	int s;
1075 	struct servtab *sep;
1076 {
1077 	long result;
1078 
1079 	result = machtime();
1080 	(void) write(s, (char *) &result, sizeof(result));
1081 }
1082 
1083 /* ARGSUSED */
1084 void
1085 machtime_dg(s, sep)
1086 	int s;
1087 	struct servtab *sep;
1088 {
1089 	long result;
1090 	struct sockaddr sa;
1091 	int size;
1092 
1093 	size = sizeof(sa);
1094 	if (recvfrom(s, (char *)&result, sizeof(result), 0, &sa, &size) < 0)
1095 		return;
1096 	result = machtime();
1097 	(void) sendto(s, (char *) &result, sizeof(result), 0, &sa, sizeof(sa));
1098 }
1099 
1100 /* ARGSUSED */
1101 void
1102 daytime_stream(s, sep)		/* Return human-readable time of day */
1103 	int s;
1104 	struct servtab *sep;
1105 {
1106 	char buffer[256];
1107 	time_t clock;
1108 
1109 	clock = time((time_t *) 0);
1110 
1111 	(void) sprintf(buffer, "%.24s\r\n", ctime(&clock));
1112 	(void) write(s, buffer, strlen(buffer));
1113 }
1114 
1115 /* ARGSUSED */
1116 void
1117 daytime_dg(s, sep)		/* Return human-readable time of day */
1118 	int s;
1119 	struct servtab *sep;
1120 {
1121 	char buffer[256];
1122 	time_t clock;
1123 	struct sockaddr sa;
1124 	int size;
1125 
1126 	clock = time((time_t *) 0);
1127 
1128 	size = sizeof(sa);
1129 	if (recvfrom(s, buffer, sizeof(buffer), 0, &sa, &size) < 0)
1130 		return;
1131 	(void) sprintf(buffer, "%.24s\r\n", ctime(&clock));
1132 	(void) sendto(s, buffer, strlen(buffer), 0, &sa, sizeof(sa));
1133 }
1134 
1135 /*
1136  * print_service:
1137  *	Dump relevant information to stderr
1138  */
1139 void
1140 print_service(action, sep)
1141 	char *action;
1142 	struct servtab *sep;
1143 {
1144 	fprintf(stderr,
1145 	    "%s: %s proto=%s, wait=%d, user=%s builtin=%x server=%s\n",
1146 	    action, sep->se_service, sep->se_proto,
1147 	    sep->se_wait, sep->se_user, (int)sep->se_bi, sep->se_server);
1148 }
1149 
1150 /*
1151  *  Based on TCPMUX.C by Mark K. Lottor November 1988
1152  *  sri-nic::ps:<mkl>tcpmux.c
1153  */
1154 
1155 
1156 static int		/* # of characters upto \r,\n or \0 */
1157 getline(fd, buf, len)
1158 	int fd;
1159 	char *buf;
1160 	int len;
1161 {
1162 	int count = 0, n;
1163 
1164 	do {
1165 		n = read(fd, buf, len-count);
1166 		if (n == 0)
1167 			return (count);
1168 		if (n < 0)
1169 			return (-1);
1170 		while (--n >= 0) {
1171 			if (*buf == '\r' || *buf == '\n' || *buf == '\0')
1172 				return (count);
1173 			count++;
1174 			buf++;
1175 		}
1176 	} while (count < len);
1177 	return (count);
1178 }
1179 
1180 #define MAX_SERV_LEN	(256+2)		/* 2 bytes for \r\n */
1181 
1182 #define strwrite(fd, buf)	(void) write(fd, buf, sizeof(buf)-1)
1183 
1184 struct servtab *
1185 tcpmux(s)
1186 	int s;
1187 {
1188 	struct servtab *sep;
1189 	char service[MAX_SERV_LEN+1];
1190 	int len;
1191 
1192 	/* Get requested service name */
1193 	if ((len = getline(s, service, MAX_SERV_LEN)) < 0) {
1194 		strwrite(s, "-Error reading service name\r\n");
1195 		return (NULL);
1196 	}
1197 	service[len] = '\0';
1198 
1199 	if (debug)
1200 		fprintf(stderr, "tcpmux: someone wants %s\n", service);
1201 
1202 	/*
1203 	 * Help is a required command, and lists available services,
1204 	 * one per line.
1205 	 */
1206 	if (!strcasecmp(service, "help")) {
1207 		for (sep = servtab; sep; sep = sep->se_next) {
1208 			if (!ISMUX(sep))
1209 				continue;
1210 			(void)write(s,sep->se_service,strlen(sep->se_service));
1211 			strwrite(s, "\r\n");
1212 		}
1213 		return (NULL);
1214 	}
1215 
1216 	/* Try matching a service in inetd.conf with the request */
1217 	for (sep = servtab; sep; sep = sep->se_next) {
1218 		if (!ISMUX(sep))
1219 			continue;
1220 		if (!strcasecmp(service, sep->se_service)) {
1221 			if (ISMUXPLUS(sep)) {
1222 				strwrite(s, "+Go\r\n");
1223 			}
1224 			return (sep);
1225 		}
1226 	}
1227 	strwrite(s, "-Service not available\r\n");
1228 	return (NULL);
1229 }
1230