]> andersk Git - openssh.git/blobdiff - packet.c
- (djm) Convert mandoc manpages to man automatically. Patch from Mark D.
[openssh.git] / packet.c
index a1a5d8a76c7ae8549e05067c4733853a4fb0ce6a..e816cb9473ca0fc0fed76c8c6f65e25e796d0194 100644 (file)
--- a/packet.c
+++ b/packet.c
@@ -37,7 +37,7 @@
  */
 
 #include "includes.h"
-RCSID("$OpenBSD: packet.c,v 1.54 2001/02/28 21:27:47 markus Exp $");
+RCSID("$OpenBSD: packet.c,v 1.61 2001/04/05 10:42:51 markus Exp $");
 
 #include "xmalloc.h"
 #include "buffer.h"
@@ -104,6 +104,7 @@ static Buffer incoming_packet;
 
 /* Scratch buffer for packet compression/decompression. */
 static Buffer compression_buffer;
+static int compression_buffer_ready = 0;
 
 /* Flag indicating whether packet compression/decompression is enabled. */
 static int packet_compression = 0;
@@ -121,35 +122,14 @@ static int interactive_mode = 0;
 int use_ssh2_packet_format = 0;
 
 /* Session key information for Encryption and MAC */
-Kex    *kex = NULL;
+Newkeys *newkeys[MODE_MAX];
 
-void
-packet_set_kex(Kex *k)
-{
-       if( k->mac[MODE_IN ].key == NULL ||
-           k->enc[MODE_IN ].key == NULL ||
-           k->enc[MODE_IN ].iv  == NULL ||
-           k->mac[MODE_OUT].key == NULL ||
-           k->enc[MODE_OUT].key == NULL ||
-           k->enc[MODE_OUT].iv  == NULL)
-               fatal("bad KEX");
-       kex = k;
-}
-void
-clear_enc_keys(Enc *enc, int len)
-{
-       memset(enc->iv,  0, len);
-       memset(enc->key, 0, len);
-       xfree(enc->iv);
-       xfree(enc->key);
-       enc->iv = NULL;
-       enc->key = NULL;
-}
 void
 packet_set_ssh2_format(void)
 {
        DBG(debug("use_ssh2_packet_format"));
        use_ssh2_packet_format = 1;
+       newkeys[MODE_IN] = newkeys[MODE_OUT] = NULL;
 }
 
 /*
@@ -270,7 +250,7 @@ packet_close()
        buffer_free(&output);
        buffer_free(&outgoing_packet);
        buffer_free(&incoming_packet);
-       if (packet_compression) {
+       if (compression_buffer_ready) {
                buffer_free(&compression_buffer);
                buffer_compress_uninit();
        }
@@ -298,15 +278,24 @@ packet_get_protocol_flags()
  * Level is compression level 1 (fastest) - 9 (slow, best) as in gzip.
  */
 
-/*** XXXXX todo: kex means re-init */
+void
+packet_init_compression()
+{
+       if (compression_buffer_ready == 1)
+               return;
+       compression_buffer_ready = 1;
+       buffer_init(&compression_buffer);
+}
+
 void
 packet_start_compression(int level)
 {
-       if (packet_compression)
+       if (packet_compression && !use_ssh2_packet_format)
                fatal("Compression already enabled.");
        packet_compression = 1;
-       buffer_init(&compression_buffer);
-       buffer_compress_init(level);
+       packet_init_compression();
+       buffer_compress_init_send(level);
+       buffer_compress_init_recv();
 }
 
 /*
@@ -389,7 +378,7 @@ packet_start2(int type)
 void
 packet_start(int type)
 {
-       DBG(debug("packet_start[%d]",type));
+       DBG(debug("packet_start[%d]", type));
        if (use_ssh2_packet_format)
                packet_start2(type);
        else
@@ -522,6 +511,56 @@ packet_send1(void)
         */
 }
 
