]> asedeno.scripts.mit.edu Git - PuTTY.git/blobdiff - ssh.c
Simplifiy handling of stdin data in SSH-2.
[PuTTY.git] / ssh.c
diff --git a/ssh.c b/ssh.c
index a94ebd4110f058c42a6da885b9ca792415f860c5..92dff019389d15f8abedfd765c0a6a41dfee4a2a 100644 (file)
--- a/ssh.c
+++ b/ssh.c
@@ -384,7 +384,7 @@ static void ssh2_msg_something_unimplemented(Ssh ssh, struct Packet *pktin);
  *    ensure that the server never has any need to throttle its end
  *    of the connection), so we set this high as well.
  * 
- *  - OUR_V2_WINSIZE is the maximum window size we present on SSH-2
+ *  - OUR_V2_WINSIZE is the default window size we present on SSH-2
  *    channels.
  *
  *  - OUR_V2_BIGWIN is the window size we advertise for the only
@@ -3138,15 +3138,21 @@ static int do_ssh_init(Ssh ssh, unsigned char c)
     /* Anything greater or equal to "1.99" means protocol 2 is supported. */
     s->proto2 = ssh_versioncmp(s->version, "1.99") >= 0;
 
-    if (conf_get_int(ssh->conf, CONF_sshprot) == 0 && !s->proto1) {
-       bombout(("SSH protocol version 1 required by configuration but "
-                "not provided by server"));
-       crStop(0);
-    }
-    if (conf_get_int(ssh->conf, CONF_sshprot) == 3 && !s->proto2) {
-       bombout(("SSH protocol version 2 required by configuration but "
-                "not provided by server"));
-       crStop(0);
+    if (conf_get_int(ssh->conf, CONF_sshprot) == 0) {
+       if (!s->proto1) {
+           bombout(("SSH protocol version 1 required by our configuration "
+                    "but not provided by server"));
+           crStop(0);
+       }
+    } else if (conf_get_int(ssh->conf, CONF_sshprot) == 3) {
+       if (!s->proto2) {
+           bombout(("SSH protocol version 2 required by our configuration "
+                    "but server only provides (old, insecure) SSH-1"));
+           crStop(0);
+       }
+    } else {
+       /* No longer support values 1 or 2 for CONF_sshprot */
+       assert(!"Unexpected value for CONF_sshprot");
     }
 
     if (s->proto2 && (conf_get_int(ssh->conf, CONF_sshprot) >= 2 || !s->proto1))
@@ -3708,13 +3714,17 @@ static const char *connect_to_host(Ssh ssh, const char *host, int port,
     }
 
     /*
-     * If the SSH version number's fixed, set it now, and if it's SSH-2,
-     * send the version string too.
+     * The SSH version number is always fixed (since we no longer support
+     * fallback between versions), so set it now, and if it's SSH-2,
+     * send the version string now too.
      */
     sshprot = conf_get_int(ssh->conf, CONF_sshprot);
+    assert(sshprot == 0 || sshprot == 3);
     if (sshprot == 0)
+       /* SSH-1 only */
        ssh->version = 1;
     if (sshprot == 3 && !ssh->bare_connection) {
+       /* SSH-2 only */
        ssh->version = 2;
        ssh_send_verstring(ssh, "SSH-", NULL);
     }
@@ -5741,6 +5751,48 @@ static void ssh1_msg_channel_close(Ssh ssh, struct Packet *pktin)
     }
 }
 
