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