* kcmd.c: Integrate ghudson's changes for client-side krb4
authorTom Yu <tlyu@mit.edu>
Tue, 24 Feb 1998 19:55:21 +0000 (19:55 +0000)
committerTom Yu <tlyu@mit.edu>
Tue, 24 Feb 1998 19:55:21 +0000 (19:55 +0000)
compatibility. [krb5-appl/483]

* krcp.c: Integrate ghudson's changes for client-side krb4
compatibility. [krb5-appl/483]

* krlogin.c: Integrate ghudson's changes for client-side krb4
compatibility. [krb5-appl/483]

* krlogind.c: Integrate ghudson's changes for client-side krb4
compatibility. [krb5-appl/483]

* krsh.c: Integrate ghudson's changes for client-side krb4
compatibility. [krb5-appl/483]

* krshd.c: Integrate ghudson's changes for client-side krb4
compatibility. [krb5-appl/483]

git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@10472 dc483132-0cff-0310-8789-dd5450dbe970

src/appl/bsd/ChangeLog
src/appl/bsd/kcmd.c
src/appl/bsd/krcp.c
src/appl/bsd/krlogin.c
src/appl/bsd/krlogind.c
src/appl/bsd/krsh.c
src/appl/bsd/krshd.c

index 9ab4cc1617c3a2e9a7387d11905bc5db65a8dd5c..f892570198383778b736e4b38c48bbbe2880c18a 100644 (file)
@@ -1,3 +1,23 @@
+Tue Feb 24 14:52:33 1998  Tom Yu  <tlyu@mit.edu>
+
+       * kcmd.c: Integrate ghudson's changes for client-side krb4
+       compatibility. [krb5-appl/483]
+       
+       * krcp.c: Integrate ghudson's changes for client-side krb4
+       compatibility. [krb5-appl/483]
+
+       * krlogin.c: Integrate ghudson's changes for client-side krb4
+       compatibility. [krb5-appl/483]
+
+       * krlogind.c: Integrate ghudson's changes for client-side krb4
+       compatibility. [krb5-appl/483]
+
+       * krsh.c: Integrate ghudson's changes for client-side krb4
+       compatibility. [krb5-appl/483]
+
+       * krshd.c: Integrate ghudson's changes for client-side krb4
+       compatibility. [krb5-appl/483]
+
 Sun Feb 22 19:16:12 1998  Tom Yu  <tlyu@mit.edu>
 
        * v4rcp.c: Punt nastiness to redefine setreuid, as we don't use
index 1f196002df35e28ae12f62e0b1c16739340ef457..c6f21e02f23a7dfd9b4dc8ebcaf21d16d24b21ac 100644 (file)
 #endif
 #endif
      
+#ifndef roundup
+#define roundup(x,y) ((((x)+(y)-1)/(y))*(y))
+#endif
+
 #include <netinet/in.h>
 #include <netdb.h>
      
 #include <errno.h>
-#include "krb5.h"
+#include <krb5.h>
+#ifdef KRB5_KRB4_COMPAT
+#include <kerberosIV/krb.h>
+#endif
 
 #include "defines.h"
 
+extern krb5_context bsd_context;
+#ifdef KRB5_KRB4_COMPAT
+extern Key_schedule v4_schedule;
+#endif
 
+#define RCMD_BUFSIZ    5120
 #define START_PORT      5120     /* arbitrary */
 char *default_service = "host";
 
-extern krb5_context bsd_context;
+/*
+ * Note that the encrypted rlogin packets take the form of a four-byte
+ * length followed by encrypted data.  On writing the data out, a significant
+ * performance penalty is suffered (at least one RTT per character, two if we
+ * are waiting for a shell to echo) by writing the data separately from the 
+ * length.  So, unlike the input buffer, which just contains the output
+ * data, the output buffer represents the entire packet.
+ */
 
+static char des_inbuf[2*RCMD_BUFSIZ];   /* needs to be > largest read size */
+static char des_outpkt[2*RCMD_BUFSIZ+4]; /* needs to be > largest write size */
+static krb5_data desinbuf;
+static krb5_data desoutbuf;
+static krb5_encrypt_block eblock;       /* eblock for encrypt/decrypt */
+static int (*input)();
+static int (*output)();
+static char storage[2*RCMD_BUFSIZ];     /* storage for the decryption */
+static int nstored = 0;
+static char *store_ptr = storage;
+static int twrite();
+static int v5_des_read(), v5_des_write();
+#ifdef KRB5_KRB4_COMPAT
+static int v4_des_read(), v4_des_write();
+static C_Block v4_session;
+static int right_justify;
+static int do_lencheck;
+#endif
 
 kcmd(sock, ahost, rport, locuser, remuser, cmd, fd2p, service, realm,
-     cred, seqno, server_seqno, laddr, faddr, authopts, anyport)
+     cred, seqno, server_seqno, laddr, faddr, authopts, anyport, suppress_err)
      int *sock;
      char **ahost;
      u_short rport;
