X-Git-Url: https://git.distorted.org.uk/~mdw/sgt/putty/blobdiff_plain/b61f81bc4c102d06f13fd68e4a73ab8fdfdb3cf5..6f3370a03ed6393c049a13b78d2188135624beea:/ssh.c diff --git a/ssh.c b/ssh.c index aabbcc4a..ef503bf5 100644 --- a/ssh.c +++ b/ssh.c @@ -558,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 }; /* @@ -4250,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; @@ -5741,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 */ @@ -6551,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; /* @@ -6563,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 @@ -6999,7 +7042,7 @@ static void ssh2_msg_channel_close(Ssh ssh, struct Packet *pktin) /* * Send outgoing EOF. */ - sshfwd_write_eof(ssh->mainchan); + sshfwd_write_eof(c); } /* @@ -8524,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. @@ -9993,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)