Mention the negotiated SSH-2 MAC algorithm(s) in the Event Log.
[u/mdw/putty] / ssh.c
diff --git a/ssh.c b/ssh.c
index 91e968c..5b5a6be 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);
@@ -4478,6 +4502,10 @@ static int do_ssh2_transport(Ssh ssh, unsigned char *in, int inlen, int ispkt)
              ssh->cscipher->text_name);
     logeventf(ssh, "Initialised %.200s server->client encryption",
              ssh->sccipher->text_name);
+    logeventf(ssh, "Initialised %.200s client->server MAC algorithm",
+             ssh->csmac->text_name);
+    logeventf(ssh, "Initialised %.200s server->client MAC algorithm",
+             ssh->scmac->text_name);
     if (ssh->cscomp->text_name)
        logeventf(ssh, "Initialised %s compression",
                  ssh->cscomp->text_name);
@@ -4610,7 +4638,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 +5217,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 +5624,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 +5669,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 +5712,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt)
                        }
                    }
                }
+               sfree(sportdesc);
            }
        }
     }
@@ -6045,7 +6089,18 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt)
                    ssh2_pkt_send(ssh);
                }
            } else if (ssh->pktin.type == SSH2_MSG_CHANNEL_OPEN_FAILURE) {
+                static const char *const reasons[] = {
+                    "<unknown reason code>",
+                    "Administratively prohibited",
+                    "Connect failed",
+                    "Unknown channel type",
+                    "Resource shortage",
+                };
                unsigned i = ssh_pkt_getuint32(ssh);
+                unsigned reason_code;
+                char *reason_string;
+                int reason_length;
+                char *message;
                struct ssh_channel *c;
                c = find234(ssh->channels, &i, ssh_channelfind);
                if (!c)
@@ -6053,7 +6108,15 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt)
                if (c->type != CHAN_SOCKDATA_DORMANT)
                    continue;          /* dunno why they're failing this */
 
-               logevent("Forwarded connection refused by server");
+                reason_code = ssh_pkt_getuint32(ssh);
+                if (reason_code >= lenof(reasons))
+                    reason_code = 0; /* ensure reasons[reason_code] in range */
+                ssh_pkt_getstring(ssh, &reason_string, &reason_length);
+                message = dupprintf("Forwarded connection refused by"
+                                    " server: %s [%.*s]", reasons[reason_code],
+                                    reason_length, reason_string);
+               logevent(message);
+                sfree(message);
 
                pfd_close(c->u.pfd.s);
 
@@ -6473,10 +6536,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);