@@ -82,6 +119,7 @@ kcmd(sock, ahost, rport, locuser, remuser, cmd, fd2p, service, realm,
      struct sockaddr_in *laddr, *faddr;
      krb5_flags authopts;
      int anyport;
+     int suppress_err;         /* Don't print if authentication fails */
 {
     int i, s, timo = 1, pid;
 #ifdef POSIX_SIGNALS
@@ -304,13 +342,18 @@ kcmd(sock, ahost, rport, locuser, remuser, cmd, fd2p, service, realm,
                           authopts, &cksumdat, ret_cred, 0,    &error, &rep_ret, NULL);
     free(cksumbuf);
     if (status) {
-       printf("Couldn't authenticate to server: %s\n", error_message(status));
+       if (!suppress_err)
+           fprintf(stderr, "Couldn't authenticate to server: %s\n",
+                   error_message(status));
        if (error) {
-           printf("Server returned error code %d (%s)\n", error->error,
-                  error_message(ERROR_TABLE_BASE_krb5 + error->error));
-           if (error->text.length) {
-               fprintf(stderr, "Error text sent from server: %s\n",
-                       error->text.data);
+           if (!suppress_err) {
+               fprintf(stderr, "Server returned error code %d (%s)\n",
+                       error->error,
+                       error_message(ERROR_TABLE_BASE_krb5 + error->error));
+               if (error->text.length) {
+                   fprintf(stderr, "Error text sent from server: %s\n",
+                           error->text.data);
+               }
            }
            krb5_free_error(bsd_context, error);
            error = 0;
@@ -393,6 +436,246 @@ kcmd(sock, ahost, rport, locuser, remuser, cmd, fd2p, service, realm,
 
 
 
+#ifdef KRB5_KRB4_COMPAT
+k4cmd(sock, ahost, rport, locuser, remuser, cmd, fd2p, ticket, service, realm,
+      cred, schedule, msg_data, laddr, faddr, authopts, anyport)
+     int *sock;
+     char **ahost;
+     u_short rport;
+     char *locuser, *remuser, *cmd;
+     int *fd2p;
+     KTEXT ticket;
+     char *service;
+     char *realm;
+     CREDENTIALS *cred;
+     Key_schedule schedule;
+     MSG_DAT *msg_data;
+     struct sockaddr_in *laddr, *faddr;
+     long authopts;
+     int anyport;
+{
+    int s, pid;
+#ifdef POSIX_SIGNALS
+    sigset_t oldmask, urgmask;
+#else
+    sigmasktype oldmask;
+#endif
+    struct sockaddr_in sin, from;
+    char c;
+    int lport = START_PORT;
+    struct hostent *hp;
+    int rc, sin_len;
+    char *host_save;
+    int status;
+
+    pid = getpid();
+    hp = gethostbyname(*ahost);
+    if (hp == 0) {
+       fprintf(stderr, "%s: unknown host\n", *ahost);
+       return (-1);
+    }
+    host_save = malloc(strlen(hp->h_name) + 1);
+    strcpy(host_save, hp->h_name);
+    *ahost = host_save;
+
+    /* If realm is null, look up from table */
+    if ((realm == NULL) || (realm[0] == '\0')) {
+       realm = krb_realmofhost(host_save);
+    }
+
+#ifdef POSIX_SIGNALS
+    sigemptyset(&urgmask);
+    sigaddset(&urgmask, SIGURG);
+    sigprocmask(SIG_BLOCK, &urgmask, &oldmask);
+#else
+    oldmask = sigblock(sigmask(SIGURG));
+#endif /* POSIX_SIGNALS */
+    for (;;) {
+       s = getport(&lport);
+       if (s < 0) {
+           if (errno == EAGAIN)
+               fprintf(stderr, "socket: All ports in use\n");
+           else
+               perror("rcmd: socket");
+#ifdef POSIX_SIGNALS
+           sigprocmask(SIG_SETMASK, &oldmask, (sigset_t*)0);
+#else
+           sigsetmask(oldmask);
+#endif /* POSIX_SIGNALS */
+           return (-1);
+       }
+       sin.sin_family = hp->h_addrtype;
+       memcpy((caddr_t)&sin.sin_addr, hp->h_addr, sizeof(sin.sin_addr));
+       sin.sin_port = rport;
+       if (connect(s, (struct sockaddr *)&sin, sizeof (sin)) >= 0)
+           break;
+       (void) close(s);
+       if (errno == EADDRINUSE) {
+           lport--;
+           continue;
+       }
+#if !(defined(tex) || defined(ultrix) || defined(sun) || defined(SYSV))
+       if (hp->h_addr_list[1] != NULL) {
+           int oerrno = errno;
+
+           fprintf(stderr,
+                   "connect to address %s: ", inet_ntoa(sin.sin_addr));
+           errno = oerrno;
+           perror(0);
+           hp->h_addr_list++;
+           memcpy((caddr_t)&sin.sin_addr, hp->h_addr_list[0],
+                  sizeof(sin.sin_addr));
+           fprintf(stderr, "Trying %s...\n", inet_ntoa(sin.sin_addr));
+           continue;
+       }
+#endif                                         /* !(defined(ultrix) || defined(sun)) */
+       perror(host_save);
+#ifdef POSIX_SIGNALS
+       sigprocmask(SIG_SETMASK, &oldmask, (sigset_t*)0);
+#else
+       sigsetmask(oldmask);
+#endif /* POSIX_SIGNALS */
+       return (-1);
+    }
+    lport--;
+    if (fd2p == 0) {
+       write(s, "", 1);
+       lport = 0;
+    } else {
+       char num[8];
+       int s2 = getport(&lport), s3;
+       int len = sizeof (from);
+
+       if (s2 < 0) {
+           status = -1;
+           goto bad;
+       }
+       listen(s2, 1);
+       (void) sprintf(num, "%d", lport);
+       if (write(s, num, strlen(num)+1) != strlen(num)+1) {
+           perror("write: setting up stderr");
+           (void) close(s2);
+           status = -1;
+           goto bad;
+       }
+       s3 = accept(s2, (struct sockaddr *)&from, &len);
+       (void) close(s2);
+       if (s3 < 0) {
+           perror("accept");
+           lport = 0;
+           status = -1;
+           goto bad;
+       }
+       *fd2p = s3;
+       from.sin_port = ntohs((u_short)from.sin_port);
+       /* This check adds nothing when using Kerberos.  */
+       if (! anyport &&
+           (from.sin_family != AF_INET ||
+            from.sin_port >= IPPORT_RESERVED)) {
+           fprintf(stderr, "socket: protocol failure in circuit setup.\n");
+           status = -1;
+           goto bad2;
+       }
+    }
+
+    /* set up the needed stuff for mutual auth */
+    *faddr = sin;
+    sin_len = sizeof (struct sockaddr_in);
+    if (getsockname(s, (struct sockaddr *)laddr, &sin_len) < 0) {
+       perror("getsockname");
+       status = -1;
+       goto bad2;
+    }
+
+    if ((status = krb_sendauth(authopts, s, ticket, service, *ahost,
+                              realm, (unsigned long) getpid(), msg_data,
+                              cred, schedule,
+                              laddr,
+                              faddr,
+                              "KCMDV0.1")) != KSUCCESS) {
+       fprintf(stderr, "krb_sendauth failed: %s\n", krb_get_err_text(status));
+       status = -1;
+       goto bad2;
+    }
+    (void) write(s, remuser, strlen(remuser)+1);
+    (void) write(s, cmd, strlen(cmd)+1);
+
+reread:
+    if ((rc=read(s, &c, 1)) != 1) {
+       if (rc==-1) {
+           perror(*ahost);
+       } else {
+           fprintf(stderr,"rcmd: bad connection with remote host\n");
+       }
+       status = -1;
+       goto bad2;
+    }
+    if (c != 0) {
+       /* If rlogind was compiled on SunOS4, and it somehow
+          got the shared library version numbers wrong, it
+          may give an ld.so warning about an old version of a
+          shared library.  Just ignore any such warning.
+          Note that the warning is a characteristic of the
+          server; we may not ourselves be running under
+          SunOS4.  */
+       if (c == 'l') {
+           char *check = "d.so: warning:";
+           char *p;
+           char cc;
+
+           p = check;
+           while (read(s, &c, 1) == 1) {
+               if (*p == '\0') {
+                   if (c == '\n')
+                       break;
+               } else {
+                   if (c != *p)
+                       break;
+                   ++p;
+               }
+           }
+
+           if (*p == '\0')
+               goto reread;
+
+           cc = 'l';
+           (void) write(2, &cc, 1);
+           if (p != check)
+               (void) write(2, check, p - check);
+       }
+
+       (void) write(2, &c, 1);
+       while (read(s, &c, 1) == 1) {
+           (void) write(2, &c, 1);
+           if (c == '\n')
+               break;
+       }
+       status = -1;
+       goto bad2;
+    }
+#ifdef POSIX_SIGNALS
+    sigprocmask(SIG_SETMASK, &oldmask, (sigset_t*)0);
+#else
+    sigsetmask(oldmask);
+#endif
+    *sock = s;
+    return (KSUCCESS);
+ bad2:
+    if (lport)
+       (void) close(*fd2p);
+ bad:
+    (void) close(s);
+#ifdef POSIX_SIGNALS
+    sigprocmask(SIG_SETMASK, &oldmask, (sigset_t*)0);
+#else
+    sigsetmask(oldmask);
+#endif
+    return (status);
+}
+#endif /* KRB5_KRB4_COMPAT */
+
+
+
 getport(alport)
      int *alport;
 {
@@ -424,9 +707,342 @@ getport(alport)
     return -1;
 }
 
+void rcmd_stream_init_normal()
+{
+    input = read;
+    output = twrite;
+}
+
+void rcmd_stream_init_krb5(keyblock, encrypt_flag, lencheck)
+     krb5_keyblock *keyblock;
+     int encrypt_flag;
+     int lencheck;
+{
+    krb5_error_code status;
+
+    if (!encrypt_flag) {
+       rcmd_stream_init_normal();
+       return;
+    }
+    desinbuf.data = des_inbuf;
+    desoutbuf.data = des_outpkt+4;     /* Set up des buffers */
+    krb5_use_enctype(bsd_context, &eblock, keyblock->enctype);
+    if ( status = krb5_process_key(bsd_context, &eblock, keyblock)) {
+       fprintf(stderr, "rcmd: Cannot process session key: %s\n",
+               error_message(status));
+       exit(1);
+    }
+    do_lencheck = lencheck;
+    input = v5_des_read;
+    output = v5_des_write;
+}
+
+#ifdef KRB5_KRB4_COMPAT
+void rcmd_stream_init_krb4(session, encrypt_flag, lencheck, justify)
+     C_Block session;
+     int encrypt_flag;
+     int lencheck;
+     int justify;
+{
+    if (!encrypt_flag) {
+       rcmd_stream_init_normal();
+       return;
+    }
+    do_lencheck = lencheck;
+    right_justify = justify;
+    input = v4_des_read;
+    output = v4_des_write;
+    memcpy(v4_session, session, sizeof(v4_session));
+}
+#endif
+
+int rcmd_stream_read(fd, buf, len)
+     int fd;
+     register char *buf;
+     int len;
+{
+    return (*input)(fd, buf, len);
+}
+
+int rcmd_stream_write(fd, buf, len)
+     int fd;
+     register char *buf;
+     int len;
+{
+    return (*output)(fd, buf, len);
+}
+
+/* Because of rcp lossage, translate fd 0 to 1 when writing. */
+static int twrite(fd, buf, len)
+     int fd;
+     char *buf;
+     int len;
+{
+    return write((fd == 0) ? 1 : fd, buf, len);
+}
+
+static int v5_des_read(fd, buf, len)
+     int fd;
+     char *buf;
+     int len;
+{
+    int nreturned = 0;
+    long net_len,rd_len;
+    int cc;
+    unsigned char c;
+    
+    if (nstored >= len) {
+       memcpy(buf, store_ptr, len);
+       store_ptr += len;
+       nstored -= len;
+       return(len);
+    } else if (nstored) {
+       memcpy(buf, store_ptr, nstored);
+       nreturned += nstored;
+       buf += nstored;
+       len -= nstored;
+       nstored = 0;
+    }
+
+    /* See the comment in v4_des_read. */
+    while (1) {
+       cc = krb5_net_read(bsd_context, fd, &c, 1);
+       /* we should check for non-blocking here, but we'd have
+          to make it save partial reads as well. */
+       if (cc <= 0) return cc; /* read error */
+       if (cc == 1) {
+           if (c == 0 || !do_lencheck) break;
+       }
+    }
+
+    rd_len = c;
+    if ((cc = krb5_net_read(bsd_context, fd, &c, 1)) != 1) return 0;
+    rd_len = (rd_len << 8) | c;
+    if ((cc = krb5_net_read(bsd_context, fd, &c, 1)) != 1) return 0;
+    rd_len = (rd_len << 8) | c;
+    if ((cc = krb5_net_read(bsd_context, fd, &c, 1)) != 1) return 0;
+    rd_len = (rd_len << 8) | c;
+
+    net_len = krb5_encrypt_size(rd_len,eblock.crypto_entry);
+    if ((net_len <= 0) || (net_len > sizeof(des_inbuf))) {
+       /* preposterous length, probably out of sync */
+       errno = EIO;
+       return(-1);
+    }
+    if ((cc = krb5_net_read(bsd_context, fd, desinbuf.data, net_len)) != net_len) {
+       /* probably out of sync */
+       errno = EIO;
+       return(-1);
+    }
+    /* decrypt info */
+    if ((krb5_decrypt(bsd_context, desinbuf.data,
+                     (krb5_pointer) storage,
+                     net_len,
+                     &eblock, 0))) {
+       /* probably out of sync */
+       errno = EIO;
+       return(-1);
+    }
+    store_ptr = storage;
+    nstored = rd_len;
+    if (nstored > len) {
+       memcpy(buf, store_ptr, len);
+       nreturned += len;
+       store_ptr += len;
+       nstored -= len;
+    } else {
+       memcpy(buf, store_ptr, nstored);
+       nreturned += nstored;
+       nstored = 0;
+    }
+
+    return(nreturned);
+}
+
+
+
+static int v5_des_write(fd, buf, len)
+     int fd;
+     char *buf;
+     int len;
+{
+    unsigned char *len_buf = (unsigned char *) des_outpkt;
+    
+    desoutbuf.length = krb5_encrypt_size(len,eblock.crypto_entry);
+    if (desoutbuf.length > sizeof(des_outpkt)-4){
+       errno = EIO;
+       return(-1);
+    }
+    if ((krb5_encrypt(bsd_context, (krb5_pointer)buf,
+                     desoutbuf.data,
+                     len,
+                     &eblock,
+                     0))){
+       errno = EIO;
+       return(-1);
+    }
+
+    len_buf[0] = (len & 0xff000000) >> 24;
+    len_buf[1] = (len & 0xff0000) >> 16;
+    len_buf[2] = (len & 0xff00) >> 8;
+    len_buf[3] = (len & 0xff);
+
+    if (write(fd, des_outpkt,desoutbuf.length+4) != desoutbuf.length+4){
+       errno = EIO;
+       return(-1);
+    }
+    else return(len);
+}
+
+
 
+#ifdef KRB5_KRB4_COMPAT
 
+static int
+v4_des_read(fd, buf, len)
+int fd;
+char *buf;
+int len;
+{
+       int nreturned = 0;
+       krb5_ui_4 net_len, rd_len;
+       int cc;
+       unsigned char c;
 
+       if (nstored >= len) {
+               memcpy(buf, store_ptr, len);
+               store_ptr += len;
+               nstored -= len;
+               return(len);
+       } else if (nstored) {
+               memcpy(buf, store_ptr, nstored);
+               nreturned += nstored;
+               buf += nstored;
+               len -= nstored;
+               nstored = 0;
+       }
+
+       /* We're fetching the length which is MSB first, and the MSB
+          has to be zero unless the client is sending more than 2^24
+          (16M) bytes in a single write (which is why this code is used
+          in rlogin but not rcp or rsh.) The only reasons we'd get
+          something other than zero are:
+               -- corruption of the tcp stream (which will show up when
+                  everything else is out of sync too)
+               -- un-caught Berkeley-style "pseudo out-of-band data" which
+                  happens any time the user hits ^C twice.
+          The latter is *very* common, as shown by an 'rlogin -x -d' 
+          using the CNS V4 rlogin.         Mark EIchin 1/95
+          */
+       while (1) {
+           cc = krb_net_read(fd, &c, 1);
+           if (cc <= 0) return cc; /* read error */
+           if (cc == 1) {
+               if (c == 0 || !do_lencheck) break;
+           }
+       }
+
+       net_len = c;
+       if ((cc = krb_net_read(fd, &c, 1)) != 1) return 0;
+       net_len = (net_len << 8) | c;
+       if ((cc = krb_net_read(fd, &c, 1)) != 1) return 0;
+       net_len = (net_len << 8) | c;
+       if ((cc = krb_net_read(fd, &c, 1)) != 1) return 0;
+       net_len = (net_len << 8) | c;
+
+       /* Note: net_len is unsigned */
+       if (net_len > sizeof(des_inbuf)) {
+               errno = EIO;
+               return(-1);
+       }
+       /* the writer tells us how much real data we are getting, but
+          we need to read the pad bytes (8-byte boundary) */
+       rd_len = roundup(net_len, 8);
+       if ((cc = krb_net_read(fd, des_inbuf, rd_len)) != rd_len) {
+               errno = EIO;
+               return(-1);
+       }
+       (void) pcbc_encrypt(des_inbuf,
+                           storage,
+                           (net_len < 8) ? 8 : net_len,
+                           v4_schedule,
+                           v4_session,
+                           DECRYPT);
+       /* 
+        * when the cleartext block is < 8 bytes, it is "right-justified"
+        * in the block, so we need to adjust the pointer to the data
+        */
+       if (net_len < 8 && right_justify)
+               store_ptr = storage + 8 - net_len;
+       else
+               store_ptr = storage;
+       nstored = net_len;
+       if (nstored > len) {
+               memcpy(buf, store_ptr, len);
+               nreturned += len;
+               store_ptr += len;
+               nstored -= len;
+       } else {
+               memcpy(buf, store_ptr, nstored);
+               nreturned += nstored;
+               nstored = 0;
+       }
+       
+       return(nreturned);
+}
+
+static int
+v4_des_write(fd, buf, len)
+int fd;
+char *buf;
+int len;
+{
+       static char garbage_buf[8];
+       unsigned char *len_buf = (unsigned char *) des_outpkt;
+
+       /* 
+        * pcbc_encrypt outputs in 8-byte (64 bit) increments
+        *
+        * it zero-fills the cleartext to 8-byte padding,
+        * so if we have cleartext of < 8 bytes, we want
+        * to insert random garbage before it so that the ciphertext
+        * differs for each transmission of the same cleartext.
+        * if len < 8 - sizeof(long), sizeof(long) bytes of random
+        * garbage should be sufficient; leave the rest as-is in the buffer.
+        * if len > 8 - sizeof(long), just garbage fill the rest.
+        */
+
+#ifdef min
+#undef min
+#endif
+#define min(a,b) ((a < b) ? a : b)
+
+       if (len < 8 && right_justify) {
+               krb5_random_confounder(8 - len, garbage_buf);
+               /* this "right-justifies" the data in the buffer */
+               (void) memcpy(garbage_buf + 8 - len, buf, len);
+       }
+       (void) pcbc_encrypt((len < 8) ? garbage_buf : buf,
+                           des_outpkt+4,
+                           (len < 8) ? 8 : len,
+                           v4_schedule,
+                           v4_session,
+                           ENCRYPT);
+
+       /* tell the other end the real amount, but send an 8-byte padded
+          packet */
+       len_buf[0] = (len & 0xff000000) >> 24;
+       len_buf[1] = (len & 0xff0000) >> 16;
+       len_buf[2] = (len & 0xff00) >> 8;
+       len_buf[3] = (len & 0xff);
+       if (write(fd, des_outpkt, roundup(len,8)+4) != roundup(len,8)+4) {
+               errno = EIO;
+               return(-1);
+       }
+       return(len);
+}
+
+#endif /* KRB5_KRB4_COMPAT */
 
 #ifndef HAVE_STRSAVE
 /* Strsave was a routine in the version 4 krb library: we put it here
@@ -448,4 +1064,3 @@ char *sp;
 }
 
 #endif
-
index a6fe0dc7efa0d157c9ce2cf1d20e5c37b5799fbb..add74daff7305df0df736eadddb458eb00bc48da 100644 (file)
@@ -66,10 +66,6 @@ char copyright[] =
 #include <varargs.h>
 #endif
 
-#ifndef roundup
-#define roundup(x,y) ((((x)+(y)-1)/(y))*(y))
-#endif
-
 #ifdef KERBEROS
 #include <krb5.h>
 #include <k5-util.h>
@@ -78,23 +74,27 @@ char copyright[] =
 #define RCP_BUFSIZ 4096
      
 int sock;
-struct sockaddr_in foreign;       /* set up by kcmd used by send_auth */
+struct sockaddr_in local, foreign; /* set up by kcmd used by v4_send_auth */
 char *krb_realm = NULL;
 char *krb_cache = NULL;
 char *krb_config = NULL;
-char des_inbuf[2*RCP_BUFSIZ];          /* needs to be > largest read size */
-char des_outbuf[2*RCP_BUFSIZ];         /* needs to be > largest write size */
-krb5_data desinbuf,desoutbuf;
 krb5_encrypt_block eblock;         /* eblock for encrypt/decrypt */
-krb5_keyblock *session_key;       /* static key for session */
 krb5_context bsd_context;
 
-void   try_normal();
+#ifdef KRB5_KRB4_COMPAT
+#include <kerberosIV/krb.h>
+Key_schedule v4_schedule;
+CREDENTIALS v4_cred;
+KTEXT_ST v4_ticket;
+MSG_DAT v4_msg_data;
+#endif
+
+void   v4_send_auth(), try_normal();
 char   **save_argv();
 #ifndef HAVE_STRSAVE
 char   *strsave();
 #endif
-int    des_write(), des_read();
+int    rcmd_stream_write(), rcmd_stream_read();
 void   usage(), sink(), source(), rsource(), verifydir(), answer_auth();
 int    response(), hosteq(), okname(), susystem();
 int    encryptflag = 0;
@@ -103,9 +103,6 @@ int encryptflag = 0;
 #define        UCB_RCP "/bin/rcp"
 #endif
 
-#else /* !KERBEROS */
-#define        des_read        read
-#define        des_write       write
 #endif /* KERBEROS */
 
 int    rem;
@@ -134,7 +131,7 @@ void        error KRB5_STDARG_P((char *fmt, ...));
 void   error KRB5_STDARG_P((char *, va_list));
 #endif
 
-#define        ga()            (void) des_write(rem, "", 1)
+#define        ga()            (void) rcmd_stream_write(rem, "", 1)
 
 int main(argc, argv)
      int argc;
@@ -162,8 +159,6 @@ int main(argc, argv)
            com_err(argv[0], status, "while initializing krb5");
            exit(1);
     }
-    desinbuf.data = des_inbuf;
-    desoutbuf.data = des_outbuf;    /* Set up des buffers */
 #endif
 
     pwd = getpwuid(userid = getuid());
@@ -237,6 +232,7 @@ int main(argc, argv)
            
          case 'f':             /* "from" */
            iamremote = 1;
+           rcmd_stream_init_normal();
 #if defined(KERBEROS)
            if (encryptflag)
              answer_auth(krb_config, krb_cache);
@@ -248,6 +244,7 @@ int main(argc, argv)
            
          case 't':             /* "to" */
            iamremote = 1;
+           rcmd_stream_init_normal();
 #if defined(KERBEROS)
            if (encryptflag)
              answer_auth(krb_config, krb_cache);
@@ -419,29 +416,35 @@ krb5_creds *cred;
                                  &cred,  
                                  0,  /* No seq # */
                                  0,  /* No server seq # */
-                                 (struct sockaddr_in *) 0,
+                                 &local,
                                  &foreign,
                                  authopts,
-                                 0); /* Not any port # */
+                                 0, /* Not any port # */
+                                 0);
                    if (status) {
-                       if (status != -1) 
-                            fprintf(stderr,
-                                    "%s: kcmd to host %s failed - %s\n",
-                                    orig_argv[0], host,
-                                    error_message(status));
+#ifdef KRB5_KRB4_COMPAT
+                       fprintf(stderr, "Trying krb4 rcp...\n");
+                       if (strncmp(buf, "-x rcp", 6) == 0)
+                           memcpy(buf, "rcp -x", 6);
+                       status = k4cmd(&sock, &host, port,
+                                      pwd->pw_name,
+                                      tuser ? tuser : pwd->pw_name, buf,
+                                      0, &v4_ticket, "rcmd", krb_realm,
+                                      NULL, NULL, NULL,
+                                      &local, &foreign, 0L, 0);
+                       if (status)
+                           try_normal(orig_argv);
+                       if (encryptflag)
+                           v4_send_auth(host, krb_realm);
+                       rcmd_stream_init_krb4(v4_cred.session, encryptflag, 0,
+                                             0);
+#else
                        try_normal(orig_argv);
+#endif
                    }
-                   else {
-                       rem = sock; 
-                       session_key = &cred->keyblock;
-                                  
-    krb5_use_enctype(bsd_context, &eblock, session_key->enctype);
-    if ((status = krb5_process_key(bsd_context, &eblock, session_key))) {
-       fprintf(stderr, "rcp: send_auth failed krb5_process_key: %s\n",
-               error_message(status));
-       exit(1);
-    }
-                   }
+                   else
+                       rcmd_stream_init_krb5(&cred->keyblock, encryptflag, 0);
+                   rem = sock;
 #else
                    rem = rcmd(&host, port, pwd->pw_name,
                               tuser ? tuser : pwd->pw_name,
@@ -519,27 +522,31 @@ krb5_creds *cred;
                              (struct sockaddr_in *) 0,
                              &foreign,
                              authopts,
-                             0); /* Not any port # */
+                             0, /* Not any port # */
+                             0);
                if (status) {
-                   if (status != -1)
-                        fprintf(stderr,
-                                "%s: kcmd to host %s failed - %s\n",
-                                orig_argv[0], host,
-                                error_message(status));
-                   try_normal(orig_argv);
-                   
-               } else {
-                   rem = sock; 
-                       session_key = &cred->keyblock;
+#ifdef KRB5_KRB4_COMPAT
+                       fprintf(stderr, "Trying krb4 rcp...\n");
+                       if (strncmp(buf, "-x rcp", 6) == 0)
+                           memcpy(buf, "rcp -x", 6);
+                       status = k4cmd(&sock, &host, port,
+                                      pwd->pw_name, suser, buf,
+                                      0, &v4_ticket, "rcmd", krb_realm,
+                                      NULL, NULL, NULL,
+                                      &local, &foreign, 0L, 0);
+                       if (status)
+                           try_normal(orig_argv);
+                       if (encryptflag)
+                           v4_send_auth(host, krb_realm);
+                       rcmd_stream_init_krb4(v4_cred.session, encryptflag, 0,
+                                             0);
+#else
+                       try_normal(orig_argv);
+#endif
+               } else
+                   rcmd_stream_init_krb5(&cred->keyblock, encryptflag, 0);
+               rem = sock; 
                                   
-    krb5_use_enctype(bsd_context, &eblock, session_key->enctype);
-    if ((status = krb5_process_key(bsd_context, &eblock, session_key))) {
-       fprintf(stderr, "rcp: send_auth failed krb5_process_key: %s\n",
-               error_message(status));
-       exit(1);
-    }
-
-               }
                euid = geteuid();
                if (euid == 0) {
                    (void) setuid(0);
@@ -558,6 +565,7 @@ krb5_creds *cred;
                           buf, 0);
                if (rem < 0)
                  continue;
+               rcmd_stream_init_normal();
 #ifdef HAVE_SETREUID
                (void) setreuid(0, userid);
                sink(1, argv+argc-1);
@@ -733,7 +741,7 @@ void source(argc, argv)
             */
            (void) sprintf(buf, "T%ld 0 %ld 0\n",
                           stb.st_mtime, stb.st_atime);
-           (void) des_write(rem, buf, strlen(buf));
+           (void) rcmd_stream_write(rem, buf, strlen(buf));
            if (response() < 0) {
                (void) close(f);
                continue;
@@ -741,7 +749,7 @@ void source(argc, argv)
        }
        (void) sprintf(buf, "C%04o %ld %s\n",
                       (int) stb.st_mode&07777, (long ) stb.st_size, last);
-       (void) des_write(rem, buf, strlen(buf));
+       (void) rcmd_stream_write(rem, buf, strlen(buf));
        if (response() < 0) {
            (void) close(f);
            continue;
@@ -757,7 +765,7 @@ void source(argc, argv)
              amt = stb.st_size - i;
            if (readerr == 0 && read(f, bp->buf, amt) != amt)
              readerr = errno;
-           (void) des_write(rem, bp->buf, amt);
+           (void) rcmd_stream_write(rem, bp->buf, amt);
        }
        (void) close(f);
        if (readerr == 0)
@@ -802,14 +810,14 @@ void rsource(name, statp)
     if (pflag) {
        (void) sprintf(buf, "T%ld 0 %ld 0\n",
                       statp->st_mtime, statp->st_atime);
-       (void) des_write(rem, buf, strlen(buf));
+       (void) rcmd_stream_write(rem, buf, strlen(buf));
        if (response() < 0) {
            closedir(d);
            return;
        }
     }
     (void) sprintf(buf, "D%04o %d %s\n", statp->st_mode&07777, 0, last);
-    (void) des_write(rem, buf, strlen(buf));
+    (void) rcmd_stream_write(rem, buf, strlen(buf));
     if (response() < 0) {
        closedir(d);
        return;
@@ -828,7 +836,7 @@ void rsource(name, statp)
        source(1, bufv);
     }
     closedir(d);
-    (void) des_write(rem, "E\n", 2);
+    (void) rcmd_stream_write(rem, "E\n", 2);
     (void) response();
 }
 
