Ignore:
Timestamp:
Nov 4, 2007, 3:16:40 AM (16 years ago)
Author:
Bruno Cornec
Message:

Update to busybox 1.7.2

File:
1 edited

Legend:

Unmodified
Added
Removed
  • branches/2.2.5/mindi-busybox/networking/inetd.c

    r821 r1765  
     1/* vi: set sw=4 ts=4: */
    12/*      $Slackware: inetd.c 1.79s 2001/02/06 13:18:00 volkerdi Exp $    */
    23/*      $OpenBSD: inetd.c,v 1.79 2001/01/30 08:30:57 deraadt Exp $      */
     
    2324 *    without specific prior written permission.
    2425 *
    25  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS" AND
    2627 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    2728 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     
    3637 */
    3738
    38 /*
    39  * Inetd - Internet super-server
     39/* Inetd - Internet super-server
    4040 *
    4141 * This program invokes all internet services as needed.
     
    5050 * on file descriptor 0.  Datagram servers may either connect
    5151 * to their peer, freeing up the original socket for inetd
    52  * to receive further messages on, or ``take over the socket'',
     52 * to receive further messages on, or "take over the socket",
    5353 * 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''.
     54 * out.  The first type of server is said to be "multi-threaded";
     55 * the second type of server "single-threaded".
    5656 *
    5757 * Inetd uses a configuration file which is read at startup
    5858 * and, possibly, at some later time in response to a hangup signal.
    59  * The configuration file is ``free format'' with fields given in the
     59 * The configuration file is "free format" with fields given in the
    6060 * order shown below.  Continuation lines for an entry must begin with
    6161 * a space or tab.  All fields must be present in each entry.
     
    105105 */
    106106
    107 /*
    108  * Here's the scoop concerning the user[.:]group feature:
     107/* inetd rules for passing file descriptors to children
     108 * (http://www.freebsd.org/cgi/man.cgi?query=inetd):
     109 *
     110 * The wait/nowait entry specifies whether the server that is invoked by
     111 * inetd will take over the socket associated with the service access point,
     112 * and thus whether inetd should wait for the server to exit before listen-
     113 * ing for new service requests.  Datagram servers must use "wait", as
     114 * they are always invoked with the original datagram socket bound to the
     115 * specified service address.  These servers must read at least one datagram
     116 * from the socket before exiting.  If a datagram server connects to its
     117 * peer, freeing the socket so inetd can receive further messages on the
     118 * socket, it is said to be a "multi-threaded" server; it should read one
     119 * datagram from the socket and create a new socket connected to the peer.
     120 * It should fork, and the parent should then exit to allow inetd to check
     121 * for new service requests to spawn new servers.  Datagram servers which
     122 * process all incoming datagrams on a socket and eventually time out are
     123 * said to be "single-threaded".  The comsat(8), (biff(1)) and talkd(8)
     124 * utilities are both examples of the latter type of datagram server.  The
     125 * tftpd(8) utility is an example of a multi-threaded datagram server.
     126 *
     127 * Servers using stream sockets generally are multi-threaded and use the
     128 * "nowait" entry. Connection requests for these services are accepted by
     129 * inetd, and the server is given only the newly-accepted socket connected
     130 * to a client of the service.  Most stream-based services operate in this
     131 * manner.  Stream-based servers that use "wait" are started with the lis-
     132 * tening service socket, and must accept at least one connection request
     133 * before exiting.  Such a server would normally accept and process incoming
     134 * connection requests until a timeout.
     135 */
     136
     137/* Here's the scoop concerning the user[.:]group feature:
    109138 *
    110139 * 1) set-group-option off.
     
    125154 *                      initgroups(name, specified group)
    126155 *                      setuid()
    127  *
    128156 */
    129157
    130 #include <sys/param.h>
    131 #include <sys/stat.h>
    132 #include <sys/ioctl.h>
    133 #include <sys/socket.h>
     158#include "libbb.h"
     159#include <syslog.h>
    134160#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
     161
     162//#define ENABLE_FEATURE_INETD_RPC 1
     163//#define ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_ECHO 1
     164//#define ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD 1
     165//#define ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_TIME 1
     166//#define ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME 1
     167//#define ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN 1
     168//#define ENABLE_FEATURE_IPV6 1
     169
     170#if ENABLE_FEATURE_INETD_RPC
    165171#include <rpc/rpc.h>
    166172#include <rpc/pmap_clnt.h>
    167173#endif
    168174
    169 #define _PATH_INETDCONF "/etc/inetd.conf"
     175extern char **environ;
     176
     177
    170178#define _PATH_INETDPID  "/var/run/inetd.pid"
    171 
    172 
    173 #define TOOMANY         0               /* don't start more than TOOMANY */
    174179
    175180#define CNT_INTVL       60              /* servers in CNT_INTVL sec. */
     
    185190
    186191/* Reserve some descriptors, 3 stdio + at least: 1 log, 1 conf. file */
    187 #define FD_MARGIN       (8)
     192#define FD_MARGIN       8
    188193static rlim_t rlim_ofile_cur = OPEN_MAX;
    189194static struct rlimit rlim_ofile;
     
    191196
    192197/* 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#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_ECHO || \
     199    ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD || \
     200    ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_TIME || \
     201    ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME || \
     202    ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN
    198203# define INETD_FEATURE_ENABLED
    199204#endif
    200205
    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
     206#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_ECHO || \
     207    ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD || \
     208    ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN
    204209# define INETD_SETPROCTITLE
    205210#endif
    206211
    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 */
     212typedef struct servtab {
     213    char *se_hostaddr;                    /* host address to listen on */
     214    char *se_service;                     /* name of service */
     215    int se_socktype;                      /* type of socket to use */
     216    int se_family;                        /* address family */
     217    char *se_proto;                       /* protocol used */
     218#if ENABLE_FEATURE_INETD_RPC
     219    int se_rpcprog;                       /* rpc program number */
     220    int se_rpcversl;                      /* rpc program lowest version */
     221    int se_rpcversh;                      /* rpc program highest version */
    218222#define isrpcservice(sep)       ((sep)->se_rpcversl != 0)
    219223#else
    220224#define isrpcservice(sep)       0
    221225#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    pid_t se_wait;                        /* single threaded server */
     227    short se_checked;                     /* looked at during merge */
     228    char *se_user;                        /* user name to run as */
     229    char *se_group;                       /* group name to run as */
    226230#ifdef INETD_FEATURE_ENABLED
    227   const struct builtin *se_bi;                 /* if built-in, description */
    228 #endif
    229   char *se_server;                      /* server program */
     231    const struct builtin *se_bi;          /* if built-in, description */
     232#endif
     233    char *se_server;                      /* server program */
    230234#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 */
     235    char *se_argv[MAXARGV + 1];           /* program arguments */
     236    int se_fd;                            /* open descriptor */
     237    union {
     238        struct sockaddr se_un_ctrladdr;
     239        struct sockaddr_in se_un_ctrladdr_in;
     240#if ENABLE_FEATURE_IPV6
     241        struct sockaddr_in6 se_un_ctrladdr_in6;
     242#endif
     243        struct sockaddr_un se_un_ctrladdr_un;
     244    } se_un;                              /* bound address */
    242245#define se_ctrladdr     se_un.se_un_ctrladdr
    243246#define se_ctrladdr_in  se_un.se_un_ctrladdr_in
    244247#define se_ctrladdr_in6 se_un.se_un_ctrladdr_in6
    245248#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;
     249    int se_ctrladdr_size;
     250    int se_max;                           /* max # of instances of this service */
     251    int se_count;                         /* number started since se_time */
     252    struct timeval se_time;               /* start of se_count */
     253    struct servtab *se_next;
    251254} servtab_t;
    252255
     
    254257
    255258#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 *);
     259struct builtin {
     260    const char *bi_service;               /* internally provided service name */
     261    int bi_socktype;                      /* type of socket supported */
     262    short bi_fork;                        /* 1 if should fork before call */
     263    short bi_wait;                        /* 1 if should wait for child */
     264    void (*bi_fn) (int, servtab_t *);
    263265};
    264266
     267        /* Echo received data */
     268#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_ECHO
     269static void echo_stream(int, servtab_t *);
     270static void echo_dg(int, servtab_t *);
     271#endif
     272        /* Internet /dev/null */
     273#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD
     274static void discard_stream(int, servtab_t *);
     275static void discard_dg(int, servtab_t *);
     276#endif
     277        /* Return 32 bit time since 1900 */
     278#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_TIME
     279static void machtime_stream(int, servtab_t *);
     280static void machtime_dg(int, servtab_t *);
     281#endif
     282        /* Return human-readable time */
     283#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME
     284static void daytime_stream(int, servtab_t *);
     285static void daytime_dg(int, servtab_t *);
     286#endif
     287        /* Familiar character generator */
     288#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN
     289static void chargen_stream(int, servtab_t *);
     290static void chargen_dg(int, servtab_t *);
     291#endif
     292
     293static const struct builtin builtins[] = {
     294#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_ECHO
    265295    /* 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
     296    {"echo", SOCK_STREAM, 1, 0, echo_stream,},
     297    {"echo", SOCK_DGRAM, 0, 0, echo_dg,},
     298#endif
     299#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD
    270300    /* 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
     301    {"discard", SOCK_STREAM, 1, 0, discard_stream,},
     302    {"discard", SOCK_DGRAM, 0, 0, discard_dg,},
     303#endif
     304#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_TIME
    275305    /* 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
     306    {"time", SOCK_STREAM, 0, 0, machtime_stream,},
     307    {"time", SOCK_DGRAM, 0, 0, machtime_dg,},
     308#endif
     309#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME
    280310    /* 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
     311    {"daytime", SOCK_STREAM, 0, 0, daytime_stream,},
     312    {"daytime", SOCK_DGRAM, 0, 0, daytime_dg,},
     313#endif
     314#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN
    285315    /* 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}
     316    {"chargen", SOCK_STREAM, 1, 0, chargen_stream,},
     317    {"chargen", SOCK_DGRAM, 0, 0, chargen_dg,},
     318#endif
     319    {NULL, 0, 0, 0, NULL}
    318320};
    319321#endif /* INETD_FEATURE_ENABLED */
     
    322324static int nsock, maxsock;
    323325static fd_set allsock;
    324 static int toomany = TOOMANY;
     326static int toomany;
    325327static int timingout;
    326328static struct servent *sp;
    327329static uid_t uid;
    328330
    329 static char *CONFIG = _PATH_INETDCONF;
     331static const char *config_filename = "/etc/inetd.conf";
    330332
    331333static FILE *fconfig;
    332 static char line[1024];
    333334static char *defhost;
    334335
    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)
     336/* xstrdup(NULL) returns NULL, but this one
     337 * will return newly-allocated "" if called with NULL arg
     338 * TODO: audit whether this makes any real difference
     339 */
     340static char *xxstrdup(char *cp)
     341{
     342    return xstrdup(cp ? cp : "");
     343}
     344
     345static int setconfig(void)
     346{
     347    free(defhost);
     348    defhost = xstrdup("*");
     349    if (fconfig != NULL) {
     350        fseek(fconfig, 0L, SEEK_SET);
     351        return 1;
     352    }
     353    fconfig = fopen(config_filename, "r");
     354    return (fconfig != NULL);
     355}
     356
     357static void endconfig(void)
     358{
     359    if (fconfig) {
     360        (void) fclose(fconfig);
     361        fconfig = NULL;
     362    }
     363    free(defhost);
     364    defhost = 0;
     365}
     366
     367#if ENABLE_FEATURE_INETD_RPC
     368static void register_rpc(servtab_t *sep)
     369{
     370    int n;
     371    struct sockaddr_in ir_sin;
     372    struct protoent *pp;
     373    socklen_t size;
     374
     375    if ((pp = getprotobyname(sep->se_proto + 4)) == NULL) {
     376        bb_perror_msg("%s: getproto", sep->se_proto);
     377        return;
     378    }
     379    size = sizeof ir_sin;
     380    if (getsockname(sep->se_fd, (struct sockaddr *) &ir_sin, &size) < 0) {
     381        bb_perror_msg("%s/%s: getsockname",
     382                sep->se_service, sep->se_proto);
     383        return;
     384    }
     385
     386    for (n = sep->se_rpcversl; n <= sep->se_rpcversh; n++) {
     387        (void) pmap_unset(sep->se_rpcprog, n);
     388        if (!pmap_set(sep->se_rpcprog, n, pp->p_proto, ntohs(ir_sin.sin_port)))
     389            bb_perror_msg("%s %s: pmap_set: %u %u %u %u",
     390                    sep->se_service, sep->se_proto,
     391                    sep->se_rpcprog, n, pp->p_proto, ntohs(ir_sin.sin_port));
     392    }
     393}
     394
     395static void unregister_rpc(servtab_t *sep)
     396{
     397    int n;
     398
     399    for (n = sep->se_rpcversl; n <= sep->se_rpcversh; n++) {
     400        if (!pmap_unset(sep->se_rpcprog, n))
     401            bb_error_msg("pmap_unset(%u, %u)", sep->se_rpcprog, n);
     402    }
     403}
     404#endif /* FEATURE_INETD_RPC */
     405
     406static void freeconfig(servtab_t *cp)
     407{
     408    int i;
     409
     410    free(cp->se_hostaddr);
     411    free(cp->se_service);
     412    free(cp->se_proto);
     413    free(cp->se_user);
     414    free(cp->se_group);
     415    free(cp->se_server);
     416    for (i = 0; i < MAXARGV; i++)
     417        free(cp->se_argv[i]);
     418}
     419
     420static int bump_nofile(void)
    419421{
    420422#define FD_CHUNK        32
    421423
    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;
     424    struct rlimit rl;
     425
     426    if (getrlimit(RLIMIT_NOFILE, &rl) < 0) {
     427        bb_perror_msg("getrlimit");
     428        return -1;
     429    }
     430    rl.rlim_cur = MIN(rl.rlim_max, rl.rlim_cur + FD_CHUNK);
     431    rl.rlim_cur = MIN(FD_SETSIZE, rl.rlim_cur + FD_CHUNK);
     432    if (rl.rlim_cur <= rlim_ofile_cur) {
     433        bb_error_msg("bump_nofile: cannot extend file limit, max = %d",
     434                        (int) rl.rlim_cur);
     435        return -1;
     436    }
     437
     438    if (setrlimit(RLIMIT_NOFILE, &rl) < 0) {
     439        bb_perror_msg("setrlimit");
     440        return -1;
     441    }
     442
     443    rlim_ofile_cur = rl.rlim_cur;
     444    return 0;
     445}
     446
     447static void setup(servtab_t *sep)
     448{
     449    int r;
     450
     451    sep->se_fd = socket(sep->se_family, sep->se_socktype, 0);
     452    if (sep->se_fd < 0) {
     453        bb_perror_msg("%s/%s: socket", sep->se_service, sep->se_proto);
     454        return;
     455    }
     456    setsockopt_reuseaddr(sep->se_fd);
     457
     458#if ENABLE_FEATURE_INETD_RPC
     459    if (isrpcservice(sep)) {
     460        struct passwd *pwd;
     461
     462        /*
     463         * for RPC services, attempt to use a reserved port
     464         * if they are going to be running as root.
     465         *
     466         * Also, zero out the port for all RPC services; let bind()
     467         * find one.
     468         */
     469        sep->se_ctrladdr_in.sin_port = 0;
     470        if (sep->se_user && (pwd = getpwnam(sep->se_user)) &&
     471                pwd->pw_uid == 0 && uid == 0)
     472            r = bindresvport(sep->se_fd, &sep->se_ctrladdr_in);
     473        else {
     474            r = bind(sep->se_fd, &sep->se_ctrladdr, sep->se_ctrladdr_size);
     475            if (r == 0) {
     476                socklen_t len = sep->se_ctrladdr_size;
     477                int saveerrno = errno;
     478
     479                /* update se_ctrladdr_in.sin_port */
     480                r = getsockname(sep->se_fd, &sep->se_ctrladdr, &len);
     481                if (r <= 0)
     482                    errno = saveerrno;
     483            }
     484        }
     485    } else
     486#endif
     487        r = bind(sep->se_fd, &sep->se_ctrladdr, sep->se_ctrladdr_size);
     488    if (r < 0) {
     489        bb_perror_msg("%s/%s (%d): bind",
     490                sep->se_service, sep->se_proto, sep->se_ctrladdr.sa_family);
     491        close(sep->se_fd);
     492        sep->se_fd = -1;
     493        if (!timingout) {
     494            timingout = 1;
     495            alarm(RETRYTIME);
     496        }
     497        return;
     498    }
     499    if (sep->se_socktype == SOCK_STREAM)
     500        listen(sep->se_fd, global_queuelen);
     501
     502    FD_SET(sep->se_fd, &allsock);
     503    nsock++;
     504    if (sep->se_fd > maxsock) {
     505        maxsock = sep->se_fd;
     506        if ((rlim_t)maxsock > rlim_ofile_cur - FD_MARGIN)
     507            bump_nofile();
     508    }
     509}
     510
     511static char *nextline(void)
     512{
     513#define line bb_common_bufsiz1
     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
     526static 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        /* bb_error_msg("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        ungetc(c, fconfig);
     546        if (c == ' ' || c == '\t') {
     547            cp = nextline();
     548            if (cp)
     549                goto again;
     550        }
     551        *cpp = NULL;
     552        /* goto erp; */
     553        return NULL;
     554    }
     555    start = cp;
     556    while (*cp && *cp != ' ' && *cp != '\t')
     557        cp++;
     558    if (*cp != '\0')
     559        *cp++ = '\0';
     560    /* if ((*cpp = cp) == NULL) */
     561    /* goto erp; */
     562
     563    *cpp = cp;
     564    return start;
     565}
     566
     567static servtab_t *new_servtab(void)
     568{
     569    return xmalloc(sizeof(servtab_t));
     570}
     571
     572static servtab_t *dupconfig(servtab_t *sep)
     573{
     574    servtab_t *newtab;
     575    int argc;
     576
     577    newtab = new_servtab();
     578    memset(newtab, 0, sizeof(servtab_t));
     579    newtab->se_service = xstrdup(sep->se_service);
     580    newtab->se_socktype = sep->se_socktype;
     581    newtab->se_family = sep->se_family;
     582    newtab->se_proto = xstrdup(sep->se_proto);
     583#if ENABLE_FEATURE_INETD_RPC
     584    newtab->se_rpcprog = sep->se_rpcprog;
     585    newtab->se_rpcversl = sep->se_rpcversl;
     586    newtab->se_rpcversh = sep->se_rpcversh;
     587#endif
     588    newtab->se_wait = sep->se_wait;
     589    newtab->se_user = xstrdup(sep->se_user);
     590    newtab->se_group = xstrdup(sep->se_group);
     591#ifdef INETD_FEATURE_ENABLED
     592    newtab->se_bi = sep->se_bi;
     593#endif
     594    newtab->se_server = xstrdup(sep->se_server);
     595
     596    for (argc = 0; argc <= MAXARGV; argc++)
     597        newtab->se_argv[argc] = xstrdup(sep->se_argv[argc]);
     598    newtab->se_max = sep->se_max;
     599
     600    return newtab;
     601}
     602
     603static servtab_t *getconfigent(void)
     604{
     605    servtab_t *sep;
     606    int argc;
     607    char *cp, *arg;
     608    char *hostdelim;
     609    servtab_t *nsep;
     610    servtab_t *psep;
     611
     612    sep = new_servtab();
     613
     614    /* memset(sep, 0, sizeof *sep); */
     615 more:
     616    /* freeconfig(sep); */
     617
     618    while ((cp = nextline()) && *cp == '#') /* skip comment line */;
     619    if (cp == NULL) {
     620        /* free(sep); */
     621        return NULL;
     622    }
     623
     624    memset((char *) sep, 0, sizeof *sep);
     625    arg = skip(&cp);
     626    if (arg == NULL) {
     627        /* A blank line. */
     628        goto more;
     629    }
     630
     631    /* Check for a host name. */
     632    hostdelim = strrchr(arg, ':');
     633    if (hostdelim) {
     634        *hostdelim = '\0';
     635        sep->se_hostaddr = xstrdup(arg);
     636        arg = hostdelim + 1;
     637        /*
     638         * If the line is of the form `host:', then just change the
     639         * default host for the following lines.
     640         */
     641        if (*arg == '\0') {
     642            arg = skip(&cp);
     643            if (cp == NULL) {
     644                free(defhost);
     645                defhost = sep->se_hostaddr;
     646                goto more;
     647            }
     648        }
     649    } else
     650        sep->se_hostaddr = xxstrdup(defhost);
     651
     652    sep->se_service = xxstrdup(arg);
     653    arg = skip(&cp);
     654
     655    if (strcmp(arg, "stream") == 0)
     656        sep->se_socktype = SOCK_STREAM;
     657    else if (strcmp(arg, "dgram") == 0)
     658        sep->se_socktype = SOCK_DGRAM;
     659    else if (strcmp(arg, "rdm") == 0)
     660        sep->se_socktype = SOCK_RDM;
     661    else if (strcmp(arg, "seqpacket") == 0)
     662        sep->se_socktype = SOCK_SEQPACKET;
     663    else if (strcmp(arg, "raw") == 0)
     664        sep->se_socktype = SOCK_RAW;
     665    else
     666        sep->se_socktype = -1;
     667
     668    sep->se_proto = xxstrdup(skip(&cp));
     669
     670    if (strcmp(sep->se_proto, "unix") == 0) {
     671        sep->se_family = AF_UNIX;
     672    } else {
     673        sep->se_family = AF_INET;
     674        if (sep->se_proto[strlen(sep->se_proto) - 1] == '6')
     675#if ENABLE_FEATURE_IPV6
     676            sep->se_family = AF_INET6;
     677#else
     678            bb_error_msg("%s: IPV6 not supported", sep->se_proto);
     679#endif
     680        if (strncmp(sep->se_proto, "rpc/", 4) == 0) {
     681#if ENABLE_FEATURE_INETD_RPC
     682            char *p, *ccp;
     683            long l;
     684
     685            p = strchr(sep->se_service, '/');
     686            if (p == 0) {
     687                bb_error_msg("%s: no rpc version", sep->se_service);
     688                goto more;
     689            }
     690            *p++ = '\0';
     691            l = strtol(p, &ccp, 0);
     692            if (ccp == p || l < 0 || l > INT_MAX) {
     693 badafterall:
     694                bb_error_msg("%s/%s: bad rpc version", sep->se_service, p);
     695                goto more;
     696            }
     697            sep->se_rpcversl = sep->se_rpcversh = l;
     698            if (*ccp == '-') {
     699                p = ccp + 1;
     700                l = strtol(p, &ccp, 0);
     701                if (ccp == p || l < 0 || l > INT_MAX || l < sep->se_rpcversl || *ccp)
     702                    goto badafterall;
     703                sep->se_rpcversh = l;
     704            } else if (*ccp != '\0')
     705                goto badafterall;
     706#else
     707            bb_error_msg("%s: rpc services not supported", sep->se_service);
     708#endif
     709        }
     710    }
     711    arg = skip(&cp);
     712    if (arg == NULL)
     713        goto more;
     714
     715    {
     716        char *s = strchr(arg, '.');
     717        if (s) {
     718            *s++ = '\0';
     719            sep->se_max = xatoi(s);
     720        } else
     721            sep->se_max = toomany;
     722    }
     723    sep->se_wait = strcmp(arg, "wait") == 0;
     724    /* if ((arg = skip(&cp, 1)) == NULL) */
     725    /* goto more; */
     726    sep->se_user = xxstrdup(skip(&cp));
     727    arg = strchr(sep->se_user, '.');
     728    if (arg == NULL)
     729        arg = strchr(sep->se_user, ':');
     730    if (arg) {
     731        *arg++ = '\0';
     732        sep->se_group = xstrdup(arg);
     733    }
     734    /* if ((arg = skip(&cp, 1)) == NULL) */
     735    /* goto more; */
     736
     737    sep->se_server = xxstrdup(skip(&cp));
     738    if (strcmp(sep->se_server, "internal") == 0) {
     739#ifdef INETD_FEATURE_ENABLED
     740        const struct builtin *bi;
     741
     742        for (bi = builtins; bi->bi_service; bi++)
     743            if (bi->bi_socktype == sep->se_socktype &&
     744                    strcmp(bi->bi_service, sep->se_service) == 0)
     745                break;
     746        if (bi->bi_service == 0) {
     747            bb_error_msg("internal service %s unknown", sep->se_service);
     748            goto more;
     749        }
     750        sep->se_bi = bi;
     751        sep->se_wait = bi->bi_wait;
     752#else
     753        bb_perror_msg("internal service %s unknown", sep->se_service);
     754        goto more;
     755#endif
     756    }
     757#ifdef INETD_FEATURE_ENABLED
     758        else
     759        sep->se_bi = NULL;
     760#endif
     761    argc = 0;
     762    for (arg = skip(&cp); cp; arg = skip(&cp)) {
     763        if (argc < MAXARGV)
     764            sep->se_argv[argc++] = xxstrdup(arg);
     765    }
     766    while (argc <= MAXARGV)
     767        sep->se_argv[argc++] = NULL;
    463768
    464769    /*
    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.
     770     * Now that we've processed the entire line, check if the hostname
     771     * specifier was a comma separated list of hostnames. If so
     772     * we'll make new entries for each address.
    470773     */
    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);
     774    while ((hostdelim = strrchr(sep->se_hostaddr, ',')) != NULL) {
     775        nsep = dupconfig(sep);
     776
     777        /*
     778         * NULL terminate the hostname field of the existing entry,
     779         * and make a dup for the new entry.
     780         */
     781        *hostdelim++ = '\0';
     782        nsep->se_hostaddr = xstrdup(hostdelim);
     783
     784        nsep->se_next = sep->se_next;
     785        sep->se_next = nsep;
     786    }
     787
     788    nsep = sep;
     789    while (nsep != NULL) {
     790        nsep->se_checked = 1;
     791        if (nsep->se_family == AF_INET) {
     792            if (LONE_CHAR(nsep->se_hostaddr, '*'))
     793                nsep->se_ctrladdr_in.sin_addr.s_addr = INADDR_ANY;
     794            else if (!inet_aton(nsep->se_hostaddr, &nsep->se_ctrladdr_in.sin_addr)) {
     795                struct hostent *hp;
     796
     797                hp = gethostbyname(nsep->se_hostaddr);
     798                if (hp == 0) {
     799                    bb_error_msg("%s: unknown host", nsep->se_hostaddr);
     800                    nsep->se_checked = 0;
     801                    goto skip;
     802                } else if (hp->h_addrtype != AF_INET) {
     803                    bb_error_msg("%s: address isn't an Internet "
     804                                  "address", nsep->se_hostaddr);
     805                    nsep->se_checked = 0;
     806                    goto skip;
     807                } else {
     808                    int i = 1;
     809
     810                    memmove(&nsep->se_ctrladdr_in.sin_addr,
     811                                   hp->h_addr_list[0], sizeof(struct in_addr));
     812                    while (hp->h_addr_list[i] != NULL) {
     813                        psep = dupconfig(nsep);
     814                        psep->se_hostaddr = xxstrdup(nsep->se_hostaddr);
     815                        psep->se_checked = 1;
     816                        memmove(&psep->se_ctrladdr_in.sin_addr,
     817                                     hp->h_addr_list[i], sizeof(struct in_addr));
     818                        psep->se_ctrladdr_size = sizeof(psep->se_ctrladdr_in);
     819                        i++;
     820                        /* Prepend to list, don't want to look up */
     821                        /* its hostname again. */
     822                        psep->se_next = sep;
     823                        sep = psep;
     824                    }
     825                }
     826            }
     827        }
     828/* XXX BUG?: is this skip: label supposed to remain? */
     829 skip:
     830        nsep = nsep->se_next;
     831    }
     832
     833    /*
     834     * Finally, free any entries which failed the gethostbyname
     835     * check.
     836     */
     837    psep = NULL;
     838    nsep = sep;
     839    while (nsep != NULL) {
     840        servtab_t *tsep;
     841
     842        if (nsep->se_checked == 0) {
     843            tsep = nsep;
     844            if (psep == NULL) {
     845                sep = nsep->se_next;
     846                nsep = sep;
     847            } else {
     848                nsep = nsep->se_next;
     849                psep->se_next = nsep;
     850            }
     851            freeconfig(tsep);
     852        } else {
     853            nsep->se_checked = 0;
     854            psep = nsep;
     855            nsep = nsep->se_next;
     856        }
     857    }
     858
     859    return sep;
     860}
     861
     862#define Block_Using_Signals(m) do { \
     863    sigemptyset(&m); \
     864    sigaddset(&m, SIGCHLD); \
     865    sigaddset(&m, SIGHUP); \
     866    sigaddset(&m, SIGALRM); \
     867    sigprocmask(SIG_BLOCK, &m, NULL); \
     868} while (0)
     869
     870static servtab_t *enter(servtab_t *cp)
     871{
     872    servtab_t *sep;
     873    sigset_t omask;
     874
     875    sep = new_servtab();
     876    *sep = *cp;
    494877    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;
     878#if ENABLE_FEATURE_INETD_RPC
     879    sep->se_rpcprog = -1;
     880#endif
     881    Block_Using_Signals(omask);
     882    sep->se_next = servtab;
     883    servtab = sep;
     884    sigprocmask(SIG_UNBLOCK, &omask, NULL);
     885    return sep;
     886}
     887
     888static int matchconf(servtab_t *old, servtab_t *new)
     889{
     890    if (strcmp(old->se_service, new->se_service) != 0)
     891        return 0;
     892
     893    if (strcmp(old->se_hostaddr, new->se_hostaddr) != 0)
     894        return 0;
     895
     896    if (strcmp(old->se_proto, new->se_proto) != 0)
     897        return 0;
     898
     899    /*
     900     * If the new servtab is bound to a specific address, check that the
     901     * old servtab is bound to the same entry. If the new service is not
     902     * bound to a specific address then the check of se_hostaddr above
     903     * is sufficient.
     904     */
     905
     906    if (old->se_family == AF_INET && new->se_family == AF_INET &&
     907            memcmp(&old->se_ctrladdr_in.sin_addr,
     908                    &new->se_ctrladdr_in.sin_addr,
     909                    sizeof(new->se_ctrladdr_in.sin_addr)) != 0)
     910        return 0;
     911
     912#if ENABLE_FEATURE_IPV6
     913    if (old->se_family == AF_INET6 && new->se_family == AF_INET6 &&
     914            memcmp(&old->se_ctrladdr_in6.sin6_addr,
     915                    &new->se_ctrladdr_in6.sin6_addr,
     916                    sizeof(new->se_ctrladdr_in6.sin6_addr)) != 0)
     917        return 0;
     918#endif
     919    return 1;
     920}
     921
     922static void config(int sig ATTRIBUTE_UNUSED)
     923{
     924    servtab_t *sep, *cp, **sepp;
     925    sigset_t omask;
     926    size_t n;
     927    char protoname[10];
     928
     929    if (!setconfig()) {
     930        bb_perror_msg("%s", config_filename);
     931        return;
     932    }
     933    for (sep = servtab; sep; sep = sep->se_next)
     934        sep->se_checked = 0;
     935    cp = getconfigent();
     936    while (cp != NULL) {
     937        for (sep = servtab; sep; sep = sep->se_next)
     938            if (matchconf(sep, cp))
     939                break;
     940
     941        if (sep != 0) {
     942            int i;
     943
     944#define SWAP(type, a, b) do {type c=(type)a; a=(type)b; b=(type)c;} while (0)
     945
     946            Block_Using_Signals(omask);
     947            /*
     948             * sep->se_wait may be holding the pid of a daemon
     949             * that we're waiting for.  If so, don't overwrite
     950             * it unless the config file explicitly says don't
     951             * wait.
     952             */
     953            if (
    596954#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;
     955                cp->se_bi == 0 &&
     956#endif
     957                (sep->se_wait == 1 || cp->se_wait == 0))
     958                sep->se_wait = cp->se_wait;
     959            SWAP(int, cp->se_max, sep->se_max);
     960            SWAP(char *, sep->se_user, cp->se_user);
     961            SWAP(char *, sep->se_group, cp->se_group);
     962            SWAP(char *, sep->se_server, cp->se_server);
     963            for (i = 0; i < MAXARGV; i++)
     964                SWAP(char *, sep->se_argv[i], cp->se_argv[i]);
     965#undef SWAP
     966
     967#if ENABLE_FEATURE_INETD_RPC
     968            if (isrpcservice(sep))
     969                unregister_rpc(sep);
     970            sep->se_rpcversl = cp->se_rpcversl;
     971            sep->se_rpcversh = cp->se_rpcversh;
     972#endif
     973            sigprocmask(SIG_UNBLOCK, &omask, NULL);
     974            freeconfig(cp);
     975        } else {
     976            sep = enter(cp);
     977        }
     978        sep->se_checked = 1;
     979
     980        switch (sep->se_family) {
     981        case AF_UNIX:
     982            if (sep->se_fd != -1)
     983                break;
     984            (void) unlink(sep->se_service);
     985            n = strlen(sep->se_service);
     986            if (n > sizeof sep->se_ctrladdr_un.sun_path - 1)
     987                n = sizeof sep->se_ctrladdr_un.sun_path - 1;
     988            safe_strncpy(sep->se_ctrladdr_un.sun_path, sep->se_service, n + 1);
     989            sep->se_ctrladdr_un.sun_family = AF_UNIX;
     990            sep->se_ctrladdr_size = n + sizeof sep->se_ctrladdr_un.sun_family;
     991            setup(sep);
     992            break;
     993        case AF_INET:
     994            sep->se_ctrladdr_in.sin_family = AF_INET;
     995            /* se_ctrladdr_in was set in getconfigent */
     996            sep->se_ctrladdr_size = sizeof sep->se_ctrladdr_in;
     997
     998#if ENABLE_FEATURE_INETD_RPC
     999            if (isrpcservice(sep)) {
     1000                struct rpcent *rp;
     1001                // FIXME: atoi_or_else(str, 0) would be handy here
     1002                sep->se_rpcprog = atoi(sep->se_service);
     1003                if (sep->se_rpcprog == 0) {
     1004                    rp = getrpcbyname(sep->se_service);
     1005                    if (rp == 0) {
     1006                        bb_error_msg("%s: unknown rpc service", sep->se_service);
     1007                        goto serv_unknown;
     1008                    }
     1009                    sep->se_rpcprog = rp->r_number;
     1010                }
     1011                if (sep->se_fd == -1)
     1012                    setup(sep);
     1013                if (sep->se_fd != -1)
     1014                    register_rpc(sep);
     1015            } else
     1016#endif
     1017            {
     1018                uint16_t port = htons(atoi(sep->se_service));
     1019                // FIXME: atoi_or_else(str, 0) would be handy here
     1020                if (!port) {
     1021                     /*XXX*/ strncpy(protoname, sep->se_proto, sizeof(protoname));
     1022                    if (isdigit(protoname[strlen(protoname) - 1]))
     1023                        protoname[strlen(protoname) - 1] = '\0';
     1024                    sp = getservbyname(sep->se_service, protoname);
     1025                    if (sp == 0) {
     1026                        bb_error_msg("%s/%s: unknown service",
     1027                                sep->se_service, sep->se_proto);
     1028                        goto serv_unknown;
     1029                    }
     1030                    port = sp->s_port;
     1031                }
     1032                if (port != sep->se_ctrladdr_in.sin_port) {
     1033                    sep->se_ctrladdr_in.sin_port = port;
     1034                    if (sep->se_fd != -1) {
     1035                        FD_CLR(sep->se_fd, &allsock);
     1036                        nsock--;
     1037                        (void) close(sep->se_fd);
     1038                    }
     1039                    sep->se_fd = -1;
     1040                }
     1041                if (sep->se_fd == -1)
     1042                    setup(sep);
     1043            }
     1044            break;
     1045#if ENABLE_FEATURE_IPV6
     1046        case AF_INET6:
     1047            sep->se_ctrladdr_in6.sin6_family = AF_INET6;
     1048            /* se_ctrladdr_in was set in getconfigent */
     1049            sep->se_ctrladdr_size = sizeof sep->se_ctrladdr_in6;
     1050
     1051#if ENABLE_FEATURE_INETD_RPC
     1052            if (isrpcservice(sep)) {
     1053                struct rpcent *rp;
     1054
     1055                sep->se_rpcprog = atoi(sep->se_service);
     1056                if (sep->se_rpcprog == 0) {
     1057                    rp = getrpcbyname(sep->se_service);
     1058                    if (rp == 0) {
     1059                        bb_error_msg("%s: unknown rpc service", sep->se_service);
     1060                        goto serv_unknown;
     1061                    }
     1062                    sep->se_rpcprog = rp->r_number;
     1063                }
     1064                if (sep->se_fd == -1)
     1065                    setup(sep);
     1066                if (sep->se_fd != -1)
     1067                    register_rpc(sep);
     1068            } else
     1069#endif
     1070            {
     1071                uint16_t port = htons(atoi(sep->se_service));
     1072
     1073                if (!port) {
     1074                     /*XXX*/ strncpy(protoname, sep->se_proto, sizeof(protoname));
     1075                    if (isdigit(protoname[strlen(protoname) - 1]))
     1076                        protoname[strlen(protoname) - 1] = '\0';
     1077                    sp = getservbyname(sep->se_service, protoname);
     1078                    if (sp == 0) {
     1079                        bb_error_msg("%s/%s: unknown service",
     1080                                sep->se_service, sep->se_proto);
     1081                        goto serv_unknown;
     1082                    }
     1083                    port = sp->s_port;
     1084                }
     1085                if (port != sep->se_ctrladdr_in6.sin6_port) {
     1086                    sep->se_ctrladdr_in6.sin6_port = port;
     1087                    if (sep->se_fd != -1) {
     1088                        FD_CLR(sep->se_fd, &allsock);
     1089                        nsock--;
     1090                        (void) close(sep->se_fd);
     1091                    }
     1092                    sep->se_fd = -1;
     1093                }
     1094                if (sep->se_fd == -1)
     1095                    setup(sep);
     1096            }
     1097            break;
     1098#endif /* FEATURE_IPV6 */
     1099        }
     1100 serv_unknown:
     1101        if (cp->se_next != NULL) {
     1102            servtab_t *tmp = cp;
     1103
     1104            cp = cp->se_next;
     1105            free(tmp);
     1106        } else {
     1107            free(cp);
     1108            cp = getconfigent();
     1109        }
     1110    }
     1111    endconfig();
    6431112    /*
    644      * If the line is of the form `host:', then just change the
    645      * default host for the following lines.
     1113     * Purge anything not looked at above.
    6461114     */
    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           }
     1115    Block_Using_Signals(omask);
     1116    sepp = &servtab;
     1117    while ((sep = *sepp)) {
     1118        if (sep->se_checked) {
     1119            sepp = &sep->se_next;
     1120            continue;
    8321121        }
    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;
     1122        *sepp = sep->se_next;
     1123        if (sep->se_fd != -1) {
     1124            FD_CLR(sep->se_fd, &allsock);
     1125            nsock--;
     1126            (void) close(sep->se_fd);
    10191127        }
     1128#if ENABLE_FEATURE_INETD_RPC
     1129        if (isrpcservice(sep))
     1130            unregister_rpc(sep);
     1131#endif
     1132        if (sep->se_family == AF_UNIX)
     1133            (void) unlink(sep->se_service);
     1134        freeconfig(sep);
     1135        free(sep);
     1136    }
     1137    sigprocmask(SIG_UNBLOCK, &omask, NULL);
     1138}
     1139
     1140
     1141static void reapchild(int sig ATTRIBUTE_UNUSED)
     1142{
     1143    pid_t pid;
     1144    int save_errno = errno, status;
     1145    servtab_t *sep;
     1146
     1147    for (;;) {
     1148        pid = wait3(&status, WNOHANG, NULL);
     1149        if (pid <= 0)
     1150            break;
     1151        for (sep = servtab; sep; sep = sep->se_next)
     1152            if (sep->se_wait == pid) {
     1153                if (WIFEXITED(status) && WEXITSTATUS(status))
     1154                    bb_error_msg("%s: exit status 0x%x",
     1155                            sep->se_server, WEXITSTATUS(status));
     1156                else if (WIFSIGNALED(status))
     1157                    bb_error_msg("%s: exit signal 0x%x",
     1158                            sep->se_server, WTERMSIG(status));
     1159                sep->se_wait = 1;
     1160                FD_SET(sep->se_fd, &allsock);
     1161                nsock++;
     1162            }
     1163    }
     1164    errno = save_errno;
     1165}
     1166
     1167static void retry(int sig ATTRIBUTE_UNUSED)
     1168{
     1169    servtab_t *sep;
     1170
     1171    timingout = 0;
     1172    for (sep = servtab; sep; sep = sep->se_next) {
     1173        if (sep->se_fd == -1) {
     1174            switch (sep->se_family) {
     1175            case AF_UNIX:
     1176            case AF_INET:
     1177#if ENABLE_FEATURE_IPV6
     1178            case AF_INET6:
     1179#endif
     1180                setup(sep);
     1181#if ENABLE_FEATURE_INETD_RPC
     1182                if (sep->se_fd != -1 && isrpcservice(sep))
     1183                    register_rpc(sep);
     1184#endif
     1185                break;
     1186            }
     1187        }
     1188    }
     1189}
     1190
     1191static void goaway(int sig ATTRIBUTE_UNUSED)
     1192{
     1193    servtab_t *sep;
     1194
     1195    /* XXX signal race walking sep list */
     1196    for (sep = servtab; sep; sep = sep->se_next) {
    10201197        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;
     1198            continue;
     1199
     1200        switch (sep->se_family) {
     1201        case AF_UNIX:
     1202            (void) unlink(sep->se_service);
     1203            break;
     1204        case AF_INET:
     1205#if ENABLE_FEATURE_IPV6
     1206        case AF_INET6:
     1207#endif
     1208#if ENABLE_FEATURE_INETD_RPC
     1209            if (sep->se_wait == 1 && isrpcservice(sep))
     1210                unregister_rpc(sep);   /* XXX signal race */
     1211#endif
     1212            break;
    10401213        }
    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);
     1214        (void) close(sep->se_fd);
     1215    }
     1216    remove_pidfile(_PATH_INETDPID);
     1217    exit(0);
    12281218}
    12291219
     
    12341224
    12351225static 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;
     1226inetd_setproctitle(char *a, int s)
     1227{
     1228    socklen_t size;
     1229    char *cp;
     1230    struct sockaddr_in prt_sin;
     1231    char buf[80];
     1232
     1233    cp = Argv[0];
     1234    size = sizeof(prt_sin);
     1235    (void) snprintf(buf, sizeof buf, "-%s", a);
     1236    if (getpeername(s, (struct sockaddr *) &prt_sin, &size) == 0) {
     1237        char *sa = inet_ntoa(prt_sin.sin_addr);
     1238
     1239        buf[sizeof(buf) - 1 - strlen(sa) - 3] = '\0';
     1240        strcat(buf, " [");
     1241        strcat(buf, sa);
     1242        strcat(buf, "]");
     1243    }
     1244    strncpy(cp, buf, LastArg - cp);
     1245    cp += strlen(cp);
     1246    while (cp < LastArg)
     1247        *cp++ = ' ';
     1248}
     1249#endif
     1250
     1251
     1252int inetd_main(int argc, char **argv);
     1253int inetd_main(int argc, char **argv)
     1254{
     1255    servtab_t *sep;
     1256    struct passwd *pwd;
     1257    struct group *grp = NULL;
     1258    int tmpint;
     1259    struct sigaction sa, sapipe;
     1260    int opt;
     1261    pid_t pid;
     1262    char buf[50];
     1263    char *stoomany;
     1264    sigset_t omask, wait_mask;
    12751265
    12761266#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 #ifdef BB_NOMMU
    1313     /* reexec for vfork() do continue parent */
    1314     vfork_daemon_rexec (0, 0, argc, argv, "-f");
    1315 #else
    1316     bb_xdaemon (0, 0);
    1317 #endif
    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 */
     1267    char **envp = environ;
     1268
     1269    Argv = argv;
     1270    if (envp == 0 || *envp == 0)
     1271        envp = argv;
     1272    while (*envp)
     1273        envp++;
     1274    LastArg = envp[-1] + strlen(envp[-1]);
     1275#endif
     1276
     1277    uid = getuid();
     1278    if (uid != 0)
     1279        config_filename = NULL;
     1280
     1281    opt = getopt32(argv, "R:f", &stoomany);
     1282    if (opt & 1)
     1283        toomany = xatoi_u(stoomany);
     1284    argv += optind;
     1285    argc -= optind;
     1286    if (argc)
     1287        config_filename = argv[0];
     1288    if (config_filename == NULL)
     1289        bb_error_msg_and_die("non-root must specify a config file");
     1290
     1291    if (!(opt & 2))
     1292        bb_daemonize_or_rexec(0, argv - optind);
     1293    else
     1294        bb_sanitize_stdio();
     1295    openlog(applet_name, LOG_PID | LOG_NOWAIT, LOG_DAEMON);
     1296    logmode = LOGMODE_SYSLOG;
     1297
     1298    if (uid == 0) {
     1299        /* If run by hand, ensure groups vector gets trashed */
     1300        gid_t gid = getgid();
     1301        setgroups(1, &gid);
     1302    }
     1303
     1304    write_pidfile(_PATH_INETDPID);
     1305
     1306    if (getrlimit(RLIMIT_NOFILE, &rlim_ofile) < 0) {
     1307        bb_perror_msg("getrlimit");
     1308    } else {
     1309        rlim_ofile_cur = rlim_ofile.rlim_cur;
     1310        if (rlim_ofile_cur == RLIM_INFINITY)    /* ! */
     1311            rlim_ofile_cur = OPEN_MAX;
     1312    }
     1313
     1314    memset((char *) &sa, 0, sizeof(sa));
     1315    sigemptyset(&sa.sa_mask);
     1316    sigaddset(&sa.sa_mask, SIGALRM);
     1317    sigaddset(&sa.sa_mask, SIGCHLD);
     1318    sigaddset(&sa.sa_mask, SIGHUP);
     1319    sa.sa_handler = retry;
     1320    sigaction(SIGALRM, &sa, NULL);
     1321    config(SIGHUP);
     1322    sa.sa_handler = config;
     1323    sigaction(SIGHUP, &sa, NULL);
     1324    sa.sa_handler = reapchild;
     1325    sigaction(SIGCHLD, &sa, NULL);
     1326    sa.sa_handler = goaway;
     1327    sigaction(SIGTERM, &sa, NULL);
     1328    sa.sa_handler = goaway;
     1329    sigaction(SIGINT, &sa, NULL);
     1330    sa.sa_handler = SIG_IGN;
     1331    sigaction(SIGPIPE, &sa, &sapipe);
     1332    memset(&wait_mask, 0, sizeof(wait_mask));
     1333    {
     1334        /* space for daemons to overwrite environment for ps */
    13681335#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);
     1336        char dummy[DUMMYSIZE];
     1337
     1338        (void) memset(dummy, 'x', DUMMYSIZE - 1);
     1339        dummy[DUMMYSIZE - 1] = '\0';
     1340
     1341        (void) setenv("inetd_dummy", dummy, 1);
     1342    }
     1343
     1344    for (;;) {
     1345        int n, ctrl = -1;
     1346        fd_set readable;
     1347
     1348        if (nsock == 0) {
     1349            Block_Using_Signals(omask);
     1350            while (nsock == 0)
     1351                sigsuspend(&wait_mask);
     1352            sigprocmask(SIG_UNBLOCK, &omask, NULL);
     1353        }
     1354
     1355        readable = allsock;
     1356        n = select(maxsock + 1, &readable, NULL, NULL, NULL);
     1357        if (n <= 0) {
     1358            if (n < 0 && errno != EINTR) {
     1359                bb_perror_msg("select");
     1360                sleep(1);
     1361            }
    14051362            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;
     1363        }
     1364
     1365        for (sep = servtab; n && sep; sep = sep->se_next) {
     1366            if (sep->se_fd == -1 || !FD_ISSET(sep->se_fd, &readable))
     1367                continue;
     1368
     1369            n--;
     1370            if (!sep->se_wait && sep->se_socktype == SOCK_STREAM) {
     1371                ctrl = accept(sep->se_fd, NULL, NULL);
     1372                if (ctrl < 0) {
     1373                    if (errno == EINTR)
     1374                        continue;
     1375                    bb_perror_msg("accept (for %s)", sep->se_service);
     1376                    continue;
     1377                }
     1378                if (sep->se_family == AF_INET && sep->se_socktype == SOCK_STREAM) {
     1379                    struct sockaddr_in peer;
     1380                    socklen_t plen = sizeof(peer);
     1381
     1382                    if (getpeername(ctrl, (struct sockaddr *) &peer, &plen) < 0) {
     1383                        bb_error_msg("cannot getpeername");
     1384                        close(ctrl);
     1385                        continue;
     1386                    }
     1387                    if (ntohs(peer.sin_port) == 20) {
     1388                        /* XXX ftp bounce */
     1389                        close(ctrl);
     1390                        continue;
     1391                    }
     1392                }
     1393            } else
     1394                ctrl = sep->se_fd;
     1395
     1396            Block_Using_Signals(omask);
     1397            pid = 0;
     1398#ifdef INETD_FEATURE_ENABLED
     1399            if (sep->se_bi == 0 || sep->se_bi->bi_fork)
     1400#endif
     1401            {
     1402                if (sep->se_count++ == 0)
     1403                    (void) gettimeofday(&sep->se_time, NULL);
     1404                else if (toomany > 0 && sep->se_count >= sep->se_max) {
     1405                    struct timeval now;
     1406
     1407                    (void) gettimeofday(&now, NULL);
     1408                    if (now.tv_sec - sep->se_time.tv_sec > CNT_INTVL) {
     1409                        sep->se_time = now;
     1410                        sep->se_count = 1;
     1411                    } else {
     1412                        if (!sep->se_wait && sep->se_socktype == SOCK_STREAM)
     1413                            close(ctrl);
     1414                        if (sep->se_family == AF_INET &&
     1415                              ntohs(sep->se_ctrladdr_in.sin_port) >= IPPORT_RESERVED) {
     1416                            /*
     1417                             * Cannot close it -- there are
     1418                             * thieves on the system.
     1419                             * Simply ignore the connection.
     1420                             */
     1421                            --sep->se_count;
     1422                            continue;
     1423                        }
     1424                        bb_error_msg("%s/%s server failing (looping), service terminated",
     1425                                  sep->se_service, sep->se_proto);
     1426                        if (!sep->se_wait && sep->se_socktype == SOCK_STREAM)
     1427                            close(ctrl);
     1428                        FD_CLR(sep->se_fd, &allsock);
     1429                        (void) close(sep->se_fd);
     1430                        sep->se_fd = -1;
     1431                        sep->se_count = 0;
     1432                        nsock--;
     1433                        sigprocmask(SIG_UNBLOCK, &omask, NULL);
     1434                        if (!timingout) {
     1435                            timingout = 1;
     1436                            alarm(RETRYTIME);
     1437                        }
     1438                        continue;
     1439                    }
     1440                }
     1441                pid = fork();
    14151442            }
    1416             if (ntohs (peer.sin_port) == 20) {
    1417               /* XXX ftp bounce */
    1418               close (ctrl);
    1419               continue;
     1443            if (pid < 0) {
     1444                bb_perror_msg("fork");
     1445                if (!sep->se_wait && sep->se_socktype == SOCK_STREAM)
     1446                    close(ctrl);
     1447                sigprocmask(SIG_UNBLOCK, &omask, NULL);
     1448                sleep(1);
     1449                continue;
    14201450            }
    1421           }
    1422         } else
    1423           ctrl = sep->se_fd;
    1424         Block_Using_Signals(omask);
    1425         pid = 0;
     1451            if (pid && sep->se_wait) {
     1452                sep->se_wait = pid;
     1453                FD_CLR(sep->se_fd, &allsock);
     1454                nsock--;
     1455            }
     1456            sigprocmask(SIG_UNBLOCK, &omask, NULL);
     1457            if (pid == 0) {
    14261458#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;
     1459                if (sep->se_bi) {
     1460                    (*sep->se_bi->bi_fn)(ctrl, sep);
     1461                } else
     1462#endif
     1463                {
     1464                    pwd = getpwnam(sep->se_user);
     1465                    if (pwd == NULL) {
     1466                        bb_error_msg("getpwnam: %s: no such user", sep->se_user);
     1467                        goto do_exit1;
     1468                    }
     1469                    if (setsid() < 0)
     1470                        bb_perror_msg("%s: setsid", sep->se_service);
     1471                    if (sep->se_group && (grp = getgrnam(sep->se_group)) == NULL) {
     1472                        bb_error_msg("getgrnam: %s: no such group", sep->se_group);
     1473                        goto do_exit1;
     1474                    }
     1475                    if (uid != 0) {
     1476                        /* a user running private inetd */
     1477                        if (uid != pwd->pw_uid)
     1478                            _exit(1);
     1479                    } else if (pwd->pw_uid) {
     1480                        if (sep->se_group)
     1481                            pwd->pw_gid = grp->gr_gid;
     1482                        xsetgid((gid_t) pwd->pw_gid);
     1483                        initgroups(pwd->pw_name, pwd->pw_gid);
     1484                        xsetuid((uid_t) pwd->pw_uid);
     1485                    } else if (sep->se_group) {
     1486                        xsetgid(grp->gr_gid);
     1487                        setgroups(1, &grp->gr_gid);
     1488                    }
     1489                    dup2(ctrl, 0);
     1490                    if (ctrl) close(ctrl);
     1491                    dup2(0, 1);
     1492                    dup2(0, 2);
     1493                    if (rlim_ofile.rlim_cur != rlim_ofile_cur)
     1494                        if (setrlimit(RLIMIT_NOFILE, &rlim_ofile) < 0)
     1495                            bb_perror_msg("setrlimit");
     1496                    closelog();
     1497                    for (tmpint = rlim_ofile_cur - 1; --tmpint > 2;)
     1498                        (void) close(tmpint);
     1499                    sigaction(SIGPIPE, &sapipe, NULL);
     1500                    execv(sep->se_server, sep->se_argv);
     1501                    bb_perror_msg("execv %s", sep->se_server);
     1502 do_exit1:
     1503                    if (sep->se_socktype != SOCK_STREAM)
     1504                        recv(0, buf, sizeof(buf), 0);
     1505                    _exit(1);
     1506                }
    14681507            }
    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               xsetgid ((gid_t) pwd->pw_gid);
    1516               initgroups (pwd->pw_name, pwd->pw_gid);
    1517               xsetuid((uid_t) pwd->pw_uid);
    1518             } else if (sep->se_group) {
    1519               xsetgid(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   }
     1508            if (!sep->se_wait && sep->se_socktype == SOCK_STREAM)
     1509                close(ctrl);
     1510        } /* for (sep = servtab...) */
     1511    } /* for (;;) */
    15441512}
    15451513
     
    15491517#define BUFSIZE 4096
    15501518
    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
     1519#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_ECHO || \
     1520    ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN || \
     1521    ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME
     1522static int dg_badinput(struct sockaddr_in *dg_sin)
     1523{
     1524    if (ntohs(dg_sin->sin_port) < IPPORT_RESERVED)
     1525        return 1;
     1526    if (dg_sin->sin_addr.s_addr == htonl(INADDR_BROADCAST))
     1527        return 1;
     1528    /* XXX compare against broadcast addresses in SIOCGIFCONF list? */
     1529    return 0;
     1530}
     1531#endif
     1532
     1533#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_ECHO
    15661534/* Echo service -- echo data back */
    15671535/* ARGSUSED */
    15681536static 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);
     1537echo_stream(int s, servtab_t *sep)
     1538{
     1539    char buffer[BUFSIZE];
     1540    int i;
     1541
     1542    inetd_setproctitle(sep->se_service, s);
     1543    while (1) {
     1544        i = read(s, buffer, sizeof(buffer));
     1545        if (i <= 0) break;
     1546        /* FIXME: this isnt correct - safe_write()? */
     1547        if (write(s, buffer, i) <= 0) break;
     1548    }
     1549    exit(0);
    15781550}
    15791551
     
    15811553/* ARGSUSED */
    15821554static 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
     1555echo_dg(int s, servtab_t *sep ATTRIBUTE_UNUSED)
     1556{
     1557    char buffer[BUFSIZE];
     1558    int i;
     1559    socklen_t size;
     1560    /* struct sockaddr_storage ss; */
     1561    struct sockaddr sa;
     1562
     1563    size = sizeof(sa);
     1564    i = recvfrom(s, buffer, sizeof(buffer), 0, &sa, &size);
     1565    if (i < 0)
     1566        return;
     1567    if (dg_badinput((struct sockaddr_in *) &sa))
     1568        return;
     1569    (void) sendto(s, buffer, i, 0, &sa, sizeof(sa));
     1570}
     1571#endif  /* FEATURE_INETD_SUPPORT_BUILTIN_ECHO */
     1572
     1573#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD
    16011574/* Discard service -- ignore data */
    16021575/* ARGSUSED */
    16031576static 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);
     1577discard_stream(int s, servtab_t *sep)
     1578{
     1579    char buffer[BUFSIZE];
     1580
     1581    inetd_setproctitle(sep->se_service, s);
     1582    while (1) {
     1583        errno = 0;
     1584        if (read(s, buffer, sizeof(buffer)) <= 0 && errno != EINTR)
     1585            exit(0);
     1586    }
    16121587}
    16131588
     
    16151590/* ARGSUSED */
    16161591static 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
     1592discard_dg(int s, servtab_t *sep ATTRIBUTE_UNUSED)
     1593{
     1594    char buffer[BUFSIZE];
     1595
     1596    (void) read(s, buffer, sizeof(buffer));
     1597}
     1598#endif /* FEATURE_INETD_SUPPORT_BUILTIN_DISCARD */
     1599
     1600
     1601#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN
    16271602#define LINESIZ 72
    16281603static char ring[128];
     
    16301605
    16311606static 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;
     1607initring(void)
     1608{
     1609    int i;
     1610
     1611    endring = ring;
     1612
     1613    for (i = 0; i <= 128; ++i)
     1614        if (isprint(i))
     1615            *endring++ = i;
    16411616}
    16421617
     
    16441619/* ARGSUSED */
    16451620static 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 ();
     1621chargen_stream(int s, servtab_t *sep)
     1622{
     1623    char *rs;
     1624    int len;
     1625    char text[LINESIZ + 2];
     1626
     1627    inetd_setproctitle(sep->se_service, s);
     1628
     1629    if (!endring) {
     1630        initring();
     1631        rs = ring;
     1632    }
     1633
     1634    text[LINESIZ] = '\r';
     1635    text[LINESIZ + 1] = '\n';
    16561636    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);
     1637    for (;;) {
     1638        len = endring - rs;
     1639        if (len >= LINESIZ)
     1640            memmove(text, rs, LINESIZ);
     1641        else {
     1642            memmove(text, rs, len);
     1643            memmove(text + len, ring, LINESIZ - len);
     1644        }
     1645        if (++rs == endring)
     1646            rs = ring;
     1647        if (write(s, text, sizeof(text)) != sizeof(text))
     1648            break;
     1649    }
     1650    exit(0);
    16741651}
    16751652
     
    16771654/* ARGSUSED */
    16781655static 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
     1656chargen_dg(int s, servtab_t *sep ATTRIBUTE_UNUSED)
     1657{
     1658    /* struct sockaddr_storage ss; */
     1659    struct sockaddr sa;
     1660    static char *rs;
     1661    int len;
     1662    char text[LINESIZ + 2];
     1663    socklen_t size;
     1664
     1665    if (endring == 0) {
     1666        initring();
     1667        rs = ring;
     1668    }
     1669
     1670    size = sizeof(sa);
     1671    if (recvfrom(s, text, sizeof(text), 0, &sa, &size) < 0)
     1672        return;
     1673    if (dg_badinput((struct sockaddr_in *) &sa))
     1674        return;
     1675
     1676    if ((len = endring - rs) >= LINESIZ)
     1677        memmove(text, rs, LINESIZ);
     1678    else {
     1679        memmove(text, rs, len);
     1680        memmove(text + len, ring, LINESIZ - len);
     1681    }
     1682    if (++rs == endring)
     1683        rs = ring;
     1684    text[LINESIZ] = '\r';
     1685    text[LINESIZ + 1] = '\n';
     1686    (void) sendto(s, text, sizeof(text), 0, &sa, sizeof(sa));
     1687}
     1688#endif /* FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN */
     1689
     1690
     1691#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_TIME
    17151692/*
    17161693 * Return a machine readable date and time, in the form of the
     
    17211698 */
    17221699
    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));
     1700static unsigned machtime(void)
     1701{
     1702    struct timeval tv;
     1703
     1704    if (gettimeofday(&tv, NULL) < 0) {
     1705        fprintf(stderr, "Unable to get time of day\n");
     1706        return 0L;
     1707    }
     1708    return htonl((unsigned) tv.tv_sec + 2208988800UL);
    17321709}
    17331710
    17341711/* ARGSUSED */
    17351712static 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));
     1713machtime_stream(int s, servtab_t *sep ATTRIBUTE_UNUSED)
     1714{
     1715    unsigned result;
     1716
     1717    result = machtime();
     1718    (void) write(s, (char *) &result, sizeof(result));
    17421719}
    17431720
    17441721/* ARGSUSED */
    17451722static 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
     1723machtime_dg(int s, servtab_t *sep ATTRIBUTE_UNUSED)
     1724{
     1725    unsigned result;
     1726    /* struct sockaddr_storage ss; */
     1727    struct sockaddr sa;
     1728    struct sockaddr_in *dg_sin;
     1729    socklen_t size;
     1730
     1731    size = sizeof(sa);
     1732    if (recvfrom(s, (char *) &result, sizeof(result), 0, &sa, &size) < 0)
     1733        return;
     1734    /* if (dg_badinput((struct sockaddr *)&ss)) */
     1735    dg_sin = (struct sockaddr_in *) &sa;
     1736    if (dg_sin->sin_addr.s_addr == htonl(INADDR_BROADCAST) ||
     1737            ntohs(dg_sin->sin_port) < IPPORT_RESERVED / 2)
     1738        return;
     1739    result = machtime();
     1740    (void) sendto(s, (char *) &result, sizeof(result), 0, &sa, sizeof(sa));
     1741}
     1742#endif /* FEATURE_INETD_SUPPORT_BUILTIN_TIME */
     1743
     1744
     1745#if ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME
    17691746/* Return human-readable time of day */
    17701747/* 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));
     1748static void daytime_stream(int s, servtab_t *sep ATTRIBUTE_UNUSED)
     1749{
     1750    char buffer[32];
     1751    time_t t;
     1752
     1753    t = time(NULL);
     1754
     1755// fdprintf instead?
     1756    (void) sprintf(buffer, "%.24s\r\n", ctime(&t));
     1757    (void) write(s, buffer, strlen(buffer));
    17801758}
    17811759
     
    17831761/* ARGSUSED */
    17841762void
    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: */
     1763daytime_dg(int s, servtab_t *sep ATTRIBUTE_UNUSED)
     1764{
     1765    char buffer[256];
     1766    time_t t;
     1767    /* struct sockaddr_storage ss; */
     1768    struct sockaddr sa;
     1769    socklen_t size;
     1770
     1771    t = time(NULL);
     1772
     1773    size = sizeof(sa);
     1774    if (recvfrom(s, buffer, sizeof(buffer), 0, &sa, &size) < 0)
     1775        return;
     1776    if (dg_badinput((struct sockaddr_in *) &sa))
     1777        return;
     1778    (void) sprintf(buffer, "%.24s\r\n", ctime(&t));
     1779    (void) sendto(s, buffer, strlen(buffer), 0, &sa, sizeof(sa));
     1780}
     1781#endif /* FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME */
Note: See TracChangeset for help on using the changeset viewer.