date and time created 87/10/16 16:19:31 by bostic
[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
92732149 14static char sccsid[] = "@(#)inetd.c 5.9 (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 }
92732149 197 (void) setpgrp(0, 0);
21ed1185 198#endif
fc99bd8d
MK
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);
21ed1185 204 config();
fc99bd8d
MK
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
21ed1185 210 for (;;) {
fc99bd8d
MK
211 int s, ctrl, n;
212 fd_set readable;
213
0ee95e67
MK
214 if (nsock == 0) {
215 (void) sigblock(SIGBLOCK);
216 while (nsock == 0)
92732149
KB
217 sigpause(0L);
218 (void) sigsetmask(0L);
0ee95e67 219 }
fc99bd8d
MK
220 readable = allsock;
221 if ((n = select(maxsock + 1, &readable, (fd_set *)0,
222 (fd_set *)0, (struct timeval *)0)) <= 0) {
223 if (n < 0 && errno != EINTR)
0ee95e67 224 syslog(LOG_WARNING, "select: %m\n");
fc99bd8d
MK
225 sleep(1);
226 continue;
227 }
228 for (sep = servtab; n && sep; sep = sep->se_next)
229 if (FD_ISSET(sep->se_fd, &readable)) {
230 n--;
21ed1185
MK
231 if (debug)
232 fprintf(stderr, "someone wants %s\n", sep->se_service);
5859fc43 233 if (!sep->se_wait && sep->se_socktype == SOCK_STREAM) {
fc99bd8d
MK
234 ctrl = accept(sep->se_fd, (struct sockaddr *)0,
235 (int *)0);
6a3125d9
RC
236 if (debug)
237 fprintf(stderr, "accept, ctrl %d\n", ctrl);
21ed1185
MK
238 if (ctrl < 0) {
239 if (errno == EINTR)
240 continue;
6a3125d9 241 syslog(LOG_WARNING, "accept: %m");
21ed1185
MK
242 continue;
243 }
244 } else
245 ctrl = sep->se_fd;
fc99bd8d 246 (void) sigblock(SIGBLOCK);
b1b30605 247 pid = 0;
fc99bd8d
MK
248 dofork = (sep->se_bi == 0 || sep->se_bi->bi_fork);
249 if (dofork) {
250 if (sep->se_count++ == 0)
251 (void)gettimeofday(&sep->se_time,
252 (struct timezone *)0);
253 else if (sep->se_count >= TOOMANY) {
254 struct timeval now;
255
256 (void)gettimeofday(&now, (struct timezone *)0);
257 if (now.tv_sec - sep->se_time.tv_sec >
258 CNT_INTVL) {
259 sep->se_time = now;
260 sep->se_count = 1;
261 } else {
262 syslog(LOG_ERR,
263 "%s/%s server failing (looping), service terminated\n",
264 sep->se_service, sep->se_proto);
265 FD_CLR(sep->se_fd, &allsock);
266 (void) close(sep->se_fd);
267 sep->se_fd = -1;
268 sep->se_count = 0;
269 nsock--;
92732149 270 sigsetmask(0L);
fc99bd8d
MK
271 if (!timingout) {
272 timingout = 1;
273 alarm(RETRYTIME);
274 }
275 continue;
276 }
277 }
b1b30605 278 pid = fork();
fc99bd8d 279 }
21ed1185 280 if (pid < 0) {
5859fc43 281 if (!sep->se_wait && sep->se_socktype == SOCK_STREAM)
21ed1185 282 close(ctrl);
92732149 283 sigsetmask(0L);
21ed1185
MK
284 sleep(1);
285 continue;
286 }
fc99bd8d 287 if (pid && sep->se_wait) {
21ed1185 288 sep->se_wait = pid;
fc99bd8d 289 FD_CLR(sep->se_fd, &allsock);
5859fc43 290 nsock--;
21ed1185 291 }
92732149 292 sigsetmask(0L);
21ed1185
MK
293 if (pid == 0) {
294#ifdef DEBUG
fc99bd8d
MK
295 int tt;
296
297 if (dofork && (tt = open("/dev/tty", O_RDWR)) > 0) {
21ed1185
MK
298 ioctl(tt, TIOCNOTTY, 0);
299 close(tt);
300 }
301#endif
fc99bd8d 302 if (dofork)
b1b30605
MK
303 for (i = getdtablesize(); --i > 2; )
304 if (i != ctrl)
305 close(i);
306 if (sep->se_bi)
307 (*sep->se_bi->bi_fn)(ctrl, sep);
308 else {
309 dup2(ctrl, 0);
310 close(ctrl);
311 dup2(0, 1);
312 dup2(0, 2);
313 if ((pwd = getpwnam(sep->se_user)) == NULL) {
314 syslog(LOG_ERR,
315 "getpwnam: %s: No such user",
316 sep->se_user);
fc99bd8d
MK
317 if (sep->se_socktype != SOCK_STREAM)
318 recv(0, buf, sizeof (buf), 0);
b1b30605
MK
319 _exit(1);
320 }
321 if (pwd->pw_uid) {
2a6b82aa 322 (void) setgid((gid_t)pwd->pw_gid);
b1b30605 323 initgroups(pwd->pw_name, pwd->pw_gid);
2a6b82aa 324 (void) setuid((uid_t)pwd->pw_uid);
b1b30605
MK
325 }
326 if (debug)
327 fprintf(stderr, "%d execl %s\n",
328 getpid(), sep->se_server);
329 execv(sep->se_server, sep->se_argv);
330 if (sep->se_socktype != SOCK_STREAM)
331 recv(0, buf, sizeof (buf), 0);
332 syslog(LOG_ERR, "execv %s: %m", sep->se_server);
333 _exit(1);
7d5eb6c4 334 }
21ed1185 335 }
5859fc43 336 if (!sep->se_wait && sep->se_socktype == SOCK_STREAM)
21ed1185 337 close(ctrl);
fc99bd8d 338 }
21ed1185
MK
339 }
340}
341
342reapchild()
343{
344 union wait status;
345 int pid;
346 register struct servtab *sep;
347
348 for (;;) {
2a6b82aa 349 pid = wait3(&status, WNOHANG, (struct rusage *)0);
21ed1185
MK
350 if (pid <= 0)
351 break;
352 if (debug)
353 fprintf(stderr, "%d reaped\n", pid);
354 for (sep = servtab; sep; sep = sep->se_next)
355 if (sep->se_wait == pid) {
356 if (status.w_status)
6a3125d9
RC
357 syslog(LOG_WARNING,
358 "%s: exit status 0x%x",
21ed1185
MK
359 sep->se_server, status);
360 if (debug)
361 fprintf(stderr, "restored %s, fd %d\n",
362 sep->se_service, sep->se_fd);
5859fc43
MK
363 FD_SET(sep->se_fd, &allsock);
364 nsock++;
21ed1185
MK
365 sep->se_wait = 1;
366 }
367 }
368}
369
370config()
371{
372 register struct servtab *sep, *cp, **sepp;
373 struct servtab *getconfigent(), *enter();
92732149 374 long omask;
21ed1185
MK
375
376 if (!setconfig()) {
6a3125d9 377 syslog(LOG_ERR, "%s: %m", CONFIG);
21ed1185
MK
378 return;
379 }
380 for (sep = servtab; sep; sep = sep->se_next)
381 sep->se_checked = 0;
382 while (cp = getconfigent()) {
383 for (sep = servtab; sep; sep = sep->se_next)
384 if (strcmp(sep->se_service, cp->se_service) == 0 &&
385 strcmp(sep->se_proto, cp->se_proto) == 0)
386 break;
387 if (sep != 0) {
388 int i;
389
fc99bd8d
MK
390 omask = sigblock(SIGBLOCK);
391 if (cp->se_bi == 0)
392 sep->se_wait = cp->se_wait;
21ed1185 393#define SWAP(a, b) { char *c = a; a = b; b = c; }
2a6b82aa
JL
394 if (cp->se_user)
395 SWAP(sep->se_user, cp->se_user);
21ed1185
MK
396 if (cp->se_server)
397 SWAP(sep->se_server, cp->se_server);
398 for (i = 0; i < MAXARGV; i++)
399 SWAP(sep->se_argv[i], cp->se_argv[i]);
400 sigsetmask(omask);
401 freeconfig(cp);
9a0fbd5b
MK
402 if (debug)
403 print_service("REDO", sep);
404 } else {
21ed1185 405 sep = enter(cp);
9a0fbd5b
MK
406 if (debug)
407 print_service("ADD ", sep);
408 }
21ed1185 409 sep->se_checked = 1;
21ed1185
MK
410 sp = getservbyname(sep->se_service, sep->se_proto);
411 if (sp == 0) {
6a3125d9 412 syslog(LOG_ERR, "%s/%s: unknown service",
21ed1185
MK
413 sep->se_service, sep->se_proto);
414 continue;
415 }
fc99bd8d
MK
416 if (sp->s_port != sep->se_ctrladdr.sin_port) {
417 sep->se_ctrladdr.sin_port = sp->s_port;
418 if (sep->se_fd != -1)
419 (void) close(sep->se_fd);
420 sep->se_fd = -1;
21ed1185 421 }
fc99bd8d
MK
422 if (sep->se_fd == -1)
423 setup(sep);
21ed1185
MK
424 }
425 endconfig();
426 /*
427 * Purge anything not looked at above.
428 */
fc99bd8d 429 omask = sigblock(SIGBLOCK);
21ed1185
MK
430 sepp = &servtab;
431 while (sep = *sepp) {
432 if (sep->se_checked) {
433 sepp = &sep->se_next;
434 continue;
435 }
436 *sepp = sep->se_next;
437 if (sep->se_fd != -1) {
5859fc43
MK
438 FD_CLR(sep->se_fd, &allsock);
439 nsock--;
21ed1185
MK
440 (void) close(sep->se_fd);
441 }
9a0fbd5b
MK
442 if (debug)
443 print_service("FREE", sep);
21ed1185
MK
444 freeconfig(sep);
445 free((char *)sep);
446 }
447 (void) sigsetmask(omask);
448}
449
fc99bd8d
MK
450retry()
451{
452 register struct servtab *sep;
453
454 timingout = 0;
455 for (sep = servtab; sep; sep = sep->se_next)
456 if (sep->se_fd == -1)
457 setup(sep);
458}
459
460setup(sep)
461 register struct servtab *sep;
462{
463 int on = 1;
464
465 if ((sep->se_fd = socket(AF_INET, sep->se_socktype, 0)) < 0) {
466 syslog(LOG_ERR, "%s/%s: socket: %m",
467 sep->se_service, sep->se_proto);
468 return;
469 }
470#define turnon(fd, opt) \
471setsockopt(fd, SOL_SOCKET, opt, (char *)&on, sizeof (on))
472 if (strcmp(sep->se_proto, "tcp") == 0 && (options & SO_DEBUG) &&
473 turnon(sep->se_fd, SO_DEBUG) < 0)
474 syslog(LOG_ERR, "setsockopt (SO_DEBUG): %m");
475 if (turnon(sep->se_fd, SO_REUSEADDR) < 0)
476 syslog(LOG_ERR, "setsockopt (SO_REUSEADDR): %m");
477#undef turnon
478 if (bind(sep->se_fd, &sep->se_ctrladdr,
479 sizeof (sep->se_ctrladdr)) < 0) {
480 syslog(LOG_ERR, "%s/%s: bind: %m",
481 sep->se_service, sep->se_proto);
482 (void) close(sep->se_fd);
483 sep->se_fd = -1;
484 if (!timingout) {
485 timingout = 1;
486 alarm(RETRYTIME);
487 }
488 return;
489 }
490 if (sep->se_socktype == SOCK_STREAM)
491 listen(sep->se_fd, 10);
492 FD_SET(sep->se_fd, &allsock);
493 nsock++;
494 if (sep->se_fd > maxsock)
495 maxsock = sep->se_fd;
496}
497
21ed1185
MK
498struct servtab *
499enter(cp)
500 struct servtab *cp;
501{
502 register struct servtab *sep;
92732149 503 long omask;
21ed1185
MK
504 char *strdup();
505
506 sep = (struct servtab *)malloc(sizeof (*sep));
507 if (sep == (struct servtab *)0) {
6a3125d9 508 syslog(LOG_ERR, "Out of memory.");
21ed1185
MK
509 exit(-1);
510 }
511 *sep = *cp;
512 sep->se_fd = -1;
fc99bd8d 513 omask = sigblock(SIGBLOCK);
21ed1185
MK
514 sep->se_next = servtab;
515 servtab = sep;
516 sigsetmask(omask);
517 return (sep);
518}
519
520FILE *fconfig = NULL;
521struct servtab serv;
522char line[256];
523char *skip(), *nextline();
524
525setconfig()
526{
527
528 if (fconfig != NULL) {
2a6b82aa 529 fseek(fconfig, 0L, L_SET);
21ed1185
MK
530 return (1);
531 }
532 fconfig = fopen(CONFIG, "r");
533 return (fconfig != NULL);
534}
535
536endconfig()
537{
538
539 if (fconfig == NULL)
540 return;
541 fclose(fconfig);
542 fconfig = NULL;
543}
544
545struct servtab *
546getconfigent()
547{
548 register struct servtab *sep = &serv;
549 char *cp, *arg;
550 int argc;
551
b1b30605 552more:
21ed1185
MK
553 while ((cp = nextline(fconfig)) && *cp == '#')
554 ;
555 if (cp == NULL)
556 return ((struct servtab *)0);
557 sep->se_service = strdup(skip(&cp));
558 arg = skip(&cp);
559 if (strcmp(arg, "stream") == 0)
560 sep->se_socktype = SOCK_STREAM;
561 else if (strcmp(arg, "dgram") == 0)
562 sep->se_socktype = SOCK_DGRAM;
563 else if (strcmp(arg, "rdm") == 0)
564 sep->se_socktype = SOCK_RDM;
565 else if (strcmp(arg, "seqpacket") == 0)
566 sep->se_socktype = SOCK_SEQPACKET;
567 else if (strcmp(arg, "raw") == 0)
568 sep->se_socktype = SOCK_RAW;
569 else
570 sep->se_socktype = -1;
571 sep->se_proto = strdup(skip(&cp));
572 arg = skip(&cp);
573 sep->se_wait = strcmp(arg, "wait") == 0;
7d5eb6c4 574 sep->se_user = strdup(skip(&cp));
21ed1185 575 sep->se_server = strdup(skip(&cp));
b1b30605
MK
576 if (strcmp(sep->se_server, "internal") == 0) {
577 register struct biltin *bi;
578
579 for (bi = biltins; bi->bi_service; bi++)
580 if (bi->bi_socktype == sep->se_socktype &&
581 strcmp(bi->bi_service, sep->se_service) == 0)
582 break;
583 if (bi->bi_service == 0) {
584 syslog(LOG_ERR, "internal service %s unknown\n",
585 sep->se_service);
586 goto more;
587 }
588 sep->se_bi = bi;
589 sep->se_wait = bi->bi_wait;
9a0fbd5b
MK
590 } else
591 sep->se_bi = NULL;
21ed1185
MK
592 argc = 0;
593 for (arg = skip(&cp); cp; arg = skip(&cp))
594 if (argc < MAXARGV)
595 sep->se_argv[argc++] = strdup(arg);
596 while (argc <= MAXARGV)
597 sep->se_argv[argc++] = NULL;
598 return (sep);
599}
600
601freeconfig(cp)
602 register struct servtab *cp;
603{
604 int i;
605
606 if (cp->se_service)
607 free(cp->se_service);
608 if (cp->se_proto)
609 free(cp->se_proto);
2a6b82aa
JL
610 if (cp->se_user)
611 free(cp->se_user);
21ed1185
MK
612 if (cp->se_server)
613 free(cp->se_server);
614 for (i = 0; i < MAXARGV; i++)
615 if (cp->se_argv[i])
616 free(cp->se_argv[i]);
617}
618
619char *
620skip(cpp)
621 char **cpp;
622{
623 register char *cp = *cpp;
624 char *start;
625
626again:
627 while (*cp == ' ' || *cp == '\t')
628 cp++;
629 if (*cp == '\0') {
630 char c;
631
632 c = getc(fconfig);
633 ungetc(c, fconfig);
634 if (c == ' ' || c == '\t')
635 if (cp = nextline(fconfig))
636 goto again;
637 *cpp = (char *)0;
638 return ((char *)0);
639 }
640 start = cp;
641 while (*cp && *cp != ' ' && *cp != '\t')
642 cp++;
643 if (*cp != '\0')
644 *cp++ = '\0';
645 *cpp = cp;
646 return (start);
647}
648
649char *
650nextline(fd)
651 FILE *fd;
652{
653 char *cp;
654
2a6b82aa 655 if (fgets(line, sizeof (line), fd) == NULL)
21ed1185
MK
656 return ((char *)0);
657 cp = index(line, '\n');
658 if (cp)
659 *cp = '\0';
660 return (line);
661}
662
663char *
664strdup(cp)
665 char *cp;
666{
667 char *new;
668
669 if (cp == NULL)
670 cp = "";
2a6b82aa 671 new = malloc((unsigned)(strlen(cp) + 1));
21ed1185 672 if (new == (char *)0) {
6a3125d9 673 syslog(LOG_ERR, "Out of memory.");
21ed1185
MK
674 exit(-1);
675 }
676 strcpy(new, cp);
677 return (new);
678}
b1b30605
MK
679
680setproctitle(a, s)
681 char *a;
682 int s;
683{
684 int size;
685 register char *cp;
686 struct sockaddr_in sin;
687 char buf[80];
688
689 cp = Argv[0];
690 size = sizeof(sin);
691 if (getpeername(s, &sin, &size) == 0)
692 sprintf(buf, "-%s [%s]", a, inet_ntoa(sin.sin_addr));
693 else
694 sprintf(buf, "-%s", a);
695 strncpy(cp, buf, LastArg - cp);
696 cp += strlen(cp);
697 while (cp < LastArg)
698 *cp++ = ' ';
699}
700
701/*
702 * Internet services provided internally by inetd:
703 */
704
705/* ARGSUSED */
706echo_stream(s, sep) /* Echo service -- echo data back */
707 int s;
708 struct servtab *sep;
709{
710 char buffer[BUFSIZ];
711 int i;
712
0ee95e67 713 setproctitle(sep->se_service, s);
b1b30605
MK
714 while ((i = read(s, buffer, sizeof(buffer))) > 0 &&
715 write(s, buffer, i) > 0)
716 ;
717 exit(0);
718}
719
720/* ARGSUSED */
721echo_dg(s, sep) /* Echo service -- echo data back */
722 int s;
723 struct servtab *sep;
724{
725 char buffer[BUFSIZ];
726 int i, size;
727 struct sockaddr sa;
728
729 size = sizeof(sa);
730 if ((i = recvfrom(s, buffer, sizeof(buffer), 0, &sa, &size)) < 0)
731 return;
732 (void) sendto(s, buffer, i, 0, &sa, sizeof(sa));
733}
734
735/* ARGSUSED */
736discard_stream(s, sep) /* Discard service -- ignore data */
737 int s;
738 struct servtab *sep;
739{
740 char buffer[BUFSIZ];
741
0ee95e67 742 setproctitle(sep->se_service, s);
b1b30605
MK
743 while (1) {
744 while (read(s, buffer, sizeof(buffer)) > 0)
745 ;
746 if (errno != EINTR)
747 break;
748 }
749 exit(0);
750}
751
752/* ARGSUSED */
753discard_dg(s, sep) /* Discard service -- ignore data */
754 int s;
755 struct servtab *sep;
756{
757 char buffer[BUFSIZ];
758
759 (void) read(s, buffer, sizeof(buffer));
760}
761
762#include <ctype.h>
763#define LINESIZ 72
764char ring[128];
765char *endring;
766
767initring()
768{
769 register int i;
770
771 endring = ring;
772
773 for (i = 0; i <= 128; ++i)
774 if (isprint(i))
775 *endring++ = i;
776}
777
778/* ARGSUSED */
779chargen_stream(s, sep) /* Character generator */
780 int s;
781 struct servtab *sep;
782{
92732149
KB
783 register char *rs;
784 int len;
b1b30605 785 char text[LINESIZ+2];
b1b30605 786
0ee95e67 787 setproctitle(sep->se_service, s);
92732149
KB
788
789 if (!endring) {
b1b30605 790 initring();
92732149
KB
791 rs = ring;
792 }
b1b30605 793
92732149
KB
794 text[LINESIZ] = '\r';
795 text[LINESIZ + 1] = '\n';
796 for (rs = ring;;) {
797 if ((len = endring - rs) >= LINESIZ)
798 bcopy(rs, text, LINESIZ);
799 else {
800 bcopy(rs, text, len);
801 bcopy(ring, text + len, LINESIZ - len);
b1b30605 802 }
92732149
KB
803 if (++rs == endring)
804 rs = ring;
805 if (write(s, text, sizeof(text)) != sizeof(text))
b1b30605
MK
806 break;
807 }
808 exit(0);
809}
810
811/* ARGSUSED */
812chargen_dg(s, sep) /* Character generator */
813 int s;
814 struct servtab *sep;
815{
b1b30605 816 struct sockaddr sa;
92732149
KB
817 static char *rs;
818 int len, size;
819 char text[LINESIZ+2];
b1b30605 820
92732149 821 if (endring == 0) {
b1b30605 822 initring();
92732149
KB
823 rs = ring;
824 }
b1b30605
MK
825
826 size = sizeof(sa);
827 if (recvfrom(s, text, sizeof(text), 0, &sa, &size) < 0)
828 return;
b1b30605 829
92732149
KB
830 if ((len = endring - rs) >= LINESIZ)
831 bcopy(rs, text, LINESIZ);
832 else {
833 bcopy(rs, text, len);
834 bcopy(ring, text + len, LINESIZ - len);
835 }
836 if (++rs == endring)
837 rs = ring;
838 text[LINESIZ] = '\r';
839 text[LINESIZ + 1] = '\n';
b1b30605
MK
840 (void) sendto(s, text, sizeof(text), 0, &sa, sizeof(sa));
841}
842
843/*
844 * Return a machine readable date and time, in the form of the
845 * number of seconds since midnight, Jan 1, 1900. Since gettimeofday
846 * returns the number of seconds since midnight, Jan 1, 1970,
847 * we must add 2208988800 seconds to this figure to make up for
848 * some seventy years Bell Labs was asleep.
849 */
b1b30605
MK
850
851long
852machtime()
853{
854 struct timeval tv;
855
2a6b82aa 856 if (gettimeofday(&tv, (struct timezone *)0) < 0) {
b1b30605 857 fprintf(stderr, "Unable to get time of day\n");
2a6b82aa 858 return (0L);
b1b30605
MK
859 }
860 return (htonl((long)tv.tv_sec + 2208988800));
861}
862
863/* ARGSUSED */
864machtime_stream(s, sep)
865 int s;
866 struct servtab *sep;
867{
868 long result;
869
870 result = machtime();
871 (void) write(s, (char *) &result, sizeof(result));
872}
873
874/* ARGSUSED */
875machtime_dg(s, sep)
876 int s;
877 struct servtab *sep;
878{
879 long result;
880 struct sockaddr sa;
881 int size;
882
883 size = sizeof(sa);
2a6b82aa 884 if (recvfrom(s, (char *)&result, sizeof(result), 0, &sa, &size) < 0)
b1b30605
MK
885 return;
886 result = machtime();
887 (void) sendto(s, (char *) &result, sizeof(result), 0, &sa, sizeof(sa));
888}
889
890/* ARGSUSED */
891daytime_stream(s, sep) /* Return human-readable time of day */
892 int s;
893 struct servtab *sep;
894{
895 char buffer[256];
896 time_t time(), clock;
897 char *ctime();
898
899 clock = time((time_t *) 0);
900
92732149 901 sprintf(buffer, "%.24s\r\n", ctime(&clock));
2a6b82aa 902 (void) write(s, buffer, strlen(buffer));
b1b30605
MK
903}
904
905/* ARGSUSED */
906daytime_dg(s, sep) /* Return human-readable time of day */
907 int s;
908 struct servtab *sep;
909{
910 char buffer[256];
911 time_t time(), clock;
912 struct sockaddr sa;
913 int size;
914 char *ctime();
915
916 clock = time((time_t *) 0);
917
918 size = sizeof(sa);
919 if (recvfrom(s, buffer, sizeof(buffer), 0, &sa, &size) < 0)
920 return;
92732149 921 sprintf(buffer, "%.24s\r\n", ctime(&clock));
b1b30605
MK
922 (void) sendto(s, buffer, strlen(buffer), 0, &sa, sizeof(sa));
923}
9a0fbd5b
MK
924
925/*
926 * print_service:
927 * Dump relevant information to stderr
928 */
929print_service(action, sep)
930 char *action;
931 struct servtab *sep;
932{
933 fprintf(stderr,
934 "%s: %s proto=%s, wait=%d, user=%s builtin=%x server=%s\n",
935 action, sep->se_service, sep->se_proto,
936 sep->se_wait, sep->se_user, sep->se_bi, sep->se_server);
937}