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