Remove a bashism in mksrcarc.sh, without which bob builds fail on
[sgt/putty] / ssh.c
diff --git a/ssh.c b/ssh.c
index eee792b..ef503bf 100644 (file)
--- a/ssh.c
+++ b/ssh.c
@@ -517,9 +517,6 @@ static void ssh_channel_destroy(struct ssh_channel *c);
 #define OUR_V2_MAXPKT 0x4000UL
 #define OUR_V2_PACKETLIMIT 0x9000UL
 
-/* Maximum length of passwords/passphrases (arbitrary) */
-#define SSH_MAX_PASSWORD_LEN 100
-
 const static struct ssh_signkey *hostkey_algs[] = { &ssh_rsa, &ssh_dss };
 
 const static struct ssh_mac *macs[] = {
@@ -561,7 +558,15 @@ enum {                                    /* channel types */
     CHAN_X11,
     CHAN_AGENT,
     CHAN_SOCKDATA,
-    CHAN_SOCKDATA_DORMANT             /* one the remote hasn't confirmed */
+    CHAN_SOCKDATA_DORMANT,            /* one the remote hasn't confirmed */
+    /*
+     * CHAN_ZOMBIE is used to indicate a channel for which we've
+     * already destroyed the local data source: for instance, if a
+     * forwarded port experiences a socket error on the local side, we
+     * immediately destroy its local socket and turn the SSH channel
+     * into CHAN_ZOMBIE.
+     */
+    CHAN_ZOMBIE
 };
 
 /*
@@ -3526,8 +3531,7 @@ static int do_ssh1_login(Ssh ssh, unsigned char *in, int inlen,
            s->cur_prompt = new_prompts(ssh->frontend);
            s->cur_prompt->to_server = TRUE;
            s->cur_prompt->name = dupstr("SSH login name");
-           /* 512 is an arbitrary upper limit on username size */
-           add_prompt(s->cur_prompt, dupstr("login as: "), TRUE, 512);
+           add_prompt(s->cur_prompt, dupstr("login as: "), TRUE);
            ret = get_userpass_input(s->cur_prompt, NULL, 0);
            while (ret < 0) {
                ssh->send_ok = 1;
@@ -3573,7 +3577,7 @@ static int do_ssh1_login(Ssh ssh, unsigned char *in, int inlen,
      * Load the public half of any configured keyfile for later use.
      */
     s->keyfile = conf_get_filename(ssh->conf, CONF_keyfile);
-    if (!filename_is_null(*s->keyfile)) {
+    if (!filename_is_null(s->keyfile)) {
        int keytype;
        logeventf(ssh, "Reading private key file \"%.150s\"",
                  filename_to_str(s->keyfile));
@@ -3820,8 +3824,7 @@ static int do_ssh1_login(Ssh ssh, unsigned char *in, int inlen,
                    s->cur_prompt->name = dupstr("SSH key passphrase");
                    add_prompt(s->cur_prompt,
                               dupprintf("Passphrase for key \"%.100s\": ",
-                                        s->publickey_comment),
-                              FALSE, SSH_MAX_PASSWORD_LEN);
+                                        s->publickey_comment), FALSE);
                    ret = get_userpass_input(s->cur_prompt, NULL, 0);
                    while (ret < 0) {
                        ssh->send_ok = 1;
@@ -3976,7 +3979,7 @@ static int do_ssh1_login(Ssh ssh, unsigned char *in, int inlen,
                              (*instr_suf) ? "\n" : "",
                              instr_suf);
                s->cur_prompt->instr_reqd = TRUE;
-               add_prompt(s->cur_prompt, prompt, FALSE, SSH_MAX_PASSWORD_LEN);
+               add_prompt(s->cur_prompt, prompt, FALSE);
                sfree(instr_suf);
            }
        }
@@ -4019,7 +4022,7 @@ static int do_ssh1_login(Ssh ssh, unsigned char *in, int inlen,
                              (*instr_suf) ? "\n" : "",
                              instr_suf);
                s->cur_prompt->instr_reqd = TRUE;
-               add_prompt(s->cur_prompt, prompt, FALSE, SSH_MAX_PASSWORD_LEN);
+               add_prompt(s->cur_prompt, prompt, FALSE);
                sfree(instr_suf);
            }
        }
@@ -4032,7 +4035,7 @@ static int do_ssh1_login(Ssh ssh, unsigned char *in, int inlen,
            s->cur_prompt->name = dupstr("SSH password");
            add_prompt(s->cur_prompt, dupprintf("%s@%s's password: ",
                                                ssh->username, ssh->savedhost),
-                      FALSE, SSH_MAX_PASSWORD_LEN);
+                      FALSE);
        }
 
        /*
@@ -4255,6 +4258,35 @@ void sshfwd_write_eof(struct ssh_channel *c)
     ssh_channel_try_eof(c);
 }
 
+void sshfwd_unclean_close(struct ssh_channel *c)
+{
+    Ssh ssh = c->ssh;
+    struct Packet *pktout;
+
+    if (ssh->state == SSH_STATE_CLOSED)
+       return;
+
+    if (!(c->closes & CLOSES_SENT_CLOSE)) {
+        pktout = ssh2_pkt_init(SSH2_MSG_CHANNEL_CLOSE);
+        ssh2_pkt_adduint32(pktout, c->remoteid);
+        ssh2_pkt_send(ssh, pktout);
+        c->closes |= CLOSES_SENT_EOF | CLOSES_SENT_CLOSE;
+    }
+
+    switch (c->type) {
+      case CHAN_X11:
+        x11_close(c->u.x11.s);
+        break;
+      case CHAN_SOCKDATA:
+      case CHAN_SOCKDATA_DORMANT:
+        pfd_close(c->u.pfd.s);
+        break;
+    }
+    c->type = CHAN_ZOMBIE;
+
+    ssh2_channel_check_close(c);
+}
+
 int sshfwd_write(struct ssh_channel *c, char *buf, int len)
 {
     Ssh ssh = c->ssh;
@@ -5746,6 +5778,12 @@ static int do_ssh2_transport(Ssh ssh, void *vin, int inlen,
                break;
            }
        }
+       if (!ssh->hostkey) {
+           bombout(("Couldn't agree a host key algorithm (available: %s)",
+                    str ? str : "(null)"));
+           crStop(0);
+       }
+
        s->guessok = s->guessok &&
            first_in_commasep_string(hostkey_algs[0]->name, str, len);
        ssh_pkt_getstring(pktin, &str, &len);    /* client->server cipher */
