diff --git a/ssh.c b/ssh.c index bc153887..1d7580cb 100644 --- a/ssh.c +++ b/ssh.c @@ -75,7 +75,6 @@ static void ssh2_channel_check_close(struct ssh_channel *c); static void ssh_channel_close_local(struct ssh_channel *c, char const *reason); static void ssh_channel_destroy(struct ssh_channel *c); static void ssh_channel_unthrottle(struct ssh_channel *c, int bufsize); -static void ssh2_msg_something_unimplemented(Ssh ssh, PktIn *pktin); static void ssh2_general_packet_processing(Ssh ssh, PktIn *pktin); static void ssh1_login_input(Ssh ssh); static void ssh2_userauth_input(Ssh ssh); @@ -8630,18 +8629,6 @@ static void ssh2_msg_unexpected(Ssh ssh, PktIn *pktin) sfree(buf); } -static void ssh2_msg_something_unimplemented(Ssh ssh, PktIn *pktin) -{ - PktOut *pktout; - pktout = ssh_bpp_new_pktout(ssh->bpp, SSH2_MSG_UNIMPLEMENTED); - put_uint32(pktout, pktin->sequence); - /* - * UNIMPLEMENTED messages MUST appear in the same order as the - * messages they respond to. Hence, never queue them. - */ - ssh_pkt_write(ssh, pktout); -} - /* * Handle the top-level SSH-2 protocol. */ @@ -8680,20 +8667,17 @@ static void ssh2_protocol_setup(Ssh ssh) #endif /* - * Most messages cause SSH2_MSG_UNIMPLEMENTED. + * All message types we don't set explicitly will dispatch to + * ssh2_msg_unexpected. */ for (i = 0; i < SSH_MAX_MSG; i++) - ssh->packet_dispatch[i] = ssh2_msg_something_unimplemented; + ssh->packet_dispatch[i] = ssh2_msg_unexpected; /* * Initially, we only accept transport messages (and a few generic * ones). do_ssh2_userauth and do_ssh2_connection will each add - * more when they start. Messages that are understood but not - * currently acceptable go to ssh2_msg_unexpected. + * more when they start. */ - ssh->packet_dispatch[SSH2_MSG_UNIMPLEMENTED] = ssh2_msg_unexpected; - ssh->packet_dispatch[SSH2_MSG_SERVICE_REQUEST] = ssh2_msg_unexpected; - ssh->packet_dispatch[SSH2_MSG_SERVICE_ACCEPT] = ssh2_msg_unexpected; ssh->packet_dispatch[SSH2_MSG_KEXINIT] = ssh2_msg_transport; ssh->packet_dispatch[SSH2_MSG_NEWKEYS] = ssh2_msg_transport; ssh->packet_dispatch[SSH2_MSG_KEXDH_INIT] = ssh2_msg_transport; @@ -8703,28 +8687,6 @@ static void ssh2_protocol_setup(Ssh ssh) ssh->packet_dispatch[SSH2_MSG_KEX_DH_GEX_INIT] = ssh2_msg_transport; ssh->packet_dispatch[SSH2_MSG_KEX_DH_GEX_REPLY] = ssh2_msg_transport; ssh->packet_dispatch[SSH2_MSG_KEXGSS_GROUP] = ssh2_msg_transport; - ssh->packet_dispatch[SSH2_MSG_USERAUTH_REQUEST] = ssh2_msg_unexpected; - ssh->packet_dispatch[SSH2_MSG_USERAUTH_FAILURE] = ssh2_msg_unexpected; - ssh->packet_dispatch[SSH2_MSG_USERAUTH_SUCCESS] = ssh2_msg_unexpected; - ssh->packet_dispatch[SSH2_MSG_USERAUTH_BANNER] = ssh2_msg_unexpected; - ssh->packet_dispatch[SSH2_MSG_USERAUTH_PK_OK] = ssh2_msg_unexpected; - /* ssh->packet_dispatch[SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ] = ssh2_msg_unexpected; duplicate case value */ - /* ssh->packet_dispatch[SSH2_MSG_USERAUTH_INFO_REQUEST] = ssh2_msg_unexpected; duplicate case value */ - ssh->packet_dispatch[SSH2_MSG_USERAUTH_INFO_RESPONSE] = ssh2_msg_unexpected; - ssh->packet_dispatch[SSH2_MSG_GLOBAL_REQUEST] = ssh2_msg_unexpected; - ssh->packet_dispatch[SSH2_MSG_REQUEST_SUCCESS] = ssh2_msg_unexpected; - ssh->packet_dispatch[SSH2_MSG_REQUEST_FAILURE] = ssh2_msg_unexpected; - ssh->packet_dispatch[SSH2_MSG_CHANNEL_OPEN] = ssh2_msg_unexpected; - ssh->packet_dispatch[SSH2_MSG_CHANNEL_OPEN_CONFIRMATION] = ssh2_msg_unexpected; - ssh->packet_dispatch[SSH2_MSG_CHANNEL_OPEN_FAILURE] = ssh2_msg_unexpected; - ssh->packet_dispatch[SSH2_MSG_CHANNEL_WINDOW_ADJUST] = ssh2_msg_unexpected; - ssh->packet_dispatch[SSH2_MSG_CHANNEL_DATA] = ssh2_msg_unexpected; - ssh->packet_dispatch[SSH2_MSG_CHANNEL_EXTENDED_DATA] = ssh2_msg_unexpected; - ssh->packet_dispatch[SSH2_MSG_CHANNEL_EOF] = ssh2_msg_unexpected; - ssh->packet_dispatch[SSH2_MSG_CHANNEL_CLOSE] = ssh2_msg_unexpected; - ssh->packet_dispatch[SSH2_MSG_CHANNEL_REQUEST] = ssh2_msg_unexpected; - ssh->packet_dispatch[SSH2_MSG_CHANNEL_SUCCESS] = ssh2_msg_unexpected; - ssh->packet_dispatch[SSH2_MSG_CHANNEL_FAILURE] = ssh2_msg_unexpected; /* * These messages have a special handler from the start. @@ -8741,38 +8703,15 @@ static void ssh2_bare_connection_protocol_setup(Ssh ssh) ssh->bpp = ssh2_bare_bpp_new(); /* - * Most messages cause SSH2_MSG_UNIMPLEMENTED. - */ - for (i = 0; i < SSH_MAX_MSG; i++) - ssh->packet_dispatch[i] = ssh2_msg_something_unimplemented; - - /* - * Initially, we set all ssh-connection messages to 'unexpected'; - * do_ssh2_connection will fill things in properly. We also handle - * a couple of messages from the transport protocol which aren't - * related to key exchange (UNIMPLEMENTED, IGNORE, DEBUG, + * Everything defaults to ssh2_msg_unexpected for the moment; + * do_ssh2_connection will fill things in properly. But we do + * handle a couple of messages from the transport protocol which + * aren't related to key exchange (UNIMPLEMENTED, IGNORE, DEBUG, * DISCONNECT). */ - ssh->packet_dispatch[SSH2_MSG_GLOBAL_REQUEST] = ssh2_msg_unexpected; - ssh->packet_dispatch[SSH2_MSG_REQUEST_SUCCESS] = ssh2_msg_unexpected; - ssh->packet_dispatch[SSH2_MSG_REQUEST_FAILURE] = ssh2_msg_unexpected; - ssh->packet_dispatch[SSH2_MSG_CHANNEL_OPEN] = ssh2_msg_unexpected; - ssh->packet_dispatch[SSH2_MSG_CHANNEL_OPEN_CONFIRMATION] = ssh2_msg_unexpected; - ssh->packet_dispatch[SSH2_MSG_CHANNEL_OPEN_FAILURE] = ssh2_msg_unexpected; - ssh->packet_dispatch[SSH2_MSG_CHANNEL_WINDOW_ADJUST] = ssh2_msg_unexpected; - ssh->packet_dispatch[SSH2_MSG_CHANNEL_DATA] = ssh2_msg_unexpected; - ssh->packet_dispatch[SSH2_MSG_CHANNEL_EXTENDED_DATA] = ssh2_msg_unexpected; - ssh->packet_dispatch[SSH2_MSG_CHANNEL_EOF] = ssh2_msg_unexpected; - ssh->packet_dispatch[SSH2_MSG_CHANNEL_CLOSE] = ssh2_msg_unexpected; - ssh->packet_dispatch[SSH2_MSG_CHANNEL_REQUEST] = ssh2_msg_unexpected; - ssh->packet_dispatch[SSH2_MSG_CHANNEL_SUCCESS] = ssh2_msg_unexpected; - ssh->packet_dispatch[SSH2_MSG_CHANNEL_FAILURE] = ssh2_msg_unexpected; + for (i = 0; i < SSH_MAX_MSG; i++) + ssh->packet_dispatch[i] = ssh2_msg_unexpected; - ssh->packet_dispatch[SSH2_MSG_UNIMPLEMENTED] = ssh2_msg_unexpected; - - /* - * These messages have a special handler from the start. - */ ssh->packet_dispatch[SSH2_MSG_DISCONNECT] = ssh2_msg_disconnect; ssh->packet_dispatch[SSH2_MSG_IGNORE] = ssh_msg_ignore; ssh->packet_dispatch[SSH2_MSG_DEBUG] = ssh2_msg_debug; diff --git a/ssh.h b/ssh.h index b438b35b..200a5407 100644 --- a/ssh.h +++ b/ssh.h @@ -1299,6 +1299,7 @@ enum { const char *ssh1_pkt_type(int type); const char *ssh2_pkt_type(Pkt_KCtx pkt_kctx, Pkt_ACtx pkt_actx, int type); +int ssh2_pkt_type_code_valid(unsigned type); /* * Need this to warn about support for the original SSH-2 keyfile diff --git a/ssh2bpp-bare.c b/ssh2bpp-bare.c index 45f757f6..c818e218 100644 --- a/ssh2bpp-bare.c +++ b/ssh2bpp-bare.c @@ -111,6 +111,12 @@ static void ssh2_bare_bpp_handle_input(BinaryPacketProtocol *bpp) &s->pktin->sequence, 0, NULL); } + if (ssh2_bpp_check_unimplemented(&s->bpp, s->pktin)) { + sfree(s->pktin); + s->pktin = NULL; + continue; + } + pq_push(s->bpp.in_pq, s->pktin); { diff --git a/ssh2bpp.c b/ssh2bpp.c index 49ab8cfd..b0dd2ea7 100644 --- a/ssh2bpp.c +++ b/ssh2bpp.c @@ -476,6 +476,12 @@ static void ssh2_bpp_handle_input(BinaryPacketProtocol *bpp) &s->pktin->sequence, 0, NULL); } + if (ssh2_bpp_check_unimplemented(&s->bpp, s->pktin)) { + sfree(s->pktin); + s->pktin = NULL; + continue; + } + pq_push(s->bpp.in_pq, s->pktin); { diff --git a/sshbpp.h b/sshbpp.h index 8fc02960..61f4fe7f 100644 --- a/sshbpp.h +++ b/sshbpp.h @@ -40,6 +40,9 @@ void ssh1_bpp_new_cipher(BinaryPacketProtocol *bpp, * up zlib compression if it was SUCCESS. */ void ssh1_bpp_requested_compression(BinaryPacketProtocol *bpp); +/* Common helper function between the SSH-2 full and bare BPPs */ +int ssh2_bpp_check_unimplemented(BinaryPacketProtocol *bpp, PktIn *pktin); + /* * Structure that tracks how much data is sent and received, for * purposes of triggering an SSH-2 rekey when either one gets over a diff --git a/sshcommon.c b/sshcommon.c index 3b7fc6a8..ac23e791 100644 --- a/sshcommon.c +++ b/sshcommon.c @@ -8,6 +8,7 @@ #include "putty.h" #include "ssh.h" +#include "sshbpp.h" #include "sshchan.h" /* ---------------------------------------------------------------------- @@ -581,3 +582,43 @@ const char *ssh2_pkt_type(Pkt_KCtx pkt_kctx, Pkt_ACtx pkt_actx, int type) #undef TRANSLATE_UNIVERSAL #undef TRANSLATE_KEX #undef TRANSLATE_AUTH + +/* ---------------------------------------------------------------------- + * Common helper function for implementations of BinaryPacketProtocol. + */ + +#define BITMAP_UNIVERSAL(y, name, value) \ + | (value >= y && value < y+32 ? 1UL << (value-y) : 0) +#define BITMAP_CONDITIONAL(y, name, value, ctx) \ + BITMAP_UNIVERSAL(y, name, value) +#define SSH2_BITMAP_WORD(y) \ + (0 SSH2_MESSAGE_TYPES(BITMAP_UNIVERSAL, BITMAP_CONDITIONAL, \ + BITMAP_CONDITIONAL, (32*y))) + +int ssh2_bpp_check_unimplemented(BinaryPacketProtocol *bpp, PktIn *pktin) +{ + static const unsigned valid_bitmap[] = { + SSH2_BITMAP_WORD(0), + SSH2_BITMAP_WORD(1), + SSH2_BITMAP_WORD(2), + SSH2_BITMAP_WORD(3), + SSH2_BITMAP_WORD(4), + SSH2_BITMAP_WORD(5), + SSH2_BITMAP_WORD(6), + SSH2_BITMAP_WORD(7), + }; + + if (pktin->type < 0x100 && + !((valid_bitmap[pktin->type >> 5] >> (pktin->type & 0x1F)) & 1)) { + PktOut *pkt = ssh_bpp_new_pktout(bpp, SSH2_MSG_UNIMPLEMENTED); + put_uint32(pkt, pktin->sequence); + ssh_bpp_format_packet(bpp, pkt); + return TRUE; + } + + return FALSE; +} + +#undef BITMAP_UNIVERSAL +#undef BITMAP_CONDITIONAL +#undef SSH1_BITMAP_WORD