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