1 /*
2  * Trivial binary packet protocol for the 'bare' ssh-connection
3  * protocol used in PuTTY's SSH-2 connection sharing system.
4  */
5 
6 #include <assert.h>
7 
8 #include "putty.h"
9 #include "ssh.h"
10 #include "sshbpp.h"
11 #include "sshcr.h"
12 
13 struct ssh2_bare_bpp_state {
14     int crState;
15     long packetlen, maxlen;
16     unsigned char *data;
17     unsigned long incoming_sequence, outgoing_sequence;
18     PktIn *pktin;
19 
20     BinaryPacketProtocol bpp;
21 };
22 
23 static void ssh2_bare_bpp_free(BinaryPacketProtocol *bpp);
24 static void ssh2_bare_bpp_handle_input(BinaryPacketProtocol *bpp);
25 static void ssh2_bare_bpp_handle_output(BinaryPacketProtocol *bpp);
26 static PktOut *ssh2_bare_bpp_new_pktout(int type);
27 
28 static const BinaryPacketProtocolVtable ssh2_bare_bpp_vtable = {
29     .free = ssh2_bare_bpp_free,
30     .handle_input = ssh2_bare_bpp_handle_input,
31     .handle_output = ssh2_bare_bpp_handle_output,
32     .new_pktout = ssh2_bare_bpp_new_pktout,
33     .queue_disconnect = ssh2_bpp_queue_disconnect, /* in sshcommon.c */
34 
35     /* packet size limit, per protocol spec in sshshare.c comment */
36     .packet_size_limit = 0x4000,
37 };
38 
ssh2_bare_bpp_new(LogContext * logctx)39 BinaryPacketProtocol *ssh2_bare_bpp_new(LogContext *logctx)
40 {
41     struct ssh2_bare_bpp_state *s = snew(struct ssh2_bare_bpp_state);
42     memset(s, 0, sizeof(*s));
43     s->bpp.vt = &ssh2_bare_bpp_vtable;
44     s->bpp.logctx = logctx;
45     ssh_bpp_common_setup(&s->bpp);
46     return &s->bpp;
47 }
48 
ssh2_bare_bpp_free(BinaryPacketProtocol * bpp)49 static void ssh2_bare_bpp_free(BinaryPacketProtocol *bpp)
50 {
51     struct ssh2_bare_bpp_state *s =
52         container_of(bpp, struct ssh2_bare_bpp_state, bpp);
53     sfree(s->pktin);
54     sfree(s);
55 }
56 
57 #define BPP_READ(ptr, len) do                                           \
58     {                                                                   \
59         bool success;                                                   \
60         crMaybeWaitUntilV((success = bufchain_try_fetch_consume(        \
61                                s->bpp.in_raw, ptr, len)) ||             \
62                           s->bpp.input_eof);                            \
63         if (!success)                                                   \
64             goto eof;                                                   \
65         ssh_check_frozen(s->bpp.ssh);                                   \
66     } while (0)
67 
ssh2_bare_bpp_handle_input(BinaryPacketProtocol * bpp)68 static void ssh2_bare_bpp_handle_input(BinaryPacketProtocol *bpp)
69 {
70     struct ssh2_bare_bpp_state *s =
71         container_of(bpp, struct ssh2_bare_bpp_state, bpp);
72 
73     crBegin(s->crState);
74 
75     while (1) {
76         /* Read the length field. */
77         {
78             unsigned char lenbuf[4];
79             BPP_READ(lenbuf, 4);
80             s->packetlen = toint(GET_32BIT_MSB_FIRST(lenbuf));
81         }
82 
83         if (s->packetlen <= 0 || s->packetlen >= (long)OUR_V2_PACKETLIMIT) {
84             ssh_sw_abort(s->bpp.ssh, "Invalid packet length received");
85             crStopV;
86         }
87 
88         /*
89          * Allocate the packet to return, now we know its length.
90          */
91         s->pktin = snew_plus(PktIn, s->packetlen);
92         s->pktin->qnode.prev = s->pktin->qnode.next = NULL;
93         s->pktin->qnode.on_free_queue = false;
94         s->maxlen = 0;
95         s->data = snew_plus_get_aux(s->pktin);
96 
97         s->pktin->sequence = s->incoming_sequence++;
98 
99         /*
100          * Read the remainder of the packet.
101          */
102         BPP_READ(s->data, s->packetlen);
103 
104         /*
105          * The data we just read is precisely the initial type byte
106          * followed by the packet payload.
107          */
108         s->pktin->type = s->data[0];
109         s->data++;
110         s->packetlen--;
111         BinarySource_INIT(s->pktin, s->data, s->packetlen);
112 
113         if (s->pktin->type == SSH2_MSG_EXT_INFO) {
114             /*
115              * Mild layer violation: EXT_INFO is not permitted in the
116              * bare ssh-connection protocol. Faulting it here means
117              * that ssh2_common_filter_queue doesn't receive it in the
118              * first place unless it's legal to have sent it.
119              */
120             ssh_proto_error(s->bpp.ssh, "Remote side sent SSH2_MSG_EXT_INFO "
121                             "in bare connection protocol");
122             return;
123         }
124 
125         /*
126          * Log incoming packet, possibly omitting sensitive fields.
127          */
128         if (s->bpp.logctx) {
129             logblank_t blanks[MAX_BLANKS];
130             int nblanks = ssh2_censor_packet(
131                 s->bpp.pls, s->pktin->type, false,
132                 make_ptrlen(s->data, s->packetlen), blanks);
133             log_packet(s->bpp.logctx, PKT_INCOMING, s->pktin->type,
134                        ssh2_pkt_type(s->bpp.pls->kctx, s->bpp.pls->actx,
135                                      s->pktin->type),
136                        get_ptr(s->pktin), get_avail(s->pktin), nblanks, blanks,
137                        &s->pktin->sequence, 0, NULL);
138         }
139 
140         if (ssh2_bpp_check_unimplemented(&s->bpp, s->pktin)) {
141             sfree(s->pktin);
142             s->pktin = NULL;
143             continue;
144         }
145 
146         s->pktin->qnode.formal_size = get_avail(s->pktin);
147         pq_push(&s->bpp.in_pq, s->pktin);
148         s->pktin = NULL;
149     }
150 
151   eof:
152     if (!s->bpp.expect_close) {
153         ssh_remote_error(s->bpp.ssh,
154                          "Remote side unexpectedly closed network connection");
155     } else {
156         ssh_remote_eof(s->bpp.ssh, "Remote side closed network connection");
157     }
158     return;  /* avoid touching s now it's been freed */
159 
160     crFinishV;
161 }
162 
ssh2_bare_bpp_new_pktout(int pkt_type)163 static PktOut *ssh2_bare_bpp_new_pktout(int pkt_type)
164 {
165     PktOut *pkt = ssh_new_packet();
166     pkt->length = 4; /* space for packet length */
167     pkt->type = pkt_type;
168     put_byte(pkt, pkt_type);
169     return pkt;
170 }
171 
ssh2_bare_bpp_format_packet(struct ssh2_bare_bpp_state * s,PktOut * pkt)172 static void ssh2_bare_bpp_format_packet(struct ssh2_bare_bpp_state *s,
173                                         PktOut *pkt)
174 {
175     if (s->bpp.logctx) {
176         ptrlen pktdata = make_ptrlen(pkt->data + 5, pkt->length - 5);
177         logblank_t blanks[MAX_BLANKS];
178         int nblanks = ssh2_censor_packet(
179             s->bpp.pls, pkt->type, true, pktdata, blanks);
180         log_packet(s->bpp.logctx, PKT_OUTGOING, pkt->type,
181                    ssh2_pkt_type(s->bpp.pls->kctx, s->bpp.pls->actx,
182                                  pkt->type),
183                    pktdata.ptr, pktdata.len, nblanks, blanks,
184                    &s->outgoing_sequence,
185                    pkt->downstream_id, pkt->additional_log_text);
186     }
187 
188     s->outgoing_sequence++;        /* only for diagnostics, really */
189 
190     PUT_32BIT_MSB_FIRST(pkt->data, pkt->length - 4);
191     bufchain_add(s->bpp.out_raw, pkt->data, pkt->length);
192 }
193 
ssh2_bare_bpp_handle_output(BinaryPacketProtocol * bpp)194 static void ssh2_bare_bpp_handle_output(BinaryPacketProtocol *bpp)
195 {
196     struct ssh2_bare_bpp_state *s =
197         container_of(bpp, struct ssh2_bare_bpp_state, bpp);
198     PktOut *pkt;
199 
200     while ((pkt = pq_pop(&s->bpp.out_pq)) != NULL) {
201         ssh2_bare_bpp_format_packet(s, pkt);
202         ssh_free_pktout(pkt);
203     }
204 }
205