home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / inetutils-1.2-src.tgz / tar.out / fsf / inetutils / rshd / rshd.c < prev   
C/C++ Source or Header  |  1996-09-28  |  19KB  |  822 lines

  1. /*-
  2.  * Copyright (c) 1988, 1989, 1992, 1993, 1994
  3.  *    The Regents of the University of California.  All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer.
  10.  * 2. Redistributions in binary form must reproduce the above copyright
  11.  *    notice, this list of conditions and the following disclaimer in the
  12.  *    documentation and/or other materials provided with the distribution.
  13.  * 3. All advertising materials mentioning features or use of this software
  14.  *    must display the following acknowledgement:
  15.  *    This product includes software developed by the University of
  16.  *    California, Berkeley and its contributors.
  17.  * 4. Neither the name of the University nor the names of its contributors
  18.  *    may be used to endorse or promote products derived from this software
  19.  *    without specific prior written permission.
  20.  *
  21.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  22.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  25.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31.  * SUCH DAMAGE.
  32.  */
  33.  
  34. #ifndef lint
  35. static char copyright[] =
  36. "@(#) Copyright (c) 1988, 1989, 1992, 1993, 1994\n\
  37.     The Regents of the University of California.  All rights reserved.\n";
  38. #endif /* not lint */
  39.  
  40. #ifndef lint
  41. static char sccsid[] = "@(#)rshd.c    8.2 (Berkeley) 4/6/94";
  42. #endif /* not lint */
  43.  
  44. /*
  45.  * remote shell server:
  46.  *    [port]\0
  47.  *    remuser\0
  48.  *    locuser\0
  49.  *    command\0
  50.  *    data
  51.  */
  52.  
  53. #ifdef HAVE_CONFIG_H
  54. #include <config.h>
  55. #endif
  56.  
  57. #include <sys/param.h>
  58. #include <sys/ioctl.h>
  59. #include <sys/time.h>
  60. #include <sys/socket.h>
  61.  
  62. #include <netinet/in.h>
  63. #include <arpa/inet.h>
  64. #include <netdb.h>
  65.  
  66. #include <errno.h>
  67. #include <fcntl.h>
  68. #include <pwd.h>
  69. #include <signal.h>
  70. #include <stdio.h>
  71. #include <stdlib.h>
  72. #include <string.h>
  73. #include <syslog.h>
  74. #include <unistd.h>
  75. #include <getopt.h>
  76.  
  77. int    keepalive = 1;
  78. int    check_all;
  79. int    log_success;        /* If TRUE, log all successful accesses */
  80. int    sent_null;
  81.  
  82. void     doit __P((struct sockaddr_in *));
  83. void     error __P((const char *, ...));
  84. char    *getstr __P((char *));
  85. int     local_domain __P((char *));
  86. char    *topdomain __P((char *));
  87. void     usage __P((void));
  88.  
  89. #ifdef    KERBEROS
  90. #include <kerberosIV/des.h>
  91. #include <kerberosIV/krb.h>
  92. #define    VERSION_SIZE    9
  93. #define SECURE_MESSAGE  "This rsh session is using DES encryption for all transmissions.\r\n"
  94. #define    OPTIONS        "alnkvxL"
  95. char    authbuf[sizeof(AUTH_DAT)];
  96. char    tickbuf[sizeof(KTEXT_ST)];
  97. int    doencrypt, use_kerberos, vacuous;
  98. Key_schedule    schedule;
  99. #else
  100. #define    OPTIONS    "alnL"
  101. #endif
  102.  
  103. int
  104. main(argc, argv)
  105.     int argc;
  106.     char *argv[];
  107. {
  108.     extern int __check_rhosts_file;
  109.     struct linger linger;
  110.     int ch, on = 1, fromlen;
  111.     struct sockaddr_in from;
  112.  
  113.     openlog("rshd", LOG_PID | LOG_ODELAY, LOG_DAEMON);
  114.  
  115.     opterr = 0;
  116.     while ((ch = getopt(argc, argv, OPTIONS)) != EOF)
  117.         switch (ch) {
  118.         case 'a':
  119.             check_all = 1;
  120.             break;
  121.         case 'l':
  122.             __check_rhosts_file = 0;
  123.             break;
  124.         case 'n':
  125.             keepalive = 0;
  126.             break;
  127. #ifdef    KERBEROS
  128.         case 'k':
  129.             use_kerberos = 1;
  130.             break;
  131.  
  132.         case 'v':
  133.             vacuous = 1;
  134.             break;
  135.  
  136. #ifdef CRYPT
  137.         case 'x':
  138.             doencrypt = 1;
  139.             break;
  140. #endif
  141. #endif
  142.         case 'L':
  143.             log_success = 1;
  144.             break;
  145.         case '?':
  146.         default:
  147.             usage();
  148.             break;
  149.         }
  150.  
  151.     argc -= optind;
  152.     argv += optind;
  153.  
  154. #ifdef    KERBEROS
  155.     if (use_kerberos && vacuous) {
  156.         syslog(LOG_ERR, "only one of -k and -v allowed");
  157.         exit(2);
  158.     }
  159. #ifdef CRYPT
  160.     if (doencrypt && !use_kerberos) {
  161.         syslog(LOG_ERR, "-k is required for -x");
  162.         exit(2);
  163.     }
  164. #endif
  165. #endif
  166.  
  167.     fromlen = sizeof (from);
  168.     if (getpeername(0, (struct sockaddr *)&from, &fromlen) < 0) {
  169.         syslog(LOG_ERR, "getpeername: %m");
  170.         _exit(1);
  171.     }
  172.     if (keepalive &&
  173.         setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, (char *)&on,
  174.         sizeof(on)) < 0)
  175.         syslog(LOG_WARNING, "setsockopt (SO_KEEPALIVE): %m");
  176.     linger.l_onoff = 1;
  177.     linger.l_linger = 60;            /* XXX */
  178.     if (setsockopt(0, SOL_SOCKET, SO_LINGER, (char *)&linger,
  179.         sizeof (linger)) < 0)
  180.         syslog(LOG_WARNING, "setsockopt (SO_LINGER): %m");
  181.     doit(&from);
  182.     /* NOTREACHED */
  183. }
  184.  
  185. char    username[20] = "USER=";
  186. char    homedir[64] = "HOME=";
  187. char    shell[64] = "SHELL=";
  188. char    path[100] = "PATH=";
  189. char    *envinit[] =
  190.         {homedir, shell, path, username, 0};
  191. char    **environ;
  192.  
  193. void
  194. doit(fromp)
  195.     struct sockaddr_in *fromp;
  196. {
  197.     extern char *__rcmd_errstr;    /* syslog hook from libc/net/rcmd.c. */
  198.     struct hostent *hp;
  199.     struct passwd *pwd;
  200.     u_short port;
  201.     fd_set ready, readfrom;
  202.     int cc, nfd, pv[2], pid, s;
  203.     int one = 1;
  204.     char *hostname, *errorstr, *errorhost;
  205.     char *cp, sig, buf[BUFSIZ];
  206.     char *cmdbuf, *locuser, *remuser;
  207.  
  208. #ifdef    KERBEROS
  209.     AUTH_DAT    *kdata = (AUTH_DAT *) NULL;
  210.     KTEXT        ticket = (KTEXT) NULL;
  211.     char        instance[INST_SZ], version[VERSION_SIZE];
  212.     struct        sockaddr_in    fromaddr;
  213.     int        rc;
  214.     long        authopts;
  215.     int        pv1[2], pv2[2];
  216.     fd_set        wready, writeto;
  217.  
  218.     fromaddr = *fromp;
  219. #endif
  220.  
  221.     (void) signal(SIGINT, SIG_DFL);
  222.     (void) signal(SIGQUIT, SIG_DFL);
  223.     (void) signal(SIGTERM, SIG_DFL);
  224. #ifdef DEBUG
  225.     { int t = open(PATH_TTY, 2);
  226.       if (t >= 0) {
  227.         ioctl(t, TIOCNOTTY, (char *)0);
  228.         (void) close(t);
  229.       }
  230.     }
  231. #endif
  232.     fromp->sin_port = ntohs((u_short)fromp->sin_port);
  233.     if (fromp->sin_family != AF_INET) {
  234.         syslog(LOG_ERR, "malformed \"from\" address (af %d)\n",
  235.             fromp->sin_family);
  236.         exit(1);
  237.     }
  238. #ifdef IP_OPTIONS
  239.       {
  240.     u_char optbuf[BUFSIZ/3], *cp;
  241.     char lbuf[BUFSIZ], *lp;
  242.     int optsize = sizeof(optbuf), ipproto;
  243.     struct protoent *ip;
  244.  
  245.     if ((ip = getprotobyname("ip")) != NULL)
  246.         ipproto = ip->p_proto;
  247.     else
  248.         ipproto = IPPROTO_IP;
  249.     if (!getsockopt(0, ipproto, IP_OPTIONS, (char *)optbuf, &optsize) &&
  250.         optsize != 0) {
  251.         lp = lbuf;
  252.         for (cp = optbuf; optsize > 0; cp++, optsize--, lp += 3)
  253.             sprintf(lp, " %2.2x", *cp);
  254.         syslog(LOG_NOTICE,
  255.             "Connection received from %s using IP options (ignored):%s",
  256.             inet_ntoa(fromp->sin_addr), lbuf);
  257.         if (setsockopt(0, ipproto, IP_OPTIONS,
  258.             (char *)NULL, optsize) != 0) {
  259.             syslog(LOG_ERR, "setsockopt IP_OPTIONS NULL: %m");
  260.             exit(1);
  261.         }
  262.     }
  263.       }
  264. #endif
  265.  
  266. #ifdef    KERBEROS
  267.     if (!use_kerberos)
  268. #endif
  269.         if (fromp->sin_port >= IPPORT_RESERVED ||
  270.             fromp->sin_port < IPPORT_RESERVED/2) {
  271.             syslog(LOG_NOTICE|LOG_AUTH,
  272.                 "Connection from %s on illegal port %u",
  273.                 inet_ntoa(fromp->sin_addr),
  274.                 fromp->sin_port);
  275.             exit(1);
  276.         }
  277.  
  278.     (void) alarm(60);
  279.     port = 0;
  280.     for (;;) {
  281.         char c;
  282.         if ((cc = read(STDIN_FILENO, &c, 1)) != 1) {
  283.             if (cc < 0)
  284.                 syslog(LOG_NOTICE, "read: %m");
  285.             shutdown(0, 1+1);
  286.             exit(1);
  287.         }
  288.         if (c== 0)
  289.             break;
  290.         port = port * 10 + c - '0';
  291.     }
  292.  
  293.     (void) alarm(0);
  294.     if (port != 0) {
  295.         int lport = IPPORT_RESERVED - 1;
  296.         s = rresvport(&lport);
  297.         if (s < 0) {
  298.             syslog(LOG_ERR, "can't get stderr port: %m");
  299.             exit(1);
  300.         }
  301. #ifdef    KERBEROS
  302.         if (!use_kerberos)
  303. #endif
  304.             if (port >= IPPORT_RESERVED) {
  305.                 syslog(LOG_ERR, "2nd port not reserved\n");
  306.                 exit(1);
  307.             }
  308.         fromp->sin_port = htons(port);
  309.         if (connect(s, (struct sockaddr *)fromp, sizeof (*fromp)) < 0) {
  310.             syslog(LOG_INFO, "connect second port %d: %m", port);
  311.             exit(1);
  312.         }
  313.     }
  314.  
  315. #ifdef    KERBEROS
  316.     if (vacuous) {
  317.         error("rshd: remote host requires Kerberos authentication\n");
  318.         exit(1);
  319.     }
  320. #endif
  321.  
  322. #ifdef notdef
  323.     /* from inetd, socket is already on 0, 1, 2 */
  324.     dup2(f, 0);
  325.     dup2(f, 1);
  326.     dup2(f, 2);
  327. #endif
  328.     errorstr = NULL;
  329.     hp = gethostbyaddr((char *)&fromp->sin_addr, sizeof (struct in_addr),
  330.         fromp->sin_family);
  331.     if (hp) {
  332.         /*
  333.          * If name returned by gethostbyaddr is in our domain,
  334.          * attempt to verify that we haven't been fooled by someone
  335.          * in a remote net; look up the name and check that this
  336.          * address corresponds to the name.
  337.          */
  338.         hostname = hp->h_name;
  339. #ifdef    KERBEROS
  340.         if (!use_kerberos)
  341. #endif
  342.         if (check_all || local_domain(hp->h_name)) {
  343.             char *remotehost = alloca (strlen (hp->h_name) + 1);
  344.             if (! remotehost)
  345.                 errorstr = "Out of memory\n";
  346.             else {
  347.                 strcpy(remotehost, hp->h_name);
  348.                 errorhost = remotehost;
  349.                 hp = gethostbyname(remotehost);
  350.                 if (hp == NULL) {
  351.                     syslog(LOG_INFO,
  352.                         "Couldn't look up address for %s",
  353.                         remotehost);
  354.                     errorstr =
  355.                    "Couldn't look up address for your host (%s)\n";
  356.                     hostname = inet_ntoa(fromp->sin_addr);
  357.                 } else for (; ; hp->h_addr_list++) {
  358.                     if (hp->h_addr_list[0] == NULL) {
  359.                         syslog(LOG_NOTICE,
  360.                      "Host addr %s not listed for host %s",
  361.                             inet_ntoa(fromp->sin_addr),
  362.                             hp->h_name);
  363.                         errorstr =
  364.                           "Host address mismatch for %s\n";
  365.                         hostname = inet_ntoa(fromp->sin_addr);
  366.                         break;
  367.                     }
  368.                     if (!bcmp(hp->h_addr_list[0],
  369.                         (caddr_t)&fromp->sin_addr,
  370.                         sizeof(fromp->sin_addr))) {
  371.                         hostname = hp->h_name;
  372.                         break;
  373.                     }
  374.                 }
  375.             }
  376.         }
  377.     } else
  378.         errorhost = hostname = inet_ntoa(fromp->sin_addr);
  379.  
  380. #ifdef    KERBEROS
  381.     if (use_kerberos) {
  382.         kdata = (AUTH_DAT *) authbuf;
  383.         ticket = (KTEXT) tickbuf;
  384.         authopts = 0L;
  385.         strcpy(instance, "*");
  386.         version[VERSION_SIZE - 1] = '\0';
  387. #ifdef CRYPT
  388.         if (doencrypt) {
  389.             struct sockaddr_in local_addr;
  390.             rc = sizeof(local_addr);
  391.             if (getsockname(0, (struct sockaddr *)&local_addr,
  392.                 &rc) < 0) {
  393.                 syslog(LOG_ERR, "getsockname: %m");
  394.                 error("rlogind: getsockname: %m");
  395.                 exit(1);
  396.             }
  397.             authopts = KOPT_DO_MUTUAL;
  398.             rc = krb_recvauth(authopts, 0, ticket,
  399.                 "rcmd", instance, &fromaddr,
  400.                 &local_addr, kdata, "", schedule,
  401.                 version);
  402.             des_set_key(kdata->session, schedule);
  403.         } else
  404. #endif
  405.             rc = krb_recvauth(authopts, 0, ticket, "rcmd",
  406.                 instance, &fromaddr,
  407.                 (struct sockaddr_in *) 0,
  408.                 kdata, "", (bit_64 *) 0, version);
  409.         if (rc != KSUCCESS) {
  410.             error("Kerberos authentication failure: %s\n",
  411.                   krb_err_txt[rc]);
  412.             exit(1);
  413.         }
  414.     } else
  415. #endif
  416.         remuser = getstr ("remuser");
  417.  
  418.     locuser = getstr ("locuser");
  419.     cmdbuf = getstr ("command");
  420.  
  421.     setpwent();
  422.     pwd = getpwnam(locuser);
  423.     if (pwd == NULL) {
  424.         syslog(LOG_INFO|LOG_AUTH,
  425.             "%s@%s as %s: unknown login. cmd='%.80s'",
  426.             remuser, hostname, locuser, cmdbuf);
  427.         if (errorstr == NULL)
  428.             errorstr = "Login incorrect.\n";
  429.         goto fail;
  430.     }
  431.     if (chdir(pwd->pw_dir) < 0) {
  432.         (void) chdir("/");
  433. #ifdef notdef
  434.         syslog(LOG_INFO|LOG_AUTH,
  435.             "%s@%s as %s: no home directory. cmd='%.80s'",
  436.             remuser, hostname, locuser, cmdbuf);
  437.         error("No remote directory.\n");
  438.         exit(1);
  439. #endif
  440.     }
  441.  
  442. #ifdef    KERBEROS
  443.     if (use_kerberos) {
  444.         if (pwd->pw_passwd != 0 && *pwd->pw_passwd != '\0') {
  445.             if (kuserok(kdata, locuser) != 0) {
  446.                 syslog(LOG_INFO|LOG_AUTH,
  447.                     "Kerberos rsh denied to %s.%s@%s",
  448.                     kdata->pname, kdata->pinst, kdata->prealm);
  449.                 error("Permission denied.\n");
  450.                 exit(1);
  451.             }
  452.         }
  453.     } else
  454. #endif
  455.  
  456.         if (errorstr ||
  457.             pwd->pw_passwd != 0 && *pwd->pw_passwd != '\0' &&
  458.             iruserok(fromp->sin_addr.s_addr, pwd->pw_uid == 0,
  459.             remuser, locuser) < 0) {
  460.             if (__rcmd_errstr)
  461.                 syslog(LOG_INFO|LOG_AUTH,
  462.                 "%s@%s as %s: permission denied (%s). cmd='%.80s'",
  463.                     remuser, hostname, locuser, __rcmd_errstr,
  464.                     cmdbuf);
  465.             else
  466.                 syslog(LOG_INFO|LOG_AUTH,
  467.                 "%s@%s as %s: permission denied. cmd='%.80s'",
  468.                     remuser, hostname, locuser, cmdbuf);
  469. fail:
  470.             if (errorstr == NULL)
  471.                 errorstr = "Permission denied.\n";
  472.             error(errorstr, errorhost);
  473.             exit(1);
  474.         }
  475.  
  476.     if (pwd->pw_uid && !access(PATH_NOLOGIN, F_OK)) {
  477.         error("Logins currently disabled.\n");
  478.         exit(1);
  479.     }
  480.  
  481.     (void) write(STDERR_FILENO, "\0", 1);
  482.     sent_null = 1;
  483.  
  484.     if (port) {
  485.         if (pipe(pv) < 0) {
  486.             error("Can't make pipe.\n");
  487.             exit(1);
  488.         }
  489. #ifdef CRYPT
  490. #ifdef KERBEROS
  491.         if (doencrypt) {
  492.             if (pipe(pv1) < 0) {
  493.                 error("Can't make 2nd pipe.\n");
  494.                 exit(1);
  495.             }
  496.             if (pipe(pv2) < 0) {
  497.                 error("Can't make 3rd pipe.\n");
  498.                 exit(1);
  499.             }
  500.         }
  501. #endif
  502. #endif
  503.         pid = fork();
  504.         if (pid == -1)  {
  505.             error("Can't fork; try again.\n");
  506.             exit(1);
  507.         }
  508.         if (pid) {
  509. #ifdef CRYPT
  510. #ifdef KERBEROS
  511.             if (doencrypt) {
  512.                 static char msg[] = SECURE_MESSAGE;
  513.                 (void) close(pv1[1]);
  514.                 (void) close(pv2[1]);
  515.                 des_write(s, msg, sizeof(msg) - 1);
  516.  
  517.             } else
  518. #endif
  519. #endif
  520.             {
  521.                 (void) close(0);
  522.                 (void) close(1);
  523.             }
  524.             (void) close(2);
  525.             (void) close(pv[1]);
  526.  
  527.             FD_ZERO(&readfrom);
  528.             FD_SET(s, &readfrom);
  529.             FD_SET(pv[0], &readfrom);
  530.             if (pv[0] > s)
  531.                 nfd = pv[0];
  532.             else
  533.                 nfd = s;
  534. #ifdef CRYPT
  535. #ifdef KERBEROS
  536.             if (doencrypt) {
  537.                 FD_ZERO(&writeto);
  538.                 FD_SET(pv2[0], &writeto);
  539.                 FD_SET(pv1[0], &readfrom);
  540.  
  541.                 nfd = MAX(nfd, pv2[0]);
  542.                 nfd = MAX(nfd, pv1[0]);
  543.             } else
  544. #endif
  545. #endif
  546.                 ioctl(pv[0], FIONBIO, (char *)&one);
  547.  
  548.             /* should set s nbio! */
  549.             nfd++;
  550.             do {
  551.                 ready = readfrom;
  552. #ifdef CRYPT
  553. #ifdef KERBEROS
  554.                 if (doencrypt) {
  555.                     wready = writeto;
  556.                     if (select(nfd, &ready,
  557.                         &wready, (fd_set *) 0,
  558.                         (struct timeval *) 0) < 0)
  559.                         break;
  560.                 } else
  561. #endif
  562. #endif
  563.                     if (select(nfd, &ready, (fd_set *)0,
  564.                       (fd_set *)0, (struct timeval *)0) < 0)
  565.                         break;
  566.                 if (FD_ISSET(s, &ready)) {
  567.                     int    ret;
  568. #ifdef CRYPT
  569. #ifdef KERBEROS
  570.                     if (doencrypt)
  571.                         ret = des_read(s, &sig, 1);
  572.                     else
  573. #endif
  574. #endif
  575.                         ret = read(s, &sig, 1);
  576.                     if (ret <= 0)
  577.                         FD_CLR(s, &readfrom);
  578.                     else
  579.                         killpg(pid, sig);
  580.                 }
  581.                 if (FD_ISSET(pv[0], &ready)) {
  582.                     errno = 0;
  583.                     cc = read(pv[0], buf, sizeof(buf));
  584.                     if (cc <= 0) {
  585.                         shutdown(s, 1+1);
  586.                         FD_CLR(pv[0], &readfrom);
  587.                     } else {
  588. #ifdef CRYPT
  589. #ifdef KERBEROS
  590.                         if (doencrypt)
  591.                             (void)
  592.                               des_write(s, buf, cc);
  593.                         else
  594. #endif
  595. #endif
  596.                             (void)
  597.                               write(s, buf, cc);
  598.                     }
  599.                 }
  600. #ifdef CRYPT
  601. #ifdef KERBEROS
  602.                 if (doencrypt && FD_ISSET(pv1[0], &ready)) {
  603.                     errno = 0;
  604.                     cc = read(pv1[0], buf, sizeof(buf));
  605.                     if (cc <= 0) {
  606.                         shutdown(pv1[0], 1+1);
  607.                         FD_CLR(pv1[0], &readfrom);
  608.                     } else
  609.                         (void) des_write(STDOUT_FILENO,
  610.                             buf, cc);
  611.                 }
  612.  
  613.                 if (doencrypt && FD_ISSET(pv2[0], &wready)) {
  614.                     errno = 0;
  615.                     cc = des_read(STDIN_FILENO,
  616.                         buf, sizeof(buf));
  617.                     if (cc <= 0) {
  618.                         shutdown(pv2[0], 1+1);
  619.                         FD_CLR(pv2[0], &writeto);
  620.                     } else
  621.                         (void) write(pv2[0], buf, cc);
  622.                 }
  623. #endif
  624. #endif
  625.  
  626.             } while (FD_ISSET(s, &readfrom) ||
  627. #ifdef CRYPT
  628. #ifdef KERBEROS
  629.                 (doencrypt && FD_ISSET(pv1[0], &readfrom)) ||
  630. #endif
  631. #endif
  632.                 FD_ISSET(pv[0], &readfrom));
  633.             exit(0);
  634.         }
  635.         setpgid (0, getpid ());
  636.         (void) close(s);
  637.         (void) close(pv[0]);
  638. #ifdef CRYPT
  639. #ifdef KERBEROS
  640.         if (doencrypt) {
  641.             close(pv1[0]); close(pv2[0]);
  642.             dup2(pv1[1], 1);
  643.             dup2(pv2[1], 0);
  644.             close(pv1[1]);
  645.             close(pv2[1]);
  646.         }
  647. #endif
  648. #endif
  649.         dup2(pv[1], 2);
  650.         close(pv[1]);
  651.     }
  652.     if (*pwd->pw_shell == '\0')
  653.         pwd->pw_shell = PATH_BSHELL;
  654. #if    BSD > 43
  655.     if (setlogin(pwd->pw_name) < 0)
  656.         syslog(LOG_ERR, "setlogin() failed: %m");
  657. #endif
  658.     (void) setgid((gid_t)pwd->pw_gid);
  659.     initgroups(pwd->pw_name, pwd->pw_gid);
  660.     (void) setuid((uid_t)pwd->pw_uid);
  661.     environ = envinit;
  662.     strncat(homedir, pwd->pw_dir, sizeof(homedir)-6);
  663.     strcat(path, PATH_DEFPATH);
  664.     strncat(shell, pwd->pw_shell, sizeof(shell)-7);
  665.     strncat(username, pwd->pw_name, sizeof(username)-6);
  666.     cp = strrchr(pwd->pw_shell, '/');
  667.     if (cp)
  668.         cp++;
  669.     else
  670.         cp = pwd->pw_shell;
  671.     endpwent();
  672.     if (log_success || pwd->pw_uid == 0) {
  673. #ifdef    KERBEROS
  674.         if (use_kerberos)
  675.             syslog(LOG_INFO|LOG_AUTH,
  676.             "Kerberos shell from %s.%s@%s on %s as %s, cmd='%.80s'",
  677.             kdata->pname, kdata->pinst, kdata->prealm,
  678.             hostname, locuser, cmdbuf);
  679.         else
  680. #endif
  681.             syslog(LOG_INFO|LOG_AUTH, "%s@%s as %s: cmd='%.80s'",
  682.             remuser, hostname, locuser, cmdbuf);
  683.     }
  684.     execl(pwd->pw_shell, cp, "-c", cmdbuf, 0);
  685.     perror(pwd->pw_shell);
  686.     exit(1);
  687. }
  688.  
  689. /*
  690.  * Report error to client.  Note: can't be used until second socket has
  691.  * connected to client, or older clients will hang waiting for that
  692.  * connection first.
  693.  */
  694. #if __STDC__
  695. #include <stdarg.h>
  696. #else
  697. #include <varargs.h>
  698. #endif
  699.  
  700. void
  701. #if __STDC__
  702. error(const char *fmt, ...)
  703. #else
  704. error(fmt, va_alist)
  705.     char *fmt;
  706.         va_dcl
  707. #endif
  708. {
  709.     va_list ap;
  710.     int len;
  711.     char *bp, buf[BUFSIZ];
  712. #if __STDC__
  713.     va_start(ap, fmt);
  714. #else
  715.     va_start(ap);
  716. #endif
  717.     bp = buf;
  718.     if (sent_null == 0) {
  719.         *bp++ = 1;
  720.         len = 1;
  721.     } else
  722.         len = 0;
  723.     (void)vsnprintf(bp, sizeof(buf) - 1, fmt, ap);
  724.     (void)write(STDERR_FILENO, buf, len + strlen(bp));
  725. }
  726.  
  727. char *
  728. getstr(err)
  729.     char *err;
  730. {
  731.     size_t buf_len = 100;
  732.     char *buf = malloc (buf_len), *end = buf;
  733.  
  734.     if (! buf) {
  735.         error ("Out of space reading %s\n", err);
  736.         exit (1);
  737.     }
  738.  
  739.     do {
  740.         /* Oh this is efficient, oh yes.  [But what can be done?] */
  741.         int rd = read(STDIN_FILENO, end, 1);
  742.         if (rd <= 0) {
  743.             if (rd == 0)
  744.                 error ("EOF reading %s\n", err);
  745.             else
  746.                 perror (err);
  747.             exit(1);
  748.         }
  749.  
  750.         end += rd;
  751.         if ((buf + buf_len - end) < (buf_len >> 3)) {
  752.             /* Not very much room left in our buffer, grow it. */
  753.             size_t end_offs = end - buf;
  754.             buf_len += buf_len;
  755.             buf = realloc (buf, buf_len);
  756.             if (! buf) {
  757.                 error ("Out of space reading %s\n", err);
  758.                 exit (1);
  759.             }
  760.             end = buf + end_offs;
  761.         }
  762.     } while (*(end - 1));
  763.  
  764.     return buf;
  765. }
  766.  
  767. /*
  768.  * Check whether host h is in our local domain,
  769.  * defined as sharing the last two components of the domain part,
  770.  * or the entire domain part if the local domain has only one component.
  771.  * If either name is unqualified (contains no '.'),
  772.  * assume that the host is local, as it will be
  773.  * interpreted as such.
  774.  */
  775. int
  776. local_domain(h)
  777.     char *h;
  778. {
  779.     extern char *localhost ();
  780.     char *hostname = localhost ();
  781.  
  782.     if (! hostname)
  783.         return 0;
  784.     else {
  785.         int is_local = 0;
  786.         char *p1 = topdomain (hostname);
  787.         char *p2 = topdomain (h);
  788.  
  789.         if (p1 == NULL || p2 == NULL || !strcasecmp(p1, p2))
  790.             is_local = 1;
  791.  
  792.         free (hostname);
  793.  
  794.         return is_local;
  795.     }
  796. }
  797.  
  798. char *
  799. topdomain(h)
  800.     char *h;
  801. {
  802.     char *p, *maybe = NULL;
  803.     int dots = 0;
  804.  
  805.     for (p = h + strlen(h); p >= h; p--) {
  806.         if (*p == '.') {
  807.             if (++dots == 2)
  808.                 return (p);
  809.             maybe = p;
  810.         }
  811.     }
  812.     return (maybe);
  813. }
  814.  
  815. void
  816. usage()
  817. {
  818.  
  819.     syslog(LOG_ERR, "usage: rshd [-%s]", OPTIONS);
  820.     exit(2);
  821. }
  822.