Add `OSU_1.5alpha4' to BUG_CHOKES_ON_SSH1_IGNORE; this is apparently enough to
[u/mdw/putty] / ssh.c
diff --git a/ssh.c b/ssh.c
index 3616d21..292fb8b 100644 (file)
--- a/ssh.c
+++ b/ssh.c
@@ -827,6 +827,12 @@ static int ssh1_rdpkt(Ssh ssh, unsigned char **data, int *datalen)
     st->biglen = st->len + st->pad;
     ssh->pktin.length = st->len - 5;
 
+    if (st->biglen < 0) {
+        bombout(("Extremely large packet length from server suggests"
+                " data stream corruption"));
+        crStop(0);
+    }
+
     if (ssh->pktin.maxlen < st->biglen) {
        ssh->pktin.maxlen = st->biglen;
        ssh->pktin.data = sresize(ssh->pktin.data, st->biglen + APIEXTRA,
@@ -1822,7 +1828,7 @@ static void ssh_detect_bugs(Ssh ssh, char *vstring)
         (!strcmp(imp, "1.2.18") || !strcmp(imp, "1.2.19") ||
          !strcmp(imp, "1.2.20") || !strcmp(imp, "1.2.21") ||
          !strcmp(imp, "1.2.22") || !strcmp(imp, "Cisco-1.25") ||
-         !strcmp(imp, "OSU_1.4alpha3")))) {
+         !strcmp(imp, "OSU_1.4alpha3") || !strcmp(imp, "OSU_1.5alpha4")))) {
        /*
         * These versions don't support SSH1_MSG_IGNORE, so we have
         * to use a different defence against password length
@@ -2435,7 +2441,7 @@ static int do_ssh1_login(Ssh ssh, unsigned char *in, int inlen, int ispkt)
 
     if (!ssh1_pkt_getrsakey(ssh, &servkey, &s->keystr1) ||
        !ssh1_pkt_getrsakey(ssh, &hostkey, &s->keystr2)) {      
-       bombout(("SSH1 public key packet stopped before public keys"));
+       bombout(("Failed to read SSH1 public keys from public key packet"));
        crStop(0);
     }
 
@@ -3443,27 +3449,40 @@ static void ssh1_protocol(Ssh ssh, unsigned char *in, int inlen, int ispkt)
                }
            }
            if (sport && dport) {
+               /* Set up a description of the source port. */
+               char *sportdesc = dupprintf("%.*s%.*s%.*s%.*s%d%.*s",
+                       (int)(*saddr?strlen(saddr):0), *saddr?saddr:NULL,
+                       (int)(*saddr?1:0), ":",
+                       (int)(sserv ? strlen(sports) : 0), sports,
+                       sserv, "(", sport, sserv, ")");
                if (type == 'L') {
-                   pfd_addforward(host, dport, *saddr ? saddr : NULL,
-                                  sport, ssh, &ssh->cfg);
-                   logeventf(ssh, "Local port %.*s%.*s%.*s%.*s%d%.*s"
-                             " forwarding to %s:%.*s%.*s%d%.*s",
-                             (int)(*saddr?strlen(saddr):0), *saddr?saddr:NULL,
-                             (int)(*saddr?1:0), ":",
-                             (int)(sserv ? strlen(sports) : 0), sports,
-                             sserv, "(", sport, sserv, ")",
-                             host,
-                             (int)(dserv ? strlen(dports) : 0), dports,
-                             dserv, "(", dport, dserv, ")");
+                   /* Verbose description of the destination port */
+                   char *dportdesc = dupprintf("%s:%.*s%.*s%d%.*s",
+                           host,
+                           (int)(dserv ? strlen(dports) : 0), dports,
+                           dserv, "(", dport, dserv, ")");
+                   const char *err = pfd_addforward(host, dport,
+                                                    *saddr ? saddr : NULL,
+                                                    sport, ssh, &ssh->cfg);
+                   if (err) {
+                       logeventf(ssh, "Local port %s forward to %s"
+                                 " failed: %s", sportdesc, dportdesc, err);
+                   } else {
+                       logeventf(ssh, "Local port %s forwarding to %s",
+                                 sportdesc, dportdesc);
+                   }
+                   sfree(dportdesc);
                } else if (type == 'D') {
-                   pfd_addforward(NULL, -1, *saddr ? saddr : NULL,
-                                  sport, ssh, &ssh->cfg);
-                   logeventf(ssh, "Local port %.*s%.*s%.*s%.*s%d%.*s"
-                             " doing SOCKS dynamic forwarding",
-                             (int)(*saddr?strlen(saddr):0), *saddr?saddr:NULL,
-                             (int)(*saddr?1:0), ":",
-                             (int)(sserv ? strlen(sports) : 0), sports,
-                             sserv, "(", sport, sserv, ")");
+                   const char *err = pfd_addforward(NULL, -1,
+                                                    *saddr ? saddr : NULL,
+                                                    sport, ssh, &ssh->cfg);
+                   if (err) {
+                       logeventf(ssh, "Local port %s SOCKS dynamic forward"
+                                 " setup failed: %s", sportdesc, err);
+                   } else {
+                       logeventf(ssh, "Local port %s doing SOCKS"
+                                 " dynamic forwarding", sportdesc);
+                   }
                } else {
                    struct ssh_rportfwd *pf;
                    pf = snew(struct ssh_rportfwd);
@@ -3506,6 +3525,7 @@ static void ssh1_protocol(Ssh ssh, unsigned char *in, int inlen, int ispkt)
                        logevent("Remote port forwarding enabled");
                    }
                }
+               sfree(sportdesc);
            }
        }
     }
@@ -4130,21 +4150,25 @@ static int do_ssh2_transport(Ssh ssh, unsigned char *in, int inlen, int ispkt)
        }
        /* List client->server compression algorithms. */
        ssh2_pkt_addstring_start(ssh);
-       for (i = 0; i < lenof(compressions) + 1; i++) {
-           const struct ssh_compress *c =
-               i == 0 ? s->preferred_comp : compressions[i - 1];
-           ssh2_pkt_addstring_str(ssh, c->name);
-           if (i < lenof(compressions))
+       assert(lenof(compressions) > 1);
+       ssh2_pkt_addstring_str(ssh, s->preferred_comp->name);
+       for (i = 0; i < lenof(compressions); i++) {
+           const struct ssh_compress *c = compressions[i];
+           if (c != s->preferred_comp) {
                ssh2_pkt_addstring_str(ssh, ",");
+               ssh2_pkt_addstring_str(ssh, c->name);
+           }
        }
        /* List server->client compression algorithms. */
        ssh2_pkt_addstring_start(ssh);
-       for (i = 0; i < lenof(compressions) + 1; i++) {
-           const struct ssh_compress *c =
-               i == 0 ? s->preferred_comp : compressions[i - 1];
-           ssh2_pkt_addstring_str(ssh, c->name);
-           if (i < lenof(compressions))
+       assert(lenof(compressions) > 1);
+       ssh2_pkt_addstring_str(ssh, s->preferred_comp->name);
+       for (i = 0; i < lenof(compressions); i++) {
+           const struct ssh_compress *c = compressions[i];
+           if (c != s->preferred_comp) {
                ssh2_pkt_addstring_str(ssh, ",");
+               ssh2_pkt_addstring_str(ssh, c->name);
+           }
        }
        /* List client->server languages. Empty list. */
        ssh2_pkt_addstring_start(ssh);
@@ -4610,7 +4634,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt)
        int num_prompts, curr_prompt, echo;
        char username[100];
        int got_username;
-       char pwprompt[200];
+       char pwprompt[512];
        char password[100];
        void *publickey_blob;
        int publickey_bloblen;
@@ -5189,9 +5213,16 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt)
 
                    ssh_pkt_getstring(ssh, &prompt, &prompt_len);
                    if (prompt_len > 0) {
-                       strncpy(s->pwprompt, prompt, sizeof(s->pwprompt));
-                       s->pwprompt[prompt_len < sizeof(s->pwprompt) ?
-                                   prompt_len : sizeof(s->pwprompt)-1] = '\0';
+                       static const char trunc[] = "<prompt truncated>: ";
+                       static const int prlen = sizeof(s->pwprompt) -
+                                                lenof(trunc);
+                       if (prompt_len > prlen) {
+                           memcpy(s->pwprompt, prompt, prlen);
+                           strcpy(s->pwprompt + prlen, trunc);
+                       } else {
+                           memcpy(s->pwprompt, prompt, prompt_len);
+                           s->pwprompt[prompt_len] = '\0';
+                       }
                    } else {
                        strcpy(s->pwprompt,
                               "<server failed to send prompt>: ");
@@ -5589,27 +5620,40 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt)
                }
            }
            if (sport && dport) {
+               /* Set up a description of the source port. */
+               char *sportdesc = dupprintf("%.*s%.*s%.*s%.*s%d%.*s",
+                       (int)(*saddr?strlen(saddr):0), *saddr?saddr:NULL,
+                       (int)(*saddr?1:0), ":",
+                       (int)(sserv ? strlen(sports) : 0), sports,
+                       sserv, "(", sport, sserv, ")");
                if (type == 'L') {
-                   pfd_addforward(host, dport, *saddr ? saddr : NULL,
-                                  sport, ssh, &ssh->cfg);
-                   logeventf(ssh, "Local port %.*s%.*s%.*s%.*s%d%.*s"
-                             " forwarding to %s:%.*s%.*s%d%.*s",
-                             (int)(*saddr?strlen(saddr):0), *saddr?saddr:NULL,
-                             (int)(*saddr?1:0), ":",
-                             (int)(sserv ? strlen(sports) : 0), sports,
-                             sserv, "(", sport, sserv, ")",
-                             host,
-                             (int)(dserv ? strlen(dports) : 0), dports,
-                             dserv, "(", dport, dserv, ")");
+                   /* Verbose description of the destination port */
+                   char *dportdesc = dupprintf("%s:%.*s%.*s%d%.*s",
+                           host,
+                           (int)(dserv ? strlen(dports) : 0), dports,
+                           dserv, "(", dport, dserv, ")");
+                   const char *err = pfd_addforward(host, dport,
+                                                    *saddr ? saddr : NULL,
+                                                    sport, ssh, &ssh->cfg);
+                   if (err) {
+                       logeventf(ssh, "Local port %s forward to %s"
+                                 " failed: %s", sportdesc, dportdesc, err);
+                   } else {
+                       logeventf(ssh, "Local port %s forwarding to %s",
+                                 sportdesc, dportdesc);
+                   }
+                   sfree(dportdesc);
                } else if (type == 'D') {
-                   pfd_addforward(NULL, -1, *saddr ? saddr : NULL,
-                                  sport, ssh, &ssh->cfg);
-                   logeventf(ssh, "Local port %.*s%.*s%.*s%.*s%d%.*s"
-                             " doing SOCKS dynamic forwarding",
-                             (int)(*saddr?strlen(saddr):0), *saddr?saddr:NULL,
-                             (int)(*saddr?1:0), ":",
-                             (int)(sserv ? strlen(sports) : 0), sports,
-                             sserv, "(", sport, sserv, ")");
+                   const char *err = pfd_addforward(NULL, -1,
+                                                    *saddr ? saddr : NULL,
+                                                    sport, ssh, &ssh->cfg);
+                   if (err) {
+                       logeventf(ssh, "Local port %s SOCKS dynamic forward"
+                                 " setup failed: %s", sportdesc, err);
+                   } else {
+                       logeventf(ssh, "Local port %s doing SOCKS"
+                                 " dynamic forwarding", sportdesc);
+                   }
                } else {
                    struct ssh_rportfwd *pf;
                    pf = snew(struct ssh_rportfwd);
@@ -5621,14 +5665,9 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt)
                                  " to %s:%d", host, dport);
                        sfree(pf);
                    } else {
-                       logeventf(ssh, "Requesting remote port "
-                                 "%.*s%.*s%.*s%.*s%d%.*s"
+                       logeventf(ssh, "Requesting remote port %s"
                                  " forward to %s:%.*s%.*s%d%.*s",
-                                 (int)(*saddr?strlen(saddr):0),
-                                 *saddr?saddr:NULL,
-                                 (int)(*saddr?1:0), ":",
-                                 (int)(sserv ? strlen(sports) : 0), sports,
-                                 sserv, "(", sport, sserv, ")",
+                                 sportdesc,
                                  host,
                                  (int)(dserv ? strlen(dports) : 0), dports,
                                  dserv, "(", dport, dserv, ")");
@@ -5669,6 +5708,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt)
                        }
                    }
                }
+               sfree(sportdesc);
            }
        }
     }
@@ -6160,9 +6200,12 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt)
                     ssh_pkt_getstring(ssh, &peeraddr, &peeraddrlen);
                    addrstr = snewn(peeraddrlen+1, char);
                    memcpy(addrstr, peeraddr, peeraddrlen);
-                   peeraddr[peeraddrlen] = '\0';
+                   addrstr[peeraddrlen] = '\0';
                     peerport = ssh_pkt_getuint32(ssh);
 
+                   logeventf(ssh, "Received X11 connect request from %s:%d",
+                             addrstr, peerport);
+
                    if (!ssh->X11_fwd_enabled)
                        error = "X11 forwarding is not enabled";
                    else if (x11_init(&c->u.x11.s, ssh->cfg.x11_display, c,
@@ -6170,6 +6213,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt)
                                      &ssh->cfg) != NULL) {
                        error = "Unable to open an X11 connection";
                    } else {
+                       logevent("Opening X11 forward connection succeeded");
                        c->type = CHAN_X11;
                    }
 
@@ -6184,6 +6228,8 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt)
                     ssh_pkt_getstring(ssh, &peeraddr, &peeraddrlen);
                     peerport = ssh_pkt_getuint32(ssh);
                    realpf = find234(ssh->rportfwds, &pf, NULL);
+                   logeventf(ssh, "Received remote port %d open request "
+                             "from %s:%d", pf.sport, peeraddr, peerport);
                    if (realpf == NULL) {
                        error = "Remote port is not recognised";
                    } else {
@@ -6191,8 +6237,8 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt)
                                                       realpf->dhost,
                                                       realpf->dport, c,
                                                       &ssh->cfg);
-                       logeventf(ssh, "Received remote port open request"
-                                 " for %s:%d", realpf->dhost, realpf->dport);
+                       logeventf(ssh, "Attempting to forward remote port to "
+                                 "%s:%d", realpf->dhost, realpf->dport);
                        if (e != NULL) {
                            logeventf(ssh, "Port open failed: %s", e);
                            error = "Port open failed";
@@ -6221,6 +6267,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt)
                    ssh2_pkt_addstring(ssh, error);
                    ssh2_pkt_addstring(ssh, "en");      /* language tag */
                    ssh2_pkt_send(ssh);
+                   logeventf(ssh, "Rejected channel open: %s", error);
                    sfree(c);
                } else {
                    c->localid = alloc_channel_id(ssh);
@@ -6466,10 +6513,6 @@ static void ssh_free(void *handle)
        crcda_free_context(ssh->crcda_ctx);
        ssh->crcda_ctx = NULL;
     }
-    if (ssh->logctx) {
-       log_free(ssh->logctx);
-       ssh->logctx = NULL;
-    }
     if (ssh->s)
        ssh_do_close(ssh);
     sfree(ssh);