+void
+set_newkeys(int mode)
+{
+       Enc *enc;
+       Mac *mac;
+       Comp *comp;
+       CipherContext *cc;
+
+       debug("newkeys: mode %d", mode);
+
+       cc = (mode == MODE_OUT) ? &send_context : &receive_context;
+       if (newkeys[mode] != NULL) {
+               debug("newkeys: rekeying");
+               /* todo: free old keys, reset compression/cipher-ctxt; */
+               memset(cc, 0, sizeof(*cc));
+               enc  = &newkeys[mode]->enc;
+               mac  = &newkeys[mode]->mac;
+               comp = &newkeys[mode]->comp;
+               memset(mac->key, 0, mac->key_len);
+               xfree(enc->name);
+               xfree(enc->iv);
+               xfree(enc->key);
+               xfree(mac->name);
+               xfree(mac->key);
+               xfree(comp->name);
+               xfree(newkeys[mode]);
+       }
+       newkeys[mode] = kex_get_newkeys(mode);
+       if (newkeys[mode] == NULL)
+               fatal("newkeys: no keys for mode %d", mode);
+       enc  = &newkeys[mode]->enc;
+       mac  = &newkeys[mode]->mac;
+       comp = &newkeys[mode]->comp;
+       if (mac->md != NULL)
+               mac->enabled = 1;
+       DBG(debug("cipher_init_context: %d", mode));
+       cipher_init(cc, enc->cipher, enc->key, enc->cipher->key_len,
+           enc->iv, enc->cipher->block_size);
+       memset(enc->iv,  0, enc->cipher->block_size);
+       memset(enc->key, 0, enc->cipher->key_len);
+       if (comp->type != 0 && comp->enabled == 0) {
+               packet_init_compression();
+               if (mode == MODE_OUT)
+                       buffer_compress_init_send(6);
+               else
+                       buffer_compress_init_recv();
+               comp->enabled = 1;
+       }
+}
+
 /*
  * Finalize packet in SSH2 format (compress, mac, encrypt, enqueue)
  */
@@ -540,10 +579,10 @@ packet_send2(void)
        Comp *comp = NULL;
        int block_size;
 
-       if (kex != NULL) {
-               enc  = &kex->enc[MODE_OUT];
-               mac  = &kex->mac[MODE_OUT];
-               comp = &kex->comp[MODE_OUT];
+       if (newkeys[MODE_OUT] != NULL) {
+               enc  = &newkeys[MODE_OUT]->enc;
+               mac  = &newkeys[MODE_OUT]->mac;
+               comp = &newkeys[MODE_OUT]->comp;
        }
        block_size = enc ? enc->cipher->block_size : 8;
 
@@ -622,22 +661,8 @@ packet_send2(void)
                log("outgoing seqnr wraps around");
        buffer_clear(&outgoing_packet);
 
-       if (type == SSH2_MSG_NEWKEYS) {
-               if (kex==NULL || mac==NULL || enc==NULL || comp==NULL)
-                       fatal("packet_send2: no KEX");
-               if (mac->md != NULL)
-                       mac->enabled = 1;
-               DBG(debug("cipher_init send_context"));
-               cipher_init(&send_context, enc->cipher,
-                   enc->key, enc->cipher->key_len,
-                   enc->iv, enc->cipher->block_size);
-               clear_enc_keys(enc, kex->we_need);
-               if (comp->type != 0 && comp->enabled == 0) {
-                       comp->enabled = 1;
-                       if (! packet_compression)
-                               packet_start_compression(6);
-               }
-       }
+       if (type == SSH2_MSG_NEWKEYS)
+               set_newkeys(MODE_OUT);
 }
 
 void
@@ -660,10 +685,13 @@ int
 packet_read(int *payload_len_ptr)
 {
        int type, len;
-       fd_set set;
+       fd_set *setp;
        char buf[8192];
        DBG(debug("packet_read()"));
 
+       setp = (fd_set *)xmalloc(howmany(connection_in+1, NFDBITS) *
+           sizeof(fd_mask));
+
        /* Since we are blocking, ensure that all written packets have been sent. */
        packet_write_wait();
 
@@ -678,17 +706,20 @@ packet_read(int *payload_len_ptr)
                    || type == SSH_CMSG_EXIT_CONFIRMATION))
                        packet_integrity_check(*payload_len_ptr, 0, type);
                /* If we got a packet, return it. */
-               if (type != SSH_MSG_NONE)
+               if (type != SSH_MSG_NONE) {
+                       xfree(setp);
                        return type;
+               }
                /*
                 * Otherwise, wait for some data to arrive, add it to the
                 * buffer, and try again.
                 */
-               FD_ZERO(&set);
-               FD_SET(connection_in, &set);
+               memset(setp, 0, howmany(connection_in + 1, NFDBITS) *
+                   sizeof(fd_mask));
+               FD_SET(connection_in, setp);
 
                /* Wait for some data to arrive. */
