| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188 | /* * 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 void ssh2_bare_bpp_handle_output(BinaryPacketProtocol *bpp);static PktOut *ssh2_bare_bpp_new_pktout(int type);static const struct BinaryPacketProtocolVtable ssh2_bare_bpp_vtable = {    ssh2_bare_bpp_free,    ssh2_bare_bpp_handle_input,    ssh2_bare_bpp_handle_output,    ssh2_bare_bpp_new_pktout,    ssh2_bpp_queue_disconnect, /* in sshcommon.c */};BinaryPacketProtocol *ssh2_bare_bpp_new(LogContext *logctx){    struct ssh2_bare_bpp_state *s = snew(struct ssh2_bare_bpp_state);    memset(s, 0, sizeof(*s));    s->bpp.vt = &ssh2_bare_bpp_vtable;    s->bpp.logctx = logctx;    ssh_bpp_common_setup(&s->bpp);    return &s->bpp;}static void ssh2_bare_bpp_free(BinaryPacketProtocol *bpp){    struct ssh2_bare_bpp_state *s =        container_of(bpp, struct ssh2_bare_bpp_state, bpp);    sfree(s->pktin);    sfree(s);}#define BPP_READ(ptr, len) do                                           \    {                                                                   \        bool success;                                                   \        crMaybeWaitUntilV((success = bufchain_try_fetch_consume(        \                               s->bpp.in_raw, ptr, len)) ||             \                          s->bpp.input_eof);                            \        if (!success)                                                   \            goto eof;                                                   \        ssh_check_frozen(s->bpp.ssh);                                   \    } while (0)static void ssh2_bare_bpp_handle_input(BinaryPacketProtocol *bpp){    struct ssh2_bare_bpp_state *s =        container_of(bpp, struct ssh2_bare_bpp_state, bpp);    crBegin(s->crState);    while (1) {        /* Read the length field. */        {            unsigned char lenbuf[4];            BPP_READ(lenbuf, 4);            s->packetlen = toint(GET_32BIT_MSB_FIRST(lenbuf));        }        if (s->packetlen <= 0 || s->packetlen >= (long)OUR_V2_PACKETLIMIT) {            ssh_sw_abort(s->bpp.ssh, "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->pktin->qnode.on_free_queue = false;        s->maxlen = 0;        s->data = snew_plus_get_aux(s->pktin);        s->pktin->sequence = s->incoming_sequence++;        /*         * Read the remainder of the packet.         */        BPP_READ(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);        s->pktin = NULL;    }  eof:    if (!s->bpp.expect_close) {        ssh_remote_error(s->bpp.ssh,                         "Remote side unexpectedly closed network connection");    } else {        ssh_remote_eof(s->bpp.ssh, "Remote side closed network connection");    }    return;  /* avoid touching s now it's been freed */    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(struct ssh2_bare_bpp_state *s,                                        PktOut *pkt){    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_MSB_FIRST(pkt->data, pkt->length - 4);    bufchain_add(s->bpp.out_raw, pkt->data, pkt->length);}static void ssh2_bare_bpp_handle_output(BinaryPacketProtocol *bpp){    struct ssh2_bare_bpp_state *s =        container_of(bpp, struct ssh2_bare_bpp_state, bpp);    PktOut *pkt;    while ((pkt = pq_pop(&s->bpp.out_pq)) != NULL) {        ssh2_bare_bpp_format_packet(s, pkt);        ssh_free_pktout(pkt);    }}
 |