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