@@ -6556,9 +6594,10 @@ static void ssh2_set_window(struct ssh_channel *c, int newwin)
     /*
      * Never send WINDOW_ADJUST for a channel that the remote side has
      * already sent EOF on; there's no point, since it won't be
-     * sending any more data anyway.
+     * sending any more data anyway. Ditto if _we've_ already sent
+     * CLOSE.
      */
-    if (c->closes & CLOSES_RCVD_EOF)
+    if (c->closes & (CLOSES_RCVD_EOF | CLOSES_SENT_CLOSE))
        return;
 
     /*
@@ -6568,7 +6607,6 @@ static void ssh2_set_window(struct ssh_channel *c, int newwin)
      */
     if ((ssh->remote_bugs & BUG_SSH2_MAXPKT) && newwin > OUR_V2_MAXPKT)
        newwin = OUR_V2_MAXPKT;
-       
 
     /*
      * Only send a WINDOW_ADJUST if there's significantly more window
@@ -6983,16 +7021,28 @@ static void ssh2_msg_channel_close(Ssh ssh, struct Packet *pktin)
      * the remote side is doing away with the entire channel. (If it
      * had wanted to send us EOF and continue receiving data from us,
      * it would have just sent CHANNEL_EOF.)
-     *
-     * For the moment, this policy applies to the main session channel
-     * only, because we have a convenient mechanism (ssh->send_ok) for
-     * ceasing to read from our local data source. Ideally I think
-     * we'd do this for auxiliary channels too, which would need an
-     * extra API call in the forwarding modules.
      */
