Oops, forgot to add BoldFont to the settings module.
[u/mdw/putty] / ssh.c
diff --git a/ssh.c b/ssh.c
index 58b6b42..3e8396f 100644 (file)
--- a/ssh.c
+++ b/ssh.c
@@ -183,6 +183,7 @@ static const char *const ssh2_disconnect_reasons[] = {
 #define BUG_CHOKES_ON_RSA                        8
 #define BUG_SSH2_RSA_PADDING                    16
 #define BUG_SSH2_DERIVEKEY                       32
+#define BUG_SSH2_DH_GEX                          64
 
 static int ssh_pkt_ctx = 0;
 
@@ -426,6 +427,16 @@ enum {                                    /* channel types */
 struct ssh_channel {
     unsigned remoteid, localid;
     int type;
+    /*
+     * In SSH1, this value contains four bits:
+     * 
+     *   1   We have sent SSH1_MSG_CHANNEL_CLOSE.
+     *   2   We have sent SSH1_MSG_CHANNEL_CLOSE_CONFIRMATION.
+     *   4   We have received SSH1_MSG_CHANNEL_CLOSE.
+     *   8   We have received SSH1_MSG_CHANNEL_CLOSE_CONFIRMATION.
+     * 
+     * A channel is completely finished with when all four bits are set.
+     */
     int closes;
     union {
        struct ssh1_data_channel {
@@ -1732,6 +1743,14 @@ static void ssh_detect_bugs(char *vstring)
        ssh_remote_bugs |= BUG_SSH2_RSA_PADDING;
        logevent("We believe remote version has SSH2 RSA padding bug");
     }
+
+    if (cfg.sshbug_dhgex2 == BUG_ON) {
+       /*
+        * These versions have the SSH2 DH GEX bug.
+        */
+       ssh_remote_bugs |= BUG_SSH2_DH_GEX;
+       logevent("We believe remote version has SSH2 DH group exchange bug");
+    }
 }
 
 static int do_ssh_init(unsigned char c)
@@ -2362,8 +2381,8 @@ static int do_ssh1_login(unsigned char *in, int inlen, int ispkt)
                c_write_str("\r\n");
            }
        } else {
-           strncpy(username, cfg.username, 99);
-           username[99] = '\0';
+           strncpy(username, cfg.username, sizeof(username));
+           username[sizeof(username)-1] = '\0';
        }
 
        send_packet(SSH1_CMSG_USER, PKT_STR, username, PKT_END);
@@ -2888,7 +2907,7 @@ void sshfwd_close(struct ssh_channel *c)
                ssh2_pkt_send();
            }
        }
-       c->closes = 1;
+       c->closes = 1;                 /* sent MSG_CLOSE */
        if (c->type == CHAN_X11) {
            c->u.x11.s = NULL;
            logevent("Forwarded X11 connection terminated");
@@ -3344,13 +3363,11 @@ static void ssh1_protocol(unsigned char *in, int inlen, int ispkt)
                unsigned i = GET_32BIT(pktin.body);
                struct ssh_channel *c;
                c = find234(ssh_channels, &i, ssh_channelfind);
-               if (c) {
+               if (c && ((int)c->remoteid) != -1) {
                    int closetype;
                    closetype =
                        (pktin.type == SSH1_MSG_CHANNEL_CLOSE ? 1 : 2);
-                   if (!(c->closes & closetype))
-                       send_packet(pktin.type, PKT_INT, c->remoteid,
-                                   PKT_END);
+
                    if ((c->closes == 0) && (c->type == CHAN_X11)) {
                        logevent("Forwarded X11 connection terminated");
                        assert(c->u.x11.s != NULL);
@@ -3363,11 +3380,23 @@ static void ssh1_protocol(unsigned char *in, int inlen, int ispkt)
                        pfd_close(c->u.pfd.s);
                        c->u.pfd.s = NULL;
                    }
-                   c->closes |= closetype;
-                   if (c->closes == 3) {
+
+                   c->closes |= (closetype << 2);   /* seen this message */
+                   if (!(c->closes & closetype)) {
+                       send_packet(pktin.type, PKT_INT, c->remoteid,
+                                   PKT_END);
+                       c->closes |= closetype;      /* sent it too */
+                   }
+
+                   if (c->closes == 15) {
                        del234(ssh_channels, c);
                        sfree(c);
                    }
+               } else {
+                   bombout(("Received CHANNEL_CLOSE%s for %s channel %d\n",
+                            pktin.type == SSH1_MSG_CHANNEL_CLOSE ? "" :
+                            "_CONFIRMATION", c ? "half-open" : "nonexistent",
+                            i));
                }
            } else if (pktin.type == SSH1_MSG_CHANNEL_DATA) {
                /* Data sent down one of our channels. */
@@ -3613,7 +3642,7 @@ static int do_ssh2_transport(unsigned char *in, int inlen, int ispkt)
     /*
      * Be prepared to work around the buggy MAC problem.
      */
-    if (cfg.buggymac || (ssh_remote_bugs & BUG_SSH2_HMAC))
+    if (ssh_remote_bugs & BUG_SSH2_HMAC)
        maclist = buggymacs, nmacs = lenof(buggymacs);
     else
        maclist = macs, nmacs = lenof(macs);
@@ -3628,6 +3657,9 @@ static int do_ssh2_transport(unsigned char *in, int inlen, int ispkt)
     /* List key exchange algorithms. */
     ssh2_pkt_addstring_start();
     for (i = 0; i < lenof(kex_algs); i++) {
+       if (kex_algs[i] == &ssh_diffiehellman_gex &&
+           (ssh_remote_bugs & BUG_SSH2_DH_GEX))
+           continue;
        ssh2_pkt_addstring_str(kex_algs[i]->name);
        if (i < lenof(kex_algs) - 1)
            ssh2_pkt_addstring_str(",");
@@ -3734,6 +3766,9 @@ static int do_ssh2_transport(unsigned char *in, int inlen, int ispkt)
     pktin.savedpos += 16;             /* skip garbage cookie */
     ssh2_pkt_getstring(&str, &len);    /* key exchange algorithms */
     for (i = 0; i < lenof(kex_algs); i++) {
+       if (kex_algs[i] == &ssh_diffiehellman_gex &&
+           (ssh_remote_bugs & BUG_SSH2_DH_GEX))
+           continue;
        if (in_commasep_string(kex_algs[i]->name, str, len)) {
            kex = kex_algs[i];
            break;
@@ -4182,8 +4217,8 @@ static void do_ssh2_authconn(unsigned char *in, int inlen, int ispkt)
            username[strcspn(username, "\n\r")] = '\0';
        } else {
            char stuff[200];
-           strncpy(username, cfg.username, 99);
-           username[99] = '\0';
+           strncpy(username, cfg.username, sizeof(username));
+           username[sizeof(username)-1] = '\0';
            if ((flags & FLAG_VERBOSE) || (flags & FLAG_INTERACTIVE)) {
                sprintf(stuff, "Using username \"%s\".\r\n", username);
                c_write_str(stuff);
@@ -5344,8 +5379,10 @@ static void do_ssh2_authconn(unsigned char *in, int inlen, int ispkt)
                struct ssh_channel *c;
 
                c = find234(ssh_channels, &i, ssh_channelfind);
-               if (!c)
-                   continue;          /* nonexistent channel */
+               if (!c || ((int)c->remoteid) == -1) {
+                   bombout(("Received CHANNEL_CLOSE for %s channel %d\n",
+                            c ? "half-open" : "nonexistent", i));
+               }
                /* Do pre-close processing on the channel. */
                switch (c->type) {
                  case CHAN_MAINSESSION: