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