date and time created 88/12/16 11:12:32 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.
9166e6a5
KB
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms are permitted
b8c620d6
KB
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.
528b0614
DF
16 */
17
18#ifndef lint
19char copyright[] =
20"@(#) Copyright (c) 1983 Regents of the University of California.\n\
21 All rights reserved.\n";
9166e6a5 22#endif /* not lint */
528b0614 23
21ed1185 24#ifndef lint
b8c620d6 25static char sccsid[] = "@(#)inetd.c 5.13 (Berkeley) %G%";
9166e6a5 26#endif /* not lint */
21ed1185
MK
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
7d5eb6c4 57 * user user to run daemon as
21ed1185
MK
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>
2a6b82aa
JL
69#include <sys/time.h>
70#include <sys/resource.h>
21ed1185
MK
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>
6a3125d9 79#include <syslog.h>
7d5eb6c4 80#include <pwd.h>
21ed1185 81
fc99bd8d
MK
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
21ed1185
MK
88extern int errno;
89
fc99bd8d 90int reapchild(), retry();
21ed1185
MK
91char *index();
92char *malloc();
93
94int debug = 0;
5859fc43
MK
95int nsock, maxsock;
96fd_set allsock;
21ed1185 97int options;
fc99bd8d 98int timingout;
21ed1185
MK
99struct servent *sp;
100
101struct 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 */
7d5eb6c4 107 char *se_user; /* user name to run as */
b1b30605 108 struct biltin *se_bi; /* if built-in, description */
21ed1185
MK
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 */
fc99bd8d
MK
114 int se_count; /* number started since se_time */
115 struct timeval se_time; /* start of se_count */
21ed1185
MK
116 struct servtab *se_next;
117} *servtab;
118
b1b30605
MK
119int echo_stream(), discard_stream(), machtime_stream();
120int daytime_stream(), chargen_stream();
121int echo_dg(), discard_dg(), machtime_dg(), daytime_dg(), chargen_dg();
122
123struct 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))
21ed1185 153char *CONFIG = "/etc/inetd.conf";
b1b30605
MK
154char **Argv;
155char *LastArg;
21ed1185 156
b1b30605 157main(argc, argv, envp)
21ed1185 158 int argc;
b1b30605 159 char *argv[], *envp[];
21ed1185 160{
21ed1185 161 register struct servtab *sep;
7d5eb6c4 162 register struct passwd *pwd;
21ed1185 163 char *cp, buf[50];
fc99bd8d
MK
164 int pid, i, dofork;
165 struct sigvec sv;
21ed1185 166
b1b30605
MK
167 Argv = argv;
168 if (envp == 0 || *envp == 0)
169 envp = argv;
170 while (*envp)
171 envp++;
172 LastArg = envp[-1] + strlen(envp[-1]);
21ed1185
MK
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 }
187nextopt:
188 argc--, argv++;
189 }
190 if (argc > 0)
191 CONFIG = argv[0];
eb7fb785
MK
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);
21ed1185 212 }
fc99bd8d
MK
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);
21ed1185 218 config();
fc99bd8d
MK
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
21ed1185 224 for (;;) {
fc99bd8d
MK
225 int s, ctrl, n;
226 fd_set readable;
227
0ee95e67
MK
228 if (nsock == 0) {
229 (void) sigblock(SIGBLOCK);
230 while (nsock == 0)
92732149
KB
231 sigpause(0L);
232 (void) sigsetmask(0L);
0ee95e67 233 }
fc99bd8d
MK
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)
0ee95e67 238 syslog(LOG_WARNING, "select: %m\n");
fc99bd8d
MK
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--;
21ed1185
MK
245 if (debug)
246 fprintf(stderr, "someone wants %s\n", sep->se_service);
5859fc43 247 if (!sep->se_wait && sep->se_socktype == SOCK_STREAM) {
fc99bd8d
MK
248 ctrl = accept(sep->se_fd, (struct sockaddr *)0,
249 (int *)0);
6a3125d9
RC
250 if (debug)
251 fprintf(stderr, "accept, ctrl %d\n", ctrl);
21ed1185
MK
252 if (ctrl < 0) {
253 if (errno == EINTR)
254 continue;
6a3125d9 255 syslog(LOG_WARNING, "accept: %m");
21ed1185
MK
256 continue;
257 }
258 } else
259 ctrl = sep->se_fd;
fc99bd8d 260 (void) sigblock(SIGBLOCK);
b1b30605 261 pid = 0;
fc99bd8d
MK
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--;
92732149 284 sigsetmask(0L);
fc99bd8d
MK
285 if (!timingout) {
286 timingout = 1;
287 alarm(RETRYTIME);
288 }
289 continue;
290 }
291 }
b1b30605 292 pid = fork();
fc99bd8d 293 }
21ed1185 294 if (pid < 0) {
5859fc43 295 if (!sep->se_wait && sep->se_socktype == SOCK_STREAM)
21ed1185 296 close(ctrl);
92732149 297 sigsetmask(0L);
21ed1185
MK
298 sleep(1);
299 continue;
300 }
fc99bd8d 301 if (pid && sep->se_wait) {
21ed1185 302 sep->se_wait = pid;
fc99bd8d 303 FD_CLR(sep->se_fd, &allsock);
5859fc43 304 nsock--;
21ed1185 305 }
92732149 306 sigsetmask(0L);
21ed1185 307 if (pid == 0) {
eb7fb785
MK
308 if (debug) {
309 int tt;
fc99bd8d 310
eb7fb785 311 if (dofork && (tt = open("/dev/tty", O_RDWR)) > 0) {
21ed1185
MK
312 ioctl(tt, TIOCNOTTY, 0);
313 close(tt);
eb7fb785
MK
314 }
315 (void) setpgrp(0, 0);
316 signal(SIGTSTP, SIG_IGN);
317 signal(SIGTTIN, SIG_IGN);
318 signal(SIGTTOU, SIG_IGN);
21ed1185 319 }
fc99bd8d 320 if (dofork)
b1b30605
MK
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);
fc99bd8d
MK
335 if (sep->se_socktype != SOCK_STREAM)
336 recv(0, buf, sizeof (buf), 0);
b1b30605
MK
337 _exit(1);
338 }
339 if (pwd->pw_uid) {
2a6b82aa 340 (void) setgid((gid_t)pwd->pw_gid);
b1b30605 341 initgroups(pwd->pw_name, pwd->pw_gid);
2a6b82aa 342 (void) setuid((uid_t)pwd->pw_uid);
b1b30605
MK
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);
7d5eb6c4 352 }
21ed1185 353 }
5859fc43 354 if (!sep->se_wait && sep->se_socktype == SOCK_STREAM)
21ed1185 355 close(ctrl);
fc99bd8d 356 }
21ed1185
MK
357 }
358}
359
360reapchild()
361{
362 union wait status;
363 int pid;
364 register struct servtab *sep;
365
366 for (;;) {
2a6b82aa 367 pid = wait3(&status, WNOHANG, (struct rusage *)0);
21ed1185
MK
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)
6a3125d9
RC
375 syslog(LOG_WARNING,
376 "%s: exit status 0x%x",
21ed1185
MK
377 sep->se_server, status);
378 if (debug)
379 fprintf(stderr, "restored %s, fd %d\n",
380 sep->se_service, sep->se_fd);
5859fc43
MK
381 FD_SET(sep->se_fd, &allsock);
382 nsock++;
21ed1185
MK
383 sep->se_wait = 1;
384 }
385 }
386}
387
388config()
389{
390 register struct servtab *sep, *cp, **sepp;
391 struct servtab *getconfigent(), *enter();
92732149 392 long omask;
21ed1185
MK
393
394 if (!setconfig()) {
6a3125d9 395 syslog(LOG_ERR, "%s: %m", CONFIG);
21ed1185
MK
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
fc99bd8d
MK
408 omask = sigblock(SIGBLOCK);
409 if (cp->se_bi == 0)
410 sep->se_wait = cp->se_wait;
21ed1185 411#define SWAP(a, b) { char *c = a; a = b; b = c; }
2a6b82aa
JL
412 if (cp->se_user)
413 SWAP(sep->se_user, cp->se_user);
21ed1185
MK
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);
9a0fbd5b
MK
420 if (debug)
421 print_service("REDO", sep);
422 } else {
21ed1185 423 sep = enter(cp);
9a0fbd5b
MK
424 if (debug)
425 print_service("ADD ", sep);
426 }
21ed1185 427 sep->se_checked = 1;
21ed1185
MK
428 sp = getservbyname(sep->se_service, sep->se_proto);
429 if (sp == 0) {
6a3125d9 430 syslog(LOG_ERR, "%s/%s: unknown service",
21ed1185
MK
431 sep->se_service, sep->se_proto);
432 continue;
433 }
fc99bd8d
MK
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;
21ed1185 439 }
fc99bd8d
MK
440 if (sep->se_fd == -1)
441 setup(sep);
21ed1185
MK
442 }
443 endconfig();
444 /*
445 * Purge anything not looked at above.
446 */
fc99bd8d 447 omask = sigblock(SIGBLOCK);
21ed1185
MK
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) {
5859fc43
MK
456 FD_CLR(sep->se_fd, &allsock);
457 nsock--;
21ed1185
MK
458 (void) close(sep->se_fd);
459 }
9a0fbd5b
MK
460 if (debug)
461 print_service("FREE", sep);
21ed1185
MK
462 freeconfig(sep);
463 free((char *)sep);
464 }
465 (void) sigsetmask(omask);
466}
467
fc99bd8d
MK
468retry()
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
478setup(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) \
489setsockopt(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
21ed1185
MK
516struct servtab *
517enter(cp)
518 struct servtab *cp;
519{
520 register struct servtab *sep;
92732149 521 long omask;
21ed1185
MK
522
523 sep = (struct servtab *)malloc(sizeof (*sep));
524 if (sep == (struct servtab *)0) {
6a3125d9 525 syslog(LOG_ERR, "Out of memory.");
21ed1185
MK
526 exit(-1);
527 }
528 *sep = *cp;
529 sep->se_fd = -1;
fc99bd8d 530 omask = sigblock(SIGBLOCK);
21ed1185
MK
531 sep->se_next = servtab;
532 servtab = sep;
533 sigsetmask(omask);
534 return (sep);
535}
536
537FILE *fconfig = NULL;
538struct servtab serv;
539char line[256];
540char *skip(), *nextline();
541
542setconfig()
543{
544
545 if (fconfig != NULL) {
2a6b82aa 546 fseek(fconfig, 0L, L_SET);
21ed1185
MK
547 return (1);
548 }
549 fconfig = fopen(CONFIG, "r");
550 return (fconfig != NULL);
551}
552
553endconfig()
554{
555
556 if (fconfig == NULL)
557 return;
558 fclose(fconfig);
559 fconfig = NULL;
560}
561
562struct servtab *
563getconfigent()
564{
565 register struct servtab *sep = &serv;
21ed1185 566 int argc;
9166e6a5 567 char *cp, *arg, *strdup();
21ed1185 568
b1b30605 569more:
21ed1185
MK
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;
7d5eb6c4 591 sep->se_user = strdup(skip(&cp));
21ed1185 592 sep->se_server = strdup(skip(&cp));
b1b30605
MK
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;
9a0fbd5b
MK
607 } else
608 sep->se_bi = NULL;
21ed1185
MK
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
618freeconfig(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);
2a6b82aa
JL
627 if (cp->se_user)
628 free(cp->se_user);
21ed1185
MK
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
636char *
637skip(cpp)
638 char **cpp;
639{
640 register char *cp = *cpp;
641 char *start;
642
643again:
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
666char *
667nextline(fd)
668 FILE *fd;
669{
670 char *cp;
671
2a6b82aa 672 if (fgets(line, sizeof (line), fd) == NULL)
21ed1185
MK
673 return ((char *)0);
674 cp = index(line, '\n');
675 if (cp)
676 *cp = '\0';
677 return (line);
678}
679
680char *
681strdup(cp)
682 char *cp;
683{
684 char *new;
685
686 if (cp == NULL)
687 cp = "";
2a6b82aa 688 new = malloc((unsigned)(strlen(cp) + 1));
21ed1185 689 if (new == (char *)0) {
6a3125d9 690 syslog(LOG_ERR, "Out of memory.");
21ed1185
MK
691 exit(-1);
692 }
693 strcpy(new, cp);
694 return (new);
695}
b1b30605
MK
696
697setproctitle(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)
9bd38ba8 709 (void) sprintf(buf, "-%s [%s]", a, inet_ntoa(sin.sin_addr));
b1b30605 710 else
9bd38ba8 711 (void) sprintf(buf, "-%s", a);
b1b30605
MK
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 */
723echo_stream(s, sep) /* Echo service -- echo data back */
724 int s;
725 struct servtab *sep;
726{
727 char buffer[BUFSIZ];
728 int i;
729
0ee95e67 730 setproctitle(sep->se_service, s);
b1b30605
MK
731 while ((i = read(s, buffer, sizeof(buffer))) > 0 &&
732 write(s, buffer, i) > 0)
733 ;
734 exit(0);
735}
736
737/* ARGSUSED */
738echo_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 */
753discard_stream(s, sep) /* Discard service -- ignore data */
754 int s;
755 struct servtab *sep;
756{
757 char buffer[BUFSIZ];
758
0ee95e67 759 setproctitle(sep->se_service, s);
b1b30605
MK
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 */
770discard_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
781char ring[128];
782char *endring;
783
784initring()
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 */
796chargen_stream(s, sep) /* Character generator */
797 int s;
798 struct servtab *sep;
799{
92732149
KB
800 register char *rs;
801 int len;
b1b30605 802 char text[LINESIZ+2];
b1b30605 803
0ee95e67 804 setproctitle(sep->se_service, s);
92732149
KB
805
806 if (!endring) {
b1b30605 807 initring();
92732149
KB
808 rs = ring;
809 }
b1b30605 810
92732149
KB
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);
b1b30605 819 }
92732149
KB
820 if (++rs == endring)
821 rs = ring;
822 if (write(s, text, sizeof(text)) != sizeof(text))
b1b30605
MK
823 break;
824 }
825 exit(0);
826}
827
828/* ARGSUSED */
829chargen_dg(s, sep) /* Character generator */
830 int s;
831 struct servtab *sep;
832{
b1b30605 833 struct sockaddr sa;
92732149
KB
834 static char *rs;
835 int len, size;
836 char text[LINESIZ+2];
b1b30605 837
92732149 838 if (endring == 0) {
b1b30605 839 initring();
92732149
KB
840 rs = ring;
841 }
b1b30605
MK
842
843 size = sizeof(sa);
844 if (recvfrom(s, text, sizeof(text), 0, &sa, &size) < 0)
845 return;
b1b30605 846
92732149
KB
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';
b1b30605
MK
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 */
b1b30605
MK
867
868long
869machtime()
870{
871 struct timeval tv;
872
2a6b82aa 873 if (gettimeofday(&tv, (struct timezone *)0) < 0) {
b1b30605 874 fprintf(stderr, "Unable to get time of day\n");
2a6b82aa 875 return (0L);
b1b30605
MK
876 }
877 return (htonl((long)tv.tv_sec + 2208988800));
878}
879
880/* ARGSUSED */
881machtime_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 */
892machtime_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);
2a6b82aa 901 if (recvfrom(s, (char *)&result, sizeof(result), 0, &sa, &size) < 0)
b1b30605
MK
902 return;
903 result = machtime();
904 (void) sendto(s, (char *) &result, sizeof(result), 0, &sa, sizeof(sa));
905}
906
907/* ARGSUSED */
908daytime_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
9bd38ba8 918 (void) sprintf(buffer, "%.24s\r\n", ctime(&clock));
2a6b82aa 919 (void) write(s, buffer, strlen(buffer));
b1b30605
MK
920}
921
922/* ARGSUSED */
923daytime_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;
9bd38ba8 938 (void) sprintf(buffer, "%.24s\r\n", ctime(&clock));
b1b30605
MK
939 (void) sendto(s, buffer, strlen(buffer), 0, &sa, sizeof(sa));
940}
9a0fbd5b
MK
941
942/*
943 * print_service:
944 * Dump relevant information to stderr
945 */
946print_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}