From 7b93b3d2e923d5e7603a10bcbf7a31219b50b270 Mon Sep 17 00:00:00 2001 From: Michael Jumper Date: Sat, 21 Dec 2019 22:51:43 -0800 Subject: [PATCH] GUACAMOLE-249: Gradually reassemble received chunks of RDPSND data. --- .../rdp/guac_rdpsnd/rdpsnd_service.c | 42 +++++++++++++++++-- .../rdp/guac_rdpsnd/rdpsnd_service.h | 15 +++++++ 2 files changed, 54 insertions(+), 3 deletions(-) diff --git a/src/protocols/rdp/guac_rdpsnd/rdpsnd_service.c b/src/protocols/rdp/guac_rdpsnd/rdpsnd_service.c index b18a2652..88048a3a 100644 --- a/src/protocols/rdp/guac_rdpsnd/rdpsnd_service.c +++ b/src/protocols/rdp/guac_rdpsnd/rdpsnd_service.c @@ -161,9 +161,45 @@ static VOID guac_rdpsnd_handle_open_event(LPVOID user_param, return; } - wStream* input_stream = Stream_New(data, data_length); - guac_rdpsnd_process_receive(rdpsnd, input_stream); - Stream_Free(input_stream, FALSE); + /* If receiving first chunk, allocate sufficient space for all remaining + * chunks */ + if (data_flags & CHANNEL_FLAG_FIRST) { + + /* Limit maximum received size */ + if (total_length > GUAC_SVC_MAX_ASSEMBLED_LENGTH) { + guac_client_log(rdpsnd->client, GUAC_LOG_WARNING, "RDP server has " + "requested to send a sequence of %i bytes, but this " + "exceeds the maximum buffer space of %i bytes. Received " + "data may be truncated.", total_length, + GUAC_SVC_MAX_ASSEMBLED_LENGTH); + total_length = GUAC_SVC_MAX_ASSEMBLED_LENGTH; + } + + rdpsnd->input_stream = Stream_New(NULL, total_length); + } + + /* Add chunk to buffer only if sufficient space remains */ + if (Stream_EnsureRemainingCapacity(rdpsnd->input_stream, data_length)) + Stream_Write(rdpsnd->input_stream, data, data_length); + else + guac_client_log(rdpsnd->client, GUAC_LOG_WARNING, "%i bytes of data " + "received from within the remote desktop session for the " + "RDPSND channel are being dropped because the maximum " + "available space for received data has been exceeded.", + data_length, rdpsnd->channel_def.name, open_handle, + rdpsnd->open_handle); + + /* Fire event once last chunk has been received */ + if (data_flags & CHANNEL_FLAG_LAST) { + + Stream_SealLength(rdpsnd->input_stream); + Stream_SetPosition(rdpsnd->input_stream, 0); + + guac_rdpsnd_process_receive(rdpsnd, rdpsnd->input_stream); + + Stream_Free(rdpsnd->input_stream, TRUE); + + } } diff --git a/src/protocols/rdp/guac_rdpsnd/rdpsnd_service.h b/src/protocols/rdp/guac_rdpsnd/rdpsnd_service.h index de615ab0..f78df847 100644 --- a/src/protocols/rdp/guac_rdpsnd/rdpsnd_service.h +++ b/src/protocols/rdp/guac_rdpsnd/rdpsnd_service.h @@ -34,6 +34,13 @@ */ #define GUAC_RDP_MAX_FORMATS 16 +/** + * The maximum number of bytes that the RDP server will be allowed to send + * within any single write operation, regardless of the number of chunks that + * write is split into. Bytes beyond this limit may be dropped. + */ +#define GUAC_SVC_MAX_ASSEMBLED_LENGTH 1048576 + /** * Abstract representation of a PCM format, including the sample rate, number * of channels, and bits per sample. @@ -103,6 +110,14 @@ typedef struct guac_rdpsnd { */ DWORD open_handle; + /** + * All data that has been received thus far from the current RDP server + * write operation. Data received along virtual channels is sent in chunks + * (typically 1600 bytes), and thus must be gradually reassembled as it is + * received. + */ + wStream* input_stream; + /** * The block number of the last SNDC_WAVE (WaveInfo) PDU received. */