Probable support for first_kex_packet_follows in KEXINIT. Not significantly
[u/mdw/putty] / ssh.c
diff --git a/ssh.c b/ssh.c
index 1a95069..0bd89a4 100644 (file)
--- a/ssh.c
+++ b/ssh.c
@@ -689,7 +689,7 @@ struct ssh_tag {
     int overall_bufsize;
     int throttled_all;
     int v1_stdout_throttling;
-    int v2_outgoing_sequence;
+    unsigned long v2_outgoing_sequence;
 
     int ssh1_rdpkt_crstate;
     int ssh2_rdpkt_crstate;
@@ -4653,6 +4653,28 @@ static int in_commasep_string(char *needle, char *haystack, int haylen)
 }
 
 /*
+ * Similar routine for checking whether we have the first string in a list.
+ */
+static int first_in_commasep_string(char *needle, char *haystack, int haylen)
+{
+    int needlen;
+    if (!needle || !haystack)         /* protect against null pointers */
+       return 0;
+    needlen = strlen(needle);
+    /*
+     * Is it at the start of the string?
+     */
+    if (haylen >= needlen &&       /* haystack is long enough */
+       !memcmp(needle, haystack, needlen) &&   /* initial match */
+       (haylen == needlen || haystack[needlen] == ',')
+       /* either , or EOS follows */
+       )
+       return 1;
+    return 0;
+}
+
+
+/*
  * SSH2 key creation method.
  */
 static void ssh2_mkkey(Ssh ssh, Bignum K, unsigned char *H,
@@ -4920,7 +4942,7 @@ static int do_ssh2_transport(Ssh ssh, void *vin, int inlen,
      */
     {
        char *str;
-       int i, j, len;
+       int i, j, len, guessok;
 
        if (pktin->type != SSH2_MSG_KEXINIT) {
            bombout(("expected key exchange packet from server"));
@@ -4959,6 +4981,13 @@ static int do_ssh2_transport(Ssh ssh, void *vin, int inlen,
                     str ? str : "(null)"));
            crStop(0);
        }
+       /*
+        * Note that the server's guess is considered wrong if it doesn't match
+        * the first algorithm in our list, even if it's still the algorithm
+        * we end up using.
+        */
+       guessok =
+           first_in_commasep_string(s->preferred_kex[0]->name, str, len);
        ssh_pkt_getstring(pktin, &str, &len);    /* host key algorithms */
        for (i = 0; i < lenof(hostkey_algs); i++) {
            if (in_commasep_string(hostkey_algs[i]->name, str, len)) {
@@ -4966,6 +4995,8 @@ static int do_ssh2_transport(Ssh ssh, void *vin, int inlen,
                break;
            }
        }
+       guessok = guessok &&
+           first_in_commasep_string(hostkey_algs[0]->name, str, len);
        ssh_pkt_getstring(pktin, &str, &len);    /* client->server cipher */
        s->warn = 0;
        for (i = 0; i < s->n_preferred_ciphers; i++) {
@@ -5058,6 +5089,10 @@ static int do_ssh2_transport(Ssh ssh, void *vin, int inlen,
                break;
            }
        }
+       ssh_pkt_getstring(pktin, &str, &len);  /* client->server language */
+       ssh_pkt_getstring(pktin, &str, &len);  /* server->client language */
+       if (ssh2_pkt_getbool(pktin) && !guessok) /* first_kex_packet_follows */
+           crWaitUntil(pktin);                /* Ignore packet */
     }
 
     /*
@@ -5799,7 +5834,7 @@ static void ssh2_msg_channel_request(Ssh ssh, struct Packet *pktin)
        if (q >= 0 && q+4 <= len) { \
            q = q + 4 + GET_32BIT(p+q); \
            if (q >= 0 && q+4 <= len && \
-                   (q = q + 4 + GET_32BIT(p+q)) && q == len) \
+                   ((q = q + 4 + GET_32BIT(p+q))!= 0) && q == len) \
                result = TRUE; \
        } \
     } while(0)
@@ -6791,6 +6826,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen,
            } else if (s->method == AUTH_KEYBOARD_INTERACTIVE) {
                if (s->curr_prompt == 0) {
                    s->pktout = ssh2_pkt_init(SSH2_MSG_USERAUTH_INFO_RESPONSE);
+                   s->pktout->forcepad = 256;
                    ssh2_pkt_adduint32(s->pktout, s->num_prompts);
                }
                if (s->need_pw) {      /* only add pw if we just got one! */