+/*
+ * Handle incoming data on an SSH-1 or SSH-2 agent-forwarding channel.
+ */
+static int ssh_agent_channel_data(struct ssh_channel *c, char *data,
+                                 int length)
+{
+    while (length > 0) {
+       if (c->u.a.lensofar < 4) {
+           unsigned int l = min(4 - c->u.a.lensofar, (unsigned)length);
+           memcpy(c->u.a.msglen + c->u.a.lensofar, data, l);
+           data += l;
+           length -= l;
+           c->u.a.lensofar += l;
+       }
+       if (c->u.a.lensofar == 4) {
+           c->u.a.totallen = 4 + GET_32BIT(c->u.a.msglen);
+           c->u.a.message = snewn(c->u.a.totallen, unsigned char);
+           memcpy(c->u.a.message, c->u.a.msglen, 4);
+       }
+       if (c->u.a.lensofar >= 4 && length > 0) {
+           unsigned int l = min(c->u.a.totallen - c->u.a.lensofar,
+                                (unsigned)length);
+           memcpy(c->u.a.message + c->u.a.lensofar, data, l);
+           data += l;
+           length -= l;
+           c->u.a.lensofar += l;
+       }
+       if (c->u.a.lensofar == c->u.a.totallen) {
+           void *reply;
+           int replylen;
+            c->u.a.outstanding_requests++;
+           if (agent_query(c->u.a.message, c->u.a.totallen, &reply, &replylen,
+                           ssh_agentf_callback, c))
+               ssh_agentf_callback(c, reply, replylen);
+           sfree(c->u.a.message);
+            c->u.a.message = NULL;
+           c->u.a.lensofar = 0;
+       }
+    }
+    return 0;   /* agent channels never back up */
+}
+
 static void ssh1_msg_channel_data(Ssh ssh, struct Packet *pktin)
 {
     /* Data sent down one of our channels. */
@@ -5762,47 +5814,7 @@ static void ssh1_msg_channel_data(Ssh ssh, struct Packet *pktin)
            bufsize = pfd_send(c->u.pfd.pf, p, len);
            break;
          case CHAN_AGENT:
-           /* Data for an agent message. Buffer it. */
-           while (len > 0) {
-               if (c->u.a.lensofar < 4) {
-                   unsigned int l = min(4 - c->u.a.lensofar, (unsigned)len);
-                   memcpy(c->u.a.msglen + c->u.a.lensofar, p,
-                          l);
-                   p += l;
-                   len -= l;
-                   c->u.a.lensofar += l;
-               }
-               if (c->u.a.lensofar == 4) {
-                   c->u.a.totallen =
-                       4 + GET_32BIT(c->u.a.msglen);
-                   c->u.a.message = snewn(c->u.a.totallen,
-                                          unsigned char);
-                   memcpy(c->u.a.message, c->u.a.msglen, 4);
-               }
-               if (c->u.a.lensofar >= 4 && len > 0) {
-                   unsigned int l =
-                       min(c->u.a.totallen - c->u.a.lensofar,
-                           (unsigned)len);
-                   memcpy(c->u.a.message + c->u.a.lensofar, p,
-                          l);
-                   p += l;
-                   len -= l;
-                   c->u.a.lensofar += l;
-               }
-               if (c->u.a.lensofar == c->u.a.totallen) {
-                   void *reply;
-                   int replylen;
-                    c->u.a.outstanding_requests++;
-                   if (agent_query(c->u.a.message,
-                                   c->u.a.totallen,
-                                   &reply, &replylen,
-                                   ssh_agentf_callback, c))
-                       ssh_agentf_callback(c, reply, replylen);
-                   sfree(c->u.a.message);
-                   c->u.a.lensofar = 0;
-               }
-           }
-           bufsize = 0;   /* agent channels never back up */
+           bufsize = ssh_agent_channel_data(c, p, len);
            break;
        }
        if (!c->throttling_conn && bufsize > SSH1_BUFFER_LIMIT) {
@@ -6813,10 +6825,53 @@ static void do_ssh2_transport(Ssh ssh, const void *vin, int inlen,
        }
 
        if (s->warn_hk) {
+            int j, k;
+            char *betteralgs;
+
            ssh_set_frozen(ssh, 1);
-           s->dlgret = askalg(ssh->frontend, "host key type",
-                              ssh->hostkey->name,
-                              ssh_dialog_callback, ssh);
+
+            /*
+             * Change warning box wording depending on why we chose a
+             * warning-level host key algorithm. If it's because
+             * that's all we have *cached*, use the askhk mechanism,
+             * and list the host keys we could usefully cross-certify.
+             * Otherwise, use askalg for the standard wording.
+             */
+            betteralgs = NULL;
+            for (j = 0; j < ssh->n_uncert_hostkeys; j++) {
+                const struct ssh_signkey_with_user_pref_id *hktype =
+                    &hostkey_algs[ssh->uncert_hostkeys[j]];
+                int better = FALSE;
+                for (k = 0; k < HK_MAX; k++) {
+                    int id = conf_get_int_int(ssh->conf, CONF_ssh_hklist, k);
+                    if (id == HK_WARN) {
+                        break;
+                    } else if (id == hktype->id) {
+                        better = TRUE;
+                        break;
+                    }
+                }
+                if (better) {
+                    if (betteralgs) {
+                        char *old_ba = betteralgs;
+                        betteralgs = dupcat(betteralgs, ",",
+                                            hktype->alg->name,
+                                            (const char *)NULL);
+                        sfree(old_ba);
+                    } else {
+                        betteralgs = dupstr(hktype->alg->name);
+                    }
+                }
+            }
+            if (betteralgs) {
+                s->dlgret = askhk(ssh->frontend, ssh->hostkey->name,
+                                  betteralgs, ssh_dialog_callback, ssh);
+                sfree(betteralgs);
+            } else {
+                s->dlgret = askalg(ssh->frontend, "host key type",
+                                   ssh->hostkey->name,
+                                   ssh_dialog_callback, ssh);
+            }
            if (s->dlgret < 0) {
                do {
                    crReturnV;
@@ -7256,7 +7311,7 @@ static void do_ssh2_transport(Ssh ssh, const void *vin, int inlen,
         * Make a note of any other host key formats that are available.
         */
        {
-           int i, j;
+           int i, j, nkeys = 0;
            char *list = NULL;
            for (i = 0; i < lenof(hostkey_algs); i++) {
                if (hostkey_algs[i].alg == ssh->hostkey)
@@ -7275,13 +7330,15 @@ static void do_ssh2_transport(Ssh ssh, const void *vin, int inlen,
                        newlist = dupprintf("%s", hostkey_algs[i].alg->name);
                    sfree(list);
                    list = newlist;
+                   nkeys++;
                }
            }
            if (list) {
                logeventf(ssh,
                          "Server also has %s host key%s, but we "
                          "don't know %s", list,
-                         j > 1 ? "s" : "", j > 1 ? "any of them" : "it");
+                         nkeys > 1 ? "s" : "",
+                         nkeys > 1 ? "any of them" : "it");
                sfree(list);
            }
        }
@@ -8024,48 +8081,7 @@ static void ssh2_msg_channel_data(Ssh ssh, struct Packet *pktin)
            bufsize = pfd_send(c->u.pfd.pf, data, length);
            break;
          case CHAN_AGENT:
-           while (length > 0) {
-               if (c->u.a.lensofar < 4) {
-                   unsigned int l = min(4 - c->u.a.lensofar,
-                                        (unsigned)length);
-                   memcpy(c->u.a.msglen + c->u.a.lensofar,
-                          data, l);
-                   data += l;
-                   length -= l;
-                   c->u.a.lensofar += l;
-               }
-               if (c->u.a.lensofar == 4) {
-                   c->u.a.totallen =
-                       4 + GET_32BIT(c->u.a.msglen);
-                   c->u.a.message = snewn(c->u.a.totallen,
-                                          unsigned char);
-                   memcpy(c->u.a.message, c->u.a.msglen, 4);
-               }
-               if (c->u.a.lensofar >= 4 && length > 0) {
-                   unsigned int l =
-                       min(c->u.a.totallen - c->u.a.lensofar,
-                           (unsigned)length);
-                   memcpy(c->u.a.message + c->u.a.lensofar,
-                          data, l);
-                   data += l;
-                   length -= l;
-                   c->u.a.lensofar += l;
-               }
-               if (c->u.a.lensofar == c->u.a.totallen) {
-                   void *reply;
-                   int replylen;
-                    c->u.a.outstanding_requests++;
-                   if (agent_query(c->u.a.message,
-                                   c->u.a.totallen,
-                                   &reply, &replylen,
-                                   ssh_agentf_callback, c))
-                       ssh_agentf_callback(c, reply, replylen);
-                   sfree(c->u.a.message);
-                    c->u.a.message = NULL;
-                   c->u.a.lensofar = 0;
-               }
-           }
-           bufsize = 0;
+           bufsize = ssh_agent_channel_data(c, data, length);
            break;
        }
        /*
@@ -9172,7 +9188,6 @@ static void do_ssh2_authconn(Ssh ssh, const unsigned char *in, int inlen,
        int pklen, alglen, commentlen;
        int siglen, retlen, len;
        char *q, *agentreq, *ret;
-       int try_send;
        struct Packet *pktout;
        Filename *keyfile;
 #ifndef NO_GSSAPI
@@ -10825,7 +10840,6 @@ static void do_ssh2_authconn(Ssh ssh, const unsigned char *in, int inlen,
        ssh->send_ok = 1;
     while (1) {
        crReturnV;
-       s->try_send = FALSE;
        if (pktin) {
 
            /*
@@ -10841,17 +10855,7 @@ static void do_ssh2_authconn(Ssh ssh, const unsigned char *in, int inlen,
             * We have spare data. Add it to the channel buffer.
             */
            ssh2_add_channel_data(ssh->mainchan, (char *)in, inlen);
-           s->try_send = TRUE;
-       }
-       if (s->try_send) {
-           int i;
-           struct ssh_channel *c;
-           /*
-            * Try to send data on all channels if we can.
-            */
-           for (i = 0; NULL != (c = index234(ssh->channels, i)); i++)
-                if (c->type != CHAN_SHARING)
-                    ssh2_try_send_and_unthrottle(ssh, c);
+           ssh2_try_send(ssh->mainchan);
        }
     }