X-Git-Url: https://git.distorted.org.uk/u/mdw/putty/blobdiff_plain/2e5b14c03fe4f9da42953ff99a602e6c90a2384f..79bf227ba7ba02e32ac710621b672e2789f9ef50:/ssh.c diff --git a/ssh.c b/ssh.c index c37762ed..6c94ba49 100644 --- a/ssh.c +++ b/ssh.c @@ -322,6 +322,8 @@ static unsigned char *ssh2_mpint_fmt(Bignum b, int *len); static void ssh2_pkt_addmp(Ssh, Bignum b); static int ssh2_pkt_construct(Ssh); static void ssh2_pkt_send(Ssh); +static int do_ssh1_login(Ssh ssh, unsigned char *in, int inlen, int ispkt); +static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt); /* * Buffer management constants. There are several of these for @@ -515,6 +517,7 @@ static void ssh2_add_channel_data(struct ssh_channel *c, char *buf, int len); static void ssh_throttle_all(Ssh ssh, int enable, int bufsize); static void ssh2_set_window(struct ssh_channel *c, unsigned newwin); static int ssh_sendbuffer(void *handle); +static void ssh_do_close(Ssh ssh); struct rdpkt1_state_tag { long len, pad, biglen, to_read; @@ -570,6 +573,7 @@ struct ssh_tag { void *frontend; + int ospeed, ispeed; /* temporaries */ int term_width, term_height; tree234 *channels; /* indexed by local id */ @@ -648,12 +652,18 @@ struct ssh_tag { * potentially reconfigure port forwardings etc in mid-session. */ Config cfg; + + /* + * Used to transfer data back from async agent callbacks. + */ + void *agent_response; + int agent_response_len; }; #define logevent(s) logevent(ssh->frontend, s) /* logevent, only printf-formatted. */ -static void logeventf(Ssh ssh, char *fmt, ...) +static void logeventf(Ssh ssh, const char *fmt, ...) { va_list ap; char *buf; @@ -668,8 +678,7 @@ static void logeventf(Ssh ssh, char *fmt, ...) #define bombout(msg) \ do { \ char *text = dupprintf msg; \ - ssh->state = SSH_STATE_CLOSED; \ - if (ssh->s) { sk_close(ssh->s); ssh->s = NULL; } \ + ssh_do_close(ssh); \ logevent(text); \ connection_fatal(ssh->frontend, "%s", text); \ sfree(text); \ @@ -842,17 +851,17 @@ static int ssh1_rdpkt(Ssh ssh, unsigned char **data, int *datalen) if (ssh->cipher && detect_attack(ssh->crcda_ctx, ssh->pktin.data, st->biglen, NULL)) { bombout(("Network attack (CRC compensation) detected!")); - crReturn(0); + crStop(0); } if (ssh->cipher) ssh->cipher->decrypt(ssh->v1_cipher_ctx, ssh->pktin.data, st->biglen); - st->realcrc = crc32(ssh->pktin.data, st->biglen - 4); + st->realcrc = crc32_compute(ssh->pktin.data, st->biglen - 4); st->gotcrc = GET_32BIT(ssh->pktin.data + st->biglen - 4); if (st->gotcrc != st->realcrc) { bombout(("Incorrect CRC received on packet")); - crReturn(0); + crStop(0); } ssh->pktin.body = ssh->pktin.data + st->pad + 1; @@ -860,9 +869,12 @@ static int ssh1_rdpkt(Ssh ssh, unsigned char **data, int *datalen) if (ssh->v1_compressing) { unsigned char *decompblk; int decomplen; - zlib_decompress_block(ssh->sc_comp_ctx, - ssh->pktin.body - 1, ssh->pktin.length + 1, - &decompblk, &decomplen); + if (!zlib_decompress_block(ssh->sc_comp_ctx, + ssh->pktin.body - 1, ssh->pktin.length + 1, + &decompblk, &decomplen)) { + bombout(("Zlib decompression encountered invalid data")); + crStop(0); + } if (ssh->pktin.maxlen < st->pad + decomplen) { ssh->pktin.maxlen = st->pad + decomplen; @@ -893,7 +905,7 @@ static int ssh1_rdpkt(Ssh ssh, unsigned char **data, int *datalen) long stringlen = GET_32BIT(ssh->pktin.body); if (stringlen + 4 != ssh->pktin.length) { bombout(("Received data packet with bogus string length")); - crReturn(0); + crStop(0); } } @@ -926,7 +938,7 @@ static int ssh1_rdpkt(Ssh ssh, unsigned char **data, int *datalen) buf[nowlen + msglen] = '\0'; /* logevent(buf); (this is now done within the bombout macro) */ bombout(("Server sent disconnect message:\n\"%s\"", buf+nowlen)); - crReturn(0); + crStop(0); } crFinish(0); @@ -981,7 +993,7 @@ static int ssh2_rdpkt(Ssh ssh, unsigned char **data, int *datalen) */ if (st->len < 0 || st->pad < 0 || st->len + st->pad < 0) { bombout(("Incoming packet was garbled on decryption")); - crReturn(0); + crStop(0); } /* @@ -1030,7 +1042,7 @@ static int ssh2_rdpkt(Ssh ssh, unsigned char **data, int *datalen) && !ssh->scmac->verify(ssh->sc_mac_ctx, ssh->pktin.data, st->len + 4, st->incoming_sequence)) { bombout(("Incorrect MAC received on packet")); - crReturn(0); + crStop(0); } st->incoming_sequence++; /* whether or not we MACed */ @@ -1094,7 +1106,7 @@ static int ssh2_rdpkt(Ssh ssh, unsigned char **data, int *datalen) ssh2_disconnect_reasons[reason] : "unknown", buf+nowlen)); sfree(buf); - crReturn(0); + crStop(0); } break; case SSH2_MSG_IGNORE: @@ -1236,7 +1248,7 @@ static int s_wrpkt_prepare(Ssh ssh) for (i = 0; i < pad; i++) ssh->pktout.data[i + 4] = random_byte(); - crc = crc32(ssh->pktout.data + 4, biglen - 4); + crc = crc32_compute(ssh->pktout.data + 4, biglen - 4); PUT_32BIT(ssh->pktout.data + biglen, crc); PUT_32BIT(ssh->pktout.data, len); @@ -1769,7 +1781,8 @@ static void ssh_detect_bugs(Ssh ssh, char *vstring) (ssh->cfg.sshbug_ignore1 == AUTO && (!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, "1.2.22") || !strcmp(imp, "Cisco-1.25") || + !strcmp(imp, "OSU_1.4alpha3")))) { /* * These versions don't support SSH1_MSG_IGNORE, so we have * to use a different defence against password length @@ -1781,7 +1794,7 @@ static void ssh_detect_bugs(Ssh ssh, char *vstring) if (ssh->cfg.sshbug_plainpw1 == FORCE_ON || (ssh->cfg.sshbug_plainpw1 == AUTO && - (!strcmp(imp, "Cisco-1.25")))) { + (!strcmp(imp, "Cisco-1.25") || !strcmp(imp, "OSU_1.4alpha3")))) { /* * These versions need a plain password sent; they can't * handle having a null and a random length of data after @@ -1805,6 +1818,7 @@ static void ssh_detect_bugs(Ssh ssh, char *vstring) if (ssh->cfg.sshbug_hmac2 == FORCE_ON || (ssh->cfg.sshbug_hmac2 == AUTO && + !wc_match("* VShell", imp) && (wc_match("2.1.0*", imp) || wc_match("2.0.*", imp) || wc_match("2.2.0*", imp) || wc_match("2.3.0*", imp) || wc_match("2.1 *", imp)))) { @@ -1817,6 +1831,7 @@ static void ssh_detect_bugs(Ssh ssh, char *vstring) if (ssh->cfg.sshbug_derivekey2 == FORCE_ON || (ssh->cfg.sshbug_derivekey2 == AUTO && + !wc_match("* VShell", imp) && (wc_match("2.0.0*", imp) || wc_match("2.0.10*", imp) ))) { /* * These versions have the key-derivation bug (failing to @@ -1938,11 +1953,11 @@ static int do_ssh_init(Ssh ssh, unsigned char c) if (ssh->cfg.sshprot == 0 && !s->proto1) { bombout(("SSH protocol version 1 required by user but not provided by server")); - crReturn(0); + crStop(0); } if (ssh->cfg.sshprot == 3 && !s->proto2) { bombout(("SSH protocol version 2 required by user but not provided by server")); - crReturn(0); + crStop(0); } if (s->proto2 && (ssh->cfg.sshprot >= 2 || !s->proto1)) { @@ -2037,19 +2052,47 @@ static void ssh_gotdata(Ssh ssh, unsigned char *data, int datalen) crFinishV; } -static int ssh_closing(Plug plug, char *error_msg, int error_code, - int calling_back) +static void ssh_do_close(Ssh ssh) { - Ssh ssh = (Ssh) plug; + int i; + struct ssh_channel *c; + ssh->state = SSH_STATE_CLOSED; if (ssh->s) { sk_close(ssh->s); ssh->s = NULL; } + /* + * Now we must shut down any port and X forwardings going + * through this connection. + */ + if (ssh->channels) { + for (i = 0; NULL != (c = index234(ssh->channels, i)); i++) { + switch (c->type) { + case CHAN_X11: + x11_close(c->u.x11.s); + break; + case CHAN_SOCKDATA: + pfd_close(c->u.pfd.s); + break; + } + del234(ssh->channels, c); + if (ssh->version == 2) + bufchain_clear(&c->v.v2.outbuffer); + sfree(c); + } + } +} + +static int ssh_closing(Plug plug, const char *error_msg, int error_code, + int calling_back) +{ + Ssh ssh = (Ssh) plug; + ssh_do_close(ssh); if (error_msg) { /* A socket error has occurred. */ logevent(error_msg); - connection_fatal(ssh->frontend, error_msg); + connection_fatal(ssh->frontend, "%s", error_msg); } else { /* Otherwise, the remote side closed the connection normally. */ } @@ -2061,10 +2104,7 @@ static int ssh_receive(Plug plug, int urgent, char *data, int len) Ssh ssh = (Ssh) plug; ssh_gotdata(ssh, (unsigned char *)data, len); if (ssh->state == SSH_STATE_CLOSED) { - if (ssh->s) { - sk_close(ssh->s); - ssh->s = NULL; - } + ssh_do_close(ssh); return 0; } return 1; @@ -2087,8 +2127,8 @@ static void ssh_sent(Plug plug, int bufsize) * Also places the canonical host name into `realhost'. It must be * freed by the caller. */ -static char *connect_to_host(Ssh ssh, char *host, int port, - char **realhost, int nodelay) +static const char *connect_to_host(Ssh ssh, char *host, int port, + char **realhost, int nodelay, int keepalive) { static const struct plug_function_table fn_table = { ssh_closing, @@ -2098,7 +2138,7 @@ static char *connect_to_host(Ssh ssh, char *host, int port, }; SockAddr addr; - char *err; + const char *err; ssh->savedhost = snewn(1 + strlen(host), char); if (!ssh->savedhost) @@ -2114,8 +2154,10 @@ static char *connect_to_host(Ssh ssh, char *host, int port, */ logeventf(ssh, "Looking up host \"%s\"", host); addr = name_lookup(host, port, realhost, &ssh->cfg); - if ((err = sk_addr_error(addr)) != NULL) + if ((err = sk_addr_error(addr)) != NULL) { + sk_addr_free(addr); return err; + } /* * Open socket. @@ -2127,7 +2169,7 @@ static char *connect_to_host(Ssh ssh, char *host, int port, } ssh->fn = &fn_table; ssh->s = new_connection(addr, *realhost, port, - 0, 1, nodelay, (Plug) ssh, &ssh->cfg); + 0, 1, nodelay, keepalive, (Plug) ssh, &ssh->cfg); if ((err = sk_socket_error(ssh->s)) != NULL) { ssh->s = NULL; return err; @@ -2180,7 +2222,7 @@ static void ssh_throttle_all(Ssh ssh, int enable, int bufsize) /* Agent channels require no buffer management. */ break; case CHAN_SOCKDATA: - pfd_override_throttle(c->u.x11.s, enable); + pfd_override_throttle(c->u.pfd.s, enable); break; } } @@ -2258,6 +2300,44 @@ static int process_userpass_input(Ssh ssh, unsigned char *in, int inlen) return 0; } +static void ssh_agent_callback(void *sshv, void *reply, int replylen) +{ + Ssh ssh = (Ssh) sshv; + + ssh->agent_response = reply; + ssh->agent_response_len = replylen; + + if (ssh->version == 1) + do_ssh1_login(ssh, NULL, -1, 0); + else + do_ssh2_authconn(ssh, NULL, -1, 0); +} + +static void ssh_agentf_callback(void *cv, void *reply, int replylen) +{ + struct ssh_channel *c = (struct ssh_channel *)cv; + Ssh ssh = c->ssh; + void *sentreply = reply; + + if (!sentreply) { + /* Fake SSH_AGENT_FAILURE. */ + sentreply = "\0\0\0\1\5"; + replylen = 5; + } + if (ssh->version == 2) { + ssh2_add_channel_data(c, sentreply, replylen); + ssh2_try_send(c); + } else { + send_packet(ssh, SSH1_MSG_CHANNEL_DATA, + PKT_INT, c->remoteid, + PKT_INT, replylen, + PKT_DATA, sentreply, replylen, + PKT_END); + } + if (reply) + sfree(reply); +} + /* * Handle the key exchange and user authentication phases. */ @@ -2301,7 +2381,7 @@ static int do_ssh1_login(Ssh ssh, unsigned char *in, int inlen, int ispkt) if (ssh->pktin.type != SSH1_SMSG_PUBLIC_KEY) { bombout(("Public key packet not received")); - crReturn(0); + crStop(0); } logevent("Received public keys"); @@ -2415,7 +2495,7 @@ static int do_ssh1_login(Ssh ssh, unsigned char *in, int inlen, int ispkt) else /* shouldn't happen */ bombout(("No supported ciphers found")); - crReturn(0); + crStop(0); } /* Warn about chosen cipher if necessary. */ @@ -2456,11 +2536,27 @@ static int do_ssh1_login(Ssh ssh, unsigned char *in, int inlen, int ispkt) ssh->crcda_ctx = crcda_make_context(); logevent("Installing CRC compensation attack detector"); + if (servkey.modulus) { + sfree(servkey.modulus); + servkey.modulus = NULL; + } + if (servkey.exponent) { + sfree(servkey.exponent); + servkey.exponent = NULL; + } + if (hostkey.modulus) { + sfree(hostkey.modulus); + hostkey.modulus = NULL; + } + if (hostkey.exponent) { + sfree(hostkey.exponent); + hostkey.exponent = NULL; + } crWaitUntil(ispkt); if (ssh->pktin.type != SSH1_SMSG_SUCCESS) { bombout(("Encryption not successfully enabled")); - crReturn(0); + crStop(0); } logevent("Successfully started encryption"); @@ -2477,7 +2573,7 @@ static int do_ssh1_login(Ssh ssh, unsigned char *in, int inlen, int ispkt) */ logevent("No username provided. Abandoning session."); ssh_closing((Plug)ssh, NULL, 0, 0); - crReturn(1); + crStop(1); } } else { int ret; /* need not be kept over crReturn */ @@ -2523,7 +2619,7 @@ static int do_ssh1_login(Ssh ssh, unsigned char *in, int inlen, int ispkt) /* Load the public half of ssh->cfg.keyfile so we notice if it's in Pageant */ if (!filename_is_null(ssh->cfg.keyfile)) { if (!rsakey_pubblob(&ssh->cfg.keyfile, - &s->publickey_blob, &s->publickey_bloblen)) + &s->publickey_blob, &s->publickey_bloblen, NULL)) s->publickey_blob = NULL; } else s->publickey_blob = NULL; @@ -2544,7 +2640,19 @@ static int do_ssh1_login(Ssh ssh, unsigned char *in, int inlen, int ispkt) /* Request the keys held by the agent. */ PUT_32BIT(s->request, 1); s->request[4] = SSH1_AGENTC_REQUEST_RSA_IDENTITIES; - agent_query(s->request, 5, &r, &s->responselen); + if (!agent_query(s->request, 5, &r, &s->responselen, + ssh_agent_callback, ssh)) { + do { + crReturn(0); + if (ispkt) { + bombout(("Unexpected data from server while waiting" + " for agent response")); + crStop(0); + } + } while (ispkt || inlen > 0); + r = ssh->agent_response; + s->responselen = ssh->agent_response_len; + } s->response = (unsigned char *) r; if (s->response && s->responselen >= 5 && s->response[4] == SSH1_AGENT_RSA_IDENTITIES_ANSWER) { @@ -2606,9 +2714,23 @@ static int do_ssh1_login(Ssh ssh, unsigned char *in, int inlen, int ispkt) memcpy(q, s->session_id, 16); q += 16; PUT_32BIT(q, 1); /* response format */ - agent_query(agentreq, len + 4, &vret, &retlen); + if (!agent_query(agentreq, len + 4, &vret, &retlen, + ssh_agent_callback, ssh)) { + sfree(agentreq); + do { + crReturn(0); + if (ispkt) { + bombout(("Unexpected data from server" + " while waiting for agent" + " response")); + crStop(0); + } + } while (ispkt || inlen > 0); + vret = ssh->agent_response; + retlen = ssh->agent_response_len; + } else + sfree(agentreq); ret = vret; - sfree(agentreq); if (ret) { if (ret[4] == SSH1_AGENT_RSA_RESPONSE) { logevent("Sending Pageant's response"); @@ -2646,6 +2768,7 @@ static int do_ssh1_login(Ssh ssh, unsigned char *in, int inlen, int ispkt) if (s->authed) break; } + sfree(s->response); } if (s->authed) break; @@ -2755,7 +2878,7 @@ static int do_ssh1_login(Ssh ssh, unsigned char *in, int inlen, int ispkt) logevent("Unable to authenticate"); connection_fatal(ssh->frontend, "Unable to authenticate"); ssh_closing((Plug)ssh, NULL, 0, 0); - crReturn(1); + crStop(1); } } else { /* Prompt may have come from server. We've munged it a bit, so @@ -2783,11 +2906,15 @@ static int do_ssh1_login(Ssh ssh, unsigned char *in, int inlen, int ispkt) s->tried_publickey = 1; { - int ret = loadrsakey(&ssh->cfg.keyfile, &s->key, s->password); + const char *error = NULL; + int ret = loadrsakey(&ssh->cfg.keyfile, &s->key, s->password, + &error); if (ret == 0) { c_write_str(ssh, "Couldn't load private key from "); c_write_str(ssh, filename_to_str(&ssh->cfg.keyfile)); - c_write_str(ssh, ".\r\n"); + c_write_str(ssh, " ("); + c_write_str(ssh, error); + c_write_str(ssh, ").\r\n"); continue; /* go and try password */ } if (ret == -1) { @@ -2810,7 +2937,7 @@ static int do_ssh1_login(Ssh ssh, unsigned char *in, int inlen, int ispkt) } if (ssh->pktin.type != SSH1_SMSG_AUTH_RSA_CHALLENGE) { bombout(("Bizarre response to offer of public key")); - crReturn(0); + crStop(0); } { @@ -2846,7 +2973,7 @@ static int do_ssh1_login(Ssh ssh, unsigned char *in, int inlen, int ispkt) continue; /* go and try password */ } else if (ssh->pktin.type != SSH1_SMSG_SUCCESS) { bombout(("Bizarre response to RSA authentication response")); - crReturn(0); + crStop(0); } break; /* we're through! */ @@ -2928,6 +3055,7 @@ static int do_ssh1_login(Ssh ssh, unsigned char *in, int inlen, int ispkt) } logevent("Sending password with camouflage packets"); ssh_pkt_defersend(ssh); + sfree(randomstr); } else if (!(ssh->remote_bugs & BUG_NEEDS_SSH1_PLAIN_PASSWORD)) { /* @@ -2979,7 +3107,7 @@ static int do_ssh1_login(Ssh ssh, unsigned char *in, int inlen, int ispkt) logevent("Authentication refused"); } else if (ssh->pktin.type != SSH1_SMSG_SUCCESS) { bombout(("Strange packet received, type %d", ssh->pktin.type)); - crReturn(0); + crStop(0); } } @@ -2992,6 +3120,11 @@ void sshfwd_close(struct ssh_channel *c) { Ssh ssh = c->ssh; + if (ssh->state != SSH_STATE_SESSION) { + assert(ssh->state == SSH_STATE_CLOSED); + return; + } + if (c && !c->closes) { /* * If the channel's remoteid is -1, we have sent @@ -3026,6 +3159,11 @@ int sshfwd_write(struct ssh_channel *c, char *buf, int len) { Ssh ssh = c->ssh; + if (ssh->state != SSH_STATE_SESSION) { + assert(ssh->state == SSH_STATE_CLOSED); + return 0; + } + if (ssh->version == 1) { send_packet(ssh, SSH1_MSG_CHANNEL_DATA, PKT_INT, c->remoteid, @@ -3048,6 +3186,11 @@ void sshfwd_unthrottle(struct ssh_channel *c, int bufsize) { Ssh ssh = c->ssh; + if (ssh->state != SSH_STATE_SESSION) { + assert(ssh->state == SSH_STATE_CLOSED); + return; + } + if (ssh->version == 1) { if (c->v.v1.throttling && bufsize < SSH1_BUFFER_LIMIT) { c->v.v1.throttling = 0; @@ -3079,7 +3222,7 @@ static void ssh1_protocol(Ssh ssh, unsigned char *in, int inlen, int ispkt) if (ssh->pktin.type != SSH1_SMSG_SUCCESS && ssh->pktin.type != SSH1_SMSG_FAILURE) { bombout(("Protocol confusion")); - crReturnV; + crStopV; } else if (ssh->pktin.type == SSH1_SMSG_FAILURE) { logevent("Agent forwarding refused"); } else { @@ -3109,7 +3252,7 @@ static void ssh1_protocol(Ssh ssh, unsigned char *in, int inlen, int ispkt) if (ssh->pktin.type != SSH1_SMSG_SUCCESS && ssh->pktin.type != SSH1_SMSG_FAILURE) { bombout(("Protocol confusion")); - crReturnV; + crStopV; } else if (ssh->pktin.type == SSH1_SMSG_FAILURE) { logevent("X11 forwarding refused"); } else { @@ -3177,6 +3320,8 @@ static void ssh1_protocol(Ssh ssh, unsigned char *in, int inlen, int ispkt) } } else { while (*ssh->portfwd_strptr) ssh->portfwd_strptr++; + dport = dserv = -1; + ssh->portfwd_strptr++; /* eat the NUL and move to next one */ } sport = atoi(sports); sserv = 0; @@ -3244,7 +3389,7 @@ static void ssh1_protocol(Ssh ssh, unsigned char *in, int inlen, int ispkt) if (ssh->pktin.type != SSH1_SMSG_SUCCESS && ssh->pktin.type != SSH1_SMSG_FAILURE) { bombout(("Protocol confusion")); - crReturnV; + crStopV; } else if (ssh->pktin.type == SSH1_SMSG_FAILURE) { c_write_str(ssh, "Server refused port" " forwarding\r\n"); @@ -3257,11 +3402,19 @@ static void ssh1_protocol(Ssh ssh, unsigned char *in, int inlen, int ispkt) } if (!ssh->cfg.nopty) { + /* Unpick the terminal-speed string. */ + /* XXX perhaps we should allow no speeds to be sent. */ + ssh->ospeed = 38400; ssh->ispeed = 38400; /* last-resort defaults */ + sscanf(ssh->cfg.termspeed, "%d,%d", &ssh->ospeed, &ssh->ispeed); + /* Send the pty request. */ send_packet(ssh, SSH1_CMSG_REQUEST_PTY, PKT_STR, ssh->cfg.termtype, PKT_INT, ssh->term_height, PKT_INT, ssh->term_width, - PKT_INT, 0, PKT_INT, 0, PKT_CHAR, 0, PKT_END); + PKT_INT, 0, PKT_INT, 0, /* width,height in pixels */ + PKT_CHAR, 192, PKT_INT, ssh->ispeed, /* TTY_OP_ISPEED */ + PKT_CHAR, 193, PKT_INT, ssh->ospeed, /* TTY_OP_OSPEED */ + PKT_CHAR, 0, PKT_END); ssh->state = SSH_STATE_INTERMED; do { crReturnV; @@ -3269,12 +3422,13 @@ static void ssh1_protocol(Ssh ssh, unsigned char *in, int inlen, int ispkt) if (ssh->pktin.type != SSH1_SMSG_SUCCESS && ssh->pktin.type != SSH1_SMSG_FAILURE) { bombout(("Protocol confusion")); - crReturnV; + crStopV; } else if (ssh->pktin.type == SSH1_SMSG_FAILURE) { c_write_str(ssh, "Server refused to allocate pty\r\n"); ssh->editing = ssh->echoing = 1; } - logevent("Allocated pty"); + logeventf(ssh, "Allocated pty (ospeed %dbps, ispeed %dbps)", + ssh->ospeed, ssh->ispeed); } else { ssh->editing = ssh->echoing = 1; } @@ -3287,7 +3441,7 @@ static void ssh1_protocol(Ssh ssh, unsigned char *in, int inlen, int ispkt) if (ssh->pktin.type != SSH1_SMSG_SUCCESS && ssh->pktin.type != SSH1_SMSG_FAILURE) { bombout(("Protocol confusion")); - crReturnV; + crStopV; } else if (ssh->pktin.type == SSH1_SMSG_FAILURE) { c_write_str(ssh, "Server refused to compress\r\n"); } @@ -3347,7 +3501,7 @@ static void ssh1_protocol(Ssh ssh, unsigned char *in, int inlen, int ispkt) } else if (ssh->pktin.type == SSH1_MSG_DISCONNECT) { ssh_closing((Plug)ssh, NULL, 0, 0); logevent("Received disconnect request"); - crReturnV; + crStopV; } else if (ssh->pktin.type == SSH1_SMSG_X11_OPEN) { /* Remote side is trying to open a channel to talk to our * X-Server. Give them back a local channel number. */ @@ -3415,7 +3569,8 @@ static void ssh1_protocol(Ssh ssh, unsigned char *in, int inlen, int ispkt) struct ssh_rportfwd pf; int hostsize, port; char host[256], buf[1024]; - char *p, *h, *e; + char *p, *h; + const char *e; c = snew(struct ssh_channel); c->ssh = ssh; @@ -3541,6 +3696,7 @@ static void ssh1_protocol(Ssh ssh, unsigned char *in, int inlen, int ispkt) ssh->pktin.type == SSH1_MSG_CHANNEL_CLOSE ? "" : "_CONFIRMATION", c ? "half-open" : "nonexistent", i)); + crStopV; } } else if (ssh->pktin.type == SSH1_MSG_CHANNEL_DATA) { /* Data sent down one of our channels. */ @@ -3550,7 +3706,7 @@ static void ssh1_protocol(Ssh ssh, unsigned char *in, int inlen, int ispkt) struct ssh_channel *c; c = find234(ssh->channels, &i, ssh_channelfind); if (c) { - int bufsize; + int bufsize = 0; switch (c->type) { case CHAN_X11: bufsize = x11_send(c->u.x11.s, (char *)p, len); @@ -3587,25 +3743,13 @@ static void ssh1_protocol(Ssh ssh, unsigned char *in, int inlen, int ispkt) c->u.a.lensofar += l; } if (c->u.a.lensofar == c->u.a.totallen) { - void *reply, *sentreply; + void *reply; int replylen; - agent_query(c->u.a.message, - c->u.a.totallen, &reply, - &replylen); - if (reply) - sentreply = reply; - else { - /* Fake SSH_AGENT_FAILURE. */ - sentreply = "\0\0\0\1\5"; - replylen = 5; - } - send_packet(ssh, SSH1_MSG_CHANNEL_DATA, - PKT_INT, c->remoteid, - PKT_INT, replylen, - PKT_DATA, sentreply, replylen, - PKT_END); - if (reply) - sfree(reply); + 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; } @@ -3638,10 +3782,10 @@ static void ssh1_protocol(Ssh ssh, unsigned char *in, int inlen, int ispkt) * we've sent EXIT_CONFIRMATION. */ ssh_closing((Plug)ssh, NULL, 0, 0); - crReturnV; + crStopV; } else { bombout(("Strange packet received: type %d", ssh->pktin.type)); - crReturnV; + crStopV; } } else { while (inlen > 0) { @@ -3914,7 +4058,7 @@ static int do_ssh2_transport(Ssh ssh, unsigned char *in, int inlen, int ispkt) if (ssh->pktin.type != SSH2_MSG_KEXINIT) { bombout(("expected key exchange packet from server")); - crReturn(0); + crStop(0); } ssh->kex = NULL; ssh->hostkey = NULL; @@ -3965,7 +4109,7 @@ static int do_ssh2_transport(Ssh ssh, unsigned char *in, int inlen, int ispkt) if (!s->cscipher_tobe) { bombout(("Couldn't agree a client-to-server cipher (available: %s)", str ? str : "(null)")); - crReturn(0); + crStop(0); } ssh2_pkt_getstring(ssh, &str, &len); /* server->client cipher */ @@ -3991,7 +4135,7 @@ static int do_ssh2_transport(Ssh ssh, unsigned char *in, int inlen, int ispkt) if (!s->sccipher_tobe) { bombout(("Couldn't agree a server-to-client cipher (available: %s)", str ? str : "(null)")); - crReturn(0); + crStop(0); } ssh2_pkt_getstring(ssh, &str, &len); /* client->server mac */ @@ -4064,7 +4208,7 @@ static int do_ssh2_transport(Ssh ssh, unsigned char *in, int inlen, int ispkt) crWaitUntil(ispkt); if (ssh->pktin.type != SSH2_MSG_KEX_DH_GEX_GROUP) { bombout(("expected key exchange group packet from server")); - crReturn(0); + crStop(0); } s->p = ssh2_pkt_getmp(ssh); s->g = ssh2_pkt_getmp(ssh); @@ -4090,7 +4234,7 @@ static int do_ssh2_transport(Ssh ssh, unsigned char *in, int inlen, int ispkt) crWaitUntil(ispkt); if (ssh->pktin.type != s->kex_reply_value) { bombout(("expected key exchange reply packet from server")); - crReturn(0); + crStop(0); } ssh2_pkt_getstring(ssh, &s->hostkeydata, &s->hostkeylen); s->f = ssh2_pkt_getmp(ssh); @@ -4122,7 +4266,7 @@ static int do_ssh2_transport(Ssh ssh, unsigned char *in, int inlen, int ispkt) !ssh->hostkey->verifysig(s->hkey, s->sigdata, s->siglen, (char *)s->exchange_hash, 20)) { bombout(("Server's host key did not match the signature supplied")); - crReturn(0); + crStop(0); } /* @@ -4154,7 +4298,7 @@ static int do_ssh2_transport(Ssh ssh, unsigned char *in, int inlen, int ispkt) crWaitUntil(ispkt); if (ssh->pktin.type != SSH2_MSG_NEWKEYS) { bombout(("expected new-keys packet from server")); - crReturn(0); + crStop(0); } /* @@ -4222,6 +4366,12 @@ static int do_ssh2_transport(Ssh ssh, unsigned char *in, int inlen, int ispkt) if (ssh->sccomp->text_name) logeventf(ssh, "Initialised %s decompression", ssh->sccomp->text_name); + freebn(s->f); + freebn(s->K); + if (ssh->kex == &ssh_diffiehellman_gex) { + freebn(s->g); + freebn(s->p); + } /* * If this is the first key exchange phase, we must pass the @@ -4369,7 +4519,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt) crWaitUntilV(ispkt); if (ssh->pktin.type != SSH2_MSG_SERVICE_ACCEPT) { bombout(("Server refused user authentication protocol")); - crReturnV; + crStopV; } /* @@ -4418,7 +4568,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt) */ logevent("No username provided. Abandoning session."); ssh_closing((Plug)ssh, NULL, 0, 0); - crReturnV; + crStopV; } } else { int ret; /* need not be saved across crReturn */ @@ -4475,7 +4625,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt) if (keytype == SSH_KEYTYPE_SSH2) { s->publickey_blob = ssh2_userkey_loadpub(&ssh->cfg.keyfile, NULL, - &s->publickey_bloblen); + &s->publickey_bloblen, NULL); } else { char *msgbuf; logeventf(ssh, "Unable to use this key file (%s)", @@ -4535,7 +4685,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt) } else if (ssh->pktin.type != SSH2_MSG_USERAUTH_FAILURE) { bombout(("Strange packet received during authentication: type %d", ssh->pktin.type)); - crReturnV; + crStopV; } s->gotit = FALSE; @@ -4604,6 +4754,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt) s->method = 0; ssh->pkt_ctx &= ~SSH2_PKTCTX_AUTH_MASK; + s->need_pw = FALSE; /* * Most password/passphrase prompts will be @@ -4631,7 +4782,19 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt) /* Request the keys held by the agent. */ PUT_32BIT(s->request, 1); s->request[4] = SSH2_AGENTC_REQUEST_IDENTITIES; - agent_query(s->request, 5, &r, &s->responselen); + if (!agent_query(s->request, 5, &r, &s->responselen, + ssh_agent_callback, ssh)) { + do { + crReturnV; + if (ispkt) { + bombout(("Unexpected data from server while" + " waiting for agent response")); + crStopV; + } + } while (ispkt || inlen > 0); + r = ssh->agent_response; + s->responselen = ssh->agent_response_len; + } s->response = (unsigned char *) r; if (s->response && s->responselen >= 5 && s->response[4] == SSH2_AGENT_IDENTITIES_ANSWER) { @@ -4735,7 +4898,21 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt) s->q += ssh->pktout.length - 5; /* And finally the (zero) flags word. */ PUT_32BIT(s->q, 0); - agent_query(s->agentreq, s->len + 4, &vret, &s->retlen); + if (!agent_query(s->agentreq, s->len + 4, + &vret, &s->retlen, + ssh_agent_callback, ssh)) { + do { + crReturnV; + if (ispkt) { + bombout(("Unexpected data from server" + " while waiting for agent" + " response")); + crStopV; + } + } while (ispkt || inlen > 0); + vret = ssh->agent_response; + s->retlen = ssh->agent_response_len; + } s->ret = vret; sfree(s->agentreq); if (s->ret) { @@ -4757,6 +4934,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt) if (s->authed) continue; } + sfree(s->response); } if (!s->method && s->can_pubkey && s->publickey_blob @@ -4779,7 +4957,8 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt) pub_blob = (unsigned char *)ssh2_userkey_loadpub(&ssh->cfg.keyfile, &algorithm, - &pub_blob_len); + &pub_blob_len, + NULL); if (pub_blob) { ssh2_pkt_init(ssh, SSH2_MSG_USERAUTH_REQUEST); ssh2_pkt_addstring(ssh, s->username); @@ -4813,9 +4992,11 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt) } else { s->need_pw = FALSE; } - c_write_str(ssh, "Authenticating with public key \""); - c_write_str(ssh, comment); - c_write_str(ssh, "\"\r\n"); + if (flags & FLAG_VERBOSE) { + c_write_str(ssh, "Authenticating with public key \""); + c_write_str(ssh, comment); + c_write_str(ssh, "\"\r\n"); + } s->method = AUTH_PUBLICKEY_FILE; } } @@ -4932,7 +5113,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt) connection_fatal(ssh->frontend, "Unable to authenticate"); ssh_closing((Plug)ssh, NULL, 0, 0); - crReturnV; + crStopV; } } else { int ret; /* need not be saved across crReturn */ @@ -4956,14 +5137,18 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt) * We have our passphrase. Now try the actual authentication. */ struct ssh2_userkey *key; + const char *error = NULL; - key = ssh2_load_userkey(&ssh->cfg.keyfile, s->password); + key = ssh2_load_userkey(&ssh->cfg.keyfile, s->password, + &error); if (key == SSH2_WRONG_PASSPHRASE || key == NULL) { if (key == SSH2_WRONG_PASSPHRASE) { c_write_str(ssh, "Wrong passphrase\r\n"); s->tried_pubkey_config = FALSE; } else { - c_write_str(ssh, "Unable to load private key\r\n"); + c_write_str(ssh, "Unable to load private key ("); + c_write_str(ssh, error); + c_write_str(ssh, ")\r\n"); s->tried_pubkey_config = TRUE; } /* Send a spurious AUTH_NONE to return to the top. */ @@ -5025,6 +5210,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt) ssh2_pkt_send(ssh); s->type = AUTH_TYPE_PUBLICKEY; + key->alg->freekey(key->data); } } else if (s->method == AUTH_PASSWORD) { /* @@ -5121,7 +5307,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt) ssh2_pkt_addstring(ssh, "en"); /* language tag */ ssh2_pkt_send(ssh); ssh_closing((Plug)ssh, NULL, 0, 0); - crReturnV; + crStopV; } } } while (!s->we_are_in); @@ -5149,12 +5335,12 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt) crWaitUntilV(ispkt); if (ssh->pktin.type != SSH2_MSG_CHANNEL_OPEN_CONFIRMATION) { bombout(("Server refused to open a session")); - crReturnV; + crStopV; /* FIXME: error data comes back in FAILURE packet */ } if (ssh2_pkt_getuint32(ssh) != ssh->mainchan->localid) { bombout(("Server's channel confirmation cited wrong channel")); - crReturnV; + crStopV; } ssh->mainchan->remoteid = ssh2_pkt_getuint32(ssh); ssh->mainchan->type = CHAN_MAINSESSION; @@ -5200,7 +5386,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt) if (ssh->pktin.type != SSH2_MSG_CHANNEL_FAILURE) { bombout(("Unexpected response to X11 forwarding request:" " packet type %d", ssh->pktin.type)); - crReturnV; + crStopV; } logevent("X11 forwarding refused"); } else { @@ -5271,6 +5457,8 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt) } } else { while (*ssh->portfwd_strptr) ssh->portfwd_strptr++; + dport = dserv = -1; + ssh->portfwd_strptr++; /* eat the NUL and move to next one */ } sport = atoi(sports); sserv = 0; @@ -5355,7 +5543,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt) bombout(("Unexpected response to port " "forwarding request: packet type %d", ssh->pktin.type)); - crReturnV; + crStopV; } logevent("Server refused this port forwarding"); } else { @@ -5394,7 +5582,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt) if (ssh->pktin.type != SSH2_MSG_CHANNEL_FAILURE) { bombout(("Unexpected response to agent forwarding request:" " packet type %d", ssh->pktin.type)); - crReturnV; + crStopV; } logevent("Agent forwarding refused"); } else { @@ -5407,6 +5595,11 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt) * Now allocate a pty for the session. */ if (!ssh->cfg.nopty) { + /* Unpick the terminal-speed string. */ + /* XXX perhaps we should allow no speeds to be sent. */ + ssh->ospeed = 38400; ssh->ispeed = 38400; /* last-resort defaults */ + sscanf(ssh->cfg.termspeed, "%d,%d", &ssh->ospeed, &ssh->ispeed); + /* Build the pty request. */ ssh2_pkt_init(ssh, SSH2_MSG_CHANNEL_REQUEST); ssh2_pkt_adduint32(ssh, ssh->mainchan->remoteid); /* recipient channel */ ssh2_pkt_addstring(ssh, "pty-req"); @@ -5417,7 +5610,11 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt) ssh2_pkt_adduint32(ssh, 0); /* pixel width */ ssh2_pkt_adduint32(ssh, 0); /* pixel height */ ssh2_pkt_addstring_start(ssh); - ssh2_pkt_addstring_data(ssh, "\0", 1); /* TTY_OP_END, no special options */ + ssh2_pkt_addbyte(ssh, 128); /* TTY_OP_ISPEED */ + ssh2_pkt_adduint32(ssh, ssh->ispeed); + ssh2_pkt_addbyte(ssh, 129); /* TTY_OP_OSPEED */ + ssh2_pkt_adduint32(ssh, ssh->ospeed); + ssh2_pkt_addstring_data(ssh, "\0", 1); /* TTY_OP_END */ ssh2_pkt_send(ssh); ssh->state = SSH_STATE_INTERMED; @@ -5437,12 +5634,13 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt) if (ssh->pktin.type != SSH2_MSG_CHANNEL_FAILURE) { bombout(("Unexpected response to pty request:" " packet type %d", ssh->pktin.type)); - crReturnV; + crStopV; } c_write_str(ssh, "Server refused to allocate pty\r\n"); ssh->editing = ssh->echoing = 1; } else { - logevent("Allocated pty"); + logeventf(ssh, "Allocated pty (ospeed %dbps, ispeed %dbps)", + ssh->ospeed, ssh->ispeed); } } else { ssh->editing = ssh->echoing = 1; @@ -5495,7 +5693,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt) if (ssh->pktin.type != SSH2_MSG_CHANNEL_FAILURE) { bombout(("Unexpected response to shell/command request:" " packet type %d", ssh->pktin.type)); - crReturnV; + crStopV; } /* * We failed to start the command. If this is the @@ -5509,7 +5707,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt) continue; } bombout(("Server refused to start a shell/command")); - crReturnV; + crStopV; } else { logevent("Started a shell/command"); } @@ -5546,7 +5744,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt) continue; /* extended but not stderr */ ssh2_pkt_getstring(ssh, &data, &length); if (data) { - int bufsize; + int bufsize = 0; c->v.v2.locwindow -= length; switch (c->type) { case CHAN_MAINSESSION: @@ -5589,22 +5787,13 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt) c->u.a.lensofar += l; } if (c->u.a.lensofar == c->u.a.totallen) { - void *reply, *sentreply; + void *reply; int replylen; - agent_query(c->u.a.message, - c->u.a.totallen, &reply, - &replylen); - if (reply) - sentreply = reply; - else { - /* Fake SSH_AGENT_FAILURE. */ - sentreply = "\0\0\0\1\5"; - replylen = 5; - } - ssh2_add_channel_data(c, sentreply, replylen); - s->try_send = TRUE; - if (reply) - sfree(reply); + 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; } @@ -5648,6 +5837,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt) if (!c || ((int)c->remoteid) == -1) { bombout(("Received CHANNEL_CLOSE for %s channel %d\n", c ? "half-open" : "nonexistent", i)); + crStopV; } /* Do pre-close processing on the channel. */ switch (c->type) { @@ -5700,7 +5890,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt) ssh2_pkt_send(ssh); #endif ssh_closing((Plug)ssh, NULL, 0, 0); - crReturnV; + crStopV; } continue; /* remote sends close; ignore (FIXME) */ } else if (ssh->pktin.type == SSH2_MSG_CHANNEL_WINDOW_ADJUST) { @@ -5778,7 +5968,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt) ssh2_pkt_send(ssh); connection_fatal(ssh->frontend, "%s", buf); ssh_closing((Plug)ssh, NULL, 0, 0); - crReturnV; + crStopV; } /* @@ -5847,10 +6037,12 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt) pktsize = ssh2_pkt_getuint32(ssh); if (typelen == 3 && !memcmp(type, "x11", 3)) { - char *addrstr = snewn(peeraddrlen+1, char); + char *addrstr; + + ssh2_pkt_getstring(ssh, &peeraddr, &peeraddrlen); + addrstr = snewn(peeraddrlen+1, char); memcpy(addrstr, peeraddr, peeraddrlen); peeraddr[peeraddrlen] = '\0'; - ssh2_pkt_getstring(ssh, &peeraddr, &peeraddrlen); peerport = ssh2_pkt_getuint32(ssh); if (!ssh->X11_fwd_enabled) @@ -5877,8 +6069,10 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt) if (realpf == NULL) { error = "Remote port is not recognised"; } else { - char *e = pfd_newconnect(&c->u.pfd.s, realpf->dhost, - realpf->dport, c, &ssh->cfg); + const char *e = pfd_newconnect(&c->u.pfd.s, + realpf->dhost, + realpf->dport, c, + &ssh->cfg); logeventf(ssh, "Received remote port open request" " for %s:%d", realpf->dhost, realpf->dport); if (e != NULL) { @@ -5927,7 +6121,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen, int ispkt) } } else { bombout(("Strange packet received: type %d", ssh->pktin.type)); - crReturnV; + crStopV; } } else { /* @@ -5987,11 +6181,12 @@ static void ssh2_protocol(Ssh ssh, unsigned char *in, int inlen, int ispkt) * * Returns an error message, or NULL on success. */ -static char *ssh_init(void *frontend_handle, void **backend_handle, - Config *cfg, - char *host, int port, char **realhost, int nodelay) +static const char *ssh_init(void *frontend_handle, void **backend_handle, + Config *cfg, + char *host, int port, char **realhost, int nodelay, + int keepalive) { - char *p; + const char *p; Ssh ssh; ssh = snew(struct ssh_tag); @@ -6073,7 +6268,7 @@ static char *ssh_init(void *frontend_handle, void **backend_handle, ssh->protocol = NULL; - p = connect_to_host(ssh, host, port, realhost, nodelay); + p = connect_to_host(ssh, host, port, realhost, nodelay, keepalive); if (p != NULL) return p; @@ -6096,10 +6291,18 @@ static void ssh_free(void *handle) ssh->csmac->free_context(ssh->cs_mac_ctx); if (ssh->sc_mac_ctx) ssh->scmac->free_context(ssh->sc_mac_ctx); - if (ssh->cs_comp_ctx) - ssh->cscomp->compress_cleanup(ssh->cs_comp_ctx); - if (ssh->sc_comp_ctx) - ssh->sccomp->compress_cleanup(ssh->sc_comp_ctx); + if (ssh->cs_comp_ctx) { + if (ssh->cscomp) + ssh->cscomp->compress_cleanup(ssh->cs_comp_ctx); + else + zlib_compress_cleanup(ssh->cs_comp_ctx); + } + if (ssh->sc_comp_ctx) { + if (ssh->sccomp) + ssh->sccomp->decompress_cleanup(ssh->sc_comp_ctx); + else + zlib_decompress_cleanup(ssh->sc_comp_ctx); + } if (ssh->kex_ctx) dh_cleanup(ssh->kex_ctx); sfree(ssh->savedhost); @@ -6133,9 +6336,24 @@ static void ssh_free(void *handle) sfree(ssh->do_ssh1_login_state); sfree(ssh->do_ssh2_transport_state); sfree(ssh->do_ssh2_authconn_state); - + if (ssh->pktout.data) { + sfree(ssh->pktout.data); + ssh->pktout.data = NULL; + } + if (ssh->pktin.data) { + sfree(ssh->pktin.data); + ssh->pktin.data = NULL; + } + if (ssh->crcda_ctx) { + crcda_free_context(ssh->crcda_ctx); + ssh->crcda_ctx = NULL; + } + if (ssh->logctx) { + log_free(ssh->logctx); + ssh->logctx = NULL; + } if (ssh->s) - sk_close(ssh->s); + ssh_do_close(ssh); sfree(ssh); }