Implement refreshing the whole dialogue box with dlg_refresh, so that
[u/mdw/putty] / ssh.c
diff --git a/ssh.c b/ssh.c
index 1a95069..ea4771c 100644 (file)
--- a/ssh.c
+++ b/ssh.c
@@ -436,6 +436,8 @@ struct ssh_channel {
     Ssh ssh;                          /* pointer back to main context */
     unsigned remoteid, localid;
     int type;
+    /* True if we opened this channel but server hasn't confirmed. */
+    int halfopen;
     /*
      * In SSH1, this value contains four bits:
      * 
@@ -689,7 +691,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;
@@ -3565,13 +3567,13 @@ void sshfwd_close(struct ssh_channel *c)
 
     if (c && !c->closes) {
        /*
-        * If the channel's remoteid is -1, we have sent
+        * If halfopen is true, we have sent
         * CHANNEL_OPEN for this channel, but it hasn't even been
         * acknowledged by the server. So we must set a close flag
         * on it now, and then when the server acks the channel
         * open, we can close it then.
         */
-       if (((int)c->remoteid) != -1) {
+       if (!c->halfopen) {
            if (ssh->version == 1) {
                send_packet(ssh, SSH1_MSG_CHANNEL_CLOSE, PKT_INT, c->remoteid,
                            PKT_END);
@@ -4093,6 +4095,7 @@ static void ssh1_smsg_x11_open(Ssh ssh, struct Packet *pktin)
            logevent
                ("Opening X11 forward connection succeeded");
            c->remoteid = remoteid;
+           c->halfopen = FALSE;
            c->localid = alloc_channel_id(ssh);
            c->closes = 0;
            c->v.v1.throttling = 0;
@@ -4121,6 +4124,7 @@ static void ssh1_smsg_agent_open(Ssh ssh, struct Packet *pktin)
        c = snew(struct ssh_channel);
        c->ssh = ssh;
        c->remoteid = remoteid;
+       c->halfopen = FALSE;
        c->localid = alloc_channel_id(ssh);
        c->closes = 0;
        c->v.v1.throttling = 0;
@@ -4178,6 +4182,7 @@ static void ssh1_msg_port_open(Ssh ssh, struct Packet *pktin)
                        PKT_INT, remoteid, PKT_END);
        } else {
            c->remoteid = remoteid;
+           c->halfopen = FALSE;
            c->localid = alloc_channel_id(ssh);
            c->closes = 0;
            c->v.v1.throttling = 0;
@@ -4200,6 +4205,7 @@ static void ssh1_msg_channel_open_confirmation(Ssh ssh, struct Packet *pktin)
     c = find234(ssh->channels, &remoteid, ssh_channelfind);
     if (c && c->type == CHAN_SOCKDATA_DORMANT) {
        c->remoteid = localid;
+       c->halfopen = FALSE;
        c->type = CHAN_SOCKDATA;
        c->v.v1.throttling = 0;
        pfd_confirm(c->u.pfd.s);
@@ -4237,7 +4243,7 @@ static void ssh1_msg_channel_close(Ssh ssh, struct Packet *pktin)
     unsigned i = ssh_pkt_getuint32(pktin);
     struct ssh_channel *c;
     c = find234(ssh->channels, &i, ssh_channelfind);
-    if (c && ((int)c->remoteid) != -1) {
+    if (c && !c->halfopen) {
        int closetype;
        closetype =
            (pktin->type == SSH1_MSG_CHANNEL_CLOSE ? 1 : 2);
@@ -4576,7 +4582,7 @@ static void ssh1_msg_disconnect(Ssh ssh, struct Packet *pktin)
     bombout(("Server sent disconnect message:\n\"%.*s\"", msglen, msg));
 }
 
-void ssh_msg_ignore(Ssh ssh, struct Packet *pktin)
+static void ssh_msg_ignore(Ssh ssh, struct Packet *pktin)
 {
     /* Do nothing, because we're ignoring it! Duhh. */
 }
@@ -4653,6 +4659,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 +4948,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 +4987,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 +5001,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 +5095,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 */
     }
 
     /*
@@ -5588,7 +5629,7 @@ static void ssh2_msg_channel_close(Ssh ssh, struct Packet *pktin)
     struct Packet *pktout;
 
     c = find234(ssh->channels, &i, ssh_channelfind);
-    if (!c || ((int)c->remoteid) == -1) {
+    if (!c || c->halfopen) {
        bombout(("Received CHANNEL_CLOSE for %s channel %d\n",
                 c ? "half-open" : "nonexistent", i));
        return;
@@ -5664,6 +5705,7 @@ static void ssh2_msg_channel_open_confirmation(Ssh ssh, struct Packet *pktin)
     if (c->type != CHAN_SOCKDATA_DORMANT)
        return;                        /* dunno why they're confirming this */
     c->remoteid = ssh_pkt_getuint32(pktin);
+    c->halfopen = FALSE;
     c->type = CHAN_SOCKDATA;
     c->v.v2.remwindow = ssh_pkt_getuint32(pktin);
     c->v.v2.remmaxpkt = ssh_pkt_getuint32(pktin);
@@ -5799,7 +5841,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)
@@ -5971,6 +6013,7 @@ static void ssh2_msg_channel_open(Ssh ssh, struct Packet *pktin)
     }
 
     c->remoteid = remid;
+    c->halfopen = FALSE;
     if (error) {
        pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_OPEN_FAILURE);
        ssh2_pkt_adduint32(pktout, c->remoteid);
@@ -6791,6 +6834,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! */
@@ -6874,6 +6918,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen,
            crStopV;
        }
        ssh->mainchan->remoteid = ssh_pkt_getuint32(pktin);
+       ssh->mainchan->halfopen = FALSE;
        ssh->mainchan->type = CHAN_MAINSESSION;
        ssh->mainchan->closes = 0;
        ssh->mainchan->v.v2.remwindow = ssh_pkt_getuint32(pktin);
@@ -7211,7 +7256,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen,
 /*
  * Handlers for SSH2 messages that might arrive at any moment.
  */
-void ssh2_msg_disconnect(Ssh ssh, struct Packet *pktin)
+static void ssh2_msg_disconnect(Ssh ssh, struct Packet *pktin)
 {
     /* log reason code in disconnect message */
     char *buf, *msg;
@@ -7240,7 +7285,7 @@ void ssh2_msg_disconnect(Ssh ssh, struct Packet *pktin)
     sfree(buf);
 }
 
-void ssh2_msg_debug(Ssh ssh, struct Packet *pktin)
+static void ssh2_msg_debug(Ssh ssh, struct Packet *pktin)
 {
     /* log the debug message */
     char *buf, *msg;
@@ -7256,7 +7301,7 @@ void ssh2_msg_debug(Ssh ssh, struct Packet *pktin)
     sfree(buf);
 }
 
-void ssh2_msg_something_unimplemented(Ssh ssh, struct Packet *pktin)
+static void ssh2_msg_something_unimplemented(Ssh ssh, struct Packet *pktin)
 {
     struct Packet *pktout;
     pktout = ssh2_pkt_init(SSH2_MSG_UNIMPLEMENTED);
@@ -7885,7 +7930,7 @@ void *new_sock_channel(void *handle, Socket s)
     c->ssh = ssh;
 
     if (c) {
-       c->remoteid = -1;              /* to be set when open confirmed */
+       c->halfopen = TRUE;
        c->localid = alloc_channel_id(ssh);
        c->closes = 0;
        c->type = CHAN_SOCKDATA_DORMANT;/* identify channel type */