Explicitly note that "remote command" semantics typically involve the server
[u/mdw/putty] / ssh.c
diff --git a/ssh.c b/ssh.c
index e0556a6..2a97bb5 100644 (file)
--- a/ssh.c
+++ b/ssh.c
@@ -679,7 +679,8 @@ struct ssh_tag {
     const struct plug_function_table *fn;
     /* the above field _must_ be first in the structure */
 
-    SHA_State exhash, exhashbase;
+    char *v_c, *v_s;
+    SHA_State exhash;
 
     Socket s;
 
@@ -2250,7 +2251,8 @@ static void ssh_detect_bugs(Ssh ssh, char *vstring)
          wc_match("OpenSSH_2.5.[0-3]*", imp) ||
          wc_match("Sun_SSH_1.0", imp) ||
          wc_match("Sun_SSH_1.0.1", imp) ||
-         wc_match("WeOnlyDo-1.2.6", imp)))) {
+         /* All versions <= 1.2.6 (they changed their format in 1.2.7) */
+         wc_match("WeOnlyDo-*", imp)))) {
        /*
         * These versions have the SSH-2 rekey bug.
         */
@@ -2383,15 +2385,19 @@ static int do_ssh_init(Ssh ssh, unsigned char c)
         ssh_fix_verstring(verstring);
 
         if (ssh->version == 2) {
+           size_t len;
             /*
              * Hash our version string and their version string.
              */
-            SHA_Init(&ssh->exhashbase);
-            sha_string(&ssh->exhashbase, verstring,
-                       strcspn(verstring, "\015\012"));
-            sha_string(&ssh->exhashbase, s->vstring,
-                       strcspn(s->vstring, "\015\012"));
-
+           len = strcspn(verstring, "\015\012");
+           ssh->v_c = snewn(len + 1, char);
+           memcpy(ssh->v_c, verstring, len);
+           ssh->v_c[len] = 0;
+           len = strcspn(s->vstring, "\015\012");
+           ssh->v_s = snewn(len + 1, char);
+           memcpy(ssh->v_s, s->vstring, len);
+           ssh->v_s[len] = 0;
+           
             /*
              * Initialise SSH-2 protocol.
              */
@@ -2496,24 +2502,29 @@ static void ssh_gotdata(Ssh ssh, unsigned char *data, int datalen)
      * everything to s_rdpkt, and then pass the resulting packets
      * to the proper protocol handler.
      */
-    if (datalen == 0)
-       crReturnV;
-
-    /*
-     * Process queued data if there is any.
-     */
-    ssh_process_queued_incoming_data(ssh);
 
     while (1) {
-       while (datalen > 0) {
-           if (ssh->frozen)
+       while (bufchain_size(&ssh->queued_incoming_data) > 0 || datalen > 0) {
+           if (ssh->frozen) {
                ssh_queue_incoming_data(ssh, &data, &datalen);
-
-           ssh_process_incoming_data(ssh, &data, &datalen);
-
+               /* This uses up all data and cannot cause anything interesting
+                * to happen; indeed, for anything to happen at all, we must
+                * return, so break out. */
+               break;
+           } else if (bufchain_size(&ssh->queued_incoming_data) > 0) {
+               /* This uses up some or all data, and may freeze the
+                * session. */
+               ssh_process_queued_incoming_data(ssh);
+           } else {
+               /* This uses up some or all data, and may freeze the
+                * session. */
+               ssh_process_incoming_data(ssh, &data, &datalen);
+           }
+           /* FIXME this is probably EBW. */
            if (ssh->state == SSH_STATE_CLOSED)
                return;
        }
+       /* We're out of data. Go and get some more. */
        crReturnV;
     }
     crFinishV;
@@ -4968,6 +4979,8 @@ static int do_ssh2_transport(Ssh ssh, void *vin, int inlen,
     struct do_ssh2_transport_state {
        int nbits, pbits, warn_kex, warn_cscipher, warn_sccipher;
        Bignum p, g, e, f, K;
+       void *our_kexinit;
+       int our_kexinitlen;
        int kex_init_value, kex_reply_value;
        const struct ssh_mac **maclist;
        int nmacs;
@@ -5191,15 +5204,14 @@ static int do_ssh2_transport(Ssh ssh, void *vin, int inlen,
        ssh2_pkt_adduint32(s->pktout, 0);
     }
 
-    ssh->exhash = ssh->exhashbase;
-    sha_string(&ssh->exhash, s->pktout->data + 5, s->pktout->length - 5);
+    s->our_kexinitlen = s->pktout->length - 5;
+    s->our_kexinit = snewn(s->our_kexinitlen, unsigned char);
+    memcpy(s->our_kexinit, s->pktout->data + 5, s->our_kexinitlen); 
 
     ssh2_pkt_send_noqueue(ssh, s->pktout);
 
     if (!pktin)
        crWaitUntil(pktin);
-    if (pktin->length > 5)
-       sha_string(&ssh->exhash, pktin->data + 5, pktin->length - 5);
 
     /*
      * Now examine the other side's KEXINIT to see what we're up
@@ -5413,6 +5425,15 @@ static int do_ssh2_transport(Ssh ssh, void *vin, int inlen,
            }
        }
 
+       SHA_Init(&ssh->exhash);
+       sha_string(&ssh->exhash, ssh->v_c, strlen(ssh->v_c));
+       sha_string(&ssh->exhash, ssh->v_s, strlen(ssh->v_s));
+       sha_string(&ssh->exhash, s->our_kexinit, s->our_kexinitlen);
+       sfree(s->our_kexinit);
+       if (pktin->length > 5)
+           sha_string(&ssh->exhash, pktin->data + 5, pktin->length - 5);
+
+
        if (s->ignorepkt) /* first_kex_packet_follows */
            crWaitUntil(pktin);                /* Ignore packet */
     }
@@ -7855,6 +7876,8 @@ static const char *ssh_init(void *frontend_handle, void **backend_handle,
     ssh->do_ssh1_login_state = NULL;
     ssh->do_ssh2_transport_state = NULL;
     ssh->do_ssh2_authconn_state = NULL;
+    ssh->v_c = NULL;
+    ssh->v_s = NULL;
     ssh->mainchan = NULL;
     ssh->throttled_all = 0;
     ssh->v1_stdout_throttling = 0;
@@ -7982,6 +8005,8 @@ static void ssh_free(void *handle)
     sfree(ssh->do_ssh1_login_state);
     sfree(ssh->do_ssh2_transport_state);
     sfree(ssh->do_ssh2_authconn_state);
+    sfree(ssh->v_c);
+    sfree(ssh->v_s);
     if (ssh->crcda_ctx) {
        crcda_free_context(ssh->crcda_ctx);
        ssh->crcda_ctx = NULL;