home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 35 Internet / 35-Internet.zip / inetd10.zip / INETD.C < prev    next >
Text File  |  1995-04-04  |  27KB  |  958 lines

  1. /*
  2.  * Copyright (c) 1983,1991 The Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Hacks for OS/2 by Jochen Friedrich <jochen@audio.pfalz.de>
  6.  *
  7.  * Redistribution and use in source and binary forms, with or without
  8.  * modification, are permitted provided that the following conditions
  9.  * are met:
  10.  * 1. Redistributions of source code must retain the above copyright
  11.  *    notice, this list of conditions and the following disclaimer.
  12.  * 2. Redistributions in binary form must reproduce the above copyright
  13.  *    notice, this list of conditions and the following disclaimer in the
  14.  *    documentation and/or other materials provided with the distribution.
  15.  * 3. All advertising materials mentioning features or use of this software
  16.  *    must display the following acknowledgement:
  17.  *      This product includes software developed by the University of
  18.  *      California, Berkeley and its contributors.
  19.  * 4. Neither the name of the University nor the names of its contributors
  20.  *    may be used to endorse or promote products derived from this software
  21.  *    without specific prior written permission.
  22.  *
  23.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  24.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  25.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  26.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  27.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  28.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  29.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  30.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  31.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  32.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  33.  * SUCH DAMAGE.
  34.  */
  35.  
  36. /*
  37.  * Inetd - Internet super-server
  38.  *
  39.  * This program invokes all internet services as needed.
  40.  * connection-oriented services are invoked each time a
  41.  * connection is made, by creating a process.  This process
  42.  * is passed the connection as file descriptor 0 and is
  43.  * expected to do a getpeername to find out the source host
  44.  * and port.
  45.  *
  46.  * Datagram oriented services are invoked when a datagram
  47.  * arrives; a process is created and passed a pending message
  48.  * on file descriptor 0.  Datagram servers may either connect
  49.  * to their peer, freeing up the original socket for inetd
  50.  * to receive further messages on, or ``take over the socket'',
  51.  * processing all arriving datagrams and, eventually, timing
  52.  * out.  The first type of server is said to be ``multi-threaded'';
  53.  * the second type of server ``single-threaded''. 
  54.  *
  55.  * Inetd uses a configuration file which is read at startup
  56.  * and, possibly, at some later time in response to a hangup signal.
  57.  * The configuration file is ``free format'' with fields given in the
  58.  * order shown below.  Continuation lines for an entry must being with
  59.  * a space or tab.  All fields must be present in each entry.
  60.  *
  61.  *      service name                    must be in /etc/services
  62.  *      socket type                     stream/dgram
  63.  *      protocol                        must be in /etc/protocols
  64.  *      wait/nowait                     single-threaded/multi-threaded
  65.  *      user                            user to run daemon as
  66.  *      server program                  full path name
  67.  *      server program arguments        maximum of MAXARGS (20)
  68.  *
  69.  * Comment lines are indicated by a `#' in column 1.
  70.  */
  71.  
  72. #define INCL_DOS
  73. #define INCL_BASE
  74. #define INCL_DOSEXCEPTIONS
  75. #include <os2.h>
  76. #include <malloc.h>
  77. #include <sys/stat.h>
  78. #include <sys/socket.h>
  79. #include <sys/time.h>
  80. #include <netinet/in.h>
  81. #include <errno.h>
  82. #include <nerrno.h>
  83. #include <direct.h>
  84. #include <process.h>
  85. #include <signal.h>
  86. #include <stdio.h>
  87. #include <stdlib.h>
  88. #include <string.h>
  89. #include <netdb.h>
  90. #include <types.h>
  91.  
  92. #include "syslog.h"
  93. #include "pwd.h"
  94. #include "fix_env.h"
  95.  
  96. #define TOOMANY         40              /* don't start more than TOOMANY */
  97. #define CNT_INTVL       60              /* servers in CNT_INTVL sec. */
  98. #define RETRYTIME       (60*10)         /* retry after bind or server fail */
  99. #define MAXSOCK         256
  100.  
  101. void    config(int);
  102. void    reapchild(void *);
  103. void    retry(void *);
  104. struct  servtab *getconfigent(void);
  105. struct  servtab *enter(struct servtab *);
  106. void    echo_stream(int*);
  107. void    discard_stream(int*);
  108. void    machtime_stream(int*);
  109. void    daytime_stream(int*);
  110. void    chargen_stream(int*);
  111. void    echo_dg(int*);
  112. void    discard_dg(int*);
  113. void    machtime_dg(int*);
  114. void    daytime_dg(int*);
  115. void    chargen_dg(int*);
  116. void    setup(struct servtab *);
  117. char    *skip(char **);
  118. char    *nextline(FILE *);
  119. void    endconfig(void);
  120. void    freeconfig(struct servtab *);
  121. void    print_service(char *, struct servtab *);
  122. int     fd_isset(int, int *, int);
  123. void    fd_set(int, int *, int *);
  124. void    fd_clr(int, int *, int *);
  125.  
  126. int     retrytime = RETRYTIME;
  127. int     debug = 0;
  128. int     nsock, maxsock;
  129. int     allsock[MAXSOCK];
  130. int     options;
  131. int     timingout;
  132. int     cansock;
  133. int     reapthread;
  134. ULONG   reapsem;
  135. struct  servent *sp;
  136. char    userenv[1024];
  137.  
  138. struct  servtab {
  139.         char    *se_service;            /* name of service */
  140.         int     se_socktype;            /* type of socket to use */
  141.         char    *se_proto;              /* protocol used */
  142.         short   se_wait;                /* single threaded server */
  143.         short   se_checked;             /* looked at during merge */
  144.         char    *se_user;               /* user name to run as */
  145.         struct  biltin *se_bi;          /* if built-in, description */
  146.         char    *se_server;             /* server program */
  147. #define MAXARGV 20
  148.         char    *se_argv[MAXARGV+1];    /* program arguments */
  149.         int     se_fd;                  /* open descriptor */
  150.         int     se_sock;                /* descriptor for stream */
  151.         struct  sockaddr_in se_ctrladdr;/* bound address */
  152.         int     se_count;               /* number started since se_time */
  153.         struct  timeval se_time;        /* start of se_count */
  154.         struct  servtab *se_next;
  155. } *servtab;
  156.  
  157. struct biltin {
  158.         char    *bi_service;            /* internally provided service name */
  159.         int     bi_socktype;            /* type of socket supported */
  160.         short   bi_fork;                /* 1 if should fork before call */
  161.         short   bi_wait;                /* 1 if should wait for child */
  162.         void    (* _Optlink bi_fn)(int*); /* function which performs it */
  163. } biltins[] = {
  164.         /* Echo received data */
  165.         "echo",         SOCK_STREAM,    1, 0,   echo_stream,
  166.         "echo",         SOCK_DGRAM,     0, 0,   echo_dg,
  167.  
  168.         /* Internet /dev/null */
  169.         "discard",      SOCK_STREAM,    1, 0,   discard_stream,
  170.         "discard",      SOCK_DGRAM,     0, 0,   discard_dg,
  171.  
  172.         /* Return 32 bit time since 1970 */
  173.         "time",         SOCK_STREAM,    0, 0,   machtime_stream,
  174.         "time",         SOCK_DGRAM,     0, 0,   machtime_dg,
  175.  
  176.         /* Return human-readable time */
  177.         "daytime",      SOCK_STREAM,    0, 0,   daytime_stream,
  178.         "daytime",      SOCK_DGRAM,     0, 0,   daytime_dg,
  179.  
  180.         /* Familiar character generator */
  181.         "chargen",      SOCK_STREAM,    1, 0,   chargen_stream,
  182.         "chargen",      SOCK_DGRAM,     0, 0,   chargen_dg,
  183.         0
  184. };
  185.  
  186. #define NUMINT  (sizeof(intab) / sizeof(struct inent))
  187. char    CONFIG[255] = "c:\\etc\\inetd.cnf";
  188. char    **Argv;
  189. char    *LastArg;
  190.  
  191. int main(int argc, char *argv[], char *envp[])
  192. {
  193.   extern char *optarg;
  194.   extern int optind;
  195.   register struct servtab *sep;
  196.   register int tmpint;
  197.   int ch, pid, dofork;
  198.   char buf[50];
  199.   char *wdir;
  200.   struct passwd *pass;
  201.  
  202.   if (sock_init()) {
  203.     fprintf(stderr,"Can't initialize TCP/IP");
  204.     exit(-1);
  205.   }
  206.   if (!(cansock = socket(AF_INET, SOCK_STREAM, 0))) {
  207.     fprintf(stderr,"Can't open sync socket");
  208.     exit(-1);
  209.   }
  210.   fix_env(CONFIG,"ETC");
  211.   Argv = argv;
  212.   if (envp == 0 || *envp == 0)
  213.     envp = argv;
  214.   while (*envp)
  215.     envp++;
  216.   LastArg = envp[-1] + strlen(envp[-1]);
  217.  
  218.   while ((ch = getopt(argc, argv, "d")) != EOF)
  219.     switch(ch) {
  220.       case 'd':
  221.         debug = 1;
  222.         options |= SO_DEBUG;
  223.         break;
  224.       case '?':
  225.       default:
  226.         fprintf(stderr, "usage: inetd [-d]");
  227.         exit(1);
  228.     }
  229.   argc -= optind;
  230.   argv += optind;
  231.  
  232.   if (argc > 0)
  233.     strcpy(CONFIG,argv[0]);
  234.   openlog("inetd", LOG_PID | LOG_NOWAIT, LOG_DAEMON);
  235.   config(0);
  236.   if (DosCreateEventSem(NULL, &reapsem, 0L, FALSE)) {
  237.     fprintf(stderr,"Can't create semaphore");
  238.     exit(-1);
  239.   }
  240.   if (!( reapthread = _beginthread(reapchild, NULL, 8192, NULL))) {
  241.     fprintf(stderr,"Can't create thread for reap");
  242.     exit(-1);
  243.   }
  244.   for (;;) {
  245.     int n;
  246.     int readable[257];
  247.  
  248.     for(n=0;n<nsock;n++) readable[n] = allsock[n];
  249.     readable[nsock]=cansock;
  250.     if (debug)
  251.       fprintf(stderr, "enter select with %d sockets\n",nsock);
  252.     if ((n = select(readable, nsock, 0, 1, -1L)) <= 0) {
  253.       errno = sock_errno();
  254.       if (n < 0 && errno != SOCEINTR) {
  255.         syslog(LOG_WARNING, "select: %m\n");
  256.         DosSleep(1000);
  257.       }
  258.       continue;
  259.     }
  260.     for (sep = servtab; n && sep; sep = sep->se_next) {
  261.       if (sep->se_fd != -1 && fd_isset(sep->se_fd, readable, nsock)) {
  262.         n--;
  263.         if (debug)
  264.           fprintf(stderr, "someone wants %s\n",
  265.                   sep->se_service);
  266.         if (sep->se_socktype == SOCK_STREAM) {
  267.           sep->se_sock = accept(sep->se_fd, (struct sockaddr *)0,
  268.                         (int *)0);
  269.           errno = sock_errno();
  270.           if (debug)
  271.             fprintf(stderr, "accept, socket %d\n", sep->se_sock);
  272.           if (sep->se_sock < 0) {
  273.             if (errno == SOCEINTR)
  274.               continue;
  275.             syslog(LOG_WARNING, "accept (for %s): %m",
  276.                    sep->se_service);
  277.             continue;
  278.           }
  279.         } else
  280.           sep->se_sock = sep->se_fd;
  281.         dofork = (sep->se_bi == 0 || sep->se_bi->bi_fork);
  282.         if (dofork) {
  283.           if (sep->se_count++ == 0)
  284.             gettimeofday(&sep->se_time,
  285.                          (struct timezone *)0);
  286.           else if (sep->se_count >= TOOMANY) {
  287.             struct timeval now;
  288.             gettimeofday(&now, (struct timezone *)0);
  289.             if (now.tv_sec - sep->se_time.tv_sec >
  290.                 CNT_INTVL) {
  291.               sep->se_time = now;
  292.               sep->se_count = 1;
  293.             } else {
  294.               syslog(LOG_ERR,
  295.                      "%s/%s server failing (looping), service terminated\n",
  296.                      sep->se_service, sep->se_proto);
  297.               fd_clr(sep->se_fd, allsock, &nsock);
  298.               soclose(sep->se_fd);
  299.               sep->se_fd = -1;
  300.               sep->se_count = 0;
  301.               if (!timingout) {
  302.                 timingout = 1;
  303.                 _beginthread(retry,NULL,32768,&retrytime);
  304.               }
  305.             }
  306.           }
  307.         }
  308.         pid=0;
  309.         if (sep->se_bi) {
  310.           int *ctrl;
  311.           ctrl=malloc(sizeof(int));
  312.           *ctrl=sep->se_sock;
  313.           if (dofork)
  314.             _beginthread( (void(*)(void*)) (sep->se_bi->bi_fn),NULL,32768,ctrl);
  315.           else
  316.             (*sep->se_bi->bi_fn)(ctrl);
  317.           }
  318.         else {
  319.           char* argv[MAXARGV+1];
  320.           int i;
  321.           char socknum[10];
  322.  
  323.           sprintf(socknum,"%d",sep->se_sock);
  324.  
  325.           if (debug)
  326.             fprintf(stderr, "%d execl %s\n",
  327.           getpid(), sep->se_server);
  328.  
  329.           for (i=0;i<=MAXARGV;i++)
  330.             if ((sep->se_argv[i])&&(strcmp(sep->se_argv[i],"%s")==0))
  331.               argv[i]=socknum;
  332.             else
  333.               argv[i]=sep->se_argv[i];
  334.           DosSuspendThread(reapthread);
  335.           sprintf(userenv,"LOGNAME=%s",sep->se_user);
  336.           putenv(userenv);
  337.  
  338.           if ((wdir = getenv("ETC")) == NULL) wdir = "c:\\etc";
  339.           pass = getpwnam(sep->se_user);
  340.           if (pass && pass->pw_dir) wdir = pass->pw_dir;
  341.  
  342.           chdir(wdir);
  343.           if (wdir[1] == ':')
  344.             _chdrive(toupper(wdir[0])-'A'+1);
  345.  
  346.           pid=spawnvp(P_NOWAIT, sep->se_server, argv);
  347.           if (pid) {
  348.             removesocketfromlist(sep->se_sock);
  349.             DosPostEventSem(reapsem);
  350.           }
  351.           if (pid && sep->se_wait) {
  352.             sep->se_wait = pid;
  353.             if (sep->se_fd >=0) {
  354.               fd_clr(sep->se_fd, allsock, &nsock);
  355.             }
  356.           }
  357.           DosResumeThread(reapthread);
  358.         }
  359.       }
  360.     }
  361.   }
  362. }
  363.  
  364. int     fd_isset(int sock, int arr[], int nsock)
  365. {
  366.   int i=0;
  367.  
  368.   while((i < nsock) && (arr[i]!=sock) && (i<MAXSOCK)) i++;
  369.   if (i==MAXSOCK) return 0;
  370.   if (i== nsock) return 0;
  371.   return 1;
  372. }
  373.  
  374. void    fd_set(int sock, int arr[], int *nsock)
  375. {
  376.   int i=0;
  377.  
  378.   if (*nsock>=MAXSOCK) return;
  379.   while((i < *nsock) && (arr[i]!=sock)) i++;
  380.   if (i!= *nsock) return;
  381.   arr[*nsock]=sock;  
  382.   (*nsock)++;
  383. }
  384.  
  385. void    fd_clr(int sock, int arr[], int *nsock)
  386. {
  387.   int i=0;
  388.  
  389.   if (*nsock==0) return;
  390.   while((i < *nsock) && (arr[i]!=sock) && (i<256)) i++;
  391.   if (i==256) return;
  392.   if (i == *nsock) return;
  393.   (*nsock)--;
  394.   while (i< *nsock)
  395.   {
  396.     arr[i]=arr[i+1];
  397.     i++;
  398.   }  
  399. }  
  400.  
  401. void reapchild(void *dummy)
  402. {
  403.   ULONG pid;
  404.   ULONG cnt;
  405.   RESULTCODES result;
  406.   register struct servtab *sep;
  407.  
  408.   while(1) {
  409.     cnt = DosWaitChild(DCWA_PROCESS, DCWW_WAIT, &result, &pid, 0);
  410.     if (cnt) {
  411.       if (cnt == ERROR_WAIT_NO_CHILDREN) {
  412.         DosWaitEventSem(reapsem, -1L);
  413.         DosResetEventSem(reapsem,&cnt);
  414.       } else syslog(LOG_WARNING, "wait result 0x%x", errno);
  415.     } else {
  416.       if (debug)
  417.         fprintf(stderr, "%d reaped\n", pid);
  418.       for (sep = servtab; sep; sep = sep->se_next)
  419.         if (sep->se_wait == pid) {
  420.           if (result.codeResult)
  421.             syslog(LOG_WARNING,
  422.               "%s: exit status 0x%x",
  423.               sep->se_server, result.codeResult);
  424.           if (result.codeTerminate)
  425.             syslog(LOG_WARNING,
  426.               "%s: exit termination 0x%x",
  427.               sep->se_server, result.codeTerminate);
  428.           if (debug)
  429.             fprintf(stderr, "restored %s, fd %d\n",
  430.               sep->se_service, sep->se_fd);
  431.           fd_set(sep->se_fd,allsock, &nsock);
  432.           sep->se_wait = 1;
  433.           if (sep->se_socktype==SOCK_STREAM) {
  434.             so_cancel(sep->se_sock);
  435.             soclose(sep->se_sock);
  436.           }
  437.           so_cancel(cansock);
  438.         }
  439.     }
  440.   }
  441. }
  442.  
  443. void config(int x)
  444. {
  445.   register struct servtab *sep, *cp, **sepp;
  446.  
  447.   if (!setconfig()) {
  448.     syslog(LOG_ERR, "%s: %m", CONFIG);
  449.     return;
  450.   }
  451.   for (sep = servtab; sep; sep = sep->se_next)
  452.     sep->se_checked = 0;
  453.   while (cp = getconfigent()) {
  454.     for (sep = servtab; sep; sep = sep->se_next)
  455.       if (strcmp(sep->se_service, cp->se_service) == 0 &&
  456.         strcmp(sep->se_proto, cp->se_proto) == 0 &&
  457.         (sep->se_socktype==cp->se_socktype))
  458.         break;
  459.     if (sep != 0) {
  460.       int i;
  461.  
  462.       /*
  463.        * sep->se_wait may be holding the pid of a daemon
  464.        * that we're waiting for.  If so, don't overwrite
  465.        * it unless the config file explicitly says don't 
  466.        * wait.
  467.        */
  468.       if (cp->se_bi == 0 && 
  469.         (sep->se_wait == 1 || cp->se_wait == 0))
  470.         sep->se_wait = cp->se_wait;
  471. #define SWAP(a, b) { char *c = a; a = b; b = c; }
  472.       if (cp->se_user)
  473.         SWAP(sep->se_user, cp->se_user);
  474.       if (cp->se_server)
  475.         SWAP(sep->se_server, cp->se_server);
  476.       for (i = 0; i < MAXARGV; i++)
  477.         SWAP(sep->se_argv[i], cp->se_argv[i]);
  478.       freeconfig(cp);
  479.       if (debug)
  480.         print_service("REDO", sep);
  481.     } else {
  482.       sep = enter(cp);
  483.       if (debug)
  484.         print_service("ADD ", sep);
  485.     }
  486.     sep->se_checked = 1;
  487.     sp = getservbyname(sep->se_service, sep->se_proto);
  488.     if (sp == 0) {
  489.       syslog(LOG_ERR, "%s/%s: unknown service",
  490.         sep->se_service, sep->se_proto);
  491.       if (sep->se_fd != -1)
  492.         soclose(sep->se_fd);
  493.       sep->se_fd = -1;
  494.       continue;
  495.     }
  496.     if (sp->s_port != sep->se_ctrladdr.sin_port) {
  497.       bzero(&sep->se_ctrladdr, sizeof(struct sockaddr_in));
  498.       sep->se_ctrladdr.sin_family = AF_INET;
  499.       sep->se_ctrladdr.sin_port = sp->s_port;
  500.       if (sep->se_fd != -1)
  501.         soclose(sep->se_fd);
  502.       sep->se_fd = -1;
  503.     }
  504.     if (sep->se_fd == -1)
  505.       setup(sep);
  506.   }
  507.   endconfig();
  508.   /*
  509.    * Purge anything not looked at above.
  510.    */
  511.   sepp = &servtab;
  512.   while (sep = *sepp) {
  513.     if (sep->se_checked) {
  514.       sepp = &sep->se_next;
  515.       continue;
  516.     }
  517.     *sepp = sep->se_next;
  518.     if (sep->se_fd != -1) {
  519.       fd_clr(sep->se_fd,allsock, &nsock);
  520.       soclose(sep->se_fd);
  521.     }
  522.     if (debug)
  523.       print_service("FREE", sep);
  524.     freeconfig(sep);
  525.     free((char *)sep);
  526.   }
  527.   signal(SIGINT, config);
  528. }
  529.  
  530. void retry(void *time)
  531. {
  532.   register struct servtab *sep;
  533.  
  534.   DosSleep( (* (int*) time) * 1000);
  535.   for (sep = servtab; sep; sep = sep->se_next)
  536.     if (sep->se_fd == -1)
  537.       setup(sep);
  538.   timingout = 0;
  539. }
  540.  
  541. void setup(struct servtab *sep)
  542. {
  543.   int on = 1;
  544.  
  545.   if ((sep->se_fd = socket(AF_INET, sep->se_socktype, 0)) < 0) {
  546.     errno = sock_errno();
  547.     syslog(LOG_ERR, "%s/%s: socket: %m",
  548.     sep->se_service, sep->se_proto);
  549.     return;
  550.   }
  551. #define turnon(fd, opt) \
  552. setsockopt(fd, SOL_SOCKET, opt, (char *)&on, sizeof (on))
  553.   if (strcmp(sep->se_proto, "tcp") == 0 && (options & SO_DEBUG) &&
  554.     turnon(sep->se_fd, SO_DEBUG) < 0)
  555.     syslog(LOG_ERR, "setsockopt (SO_DEBUG): %m");
  556.   if (turnon(sep->se_fd, SO_REUSEADDR) < 0)
  557.     syslog(LOG_ERR, "setsockopt (SO_REUSEADDR): %m");
  558. #undef turnon
  559.   if (bind(sep->se_fd, (struct sockaddr *)&sep->se_ctrladdr,
  560.     sizeof (sep->se_ctrladdr)) < 0) {
  561.     errno = sock_errno();
  562.     syslog(LOG_ERR, "%s/%s: bind: %m",
  563.     sep->se_service, sep->se_proto);
  564.     soclose(sep->se_fd);
  565.     sep->se_fd = -1;
  566.     if (!timingout) {
  567.       timingout = 1;
  568.       _beginthread(retry,NULL,8192,&retrytime);
  569.     }
  570.     return;
  571.   }
  572.   if (sep->se_socktype == SOCK_STREAM)
  573.     listen(sep->se_fd, 10);
  574.   fd_set(sep->se_fd, allsock, &nsock);
  575.     if (sep->se_fd > maxsock)
  576.   maxsock = sep->se_fd;
  577. }
  578.  
  579. struct servtab *enter(struct servtab *cp)
  580. {
  581.   register struct servtab *sep;
  582.  
  583.   sep = (struct servtab *)malloc(sizeof (*sep));
  584.   if (sep == (struct servtab *)0) {
  585.     syslog(LOG_ERR, "Out of memory.");
  586.     exit(-1);
  587.   }
  588.   *sep = *cp;
  589.   sep->se_fd = -1;
  590.   sep->se_next = servtab;
  591.   servtab = sep;
  592.   return (sep);
  593. }
  594.  
  595. FILE    *fconfig = NULL;
  596. struct  servtab serv;
  597. char    line[256];
  598.  
  599. int setconfig(void)
  600. {
  601.  
  602.   if (fconfig != NULL) {
  603.     fseek(fconfig, 0L, 0);
  604.     return (1);
  605.   }
  606.   fconfig = fopen(CONFIG, "r");
  607.   return (fconfig != NULL);
  608. }
  609.  
  610. void endconfig(void)
  611. {
  612.   if (fconfig) {
  613.     (void) fclose(fconfig);
  614.     fconfig = NULL;
  615.   }
  616. }
  617.  
  618. struct servtab * getconfigent(void)
  619. {
  620.   register struct servtab *sep = &serv;
  621.   int argc;
  622.   char *cp, *arg, *newstr();
  623.  
  624. more:
  625.   while ((cp = nextline(fconfig)) && *cp == '#')
  626.     ;
  627.   if (cp == NULL)
  628.     return ((struct servtab *)0);
  629.   sep->se_service = newstr(skip(&cp));
  630.   arg = newstr(skip(&cp));
  631.   if (strcmp(arg, "stream") == 0)
  632.     sep->se_socktype = SOCK_STREAM;
  633.   else if (strcmp(arg, "dgram") == 0)
  634.     sep->se_socktype = SOCK_DGRAM;
  635.   else
  636.     sep->se_socktype = -1;
  637.   free(arg);
  638.   sep->se_proto = newstr(skip(&cp));
  639.   arg = newstr(skip(&cp));
  640.   sep->se_wait = strcmp(arg, "wait") == 0;
  641.   free(arg);
  642.   sep->se_user = newstr(skip(&cp));
  643.   sep->se_server = newstr(skip(&cp));
  644.   if (strcmp(sep->se_server, "internal") == 0) {
  645.     register struct biltin *bi;
  646.  
  647.     for (bi = biltins; bi->bi_service; bi++)
  648.       if (bi->bi_socktype == sep->se_socktype &&
  649.         strcmp(bi->bi_service, sep->se_service) == 0)
  650.         break;
  651.     if (bi->bi_service == 0) {
  652.       syslog(LOG_ERR, "internal service %s unknown\n",
  653.         sep->se_service);
  654.       goto more;
  655.     }
  656.     sep->se_bi = bi;
  657.     sep->se_wait = bi->bi_wait;
  658.   } else
  659.     sep->se_bi = NULL;
  660.  
  661.   sep->se_argv[0]=newstr(sep->se_server);
  662.   sep->se_argv[1]=newstr("            ");
  663.   argc = 1;
  664.   for (arg = skip(&cp); cp; arg = skip(&cp))
  665.     if (argc < MAXARGV)
  666.       sep->se_argv[argc++] = newstr(arg);
  667.   while (argc <= MAXARGV)
  668.     sep->se_argv[argc++] = NULL;
  669.   return (sep);
  670. }
  671.  
  672. void freeconfig(struct servtab *cp)
  673. {
  674.   int i;
  675.  
  676.   if (cp->se_service)
  677.     free(cp->se_service);
  678.   if (cp->se_proto)
  679.     free(cp->se_proto);
  680.   if (cp->se_user)
  681.     free(cp->se_user);
  682.   if (cp->se_server)
  683.     free(cp->se_server);
  684.   for (i = 0; i < MAXARGV; i++)
  685.     if (cp->se_argv[i])
  686.       free(cp->se_argv[i]);
  687. }
  688.  
  689. char * skip(char **cpp)
  690. {
  691.   register char *cp = *cpp;
  692.   char *start;
  693.  
  694.   if (cp==(char *) 0) return cp;
  695. again:
  696.   while (*cp == ' ' || *cp == '\t')
  697.     cp++;
  698.   if (*cp == '\0') {
  699.     int c;
  700.  
  701.     c = getc(fconfig);
  702.     (void) ungetc(c, fconfig);
  703.     if (c == ' ' || c == '\t')
  704.       if (cp = nextline(fconfig))
  705.         goto again;
  706.     *cpp = (char *)0;
  707.     return ((char *)0);
  708.   }
  709.   start = cp;
  710.   while (*cp && *cp != ' ' && *cp != '\t')
  711.     cp++;
  712.   if (*cp != '\0')
  713.     *cp++ = '\0';
  714.   *cpp = cp;
  715.   return (start);
  716. }
  717.  
  718. char * nextline(FILE *fd)
  719. {
  720.   char *cp;
  721.  
  722.   if (fgets(line, sizeof (line), fd) == NULL)
  723.     return ((char *)0);
  724.   cp = index(line, '\n');
  725.   if (cp)
  726.     *cp = '\0';
  727.   return (line);
  728. }
  729.  
  730. char * newstr(char *cp)
  731. {
  732.   if (cp = strdup(cp ? cp : ""))
  733.     return(cp);
  734.   syslog(LOG_ERR, "strdup: %m");
  735.   exit(-1);
  736. }
  737.  
  738. /*
  739.  * Internet services provided internally by inetd:
  740.  */
  741. #define BUFSIZE 8192
  742.  
  743. void echo_stream(int *s) /* Echo service -- echo data back */
  744. {
  745.   char buffer[BUFSIZE];
  746.   int i;
  747.  
  748.   while ((i = recv(*s, buffer, sizeof(buffer),0)) > 0 &&
  749.     send(*s, buffer, i, 0) > 0)
  750.     ;
  751.   so_cancel(*s);
  752.   soclose(*s);
  753.   free(s);
  754. }
  755.  
  756. void echo_dg(int *s) /* Echo service -- echo data back */
  757. {
  758.   char buffer[BUFSIZE];
  759.   int i, size;
  760.   struct sockaddr sa;
  761.  
  762.   size = sizeof(sa);
  763.   if ((i = recvfrom(*s, buffer, sizeof(buffer), 0, &sa, &size)) < 0)
  764.     return;
  765.   sendto(*s, buffer, i, 0, &sa, sizeof(sa));
  766.   free(s);
  767. }
  768.  
  769. void discard_stream(int *s) /* Discard service -- ignore data */
  770. {
  771.   int ret;
  772.   char buffer[BUFSIZE];
  773.  
  774.   while (1) {
  775.     while ((ret = recv(*s, buffer, sizeof(buffer),0)) > 0)
  776.       ;
  777.     errno = sock_errno();
  778.     if (ret == 0 || errno != SOCEINTR)
  779.       break;
  780.   }
  781.   so_cancel(*s);
  782.   soclose(*s);
  783.   free(s);
  784. }
  785.  
  786. void discard_dg(int *s) /* Discard service -- ignore data */
  787. {
  788.   char buffer[BUFSIZE];
  789.  
  790.   recv(*s, buffer, sizeof(buffer),0);
  791.   free(s);
  792. }
  793.  
  794. #include <ctype.h>
  795. #define LINESIZ 72
  796. char ring[128];
  797. char *endring;
  798.  
  799. void initring(void)
  800. {
  801.   register int i;
  802.  
  803.   endring = ring;
  804.  
  805.   for (i = 0; i <= 128; ++i)
  806.     if (isprint(i))
  807.       *endring++ = i;
  808. }
  809.  
  810. void chargen_stream(int *s) /* Character generator */
  811. {
  812.   register char *rs;
  813.   int len;
  814.   char text[LINESIZ+2];
  815.  
  816.   if (!endring) {
  817.     initring();
  818.     rs = ring;
  819.   }
  820.  
  821.   text[LINESIZ] = '\r';
  822.   text[LINESIZ + 1] = '\n';
  823.   for (rs = ring;;) {
  824.     if ((len = endring - rs) >= LINESIZ)
  825.       bcopy(rs, text, LINESIZ);
  826.     else {
  827.       bcopy(rs, text, len);
  828.       bcopy(ring, text + len, LINESIZ - len);
  829.     }
  830.     if (++rs == endring)
  831.       rs = ring;
  832.     if (send(*s, text, sizeof(text),0) != sizeof(text))
  833.       break;
  834.   }
  835.   so_cancel(*s);
  836.   soclose(*s);
  837.   free(s);
  838. }
  839.  
  840. void chargen_dg(int *s) /* Character generator */
  841. {
  842.   struct sockaddr sa;
  843.   static char *rs;
  844.   int len, size;
  845.   char text[LINESIZ+2];
  846.  
  847.   if (endring == 0) {
  848.     initring();
  849.     rs = ring;
  850.   }
  851.  
  852.   size = sizeof(sa);
  853.   if (recvfrom(*s, text, sizeof(text), 0, &sa, &size) < 0)
  854.     return;
  855.  
  856.   if ((len = endring - rs) >= LINESIZ)
  857.     bcopy(rs, text, LINESIZ);
  858.   else {
  859.     bcopy(rs, text, len);
  860.     bcopy(ring, text + len, LINESIZ - len);
  861.   }
  862.   if (++rs == endring)
  863.     rs = ring;
  864.   text[LINESIZ] = '\r';
  865.   text[LINESIZ + 1] = '\n';
  866.   sendto(*s, text, sizeof(text), 0, &sa, sizeof(sa));
  867.   free(s);
  868. }
  869.  
  870. /*
  871.  * Return a machine readable date and time, in the form of the
  872.  * number of seconds since midnight, Jan 1, 1900.  Since gettimeofday
  873.  * returns the number of seconds since midnight, Jan 1, 1970,
  874.  * we must add 2208988800 seconds to this figure to make up for
  875.  * some seventy years Bell Labs was asleep.
  876.  */
  877.  
  878. long machtime(void)
  879. {
  880.   struct timeval tv;
  881.  
  882.   if (gettimeofday(&tv, (struct timezone *)0) < 0) {
  883.     syslog(LOG_ERR, "Unable to get time of day");
  884.     return (0L);
  885.   }
  886.   return (htonl((long)tv.tv_sec + 2208988800));
  887. }
  888.  
  889. void machtime_stream(int *s)
  890. {
  891.   long result;
  892.  
  893.   result = machtime();
  894.   send(*s, (char *) &result, sizeof(result),0);
  895.   so_cancel(*s);
  896.   soclose(*s);
  897.   free(s);
  898. }
  899.  
  900. void machtime_dg(int *s)
  901. {
  902.   long result;
  903.   struct sockaddr sa;
  904.   int size;
  905.  
  906.   size = sizeof(sa);
  907.   if (recvfrom(*s, (char *)&result, sizeof(result), 0, &sa, &size) < 0)
  908.     return;
  909.   result = machtime();
  910.   sendto(*s, (char *) &result, sizeof(result), 0, &sa, sizeof(sa));
  911.   free(s);
  912. }
  913.  
  914. void daytime_stream(int *s) /* Return human-readable time of day */
  915. {
  916.   char buffer[256];
  917.   time_t time(), clock;
  918.   char *ctime();
  919.  
  920.   clock = time((time_t *) 0);
  921.  
  922.   sprintf(buffer, "%.24s\r\n", ctime(&clock));
  923.   send(*s, buffer, strlen(buffer),0);
  924.   so_cancel(*s);
  925.   soclose(*s);
  926.   free(s);
  927. }
  928.  
  929. void daytime_dg(int *s) /* Return human-readable time of day */
  930. {
  931.   char buffer[256];
  932.   time_t time(), clock;
  933.   struct sockaddr sa;
  934.   int size;
  935.   char *ctime();
  936.  
  937.   clock = time((time_t *) 0);
  938.  
  939.   size = sizeof(sa);
  940.   if (recvfrom(*s, buffer, sizeof(buffer), 0, &sa, &size) < 0)
  941.     return;
  942.   sprintf(buffer, "%.24s\r\n", ctime(&clock));
  943.   sendto(*s, buffer, strlen(buffer), 0, &sa, sizeof(sa));
  944.   free(s);
  945. }
  946.  
  947. /*
  948.  * print_service:
  949.  *      Dump relevant information to stderr
  950.  */
  951. void print_service(char *action, struct servtab *sep)
  952. {
  953.   fprintf(stderr,
  954.     "%s: %s proto=%s, wait=%d, user=%s builtin=%x server=%s\n",
  955.     action, sep->se_service, sep->se_proto,
  956.     sep->se_wait, sep->se_user, (int)sep->se_bi, sep->se_server);
  957. }
  958.