+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
#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;
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
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;
+#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;
{
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
}
#endif
-
#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>
#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;
#define UCB_RCP "/bin/rcp"
#endif
-#else /* !KERBEROS */
-#define des_read read
-#define des_write write
#endif /* KERBEROS */
int rem;
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;
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());
case 'f': /* "from" */
iamremote = 1;
+ rcmd_stream_init_normal();
#if defined(KERBEROS)
if (encryptflag)
answer_auth(krb_config, krb_cache);
case 't': /* "to" */
iamremote = 1;
+ rcmd_stream_init_normal();
#if defined(KERBEROS)
if (encryptflag)
answer_auth(krb_config, krb_cache);
&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,
(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);
buf, 0);
if (rem < 0)
continue;
+ rcmd_stream_init_normal();
#ifdef HAVE_SETREUID
(void) setreuid(0, userid);
sink(1, argv+argc-1);
*/
(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;
}
(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;
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)
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;
source(1, bufv);
}
closedir(d);
- (void) des_write(rem, "E\n", 2);
+ (void) rcmd_stream_write(rem, "E\n", 2);
(void) response();
}
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) {
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');
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;
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");
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) {
+/* 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, ...)
(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));
}
+/* 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;
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;
}
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 */
#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;
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
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;
com_err(argv[0], status, "while initializing krb5");
exit(1);
}
- desinbuf.data = des_inbuf;
- desoutbuf.data = des_outpkt+4; /* Set up des buffers */
#endif
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,
#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;
}
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));
}
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)
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 */
#ifdef KERBEROS
-#include "krb5.h"
+#include <krb5.h>
#include <kerberosIV/krb.h>
#include <libpty.h>
#ifdef HAVE_UTMP_H
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;
#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
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");
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);
#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);
}
}
}
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 {
#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);
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);
/* NOTREACHED */
}
+#endif /* KERBEROS */
+
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
#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
&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");
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 */
#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
*/
#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
int one = 1;
struct servent *sp;
struct servent defaultservent;
+ struct sockaddr_in local, foreign;
+ int suppress;
#ifdef POSIX_SIGNALS
sigset_t omask, igmask;
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;
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,
&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));
}
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;
}
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);
}
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);
krb5_sigtype sendsig(signo)
char signo;
{
- (void) des_write(rfd2, &signo, 1);
+ (void) rcmd_stream_write(rfd2, &signo, 1);
}
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 */
#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:"
#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;
#else /* !KERBEROS */
#define ARGSTR "RD:?"
-int (*des_read)() = read;
-int (*des_write)() = write;
#endif /* KERBEROS */
}
#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;
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
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)) {
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
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);
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.
}
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;
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;
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);
}
exit(1);
}
-#endif /* KERBEROS */