mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-01-09 17:38:00 +00:00
09c3439b5a
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.
167 lines
4.9 KiB
C
167 lines
4.9 KiB
C
/*
|
|
* Trivial binary packet protocol for the 'bare' ssh-connection
|
|
* protocol used in PuTTY's SSH-2 connection sharing system.
|
|
*/
|
|
|
|
#include <assert.h>
|
|
|
|
#include "putty.h"
|
|
#include "ssh.h"
|
|
#include "sshbpp.h"
|
|
#include "sshcr.h"
|
|
|
|
struct ssh2_bare_bpp_state {
|
|
int crState;
|
|
long packetlen, maxlen;
|
|
unsigned char *data;
|
|
unsigned long incoming_sequence, outgoing_sequence;
|
|
PktIn *pktin;
|
|
|
|
BinaryPacketProtocol bpp;
|
|
};
|
|
|
|
static void ssh2_bare_bpp_free(BinaryPacketProtocol *bpp);
|
|
static void ssh2_bare_bpp_handle_input(BinaryPacketProtocol *bpp);
|
|
static PktOut *ssh2_bare_bpp_new_pktout(int type);
|
|
static void ssh2_bare_bpp_format_packet(BinaryPacketProtocol *bpp, PktOut *);
|
|
|
|
static const struct BinaryPacketProtocolVtable ssh2_bare_bpp_vtable = {
|
|
ssh2_bare_bpp_free,
|
|
ssh2_bare_bpp_handle_input,
|
|
ssh2_bare_bpp_new_pktout,
|
|
ssh2_bare_bpp_format_packet,
|
|
};
|
|
|
|
BinaryPacketProtocol *ssh2_bare_bpp_new(void)
|
|
{
|
|
struct ssh2_bare_bpp_state *s = snew(struct ssh2_bare_bpp_state);
|
|
memset(s, 0, sizeof(*s));
|
|
s->bpp.vt = &ssh2_bare_bpp_vtable;
|
|
return &s->bpp;
|
|
}
|
|
|
|
static void ssh2_bare_bpp_free(BinaryPacketProtocol *bpp)
|
|
{
|
|
struct ssh2_bare_bpp_state *s =
|
|
FROMFIELD(bpp, struct ssh2_bare_bpp_state, bpp);
|
|
if (s->pktin)
|
|
ssh_unref_packet(s->pktin);
|
|
sfree(s);
|
|
}
|
|
|
|
static void ssh2_bare_bpp_handle_input(BinaryPacketProtocol *bpp)
|
|
{
|
|
struct ssh2_bare_bpp_state *s =
|
|
FROMFIELD(bpp, struct ssh2_bare_bpp_state, bpp);
|
|
|
|
crBegin(s->crState);
|
|
|
|
while (1) {
|
|
/* Read the length field. */
|
|
{
|
|
unsigned char lenbuf[4];
|
|
crMaybeWaitUntilV(bufchain_try_fetch_consume(
|
|
s->bpp.in_raw, lenbuf, 4));
|
|
s->packetlen = toint(GET_32BIT_MSB_FIRST(lenbuf));
|
|
}
|
|
|
|
if (s->packetlen <= 0 || s->packetlen >= (long)OUR_V2_PACKETLIMIT) {
|
|
s->bpp.error = dupstr("Invalid packet length received");
|
|
crStopV;
|
|
}
|
|
|
|
/*
|
|
* Allocate the packet to return, now we know its length.
|
|
*/
|
|
s->pktin = snew_plus(PktIn, s->packetlen);
|
|
s->pktin->qnode.prev = s->pktin->qnode.next = NULL;
|
|
s->maxlen = 0;
|
|
s->pktin->refcount = 1;
|
|
s->data = snew_plus_get_aux(s->pktin);
|
|
|
|
s->pktin->sequence = s->incoming_sequence++;
|
|
|
|
/*
|
|
* Read the remainder of the packet.
|
|
*/
|
|
crMaybeWaitUntilV(bufchain_try_fetch_consume(
|
|
s->bpp.in_raw, s->data, s->packetlen));
|
|
|
|
/*
|
|
* The data we just read is precisely the initial type byte
|
|
* followed by the packet payload.
|
|
*/
|
|
s->pktin->type = s->data[0];
|
|
s->data++;
|
|
s->packetlen--;
|
|
BinarySource_INIT(s->pktin, s->data, s->packetlen);
|
|
|
|
/*
|
|
* Log incoming packet, possibly omitting sensitive fields.
|
|
*/
|
|
if (s->bpp.logctx) {
|
|
logblank_t blanks[MAX_BLANKS];
|
|
int nblanks = ssh2_censor_packet(
|
|
s->bpp.pls, s->pktin->type, FALSE,
|
|
make_ptrlen(s->data, s->packetlen), blanks);
|
|
log_packet(s->bpp.logctx, PKT_INCOMING, s->pktin->type,
|
|
ssh2_pkt_type(s->bpp.pls->kctx, s->bpp.pls->actx,
|
|
s->pktin->type),
|
|
get_ptr(s->pktin), get_avail(s->pktin), nblanks, blanks,
|
|
&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);
|
|
|
|
{
|
|
int type = s->pktin->type;
|
|
s->pktin = NULL;
|
|
|
|
if (type == SSH2_MSG_DISCONNECT)
|
|
s->bpp.seen_disconnect = TRUE;
|
|
}
|
|
}
|
|
crFinishV;
|
|
}
|
|
|
|
static PktOut *ssh2_bare_bpp_new_pktout(int pkt_type)
|
|
{
|
|
PktOut *pkt = ssh_new_packet();
|
|
pkt->length = 4; /* space for packet length */
|
|
pkt->type = pkt_type;
|
|
put_byte(pkt, pkt_type);
|
|
return pkt;
|
|
}
|
|
|
|
static void ssh2_bare_bpp_format_packet(BinaryPacketProtocol *bpp, PktOut *pkt)
|
|
{
|
|
struct ssh2_bare_bpp_state *s =
|
|
FROMFIELD(bpp, struct ssh2_bare_bpp_state, bpp);
|
|
|
|
if (s->bpp.logctx) {
|
|
ptrlen pktdata = make_ptrlen(pkt->data + 5, pkt->length - 5);
|
|
logblank_t blanks[MAX_BLANKS];
|
|
int nblanks = ssh2_censor_packet(
|
|
s->bpp.pls, pkt->type, TRUE, pktdata, blanks);
|
|
log_packet(s->bpp.logctx, PKT_OUTGOING, pkt->type,
|
|
ssh2_pkt_type(s->bpp.pls->kctx, s->bpp.pls->actx,
|
|
pkt->type),
|
|
pktdata.ptr, pktdata.len, nblanks, blanks,
|
|
&s->outgoing_sequence,
|
|
pkt->downstream_id, pkt->additional_log_text);
|
|
}
|
|
|
|
s->outgoing_sequence++; /* only for diagnostics, really */
|
|
|
|
PUT_32BIT(pkt->data, pkt->length - 4);
|
|
bufchain_add(s->bpp.out_raw, pkt->data, pkt->length);
|
|
|
|
ssh_free_pktout(pkt);
|
|
}
|