@@ -837,7 +845,7 @@ void rsource(name, statp)
 int response()
 {
     char resp, c, rbuf[RCP_BUFSIZ], *cp = rbuf;
-    if (des_read(rem, &resp, 1) != 1)
+    if (rcmd_stream_read(rem, &resp, 1) != 1)
       lostconn();
     switch (resp) {
        
@@ -850,7 +858,7 @@ int response()
       case 1:                          /* error, followed by err msg */
       case 2:                          /* fatal error, "" */
        do {
-           if (des_read(rem, &c, 1) != 1)
+           if (rcmd_stream_read(rem, &c, 1) != 1)
              lostconn();
            *cp++ = c;
        } while (cp < &rbuf[RCP_BUFSIZ] && c != '\n');
@@ -933,12 +941,12 @@ void sink(argc, argv)
       targisdir = 1;
     for (first = 1; ; first = 0) {
        cp = cmdbuf;
-       if (des_read(rem, cp, 1) <= 0)
+       if (rcmd_stream_read(rem, cp, 1) <= 0)
          return;
        if (*cp++ == '\n')
          SCREWUP("unexpected '\\n'");
        do {
-           if (des_read(rem, cp, 1) != 1)
+           if (rcmd_stream_read(rem, cp, 1) != 1)
              SCREWUP("lost connection");
        } while (*cp++ != '\n');
        *cp = 0;
@@ -1056,7 +1064,7 @@ void sink(argc, argv)
              amt = size - i;
            count += amt;
            do {
-               j = des_read(rem, cp, amt);
+               j = rcmd_stream_read(rem, cp, amt);
                if (j <= 0) {
                    if (j == 0)
                      error("rcp: dropped connection");
@@ -1111,11 +1119,6 @@ struct buffer *allocbuf(bp, fd, blksize)
        error("rcp: fstat: %s\n", error_message(errno));
        return (NULLBUF);
     }
-#ifdef NOROUNDUP
-    size = 0;
-#else
-    size = roundup(stb.st_blksize, blksize);
-#endif
 
     size = blksize;
     if (bp->cnt < size) {
@@ -1133,6 +1136,10 @@ struct buffer *allocbuf(bp, fd, blksize)
 
 
 
+/* This function is mostly vestigial, since under normal operation
+ * the -x flag doesn't get set for the server process for encrypted
+ * rcp.  It only gets called by beta clients attempting user-to-user
+ * authentication. */
 void
 #ifdef HAVE_STDARG_H
 error(char *fmt, ...)
@@ -1157,7 +1164,7 @@ error(fmt, va_alist)
     (void) vsprintf(cp, fmt, ap);
     va_end(ap);
 
-    (void) des_write(rem, buf, strlen(buf));
+    (void) rcmd_stream_write(rem, buf, strlen(buf));
     if (iamremote == 0)
       (void) write(2, buf+1, strlen(buf+1));
 }
@@ -1250,6 +1257,10 @@ char **save_argv(argc, argv)
 
 
 
+/* This function is mostly vestigial, since under normal operation
+ * the -x flag doesn't get set for the server process for encrypted
+ * rcp.  It only gets called by beta clients attempting user-to-user
+ * authentication. */
 void
   answer_auth(config_file, ccache_file)
     char *config_file;
@@ -1311,18 +1322,12 @@ void
        exit(1);
     }
     
-    /* setup eblock for des_read and write */
-    krb5_copy_keyblock(bsd_context, &new_creds->keyblock,&session_key);
+    rcmd_stream_init_krb5(&new_creds->keyblock, encryptflag, 0);
     
     /* cleanup */
     krb5_free_cred_contents(bsd_context, &creds);
     krb5_free_creds(bsd_context, new_creds);
     krb5_free_data_contents(bsd_context, &msg);
-    
-    /* OK process key */
-    krb5_use_enctype(bsd_context, &eblock, session_key->enctype);
-    if ((status = krb5_process_key(bsd_context, &eblock, session_key)))
-       exit(1);
 
     return;
 }
@@ -1333,127 +1338,34 @@ char storage[2*RCP_BUFSIZ];            /* storage for the decryption */
 int nstored = 0;
 char *store_ptr = storage;
 
-int des_read(fd, buf, len)
-     int fd;
-     register char *buf;
-     int len;
-{
-    int nreturned = 0;
-    long net_len,rd_len;
-    int cc;
-    krb5_error_code status;
-    unsigned char len_buf[4];
-    
-    if (!encryptflag)
-      return(read(fd, buf, len));
-    
-    if (nstored >= len) {
-       memcpy(buf, store_ptr, len);
-       store_ptr += len;
-       nstored -= len;
-       return(len);
-    } else if (nstored) {
-       memcpy(buf, store_ptr, nstored);
-       nreturned += nstored;
-       buf += nstored;
-       len -= nstored;
-       nstored = 0;
-    }
-    
-    if ((cc = krb5_net_read(bsd_context, fd, (char *)len_buf, 4)) != 4) {
-       /* XXX can't read enough, pipe must have closed */
-       return(0);
-    }
-    rd_len =
-       ((len_buf[0]<<24) | (len_buf[1]<<16) | (len_buf[2]<<8) | len_buf[3]);
-    net_len = krb5_encrypt_size(rd_len,eblock.crypto_entry);
-    if (net_len <= 0 || net_len > sizeof(des_inbuf)) {
-       /* preposterous length; assume out-of-sync; only
-          recourse is to close connection, so return 0 */
-       error( "rcp: Des_read size problem net_len %d rd_len %d %d.\n",
-             net_len,rd_len, len);
-       errno = E2BIG;
-       return(-1);
-    }
-    if ((cc = krb5_net_read(bsd_context, fd, desinbuf.data, net_len)) != net_len) {
-       /* pipe must have closed, return 0 */
-       error( "rcp: Des_read error: length received %d != expected %d.\n",
-             cc,net_len);
-       return(0);
-    }
-    /* decrypt info */
-    if ((status = krb5_decrypt(bsd_context, desinbuf.data,
-                              (krb5_pointer) storage,
-                              net_len,
-                              &eblock, 0))) {
-       error("rcp: Des_read cannot decrypt data from network %s.\n",
-             error_message(status));
-       return(0);
-    }
-    store_ptr = storage;
-    nstored = rd_len;
-    if (nstored > len) {
-       memcpy(buf, store_ptr, len);
-       nreturned += len;
-       store_ptr += len;
-       nstored -= len;
-    } else {
-       memcpy(buf, store_ptr, nstored);
-       nreturned += nstored;
-       nstored = 0;
-    }
-    
-    return(nreturned);
-}
-
-
-int des_write(fd, buf, len)
-     int fd;
-     char *buf;
-     int len;
+#ifdef KRB5_KRB4_COMPAT
+void
+v4_send_auth(host,realm)
+char *host;
+char *realm;
 {
-    static krb5_data des_write_buf;
-    static int des_write_maxsize;
-    unsigned char len_buf[4];
-
-    /* 
-     * Note that rcp depends on the same file descriptor being both 
-     * input and output to the remote side.  This is bogus, especially 
-     * when rcp is being run by a rsh that pipes. Fix it here because it 
-     * would require significantly more work in other places. --hartmans 1/96
-     */
-    
-    if (fd == 0)
-       fd = 1;
-    if (!encryptflag)
-      return(krb5_net_write(bsd_context, fd, buf, len));
-    
-    des_write_buf.length = krb5_encrypt_size(len,eblock.crypto_entry);
-
-    if (des_write_buf.length > des_write_maxsize) {
-       if (des_write_buf.data) 
-           free(des_write_buf.data);
-       des_write_maxsize = des_write_buf.length;
-       if ((des_write_buf.data = malloc(des_write_maxsize)) == NULL) {
-           des_write_maxsize = 0;
-           return(-1);
+       long authopts;
+
+       if ((realm == NULL) || (realm[0] == '\0'))
+            realm = krb_realmofhost(host);
+       /* this needs to be sent again, because the
+          rcp process needs the key.  the rshd has
+          grabbed the first one. */
+       authopts = KOPT_DO_MUTUAL;
+       if ((rem = krb_sendauth(authopts, sock, &v4_ticket,
+                               "rcmd", host,
+                               realm, (unsigned long) getpid(),
+                               &v4_msg_data,
+                               &v4_cred, v4_schedule,
+                               &local,
+                               &foreign,
+                               "KCMDV0.1")) != KSUCCESS) {
+               fprintf(stderr,
+                       "krb_sendauth mutual fail: %s\n",
+                       krb_get_err_text(rem));
+               exit(1);
        }
-    }
-
-    if ((krb5_encrypt(bsd_context, (krb5_pointer)buf, des_write_buf.data, 
-                     len, &eblock, 0))) {
-       return(-1);
-    }
-    
-    len_buf[0] = (len & 0xff000000) >> 24;
-    len_buf[1] = (len & 0xff0000) >> 16;
-    len_buf[2] = (len & 0xff00) >> 8;
-    len_buf[3] = (len & 0xff);
-    if ((write(fd, len_buf, 4) != 4) || (write(fd, des_write_buf.data, 
-       des_write_buf.length) != des_write_buf.length)) {
-       return(-1);
-    }
-    return(len);
 }
+#endif /* KRB5_KRB4_COMPAT */
 
 #endif /* KERBEROS */
index ada567013b286157081979103b4b0f639a9a3afe..e3f89788cc3ec0c0e33786cd6066b9ba45572523 100644 (file)
@@ -129,29 +129,15 @@ char copyright[] =
 #endif
 
 
-#ifndef roundup
-#define roundup(x,y) ((((x)+(y)-1)/(y))*(y))
-#endif
-
 #ifdef KERBEROS
-#include "krb5.h"
-#include "com_err.h"
+#include <krb5.h>
+#include <com_err.h>
 #include "defines.h"
+#ifdef KRB5_KRB4_COMPAT
+#include <kerberosIV/krb.h>
+#endif
      
 #define RLOGIN_BUFSIZ 5120
-     /*
- * Note that the encrypted rlogin packets take the form of a four-byte
- *length followed by encrypted data.  On writing the data out, a significant
- * performance penalty is suffered (at least one RTT per character, two if we
- * are waiting for a shell to echo) by writing the data separately from the 
- * length.  So, unlike the input buffer, which just contains the output
- * data, the output buffer represents the entire packet.
- */
-
-char des_inbuf[2*RLOGIN_BUFSIZ];       /* needs to be > largest read size */
-char des_outpkt[2*RLOGIN_BUFSIZ+4];      /* needs to be > largest write size */
-krb5_data desinbuf,desoutbuf;
-krb5_encrypt_block eblock;      /* eblock for encrypt/decrypt */
 
 void try_normal();
 char *krb_realm = (char *)0;
@@ -161,14 +147,16 @@ krb5_creds *cred;
 struct sockaddr_in local, foreign;
 krb5_context bsd_context;
 
+#ifdef KRB5_KRB4_COMPAT
+Key_schedule v4_schedule;
+CREDENTIALS v4_cred;
+#endif
+
 #ifndef UCB_RLOGIN
 #define UCB_RLOGIN      "/usr/ucb/rlogin"
 #endif
 
 #include "rpaths.h"
-#else /* !KERBEROS */
-#define des_read read
-#define des_write write
 #endif /* KERBEROS */
 
 # ifndef TIOCPKT_WINDOW
@@ -338,6 +326,10 @@ main(argc, argv)
     int sock;
     krb5_flags authopts;
     krb5_error_code status;
+#ifdef KRB5_KRB4_COMPAT
+    KTEXT_ST v4_ticket;
+    MSG_DAT v4_msg_data;
+#endif
 #endif
     int debug_port = 0;
    
@@ -476,8 +468,6 @@ main(argc, argv)
            com_err(argv[0], status, "while initializing krb5");
            exit(1);
     }
-    desinbuf.data = des_inbuf;
-    desoutbuf.data = des_outpkt+4;     /* Set up des buffers */
 #endif
 
 
@@ -586,25 +576,27 @@ main(argc, argv)
                  0,            /* No need for server seq # */
                  &local, &foreign,
                  authopts,
-                 0);           /* Not any port # */
+                 0,            /* Not any port # */
+                 0);
     if (status) {
-       /* should check for KDC_PR_UNKNOWN, NO_TKT_FILE here -- XXX */
-        if (status != -1) 
-             fprintf(stderr,
-                     "%s: kcmd to host %s failed - %s\n",orig_argv[0], host,
-                     error_message(status));
-        try_normal(orig_argv);
-    }
+#ifdef KRB5_KRB4_COMPAT
+       fprintf(stderr, "Trying krb4 rlogin...\n");
+       status = k4cmd(&sock, &host, debug_port,
+                      null_local_username ? NULL : pwd->pw_name,
+                      name ? name : pwd->pw_name, term,
+                      0, &v4_ticket, "rcmd", krb_realm,
+                      &v4_cred, v4_schedule, &v4_msg_data, &local, &foreign,
+                      (encrypt_flag) ? KOPT_DO_MUTUAL : 0L, 0);
+       if (status)
+           try_normal(orig_argv);
+       rcmd_stream_init_krb4(v4_cred.session, encrypt_flag, 1, 1);
+#else
+       try_normal(orig_argv);
+#endif
+    } else
+       rcmd_stream_init_krb5(&cred->keyblock, encrypt_flag, 1);
     rem = sock;
     
