1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-01-09 17:38:00 +00:00

Re-architected the top level of the SSH protocol handlers.

ssh1_protocol() and ssh2_protocol() are now high-level functions
which see _every_ SSH packet and decide which lower-level function
to pass it to. Also, they each support a dispatch table of simple
handler functions for message types which can arrive at any time.
Results are:

 - ignore, debug and disconnect messages are now handled by the
   dispatch table rather than being warts in the rdpkt functions

 - SSH2_MSG_WINDOW_ADJUST is handled by the dispatch table, which
   means that do_ssh2_authconn doesn't have to explicitly
   special-case it absolutely every time it waits for a response to
   its latest channel request

 - the top-level SSH2 protocol function chooses whether messages get
   funnelled to the transport layer or the auth/conn layer based on
   the message number ranges defined in the SSH architecture draft -
   so things that should go to auth/conn go there even in the middle
   of a rekey (although a special case is that nothing goes to
   auth/conn until initial kex has finished). This should fix the
   other half of ssh2-kex-data.

[originally from svn r4901]
This commit is contained in:
Simon Tatham 2004-11-24 20:35:15 +00:00
parent 06e9857f89
commit a4ba026838

502
ssh.c
View File

@ -512,6 +512,7 @@ struct ssh_rportfwd {
struct Packet {
long length;
int type;
unsigned long sequence;
unsigned char *data;
unsigned char *body;
long savedpos;
@ -529,6 +530,8 @@ static void ssh1_protocol(Ssh ssh, unsigned char *in, int inlen,
struct Packet *pktin);
static void ssh2_protocol(Ssh ssh, unsigned char *in, int inlen,
struct Packet *pktin);
static void ssh1_protocol_setup(Ssh ssh);
static void ssh2_protocol_setup(Ssh ssh);
static void ssh_size(void *handle, int width, int height);
static void ssh_special(void *handle, Telnet_Special);
static int ssh2_try_send(struct ssh_channel *c);
@ -558,6 +561,8 @@ struct rdpkt2_state_tag {
struct Packet *pktin;
};
typedef void (*handler_fn_t)(Ssh ssh, struct Packet *pktin);
struct ssh_tag {
const struct plug_function_table *fn;
/* the above field _must_ be first in the structure */
@ -654,8 +659,8 @@ struct ssh_tag {
int ssh2_rdpkt_crstate;
int do_ssh_init_crstate;
int ssh_gotdata_crstate;
int ssh1_protocol_crstate;
int do_ssh1_login_crstate;
int do_ssh1_connection_crstate;
int do_ssh2_transport_crstate;
int do_ssh2_authconn_crstate;
@ -667,6 +672,9 @@ struct ssh_tag {
struct rdpkt1_state_tag rdpkt1_state;
struct rdpkt2_state_tag rdpkt2_state;
/* ssh1 and ssh2 use this for different things, but both use it */
int protocol_initial_phase_done;
void (*protocol) (Ssh ssh, unsigned char *in, int inlen,
struct Packet *pkt);
struct Packet *(*s_rdpkt) (Ssh ssh, unsigned char **data, int *datalen);
@ -684,6 +692,12 @@ struct ssh_tag {
*/
void *agent_response;
int agent_response_len;
/*
* Dispatch table for packet types that we may have to deal
* with at any time.
*/
handler_fn_t packet_dispatch[256];
};
#define logevent(s) logevent(ssh->frontend, s)
@ -873,8 +887,6 @@ static struct Packet *ssh1_rdpkt(Ssh ssh, unsigned char **data, int *datalen)
crBegin(ssh->ssh1_rdpkt_crstate);
next_packet:
st->pktin = ssh_new_packet();
st->pktin->type = 0;
@ -992,48 +1004,6 @@ static struct Packet *ssh1_rdpkt(Ssh ssh, unsigned char **data, int *datalen)
nblanks, &blank);
}
if (st->pktin->type == SSH1_SMSG_STDOUT_DATA ||
st->pktin->type == SSH1_SMSG_STDERR_DATA ||
st->pktin->type == SSH1_MSG_DEBUG ||
st->pktin->type == SSH1_SMSG_AUTH_TIS_CHALLENGE ||
st->pktin->type == SSH1_SMSG_AUTH_CCARD_CHALLENGE) {
long stringlen = GET_32BIT(st->pktin->body);
if (stringlen + 4 != st->pktin->length) {
bombout(("Received data packet with bogus string length"));
ssh_free_packet(st->pktin);
crStop(NULL);
}
}
if (st->pktin->type == SSH1_MSG_DEBUG) {
char *buf, *msg;
int msglen;
ssh_pkt_getstring(st->pktin, &msg, &msglen);
buf = dupprintf("Remote debug message: %.*s", msglen, msg);
logevent(buf);
sfree(buf);
ssh_free_packet(st->pktin);
goto next_packet;
} else if (st->pktin->type == SSH1_MSG_IGNORE) {
/* do nothing */
ssh_free_packet(st->pktin);
goto next_packet;
}
if (st->pktin->type == SSH1_MSG_DISCONNECT) {
/* log reason code in disconnect message */
char *msg;
int msglen;
ssh_pkt_getstring(st->pktin, &msg, &msglen);
bombout(("Server sent disconnect message:\n\"%.*s\"", msglen, msg));
ssh_free_packet(st->pktin);
crStop(NULL);
}
crFinish(st->pktin);
}
@ -1043,8 +1013,6 @@ static struct Packet *ssh2_rdpkt(Ssh ssh, unsigned char **data, int *datalen)
crBegin(ssh->ssh2_rdpkt_crstate);
next_packet:
st->pktin = ssh_new_packet();
st->pktin->type = 0;
@ -1136,7 +1104,8 @@ static struct Packet *ssh2_rdpkt(Ssh ssh, unsigned char **data, int *datalen)
ssh_free_packet(st->pktin);
crStop(NULL);
}
st->incoming_sequence++; /* whether or not we MACed */
st->pktin->sequence = st->incoming_sequence++;
/*
* Decompress packet payload.
@ -1191,115 +1160,6 @@ static struct Packet *ssh2_rdpkt(Ssh ssh, unsigned char **data, int *datalen)
nblanks, &blank);
}
switch (st->pktin->type) {
/*
* These packets we must handle instantly.
*/
case SSH2_MSG_DISCONNECT:
{
/* log reason code in disconnect message */
char *buf, *msg;
int nowlen, reason, msglen;
reason = ssh_pkt_getuint32(st->pktin);
ssh_pkt_getstring(st->pktin, &msg, &msglen);
if (reason > 0 && reason < lenof(ssh2_disconnect_reasons)) {
buf = dupprintf("Received disconnect message (%s)",
ssh2_disconnect_reasons[reason]);
} else {
buf = dupprintf("Received disconnect message (unknown"
" type %d)", reason);
}
logevent(buf);
sfree(buf);
buf = dupprintf("Disconnection message text: %n%.*s",
&nowlen, msglen, msg);
logevent(buf);
bombout(("Server sent disconnect message\ntype %d (%s):\n\"%s\"",
reason,
(reason > 0 && reason < lenof(ssh2_disconnect_reasons)) ?
ssh2_disconnect_reasons[reason] : "unknown",
buf+nowlen));
sfree(buf);
ssh_free_packet(st->pktin);
crStop(NULL);
}
break;
case SSH2_MSG_IGNORE:
ssh_free_packet(st->pktin);
goto next_packet;
case SSH2_MSG_DEBUG:
{
/* log the debug message */
char *buf, *msg;
int msglen;
int always_display;
/* XXX maybe we should actually take notice of this */
always_display = ssh2_pkt_getbool(st->pktin);
ssh_pkt_getstring(st->pktin, &msg, &msglen);
buf = dupprintf("Remote debug message: %.*s", msglen, msg);
logevent(buf);
sfree(buf);
}
ssh_free_packet(st->pktin);
goto next_packet;
/*
* These packets we need do nothing about here.
*/
case SSH2_MSG_UNIMPLEMENTED:
case SSH2_MSG_SERVICE_REQUEST:
case SSH2_MSG_SERVICE_ACCEPT:
case SSH2_MSG_KEXINIT:
case SSH2_MSG_NEWKEYS:
case SSH2_MSG_KEXDH_INIT:
case SSH2_MSG_KEXDH_REPLY:
/* case SSH2_MSG_KEX_DH_GEX_REQUEST: duplicate case value */
/* case SSH2_MSG_KEX_DH_GEX_GROUP: duplicate case value */
case SSH2_MSG_KEX_DH_GEX_INIT:
case SSH2_MSG_KEX_DH_GEX_REPLY:
case SSH2_MSG_USERAUTH_REQUEST:
case SSH2_MSG_USERAUTH_FAILURE:
case SSH2_MSG_USERAUTH_SUCCESS:
case SSH2_MSG_USERAUTH_BANNER:
case SSH2_MSG_USERAUTH_PK_OK:
/* case SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ: duplicate case value */
/* case SSH2_MSG_USERAUTH_INFO_REQUEST: duplicate case value */
case SSH2_MSG_USERAUTH_INFO_RESPONSE:
case SSH2_MSG_GLOBAL_REQUEST:
case SSH2_MSG_REQUEST_SUCCESS:
case SSH2_MSG_REQUEST_FAILURE:
case SSH2_MSG_CHANNEL_OPEN:
case SSH2_MSG_CHANNEL_OPEN_CONFIRMATION:
case SSH2_MSG_CHANNEL_OPEN_FAILURE:
case SSH2_MSG_CHANNEL_WINDOW_ADJUST:
case SSH2_MSG_CHANNEL_DATA:
case SSH2_MSG_CHANNEL_EXTENDED_DATA:
case SSH2_MSG_CHANNEL_EOF:
case SSH2_MSG_CHANNEL_CLOSE:
case SSH2_MSG_CHANNEL_REQUEST:
case SSH2_MSG_CHANNEL_SUCCESS:
case SSH2_MSG_CHANNEL_FAILURE:
break;
/*
* For anything else we send SSH2_MSG_UNIMPLEMENTED.
*/
default:
{
struct Packet *pktout;
pktout = ssh2_pkt_init(SSH2_MSG_UNIMPLEMENTED);
ssh2_pkt_adduint32(pktout, st->incoming_sequence - 1);
/* UNIMPLEMENTED messages MUST appear in the same order as
* the messages they respond to. Hence, never queue them. */
ssh2_pkt_send_noqueue(ssh, pktout);
}
break;
}
crFinish(st->pktin);
}
@ -2273,6 +2133,7 @@ static int do_ssh_init(Ssh ssh, unsigned char c)
logevent("Using SSH protocol version 2");
sk_write(ssh->s, verstring, strlen(verstring));
ssh->protocol = ssh2_protocol;
ssh2_protocol_setup(ssh);
ssh->version = 2;
ssh->s_rdpkt = ssh2_rdpkt;
} else {
@ -2290,6 +2151,7 @@ static int do_ssh_init(Ssh ssh, unsigned char c)
logevent("Using SSH protocol version 1");
sk_write(ssh->s, verstring, strlen(verstring));
ssh->protocol = ssh1_protocol;
ssh1_protocol_setup(ssh);
ssh->version = 1;
ssh->s_rdpkt = ssh1_rdpkt;
}
@ -2672,6 +2534,8 @@ static int do_ssh1_login(Ssh ssh, unsigned char *in, int inlen,
crBegin(ssh->do_ssh1_login_crstate);
random_init();
if (!pktin)
crWaitUntil(pktin);
@ -3574,18 +3438,10 @@ void sshfwd_unthrottle(struct ssh_channel *c, int bufsize)
}
}
static void ssh1_protocol(Ssh ssh, unsigned char *in, int inlen,
struct Packet *pktin)
static void do_ssh1_connection(Ssh ssh, unsigned char *in, int inlen,
struct Packet *pktin)
{
crBegin(ssh->ssh1_protocol_crstate);
random_init();
while (!do_ssh1_login(ssh, in, inlen, pktin)) {
crReturnV;
}
if (ssh->state == SSH_STATE_CLOSED)
crReturnV;
crBegin(ssh->do_ssh1_connection_crstate);
if (ssh->cfg.agentfwd && agent_exists()) {
logevent("Requesting agent forwarding");
@ -4200,6 +4056,74 @@ static void ssh1_protocol(Ssh ssh, unsigned char *in, int inlen,
crFinishV;
}
/*
* Handle the top-level SSH2 protocol.
*/
static void ssh1_msg_debug(Ssh ssh, struct Packet *pktin)
{
char *buf, *msg;
int msglen;
ssh_pkt_getstring(pktin, &msg, &msglen);
buf = dupprintf("Remote debug message: %.*s", msglen, msg);
logevent(buf);
sfree(buf);
}
static void ssh1_msg_disconnect(Ssh ssh, struct Packet *pktin)
{
/* log reason code in disconnect message */
char *msg;
int msglen;
ssh_pkt_getstring(pktin, &msg, &msglen);
bombout(("Server sent disconnect message:\n\"%.*s\"", msglen, msg));
}
void ssh_msg_ignore(Ssh ssh, struct Packet *pktin)
{
/* Do nothing, because we're ignoring it! Duhh. */
}
static void ssh1_protocol_setup(Ssh ssh)
{
int i;
/*
* Most messages are handled by the coroutines.
*/
for (i = 0; i < 256; i++)
ssh->packet_dispatch[i] = NULL;
/*
* These special message types we install handlers for.
*/
ssh->packet_dispatch[SSH1_MSG_DISCONNECT] = ssh1_msg_disconnect;
ssh->packet_dispatch[SSH1_MSG_IGNORE] = ssh_msg_ignore;
ssh->packet_dispatch[SSH1_MSG_DEBUG] = ssh1_msg_debug;
}
static void ssh1_protocol(Ssh ssh, unsigned char *in, int inlen,
struct Packet *pktin)
{
if (ssh->state == SSH_STATE_CLOSED)
return;
if (pktin && ssh->packet_dispatch[pktin->type]) {
ssh->packet_dispatch[pktin->type](ssh, pktin);
return;
}
if (!ssh->protocol_initial_phase_done) {
if (do_ssh1_login(ssh, in, inlen, pktin))
ssh->protocol_initial_phase_done = TRUE;
else
return;
}
do_ssh1_connection(ssh, in, inlen, pktin);
}
/*
* Utility routine for decoding comma-separated strings in KEXINIT.
*/
@ -4812,7 +4736,7 @@ static int do_ssh2_transport(Ssh ssh, unsigned char *in, int inlen,
* it would only confuse the layer above.
*/
if (!s->first_kex) {
crReturn(0);
crReturn(1);
}
s->first_kex = 0;
@ -4900,6 +4824,15 @@ static void ssh2_set_window(struct ssh_channel *c, unsigned newwin)
}
}
void ssh2_msg_channel_window_adjust(Ssh ssh, struct Packet *pktin)
{
unsigned i = ssh_pkt_getuint32(pktin);
struct ssh_channel *c;
c = find234(ssh->channels, &i, ssh_channelfind);
if (c && !c->closes)
c->v.v2.remwindow += ssh_pkt_getuint32(pktin);
}
/*
* Handle the SSH2 userauth and connection layers.
*/
@ -5774,6 +5707,13 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen,
ssh->channels = newtree234(ssh_channelcmp);
/*
* Set up handlers for some connection protocol messages, so we
* don't have to handle them repeatedly in this coroutine.
*/
ssh->packet_dispatch[SSH2_MSG_CHANNEL_WINDOW_ADJUST] =
ssh2_msg_channel_window_adjust;
/*
* Create the main session channel.
*/
@ -5829,17 +5769,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen,
ssh2_pkt_adduint32(s->pktout, x11_get_screen_number(ssh->cfg.x11_display));
ssh2_pkt_send(ssh, s->pktout);
do {
crWaitUntilV(pktin);
if (pktin->type == SSH2_MSG_CHANNEL_WINDOW_ADJUST) {
unsigned i = ssh_pkt_getuint32(pktin);
struct ssh_channel *c;
c = find234(ssh->channels, &i, ssh_channelfind);
if (!c)
continue; /* nonexistent channel */
c->v.v2.remwindow += ssh_pkt_getuint32(pktin);
}
} while (pktin->type == SSH2_MSG_CHANNEL_WINDOW_ADJUST);
crWaitUntilV(pktin);
if (pktin->type != SSH2_MSG_CHANNEL_SUCCESS) {
if (pktin->type != SSH2_MSG_CHANNEL_FAILURE) {
@ -5995,17 +5925,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen,
ssh2_pkt_adduint32(s->pktout, sport);
ssh2_pkt_send(ssh, s->pktout);
do {
crWaitUntilV(pktin);
if (pktin->type == SSH2_MSG_CHANNEL_WINDOW_ADJUST) {
unsigned i = ssh_pkt_getuint32(pktin);
struct ssh_channel *c;
c = find234(ssh->channels, &i, ssh_channelfind);
if (!c)
continue;/* nonexistent channel */
c->v.v2.remwindow += ssh_pkt_getuint32(pktin);
}
} while (pktin->type == SSH2_MSG_CHANNEL_WINDOW_ADJUST);
crWaitUntilV(pktin);
if (pktin->type != SSH2_MSG_REQUEST_SUCCESS) {
if (pktin->type != SSH2_MSG_REQUEST_FAILURE) {
@ -6036,17 +5956,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen,
ssh2_pkt_addbool(s->pktout, 1); /* want reply */
ssh2_pkt_send(ssh, s->pktout);
do {
crWaitUntilV(pktin);
if (pktin->type == SSH2_MSG_CHANNEL_WINDOW_ADJUST) {
unsigned i = ssh_pkt_getuint32(pktin);
struct ssh_channel *c;
c = find234(ssh->channels, &i, ssh_channelfind);
if (!c)
continue; /* nonexistent channel */
c->v.v2.remwindow += ssh_pkt_getuint32(pktin);
}
} while (pktin->type == SSH2_MSG_CHANNEL_WINDOW_ADJUST);
crWaitUntilV(pktin);
if (pktin->type != SSH2_MSG_CHANNEL_SUCCESS) {
if (pktin->type != SSH2_MSG_CHANNEL_FAILURE) {
@ -6088,17 +5998,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen,
ssh2_pkt_send(ssh, s->pktout);
ssh->state = SSH_STATE_INTERMED;
do {
crWaitUntilV(pktin);
if (pktin->type == SSH2_MSG_CHANNEL_WINDOW_ADJUST) {
unsigned i = ssh_pkt_getuint32(pktin);
struct ssh_channel *c;
c = find234(ssh->channels, &i, ssh_channelfind);
if (!c)
continue; /* nonexistent channel */
c->v.v2.remwindow += ssh_pkt_getuint32(pktin);
}
} while (pktin->type == SSH2_MSG_CHANNEL_WINDOW_ADJUST);
crWaitUntilV(pktin);
if (pktin->type != SSH2_MSG_CHANNEL_SUCCESS) {
if (pktin->type != SSH2_MSG_CHANNEL_FAILURE) {
@ -6155,17 +6055,7 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen,
s->env_left = s->num_env;
while (s->env_left > 0) {
do {
crWaitUntilV(pktin);
if (pktin->type == SSH2_MSG_CHANNEL_WINDOW_ADJUST) {
unsigned i = ssh_pkt_getuint32(pktin);
struct ssh_channel *c;
c = find234(ssh->channels, &i, ssh_channelfind);
if (!c)
continue; /* nonexistent channel */
c->v.v2.remwindow += ssh_pkt_getuint32(pktin);
}
} while (pktin->type == SSH2_MSG_CHANNEL_WINDOW_ADJUST);
crWaitUntilV(pktin);
if (pktin->type != SSH2_MSG_CHANNEL_SUCCESS) {
if (pktin->type != SSH2_MSG_CHANNEL_FAILURE) {
@ -6224,17 +6114,9 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen,
ssh2_pkt_addbool(s->pktout, 1); /* want reply */
}
ssh2_pkt_send(ssh, s->pktout);
do {
crWaitUntilV(pktin);
if (pktin->type == SSH2_MSG_CHANNEL_WINDOW_ADJUST) {
unsigned i = ssh_pkt_getuint32(pktin);
struct ssh_channel *c;
c = find234(ssh->channels, &i, ssh_channelfind);
if (!c)
continue; /* nonexistent channel */
c->v.v2.remwindow += ssh_pkt_getuint32(pktin);
}
} while (pktin->type == SSH2_MSG_CHANNEL_WINDOW_ADJUST);
crWaitUntilV(pktin);
if (pktin->type != SSH2_MSG_CHANNEL_SUCCESS) {
if (pktin->type != SSH2_MSG_CHANNEL_FAILURE) {
bombout(("Unexpected response to shell/command request:"
@ -6444,14 +6326,6 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen,
crStopV;
}
continue; /* remote sends close; ignore (FIXME) */
} else if (pktin->type == SSH2_MSG_CHANNEL_WINDOW_ADJUST) {
unsigned i = ssh_pkt_getuint32(pktin);
struct ssh_channel *c;
c = find234(ssh->channels, &i, ssh_channelfind);
if (!c || c->closes)
continue; /* nonexistent or closing channel */
c->v.v2.remwindow += ssh_pkt_getuint32(pktin);
s->try_send = TRUE;
} else if (pktin->type == SSH2_MSG_CHANNEL_OPEN_CONFIRMATION) {
unsigned i = ssh_pkt_getuint32(pktin);
struct ssh_channel *c;
@ -6821,15 +6695,149 @@ static void do_ssh2_authconn(Ssh ssh, unsigned char *in, int inlen,
crFinishV;
}
/*
* Handlers for SSH2 messages that might arrive at any moment.
*/
void ssh2_msg_disconnect(Ssh ssh, struct Packet *pktin)
{
/* log reason code in disconnect message */
char *buf, *msg;
int nowlen, reason, msglen;
reason = ssh_pkt_getuint32(pktin);
ssh_pkt_getstring(pktin, &msg, &msglen);
if (reason > 0 && reason < lenof(ssh2_disconnect_reasons)) {
buf = dupprintf("Received disconnect message (%s)",
ssh2_disconnect_reasons[reason]);
} else {
buf = dupprintf("Received disconnect message (unknown"
" type %d)", reason);
}
logevent(buf);
sfree(buf);
buf = dupprintf("Disconnection message text: %n%.*s",
&nowlen, msglen, msg);
logevent(buf);
bombout(("Server sent disconnect message\ntype %d (%s):\n\"%s\"",
reason,
(reason > 0 && reason < lenof(ssh2_disconnect_reasons)) ?
ssh2_disconnect_reasons[reason] : "unknown",
buf+nowlen));
sfree(buf);
}
void ssh2_msg_debug(Ssh ssh, struct Packet *pktin)
{
/* log the debug message */
char *buf, *msg;
int msglen;
int always_display;
/* XXX maybe we should actually take notice of this */
always_display = ssh2_pkt_getbool(pktin);
ssh_pkt_getstring(pktin, &msg, &msglen);
buf = dupprintf("Remote debug message: %.*s", msglen, msg);
logevent(buf);
sfree(buf);
}
void ssh2_msg_something_unimplemented(Ssh ssh, struct Packet *pktin)
{
struct Packet *pktout;
pktout = ssh2_pkt_init(SSH2_MSG_UNIMPLEMENTED);
ssh2_pkt_adduint32(pktout, pktin->sequence);
/*
* UNIMPLEMENTED messages MUST appear in the same order as the
* messages they respond to. Hence, never queue them.
*/
ssh2_pkt_send_noqueue(ssh, pktout);
}
/*
* Handle the top-level SSH2 protocol.
*/
static void ssh2_protocol_setup(Ssh ssh)
{
int i;
/*
* Most messages cause SSH2_MSG_UNIMPLEMENTED.
*/
for (i = 0; i < 256; i++)
ssh->packet_dispatch[i] = ssh2_msg_something_unimplemented;
/*
* Any message we actually understand, we set to NULL so that
* the coroutines will get it.
*/
ssh->packet_dispatch[SSH2_MSG_UNIMPLEMENTED] = NULL;
ssh->packet_dispatch[SSH2_MSG_SERVICE_REQUEST] = NULL;
ssh->packet_dispatch[SSH2_MSG_SERVICE_ACCEPT] = NULL;
ssh->packet_dispatch[SSH2_MSG_KEXINIT] = NULL;
ssh->packet_dispatch[SSH2_MSG_NEWKEYS] = NULL;
ssh->packet_dispatch[SSH2_MSG_KEXDH_INIT] = NULL;
ssh->packet_dispatch[SSH2_MSG_KEXDH_REPLY] = NULL;
/* ssh->packet_dispatch[SSH2_MSG_KEX_DH_GEX_REQUEST] = NULL; duplicate case value */
/* ssh->packet_dispatch[SSH2_MSG_KEX_DH_GEX_GROUP] = NULL; duplicate case value */
ssh->packet_dispatch[SSH2_MSG_KEX_DH_GEX_INIT] = NULL;
ssh->packet_dispatch[SSH2_MSG_KEX_DH_GEX_REPLY] = NULL;
ssh->packet_dispatch[SSH2_MSG_USERAUTH_REQUEST] = NULL;
ssh->packet_dispatch[SSH2_MSG_USERAUTH_FAILURE] = NULL;
ssh->packet_dispatch[SSH2_MSG_USERAUTH_SUCCESS] = NULL;
ssh->packet_dispatch[SSH2_MSG_USERAUTH_BANNER] = NULL;
ssh->packet_dispatch[SSH2_MSG_USERAUTH_PK_OK] = NULL;
/* ssh->packet_dispatch[SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ] = NULL; duplicate case value */
/* ssh->packet_dispatch[SSH2_MSG_USERAUTH_INFO_REQUEST] = NULL; duplicate case value */
ssh->packet_dispatch[SSH2_MSG_USERAUTH_INFO_RESPONSE] = NULL;
ssh->packet_dispatch[SSH2_MSG_GLOBAL_REQUEST] = NULL;
ssh->packet_dispatch[SSH2_MSG_REQUEST_SUCCESS] = NULL;
ssh->packet_dispatch[SSH2_MSG_REQUEST_FAILURE] = NULL;
ssh->packet_dispatch[SSH2_MSG_CHANNEL_OPEN] = NULL;
ssh->packet_dispatch[SSH2_MSG_CHANNEL_OPEN_CONFIRMATION] = NULL;
ssh->packet_dispatch[SSH2_MSG_CHANNEL_OPEN_FAILURE] = NULL;
ssh->packet_dispatch[SSH2_MSG_CHANNEL_WINDOW_ADJUST] = NULL;
ssh->packet_dispatch[SSH2_MSG_CHANNEL_DATA] = NULL;
ssh->packet_dispatch[SSH2_MSG_CHANNEL_EXTENDED_DATA] = NULL;
ssh->packet_dispatch[SSH2_MSG_CHANNEL_EOF] = NULL;
ssh->packet_dispatch[SSH2_MSG_CHANNEL_CLOSE] = NULL;
ssh->packet_dispatch[SSH2_MSG_CHANNEL_REQUEST] = NULL;
ssh->packet_dispatch[SSH2_MSG_CHANNEL_SUCCESS] = NULL;
ssh->packet_dispatch[SSH2_MSG_CHANNEL_FAILURE] = NULL;
/*
* These special message types we install handlers for.
*/
ssh->packet_dispatch[SSH2_MSG_DISCONNECT] = ssh2_msg_disconnect;
ssh->packet_dispatch[SSH2_MSG_IGNORE] = ssh_msg_ignore; /* shared with ssh1 */
ssh->packet_dispatch[SSH2_MSG_DEBUG] = ssh2_msg_debug;
}
static void ssh2_protocol(Ssh ssh, unsigned char *in, int inlen,
struct Packet *pktin)
{
if (do_ssh2_transport(ssh, in, inlen, pktin) == 0)
if (ssh->state == SSH_STATE_CLOSED)
return;
do_ssh2_authconn(ssh, in, inlen, pktin);
if (pktin && ssh->packet_dispatch[pktin->type]) {
ssh->packet_dispatch[pktin->type](ssh, pktin);
return;
}
if (!ssh->protocol_initial_phase_done ||
(pktin && pktin->type >= 20 && pktin->type < 50)) {
if (do_ssh2_transport(ssh, in, inlen, pktin) &&
!ssh->protocol_initial_phase_done) {
ssh->protocol_initial_phase_done = TRUE;
/*
* Allow authconn to initialise itself.
*/
do_ssh2_authconn(ssh, NULL, 0, NULL);
}
} else {
do_ssh2_authconn(ssh, in, inlen, pktin);
}
}
/*
@ -6885,7 +6893,7 @@ static const char *ssh_init(void *frontend_handle, void **backend_handle,
ssh->ssh2_rdpkt_crstate = 0;
ssh->do_ssh_init_crstate = 0;
ssh->ssh_gotdata_crstate = 0;
ssh->ssh1_protocol_crstate = 0;
ssh->do_ssh1_connection_crstate = 0;
ssh->do_ssh1_login_crstate = 0;
ssh->do_ssh2_transport_crstate = 0;
ssh->do_ssh2_authconn_crstate = 0;
@ -6923,6 +6931,8 @@ static const char *ssh_init(void *frontend_handle, void **backend_handle,
ssh->protocol = NULL;
ssh->protocol_initial_phase_done = FALSE;
p = connect_to_host(ssh, host, port, realhost, nodelay, keepalive);
if (p != NULL)
return p;