blob: 047358c905dee884d10e7ae98f78f2a8d1087706 [file] [log] [blame]
Glenn L McGrath06e95652003-02-09 06:51:14 +00001/*
2 * Copyright (c) 1983,1991 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * David A. Holland.
7 *
8 * Busybox port by Vladimir Oleynik (C) 2001-2003 <dzo@simtreas.ru>
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 *
24 */
25
26/*
27 * Inetd - Internet super-server
28 *
29 * This program invokes all internet services as needed.
30 * connection-oriented services are invoked each time a
31 * connection is made, by creating a process. This process
32 * is passed the connection as file descriptor 0 and is
33 * expected to do a getpeername to find out the source host
34 * and port.
35 *
36 * Datagram oriented services are invoked when a datagram
37 * arrives; a process is created and passed a pending message
38 * on file descriptor 0. Datagram servers may either connect
39 * to their peer, freeing up the original socket for inetd
40 * to receive further messages on, or ``take over the socket'',
41 * processing all arriving datagrams and, eventually, timing
42 * out. The first type of server is said to be ``multi-threaded'';
43 * the second type of server ``single-threaded''.
44 *
45 * Inetd uses a configuration file which is read at startup
46 * and, possibly, at some later time in response to a hangup signal.
47 * The configuration file is ``free format'' with fields given in the
48 * order shown below. Continuation lines for an entry must being with
49 * a space or tab. All fields must be present in each entry.
50 *
51 * service name must be in /etc/services
52 * socket type stream/dgram/raw/rdm/seqpacket
53 * protocol must be in /etc/protocols
54 * wait/nowait[.max] single-threaded/multi-threaded, max #
55 * user[.group] user/group to run daemon as
56 * server program full path name
57 * server program arguments maximum of MAXARGS (20)
58 *
59 * RPC services unsuported
60 *
61 * Comment lines are indicated by a `#' in column 1.
62 */
63
64/*
65 * Here's the scoop concerning the user.group feature:
66 *
67 * 1) No group listed.
68 *
69 * a) for root: NO setuid() or setgid() is done
70 *
71 * b) nonroot: setuid()
72 * setgid(primary group as found in passwd)
73 * initgroups(name, primary group)
74 *
75 * 2) set-group-option on.
76 *
77 * a) for root: NO setuid()
78 * setgid(specified group)
79 * setgroups(1, specified group)
80 *
81 * b) nonroot: setuid()
82 * setgid(specified group)
83 * initgroups(name, specified group)
84 *
85 * All supplementary groups are discarded at startup in case inetd was
86 * run manually.
87 */
88
89#define __USE_BSD_SIGNAL
90
91#include "busybox.h"
92
93#include <sys/param.h>
94#include <sys/stat.h>
95#include <sys/ioctl.h>
96#include <sys/socket.h>
97#include <sys/un.h>
98#include <sys/file.h>
99#include <sys/wait.h>
100#include <sys/time.h>
101#include <sys/resource.h>
102
103#ifndef __linux__
104#ifndef RLIMIT_NOFILE
105#define RLIMIT_NOFILE RLIMIT_OFILE
106#endif
107#endif
108
109#include <sys/param.h>
110#include <sys/stat.h>
111#include <sys/ioctl.h>
112#include <sys/socket.h>
113#include <sys/file.h>
114#include <sys/wait.h>
115#include <sys/time.h>
116#include <sys/resource.h>
117
118#include <netinet/in.h>
119#include <netinet/ip.h>
120#include <arpa/inet.h>
121
122#include <errno.h>
123#include <signal.h>
124#include <netdb.h>
125#include <syslog.h>
126#include <pwd.h>
127#include <grp.h>
128#include <stdio.h>
129#include <stdlib.h>
130#include <string.h>
131#include <getopt.h>
132#include <unistd.h>
133#include <stdarg.h>
134
135#define _PATH_INETDCONF "/etc/inetd.conf"
136#define _PATH_INETDPID "/var/run/inetd.pid"
137
138#ifndef MIN
139#define MIN(a, b) ((a) < (b) ? (a) : (b))
140#endif
141
142#define TOOMANY 40 /* don't start more than TOOMANY */
143#define CNT_INTVL 60 /* servers in CNT_INTVL sec. */
144#define RETRYTIME (60*10) /* retry after bind or server fail */
145
146#ifndef OPEN_MAX
147#define OPEN_MAX 64
148#endif
149
150
151/* Reserve some descriptors, 3 stdio + at least: 1 log, 1 conf. file */
152#define FD_MARGIN (8)
153static int rlim_ofile_cur = OPEN_MAX;
154
155#ifdef RLIMIT_NOFILE
156static struct rlimit rlim_ofile;
157#endif
158
159
160static struct servtab {
161 char *se_service; /* name of service */
162 int se_socktype; /* type of socket to use */
163 int se_family; /* address family */
164 char *se_proto; /* protocol used */
165 short se_wait; /* single threaded server */
166 short se_checked; /* looked at during merge */
167 char *se_user; /* user name to run as */
168 char *se_group; /* group name to run as */
169#ifndef INETD_UNSUPPORT_BILTIN
170 const struct biltin *se_bi; /* if built-in, description */
171#endif
172 char *se_server; /* server program */
173#define MAXARGV 20
174 char *se_argv[MAXARGV+1]; /* program arguments */
175 int se_fd; /* open descriptor */
176 union {
177 struct sockaddr se_un_ctrladdr;
178 struct sockaddr_in se_un_ctrladdr_in;
179 struct sockaddr_un se_un_ctrladdr_un;
180 } se_un; /* bound address */
181#define se_ctrladdr se_un.se_un_ctrladdr
182#define se_ctrladdr_in se_un.se_un_ctrladdr_in
183#define se_ctrladdr_un se_un.se_un_ctrladdr_un
184 int se_ctrladdr_size;
185 int se_max; /* max # of instances of this service */
186 int se_count; /* number started since se_time */
187 struct timeval se_time; /* start of se_count */
188 struct servtab *se_next;
189} *servtab;
190
191/* Length of socket listen queue. Should be per-service probably. */
192static int global_queuelen = 128;
193
194static int nsock, maxsock;
195static fd_set allsock;
196static int timingout;
197static sigset_t blockmask, emptymask;
198
199
200#define INETD_UNSUPPORT_BILTIN 1
201
202 /* Echo received data */
203#ifdef CONFIG_FEATURE_INETD_SUPPORT_BILTIN_ECHO
204#undef INETD_UNSUPPORT_BILTIN
205static void echo_stream(int, struct servtab *);
206static void echo_dg(int, struct servtab *);
207#endif
208 /* Internet /dev/null */
209#ifdef CONFIG_FEATURE_INETD_SUPPORT_BILTIN_DISCARD
210#undef INETD_UNSUPPORT_BILTIN
211static void discard_stream(int, struct servtab *);
212static void discard_dg(int, struct servtab *);
213#endif
214 /* Return 32 bit time since 1900 */
215#ifdef CONFIG_FEATURE_INETD_SUPPORT_BILTIN_TIME
216#undef INETD_UNSUPPORT_BILTIN
217static void machtime_stream(int, struct servtab *);
218static void machtime_dg(int, struct servtab *);
219#endif
220 /* Return human-readable time */
221#ifdef CONFIG_FEATURE_INETD_SUPPORT_BILTIN_DAYTIME
222#undef INETD_UNSUPPORT_BILTIN
223static void daytime_stream(int, struct servtab *);
224static void daytime_dg(int, struct servtab *);
225#endif
226 /* Familiar character generator */
227#ifdef CONFIG_FEATURE_INETD_SUPPORT_BILTIN_CHARGEN
228#undef INETD_UNSUPPORT_BILTIN
229static void chargen_stream(int, struct servtab *);
230static void chargen_dg(int, struct servtab *);
231#endif
232
233#ifndef INETD_UNSUPPORT_BILTIN
234struct biltin {
235 const char *bi_service; /* internally provided service name */
236 int bi_socktype; /* type of socket supported */
237 short bi_fork; /* 1 if should fork before call */
238 short bi_wait; /* 1 if should wait for child */
239 void (*bi_fn)(int, struct servtab *); /* fn which performs it */
240};
241
242static const struct biltin biltins[] = {
243#ifdef CONFIG_FEATURE_INETD_SUPPORT_BILTIN_ECHO
244 /* Echo received data */
245 { "echo", SOCK_STREAM, 1, 0, echo_stream, },
246 { "echo", SOCK_DGRAM, 0, 0, echo_dg, },
247#endif
248#ifdef CONFIG_FEATURE_INETD_SUPPORT_BILTIN_DISCARD
249 /* Internet /dev/null */
250 { "discard", SOCK_STREAM, 1, 0, discard_stream, },
251 { "discard", SOCK_DGRAM, 0, 0, discard_dg, },
252#endif
253#ifdef CONFIG_FEATURE_INETD_SUPPORT_BILTIN_TIME
254 /* Return 32 bit time since 1900 */
255 { "time", SOCK_STREAM, 0, 0, machtime_stream, },
256 { "time", SOCK_DGRAM, 0, 0, machtime_dg, },
257#endif
258#ifdef CONFIG_FEATURE_INETD_SUPPORT_BILTIN_DAYTIME
259 /* Return human-readable time */
260 { "daytime", SOCK_STREAM, 0, 0, daytime_stream, },
261 { "daytime", SOCK_DGRAM, 0, 0, daytime_dg, },
262#endif
263#ifdef CONFIG_FEATURE_INETD_SUPPORT_BILTIN_CHARGEN
264 /* Familiar character generator */
265 { "chargen", SOCK_STREAM, 1, 0, chargen_stream, },
266 { "chargen", SOCK_DGRAM, 0, 0, chargen_dg, },
267#endif
268 { NULL, 0, 0, 0, NULL }
269};
270#endif /* INETD_UNSUPPORT_BILTIN */
271
272#define NUMINT (sizeof(intab) / sizeof(struct inent))
273static const char *CONFIG = _PATH_INETDCONF;
274
275#define BCOPY(s, d, z) memcpy(d, s, z)
276
277static void
278syslog_err_and_discard_dg(int se_socktype, const char *msg, ...)
279 __attribute__ ((noreturn, format (printf, 2, 3)));
280
281static void
282syslog_err_and_discard_dg(int se_socktype, const char *msg, ...)
283{
284 char buf[50];
285 va_list p;
286
287 va_start(p, msg);
288 vsyslog(LOG_ERR, msg, p);
289 if (se_socktype != SOCK_STREAM)
290 recv(0, buf, sizeof (buf), 0);
291 _exit(1);
292}
293
294static FILE *fconfig;
295static char line[256];
296
297static FILE *
298setconfig(void)
299{
300 FILE *f = fconfig;
301
302 if (f != NULL) {
303 fseek(f, 0L, L_SET);
304 } else {
305 f = fconfig = fopen(CONFIG, "r");
306 if(f == NULL)
307 syslog(LOG_ERR, "%s: %m", CONFIG);
308 }
309 return f;
310}
311
312static char *
313nextline(void)
314{
315 char *cp;
316 FILE *fd = fconfig;
317
318 if (fgets(line, sizeof (line), fd) == NULL)
319 return ((char *)0);
320 cp = strchr(line, '\n');
321 if (cp)
322 *cp = '\0';
323 return (line);
324}
325
326static char *
327skip(char **cpp)
328{
329 char *cp = *cpp;
330 char *start;
331
332 if (*cpp == NULL)
333 return ((char *)0);
334
335again:
336 while (*cp == ' ' || *cp == '\t')
337 cp++;
338 if (*cp == '\0') {
339 int c;
340
341 c = getc(fconfig);
342 (void) ungetc(c, fconfig);
343 if (c == ' ' || c == '\t')
344 if ((cp = nextline()) != NULL)
345 goto again;
346 *cpp = NULL;
347 return NULL;
348 }
349 start = cp;
350 while (*cp && *cp != ' ' && *cp != '\t')
351 cp++;
352 if (*cp != '\0')
353 *cp++ = '\0';
354 *cpp = cp;
355 return (start);
356}
357
358static char *
359newstr(char *cp)
360{
361 cp = strdup(cp ? cp : "");
362 if (cp)
363 return(cp);
364
365 syslog_err_and_discard_dg(SOCK_STREAM, "strdup: %m");
366}
367
368
369static struct servtab *
370getconfigent(void)
371{
372 static struct servtab serv;
373 struct servtab *sep = &serv;
374 int argc;
375 char *cp, *arg;
376
377more:
378 while ((cp = nextline()) && *cp == '#')
379 ;
380 if (cp == NULL)
381 return ((struct servtab *)0);
382 memset((char *)sep, 0, sizeof *sep);
383 sep->se_service = newstr(skip(&cp));
384 arg = skip(&cp);
385 if (arg == NULL)
386 goto more;
387
388 if (strcmp(arg, "stream") == 0)
389 sep->se_socktype = SOCK_STREAM;
390 else if (strcmp(arg, "dgram") == 0)
391 sep->se_socktype = SOCK_DGRAM;
392 else if (strcmp(arg, "rdm") == 0)
393 sep->se_socktype = SOCK_RDM;
394 else if (strcmp(arg, "seqpacket") == 0)
395 sep->se_socktype = SOCK_SEQPACKET;
396 else if (strcmp(arg, "raw") == 0)
397 sep->se_socktype = SOCK_RAW;
398 else
399 sep->se_socktype = -1;
400
401 sep->se_proto = newstr(skip(&cp));
402 if (strcmp(sep->se_proto, "unix") == 0) {
403 sep->se_family = AF_UNIX;
404 } else {
405 sep->se_family = AF_INET;
406 if (strncmp(sep->se_proto, "rpc/", 4) == 0) {
407 syslog(LOG_ERR, "%s: rpc services not suported",
408 sep->se_service);
409 goto more;
410 }
411 }
412 arg = skip(&cp);
413 if (arg == NULL)
414 goto more;
415 {
416 char *s = strchr(arg, '.');
417 if (s) {
418 *s++ = '\0';
419 sep->se_max = atoi(s);
420 } else
421 sep->se_max = TOOMANY;
422 }
423 sep->se_wait = strcmp(arg, "wait") == 0;
424 sep->se_user = newstr(skip(&cp));
425 sep->se_group = strchr(sep->se_user, '.');
426 if (sep->se_group) {
427 *sep->se_group++ = '\0';
428 }
429 sep->se_server = newstr(skip(&cp));
430 if (strcmp(sep->se_server, "internal") == 0) {
431#ifndef INETD_UNSUPPORT_BILTIN
432 const struct biltin *bi;
433
434 for (bi = biltins; bi->bi_service; bi++)
435 if (bi->bi_socktype == sep->se_socktype &&
436 strcmp(bi->bi_service, sep->se_service) == 0)
437 break;
438 if (bi->bi_service == 0) {
439 syslog(LOG_ERR, "internal service %s unknown",
440 sep->se_service);
441 goto more;
442 }
443 sep->se_bi = bi;
444 sep->se_wait = bi->bi_wait;
445#else
446 syslog(LOG_ERR, "internal service %s unknown",
447 sep->se_service);
448 goto more;
449#endif
450 } else
451#ifndef INETD_UNSUPPORT_BILTIN
452 sep->se_bi = NULL
453#endif
454 ;
455 argc = 0;
456 for (arg = skip(&cp); cp; arg = skip(&cp)) {
457 if (argc < MAXARGV)
458 sep->se_argv[argc++] = newstr(arg);
459 }
460 while (argc <= MAXARGV)
461 sep->se_argv[argc++] = NULL;
462 return (sep);
463}
464
465static void
466freeconfig(struct servtab *cp)
467{
468 int i;
469
470 free(cp->se_service);
471 free(cp->se_proto);
472 free(cp->se_user);
473 /* Note: se_group is part of the newstr'ed se_user */
474 free(cp->se_server);
475 for (i = 0; i < MAXARGV; i++)
476 free(cp->se_argv[i]);
477}
478
479#ifndef INETD_UNSUPPORT_BILTIN
480static char **Argv;
481static char *LastArg;
482
483static void
484setproctitle(char *a, int s)
485{
486 size_t size;
487 char *cp;
488 struct sockaddr_in sn;
489 char buf[80];
490
491 cp = Argv[0];
492 size = sizeof(sn);
493 if (getpeername(s, (struct sockaddr *)&sn, &size) == 0)
494 (void) sprintf(buf, "-%s [%s]", a, inet_ntoa(sn.sin_addr));
495 else
496 (void) sprintf(buf, "-%s", a);
497 strncpy(cp, buf, LastArg - cp);
498 cp += strlen(cp);
499 while (cp < LastArg)
500 *cp++ = ' ';
501}
502#endif /* INETD_UNSUPPORT_BILTIN */
503
504static struct servtab *
505enter(struct servtab *cp)
506{
507 struct servtab *sep;
508 sigset_t oldmask;
509
510 sep = (struct servtab *)malloc(sizeof (*sep));
511 if (sep == NULL) {
512 syslog_err_and_discard_dg(SOCK_STREAM, memory_exhausted);
513 }
514 *sep = *cp;
515 sep->se_fd = -1;
516 sigprocmask(SIG_BLOCK, &blockmask, &oldmask);
517 sep->se_next = servtab;
518 servtab = sep;
519 sigprocmask(SIG_SETMASK, &oldmask, NULL);
520 return (sep);
521}
522
523static int
524bump_nofile(void)
525{
526#ifdef RLIMIT_NOFILE
527
528#define FD_CHUNK 32
529
530 struct rlimit rl;
531
532 if (getrlimit(RLIMIT_NOFILE, &rl) < 0) {
533 syslog(LOG_ERR, "getrlimit: %m");
534 return -1;
535 }
536 rl.rlim_cur = MIN(rl.rlim_max, rl.rlim_cur + FD_CHUNK);
537 if (rl.rlim_cur <= rlim_ofile_cur) {
538 syslog(LOG_ERR,
539 "bump_nofile: cannot extend file limit, max = %d",
540 rl.rlim_cur);
541 return -1;
542 }
543
544 if (setrlimit(RLIMIT_NOFILE, &rl) < 0) {
545 syslog(LOG_ERR, "setrlimit: %m");
546 return -1;
547 }
548
549 rlim_ofile_cur = rl.rlim_cur;
550 return 0;
551
552#else
553 syslog(LOG_ERR, "bump_nofile: cannot extend file limit");
554 return -1;
555#endif
556}
557
558
559static void
560setup(struct servtab *sep)
561{
562 int on = 1;
563
564 if ((sep->se_fd = socket(sep->se_family, sep->se_socktype, 0)) < 0) {
565 syslog(LOG_ERR, "%s/%s: socket: %m",
566 sep->se_service, sep->se_proto);
567 return;
568 }
569 if (setsockopt(sep->se_fd, SOL_SOCKET, SO_REUSEADDR, (void *)&on,
570 sizeof(on)) < 0)
571 syslog(LOG_ERR, "setsockopt (SO_REUSEADDR): %m");
572 if (bind(sep->se_fd, &sep->se_ctrladdr, sep->se_ctrladdr_size) < 0) {
573 syslog(LOG_ERR, "%s/%s: bind: %m",
574 sep->se_service, sep->se_proto);
575 (void) close(sep->se_fd);
576 sep->se_fd = -1;
577 if (!timingout) {
578 timingout = 1;
579 alarm(RETRYTIME);
580 }
581 return;
582 }
583 if (sep->se_socktype == SOCK_STREAM)
584 listen(sep->se_fd, global_queuelen);
585
586 FD_SET(sep->se_fd, &allsock);
587 nsock++;
588 if (sep->se_fd > maxsock) {
589 maxsock = sep->se_fd;
590 if (maxsock > rlim_ofile_cur - FD_MARGIN)
591 bump_nofile();
592 }
593}
594
595static void
596config(int signum)
597{
598 struct servtab *sep, *cp, **sepp;
599 sigset_t oldmask;
600 unsigned n;
601
602 (void)signum;
603 if (setconfig() == NULL)
604 return;
605
606 for (sep = servtab; sep; sep = sep->se_next)
607 sep->se_checked = 0;
608 while ((cp = getconfigent()) != NULL) {
609 for (sep = servtab; sep; sep = sep->se_next)
610 if (strcmp(sep->se_service, cp->se_service) == 0 &&
611 strcmp(sep->se_proto, cp->se_proto) == 0)
612 break;
613 if (sep != 0) {
614 int i;
615
616#define SWAP(type, a, b) {type c=(type)a; (type)a=(type)b; (type)b=(type)c;}
617
618 sigprocmask(SIG_BLOCK, &emptymask, &oldmask);
619 /*
620 * sep->se_wait may be holding the pid of a daemon
621 * that we're waiting for. If so, don't overwrite
622 * it unless the config file explicitly says don't
623 * wait.
624 */
625 if (
626#ifndef INETD_UNSUPPORT_BILTIN
627 cp->se_bi == 0 &&
628#endif
629 (sep->se_wait == 1 || cp->se_wait == 0))
630 sep->se_wait = cp->se_wait;
631 if (cp->se_max != sep->se_max)
632 SWAP(int, cp->se_max, sep->se_max);
633 if (cp->se_user)
634 SWAP(char *, sep->se_user, cp->se_user);
635 if (cp->se_group)
636 SWAP(char *, sep->se_group, cp->se_group);
637 if (cp->se_server)
638 SWAP(char *, sep->se_server, cp->se_server);
639 for (i = 0; i < MAXARGV; i++)
640 SWAP(char *, sep->se_argv[i], cp->se_argv[i]);
641#undef SWAP
642 sigprocmask(SIG_SETMASK, &oldmask, NULL);
643 freeconfig(cp);
644 } else {
645 sep = enter(cp);
646 }
647 sep->se_checked = 1;
648
649 switch (sep->se_family) {
650 case AF_UNIX:
651 if (sep->se_fd != -1)
652 break;
653 (void)unlink(sep->se_service);
654 n = strlen(sep->se_service);
655 if (n > sizeof(sep->se_ctrladdr_un.sun_path) - 1)
656 n = sizeof(sep->se_ctrladdr_un.sun_path) - 1;
657 strncpy(sep->se_ctrladdr_un.sun_path, sep->se_service, n);
658 sep->se_ctrladdr_un.sun_family = AF_UNIX;
659 sep->se_ctrladdr_size = n +
660 sizeof sep->se_ctrladdr_un.sun_family;
661 setup(sep);
662 break;
663 case AF_INET:
664 sep->se_ctrladdr_in.sin_family = AF_INET;
665 sep->se_ctrladdr_size = sizeof sep->se_ctrladdr_in;
666 {
667 u_short port = htons(atoi(sep->se_service));
668
669 if (!port) {
670 struct servent *sp;
671 sp = getservbyname(sep->se_service,
672 sep->se_proto);
673 if (sp == 0) {
674 syslog(LOG_ERR,
675 "%s/%s: unknown service",
676 sep->se_service, sep->se_proto);
677 continue;
678 }
679 port = sp->s_port;
680 }
681 if (port != sep->se_ctrladdr_in.sin_port) {
682 sep->se_ctrladdr_in.sin_port = port;
683 if (sep->se_fd != -1) {
684 FD_CLR(sep->se_fd, &allsock);
685 nsock--;
686 (void) close(sep->se_fd);
687 }
688 sep->se_fd = -1;
689 }
690 if (sep->se_fd == -1)
691 setup(sep);
692 }
693 }
694 }
695 if (fconfig) {
696 (void) fclose(fconfig);
697 fconfig = NULL;
698 }
699 /*
700 * Purge anything not looked at above.
701 */
702 sigprocmask(SIG_SETMASK, &blockmask, &oldmask);
703 sepp = &servtab;
704 while ((sep = *sepp) != NULL) {
705 if (sep->se_checked) {
706 sepp = &sep->se_next;
707 continue;
708 }
709 *sepp = sep->se_next;
710 if (sep->se_fd != -1) {
711 FD_CLR(sep->se_fd, &allsock);
712 nsock--;
713 (void) close(sep->se_fd);
714 }
715 if (sep->se_family == AF_UNIX)
716 (void)unlink(sep->se_service);
717 freeconfig(sep);
718 free((char *)sep);
719 }
720 sigprocmask(SIG_SETMASK, &oldmask, NULL);
721}
722
723
724
725static void
726reapchild(int signum)
727{
728 int status;
729 int pid;
730 struct servtab *sep;
731
732 (void)signum;
733 for (;;) {
734 pid = wait3(&status, WNOHANG, (struct rusage *)0);
735 if (pid <= 0)
736 break;
737 for (sep = servtab; sep; sep = sep->se_next)
738 if (sep->se_wait == pid) {
739 if (WIFEXITED(status) && WEXITSTATUS(status))
740 syslog(LOG_WARNING,
741 "%s: exit status 0x%x",
742 sep->se_server, WEXITSTATUS(status));
743 else if (WIFSIGNALED(status))
744 syslog(LOG_WARNING,
745 "%s: exit signal 0x%x",
746 sep->se_server, WTERMSIG(status));
747 sep->se_wait = 1;
748 FD_SET(sep->se_fd, &allsock);
749 nsock++;
750 }
751 }
752}
753
754static void
755retry(int signum)
756{
757 struct servtab *sep;
758
759 (void)signum;
760 timingout = 0;
761 for (sep = servtab; sep; sep = sep->se_next) {
762 if (sep->se_fd == -1) {
763 switch (sep->se_family) {
764 case AF_UNIX:
765 case AF_INET:
766 setup(sep);
767 break;
768 }
769 }
770 }
771}
772
773static void
774goaway(int signum)
775{
776 struct servtab *sep;
777
778 (void)signum;
779 for (sep = servtab; sep; sep = sep->se_next)
780 if (sep->se_fd != -1 && sep->se_family == AF_UNIX)
781 (void)unlink(sep->se_service);
782 (void)unlink(_PATH_INETDPID);
783 exit(0);
784}
785
786
787
788extern int
789inetd_main(int argc, char *argv[])
790{
791 struct servtab *sep;
792 struct passwd *pwd;
793 struct group *grp = NULL;
794 struct sigaction sa;
795 int ch, pid;
796 gid_t gid;
797
798#ifdef INETD_UNSUPPORT_BILTIN
799# define dofork 1
800#else
801 int dofork;
802 extern char **environ;
803#endif
804
805 gid = getgid();
806 setgroups(1, &gid);
807
808#ifndef INETD_UNSUPPORT_BILTIN
809 Argv = argv;
810 if (environ == 0 || *environ == 0)
811 environ = argv;
812 while (*environ)
813 environ++;
814 LastArg = environ[-1] + strlen(environ[-1]);
815#endif
816
817 while ((ch = getopt(argc, argv, "q:")) != EOF)
818 switch(ch) {
819 case 'q':
820 global_queuelen = atoi(optarg);
821 if (global_queuelen < 8) global_queuelen=8;
822 break;
823 default:
824 show_usage(); // "[-q len] [conf]"
825 }
826 argc -= optind;
827 argv += optind;
828
829 if (argc > 0)
830 CONFIG = argv[0];
831
832 daemon(0, 0);
833 openlog(applet_name, LOG_PID | LOG_NOWAIT, LOG_DAEMON);
834 {
835 FILE *fp;
836
837 if ((fp = fopen(_PATH_INETDPID, "w")) != NULL) {
838 fprintf(fp, "%u\n", getpid());
839 (void)fclose(fp);
840 }
841 }
842
843#ifdef RLIMIT_NOFILE
844 if (getrlimit(RLIMIT_NOFILE, &rlim_ofile) < 0) {
845 syslog(LOG_ERR, "getrlimit: %m");
846 } else {
847 rlim_ofile_cur = rlim_ofile.rlim_cur;
848 if (rlim_ofile_cur == RLIM_INFINITY) /* ! */
849 rlim_ofile_cur = OPEN_MAX;
850 }
851#endif
852
853 config(0);
854
855 sigemptyset(&emptymask);
856 sigemptyset(&blockmask);
857 sigaddset(&blockmask, SIGCHLD);
858 sigaddset(&blockmask, SIGHUP);
859 sigaddset(&blockmask, SIGALRM);
860
861 memset(&sa, 0, sizeof(sa));
862 sa.sa_mask = blockmask;
863 sa.sa_handler = retry;
864 sigaction(SIGALRM, &sa, NULL);
865 sa.sa_handler = config;
866 sigaction(SIGHUP, &sa, NULL);
867 sa.sa_handler = reapchild;
868 sigaction(SIGCHLD, &sa, NULL);
869 sa.sa_handler = goaway;
870 sigaction(SIGTERM, &sa, NULL);
871 sa.sa_handler = goaway;
872 sigaction(SIGINT, &sa, NULL);
873 sa.sa_handler = SIG_IGN;
874 sigaction(SIGPIPE, &sa, NULL);
875
876 {
877 /* space for daemons to overwrite environment for ps */
878#define DUMMYSIZE 100
879 char dummy[DUMMYSIZE];
880
881 (void)memset(dummy, 'x', DUMMYSIZE - 1);
882 dummy[DUMMYSIZE - 1] = '\0';
883
884 (void)setenv("inetd_dummy", dummy, 1);
885 }
886
887 for (;;) {
888 int n, ctrl;
889 fd_set readable;
890
891 if (nsock == 0) {
892 sigprocmask(SIG_BLOCK, &blockmask, NULL);
893 while (nsock == 0)
894 sigsuspend(&emptymask);
895 sigprocmask(SIG_SETMASK, &emptymask, NULL);
896 }
897 readable = allsock;
898 if ((n = select(maxsock + 1, &readable, (fd_set *)0,
899 (fd_set *)0, (struct timeval *)0)) <= 0) {
900 if (n < 0 && errno != EINTR)
901 syslog(LOG_WARNING, "select: %m");
902 sleep(1);
903 continue;
904 }
905 for (sep = servtab; n && sep; sep = sep->se_next)
906 if (sep->se_fd != -1 && FD_ISSET(sep->se_fd, &readable)) {
907 n--;
908 if (!sep->se_wait && sep->se_socktype == SOCK_STREAM) {
909 /* Fixed AGC */
910 fcntl(sep->se_fd, F_SETFL, O_NDELAY);
911 /* --------- */
912 ctrl = accept(sep->se_fd, NULL, NULL);
913 fcntl(sep->se_fd, F_SETFL, 0);
914 if (ctrl < 0) {
915 if (errno == EINTR || errno == EWOULDBLOCK)
916 continue;
917 syslog(LOG_WARNING, "accept (for %s): %m",
918 sep->se_service);
919 continue;
920 }
921 } else
922 ctrl = sep->se_fd;
923 sigprocmask(SIG_BLOCK, &blockmask, NULL);
924 pid = 0;
925#ifndef INETD_UNSUPPORT_BILTIN
926 dofork = (sep->se_bi == 0 || sep->se_bi->bi_fork);
927#endif
928 if (dofork) {
929 if (sep->se_count++ == 0)
930 (void)gettimeofday(&sep->se_time,
931 (struct timezone *)0);
932 else if (sep->se_count >= sep->se_max) {
933 struct timeval now;
934
935 (void)gettimeofday(&now, (struct timezone *)0);
936 if (now.tv_sec - sep->se_time.tv_sec >
937 CNT_INTVL) {
938 sep->se_time = now;
939 sep->se_count = 1;
940 } else {
941 syslog(LOG_ERR,
942 "%s/%s server failing (looping), service terminated",
943 sep->se_service, sep->se_proto);
944 FD_CLR(sep->se_fd, &allsock);
945 (void) close(sep->se_fd);
946 sep->se_fd = -1;
947 sep->se_count = 0;
948 nsock--;
949 sigprocmask(SIG_SETMASK, &emptymask,
950 NULL);
951 if (!timingout) {
952 timingout = 1;
953 alarm(RETRYTIME);
954 }
955 continue;
956 }
957 }
958 pid = fork();
959 }
960 if (pid < 0) {
961 syslog(LOG_ERR, "fork: %m");
962 if (sep->se_socktype == SOCK_STREAM)
963 close(ctrl);
964 sigprocmask(SIG_SETMASK, &emptymask, NULL);
965 sleep(1);
966 continue;
967 }
968 if (pid && sep->se_wait) {
969 sep->se_wait = pid;
970 FD_CLR(sep->se_fd, &allsock);
971 nsock--;
972 }
973 sigprocmask(SIG_SETMASK, &emptymask, NULL);
974 if (pid == 0) {
975#ifndef INETD_UNSUPPORT_BILTIN
976 if (sep->se_bi)
977 (*sep->se_bi->bi_fn)(ctrl, sep);
978 else
979#endif
980 {
981 if ((pwd = getpwnam(sep->se_user)) == NULL) {
982 syslog_err_and_discard_dg(
983 sep->se_socktype,
984 "getpwnam: %s: No such user",
985 sep->se_user);
986 }
987 if (sep->se_group &&
988 (grp = getgrnam(sep->se_group)) == NULL) {
989 syslog_err_and_discard_dg(
990 sep->se_socktype,
991 "getgrnam: %s: No such group",
992 sep->se_group);
993 }
994 /*
995 * Ok. There are four cases here:
996 * 1. nonroot user, no group specified
997 * 2. nonroot user, some group specified
998 * 3. root user, no group specified
999 * 4. root user, some group specified
1000 * In cases 2 and 4 we setgid to the specified
1001 * group. In cases 1 and 2 we run initgroups
1002 * to run with the groups of the given user.
1003 * In case 4 we do setgroups to run with the
1004 * given group. In case 3 we do nothing.
1005 */
1006 if (pwd->pw_uid) {
1007 if (sep->se_group)
1008 pwd->pw_gid = grp->gr_gid;
1009 setgid((gid_t)pwd->pw_gid);
1010 initgroups(pwd->pw_name, pwd->pw_gid);
1011 setuid((uid_t)pwd->pw_uid);
1012 } else if (sep->se_group) {
1013 setgid((gid_t)grp->gr_gid);
1014 setgroups(1, &grp->gr_gid);
1015 }
1016 dup2(ctrl, 0);
1017 close(ctrl);
1018 dup2(0, 1);
1019 dup2(0, 2);
1020#ifdef RLIMIT_NOFILE
1021 if (rlim_ofile.rlim_cur != rlim_ofile_cur) {
1022 if (setrlimit(RLIMIT_NOFILE,
1023 &rlim_ofile) < 0)
1024 syslog(LOG_ERR,"setrlimit: %m");
1025 }
1026#endif
1027 for (ctrl = rlim_ofile_cur-1; --ctrl > 2; )
1028 (void)close(ctrl);
1029
1030 memset(&sa, 0, sizeof(sa));
1031 sa.sa_handler = SIG_DFL;
1032 sigaction(SIGPIPE, &sa, NULL);
1033
1034 execv(sep->se_server, sep->se_argv);
1035 syslog_err_and_discard_dg(sep->se_socktype,
1036 "execv %s: %m", sep->se_server);
1037 }
1038 }
1039 if (!sep->se_wait && sep->se_socktype == SOCK_STREAM)
1040 close(ctrl);
1041 }
1042 }
1043}
1044
1045
1046/*
1047 * Internet services provided internally by inetd:
1048 */
1049#define BUFSIZE 4096
1050
1051#ifdef CONFIG_FEATURE_INETD_SUPPORT_BILTIN_ECHO
1052/* Echo service -- echo data back */
1053static void
1054echo_stream(int s, struct servtab *sep)
1055{
1056 char buffer[BUFSIZE];
1057 int i;
1058
1059 setproctitle(sep->se_service, s);
1060 while ((i = read(s, buffer, sizeof(buffer))) > 0 &&
1061 write(s, buffer, i) > 0)
1062 ;
1063 exit(0);
1064}
1065
1066/* Echo service -- echo data back */
1067static void
1068echo_dg(int s, struct servtab *sep)
1069{
1070 char buffer[BUFSIZE];
1071 int i;
1072 size_t size;
1073 struct sockaddr sa;
1074
1075 (void)sep;
1076
1077 size = sizeof(sa);
1078 if ((i = recvfrom(s, buffer, sizeof(buffer), 0, &sa, &size)) < 0)
1079 return;
1080 (void) sendto(s, buffer, i, 0, &sa, sizeof(sa));
1081}
1082#endif /* CONFIG_FEATURE_INETD_SUPPORT_BILTIN_ECHO */
1083
1084
1085#ifdef CONFIG_FEATURE_INETD_SUPPORT_BILTIN_DISCARD
1086/* Discard service -- ignore data */
1087static void
1088discard_stream(int s, struct servtab *sep)
1089{
1090 char buffer[BUFSIZE];
1091
1092 setproctitle(sep->se_service, s);
1093 while ((errno = 0, read(s, buffer, sizeof(buffer)) > 0) ||
1094 errno == EINTR)
1095 ;
1096 exit(0);
1097}
1098
1099/* Discard service -- ignore data */
1100static void
1101discard_dg(int s, struct servtab *sep)
1102{
1103 char buffer[BUFSIZE];
1104 (void)sep;
1105 read(s, buffer, sizeof(buffer));
1106}
1107#endif /* CONFIG_FEATURE_INETD_SUPPORT_BILTIN_DISCARD */
1108
1109
1110#ifdef CONFIG_FEATURE_INETD_SUPPORT_BILTIN_CHARGEN
1111#include <ctype.h>
1112#define LINESIZ 72
1113static char ring[128];
1114static char *endring;
1115
1116static void
1117initring(void)
1118{
1119 int i;
1120
1121 endring = ring;
1122
1123 for (i = 0; i <= 128; ++i)
1124 if (isprint(i))
1125 *endring++ = i;
1126}
1127
1128/* Character generator */
1129static void
1130chargen_stream(int s, struct servtab *sep)
1131{
1132 char *rs;
1133 int len;
1134 char text[LINESIZ+2];
1135
1136 setproctitle(sep->se_service, s);
1137
1138 if (!endring) {
1139 initring();
1140 rs = ring;
1141 }
1142
1143 text[LINESIZ] = '\r';
1144 text[LINESIZ + 1] = '\n';
1145 for (rs = ring;;) {
1146 if ((len = endring - rs) >= LINESIZ)
1147 BCOPY(rs, text, LINESIZ);
1148 else {
1149 BCOPY(rs, text, len);
1150 BCOPY(ring, text + len, LINESIZ - len);
1151 }
1152 if (++rs == endring)
1153 rs = ring;
1154 if (write(s, text, sizeof(text)) != sizeof(text))
1155 break;
1156 }
1157 exit(0);
1158}
1159
1160/* Character generator */
1161static void
1162chargen_dg(int s, struct servtab *sep)
1163{
1164 struct sockaddr sa;
1165 static char *rs;
1166 size_t len, size;
1167 char text[LINESIZ+2];
1168
1169 (void)sep;
1170
1171 if (endring == 0) {
1172 initring();
1173 rs = ring;
1174 }
1175
1176 size = sizeof(sa);
1177 if (recvfrom(s, text, sizeof(text), 0, &sa, &size) < 0)
1178 return;
1179
1180 if ((len = endring - rs) >= LINESIZ)
1181 BCOPY(rs, text, LINESIZ);
1182 else {
1183 BCOPY(rs, text, len);
1184 BCOPY(ring, text + len, LINESIZ - len);
1185 }
1186 if (++rs == endring)
1187 rs = ring;
1188 text[LINESIZ] = '\r';
1189 text[LINESIZ + 1] = '\n';
1190 (void) sendto(s, text, sizeof(text), 0, &sa, sizeof(sa));
1191}
1192#endif /* CONFIG_FEATURE_INETD_SUPPORT_BILTIN_CHARGEN */
1193
1194
1195#ifdef CONFIG_FEATURE_INETD_SUPPORT_BILTIN_TIME
1196/*
1197 * Return a machine readable date and time, in the form of the
1198 * number of seconds since midnight, Jan 1, 1900. Since gettimeofday
1199 * returns the number of seconds since midnight, Jan 1, 1970,
1200 * we must add 2208988800 seconds to this figure to make up for
1201 * some seventy years Bell Labs was asleep.
1202 */
1203
1204static long
1205machtime(void)
1206{
1207 struct timeval tv;
1208
1209 if (gettimeofday(&tv, (struct timezone *)0) < 0) {
1210 fprintf(stderr, "Unable to get time of day\n");
1211 return (0L);
1212 }
1213 return (htonl((long)tv.tv_sec + 2208988800UL));
1214}
1215
1216static void
1217machtime_stream(int s, struct servtab *sep)
1218{
1219 long result;
1220 (void)sep;
1221
1222 result = machtime();
1223 write(s, (char *) &result, sizeof(result));
1224}
1225
1226static void
1227machtime_dg(int s, struct servtab *sep)
1228{
1229 long result;
1230 struct sockaddr sa;
1231 size_t size;
1232 (void)sep;
1233
1234 size = sizeof(sa);
1235 if (recvfrom(s, (char *)&result, sizeof(result), 0, &sa, &size) < 0)
1236 return;
1237 result = machtime();
1238 (void) sendto(s, (char *) &result, sizeof(result), 0, &sa, sizeof(sa));
1239}
1240#endif /* CONFIG_FEATURE_INETD_SUPPORT_BILTIN_TIME */
1241
1242
1243#ifdef CONFIG_FEATURE_INETD_SUPPORT_BILTIN_DAYTIME
1244/* Return human-readable time of day */
1245static int
1246human_readable_time_sprintf(char *buffer)
1247{
1248 time_t clocc = time(NULL);
1249
1250 return sprintf(buffer, "%.24s\r\n", ctime(&clocc));
1251}
1252
1253static void
1254daytime_stream(int s, struct servtab *sep)
1255{
1256 char buffer[256];
1257 size_t st = human_readable_time_sprintf(buffer);
1258
1259 (void)sep;
1260
1261 write(s, buffer, st);
1262}
1263
1264/* Return human-readable time of day */
1265static void
1266daytime_dg(int s, struct servtab *sep)
1267{
1268 char buffer[256];
1269 struct sockaddr sa;
1270 size_t size;
1271
1272 (void)sep;
1273
1274 size = sizeof(sa);
1275 if (recvfrom(s, buffer, sizeof(buffer), 0, &sa, &size) < 0)
1276 return;
1277 size = human_readable_time_sprintf(buffer);
1278 sendto(s, buffer, size, 0, &sa, sizeof(sa));
1279}
1280#endif /* CONFIG_FEATURE_INETD_SUPPORT_BILTIN_DAYTIME */