-               while (select(connection_in + 1, &set, NULL, NULL, NULL) == -1 &&
+               while (select(connection_in + 1, setp, NULL, NULL, NULL) == -1 &&
                    (errno == EAGAIN || errno == EINTR))
                        ;
 
@@ -827,10 +858,10 @@ packet_read_poll2(int *payload_len_ptr)
        Mac *mac   = NULL;
        Comp *comp = NULL;
 
-       if (kex != NULL) {
-               enc  = &kex->enc[MODE_IN];
-               mac  = &kex->mac[MODE_IN];
-               comp = &kex->comp[MODE_IN];
+       if (newkeys[MODE_IN] != NULL) {
+               enc  = &newkeys[MODE_IN]->enc;
+               mac  = &newkeys[MODE_IN]->mac;
+               comp = &newkeys[MODE_IN]->comp;
        }
        maclen = mac && mac->enabled ? mac->mac_len : 0;
        block_size = enc ? enc->cipher->block_size : 8;
@@ -924,25 +955,11 @@ packet_read_poll2(int *payload_len_ptr)
        /* extract packet type */
        type = (u_char)buf[0];
 
-       if (type == SSH2_MSG_NEWKEYS) {
-               if (kex==NULL || mac==NULL || enc==NULL || comp==NULL)
-                       fatal("packet_read_poll2: no KEX");
-               if (mac->md != NULL)
-                       mac->enabled = 1;
-               DBG(debug("cipher_init receive_context"));
-               cipher_init(&receive_context, enc->cipher,
-                   enc->key, enc->cipher->key_len,
-                   enc->iv, enc->cipher->block_size);
-               clear_enc_keys(enc, kex->we_need);
-               if (comp->type != 0 && comp->enabled == 0) {
-                       comp->enabled = 1;
-                       if (! packet_compression)
-                               packet_start_compression(6);
-               }
-       }
+       if (type == SSH2_MSG_NEWKEYS)
+               set_newkeys(MODE_IN);
 
 #ifdef PACKET_DEBUG
-       fprintf(stderr, "read/plain[%d]:\r\n",type);
+       fprintf(stderr, "read/plain[%d]:\r\n", type);
        buffer_dump(&incoming_packet);
 #endif
        return (u_char)type;
@@ -1194,17 +1211,21 @@ packet_write_poll()
 void
 packet_write_wait()
 {
+       fd_set *setp;
+
+       setp = (fd_set *)xmalloc(howmany(connection_out + 1, NFDBITS) *
+           sizeof(fd_mask));
        packet_write_poll();
        while (packet_have_data_to_write()) {
-               fd_set set;
-
-               FD_ZERO(&set);
-               FD_SET(connection_out, &set);
-               while (select(connection_out + 1, NULL, &set, NULL, NULL) == -1 &&
+               memset(setp, 0, howmany(connection_out + 1, NFDBITS) *
+                   sizeof(fd_mask));
+               FD_SET(connection_out, setp);
+               while (select(connection_out + 1, NULL, setp, NULL, NULL) == -1 &&
                    (errno == EAGAIN || errno == EINTR))
                        ;
                packet_write_poll();
        }
+       xfree(setp);
 }
 
 /* Returns true if there is buffered data to write to the connection. */
@@ -1308,10 +1329,10 @@ packet_set_maxsize(int s)
 
 /*
  * 9.2.  Ignored Data Message
- * 
+ *
  *   byte      SSH_MSG_IGNORE
  *   string    data
- * 
+ *
  * All implementations MUST understand (and ignore) this message at any
  * time (after receiving the protocol version). No implementation is
  * required to send them. This message can be used as an additional
@@ -1329,8 +1350,8 @@ packet_inject_ignore(int sumlen)
 
        have = buffer_len(&outgoing_packet);
        debug2("packet_inject_ignore: current %d", have);
-       if (kex != NULL)
-       enc  = &kex->enc[MODE_OUT];
+       if (newkeys[MODE_OUT] != NULL)
+               enc  = &newkeys[MODE_OUT]->enc;
        blocksize = enc ? enc->cipher->block_size : 8;
        padlen = blocksize - (have % blocksize);
        if (padlen < 4)
This page took 0.046811 seconds and 4 git commands to generate.