busybox/networking/inetd.c
<<
>>
Prefs
   1/* vi: set sw=4 ts=4: */
   2/*      $Slackware: inetd.c 1.79s 2001/02/06 13:18:00 volkerdi Exp $    */
   3/*      $OpenBSD: inetd.c,v 1.79 2001/01/30 08:30:57 deraadt Exp $      */
   4/*      $NetBSD: inetd.c,v 1.11 1996/02/22 11:14:41 mycroft Exp $       */
   5/* Busybox port by Vladimir Oleynik (C) 2001-2005 <dzo@simtreas.ru>     */
   6/* IPv6 support, many bug fixes by Denys Vlasenko (c) 2008 */
   7/*
   8 * Copyright (c) 1983,1991 The Regents of the University of California.
   9 * All rights reserved.
  10 *
  11 * Redistribution and use in source and binary forms, with or without
  12 * modification, are permitted provided that the following conditions
  13 * are met:
  14 * 1. Redistributions of source code must retain the above copyright
  15 *    notice, this list of conditions and the following disclaimer.
  16 * 2. Redistributions in binary form must reproduce the above copyright
  17 *    notice, this list of conditions and the following disclaimer in the
  18 *    documentation and/or other materials provided with the distribution.
  19 * 3. All advertising materials mentioning features or use of this software
  20 *    must display the following acknowledgement:
  21 *      This product includes software developed by the University of
  22 *      California, Berkeley and its contributors.
  23 * 4. Neither the name of the University nor the names of its contributors
  24 *    may be used to endorse or promote products derived from this software
  25 *    without specific prior written permission.
  26 *
  27 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS" AND
  28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  30 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  37 * SUCH DAMAGE.
  38 */
  39
  40/* Inetd - Internet super-server
  41 *
  42 * This program invokes configured services when a connection
  43 * from a peer is established or a datagram arrives.
  44 * Connection-oriented services are invoked each time a
  45 * connection is made, by creating a process.  This process
  46 * is passed the connection as file descriptor 0 and is
  47 * expected to do a getpeername to find out peer's host
  48 * and port.
  49 * Datagram oriented services are invoked when a datagram
  50 * arrives; a process is created and passed a pending message
  51 * on file descriptor 0. peer's address can be obtained
  52 * using recvfrom.
  53 *
  54 * Inetd uses a configuration file which is read at startup
  55 * and, possibly, at some later time in response to a hangup signal.
  56 * The configuration file is "free format" with fields given in the
  57 * order shown below.  Continuation lines for an entry must begin with
  58 * a space or tab.  All fields must be present in each entry.
  59 *
  60 *      service_name                    must be in /etc/services
  61 *      socket_type                     stream/dgram/raw/rdm/seqpacket
  62 *      protocol                        must be in /etc/protocols
  63 *                                      (usually "tcp" or "udp")
  64 *      wait/nowait[.max]               single-threaded/multi-threaded, max #
  65 *      user[.group] or user[:group]    user/group to run daemon as
  66 *      server_program                  full path name
  67 *      server_program_arguments        maximum of MAXARGS (20)
  68 *
  69 * For RPC services
  70 *      service_name/version            must be in /etc/rpc
  71 *      socket_type                     stream/dgram/raw/rdm/seqpacket
  72 *      rpc/protocol                    "rpc/tcp" etc
  73 *      wait/nowait[.max]               single-threaded/multi-threaded
  74 *      user[.group] or user[:group]    user to run daemon as
  75 *      server_program                  full path name
  76 *      server_program_arguments        maximum of MAXARGS (20)
  77 *
  78 * For non-RPC services, the "service name" can be of the form
  79 * hostaddress:servicename, in which case the hostaddress is used
  80 * as the host portion of the address to listen on.  If hostaddress
  81 * consists of a single '*' character, INADDR_ANY is used.
  82 *
  83 * A line can also consist of just
  84 *      hostaddress:
  85 * where hostaddress is as in the preceding paragraph.  Such a line must
  86 * have no further fields; the specified hostaddress is remembered and
  87 * used for all further lines that have no hostaddress specified,
  88 * until the next such line (or EOF).  (This is why * is provided to
  89 * allow explicit specification of INADDR_ANY.)  A line
  90 *      *:
  91 * is implicitly in effect at the beginning of the file.
  92 *
  93 * The hostaddress specifier may (and often will) contain dots;
  94 * the service name must not.
  95 *
  96 * For RPC services, host-address specifiers are accepted and will
  97 * work to some extent; however, because of limitations in the
  98 * portmapper interface, it will not work to try to give more than
  99 * one line for any given RPC service, even if the host-address
 100 * specifiers are different.
 101 *
 102 * Comment lines are indicated by a '#' in column 1.
 103 */
 104
 105/* inetd rules for passing file descriptors to children
 106 * (http://www.freebsd.org/cgi/man.cgi?query=inetd):
 107 *
 108 * The wait/nowait entry specifies whether the server that is invoked by
 109 * inetd will take over the socket associated with the service access point,
 110 * and thus whether inetd should wait for the server to exit before listen-
 111 * ing for new service requests.  Datagram servers must use "wait", as
 112 * they are always invoked with the original datagram socket bound to the
 113 * specified service address.  These servers must read at least one datagram
 114 * from the socket before exiting.  If a datagram server connects to its
 115 * peer, freeing the socket so inetd can receive further messages on the
 116 * socket, it is said to be a "multi-threaded" server; it should read one
 117 * datagram from the socket and create a new socket connected to the peer.
 118 * It should fork, and the parent should then exit to allow inetd to check
 119 * for new service requests to spawn new servers.  Datagram servers which
 120 * process all incoming datagrams on a socket and eventually time out are
 121 * said to be "single-threaded".  The comsat(8), biff(1) and talkd(8)
 122 * utilities are both examples of the latter type of datagram server.  The
 123 * tftpd(8) utility is an example of a multi-threaded datagram server.
 124 *
 125 * Servers using stream sockets generally are multi-threaded and use the
 126 * "nowait" entry. Connection requests for these services are accepted by
 127 * inetd, and the server is given only the newly-accepted socket connected
 128 * to a client of the service.  Most stream-based services operate in this
 129 * manner.  Stream-based servers that use "wait" are started with the lis-
 130 * tening service socket, and must accept at least one connection request
 131 * before exiting.  Such a server would normally accept and process incoming
 132 * connection requests until a timeout.
 133 */
 134
 135/* Despite of above doc saying that dgram services must use "wait",
 136 * "udp nowait" servers are implemented in busyboxed inetd.
 137 * IPv6 addresses are also implemented. However, they may look ugly -
 138 * ":::service..." means "address '::' (IPv6 wildcard addr)":"service"...
 139 * You have to put "tcp6"/"udp6" in protocol field to select IPv6.
 140 */
 141
 142/* Here's the scoop concerning the user[:group] feature:
 143 * 1) group is not specified:
 144 *      a) user = root: NO setuid() or setgid() is done
 145 *      b) other:       initgroups(name, primary group)
 146 *                      setgid(primary group as found in passwd)
 147 *                      setuid()
 148 * 2) group is specified:
 149 *      a) user = root: setgid(specified group)
 150 *                      NO initgroups()
 151 *                      NO setuid()
 152 *      b) other:       initgroups(name, specified group)
 153 *                      setgid(specified group)
 154 *                      setuid()
 155 */
 156
 157//usage:#define inetd_trivial_usage
 158//usage:       "[-fe] [-q N] [-R N] [CONFFILE]"
 159//usage:#define inetd_full_usage "\n\n"
 160//usage:       "Listen for network connections and launch programs\n"
 161//usage:     "\n        -f      Run in foreground"
 162//usage:     "\n        -e      Log to stderr"
 163//usage:     "\n        -q N    Socket listen queue (default: 128)"
 164//usage:     "\n        -R N    Pause services after N connects/min"
 165//usage:     "\n                (default: 0 - disabled)"
 166
 167#include <syslog.h>
 168#include <sys/un.h>
 169
 170#include "libbb.h"
 171
 172#if ENABLE_FEATURE_INETD_RPC
 173# if defined(__UCLIBC__) && ! defined(__UCLIBC_HAS_RPC__)
 174#  error "You need to build uClibc with UCLIBC_HAS_RPC for NFS support"
 175# endif
 176# include <rpc/rpc.h>
 177# include <rpc/pmap_clnt.h>
 178#endif
 179
 180#if !BB_MMU
 181/* stream version of chargen is forking but not execing,
 182 * can't do that (easily) on NOMMU */
 183#undef  ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN
 184#define ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN 0
 185#endif
 186
 187#define _PATH_INETDPID  "/var/run/inetd.pid"
 188
 189#define CNT_INTERVAL    60      /* servers in CNT_INTERVAL sec. */
 190#define RETRYTIME       60      /* retry after bind or server fail */
 191
 192// TODO: explain, or get rid of setrlimit games
 193
 194#ifndef RLIMIT_NOFILE
 195#define RLIMIT_NOFILE   RLIMIT_OFILE
 196#endif
 197
 198#ifndef OPEN_MAX
 199#define OPEN_MAX        64
 200#endif
 201
 202/* Reserve some descriptors, 3 stdio + at least: 1 log, 1 conf. file */
 203#define FD_MARGIN       8
 204
 205#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD \
 206 || ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_ECHO    \
 207 || ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN \
 208 || ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_TIME    \
 209 || ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME
 210# define INETD_BUILTINS_ENABLED
 211#endif
 212
 213typedef struct servtab_t {
 214        /* The most frequently referenced one: */
 215        int se_fd;                            /* open descriptor */
 216        /* NB: 'biggest fields last' saves on code size (~250 bytes) */
 217        /* [addr:]service socktype proto wait user[:group] prog [args] */
 218        char *se_local_hostname;              /* addr to listen on */
 219        char *se_service;                     /* "80" or "www" or "mount/2[-3]" */
 220        /* socktype is in se_socktype */      /* "stream" "dgram" "raw" "rdm" "seqpacket" */
 221        char *se_proto;                       /* "unix" or "[rpc/]tcp[6]" */
 222#if ENABLE_FEATURE_INETD_RPC
 223        int se_rpcprog;                       /* rpc program number */
 224        int se_rpcver_lo;                     /* rpc program lowest version */
 225        int se_rpcver_hi;                     /* rpc program highest version */
 226#define is_rpc_service(sep)       ((sep)->se_rpcver_lo != 0)
 227#else
 228#define is_rpc_service(sep)       0
 229#endif
 230        pid_t se_wait;                        /* 0:"nowait", 1:"wait", >1:"wait" */
 231                                              /* and waiting for this pid */
 232        socktype_t se_socktype;               /* SOCK_STREAM/DGRAM/RDM/... */
 233        family_t se_family;                   /* AF_UNIX/INET[6] */
 234        /* se_proto_no is used by RPC code only... hmm */
 235        smallint se_proto_no;                 /* IPPROTO_TCP/UDP, n/a for AF_UNIX */
 236        smallint se_checked;                  /* looked at during merge */
 237        unsigned se_max;                      /* allowed instances per minute */
 238        unsigned se_count;                    /* number started since se_time */
 239        unsigned se_time;                     /* when we started counting */
 240        char *se_user;                        /* user name to run as */
 241        char *se_group;                       /* group name to run as, can be NULL */
 242#ifdef INETD_BUILTINS_ENABLED
 243        const struct builtin *se_builtin;     /* if built-in, description */
 244#endif
 245        struct servtab_t *se_next;
 246        len_and_sockaddr *se_lsa;
 247        char *se_program;                     /* server program */
 248#define MAXARGV 20
 249        char *se_argv[MAXARGV + 1];           /* program arguments */
 250} servtab_t;
 251
 252#ifdef INETD_BUILTINS_ENABLED
 253/* Echo received data */
 254#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_ECHO
 255static void FAST_FUNC echo_stream(int, servtab_t *);
 256static void FAST_FUNC echo_dg(int, servtab_t *);
 257#endif
 258/* Internet /dev/null */
 259#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD
 260static void FAST_FUNC discard_stream(int, servtab_t *);
 261static void FAST_FUNC discard_dg(int, servtab_t *);
 262#endif
 263/* Return 32 bit time since 1900 */
 264#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_TIME
 265static void FAST_FUNC machtime_stream(int, servtab_t *);
 266static void FAST_FUNC machtime_dg(int, servtab_t *);
 267#endif
 268/* Return human-readable time */
 269#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME
 270static void FAST_FUNC daytime_stream(int, servtab_t *);
 271static void FAST_FUNC daytime_dg(int, servtab_t *);
 272#endif
 273/* Familiar character generator */
 274#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN
 275static void FAST_FUNC chargen_stream(int, servtab_t *);
 276static void FAST_FUNC chargen_dg(int, servtab_t *);
 277#endif
 278
 279struct builtin {
 280        /* NB: not necessarily NUL terminated */
 281        char bi_service7[7];      /* internally provided service name */
 282        uint8_t bi_fork;          /* 1 if stream fn should run in child */
 283        void (*bi_stream_fn)(int, servtab_t *) FAST_FUNC;
 284        void (*bi_dgram_fn)(int, servtab_t *) FAST_FUNC;
 285};
 286
 287static const struct builtin builtins[] = {
 288#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_ECHO
 289        { "echo", 1, echo_stream, echo_dg },
 290#endif
 291#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD
 292        { "discard", 1, discard_stream, discard_dg },
 293#endif
 294#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN
 295        { "chargen", 1, chargen_stream, chargen_dg },
 296#endif
 297#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_TIME
 298        { "time", 0, machtime_stream, machtime_dg },
 299#endif
 300#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME
 301        { "daytime", 0, daytime_stream, daytime_dg },
 302#endif
 303};
 304#endif /* INETD_BUILTINS_ENABLED */
 305
 306struct globals {
 307        rlim_t rlim_ofile_cur;
 308        struct rlimit rlim_ofile;
 309        servtab_t *serv_list;
 310        int global_queuelen;
 311        int maxsock;         /* max fd# in allsock, -1: unknown */
 312        /* whenever maxsock grows, prev_maxsock is set to new maxsock,
 313         * but if maxsock is set to -1, prev_maxsock is not changed */
 314        int prev_maxsock;
 315        unsigned max_concurrency;
 316        smallint alarm_armed;
 317        uid_t real_uid; /* user ID who ran us */
 318        const char *config_filename;
 319        parser_t *parser;
 320        char *default_local_hostname;
 321#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN
 322        char *end_ring;
 323        char *ring_pos;
 324        char ring[128];
 325#endif
 326        fd_set allsock;
 327        /* Used in next_line(), and as scratch read buffer */
 328        char line[256];          /* _at least_ 256, see LINE_SIZE */
 329} FIX_ALIASING;
 330#define G (*(struct globals*)&bb_common_bufsiz1)
 331enum { LINE_SIZE = COMMON_BUFSIZE - offsetof(struct globals, line) };
 332struct BUG_G_too_big {
 333        char BUG_G_too_big[sizeof(G) <= COMMON_BUFSIZE ? 1 : -1];
 334};
 335#define rlim_ofile_cur  (G.rlim_ofile_cur )
 336#define rlim_ofile      (G.rlim_ofile     )
 337#define serv_list       (G.serv_list      )
 338#define global_queuelen (G.global_queuelen)
 339#define maxsock         (G.maxsock        )
 340#define prev_maxsock    (G.prev_maxsock   )
 341#define max_concurrency (G.max_concurrency)
 342#define alarm_armed     (G.alarm_armed    )
 343#define real_uid        (G.real_uid       )
 344#define config_filename (G.config_filename)
 345#define parser          (G.parser         )
 346#define default_local_hostname (G.default_local_hostname)
 347#define first_ps_byte   (G.first_ps_byte  )
 348#define last_ps_byte    (G.last_ps_byte   )
 349#define end_ring        (G.end_ring       )
 350#define ring_pos        (G.ring_pos       )
 351#define ring            (G.ring           )
 352#define allsock         (G.allsock        )
 353#define line            (G.line           )
 354#define INIT_G() do { \
 355        rlim_ofile_cur = OPEN_MAX; \
 356        global_queuelen = 128; \
 357        config_filename = "/etc/inetd.conf"; \
 358} while (0)
 359
 360static void maybe_close(int fd)
 361{
 362        if (fd >= 0)
 363                close(fd);
 364}
 365
 366// TODO: move to libbb?
 367static len_and_sockaddr *xzalloc_lsa(int family)
 368{
 369        len_and_sockaddr *lsa;
 370        int sz;
 371
 372        sz = sizeof(struct sockaddr_in);
 373        if (family == AF_UNIX)
 374                sz = sizeof(struct sockaddr_un);
 375#if ENABLE_FEATURE_IPV6
 376        if (family == AF_INET6)
 377                sz = sizeof(struct sockaddr_in6);
 378#endif
 379        lsa = xzalloc(LSA_LEN_SIZE + sz);
 380        lsa->len = sz;
 381        lsa->u.sa.sa_family = family;
 382        return lsa;
 383}
 384
 385static void rearm_alarm(void)
 386{
 387        if (!alarm_armed) {
 388                alarm_armed = 1;
 389                alarm(RETRYTIME);
 390        }
 391}
 392
 393static void block_CHLD_HUP_ALRM(sigset_t *m)
 394{
 395        sigemptyset(m);
 396        sigaddset(m, SIGCHLD);
 397        sigaddset(m, SIGHUP);
 398        sigaddset(m, SIGALRM);
 399        sigprocmask(SIG_BLOCK, m, m); /* old sigmask is stored in m */
 400}
 401
 402static void restore_sigmask(sigset_t *m)
 403{
 404        sigprocmask(SIG_SETMASK, m, NULL);
 405}
 406
 407#if ENABLE_FEATURE_INETD_RPC
 408static void register_rpc(servtab_t *sep)
 409{
 410        int n;
 411        struct sockaddr_in ir_sin;
 412        socklen_t size;
 413
 414        size = sizeof(ir_sin);
 415        if (getsockname(sep->se_fd, (struct sockaddr *) &ir_sin, &size) < 0) {
 416                bb_perror_msg("getsockname");
 417                return;
 418        }
 419
 420        for (n = sep->se_rpcver_lo; n <= sep->se_rpcver_hi; n++) {
 421                pmap_unset(sep->se_rpcprog, n);
 422                if (!pmap_set(sep->se_rpcprog, n, sep->se_proto_no, ntohs(ir_sin.sin_port)))
 423                        bb_perror_msg("%s %s: pmap_set(%u,%u,%u,%u)",
 424                                sep->se_service, sep->se_proto,
 425                                sep->se_rpcprog, n, sep->se_proto_no, ntohs(ir_sin.sin_port));
 426        }
 427}
 428
 429static void unregister_rpc(servtab_t *sep)
 430{
 431        int n;
 432
 433        for (n = sep->se_rpcver_lo; n <= sep->se_rpcver_hi; n++) {
 434                if (!pmap_unset(sep->se_rpcprog, n))
 435                        bb_perror_msg("pmap_unset(%u,%u)", sep->se_rpcprog, n);
 436        }
 437}
 438#endif /* FEATURE_INETD_RPC */
 439
 440static void bump_nofile(void)
 441{
 442        enum { FD_CHUNK = 32 };
 443        struct rlimit rl;
 444
 445        /* Never fails under Linux (except if you pass it bad arguments) */
 446        getrlimit(RLIMIT_NOFILE, &rl);
 447        rl.rlim_cur = MIN(rl.rlim_max, rl.rlim_cur + FD_CHUNK);
 448        rl.rlim_cur = MIN(FD_SETSIZE, rl.rlim_cur + FD_CHUNK);
 449        if (rl.rlim_cur <= rlim_ofile_cur) {
 450                bb_error_msg("can't extend file limit, max = %d",
 451                                                (int) rl.rlim_cur);
 452                return;
 453        }
 454
 455        if (setrlimit(RLIMIT_NOFILE, &rl) < 0) {
 456                bb_perror_msg("setrlimit");
 457                return;
 458        }
 459
 460        rlim_ofile_cur = rl.rlim_cur;
 461}
 462
 463static void remove_fd_from_set(int fd)
 464{
 465        if (fd >= 0) {
 466                FD_CLR(fd, &allsock);
 467                maxsock = -1;
 468        }
 469}
 470
 471static void add_fd_to_set(int fd)
 472{
 473        if (fd >= 0) {
 474                FD_SET(fd, &allsock);
 475                if (maxsock >= 0 && fd > maxsock) {
 476                        prev_maxsock = maxsock = fd;
 477                        if ((rlim_t)fd > rlim_ofile_cur - FD_MARGIN)
 478                                bump_nofile();
 479                }
 480        }
 481}
 482
 483static void recalculate_maxsock(void)
 484{
 485        int fd = 0;
 486
 487        /* We may have no services, in this case maxsock should still be >= 0
 488         * (code elsewhere is not happy with maxsock == -1) */
 489        maxsock = 0;
 490        while (fd <= prev_maxsock) {
 491                if (FD_ISSET(fd, &allsock))
 492                        maxsock = fd;
 493                fd++;
 494        }
 495        prev_maxsock = maxsock;
 496        if ((rlim_t)maxsock > rlim_ofile_cur - FD_MARGIN)
 497                bump_nofile();
 498}
 499
 500static void prepare_socket_fd(servtab_t *sep)
 501{
 502        int r, fd;
 503
 504        fd = socket(sep->se_family, sep->se_socktype, 0);
 505        if (fd < 0) {
 506                bb_perror_msg("socket");
 507                return;
 508        }
 509        setsockopt_reuseaddr(fd);
 510
 511#if ENABLE_FEATURE_INETD_RPC
 512        if (is_rpc_service(sep)) {
 513                struct passwd *pwd;
 514
 515                /* zero out the port for all RPC services; let bind()
 516                 * find one. */
 517                set_nport(&sep->se_lsa->u.sa, 0);
 518
 519                /* for RPC services, attempt to use a reserved port
 520                 * if they are going to be running as root. */
 521                if (real_uid == 0 && sep->se_family == AF_INET
 522                 && (pwd = getpwnam(sep->se_user)) != NULL
 523                 && pwd->pw_uid == 0
 524                ) {
 525                        r = bindresvport(fd, &sep->se_lsa->u.sin);
 526                } else {
 527                        r = bind(fd, &sep->se_lsa->u.sa, sep->se_lsa->len);
 528                }
 529                if (r == 0) {
 530                        int saveerrno = errno;
 531                        /* update lsa with port# */
 532                        getsockname(fd, &sep->se_lsa->u.sa, &sep->se_lsa->len);
 533                        errno = saveerrno;
 534                }
 535        } else
 536#endif
 537        {
 538                if (sep->se_family == AF_UNIX) {
 539                        struct sockaddr_un *sun;
 540                        sun = (struct sockaddr_un*)&(sep->se_lsa->u.sa);
 541                        unlink(sun->sun_path);
 542                }
 543                r = bind(fd, &sep->se_lsa->u.sa, sep->se_lsa->len);
 544        }
 545        if (r < 0) {
 546                bb_perror_msg("%s/%s: bind",
 547                                sep->se_service, sep->se_proto);
 548                close(fd);
 549                rearm_alarm();
 550                return;
 551        }
 552        if (sep->se_socktype == SOCK_STREAM)
 553                listen(fd, global_queuelen);
 554
 555        add_fd_to_set(fd);
 556        sep->se_fd = fd;
 557}
 558
 559static int reopen_config_file(void)
 560{
 561        free(default_local_hostname);
 562        default_local_hostname = xstrdup("*");
 563        if (parser != NULL)
 564                config_close(parser);
 565        parser = config_open(config_filename);
 566        return (parser != NULL);
 567}
 568
 569static void close_config_file(void)
 570{
 571        if (parser) {
 572                config_close(parser);
 573                parser = NULL;
 574        }
 575}
 576
 577static void free_servtab_strings(servtab_t *cp)
 578{
 579        int i;
 580
 581        free(cp->se_local_hostname);
 582        free(cp->se_service);
 583        free(cp->se_proto);
 584        free(cp->se_user);
 585        free(cp->se_group);
 586        free(cp->se_lsa); /* not a string in fact */
 587        free(cp->se_program);
 588        for (i = 0; i < MAXARGV; i++)
 589                free(cp->se_argv[i]);
 590}
 591
 592static servtab_t *new_servtab(void)
 593{
 594        servtab_t *newtab = xzalloc(sizeof(servtab_t));
 595        newtab->se_fd = -1; /* paranoia */
 596        return newtab;
 597}
 598
 599static servtab_t *dup_servtab(servtab_t *sep)
 600{
 601        servtab_t *newtab;
 602        int argc;
 603
 604        newtab = new_servtab();
 605        *newtab = *sep; /* struct copy */
 606        /* deep-copying strings */
 607        newtab->se_service = xstrdup(newtab->se_service);
 608        newtab->se_proto = xstrdup(newtab->se_proto);
 609        newtab->se_user = xstrdup(newtab->se_user);
 610        newtab->se_group = xstrdup(newtab->se_group);
 611        newtab->se_program = xstrdup(newtab->se_program);
 612        for (argc = 0; argc <= MAXARGV; argc++)
 613                newtab->se_argv[argc] = xstrdup(newtab->se_argv[argc]);
 614        /* NB: se_fd, se_hostaddr and se_next are always
 615         * overwrittend by callers, so we don't bother resetting them
 616         * to NULL/0/-1 etc */
 617
 618        return newtab;
 619}
 620
 621/* gcc generates much more code if this is inlined */
 622static servtab_t *parse_one_line(void)
 623{
 624        int argc;
 625        char *token[6+MAXARGV];
 626        char *p, *arg;
 627        char *hostdelim;
 628        servtab_t *sep;
 629        servtab_t *nsep;
 630 new:
 631        sep = new_servtab();
 632 more:
 633        argc = config_read(parser, token, 6+MAXARGV, 1, "# \t", PARSE_NORMAL);
 634        if (!argc) {
 635                free(sep);
 636                return NULL;
 637        }
 638
 639        /* [host:]service socktype proto wait user[:group] prog [args] */
 640        /* Check for "host:...." line */
 641        arg = token[0];
 642        hostdelim = strrchr(arg, ':');
 643        if (hostdelim) {
 644                *hostdelim = '\0';
 645                sep->se_local_hostname = xstrdup(arg);
 646                arg = hostdelim + 1;
 647                if (*arg == '\0' && argc == 1) {
 648                        /* Line has just "host:", change the
 649                         * default host for the following lines. */
 650                        free(default_local_hostname);
 651                        default_local_hostname = sep->se_local_hostname;
 652                        goto more;
 653                }
 654        } else
 655                sep->se_local_hostname = xstrdup(default_local_hostname);
 656
 657        /* service socktype proto wait user[:group] prog [args] */
 658        sep->se_service = xstrdup(arg);
 659
 660        /* socktype proto wait user[:group] prog [args] */
 661        if (argc < 6) {
 662 parse_err:
 663                bb_error_msg("parse error on line %u, line is ignored",
 664                                parser->lineno);
 665                free_servtab_strings(sep);
 666                /* Just "goto more" can make sep to carry over e.g.
 667                 * "rpc"-ness (by having se_rpcver_lo != 0).
 668                 * We will be more paranoid: */
 669                free(sep);
 670                goto new;
 671        }
 672
 673        {
 674                static const int8_t SOCK_xxx[] ALIGN1 = {
 675                        -1,
 676                        SOCK_STREAM, SOCK_DGRAM, SOCK_RDM,
 677                        SOCK_SEQPACKET, SOCK_RAW
 678                };
 679                sep->se_socktype = SOCK_xxx[1 + index_in_strings(
 680                        "stream""\0" "dgram""\0" "rdm""\0"
 681                        "seqpacket""\0" "raw""\0"
 682                        , token[1])];
 683        }
 684
 685        /* {unix,[rpc/]{tcp,udp}[6]} wait user[:group] prog [args] */
 686        sep->se_proto = arg = xstrdup(token[2]);
 687        if (strcmp(arg, "unix") == 0) {
 688                sep->se_family = AF_UNIX;
 689        } else {
 690                char *six;
 691                sep->se_family = AF_INET;
 692                six = last_char_is(arg, '6');
 693                if (six) {
 694#if ENABLE_FEATURE_IPV6
 695                        *six = '\0';
 696                        sep->se_family = AF_INET6;
 697#else
 698                        bb_error_msg("%s: no support for IPv6", sep->se_proto);
 699                        goto parse_err;
 700#endif
 701                }
 702                if (strncmp(arg, "rpc/", 4) == 0) {
 703#if ENABLE_FEATURE_INETD_RPC
 704                        unsigned n;
 705                        arg += 4;
 706                        p = strchr(sep->se_service, '/');
 707                        if (p == NULL) {
 708                                bb_error_msg("no rpc version: '%s'", sep->se_service);
 709                                goto parse_err;
 710                        }
 711                        *p++ = '\0';
 712                        n = bb_strtou(p, &p, 10);
 713                        if (n > INT_MAX) {
 714 bad_ver_spec:
 715                                bb_error_msg("bad rpc version");
 716                                goto parse_err;
 717                        }
 718                        sep->se_rpcver_lo = sep->se_rpcver_hi = n;
 719                        if (*p == '-') {
 720                                p++;
 721                                n = bb_strtou(p, &p, 10);
 722                                if (n > INT_MAX || (int)n < sep->se_rpcver_lo)
 723                                        goto bad_ver_spec;
 724                                sep->se_rpcver_hi = n;
 725                        }
 726                        if (*p != '\0')
 727                                goto bad_ver_spec;
 728#else
 729                        bb_error_msg("no support for rpc services");
 730                        goto parse_err;
 731#endif
 732                }
 733                /* we don't really need getprotobyname()! */
 734                if (strcmp(arg, "tcp") == 0)
 735                        sep->se_proto_no = IPPROTO_TCP; /* = 6 */
 736                if (strcmp(arg, "udp") == 0)
 737                        sep->se_proto_no = IPPROTO_UDP; /* = 17 */
 738                if (six)
 739                        *six = '6';
 740                if (!sep->se_proto_no) /* not tcp/udp?? */
 741                        goto parse_err;
 742        }
 743
 744        /* [no]wait[.max] user[:group] prog [args] */
 745        arg = token[3];
 746        sep->se_max = max_concurrency;
 747        p = strchr(arg, '.');
 748        if (p) {
 749                *p++ = '\0';
 750                sep->se_max = bb_strtou(p, NULL, 10);
 751                if (errno)
 752                        goto parse_err;
 753        }
 754        sep->se_wait = (arg[0] != 'n' || arg[1] != 'o');
 755        if (!sep->se_wait) /* "no" seen */
 756                arg += 2;
 757        if (strcmp(arg, "wait") != 0)
 758                goto parse_err;
 759
 760        /* user[:group] prog [args] */
 761        sep->se_user = xstrdup(token[4]);
 762        arg = strchr(sep->se_user, '.');
 763        if (arg == NULL)
 764                arg = strchr(sep->se_user, ':');
 765        if (arg) {
 766                *arg++ = '\0';
 767                sep->se_group = xstrdup(arg);
 768        }
 769
 770        /* prog [args] */
 771        sep->se_program = xstrdup(token[5]);
 772#ifdef INETD_BUILTINS_ENABLED
 773        if (strcmp(sep->se_program, "internal") == 0
 774         && strlen(sep->se_service) <= 7
 775         && (sep->se_socktype == SOCK_STREAM
 776             || sep->se_socktype == SOCK_DGRAM)
 777        ) {
 778                unsigned i;
 779                for (i = 0; i < ARRAY_SIZE(builtins); i++)
 780                        if (strncmp(builtins[i].bi_service7, sep->se_service, 7) == 0)
 781                                goto found_bi;
 782                bb_error_msg("unknown internal service %s", sep->se_service);
 783                goto parse_err;
 784 found_bi:
 785                sep->se_builtin = &builtins[i];
 786                /* stream builtins must be "nowait", dgram must be "wait" */
 787                if (sep->se_wait != (sep->se_socktype == SOCK_DGRAM))
 788                        goto parse_err;
 789        }
 790#endif
 791        argc = 0;
 792        while ((arg = token[6+argc]) != NULL && argc < MAXARGV)
 793                sep->se_argv[argc++] = xstrdup(arg);
 794        /* Some inetd.conf files have no argv's, not even argv[0].
 795         * Fix them up.
 796         * (Technically, programs can be execed with argv[0] = NULL,
 797         * but many programs do not like that at all) */
 798        if (argc == 0)
 799                sep->se_argv[0] = xstrdup(sep->se_program);
 800
 801        /* catch mixups. "<service> stream udp ..." == wtf */
 802        if (sep->se_socktype == SOCK_STREAM) {
 803                if (sep->se_proto_no == IPPROTO_UDP)
 804                        goto parse_err;
 805        }
 806        if (sep->se_socktype == SOCK_DGRAM) {
 807                if (sep->se_proto_no == IPPROTO_TCP)
 808                        goto parse_err;
 809        }
 810
 811//      bb_info_msg(
 812//              "ENTRY[%s][%s][%s][%d][%d][%d][%d][%d][%s][%s][%s]",
 813//              sep->se_local_hostname, sep->se_service, sep->se_proto, sep->se_wait, sep->se_proto_no,
 814//              sep->se_max, sep->se_count, sep->se_time, sep->se_user, sep->se_group, sep->se_program);
 815
 816        /* check if the hostname specifier is a comma separated list
 817         * of hostnames. we'll make new entries for each address. */
 818        while ((hostdelim = strrchr(sep->se_local_hostname, ',')) != NULL) {
 819                nsep = dup_servtab(sep);
 820                /* NUL terminate the hostname field of the existing entry,
 821                 * and make a dup for the new entry. */
 822                *hostdelim++ = '\0';
 823                nsep->se_local_hostname = xstrdup(hostdelim);
 824                nsep->se_next = sep->se_next;
 825                sep->se_next = nsep;
 826        }
 827
 828        /* was doing it here: */
 829        /* DNS resolution, create copies for each IP address */
 830        /* IPv6-ization destroyed it :( */
 831
 832        return sep;
 833}
 834
 835static servtab_t *insert_in_servlist(servtab_t *cp)
 836{
 837        servtab_t *sep;
 838        sigset_t omask;
 839
 840        sep = new_servtab();
 841        *sep = *cp; /* struct copy */
 842        sep->se_fd = -1;
 843#if ENABLE_FEATURE_INETD_RPC
 844        sep->se_rpcprog = -1;
 845#endif
 846        block_CHLD_HUP_ALRM(&omask);
 847        sep->se_next = serv_list;
 848        serv_list = sep;
 849        restore_sigmask(&omask);
 850        return sep;
 851}
 852
 853static int same_serv_addr_proto(servtab_t *old, servtab_t *new)
 854{
 855        if (strcmp(old->se_local_hostname, new->se_local_hostname) != 0)
 856                return 0;
 857        if (strcmp(old->se_service, new->se_service) != 0)
 858                return 0;
 859        if (strcmp(old->se_proto, new->se_proto) != 0)
 860                return 0;
 861        return 1;
 862}
 863
 864static void reread_config_file(int sig UNUSED_PARAM)
 865{
 866        servtab_t *sep, *cp, **sepp;
 867        len_and_sockaddr *lsa;
 868        sigset_t omask;
 869        unsigned n;
 870        uint16_t port;
 871        int save_errno = errno;
 872
 873        if (!reopen_config_file())
 874                goto ret;
 875        for (sep = serv_list; sep; sep = sep->se_next)
 876                sep->se_checked = 0;
 877
 878        goto first_line;
 879        while (1) {
 880                if (cp == NULL) {
 881 first_line:
 882                        cp = parse_one_line();
 883                        if (cp == NULL)
 884                                break;
 885                }
 886                for (sep = serv_list; sep; sep = sep->se_next)
 887                        if (same_serv_addr_proto(sep, cp))
 888                                goto equal_servtab;
 889                /* not an "equal" servtab */
 890                sep = insert_in_servlist(cp);
 891                goto after_check;
 892 equal_servtab:
 893                {
 894                        int i;
 895
 896                        block_CHLD_HUP_ALRM(&omask);
 897#if ENABLE_FEATURE_INETD_RPC
 898                        if (is_rpc_service(sep))
 899                                unregister_rpc(sep);
 900                        sep->se_rpcver_lo = cp->se_rpcver_lo;
 901                        sep->se_rpcver_hi = cp->se_rpcver_hi;
 902#endif
 903                        if (cp->se_wait == 0) {
 904                                /* New config says "nowait". If old one
 905                                 * was "wait", we currently may be waiting
 906                                 * for a child (and not accepting connects).
 907                                 * Stop waiting, start listening again.
 908                                 * (if it's not true, this op is harmless) */
 909                                add_fd_to_set(sep->se_fd);
 910                        }
 911                        sep->se_wait = cp->se_wait;
 912                        sep->se_max = cp->se_max;
 913                        /* string fields need more love - we don't want to leak them */
 914#define SWAP(type, a, b) do { type c = (type)a; a = (type)b; b = (type)c; } while (0)
 915                        SWAP(char*, sep->se_user, cp->se_user);
 916                        SWAP(char*, sep->se_group, cp->se_group);
 917                        SWAP(char*, sep->se_program, cp->se_program);
 918                        for (i = 0; i < MAXARGV; i++)
 919                                SWAP(char*, sep->se_argv[i], cp->se_argv[i]);
 920#undef SWAP
 921                        restore_sigmask(&omask);
 922                        free_servtab_strings(cp);
 923                }
 924 after_check:
 925                /* cp->string_fields are consumed by insert_in_servlist()
 926                 * or freed at this point, cp itself is not yet freed. */
 927                sep->se_checked = 1;
 928
 929                /* create new len_and_sockaddr */
 930                switch (sep->se_family) {
 931                        struct sockaddr_un *sun;
 932                case AF_UNIX:
 933                        lsa = xzalloc_lsa(AF_UNIX);
 934                        sun = (struct sockaddr_un*)&lsa->u.sa;
 935                        safe_strncpy(sun->sun_path, sep->se_service, sizeof(sun->sun_path));
 936                        break;
 937
 938                default: /* case AF_INET, case AF_INET6 */
 939                        n = bb_strtou(sep->se_service, NULL, 10);
 940#if ENABLE_FEATURE_INETD_RPC
 941                        if (is_rpc_service(sep)) {
 942                                sep->se_rpcprog = n;
 943                                if (errno) { /* se_service is not numeric */
 944                                        struct rpcent *rp = getrpcbyname(sep->se_service);
 945                                        if (rp == NULL) {
 946                                                bb_error_msg("%s: unknown rpc service", sep->se_service);
 947                                                goto next_cp;
 948                                        }
 949                                        sep->se_rpcprog = rp->r_number;
 950                                }
 951                                if (sep->se_fd == -1)
 952                                        prepare_socket_fd(sep);
 953                                if (sep->se_fd != -1)
 954                                        register_rpc(sep);
 955                                goto next_cp;
 956                        }
 957#endif
 958                        /* what port to listen on? */
 959                        port = htons(n);
 960                        if (errno || n > 0xffff) { /* se_service is not numeric */
 961                                char protoname[4];
 962                                struct servent *sp;
 963                                /* can result only in "tcp" or "udp": */
 964                                safe_strncpy(protoname, sep->se_proto, 4);
 965                                sp = getservbyname(sep->se_service, protoname);
 966                                if (sp == NULL) {
 967                                        bb_error_msg("%s/%s: unknown service",
 968                                                        sep->se_service, sep->se_proto);
 969                                        goto next_cp;
 970                                }
 971                                port = sp->s_port;
 972                        }
 973                        if (LONE_CHAR(sep->se_local_hostname, '*')) {
 974                                lsa = xzalloc_lsa(sep->se_family);
 975                                set_nport(&lsa->u.sa, port);
 976                        } else {
 977                                lsa = host_and_af2sockaddr(sep->se_local_hostname,
 978                                                ntohs(port), sep->se_family);
 979                                if (!lsa) {
 980                                        bb_error_msg("%s/%s: unknown host '%s'",
 981                                                sep->se_service, sep->se_proto,
 982                                                sep->se_local_hostname);
 983                                        goto next_cp;
 984                                }
 985                        }
 986                        break;
 987                } /* end of "switch (sep->se_family)" */
 988
 989                /* did lsa change? Then close/open */
 990                if (sep->se_lsa == NULL
 991                 || lsa->len != sep->se_lsa->len
 992                 || memcmp(&lsa->u.sa, &sep->se_lsa->u.sa, lsa->len) != 0
 993                ) {
 994                        remove_fd_from_set(sep->se_fd);
 995                        maybe_close(sep->se_fd);
 996                        free(sep->se_lsa);
 997                        sep->se_lsa = lsa;
 998                        sep->se_fd = -1;
 999                } else {
1000                        free(lsa);
1001                }
1002                if (sep->se_fd == -1)
1003                        prepare_socket_fd(sep);
1004 next_cp:
1005                sep = cp->se_next;
1006                free(cp);
1007                cp = sep;
1008        } /* end of "while (1) parse lines" */
1009        close_config_file();
1010
1011        /* Purge anything not looked at above - these are stale entries,
1012         * new config file doesnt have them. */
1013        block_CHLD_HUP_ALRM(&omask);
1014        sepp = &serv_list;
1015        while ((sep = *sepp)) {
1016                if (sep->se_checked) {
1017                        sepp = &sep->se_next;
1018                        continue;
1019                }
1020                *sepp = sep->se_next;
1021                remove_fd_from_set(sep->se_fd);
1022                maybe_close(sep->se_fd);
1023#if ENABLE_FEATURE_INETD_RPC
1024                if (is_rpc_service(sep))
1025                        unregister_rpc(sep);
1026#endif
1027                if (sep->se_family == AF_UNIX)
1028                        unlink(sep->se_service);
1029                free_servtab_strings(sep);
1030                free(sep);
1031        }
1032        restore_sigmask(&omask);
1033 ret:
1034        errno = save_errno;
1035}
1036
1037static void reap_child(int sig UNUSED_PARAM)
1038{
1039        pid_t pid;
1040        int status;
1041        servtab_t *sep;
1042        int save_errno = errno;
1043
1044        for (;;) {
1045                pid = wait_any_nohang(&status);
1046                if (pid <= 0)
1047                        break;
1048                for (sep = serv_list; sep; sep = sep->se_next) {
1049                        if (sep->se_wait != pid)
1050                                continue;
1051                        /* One of our "wait" services */
1052                        if (WIFEXITED(status) && WEXITSTATUS(status))
1053                                bb_error_msg("%s: exit status %u",
1054                                                sep->se_program, WEXITSTATUS(status));
1055                        else if (WIFSIGNALED(status))
1056                                bb_error_msg("%s: exit signal %u",
1057                                                sep->se_program, WTERMSIG(status));
1058                        sep->se_wait = 1;
1059                        add_fd_to_set(sep->se_fd);
1060                        break;
1061                }
1062        }
1063        errno = save_errno;
1064}
1065
1066static void retry_network_setup(int sig UNUSED_PARAM)
1067{
1068        int save_errno = errno;
1069        servtab_t *sep;
1070
1071        alarm_armed = 0;
1072        for (sep = serv_list; sep; sep = sep->se_next) {
1073                if (sep->se_fd == -1) {
1074                        prepare_socket_fd(sep);
1075#if ENABLE_FEATURE_INETD_RPC
1076                        if (sep->se_fd != -1 && is_rpc_service(sep))
1077                                register_rpc(sep);
1078#endif
1079                }
1080        }
1081        errno = save_errno;
1082}
1083
1084static void clean_up_and_exit(int sig UNUSED_PARAM)
1085{
1086        servtab_t *sep;
1087
1088        /* XXX signal race walking sep list */
1089        for (sep = serv_list; sep; sep = sep->se_next) {
1090                if (sep->se_fd == -1)
1091                        continue;
1092
1093                switch (sep->se_family) {
1094                case AF_UNIX:
1095                        unlink(sep->se_service);
1096                        break;
1097                default: /* case AF_INET, AF_INET6 */
1098#if ENABLE_FEATURE_INETD_RPC
1099                        if (sep->se_wait == 1 && is_rpc_service(sep))
1100                                unregister_rpc(sep);   /* XXX signal race */
1101#endif
1102                        break;
1103                }
1104                if (ENABLE_FEATURE_CLEAN_UP)
1105                        close(sep->se_fd);
1106        }
1107        remove_pidfile(_PATH_INETDPID);
1108        exit(EXIT_SUCCESS);
1109}
1110
1111int inetd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
1112int inetd_main(int argc UNUSED_PARAM, char **argv)
1113{
1114        struct sigaction sa, saved_pipe_handler;
1115        servtab_t *sep, *sep2;
1116        struct passwd *pwd;
1117        struct group *grp = grp; /* for compiler */
1118        int opt;
1119        pid_t pid;
1120        sigset_t omask;
1121
1122        INIT_G();
1123
1124        real_uid = getuid();
1125        if (real_uid != 0) /* run by non-root user */
1126                config_filename = NULL;
1127
1128        opt_complementary = "R+:q+"; /* -q N, -R N */
1129        opt = getopt32(argv, "R:feq:", &max_concurrency, &global_queuelen);
1130        argv += optind;
1131        //argc -= optind;
1132        if (argv[0])
1133                config_filename = argv[0];
1134        if (config_filename == NULL)
1135                bb_error_msg_and_die("non-root must specify config file");
1136        if (!(opt & 2))
1137                bb_daemonize_or_rexec(0, argv - optind);
1138        else
1139                bb_sanitize_stdio();
1140        if (!(opt & 4)) {
1141                /* LOG_NDELAY: connect to syslog daemon NOW.
1142                 * Otherwise, we may open syslog socket
1143                 * in vforked child, making opened fds and syslog()
1144                 * internal state inconsistent.
1145                 * This was observed to leak file descriptors. */
1146                openlog(applet_name, LOG_PID | LOG_NDELAY, LOG_DAEMON);
1147                logmode = LOGMODE_SYSLOG;
1148        }
1149
1150        if (real_uid == 0) {
1151                /* run by root, ensure groups vector gets trashed */
1152                gid_t gid = getgid();
1153                setgroups(1, &gid);
1154        }
1155
1156        write_pidfile(_PATH_INETDPID);
1157
1158        /* never fails under Linux (except if you pass it bad arguments) */
1159        getrlimit(RLIMIT_NOFILE, &rlim_ofile);
1160        rlim_ofile_cur = rlim_ofile.rlim_cur;
1161        if (rlim_ofile_cur == RLIM_INFINITY)    /* ! */
1162                rlim_ofile_cur = OPEN_MAX;
1163
1164        memset(&sa, 0, sizeof(sa));
1165        /*sigemptyset(&sa.sa_mask); - memset did it */
1166        sigaddset(&sa.sa_mask, SIGALRM);
1167        sigaddset(&sa.sa_mask, SIGCHLD);
1168        sigaddset(&sa.sa_mask, SIGHUP);
1169//FIXME: explain why no SA_RESTART
1170//FIXME: retry_network_setup is unsafe to run in signal handler (many reasons)!
1171        sa.sa_handler = retry_network_setup;
1172        sigaction_set(SIGALRM, &sa);
1173//FIXME: reread_config_file is unsafe to run in signal handler(many reasons)!
1174        sa.sa_handler = reread_config_file;
1175        sigaction_set(SIGHUP, &sa);
1176//FIXME: reap_child is unsafe to run in signal handler (uses stdio)!
1177        sa.sa_handler = reap_child;
1178        sigaction_set(SIGCHLD, &sa);
1179//FIXME: clean_up_and_exit is unsafe to run in signal handler (uses stdio)!
1180        sa.sa_handler = clean_up_and_exit;
1181        sigaction_set(SIGTERM, &sa);
1182        sa.sa_handler = clean_up_and_exit;
1183        sigaction_set(SIGINT, &sa);
1184        sa.sa_handler = SIG_IGN;
1185        sigaction(SIGPIPE, &sa, &saved_pipe_handler);
1186
1187        reread_config_file(SIGHUP); /* load config from file */
1188
1189        for (;;) {
1190                int ready_fd_cnt;
1191                int ctrl, accepted_fd, new_udp_fd;
1192                fd_set readable;
1193
1194                if (maxsock < 0)
1195                        recalculate_maxsock();
1196
1197                readable = allsock; /* struct copy */
1198                /* if there are no fds to wait on, we will block
1199                 * until signal wakes us up (maxsock == 0, but readable
1200                 * never contains fds 0 and 1...) */
1201                ready_fd_cnt = select(maxsock + 1, &readable, NULL, NULL, NULL);
1202                if (ready_fd_cnt < 0) {
1203                        if (errno != EINTR) {
1204                                bb_perror_msg("select");
1205                                sleep(1);
1206                        }
1207                        continue;
1208                }
1209
1210                for (sep = serv_list; ready_fd_cnt && sep; sep = sep->se_next) {
1211                        if (sep->se_fd == -1 || !FD_ISSET(sep->se_fd, &readable))
1212                                continue;
1213
1214                        ready_fd_cnt--;
1215                        ctrl = sep->se_fd;
1216                        accepted_fd = -1;
1217                        new_udp_fd = -1;
1218                        if (!sep->se_wait) {
1219                                if (sep->se_socktype == SOCK_STREAM) {
1220                                        ctrl = accepted_fd = accept(sep->se_fd, NULL, NULL);
1221                                        if (ctrl < 0) {
1222                                                if (errno != EINTR)
1223                                                        bb_perror_msg("accept (for %s)", sep->se_service);
1224                                                continue;
1225                                        }
1226                                }
1227                                /* "nowait" udp */
1228                                if (sep->se_socktype == SOCK_DGRAM
1229                                 && sep->se_family != AF_UNIX
1230                                ) {
1231/* How udp "nowait" works:
1232 * child peeks at (received and buffered by kernel) UDP packet,
1233 * performs connect() on the socket so that it is linked only
1234 * to this peer. But this also affects parent, because descriptors
1235 * are shared after fork() a-la dup(). When parent performs
1236 * select(), it will see this descriptor connected to the peer (!)
1237 * and still readable, will act on it and mess things up
1238 * (can create many copies of same child, etc).
1239 * Parent must create and use new socket instead. */
1240                                        new_udp_fd = socket(sep->se_family, SOCK_DGRAM, 0);
1241                                        if (new_udp_fd < 0) { /* error: eat packet, forget about it */
1242 udp_err:
1243                                                recv(sep->se_fd, line, LINE_SIZE, MSG_DONTWAIT);
1244                                                continue;
1245                                        }
1246                                        setsockopt_reuseaddr(new_udp_fd);
1247                                        /* TODO: better do bind after vfork in parent,
1248                                         * so that we don't have two wildcard bound sockets
1249                                         * even for a brief moment? */
1250                                        if (bind(new_udp_fd, &sep->se_lsa->u.sa, sep->se_lsa->len) < 0) {
1251                                                close(new_udp_fd);
1252                                                goto udp_err;
1253                                        }
1254                                }
1255                        }
1256
1257                        block_CHLD_HUP_ALRM(&omask);
1258                        pid = 0;
1259#ifdef INETD_BUILTINS_ENABLED
1260                        /* do we need to fork? */
1261                        if (sep->se_builtin == NULL
1262                         || (sep->se_socktype == SOCK_STREAM
1263                             && sep->se_builtin->bi_fork))
1264#endif
1265                        {
1266                                if (sep->se_max != 0) {
1267                                        if (++sep->se_count == 1)
1268                                                sep->se_time = monotonic_sec();
1269                                        else if (sep->se_count >= sep->se_max) {
1270                                                unsigned now = monotonic_sec();
1271                                                /* did we accumulate se_max connects too quickly? */
1272                                                if (now - sep->se_time <= CNT_INTERVAL) {
1273                                                        bb_error_msg("%s/%s: too many connections, pausing",
1274                                                                        sep->se_service, sep->se_proto);
1275                                                        remove_fd_from_set(sep->se_fd);
1276                                                        close(sep->se_fd);
1277                                                        sep->se_fd = -1;
1278                                                        sep->se_count = 0;
1279                                                        rearm_alarm(); /* will revive it in RETRYTIME sec */
1280                                                        restore_sigmask(&omask);
1281                                                        maybe_close(accepted_fd);
1282                                                        continue; /* -> check next fd in fd set */
1283                                                }
1284                                                sep->se_count = 0;
1285                                        }
1286                                }
1287                                /* on NOMMU, streamed chargen
1288                                 * builtin wouldn't work, but it is
1289                                 * not allowed on NOMMU (ifdefed out) */
1290#ifdef INETD_BUILTINS_ENABLED
1291                                if (BB_MMU && sep->se_builtin)
1292                                        pid = fork();
1293                                else
1294#endif
1295                                        pid = vfork();
1296
1297                                if (pid < 0) { /* fork error */
1298                                        bb_perror_msg("vfork"+1);
1299                                        sleep(1);
1300                                        restore_sigmask(&omask);
1301                                        maybe_close(accepted_fd);
1302                                        continue; /* -> check next fd in fd set */
1303                                }
1304                                if (pid == 0)
1305                                        pid--; /* -1: "we did fork and we are child" */
1306                        }
1307                        /* if pid == 0 here, we never forked */
1308
1309                        if (pid > 0) { /* parent */
1310                                if (sep->se_wait) {
1311                                        /* tcp wait: we passed listening socket to child,
1312                                         * will wait for child to terminate */
1313                                        sep->se_wait = pid;
1314                                        remove_fd_from_set(sep->se_fd);
1315                                }
1316                                if (new_udp_fd >= 0) {
1317                                        /* udp nowait: child connected the socket,
1318                                         * we created and will use new, unconnected one */
1319                                        xmove_fd(new_udp_fd, sep->se_fd);
1320                                }
1321                                restore_sigmask(&omask);
1322                                maybe_close(accepted_fd);
1323                                continue; /* -> check next fd in fd set */
1324                        }
1325
1326                        /* we are either child or didn't vfork at all */
1327#ifdef INETD_BUILTINS_ENABLED
1328                        if (sep->se_builtin) {
1329                                if (pid) { /* "pid" is -1: we did vfork */
1330                                        close(sep->se_fd); /* listening socket */
1331                                        logmode = LOGMODE_NONE; /* make xwrite etc silent */
1332                                }
1333                                restore_sigmask(&omask);
1334                                if (sep->se_socktype == SOCK_STREAM)
1335                                        sep->se_builtin->bi_stream_fn(ctrl, sep);
1336                                else
1337                                        sep->se_builtin->bi_dgram_fn(ctrl, sep);
1338                                if (pid) /* we did vfork */
1339                                        _exit(EXIT_FAILURE);
1340                                maybe_close(accepted_fd);
1341                                continue; /* -> check next fd in fd set */
1342                        }
1343#endif
1344                        /* child */
1345                        setsid();
1346                        /* "nowait" udp */
1347                        if (new_udp_fd >= 0) {
1348                                len_and_sockaddr *lsa = xzalloc_lsa(sep->se_family);
1349                                /* peek at the packet and remember peer addr */
1350                                int r = recvfrom(ctrl, NULL, 0, MSG_PEEK|MSG_DONTWAIT,
1351                                        &lsa->u.sa, &lsa->len);
1352                                if (r < 0)
1353                                        goto do_exit1;
1354                                /* make this socket "connected" to peer addr:
1355                                 * only packets from this peer will be recv'ed,
1356                                 * and bare write()/send() will work on it */
1357                                connect(ctrl, &lsa->u.sa, lsa->len);
1358                                free(lsa);
1359                        }
1360                        /* prepare env and exec program */
1361                        pwd = getpwnam(sep->se_user);
1362                        if (pwd == NULL) {
1363                                bb_error_msg("%s: no such %s", sep->se_user, "user");
1364                                goto do_exit1;
1365                        }
1366                        if (sep->se_group && (grp = getgrnam(sep->se_group)) == NULL) {
1367                                bb_error_msg("%s: no such %s", sep->se_group, "group");
1368                                goto do_exit1;
1369                        }
1370                        if (real_uid != 0 && real_uid != pwd->pw_uid) {
1371                                /* a user running private inetd */
1372                                bb_error_msg("non-root must run services as himself");
1373                                goto do_exit1;
1374                        }
1375                        if (pwd->pw_uid) {
1376                                if (sep->se_group)
1377                                        pwd->pw_gid = grp->gr_gid;
1378                                /* initgroups, setgid, setuid: */
1379                                change_identity(pwd);
1380                        } else if (sep->se_group) {
1381                                xsetgid(grp->gr_gid);
1382                                setgroups(1, &grp->gr_gid);
1383                        }
1384                        if (rlim_ofile.rlim_cur != rlim_ofile_cur)
1385                                if (setrlimit(RLIMIT_NOFILE, &rlim_ofile) < 0)
1386                                        bb_perror_msg("setrlimit");
1387
1388                        /* closelog(); - WRONG. we are after vfork,
1389                         * this may confuse syslog() internal state.
1390                         * Let's hope libc sets syslog fd to CLOEXEC...
1391                         */
1392                        xmove_fd(ctrl, STDIN_FILENO);
1393                        xdup2(STDIN_FILENO, STDOUT_FILENO);
1394                        /* manpages of inetd I managed to find either say
1395                         * that stderr is also redirected to the network,
1396                         * or do not talk about redirection at all (!) */
1397                        if (!sep->se_wait) /* only for usual "tcp nowait" */
1398                                xdup2(STDIN_FILENO, STDERR_FILENO);
1399                        /* NB: among others, this loop closes listening sockets
1400                         * for nowait stream children */
1401                        for (sep2 = serv_list; sep2; sep2 = sep2->se_next)
1402                                if (sep2->se_fd != ctrl)
1403                                        maybe_close(sep2->se_fd);
1404                        sigaction_set(SIGPIPE, &saved_pipe_handler);
1405                        restore_sigmask(&omask);
1406                        BB_EXECVP(sep->se_program, sep->se_argv);
1407                        bb_perror_msg("can't execute '%s'", sep->se_program);
1408 do_exit1:
1409                        /* eat packet in udp case */
1410                        if (sep->se_socktype != SOCK_STREAM)
1411                                recv(0, line, LINE_SIZE, MSG_DONTWAIT);
1412                        _exit(EXIT_FAILURE);
1413                } /* for (sep = servtab...) */
1414        } /* for (;;) */
1415}
1416
1417#if !BB_MMU
1418static const char *const cat_args[] = { "cat", NULL };
1419#endif
1420
1421/*
1422 * Internet services provided internally by inetd:
1423 */
1424#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_ECHO
1425/* Echo service -- echo data back. */
1426/* ARGSUSED */
1427static void FAST_FUNC echo_stream(int s, servtab_t *sep UNUSED_PARAM)
1428{
1429#if BB_MMU
1430        while (1) {
1431                ssize_t sz = safe_read(s, line, LINE_SIZE);
1432                if (sz <= 0)
1433                        break;
1434                xwrite(s, line, sz);
1435        }
1436#else
1437        /* We are after vfork here! */
1438        /* move network socket to stdin/stdout */
1439        xmove_fd(s, STDIN_FILENO);
1440        xdup2(STDIN_FILENO, STDOUT_FILENO);
1441        /* no error messages please... */
1442        close(STDERR_FILENO);
1443        xopen(bb_dev_null, O_WRONLY);
1444        BB_EXECVP("cat", (char**)cat_args);
1445        /* on failure we return to main, which does exit(EXIT_FAILURE) */
1446#endif
1447}
1448static void FAST_FUNC echo_dg(int s, servtab_t *sep)
1449{
1450        enum { BUFSIZE = 12*1024 }; /* for jumbo sized packets! :) */
1451        char *buf = xmalloc(BUFSIZE); /* too big for stack */
1452        int sz;
1453        len_and_sockaddr *lsa = alloca(LSA_LEN_SIZE + sep->se_lsa->len);
1454
1455        lsa->len = sep->se_lsa->len;
1456        /* dgram builtins are non-forking - DONT BLOCK! */
1457        sz = recvfrom(s, buf, BUFSIZE, MSG_DONTWAIT, &lsa->u.sa, &lsa->len);
1458        if (sz > 0)
1459                sendto(s, buf, sz, 0, &lsa->u.sa, lsa->len);
1460        free(buf);
1461}
1462#endif  /* FEATURE_INETD_SUPPORT_BUILTIN_ECHO */
1463
1464
1465#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD
1466/* Discard service -- ignore data. */
1467/* ARGSUSED */
1468static void FAST_FUNC discard_stream(int s, servtab_t *sep UNUSED_PARAM)
1469{
1470#if BB_MMU
1471        while (safe_read(s, line, LINE_SIZE) > 0)
1472                continue;
1473#else
1474        /* We are after vfork here! */
1475        /* move network socket to stdin */
1476        xmove_fd(s, STDIN_FILENO);
1477        /* discard output */
1478        close(STDOUT_FILENO);
1479        xopen(bb_dev_null, O_WRONLY);
1480        /* no error messages please... */
1481        xdup2(STDOUT_FILENO, STDERR_FILENO);
1482        BB_EXECVP("cat", (char**)cat_args);
1483        /* on failure we return to main, which does exit(EXIT_FAILURE) */
1484#endif
1485}
1486/* ARGSUSED */
1487static void FAST_FUNC discard_dg(int s, servtab_t *sep UNUSED_PARAM)
1488{
1489        /* dgram builtins are non-forking - DONT BLOCK! */
1490        recv(s, line, LINE_SIZE, MSG_DONTWAIT);
1491}
1492#endif /* FEATURE_INETD_SUPPORT_BUILTIN_DISCARD */
1493
1494
1495#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN
1496#define LINESIZ 72
1497static void init_ring(void)
1498{
1499        int i;
1500
1501        end_ring = ring;
1502        for (i = ' '; i < 127; i++)
1503                *end_ring++ = i;
1504}
1505/* Character generator. MMU arches only. */
1506/* ARGSUSED */
1507static void FAST_FUNC chargen_stream(int s, servtab_t *sep UNUSED_PARAM)
1508{
1509        char *rs;
1510        int len;
1511        char text[LINESIZ + 2];
1512
1513        if (!end_ring) {
1514                init_ring();
1515                rs = ring;
1516        }
1517
1518        text[LINESIZ] = '\r';
1519        text[LINESIZ + 1] = '\n';
1520        rs = ring;
1521        for (;;) {
1522                len = end_ring - rs;
1523                if (len >= LINESIZ)
1524                        memmove(text, rs, LINESIZ);
1525                else {
1526                        memmove(text, rs, len);
1527                        memmove(text + len, ring, LINESIZ - len);
1528                }
1529                if (++rs == end_ring)
1530                        rs = ring;
1531                xwrite(s, text, sizeof(text));
1532        }
1533}
1534/* ARGSUSED */
1535static void FAST_FUNC chargen_dg(int s, servtab_t *sep)
1536{
1537        int len;
1538        char text[LINESIZ + 2];
1539        len_and_sockaddr *lsa = alloca(LSA_LEN_SIZE + sep->se_lsa->len);
1540
1541        /* Eat UDP packet which started it all */
1542        /* dgram builtins are non-forking - DONT BLOCK! */
1543        lsa->len = sep->se_lsa->len;
1544        if (recvfrom(s, text, sizeof(text), MSG_DONTWAIT, &lsa->u.sa, &lsa->len) < 0)
1545                return;
1546
1547        if (!end_ring) {
1548                init_ring();
1549                ring_pos = ring;
1550        }
1551
1552        len = end_ring - ring_pos;
1553        if (len >= LINESIZ)
1554                memmove(text, ring_pos, LINESIZ);
1555        else {
1556                memmove(text, ring_pos, len);
1557                memmove(text + len, ring, LINESIZ - len);
1558        }
1559        if (++ring_pos == end_ring)
1560                ring_pos = ring;
1561        text[LINESIZ] = '\r';
1562        text[LINESIZ + 1] = '\n';
1563        sendto(s, text, sizeof(text), 0, &lsa->u.sa, lsa->len);
1564}
1565#endif /* FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN */
1566
1567
1568#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_TIME
1569/*
1570 * Return a machine readable date and time, in the form of the
1571 * number of seconds since midnight, Jan 1, 1900.  Since gettimeofday
1572 * returns the number of seconds since midnight, Jan 1, 1970,
1573 * we must add 2208988800 seconds to this figure to make up for
1574 * some seventy years Bell Labs was asleep.
1575 */
1576static uint32_t machtime(void)
1577{
1578        struct timeval tv;
1579
1580        gettimeofday(&tv, NULL);
1581        return htonl((uint32_t)(tv.tv_sec + 2208988800));
1582}
1583/* ARGSUSED */
1584static void FAST_FUNC machtime_stream(int s, servtab_t *sep UNUSED_PARAM)
1585{
1586        uint32_t result;
1587
1588        result = machtime();
1589        full_write(s, &result, sizeof(result));
1590}
1591static void FAST_FUNC machtime_dg(int s, servtab_t *sep)
1592{
1593        uint32_t result;
1594        len_and_sockaddr *lsa = alloca(LSA_LEN_SIZE + sep->se_lsa->len);
1595
1596        lsa->len = sep->se_lsa->len;
1597        if (recvfrom(s, line, LINE_SIZE, MSG_DONTWAIT, &lsa->u.sa, &lsa->len) < 0)
1598                return;
1599
1600        result = machtime();
1601        sendto(s, &result, sizeof(result), 0, &lsa->u.sa, lsa->len);
1602}
1603#endif /* FEATURE_INETD_SUPPORT_BUILTIN_TIME */
1604
1605
1606#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME
1607/* Return human-readable time of day */
1608/* ARGSUSED */
1609static void FAST_FUNC daytime_stream(int s, servtab_t *sep UNUSED_PARAM)
1610{
1611        time_t t;
1612
1613        t = time(NULL);
1614        fdprintf(s, "%.24s\r\n", ctime(&t));
1615}
1616static void FAST_FUNC daytime_dg(int s, servtab_t *sep)
1617{
1618        time_t t;
1619        len_and_sockaddr *lsa = alloca(LSA_LEN_SIZE + sep->se_lsa->len);
1620
1621        lsa->len = sep->se_lsa->len;
1622        if (recvfrom(s, line, LINE_SIZE, MSG_DONTWAIT, &lsa->u.sa, &lsa->len) < 0)
1623                return;
1624
1625        t = time(NULL);
1626        sprintf(line, "%.24s\r\n", ctime(&t));
1627        sendto(s, line, strlen(line), 0, &lsa->u.sa, lsa->len);
1628}
1629#endif /* FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME */
1630