Move SSH_MSG_UNEXPECTED generation into the BPP.

Now I've got a list macro defining all the packet types we recognise,
I can use it to write a test for 'is this a recognised code?', and use
that in turn to centralise detection of completely unrecognised codes
into the binary packet protocol, where any such messages will be
handled entirely internally and never even be seen by the next level
up. This lets me remove another big pile of boilerplate in ssh.c.
This commit is contained in:
Simon Tatham 2018-09-24 13:45:10 +01:00
Родитель 8cb68390e4
Коммит 09c3439b5a
6 изменённых файлов: 67 добавлений и 71 удалений

81
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;

1
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

Просмотреть файл

@ -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);
{

Просмотреть файл

@ -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);
{

Просмотреть файл

@ -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

Просмотреть файл

@ -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