home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / N / TCPIP / NETKIT-B.05 / NETKIT-B / NetKit-B-0.05 / inetd / inetd.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-05-23  |  36.5 KB  |  1,623 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[] = "from: @(#)inetd.c    5.30 (Berkeley) 6/3/91";*/
  42. static char rcsid[] = "$Id: inetd.c,v 1.1 1994/05/23 09:04:44 rzsfl Exp rzsfl $";
  43. #endif /* not lint */
  44.  
  45. /*
  46.  * Inetd - Internet super-server
  47.  *
  48.  * This program invokes all internet services as needed.
  49.  * connection-oriented services are invoked each time a
  50.  * connection is made, by creating a process.  This process
  51.  * is passed the connection as file descriptor 0 and is
  52.  * expected to do a getpeername to find out the source host
  53.  * and port.
  54.  *
  55.  * Datagram oriented services are invoked when a datagram
  56.  * arrives; a process is created and passed a pending message
  57.  * on file descriptor 0.  Datagram servers may either connect
  58.  * to their peer, freeing up the original socket for inetd
  59.  * to receive further messages on, or ``take over the socket'',
  60.  * processing all arriving datagrams and, eventually, timing
  61.  * out.     The first type of server is said to be ``multi-threaded'';
  62.  * the second type of server ``single-threaded''. 
  63.  *
  64.  * Inetd uses a configuration file which is read at startup
  65.  * and, possibly, at some later time in response to a hangup signal.
  66.  * The configuration file is ``free format'' with fields given in the
  67.  * order shown below.  Continuation lines for an entry must being with
  68.  * a space or tab.  All fields must be present in each entry.
  69.  *
  70.  *    service name            must be in /etc/services
  71.  *    socket type            stream/dgram/raw/rdm/seqpacket
  72.  *    protocol            must be in /etc/protocols
  73.  *    wait/nowait[.max]        single-threaded/multi-threaded, max #
  74.  *    user[.group]            user/group to run daemon as
  75.  *    server program            full path name
  76.  *    server program arguments    maximum of MAXARGS (20)
  77.  *
  78.  * For RPC services
  79.  *      service name/version            must be in /etc/rpc
  80.  *    socket type            stream/dgram/raw/rdm/seqpacket
  81.  *    protocol            must be in /etc/protocols
  82.  *    wait/nowait[.max]        single-threaded/multi-threaded
  83.  *    user[.group]            user to run daemon as
  84.  *    server program            full path name
  85.  *    server program arguments    maximum of MAXARGS (20)
  86.  *
  87.  * Comment lines are indicated by a `#' in column 1.
  88.  */
  89.  
  90. /*
  91.  * Here's the scoop concerning the user.group feature:
  92.  *
  93.  * 1) set-group-option off.
  94.  * 
  95.  *     a) user = root:    NO setuid() or setgid() is done
  96.  * 
  97.  *     b) other:    setuid()
  98.  *             setgid(primary group as found in passwd)
  99.  *             initgroups(name, primary group)
  100.  * 
  101.  * 2) set-group-option on.
  102.  * 
  103.  *     a) user = root:    NO setuid()
  104.  *             setgid(specified group)
  105.  *             NO initgroups()
  106.  * 
  107.  *     b) other:    setuid()
  108.  *             setgid(specified group)
  109.  *             initgroups(name, specified group)
  110.  * 
  111.  */
  112.  
  113. #include <sys/param.h>
  114. #include <sys/stat.h>
  115. #include <sys/ioctl.h>
  116. #include <sys/socket.h>
  117. #include <sys/un.h>
  118. #include <sys/file.h>
  119. #include <sys/wait.h>
  120. #include <sys/time.h>
  121. #include <sys/resource.h>
  122.  
  123. #ifndef __linux__
  124. #ifndef RLIMIT_NOFILE
  125. #define RLIMIT_NOFILE    RLIMIT_OFILE
  126. #endif
  127. #endif
  128.  
  129. #define RPC
  130.  
  131. #include <sys/param.h>
  132. #include <sys/stat.h>
  133. #include <sys/ioctl.h>
  134. #include <sys/socket.h>
  135. #include <sys/file.h>
  136. #include <sys/wait.h>
  137. #include <sys/time.h>
  138. #include <sys/resource.h>
  139.  
  140. #include <netinet/in.h>
  141. #include <arpa/inet.h>
  142.  
  143. #include <errno.h>
  144. #include <signal.h>
  145. #include <netdb.h>
  146. #include <syslog.h>
  147. #include <pwd.h>
  148. #include <grp.h>
  149. #include <stdio.h>
  150. #include <string.h>
  151. #ifdef RPC
  152. #include <rpc/rpc.h>
  153. #endif
  154. #include "pathnames.h"
  155.  
  156. #define    TOOMANY        40        /* don't start more than TOOMANY */
  157. #define    CNT_INTVL    60        /* servers in CNT_INTVL sec. */
  158. #define    RETRYTIME    (60*10)        /* retry after bind or server fail */
  159.  
  160. #define    SIGBLOCK    (sigmask(SIGCHLD)|sigmask(SIGHUP)|sigmask(SIGALRM))
  161.  
  162. extern    int errno;
  163.  
  164. void    config(), reapchild(), retry(), goaway();
  165. char    *index();
  166.  
  167. int    debug = 0;
  168. int    nsock, maxsock;
  169. fd_set    allsock;
  170. int    options;
  171. int    timingout;
  172. struct    servent *sp;
  173. char    *curdom;
  174.  
  175. #ifndef OPEN_MAX
  176. #define OPEN_MAX    64
  177. #endif
  178.  
  179. /* Reserve some descriptors, 3 stdio + at least: 1 log, 1 conf. file */
  180. #define FD_MARGIN    (8)
  181. int    rlim_ofile_cur = OPEN_MAX;
  182.  
  183. #ifdef RLIMIT_NOFILE
  184. struct rlimit    rlim_ofile;
  185. #endif
  186.  
  187. struct    servtab {
  188.     char    *se_service;        /* name of service */
  189.     int    se_socktype;        /* type of socket to use */
  190.     int    se_family;        /* address family */
  191.     char    *se_proto;        /* protocol used */
  192.     int    se_rpcprog;        /* rpc program number */
  193.     int    se_rpcversl;        /* rpc program lowest version */
  194.     int    se_rpcversh;        /* rpc program highest version */
  195. #define isrpcservice(sep)    ((sep)->se_rpcversl != 0)
  196.     short    se_wait;        /* single threaded server */
  197.     short    se_checked;        /* looked at during merge */
  198.     char    *se_user;        /* user name to run as */
  199.     char    *se_group;        /* group name to run as */
  200.     struct    biltin *se_bi;        /* if built-in, description */
  201.     char    *se_server;        /* server program */
  202. #define    MAXARGV 20
  203.     char    *se_argv[MAXARGV+1];    /* program arguments */
  204.     int    se_fd;            /* open descriptor */
  205.     union {
  206.         struct    sockaddr se_un_ctrladdr;
  207.         struct    sockaddr_in se_un_ctrladdr_in;
  208.         struct    sockaddr_un se_un_ctrladdr_un;
  209.     } se_un;            /* bound address */
  210. #define se_ctrladdr    se_un.se_un_ctrladdr
  211. #define se_ctrladdr_in    se_un.se_un_ctrladdr_in
  212. #define se_ctrladdr_un    se_un.se_un_ctrladdr_un
  213.     int    se_ctrladdr_size;
  214.     int    se_max;            /* max # of instances of this service */
  215.     int    se_count;        /* number started since se_time */
  216.     struct    timeval se_time;    /* start of se_count */
  217. #ifdef MULOG
  218.     int    se_log;
  219. #define MULOG_RFC931    0x40000000
  220. #endif
  221.     struct    servtab *se_next;
  222. } *servtab;
  223.  
  224. int echo_stream(), discard_stream(), machtime_stream();
  225. int daytime_stream(), chargen_stream();
  226. int echo_dg(), discard_dg(), machtime_dg(), daytime_dg(), chargen_dg();
  227.  
  228. struct biltin {
  229.     char    *bi_service;        /* internally provided service name */
  230.     int    bi_socktype;        /* type of socket supported */
  231.     short    bi_fork;        /* 1 if should fork before call */
  232.     short    bi_wait;        /* 1 if should wait for child */
  233.     int    (*bi_fn)();        /* function which performs it */
  234. } biltins[] = {
  235.     /* Echo received data */
  236.     "echo",        SOCK_STREAM,    1, 0,    echo_stream,
  237.     "echo",        SOCK_DGRAM,    0, 0,    echo_dg,
  238.  
  239.     /* Internet /dev/null */
  240.     "discard",    SOCK_STREAM,    1, 0,    discard_stream,
  241.     "discard",    SOCK_DGRAM,    0, 0,    discard_dg,
  242.  
  243.     /* Return 32 bit time since 1900 */
  244.     "time",        SOCK_STREAM,    0, 0,    machtime_stream,
  245.     "time",        SOCK_DGRAM,    0, 0,    machtime_dg,
  246.  
  247.     /* Return human-readable time */
  248.     "daytime",    SOCK_STREAM,    0, 0,    daytime_stream,
  249.     "daytime",    SOCK_DGRAM,    0, 0,    daytime_dg,
  250.  
  251.     /* Familiar character generator */
  252.     "chargen",    SOCK_STREAM,    1, 0,    chargen_stream,
  253.     "chargen",    SOCK_DGRAM,    0, 0,    chargen_dg,
  254.     0
  255. };
  256.  
  257. #define NUMINT    (sizeof(intab) / sizeof(struct inent))
  258. char    *CONFIG = _PATH_INETDCONF;
  259. char    **Argv;
  260. char     *LastArg;
  261. char    *progname;
  262.  
  263. #ifdef sun
  264. /*
  265.  * Sun's RPC library caches the result of `dtablesize()'
  266.  * This is incompatible with our "bumping" of file descriptors "on demand"
  267.  */
  268. int
  269. _rpc_dtablesize()
  270. {
  271.     return rlim_ofile_cur;
  272. }
  273. #endif
  274.  
  275. main(argc, argv, envp)
  276.     int argc;
  277.     char *argv[], *envp[];
  278. {
  279.     extern char *optarg;
  280.     extern int optind;
  281.     register struct servtab *sep;
  282.     register struct passwd *pwd;
  283.     register struct group *grp;
  284.     register int tmpint;
  285.     struct sigvec sv;
  286.     int ch, pid, dofork;
  287.     char buf[50];
  288.  
  289.     Argv = argv;
  290.     if (envp == 0 || *envp == 0)
  291.         envp = argv;
  292.     while (*envp)
  293.         envp++;
  294.     LastArg = envp[-1] + strlen(envp[-1]);
  295.  
  296.     progname = strrchr(argv[0], '/');
  297.     progname = progname ? progname + 1 : argv[0];
  298.  
  299.     while ((ch = getopt(argc, argv, "d")) != EOF)
  300.         switch(ch) {
  301.         case 'd':
  302.             debug = 1;
  303.             options |= SO_DEBUG;
  304.             break;
  305.         case '?':
  306.         default:
  307.             fprintf(stderr, "usage: %s [-d] [conf]", progname);
  308.             exit(1);
  309.         }
  310.     argc -= optind;
  311.     argv += optind;
  312.  
  313.     if (argc > 0)
  314.         CONFIG = argv[0];
  315.  
  316.     if (debug == 0)
  317.         daemon(0, 0);
  318.     openlog(progname, LOG_PID | LOG_NOWAIT, LOG_DAEMON);
  319.     logpid();
  320.  
  321. #ifdef RLIMIT_NOFILE
  322.     if (getrlimit(RLIMIT_NOFILE, &rlim_ofile) < 0) {
  323.         syslog(LOG_ERR, "getrlimit: %m");
  324.     } else {
  325.         rlim_ofile_cur = rlim_ofile.rlim_cur;
  326.         if (rlim_ofile_cur == RLIM_INFINITY)    /* ! */
  327.             rlim_ofile_cur = OPEN_MAX;
  328.     }
  329. #endif
  330.  
  331.     bzero((char *)&sv, sizeof(sv));
  332.     sv.sv_mask = SIGBLOCK;
  333.     sv.sv_handler = retry;
  334.     sigvec(SIGALRM, &sv, (struct sigvec *)0);
  335.     config();
  336.     sv.sv_handler = config;
  337.     sigvec(SIGHUP, &sv, (struct sigvec *)0);
  338.     sv.sv_handler = reapchild;
  339.     sigvec(SIGCHLD, &sv, (struct sigvec *)0);
  340.     sv.sv_handler = goaway;
  341.     sigvec(SIGTERM, &sv, (struct sigvec *)0);
  342.     sv.sv_handler = goaway;
  343.     sigvec(SIGINT, &sv, (struct sigvec *)0);
  344.  
  345.     {
  346.         /* space for daemons to overwrite environment for ps */
  347. #define    DUMMYSIZE    100
  348.         char dummy[DUMMYSIZE];
  349.  
  350.         (void)memset(dummy, 'x', DUMMYSIZE - 1);
  351.         dummy[DUMMYSIZE - 1] = '\0';
  352.  
  353.         (void)setenv("inetd_dummy", dummy, 1);
  354.     }
  355.  
  356.     for (;;) {
  357.         int n, ctrl;
  358.         fd_set readable;
  359.  
  360.         if (nsock == 0) {
  361.         (void) sigblock(SIGBLOCK);
  362.         while (nsock == 0)
  363.             sigpause(0L);
  364.         (void) sigsetmask(0L);
  365.         }
  366.         readable = allsock;
  367.         if ((n = select(maxsock + 1, &readable, (fd_set *)0,
  368.         (fd_set *)0, (struct timeval *)0)) <= 0) {
  369.             if (n < 0 && errno != EINTR)
  370.             syslog(LOG_WARNING, "select: %m\n");
  371.             sleep(1);
  372.             continue;
  373.         }
  374.         for (sep = servtab; n && sep; sep = sep->se_next)
  375.         if (sep->se_fd != -1 && FD_ISSET(sep->se_fd, &readable)) {
  376.         n--;
  377.         if (debug)
  378.             fprintf(stderr, "someone wants %s\n", sep->se_service);
  379.         if (!sep->se_wait && sep->se_socktype == SOCK_STREAM) {
  380.             /* Fixed AGC */
  381.             fcntl(sep->se_fd,F_SETFL,O_NDELAY);
  382.             /* --------- */
  383.             ctrl = accept(sep->se_fd, (struct sockaddr *)0,
  384.                 (int *)0);
  385.             fcntl(sep->se_fd,F_SETFL, 0);
  386.             if (debug)
  387.                 fprintf(stderr, "accept, ctrl %d\n", ctrl);
  388.             if (ctrl < 0) {
  389.                 if (errno == EINTR || errno == EWOULDBLOCK)
  390.                     continue;
  391.                 syslog(LOG_WARNING, "accept (for %s): %m",
  392.                     sep->se_service);
  393.                 continue;
  394.             }
  395.         } else
  396.             ctrl = sep->se_fd;
  397.         (void) sigblock(SIGBLOCK);
  398.         pid = 0;
  399.         dofork = (sep->se_bi == 0 || sep->se_bi->bi_fork);
  400.         if (dofork) {
  401.             if (sep->se_count++ == 0)
  402.                 (void)gettimeofday(&sep->se_time,
  403.                     (struct timezone *)0);
  404.             else if (sep->se_count >= sep->se_max) {
  405.                 struct timeval now;
  406.  
  407.                 (void)gettimeofday(&now, (struct timezone *)0);
  408.                 if (now.tv_sec - sep->se_time.tv_sec >
  409.                     CNT_INTVL) {
  410.                     sep->se_time = now;
  411.                     sep->se_count = 1;
  412.                 } else {
  413.                     syslog(LOG_ERR,
  414.             "%s/%s server failing (looping), service terminated\n",
  415.                         sep->se_service, sep->se_proto);
  416.                     FD_CLR(sep->se_fd, &allsock);
  417.                     (void) close(sep->se_fd);
  418.                     sep->se_fd = -1;
  419.                     sep->se_count = 0;
  420.                     nsock--;
  421.                     sigsetmask(0L);
  422.                     if (!timingout) {
  423.                         timingout = 1;
  424.                         alarm(RETRYTIME);
  425.                     }
  426.                     continue;
  427.                 }
  428.             }
  429.             pid = fork();
  430.         }
  431.         if (pid < 0) {
  432.             syslog(LOG_ERR, "fork: %m");
  433.             if (sep->se_socktype == SOCK_STREAM)
  434.                 close(ctrl);
  435.             sigsetmask(0L);
  436.             sleep(1);
  437.             continue;
  438.         }
  439.         if (pid && sep->se_wait) {
  440.             sep->se_wait = pid;
  441.             FD_CLR(sep->se_fd, &allsock);
  442.             nsock--;
  443.         }
  444.         sigsetmask(0L);
  445.         if (pid == 0) {
  446.             if (debug && dofork)
  447.                 setsid();
  448.             if (sep->se_bi)
  449.                 (*sep->se_bi->bi_fn)(ctrl, sep);
  450.             else {
  451.                 if ((pwd = getpwnam(sep->se_user)) == NULL) {
  452.                     syslog(LOG_ERR,
  453.                         "getpwnam: %s: No such user",
  454.                         sep->se_user);
  455.                     if (sep->se_socktype != SOCK_STREAM)
  456.                         recv(0, buf, sizeof (buf), 0);
  457.                     _exit(1);
  458.                 }
  459.                 if (sep->se_group &&
  460.                     (grp = getgrnam(sep->se_group)) == NULL) {
  461.                     syslog(LOG_ERR,
  462.                         "getgrnam: %s: No such group",
  463.                         sep->se_group);
  464.                     if (sep->se_socktype != SOCK_STREAM)
  465.                         recv(0, buf, sizeof (buf), 0);
  466.                     _exit(1);
  467.                 }
  468.                 if (pwd->pw_uid) {
  469.                     if (sep->se_group)
  470.                         pwd->pw_gid = grp->gr_gid;
  471.                     (void) setgid((gid_t)pwd->pw_gid);
  472.                     initgroups(pwd->pw_name, pwd->pw_gid);
  473.                     (void) setuid((uid_t)pwd->pw_uid);
  474.                 } else if (sep->se_group) {
  475.                     (void) setgid((gid_t)grp->gr_gid);
  476.                 }
  477.                 if (debug)
  478.                     fprintf(stderr, "%d execl %s\n",
  479.                         getpid(), sep->se_server);
  480. #ifdef MULOG
  481.                 if (sep->se_log)
  482.                     dolog(sep, ctrl);
  483. #endif
  484.                 dup2(ctrl, 0);
  485.                 close(ctrl);
  486.                 dup2(0, 1);
  487.                 dup2(0, 2);
  488. #ifdef RLIMIT_NOFILE
  489.                 if (rlim_ofile.rlim_cur != rlim_ofile_cur) {
  490.                     if (setrlimit(RLIMIT_NOFILE,
  491.                             &rlim_ofile) < 0)
  492.                         syslog(LOG_ERR,"setrlimit: %m");
  493.                 }
  494. #endif
  495.                 for (tmpint = rlim_ofile_cur-1; --tmpint > 2; )
  496.                     (void)close(tmpint);
  497.                 execv(sep->se_server, sep->se_argv);
  498.                 if (sep->se_socktype != SOCK_STREAM)
  499.                     recv(0, buf, sizeof (buf), 0);
  500.                 syslog(LOG_ERR, "execv %s: %m", sep->se_server);
  501.                 _exit(1);
  502.             }
  503.         }
  504.         if (!sep->se_wait && sep->se_socktype == SOCK_STREAM)
  505.             close(ctrl);
  506.         }
  507.     }
  508. }
  509.  
  510. void
  511. reapchild()
  512. {
  513.     int status;
  514.     int pid;
  515.     register struct servtab *sep;
  516.  
  517.     for (;;) {
  518.         pid = wait3(&status, WNOHANG, (struct rusage *)0);
  519.         if (pid <= 0)
  520.             break;
  521.         if (debug)
  522.             fprintf(stderr, "%d reaped\n", pid);
  523.         for (sep = servtab; sep; sep = sep->se_next)
  524.             if (sep->se_wait == pid) {
  525.                 if (WIFEXITED(status) && WEXITSTATUS(status))
  526.                     syslog(LOG_WARNING,
  527.                         "%s: exit status 0x%x",
  528.                         sep->se_server, WEXITSTATUS(status));
  529.                 else if (WIFSIGNALED(status))
  530.                     syslog(LOG_WARNING,
  531.                         "%s: exit signal 0x%x",
  532.                         sep->se_server, WTERMSIG(status));
  533.                 sep->se_wait = 1;
  534.                 FD_SET(sep->se_fd, &allsock);
  535.                 nsock++;
  536.                 if (debug)
  537.                     fprintf(stderr, "restored %s, fd %d\n",
  538.                         sep->se_service, sep->se_fd);
  539.             }
  540.     }
  541. }
  542.  
  543. void
  544. config()
  545. {
  546.     register struct servtab *sep, *cp, **sepp;
  547.     struct servtab *getconfigent(), *enter();
  548.     long omask;
  549.     int n;
  550.  
  551.     if (!setconfig()) {
  552.         syslog(LOG_ERR, "%s: %m", CONFIG);
  553.         return;
  554.     }
  555.     for (sep = servtab; sep; sep = sep->se_next)
  556.         sep->se_checked = 0;
  557.     while (cp = getconfigent()) {
  558.         for (sep = servtab; sep; sep = sep->se_next)
  559.             if (strcmp(sep->se_service, cp->se_service) == 0 &&
  560.                 strcmp(sep->se_proto, cp->se_proto) == 0)
  561.                 break;
  562.         if (sep != 0) {
  563.             int i;
  564.  
  565. #define SWAP(type, a, b) {type c=(type)a; (type)a=(type)b; (type)b=(type)c;}
  566.  
  567.             omask = sigblock(SIGBLOCK);
  568.             /*
  569.              * sep->se_wait may be holding the pid of a daemon
  570.              * that we're waiting for.  If so, don't overwrite
  571.              * it unless the config file explicitly says don't 
  572.              * wait.
  573.              */
  574.             if (cp->se_bi == 0 && 
  575.                 (sep->se_wait == 1 || cp->se_wait == 0))
  576.                 sep->se_wait = cp->se_wait;
  577.             if (cp->se_max != sep->se_max)
  578.                 SWAP(int, cp->se_max, sep->se_max);
  579.             if (cp->se_user)
  580.                 SWAP(char *, sep->se_user, cp->se_user);
  581.             if (cp->se_group)
  582.                 SWAP(char *, sep->se_group, cp->se_group);
  583.             if (cp->se_server)
  584.                 SWAP(char *, sep->se_server, cp->se_server);
  585.             for (i = 0; i < MAXARGV; i++)
  586.                 SWAP(char *, sep->se_argv[i], cp->se_argv[i]);
  587. #undef SWAP
  588.             if (isrpcservice(sep))
  589.                 unregister_rpc(sep);
  590.             sep->se_rpcversl = cp->se_rpcversl;
  591.             sep->se_rpcversh = cp->se_rpcversh;
  592.             sigsetmask(omask);
  593.             freeconfig(cp);
  594.             if (debug)
  595.                 print_service("REDO", sep);
  596.         } else {
  597.             sep = enter(cp);
  598.             if (debug)
  599.                 print_service("ADD ", sep);
  600.         }
  601.         sep->se_checked = 1;
  602.  
  603.         switch (sep->se_family) {
  604.         case AF_UNIX:
  605.             if (sep->se_fd != -1)
  606.                 break;
  607.             (void)unlink(sep->se_service);
  608.             n = strlen(sep->se_service);
  609.             if (n > sizeof sep->se_ctrladdr_un.sun_path - 1) 
  610.                 n = sizeof sep->se_ctrladdr_un.sun_path - 1;
  611.             strncpy(sep->se_ctrladdr_un.sun_path, sep->se_service, n);
  612.             sep->se_ctrladdr_un.sun_family = AF_UNIX;
  613.             sep->se_ctrladdr_size = n +
  614.                     sizeof sep->se_ctrladdr_un.sun_family;
  615.             setup(sep);
  616.             break;
  617.         case AF_INET:
  618.             sep->se_ctrladdr_in.sin_family = AF_INET;
  619.             sep->se_ctrladdr_size = sizeof sep->se_ctrladdr_in;
  620.             if (isrpcservice(sep)) {
  621.                 struct rpcent *rp;
  622.  
  623.                 sep->se_rpcprog = atoi(sep->se_service);
  624.                 if (sep->se_rpcprog == 0) {
  625.                     rp = getrpcbyname(sep->se_service);
  626.                     if (rp == 0) {
  627.                         syslog(LOG_ERR,
  628.                             "%s: unknown service",
  629.                             sep->se_service);
  630.                         continue;
  631.                     }
  632.                     sep->se_rpcprog = rp->r_number;
  633.                 }
  634.                 if (sep->se_fd == -1)
  635.                     setup(sep);
  636.                 if (sep->se_fd != -1)
  637.                     register_rpc(sep);
  638.             } else {
  639.                 u_short port = htons(atoi(sep->se_service));
  640.  
  641.                 if (!port) {
  642.                     sp = getservbyname(sep->se_service,
  643.                                 sep->se_proto);
  644.                     if (sp == 0) {
  645.                         syslog(LOG_ERR,
  646.                             "%s/%s: unknown service",
  647.                             sep->se_service, sep->se_proto);
  648.                         continue;
  649.                     }
  650.                     port = sp->s_port;
  651.                 }
  652.                 if (port != sep->se_ctrladdr_in.sin_port) {
  653.                     sep->se_ctrladdr_in.sin_port = port;
  654.                     if (sep->se_fd != -1) {
  655.                         FD_CLR(sep->se_fd, &allsock);
  656.                         nsock--;
  657.                         (void) close(sep->se_fd);
  658.                     }
  659.                     sep->se_fd = -1;
  660.                 }
  661.                 if (sep->se_fd == -1)
  662.                     setup(sep);
  663.             }
  664.         }
  665.     }
  666.     endconfig();
  667.     /*
  668.      * Purge anything not looked at above.
  669.      */
  670.     omask = sigblock(SIGBLOCK);
  671.     sepp = &servtab;
  672.     while (sep = *sepp) {
  673.         if (sep->se_checked) {
  674.             sepp = &sep->se_next;
  675.             continue;
  676.         }
  677.         *sepp = sep->se_next;
  678.         if (sep->se_fd != -1) {
  679.             FD_CLR(sep->se_fd, &allsock);
  680.             nsock--;
  681.             (void) close(sep->se_fd);
  682.         }
  683.         if (isrpcservice(sep))
  684.             unregister_rpc(sep);
  685.         if (sep->se_family == AF_UNIX)
  686.             (void)unlink(sep->se_service);
  687.         if (debug)
  688.             print_service("FREE", sep);
  689.         freeconfig(sep);
  690.         free((char *)sep);
  691.     }
  692.     (void) sigsetmask(omask);
  693. }
  694.  
  695. void
  696. retry()
  697. {
  698.     register struct servtab *sep;
  699.  
  700.     timingout = 0;
  701.     for (sep = servtab; sep; sep = sep->se_next) {
  702.         if (sep->se_fd == -1) {
  703.             switch (sep->se_family) {
  704.             case AF_UNIX:
  705.             case AF_INET:
  706.                 setup(sep);
  707.                 if (sep->se_fd != -1 && isrpcservice(sep))
  708.                     register_rpc(sep);
  709.                 break;
  710.             }
  711.         }
  712.     }
  713. }
  714.  
  715. void
  716. goaway()
  717. {
  718.     register struct servtab *sep;
  719.  
  720.     for (sep = servtab; sep; sep = sep->se_next) {
  721.         if (sep->se_fd == -1)
  722.             continue;
  723.  
  724.         switch (sep->se_family) {
  725.         case AF_UNIX:
  726.             (void)unlink(sep->se_service);
  727.             break;
  728.         case AF_INET:
  729.             if (sep->se_wait == 1 && isrpcservice(sep))
  730.                 unregister_rpc(sep);
  731.             break;
  732.         }
  733.         (void)close(sep->se_fd);
  734.     }
  735.     (void)unlink(_PATH_INETDPID);
  736.     exit(0);
  737. }
  738.  
  739.  
  740. setup(sep)
  741.     register struct servtab *sep;
  742. {
  743.     int on = 1;
  744.  
  745.     if ((sep->se_fd = socket(sep->se_family, sep->se_socktype, 0)) < 0) {
  746.         syslog(LOG_ERR, "%s/%s: socket: %m",
  747.             sep->se_service, sep->se_proto);
  748.         return;
  749.     }
  750. #define    turnon(fd, opt) \
  751. setsockopt(fd, SOL_SOCKET, opt, (char *)&on, sizeof (on))
  752.     if (strcmp(sep->se_proto, "tcp") == 0 && (options & SO_DEBUG) &&
  753.         turnon(sep->se_fd, SO_DEBUG) < 0)
  754.         syslog(LOG_ERR, "setsockopt (SO_DEBUG): %m");
  755.     if (turnon(sep->se_fd, SO_REUSEADDR) < 0)
  756.         syslog(LOG_ERR, "setsockopt (SO_REUSEADDR): %m");
  757. #undef turnon
  758.     if (bind(sep->se_fd, &sep->se_ctrladdr, sep->se_ctrladdr_size) < 0) {
  759.         syslog(LOG_ERR, "%s/%s: bind: %m",
  760.             sep->se_service, sep->se_proto);
  761.         (void) close(sep->se_fd);
  762.         sep->se_fd = -1;
  763.         if (!timingout) {
  764.             timingout = 1;
  765.             alarm(RETRYTIME);
  766.         }
  767.         return;
  768.     }
  769.     if (sep->se_socktype == SOCK_STREAM)
  770.         listen(sep->se_fd, 10);
  771.  
  772.     FD_SET(sep->se_fd, &allsock);
  773.     nsock++;
  774.     if (sep->se_fd > maxsock) {
  775.         maxsock = sep->se_fd;
  776.         if (maxsock > rlim_ofile_cur - FD_MARGIN)
  777.             bump_nofile();
  778.     }
  779. }
  780.  
  781. register_rpc(sep)
  782.     register struct servtab *sep;
  783. {
  784. #ifdef RPC
  785.     int n;
  786.     struct sockaddr_in sin;
  787.     struct protoent *pp;
  788.  
  789.     if ((pp = getprotobyname(sep->se_proto+4)) == NULL) {
  790.         syslog(LOG_ERR, "%s: getproto: %m",
  791.             sep->se_proto);
  792.         return;
  793.     }
  794.     n = sizeof sin;
  795.     if (getsockname(sep->se_fd, (struct sockaddr *)&sin, &n) < 0) {
  796.         syslog(LOG_ERR, "%s/%s: getsockname: %m",
  797.             sep->se_service, sep->se_proto);
  798.         return;
  799.     }
  800.  
  801.     for (n = sep->se_rpcversl; n <= sep->se_rpcversh; n++) {
  802.         if (debug)
  803.             fprintf(stderr, "pmap_set: %u %u %u %u\n",
  804.             sep->se_rpcprog, n, pp->p_proto, ntohs(sin.sin_port));
  805.         (void)pmap_unset(sep->se_rpcprog, n);
  806.         if (!pmap_set(sep->se_rpcprog, n, pp->p_proto, ntohs(sin.sin_port)))
  807.             syslog(LOG_ERR, "pmap_set: %u %u %u %u: %m",
  808.             sep->se_rpcprog, n, pp->p_proto, ntohs(sin.sin_port));
  809.     }
  810. #endif /* RPC */
  811. }
  812.  
  813. unregister_rpc(sep)
  814.     register struct servtab *sep;
  815. {
  816. #ifdef RPC
  817.     int n;
  818.  
  819.     for (n = sep->se_rpcversl; n <= sep->se_rpcversh; n++) {
  820.         if (debug)
  821.             fprintf(stderr, "pmap_unset(%u, %u)\n",
  822.                 sep->se_rpcprog, n);
  823.         if (!pmap_unset(sep->se_rpcprog, n))
  824.             syslog(LOG_ERR, "pmap_unset(%u, %u)\n",
  825.                 sep->se_rpcprog, n);
  826.     }
  827. #endif /* RPC */
  828. }
  829.  
  830.  
  831. struct servtab *
  832. enter(cp)
  833.     struct servtab *cp;
  834. {
  835.     register struct servtab *sep;
  836.     long omask;
  837.  
  838.     sep = (struct servtab *)malloc(sizeof (*sep));
  839.     if (sep == (struct servtab *)0) {
  840.         syslog(LOG_ERR, "Out of memory.");
  841.         exit(-1);
  842.     }
  843.     *sep = *cp;
  844.     sep->se_fd = -1;
  845.     sep->se_rpcprog = -1;
  846.     omask = sigblock(SIGBLOCK);
  847.     sep->se_next = servtab;
  848.     servtab = sep;
  849.     sigsetmask(omask);
  850.     return (sep);
  851. }
  852.  
  853. FILE    *fconfig = NULL;
  854. struct    servtab serv;
  855. char    line[256];
  856. char    *skip(), *nextline();
  857.  
  858. setconfig()
  859. {
  860.  
  861.     if (fconfig != NULL) {
  862.         fseek(fconfig, 0L, L_SET);
  863.         return (1);
  864.     }
  865.     fconfig = fopen(CONFIG, "r");
  866.     return (fconfig != NULL);
  867. }
  868.  
  869. endconfig()
  870. {
  871.     if (fconfig) {
  872.         (void) fclose(fconfig);
  873.         fconfig = NULL;
  874.     }
  875. }
  876.  
  877. struct servtab *
  878. getconfigent()
  879. {
  880.     register struct servtab *sep = &serv;
  881.     int argc;
  882.     char *cp, *arg, *newstr();
  883.  
  884. more:
  885. #ifdef MULOG
  886.     while ((cp = nextline(fconfig)) && *cp == '#') {
  887.         /* Avoid use of `skip' if there is a danger of it looking
  888.          * at continuation lines.
  889.          */
  890.         do {
  891.             cp++;
  892.         } while (*cp == ' ' || *cp == '\t');
  893.         if (*cp == '\0')
  894.             continue;
  895.         if ((arg = skip(&cp)) == NULL)
  896.             continue;
  897.         if (strcmp(arg, "DOMAIN"))
  898.             continue;
  899.         if (curdom)
  900.             free(curdom);
  901.         curdom = NULL;
  902.         while (*cp == ' ' || *cp == '\t')
  903.             cp++;
  904.         if (*cp == '\0')
  905.             continue;
  906.         arg = cp;
  907.         while (*cp && *cp != ' ' && *cp != '\t')
  908.             cp++;
  909.         if (*cp != '\0')
  910.             *cp++ = '\0';
  911.         curdom = newstr(arg);
  912.     }
  913. #else
  914.     while ((cp = nextline(fconfig)) && *cp == '#')
  915.         ;
  916. #endif
  917.     if (cp == NULL)
  918.         return ((struct servtab *)0);
  919.     bzero((char *)sep, sizeof *sep);
  920.     sep->se_service = newstr(skip(&cp));
  921.     arg = skip(&cp);
  922.     if (arg == NULL)
  923.         goto more;
  924.  
  925.     if (strcmp(arg, "stream") == 0)
  926.         sep->se_socktype = SOCK_STREAM;
  927.     else if (strcmp(arg, "dgram") == 0)
  928.         sep->se_socktype = SOCK_DGRAM;
  929.     else if (strcmp(arg, "rdm") == 0)
  930.         sep->se_socktype = SOCK_RDM;
  931.     else if (strcmp(arg, "seqpacket") == 0)
  932.         sep->se_socktype = SOCK_SEQPACKET;
  933.     else if (strcmp(arg, "raw") == 0)
  934.         sep->se_socktype = SOCK_RAW;
  935.     else
  936.         sep->se_socktype = -1;
  937.  
  938.     sep->se_proto = newstr(skip(&cp));
  939.     if (strcmp(sep->se_proto, "unix") == 0) {
  940.         sep->se_family = AF_UNIX;
  941.     } else {
  942.         sep->se_family = AF_INET;
  943.         if (strncmp(sep->se_proto, "rpc/", 4) == 0) {
  944. #ifdef RPC
  945.             char *cp, *ccp;
  946.             cp = index(sep->se_service, '/');
  947.             if (cp == 0) {
  948.                 syslog(LOG_ERR, "%s: no rpc version",
  949.                     sep->se_service);
  950.                 goto more;
  951.             }
  952.             *cp++ = '\0';
  953.             sep->se_rpcversl =
  954.                 sep->se_rpcversh = strtol(cp, &ccp, 0);
  955.             if (ccp == cp) {
  956.         badafterall:
  957.                 syslog(LOG_ERR, "%s/%s: bad rpc version",
  958.                     sep->se_service, cp);
  959.                 goto more;
  960.             }
  961.             if (*ccp == '-') {
  962.                 cp = ccp + 1;
  963.                 sep->se_rpcversh = strtol(cp, &ccp, 0); 
  964.                 if (ccp == cp)
  965.                     goto badafterall;
  966.             }
  967. #else
  968.             syslog(LOG_ERR, "%s: rpc services not suported",
  969.                 sep->se_service);
  970.             goto more;
  971. #endif /* RPC */
  972.         }
  973.     }
  974.     arg = skip(&cp);
  975.     if (arg == NULL)
  976.         goto more;
  977.     {
  978.         char    *s = index(arg, '.');
  979.         if (s) {
  980.             *s++ = '\0';
  981.             sep->se_max = atoi(s);
  982.         } else
  983.             sep->se_max = TOOMANY;
  984.     }
  985.     sep->se_wait = strcmp(arg, "wait") == 0;
  986.     sep->se_user = newstr(skip(&cp));
  987.     if (sep->se_group = index(sep->se_user, '.')) {
  988.         *sep->se_group++ = '\0';
  989.     }
  990.     sep->se_server = newstr(skip(&cp));
  991.     if (strcmp(sep->se_server, "internal") == 0) {
  992.         register struct biltin *bi;
  993.  
  994.         for (bi = biltins; bi->bi_service; bi++)
  995.             if (bi->bi_socktype == sep->se_socktype &&
  996.                 strcmp(bi->bi_service, sep->se_service) == 0)
  997.                 break;
  998.         if (bi->bi_service == 0) {
  999.             syslog(LOG_ERR, "internal service %s unknown\n",
  1000.                 sep->se_service);
  1001.             goto more;
  1002.         }
  1003.         sep->se_bi = bi;
  1004.         sep->se_wait = bi->bi_wait;
  1005.     } else
  1006.         sep->se_bi = NULL;
  1007.     argc = 0;
  1008.     for (arg = skip(&cp); cp; arg = skip(&cp)) {
  1009. #if MULOG
  1010.         char *colon, *rindex();
  1011.  
  1012.         if (argc == 0 && (colon = rindex(arg, ':'))) {
  1013.             while (arg < colon) {
  1014.                 int    x;
  1015.                 char    *ccp;
  1016.  
  1017.                 switch (*arg++) {
  1018.                 case 'l':
  1019.                     x = 1;
  1020.                     if (isdigit(*arg)) {
  1021.                         x = strtol(arg, &ccp, 0);
  1022.                         if (ccp == arg)
  1023.                             break;
  1024.                         arg = ccp;
  1025.                     }
  1026.                     sep->se_log &= ~MULOG_RFC931;
  1027.                     sep->se_log |= x;
  1028.                     break;
  1029.                 case 'a':
  1030.                     sep->se_log |= MULOG_RFC931;
  1031.                     break;
  1032.                 default:
  1033.                     break;
  1034.                 }
  1035.             }
  1036.             arg = colon + 1;
  1037.         }
  1038. #endif
  1039.         if (argc < MAXARGV)
  1040.             sep->se_argv[argc++] = newstr(arg);
  1041.     }
  1042.     while (argc <= MAXARGV)
  1043.         sep->se_argv[argc++] = NULL;
  1044.     return (sep);
  1045. }
  1046.  
  1047. freeconfig(cp)
  1048.     register struct servtab *cp;
  1049. {
  1050.     int i;
  1051.  
  1052.     if (cp->se_service)
  1053.         free(cp->se_service);
  1054.     if (cp->se_proto)
  1055.         free(cp->se_proto);
  1056.     if (cp->se_user)
  1057.         free(cp->se_user);
  1058.     /* Note: se_group is part of the newstr'ed se_user */
  1059.     if (cp->se_server)
  1060.         free(cp->se_server);
  1061.     for (i = 0; i < MAXARGV; i++)
  1062.         if (cp->se_argv[i])
  1063.             free(cp->se_argv[i]);
  1064. }
  1065.  
  1066. char *
  1067. skip(cpp)
  1068.     char **cpp;
  1069. {
  1070.     register char *cp = *cpp;
  1071.     char *start;
  1072.  
  1073.     if (*cpp == NULL)
  1074.         return ((char *)0);
  1075.  
  1076. again:
  1077.     while (*cp == ' ' || *cp == '\t')
  1078.         cp++;
  1079.     if (*cp == '\0') {
  1080.         int c;
  1081.  
  1082.         c = getc(fconfig);
  1083.         (void) ungetc(c, fconfig);
  1084.         if (c == ' ' || c == '\t')
  1085.             if (cp = nextline(fconfig))
  1086.                 goto again;
  1087.         *cpp = (char *)0;
  1088.         return ((char *)0);
  1089.     }
  1090.     start = cp;
  1091.     while (*cp && *cp != ' ' && *cp != '\t')
  1092.         cp++;
  1093.     if (*cp != '\0')
  1094.         *cp++ = '\0';
  1095.     *cpp = cp;
  1096.     return (start);
  1097. }
  1098.  
  1099. char *
  1100. nextline(fd)
  1101.     FILE *fd;
  1102. {
  1103.     char *cp;
  1104.  
  1105.     if (fgets(line, sizeof (line), fd) == NULL)
  1106.         return ((char *)0);
  1107.     cp = index(line, '\n');
  1108.     if (cp)
  1109.         *cp = '\0';
  1110.     return (line);
  1111. }
  1112.  
  1113. char *
  1114. newstr(cp)
  1115.     char *cp;
  1116. {
  1117.     if (cp = strdup(cp ? cp : ""))
  1118.         return(cp);
  1119.     syslog(LOG_ERR, "strdup: %m");
  1120.     exit(-1);
  1121. }
  1122.  
  1123. setproctitle(a, s)
  1124.     char *a;
  1125.     int s;
  1126. {
  1127.     int size;
  1128.     register char *cp;
  1129.     struct sockaddr_in sin;
  1130.     char buf[80];
  1131.  
  1132.     cp = Argv[0];
  1133.     size = sizeof(sin);
  1134.     if (getpeername(s, (struct sockaddr *)&sin, &size) == 0)
  1135.         (void) sprintf(buf, "-%s [%s]", a, inet_ntoa(sin.sin_addr)); 
  1136.     else
  1137.         (void) sprintf(buf, "-%s", a); 
  1138.     strncpy(cp, buf, LastArg - cp);
  1139.     cp += strlen(cp);
  1140.     while (cp < LastArg)
  1141.         *cp++ = ' ';
  1142. }
  1143.  
  1144. logpid()
  1145. {
  1146.     FILE *fp;
  1147.  
  1148.     if ((fp = fopen(_PATH_INETDPID, "w")) != NULL) {
  1149.         fprintf(fp, "%u\n", getpid());
  1150.         (void)fclose(fp);
  1151.     }
  1152. }
  1153.  
  1154. bump_nofile()
  1155. {
  1156. #ifdef RLIMIT_NOFILE
  1157.  
  1158. #define FD_CHUNK    32
  1159.  
  1160.     struct rlimit rl;
  1161.  
  1162.     if (getrlimit(RLIMIT_NOFILE, &rl) < 0) {
  1163.         syslog(LOG_ERR, "getrlimit: %m");
  1164.         return -1;
  1165.     }
  1166.     rl.rlim_cur = MIN(rl.rlim_max, rl.rlim_cur + FD_CHUNK);
  1167.     if (rl.rlim_cur <= rlim_ofile_cur) {
  1168.         syslog(LOG_ERR,
  1169.             "bump_nofile: cannot extend file limit, max = %d",
  1170.             rl.rlim_cur);
  1171.         return -1;
  1172.     }
  1173.  
  1174.     if (setrlimit(RLIMIT_NOFILE, &rl) < 0) {
  1175.         syslog(LOG_ERR, "setrlimit: %m");
  1176.         return -1;
  1177.     }
  1178.  
  1179.     rlim_ofile_cur = rl.rlim_cur;
  1180.     return 0;
  1181.  
  1182. #else
  1183.     syslog(LOG_ERR, "bump_nofile: cannot extend file limit");
  1184.     return -1;
  1185. #endif
  1186. }
  1187.  
  1188. /*
  1189.  * Internet services provided internally by inetd:
  1190.  */
  1191. #define    BUFSIZE    4096
  1192.  
  1193. /* ARGSUSED */
  1194. echo_stream(s, sep)        /* Echo service -- echo data back */
  1195.     int s;
  1196.     struct servtab *sep;
  1197. {
  1198.     char buffer[BUFSIZE];
  1199.     int i;
  1200.  
  1201.     setproctitle(sep->se_service, s);
  1202.     while ((i = read(s, buffer, sizeof(buffer))) > 0 &&
  1203.         write(s, buffer, i) > 0)
  1204.         ;
  1205.     exit(0);
  1206. }
  1207.  
  1208. /* ARGSUSED */
  1209. echo_dg(s, sep)            /* Echo service -- echo data back */
  1210.     int s;
  1211.     struct servtab *sep;
  1212. {
  1213.     char buffer[BUFSIZE];
  1214.     int i, size;
  1215.     struct sockaddr sa;
  1216.  
  1217.     size = sizeof(sa);
  1218.     if ((i = recvfrom(s, buffer, sizeof(buffer), 0, &sa, &size)) < 0)
  1219.         return;
  1220.     (void) sendto(s, buffer, i, 0, &sa, sizeof(sa));
  1221. }
  1222.  
  1223. /* ARGSUSED */
  1224. discard_stream(s, sep)        /* Discard service -- ignore data */
  1225.     int s;
  1226.     struct servtab *sep;
  1227. {
  1228.     char buffer[BUFSIZE];
  1229.  
  1230.     setproctitle(sep->se_service, s);
  1231.     while ((errno = 0, read(s, buffer, sizeof(buffer)) > 0) ||
  1232.             errno == EINTR)
  1233.         ;
  1234.     exit(0);
  1235. }
  1236.  
  1237. /* ARGSUSED */
  1238. discard_dg(s, sep)        /* Discard service -- ignore data */
  1239.     int s;
  1240.     struct servtab *sep;
  1241. {
  1242.     char buffer[BUFSIZE];
  1243.  
  1244.     (void) read(s, buffer, sizeof(buffer));
  1245. }
  1246.  
  1247. #include <ctype.h>
  1248. #define LINESIZ 72
  1249. char ring[128];
  1250. char *endring;
  1251.  
  1252. initring()
  1253. {
  1254.     register int i;
  1255.  
  1256.     endring = ring;
  1257.  
  1258.     for (i = 0; i <= 128; ++i)
  1259.         if (isprint(i))
  1260.             *endring++ = i;
  1261. }
  1262.  
  1263. /* ARGSUSED */
  1264. chargen_stream(s, sep)        /* Character generator */
  1265.     int s;
  1266.     struct servtab *sep;
  1267. {
  1268.     register char *rs;
  1269.     int len;
  1270.     char text[LINESIZ+2];
  1271.  
  1272.     setproctitle(sep->se_service, s);
  1273.  
  1274.     if (!endring) {
  1275.         initring();
  1276.         rs = ring;
  1277.     }
  1278.  
  1279.     text[LINESIZ] = '\r';
  1280.     text[LINESIZ + 1] = '\n';
  1281.     for (rs = ring;;) {
  1282.         if ((len = endring - rs) >= LINESIZ)
  1283.             bcopy(rs, text, LINESIZ);
  1284.         else {
  1285.             bcopy(rs, text, len);
  1286.             bcopy(ring, text + len, LINESIZ - len);
  1287.         }
  1288.         if (++rs == endring)
  1289.             rs = ring;
  1290.         if (write(s, text, sizeof(text)) != sizeof(text))
  1291.             break;
  1292.     }
  1293.     exit(0);
  1294. }
  1295.  
  1296. /* ARGSUSED */
  1297. chargen_dg(s, sep)        /* Character generator */
  1298.     int s;
  1299.     struct servtab *sep;
  1300. {
  1301.     struct sockaddr sa;
  1302.     static char *rs;
  1303.     int len, size;
  1304.     char text[LINESIZ+2];
  1305.  
  1306.     if (endring == 0) {
  1307.         initring();
  1308.         rs = ring;
  1309.     }
  1310.  
  1311.     size = sizeof(sa);
  1312.     if (recvfrom(s, text, sizeof(text), 0, &sa, &size) < 0)
  1313.         return;
  1314.  
  1315.     if ((len = endring - rs) >= LINESIZ)
  1316.         bcopy(rs, text, LINESIZ);
  1317.     else {
  1318.         bcopy(rs, text, len);
  1319.         bcopy(ring, text + len, LINESIZ - len);
  1320.     }
  1321.     if (++rs == endring)
  1322.         rs = ring;
  1323.     text[LINESIZ] = '\r';
  1324.     text[LINESIZ + 1] = '\n';
  1325.     (void) sendto(s, text, sizeof(text), 0, &sa, sizeof(sa));
  1326. }
  1327.  
  1328. /*
  1329.  * Return a machine readable date and time, in the form of the
  1330.  * number of seconds since midnight, Jan 1, 1900.  Since gettimeofday
  1331.  * returns the number of seconds since midnight, Jan 1, 1970,
  1332.  * we must add 2208988800 seconds to this figure to make up for
  1333.  * some seventy years Bell Labs was asleep.
  1334.  */
  1335.  
  1336. long
  1337. machtime()
  1338. {
  1339.     struct timeval tv;
  1340.  
  1341.     if (gettimeofday(&tv, (struct timezone *)0) < 0) {
  1342.         fprintf(stderr, "Unable to get time of day\n");
  1343.         return (0L);
  1344.     }
  1345.     return (htonl((long)tv.tv_sec + 2208988800UL));
  1346. }
  1347.  
  1348. /* ARGSUSED */
  1349. machtime_stream(s, sep)
  1350.     int s;
  1351.     struct servtab *sep;
  1352. {
  1353.     long result;
  1354.  
  1355.     result = machtime();
  1356.     (void) write(s, (char *) &result, sizeof(result));
  1357. }
  1358.  
  1359. /* ARGSUSED */
  1360. machtime_dg(s, sep)
  1361.     int s;
  1362.     struct servtab *sep;
  1363. {
  1364.     long result;
  1365.     struct sockaddr sa;
  1366.     int size;
  1367.  
  1368.     size = sizeof(sa);
  1369.     if (recvfrom(s, (char *)&result, sizeof(result), 0, &sa, &size) < 0)
  1370.         return;
  1371.     result = machtime();
  1372.     (void) sendto(s, (char *) &result, sizeof(result), 0, &sa, sizeof(sa));
  1373. }
  1374.  
  1375. /* ARGSUSED */
  1376. daytime_stream(s, sep)        /* Return human-readable time of day */
  1377.     int s;
  1378.     struct servtab *sep;
  1379. {
  1380.     char buffer[256];
  1381.     time_t time(), clock;
  1382.     char *ctime();
  1383.  
  1384.     clock = time((time_t *) 0);
  1385.  
  1386.     (void) sprintf(buffer, "%.24s\r\n", ctime(&clock));
  1387.     (void) write(s, buffer, strlen(buffer));
  1388. }
  1389.  
  1390. /* ARGSUSED */
  1391. daytime_dg(s, sep)        /* Return human-readable time of day */
  1392.     int s;
  1393.     struct servtab *sep;
  1394. {
  1395.     char buffer[256];
  1396.     time_t time(), clock;
  1397.     struct sockaddr sa;
  1398.     int size;
  1399.     char *ctime();
  1400.  
  1401.     clock = time((time_t *) 0);
  1402.  
  1403.     size = sizeof(sa);
  1404.     if (recvfrom(s, buffer, sizeof(buffer), 0, &sa, &size) < 0)
  1405.         return;
  1406.     (void) sprintf(buffer, "%.24s\r\n", ctime(&clock));
  1407.     (void) sendto(s, buffer, strlen(buffer), 0, &sa, sizeof(sa));
  1408. }
  1409.  
  1410. /*
  1411.  * print_service:
  1412.  *    Dump relevant information to stderr
  1413.  */
  1414. print_service(action, sep)
  1415.     char *action;
  1416.     struct servtab *sep;
  1417. {
  1418.     if (isrpcservice(sep))
  1419.         fprintf(stderr,
  1420.             "%s: %s rpcprog=%d, rpcvers = %d/%d, proto=%s, wait.max=%d.%d, user.group=%s.%s builtin=%x server=%s\n",
  1421.             action, sep->se_service,
  1422.             sep->se_rpcprog, sep->se_rpcversh, sep->se_rpcversl, sep->se_proto,
  1423.             sep->se_wait, sep->se_max, sep->se_user, sep->se_group,
  1424.             (int)sep->se_bi, sep->se_server);
  1425.     else
  1426.         fprintf(stderr,
  1427.             "%s: %s proto=%s, wait.max=%d.%d, user.group=%s.%s builtin=%x server=%s\n",
  1428.             action, sep->se_service, sep->se_proto,
  1429.             sep->se_wait, sep->se_max, sep->se_user, sep->se_group,
  1430.             (int)sep->se_bi, sep->se_server);
  1431. }
  1432.  
  1433. #ifdef MULOG
  1434. dolog(sep, ctrl)
  1435.     struct servtab *sep;
  1436.     int        ctrl;
  1437. {
  1438.     struct sockaddr        sa;
  1439.     struct sockaddr_in    *sin = (struct sockaddr_in *)&sa;
  1440.     int            len = sizeof(sa);
  1441.     struct hostent        *hp;
  1442.     char            *host, *dp, buf[BUFSIZ], *rfc931_name();
  1443.     int            connected = 1;
  1444.  
  1445.     if (sep->se_family != AF_INET)
  1446.         return;
  1447.  
  1448.     if (getpeername(ctrl, &sa, &len) < 0) {
  1449.         if (errno != ENOTCONN) {
  1450.             syslog(LOG_ERR, "getpeername: %m");
  1451.             return;
  1452.         }
  1453.         if (recvfrom(ctrl, buf, sizeof(buf), MSG_PEEK, &sa, &len) < 0) {
  1454.             syslog(LOG_ERR, "recvfrom: %m");
  1455.             return;
  1456.         }
  1457.         connected = 0;
  1458.     }
  1459.     if (sa.sa_family != AF_INET) {
  1460.         syslog(LOG_ERR, "unexpected address family %u", sa.sa_family);
  1461.         return;
  1462.     }
  1463.  
  1464.     hp = gethostbyaddr((char *) &sin->sin_addr.s_addr,
  1465.                 sizeof (sin->sin_addr.s_addr), AF_INET);
  1466.  
  1467.     host = hp?hp->h_name:inet_ntoa(sin->sin_addr);
  1468.  
  1469.     switch (sep->se_log & ~MULOG_RFC931) {
  1470.     case 0:
  1471.         return;
  1472.     case 1:
  1473.         if (curdom == NULL || *curdom == '\0')
  1474.             break;
  1475.         dp = host + strlen(host) - strlen(curdom);
  1476.         if (dp < host)
  1477.             break;
  1478.         if (debug)
  1479.             fprintf(stderr, "check \"%s\" against curdom \"%s\"\n",
  1480.                     host, curdom);
  1481.         if (strcasecmp(dp, curdom) == 0)
  1482.             return;
  1483.         break;
  1484.     case 2:
  1485.     default:
  1486.         break;
  1487.     }
  1488.  
  1489.     openlog("", LOG_NOWAIT, MULOG);
  1490.  
  1491.     if (connected && (sep->se_log & MULOG_RFC931))
  1492.         syslog(LOG_INFO, "%s@%s wants %s",
  1493.                 rfc931_name(sin, ctrl), host, sep->se_service);
  1494.     else
  1495.         syslog(LOG_INFO, "%s wants %s",
  1496.                 host, sep->se_service);
  1497. }
  1498. /*
  1499.  * From tcp_log by
  1500.  *  Wietse Venema, Eindhoven University of Technology, The Netherlands.
  1501.  */
  1502. #if 0
  1503. static char sccsid[] = "@(#) rfc931.c 1.3 92/08/31 22:54:46";
  1504. #endif
  1505.  
  1506. #include <setjmp.h>
  1507.  
  1508. #define    RFC931_PORT    113        /* Semi-well-known port */
  1509. #define    TIMEOUT        4
  1510. #define    TIMEOUT2    10
  1511.  
  1512. static jmp_buf timebuf;
  1513.  
  1514. /* timeout - handle timeouts */
  1515.  
  1516. static void timeout(sig)
  1517. int     sig;
  1518. {
  1519.     longjmp(timebuf, sig);
  1520. }
  1521.  
  1522. /* rfc931_name - return remote user name */
  1523.  
  1524. char *
  1525. rfc931_name(there, ctrl)
  1526. struct sockaddr_in *there;        /* remote link information */
  1527. int    ctrl;
  1528. {
  1529.     struct sockaddr_in here;    /* local link information */
  1530.     struct sockaddr_in sin;        /* for talking to RFC931 daemon */
  1531.     int        length;
  1532.     int        s;
  1533.     unsigned    remote;
  1534.     unsigned    local;
  1535.     static char    user[256];        /* XXX */
  1536.     char        buf[256];
  1537.     char        *cp;
  1538.     char        *result = "USER_UNKNOWN";
  1539.     int        len;
  1540.  
  1541.     /* Find out local port number of our stdin. */
  1542.  
  1543.     length = sizeof(here);
  1544.     if (getsockname(ctrl, (struct sockaddr *) &here, &length) == -1) {
  1545.         syslog(LOG_ERR, "getsockname: %m");
  1546.         return (result);
  1547.     }
  1548.     /* Set up timer so we won't get stuck. */
  1549.  
  1550.     if ((s = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
  1551.         syslog(LOG_ERR, "socket: %m");
  1552.         return (result);
  1553.     }
  1554.  
  1555.     sin = here;
  1556.     sin.sin_port = htons(0);
  1557.     if (bind(s, (struct sockaddr *) &sin, sizeof(sin)) == -1) {
  1558.         syslog(LOG_ERR, "bind: %m");
  1559.         return (result);
  1560.     }
  1561.  
  1562.     signal(SIGALRM, timeout);
  1563.     if (setjmp(timebuf)) {
  1564.         close(s);            /* not: fclose(fp) */
  1565.         return (result);
  1566.     }
  1567.     alarm(TIMEOUT);
  1568.  
  1569.     /* Connect to the RFC931 daemon. */
  1570.  
  1571.     sin = *there;
  1572.     sin.sin_port = htons(RFC931_PORT);
  1573.     if (connect(s, (struct sockaddr *) &sin, sizeof(sin)) == -1) {
  1574.         close(s);
  1575.         alarm(0);
  1576.         return (result);
  1577.     }
  1578.  
  1579.     /* Query the RFC 931 server. Would 13-byte writes ever be broken up? */
  1580.     sprintf(buf, "%u,%u\r\n", ntohs(there->sin_port), ntohs(here.sin_port));
  1581.  
  1582.  
  1583.     for (len = 0, cp = buf; len < strlen(buf); ) {
  1584.         int    n;
  1585.         if ((n = write(s, cp, strlen(buf) - len)) == -1) {
  1586.             close(s);
  1587.             alarm(0);
  1588.             return (result);
  1589.         }
  1590.         cp += n;
  1591.         len += n;
  1592.     }
  1593.  
  1594.     /* Read response */
  1595.     for (cp = buf; cp < buf + sizeof(buf) - 1; ) {
  1596.         char    c;
  1597.         if (read(s, &c, 1) != 1) {
  1598.             close(s);
  1599.             alarm(0);
  1600.             return (result);
  1601.         }
  1602.         if (c == '\n')
  1603.             break;
  1604.         *cp++ = c;
  1605.     }
  1606.     *cp = '\0';
  1607.  
  1608.     if (sscanf(buf, "%u , %u : USERID :%*[^:]:%255s", &remote, &local, user) == 3
  1609.         && ntohs(there->sin_port) == remote
  1610.         && ntohs(here.sin_port) == local) {
  1611.  
  1612.         /* Strip trailing carriage return. */
  1613.         if (cp = strchr(user, '\r'))
  1614.             *cp = 0;
  1615.         result = user;
  1616.     }
  1617.  
  1618.     alarm(0);
  1619.     close(s);
  1620.     return (result);
  1621. }
  1622. #endif
  1623.