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