xref: /csrg-svn/usr.sbin/inetd/inetd.c (revision 26877)
121134Sdist /*
221134Sdist  * Copyright (c) 1983 Regents of the University of California.
321134Sdist  * All rights reserved.  The Berkeley software License Agreement
421134Sdist  * specifies the terms and conditions for redistribution.
521134Sdist  */
621134Sdist 
716374Skarels #ifndef lint
821134Sdist char copyright[] =
921134Sdist "@(#) Copyright (c) 1983 Regents of the University of California.\n\
1021134Sdist  All rights reserved.\n";
1121134Sdist #endif not lint
1216374Skarels 
1321134Sdist #ifndef lint
14*26877Skarels static char sccsid[] = "@(#)inetd.c	5.4 (Berkeley) 03/13/86";
1521134Sdist #endif not lint
1621134Sdist 
1716374Skarels /*
1816374Skarels  * Inetd - Internet super-server
1916374Skarels  *
2016374Skarels  * This program invokes all internet services as needed.
2116374Skarels  * connection-oriented services are invoked each time a
2216374Skarels  * connection is made, by creating a process.  This process
2316374Skarels  * is passed the connection as file descriptor 0 and is
2416374Skarels  * expected to do a getpeername to find out the source host
2516374Skarels  * and port.
2616374Skarels  *
2716374Skarels  * Datagram oriented services are invoked when a datagram
2816374Skarels  * arrives; a process is created and passed a pending message
2916374Skarels  * on file descriptor 0.  Datagram servers may either connect
3016374Skarels  * to their peer, freeing up the original socket for inetd
3116374Skarels  * to receive further messages on, or ``take over the socket'',
3216374Skarels  * processing all arriving datagrams and, eventually, timing
3316374Skarels  * out.	 The first type of server is said to be ``multi-threaded'';
3416374Skarels  * the second type of server ``single-threaded''.
3516374Skarels  *
3616374Skarels  * Inetd uses a configuration file which is read at startup
3716374Skarels  * and, possibly, at some later time in response to a hangup signal.
3816374Skarels  * The configuration file is ``free format'' with fields given in the
3916374Skarels  * order shown below.  Continuation lines for an entry must being with
4016374Skarels  * a space or tab.  All fields must be present in each entry.
4116374Skarels  *
4216374Skarels  *	service name			must be in /etc/services
4316374Skarels  *	socket type			stream/dgram/raw/rdm/seqpacket
4416374Skarels  *	protocol			must be in /etc/protocols
4516374Skarels  *	wait/nowait			single-threaded/multi-threaded
4617346Sbloom  *	user				user to run daemon as
4716374Skarels  *	server program			full path name
4816374Skarels  *	server program arguments	maximum of MAXARGS (5)
4916374Skarels  *
5016374Skarels  * Comment lines are indicated by a `#' in column 1.
5116374Skarels  */
5216374Skarels #include <sys/param.h>
5316374Skarels #include <sys/stat.h>
5416374Skarels #include <sys/ioctl.h>
5516374Skarels #include <sys/socket.h>
5616374Skarels #include <sys/file.h>
5716374Skarels #include <sys/wait.h>
5816374Skarels 
5916374Skarels #include <netinet/in.h>
6016374Skarels #include <arpa/inet.h>
6116374Skarels 
6216374Skarels #include <errno.h>
6316374Skarels #include <stdio.h>
6416374Skarels #include <signal.h>
6516374Skarels #include <netdb.h>
6616510Sralph #include <syslog.h>
6717346Sbloom #include <pwd.h>
6816374Skarels 
6916374Skarels extern	int errno;
7016374Skarels 
7116374Skarels int	reapchild();
7216374Skarels char	*index();
7316374Skarels char	*malloc();
7416374Skarels 
7516374Skarels int	debug = 0;
7625046Skarels int	nsock, maxsock;
7725046Skarels fd_set	allsock;
7816374Skarels int	options;
7916374Skarels struct	servent *sp;
8016374Skarels 
8116374Skarels struct	servtab {
8216374Skarels 	char	*se_service;		/* name of service */
8316374Skarels 	int	se_socktype;		/* type of socket to use */
8416374Skarels 	char	*se_proto;		/* protocol used */
8516374Skarels 	short	se_wait;		/* single threaded server */
8616374Skarels 	short	se_checked;		/* looked at during merge */
8717346Sbloom 	char	*se_user;		/* user name to run as */
88*26877Skarels 	struct	biltin *se_bi;		/* if built-in, description */
8916374Skarels 	char	*se_server;		/* server program */
9016374Skarels #define MAXARGV 5
9116374Skarels 	char	*se_argv[MAXARGV+1];	/* program arguments */
9216374Skarels 	int	se_fd;			/* open descriptor */
9316374Skarels 	struct	sockaddr_in se_ctrladdr;/* bound address */
9416374Skarels 	struct	servtab *se_next;
9516374Skarels } *servtab;
9616374Skarels 
97*26877Skarels int echo_stream(), discard_stream(), machtime_stream();
98*26877Skarels int daytime_stream(), chargen_stream();
99*26877Skarels int echo_dg(), discard_dg(), machtime_dg(), daytime_dg(), chargen_dg();
100*26877Skarels 
101*26877Skarels struct biltin {
102*26877Skarels 	char	*bi_service;		/* internally provided service name */
103*26877Skarels 	int	bi_socktype;		/* type of socket supported */
104*26877Skarels 	short	bi_fork;		/* 1 if should fork before call */
105*26877Skarels 	short	bi_wait;		/* 1 if should wait for child */
106*26877Skarels 	int	(*bi_fn)();		/* function which performs it */
107*26877Skarels } biltins[] = {
108*26877Skarels 	/* Echo received data */
109*26877Skarels 	"echo",		SOCK_STREAM,	1, 0,	echo_stream,
110*26877Skarels 	"echo",		SOCK_DGRAM,	0, 0,	echo_dg,
111*26877Skarels 
112*26877Skarels 	/* Internet /dev/null */
113*26877Skarels 	"discard",	SOCK_STREAM,	1, 0,	discard_stream,
114*26877Skarels 	"discard",	SOCK_DGRAM,	0, 0,	discard_dg,
115*26877Skarels 
116*26877Skarels 	/* Return 32 bit time since 1970 */
117*26877Skarels 	"time",		SOCK_STREAM,	0, 0,	machtime_stream,
118*26877Skarels 	"time",		SOCK_DGRAM,	0, 0,	machtime_dg,
119*26877Skarels 
120*26877Skarels 	/* Return human-readable time */
121*26877Skarels 	"daytime",	SOCK_STREAM,	0, 0,	daytime_stream,
122*26877Skarels 	"daytime",	SOCK_DGRAM,	0, 0,	daytime_dg,
123*26877Skarels 
124*26877Skarels 	/* Familiar character generator */
125*26877Skarels 	"chargen",	SOCK_STREAM,	1, 0,	chargen_stream,
126*26877Skarels 	"chargen",	SOCK_DGRAM,	0, 0,	chargen_dg,
127*26877Skarels 	0
128*26877Skarels };
129*26877Skarels 
130*26877Skarels #define NUMINT	(sizeof(intab) / sizeof(struct inent))
13116374Skarels char	*CONFIG = "/etc/inetd.conf";
132*26877Skarels char	**Argv;
133*26877Skarels char 	*LastArg;
13416374Skarels 
135*26877Skarels main(argc, argv, envp)
13616374Skarels 	int argc;
137*26877Skarels 	char *argv[], *envp[];
13816374Skarels {
13916374Skarels 	register struct servtab *sep;
14017346Sbloom 	register struct passwd *pwd;
14116374Skarels 	char *cp, buf[50];
14216374Skarels 	int pid, i;
14316374Skarels 
144*26877Skarels 	Argv = argv;
145*26877Skarels 	if (envp == 0 || *envp == 0)
146*26877Skarels 		envp = argv;
147*26877Skarels 	while (*envp)
148*26877Skarels 		envp++;
149*26877Skarels 	LastArg = envp[-1] + strlen(envp[-1]);
15016374Skarels 	argc--, argv++;
15116374Skarels 	while (argc > 0 && *argv[0] == '-') {
15216374Skarels 		for (cp = &argv[0][1]; *cp; cp++) switch (*cp) {
15316374Skarels 
15416374Skarels 		case 'd':
15516374Skarels 			debug = 1;
15616374Skarels 			options |= SO_DEBUG;
15716374Skarels 			break;
15816374Skarels 
15916374Skarels 		default:
16016374Skarels 			fprintf(stderr,
16116374Skarels 			    "inetd: Unknown flag -%c ignored.\n", *cp);
16216374Skarels 			break;
16316374Skarels 		}
16416374Skarels nextopt:
16516374Skarels 		argc--, argv++;
16616374Skarels 	}
16716374Skarels 	if (argc > 0)
16816374Skarels 		CONFIG = argv[0];
16916374Skarels #ifndef DEBUG
17016374Skarels 	if (fork())
17116374Skarels 		exit(0);
17216374Skarels 	{ int s;
17316374Skarels 	for (s = 0; s < 10; s++)
17416374Skarels 		(void) close(s);
17516374Skarels 	}
17616374Skarels 	(void) open("/", O_RDONLY);
17716374Skarels 	(void) dup2(0, 1);
17816374Skarels 	(void) dup2(0, 2);
17916374Skarels 	{ int tt = open("/dev/tty", O_RDWR);
18016374Skarels 	  if (tt > 0) {
18116374Skarels 		ioctl(tt, TIOCNOTTY, 0);
18216374Skarels 		close(tt);
18316374Skarels 	  }
18416374Skarels 	}
18516374Skarels #endif
18624856Seric 	openlog("inetd", LOG_PID, LOG_DAEMON);
18716374Skarels 	config();
18816374Skarels 	signal(SIGHUP, config);
18916374Skarels 	signal(SIGCHLD, reapchild);
19016374Skarels 	for (;;) {
19125046Skarels 		int s, ctrl, n;
19225046Skarels 		fd_set readable;
19316374Skarels 
19425046Skarels 		while (nsock == 0)
19516374Skarels 			sigpause(0);
19616374Skarels 		readable = allsock;
19725046Skarels 		if ((n = select(maxsock + 1, &readable, 0, 0, 0)) <= 0)
19816374Skarels 			continue;
19925046Skarels 		for (s = 0; s <= maxsock; s++)
20025046Skarels 			if (FD_ISSET(s, &readable))
20125046Skarels 				break;
20216374Skarels 		for (sep = servtab; sep; sep = sep->se_next)
20316374Skarels 			if (s == sep->se_fd)
20416374Skarels 				goto found;
20516374Skarels 		abort(1);
20616374Skarels 	found:
20716374Skarels 		if (debug)
20816374Skarels 			fprintf(stderr, "someone wants %s\n", sep->se_service);
20925046Skarels 		if (!sep->se_wait && sep->se_socktype == SOCK_STREAM) {
21016374Skarels 			ctrl = accept(s, 0, 0);
21116510Sralph 			if (debug)
21216510Sralph 				fprintf(stderr, "accept, ctrl %d\n", ctrl);
21316374Skarels 			if (ctrl < 0) {
21416374Skarels 				if (errno == EINTR)
21516374Skarels 					continue;
21616510Sralph 				syslog(LOG_WARNING, "accept: %m");
21716374Skarels 				continue;
21816374Skarels 			}
21916374Skarels 		} else
22016374Skarels 			ctrl = sep->se_fd;
22125046Skarels 		sigblock(sigmask(SIGCHLD)|sigmask(SIGHUP));
222*26877Skarels 		pid = 0;
223*26877Skarels 		if (sep->se_bi == 0 || sep->se_bi->bi_fork)
224*26877Skarels 			pid = fork();
22516374Skarels 		if (pid < 0) {
22625046Skarels 			if (!sep->se_wait && sep->se_socktype == SOCK_STREAM)
22716374Skarels 				close(ctrl);
22816374Skarels 			sleep(1);
22916374Skarels 			continue;
23016374Skarels 		}
23116374Skarels 		if (sep->se_wait) {
23216374Skarels 			sep->se_wait = pid;
23325046Skarels 			FD_CLR(s, &allsock);
23425046Skarels 			nsock--;
23516374Skarels 		}
23616374Skarels 		sigsetmask(0);
23716374Skarels 		if (pid == 0) {
23816374Skarels #ifdef	DEBUG
23916374Skarels 			int tt = open("/dev/tty", O_RDWR);
24016374Skarels 			if (tt > 0) {
24116374Skarels 				ioctl(tt, TIOCNOTTY, 0);
24216374Skarels 				close(tt);
24316374Skarels 			}
24416374Skarels #endif
245*26877Skarels 			if (sep->se_bi == 0 || sep->se_bi->bi_fork)
246*26877Skarels 				for (i = getdtablesize(); --i > 2; )
247*26877Skarels 					if (i != ctrl)
248*26877Skarels 						close(i);
249*26877Skarels 			if (sep->se_bi)
250*26877Skarels 				(*sep->se_bi->bi_fn)(ctrl, sep);
251*26877Skarels 			else {
252*26877Skarels 				dup2(ctrl, 0);
253*26877Skarels 				close(ctrl);
254*26877Skarels 				dup2(0, 1);
255*26877Skarels 				dup2(0, 2);
256*26877Skarels 				if ((pwd = getpwnam(sep->se_user)) == NULL) {
257*26877Skarels 					syslog(LOG_ERR,
258*26877Skarels 						"getpwnam: %s: No such user",
259*26877Skarels 						sep->se_user);
260*26877Skarels 					_exit(1);
261*26877Skarels 				}
262*26877Skarels 				if (pwd->pw_uid) {
263*26877Skarels 					(void) setgid(pwd->pw_gid);
264*26877Skarels 					initgroups(pwd->pw_name, pwd->pw_gid);
265*26877Skarels 					(void) setuid(pwd->pw_uid);
266*26877Skarels 				}
267*26877Skarels 				if (debug)
268*26877Skarels 					fprintf(stderr, "%d execl %s\n",
269*26877Skarels 					    getpid(), sep->se_server);
270*26877Skarels 				execv(sep->se_server, sep->se_argv);
271*26877Skarels 				if (sep->se_socktype != SOCK_STREAM)
272*26877Skarels 					recv(0, buf, sizeof (buf), 0);
273*26877Skarels 				syslog(LOG_ERR, "execv %s: %m", sep->se_server);
274*26877Skarels 				_exit(1);
27517346Sbloom 			}
27616374Skarels 		}
27725046Skarels 		if (!sep->se_wait && sep->se_socktype == SOCK_STREAM)
27816374Skarels 			close(ctrl);
27916374Skarels 	}
28016374Skarels }
28116374Skarels 
28216374Skarels reapchild()
28316374Skarels {
28416374Skarels 	union wait status;
28516374Skarels 	int pid;
28616374Skarels 	register struct servtab *sep;
28716374Skarels 
28816374Skarels 	for (;;) {
28916374Skarels 		pid = wait3(&status, WNOHANG, 0);
29016374Skarels 		if (pid <= 0)
29116374Skarels 			break;
29216374Skarels 		if (debug)
29316374Skarels 			fprintf(stderr, "%d reaped\n", pid);
29416374Skarels 		for (sep = servtab; sep; sep = sep->se_next)
29516374Skarels 			if (sep->se_wait == pid) {
29616374Skarels 				if (status.w_status)
29716510Sralph 					syslog(LOG_WARNING,
29816510Sralph 					    "%s: exit status 0x%x",
29916374Skarels 					    sep->se_server, status);
30016374Skarels 				if (debug)
30116374Skarels 					fprintf(stderr, "restored %s, fd %d\n",
30216374Skarels 					    sep->se_service, sep->se_fd);
30325046Skarels 				FD_SET(sep->se_fd, &allsock);
30425046Skarels 				nsock++;
30516374Skarels 				sep->se_wait = 1;
30616374Skarels 			}
30716374Skarels 	}
30816374Skarels }
30916374Skarels 
31016374Skarels config()
31116374Skarels {
31216374Skarels 	register struct servtab *sep, *cp, **sepp;
31316374Skarels 	struct servtab *getconfigent(), *enter();
31417156Ssam 	int omask, on = 1;
31516374Skarels 
31616374Skarels 	if (!setconfig()) {
31716510Sralph 		syslog(LOG_ERR, "%s: %m", CONFIG);
31816374Skarels 		return;
31916374Skarels 	}
32016374Skarels 	for (sep = servtab; sep; sep = sep->se_next)
32116374Skarels 		sep->se_checked = 0;
32216374Skarels 	while (cp = getconfigent()) {
32316374Skarels 		for (sep = servtab; sep; sep = sep->se_next)
32416374Skarels 			if (strcmp(sep->se_service, cp->se_service) == 0 &&
32516374Skarels 			    strcmp(sep->se_proto, cp->se_proto) == 0)
32616374Skarels 				break;
32716374Skarels 		if (sep != 0) {
32816374Skarels 			int i;
32916374Skarels 
33025046Skarels 			omask = sigblock(sigmask(SIGCHLD));
33116374Skarels 			sep->se_wait = cp->se_wait;
33216374Skarels #define SWAP(a, b) { char *c = a; a = b; b = c; }
33316374Skarels 			if (cp->se_server)
33416374Skarels 				SWAP(sep->se_server, cp->se_server);
33516374Skarels 			for (i = 0; i < MAXARGV; i++)
33616374Skarels 				SWAP(sep->se_argv[i], cp->se_argv[i]);
33716374Skarels 			sigsetmask(omask);
33816374Skarels 			freeconfig(cp);
33916374Skarels 		} else
34016374Skarels 			sep = enter(cp);
34116374Skarels 		sep->se_checked = 1;
34216374Skarels 		if (sep->se_fd != -1)
34316374Skarels 			continue;
34416374Skarels 		sp = getservbyname(sep->se_service, sep->se_proto);
34516374Skarels 		if (sp == 0) {
34616510Sralph 			syslog(LOG_ERR, "%s/%s: unknown service",
34716374Skarels 			    sep->se_service, sep->se_proto);
34816374Skarels 			continue;
34916374Skarels 		}
35016374Skarels 		sep->se_ctrladdr.sin_port = sp->s_port;
35116374Skarels 		if ((sep->se_fd = socket(AF_INET, sep->se_socktype, 0)) < 0) {
35216510Sralph 			syslog(LOG_ERR, "%s/%s: socket: %m",
35316374Skarels 			    sep->se_service, sep->se_proto);
35416374Skarels 			continue;
35516374Skarels 		}
35617156Ssam #define	turnon(fd, opt) \
35717156Ssam 	setsockopt(fd, SOL_SOCKET, opt, &on, sizeof (on))
35816374Skarels 		if (strcmp(sep->se_proto, "tcp") == 0 && (options & SO_DEBUG) &&
35917156Ssam 		    turnon(sep->se_fd, SO_DEBUG) < 0)
36016510Sralph 			syslog(LOG_ERR, "setsockopt (SO_DEBUG): %m");
36117156Ssam 		if (turnon(sep->se_fd, SO_REUSEADDR) < 0)
36216510Sralph 			syslog(LOG_ERR, "setsockopt (SO_REUSEADDR): %m");
36317156Ssam #undef turnon
36416374Skarels 		if (bind(sep->se_fd, &sep->se_ctrladdr,
36516374Skarels 		    sizeof (sep->se_ctrladdr), 0) < 0) {
36616510Sralph 			syslog(LOG_ERR, "%s/%s: bind: %m",
36716374Skarels 			    sep->se_service, sep->se_proto);
36816374Skarels 			continue;
36916374Skarels 		}
37016374Skarels 		if (sep->se_socktype == SOCK_STREAM)
37116374Skarels 			listen(sep->se_fd, 10);
37225046Skarels 		FD_SET(sep->se_fd, &allsock);
37325046Skarels 		nsock++;
37425046Skarels 		if (sep->se_fd > maxsock)
37525046Skarels 			maxsock = sep->se_fd;
37616374Skarels 	}
37716374Skarels 	endconfig();
37816374Skarels 	/*
37916374Skarels 	 * Purge anything not looked at above.
38016374Skarels 	 */
38125046Skarels 	omask = sigblock(sigmask(SIGCHLD));
38216374Skarels 	sepp = &servtab;
38316374Skarels 	while (sep = *sepp) {
38416374Skarels 		if (sep->se_checked) {
38516374Skarels 			sepp = &sep->se_next;
38616374Skarels 			continue;
38716374Skarels 		}
38816374Skarels 		*sepp = sep->se_next;
38916374Skarels 		if (sep->se_fd != -1) {
39025046Skarels 			FD_CLR(sep->se_fd, &allsock);
39125046Skarels 			nsock--;
39216374Skarels 			(void) close(sep->se_fd);
39316374Skarels 		}
39416374Skarels 		freeconfig(sep);
39516374Skarels 		free((char *)sep);
39616374Skarels 	}
39716374Skarels 	(void) sigsetmask(omask);
39816374Skarels }
39916374Skarels 
40016374Skarels struct servtab *
40116374Skarels enter(cp)
40216374Skarels 	struct servtab *cp;
40316374Skarels {
40416374Skarels 	register struct servtab *sep;
40525046Skarels 	int omask;
40616374Skarels 	char *strdup();
40716374Skarels 
40816374Skarels 	sep = (struct servtab *)malloc(sizeof (*sep));
40916374Skarels 	if (sep == (struct servtab *)0) {
41016510Sralph 		syslog(LOG_ERR, "Out of memory.");
41116374Skarels 		exit(-1);
41216374Skarels 	}
41316374Skarels 	*sep = *cp;
41416374Skarels 	sep->se_fd = -1;
41525046Skarels 	omask = sigblock(sigmask(SIGCHLD));
41616374Skarels 	sep->se_next = servtab;
41716374Skarels 	servtab = sep;
41816374Skarels 	sigsetmask(omask);
41916374Skarels 	return (sep);
42016374Skarels }
42116374Skarels 
42216374Skarels FILE	*fconfig = NULL;
42316374Skarels struct	servtab serv;
42416374Skarels char	line[256];
42516374Skarels char	*skip(), *nextline();
42616374Skarels 
42716374Skarels setconfig()
42816374Skarels {
42916374Skarels 
43016374Skarels 	if (fconfig != NULL) {
43116374Skarels 		fseek(fconfig, 0, L_SET);
43216374Skarels 		return (1);
43316374Skarels 	}
43416374Skarels 	fconfig = fopen(CONFIG, "r");
43516374Skarels 	return (fconfig != NULL);
43616374Skarels }
43716374Skarels 
43816374Skarels endconfig()
43916374Skarels {
44016374Skarels 
44116374Skarels 	if (fconfig == NULL)
44216374Skarels 		return;
44316374Skarels 	fclose(fconfig);
44416374Skarels 	fconfig = NULL;
44516374Skarels }
44616374Skarels 
44716374Skarels struct servtab *
44816374Skarels getconfigent()
44916374Skarels {
45016374Skarels 	register struct servtab *sep = &serv;
45116374Skarels 	char *cp, *arg;
45216374Skarels 	int argc;
45316374Skarels 
454*26877Skarels more:
45516374Skarels 	while ((cp = nextline(fconfig)) && *cp == '#')
45616374Skarels 		;
45716374Skarels 	if (cp == NULL)
45816374Skarels 		return ((struct servtab *)0);
45916374Skarels 	sep->se_service = strdup(skip(&cp));
46016374Skarels 	arg = skip(&cp);
46116374Skarels 	if (strcmp(arg, "stream") == 0)
46216374Skarels 		sep->se_socktype = SOCK_STREAM;
46316374Skarels 	else if (strcmp(arg, "dgram") == 0)
46416374Skarels 		sep->se_socktype = SOCK_DGRAM;
46516374Skarels 	else if (strcmp(arg, "rdm") == 0)
46616374Skarels 		sep->se_socktype = SOCK_RDM;
46716374Skarels 	else if (strcmp(arg, "seqpacket") == 0)
46816374Skarels 		sep->se_socktype = SOCK_SEQPACKET;
46916374Skarels 	else if (strcmp(arg, "raw") == 0)
47016374Skarels 		sep->se_socktype = SOCK_RAW;
47116374Skarels 	else
47216374Skarels 		sep->se_socktype = -1;
47316374Skarels 	sep->se_proto = strdup(skip(&cp));
47416374Skarels 	arg = skip(&cp);
47516374Skarels 	sep->se_wait = strcmp(arg, "wait") == 0;
47617346Sbloom 	sep->se_user = strdup(skip(&cp));
47716374Skarels 	sep->se_server = strdup(skip(&cp));
478*26877Skarels 	if (strcmp(sep->se_server, "internal") == 0) {
479*26877Skarels 		register struct biltin *bi;
480*26877Skarels 
481*26877Skarels 		for (bi = biltins; bi->bi_service; bi++)
482*26877Skarels 			if (bi->bi_socktype == sep->se_socktype &&
483*26877Skarels 			    strcmp(bi->bi_service, sep->se_service) == 0)
484*26877Skarels 				break;
485*26877Skarels 		if (bi->bi_service == 0) {
486*26877Skarels 			syslog(LOG_ERR, "internal service %s unknown\n",
487*26877Skarels 				sep->se_service);
488*26877Skarels 			goto more;
489*26877Skarels 		}
490*26877Skarels 		sep->se_bi = bi;
491*26877Skarels 		sep->se_wait = bi->bi_wait;
492*26877Skarels 	}
49316374Skarels 	argc = 0;
49416374Skarels 	for (arg = skip(&cp); cp; arg = skip(&cp))
49516374Skarels 		if (argc < MAXARGV)
49616374Skarels 			sep->se_argv[argc++] = strdup(arg);
49716374Skarels 	while (argc <= MAXARGV)
49816374Skarels 		sep->se_argv[argc++] = NULL;
49916374Skarels 	return (sep);
50016374Skarels }
50116374Skarels 
50216374Skarels freeconfig(cp)
50316374Skarels 	register struct servtab *cp;
50416374Skarels {
50516374Skarels 	int i;
50616374Skarels 
50716374Skarels 	if (cp->se_service)
50816374Skarels 		free(cp->se_service);
50916374Skarels 	if (cp->se_proto)
51016374Skarels 		free(cp->se_proto);
51116374Skarels 	if (cp->se_server)
51216374Skarels 		free(cp->se_server);
51316374Skarels 	for (i = 0; i < MAXARGV; i++)
51416374Skarels 		if (cp->se_argv[i])
51516374Skarels 			free(cp->se_argv[i]);
51616374Skarels }
51716374Skarels 
51816374Skarels char *
51916374Skarels skip(cpp)
52016374Skarels 	char **cpp;
52116374Skarels {
52216374Skarels 	register char *cp = *cpp;
52316374Skarels 	char *start;
52416374Skarels 
52516374Skarels again:
52616374Skarels 	while (*cp == ' ' || *cp == '\t')
52716374Skarels 		cp++;
52816374Skarels 	if (*cp == '\0') {
52916374Skarels 		char c;
53016374Skarels 
53116374Skarels 		c = getc(fconfig);
53216374Skarels 		ungetc(c, fconfig);
53316374Skarels 		if (c == ' ' || c == '\t')
53416374Skarels 			if (cp = nextline(fconfig))
53516374Skarels 				goto again;
53616374Skarels 		*cpp = (char *)0;
53716374Skarels 		return ((char *)0);
53816374Skarels 	}
53916374Skarels 	start = cp;
54016374Skarels 	while (*cp && *cp != ' ' && *cp != '\t')
54116374Skarels 		cp++;
54216374Skarels 	if (*cp != '\0')
54316374Skarels 		*cp++ = '\0';
54416374Skarels 	*cpp = cp;
54516374Skarels 	return (start);
54616374Skarels }
54716374Skarels 
54816374Skarels char *
54916374Skarels nextline(fd)
55016374Skarels 	FILE *fd;
55116374Skarels {
55216374Skarels 	char *cp;
55316374Skarels 
55416374Skarels 	if (fgets(line, sizeof (line), fconfig) == NULL)
55516374Skarels 		return ((char *)0);
55616374Skarels 	cp = index(line, '\n');
55716374Skarels 	if (cp)
55816374Skarels 		*cp = '\0';
55916374Skarels 	return (line);
56016374Skarels }
56116374Skarels 
56216374Skarels char *
56316374Skarels strdup(cp)
56416374Skarels 	char *cp;
56516374Skarels {
56616374Skarels 	char *new;
56716374Skarels 
56816374Skarels 	if (cp == NULL)
56916374Skarels 		cp = "";
57016374Skarels 	new = malloc(strlen(cp) + 1);
57116374Skarels 	if (new == (char *)0) {
57216510Sralph 		syslog(LOG_ERR, "Out of memory.");
57316374Skarels 		exit(-1);
57416374Skarels 	}
57516374Skarels 	strcpy(new, cp);
57616374Skarels 	return (new);
57716374Skarels }
578*26877Skarels 
579*26877Skarels setproctitle(a, s)
580*26877Skarels 	char *a;
581*26877Skarels 	int s;
582*26877Skarels {
583*26877Skarels 	int size;
584*26877Skarels 	register char *cp;
585*26877Skarels 	struct sockaddr_in sin;
586*26877Skarels 	char buf[80];
587*26877Skarels 
588*26877Skarels 	cp = Argv[0];
589*26877Skarels 	size = sizeof(sin);
590*26877Skarels 	if (getpeername(s, &sin, &size) == 0)
591*26877Skarels 		sprintf(buf, "-%s [%s]", a, inet_ntoa(sin.sin_addr));
592*26877Skarels 	else
593*26877Skarels 		sprintf(buf, "-%s", a);
594*26877Skarels 	strncpy(cp, buf, LastArg - cp);
595*26877Skarels 	cp += strlen(cp);
596*26877Skarels 	while (cp < LastArg)
597*26877Skarels 		*cp++ = ' ';
598*26877Skarels }
599*26877Skarels 
600*26877Skarels /*
601*26877Skarels  * Internet services provided internally by inetd:
602*26877Skarels  */
603*26877Skarels 
604*26877Skarels /* ARGSUSED */
605*26877Skarels echo_stream(s, sep)		/* Echo service -- echo data back */
606*26877Skarels 	int s;
607*26877Skarels 	struct servtab *sep;
608*26877Skarels {
609*26877Skarels 	char buffer[BUFSIZ];
610*26877Skarels 	int i;
611*26877Skarels 
612*26877Skarels 	setproctitle("echo", s);
613*26877Skarels 	while ((i = read(s, buffer, sizeof(buffer))) > 0 &&
614*26877Skarels 	    write(s, buffer, i) > 0)
615*26877Skarels 		;
616*26877Skarels 	exit(0);
617*26877Skarels }
618*26877Skarels 
619*26877Skarels /* ARGSUSED */
620*26877Skarels echo_dg(s, sep)			/* Echo service -- echo data back */
621*26877Skarels 	int s;
622*26877Skarels 	struct servtab *sep;
623*26877Skarels {
624*26877Skarels 	char buffer[BUFSIZ];
625*26877Skarels 	int i, size;
626*26877Skarels 	struct sockaddr sa;
627*26877Skarels 
628*26877Skarels 	size = sizeof(sa);
629*26877Skarels 	if ((i = recvfrom(s, buffer, sizeof(buffer), 0, &sa, &size)) < 0)
630*26877Skarels 		return;
631*26877Skarels 	(void) sendto(s, buffer, i, 0, &sa, sizeof(sa));
632*26877Skarels }
633*26877Skarels 
634*26877Skarels /* ARGSUSED */
635*26877Skarels discard_stream(s, sep)		/* Discard service -- ignore data */
636*26877Skarels 	int s;
637*26877Skarels 	struct servtab *sep;
638*26877Skarels {
639*26877Skarels 	char buffer[BUFSIZ];
640*26877Skarels 
641*26877Skarels 	setproctitle("discard", s);
642*26877Skarels 	while (1) {
643*26877Skarels 		while (read(s, buffer, sizeof(buffer)) > 0)
644*26877Skarels 			;
645*26877Skarels 		if (errno != EINTR)
646*26877Skarels 			break;
647*26877Skarels 	}
648*26877Skarels 	exit(0);
649*26877Skarels }
650*26877Skarels 
651*26877Skarels /* ARGSUSED */
652*26877Skarels discard_dg(s, sep)		/* Discard service -- ignore data */
653*26877Skarels 	int s;
654*26877Skarels 	struct servtab *sep;
655*26877Skarels {
656*26877Skarels 	char buffer[BUFSIZ];
657*26877Skarels 
658*26877Skarels 	(void) read(s, buffer, sizeof(buffer));
659*26877Skarels }
660*26877Skarels 
661*26877Skarels #include <ctype.h>
662*26877Skarels #define LINESIZ 72
663*26877Skarels char ring[128];
664*26877Skarels char *endring;
665*26877Skarels 
666*26877Skarels initring()
667*26877Skarels {
668*26877Skarels 	register int i;
669*26877Skarels 
670*26877Skarels 	endring = ring;
671*26877Skarels 
672*26877Skarels 	for (i = 0; i <= 128; ++i)
673*26877Skarels 		if (isprint(i))
674*26877Skarels 			*endring++ = i;
675*26877Skarels }
676*26877Skarels 
677*26877Skarels /* ARGSUSED */
678*26877Skarels chargen_stream(s, sep)		/* Character generator */
679*26877Skarels 	int s;
680*26877Skarels 	struct servtab *sep;
681*26877Skarels {
682*26877Skarels 	char text[LINESIZ+2];
683*26877Skarels 	register int i;
684*26877Skarels 	register char *rp, *rs, *dp;
685*26877Skarels 
686*26877Skarels 	setproctitle("discard", s);
687*26877Skarels 	if (endring == 0)
688*26877Skarels 		initring();
689*26877Skarels 
690*26877Skarels 	for (rs = ring; ; ++rs) {
691*26877Skarels 		if (rs >= endring)
692*26877Skarels 			rs = ring;
693*26877Skarels 		rp = rs;
694*26877Skarels 		dp = text;
695*26877Skarels 		i = MIN(LINESIZ, endring - rp);
696*26877Skarels 		bcopy(rp, dp, i);
697*26877Skarels 		dp += i;
698*26877Skarels 		if ((rp += i) >= endring)
699*26877Skarels 			rp = ring;
700*26877Skarels 		if (i < LINESIZ) {
701*26877Skarels 			i = LINESIZ - i;
702*26877Skarels 			bcopy(rp, dp, i);
703*26877Skarels 			dp += i;
704*26877Skarels 			if ((rp += i) >= endring)
705*26877Skarels 				rp = ring;
706*26877Skarels 		}
707*26877Skarels 		*dp++ = '\r';
708*26877Skarels 		*dp++ = '\n';
709*26877Skarels 
710*26877Skarels 		if (write(s, text, dp - text) != dp - text)
711*26877Skarels 			break;
712*26877Skarels 	}
713*26877Skarels 	exit(0);
714*26877Skarels }
715*26877Skarels 
716*26877Skarels /* ARGSUSED */
717*26877Skarels chargen_dg(s, sep)		/* Character generator */
718*26877Skarels 	int s;
719*26877Skarels 	struct servtab *sep;
720*26877Skarels {
721*26877Skarels 	char text[LINESIZ+2];
722*26877Skarels 	register int i;
723*26877Skarels 	register char *rp;
724*26877Skarels 	static char *rs = ring;
725*26877Skarels 	struct sockaddr sa;
726*26877Skarels 	int size;
727*26877Skarels 
728*26877Skarels 	if (endring == 0)
729*26877Skarels 		initring();
730*26877Skarels 
731*26877Skarels 	size = sizeof(sa);
732*26877Skarels 	if (recvfrom(s, text, sizeof(text), 0, &sa, &size) < 0)
733*26877Skarels 		return;
734*26877Skarels 	rp = rs;
735*26877Skarels 	if (rs++ >= endring)
736*26877Skarels 		rs = ring;
737*26877Skarels 	i = MIN(LINESIZ - 2, endring - rp);
738*26877Skarels 	bcopy(rp, text, i);
739*26877Skarels 	if ((rp += i) >= endring)
740*26877Skarels 		rp = ring;
741*26877Skarels 	if (i < LINESIZ - 2) {
742*26877Skarels 		bcopy(rp, text, i);
743*26877Skarels 		if ((rp += i) >= endring)
744*26877Skarels 			rp = ring;
745*26877Skarels 	}
746*26877Skarels 	text[LINESIZ - 2] = '\r';
747*26877Skarels 	text[LINESIZ - 1] = '\n';
748*26877Skarels 
749*26877Skarels 	(void) sendto(s, text, sizeof(text), 0, &sa, sizeof(sa));
750*26877Skarels }
751*26877Skarels 
752*26877Skarels /*
753*26877Skarels  * Return a machine readable date and time, in the form of the
754*26877Skarels  * number of seconds since midnight, Jan 1, 1900.  Since gettimeofday
755*26877Skarels  * returns the number of seconds since midnight, Jan 1, 1970,
756*26877Skarels  * we must add 2208988800 seconds to this figure to make up for
757*26877Skarels  * some seventy years Bell Labs was asleep.
758*26877Skarels  */
759*26877Skarels #include <sys/time.h>
760*26877Skarels 
761*26877Skarels long
762*26877Skarels machtime()
763*26877Skarels {
764*26877Skarels 	struct timeval tv;
765*26877Skarels 
766*26877Skarels 	if (gettimeofday(&tv, 0) < 0) {
767*26877Skarels 		fprintf(stderr, "Unable to get time of day\n");
768*26877Skarels 		return;
769*26877Skarels 	}
770*26877Skarels 	return (htonl((long)tv.tv_sec + 2208988800));
771*26877Skarels }
772*26877Skarels 
773*26877Skarels /* ARGSUSED */
774*26877Skarels machtime_stream(s, sep)
775*26877Skarels 	int s;
776*26877Skarels 	struct servtab *sep;
777*26877Skarels {
778*26877Skarels 	long result;
779*26877Skarels 
780*26877Skarels 	result = machtime();
781*26877Skarels 	(void) write(s, (char *) &result, sizeof(result));
782*26877Skarels }
783*26877Skarels 
784*26877Skarels /* ARGSUSED */
785*26877Skarels machtime_dg(s, sep)
786*26877Skarels 	int s;
787*26877Skarels 	struct servtab *sep;
788*26877Skarels {
789*26877Skarels 	long result;
790*26877Skarels 	struct sockaddr sa;
791*26877Skarels 	int size;
792*26877Skarels 
793*26877Skarels 	size = sizeof(sa);
794*26877Skarels 	if (recvfrom(s, &result, sizeof(result), 0, &sa, &size) < 0)
795*26877Skarels 		return;
796*26877Skarels 	result = machtime();
797*26877Skarels 	(void) sendto(s, (char *) &result, sizeof(result), 0, &sa, sizeof(sa));
798*26877Skarels }
799*26877Skarels 
800*26877Skarels /* ARGSUSED */
801*26877Skarels daytime_stream(s, sep)		/* Return human-readable time of day */
802*26877Skarels 	int s;
803*26877Skarels 	struct servtab *sep;
804*26877Skarels {
805*26877Skarels 	char buffer[256];
806*26877Skarels 	time_t time(), clock;
807*26877Skarels 	char *ctime();
808*26877Skarels 
809*26877Skarels 	clock = time((time_t *) 0);
810*26877Skarels 
811*26877Skarels 	sprintf(buffer, "%s\r", ctime(&clock));
812*26877Skarels 	write(s, buffer, strlen(buffer));
813*26877Skarels }
814*26877Skarels 
815*26877Skarels /* ARGSUSED */
816*26877Skarels daytime_dg(s, sep)		/* Return human-readable time of day */
817*26877Skarels 	int s;
818*26877Skarels 	struct servtab *sep;
819*26877Skarels {
820*26877Skarels 	char buffer[256];
821*26877Skarels 	time_t time(), clock;
822*26877Skarels 	struct sockaddr sa;
823*26877Skarels 	int size;
824*26877Skarels 	char *ctime();
825*26877Skarels 
826*26877Skarels 	clock = time((time_t *) 0);
827*26877Skarels 
828*26877Skarels 	size = sizeof(sa);
829*26877Skarels 	if (recvfrom(s, buffer, sizeof(buffer), 0, &sa, &size) < 0)
830*26877Skarels 		return;
831*26877Skarels 	sprintf(buffer, "%s\r", ctime(&clock));
832*26877Skarels 	(void) sendto(s, buffer, strlen(buffer), 0, &sa, sizeof(sa));
833*26877Skarels }
834