replace ancient sun support with tahoe support
[unix-history] / usr / src / usr.sbin / inetd / inetd.c
CommitLineData
528b0614
DF
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
8char copyright[] =
9"@(#) Copyright (c) 1983 Regents of the University of California.\n\
10 All rights reserved.\n";
11#endif not lint
12
21ed1185 13#ifndef lint
9a0fbd5b 14static char sccsid[] = "@(#)inetd.c 5.7 (Berkeley) %G%";
528b0614 15#endif not lint
21ed1185
MK
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
7d5eb6c4 46 * user user to run daemon as
21ed1185
MK
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>
2a6b82aa
JL
58#include <sys/time.h>
59#include <sys/resource.h>
21ed1185
MK
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>
6a3125d9 68#include <syslog.h>
7d5eb6c4 69#include <pwd.h>
21ed1185 70
fc99bd8d
MK
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
21ed1185
MK
77extern int errno;
78
fc99bd8d 79int reapchild(), retry();
21ed1185
MK
80char *index();
81char *malloc();
82
83int debug = 0;
5859fc43
MK
84int nsock, maxsock;
85fd_set allsock;
21ed1185 86int options;
fc99bd8d 87int timingout;
21ed1185
MK
88struct servent *sp;
89
90struct 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 */
7d5eb6c4 96 char *se_user; /* user name to run as */
b1b30605 97 struct biltin *se_bi; /* if built-in, description */
21ed1185
MK
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 */
fc99bd8d
MK
103 int se_count; /* number started since se_time */
104 struct timeval se_time; /* start of se_count */
21ed1185
MK
105 struct servtab *se_next;
106} *servtab;
107
b1b30605
MK
108int echo_stream(), discard_stream(), machtime_stream();
109int daytime_stream(), chargen_stream();
110int echo_dg(), discard_dg(), machtime_dg(), daytime_dg(), chargen_dg();
111
112struct 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))
21ed1185 142char *CONFIG = "/etc/inetd.conf";
b1b30605
MK
143char **Argv;
144char *LastArg;
21ed1185 145
b1b30605 146main(argc, argv, envp)
21ed1185 147 int argc;
b1b30605 148 char *argv[], *envp[];
21ed1185 149{
21ed1185 150 register struct servtab *sep;
7d5eb6c4 151 register struct passwd *pwd;
21ed1185 152 char *cp, buf[50];
fc99bd8d
MK
153 int pid, i, dofork;
154 struct sigvec sv;
21ed1185 155
b1b30605
MK
156 Argv = argv;
157 if (envp == 0 || *envp == 0)
158 envp = argv;
159 while (*envp)
160 envp++;
161 LastArg = envp[-1] + strlen(envp[-1]);
21ed1185
MK
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 }
176nextopt:
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) {
2a6b82aa 193 ioctl(tt, TIOCNOTTY, (char *)0);
21ed1185
MK
194 close(tt);
195 }
196 }
197#endif
fc99bd8d
MK
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);
21ed1185 203 config();
fc99bd8d
MK
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
21ed1185 209 for (;;) {
fc99bd8d
MK
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--;
21ed1185
MK
226 if (debug)
227 fprintf(stderr, "someone wants %s\n", sep->se_service);
5859fc43 228 if (!sep->se_wait && sep->se_socktype == SOCK_STREAM) {
fc99bd8d
MK
229 ctrl = accept(sep->se_fd, (struct sockaddr *)0,
230 (int *)0);
6a3125d9
RC
231 if (debug)
232 fprintf(stderr, "accept, ctrl %d\n", ctrl);
21ed1185
MK
233 if (ctrl < 0) {
234 if (errno == EINTR)
235 continue;
6a3125d9 236 syslog(LOG_WARNING, "accept: %m");
21ed1185
MK
237 continue;
238 }
239 } else
240 ctrl = sep->se_fd;
fc99bd8d 241 (void) sigblock(SIGBLOCK);
b1b30605 242 pid = 0;
fc99bd8d
MK
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 }
b1b30605 273 pid = fork();
fc99bd8d 274 }
21ed1185 275 if (pid < 0) {
5859fc43 276 if (!sep->se_wait && sep->se_socktype == SOCK_STREAM)
21ed1185 277 close(ctrl);
fc99bd8d 278 sigsetmask(0);
21ed1185
MK
279 sleep(1);
280 continue;
281 }
fc99bd8d 282 if (pid && sep->se_wait) {
21ed1185 283 sep->se_wait = pid;
fc99bd8d 284 FD_CLR(sep->se_fd, &allsock);
5859fc43 285 nsock--;
21ed1185
MK
286 }
287 sigsetmask(0);
288 if (pid == 0) {
289#ifdef DEBUG
fc99bd8d
MK
290 int tt;
291
292 if (dofork && (tt = open("/dev/tty", O_RDWR)) > 0) {
21ed1185
MK
293 ioctl(tt, TIOCNOTTY, 0);
294 close(tt);
295 }
296#endif
fc99bd8d 297 if (dofork)
b1b30605
MK
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);
fc99bd8d
MK
312 if (sep->se_socktype != SOCK_STREAM)
313 recv(0, buf, sizeof (buf), 0);
b1b30605
MK
314 _exit(1);
315 }
316 if (pwd->pw_uid) {
2a6b82aa 317 (void) setgid((gid_t)pwd->pw_gid);
b1b30605 318 initgroups(pwd->pw_name, pwd->pw_gid);
2a6b82aa 319 (void) setuid((uid_t)pwd->pw_uid);
b1b30605
MK
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);
7d5eb6c4 329 }
21ed1185 330 }
5859fc43 331 if (!sep->se_wait && sep->se_socktype == SOCK_STREAM)
21ed1185 332 close(ctrl);
fc99bd8d 333 }
21ed1185
MK
334 }
335}
336
337reapchild()
338{
339 union wait status;
340 int pid;
341 register struct servtab *sep;
342
343 for (;;) {
2a6b82aa 344 pid = wait3(&status, WNOHANG, (struct rusage *)0);
21ed1185
MK
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)
6a3125d9
RC
352 syslog(LOG_WARNING,
353 "%s: exit status 0x%x",
21ed1185
MK
354 sep->se_server, status);
355 if (debug)
356 fprintf(stderr, "restored %s, fd %d\n",
357 sep->se_service, sep->se_fd);
5859fc43
MK
358 FD_SET(sep->se_fd, &allsock);
359 nsock++;
21ed1185
MK
360 sep->se_wait = 1;
361 }
362 }
363}
364
365config()
366{
367 register struct servtab *sep, *cp, **sepp;
368 struct servtab *getconfigent(), *enter();
fc99bd8d 369 int omask;
21ed1185
MK
370
371 if (!setconfig()) {
6a3125d9 372 syslog(LOG_ERR, "%s: %m", CONFIG);
21ed1185
MK
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
fc99bd8d
MK
385 omask = sigblock(SIGBLOCK);
386 if (cp->se_bi == 0)
387 sep->se_wait = cp->se_wait;
21ed1185 388#define SWAP(a, b) { char *c = a; a = b; b = c; }
2a6b82aa
JL
389 if (cp->se_user)
390 SWAP(sep->se_user, cp->se_user);
21ed1185
MK
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);
9a0fbd5b
MK
397 if (debug)
398 print_service("REDO", sep);
399 } else {
21ed1185 400 sep = enter(cp);
9a0fbd5b
MK
401 if (debug)
402 print_service("ADD ", sep);
403 }
21ed1185 404 sep->se_checked = 1;
21ed1185
MK
405 sp = getservbyname(sep->se_service, sep->se_proto);
406 if (sp == 0) {
6a3125d9 407 syslog(LOG_ERR, "%s/%s: unknown service",
21ed1185
MK
408 sep->se_service, sep->se_proto);
409 continue;
410 }
fc99bd8d
MK
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;
21ed1185 416 }
fc99bd8d
MK
417 if (sep->se_fd == -1)
418 setup(sep);
21ed1185
MK
419 }
420 endconfig();
421 /*
422 * Purge anything not looked at above.
423 */
fc99bd8d 424 omask = sigblock(SIGBLOCK);
21ed1185
MK
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) {
5859fc43
MK
433 FD_CLR(sep->se_fd, &allsock);
434 nsock--;
21ed1185
MK
435 (void) close(sep->se_fd);
436 }
9a0fbd5b
MK
437 if (debug)
438 print_service("FREE", sep);
21ed1185
MK
439 freeconfig(sep);
440 free((char *)sep);
441 }
442 (void) sigsetmask(omask);
443}
444
fc99bd8d
MK
445retry()
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
455setup(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) \
466setsockopt(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
21ed1185
MK
493struct servtab *
494enter(cp)
495 struct servtab *cp;
496{
497 register struct servtab *sep;
5859fc43 498 int omask;
21ed1185
MK
499 char *strdup();
500
501 sep = (struct servtab *)malloc(sizeof (*sep));
502 if (sep == (struct servtab *)0) {
6a3125d9 503 syslog(LOG_ERR, "Out of memory.");
21ed1185
MK
504 exit(-1);
505 }
506 *sep = *cp;
507 sep->se_fd = -1;
fc99bd8d 508 omask = sigblock(SIGBLOCK);
21ed1185
MK
509 sep->se_next = servtab;
510 servtab = sep;
511 sigsetmask(omask);
512 return (sep);
513}
514
515FILE *fconfig = NULL;
516struct servtab serv;
517char line[256];
518char *skip(), *nextline();
519
520setconfig()
521{
522
523 if (fconfig != NULL) {
2a6b82aa 524 fseek(fconfig, 0L, L_SET);
21ed1185
MK
525 return (1);
526 }
527 fconfig = fopen(CONFIG, "r");
528 return (fconfig != NULL);
529}
530
531endconfig()
532{
533
534 if (fconfig == NULL)
535 return;
536 fclose(fconfig);
537 fconfig = NULL;
538}
539
540struct servtab *
541getconfigent()
542{
543 register struct servtab *sep = &serv;
544 char *cp, *arg;
545 int argc;
546
b1b30605 547more:
21ed1185
MK
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;
7d5eb6c4 569 sep->se_user = strdup(skip(&cp));
21ed1185 570 sep->se_server = strdup(skip(&cp));
b1b30605
MK
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;
9a0fbd5b
MK
585 } else
586 sep->se_bi = NULL;
21ed1185
MK
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
596freeconfig(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);
2a6b82aa
JL
605 if (cp->se_user)
606 free(cp->se_user);
21ed1185
MK
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
614char *
615skip(cpp)
616 char **cpp;
617{
618 register char *cp = *cpp;
619 char *start;
620
621again:
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
644char *
645nextline(fd)
646 FILE *fd;
647{
648 char *cp;
649
2a6b82aa 650 if (fgets(line, sizeof (line), fd) == NULL)
21ed1185
MK
651 return ((char *)0);
652 cp = index(line, '\n');
653 if (cp)
654 *cp = '\0';
655 return (line);
656}
657
658char *
659strdup(cp)
660 char *cp;
661{
662 char *new;
663
664 if (cp == NULL)
665 cp = "";
2a6b82aa 666 new = malloc((unsigned)(strlen(cp) + 1));
21ed1185 667 if (new == (char *)0) {
6a3125d9 668 syslog(LOG_ERR, "Out of memory.");
21ed1185
MK
669 exit(-1);
670 }
671 strcpy(new, cp);
672 return (new);
673}
b1b30605
MK
674
675setproctitle(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 */
701echo_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 */
716echo_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 */
731discard_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 */
748discard_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
759char ring[128];
760char *endring;
761
762initring()
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 */
774chargen_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 */
813chargen_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 */
b1b30605
MK
855
856long
857machtime()
858{
859 struct timeval tv;
860
2a6b82aa 861 if (gettimeofday(&tv, (struct timezone *)0) < 0) {
b1b30605 862 fprintf(stderr, "Unable to get time of day\n");
2a6b82aa 863 return (0L);
b1b30605
MK
864 }
865 return (htonl((long)tv.tv_sec + 2208988800));
866}
867
868/* ARGSUSED */
869machtime_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 */
880machtime_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);
2a6b82aa 889 if (recvfrom(s, (char *)&result, sizeof(result), 0, &sa, &size) < 0)
b1b30605
MK
890 return;
891 result = machtime();
892 (void) sendto(s, (char *) &result, sizeof(result), 0, &sa, sizeof(sa));
893}
894
895/* ARGSUSED */
896daytime_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));
2a6b82aa 907 (void) write(s, buffer, strlen(buffer));
b1b30605
MK
908}
909
910/* ARGSUSED */
911daytime_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}
9a0fbd5b
MK
929
930/*
931 * print_service:
932 * Dump relevant information to stderr
933 */
934print_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}