From 0c1b302362748e639f4f8230d934c71b2452f52e Mon Sep 17 00:00:00 2001 From: Tom Yu Date: Tue, 24 Feb 1998 19:55:21 +0000 Subject: [PATCH] * 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] git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@10472 dc483132-0cff-0310-8789-dd5450dbe970 --- src/appl/bsd/ChangeLog | 20 ++ src/appl/bsd/kcmd.c | 635 +++++++++++++++++++++++++++++++++++++++- src/appl/bsd/krcp.c | 306 +++++++------------ src/appl/bsd/krlogin.c | 380 +++--------------------- src/appl/bsd/krlogind.c | 388 +----------------------- src/appl/bsd/krsh.c | 202 ++++--------- src/appl/bsd/krshd.c | 177 ++--------- 7 files changed, 875 insertions(+), 1233 deletions(-) diff --git a/src/appl/bsd/ChangeLog b/src/appl/bsd/ChangeLog index 9ab4cc161..f89257019 100644 --- a/src/appl/bsd/ChangeLog +++ b/src/appl/bsd/ChangeLog @@ -1,3 +1,23 @@ +Tue Feb 24 14:52:33 1998 Tom Yu + + * 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 * v4rcp.c: Punt nastiness to redefine setreuid, as we don't use diff --git a/src/appl/bsd/kcmd.c b/src/appl/bsd/kcmd.c index 1f196002d..c6f21e02f 100644 --- a/src/appl/bsd/kcmd.c +++ b/src/appl/bsd/kcmd.c @@ -52,23 +52,60 @@ #endif #endif +#ifndef roundup +#define roundup(x,y) ((((x)+(y)-1)/(y))*(y)) +#endif + #include #include #include -#include "krb5.h" +#include +#ifdef KRB5_KRB4_COMPAT +#include +#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 - diff --git a/src/appl/bsd/krcp.c b/src/appl/bsd/krcp.c index a6fe0dc7e..add74daff 100644 --- a/src/appl/bsd/krcp.c +++ b/src/appl/bsd/krcp.c @@ -66,10 +66,6 @@ char copyright[] = #include #endif -#ifndef roundup -#define roundup(x,y) ((((x)+(y)-1)/(y))*(y)) -#endif - #ifdef KERBEROS #include #include @@ -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 +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 */ diff --git a/src/appl/bsd/krlogin.c b/src/appl/bsd/krlogin.c index ada567013..e3f89788c 100644 --- a/src/appl/bsd/krlogin.c +++ b/src/appl/bsd/krlogin.c @@ -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 +#include #include "defines.h" +#ifdef KRB5_KRB4_COMPAT +#include +#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 */ diff --git a/src/appl/bsd/krlogind.c b/src/appl/bsd/krlogind.c index d68a0d27f..b24fa445e 100644 --- a/src/appl/bsd/krlogind.c +++ b/src/appl/bsd/krlogind.c @@ -205,7 +205,7 @@ struct winsize { #ifdef KERBEROS -#include "krb5.h" +#include #include #include #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 */ diff --git a/src/appl/bsd/krsh.c b/src/appl/bsd/krsh.c index a7fabc432..1b033e3cf 100644 --- a/src/appl/bsd/krsh.c +++ b/src/appl/bsd/krsh.c @@ -62,11 +62,19 @@ char copyright[] = #endif #ifdef KERBEROS -#include "krb5.h" -#include "com_err.h" +#include +#include #include "defines.h" +#ifdef KRB5_KRB4_COMPAT +#include +#endif #endif /* KERBEROS */ - + +#ifdef KRB5_KRB4_COMPAT +#include +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 */ diff --git a/src/appl/bsd/krshd.c b/src/appl/bsd/krshd.c index 991856399..71cadcc7f 100644 --- a/src/appl/bsd/krshd.c +++ b/src/appl/bsd/krshd.c @@ -152,10 +152,13 @@ char copyright[] = #endif #ifdef KERBEROS -#include "krb5.h" -#include "com_err.h" +#include +#include #include "loginpaths.h" +#ifdef KRB5_KRB4_COMPAT #include +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 */ -- 2.26.2