home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 4: GNU Archives / Linux Cubed Series 4 - GNU Archives.iso / gnu / inetutil.1 / inetutil / inetutils-1.1 / inetd / inetd.c < prev    next >
Encoding:
C/C++ Source or Header  |  1996-07-27  |  29.2 KB  |  1,265 lines

  1. /*
  2.  * Copyright (c) 1983, 1991, 1993, 1994
  3.  *    The Regents of the University of California.  All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer.
  10.  * 2. Redistributions in binary form must reproduce the above copyright
  11.  *    notice, this list of conditions and the following disclaimer in the
  12.  *    documentation and/or other materials provided with the distribution.
  13.  * 3. All advertising materials mentioning features or use of this software
  14.  *    must display the following acknowledgement:
  15.  *    This product includes software developed by the University of
  16.  *    California, Berkeley and its contributors.
  17.  * 4. Neither the name of the University nor the names of its contributors
  18.  *    may be used to endorse or promote products derived from this software
  19.  *    without specific prior written permission.
  20.  *
  21.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  22.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  25.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31.  * SUCH DAMAGE.
  32.  */
  33.  
  34. #ifndef lint
  35. static char copyright[] =
  36. "@(#) Copyright (c) 1983, 1991, 1993, 1994\n\
  37.     The Regents of the University of California.  All rights reserved.\n";
  38. #endif /* not lint */
  39.  
  40. #ifndef lint
  41. static char sccsid[] = "@(#)inetd.c    8.4 (Berkeley) 4/13/94";
  42. #endif /* not lint */
  43.  
  44. /*
  45.  * Inetd - Internet super-server
  46.  *
  47.  * This program invokes all internet services as needed.  Connection-oriented
  48.  * services are invoked each time a connection is made, by creating a process.
  49.  * This process is passed the connection as file descriptor 0 and is expected
  50.  * to do a getpeername to find out the source host and port.
  51.  *
  52.  * Datagram oriented services are invoked when a datagram
  53.  * arrives; a process is created and passed a pending message
  54.  * on file descriptor 0.  Datagram servers may either connect
  55.  * to their peer, freeing up the original socket for inetd
  56.  * to receive further messages on, or ``take over the socket'',
  57.  * processing all arriving datagrams and, eventually, timing
  58.  * out.     The first type of server is said to be ``multi-threaded'';
  59.  * the second type of server ``single-threaded''. 
  60.  *
  61.  * Inetd uses a configuration file which is read at startup
  62.  * and, possibly, at some later time in response to a hangup signal.
  63.  * The configuration file is ``free format'' with fields given in the
  64.  * order shown below.  Continuation lines for an entry must being with
  65.  * a space or tab.  All fields must be present in each entry.
  66.  *
  67.  *    service name            must be in /etc/services or must
  68.  *                    name a tcpmux service
  69.  *    socket type            stream/dgram/raw/rdm/seqpacket
  70.  *    protocol            must be in /etc/protocols
  71.  *    wait/nowait            single-threaded/multi-threaded
  72.  *    user                user to run daemon as
  73.  *    server program            full path name
  74.  *    server program arguments    maximum of MAXARGS (20)
  75.  *
  76.  * TCP services without official port numbers are handled with the
  77.  * RFC1078-based tcpmux internal service. Tcpmux listens on port 1 for
  78.  * requests. When a connection is made from a foreign host, the service
  79.  * requested is passed to tcpmux, which looks it up in the servtab list
  80.  * and returns the proper entry for the service. Tcpmux returns a
  81.  * negative reply if the service doesn't exist, otherwise the invoked
  82.  * server is expected to return the positive reply if the service type in
  83.  * inetd.conf file has the prefix "tcpmux/". If the service type has the
  84.  * prefix "tcpmux/+", tcpmux will return the positive reply for the
  85.  * process; this is for compatibility with older server code, and also
  86.  * allows you to invoke programs that use stdin/stdout without putting any
  87.  * special server code in them. Services that use tcpmux are "nowait"
  88.  * because they do not have a well-known port and hence cannot listen
  89.  * for new requests.
  90.  *
  91.  * Comment lines are indicated by a `#' in column 1.
  92.  */
  93.  
  94. #ifdef HAVE_CONFIG_H
  95. #include <config.h>
  96. #endif
  97.  
  98. #include <sys/param.h>
  99. #include <sys/stat.h>
  100. #include <sys/ioctl.h>
  101. #include <sys/socket.h>
  102. #include <sys/wait.h>
  103. #include <sys/time.h>
  104. #include <sys/resource.h>
  105.  
  106. #include <netinet/in.h>
  107. #include <arpa/inet.h>
  108.  
  109. #include <errno.h>
  110. #include <fcntl.h>
  111. #include <netdb.h>
  112. #include <pwd.h>
  113. #include <signal.h>
  114. #include <stdio.h>
  115. #include <stdlib.h>
  116. #include <string.h>
  117. #include <syslog.h>
  118. #include <unistd.h>
  119. #include <paths.h>
  120. #include <getopt.h>
  121.  
  122. #define    TOOMANY        40        /* don't start more than TOOMANY */
  123. #define    CNT_INTVL    60        /* servers in CNT_INTVL sec. */
  124. #define    RETRYTIME    (60*10)        /* retry after bind or server fail */
  125.  
  126. #define    SIGBLOCK    (sigmask(SIGCHLD)|sigmask(SIGHUP)|sigmask(SIGALRM))
  127.  
  128.  
  129. int    debug = 0;
  130. int    nsock, maxsock;
  131. fd_set    allsock;
  132. int    options;
  133. int    timingout;
  134. int    toomany = TOOMANY;
  135. struct    servent *sp;
  136.  
  137. struct    servtab {
  138.     char    *se_service;        /* name of service */
  139.     int    se_socktype;        /* type of socket to use */
  140.     char    *se_proto;        /* protocol used */
  141.     short    se_wait;        /* single threaded server */
  142.     short    se_checked;        /* looked at during merge */
  143.     char    *se_user;        /* user name to run as */
  144.     struct    biltin *se_bi;        /* if built-in, description */
  145.     char    *se_server;        /* server program */
  146. #define    MAXARGV 20
  147.     char    *se_argv[MAXARGV+1];    /* program arguments */
  148.     int    se_fd;            /* open descriptor */
  149.     int    se_type;        /* type */
  150.     struct    sockaddr_in se_ctrladdr;/* bound address */
  151.     int    se_count;        /* number started since se_time */
  152.     struct    timeval se_time;    /* start of se_count */
  153.     struct    servtab *se_next;
  154. } *servtab;
  155.  
  156. #define NORM_TYPE    0
  157. #define MUX_TYPE    1
  158. #define MUXPLUS_TYPE    2
  159. #define ISMUX(sep)    (((sep)->se_type == MUX_TYPE) || \
  160.              ((sep)->se_type == MUXPLUS_TYPE))
  161. #define ISMUXPLUS(sep)    ((sep)->se_type == MUXPLUS_TYPE)
  162.  
  163.  
  164. void        chargen_dg __P((int, struct servtab *));
  165. void        chargen_stream __P((int, struct servtab *));
  166. void        close_sep __P((struct servtab *));
  167. void        config __P((int));
  168. void        daytime_dg __P((int, struct servtab *));
  169. void        daytime_stream __P((int, struct servtab *));
  170. void        discard_dg __P((int, struct servtab *));
  171. void        discard_stream __P((int, struct servtab *));
  172. void        echo_dg __P((int, struct servtab *));
  173. void        echo_stream __P((int, struct servtab *));
  174. void        endconfig __P((void));
  175. struct servtab *enter __P((struct servtab *));
  176. void        freeconfig __P((struct servtab *));
  177. struct servtab *getconfigent __P((void));
  178. void        machtime_dg __P((int, struct servtab *));
  179. void        machtime_stream __P((int, struct servtab *));
  180. char           *newstr __P((char *));
  181. char           *nextline __P((FILE *));
  182. void        print_service __P((char *, struct servtab *));
  183. void        reapchild __P((int));
  184. void        retry __P((int));
  185. int        setconfig __P((void));
  186. void        setup __P((struct servtab *));
  187. char           *sskip __P((char **));
  188. char           *skip __P((char **));
  189. struct servtab *tcpmux __P((int));
  190.  
  191. struct biltin {
  192.     char    *bi_service;        /* internally provided service name */
  193.     int    bi_socktype;        /* type of socket supported */
  194.     short    bi_fork;        /* 1 if should fork before call */
  195.     short    bi_wait;        /* 1 if should wait for child */
  196.     void    (*bi_fn)();        /* function which performs it */
  197. } biltins[] = {
  198.     /* Echo received data */
  199.     { "echo",    SOCK_STREAM,    1, 0,    echo_stream },
  200.     { "echo",    SOCK_DGRAM,    0, 0,    echo_dg },
  201.  
  202.     /* Internet /dev/null */
  203.     { "discard",    SOCK_STREAM,    1, 0,    discard_stream },
  204.     { "discard",    SOCK_DGRAM,    0, 0,    discard_dg },
  205.  
  206.     /* Return 32 bit time since 1970 */
  207.     { "time",    SOCK_STREAM,    0, 0,    machtime_stream },
  208.     { "time",    SOCK_DGRAM,    0, 0,    machtime_dg },
  209.  
  210.     /* Return human-readable time */
  211.     { "daytime",    SOCK_STREAM,    0, 0,    daytime_stream },
  212.     { "daytime",    SOCK_DGRAM,    0, 0,    daytime_dg },
  213.  
  214.     /* Familiar character generator */
  215.     { "chargen",    SOCK_STREAM,    1, 0,    chargen_stream },
  216.     { "chargen",    SOCK_DGRAM,    0, 0,    chargen_dg },
  217.  
  218.     { "tcpmux",    SOCK_STREAM,    1, 0,    (void (*)())tcpmux },
  219.  
  220.     { NULL }
  221. };
  222.  
  223. #define NUMINT    (sizeof(intab) / sizeof(struct inent))
  224. char    *CONFIG = _PATH_INETDCONF;
  225. char    **Argv;
  226. char     *LastArg;
  227.  
  228. int
  229. main(argc, argv, envp)
  230.     int argc;
  231.     char *argv[], *envp[];
  232. {
  233.     struct servtab *sep;
  234.     struct passwd *pwd;
  235.     struct sigvec sv;
  236.     int tmpint, ch, dofork;
  237.     pid_t pid;
  238.     char buf[50];
  239.  
  240.     Argv = argv;
  241.     if (envp == 0 || *envp == 0)
  242.         envp = argv;
  243.     while (*envp)
  244.         envp++;
  245.     LastArg = envp[-1] + strlen(envp[-1]);
  246.  
  247.     openlog("inetd", LOG_PID | LOG_NOWAIT, LOG_DAEMON);
  248.  
  249.     while ((ch = getopt(argc, argv, "dR:")) != EOF)
  250.         switch(ch) {
  251.         case 'd':
  252.             debug = 1;
  253.             options |= SO_DEBUG;
  254.             break;
  255.         case 'R': {    /* invocation rate */
  256.             char *p;
  257.  
  258.             tmpint = strtol(optarg, &p, 0);
  259.             if (tmpint < 1 || *p)
  260.                 syslog(LOG_ERR,
  261.                      "-R %s: bad value for service invocation rate",
  262.                     optarg);
  263.             else
  264.                 toomany = tmpint;
  265.             break;
  266.         }
  267.         case '?':
  268.         default:
  269.             syslog(LOG_ERR,
  270.                 "usage: inetd [-d] [-R rate] [conf-file]");
  271.             exit(1);
  272.         }
  273.     argc -= optind;
  274.     argv += optind;
  275.  
  276.     if (argc > 0)
  277.         CONFIG = argv[0];
  278.     if (debug == 0) {
  279.         daemon(0, 0);
  280.     }
  281.     memset(&sv, 0, sizeof(sv));
  282.     sv.sv_mask = SIGBLOCK;
  283.     sv.sv_handler = retry;
  284.     sigvec(SIGALRM, &sv, (struct sigvec *)0);
  285.     config(SIGHUP);
  286.     sv.sv_handler = config;
  287.     sigvec(SIGHUP, &sv, (struct sigvec *)0);
  288.     sv.sv_handler = reapchild;
  289.     sigvec(SIGCHLD, &sv, (struct sigvec *)0);
  290.  
  291.     {
  292.         /* space for daemons to overwrite environment for ps */
  293. #define    DUMMYSIZE    100
  294.         char dummy[DUMMYSIZE];
  295.  
  296.         (void)memset(dummy, 'x', sizeof(DUMMYSIZE) - 1);
  297.         dummy[DUMMYSIZE - 1] = '\0';
  298.         (void)setenv("inetd_dummy", dummy, 1);
  299.     }
  300.  
  301.     for (;;) {
  302.         int n, ctrl;
  303.         fd_set readable;
  304.  
  305.         if (nsock == 0) {
  306.         (void) sigblock(SIGBLOCK);
  307.         while (nsock == 0)
  308.             sigpause(0L);
  309.         (void) sigsetmask(0L);
  310.         }
  311.         readable = allsock;
  312.         if ((n = select(maxsock + 1, &readable, (fd_set *)0,
  313.         (fd_set *)0, (struct timeval *)0)) <= 0) {
  314.             if (n < 0 && errno != EINTR)
  315.             syslog(LOG_WARNING, "select: %m");
  316.             sleep(1);
  317.             continue;
  318.         }
  319.         for (sep = servtab; n && sep; sep = sep->se_next)
  320.             if (sep->se_fd != -1 && FD_ISSET(sep->se_fd, &readable)) {
  321.             n--;
  322.             if (debug)
  323.                 fprintf(stderr, "someone wants %s\n",
  324.                 sep->se_service);
  325.             if (!sep->se_wait && sep->se_socktype == SOCK_STREAM) {
  326.                 ctrl = accept(sep->se_fd, (struct sockaddr *)0,
  327.                 (int *)0);
  328.                 if (debug)
  329.                     fprintf(stderr, "accept, ctrl %d\n", ctrl);
  330.                 if (ctrl < 0) {
  331.                     if (errno != EINTR)
  332.                         syslog(LOG_WARNING,
  333.                         "accept (for %s): %m",
  334.                         sep->se_service);
  335.                     continue;
  336.                 }
  337.                 /*
  338.                  * Call tcpmux to find the real service to exec.
  339.                  */
  340.                 if (sep->se_bi &&
  341.                 sep->se_bi->bi_fn == (void (*)()) tcpmux) {
  342.                     sep = tcpmux(ctrl);
  343.                     if (sep == NULL) {
  344.                         close(ctrl);
  345.                         continue;
  346.                     }
  347.                 }
  348.             } else
  349.                 ctrl = sep->se_fd;
  350.             (void) sigblock(SIGBLOCK);
  351.             pid = 0;
  352.             dofork = (sep->se_bi == 0 || sep->se_bi->bi_fork);
  353.             if (dofork) {
  354.                 if (sep->se_count++ == 0)
  355.                 (void)gettimeofday(&sep->se_time,
  356.                     (struct timezone *)0);
  357.                 else if (sep->se_count >= toomany) {
  358.                 struct timeval now;
  359.  
  360.                 (void)gettimeofday(&now, (struct timezone *)0);
  361.                 if (now.tv_sec - sep->se_time.tv_sec >
  362.                     CNT_INTVL) {
  363.                     sep->se_time = now;
  364.                     sep->se_count = 1;
  365.                 } else {
  366.                     syslog(LOG_ERR,
  367.             "%s/%s server failing (looping), service terminated",
  368.                         sep->se_service, sep->se_proto);
  369.                     close_sep(sep);
  370.                     sigsetmask(0L);
  371.                     if (!timingout) {
  372.                         timingout = 1;
  373.                         alarm(RETRYTIME);
  374.                     }
  375.                     continue;
  376.                 }
  377.                 }
  378.                 pid = fork();
  379.             }
  380.             if (pid < 0) {
  381.                 syslog(LOG_ERR, "fork: %m");
  382.                 if (!sep->se_wait &&
  383.                 sep->se_socktype == SOCK_STREAM)
  384.                     close(ctrl);
  385.                 sigsetmask(0L);
  386.                 sleep(1);
  387.                 continue;
  388.             }
  389.             if (pid && sep->se_wait) {
  390.                 sep->se_wait = pid;
  391.                 if (sep->se_fd >= 0) {
  392.                 FD_CLR(sep->se_fd, &allsock);
  393.                     nsock--;
  394.                 }
  395.             }
  396.             sigsetmask(0L);
  397.             if (pid == 0) {
  398.                 if (debug && dofork)
  399.                 setsid();
  400.                 if (dofork) {
  401.                 if (debug)
  402.                     fprintf(stderr, "+ Closing from %d\n",
  403.                         maxsock);
  404.                 for (tmpint = maxsock; tmpint > 2; tmpint--)
  405.                     if (tmpint != ctrl)
  406.                         close(tmpint);
  407.                 }
  408.                 if (sep->se_bi)
  409.                 (*sep->se_bi->bi_fn)(ctrl, sep);
  410.                 else {
  411.                 if (debug)
  412.                     fprintf(stderr, "%d execl %s\n",
  413.                         getpid(), sep->se_server);
  414.                 dup2(ctrl, 0);
  415.                 close(ctrl);
  416.                 dup2(0, 1);
  417.                 dup2(0, 2);
  418.                 if ((pwd = getpwnam(sep->se_user)) == NULL) {
  419.                     syslog(LOG_ERR,
  420.                         "%s/%s: %s: No such user",
  421.                         sep->se_service, sep->se_proto,
  422.                         sep->se_user);
  423.                     if (sep->se_socktype != SOCK_STREAM)
  424.                         recv(0, buf, sizeof (buf), 0);
  425.                     _exit(1);
  426.                 }
  427.                 if (pwd->pw_uid) {
  428.                     if (setgid(pwd->pw_gid) < 0) {
  429.                         syslog(LOG_ERR,
  430.                           "%s: can't set gid %d: %m", 
  431.                           sep->se_service, pwd->pw_gid);
  432.                         _exit(1);
  433.                     }
  434.                     (void) initgroups(pwd->pw_name,
  435.                             pwd->pw_gid);
  436.                     if (setuid(pwd->pw_uid) < 0) {
  437.                         syslog(LOG_ERR,
  438.                           "%s: can't set uid %d: %m", 
  439.                           sep->se_service, pwd->pw_uid);
  440.                         _exit(1);
  441.                     }
  442.                 }
  443.                 execv(sep->se_server, sep->se_argv);
  444.                 if (sep->se_socktype != SOCK_STREAM)
  445.                     recv(0, buf, sizeof (buf), 0);
  446.                 syslog(LOG_ERR,
  447.                     "cannot execute %s: %m", sep->se_server);
  448.                 _exit(1);
  449.                 }
  450.             }
  451.             if (!sep->se_wait && sep->se_socktype == SOCK_STREAM)
  452.                 close(ctrl);
  453.         }
  454.     }
  455. }
  456.  
  457. void
  458. reapchild(signo)
  459.     int signo;
  460. {
  461.     int status;
  462.     pid_t pid;
  463.     struct servtab *sep;
  464.  
  465.     for (;;) {
  466.         pid = wait3(&status, WNOHANG, (struct rusage *)0);
  467.         if (pid <= 0)
  468.             break;
  469.         if (debug)
  470.             fprintf(stderr, "%d reaped, status %#x\n", 
  471.                 pid, status);
  472.         for (sep = servtab; sep; sep = sep->se_next)
  473.             if (sep->se_wait == pid) {
  474.                 if (status)
  475.                     syslog(LOG_WARNING,
  476.                         "%s: exit status 0x%x",
  477.                         sep->se_server, status);
  478.                 if (debug)
  479.                     fprintf(stderr, "restored %s, fd %d\n",
  480.                         sep->se_service, sep->se_fd);
  481.                 FD_SET(sep->se_fd, &allsock);
  482.                 nsock++;
  483.                 sep->se_wait = 1;
  484.             }
  485.     }
  486. }
  487.  
  488. void
  489. config(signo)
  490.     int signo;
  491. {
  492.     struct servtab *sep, *cp, **sepp;
  493.     struct passwd *pwd;
  494.     long omask;
  495.  
  496.     if (!setconfig()) {
  497.         syslog(LOG_ERR, "%s: %m", CONFIG);
  498.         return;
  499.     }
  500.     for (sep = servtab; sep; sep = sep->se_next)
  501.         sep->se_checked = 0;
  502.     while (cp = getconfigent()) {
  503.         if ((pwd = getpwnam(cp->se_user)) == NULL) {
  504.             syslog(LOG_ERR,
  505.                 "%s/%s: No such user '%s', service ignored",
  506.                 cp->se_service, cp->se_proto, cp->se_user);
  507.             continue;
  508.         }
  509.         for (sep = servtab; sep; sep = sep->se_next)
  510.             if (strcmp(sep->se_service, cp->se_service) == 0 &&
  511.                 strcmp(sep->se_proto, cp->se_proto) == 0)
  512.                 break;
  513.         if (sep != 0) {
  514.             int i;
  515.  
  516.             omask = sigblock(SIGBLOCK);
  517.             /*
  518.              * sep->se_wait may be holding the pid of a daemon
  519.              * that we're waiting for.  If so, don't overwrite
  520.              * it unless the config file explicitly says don't 
  521.              * wait.
  522.              */
  523.             if (cp->se_bi == 0 && 
  524.                 (sep->se_wait == 1 || cp->se_wait == 0))
  525.                 sep->se_wait = cp->se_wait;
  526. #define SWAP(a, b) { char *c = a; a = b; b = c; }
  527.             if (cp->se_user)
  528.                 SWAP(sep->se_user, cp->se_user);
  529.             if (cp->se_server)
  530.                 SWAP(sep->se_server, cp->se_server);
  531.             for (i = 0; i < MAXARGV; i++)
  532.                 SWAP(sep->se_argv[i], cp->se_argv[i]);
  533.             sigsetmask(omask);
  534.             freeconfig(cp);
  535.             if (debug)
  536.                 print_service("REDO", sep);
  537.         } else {
  538.             sep = enter(cp);
  539.             if (debug)
  540.                 print_service("ADD ", sep);
  541.         }
  542.         sep->se_checked = 1;
  543.         if (ISMUX(sep)) {
  544.             sep->se_fd = -1;
  545.             continue;
  546.         }
  547.         sp = getservbyname(sep->se_service, sep->se_proto);
  548.         if (sp == 0) {
  549.             syslog(LOG_ERR, "%s/%s: unknown service",
  550.                 sep->se_service, sep->se_proto);
  551.             sep->se_checked = 0;
  552.             continue;
  553.         }
  554.         if (sp->s_port != sep->se_ctrladdr.sin_port) {
  555.             sep->se_ctrladdr.sin_family = AF_INET;
  556.             sep->se_ctrladdr.sin_port = sp->s_port;
  557.             if (sep->se_fd >= 0)
  558.                 close_sep(sep);
  559.         }
  560.         if (sep->se_fd == -1)
  561.             setup(sep);
  562.     }
  563.     endconfig();
  564.     /*
  565.      * Purge anything not looked at above.
  566.      */
  567.     omask = sigblock(SIGBLOCK);
  568.     sepp = &servtab;
  569.     while (sep = *sepp) {
  570.         if (sep->se_checked) {
  571.             sepp = &sep->se_next;
  572.             continue;
  573.         }
  574.         *sepp = sep->se_next;
  575.         if (sep->se_fd >= 0)
  576.             close_sep(sep);
  577.         if (debug)
  578.             print_service("FREE", sep);
  579.         freeconfig(sep);
  580.         free((char *)sep);
  581.     }
  582.     (void) sigsetmask(omask);
  583. }
  584.  
  585. void
  586. retry(signo)
  587.     int signo;
  588. {
  589.     struct servtab *sep;
  590.  
  591.     timingout = 0;
  592.     for (sep = servtab; sep; sep = sep->se_next)
  593.         if (sep->se_fd == -1)
  594.             setup(sep);
  595. }
  596.  
  597. void
  598. setup(sep)
  599.     struct servtab *sep;
  600. {
  601.     int on = 1;
  602.  
  603.     if ((sep->se_fd = socket(AF_INET, sep->se_socktype, 0)) < 0) {
  604.         if (debug)
  605.             fprintf(stderr, "socket failed on %s/%s: %s\n", 
  606.                 sep->se_service, sep->se_proto,
  607.                 strerror(errno));
  608.         syslog(LOG_ERR, "%s/%s: socket: %m",
  609.             sep->se_service, sep->se_proto);
  610.         return;
  611.     }
  612. #define    turnon(fd, opt) \
  613. setsockopt(fd, SOL_SOCKET, opt, (char *)&on, sizeof (on))
  614.     if (strcmp(sep->se_proto, "tcp") == 0 && (options & SO_DEBUG) &&
  615.         turnon(sep->se_fd, SO_DEBUG) < 0)
  616.         syslog(LOG_ERR, "setsockopt (SO_DEBUG): %m");
  617.     if (turnon(sep->se_fd, SO_REUSEADDR) < 0)
  618.         syslog(LOG_ERR, "setsockopt (SO_REUSEADDR): %m");
  619. #undef turnon
  620.     if (bind(sep->se_fd, (struct sockaddr *)&sep->se_ctrladdr,
  621.         sizeof (sep->se_ctrladdr)) < 0) {
  622.         if (debug)
  623.             fprintf(stderr, "bind failed on %s/%s: %s\n",
  624.                 sep->se_service, sep->se_proto,
  625.                 strerror(errno));
  626.         syslog(LOG_ERR, "%s/%s: bind: %m",
  627.             sep->se_service, sep->se_proto);
  628.         (void) close(sep->se_fd);
  629.         sep->se_fd = -1;
  630.         if (!timingout) {
  631.             timingout = 1;
  632.             alarm(RETRYTIME);
  633.         }
  634.         return;
  635.     }
  636.     if (sep->se_socktype == SOCK_STREAM)
  637.         listen(sep->se_fd, 10);
  638.     FD_SET(sep->se_fd, &allsock);
  639.     nsock++;
  640.     if (sep->se_fd > maxsock)
  641.         maxsock = sep->se_fd;
  642.     if (debug) {
  643.         fprintf(stderr, "registered %s on %d\n",
  644.             sep->se_server, sep->se_fd);
  645.     }
  646. }
  647.  
  648. /*
  649.  * Finish with a service and its socket.
  650.  */
  651. void
  652. close_sep(sep)
  653.     struct servtab *sep;
  654. {
  655.     if (sep->se_fd >= 0) {
  656.         nsock--;
  657.         FD_CLR(sep->se_fd, &allsock);
  658.         (void) close(sep->se_fd);
  659.         sep->se_fd = -1;
  660.     }
  661.     sep->se_count = 0;
  662.     /*
  663.      * Don't keep the pid of this running deamon: when reapchild()
  664.      * reaps this pid, it would erroneously increment nsock.
  665.      */
  666.     if (sep->se_wait > 1)
  667.         sep->se_wait = 1;
  668. }
  669.  
  670. struct servtab *
  671. enter(cp)
  672.     struct servtab *cp;
  673. {
  674.     struct servtab *sep;
  675.     long omask;
  676.  
  677.     sep = (struct servtab *)malloc(sizeof (*sep));
  678.     if (sep == (struct servtab *)0) {
  679.         syslog(LOG_ERR, "Out of memory.");
  680.         exit(-1);
  681.     }
  682.     *sep = *cp;
  683.     sep->se_fd = -1;
  684.     omask = sigblock(SIGBLOCK);
  685.     sep->se_next = servtab;
  686.     servtab = sep;
  687.     sigsetmask(omask);
  688.     return (sep);
  689. }
  690.  
  691. FILE    *fconfig = NULL;
  692. struct    servtab serv;
  693. #ifdef LINE_MAX
  694. char    line[LINE_MAX];
  695. #else
  696. char     line[2048];
  697. #endif
  698.  
  699. int
  700. setconfig()
  701. {
  702.  
  703.     if (fconfig != NULL) {
  704.         fseek(fconfig, 0L, SEEK_SET);
  705.         return (1);
  706.     }
  707.     fconfig = fopen(CONFIG, "r");
  708.     return (fconfig != NULL);
  709. }
  710.  
  711. void
  712. endconfig()
  713. {
  714.     if (fconfig) {
  715.         (void) fclose(fconfig);
  716.         fconfig = NULL;
  717.     }
  718. }
  719.  
  720. struct servtab *
  721. getconfigent()
  722. {
  723.     struct servtab *sep = &serv;
  724.     int argc;
  725.     char *cp, *arg;
  726.     static char TCPMUX_TOKEN[] = "tcpmux/";
  727. #define MUX_LEN        (sizeof(TCPMUX_TOKEN)-1)
  728.  
  729. more:
  730.     while ((cp = nextline(fconfig)) && (*cp == '#' || *cp == '\0'))
  731.         ;
  732.     if (cp == NULL)
  733.         return ((struct servtab *)0);
  734.     /*
  735.      * clear the static buffer, since some fields (se_ctrladdr,
  736.      * for example) don't get initialized here.
  737.      */
  738.     memset((caddr_t)sep, 0, sizeof *sep);
  739.     arg = skip(&cp);
  740.     if (cp == NULL) {
  741.         /* got an empty line containing just blanks/tabs. */
  742.         goto more;
  743.     }
  744.     if (strncmp(arg, TCPMUX_TOKEN, MUX_LEN) == 0) {
  745.         char *c = arg + MUX_LEN;
  746.         if (*c == '+') {
  747.             sep->se_type = MUXPLUS_TYPE;
  748.             c++;
  749.         } else
  750.             sep->se_type = MUX_TYPE;
  751.         sep->se_service = newstr(c);
  752.     } else {
  753.         sep->se_service = newstr(arg);
  754.         sep->se_type = NORM_TYPE;
  755.     }
  756.     arg = sskip(&cp);
  757.     if (strcmp(arg, "stream") == 0)
  758.         sep->se_socktype = SOCK_STREAM;
  759.     else if (strcmp(arg, "dgram") == 0)
  760.         sep->se_socktype = SOCK_DGRAM;
  761.     else if (strcmp(arg, "rdm") == 0)
  762.         sep->se_socktype = SOCK_RDM;
  763.     else if (strcmp(arg, "seqpacket") == 0)
  764.         sep->se_socktype = SOCK_SEQPACKET;
  765.     else if (strcmp(arg, "raw") == 0)
  766.         sep->se_socktype = SOCK_RAW;
  767.     else
  768.         sep->se_socktype = -1;
  769.     sep->se_proto = newstr(sskip(&cp));
  770.     arg = sskip(&cp);
  771.     sep->se_wait = strcmp(arg, "wait") == 0;
  772.     if (ISMUX(sep)) {
  773.         /*
  774.          * Silently enforce "nowait" for TCPMUX services since
  775.          * they don't have an assigned port to listen on.
  776.          */
  777.         sep->se_wait = 0;
  778.  
  779.         if (strcmp(sep->se_proto, "tcp")) {
  780.             syslog(LOG_ERR, 
  781.                 "%s: bad protocol for tcpmux service %s",
  782.                 CONFIG, sep->se_service);
  783.             goto more;
  784.         }
  785.         if (sep->se_socktype != SOCK_STREAM) {
  786.             syslog(LOG_ERR, 
  787.                 "%s: bad socket type for tcpmux service %s",
  788.                 CONFIG, sep->se_service);
  789.             goto more;
  790.         }
  791.     }
  792.     sep->se_user = newstr(sskip(&cp));
  793.     sep->se_server = newstr(sskip(&cp));
  794.     if (strcmp(sep->se_server, "internal") == 0) {
  795.         struct biltin *bi;
  796.  
  797.         for (bi = biltins; bi->bi_service; bi++)
  798.             if (bi->bi_socktype == sep->se_socktype &&
  799.                 strcmp(bi->bi_service, sep->se_service) == 0)
  800.                 break;
  801.         if (bi->bi_service == 0) {
  802.             syslog(LOG_ERR, "internal service %s unknown",
  803.                 sep->se_service);
  804.             goto more;
  805.         }
  806.         sep->se_bi = bi;
  807.         sep->se_wait = bi->bi_wait;
  808.     } else
  809.         sep->se_bi = NULL;
  810.     argc = 0;
  811.     for (arg = skip(&cp); cp; arg = skip(&cp))
  812.         if (argc < MAXARGV)
  813.             sep->se_argv[argc++] = newstr(arg);
  814.     while (argc <= MAXARGV)
  815.         sep->se_argv[argc++] = NULL;
  816.     return (sep);
  817. }
  818.  
  819. void
  820. freeconfig(cp)
  821.     struct servtab *cp;
  822. {
  823.     int i;
  824.  
  825.     if (cp->se_service)
  826.         free(cp->se_service);
  827.     if (cp->se_proto)
  828.         free(cp->se_proto);
  829.     if (cp->se_user)
  830.         free(cp->se_user);
  831.     if (cp->se_server)
  832.         free(cp->se_server);
  833.     for (i = 0; i < MAXARGV; i++)
  834.         if (cp->se_argv[i])
  835.             free(cp->se_argv[i]);
  836. }
  837.  
  838.  
  839. /*
  840.  * Safe skip - if skip returns null, log a syntax error in the
  841.  * configuration file and exit.
  842.  */
  843. char *
  844. sskip(cpp)
  845.     char **cpp;
  846. {
  847.     char *cp;
  848.  
  849.     cp = skip(cpp);
  850.     if (cp == NULL) {
  851.         syslog(LOG_ERR, "%s: syntax error", CONFIG);
  852.         exit(-1);
  853.     }
  854.     return (cp);
  855. }
  856.  
  857. char *
  858. skip(cpp)
  859.     char **cpp;
  860. {
  861.     char *cp = *cpp;
  862.     char *start;
  863.  
  864. again:
  865.     while (*cp == ' ' || *cp == '\t')
  866.         cp++;
  867.     if (*cp == '\0') {
  868.         int c;
  869.  
  870.         c = getc(fconfig);
  871.         (void) ungetc(c, fconfig);
  872.         if (c == ' ' || c == '\t')
  873.             if (cp = nextline(fconfig))
  874.                 goto again;
  875.         *cpp = (char *)0;
  876.         return ((char *)0);
  877.     }
  878.     start = cp;
  879.     while (*cp && *cp != ' ' && *cp != '\t')
  880.         cp++;
  881.     if (*cp != '\0')
  882.         *cp++ = '\0';
  883.     *cpp = cp;
  884.     return (start);
  885. }
  886.  
  887. char *
  888. nextline(fd)
  889.     FILE *fd;
  890. {
  891.     char *cp;
  892.  
  893.     if (fgets(line, sizeof (line), fd) == NULL)
  894.         return ((char *)0);
  895.     cp = strchr(line, '\n');
  896.     if (cp)
  897.         *cp = '\0';
  898.     return (line);
  899. }
  900.  
  901. char *
  902. newstr(cp)
  903.     char *cp;
  904. {
  905.     if (cp = strdup(cp ? cp : ""))
  906.         return (cp);
  907.     syslog(LOG_ERR, "strdup: %m");
  908.     exit(-1);
  909. }
  910.  
  911. void
  912. set_proc_title(a, s)
  913.     char *a;
  914.     int s;
  915. {
  916.     int size;
  917.     char *cp;
  918.     struct sockaddr_in sin;
  919.     char buf[80];
  920.  
  921.     cp = Argv[0];
  922.     size = sizeof(sin);
  923.     if (getpeername(s, (struct sockaddr *)&sin, &size) == 0)
  924.         (void) sprintf(buf, "-%s [%s]", a, inet_ntoa(sin.sin_addr)); 
  925.     else
  926.         (void) sprintf(buf, "-%s", a); 
  927.     strncpy(cp, buf, LastArg - cp);
  928.     cp += strlen(cp);
  929.     while (cp < LastArg)
  930.         *cp++ = ' ';
  931. }
  932.  
  933. /*
  934.  * Internet services provided internally by inetd:
  935.  */
  936. #define    BUFSIZE    8192
  937.  
  938. /* ARGSUSED */
  939. void
  940. echo_stream(s, sep)        /* Echo service -- echo data back */
  941.     int s;
  942.     struct servtab *sep;
  943. {
  944.     char buffer[BUFSIZE];
  945.     int i;
  946.  
  947.     set_proc_title(sep->se_service, s);
  948.     while ((i = read(s, buffer, sizeof(buffer))) > 0 &&
  949.         write(s, buffer, i) > 0)
  950.         ;
  951.     exit(0);
  952. }
  953.  
  954. /* ARGSUSED */
  955. void
  956. echo_dg(s, sep)            /* Echo service -- echo data back */
  957.     int s;
  958.     struct servtab *sep;
  959. {
  960.     char buffer[BUFSIZE];
  961.     int i, size;
  962.     struct sockaddr sa;
  963.  
  964.     size = sizeof(sa);
  965.     if ((i = recvfrom(s, buffer, sizeof(buffer), 0, &sa, &size)) < 0)
  966.         return;
  967.     (void) sendto(s, buffer, i, 0, &sa, sizeof(sa));
  968. }
  969.  
  970. /* ARGSUSED */
  971. void
  972. discard_stream(s, sep)        /* Discard service -- ignore data */
  973.     int s;
  974.     struct servtab *sep;
  975. {
  976.     int ret;
  977.     char buffer[BUFSIZE];
  978.  
  979.     set_proc_title(sep->se_service, s);
  980.     while (1) {
  981.         while ((ret = read(s, buffer, sizeof(buffer))) > 0)
  982.             ;
  983.         if (ret == 0 || errno != EINTR)
  984.             break;
  985.     }
  986.     exit(0);
  987. }
  988.  
  989. /* ARGSUSED */
  990. void
  991. discard_dg(s, sep)        /* Discard service -- ignore data */
  992.     int s;
  993.     struct servtab *sep;
  994. {
  995.     char buffer[BUFSIZE];
  996.  
  997.     (void) read(s, buffer, sizeof(buffer));
  998. }
  999.  
  1000. #include <ctype.h>
  1001. #define LINESIZ 72
  1002. char ring[128];
  1003. char *endring;
  1004.  
  1005. void
  1006. initring()
  1007. {
  1008.     int i;
  1009.  
  1010.     endring = ring;
  1011.  
  1012.     for (i = 0; i <= 128; ++i)
  1013.         if (isprint(i))
  1014.             *endring++ = i;
  1015. }
  1016.  
  1017. /* ARGSUSED */
  1018. void
  1019. chargen_stream(s, sep)        /* Character generator */
  1020.     int s;
  1021.     struct servtab *sep;
  1022. {
  1023.     int len;
  1024.     char *rs, text[LINESIZ+2];
  1025.  
  1026.     set_proc_title(sep->se_service, s);
  1027.  
  1028.     if (!endring) {
  1029.         initring();
  1030.         rs = ring;
  1031.     }
  1032.  
  1033.     text[LINESIZ] = '\r';
  1034.     text[LINESIZ + 1] = '\n';
  1035.     for (rs = ring;;) {
  1036.         if ((len = endring - rs) >= LINESIZ)
  1037.             memmove(text, rs, LINESIZ);
  1038.         else {
  1039.             memmove(text, rs, len);
  1040.             memmove(text + len, ring, LINESIZ - len);
  1041.         }
  1042.         if (++rs == endring)
  1043.             rs = ring;
  1044.         if (write(s, text, sizeof(text)) != sizeof(text))
  1045.             break;
  1046.     }
  1047.     exit(0);
  1048. }
  1049.  
  1050. /* ARGSUSED */
  1051. void
  1052. chargen_dg(s, sep)        /* Character generator */
  1053.     int s;
  1054.     struct servtab *sep;
  1055. {
  1056.     struct sockaddr sa;
  1057.     static char *rs;
  1058.     int len, size;
  1059.     char text[LINESIZ+2];
  1060.  
  1061.     if (endring == 0) {
  1062.         initring();
  1063.         rs = ring;
  1064.     }
  1065.  
  1066.     size = sizeof(sa);
  1067.     if (recvfrom(s, text, sizeof(text), 0, &sa, &size) < 0)
  1068.         return;
  1069.  
  1070.     if ((len = endring - rs) >= LINESIZ)
  1071.         memmove(text, rs, LINESIZ);
  1072.     else {
  1073.         memmove(text, rs, len);
  1074.         memmove(text + len, ring, LINESIZ - len);
  1075.     }
  1076.     if (++rs == endring)
  1077.         rs = ring;
  1078.     text[LINESIZ] = '\r';
  1079.     text[LINESIZ + 1] = '\n';
  1080.     (void) sendto(s, text, sizeof(text), 0, &sa, sizeof(sa));
  1081. }
  1082.  
  1083. /*
  1084.  * Return a machine readable date and time, in the form of the
  1085.  * number of seconds since midnight, Jan 1, 1900.  Since gettimeofday
  1086.  * returns the number of seconds since midnight, Jan 1, 1970,
  1087.  * we must add 2208988800 seconds to this figure to make up for
  1088.  * some seventy years Bell Labs was asleep.
  1089.  */
  1090.  
  1091. long
  1092. machtime()
  1093. {
  1094.     struct timeval tv;
  1095.  
  1096.     if (gettimeofday(&tv, (struct timezone *)0) < 0) {
  1097.         if (debug)
  1098.             fprintf(stderr, "Unable to get time of day\n");
  1099.         return (0L);
  1100.     }
  1101. #define    OFFSET ((u_long)25567 * 24*60*60)
  1102.     return (htonl((long)(tv.tv_sec + OFFSET)));
  1103. #undef OFFSET
  1104. }
  1105.  
  1106. /* ARGSUSED */
  1107. void
  1108. machtime_stream(s, sep)
  1109.     int s;
  1110.     struct servtab *sep;
  1111. {
  1112.     long result;
  1113.  
  1114.     result = machtime();
  1115.     (void) write(s, (char *) &result, sizeof(result));
  1116. }
  1117.  
  1118. /* ARGSUSED */
  1119. void
  1120. machtime_dg(s, sep)
  1121.     int s;
  1122.     struct servtab *sep;
  1123. {
  1124.     long result;
  1125.     struct sockaddr sa;
  1126.     int size;
  1127.  
  1128.     size = sizeof(sa);
  1129.     if (recvfrom(s, (char *)&result, sizeof(result), 0, &sa, &size) < 0)
  1130.         return;
  1131.     result = machtime();
  1132.     (void) sendto(s, (char *) &result, sizeof(result), 0, &sa, sizeof(sa));
  1133. }
  1134.  
  1135. /* ARGSUSED */
  1136. void
  1137. daytime_stream(s, sep)        /* Return human-readable time of day */
  1138.     int s;
  1139.     struct servtab *sep;
  1140. {
  1141.     char buffer[256];
  1142.     time_t clock;
  1143.  
  1144.     clock = time((time_t *) 0);
  1145.  
  1146.     (void) sprintf(buffer, "%.24s\r\n", ctime(&clock));
  1147.     (void) write(s, buffer, strlen(buffer));
  1148. }
  1149.  
  1150. /* ARGSUSED */
  1151. void
  1152. daytime_dg(s, sep)        /* Return human-readable time of day */
  1153.     int s;
  1154.     struct servtab *sep;
  1155. {
  1156.     char buffer[256];
  1157.     time_t clock;
  1158.     struct sockaddr sa;
  1159.     int size;
  1160.  
  1161.     clock = time((time_t *) 0);
  1162.  
  1163.     size = sizeof(sa);
  1164.     if (recvfrom(s, buffer, sizeof(buffer), 0, &sa, &size) < 0)
  1165.         return;
  1166.     (void) sprintf(buffer, "%.24s\r\n", ctime(&clock));
  1167.     (void) sendto(s, buffer, strlen(buffer), 0, &sa, sizeof(sa));
  1168. }
  1169.  
  1170. /*
  1171.  * print_service:
  1172.  *    Dump relevant information to stderr
  1173.  */
  1174. void
  1175. print_service(action, sep)
  1176.     char *action;
  1177.     struct servtab *sep;
  1178. {
  1179.     fprintf(stderr,
  1180.         "%s: %s proto=%s, wait=%d, user=%s builtin=%x server=%s\n",
  1181.         action, sep->se_service, sep->se_proto,
  1182.         sep->se_wait, sep->se_user, (int)sep->se_bi, sep->se_server);
  1183. }
  1184.  
  1185. /*
  1186.  *  Based on TCPMUX.C by Mark K. Lottor November 1988
  1187.  *  sri-nic::ps:<mkl>tcpmux.c
  1188.  */
  1189.  
  1190.  
  1191. static int        /* # of characters upto \r,\n or \0 */
  1192. fd_getline(fd, buf, len)
  1193.     int fd;
  1194.     char *buf;
  1195.     int len;
  1196. {
  1197.     int count = 0, n;
  1198.  
  1199.     do {
  1200.         n = read(fd, buf, len-count);
  1201.         if (n == 0)
  1202.             return (count);
  1203.         if (n < 0)
  1204.             return (-1);
  1205.         while (--n >= 0) {
  1206.             if (*buf == '\r' || *buf == '\n' || *buf == '\0')
  1207.                 return (count);
  1208.             count++;
  1209.             buf++;
  1210.         }
  1211.     } while (count < len);
  1212.     return (count);
  1213. }
  1214.  
  1215. #define MAX_SERV_LEN    (256+2)        /* 2 bytes for \r\n */
  1216.  
  1217. #define strwrite(fd, buf)    (void) write(fd, buf, sizeof(buf)-1)
  1218.  
  1219. struct servtab *
  1220. tcpmux(s)
  1221.     int s;
  1222. {
  1223.     struct servtab *sep;
  1224.     char service[MAX_SERV_LEN+1];
  1225.     int len;
  1226.  
  1227.     /* Get requested service name */
  1228.     if ((len = fd_getline(s, service, MAX_SERV_LEN)) < 0) {
  1229.         strwrite(s, "-Error reading service name\r\n");
  1230.         return (NULL);
  1231.     }
  1232.     service[len] = '\0';
  1233.  
  1234.     if (debug)
  1235.         fprintf(stderr, "tcpmux: someone wants %s\n", service);
  1236.  
  1237.     /*
  1238.      * Help is a required command, and lists available services,
  1239.      * one per line.
  1240.      */
  1241.     if (!strcasecmp(service, "help")) {
  1242.         for (sep = servtab; sep; sep = sep->se_next) {
  1243.             if (!ISMUX(sep))
  1244.                 continue;
  1245.             (void)write(s,sep->se_service,strlen(sep->se_service));
  1246.             strwrite(s, "\r\n");
  1247.         }
  1248.         return (NULL);
  1249.     }
  1250.  
  1251.     /* Try matching a service in inetd.conf with the request */
  1252.     for (sep = servtab; sep; sep = sep->se_next) {
  1253.         if (!ISMUX(sep))
  1254.             continue;
  1255.         if (!strcasecmp(service, sep->se_service)) {
  1256.             if (ISMUXPLUS(sep)) {
  1257.                 strwrite(s, "+Go\r\n");
  1258.             }
  1259.             return (sep);
  1260.         }
  1261.     }
  1262.     strwrite(s, "-Service not available\r\n");
  1263.     return (NULL);
  1264. }
  1265.