From 76f0ff261edb3eb93f2433e3bb28fc595cca0f50 Mon Sep 17 00:00:00 2001 From: Johan Danielsson Date: Tue, 3 Sep 2002 20:03:46 +0000 Subject: [PATCH] handle protocol version 2 git-svn-id: svn://svn.h5l.se/heimdal/trunk/heimdal@11349 ec53bebd-3082-4978-b11e-865c3cabbd6b --- appl/rsh/common.c | 84 +++++++++++++++++++++++++++++++++++---------- appl/rsh/rsh.c | 66 ++++++++++++++++++++++++++++++----- appl/rsh/rsh_locl.h | 20 +++++++---- appl/rsh/rshd.c | 61 ++++++++++++++++++++++++-------- 4 files changed, 182 insertions(+), 49 deletions(-) diff --git a/appl/rsh/common.c b/appl/rsh/common.c index ab1952cb8..edf416e09 100644 --- a/appl/rsh/common.c +++ b/appl/rsh/common.c @@ -36,10 +36,36 @@ RCSID("$Id$"); #if defined(KRB4) || defined(KRB5) +#ifdef KRB5 +int key_usage = 1026; + +void *ivec_in[2]; +void *ivec_out[2]; + +void +init_ivecs(int client) +{ + size_t blocksize; + + krb5_crypto_block_size(context, crypto, &blocksize); + + ivec_in[0] = malloc(blocksize); + memset(ivec_in[0], client, blocksize); + + ivec_in[1] = malloc(blocksize); + memset(ivec_in[1], 2 | client, blocksize); + + ivec_out[0] = malloc(blocksize); + memset(ivec_out[0], !client, blocksize); + + ivec_out[1] = malloc(blocksize); + memset(ivec_out[1], 2 | !client, blocksize); +} +#endif + + ssize_t -do_read (int fd, - void *buf, - size_t sz) +do_read (int fd, void *buf, size_t sz, void *ivec) { if (do_encrypt) { #ifdef KRB4 @@ -61,7 +87,11 @@ do_read (int fd, len = ntohl(len); if (len > sz) abort (); - outer_len = krb5_get_wrapped_length (context, crypto, len); + /* ivec will be non null for protocol version 2 */ + if(ivec != NULL) + outer_len = krb5_get_wrapped_length (context, crypto, len + 4); + else + outer_len = krb5_get_wrapped_length (context, crypto, len); edata = malloc (outer_len); if (edata == NULL) errx (1, "malloc: cannot allocate %u bytes", outer_len); @@ -69,13 +99,22 @@ do_read (int fd, if (ret <= 0) return ret; - status = krb5_decrypt(context, crypto, KRB5_KU_OTHER_ENCRYPTED, - edata, outer_len, &data); + status = krb5_decrypt_ivec(context, crypto, key_usage, + edata, outer_len, &data, ivec); free (edata); if (status) - errx (1, "%s", krb5_get_err_text (context, status)); - memcpy (buf, data.data, len); + krb5_err (context, 1, status, "decrypting data"); + if(ivec != NULL) { + unsigned long l; + if(data.length < len + 4) + errx (1, "data received is too short"); + _krb5_get_int(data.data, &l, 4); + if(l != len) + errx (1, "inconsistency in received data"); + memcpy (buf, (unsigned char *)data.data+4, len); + } else + memcpy (buf, data.data, len); krb5_data_free (&data); return len; } else @@ -86,7 +125,7 @@ do_read (int fd, } ssize_t -do_write (int fd, void *buf, size_t sz) +do_write (int fd, void *buf, size_t sz, void *ivec) { if (do_encrypt) { #ifdef KRB4 @@ -98,20 +137,27 @@ do_write (int fd, void *buf, size_t sz) if(auth_method == AUTH_KRB5) { krb5_error_code status; krb5_data data; - u_int32_t len; + unsigned char len[4]; int ret; - status = krb5_encrypt(context, crypto, KRB5_KU_OTHER_ENCRYPTED, - buf, sz, &data); - + _krb5_put_int(len, sz, 4); + if(ivec != NULL) { + unsigned char *tmp = malloc(sz + 4); + if(tmp == NULL) + err(1, "malloc"); + _krb5_put_int(tmp, sz, 4); + memcpy(tmp + 4, buf, sz); + status = krb5_encrypt_ivec(context, crypto, key_usage, + tmp, sz + 4, &data, ivec); + free(tmp); + } else + status = krb5_encrypt_ivec(context, crypto, key_usage, + buf, sz, &data, ivec); + if (status) - errx (1, "%s", krb5_get_err_text(context, status)); + krb5_err(context, 1, status, "encrypting data"); - assert (krb5_get_wrapped_length (context, crypto, - sz) == data.length); - - len = htonl(sz); - ret = krb5_net_write (context, &fd, &len, 4); + ret = krb5_net_write (context, &fd, len, 4); if (ret != 4) return ret; ret = krb5_net_write (context, &fd, data.data, data.length); diff --git a/appl/rsh/rsh.c b/appl/rsh/rsh.c index 81fff1870..c263fb2fb 100644 --- a/appl/rsh/rsh.c +++ b/appl/rsh/rsh.c @@ -67,6 +67,8 @@ static const char *user; static int do_version; static int do_help; static int do_errsock = 1; +static char *protocol_version_str; +static int protocol_version = 2; /* * @@ -80,6 +82,11 @@ loop (int s, int errsock) fd_set real_readset; int count = 1; +#ifdef KRB5 + if(auth_method == AUTH_KRB5 && protocol_version == 2) + init_ivecs(1); +#endif + if (s >= FD_SETSIZE || errsock >= FD_SETSIZE) errx (1, "fd too large"); @@ -106,7 +113,7 @@ loop (int s, int errsock) err (1, "select"); } if (FD_ISSET(s, &readset)) { - ret = do_read (s, buf, sizeof(buf)); + ret = do_read (s, buf, sizeof(buf), ivec_in[0]); if (ret < 0) err (1, "read"); else if (ret == 0) { @@ -118,7 +125,7 @@ loop (int s, int errsock) net_write (STDOUT_FILENO, buf, ret); } if (errsock != -1 && FD_ISSET(errsock, &readset)) { - ret = do_read (errsock, buf, sizeof(buf)); + ret = do_read (errsock, buf, sizeof(buf), ivec_in[1]); if (ret < 0) err (1, "read"); else if (ret == 0) { @@ -138,7 +145,7 @@ loop (int s, int errsock) FD_CLR(STDIN_FILENO, &real_readset); shutdown (s, SHUT_WR); } else - do_write (s, buf, ret); + do_write (s, buf, ret, ivec_out[0]); } } } @@ -166,7 +173,7 @@ send_krb4_auth(int s, getpid(), &msg, &cred, schedule, (struct sockaddr_in *)thisaddr, (struct sockaddr_in *)thataddr, - KCMD_VERSION); + KCMD_OLD_VERSION); if (status != KSUCCESS) { warnx("%s: %s", hostname, krb_get_err_text(status)); return 1; @@ -282,6 +289,8 @@ send_krb5_auth(int s, int status; size_t len; krb5_auth_context auth_context = NULL; + const char *protocol_string = NULL; + krb5_flags ap_opts; status = krb5_sname_to_principal(context, hostname, @@ -300,13 +309,31 @@ send_krb5_auth(int s, cmd, remote_user); + ap_opts = 0; + + if(do_encrypt) + ap_opts |= AP_OPTS_MUTUAL_REQUIRED; + + switch(protocol_version) { + case 2: + ap_opts |= AP_OPTS_USE_SUBKEY; + protocol_string = KCMD_NEW_VERSION; + break; + case 1: + protocol_string = KCMD_OLD_VERSION; + key_usage = KRB5_KU_OTHER_ENCRYPTED; + break; + default: + abort(); + } + status = krb5_sendauth (context, &auth_context, &s, - KCMD_VERSION, + protocol_string, NULL, server, - do_encrypt ? AP_OPTS_MUTUAL_REQUIRED : 0, + ap_opts, &cksum_data, NULL, NULL, @@ -318,7 +345,9 @@ send_krb5_auth(int s, return 1; } - status = krb5_auth_con_getkey (context, auth_context, &keyblock); + status = krb5_auth_con_getlocalsubkey (context, auth_context, &keyblock); + if(keyblock == NULL) + status = krb5_auth_con_getkey (context, auth_context, &keyblock); if (status) { warnx ("krb5_auth_con_getkey: %s", krb5_get_err_text(context, status)); return 1; @@ -552,7 +581,7 @@ proto (int s, int errsock, (void *)&one, sizeof(one)) < 0) warn("setsockopt stderr"); } - + return loop (s, errsock2); } @@ -777,6 +806,8 @@ struct getargs args[] = { "port" }, { "user", 'l', arg_string, &user, "Run as this user", "login" }, { "stderr", 'e', arg_negative_flag, &do_errsock, "Don't open stderr"}, + { "protocol", 'P', arg_string, &protocol_version_str, + "Protocol version", "protocol" }, { "version", 0, arg_flag, &do_version, NULL }, { "help", 0, arg_flag, &do_help, NULL } }; @@ -840,7 +871,24 @@ main(int argc, char **argv) print_version (NULL); return 0; } - + + if(protocol_version_str != NULL) { + if(strcasecmp(protocol_version_str, "N") == 0) + protocol_version = 2; + else if(strcasecmp(protocol_version_str, "O") == 0) + protocol_version = 1; + else { + char *end; + int v; + v = strtol(protocol_version_str, &end, 0); + if(*end != '\0' || (v != 1 && v != 2)) { + errx(1, "unknown protocol version \"%s\"", + protocol_version_str); + } + protocol_version = v; + } + } + #ifdef KRB5 status = krb5_init_context (&context); if (status) { diff --git a/appl/rsh/rsh_locl.h b/appl/rsh/rsh_locl.h index bed379e55..593598b59 100644 --- a/appl/rsh/rsh_locl.h +++ b/appl/rsh/rsh_locl.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997 - 2000, 2002 Kungliga Tekniska Högskolan + * Copyright (c) 1997 - 2002 Kungliga Tekniska Högskolan * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * @@ -99,6 +99,7 @@ #endif #ifdef KRB5 #include +#include /* for _krb5_{get,put}_int */ #endif #ifdef KRB4 #include @@ -132,25 +133,30 @@ extern int do_encrypt; extern krb5_context context; extern krb5_keyblock *keyblock; extern krb5_crypto crypto; +extern int key_usage; +extern void *ivec_in[2]; +extern void *ivec_out[2]; +void init_ivecs(int); #endif #ifdef KRB4 extern des_key_schedule schedule; extern des_cblock iv; #endif -#define KCMD_VERSION "KCMDV0.1" +#define KCMD_OLD_VERSION "KCMDV0.1" +#define KCMD_NEW_VERSION "KCMDV0.2" #define USERNAME_SZ 16 #define COMMAND_SZ 1024 -#define RSH_BUFSIZ (16 * 1024) +#define RSH_BUFSIZ (5 * 1024) /* MIT kcmd can't handle larger buffers */ #define PATH_RSH BINDIR "/rsh" #if defined(KRB4) || defined(KRB5) -ssize_t do_read (int fd, void *buf, size_t sz); -ssize_t do_write (int fd, void *buf, size_t sz); +ssize_t do_read (int, void*, size_t, void*); +ssize_t do_write (int, void*, size_t, void*); #else -#define do_write(F, B, L) write((F), (B), (L)) -#define do_read(F, B, L) read((F), (B), (L)) +#define do_write(F, B, L, I) write((F), (B), (L)) +#define do_read(F, B, L, I) read((F), (B), (L)) #endif diff --git a/appl/rsh/rshd.c b/appl/rsh/rshd.c index fdb2354c1..6cbd34255 100644 --- a/appl/rsh/rshd.c +++ b/appl/rsh/rshd.c @@ -199,7 +199,7 @@ recv_krb4_auth (int s, u_char *buf, version); if (status != KSUCCESS) syslog_and_die ("recvauth: %s", krb_get_err_text(status)); - if (strncmp (version, KCMD_VERSION, KRB_SENDAUTH_VLEN) != 0) + if (strncmp (version, KCMD_OLD_VERSION, KRB_SENDAUTH_VLEN) != 0) syslog_and_die ("bad version: %s", version); read_str (s, server_username, USERNAME_SZ, "remote username"); @@ -277,6 +277,24 @@ krb5_start_session (void) return; } +static int protocol_version; + +static krb5_boolean +match_kcmd_version(const void *data, const char *version) +{ + if(strcmp(version, KCMD_NEW_VERSION) == 0) { + protocol_version = 2; + return TRUE; + } + if(strcmp(version, KCMD_OLD_VERSION) == 0) { + protocol_version = 1; + key_usage = KRB5_KU_OTHER_ENCRYPTED; + return TRUE; + } + return FALSE; +} + + static int recv_krb5_auth (int s, u_char *buf, struct sockaddr *thisaddr, @@ -311,14 +329,15 @@ recv_krb5_auth (int s, u_char *buf, syslog_and_die ("krb5_sock_to_principal: %s", krb5_get_err_text(context, status)); - status = krb5_recvauth(context, - &auth_context, - &s, - KCMD_VERSION, - server, - KRB5_RECVAUTH_IGNORE_VERSION, - NULL, - &ticket); + status = krb5_recvauth_match_version(context, + &auth_context, + &s, + match_kcmd_version, + NULL, + server, + KRB5_RECVAUTH_IGNORE_VERSION, + NULL, + &ticket); krb5_free_principal (context, server); if (status) syslog_and_die ("krb5_recvauth: %s", @@ -328,8 +347,17 @@ recv_krb5_auth (int s, u_char *buf, read_str (s, cmd, COMMAND_SZ, "command"); read_str (s, client_username, COMMAND_SZ, "local username"); - status = krb5_auth_con_getkey (context, auth_context, &keyblock); - if (status) + if(protocol_version == 2) { + status = krb5_auth_con_getremotesubkey(context, auth_context, + &keyblock); + if(status != 0 || keyblock == NULL) + syslog_and_die("failed to get remote subkey"); + } else if(protocol_version == 1) { + status = krb5_auth_con_getkey (context, auth_context, &keyblock); + if(status != 0 || keyblock == NULL) + syslog_and_die("failed to get key"); + } + if (status != 0 || keyblock == NULL) syslog_and_die ("krb5_auth_con_getkey: %s", krb5_get_err_text(context, status)); @@ -436,6 +464,11 @@ loop (int from0, int to0, if(from0 >= FD_SETSIZE || from1 >= FD_SETSIZE || from2 >= FD_SETSIZE) errx (1, "fd too large"); +#ifdef KRB5 + if(auth_method == AUTH_KRB5 && protocol_version == 2) + init_ivecs(0); +#endif + FD_ZERO(&real_readset); FD_SET(from0, &real_readset); FD_SET(from1, &real_readset); @@ -454,7 +487,7 @@ loop (int from0, int to0, syslog_and_die ("select: %m"); } if (FD_ISSET(from0, &readset)) { - ret = do_read (from0, buf, sizeof(buf)); + ret = do_read (from0, buf, sizeof(buf), ivec_in[0]); if (ret < 0) syslog_and_die ("read: %m"); else if (ret == 0) { @@ -475,7 +508,7 @@ loop (int from0, int to0, if (--count == 0) exit (0); } else - do_write (to1, buf, ret); + do_write (to1, buf, ret, ivec_out[0]); } if (FD_ISSET(from2, &readset)) { ret = read (from2, buf, sizeof(buf)); @@ -488,7 +521,7 @@ loop (int from0, int to0, if (--count == 0) exit (0); } else - do_write (to2, buf, ret); + do_write (to2, buf, ret, ivec_out[1]); } } }