-    /* setup eblock for des_read and write */
-    krb5_use_enctype(bsd_context, &eblock,cred->keyblock.enctype);
-    if ( status = krb5_process_key(bsd_context, &eblock,&cred->keyblock)) {
-       fprintf(stderr,
-               "%s: Cannot process session key : %s.\n",
-               orig_argv[0], error_message(status));
-       exit(1);
-    }
 #else
     rem = rcmd(&host, debug_port,
               null_local_username ? NULL : pwd->pw_name,
@@ -1060,9 +1052,9 @@ writer()
 #endif
 
            if (c != cmdchar)
-             (void) des_write(rem, &cmdchar, 1);
+             (void) rcmd_stream_write(rem, &cmdchar, 1);
        }
-       if (des_write(rem, &c, 1) == 0) {
+       if (rcmd_stream_write(rem, &c, 1) == 0) {
            prf("line gone");
            break;
        }
@@ -1177,7 +1169,7 @@ sendwindow()
     wp->ws_col = htons(winsize.ws_col);
     wp->ws_xpixel = htons(winsize.ws_xpixel);
     wp->ws_ypixel = htons(winsize.ws_ypixel);
-    (void) des_write(rem, obuf, sizeof(obuf));
+    (void) rcmd_stream_write(rem, obuf, sizeof(obuf));
 }
 
 
