home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 4: GNU Archives / Linux Cubed Series 4 - GNU Archives.iso / gnu / inetutil.1 / inetutil / inetutils-1.1 / rsh / rsh.c < prev   
Encoding:
C/C++ Source or Header  |  1996-07-22  |  10.2 KB  |  499 lines

  1. /*-
  2.  * Copyright (c) 1983, 1990, 1993, 1994
  3.  *    The Regents of the University of California.  All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice, this list of conditions and the following disclaimer.
  10.  * 2. Redistributions in binary form must reproduce the above copyright
  11.  *    notice, this list of conditions and the following disclaimer in the
  12.  *    documentation and/or other materials provided with the distribution.
  13.  * 3. All advertising materials mentioning features or use of this software
  14.  *    must display the following acknowledgement:
  15.  *    This product includes software developed by the University of
  16.  *    California, Berkeley and its contributors.
  17.  * 4. Neither the name of the University nor the names of its contributors
  18.  *    may be used to endorse or promote products derived from this software
  19.  *    without specific prior written permission.
  20.  *
  21.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  22.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  23.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  24.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  25.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  26.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  27.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  28.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  29.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  30.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31.  * SUCH DAMAGE.
  32.  */
  33.  
  34. #ifndef lint
  35. static char copyright[] =
  36. "@(#) Copyright (c) 1983, 1990, 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[] = "@(#)rsh.c    8.4 (Berkeley) 4/29/95";
  42. #endif /* not lint */
  43.  
  44. /*
  45.  * $Source: /gd4/gnu/inetutils/rsh/RCS/rsh.c,v $
  46.  * $Header: /gd4/gnu/inetutils/rsh/RCS/rsh.c,v 1.5 1996/07/22 16:59:05 miles Exp $
  47.  */
  48.  
  49. #ifdef HAVE_CONFIG_H
  50. #include <config.h>
  51. #endif
  52.  
  53. #include <sys/types.h>
  54. #include <sys/signal.h>
  55. #include <sys/socket.h>
  56. #include <sys/ioctl.h>
  57. #include <sys/file.h>
  58.  
  59. #include <netinet/in.h>
  60. #include <netdb.h>
  61.  
  62. #include <err.h>
  63. #include <errno.h>
  64. #include <pwd.h>
  65. #include <signal.h>
  66. #include <stdio.h>
  67. #include <stdlib.h>
  68. #include <string.h>
  69. #include <unistd.h>
  70. #include <varargs.h>
  71. #include <getopt.h>
  72.  
  73. #ifdef KERBEROS
  74. #include <kerberosIV/des.h>
  75. #include <kerberosIV/krb.h>
  76.  
  77. CREDENTIALS cred;
  78. Key_schedule schedule;
  79. int use_kerberos = 1, doencrypt;
  80. char dst_realm_buf[REALM_SZ], *dest_realm;
  81. extern char *krb_realmofhost();
  82. #endif
  83.  
  84. /*
  85.  * rsh - remote shell
  86.  */
  87. int    rfd2;
  88.  
  89. char   *copyargs __P((char **));
  90. void    sendsig __P((int));
  91. void    talk __P((int, long, pid_t, int));
  92. void    usage __P((void));
  93. void    warning __P(());
  94.  
  95. int
  96. main(argc, argv)
  97.     int argc;
  98.     char **argv;
  99. {
  100.     struct passwd *pw;
  101.     struct servent *sp;
  102.     long omask;
  103.     int argoff, asrsh, ch, dflag, nflag, one, rem;
  104.     pid_t pid;
  105.     uid_t uid;
  106.     char *args, *host, *p, *user;
  107.  
  108. #ifndef HAVE___PROGNAME
  109.     extern char *__progname;
  110.     __progname = argv[0];
  111. #endif
  112.  
  113.     argoff = asrsh = dflag = nflag = 0;
  114.     one = 1;
  115.     host = user = NULL;
  116.  
  117.     /* if called as something other than "rsh", use it as the host name */
  118.     if (p = strrchr(argv[0], '/'))
  119.         ++p;
  120.     else
  121.         p = argv[0];
  122.     if (strcmp(p, "rsh"))
  123.         host = p;
  124.     else
  125.         asrsh = 1;
  126.  
  127.     /* handle "rsh host flags" */
  128.     if (!host && argc > 2 && argv[1][0] != '-') {
  129.         host = argv[1];
  130.         argoff = 1;
  131.     }
  132.  
  133. #ifdef KERBEROS
  134. #ifdef CRYPT
  135. #define    OPTIONS    "8KLdek:l:nwx"
  136. #else
  137. #define    OPTIONS    "8KLdek:l:nw"
  138. #endif
  139. #else
  140. #define    OPTIONS    "8KLdel:nw"
  141. #endif
  142.     while ((ch = getopt(argc - argoff, argv + argoff, OPTIONS)) != EOF)
  143.         switch(ch) {
  144.         case 'K':
  145. #ifdef KERBEROS
  146.             use_kerberos = 0;
  147. #endif
  148.             break;
  149.         case 'L':    /* -8Lew are ignored to allow rlogin aliases */
  150.         case 'e':
  151.         case 'w':
  152.         case '8':
  153.             break;
  154.         case 'd':
  155.             dflag = 1;
  156.             break;
  157.         case 'l':
  158.             user = optarg;
  159.             break;
  160. #ifdef KERBEROS
  161.         case 'k':
  162.             dest_realm = dst_realm_buf;
  163.             strncpy(dest_realm, optarg, REALM_SZ);
  164.             break;
  165. #endif
  166.         case 'n':
  167.             nflag = 1;
  168.             break;
  169. #ifdef KERBEROS
  170. #ifdef CRYPT
  171.         case 'x':
  172.             doencrypt = 1;
  173.             des_set_key(cred.session, schedule);
  174.             break;
  175. #endif
  176. #endif
  177.         case '?':
  178.         default:
  179.             usage();
  180.         }
  181.     optind += argoff;
  182.  
  183.     /* if haven't gotten a host yet, do so */
  184.     if (!host && !(host = argv[optind++]))
  185.         usage();
  186.  
  187.     /* if no further arguments, must have been called as rlogin. */
  188.     if (!argv[optind]) {
  189.         if (asrsh)
  190.             *argv = "rlogin";
  191.         execv(_PATH_RLOGIN, argv);
  192.         err(1, "can't exec %s", _PATH_RLOGIN);
  193.     }
  194.  
  195.     argc -= optind;
  196.     argv += optind;
  197.  
  198.     if (!(pw = getpwuid(uid = getuid())))
  199.         errx(1, "unknown user id");
  200.     /* Accept user1@host format, though "-l user2" overrides user1 */
  201.     p = strchr(host, '@');
  202.     if (p) {
  203.         *p = '\0';
  204.         if (!user && p > host)
  205.             user = host;
  206.         host = p + 1;
  207.         if (*host == '\0')
  208.             usage();
  209.     }
  210.     if (!user)
  211.         user = pw->pw_name;
  212.  
  213. #ifdef KERBEROS
  214. #ifdef CRYPT
  215.     /* -x turns off -n */
  216.     if (doencrypt)
  217.         nflag = 0;
  218. #endif
  219. #endif
  220.  
  221.     args = copyargs(argv);
  222.  
  223.     sp = NULL;
  224. #ifdef KERBEROS
  225.     if (use_kerberos) {
  226.         sp = getservbyname((doencrypt ? "ekshell" : "kshell"), "tcp");
  227.         if (sp == NULL) {
  228.             use_kerberos = 0;
  229.             warning("can't get entry for %s/tcp service",
  230.                 doencrypt ? "ekshell" : "kshell");
  231.         }
  232.     }
  233. #endif
  234.     if (sp == NULL)
  235.         sp = getservbyname("shell", "tcp");
  236.     if (sp == NULL)
  237.         errx(1, "shell/tcp: unknown service");
  238.  
  239. #ifdef KERBEROS
  240. try_connect:
  241.     if (use_kerberos) {
  242.         struct hostent *hp;
  243.  
  244.         /* fully qualify hostname (needed for krb_realmofhost) */
  245.         hp = gethostbyname(host);
  246.         if (hp != NULL && !(host = strdup(hp->h_name)))
  247.             err(1, NULL);
  248.  
  249.         rem = KSUCCESS;
  250.         errno = 0;
  251.         if (dest_realm == NULL)
  252.             dest_realm = krb_realmofhost(host);
  253.  
  254. #ifdef CRYPT
  255.         if (doencrypt)
  256.             rem = krcmd_mutual(&host, sp->s_port, user, args,
  257.                 &rfd2, dest_realm, &cred, schedule);
  258.         else
  259. #endif
  260.             rem = krcmd(&host, sp->s_port, user, args, &rfd2,
  261.                 dest_realm);
  262.         if (rem < 0) {
  263.             use_kerberos = 0;
  264.             sp = getservbyname("shell", "tcp");
  265.             if (sp == NULL)
  266.                 errx(1, "shell/tcp: unknown service");
  267.             if (errno == ECONNREFUSED)
  268.                 warning("remote host doesn't support Kerberos");
  269.             if (errno == ENOENT)
  270.                 warning("can't provide Kerberos auth data");
  271.             goto try_connect;
  272.         }
  273.     } else {
  274.         if (doencrypt)
  275.             errx(1, "the -x flag requires Kerberos authentication");
  276.         rem = rcmd(&host, sp->s_port, pw->pw_name, user, args, &rfd2);
  277.     }
  278. #else
  279.     rem = rcmd(&host, sp->s_port, pw->pw_name, user, args, &rfd2);
  280. #endif
  281.  
  282.     if (rem < 0)
  283.         exit(1);
  284.  
  285.     if (rfd2 < 0)
  286.         errx(1, "can't establish stderr");
  287.     if (dflag) {
  288.         if (setsockopt(rem, SOL_SOCKET, SO_DEBUG, &one,
  289.             sizeof(one)) < 0)
  290.             warn("setsockopt");
  291.         if (setsockopt(rfd2, SOL_SOCKET, SO_DEBUG, &one,
  292.             sizeof(one)) < 0)
  293.             warn("setsockopt");
  294.     }
  295.  
  296.     (void)setuid(uid);
  297.     omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGTERM));
  298.     if (signal(SIGINT, SIG_IGN) != SIG_IGN)
  299.         (void)signal(SIGINT, sendsig);
  300.     if (signal(SIGQUIT, SIG_IGN) != SIG_IGN)
  301.         (void)signal(SIGQUIT, sendsig);
  302.     if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
  303.         (void)signal(SIGTERM, sendsig);
  304.  
  305.     if (!nflag) {
  306.         pid = fork();
  307.         if (pid < 0)
  308.             err(1, "fork");
  309.     }
  310.  
  311. #ifdef KERBEROS
  312. #ifdef CRYPT
  313.     if (!doencrypt)
  314. #endif
  315. #endif
  316.     {
  317.         (void)ioctl(rfd2, FIONBIO, &one);
  318.         (void)ioctl(rem, FIONBIO, &one);
  319.     }
  320.  
  321.     talk(nflag, omask, pid, rem);
  322.  
  323.     if (!nflag)
  324.         (void)kill(pid, SIGKILL);
  325.     exit(0);
  326. }
  327.  
  328. void
  329. talk(nflag, omask, pid, rem)
  330.     int nflag;
  331.     long omask;
  332.     pid_t pid;
  333.     int rem;
  334. {
  335.     int cc, wc;
  336.     fd_set readfrom, ready, rembits;
  337.     char *bp, buf[BUFSIZ];
  338.  
  339.     if (!nflag && pid == 0) {
  340.         (void)close(rfd2);
  341.  
  342. reread:        errno = 0;
  343.         if ((cc = read(0, buf, sizeof buf)) <= 0)
  344.             goto done;
  345.         bp = buf;
  346.  
  347. rewrite:    
  348.         FD_ZERO(&rembits);
  349.         FD_SET(rem, &rembits);
  350.         if (select(16, 0, &rembits, 0, 0) < 0) {
  351.             if (errno != EINTR)
  352.                 err(1, "select");
  353.             goto rewrite;
  354.         }
  355.         if (!FD_ISSET(rem, &rembits))
  356.             goto rewrite;
  357. #ifdef KERBEROS
  358. #ifdef CRYPT
  359.         if (doencrypt)
  360.             wc = des_write(rem, bp, cc);
  361.         else
  362. #endif
  363. #endif
  364.             wc = write(rem, bp, cc);
  365.         if (wc < 0) {
  366.             if (errno == EWOULDBLOCK)
  367.                 goto rewrite;
  368.             goto done;
  369.         }
  370.         bp += wc;
  371.         cc -= wc;
  372.         if (cc == 0)
  373.             goto reread;
  374.         goto rewrite;
  375. done:
  376.         (void)shutdown(rem, 1);
  377.         exit(0);
  378.     }
  379.  
  380.     (void)sigsetmask(omask);
  381.     FD_ZERO(&readfrom);
  382.     FD_SET(rfd2, &readfrom);
  383.     FD_SET(rem, &readfrom);
  384.     do {
  385.         ready = readfrom;
  386.         if (select(16, &ready, 0, 0, 0) < 0) {
  387.             if (errno != EINTR)
  388.                 err(1, "select");
  389.             continue;
  390.         }
  391.         if (FD_ISSET(rfd2, &ready)) {
  392.             errno = 0;
  393. #ifdef KERBEROS
  394. #ifdef CRYPT
  395.             if (doencrypt)
  396.                 cc = des_read(rfd2, buf, sizeof buf);
  397.             else
  398. #endif
  399. #endif
  400.                 cc = read(rfd2, buf, sizeof buf);
  401.             if (cc <= 0) {
  402.                 if (errno != EWOULDBLOCK)
  403.                     FD_CLR(rfd2, &readfrom);
  404.             } else
  405.                 (void)write(2, buf, cc);
  406.         }
  407.         if (FD_ISSET(rem, &ready)) {
  408.             errno = 0;
  409. #ifdef KERBEROS
  410. #ifdef CRYPT
  411.             if (doencrypt)
  412.                 cc = des_read(rem, buf, sizeof buf);
  413.             else
  414. #endif
  415. #endif
  416.                 cc = read(rem, buf, sizeof buf);
  417.             if (cc <= 0) {
  418.                 if (errno != EWOULDBLOCK)
  419.                     FD_CLR(rem, &readfrom);
  420.             } else
  421.                 (void)write(1, buf, cc);
  422.         }
  423.     } while (FD_ISSET(rfd2, &readfrom) || FD_ISSET(rem, &readfrom));
  424. }
  425.  
  426. void
  427. sendsig(sig)
  428.     int sig;
  429. {
  430.     char signo;
  431.  
  432.     signo = sig;
  433. #ifdef KERBEROS
  434. #ifdef CRYPT
  435.     if (doencrypt)
  436.         (void)des_write(rfd2, &signo, 1);
  437.     else
  438. #endif
  439. #endif
  440.         (void)write(rfd2, &signo, 1);
  441. }
  442.  
  443. #ifdef KERBEROS
  444. /* VARARGS */
  445. void
  446. warning(va_alist)
  447. va_dcl
  448. {
  449.     va_list ap;
  450.     char *fmt;
  451.  
  452.     (void)fprintf(stderr, "rsh: warning, using standard rsh: ");
  453.     va_start(ap);
  454.     fmt = va_arg(ap, char *);
  455.     vfprintf(stderr, fmt, ap);
  456.     va_end(ap);
  457.     (void)fprintf(stderr, ".\n");
  458. }
  459. #endif
  460.  
  461. char *
  462. copyargs(argv)
  463.     char **argv;
  464. {
  465.     int cc;
  466.     char **ap, *args, *p;
  467.  
  468.     cc = 0;
  469.     for (ap = argv; *ap; ++ap)
  470.         cc += strlen(*ap) + 1;
  471.     if (!(args = malloc((u_int)cc)))
  472.         err(1, NULL);
  473.     for (p = args, ap = argv; *ap; ++ap) {
  474.         (void)strcpy(p, *ap);
  475.         for (p = strcpy(p, *ap); *p; ++p);
  476.         if (ap[1])
  477.             *p++ = ' ';
  478.     }
  479.     return (args);
  480. }
  481.  
  482. void
  483. usage()
  484. {
  485.  
  486.     (void)fprintf(stderr,
  487.         "usage: rsh [-nd%s]%s[-l login] [login@]host [command]\n",
  488. #ifdef KERBEROS
  489. #ifdef CRYPT
  490.         "x", " [-k realm] ");
  491. #else
  492.         "", " [-k realm] ");
  493. #endif
  494. #else
  495.         "", " ");
  496. #endif
  497.     exit(1);
  498. }
  499.