home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / usr.sbin / inetd / inetd.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-06-03  |  22.3 KB  |  965 lines

  1. /*
  2.  * Copyright (c) 1983,1991 The Regents of the University of California.
  3.  * 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. char copyright[] =
  36. "@(#) Copyright (c) 1983 Regents of the University of California.\n\
  37.  All rights reserved.\n";
  38. #endif /* not lint */
  39.  
  40. #ifndef lint
  41. static char sccsid[] = "@(#)inetd.c    5.30 (Berkeley) 6/3/91";
  42. #endif /* not lint */
  43.  
  44. /*
  45.  * Inetd - Internet super-server
  46.  *
  47.  * This program invokes all internet services as needed.
  48.  * connection-oriented services are invoked each time a
  49.  * connection is made, by creating a process.  This process
  50.  * is passed the connection as file descriptor 0 and is
  51.  * expected to do a getpeername to find out the source host
  52.  * and port.
  53.  *
  54.  * Datagram oriented services are invoked when a datagram
  55.  * arrives; a process is created and passed a pending message
  56.  * on file descriptor 0.  Datagram servers may either connect
  57.  * to their peer, freeing up the original socket for inetd
  58.  * to receive further messages on, or ``take over the socket'',
  59.  * processing all arriving datagrams and, eventually, timing
  60.  * out.     The first type of server is said to be ``multi-threaded'';
  61.  * the second type of server ``single-threaded''. 
  62.  *
  63.  * Inetd uses a configuration file which is read at startup
  64.  * and, possibly, at some later time in response to a hangup signal.
  65.  * The configuration file is ``free format'' with fields given in the
  66.  * order shown below.  Continuation lines for an entry must being with
  67.  * a space or tab.  All fields must be present in each entry.
  68.  *
  69.  *    service name            must be in /etc/services
  70.  *    socket type            stream/dgram/raw/rdm/seqpacket
  71.  *    protocol            must be in /etc/protocols
  72.  *    wait/nowait            single-threaded/multi-threaded
  73.  *    user                user to run daemon as
  74.  *    server program            full path name
  75.  *    server program arguments    maximum of MAXARGS (20)
  76.  *
  77.  * Comment lines are indicated by a `#' in column 1.
  78.  */
  79. #include <sys/param.h>
  80. #include <sys/stat.h>
  81. #include <sys/ioctl.h>
  82. #include <sys/socket.h>
  83. #include <sys/file.h>
  84. #include <sys/wait.h>
  85. #include <sys/time.h>
  86. #include <sys/resource.h>
  87.  
  88. #include <netinet/in.h>
  89. #include <arpa/inet.h>
  90.  
  91. #include <errno.h>
  92. #include <signal.h>
  93. #include <netdb.h>
  94. #include <syslog.h>
  95. #include <pwd.h>
  96. #include <stdio.h>
  97. #include <string.h>
  98. #include "pathnames.h"
  99.  
  100. #define    TOOMANY        40        /* don't start more than TOOMANY */
  101. #define    CNT_INTVL    60        /* servers in CNT_INTVL sec. */
  102. #define    RETRYTIME    (60*10)        /* retry after bind or server fail */
  103.  
  104. #define    SIGBLOCK    (sigmask(SIGCHLD)|sigmask(SIGHUP)|sigmask(SIGALRM))
  105.  
  106. extern    int errno;
  107.  
  108. void    config(), reapchild(), retry();
  109. char    *index();
  110. char    *malloc();
  111.  
  112. int    debug = 0;
  113. int    nsock, maxsock;
  114. fd_set    allsock;
  115. int    options;
  116. int    timingout;
  117. struct    servent *sp;
  118.  
  119. struct    servtab {
  120.     char    *se_service;        /* name of service */
  121.     int    se_socktype;        /* type of socket to use */
  122.     char    *se_proto;        /* protocol used */
  123.     short    se_wait;        /* single threaded server */
  124.     short    se_checked;        /* looked at during merge */
  125.     char    *se_user;        /* user name to run as */
  126.     struct    biltin *se_bi;        /* if built-in, description */
  127.     char    *se_server;        /* server program */
  128. #define    MAXARGV 20
  129.     char    *se_argv[MAXARGV+1];    /* program arguments */
  130.     int    se_fd;            /* open descriptor */
  131.     struct    sockaddr_in se_ctrladdr;/* bound address */
  132.     int    se_count;        /* number started since se_time */
  133.     struct    timeval se_time;    /* start of se_count */
  134.     struct    servtab *se_next;
  135. } *servtab;
  136.  
  137. int echo_stream(), discard_stream(), machtime_stream();
  138. int daytime_stream(), chargen_stream();
  139. int echo_dg(), discard_dg(), machtime_dg(), daytime_dg(), chargen_dg();
  140.  
  141. struct biltin {
  142.     char    *bi_service;        /* internally provided service name */
  143.     int    bi_socktype;        /* type of socket supported */
  144.     short    bi_fork;        /* 1 if should fork before call */
  145.     short    bi_wait;        /* 1 if should wait for child */
  146.     int    (*bi_fn)();        /* function which performs it */
  147. } biltins[] = {
  148.     /* Echo received data */
  149.     "echo",        SOCK_STREAM,    1, 0,    echo_stream,
  150.     "echo",        SOCK_DGRAM,    0, 0,    echo_dg,
  151.  
  152.     /* Internet /dev/null */
  153.     "discard",    SOCK_STREAM,    1, 0,    discard_stream,
  154.     "discard",    SOCK_DGRAM,    0, 0,    discard_dg,
  155.  
  156.     /* Return 32 bit time since 1970 */
  157.     "time",        SOCK_STREAM,    0, 0,    machtime_stream,
  158.     "time",        SOCK_DGRAM,    0, 0,    machtime_dg,
  159.  
  160.     /* Return human-readable time */
  161.     "daytime",    SOCK_STREAM,    0, 0,    daytime_stream,
  162.     "daytime",    SOCK_DGRAM,    0, 0,    daytime_dg,
  163.  
  164.     /* Familiar character generator */
  165.     "chargen",    SOCK_STREAM,    1, 0,    chargen_stream,
  166.     "chargen",    SOCK_DGRAM,    0, 0,    chargen_dg,
  167.     0
  168. };
  169.  
  170. #define NUMINT    (sizeof(intab) / sizeof(struct inent))
  171. char    *CONFIG = _PATH_INETDCONF;
  172. char    **Argv;
  173. char     *LastArg;
  174.  
  175. main(argc, argv, envp)
  176.     int argc;
  177.     char *argv[], *envp[];
  178. {
  179.     extern char *optarg;
  180.     extern int optind;
  181.     register struct servtab *sep;
  182.     register struct passwd *pwd;
  183.     register int tmpint;
  184.     struct sigvec sv;
  185.     int ch, pid, dofork;
  186.     char buf[50];
  187.  
  188.     Argv = argv;
  189.     if (envp == 0 || *envp == 0)
  190.         envp = argv;
  191.     while (*envp)
  192.         envp++;
  193.     LastArg = envp[-1] + strlen(envp[-1]);
  194.  
  195.     while ((ch = getopt(argc, argv, "d")) != EOF)
  196.         switch(ch) {
  197.         case 'd':
  198.             debug = 1;
  199.             options |= SO_DEBUG;
  200.             break;
  201.         case '?':
  202.         default:
  203.             fprintf(stderr, "usage: inetd [-d]");
  204.             exit(1);
  205.         }
  206.     argc -= optind;
  207.     argv += optind;
  208.  
  209.     if (argc > 0)
  210.         CONFIG = argv[0];
  211.     if (debug == 0)
  212.         daemon(0, 0);
  213.     openlog("inetd", LOG_PID | LOG_NOWAIT, LOG_DAEMON);
  214.     bzero((char *)&sv, sizeof(sv));
  215.     sv.sv_mask = SIGBLOCK;
  216.     sv.sv_handler = retry;
  217.     sigvec(SIGALRM, &sv, (struct sigvec *)0);
  218.     config();
  219.     sv.sv_handler = config;
  220.     sigvec(SIGHUP, &sv, (struct sigvec *)0);
  221.     sv.sv_handler = reapchild;
  222.     sigvec(SIGCHLD, &sv, (struct sigvec *)0);
  223.  
  224.     {
  225.         /* space for daemons to overwrite environment for ps */
  226. #define    DUMMYSIZE    100
  227.         char dummy[DUMMYSIZE];
  228.  
  229.         (void)memset(dummy, 'x', sizeof(DUMMYSIZE) - 1);
  230.         dummy[DUMMYSIZE - 1] = '\0';
  231.         (void)setenv("inetd_dummy", dummy, 1);
  232.     }
  233.  
  234.     for (;;) {
  235.         int n, ctrl;
  236.         fd_set readable;
  237.  
  238.         if (nsock == 0) {
  239.         (void) sigblock(SIGBLOCK);
  240.         while (nsock == 0)
  241.             sigpause(0L);
  242.         (void) sigsetmask(0L);
  243.         }
  244.         readable = allsock;
  245.         if ((n = select(maxsock + 1, &readable, (fd_set *)0,
  246.         (fd_set *)0, (struct timeval *)0)) <= 0) {
  247.             if (n < 0 && errno != EINTR)
  248.             syslog(LOG_WARNING, "select: %m\n");
  249.             sleep(1);
  250.             continue;
  251.         }
  252.         for (sep = servtab; n && sep; sep = sep->se_next)
  253.             if (sep->se_fd != -1 && FD_ISSET(sep->se_fd, &readable)) {
  254.             n--;
  255.             if (debug)
  256.                 fprintf(stderr, "someone wants %s\n",
  257.                 sep->se_service);
  258.             if (sep->se_socktype == SOCK_STREAM) {
  259.                 ctrl = accept(sep->se_fd, (struct sockaddr *)0,
  260.                 (int *)0);
  261.                 if (debug)
  262.                     fprintf(stderr, "accept, ctrl %d\n", ctrl);
  263.                 if (ctrl < 0) {
  264.                     if (errno == EINTR)
  265.                         continue;
  266.                     syslog(LOG_WARNING, "accept (for %s): %m",
  267.                         sep->se_service);
  268.                     continue;
  269.                 }
  270.             } else
  271.                 ctrl = sep->se_fd;
  272.             (void) sigblock(SIGBLOCK);
  273.             pid = 0;
  274.             dofork = (sep->se_bi == 0 || sep->se_bi->bi_fork);
  275.             if (dofork) {
  276.                 if (sep->se_count++ == 0)
  277.                 (void)gettimeofday(&sep->se_time,
  278.                     (struct timezone *)0);
  279.                 else if (sep->se_count >= TOOMANY) {
  280.                 struct timeval now;
  281.  
  282.                 (void)gettimeofday(&now, (struct timezone *)0);
  283.                 if (now.tv_sec - sep->se_time.tv_sec >
  284.                     CNT_INTVL) {
  285.                     sep->se_time = now;
  286.                     sep->se_count = 1;
  287.                 } else {
  288.                     syslog(LOG_ERR,
  289.             "%s/%s server failing (looping), service terminated\n",
  290.                         sep->se_service, sep->se_proto);
  291.                     FD_CLR(sep->se_fd, &allsock);
  292.                     (void) close(sep->se_fd);
  293.                     sep->se_fd = -1;
  294.                     sep->se_count = 0;
  295.                     nsock--;
  296.                     if (!timingout) {
  297.                         timingout = 1;
  298.                         alarm(RETRYTIME);
  299.                     }
  300.                 }
  301.                 }
  302.                 pid = fork();
  303.             }
  304.             if (pid < 0) {
  305.                 syslog(LOG_ERR, "fork: %m");
  306.                 if (sep->se_socktype == SOCK_STREAM)
  307.                     close(ctrl);
  308.                 sigsetmask(0L);
  309.                 sleep(1);
  310.                 continue;
  311.             }
  312.             if (pid && sep->se_wait) {
  313.                 sep->se_wait = pid;
  314.                 if (sep->se_fd >= 0) {
  315.                 FD_CLR(sep->se_fd, &allsock);
  316.                     nsock--;
  317.                 }
  318.             }
  319.             sigsetmask(0L);
  320.             if (pid == 0) {
  321.                 if (debug && dofork)
  322.                 setsid();
  323.                 if (dofork)
  324.                 for (tmpint = maxsock; --tmpint > 2; )
  325.                     if (tmpint != ctrl)
  326.                         close(tmpint);
  327.                 if (sep->se_bi)
  328.                 (*sep->se_bi->bi_fn)(ctrl, sep);
  329.                 else {
  330.                 if (debug)
  331.                     fprintf(stderr, "%d execl %s\n",
  332.                         getpid(), sep->se_server);
  333.                 dup2(ctrl, 0);
  334.                 close(ctrl);
  335.                 dup2(0, 1);
  336.                 dup2(0, 2);
  337.                 if ((pwd = getpwnam(sep->se_user)) == NULL) {
  338.                     syslog(LOG_ERR,
  339.                         "getpwnam: %s: No such user",
  340.                         sep->se_user);
  341.                     if (sep->se_socktype != SOCK_STREAM)
  342.                         recv(0, buf, sizeof (buf), 0);
  343.                     _exit(1);
  344.                 }
  345.                 if (pwd->pw_uid) {
  346.                     (void) setgid((gid_t)pwd->pw_gid);
  347.                     initgroups(pwd->pw_name, pwd->pw_gid);
  348.                     (void) setuid((uid_t)pwd->pw_uid);
  349.                 }
  350.                 execv(sep->se_server, sep->se_argv);
  351.                 if (sep->se_socktype != SOCK_STREAM)
  352.                     recv(0, buf, sizeof (buf), 0);
  353.                 syslog(LOG_ERR, "execv %s: %m", sep->se_server);
  354.                 _exit(1);
  355.                 }
  356.             }
  357.             if (sep->se_socktype == SOCK_STREAM)
  358.                 close(ctrl);
  359.         }
  360.     }
  361. }
  362.  
  363. void
  364. reapchild()
  365. {
  366.     int status;
  367.     int pid;
  368.     register struct servtab *sep;
  369.  
  370.     for (;;) {
  371.         pid = wait3(&status, WNOHANG, (struct rusage *)0);
  372.         if (pid <= 0)
  373.             break;
  374.         if (debug)
  375.             fprintf(stderr, "%d reaped\n", pid);
  376.         for (sep = servtab; sep; sep = sep->se_next)
  377.             if (sep->se_wait == pid) {
  378.                 if (status)
  379.                     syslog(LOG_WARNING,
  380.                         "%s: exit status 0x%x",
  381.                         sep->se_server, status);
  382.                 if (debug)
  383.                     fprintf(stderr, "restored %s, fd %d\n",
  384.                         sep->se_service, sep->se_fd);
  385.                 FD_SET(sep->se_fd, &allsock);
  386.                 nsock++;
  387.                 sep->se_wait = 1;
  388.             }
  389.     }
  390. }
  391.  
  392. void
  393. config()
  394. {
  395.     register struct servtab *sep, *cp, **sepp;
  396.     struct servtab *getconfigent(), *enter();
  397.     long omask;
  398.  
  399.     if (!setconfig()) {
  400.         syslog(LOG_ERR, "%s: %m", CONFIG);
  401.         return;
  402.     }
  403.     for (sep = servtab; sep; sep = sep->se_next)
  404.         sep->se_checked = 0;
  405.     while (cp = getconfigent()) {
  406.         for (sep = servtab; sep; sep = sep->se_next)
  407.             if (strcmp(sep->se_service, cp->se_service) == 0 &&
  408.                 strcmp(sep->se_proto, cp->se_proto) == 0)
  409.                 break;
  410.         if (sep != 0) {
  411.             int i;
  412.  
  413.             omask = sigblock(SIGBLOCK);
  414.             /*
  415.              * sep->se_wait may be holding the pid of a daemon
  416.              * that we're waiting for.  If so, don't overwrite
  417.              * it unless the config file explicitly says don't 
  418.              * wait.
  419.              */
  420.             if (cp->se_bi == 0 && 
  421.                 (sep->se_wait == 1 || cp->se_wait == 0))
  422.                 sep->se_wait = cp->se_wait;
  423. #define SWAP(a, b) { char *c = a; a = b; b = c; }
  424.             if (cp->se_user)
  425.                 SWAP(sep->se_user, cp->se_user);
  426.             if (cp->se_server)
  427.                 SWAP(sep->se_server, cp->se_server);
  428.             for (i = 0; i < MAXARGV; i++)
  429.                 SWAP(sep->se_argv[i], cp->se_argv[i]);
  430.             sigsetmask(omask);
  431.             freeconfig(cp);
  432.             if (debug)
  433.                 print_service("REDO", sep);
  434.         } else {
  435.             sep = enter(cp);
  436.             if (debug)
  437.                 print_service("ADD ", sep);
  438.         }
  439.         sep->se_checked = 1;
  440.         sp = getservbyname(sep->se_service, sep->se_proto);
  441.         if (sp == 0) {
  442.             syslog(LOG_ERR, "%s/%s: unknown service",
  443.                 sep->se_service, sep->se_proto);
  444.             if (sep->se_fd != -1)
  445.                 (void) close(sep->se_fd);
  446.             sep->se_fd = -1;
  447.             continue;
  448.         }
  449.         if (sp->s_port != sep->se_ctrladdr.sin_port) {
  450.             sep->se_ctrladdr.sin_port = sp->s_port;
  451.             if (sep->se_fd != -1)
  452.                 (void) close(sep->se_fd);
  453.             sep->se_fd = -1;
  454.         }
  455.         if (sep->se_fd == -1)
  456.             setup(sep);
  457.     }
  458.     endconfig();
  459.     /*
  460.      * Purge anything not looked at above.
  461.      */
  462.     omask = sigblock(SIGBLOCK);
  463.     sepp = &servtab;
  464.     while (sep = *sepp) {
  465.         if (sep->se_checked) {
  466.             sepp = &sep->se_next;
  467.             continue;
  468.         }
  469.         *sepp = sep->se_next;
  470.         if (sep->se_fd != -1) {
  471.             FD_CLR(sep->se_fd, &allsock);
  472.             nsock--;
  473.             (void) close(sep->se_fd);
  474.         }
  475.         if (debug)
  476.             print_service("FREE", sep);
  477.         freeconfig(sep);
  478.         free((char *)sep);
  479.     }
  480.     (void) sigsetmask(omask);
  481. }
  482.  
  483. void
  484. retry()
  485. {
  486.     register struct servtab *sep;
  487.  
  488.     timingout = 0;
  489.     for (sep = servtab; sep; sep = sep->se_next)
  490.         if (sep->se_fd == -1)
  491.             setup(sep);
  492. }
  493.  
  494. setup(sep)
  495.     register struct servtab *sep;
  496. {
  497.     int on = 1;
  498.  
  499.     if ((sep->se_fd = socket(AF_INET, sep->se_socktype, 0)) < 0) {
  500.         syslog(LOG_ERR, "%s/%s: socket: %m",
  501.             sep->se_service, sep->se_proto);
  502.         return;
  503.     }
  504. #define    turnon(fd, opt) \
  505. setsockopt(fd, SOL_SOCKET, opt, (char *)&on, sizeof (on))
  506.     if (strcmp(sep->se_proto, "tcp") == 0 && (options & SO_DEBUG) &&
  507.         turnon(sep->se_fd, SO_DEBUG) < 0)
  508.         syslog(LOG_ERR, "setsockopt (SO_DEBUG): %m");
  509.     if (turnon(sep->se_fd, SO_REUSEADDR) < 0)
  510.         syslog(LOG_ERR, "setsockopt (SO_REUSEADDR): %m");
  511. #undef turnon
  512.     if (bind(sep->se_fd, (struct sockaddr *)&sep->se_ctrladdr,
  513.         sizeof (sep->se_ctrladdr)) < 0) {
  514.         syslog(LOG_ERR, "%s/%s: bind: %m",
  515.             sep->se_service, sep->se_proto);
  516.         (void) close(sep->se_fd);
  517.         sep->se_fd = -1;
  518.         if (!timingout) {
  519.             timingout = 1;
  520.             alarm(RETRYTIME);
  521.         }
  522.         return;
  523.     }
  524.     if (sep->se_socktype == SOCK_STREAM)
  525.         listen(sep->se_fd, 10);
  526.     FD_SET(sep->se_fd, &allsock);
  527.     nsock++;
  528.     if (sep->se_fd > maxsock)
  529.         maxsock = sep->se_fd;
  530. }
  531.  
  532. struct servtab *
  533. enter(cp)
  534.     struct servtab *cp;
  535. {
  536.     register struct servtab *sep;
  537.     long omask;
  538.  
  539.     sep = (struct servtab *)malloc(sizeof (*sep));
  540.     if (sep == (struct servtab *)0) {
  541.         syslog(LOG_ERR, "Out of memory.");
  542.         exit(-1);
  543.     }
  544.     *sep = *cp;
  545.     sep->se_fd = -1;
  546.     omask = sigblock(SIGBLOCK);
  547.     sep->se_next = servtab;
  548.     servtab = sep;
  549.     sigsetmask(omask);
  550.     return (sep);
  551. }
  552.  
  553. FILE    *fconfig = NULL;
  554. struct    servtab serv;
  555. char    line[256];
  556. char    *skip(), *nextline();
  557.  
  558. setconfig()
  559. {
  560.  
  561.     if (fconfig != NULL) {
  562.         fseek(fconfig, 0L, L_SET);
  563.         return (1);
  564.     }
  565.     fconfig = fopen(CONFIG, "r");
  566.     return (fconfig != NULL);
  567. }
  568.  
  569. endconfig()
  570. {
  571.     if (fconfig) {
  572.         (void) fclose(fconfig);
  573.         fconfig = NULL;
  574.     }
  575. }
  576.  
  577. struct servtab *
  578. getconfigent()
  579. {
  580.     register struct servtab *sep = &serv;
  581.     int argc;
  582.     char *cp, *arg, *newstr();
  583.  
  584. more:
  585.     while ((cp = nextline(fconfig)) && *cp == '#')
  586.         ;
  587.     if (cp == NULL)
  588.         return ((struct servtab *)0);
  589.     sep->se_service = newstr(skip(&cp));
  590.     arg = skip(&cp);
  591.     if (strcmp(arg, "stream") == 0)
  592.         sep->se_socktype = SOCK_STREAM;
  593.     else if (strcmp(arg, "dgram") == 0)
  594.         sep->se_socktype = SOCK_DGRAM;
  595.     else if (strcmp(arg, "rdm") == 0)
  596.         sep->se_socktype = SOCK_RDM;
  597.     else if (strcmp(arg, "seqpacket") == 0)
  598.         sep->se_socktype = SOCK_SEQPACKET;
  599.     else if (strcmp(arg, "raw") == 0)
  600.         sep->se_socktype = SOCK_RAW;
  601.     else
  602.         sep->se_socktype = -1;
  603.     sep->se_proto = newstr(skip(&cp));
  604.     arg = skip(&cp);
  605.     sep->se_wait = strcmp(arg, "wait") == 0;
  606.     sep->se_user = newstr(skip(&cp));
  607.     sep->se_server = newstr(skip(&cp));
  608.     if (strcmp(sep->se_server, "internal") == 0) {
  609.         register struct biltin *bi;
  610.  
  611.         for (bi = biltins; bi->bi_service; bi++)
  612.             if (bi->bi_socktype == sep->se_socktype &&
  613.                 strcmp(bi->bi_service, sep->se_service) == 0)
  614.                 break;
  615.         if (bi->bi_service == 0) {
  616.             syslog(LOG_ERR, "internal service %s unknown\n",
  617.                 sep->se_service);
  618.             goto more;
  619.         }
  620.         sep->se_bi = bi;
  621.         sep->se_wait = bi->bi_wait;
  622.     } else
  623.         sep->se_bi = NULL;
  624.     argc = 0;
  625.     for (arg = skip(&cp); cp; arg = skip(&cp))
  626.         if (argc < MAXARGV)
  627.             sep->se_argv[argc++] = newstr(arg);
  628.     while (argc <= MAXARGV)
  629.         sep->se_argv[argc++] = NULL;
  630.     return (sep);
  631. }
  632.  
  633. freeconfig(cp)
  634.     register struct servtab *cp;
  635. {
  636.     int i;
  637.  
  638.     if (cp->se_service)
  639.         free(cp->se_service);
  640.     if (cp->se_proto)
  641.         free(cp->se_proto);
  642.     if (cp->se_user)
  643.         free(cp->se_user);
  644.     if (cp->se_server)
  645.         free(cp->se_server);
  646.     for (i = 0; i < MAXARGV; i++)
  647.         if (cp->se_argv[i])
  648.             free(cp->se_argv[i]);
  649. }
  650.  
  651. char *
  652. skip(cpp)
  653.     char **cpp;
  654. {
  655.     register char *cp = *cpp;
  656.     char *start;
  657.  
  658. again:
  659.     while (*cp == ' ' || *cp == '\t')
  660.         cp++;
  661.     if (*cp == '\0') {
  662.         int c;
  663.  
  664.         c = getc(fconfig);
  665.         (void) ungetc(c, fconfig);
  666.         if (c == ' ' || c == '\t')
  667.             if (cp = nextline(fconfig))
  668.                 goto again;
  669.         *cpp = (char *)0;
  670.         return ((char *)0);
  671.     }
  672.     start = cp;
  673.     while (*cp && *cp != ' ' && *cp != '\t')
  674.         cp++;
  675.     if (*cp != '\0')
  676.         *cp++ = '\0';
  677.     *cpp = cp;
  678.     return (start);
  679. }
  680.  
  681. char *
  682. nextline(fd)
  683.     FILE *fd;
  684. {
  685.     char *cp;
  686.  
  687.     if (fgets(line, sizeof (line), fd) == NULL)
  688.         return ((char *)0);
  689.     cp = index(line, '\n');
  690.     if (cp)
  691.         *cp = '\0';
  692.     return (line);
  693. }
  694.  
  695. char *
  696. newstr(cp)
  697.     char *cp;
  698. {
  699.     if (cp = strdup(cp ? cp : ""))
  700.         return(cp);
  701.     syslog(LOG_ERR, "strdup: %m");
  702.     exit(-1);
  703. }
  704.  
  705. setproctitle(a, s)
  706.     char *a;
  707.     int s;
  708. {
  709.     int size;
  710.     register char *cp;
  711.     struct sockaddr_in sin;
  712.     char buf[80];
  713.  
  714.     cp = Argv[0];
  715.     size = sizeof(sin);
  716.     if (getpeername(s, (struct sockaddr *)&sin, &size) == 0)
  717.         (void) sprintf(buf, "-%s [%s]", a, inet_ntoa(sin.sin_addr)); 
  718.     else
  719.         (void) sprintf(buf, "-%s", a); 
  720.     strncpy(cp, buf, LastArg - cp);
  721.     cp += strlen(cp);
  722.     while (cp < LastArg)
  723.         *cp++ = ' ';
  724. }
  725.  
  726. /*
  727.  * Internet services provided internally by inetd:
  728.  */
  729. #define    BUFSIZE    8192
  730.  
  731. /* ARGSUSED */
  732. echo_stream(s, sep)        /* Echo service -- echo data back */
  733.     int s;
  734.     struct servtab *sep;
  735. {
  736.     char buffer[BUFSIZE];
  737.     int i;
  738.  
  739.     setproctitle(sep->se_service, s);
  740.     while ((i = read(s, buffer, sizeof(buffer))) > 0 &&
  741.         write(s, buffer, i) > 0)
  742.         ;
  743.     exit(0);
  744. }
  745.  
  746. /* ARGSUSED */
  747. echo_dg(s, sep)            /* Echo service -- echo data back */
  748.     int s;
  749.     struct servtab *sep;
  750. {
  751.     char buffer[BUFSIZE];
  752.     int i, size;
  753.     struct sockaddr sa;
  754.  
  755.     size = sizeof(sa);
  756.     if ((i = recvfrom(s, buffer, sizeof(buffer), 0, &sa, &size)) < 0)
  757.         return;
  758.     (void) sendto(s, buffer, i, 0, &sa, sizeof(sa));
  759. }
  760.  
  761. /* ARGSUSED */
  762. discard_stream(s, sep)        /* Discard service -- ignore data */
  763.     int s;
  764.     struct servtab *sep;
  765. {
  766.     int ret;
  767.     char buffer[BUFSIZE];
  768.  
  769.     setproctitle(sep->se_service, s);
  770.     while (1) {
  771.         while ((ret = read(s, buffer, sizeof(buffer))) > 0)
  772.             ;
  773.         if (ret == 0 || errno != EINTR)
  774.             break;
  775.     }
  776.     exit(0);
  777. }
  778.  
  779. /* ARGSUSED */
  780. discard_dg(s, sep)        /* Discard service -- ignore data */
  781.     int s;
  782.     struct servtab *sep;
  783. {
  784.     char buffer[BUFSIZE];
  785.  
  786.     (void) read(s, buffer, sizeof(buffer));
  787. }
  788.  
  789. #include <ctype.h>
  790. #define LINESIZ 72
  791. char ring[128];
  792. char *endring;
  793.  
  794. initring()
  795. {
  796.     register int i;
  797.  
  798.     endring = ring;
  799.  
  800.     for (i = 0; i <= 128; ++i)
  801.         if (isprint(i))
  802.             *endring++ = i;
  803. }
  804.  
  805. /* ARGSUSED */
  806. chargen_stream(s, sep)        /* Character generator */
  807.     int s;
  808.     struct servtab *sep;
  809. {
  810.     register char *rs;
  811.     int len;
  812.     char text[LINESIZ+2];
  813.  
  814.     setproctitle(sep->se_service, s);
  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 (write(s, text, sizeof(text)) != sizeof(text))
  833.             break;
  834.     }
  835.     exit(0);
  836. }
  837.  
  838. /* ARGSUSED */
  839. chargen_dg(s, sep)        /* Character generator */
  840.     int s;
  841.     struct servtab *sep;
  842. {
  843.     struct sockaddr sa;
  844.     static char *rs;
  845.     int len, size;
  846.     char text[LINESIZ+2];
  847.  
  848.     if (endring == 0) {
  849.         initring();
  850.         rs = ring;
  851.     }
  852.  
  853.     size = sizeof(sa);
  854.     if (recvfrom(s, text, sizeof(text), 0, &sa, &size) < 0)
  855.         return;
  856.  
  857.     if ((len = endring - rs) >= LINESIZ)
  858.         bcopy(rs, text, LINESIZ);
  859.     else {
  860.         bcopy(rs, text, len);
  861.         bcopy(ring, text + len, LINESIZ - len);
  862.     }
  863.     if (++rs == endring)
  864.         rs = ring;
  865.     text[LINESIZ] = '\r';
  866.     text[LINESIZ + 1] = '\n';
  867.     (void) sendto(s, text, sizeof(text), 0, &sa, sizeof(sa));
  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
  879. machtime()
  880. {
  881.     struct timeval tv;
  882.  
  883.     if (gettimeofday(&tv, (struct timezone *)0) < 0) {
  884.         fprintf(stderr, "Unable to get time of day\n");
  885.         return (0L);
  886.     }
  887.     return (htonl((long)tv.tv_sec + 2208988800));
  888. }
  889.  
  890. /* ARGSUSED */
  891. machtime_stream(s, sep)
  892.     int s;
  893.     struct servtab *sep;
  894. {
  895.     long result;
  896.  
  897.     result = machtime();
  898.     (void) write(s, (char *) &result, sizeof(result));
  899. }
  900.  
  901. /* ARGSUSED */
  902. machtime_dg(s, sep)
  903.     int s;
  904.     struct servtab *sep;
  905. {
  906.     long result;
  907.     struct sockaddr sa;
  908.     int size;
  909.  
  910.     size = sizeof(sa);
  911.     if (recvfrom(s, (char *)&result, sizeof(result), 0, &sa, &size) < 0)
  912.         return;
  913.     result = machtime();
  914.     (void) sendto(s, (char *) &result, sizeof(result), 0, &sa, sizeof(sa));
  915. }
  916.  
  917. /* ARGSUSED */
  918. daytime_stream(s, sep)        /* Return human-readable time of day */
  919.     int s;
  920.     struct servtab *sep;
  921. {
  922.     char buffer[256];
  923.     time_t time(), clock;
  924.     char *ctime();
  925.  
  926.     clock = time((time_t *) 0);
  927.  
  928.     (void) sprintf(buffer, "%.24s\r\n", ctime(&clock));
  929.     (void) write(s, buffer, strlen(buffer));
  930. }
  931.  
  932. /* ARGSUSED */
  933. daytime_dg(s, sep)        /* Return human-readable time of day */
  934.     int s;
  935.     struct servtab *sep;
  936. {
  937.     char buffer[256];
  938.     time_t time(), clock;
  939.     struct sockaddr sa;
  940.     int size;
  941.     char *ctime();
  942.  
  943.     clock = time((time_t *) 0);
  944.  
  945.     size = sizeof(sa);
  946.     if (recvfrom(s, buffer, sizeof(buffer), 0, &sa, &size) < 0)
  947.         return;
  948.     (void) sprintf(buffer, "%.24s\r\n", ctime(&clock));
  949.     (void) sendto(s, buffer, strlen(buffer), 0, &sa, sizeof(sa));
  950. }
  951.  
  952. /*
  953.  * print_service:
  954.  *    Dump relevant information to stderr
  955.  */
  956. print_service(action, sep)
  957.     char *action;
  958.     struct servtab *sep;
  959. {
  960.     fprintf(stderr,
  961.         "%s: %s proto=%s, wait=%d, user=%s builtin=%x server=%s\n",
  962.         action, sep->se_service, sep->se_proto,
  963.         sep->se_wait, sep->se_user, (int)sep->se_bi, sep->se_server);
  964. }
  965.