3ecd322921b2c6b1cc6006306fbcccf6153a7054
[oweals/busybox.git] / networking / inetd.c
1 /*      $Slackware: inetd.c 1.79s 2001/02/06 13:18:00 volkerdi Exp $    */
2 /*      $OpenBSD: inetd.c,v 1.79 2001/01/30 08:30:57 deraadt Exp $      */
3 /*      $NetBSD: inetd.c,v 1.11 1996/02/22 11:14:41 mycroft Exp $       */
4 /* Busybox port by Vladimir Oleynik (C) 2001-2005 <dzo@simtreas.ru>     */
5 /*
6  * Copyright (c) 1983,1991 The Regents of the University of California.
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  * 3. All advertising materials mentioning features or use of this software
18  *    must display the following acknowledgement:
19  *      This product includes software developed by the University of
20  *      California, Berkeley and its contributors.
21  * 4. Neither the name of the University nor the names of its contributors
22  *    may be used to endorse or promote products derived from this software
23  *    without specific prior written permission.
24  *
25  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35  * SUCH DAMAGE.
36  */
37
38 /*
39  * Inetd - Internet super-server
40  *
41  * This program invokes all internet services as needed.
42  * connection-oriented services are invoked each time a
43  * connection is made, by creating a process.  This process
44  * is passed the connection as file descriptor 0 and is
45  * expected to do a getpeername to find out the source host
46  * and port.
47  *
48  * Datagram oriented services are invoked when a datagram
49  * arrives; a process is created and passed a pending message
50  * on file descriptor 0.  Datagram servers may either connect
51  * to their peer, freeing up the original socket for inetd
52  * to receive further messages on, or ``take over the socket'',
53  * processing all arriving datagrams and, eventually, timing
54  * out.  The first type of server is said to be ``multi-threaded'';
55  * the second type of server ``single-threaded''.
56  *
57  * Inetd uses a configuration file which is read at startup
58  * and, possibly, at some later time in response to a hangup signal.
59  * The configuration file is ``free format'' with fields given in the
60  * order shown below.  Continuation lines for an entry must begin with
61  * a space or tab.  All fields must be present in each entry.
62  *
63  *      service name                    must be in /etc/services
64  *      socket type                     stream/dgram/raw/rdm/seqpacket
65  *      protocol                        must be in /etc/protocols
66  *      wait/nowait[.max]               single-threaded/multi-threaded, max #
67  *      user[.group] or user[:group]    user/group to run daemon as
68  *      server program                  full path name
69  *      server program arguments        maximum of MAXARGS (20)
70  *
71  * For RPC services
72  *      service name/version            must be in /etc/rpc
73  *      socket type                     stream/dgram/raw/rdm/seqpacket
74  *      protocol                        must be in /etc/protocols
75  *      wait/nowait[.max]               single-threaded/multi-threaded
76  *      user[.group] or user[:group]    user to run daemon as
77  *      server program                  full path name
78  *      server program arguments        maximum of MAXARGS (20)
79  *
80  * For non-RPC services, the "service name" can be of the form
81  * hostaddress:servicename, in which case the hostaddress is used
82  * as the host portion of the address to listen on.  If hostaddress
83  * consists of a single `*' character, INADDR_ANY is used.
84  *
85  * A line can also consist of just
86  *      hostaddress:
87  * where hostaddress is as in the preceding paragraph.  Such a line must
88  * have no further fields; the specified hostaddress is remembered and
89  * used for all further lines that have no hostaddress specified,
90  * until the next such line (or EOF).  (This is why * is provided to
91  * allow explicit specification of INADDR_ANY.)  A line
92  *      *:
93  * is implicitly in effect at the beginning of the file.
94  *
95  * The hostaddress specifier may (and often will) contain dots;
96  * the service name must not.
97  *
98  * For RPC services, host-address specifiers are accepted and will
99  * work to some extent; however, because of limitations in the
100  * portmapper interface, it will not work to try to give more than
101  * one line for any given RPC service, even if the host-address
102  * specifiers are different.
103  *
104  * Comment lines are indicated by a `#' in column 1.
105  */
106
107 /*
108  * Here's the scoop concerning the user[.:]group feature:
109  *
110  * 1) set-group-option off.
111  *
112  *      a) user = root: NO setuid() or setgid() is done
113  *
114  *      b) other:       setgid(primary group as found in passwd)
115  *                      initgroups(name, primary group)
116  *                      setuid()
117  *
118  * 2) set-group-option on.
119  *
120  *      a) user = root: setgid(specified group)
121  *                      NO initgroups()
122  *                      NO setuid()
123  *
124  *      b) other:       setgid(specified group)
125  *                      initgroups(name, specified group)
126  *                      setuid()
127  *
128  */
129
130 #include <sys/param.h>
131 #include <sys/stat.h>
132 #include <sys/ioctl.h>
133 #include <sys/socket.h>
134 #include <sys/un.h>
135 #include <sys/file.h>
136 #include <sys/wait.h>
137 #include <sys/resource.h>
138
139
140 #include <netinet/in.h>
141 #include <arpa/inet.h>
142
143 #include <errno.h>
144 #include <signal.h>
145 #include <netdb.h>
146 #include <syslog.h>
147 #include <stdio.h>
148 #include <stdlib.h>
149 #include <unistd.h>
150 #include <string.h>
151 #include <ctype.h>
152 #include <time.h>
153
154 #include "busybox.h"
155
156 //#define CONFIG_FEATURE_INETD_RPC
157 //#define CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_ECHO
158 //#define CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD
159 //#define CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_TIME
160 //#define CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME
161 //#define CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN
162 //#define CONFIG_FEATURE_IPV6
163
164 #ifdef CONFIG_FEATURE_INETD_RPC
165 #include <rpc/rpc.h>
166 #include <rpc/pmap_clnt.h>
167 #endif
168
169 #define _PATH_INETDCONF "/etc/inetd.conf"
170 #define _PATH_INETDPID  "/var/run/inetd.pid"
171
172
173 #define TOOMANY         0               /* don't start more than TOOMANY */
174
175 #define CNT_INTVL       60              /* servers in CNT_INTVL sec. */
176 #define RETRYTIME       (60*10)         /* retry after bind or server fail */
177
178 #ifndef RLIMIT_NOFILE
179 #define RLIMIT_NOFILE   RLIMIT_OFILE
180 #endif
181
182 #ifndef OPEN_MAX
183 #define OPEN_MAX        64
184 #endif
185
186 /* Reserve some descriptors, 3 stdio + at least: 1 log, 1 conf. file */
187 #define FD_MARGIN       (8)
188 static rlim_t rlim_ofile_cur = OPEN_MAX;
189 static struct rlimit rlim_ofile;
190
191
192 /* Check unsupporting builtin */
193 #if defined CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_ECHO || \
194         defined CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD || \
195         defined CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_TIME || \
196         defined CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME || \
197         defined CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN
198 # define INETD_FEATURE_ENABLED
199 #endif
200
201 #if defined CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_ECHO || \
202         defined CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD || \
203         defined CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN
204 # define INETD_SETPROCTITLE
205 #endif
206
207 typedef struct servtab
208 {
209   char *se_hostaddr;                    /* host address to listen on */
210   char *se_service;                     /* name of service */
211   int se_socktype;                      /* type of socket to use */
212   int se_family;                        /* address family */
213   char *se_proto;                       /* protocol used */
214 #ifdef CONFIG_FEATURE_INETD_RPC
215   int se_rpcprog;                       /* rpc program number */
216   int se_rpcversl;                      /* rpc program lowest version */
217   int se_rpcversh;                      /* rpc program highest version */
218 #define isrpcservice(sep)       ((sep)->se_rpcversl != 0)
219 #else
220 #define isrpcservice(sep)       0
221 #endif
222   pid_t se_wait;                        /* single threaded server */
223   short se_checked;                     /* looked at during merge */
224   char *se_user;                        /* user name to run as */
225   char *se_group;                       /* group name to run as */
226 #ifdef INETD_FEATURE_ENABLED
227   const struct builtin *se_bi;                 /* if built-in, description */
228 #endif
229   char *se_server;                      /* server program */
230 #define MAXARGV 20
231   char *se_argv[MAXARGV + 1];           /* program arguments */
232   int se_fd;                            /* open descriptor */
233   union
234   {
235         struct sockaddr se_un_ctrladdr;
236         struct sockaddr_in se_un_ctrladdr_in;
237 #ifdef CONFIG_FEATURE_IPV6
238         struct sockaddr_in6 se_un_ctrladdr_in6;
239 #endif
240         struct sockaddr_un se_un_ctrladdr_un;
241   } se_un;                              /* bound address */
242 #define se_ctrladdr     se_un.se_un_ctrladdr
243 #define se_ctrladdr_in  se_un.se_un_ctrladdr_in
244 #define se_ctrladdr_in6 se_un.se_un_ctrladdr_in6
245 #define se_ctrladdr_un  se_un.se_un_ctrladdr_un
246   int se_ctrladdr_size;
247   int se_max;                           /* max # of instances of this service */
248   int se_count;                         /* number started since se_time */
249   struct timeval se_time;               /* start of se_count */
250   struct servtab *se_next;
251 } servtab_t;
252
253 static servtab_t *servtab;
254
255 #ifdef INETD_FEATURE_ENABLED
256 struct builtin
257 {
258   const char *bi_service;               /* internally provided service name */
259   int bi_socktype;                      /* type of socket supported */
260   short bi_fork;                        /* 1 if should fork before call */
261   short bi_wait;                        /* 1 if should wait for child */
262   void (*bi_fn) (int, servtab_t *);
263 };
264
265         /* Echo received data */
266 #ifdef CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_ECHO
267 static void echo_stream (int, servtab_t *);
268 static void echo_dg (int, servtab_t *);
269 #endif
270         /* Internet /dev/null */
271 #ifdef CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD
272 static void discard_stream (int, servtab_t *);
273 static void discard_dg (int, servtab_t *);
274 #endif
275         /* Return 32 bit time since 1900 */
276 #ifdef CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_TIME
277 static void machtime_stream (int, servtab_t *);
278 static void machtime_dg (int, servtab_t *);
279 #endif
280         /* Return human-readable time */
281 #ifdef CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME
282 static void daytime_stream (int, servtab_t *);
283 static void daytime_dg (int, servtab_t *);
284 #endif
285         /* Familiar character generator */
286 #ifdef CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN
287 static void chargen_stream (int, servtab_t *);
288 static void chargen_dg (int, servtab_t *);
289 #endif
290
291 static const struct builtin builtins[] = {
292 #ifdef CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_ECHO
293   /* Echo received data */
294   {"echo", SOCK_STREAM, 1, 0, echo_stream,},
295   {"echo", SOCK_DGRAM, 0, 0, echo_dg,},
296 #endif
297 #ifdef CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD
298   /* Internet /dev/null */
299   {"discard", SOCK_STREAM, 1, 0, discard_stream,},
300   {"discard", SOCK_DGRAM, 0, 0, discard_dg,},
301 #endif
302 #ifdef CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_TIME
303   /* Return 32 bit time since 1900 */
304   {"time", SOCK_STREAM, 0, 0, machtime_stream,},
305   {"time", SOCK_DGRAM, 0, 0, machtime_dg,},
306 #endif
307 #ifdef CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME
308   /* Return human-readable time */
309   {"daytime", SOCK_STREAM, 0, 0, daytime_stream,},
310   {"daytime", SOCK_DGRAM, 0, 0, daytime_dg,},
311 #endif
312 #ifdef CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN
313   /* Familiar character generator */
314   {"chargen", SOCK_STREAM, 1, 0, chargen_stream,},
315   {"chargen", SOCK_DGRAM, 0, 0, chargen_dg,},
316 #endif
317   {NULL, 0, 0, 0, NULL}
318 };
319 #endif /* INETD_FEATURE_ENABLED */
320
321 static int global_queuelen = 128;
322 static int nsock, maxsock;
323 static fd_set allsock;
324 static int toomany = TOOMANY;
325 static int timingout;
326 static struct servent *sp;
327 static uid_t uid;
328
329 static char *CONFIG = _PATH_INETDCONF;
330
331 static FILE *fconfig;
332 static char line[1024];
333 static char *defhost;
334
335 static char *newstr (char *cp)
336 {
337   if ((cp = strdup (cp ? cp : "")))
338         return (cp);
339   syslog (LOG_ERR, "strdup: %m");
340   exit (1);
341 }
342
343 static int setconfig (void)
344 {
345   free (defhost);
346   defhost = newstr ("*");
347   if (fconfig != NULL) {
348         fseek (fconfig, 0L, SEEK_SET);
349         return (1);
350   }
351   fconfig = fopen (CONFIG, "r");
352   return (fconfig != NULL);
353 }
354
355 static void endconfig (void)
356 {
357   if (fconfig) {
358         (void) fclose (fconfig);
359         fconfig = NULL;
360   }
361   free (defhost);
362   defhost = 0;
363 }
364
365 #ifdef CONFIG_FEATURE_INETD_RPC
366 static void register_rpc (servtab_t *sep)
367 {
368   int n;
369   struct sockaddr_in ir_sin;
370   struct protoent *pp;
371   socklen_t size;
372
373   if ((pp = getprotobyname (sep->se_proto + 4)) == NULL) {
374         syslog (LOG_ERR, "%s: getproto: %m", sep->se_proto);
375         return;
376   }
377   size = sizeof ir_sin;
378   if (getsockname (sep->se_fd, (struct sockaddr *) &ir_sin, &size) < 0) {
379         syslog (LOG_ERR, "%s/%s: getsockname: %m",
380                         sep->se_service, sep->se_proto);
381         return;
382   }
383
384   for (n = sep->se_rpcversl; n <= sep->se_rpcversh; n++) {
385         (void) pmap_unset (sep->se_rpcprog, n);
386         if (!pmap_set (sep->se_rpcprog, n, pp->p_proto, ntohs (ir_sin.sin_port)))
387           syslog (LOG_ERR, "%s %s: pmap_set: %u %u %u %u: %m",
388                           sep->se_service, sep->se_proto,
389                           sep->se_rpcprog, n, pp->p_proto, ntohs (ir_sin.sin_port));
390   }
391 }
392
393 static void unregister_rpc (servtab_t *sep)
394 {
395   int n;
396
397   for (n = sep->se_rpcversl; n <= sep->se_rpcversh; n++) {
398         if (!pmap_unset (sep->se_rpcprog, n))
399           syslog (LOG_ERR, "pmap_unset(%u, %u)", sep->se_rpcprog, n);
400   }
401 }
402 #endif /* CONFIG_FEATURE_INETD_RPC */
403
404 static void freeconfig (servtab_t *cp)
405 {
406   int i;
407
408   free (cp->se_hostaddr);
409   free (cp->se_service);
410   free (cp->se_proto);
411   free (cp->se_user);
412   free (cp->se_group);
413   free (cp->se_server);
414   for (i = 0; i < MAXARGV; i++)
415         free (cp->se_argv[i]);
416 }
417
418 static int bump_nofile (void)
419 {
420 #define FD_CHUNK        32
421
422   struct rlimit rl;
423
424   if (getrlimit (RLIMIT_NOFILE, &rl) < 0) {
425         syslog (LOG_ERR, "getrlimit: %m");
426         return -1;
427   }
428   rl.rlim_cur = MIN (rl.rlim_max, rl.rlim_cur + FD_CHUNK);
429   rl.rlim_cur = MIN (FD_SETSIZE, rl.rlim_cur + FD_CHUNK);
430   if (rl.rlim_cur <= rlim_ofile_cur) {
431         syslog (LOG_ERR, "bump_nofile: cannot extend file limit, max = %d",
432                         (int) rl.rlim_cur);
433         return -1;
434   }
435
436   if (setrlimit (RLIMIT_NOFILE, &rl) < 0) {
437         syslog (LOG_ERR, "setrlimit: %m");
438         return -1;
439   }
440
441   rlim_ofile_cur = rl.rlim_cur;
442   return 0;
443 }
444
445 static void setup (servtab_t *sep)
446 {
447   int on = 1;
448   int r;
449
450   if ((sep->se_fd = socket (sep->se_family, sep->se_socktype, 0)) < 0) {
451         syslog (LOG_ERR, "%s/%s: socket: %m", sep->se_service, sep->se_proto);
452         return;
453   }
454 #define turnon(fd, opt) \
455 setsockopt(fd, SOL_SOCKET, opt, (char *)&on, sizeof (on))
456   if (turnon (sep->se_fd, SO_REUSEADDR) < 0)
457         syslog (LOG_ERR, "setsockopt (SO_REUSEADDR): %m");
458 #undef turnon
459
460 #ifdef CONFIG_FEATURE_INETD_RPC
461   if (isrpcservice (sep)) {
462         struct passwd *pwd;
463
464         /*
465          * for RPC services, attempt to use a reserved port
466          * if they are going to be running as root.
467          *
468          * Also, zero out the port for all RPC services; let bind()
469          * find one.
470          */
471         sep->se_ctrladdr_in.sin_port = 0;
472         if (sep->se_user && (pwd = getpwnam (sep->se_user)) &&
473                 pwd->pw_uid == 0 && uid == 0)
474           r = bindresvport (sep->se_fd, &sep->se_ctrladdr_in);
475         else {
476           r = bind (sep->se_fd, &sep->se_ctrladdr, sep->se_ctrladdr_size);
477           if (r == 0) {
478                 socklen_t len = sep->se_ctrladdr_size;
479                 int saveerrno = errno;
480
481                 /* update se_ctrladdr_in.sin_port */
482                 r = getsockname (sep->se_fd, &sep->se_ctrladdr, &len);
483                 if (r <= 0)
484                   errno = saveerrno;
485           }
486         }
487   } else
488 #endif
489         r = bind (sep->se_fd, &sep->se_ctrladdr, sep->se_ctrladdr_size);
490   if (r < 0) {
491         syslog (LOG_ERR, "%s/%s (%d): bind: %m",
492                         sep->se_service, sep->se_proto, sep->se_ctrladdr.sa_family);
493         close (sep->se_fd);
494         sep->se_fd = -1;
495         if (!timingout) {
496           timingout = 1;
497           alarm (RETRYTIME);
498         }
499         return;
500   }
501   if (sep->se_socktype == SOCK_STREAM)
502         listen (sep->se_fd, global_queuelen);
503
504   FD_SET (sep->se_fd, &allsock);
505   nsock++;
506   if (sep->se_fd > maxsock) {
507         maxsock = sep->se_fd;
508         if ((rlim_t)maxsock > rlim_ofile_cur - FD_MARGIN)
509           bump_nofile ();
510   }
511 }
512
513 static char *nextline (void)
514 {
515   char *cp;
516   FILE *fd = fconfig;
517
518   if (fgets (line, sizeof (line), fd) == NULL)
519         return (NULL);
520   cp = strchr (line, '\n');
521   if (cp)
522         *cp = '\0';
523   return (line);
524 }
525
526 static char *skip (char **cpp) /* int report; */
527 {
528   char *cp = *cpp;
529   char *start;
530
531 /* erp: */
532   if (*cpp == NULL) {
533         /* if (report) */
534         /* syslog(LOG_ERR, "syntax error in inetd config file"); */
535         return (NULL);
536   }
537
538 again:
539   while (*cp == ' ' || *cp == '\t')
540         cp++;
541   if (*cp == '\0') {
542         int c;
543
544         c = getc (fconfig);
545         (void) ungetc (c, fconfig);
546         if (c == ' ' || c == '\t')
547           if ((cp = nextline ()))
548                 goto again;
549         *cpp = NULL;
550         /* goto erp; */
551         return (NULL);
552   }
553   start = cp;
554   while (*cp && *cp != ' ' && *cp != '\t')
555         cp++;
556   if (*cp != '\0')
557         *cp++ = '\0';
558   /* if ((*cpp = cp) == NULL) */
559   /* goto erp; */
560
561   *cpp = cp;
562   return (start);
563 }
564
565 static servtab_t *new_servtab(void)
566 {
567   servtab_t *sep;
568
569   sep = (servtab_t *) malloc (sizeof (servtab_t));
570   if (sep == NULL) {
571         syslog (LOG_ERR, bb_msg_memory_exhausted);
572         exit (1);
573   }
574   return sep;
575 }
576
577 static servtab_t *dupconfig (servtab_t *sep)
578 {
579   servtab_t *newtab;
580   int argc;
581
582   newtab = new_servtab();
583   memset (newtab, 0, sizeof (servtab_t));
584   newtab->se_service = sep->se_service ? newstr (sep->se_service) : NULL;
585   newtab->se_socktype = sep->se_socktype;
586   newtab->se_family = sep->se_family;
587   newtab->se_proto = sep->se_proto ? newstr (sep->se_proto) : NULL;
588 #ifdef CONFIG_FEATURE_INETD_RPC
589   newtab->se_rpcprog = sep->se_rpcprog;
590   newtab->se_rpcversl = sep->se_rpcversl;
591   newtab->se_rpcversh = sep->se_rpcversh;
592 #endif
593   newtab->se_wait = sep->se_wait;
594   newtab->se_user = sep->se_user ? newstr (sep->se_user) : NULL;
595   newtab->se_group = sep->se_group ? newstr (sep->se_group) : NULL;
596 #ifdef INETD_FEATURE_ENABLED
597   newtab->se_bi = sep->se_bi;
598 #endif
599   newtab->se_server = sep->se_server ? newstr (sep->se_server) : 0;
600
601   for (argc = 0; argc <= MAXARGV; argc++)
602         newtab->se_argv[argc] = sep->se_argv[argc] ?
603           newstr (sep->se_argv[argc]) : NULL;
604   newtab->se_max = sep->se_max;
605
606   return (newtab);
607 }
608
609 static servtab_t *getconfigent (void)
610 {
611   servtab_t *sep;
612   int argc;
613   char *cp, *arg;
614   char *hostdelim;
615   servtab_t *nsep;
616   servtab_t *psep;
617
618   sep = new_servtab();
619
620   /* memset(sep, 0, sizeof *sep); */
621 more:
622   /* freeconfig(sep); */
623
624   while ((cp = nextline ()) && *cp == '#');
625   if (cp == NULL) {
626         /* free(sep); */
627         return (NULL);
628   }
629
630   memset ((char *) sep, 0, sizeof *sep);
631   arg = skip (&cp);
632   if (arg == NULL) {
633         /* A blank line. */
634         goto more;
635   }
636
637   /* Check for a host name. */
638   hostdelim = strrchr (arg, ':');
639   if (hostdelim) {
640         *hostdelim = '\0';
641         sep->se_hostaddr = newstr (arg);
642         arg = hostdelim + 1;
643         /*
644          * If the line is of the form `host:', then just change the
645          * default host for the following lines.
646          */
647         if (*arg == '\0') {
648           arg = skip (&cp);
649           if (cp == NULL) {
650                 free (defhost);
651                 defhost = sep->se_hostaddr;
652                 goto more;
653           }
654         }
655   } else
656         sep->se_hostaddr = newstr (defhost);
657
658   sep->se_service = newstr (arg);
659   arg = skip (&cp);
660
661   if (strcmp (arg, "stream") == 0)
662         sep->se_socktype = SOCK_STREAM;
663   else if (strcmp (arg, "dgram") == 0)
664         sep->se_socktype = SOCK_DGRAM;
665   else if (strcmp (arg, "rdm") == 0)
666         sep->se_socktype = SOCK_RDM;
667   else if (strcmp (arg, "seqpacket") == 0)
668         sep->se_socktype = SOCK_SEQPACKET;
669   else if (strcmp (arg, "raw") == 0)
670         sep->se_socktype = SOCK_RAW;
671   else
672         sep->se_socktype = -1;
673
674   sep->se_proto = newstr (skip (&cp));
675
676   if (strcmp (sep->se_proto, "unix") == 0) {
677         sep->se_family = AF_UNIX;
678   } else {
679         sep->se_family = AF_INET;
680         if (sep->se_proto[strlen (sep->se_proto) - 1] == '6')
681 #ifdef CONFIG_FEATURE_IPV6
682           sep->se_family = AF_INET6;
683 #else
684           syslog (LOG_ERR, "%s: IPV6 not supported", sep->se_proto);
685 #endif
686         if (strncmp (sep->se_proto, "rpc/", 4) == 0) {
687 #ifdef CONFIG_FEATURE_INETD_RPC
688           char *p, *ccp;
689           long l;
690
691           p = strchr (sep->se_service, '/');
692           if (p == 0) {
693                 syslog (LOG_ERR, "%s: no rpc version", sep->se_service);
694                 goto more;
695           }
696           *p++ = '\0';
697           l = strtol (p, &ccp, 0);
698           if (ccp == p || l < 0 || l > INT_MAX) {
699           badafterall:
700                 syslog (LOG_ERR, "%s/%s: bad rpc version", sep->se_service, p);
701                 goto more;
702           }
703           sep->se_rpcversl = sep->se_rpcversh = l;
704           if (*ccp == '-') {
705                 p = ccp + 1;
706                 l = strtol (p, &ccp, 0);
707                 if (ccp == p || l < 0 || l > INT_MAX || l < sep->se_rpcversl || *ccp)
708                   goto badafterall;
709                 sep->se_rpcversh = l;
710           } else if (*ccp != '\0')
711                 goto badafterall;
712 #else
713         syslog (LOG_ERR, "%s: rpc services not supported", sep->se_service);
714 #endif
715         }
716   }
717   arg = skip (&cp);
718   if (arg == NULL)
719         goto more;
720
721   {
722         char *s = strchr (arg, '.');
723         if (s) {
724           *s++ = '\0';
725           sep->se_max = atoi (s);
726         } else
727           sep->se_max = toomany;
728   }
729   sep->se_wait = strcmp (arg, "wait") == 0;
730   /* if ((arg = skip(&cp, 1)) == NULL) */
731   /* goto more; */
732   sep->se_user = newstr (skip (&cp));
733   arg = strchr (sep->se_user, '.');
734   if (arg == NULL)
735         arg = strchr (sep->se_user, ':');
736   if (arg) {
737         *arg++ = '\0';
738         sep->se_group = newstr (arg);
739   }
740   /* if ((arg = skip(&cp, 1)) == NULL) */
741   /* goto more; */
742
743   sep->se_server = newstr (skip (&cp));
744   if (strcmp (sep->se_server, "internal") == 0) {
745 #ifdef INETD_FEATURE_ENABLED
746         const struct builtin *bi;
747
748         for (bi = builtins; bi->bi_service; bi++)
749           if (bi->bi_socktype == sep->se_socktype &&
750                   strcmp (bi->bi_service, sep->se_service) == 0)
751                 break;
752         if (bi->bi_service == 0) {
753           syslog (LOG_ERR, "internal service %s unknown", sep->se_service);
754           goto more;
755         }
756         sep->se_bi = bi;
757         sep->se_wait = bi->bi_wait;
758 #else
759         syslog (LOG_ERR, "internal service %s unknown", sep->se_service);
760         goto more;
761 #endif
762   }
763 #ifdef INETD_FEATURE_ENABLED
764     else
765         sep->se_bi = NULL;
766 #endif
767   argc = 0;
768   for (arg = skip (&cp); cp; arg = skip (&cp)) {
769         if (argc < MAXARGV)
770           sep->se_argv[argc++] = newstr (arg);
771   }
772   while (argc <= MAXARGV)
773         sep->se_argv[argc++] = NULL;
774
775   /*
776    * Now that we've processed the entire line, check if the hostname
777    * specifier was a comma separated list of hostnames. If so
778    * we'll make new entries for each address.
779    */
780   while ((hostdelim = strrchr (sep->se_hostaddr, ',')) != NULL) {
781         nsep = dupconfig (sep);
782
783         /*
784          * NULL terminate the hostname field of the existing entry,
785          * and make a dup for the new entry.
786          */
787         *hostdelim++ = '\0';
788         nsep->se_hostaddr = newstr (hostdelim);
789
790         nsep->se_next = sep->se_next;
791         sep->se_next = nsep;
792   }
793
794   nsep = sep;
795   while (nsep != NULL) {
796         nsep->se_checked = 1;
797         if (nsep->se_family == AF_INET) {
798           if (!strcmp (nsep->se_hostaddr, "*"))
799                 nsep->se_ctrladdr_in.sin_addr.s_addr = INADDR_ANY;
800           else if (!inet_aton (nsep->se_hostaddr, &nsep->se_ctrladdr_in.sin_addr)) {
801                 struct hostent *hp;
802
803                 hp = gethostbyname (nsep->se_hostaddr);
804                 if (hp == 0) {
805                   syslog (LOG_ERR, "%s: unknown host", nsep->se_hostaddr);
806                   nsep->se_checked = 0;
807                   goto skip;
808                 } else if (hp->h_addrtype != AF_INET) {
809                   syslog (LOG_ERR,
810                                   "%s: address isn't an Internet "
811                                   "address", nsep->se_hostaddr);
812                   nsep->se_checked = 0;
813                   goto skip;
814                 } else {
815                   int i = 1;
816
817                   memmove (&nsep->se_ctrladdr_in.sin_addr,
818                                    hp->h_addr_list[0], sizeof (struct in_addr));
819                   while (hp->h_addr_list[i] != NULL) {
820                         psep = dupconfig (nsep);
821                         psep->se_hostaddr = newstr (nsep->se_hostaddr);
822                         psep->se_checked = 1;
823                         memmove (&psep->se_ctrladdr_in.sin_addr,
824                                          hp->h_addr_list[i], sizeof (struct in_addr));
825                         psep->se_ctrladdr_size = sizeof (psep->se_ctrladdr_in);
826                         i++;
827                         /* Prepend to list, don't want to look up its */
828                         /* hostname again. */
829                         psep->se_next = sep;
830                         sep = psep;
831                   }
832                 }
833           }
834         }
835 /* XXX BUG?: is this skip: label supposed to remain? */
836   skip:
837         nsep = nsep->se_next;
838   }
839
840   /*
841    * Finally, free any entries which failed the gethostbyname
842    * check.
843    */
844   psep = NULL;
845   nsep = sep;
846   while (nsep != NULL) {
847         servtab_t *tsep;
848
849         if (nsep->se_checked == 0) {
850           tsep = nsep;
851           if (psep == NULL) {
852                 sep = nsep->se_next;
853                 nsep = sep;
854           } else {
855                 nsep = nsep->se_next;
856                 psep->se_next = nsep;
857           }
858           freeconfig (tsep);
859         } else {
860           nsep->se_checked = 0;
861           psep = nsep;
862           nsep = nsep->se_next;
863         }
864   }
865
866   return (sep);
867 }
868
869 #define Block_Using_Signals(m) do {     sigemptyset(&m); \
870                                         sigaddset(&m, SIGCHLD); \
871                                         sigaddset(&m, SIGHUP); \
872                                         sigaddset(&m, SIGALRM); \
873                                         sigprocmask(SIG_BLOCK, &m, NULL); \
874                                 } while(0)
875
876
877 static servtab_t *enter (servtab_t *cp)
878 {
879   servtab_t *sep;
880   sigset_t omask;
881
882   sep = new_servtab();
883   *sep = *cp;
884   sep->se_fd = -1;
885 #ifdef CONFIG_FEATURE_INETD_RPC
886   sep->se_rpcprog = -1;
887 #endif
888   Block_Using_Signals(omask);
889   sep->se_next = servtab;
890   servtab = sep;
891   sigprocmask(SIG_UNBLOCK, &omask, NULL);
892   return (sep);
893 }
894
895 static int matchconf (servtab_t *old, servtab_t *new)
896 {
897   if (strcmp (old->se_service, new->se_service) != 0)
898         return (0);
899
900   if (strcmp (old->se_hostaddr, new->se_hostaddr) != 0)
901         return (0);
902
903   if (strcmp (old->se_proto, new->se_proto) != 0)
904         return (0);
905
906   /*
907    * If the new servtab is bound to a specific address, check that the
908    * old servtab is bound to the same entry. If the new service is not
909    * bound to a specific address then the check of se_hostaddr above
910    * is sufficient.
911    */
912
913   if (old->se_family == AF_INET && new->se_family == AF_INET &&
914           memcmp (&old->se_ctrladdr_in.sin_addr,
915                           &new->se_ctrladdr_in.sin_addr,
916                           sizeof (new->se_ctrladdr_in.sin_addr)) != 0)
917         return (0);
918
919 #ifdef CONFIG_FEATURE_IPV6
920   if (old->se_family == AF_INET6 && new->se_family == AF_INET6 &&
921           memcmp (&old->se_ctrladdr_in6.sin6_addr,
922                           &new->se_ctrladdr_in6.sin6_addr,
923                           sizeof (new->se_ctrladdr_in6.sin6_addr)) != 0)
924         return (0);
925 #endif
926   return (1);
927 }
928
929 static void config (int sig ATTRIBUTE_UNUSED)
930 {
931   servtab_t *sep, *cp, **sepp;
932   sigset_t omask;
933   int add;
934   size_t n;
935   char protoname[10];
936
937   if (!setconfig ()) {
938         syslog (LOG_ERR, "%s: %m", CONFIG);
939         return;
940   }
941   for (sep = servtab; sep; sep = sep->se_next)
942         sep->se_checked = 0;
943   cp = getconfigent ();
944   while (cp != NULL) {
945         for (sep = servtab; sep; sep = sep->se_next)
946           if (matchconf (sep, cp))
947                 break;
948         add = 0;
949         if (sep != 0) {
950           int i;
951
952 #define SWAP(type, a, b) do {type c=(type)a; a=(type)b; b=(type)c;} while (0)
953
954           Block_Using_Signals(omask);
955           /*
956            * sep->se_wait may be holding the pid of a daemon
957            * that we're waiting for.  If so, don't overwrite
958            * it unless the config file explicitly says don't
959            * wait.
960            */
961           if (
962 #ifdef INETD_FEATURE_ENABLED
963                    cp->se_bi == 0 &&
964 #endif
965                 (sep->se_wait == 1 || cp->se_wait == 0))
966                 sep->se_wait = cp->se_wait;
967           SWAP (int, cp->se_max, sep->se_max);
968           SWAP (char *, sep->se_user, cp->se_user);
969           SWAP (char *, sep->se_group, cp->se_group);
970           SWAP (char *, sep->se_server, cp->se_server);
971           for (i = 0; i < MAXARGV; i++)
972                 SWAP (char *, sep->se_argv[i], cp->se_argv[i]);
973 #undef SWAP
974
975 #ifdef CONFIG_FEATURE_INETD_RPC
976           if (isrpcservice (sep))
977                 unregister_rpc (sep);
978           sep->se_rpcversl = cp->se_rpcversl;
979           sep->se_rpcversh = cp->se_rpcversh;
980 #endif
981           sigprocmask(SIG_UNBLOCK, &omask, NULL);
982           freeconfig (cp);
983           add = 1;
984         } else {
985           sep = enter (cp);
986         }
987         sep->se_checked = 1;
988
989         switch (sep->se_family) {
990         case AF_UNIX:
991           if (sep->se_fd != -1)
992                 break;
993           (void) unlink (sep->se_service);
994           n = strlen (sep->se_service);
995           if (n > sizeof sep->se_ctrladdr_un.sun_path - 1)
996                 n = sizeof sep->se_ctrladdr_un.sun_path - 1;
997           safe_strncpy (sep->se_ctrladdr_un.sun_path, sep->se_service, n + 1);
998           sep->se_ctrladdr_un.sun_family = AF_UNIX;
999           sep->se_ctrladdr_size = n + sizeof sep->se_ctrladdr_un.sun_family;
1000           setup (sep);
1001           break;
1002         case AF_INET:
1003           sep->se_ctrladdr_in.sin_family = AF_INET;
1004           /* se_ctrladdr_in was set in getconfigent */
1005           sep->se_ctrladdr_size = sizeof sep->se_ctrladdr_in;
1006
1007 #ifdef CONFIG_FEATURE_INETD_RPC
1008           if (isrpcservice (sep)) {
1009                 struct rpcent *rp;
1010
1011                 sep->se_rpcprog = atoi (sep->se_service);
1012                 if (sep->se_rpcprog == 0) {
1013                   rp = getrpcbyname (sep->se_service);
1014                   if (rp == 0) {
1015                         syslog (LOG_ERR, "%s: unknown rpc service", sep->se_service);
1016                         goto serv_unknown;
1017                   }
1018                   sep->se_rpcprog = rp->r_number;
1019                 }
1020                 if (sep->se_fd == -1)
1021                   setup (sep);
1022                 if (sep->se_fd != -1)
1023                   register_rpc (sep);
1024           } else
1025 #endif
1026              {
1027                 u_short port = htons (atoi (sep->se_service));
1028
1029                 if (!port) {
1030                    /*XXX*/ strncpy (protoname, sep->se_proto, sizeof (protoname));
1031                   if (isdigit (protoname[strlen (protoname) - 1]))
1032                         protoname[strlen (protoname) - 1] = '\0';
1033                   sp = getservbyname (sep->se_service, protoname);
1034                   if (sp == 0) {
1035                         syslog (LOG_ERR,
1036                                         "%s/%s: unknown service", sep->se_service, sep->se_proto);
1037                         goto serv_unknown;
1038                   }
1039                   port = sp->s_port;
1040                 }
1041                 if (port != sep->se_ctrladdr_in.sin_port) {
1042                   sep->se_ctrladdr_in.sin_port = port;
1043                   if (sep->se_fd != -1) {
1044                         FD_CLR (sep->se_fd, &allsock);
1045                         nsock--;
1046                         (void) close (sep->se_fd);
1047                   }
1048                   sep->se_fd = -1;
1049                 }
1050                 if (sep->se_fd == -1)
1051                   setup (sep);
1052           }
1053           break;
1054 #ifdef CONFIG_FEATURE_IPV6
1055         case AF_INET6:
1056           sep->se_ctrladdr_in6.sin6_family = AF_INET6;
1057           /* se_ctrladdr_in was set in getconfigent */
1058           sep->se_ctrladdr_size = sizeof sep->se_ctrladdr_in6;
1059
1060 #ifdef CONFIG_FEATURE_INETD_RPC
1061           if (isrpcservice (sep)) {
1062                 struct rpcent *rp;
1063
1064                 sep->se_rpcprog = atoi (sep->se_service);
1065                 if (sep->se_rpcprog == 0) {
1066                   rp = getrpcbyname (sep->se_service);
1067                   if (rp == 0) {
1068                         syslog (LOG_ERR, "%s: unknown rpc service", sep->se_service);
1069                         goto serv_unknown;
1070                   }
1071                   sep->se_rpcprog = rp->r_number;
1072                 }
1073                 if (sep->se_fd == -1)
1074                   setup (sep);
1075                 if (sep->se_fd != -1)
1076                   register_rpc (sep);
1077           } else
1078 #endif
1079                 {
1080                 u_short port = htons (atoi (sep->se_service));
1081
1082                 if (!port) {
1083                    /*XXX*/ strncpy (protoname, sep->se_proto, sizeof (protoname));
1084                   if (isdigit (protoname[strlen (protoname) - 1]))
1085                         protoname[strlen (protoname) - 1] = '\0';
1086                   sp = getservbyname (sep->se_service, protoname);
1087                   if (sp == 0) {
1088                         syslog (LOG_ERR,
1089                                         "%s/%s: unknown service", sep->se_service, sep->se_proto);
1090                         goto serv_unknown;
1091                   }
1092                   port = sp->s_port;
1093                 }
1094                 if (port != sep->se_ctrladdr_in6.sin6_port) {
1095                   sep->se_ctrladdr_in6.sin6_port = port;
1096                   if (sep->se_fd != -1) {
1097                         FD_CLR (sep->se_fd, &allsock);
1098                         nsock--;
1099                         (void) close (sep->se_fd);
1100                   }
1101                   sep->se_fd = -1;
1102                 }
1103                 if (sep->se_fd == -1)
1104                   setup (sep);
1105           }
1106           break;
1107 #endif /* CONFIG_FEATURE_IPV6 */
1108         }
1109   serv_unknown:
1110         if (cp->se_next != NULL) {
1111           servtab_t *tmp = cp;
1112
1113           cp = cp->se_next;
1114           free (tmp);
1115         } else {
1116           free (cp);
1117           cp = getconfigent ();
1118         }
1119   }
1120   endconfig ();
1121   /*
1122    * Purge anything not looked at above.
1123    */
1124   Block_Using_Signals(omask);
1125   sepp = &servtab;
1126   while ((sep = *sepp)) {
1127         if (sep->se_checked) {
1128           sepp = &sep->se_next;
1129           continue;
1130         }
1131         *sepp = sep->se_next;
1132         if (sep->se_fd != -1) {
1133           FD_CLR (sep->se_fd, &allsock);
1134           nsock--;
1135           (void) close (sep->se_fd);
1136         }
1137 #ifdef CONFIG_FEATURE_INETD_RPC
1138         if (isrpcservice (sep))
1139           unregister_rpc (sep);
1140 #endif
1141         if (sep->se_family == AF_UNIX)
1142           (void) unlink (sep->se_service);
1143         freeconfig (sep);
1144         free (sep);
1145   }
1146   sigprocmask(SIG_UNBLOCK, &omask, NULL);
1147 }
1148
1149
1150 static void reapchild (int sig ATTRIBUTE_UNUSED)
1151 {
1152   pid_t pid;
1153   int save_errno = errno, status;
1154   servtab_t *sep;
1155
1156   for (;;) {
1157         pid = wait3 (&status, WNOHANG, NULL);
1158         if (pid <= 0)
1159           break;
1160         for (sep = servtab; sep; sep = sep->se_next)
1161           if (sep->se_wait == pid) {
1162                 if (WIFEXITED (status) && WEXITSTATUS (status))
1163                   syslog (LOG_WARNING,
1164                                   "%s: exit status 0x%x",
1165                                   sep->se_server, WEXITSTATUS (status));
1166                 else if (WIFSIGNALED (status))
1167                   syslog (LOG_WARNING,
1168                                   "%s: exit signal 0x%x", sep->se_server, WTERMSIG (status));
1169                 sep->se_wait = 1;
1170                 FD_SET (sep->se_fd, &allsock);
1171                 nsock++;
1172           }
1173   }
1174   errno = save_errno;
1175 }
1176
1177 static void retry (int sig ATTRIBUTE_UNUSED)
1178 {
1179   servtab_t *sep;
1180
1181   timingout = 0;
1182   for (sep = servtab; sep; sep = sep->se_next) {
1183         if (sep->se_fd == -1) {
1184           switch (sep->se_family) {
1185           case AF_UNIX:
1186           case AF_INET:
1187 #ifdef CONFIG_FEATURE_IPV6
1188           case AF_INET6:
1189 #endif
1190                 setup (sep);
1191 #ifdef CONFIG_FEATURE_INETD_RPC
1192                 if (sep->se_fd != -1 && isrpcservice (sep))
1193                   register_rpc (sep);
1194 #endif
1195                 break;
1196           }
1197         }
1198   }
1199 }
1200
1201 static void goaway (int sig ATTRIBUTE_UNUSED)
1202 {
1203   servtab_t *sep;
1204
1205   /* XXX signal race walking sep list */
1206   for (sep = servtab; sep; sep = sep->se_next) {
1207         if (sep->se_fd == -1)
1208           continue;
1209
1210         switch (sep->se_family) {
1211         case AF_UNIX:
1212           (void) unlink (sep->se_service);
1213           break;
1214         case AF_INET:
1215 #ifdef CONFIG_FEATURE_IPV6
1216         case AF_INET6:
1217 #endif
1218 #ifdef CONFIG_FEATURE_INETD_RPC
1219           if (sep->se_wait == 1 && isrpcservice (sep))
1220                 unregister_rpc (sep);   /* XXX signal race */
1221 #endif
1222           break;
1223         }
1224         (void) close (sep->se_fd);
1225   }
1226   (void) unlink (_PATH_INETDPID);
1227   exit (0);
1228 }
1229
1230
1231 #ifdef INETD_SETPROCTITLE
1232 static char **Argv;
1233 static char *LastArg;
1234
1235 static void
1236 inetd_setproctitle (char *a, int s)
1237 {
1238   socklen_t size;
1239   char *cp;
1240   struct sockaddr_in prt_sin;
1241   char buf[80];
1242
1243   cp = Argv[0];
1244   size = sizeof (prt_sin);
1245   (void) snprintf (buf, sizeof buf, "-%s", a);
1246   if (getpeername (s, (struct sockaddr *) &prt_sin, &size) == 0) {
1247         char *sa = inet_ntoa (prt_sin.sin_addr);
1248
1249         buf[sizeof (buf) - 1 - strlen (sa) - 3] = '\0';
1250         strcat (buf, " [");
1251         strcat (buf, sa);
1252         strcat (buf, "]");
1253   }
1254   strncpy (cp, buf, LastArg - cp);
1255   cp += strlen (cp);
1256   while (cp < LastArg)
1257         *cp++ = ' ';
1258 }
1259 #endif
1260
1261
1262 int
1263 inetd_main (int argc, char *argv[])
1264 {
1265   servtab_t *sep;
1266   struct passwd *pwd;
1267   struct group *grp = NULL;
1268   int tmpint;
1269   struct sigaction sa, sapipe;
1270   int opt;
1271   pid_t pid;
1272   char buf[50];
1273   char *stoomany;
1274   sigset_t omask, wait_mask;
1275
1276 #ifdef INETD_SETPROCTITLE
1277   extern char **environ;
1278   char **envp = environ;
1279
1280   Argv = argv;
1281   if (envp == 0 || *envp == 0)
1282         envp = argv;
1283   while (*envp)
1284         envp++;
1285   LastArg = envp[-1] + strlen (envp[-1]);
1286 #endif
1287
1288   openlog (bb_applet_name, LOG_PID | LOG_NOWAIT, LOG_DAEMON);
1289
1290   opt = bb_getopt_ulflags (argc, argv, "R:f", &stoomany);
1291   if(opt & 1) {
1292         char *e;
1293
1294         toomany = strtoul (stoomany, &e, 0);
1295         if (!(toomany >= 0 && *e == '\0')) {
1296                 toomany = TOOMANY;
1297                 syslog (LOG_ERR, "-R %s: bad value for service invocation rate", stoomany);
1298         }
1299   }
1300   argc -= optind;
1301   argv += optind;
1302
1303   uid = getuid ();
1304   if (uid != 0)
1305         CONFIG = NULL;
1306   if (argc > 0)
1307         CONFIG = argv[0];
1308   if (CONFIG == NULL)
1309         bb_error_msg_and_die ("non-root must specify a config file");
1310
1311   if (!(opt & 2)) {
1312 #if defined(__uClinux__)
1313         /* reexec for vfork() do continue parent */
1314         vfork_daemon_rexec (0, 0, argc, argv, "-f");
1315 #else
1316         daemon (0, 0); /* bb_xdaemon? */
1317 #endif /* uClinux */
1318   } else {
1319         setsid ();
1320   }
1321
1322   if (uid == 0) {
1323         gid_t gid = getgid ();
1324
1325         /* If run by hand, ensure groups vector gets trashed */
1326         setgroups (1, &gid);
1327   }
1328
1329   {
1330         FILE *fp;
1331
1332         if ((fp = fopen (_PATH_INETDPID, "w")) != NULL) {
1333                 fprintf (fp, "%u\n", getpid ());
1334                 (void) fclose (fp);
1335         }
1336   }
1337
1338   if (getrlimit (RLIMIT_NOFILE, &rlim_ofile) < 0) {
1339         syslog (LOG_ERR, "getrlimit: %m");
1340   } else {
1341         rlim_ofile_cur = rlim_ofile.rlim_cur;
1342         if (rlim_ofile_cur == RLIM_INFINITY)    /* ! */
1343           rlim_ofile_cur = OPEN_MAX;
1344   }
1345
1346   memset ((char *) &sa, 0, sizeof (sa));
1347   sigemptyset (&sa.sa_mask);
1348   sigaddset (&sa.sa_mask, SIGALRM);
1349   sigaddset (&sa.sa_mask, SIGCHLD);
1350   sigaddset (&sa.sa_mask, SIGHUP);
1351   sa.sa_handler = retry;
1352   sigaction (SIGALRM, &sa, NULL);
1353   /* doconfig(); */
1354   config (SIGHUP);
1355   sa.sa_handler = config;
1356   sigaction (SIGHUP, &sa, NULL);
1357   sa.sa_handler = reapchild;
1358   sigaction (SIGCHLD, &sa, NULL);
1359   sa.sa_handler = goaway;
1360   sigaction (SIGTERM, &sa, NULL);
1361   sa.sa_handler = goaway;
1362   sigaction (SIGINT, &sa, NULL);
1363   sa.sa_handler = SIG_IGN;
1364   sigaction (SIGPIPE, &sa, &sapipe);
1365   memset(&wait_mask, 0, sizeof(wait_mask));
1366   {
1367         /* space for daemons to overwrite environment for ps */
1368 #define DUMMYSIZE       100
1369         char dummy[DUMMYSIZE];
1370
1371         (void) memset (dummy, 'x', DUMMYSIZE - 1);
1372         dummy[DUMMYSIZE - 1] = '\0';
1373
1374         (void) setenv ("inetd_dummy", dummy, 1);
1375   }
1376
1377   for (;;) {
1378         int n, ctrl = -1;
1379         fd_set readable;
1380
1381         if (nsock == 0) {
1382           Block_Using_Signals(omask);
1383           while (nsock == 0)
1384                 sigsuspend (&wait_mask);
1385           sigprocmask(SIG_UNBLOCK, &omask, NULL);
1386         }
1387
1388         readable = allsock;
1389         if ((n = select (maxsock + 1, &readable, NULL, NULL, NULL)) <= 0) {
1390           if (n < 0 && errno != EINTR) {
1391                 syslog (LOG_WARNING, "select: %m");
1392                 sleep (1);
1393           }
1394           continue;
1395         }
1396         for (sep = servtab; n && sep; sep = sep->se_next)
1397           if (sep->se_fd != -1 && FD_ISSET (sep->se_fd, &readable)) {
1398                 n--;
1399                 if (!sep->se_wait && sep->se_socktype == SOCK_STREAM) {
1400                   ctrl = accept (sep->se_fd, NULL, NULL);
1401                   if (ctrl < 0) {
1402                         if (errno == EINTR)
1403                           continue;
1404                         syslog (LOG_WARNING, "accept (for %s): %m", sep->se_service);
1405                         continue;
1406                   }
1407                   if (sep->se_family == AF_INET && sep->se_socktype == SOCK_STREAM) {
1408                         struct sockaddr_in peer;
1409                         socklen_t plen = sizeof (peer);
1410
1411                         if (getpeername (ctrl, (struct sockaddr *) &peer, &plen) < 0) {
1412                           syslog (LOG_WARNING, "could not getpeername");
1413                           close (ctrl);
1414                           continue;
1415                         }
1416                         if (ntohs (peer.sin_port) == 20) {
1417                           /* XXX ftp bounce */
1418                           close (ctrl);
1419                           continue;
1420                         }
1421                   }
1422                 } else
1423                   ctrl = sep->se_fd;
1424                 Block_Using_Signals(omask);
1425                 pid = 0;
1426 #ifdef INETD_FEATURE_ENABLED
1427                 if (sep->se_bi == 0 || sep->se_bi->bi_fork)
1428 #endif
1429                 {
1430                   if (sep->se_count++ == 0)
1431                         (void) gettimeofday (&sep->se_time, NULL);
1432                   else if (toomany > 0 && sep->se_count >= sep->se_max) {
1433                         struct timeval now;
1434
1435                         (void) gettimeofday (&now, NULL);
1436                         if (now.tv_sec - sep->se_time.tv_sec > CNT_INTVL) {
1437                           sep->se_time = now;
1438                           sep->se_count = 1;
1439                         } else {
1440                           if (!sep->se_wait && sep->se_socktype == SOCK_STREAM)
1441                                 close (ctrl);
1442                           if (sep->se_family == AF_INET &&
1443                                   ntohs (sep->se_ctrladdr_in.sin_port) >= IPPORT_RESERVED) {
1444                                 /*
1445                                  * Cannot close it -- there are
1446                                  * thieves on the system.
1447                                  * Simply ignore the connection.
1448                                  */
1449                                 --sep->se_count;
1450                                 continue;
1451                           }
1452                           syslog (LOG_ERR,
1453                                           "%s/%s server failing (looping), service terminated",
1454                                           sep->se_service, sep->se_proto);
1455                           if (!sep->se_wait && sep->se_socktype == SOCK_STREAM)
1456                                 close (ctrl);
1457                           FD_CLR (sep->se_fd, &allsock);
1458                           (void) close (sep->se_fd);
1459                           sep->se_fd = -1;
1460                           sep->se_count = 0;
1461                           nsock--;
1462                           sigprocmask(SIG_UNBLOCK, &omask, NULL);
1463                           if (!timingout) {
1464                                 timingout = 1;
1465                                 alarm (RETRYTIME);
1466                           }
1467                           continue;
1468                         }
1469                   }
1470                   pid = fork ();
1471                 }
1472                 if (pid < 0) {
1473                   syslog (LOG_ERR, "fork: %m");
1474                   if (!sep->se_wait && sep->se_socktype == SOCK_STREAM)
1475                         close (ctrl);
1476                   sigprocmask(SIG_UNBLOCK, &omask, NULL);
1477                   sleep (1);
1478                   continue;
1479                 }
1480                 if (pid && sep->se_wait) {
1481                   sep->se_wait = pid;
1482                   FD_CLR (sep->se_fd, &allsock);
1483                   nsock--;
1484                 }
1485                 sigprocmask(SIG_UNBLOCK, &omask, NULL);
1486                 if (pid == 0) {
1487 #ifdef INETD_FEATURE_ENABLED
1488                   if (sep->se_bi) {
1489                         (*sep->se_bi->bi_fn) (ctrl, sep);
1490                   } else
1491 #endif
1492                         {
1493                         if ((pwd = getpwnam (sep->se_user)) == NULL) {
1494                           syslog (LOG_ERR, "getpwnam: %s: No such user", sep->se_user);
1495                           if (sep->se_socktype != SOCK_STREAM)
1496                                 recv (0, buf, sizeof (buf), 0);
1497                           _exit (1);
1498                         }
1499                         if (setsid () < 0)
1500                           syslog (LOG_ERR, "%s: setsid: %m", sep->se_service);
1501                         if (sep->se_group && (grp = getgrnam (sep->se_group)) == NULL) {
1502                           syslog (LOG_ERR, "getgrnam: %s: No such group", sep->se_group);
1503                           if (sep->se_socktype != SOCK_STREAM)
1504                                 recv (0, buf, sizeof (buf), 0);
1505                           _exit (1);
1506                         }
1507                         if (uid != 0) {
1508                           /* a user running private inetd */
1509                           if (uid != pwd->pw_uid)
1510                                 _exit (1);
1511                         } else if (pwd->pw_uid) {
1512                           if (sep->se_group) {
1513                                 pwd->pw_gid = grp->gr_gid;
1514                           }
1515                           setgid ((gid_t) pwd->pw_gid);
1516                           initgroups (pwd->pw_name, pwd->pw_gid);
1517                           setuid ((uid_t) pwd->pw_uid);
1518                         } else if (sep->se_group) {
1519                           setgid (grp->gr_gid);
1520                           setgroups (1, &grp->gr_gid);
1521                         }
1522                         dup2 (ctrl, 0);
1523                         close (ctrl);
1524                         dup2 (0, 1);
1525                         dup2 (0, 2);
1526                         if (rlim_ofile.rlim_cur != rlim_ofile_cur)
1527                           if (setrlimit (RLIMIT_NOFILE, &rlim_ofile) < 0)
1528                                 syslog (LOG_ERR, "setrlimit: %m");
1529                         closelog ();
1530                         for (tmpint = rlim_ofile_cur - 1; --tmpint > 2;)
1531                           (void) close (tmpint);
1532                         sigaction (SIGPIPE, &sapipe, NULL);
1533                         execv (sep->se_server, sep->se_argv);
1534                         if (sep->se_socktype != SOCK_STREAM)
1535                           recv (0, buf, sizeof (buf), 0);
1536                         syslog (LOG_ERR, "execv %s: %m", sep->se_server);
1537                         _exit (1);
1538                   }
1539                 }
1540                 if (!sep->se_wait && sep->se_socktype == SOCK_STREAM)
1541                   close (ctrl);
1542           }
1543   }
1544 }
1545
1546 /*
1547  * Internet services provided internally by inetd:
1548  */
1549 #define BUFSIZE 4096
1550
1551 #if defined(CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_ECHO) || \
1552     defined(CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN) || \
1553     defined(CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME)
1554 static int dg_badinput (struct sockaddr_in *dg_sin)
1555 {
1556   if (ntohs (dg_sin->sin_port) < IPPORT_RESERVED)
1557         return (1);
1558   if (dg_sin->sin_addr.s_addr == htonl (INADDR_BROADCAST))
1559         return (1);
1560   /* XXX compare against broadcast addresses in SIOCGIFCONF list? */
1561   return (0);
1562 }
1563 #endif
1564
1565 #ifdef CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_ECHO
1566 /* Echo service -- echo data back */
1567 /* ARGSUSED */
1568 static void
1569 echo_stream (int s, servtab_t *sep)
1570 {
1571   char buffer[BUFSIZE];
1572   int i;
1573
1574   inetd_setproctitle (sep->se_service, s);
1575   while ((i = read (s, buffer, sizeof (buffer))) > 0 &&
1576                  write (s, buffer, i) > 0);
1577   exit (0);
1578 }
1579
1580 /* Echo service -- echo data back */
1581 /* ARGSUSED */
1582 static void
1583 echo_dg (int s, servtab_t *sep ATTRIBUTE_UNUSED)
1584 {
1585   char buffer[BUFSIZE];
1586   int i;
1587   socklen_t size;
1588   /* struct sockaddr_storage ss; */
1589   struct sockaddr sa;
1590
1591   size = sizeof (sa);
1592   if ((i = recvfrom (s, buffer, sizeof (buffer), 0, &sa, &size)) < 0)
1593         return;
1594   if (dg_badinput ((struct sockaddr_in *) &sa))
1595         return;
1596   (void) sendto (s, buffer, i, 0, &sa, sizeof (sa));
1597 }
1598 #endif  /* CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_ECHO */
1599
1600 #ifdef CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD
1601 /* Discard service -- ignore data */
1602 /* ARGSUSED */
1603 static void
1604 discard_stream (int s, servtab_t *sep)
1605 {
1606   char buffer[BUFSIZE];
1607
1608   inetd_setproctitle (sep->se_service, s);
1609   while ((errno = 0, read (s, buffer, sizeof (buffer)) > 0) ||
1610                  errno == EINTR);
1611   exit (0);
1612 }
1613
1614 /* Discard service -- ignore data */
1615 /* ARGSUSED */
1616 static void
1617 discard_dg (int s, servtab_t *sep ATTRIBUTE_UNUSED)
1618 {
1619   char buffer[BUFSIZE];
1620
1621   (void) read (s, buffer, sizeof (buffer));
1622 }
1623 #endif /* CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD */
1624
1625
1626 #ifdef CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN
1627 #define LINESIZ 72
1628 static char ring[128];
1629 static char *endring;
1630
1631 static void
1632 initring (void)
1633 {
1634   int i;
1635
1636   endring = ring;
1637
1638   for (i = 0; i <= 128; ++i)
1639         if (isprint (i))
1640           *endring++ = i;
1641 }
1642
1643 /* Character generator */
1644 /* ARGSUSED */
1645 static void
1646 chargen_stream (int s, servtab_t *sep)
1647 {
1648   char *rs;
1649   int len;
1650   char text[LINESIZ + 2];
1651
1652   inetd_setproctitle (sep->se_service, s);
1653
1654   if (!endring) {
1655         initring ();
1656         rs = ring;
1657   }
1658
1659   text[LINESIZ] = '\r';
1660   text[LINESIZ + 1] = '\n';
1661   for (rs = ring;;) {
1662         if ((len = endring - rs) >= LINESIZ)
1663           memmove (text, rs, LINESIZ);
1664         else {
1665           memmove (text, rs, len);
1666           memmove (text + len, ring, LINESIZ - len);
1667         }
1668         if (++rs == endring)
1669           rs = ring;
1670         if (write (s, text, sizeof (text)) != sizeof (text))
1671           break;
1672   }
1673   exit (0);
1674 }
1675
1676 /* Character generator */
1677 /* ARGSUSED */
1678 static void
1679 chargen_dg (int s, servtab_t *sep ATTRIBUTE_UNUSED)
1680 {
1681   /* struct sockaddr_storage ss; */
1682   struct sockaddr sa;
1683   static char *rs;
1684   int len;
1685   char text[LINESIZ + 2];
1686   socklen_t size;
1687
1688   if (endring == 0) {
1689         initring ();
1690         rs = ring;
1691   }
1692
1693   size = sizeof (sa);
1694   if (recvfrom (s, text, sizeof (text), 0, &sa, &size) < 0)
1695         return;
1696   if (dg_badinput ((struct sockaddr_in *) &sa))
1697         return;
1698
1699   if ((len = endring - rs) >= LINESIZ)
1700         memmove (text, rs, LINESIZ);
1701   else {
1702         memmove (text, rs, len);
1703         memmove (text + len, ring, LINESIZ - len);
1704   }
1705   if (++rs == endring)
1706         rs = ring;
1707   text[LINESIZ] = '\r';
1708   text[LINESIZ + 1] = '\n';
1709   (void) sendto (s, text, sizeof (text), 0, &sa, sizeof (sa));
1710 }
1711 #endif /* CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN */
1712
1713
1714 #ifdef CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_TIME
1715 /*
1716  * Return a machine readable date and time, in the form of the
1717  * number of seconds since midnight, Jan 1, 1900.  Since gettimeofday
1718  * returns the number of seconds since midnight, Jan 1, 1970,
1719  * we must add 2208988800 seconds to this figure to make up for
1720  * some seventy years Bell Labs was asleep.
1721  */
1722
1723 static u_int machtime (void)
1724 {
1725   struct timeval tv;
1726
1727   if (gettimeofday (&tv, NULL) < 0) {
1728         fprintf (stderr, "Unable to get time of day\n");
1729         return (0L);
1730   }
1731   return (htonl ((u_int) tv.tv_sec + 2208988800UL));
1732 }
1733
1734 /* ARGSUSED */
1735 static void
1736 machtime_stream (int s, servtab_t *sep ATTRIBUTE_UNUSED)
1737 {
1738   u_int result;
1739
1740   result = machtime ();
1741   (void) write (s, (char *) &result, sizeof (result));
1742 }
1743
1744 /* ARGSUSED */
1745 static void
1746 machtime_dg (int s, servtab_t *sep ATTRIBUTE_UNUSED)
1747 {
1748   u_int result;
1749   /* struct sockaddr_storage ss; */
1750   struct sockaddr sa;
1751   struct sockaddr_in *dg_sin;
1752   socklen_t size;
1753
1754   size = sizeof (sa);
1755   if (recvfrom (s, (char *) &result, sizeof (result), 0, &sa, &size) < 0)
1756         return;
1757   /* if (dg_badinput((struct sockaddr *)&ss)) */
1758   dg_sin = (struct sockaddr_in *) &sa;
1759   if (dg_sin->sin_addr.s_addr == htonl (INADDR_BROADCAST) ||
1760           ntohs (dg_sin->sin_port) < IPPORT_RESERVED / 2)
1761         return;
1762   result = machtime ();
1763   (void) sendto (s, (char *) &result, sizeof (result), 0, &sa, sizeof (sa));
1764 }
1765 #endif /* CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_TIME */
1766
1767
1768 #ifdef CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME
1769 /* Return human-readable time of day */
1770 /* ARGSUSED */
1771 static void daytime_stream (int s, servtab_t *sep ATTRIBUTE_UNUSED)
1772 {
1773   char buffer[256];
1774   time_t t;
1775
1776   t = time (NULL);
1777
1778   (void) sprintf (buffer, "%.24s\r\n", ctime (&t));
1779   (void) write (s, buffer, strlen (buffer));
1780 }
1781
1782 /* Return human-readable time of day */
1783 /* ARGSUSED */
1784 void
1785 daytime_dg (int s, servtab_t *sep ATTRIBUTE_UNUSED)
1786 {
1787   char buffer[256];
1788   time_t t;
1789   /* struct sockaddr_storage ss; */
1790   struct sockaddr sa;
1791   socklen_t size;
1792
1793   t = time ((time_t *) 0);
1794
1795   size = sizeof (sa);
1796   if (recvfrom (s, buffer, sizeof (buffer), 0, &sa, &size) < 0)
1797         return;
1798   if (dg_badinput ((struct sockaddr_in *) &sa))
1799         return;
1800   (void) sprintf (buffer, "%.24s\r\n", ctime (&t));
1801   (void) sendto (s, buffer, strlen (buffer), 0, &sa, sizeof (sa));
1802 }
1803 #endif /* CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME */
1804 /* vi: set sw=4 ts=4: */