@@ -1362,7 +1354,7 @@ fd_set readset, excset, writeset;
                bufp += n;
            }
            if (FD_ISSET(rem, &readset)) {
-               rcvcnt = des_read(rem, rcvbuf, sizeof (rcvbuf));
+               rcvcnt = rcmd_stream_read(rem, rcvbuf, sizeof (rcvbuf));
                if (rcvcnt == 0)
                    return (0);
                if (rcvcnt < 0)
@@ -1597,307 +1589,7 @@ void try_normal(argv)
     perror("exec");
     exit(1);
 }
-
-
-
-char storage[2*RLOGIN_BUFSIZ];         /* storage for the decryption */
-int nstored = 0;
-char *store_ptr = storage;
-
-#ifndef OLD_VERSION
-
-int des_read(fd, buf, len)
-     int fd;
-     register char *buf;
-     int len;
-{
-    int nreturned = 0;
-    long net_len,rd_len;
-    int cc;
-    unsigned char len_buf[4];
-    
-    if (!encrypt_flag)
-      return(read(fd, buf, len));
-    
-    if (nstored >= len) {
-       memcpy(buf, store_ptr, len);
-       store_ptr += len;
-       nstored -= len;
-       return(len);
-    } else if (nstored) {
-       memcpy(buf, store_ptr, nstored);
-       nreturned += nstored;
-       buf += nstored;
-       len -= nstored;
-       nstored = 0;
-    }
-    
-#if 0
-    if ((cc = krb5_net_read(bsd_context, fd, (char *)&len_buf, 4)) != 4) {
-       /* XXX can't read enough, pipe must have closed */
-       return(0);
-    }
-    rd_len =
-       ((len_buf[0]<<24) | (len_buf[1]<<16) | (len_buf[2]<<8) | len_buf[3]);
-#else
-       {
-           unsigned char c;
-           int gotzero = 0;
-
-           /* See the comment in v4_des_read. */
-           do {
-               cc = krb5_net_read(bsd_context, fd, &c, 1);
-               /* we should check for non-blocking here, but we'd have
-                  to make it save partial reads as well. */
-               if (cc <= 0) return cc; /* read error */
-               if (cc == 1) {
-                   if (c == 0) gotzero = 1;
-               }
-           } while (!gotzero);
-
-           if ((cc = krb5_net_read(bsd_context, fd, &c, 1)) != 1) return 0;
-           rd_len = c;
-           if ((cc = krb5_net_read(bsd_context, fd, &c, 1)) != 1) return 0;
-           rd_len = (rd_len << 8) | c;
-           if ((cc = krb5_net_read(bsd_context, fd, &c, 1)) != 1) return 0;
-           rd_len = (rd_len << 8) | c;
-       }
-
-#endif
-    net_len = krb5_encrypt_size(rd_len,eblock.crypto_entry);
-    if ((net_len <= 0) || (net_len > sizeof(des_inbuf))) {
-       /* preposterous length; assume out-of-sync; only
-          recourse is to close connection, so return 0 */
-       fprintf(stderr,"Read size problem.\n");
-       return(0);
-    }
-    if ((cc = krb5_net_read(bsd_context, fd, desinbuf.data, net_len)) != net_len) {
-       /* pipe must have closed, return 0 */
-       fprintf(stderr,
-               "Read error: length received %d != expected %d.\n",
-               cc,net_len);
-       return(0);
-    }
-    /* decrypt info */
-    if ((krb5_decrypt(bsd_context, desinbuf.data,
-                     (krb5_pointer) storage,
-                     net_len,
-                     &eblock, 0))) {
-       fprintf(stderr,"Cannot decrypt data from network.\n");
-       return(0);
-    }
-    store_ptr = storage;
-    nstored = rd_len;
-    if (nstored > len) {
-       memcpy(buf, store_ptr, len);
-       nreturned += len;
-       store_ptr += len;
-       nstored -= len;
-    } else {
-       memcpy(buf, store_ptr, nstored);
-       nreturned += nstored;
-       nstored = 0;
-    }
-    
-    return(nreturned);
-}
-
-
-
-int des_write(fd, buf, len)
-     int fd;
-     char *buf;
-     int len;
-{
-  unsigned char *len_buf = (unsigned char *) des_outpkt;
-    
-  if (!encrypt_flag)
-      return(write(fd, buf, len));
-    
-    
-    desoutbuf.length = krb5_encrypt_size(len,eblock.crypto_entry);
-    if (desoutbuf.length > sizeof(des_outpkt)-4){
-       fprintf(stderr,"Write size problem.\n");
-       return(-1);
-    }
-    if ((krb5_encrypt(bsd_context, (krb5_pointer)buf,
-                     desoutbuf.data,
-                     len,
-                     &eblock,
-                     0))){
-       fprintf(stderr,"Write encrypt problem.\n");
-       return(-1);
-    }
-
-    len_buf[0] = (len & 0xff000000) >> 24;
-    len_buf[1] = (len & 0xff0000) >> 16;
-    len_buf[2] = (len & 0xff00) >> 8;
-    len_buf[3] = (len & 0xff);
-
-    if (write(fd, des_outpkt,desoutbuf.length+4) != desoutbuf.length+4){
-      fprintf(stderr,"Could not write out all data\n");
-       return(-1);
-    }
-    else return(len);
-}
-
-
-
-#else /* Original version  placed here so that testing could be done
-        to determine why rlogin with encryption on is slower with
-        version 5 as compared to version 4. */
-
-#define ENCRYPT 1
-#define DECRYPT 0
-
-
-
-int des_read(fd, buf, len)
-     int fd;
-     register char *buf;
-     int len;
-{
-    int nreturned = 0;
-    long net_len, rd_len;
-    int cc;
-    unsigned char len_buf[4];
-    
-    if (!encrypt_flag)
-      return(read(fd, buf, len));
-    
-    if (nstored >= len) {
-       memcpy(buf, store_ptr, len);
-       store_ptr += len;
-       nstored -= len;
-       return(len);
-    } else if (nstored) {
-       memcpy(buf, store_ptr, nstored);
-       nreturned += nstored;
-       buf += nstored;
-       len -= nstored;
-       nstored = 0;
-    }
-#if 0
-    if ((cc = krb5_net_read(bsd_context, fd, len_buf, 4)) != 4) {
-       /* XXX can't read enough, pipe must have closed */
-       return(0);
-    }
-    net_len =
-       ((len_buf[0]<<24) | (len_buf[1]<<16) | (len_buf[2]<<8) | len_buf[3]);
-#else
-       {
-           unsigned char c;
-           int gotzero = 0;
-
-           /* See the comment in v4_des_read. */
-           do {
-               cc = krb5_net_read(bsd_context, fd, &c, 1);
-               /* we should check for non-blocking here, but we'd have
-                  to make it save partial reads as well. */
-               if (cc < 0) return 0; /* read error */
-               if (cc == 1) {
-                   if (c == 0) gotzero = 1;
-               }
-           } while (!gotzero);
-
-           if ((cc = krb5_net_read(bsd_context, fd, &c, 1)) != 1) return 0;
-           net_len = c;
-           if ((cc = krb5_net_read(bsd_context, fd, &c, 1)) != 1) return 0;
-           net_len = (net_len << 8) | c;
-           if ((cc = krb5_net_read(bsd_context, fd, &c, 1)) != 1) return 0;
-           net_len = (net_len << 8) | c;
-       }
-#endif
-    if (net_len < 0 || net_len > sizeof(des_inbuf)) {
-       /* XXX preposterous length, probably out of sync.
-          act as if pipe closed */
-       return(0);
-    }
-    /* the writer tells us how much real data we are getting, but
-       we need to read the pad bytes (8-byte boundary) */
-#ifdef NOROUNDUP
-    rd_len = ((((net_len)+((8)-1))/(8))*(8));
-#else
-    rd_len = roundup(net_len, 8);
-#endif
-    if ((cc = krb5_net_read(bsd_context, fd, des_inbuf, rd_len)) != rd_len) {
-       /* pipe must have closed, return 0 */
-       return(0);
-    }
-    (void) mit_des_cbc_encrypt(
-                              des_inbuf,
-                              storage,
-                              (net_len < 8) ? 8 : net_len,
-                              eblock.priv,
-                              eblock.key->contents,
-                              DECRYPT);
-    /*
-     * when the cleartext block is < 8 bytes, it is "right-justified"
-     * in the block, so we need to adjust the pointer to the data
-     */
-    if (net_len < 8)
-      store_ptr = storage + 8 - net_len;
-    else
-      store_ptr = storage;
-    nstored = net_len;
-    if (nstored > len) {
-       memcpy(buf, store_ptr, len);
-       nreturned += len;
-       store_ptr += len;
-       nstored -= len;
-    } else {
-       memcpy(buf, store_ptr, nstored);
-       nreturned += nstored;
-       nstored = 0;
-    }
-    return(nreturned);
-}
-
-
-
-int des_write(fd, buf, len)
-     int fd;
-     char *buf;
-     int len;
-{
-    static char garbage_buf[8];
-    unsigned char len_buf[4];
-    
-    if (!encrypt_flag)
-      return(write(fd, buf, len));
-    
-#define min(a,b) ((a < b) ? a : b)
-    
-    if (len < 8) {
-       krb5_random_confounder(bsd_context, 8 - len, &garbage_buf);
-       /* this "right-justifies" the data in the buffer */
-       (void) memcpy(garbage_buf + 8 - len, buf, len);
-    }
-    
-    (void) mit_des_cbc_encrypt((len < 8) ? garbage_buf : buf,
-                              des_outbuf,
-                              (len < 8) ? 8 : len,
-                              eblock.priv,
-                              eblock.key->contents,
-                              ENCRYPT);
-    
-    /* tell the other end the real amount, but send an 8-byte padded
-       packet */
-    len_buf[0] = (len & 0xff000000) >> 24;
-    len_buf[1] = (len & 0xff0000) >> 16;
-    len_buf[2] = (len & 0xff00) >> 8;
-    len_buf[3] = (len & 0xff);
-    (void) write(fd, len_buf, 4);
-#ifdef NOROUNDUP
-    (void) write(fd, des_outbuf, ((((len)+((8)-1))/(8))*(8)));
-#else
-    (void) write(fd, des_outbuf, roundup(len,8));
 #endif
-    return(len);
-}
-
-#endif /* OLD_VERSION */
-#endif /* KERBEROS */
 
 
 
