xref: /original-bsd/usr.sbin/inetd/inetd.c (revision ff17a116)
1 /*
2  * Copyright (c) 1983 Regents of the University of California.
3  * All rights reserved.  The Berkeley software License Agreement
4  * specifies the terms and conditions for redistribution.
5  */
6 
7 #ifndef lint
8 char copyright[] =
9 "@(#) Copyright (c) 1983 Regents of the University of California.\n\
10  All rights reserved.\n";
11 #endif not lint
12 
13 #ifndef lint
14 static char sccsid[] = "@(#)inetd.c	5.7 (Berkeley) 08/19/86";
15 #endif not lint
16 
17 /*
18  * Inetd - Internet super-server
19  *
20  * This program invokes all internet services as needed.
21  * connection-oriented services are invoked each time a
22  * connection is made, by creating a process.  This process
23  * is passed the connection as file descriptor 0 and is
24  * expected to do a getpeername to find out the source host
25  * and port.
26  *
27  * Datagram oriented services are invoked when a datagram
28  * arrives; a process is created and passed a pending message
29  * on file descriptor 0.  Datagram servers may either connect
30  * to their peer, freeing up the original socket for inetd
31  * to receive further messages on, or ``take over the socket'',
32  * processing all arriving datagrams and, eventually, timing
33  * out.	 The first type of server is said to be ``multi-threaded'';
34  * the second type of server ``single-threaded''.
35  *
36  * Inetd uses a configuration file which is read at startup
37  * and, possibly, at some later time in response to a hangup signal.
38  * The configuration file is ``free format'' with fields given in the
39  * order shown below.  Continuation lines for an entry must being with
40  * a space or tab.  All fields must be present in each entry.
41  *
42  *	service name			must be in /etc/services
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 (5)
49  *
50  * Comment lines are indicated by a `#' in column 1.
51  */
52 #include <sys/param.h>
53 #include <sys/stat.h>
54 #include <sys/ioctl.h>
55 #include <sys/socket.h>
56 #include <sys/file.h>
57 #include <sys/wait.h>
58 #include <sys/time.h>
59 #include <sys/resource.h>
60 
61 #include <netinet/in.h>
62 #include <arpa/inet.h>
63 
64 #include <errno.h>
65 #include <stdio.h>
66 #include <signal.h>
67 #include <netdb.h>
68 #include <syslog.h>
69 #include <pwd.h>
70 
71 #define	TOOMANY		40		/* don't start more than TOOMANY */
72 #define	CNT_INTVL	60		/* servers in CNT_INTVL sec. */
73 #define	RETRYTIME	(60*10)		/* retry after bind or server fail */
74 
75 #define	SIGBLOCK	(sigmask(SIGCHLD)|sigmask(SIGHUP)|sigmask(SIGALRM))
76 
77 extern	int errno;
78 
79 int	reapchild(), retry();
80 char	*index();
81 char	*malloc();
82 
83 int	debug = 0;
84 int	nsock, maxsock;
85 fd_set	allsock;
86 int	options;
87 int	timingout;
88 struct	servent *sp;
89 
90 struct	servtab {
91 	char	*se_service;		/* name of service */
92 	int	se_socktype;		/* type of socket to use */
93 	char	*se_proto;		/* protocol used */
94 	short	se_wait;		/* single threaded server */
95 	short	se_checked;		/* looked at during merge */
96 	char	*se_user;		/* user name to run as */
97 	struct	biltin *se_bi;		/* if built-in, description */
98 	char	*se_server;		/* server program */
99 #define MAXARGV 5
100 	char	*se_argv[MAXARGV+1];	/* program arguments */
101 	int	se_fd;			/* open descriptor */
102 	struct	sockaddr_in se_ctrladdr;/* bound address */
103 	int	se_count;		/* number started since se_time */
104 	struct	timeval se_time;	/* start of se_count */
105 	struct	servtab *se_next;
106 } *servtab;
107 
108 int echo_stream(), discard_stream(), machtime_stream();
109 int daytime_stream(), chargen_stream();
110 int echo_dg(), discard_dg(), machtime_dg(), daytime_dg(), chargen_dg();
111 
112 struct biltin {
113 	char	*bi_service;		/* internally provided service name */
114 	int	bi_socktype;		/* type of socket supported */
115 	short	bi_fork;		/* 1 if should fork before call */
116 	short	bi_wait;		/* 1 if should wait for child */
117 	int	(*bi_fn)();		/* function which performs it */
118 } biltins[] = {
119 	/* Echo received data */
120 	"echo",		SOCK_STREAM,	1, 0,	echo_stream,
121 	"echo",		SOCK_DGRAM,	0, 0,	echo_dg,
122 
123 	/* Internet /dev/null */
124 	"discard",	SOCK_STREAM,	1, 0,	discard_stream,
125 	"discard",	SOCK_DGRAM,	0, 0,	discard_dg,
126 
127 	/* Return 32 bit time since 1970 */
128 	"time",		SOCK_STREAM,	0, 0,	machtime_stream,
129 	"time",		SOCK_DGRAM,	0, 0,	machtime_dg,
130 
131 	/* Return human-readable time */
132 	"daytime",	SOCK_STREAM,	0, 0,	daytime_stream,
133 	"daytime",	SOCK_DGRAM,	0, 0,	daytime_dg,
134 
135 	/* Familiar character generator */
136 	"chargen",	SOCK_STREAM,	1, 0,	chargen_stream,
137 	"chargen",	SOCK_DGRAM,	0, 0,	chargen_dg,
138 	0
139 };
140 
141 #define NUMINT	(sizeof(intab) / sizeof(struct inent))
142 char	*CONFIG = "/etc/inetd.conf";
143 char	**Argv;
144 char 	*LastArg;
145 
146 main(argc, argv, envp)
147 	int argc;
148 	char *argv[], *envp[];
149 {
150 	register struct servtab *sep;
151 	register struct passwd *pwd;
152 	char *cp, buf[50];
153 	int pid, i, dofork;
154 	struct sigvec sv;
155 
156 	Argv = argv;
157 	if (envp == 0 || *envp == 0)
158 		envp = argv;
159 	while (*envp)
160 		envp++;
161 	LastArg = envp[-1] + strlen(envp[-1]);
162 	argc--, argv++;
163 	while (argc > 0 && *argv[0] == '-') {
164 		for (cp = &argv[0][1]; *cp; cp++) switch (*cp) {
165 
166 		case 'd':
167 			debug = 1;
168 			options |= SO_DEBUG;
169 			break;
170 
171 		default:
172 			fprintf(stderr,
173 			    "inetd: Unknown flag -%c ignored.\n", *cp);
174 			break;
175 		}
176 nextopt:
177 		argc--, argv++;
178 	}
179 	if (argc > 0)
180 		CONFIG = argv[0];
181 #ifndef DEBUG
182 	if (fork())
183 		exit(0);
184 	{ int s;
185 	for (s = 0; s < 10; s++)
186 		(void) close(s);
187 	}
188 	(void) open("/", O_RDONLY);
189 	(void) dup2(0, 1);
190 	(void) dup2(0, 2);
191 	{ int tt = open("/dev/tty", O_RDWR);
192 	  if (tt > 0) {
193 		ioctl(tt, TIOCNOTTY, (char *)0);
194 		close(tt);
195 	  }
196 	}
197 #endif
198 	openlog("inetd", LOG_PID | LOG_NOWAIT, LOG_DAEMON);
199 	bzero((char *)&sv, sizeof(sv));
200 	sv.sv_mask = SIGBLOCK;
201 	sv.sv_handler = retry;
202 	sigvec(SIGALRM, &sv, (struct sigvec *)0);
203 	config();
204 	sv.sv_handler = config;
205 	sigvec(SIGHUP, &sv, (struct sigvec *)0);
206 	sv.sv_handler = reapchild;
207 	sigvec(SIGCHLD, &sv, (struct sigvec *)0);
208 
209 	for (;;) {
210 	    int s, ctrl, n;
211 	    fd_set readable;
212 
213 	    while (nsock == 0)
214 		    sigpause(0);
215 	    readable = allsock;
216 	    if ((n = select(maxsock + 1, &readable, (fd_set *)0,
217 		(fd_set *)0, (struct timeval *)0)) <= 0) {
218 		    if (n < 0 && errno != EINTR)
219 				syslog(LOG_WARNING, "select: %m\n");
220 		    sleep(1);
221 		    continue;
222 	    }
223 	    for (sep = servtab; n && sep; sep = sep->se_next)
224 	    if (FD_ISSET(sep->se_fd, &readable)) {
225 		n--;
226 		if (debug)
227 			fprintf(stderr, "someone wants %s\n", sep->se_service);
228 		if (!sep->se_wait && sep->se_socktype == SOCK_STREAM) {
229 			ctrl = accept(sep->se_fd, (struct sockaddr *)0,
230 			    (int *)0);
231 			if (debug)
232 				fprintf(stderr, "accept, ctrl %d\n", ctrl);
233 			if (ctrl < 0) {
234 				if (errno == EINTR)
235 					continue;
236 				syslog(LOG_WARNING, "accept: %m");
237 				continue;
238 			}
239 		} else
240 			ctrl = sep->se_fd;
241 		(void) sigblock(SIGBLOCK);
242 		pid = 0;
243 		dofork = (sep->se_bi == 0 || sep->se_bi->bi_fork);
244 		if (dofork) {
245 			if (sep->se_count++ == 0)
246 			    (void)gettimeofday(&sep->se_time,
247 			        (struct timezone *)0);
248 			else if (sep->se_count >= TOOMANY) {
249 				struct timeval now;
250 
251 				(void)gettimeofday(&now, (struct timezone *)0);
252 				if (now.tv_sec - sep->se_time.tv_sec >
253 				    CNT_INTVL) {
254 					sep->se_time = now;
255 					sep->se_count = 1;
256 				} else {
257 					syslog(LOG_ERR,
258 			"%s/%s server failing (looping), service terminated\n",
259 					    sep->se_service, sep->se_proto);
260 					FD_CLR(sep->se_fd, &allsock);
261 					(void) close(sep->se_fd);
262 					sep->se_fd = -1;
263 					sep->se_count = 0;
264 					nsock--;
265 					sigsetmask(0);
266 					if (!timingout) {
267 						timingout = 1;
268 						alarm(RETRYTIME);
269 					}
270 					continue;
271 				}
272 			}
273 			pid = fork();
274 		}
275 		if (pid < 0) {
276 			if (!sep->se_wait && sep->se_socktype == SOCK_STREAM)
277 				close(ctrl);
278 			sigsetmask(0);
279 			sleep(1);
280 			continue;
281 		}
282 		if (pid && sep->se_wait) {
283 			sep->se_wait = pid;
284 			FD_CLR(sep->se_fd, &allsock);
285 			nsock--;
286 		}
287 		sigsetmask(0);
288 		if (pid == 0) {
289 #ifdef	DEBUG
290 			int tt;
291 
292 			if (dofork && (tt = open("/dev/tty", O_RDWR)) > 0) {
293 				ioctl(tt, TIOCNOTTY, 0);
294 				close(tt);
295 			}
296 #endif
297 			if (dofork)
298 				for (i = getdtablesize(); --i > 2; )
299 					if (i != ctrl)
300 						close(i);
301 			if (sep->se_bi)
302 				(*sep->se_bi->bi_fn)(ctrl, sep);
303 			else {
304 				dup2(ctrl, 0);
305 				close(ctrl);
306 				dup2(0, 1);
307 				dup2(0, 2);
308 				if ((pwd = getpwnam(sep->se_user)) == NULL) {
309 					syslog(LOG_ERR,
310 						"getpwnam: %s: No such user",
311 						sep->se_user);
312 					if (sep->se_socktype != SOCK_STREAM)
313 						recv(0, buf, sizeof (buf), 0);
314 					_exit(1);
315 				}
316 				if (pwd->pw_uid) {
317 					(void) setgid((gid_t)pwd->pw_gid);
318 					initgroups(pwd->pw_name, pwd->pw_gid);
319 					(void) setuid((uid_t)pwd->pw_uid);
320 				}
321 				if (debug)
322 					fprintf(stderr, "%d execl %s\n",
323 					    getpid(), sep->se_server);
324 				execv(sep->se_server, sep->se_argv);
325 				if (sep->se_socktype != SOCK_STREAM)
326 					recv(0, buf, sizeof (buf), 0);
327 				syslog(LOG_ERR, "execv %s: %m", sep->se_server);
328 				_exit(1);
329 			}
330 		}
331 		if (!sep->se_wait && sep->se_socktype == SOCK_STREAM)
332 			close(ctrl);
333 	    }
334 	}
335 }
336 
337 reapchild()
338 {
339 	union wait status;
340 	int pid;
341 	register struct servtab *sep;
342 
343 	for (;;) {
344 		pid = wait3(&status, WNOHANG, (struct rusage *)0);
345 		if (pid <= 0)
346 			break;
347 		if (debug)
348 			fprintf(stderr, "%d reaped\n", pid);
349 		for (sep = servtab; sep; sep = sep->se_next)
350 			if (sep->se_wait == pid) {
351 				if (status.w_status)
352 					syslog(LOG_WARNING,
353 					    "%s: exit status 0x%x",
354 					    sep->se_server, status);
355 				if (debug)
356 					fprintf(stderr, "restored %s, fd %d\n",
357 					    sep->se_service, sep->se_fd);
358 				FD_SET(sep->se_fd, &allsock);
359 				nsock++;
360 				sep->se_wait = 1;
361 			}
362 	}
363 }
364 
365 config()
366 {
367 	register struct servtab *sep, *cp, **sepp;
368 	struct servtab *getconfigent(), *enter();
369 	int omask;
370 
371 	if (!setconfig()) {
372 		syslog(LOG_ERR, "%s: %m", CONFIG);
373 		return;
374 	}
375 	for (sep = servtab; sep; sep = sep->se_next)
376 		sep->se_checked = 0;
377 	while (cp = getconfigent()) {
378 		for (sep = servtab; sep; sep = sep->se_next)
379 			if (strcmp(sep->se_service, cp->se_service) == 0 &&
380 			    strcmp(sep->se_proto, cp->se_proto) == 0)
381 				break;
382 		if (sep != 0) {
383 			int i;
384 
385 			omask = sigblock(SIGBLOCK);
386 			if (cp->se_bi == 0)
387 				sep->se_wait = cp->se_wait;
388 #define SWAP(a, b) { char *c = a; a = b; b = c; }
389 			if (cp->se_user)
390 				SWAP(sep->se_user, cp->se_user);
391 			if (cp->se_server)
392 				SWAP(sep->se_server, cp->se_server);
393 			for (i = 0; i < MAXARGV; i++)
394 				SWAP(sep->se_argv[i], cp->se_argv[i]);
395 			sigsetmask(omask);
396 			freeconfig(cp);
397 			if (debug)
398 				print_service("REDO", sep);
399 		} else {
400 			sep = enter(cp);
401 			if (debug)
402 				print_service("ADD ", sep);
403 		}
404 		sep->se_checked = 1;
405 		sp = getservbyname(sep->se_service, sep->se_proto);
406 		if (sp == 0) {
407 			syslog(LOG_ERR, "%s/%s: unknown service",
408 			    sep->se_service, sep->se_proto);
409 			continue;
410 		}
411 		if (sp->s_port != sep->se_ctrladdr.sin_port) {
412 			sep->se_ctrladdr.sin_port = sp->s_port;
413 			if (sep->se_fd != -1)
414 				(void) close(sep->se_fd);
415 			sep->se_fd = -1;
416 		}
417 		if (sep->se_fd == -1)
418 			setup(sep);
419 	}
420 	endconfig();
421 	/*
422 	 * Purge anything not looked at above.
423 	 */
424 	omask = sigblock(SIGBLOCK);
425 	sepp = &servtab;
426 	while (sep = *sepp) {
427 		if (sep->se_checked) {
428 			sepp = &sep->se_next;
429 			continue;
430 		}
431 		*sepp = sep->se_next;
432 		if (sep->se_fd != -1) {
433 			FD_CLR(sep->se_fd, &allsock);
434 			nsock--;
435 			(void) close(sep->se_fd);
436 		}
437 		if (debug)
438 			print_service("FREE", sep);
439 		freeconfig(sep);
440 		free((char *)sep);
441 	}
442 	(void) sigsetmask(omask);
443 }
444 
445 retry()
446 {
447 	register struct servtab *sep;
448 
449 	timingout = 0;
450 	for (sep = servtab; sep; sep = sep->se_next)
451 		if (sep->se_fd == -1)
452 			setup(sep);
453 }
454 
455 setup(sep)
456 	register struct servtab *sep;
457 {
458 	int on = 1;
459 
460 	if ((sep->se_fd = socket(AF_INET, sep->se_socktype, 0)) < 0) {
461 		syslog(LOG_ERR, "%s/%s: socket: %m",
462 		    sep->se_service, sep->se_proto);
463 		return;
464 	}
465 #define	turnon(fd, opt) \
466 setsockopt(fd, SOL_SOCKET, opt, (char *)&on, sizeof (on))
467 	if (strcmp(sep->se_proto, "tcp") == 0 && (options & SO_DEBUG) &&
468 	    turnon(sep->se_fd, SO_DEBUG) < 0)
469 		syslog(LOG_ERR, "setsockopt (SO_DEBUG): %m");
470 	if (turnon(sep->se_fd, SO_REUSEADDR) < 0)
471 		syslog(LOG_ERR, "setsockopt (SO_REUSEADDR): %m");
472 #undef turnon
473 	if (bind(sep->se_fd, &sep->se_ctrladdr,
474 	    sizeof (sep->se_ctrladdr)) < 0) {
475 		syslog(LOG_ERR, "%s/%s: bind: %m",
476 		    sep->se_service, sep->se_proto);
477 		(void) close(sep->se_fd);
478 		sep->se_fd = -1;
479 		if (!timingout) {
480 			timingout = 1;
481 			alarm(RETRYTIME);
482 		}
483 		return;
484 	}
485 	if (sep->se_socktype == SOCK_STREAM)
486 		listen(sep->se_fd, 10);
487 	FD_SET(sep->se_fd, &allsock);
488 	nsock++;
489 	if (sep->se_fd > maxsock)
490 		maxsock = sep->se_fd;
491 }
492 
493 struct servtab *
494 enter(cp)
495 	struct servtab *cp;
496 {
497 	register struct servtab *sep;
498 	int omask;
499 	char *strdup();
500 
501 	sep = (struct servtab *)malloc(sizeof (*sep));
502 	if (sep == (struct servtab *)0) {
503 		syslog(LOG_ERR, "Out of memory.");
504 		exit(-1);
505 	}
506 	*sep = *cp;
507 	sep->se_fd = -1;
508 	omask = sigblock(SIGBLOCK);
509 	sep->se_next = servtab;
510 	servtab = sep;
511 	sigsetmask(omask);
512 	return (sep);
513 }
514 
515 FILE	*fconfig = NULL;
516 struct	servtab serv;
517 char	line[256];
518 char	*skip(), *nextline();
519 
520 setconfig()
521 {
522 
523 	if (fconfig != NULL) {
524 		fseek(fconfig, 0L, L_SET);
525 		return (1);
526 	}
527 	fconfig = fopen(CONFIG, "r");
528 	return (fconfig != NULL);
529 }
530 
531 endconfig()
532 {
533 
534 	if (fconfig == NULL)
535 		return;
536 	fclose(fconfig);
537 	fconfig = NULL;
538 }
539 
540 struct servtab *
541 getconfigent()
542 {
543 	register struct servtab *sep = &serv;
544 	char *cp, *arg;
545 	int argc;
546 
547 more:
548 	while ((cp = nextline(fconfig)) && *cp == '#')
549 		;
550 	if (cp == NULL)
551 		return ((struct servtab *)0);
552 	sep->se_service = strdup(skip(&cp));
553 	arg = skip(&cp);
554 	if (strcmp(arg, "stream") == 0)
555 		sep->se_socktype = SOCK_STREAM;
556 	else if (strcmp(arg, "dgram") == 0)
557 		sep->se_socktype = SOCK_DGRAM;
558 	else if (strcmp(arg, "rdm") == 0)
559 		sep->se_socktype = SOCK_RDM;
560 	else if (strcmp(arg, "seqpacket") == 0)
561 		sep->se_socktype = SOCK_SEQPACKET;
562 	else if (strcmp(arg, "raw") == 0)
563 		sep->se_socktype = SOCK_RAW;
564 	else
565 		sep->se_socktype = -1;
566 	sep->se_proto = strdup(skip(&cp));
567 	arg = skip(&cp);
568 	sep->se_wait = strcmp(arg, "wait") == 0;
569 	sep->se_user = strdup(skip(&cp));
570 	sep->se_server = strdup(skip(&cp));
571 	if (strcmp(sep->se_server, "internal") == 0) {
572 		register struct biltin *bi;
573 
574 		for (bi = biltins; bi->bi_service; bi++)
575 			if (bi->bi_socktype == sep->se_socktype &&
576 			    strcmp(bi->bi_service, sep->se_service) == 0)
577 				break;
578 		if (bi->bi_service == 0) {
579 			syslog(LOG_ERR, "internal service %s unknown\n",
580 				sep->se_service);
581 			goto more;
582 		}
583 		sep->se_bi = bi;
584 		sep->se_wait = bi->bi_wait;
585 	} else
586 		sep->se_bi = NULL;
587 	argc = 0;
588 	for (arg = skip(&cp); cp; arg = skip(&cp))
589 		if (argc < MAXARGV)
590 			sep->se_argv[argc++] = strdup(arg);
591 	while (argc <= MAXARGV)
592 		sep->se_argv[argc++] = NULL;
593 	return (sep);
594 }
595 
596 freeconfig(cp)
597 	register struct servtab *cp;
598 {
599 	int i;
600 
601 	if (cp->se_service)
602 		free(cp->se_service);
603 	if (cp->se_proto)
604 		free(cp->se_proto);
605 	if (cp->se_user)
606 		free(cp->se_user);
607 	if (cp->se_server)
608 		free(cp->se_server);
609 	for (i = 0; i < MAXARGV; i++)
610 		if (cp->se_argv[i])
611 			free(cp->se_argv[i]);
612 }
613 
614 char *
615 skip(cpp)
616 	char **cpp;
617 {
618 	register char *cp = *cpp;
619 	char *start;
620 
621 again:
622 	while (*cp == ' ' || *cp == '\t')
623 		cp++;
624 	if (*cp == '\0') {
625 		char c;
626 
627 		c = getc(fconfig);
628 		ungetc(c, fconfig);
629 		if (c == ' ' || c == '\t')
630 			if (cp = nextline(fconfig))
631 				goto again;
632 		*cpp = (char *)0;
633 		return ((char *)0);
634 	}
635 	start = cp;
636 	while (*cp && *cp != ' ' && *cp != '\t')
637 		cp++;
638 	if (*cp != '\0')
639 		*cp++ = '\0';
640 	*cpp = cp;
641 	return (start);
642 }
643 
644 char *
645 nextline(fd)
646 	FILE *fd;
647 {
648 	char *cp;
649 
650 	if (fgets(line, sizeof (line), fd) == NULL)
651 		return ((char *)0);
652 	cp = index(line, '\n');
653 	if (cp)
654 		*cp = '\0';
655 	return (line);
656 }
657 
658 char *
659 strdup(cp)
660 	char *cp;
661 {
662 	char *new;
663 
664 	if (cp == NULL)
665 		cp = "";
666 	new = malloc((unsigned)(strlen(cp) + 1));
667 	if (new == (char *)0) {
668 		syslog(LOG_ERR, "Out of memory.");
669 		exit(-1);
670 	}
671 	strcpy(new, cp);
672 	return (new);
673 }
674 
675 setproctitle(a, s)
676 	char *a;
677 	int s;
678 {
679 	int size;
680 	register char *cp;
681 	struct sockaddr_in sin;
682 	char buf[80];
683 
684 	cp = Argv[0];
685 	size = sizeof(sin);
686 	if (getpeername(s, &sin, &size) == 0)
687 		sprintf(buf, "-%s [%s]", a, inet_ntoa(sin.sin_addr));
688 	else
689 		sprintf(buf, "-%s", a);
690 	strncpy(cp, buf, LastArg - cp);
691 	cp += strlen(cp);
692 	while (cp < LastArg)
693 		*cp++ = ' ';
694 }
695 
696 /*
697  * Internet services provided internally by inetd:
698  */
699 
700 /* ARGSUSED */
701 echo_stream(s, sep)		/* Echo service -- echo data back */
702 	int s;
703 	struct servtab *sep;
704 {
705 	char buffer[BUFSIZ];
706 	int i;
707 
708 	setproctitle("echo", s);
709 	while ((i = read(s, buffer, sizeof(buffer))) > 0 &&
710 	    write(s, buffer, i) > 0)
711 		;
712 	exit(0);
713 }
714 
715 /* ARGSUSED */
716 echo_dg(s, sep)			/* Echo service -- echo data back */
717 	int s;
718 	struct servtab *sep;
719 {
720 	char buffer[BUFSIZ];
721 	int i, size;
722 	struct sockaddr sa;
723 
724 	size = sizeof(sa);
725 	if ((i = recvfrom(s, buffer, sizeof(buffer), 0, &sa, &size)) < 0)
726 		return;
727 	(void) sendto(s, buffer, i, 0, &sa, sizeof(sa));
728 }
729 
730 /* ARGSUSED */
731 discard_stream(s, sep)		/* Discard service -- ignore data */
732 	int s;
733 	struct servtab *sep;
734 {
735 	char buffer[BUFSIZ];
736 
737 	setproctitle("discard", s);
738 	while (1) {
739 		while (read(s, buffer, sizeof(buffer)) > 0)
740 			;
741 		if (errno != EINTR)
742 			break;
743 	}
744 	exit(0);
745 }
746 
747 /* ARGSUSED */
748 discard_dg(s, sep)		/* Discard service -- ignore data */
749 	int s;
750 	struct servtab *sep;
751 {
752 	char buffer[BUFSIZ];
753 
754 	(void) read(s, buffer, sizeof(buffer));
755 }
756 
757 #include <ctype.h>
758 #define LINESIZ 72
759 char ring[128];
760 char *endring;
761 
762 initring()
763 {
764 	register int i;
765 
766 	endring = ring;
767 
768 	for (i = 0; i <= 128; ++i)
769 		if (isprint(i))
770 			*endring++ = i;
771 }
772 
773 /* ARGSUSED */
774 chargen_stream(s, sep)		/* Character generator */
775 	int s;
776 	struct servtab *sep;
777 {
778 	char text[LINESIZ+2];
779 	register int i;
780 	register char *rp, *rs, *dp;
781 
782 	setproctitle("discard", s);
783 	if (endring == 0)
784 		initring();
785 
786 	for (rs = ring; ; ++rs) {
787 		if (rs >= endring)
788 			rs = ring;
789 		rp = rs;
790 		dp = text;
791 		i = MIN(LINESIZ, endring - rp);
792 		bcopy(rp, dp, i);
793 		dp += i;
794 		if ((rp += i) >= endring)
795 			rp = ring;
796 		if (i < LINESIZ) {
797 			i = LINESIZ - i;
798 			bcopy(rp, dp, i);
799 			dp += i;
800 			if ((rp += i) >= endring)
801 				rp = ring;
802 		}
803 		*dp++ = '\r';
804 		*dp++ = '\n';
805 
806 		if (write(s, text, dp - text) != dp - text)
807 			break;
808 	}
809 	exit(0);
810 }
811 
812 /* ARGSUSED */
813 chargen_dg(s, sep)		/* Character generator */
814 	int s;
815 	struct servtab *sep;
816 {
817 	char text[LINESIZ+2];
818 	register int i;
819 	register char *rp;
820 	static char *rs = ring;
821 	struct sockaddr sa;
822 	int size;
823 
824 	if (endring == 0)
825 		initring();
826 
827 	size = sizeof(sa);
828 	if (recvfrom(s, text, sizeof(text), 0, &sa, &size) < 0)
829 		return;
830 	rp = rs;
831 	if (rs++ >= endring)
832 		rs = ring;
833 	i = MIN(LINESIZ - 2, endring - rp);
834 	bcopy(rp, text, i);
835 	if ((rp += i) >= endring)
836 		rp = ring;
837 	if (i < LINESIZ - 2) {
838 		bcopy(rp, text, i);
839 		if ((rp += i) >= endring)
840 			rp = ring;
841 	}
842 	text[LINESIZ - 2] = '\r';
843 	text[LINESIZ - 1] = '\n';
844 
845 	(void) sendto(s, text, sizeof(text), 0, &sa, sizeof(sa));
846 }
847 
848 /*
849  * Return a machine readable date and time, in the form of the
850  * number of seconds since midnight, Jan 1, 1900.  Since gettimeofday
851  * returns the number of seconds since midnight, Jan 1, 1970,
852  * we must add 2208988800 seconds to this figure to make up for
853  * some seventy years Bell Labs was asleep.
854  */
855 
856 long
857 machtime()
858 {
859 	struct timeval tv;
860 
861 	if (gettimeofday(&tv, (struct timezone *)0) < 0) {
862 		fprintf(stderr, "Unable to get time of day\n");
863 		return (0L);
864 	}
865 	return (htonl((long)tv.tv_sec + 2208988800));
866 }
867 
868 /* ARGSUSED */
869 machtime_stream(s, sep)
870 	int s;
871 	struct servtab *sep;
872 {
873 	long result;
874 
875 	result = machtime();
876 	(void) write(s, (char *) &result, sizeof(result));
877 }
878 
879 /* ARGSUSED */
880 machtime_dg(s, sep)
881 	int s;
882 	struct servtab *sep;
883 {
884 	long result;
885 	struct sockaddr sa;
886 	int size;
887 
888 	size = sizeof(sa);
889 	if (recvfrom(s, (char *)&result, sizeof(result), 0, &sa, &size) < 0)
890 		return;
891 	result = machtime();
892 	(void) sendto(s, (char *) &result, sizeof(result), 0, &sa, sizeof(sa));
893 }
894 
895 /* ARGSUSED */
896 daytime_stream(s, sep)		/* Return human-readable time of day */
897 	int s;
898 	struct servtab *sep;
899 {
900 	char buffer[256];
901 	time_t time(), clock;
902 	char *ctime();
903 
904 	clock = time((time_t *) 0);
905 
906 	sprintf(buffer, "%s\r", ctime(&clock));
907 	(void) write(s, buffer, strlen(buffer));
908 }
909 
910 /* ARGSUSED */
911 daytime_dg(s, sep)		/* Return human-readable time of day */
912 	int s;
913 	struct servtab *sep;
914 {
915 	char buffer[256];
916 	time_t time(), clock;
917 	struct sockaddr sa;
918 	int size;
919 	char *ctime();
920 
921 	clock = time((time_t *) 0);
922 
923 	size = sizeof(sa);
924 	if (recvfrom(s, buffer, sizeof(buffer), 0, &sa, &size) < 0)
925 		return;
926 	sprintf(buffer, "%s\r", ctime(&clock));
927 	(void) sendto(s, buffer, strlen(buffer), 0, &sa, sizeof(sa));
928 }
929 
930 /*
931  * print_service:
932  *	Dump relevant information to stderr
933  */
934 print_service(action, sep)
935 	char *action;
936 	struct servtab *sep;
937 {
938 	fprintf(stderr,
939 	    "%s: %s proto=%s, wait=%d, user=%s builtin=%x server=%s\n",
940 	    action, sep->se_service, sep->se_proto,
941 	    sep->se_wait, sep->se_user, sep->se_bi, sep->se_server);
942 }
943