1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-02-03 21:52:24 +00:00

Use strbuf to tidy up sshshare.c.

Another big pile of packet-construction now looks simpler and nicer,
although - as with the agent messages - I've done that tiny cheat of
filling in the length field at the start of the packet frame at the
very end of processing.
This commit is contained in:
Simon Tatham 2018-05-24 13:27:34 +01:00
parent b6cbad89fc
commit 855a6eaadd

View File

@ -709,6 +709,8 @@ static void send_packet_to_downstream(struct ssh_sharing_connstate *cs,
int type, const void *pkt, int pktlen, int type, const void *pkt, int pktlen,
struct share_channel *chan) struct share_channel *chan)
{ {
strbuf *packet;
if (!cs->sock) /* throw away all packets destined for a dead downstream */ if (!cs->sock) /* throw away all packets destined for a dead downstream */
return; return;
@ -729,7 +731,6 @@ static void send_packet_to_downstream(struct ssh_sharing_connstate *cs,
* send them as separate CHANNEL_DATA packets. * send them as separate CHANNEL_DATA packets.
*/ */
const char *upkt = (const char *)pkt; const char *upkt = (const char *)pkt;
char header[13]; /* 4 length + 1 type + 4 channel id + 4 string len */
int len = toint(GET_32BIT(upkt + 4)); int len = toint(GET_32BIT(upkt + 4));
upkt += 8; /* skip channel id + length field */ upkt += 8; /* skip channel id + length field */
@ -740,25 +741,30 @@ static void send_packet_to_downstream(struct ssh_sharing_connstate *cs,
do { do {
int this_len = (len > chan->downstream_maxpkt ? int this_len = (len > chan->downstream_maxpkt ?
chan->downstream_maxpkt : len); chan->downstream_maxpkt : len);
PUT_32BIT(header, this_len + 9);
header[4] = type; packet = strbuf_new();
PUT_32BIT(header + 5, chan->downstream_id); put_uint32(packet, 0); /* placeholder for length field */
PUT_32BIT(header + 9, this_len); put_byte(packet, type);
sk_write(cs->sock, header, 13); put_uint32(packet, chan->downstream_id);
sk_write(cs->sock, upkt, this_len); put_uint32(packet, this_len);
put_data(packet, upkt, this_len);
len -= this_len; len -= this_len;
upkt += this_len; upkt += this_len;
PUT_32BIT(packet->s, packet->len-4);
sk_write(cs->sock, packet->s, packet->len);
strbuf_free(packet);
} while (len > 0); } while (len > 0);
} else { } else {
/* /*
* Just do the obvious thing. * Just do the obvious thing.
*/ */
char header[9]; packet = strbuf_new();
put_uint32(packet, 0); /* placeholder for length field */
PUT_32BIT(header, pktlen + 1); put_byte(packet, type);
header[4] = type; put_data(packet, pkt, pktlen);
sk_write(cs->sock, header, 5); PUT_32BIT(packet->s, packet->len-4);
sk_write(cs->sock, pkt, pktlen); sk_write(cs->sock, packet->s, packet->len);
strbuf_free(packet);
} }
} }
@ -778,19 +784,18 @@ static void share_try_cleanup(struct ssh_sharing_connstate *cs)
index234(cs->halfchannels, 0)) != NULL) { index234(cs->halfchannels, 0)) != NULL) {
static const char reason[] = "PuTTY downstream no longer available"; static const char reason[] = "PuTTY downstream no longer available";
static const char lang[] = "en"; static const char lang[] = "en";
unsigned char packet[256]; strbuf *packet;
int pos = 0;
PUT_32BIT(packet + pos, hc->server_id); pos += 4; packet = strbuf_new();
PUT_32BIT(packet + pos, SSH2_OPEN_CONNECT_FAILED); pos += 4; put_uint32(packet, hc->server_id);
PUT_32BIT(packet + pos, strlen(reason)); pos += 4; put_uint32(packet, SSH2_OPEN_CONNECT_FAILED);
memcpy(packet + pos, reason, strlen(reason)); pos += strlen(reason); put_stringz(packet, reason);
PUT_32BIT(packet + pos, strlen(lang)); pos += 4; put_stringz(packet, lang);
memcpy(packet + pos, lang, strlen(lang)); pos += strlen(lang); ssh_send_packet_from_downstream(
ssh_send_packet_from_downstream(cs->parent->ssh, cs->id, cs->parent->ssh, cs->id, SSH2_MSG_CHANNEL_OPEN_FAILURE,
SSH2_MSG_CHANNEL_OPEN_FAILURE, packet->s, packet->len,
packet, pos, "cleanup after" "cleanup after downstream went away");
" downstream went away"); strbuf_free(packet);
share_remove_halfchannel(cs, hc); share_remove_halfchannel(cs, hc);
} }
@ -810,15 +815,17 @@ static void share_try_cleanup(struct ssh_sharing_connstate *cs)
*/ */
for (i = 0; (chan = (struct share_channel *) for (i = 0; (chan = (struct share_channel *)
index234(cs->channels_by_us, i)) != NULL; i++) { index234(cs->channels_by_us, i)) != NULL; i++) {
unsigned char packet[256]; strbuf *packet;
int pos = 0;
if (chan->state != SENT_CLOSE && chan->state != UNACKNOWLEDGED) { if (chan->state != SENT_CLOSE && chan->state != UNACKNOWLEDGED) {
PUT_32BIT(packet + pos, chan->server_id); pos += 4; packet = strbuf_new();
ssh_send_packet_from_downstream(cs->parent->ssh, cs->id, put_uint32(packet, chan->server_id);
SSH2_MSG_CHANNEL_CLOSE, ssh_send_packet_from_downstream(
packet, pos, "cleanup after" cs->parent->ssh, cs->id, SSH2_MSG_CHANNEL_CLOSE,
" downstream went away"); packet->s, packet->len,
"cleanup after downstream went away");
strbuf_free(packet);
if (chan->state != RCVD_CLOSE) { if (chan->state != RCVD_CLOSE) {
chan->state = SENT_CLOSE; chan->state = SENT_CLOSE;
} else { } else {
@ -841,27 +848,16 @@ static void share_try_cleanup(struct ssh_sharing_connstate *cs)
for (i = 0; (fwd = (struct share_forwarding *) for (i = 0; (fwd = (struct share_forwarding *)
index234(cs->forwardings, i)) != NULL; i++) { index234(cs->forwardings, i)) != NULL; i++) {
if (fwd->active) { if (fwd->active) {
static const char request[] = "cancel-tcpip-forward"; strbuf *packet = strbuf_new();
char *packet = snewn(256 + strlen(fwd->host), char); put_stringz(packet, "cancel-tcpip-forward");
int pos = 0; put_bool(packet, FALSE); /* !want_reply */
put_stringz(packet, fwd->host);
PUT_32BIT(packet + pos, strlen(request)); pos += 4; put_uint32(packet, fwd->port);
memcpy(packet + pos, request, strlen(request)); ssh_send_packet_from_downstream(
pos += strlen(request); cs->parent->ssh, cs->id, SSH2_MSG_GLOBAL_REQUEST,
packet->s, packet->len,
packet[pos++] = 0; /* !want_reply */ "cleanup after downstream went away");
strbuf_free(packet);
PUT_32BIT(packet + pos, strlen(fwd->host)); pos += 4;
memcpy(packet + pos, fwd->host, strlen(fwd->host));
pos += strlen(fwd->host);
PUT_32BIT(packet + pos, fwd->port); pos += 4;
ssh_send_packet_from_downstream(cs->parent->ssh, cs->id,
SSH2_MSG_GLOBAL_REQUEST,
packet, pos, "cleanup after"
" downstream went away");
sfree(packet);
share_remove_forwarding(cs, fwd); share_remove_forwarding(cs, fwd);
i--; /* don't accidentally skip one as a result */ i--; /* don't accidentally skip one as a result */
@ -892,21 +888,13 @@ static void share_begin_cleanup(struct ssh_sharing_connstate *cs)
static void share_disconnect(struct ssh_sharing_connstate *cs, static void share_disconnect(struct ssh_sharing_connstate *cs,
const char *message) const char *message)
{ {
static const char lang[] = "en"; strbuf *packet = strbuf_new();
int msglen = strlen(message); put_uint32(packet, SSH2_DISCONNECT_PROTOCOL_ERROR);
char *packet = snewn(msglen + 256, char); put_stringz(packet, message);
int pos = 0; put_stringz(packet, "en"); /* language */
send_packet_to_downstream(cs, SSH2_MSG_DISCONNECT,
PUT_32BIT(packet + pos, SSH2_DISCONNECT_PROTOCOL_ERROR); pos += 4; packet->s, packet->len, NULL);
strbuf_free(packet);
PUT_32BIT(packet + pos, msglen); pos += 4;
memcpy(packet + pos, message, msglen);
pos += msglen;
PUT_32BIT(packet + pos, strlen(lang)); pos += 4;
memcpy(packet + pos, lang, strlen(lang)); pos += strlen(lang);
send_packet_to_downstream(cs, SSH2_MSG_DISCONNECT, packet, pos, NULL);
share_begin_cleanup(cs); share_begin_cleanup(cs);
} }
@ -976,12 +964,10 @@ static int getstring_size(const void *data, int datalen)
} }
/* /*
* Append a message to the end of an xchannel's queue, with the length * Append a message to the end of an xchannel's queue.
* and type code filled in and the data block allocated but
* uninitialised.
*/ */
struct share_xchannel_message *share_xchannel_add_message static void share_xchannel_add_message(
(struct share_xchannel *xc, int type, int len) struct share_xchannel *xc, int type, const void *data, int len)
{ {
unsigned char *block; unsigned char *block;
struct share_xchannel_message *msg; struct share_xchannel_message *msg;
@ -996,6 +982,7 @@ struct share_xchannel_message *share_xchannel_add_message
msg->data = block + sizeof(struct share_xchannel_message); msg->data = block + sizeof(struct share_xchannel_message);
msg->datalen = len; msg->datalen = len;
msg->type = type; msg->type = type;
memcpy(msg->data, data, len);
/* /*
* Queue it in the xchannel. * Queue it in the xchannel.
@ -1006,8 +993,6 @@ struct share_xchannel_message *share_xchannel_add_message
xc->msghead = msg; xc->msghead = msg;
msg->next = NULL; msg->next = NULL;
xc->msgtail = msg; xc->msgtail = msg;
return msg;
} }
void share_dead_xchannel_respond(struct ssh_sharing_connstate *cs, void share_dead_xchannel_respond(struct ssh_sharing_connstate *cs,
@ -1030,11 +1015,13 @@ void share_dead_xchannel_respond(struct ssh_sharing_connstate *cs,
int wantreplypos = getstring_size(msg->data, msg->datalen); int wantreplypos = getstring_size(msg->data, msg->datalen);
if (wantreplypos > 0 && wantreplypos < msg->datalen && if (wantreplypos > 0 && wantreplypos < msg->datalen &&
msg->data[wantreplypos] != 0) { msg->data[wantreplypos] != 0) {
unsigned char id[4]; strbuf *packet = strbuf_new();
PUT_32BIT(id, xc->server_id); put_uint32(packet, xc->server_id);
ssh_send_packet_from_downstream ssh_send_packet_from_downstream
(cs->parent->ssh, cs->id, SSH2_MSG_CHANNEL_FAILURE, id, 4, (cs->parent->ssh, cs->id, SSH2_MSG_CHANNEL_FAILURE,
packet->s, packet->len,
"downstream refused X channel open"); "downstream refused X channel open");
strbuf_free(packet);
} }
} else if (msg->type == SSH2_MSG_CHANNEL_CLOSE) { } else if (msg->type == SSH2_MSG_CHANNEL_CLOSE) {
/* /*
@ -1057,7 +1044,7 @@ void share_xchannel_confirmation(struct ssh_sharing_connstate *cs,
struct share_channel *chan, struct share_channel *chan,
unsigned downstream_window) unsigned downstream_window)
{ {
unsigned char window_adjust[8]; strbuf *packet;
/* /*
* Send all the queued messages downstream. * Send all the queued messages downstream.
@ -1079,12 +1066,14 @@ void share_xchannel_confirmation(struct ssh_sharing_connstate *cs,
* size downstream thinks it's presented with the one we've * size downstream thinks it's presented with the one we've
* actually presented. * actually presented.
*/ */
PUT_32BIT(window_adjust, xc->server_id); packet = strbuf_new();
PUT_32BIT(window_adjust + 4, downstream_window - xc->window); put_uint32(packet, xc->server_id);
ssh_send_packet_from_downstream(cs->parent->ssh, cs->id, put_uint32(packet, downstream_window - xc->window);
SSH2_MSG_CHANNEL_WINDOW_ADJUST, ssh_send_packet_from_downstream(
window_adjust, 8, "window adjustment after" cs->parent->ssh, cs->id, SSH2_MSG_CHANNEL_WINDOW_ADJUST,
" downstream accepted X channel"); packet->s, packet->len,
"window adjustment after downstream accepted X channel");
strbuf_free(packet);
} }
void share_xchannel_failure(struct ssh_sharing_connstate *cs, void share_xchannel_failure(struct ssh_sharing_connstate *cs,
@ -1094,11 +1083,13 @@ void share_xchannel_failure(struct ssh_sharing_connstate *cs,
* If downstream refuses to open our X channel at all for some * If downstream refuses to open our X channel at all for some
* reason, we must respond by sending an emergency CLOSE upstream. * reason, we must respond by sending an emergency CLOSE upstream.
*/ */
unsigned char id[4]; strbuf *packet = strbuf_new();
PUT_32BIT(id, xc->server_id); put_uint32(packet, xc->server_id);
ssh_send_packet_from_downstream ssh_send_packet_from_downstream(
(cs->parent->ssh, cs->id, SSH2_MSG_CHANNEL_CLOSE, id, 4, cs->parent->ssh, cs->id, SSH2_MSG_CHANNEL_CLOSE,
"downstream refused X channel open"); packet->s, packet->len,
"downstream refused X channel open");
strbuf_free(packet);
/* /*
* Now mark the xchannel as dead, and respond to anything sent on * Now mark the xchannel as dead, and respond to anything sent on
@ -1119,11 +1110,9 @@ void share_setup_x11_channel(void *csv, void *chanv,
struct ssh_sharing_connstate *cs = (struct ssh_sharing_connstate *)csv; struct ssh_sharing_connstate *cs = (struct ssh_sharing_connstate *)csv;
struct share_channel *chan = (struct share_channel *)chanv; struct share_channel *chan = (struct share_channel *)chanv;
struct share_xchannel *xc; struct share_xchannel *xc;
struct share_xchannel_message *msg;
void *greeting; void *greeting;
int greeting_len; int greeting_len;
unsigned char *pkt; strbuf *packet;
int pktlen;
/* /*
* Create an xchannel containing data we've already received from * Create an xchannel containing data we've already received from
@ -1136,32 +1125,32 @@ void share_setup_x11_channel(void *csv, void *chanv,
chan->x11_auth_proto, chan->x11_auth_proto,
chan->x11_auth_data, chan->x11_auth_datalen, chan->x11_auth_data, chan->x11_auth_datalen,
peer_addr, peer_port, &greeting_len); peer_addr, peer_port, &greeting_len);
msg = share_xchannel_add_message(xc, SSH2_MSG_CHANNEL_DATA, packet = strbuf_new();
8 + greeting_len + initial_len); put_uint32(packet, 0); /* leave the channel id field unfilled - we
/* leave the channel id field unfilled - we don't know the * don't know the downstream id yet */
* downstream id yet, of course */ put_uint32(packet, greeting_len + initial_len);
PUT_32BIT(msg->data + 4, greeting_len + initial_len); put_data(packet, greeting, greeting_len);
memcpy(msg->data + 8, greeting, greeting_len); put_data(packet, initial_data, initial_len);
memcpy(msg->data + 8 + greeting_len, initial_data, initial_len);
sfree(greeting); sfree(greeting);
share_xchannel_add_message(xc, SSH2_MSG_CHANNEL_DATA,
packet->s, packet->len);
strbuf_free(packet);
xc->window = client_adjusted_window + greeting_len; xc->window = client_adjusted_window + greeting_len;
/* /*
* Send on a CHANNEL_OPEN to downstream. * Send on a CHANNEL_OPEN to downstream.
*/ */
pktlen = 27 + strlen(peer_addr); packet = strbuf_new();
pkt = snewn(pktlen, unsigned char); put_stringz(packet, "x11");
PUT_32BIT(pkt, 3); /* strlen("x11") */ put_uint32(packet, server_id);
memcpy(pkt+4, "x11", 3); put_uint32(packet, server_currwin);
PUT_32BIT(pkt+7, server_id); put_uint32(packet, server_maxpkt);
PUT_32BIT(pkt+11, server_currwin); put_stringz(packet, peer_addr);
PUT_32BIT(pkt+15, server_maxpkt); put_uint32(packet, peer_port);
PUT_32BIT(pkt+19, strlen(peer_addr)); send_packet_to_downstream(cs, SSH2_MSG_CHANNEL_OPEN,
memcpy(pkt+23, peer_addr, strlen(peer_addr)); packet->s, packet->len, NULL);
PUT_32BIT(pkt+23+strlen(peer_addr), peer_port); strbuf_free(packet);
send_packet_to_downstream(cs, SSH2_MSG_CHANNEL_OPEN, pkt, pktlen, NULL);
sfree(pkt);
/* /*
* If this was a once-only X forwarding, clean it up now. * If this was a once-only X forwarding, clean it up now.
@ -1289,10 +1278,7 @@ void share_got_pkt_from_server(void *csv, int type,
* The unusual case: this id refers to an xchannel. Add it * The unusual case: this id refers to an xchannel. Add it
* to the xchannel's queue. * to the xchannel's queue.
*/ */
struct share_xchannel_message *msg; share_xchannel_add_message(xc, type, pkt, pktlen);
msg = share_xchannel_add_message(xc, type, pktlen);
memcpy(msg->data, pkt, pktlen);
/* If the xchannel is dead, then also respond to it (which /* If the xchannel is dead, then also respond to it (which
* may involve deleting the channel). */ * may involve deleting the channel). */
@ -1319,6 +1305,7 @@ static void share_got_pkt_from_downstream(struct ssh_sharing_connstate *cs,
struct share_channel *chan; struct share_channel *chan;
struct share_halfchannel *hc; struct share_halfchannel *hc;
struct share_xchannel *xc; struct share_xchannel *xc;
strbuf *packet;
char *err = NULL; char *err = NULL;
switch (type) { switch (type) {
@ -1614,15 +1601,17 @@ static void share_got_pkt_from_downstream(struct ssh_sharing_connstate *cs,
if (!strcmp(request_name, "auth-agent-req@openssh.com") && if (!strcmp(request_name, "auth-agent-req@openssh.com") &&
!ssh_agent_forwarding_permitted(cs->parent->ssh)) { !ssh_agent_forwarding_permitted(cs->parent->ssh)) {
unsigned server_id = GET_32BIT(pkt); unsigned server_id = GET_32BIT(pkt);
unsigned char recipient_id[4];
sfree(request_name); sfree(request_name);
chan = share_find_channel_by_server(cs, server_id); chan = share_find_channel_by_server(cs, server_id);
if (chan) { if (chan) {
PUT_32BIT(recipient_id, chan->downstream_id); packet = strbuf_new();
send_packet_to_downstream(cs, SSH2_MSG_CHANNEL_FAILURE, put_uint32(packet, chan->downstream_id);
recipient_id, 4, NULL); send_packet_to_downstream(
cs, SSH2_MSG_CHANNEL_FAILURE,
packet->s, packet->len, NULL);
strbuf_free(packet);
} else { } else {
char *buf = dupprintf("Agent forwarding request for " char *buf = dupprintf("Agent forwarding request for "
"unrecognised channel %u", server_id); "unrecognised channel %u", server_id);
@ -1646,7 +1635,7 @@ static void share_got_pkt_from_downstream(struct ssh_sharing_connstate *cs,
unsigned server_id = GET_32BIT(pkt); unsigned server_id = GET_32BIT(pkt);
int want_reply, single_connection, screen; int want_reply, single_connection, screen;
char *auth_proto_str, *auth_data; char *auth_proto_str, *auth_data;
int auth_proto, protolen, datalen; int auth_proto;
int pos; int pos;
sfree(request_name); sfree(request_name);
@ -1688,10 +1677,12 @@ static void share_got_pkt_from_downstream(struct ssh_sharing_connstate *cs,
if (auth_proto < 0) { if (auth_proto < 0) {
/* Reject due to not understanding downstream's /* Reject due to not understanding downstream's
* requested authorisation method. */ * requested authorisation method. */
unsigned char recipient_id[4]; packet = strbuf_new();
PUT_32BIT(recipient_id, chan->downstream_id); put_uint32(packet, chan->downstream_id);
send_packet_to_downstream(cs, SSH2_MSG_CHANNEL_FAILURE, send_packet_to_downstream(
recipient_id, 4, NULL); cs, SSH2_MSG_CHANNEL_FAILURE,
packet->s, packet->len, NULL);
strbuf_free(packet);
sfree(auth_data); sfree(auth_data);
break; break;
} }
@ -1710,25 +1701,18 @@ static void share_got_pkt_from_downstream(struct ssh_sharing_connstate *cs,
* containing our own auth data, and send that to the * containing our own auth data, and send that to the
* server. * server.
*/ */
protolen = strlen(chan->x11_auth_upstream->protoname); packet = strbuf_new();
datalen = strlen(chan->x11_auth_upstream->datastring); put_uint32(packet, server_id);
pktlen = 29+protolen+datalen; put_stringz(packet, "x11-req");
pkt = snewn(pktlen, unsigned char); put_bool(packet, want_reply);
PUT_32BIT(pkt, server_id); put_bool(packet, single_connection);
PUT_32BIT(pkt+4, 7); /* strlen("x11-req") */ put_stringz(packet, chan->x11_auth_upstream->protoname);
memcpy(pkt+8, "x11-req", 7); put_stringz(packet, chan->x11_auth_upstream->datastring);
pkt[15] = want_reply; put_uint32(packet, screen);
pkt[16] = single_connection; ssh_send_packet_from_downstream(
PUT_32BIT(pkt+17, protolen); cs->parent->ssh, cs->id, SSH2_MSG_CHANNEL_REQUEST,
memcpy(pkt+21, chan->x11_auth_upstream->protoname, protolen); packet->s, packet->len, NULL);
PUT_32BIT(pkt+21+protolen, datalen); strbuf_free(packet);
memcpy(pkt+25+protolen, chan->x11_auth_upstream->datastring,
datalen);
PUT_32BIT(pkt+25+protolen+datalen, screen);
ssh_send_packet_from_downstream(cs->parent->ssh, cs->id,
SSH2_MSG_CHANNEL_REQUEST,
pkt, pktlen, NULL);
sfree(pkt);
break; break;
} }