-    if (c->type == CHAN_MAINSESSION && !(c->closes & CLOSES_SENT_EOF)) {
-        sshfwd_write_eof(ssh->mainchan);
-        ssh->send_ok = 0;          /* now stop trying to read from stdin */
+    if (!(c->closes & CLOSES_SENT_EOF)) {
+        /*
+         * Make sure we don't read any more from whatever our local
+         * data source is for this channel.
+         */
+        switch (c->type) {
+          case CHAN_MAINSESSION:
+            ssh->send_ok = 0;     /* stop trying to read from stdin */
+            break;
+          case CHAN_X11:
+           x11_override_throttle(c->u.x11.s, 1);
+           break;
+         case CHAN_SOCKDATA:
+           pfd_override_throttle(c->u.pfd.s, 1);
+           break;
+        }
+
+        /*
+         * Send outgoing EOF.
+         */
+        sshfwd_write_eof(c);
     }
 
     /*
@@ -7517,7 +7567,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen,
         * for later use.
         */
        s->keyfile = conf_get_filename(ssh->conf, CONF_keyfile);
-       if (!filename_is_null(*s->keyfile)) {
+       if (!filename_is_null(s->keyfile)) {
            int keytype;
            logeventf(ssh, "Reading private key file \"%.150s\"",
                      filename_to_str(s->keyfile));
@@ -7663,8 +7713,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen,
            s->cur_prompt = new_prompts(ssh->frontend);
            s->cur_prompt->to_server = TRUE;
            s->cur_prompt->name = dupstr("SSH login name");
-           /* 512 is an arbitrary limit :-( */
-           add_prompt(s->cur_prompt, dupstr("login as: "), TRUE, 512); 
+           add_prompt(s->cur_prompt, dupstr("login as: "), TRUE); 
            ret = get_userpass_input(s->cur_prompt, NULL, 0);
            while (ret < 0) {
                ssh->send_ok = 1;
@@ -8070,7 +8119,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen,
                        add_prompt(s->cur_prompt,
                                   dupprintf("Passphrase for key \"%.100s\": ",
                                             s->publickey_comment),
-                                  FALSE, SSH_MAX_PASSWORD_LEN);
+                                  FALSE);
                        ret = get_userpass_input(s->cur_prompt, NULL, 0);
                        while (ret < 0) {
                            ssh->send_ok = 1;
@@ -8450,7 +8499,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen,
                        }
                        add_prompt(s->cur_prompt,
                                   dupprintf("%.*s", prompt_len, prompt),
-                                  echo, SSH_MAX_PASSWORD_LEN);
+                                   echo);
                    }
 
                    if (name_len) {
@@ -8518,6 +8567,13 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen,
                    }
                    ssh2_pkt_send_with_padding(ssh, s->pktout, 256);
 
+                    /*
+                     * Free the prompts structure from this iteration.
+                     * If there's another, a new one will be allocated
+                     * when we return to the top of this while loop.
+                     */
+                    free_prompts(s->cur_prompt);
+
                    /*
                     * Get the next packet in case it's another
                     * INFO_REQUEST.
@@ -8547,7 +8603,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen,
                add_prompt(s->cur_prompt, dupprintf("%s@%s's password: ",
                                                    ssh->username,
                                                    ssh->savedhost),
-                          FALSE, SSH_MAX_PASSWORD_LEN);
+                          FALSE);
 
                ret = get_userpass_input(s->cur_prompt, NULL, 0);
                while (ret < 0) {
@@ -8649,11 +8705,11 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen,
                     */
                    add_prompt(s->cur_prompt,
                               dupstr("Current password (blank for previously entered password): "),
-                              FALSE, SSH_MAX_PASSWORD_LEN);
+                              FALSE);
                    add_prompt(s->cur_prompt, dupstr("Enter new password: "),
-                              FALSE, SSH_MAX_PASSWORD_LEN);
+                              FALSE);
                    add_prompt(s->cur_prompt, dupstr("Confirm new password: "),
-                              FALSE, SSH_MAX_PASSWORD_LEN);
+                              FALSE);
 
                    /*
                     * Loop until the user manages to enter the same
@@ -9987,6 +10043,12 @@ static void ssh_unthrottle(void *handle, int bufsize)
            }
        }
     }
+
+    /*
+     * Now process any SSH connection data that was stashed in our
+     * queue while we were frozen.
+     */
+    ssh_process_queued_incoming_data(ssh);
 }
 
 void ssh_send_port_open(void *channel, char *hostname, int port, char *org)