X-Git-Url: https://git.distorted.org.uk/u/mdw/putty/blobdiff_plain/df85f78b7d1ccff40d78febeab9c350ea910e27f..cbe2d68fd7c7c7bac692b3a2d200a5d2429ab201:/ssh.c diff --git a/ssh.c b/ssh.c index 925c5b5e..337cfa8b 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; @@ -648,12 +651,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 +677,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,7 +850,7 @@ 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) @@ -852,7 +860,7 @@ static int ssh1_rdpkt(Ssh ssh, unsigned char **data, int *datalen) 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; @@ -893,7 +901,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 +934,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 +989,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 +1038,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 +1102,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: @@ -1938,11 +1946,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 +2045,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 +2097,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 +2120,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) { static const struct plug_function_table fn_table = { ssh_closing, @@ -2098,7 +2131,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) @@ -2180,7 +2213,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 +2291,44 @@ static int process_userpass_input(Ssh ssh, unsigned char *in, int inlen) return 0; } +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); +} + +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 +2372,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 +2486,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. */ @@ -2460,7 +2531,7 @@ static int do_ssh1_login(Ssh ssh, unsigned char *in, int inlen, int ispkt) if (ssh->pktin.type != SSH1_SMSG_SUCCESS) { bombout(("Encryption not successfully enabled")); - crReturn(0); + crStop(0); } logevent("Successfully started encryption"); @@ -2477,7 +2548,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 */ @@ -2544,7 +2615,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 +2689,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"); @@ -2755,7 +2852,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 @@ -2810,7 +2907,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 +2943,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! */ @@ -2979,7 +3076,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 +3089,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 +3128,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 +3155,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 +3191,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 +3221,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 +3289,7 @@ static void ssh1_protocol(Ssh ssh, unsigned char *in, int inlen, int ispkt) } } else { while (*ssh->portfwd_strptr) ssh->portfwd_strptr++; + dport = dserv = -1; } sport = atoi(sports); sserv = 0; @@ -3244,7 +3357,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"); @@ -3269,7 +3382,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 allocate pty\r\n"); ssh->editing = ssh->echoing = 1; @@ -3287,7 +3400,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 +3460,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 +3528,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 +3655,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 +3665,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 +3702,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 +3741,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 +4017,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 +4068,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 +4094,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 +4167,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 +4193,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 +4225,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 +4257,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); } /* @@ -4369,7 +4472,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 +4521,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 */ @@ -4535,7 +4638,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; @@ -4631,7 +4734,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 +4850,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) { @@ -4932,7 +5061,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 */ @@ -5121,7 +5250,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 +5278,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 +5329,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 +5400,7 @@ 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; } sport = atoi(sports); sserv = 0; @@ -5355,7 +5485,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 +5524,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 { @@ -5437,7 +5567,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 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; @@ -5495,7 +5625,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 +5639,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 +5676,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 +5719,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 +5769,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 +5822,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 +5900,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; } /* @@ -5879,8 +6001,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) { @@ -5929,7 +6053,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 { /* @@ -5989,11 +6113,11 @@ 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) { - char *p; + const char *p; Ssh ssh; ssh = snew(struct ssh_tag); @@ -6137,7 +6261,7 @@ static void ssh_free(void *handle) sfree(ssh->do_ssh2_authconn_state); if (ssh->s) - sk_close(ssh->s); + ssh_do_close(ssh); sfree(ssh); }