index d68a0d27f4c07c2f54fc0da96aaf42187f300748..b24fa445eeff51235fc44d6c161a9e542eeb96ed 100644 (file)
@@ -205,7 +205,7 @@ struct winsize {
 
 #ifdef KERBEROS
      
-#include "krb5.h"
+#include <krb5.h>
 #include <kerberosIV/krb.h>
 #include <libpty.h>
 #ifdef HAVE_UTMP_H
@@ -222,28 +222,10 @@ int non_privileged = 0; /* set when connection is seen to be from */
 
 AUTH_DAT       *v4_kdata;
 Key_schedule v4_schedule;
-int v4_des_read(), v4_des_write();
-
-#define RLOGIND_BUFSIZ 5120
-
-int v5_des_read(), v5_des_write();
 
 #include "com_err.h"
      
 #define SECURE_MESSAGE  "This rlogin session is using DES encryption for all data transmissions.\r\n"
-/*
- * Note that the encrypted rlogin packets take the form of a four-byte
- *length followed by encrypted data.  On writing the data out, a significant
- * performance penalty is suffered (at least one RTT per character, two if we
- * are waiting for a shell to echo) by writing the data separately from the 
- * length.  So, unlike the input buffer, which just contains the output
- * data, the output buffer represents the entire packet.
- */
- int (*des_read)(), (*des_write)();
-char des_inbuf[2*RLOGIND_BUFSIZ]; /* needs to be > largest read size */
-char des_outpkt[2*RLOGIND_BUFSIZ+4];/* needs to be > largest write size */
-krb5_data desinbuf,desoutbuf;
-krb5_encrypt_block eblock;        /* eblock for encrypt/decrypt */
 
 krb5_authenticator      *kdata;
 krb5_ticket     *ticket = 0;
@@ -255,8 +237,6 @@ krb5_keytab keytab = NULL;
 #define ARGSTR "k54ciepPD:S:M:L:f?"
 #else /* !KERBEROS */
 #define ARGSTR "rpPD:f?"
-#define (*des_read)  read
-#define (*des_write) write
 #endif /* KERBEROS */
 
 #ifndef LOGIN_PROGRAM
@@ -610,13 +590,7 @@ int syncpipe[2];
     if (fromp->sin_family != AF_INET)
       fatal(f, "Permission denied - Malformed from address\n");
     
-#ifdef KERBEROS
-
-       /* setup des buffers */
-    desinbuf.data = des_inbuf;
-    desoutbuf.data = des_outpkt+4;    /* Set up des buffers */
-
-#else /* !KERBEROS */
+#ifndef KERBEROS
     if (fromp->sin_port >= IPPORT_RESERVED ||
        fromp->sin_port < IPPORT_RESERVED/2)
       fatal(f, "Permission denied - Connection from bad port");
@@ -633,6 +607,7 @@ int syncpipe[2];
     getstr(f, rusername, sizeof(rusername), "remuser");
     getstr(f, lusername, sizeof(lusername), "locuser");
     getstr(f, term, sizeof(term), "Terminal type");
+    rcmd_stream_init_normal();
 #endif
     
     write(f, "", 1);
@@ -808,7 +783,7 @@ int syncpipe[2];
     
 #if defined(KERBEROS) 
     if (do_encrypt) {
-       if (((*des_write)(f, SECURE_MESSAGE, sizeof(SECURE_MESSAGE))) < 0){
+       if (rcmd_stream_write(f, SECURE_MESSAGE, sizeof(SECURE_MESSAGE)) < 0){
            sprintf(buferror, "Cannot encrypt-write network.");
            fatal(p,buferror);
        }
@@ -978,7 +953,7 @@ void protocol(f, p)
            }
        }
        if (FD_ISSET(f, &ibits)) {
-           fcc = (*des_read)(f, fibuf, sizeof (fibuf));
+           fcc = rcmd_stream_read(f, fibuf, sizeof (fibuf));
            if (fcc < 0 && ((errno == EWOULDBLOCK) || (errno == EAGAIN)))
              fcc = 0;
            else {
@@ -1036,7 +1011,7 @@ void protocol(f, p)
 #endif
        }
        if (FD_ISSET(f, &obits) && pcc > 0) {
-           cc = (*des_write)(f, pbp, pcc);
+           cc = rcmd_stream_write(f, pbp, pcc);
            if (cc < 0 && ((errno == EWOULDBLOCK) || (errno == EAGAIN))) {
                /* also shouldn't happen */
                sleep(5);
@@ -1075,7 +1050,7 @@ void fatal(f, msg)
     buf[0] = '\01';            /* error indicator */
     (void) sprintf(buf + 1, "%s: %s.\r\n",progname, msg);
     if ((f == netf) && (pid > 0))
-      (void) (*des_write)(f, buf, strlen(buf));
+      (void) rcmd_stream_write(f, buf, strlen(buf));
     else
       (void) write(f, buf, strlen(buf));
     syslog(LOG_ERR,"%s\n",msg);
@@ -1198,6 +1173,8 @@ do_krb_login(host)
     /* NOTREACHED */
 }
 
+#endif /* KERBEROS */
+
 
 
 void getstr(fd, buf, cnt, err)
@@ -1223,166 +1200,6 @@ void getstr(fd, buf, cnt, err)
 
 
 
-char storage[2*RLOGIND_BUFSIZ];             /* storage for the decryption */
-int nstored = 0;
-char *store_ptr = storage;
-
-int
-v5_des_read(fd, buf, len)
-     int fd;
-     register char *buf;
-     int len;
-{
-    int nreturned = 0;
-    krb5_ui_4 net_len,rd_len;
-    int cc,retry;
-#if 0
-    unsigned char len_buf[4];
-#endif
-    
-    if (!do_encrypt)
-      return(read(fd, buf, len));
-    
-    if (nstored >= len) {
-       memcpy(buf, store_ptr, len);
-       store_ptr += len;
-       nstored -= len;
-       return(len);
-    } else if (nstored) {
-       memcpy(buf, store_ptr, nstored);
-       nreturned += nstored;
-       buf += nstored;
-       len -= nstored;
-       nstored = 0;
-    }
-    
-#if 0
-    if ((cc = krb5_net_read(bsd_context, fd, (char *)len_buf, 4)) != 4) {
-       if ((cc < 0)  && ((errno == EWOULDBLOCK) || (errno == EAGAIN)))
-           return(cc);
-       /* XXX can't read enough, pipe must have closed */
-       return(0);
-    }
-    rd_len =
-       (((krb5_ui_4)len_buf[0]<<24) |
-        ((krb5_ui_4)len_buf[1]<<16) |
-        ((krb5_ui_4)len_buf[2]<<8) |
-        (krb5_ui_4)len_buf[3]);
-#else
-       {
-           unsigned char c;
-           int gotzero = 0;
-
-           /* See the comment in v4_des_read. */
-           do {
-               cc = krb5_net_read(bsd_context, fd, &c, 1);
-               /* we should check for non-blocking here, but we'd have
-                  to make it save partial reads as well. */
-               if (cc <= 0) return 0; /* read error */
-               if (cc == 1) {
-                   if (c == 0) gotzero = 1;
-               }
-           } while (!gotzero);
-
-           if ((cc = krb5_net_read(bsd_context, fd, &c, 1)) != 1) return 0;
-           rd_len = c;
-           if ((cc = krb5_net_read(bsd_context, fd, &c, 1)) != 1) return 0;
-           rd_len = (rd_len << 8) | c;
-           if ((cc = krb5_net_read(bsd_context, fd, &c, 1)) != 1) return 0;
-           rd_len = (rd_len << 8) | c;
-       }
-#endif
-    net_len = krb5_encrypt_size(rd_len,eblock.crypto_entry);
-    /* note net_len is unsigned */
-    if (net_len > sizeof(des_inbuf)) {
-       /* XXX preposterous length, probably out of sync.
-          act as if pipe closed */
-       syslog(LOG_ERR,"Read size problem.");
-       return(0);
-    }
-    retry = 0;
-  datard:
-    if ((cc = krb5_net_read(bsd_context,fd,desinbuf.data,net_len)) != net_len) {
-       /* XXX can't read enough, pipe must have closed */
-       if ((cc < 0)  && ((errno == EWOULDBLOCK) || (errno == EAGAIN))) {
-           retry++;
-           sleep(1);
-           if (retry > MAXRETRIES){
-               syslog(LOG_ERR,
-                      "des_read retry count exceeded %d\n",
-                      retry);
-               return(0);
-           }
-           goto datard;
-       }
-       syslog(LOG_ERR,
-              "Read data received %d != expected %d.",
-              cc, net_len);
-       return(0);
-    }
-    /* decrypt info */
-    if ((krb5_decrypt(bsd_context, desinbuf.data,
-                     (krb5_pointer) storage,
-                     net_len,
-                     &eblock, 0))) {
-       syslog(LOG_ERR,"Read decrypt problem.");
-       return(0);
-    }
-    store_ptr = storage;
-    nstored = rd_len;
-    if (nstored > len) {
-       memcpy(buf, store_ptr, len);
-       nreturned += len;
-       store_ptr += len;
-       nstored -= len;
-    } else {
-       memcpy(buf, store_ptr, nstored);
-       nreturned += nstored;
-       nstored = 0;
-    }
-    return(nreturned);
-}
-    
-
-int
-v5_des_write(fd, buf, len)
-     int fd;
-     char *buf;
-     int len;
-{
-  unsigned char *len_buf = (unsigned char *) des_outpkt;
-    
-    if (!do_encrypt)
-      return(write(fd, buf, len));
-    
-    
-    desoutbuf.length = krb5_encrypt_size(len,eblock.crypto_entry);
-    if (desoutbuf.length > sizeof(des_outpkt)-4){
-       syslog(LOG_ERR,"Write size problem.");
-       return(-1);
-    }
-    if ((krb5_encrypt(bsd_context, (krb5_pointer)buf,
-                     desoutbuf.data,
-                     len,
-                     &eblock,
-                     0))){
-       syslog(LOG_ERR,"Write encrypt problem.");
-       return(-1);
-    }
-
-    len_buf[0] = (len & 0xff000000) >> 24;
-    len_buf[1] = (len & 0xff0000) >> 16;
-    len_buf[2] = (len & 0xff00) >> 8;
-    len_buf[3] = (len & 0xff);
-
-    if (write(fd, des_outpkt,desoutbuf.length+4) != desoutbuf.length+4){
-       syslog(LOG_ERR,"Could not write out all data.");
-       return(-1);
-    }
-    else return(len);
-}
-#endif /* KERBEROS */
-
 void usage()
 {
 #ifdef KERBEROS
@@ -1567,8 +1384,7 @@ recvauth(valid_checksum)
 #ifdef KRB5_KRB4_COMPAT
     if (auth_sys == KRB5_RECVAUTH_V4) {
 
-       des_read  = v4_des_read;
-       des_write = v4_des_write;
+       rcmd_stream_init_krb4(v4_kdata->session, do_encrypt, 1, 1);
 
        /* We do not really know the remote user's login name.
          * Assume it to be the same as the first component of the
@@ -1593,24 +1409,13 @@ recvauth(valid_checksum)
                                      &client)))
        return status;
 
-    des_read  = v5_des_read;
-    des_write = v5_des_write;
+    rcmd_stream_init_krb5(ticket->enc_part2->session, do_encrypt, 1);
 
     getstr(netf, rusername, sizeof(rusername), "remuser");
 
     if ((status = krb5_unparse_name(bsd_context, client, &krusername)))
        return status;
     
-    /* Setup up eblock if encrypted login session */
-    /* otherwise zero out session key */
-    if (do_encrypt) {
-       krb5_use_enctype(bsd_context, &eblock,
-                        ticket->enc_part2->session->enctype);
-       if ((status = krb5_process_key(bsd_context, &eblock,
-                                      ticket->enc_part2->session)))
-           fatal(netf, "Permission denied");
-    }      
-
     if ((status = krb5_read_message(bsd_context, (krb5_pointer)&netf, &inbuf)))
        fatal(netf, "Error reading message");
 
@@ -1622,175 +1427,4 @@ recvauth(valid_checksum)
     return 0;
 }
 
-
-#ifdef KRB5_KRB4_COMPAT
-
-int
-v4_des_read(fd, buf, len)
-int fd;
-register char *buf;
-int len;
-{
-       int nreturned = 0;
-       krb5_ui_4 net_len, rd_len;
-       int cc;
-#if 0
-       unsigned char len_buf[4];
-#endif
-
-       if (!do_encrypt)
-               return(read(fd, buf, len));
-
-       if (nstored >= len) {
-               memcpy(buf, store_ptr, len);
-               store_ptr += len;
-               nstored -= len;
-               return(len);
-       } else if (nstored) {
-               memcpy(buf, store_ptr, nstored);
-               nreturned += nstored;
-               buf += nstored;
-               len -= nstored;
-               nstored = 0;
-       }
-
-#if 0
-       if ((cc = krb_net_read(fd, (char *)len_buf, 4)) != 4) {
-               /* XXX can't read enough, pipe
-                  must have closed */
-               return(0);
-       }
-       net_len = (((krb5_ui_4)len_buf[0]<<24) |
-                  ((krb5_ui_4)len_buf[1]<<16) |
-                  ((krb5_ui_4)len_buf[2]<<8) |
-                  (krb5_ui_4)len_buf[3]);
-#else
-       {
-           unsigned char c;
-           int gotzero = 0;
-
-           /* We're fetching the length which is MSB first, and the MSB
-              has to be zero unless the client is sending more than 2^24
-              (16M) bytes in a single write (which is why this code is in
-              rlogin but not rcp or rsh.) The only reasons we'd get something
-              other than zero are:
-                  -- corruption of the tcp stream (which will show up when
-                     everything else is out of sync too)
-                  -- un-caught Berkeley-style "pseudo out-of-band data" which
-                     happens any time the user hits ^C twice.
-              The latter is *very* common, as shown by an 'rlogin -x -d' 
-              using the CNS V4 rlogin.         Mark EIchin 1/95
-             */
-           do {
-               cc = krb_net_read(fd, &c, 1);
-               if (cc <= 0) return 0; /* read error */
-               if (cc == 1) {
-                   if (c == 0) gotzero = 1;
-               }
-           } while (!gotzero);
-
-           if ((cc = krb_net_read(fd, &c, 1)) != 1) return 0;
-           net_len = c;
-           if ((cc = krb_net_read(fd, &c, 1)) != 1) return 0;
-           net_len = (net_len << 8) | c;
-           if ((cc = krb_net_read(fd, &c, 1)) != 1) return 0;
-           net_len = (net_len << 8) | c;
-       }
-
-#endif
-       /* Note: net_len is unsigned */
-       if (net_len > sizeof(des_inbuf)) {
-               /* XXX preposterous length, probably out of sync.
-                  act as if pipe closed */
-               return(0);
-       }
-       /* the writer tells us how much real data we are getting, but
-          we need to read the pad bytes (8-byte boundary) */
-       rd_len = roundup(net_len, 8);
-       if ((cc = krb_net_read(fd, des_inbuf, rd_len)) != rd_len) {
-               /* XXX can't read enough, pipe
-                  must have closed */
-               return(0);
-       }
-       (void) pcbc_encrypt(des_inbuf,
-                           storage,
-                           (net_len < 8) ? 8 : net_len,
-                           v4_schedule,
-                           v4_kdata->session,
-                           DECRYPT);
-       /* 
-        * when the cleartext block is < 8 bytes, it is "right-justified"
-        * in the block, so we need to adjust the pointer to the data
-        */
-       if (net_len < 8)
-               store_ptr = storage + 8 - net_len;
-       else
-               store_ptr = storage;
-       nstored = net_len;
-       if (nstored > len) {
-               memcpy(buf, store_ptr, len);
-               nreturned += len;
-               store_ptr += len;
-               nstored -= len;
-       } else {
-               memcpy(buf, store_ptr, nstored);
-               nreturned += nstored;
-               nstored = 0;
-       }
-       
-       return(nreturned);
-}
-
-int
-v4_des_write(fd, buf, len)
-int fd;
-char *buf;
-int len;
-{
-       static char garbage_buf[8];
-       unsigned char *len_buf = (unsigned char *) des_outpkt;
-
-       if (!do_encrypt)
-               return(write(fd, buf, len));
-
-       /* 
-        * pcbc_encrypt outputs in 8-byte (64 bit) increments
-        *
-        * it zero-fills the cleartext to 8-byte padding,
-        * so if we have cleartext of < 8 bytes, we want
-        * to insert random garbage before it so that the ciphertext
-        * differs for each transmission of the same cleartext.
-        * if len < 8 - sizeof(long), sizeof(long) bytes of random
-        * garbage should be sufficient; leave the rest as-is in the buffer.
-        * if len > 8 - sizeof(long), just garbage fill the rest.
-        */
-
-#ifdef min
-#undef min
-#endif
-#define min(a,b) ((a < b) ? a : b)
-
-       if (len < 8) {
-               krb5_random_confounder(8 - len, garbage_buf);
-               /* this "right-justifies" the data in the buffer */
-               (void) memcpy(garbage_buf + 8 - len, buf, len);
-       }
-       (void) pcbc_encrypt((len < 8) ? garbage_buf : buf,
-                           des_outpkt+4,
-                           (len < 8) ? 8 : len,
-                           v4_schedule,
-                           v4_kdata->session,
-                           ENCRYPT);
-
-       /* tell the other end the real amount, but send an 8-byte padded
-          packet */
-       len_buf[0] = (len & 0xff000000) >> 24;
-       len_buf[1] = (len & 0xff0000) >> 16;
-       len_buf[2] = (len & 0xff00) >> 8;
-       len_buf[3] = (len & 0xff);
-       (void) write(fd, des_outpkt, roundup(len,8)+4);
-       return(len);
-}
-
-#endif /* KRB5_KRB4_COMPAT */
 #endif /* KERBEROS */
index a7fabc432481bd88c1ece0f7f347a4b86814eb05..1b033e3cf414e3befb748d36c52818fb56bda21f 100644 (file)
@@ -62,11 +62,19 @@ char copyright[] =
 #endif
 
 #ifdef KERBEROS
-#include "krb5.h"
-#include "com_err.h"
+#include <krb5.h>
+#include <com_err.h>
 #include "defines.h"
+#ifdef KRB5_KRB4_COMPAT
+#include <kerberosIV/krb.h>
+#endif
 #endif /* KERBEROS */
-     
+
+#ifdef KRB5_KRB4_COMPAT
+#include <kerberosIV/krb.h>
+Key_schedule v4_schedule;
+#endif
+
 /*
  * rsh - remote shell
  */
@@ -87,22 +95,18 @@ krb5_sigtype  sendsig();
 
 #define RSH_BUFSIZ 4096
 
-char des_inbuf[2*RSH_BUFSIZ];       /* needs to be > largest read size */
-char des_outbuf[2*RSH_BUFSIZ];      /* needs to be > largest write size */
-krb5_data desinbuf,desoutbuf;
-krb5_encrypt_block eblock;      /* eblock for encrypt/decrypt */
 krb5_context bsd_context;
 krb5_creds *cred;
 
+#ifdef KRB5_KRB4_COMPAT
+Key_schedule v4_schedule;
+CREDENTIALS v4_cred;
+#endif
+
 int    encrypt_flag = 0;
 char   *krb_realm = (char *)0;
 void   try_normal();
 
-#else /* KERBEROS */
-
-#define des_read read
-#define des_write write
-
 #endif /* KERBEROS */
 
 #ifndef RLOGIN_PROGRAM
@@ -132,6 +136,8 @@ main(argc, argv0)
     int one = 1;
     struct servent *sp;
     struct servent defaultservent;
+    struct sockaddr_in local, foreign;
+    int suppress;
 
 #ifdef POSIX_SIGNALS
     sigset_t omask, igmask;
@@ -143,6 +149,10 @@ main(argc, argv0)
     krb5_flags authopts;
     krb5_error_code status;
     int fflag = 0, Fflag = 0;
+#ifdef KRB5_KRB4_COMPAT
+    KTEXT_ST v4_ticket;
+    MSG_DAT v4_msg_data;
+#endif
 #endif  /* KERBEROS */
     int debug_port = 0;
 
@@ -346,7 +356,9 @@ main(argc, argv0)
       authopts |= OPTS_FORWARD_CREDS;
     if (Fflag)
       authopts |= OPTS_FORWARDABLE_CREDS;    
-
+#ifdef HAVE_ISATTY
+    suppress = !isatty(fileno(stderr));
+#endif
     status = kcmd(&rem, &host, debug_port,
                  pwd->pw_name,
                  user ? user : pwd->pw_name,
@@ -354,28 +366,34 @@ main(argc, argv0)
                  &cred,
                  0,           /* No need for sequence number */
                  0,           /* No need for server seq # */
-                 (struct sockaddr_in *) 0,
-                 (struct sockaddr_in *) 0,
+                 &local, &foreign,
                  authopts,
-                 1);   /* Always set anyport, there is no need not to. --proven */
+                 1,    /* Always set anyport, there is no need not to. --proven */
+                 suppress);
     if (status) {
-        /* check NO_TKT_FILE or equivalent... */
-        if (status != -1) 
-             fprintf(stderr,
-                     "%s: kcmd to host %s failed - %s\n",argv0[0], host,
-                     error_message(status));
-        try_normal(argv0);
-    }
-
-    /* Setup for des_read and write */
-    desinbuf.data = des_inbuf;
-    desoutbuf.data = des_outbuf;
-    krb5_use_enctype(bsd_context, &eblock,cred->keyblock.enctype);
-    if (status = krb5_process_key(bsd_context, &eblock,&cred->keyblock)) {
-        fprintf(stderr, "%s: Cannot process session key : %s.\n",
-                argv0, error_message(status));
-        exit(1);
-    }
+#ifdef KRB5_KRB4_COMPAT
+       /* No encrypted Kerberos 4 rsh. */
+       if (encrypt_flag)
+           exit(1);
+#ifdef HAVE_ISATTY
+       if (isatty(fileno(stderr)))
+           fprintf(stderr, "Trying krb4 rsh...\n");
+#endif
+       status = k4cmd(&rem, &host, debug_port,
+                      pwd->pw_name,
+                      user ? user : pwd->pw_name, args,
+                      &rfd2, &v4_ticket, "rcmd", krb_realm,
+                      &v4_cred, v4_schedule, &v4_msg_data,
+                      &local, &foreign, 0L, 0);
+       if (status)
+           try_normal(argv0);
+       rcmd_stream_init_krb4(v4_cred.session, encrypt_flag, 0, 1);
+#else
+       try_normal(argv0);
+#endif
+    } else
+       rcmd_stream_init_krb5(&cred->keyblock, encrypt_flag, 0);
+
 #ifdef HAVE_ISATTY
     if(encrypt_flag&&isatty(2)) {
        write(2,SECURE_MESSAGE, strlen(SECURE_MESSAGE));
@@ -471,7 +489,7 @@ main(argc, argv0)
        }
        if (FD_ISSET(rem, &rembits) == 0)
          goto rewrite;
-       wc = des_write(rem, bp, cc);
+       wc = rcmd_stream_write(rem, bp, cc);
        if (wc < 0) {
            if ((errno == EWOULDBLOCK) || (errno == EAGAIN))
              goto rewrite;
@@ -506,7 +524,7 @@ main(argc, argv0)
        }
        if (FD_ISSET(rfd2, &ready)) {
            errno = 0;
-           cc = des_read(rfd2, buf, sizeof buf);
+           cc = rcmd_stream_read(rfd2, buf, sizeof buf);
            if (cc <= 0) {
                if ((errno != EWOULDBLOCK) && (errno != EAGAIN))
                    FD_CLR(rfd2, &readfrom);
@@ -515,7 +533,7 @@ main(argc, argv0)
        }
        if (FD_ISSET(rem, &ready)) {
            errno = 0;
-           cc = des_read(rem, buf, sizeof buf);
+           cc = rcmd_stream_read(rem, buf, sizeof buf);
            if (cc <= 0) {
                if ((errno != EWOULDBLOCK) && (errno != EAGAIN))
                    FD_CLR(rem, &readfrom);
@@ -539,7 +557,7 @@ main(argc, argv0)
 krb5_sigtype sendsig(signo)
      char signo;
 {
-    (void) des_write(rfd2, &signo, 1);
+    (void) rcmd_stream_write(rfd2, &signo, 1);
 }
 
 
@@ -576,114 +594,4 @@ void try_normal(argv)
     perror("exec");
     exit(1);
 }
-
-
-char storage[2*RSH_BUFSIZ];
-int nstored = 0;
-char *store_ptr = storage;
-
-int des_read(fd, buf, len)
-     int fd;
-     register char *buf;
-     int len;
-{
-    int nreturned = 0;
-    long net_len,rd_len;
-    int cc;
-    unsigned char len_buf[4];
-    
-    if (!encrypt_flag)
-      return(read(fd, buf, len));
-    
-    if (nstored >= len) {
-       memcpy(buf, store_ptr, len);
-       store_ptr += len;
-       nstored -= len;
-       return(len);
-    } else if (nstored) {
-       memcpy(buf, store_ptr, nstored);
-       nreturned += nstored;
-       buf += nstored;
-       len -= nstored;
-       nstored = 0;
-    }
-    
-    if ((cc = krb5_net_read(bsd_context, fd, len_buf, 4)) != 4) {
-       /* XXX can't read enough, pipe must have closed */
-       return(0);
-    }
-    rd_len =
-       ((len_buf[0]<<24) | (len_buf[1]<<16) | (len_buf[2]<<8) | len_buf[3]);
-    net_len = krb5_encrypt_size(rd_len,eblock.crypto_entry);
-    if ((net_len <= 0) || (net_len > sizeof(des_inbuf))) {
-       /* preposterous length; assume out-of-sync; only
-          recourse is to close connection, so return 0 */
-       fprintf(stderr,"Read size problem.\n");
-       return(0);
-    }
-    if ((cc = krb5_net_read(bsd_context, fd, desinbuf.data, net_len)) != net_len) {
-       /* pipe must have closed, return 0 */
-       fprintf(stderr, "Read error: length received %d != expected %d.\n",
-               cc, net_len);
-       return(0);
-    }
-    /* decrypt info */
-    if (cc = krb5_decrypt(bsd_context, desinbuf.data, (krb5_pointer) storage,
-                         net_len, &eblock, 0)) {
-       fprintf(stderr,"Cannot decrypt data from network\n");
-       return(0);
-    }
-    store_ptr = storage;
-    nstored = rd_len;
-    if (nstored > len) {
-       memcpy(buf, store_ptr, len);
-       nreturned += len;
-       store_ptr += len;
-       nstored -= len;
-    } else {
-       memcpy(buf, store_ptr, nstored);
-       nreturned += nstored;
-       nstored = 0;
-    }
-    
-    return(nreturned);
-}
-
-
-
-int des_write(fd, buf, len)
-     int fd;
-     char *buf;
-     int len;
-{
-    unsigned char len_buf[4];
-    
-    if (!encrypt_flag)
-      return(write(fd, buf, len));
-    
-    desoutbuf.length = krb5_encrypt_size(len, eblock.crypto_entry);
-    if (desoutbuf.length > sizeof(des_outbuf)){
-       fprintf(stderr,"Write size problem.\n");
-       return(-1);
-    }
-    if (( krb5_encrypt(bsd_context, (krb5_pointer)buf,
-                      desoutbuf.data,
-                      len,
-                      &eblock,
-                      0))){
-       fprintf(stderr,"Write encrypt problem.\n");
-       return(-1);
-    }
-    
-    len_buf[0] = (len & 0xff000000) >> 24;
-    len_buf[1] = (len & 0xff0000) >> 16;
-    len_buf[2] = (len & 0xff00) >> 8;
-    len_buf[3] = (len & 0xff);
-    (void) write(fd, len_buf, 4);
-    if (write(fd, desoutbuf.data,desoutbuf.length) != desoutbuf.length){
-       fprintf(stderr,"Could not write out all data.\n");
-       return(-1);
-    }
-    else return(len); 
-}
 #endif /* KERBEROS */
index 9918563997ef357a9171eb1418690d7ec3182845..71cadcc7f5a5090c4b83c59c70e261a3ad46dba9 100644 (file)
@@ -152,10 +152,13 @@ char copyright[] =
 #endif
 
 #ifdef KERBEROS
-#include "krb5.h"
-#include "com_err.h"
+#include <krb5.h>
+#include <com_err.h>
 #include "loginpaths.h"
+#ifdef KRB5_KRB4_COMPAT
 #include <kerberosIV/krb.h>
+Key_schedule v4_schedule;
+#endif
 
 #define ARGSTR "ek54ciD:S:M:AP:?L:"
 
@@ -164,20 +167,12 @@ char copyright[] =
 
 #define MAXRETRIES 4
 
-char des_inbuf[2*RSHD_BUFSIZ];    /* needs to be > largest read size */
-krb5_encrypt_block eblock;        /* eblock for encrypt/decrypt */
-char des_outbuf[2*RSHD_BUFSIZ];   /* needs to be > largest write size */
-krb5_data desinbuf,desoutbuf;
 krb5_context bsd_context;
 char *srvtab = NULL;
 krb5_keytab keytab = NULL;
 krb5_ccache ccache = NULL;
 void fatal();
-int v5_des_read();
-int v5_des_write();
 
-int (*des_read)() = v5_des_read;
-int (*des_write)() = v5_des_write;
 int require_encrypt = 0;
 int do_encrypt = 0;
 int anyport = 0;
@@ -187,8 +182,6 @@ int netf;
 #else /* !KERBEROS */
 
 #define ARGSTR "RD:?"
-int (*des_read)() = read;
-int (*des_write)() = write;
      
 #endif /* KERBEROS */
      
@@ -641,8 +634,6 @@ void doit(f, fromp)
     }
 #ifdef KERBEROS
     netf = f;
-    desinbuf.data = des_inbuf;
-    desoutbuf.data = des_outbuf;
     if ( (fromp->sin_port >= IPPORT_RESERVED ||
            fromp->sin_port < IPPORT_RESERVED/2))
       non_privileged = 1;
@@ -750,12 +741,11 @@ void doit(f, fromp)
        error("Authentication failed: %s\n", error_message(status));
        exit(1);
     }
-    if (!strncmp(cmdbuf, "-x ", 3))
-       do_encrypt = 1;
 #else
     getstr(f, remuser, sizeof(remuser), "remuser");
     getstr(f, locuser, sizeof(locuser), "locuser");
     getstr(f, cmdbuf, sizeof(cmdbuf), "command");
+    rcmd_stream_init_normal();
 #endif /* KERBEROS */
     
 #ifdef CRAY
@@ -1205,7 +1195,7 @@ if(port)
                        shutdown(s, 1+1);
                        FD_CLR(pv[0], &readfrom);
                    } else {
-                       (void) (*des_write)(s, buf, cc);
+                       (void) rcmd_stream_write(s, buf, cc);
                    }
                }
                if (FD_ISSET(pw[0], &ready)) {
@@ -1216,12 +1206,12 @@ if(port)
                        shutdown(f, 1+1);
                        FD_CLR(pw[0], &readfrom);
                    } else {
-                       (void) (*des_write)(f, buf, cc);
+                       (void) rcmd_stream_write(f, buf, cc);
                    }
                }
                if (port&&FD_ISSET(s, &ready)) {
                    /* read from the alternate channel, signal the child */
-                   if ((*des_read)(s, &sig, 1) <= 0) {
+                   if (rcmd_stream_read(s, &sig, 1) <= 0) {
                        FD_CLR(s, &readfrom);
                    } else {
 #ifdef POSIX_SIGNALS
@@ -1237,7 +1227,7 @@ if(port)
                if (FD_ISSET(f, &ready)) {
                    /* read from the net, write to child stdin */
                    errno = 0;
-                   cc = (*des_read)(f, buf, sizeof(buf));
+                   cc = rcmd_stream_read(f, buf, sizeof(buf));
                    if (cc <= 0) {
                        (void) close(px[1]);
                        FD_CLR(f, &readfrom);
@@ -1800,6 +1790,8 @@ recvauth(netf, peersin, valid_checksum)
     getstr(netf, cmdbuf, sizeof(cmdbuf), "command");
 
     if (auth_sys == KRB5_RECVAUTH_V4) {
+       rcmd_stream_init_normal();
+       
        /* We do not really know the remote user's login name.
          * Assume it to be the same as the first component of the
         * principal's name. 
@@ -1863,14 +1855,12 @@ recvauth(netf, peersin, valid_checksum)
     }
     krb5_free_authenticator(bsd_context, authenticator);
 
-    
-    /* Setup eblock for encrypted sessions. */
-    krb5_use_enctype(bsd_context, &eblock, ticket->enc_part2->session->enctype);
-    if ((status = krb5_process_key(bsd_context, &eblock,
-                                  ticket->enc_part2->session)))
-       fatal(netf, "Permission denied");
 
-    /* Null out the "session" because eblock.key references the session
+    if (!strncmp(cmdbuf, "-x ", 3))
+       do_encrypt = 1;
+    rcmd_stream_init_krb5(ticket->enc_part2->session, do_encrypt, 0);
+
+    /* Null out the "session" because kcmd.c references the session
      * key here, and we do not want krb5_free_ticket() to destroy it. */
     ticket->enc_part2->session = 0;
 
@@ -1903,137 +1893,9 @@ recvauth(netf, peersin, valid_checksum)
     krb5_free_ticket(bsd_context, ticket);
     return 0;
 }
+#endif /* KERBEROS */
 
 
-char storage[2*RSHD_BUFSIZ];               /* storage for the decryption */
-int nstored = 0;
-char *store_ptr = storage;
-
-int
-v5_des_read(fd, buf, len)
-     int fd;
-     register char *buf;
-     int len;
-{
-    int nreturned = 0;
-    krb5_ui_4 net_len,rd_len;
-    int cc,retry;
-    unsigned char len_buf[4];
-    
-    if (!do_encrypt)
-      return(read(fd, buf, len));
-    
-    if (nstored >= len) {
-       memcpy(buf, store_ptr, len);
-       store_ptr += len;
-       nstored -= len;
-       return(len);
-    } else if (nstored) {
-       memcpy(buf, store_ptr, nstored);
-       nreturned += nstored;
-       buf += nstored;
-       len -= nstored;
-       nstored = 0;
-    }
-    
-    if ((cc = krb5_net_read(bsd_context, fd, (char *)len_buf, 4)) != 4) {
-       if ((cc < 0)  && ((errno == EWOULDBLOCK) || (errno == EAGAIN)))
-           return(cc);
-       /* XXX can't read enough, pipe must have closed */
-       return(0);
-    }
-    rd_len =
-       ((len_buf[0]<<24) |
-        (len_buf[1]<<16) |
-        (len_buf[2]<<8) |
-        len_buf[3]);
-    net_len = krb5_encrypt_size(rd_len, eblock.crypto_entry);
-    /* note: net_len is unsigned */
-    if (net_len > sizeof(des_inbuf)) {
-       /* XXX preposterous length, probably out of sync.
-          act as if pipe closed */
-       syslog(LOG_ERR,"Read size problem (rd_len=%d, net_len=%d)",
-              rd_len, net_len);
-       return(0);
-    }
-    retry = 0;
-  datard:
-    if ((cc = krb5_net_read(bsd_context, fd, desinbuf.data, net_len)) != net_len) {
-       /* XXX can't read enough, pipe must have closed */
-       if ((cc < 0)  && ((errno == EWOULDBLOCK) || (errno == EAGAIN))) {
-           retry++;
-           if (retry > MAXRETRIES){
-               syslog(LOG_ERR, "des_read retry count exceeded %d\n", retry);
-               return(0);
-           }
-           sleep(1);
-           goto datard;
-       }
-       syslog(LOG_ERR,
-              "Read data received %d != expected %d.",
-              cc, net_len);
-       return(0);
-    }
-
-    /* decrypt info */
-    if (krb5_decrypt(bsd_context, desinbuf.data, (krb5_pointer) storage, net_len,
-                    &eblock, 0)) {
-       syslog(LOG_ERR,"Read decrypt problem.");
-       return(0);
-    }
-
-    store_ptr = storage;
-    nstored = rd_len;
-    if (nstored > len) {
-       memcpy(buf, store_ptr, len);
-       nreturned += len;
-       store_ptr += len;
-       nstored -= len;
-    } else {
-       memcpy(buf, store_ptr, nstored);
-       nreturned += nstored;
-       nstored = 0;
-    }
-    return(nreturned);
-}
-    
-
-int
-v5_des_write(fd, buf, len)
-     int fd;
-     char *buf;
-     int len;
-{
-    unsigned char len_buf[4];
-    
-    if (!do_encrypt)
-      return(write(fd, buf, len));
-    
-    desoutbuf.length = krb5_encrypt_size(len, eblock.crypto_entry);
-    if (desoutbuf.length > sizeof(des_outbuf)){
-       syslog(LOG_ERR,"Write size problem (%d > %d)",
-              desoutbuf.length, sizeof(des_outbuf));
-       return(-1);
-    }
-
-    if (krb5_encrypt(bsd_context, (krb5_pointer)buf, desoutbuf.data, len, &eblock, 0)) {
-       syslog(LOG_ERR,"Write encrypt problem.");
-       return(-1);
-    }
-    
-    len_buf[0] = (len & 0xff000000) >> 24;
-    len_buf[1] = (len & 0xff0000) >> 16;
-    len_buf[2] = (len & 0xff00) >> 8;
-    len_buf[3] = (len & 0xff);
-    (void) write(fd, len_buf, 4);
-
-    if (write(fd, desoutbuf.data, desoutbuf.length) != desoutbuf.length){
-       syslog(LOG_ERR,"Could not write out all data.");
-       return(-1);
-    }
-    else return(len);
-}
-
 
 void fatal(f, msg)
      int f;
@@ -2047,7 +1909,7 @@ void fatal(f, msg)
     buf[0] = '\01';             /* error indicator */
     (void) sprintf(buf + 1, "%s: %s.\r\n",progname, msg);
     if ((f == netf) && (pid > 0))
-      (void) (*des_write)(f, buf, strlen(buf));
+      (void) rcmd_stream_write(f, buf, strlen(buf));
     else
       (void) write(f, buf, strlen(buf));
     syslog(LOG_ERR,"%s\n",msg);
@@ -2063,4 +1925,3 @@ void fatal(f, msg)
     }
     exit(1);
 }
-#endif /* KERBEROS */