Implemented 2.2.1.17.1 Persistent Key List PDU Data, added checks

* Implemented missing server side version of PDU (just skip data)
* Refactored read/write functions to properly check stream
  length/capacity and handle return values.
This commit is contained in:
akallabeth 2020-11-19 15:21:49 +01:00 committed by akallabeth
parent bf8a01cb63
commit 5409f4f043
9 changed files with 181 additions and 64 deletions

View File

@ -38,14 +38,18 @@ static const char* const CTRLACTION_STRINGS[] =
*/
static BOOL rdp_recv_server_synchronize_pdu(rdpRdp* rdp, wStream* s);
static BOOL rdp_recv_client_font_list_pdu(wStream* s);
static BOOL rdp_recv_client_persistent_key_list_pdu(wStream* s);
static BOOL rdp_recv_server_font_map_pdu(rdpRdp* rdp, wStream* s);
static BOOL rdp_recv_client_font_map_pdu(rdpRdp* rdp, wStream* s);
static BOOL rdp_send_server_font_map_pdu(rdpRdp* rdp);
static void rdp_write_synchronize_pdu(wStream* s, rdpSettings* settings)
static BOOL rdp_write_synchronize_pdu(wStream* s, rdpSettings* settings)
{
if (Stream_GetRemainingCapacity(s) < 4)
return FALSE;
Stream_Write_UINT16(s, SYNCMSGTYPE_SYNC); /* messageType (2 bytes) */
Stream_Write_UINT16(s, settings->PduSource); /* targetUser (2 bytes) */
return TRUE;
}
BOOL rdp_recv_synchronize_pdu(rdpRdp* rdp, wStream* s)
@ -65,7 +69,13 @@ BOOL rdp_recv_server_synchronize_pdu(rdpRdp* rdp, wStream* s)
BOOL rdp_send_server_synchronize_pdu(rdpRdp* rdp)
{
wStream* s = rdp_data_pdu_init(rdp);
rdp_write_synchronize_pdu(s, rdp->settings);
if (!s)
return FALSE;
if (!rdp_write_synchronize_pdu(s, rdp->settings))
{
Stream_Free(s, TRUE);
return FALSE;
}
return rdp_send_data_pdu(rdp, s, DATA_PDU_TYPE_SYNCHRONIZE, rdp->mcs->userId);
}
@ -90,7 +100,13 @@ BOOL rdp_recv_client_synchronize_pdu(rdpRdp* rdp, wStream* s)
BOOL rdp_send_client_synchronize_pdu(rdpRdp* rdp)
{
wStream* s = rdp_data_pdu_init(rdp);
rdp_write_synchronize_pdu(s, rdp->settings);
if (!s)
return FALSE;
if (!rdp_write_synchronize_pdu(s, rdp->settings))
{
Stream_Free(s, TRUE);
return FALSE;
}
return rdp_send_data_pdu(rdp, s, DATA_PDU_TYPE_SYNCHRONIZE, rdp->mcs->userId);
}
@ -105,11 +121,14 @@ static BOOL rdp_recv_control_pdu(wStream* s, UINT16* action)
return TRUE;
}
static void rdp_write_client_control_pdu(wStream* s, UINT16 action)
static BOOL rdp_write_client_control_pdu(wStream* s, UINT16 action)
{
if (Stream_GetRemainingCapacity(s) < 8)
return FALSE;
Stream_Write_UINT16(s, action); /* action (2 bytes) */
Stream_Write_UINT16(s, 0); /* grantId (2 bytes) */
Stream_Write_UINT32(s, 0); /* controlId (4 bytes) */
return TRUE;
}
BOOL rdp_recv_server_control_pdu(rdpRdp* rdp, wStream* s)
@ -137,6 +156,13 @@ BOOL rdp_recv_server_control_pdu(rdpRdp* rdp, wStream* s)
BOOL rdp_send_server_control_cooperate_pdu(rdpRdp* rdp)
{
wStream* s = rdp_data_pdu_init(rdp);
if (!s)
return FALSE;
if (Stream_GetRemainingCapacity(s) < 8)
{
Stream_Free(s, TRUE);
return FALSE;
}
Stream_Write_UINT16(s, CTRLACTION_COOPERATE); /* action (2 bytes) */
Stream_Write_UINT16(s, 0); /* grantId (2 bytes) */
Stream_Write_UINT32(s, 0); /* controlId (4 bytes) */
@ -146,6 +172,13 @@ BOOL rdp_send_server_control_cooperate_pdu(rdpRdp* rdp)
BOOL rdp_send_server_control_granted_pdu(rdpRdp* rdp)
{
wStream* s = rdp_data_pdu_init(rdp);
if (!s)
return FALSE;
if (Stream_GetRemainingCapacity(s) < 8)
{
Stream_Free(s, TRUE);
return FALSE;
}
Stream_Write_UINT16(s, CTRLACTION_GRANTED_CONTROL); /* action (2 bytes) */
Stream_Write_UINT16(s, rdp->mcs->userId); /* grantId (2 bytes) */
Stream_Write_UINT32(s, 0x03EA); /* controlId (4 bytes) */
@ -155,18 +188,29 @@ BOOL rdp_send_server_control_granted_pdu(rdpRdp* rdp)
BOOL rdp_send_client_control_pdu(rdpRdp* rdp, UINT16 action)
{
wStream* s = rdp_data_pdu_init(rdp);
rdp_write_client_control_pdu(s, action);
if (!s)
return FALSE;
if (!rdp_write_client_control_pdu(s, action))
{
Stream_Free(s, TRUE);
return FALSE;
}
return rdp_send_data_pdu(rdp, s, DATA_PDU_TYPE_CONTROL, rdp->mcs->userId);
}
static void rdp_write_persistent_list_entry(wStream* s, UINT32 key1, UINT32 key2)
static BOOL rdp_write_persistent_list_entry(wStream* s, UINT32 key1, UINT32 key2)
{
if (Stream_GetRemainingCapacity(s) < 8)
return FALSE;
Stream_Write_UINT32(s, key1); /* key1 (4 bytes) */
Stream_Write_UINT32(s, key2); /* key2 (4 bytes) */
return TRUE;
}
static void rdp_write_client_persistent_key_list_pdu(wStream* s, rdpSettings* settings)
static BOOL rdp_write_client_persistent_key_list_pdu(wStream* s, const rdpSettings* settings)
{
if (Stream_GetRemainingCapacity(s) < 24)
return FALSE;
Stream_Write_UINT16(s, 0); /* numEntriesCache0 (2 bytes) */
Stream_Write_UINT16(s, 0); /* numEntriesCache1 (2 bytes) */
Stream_Write_UINT16(s, 0); /* numEntriesCache2 (2 bytes) */
@ -181,38 +225,77 @@ static void rdp_write_client_persistent_key_list_pdu(wStream* s, rdpSettings* se
Stream_Write_UINT8(s, 0); /* pad1 (1 byte) */
Stream_Write_UINT16(s, 0); /* pad3 (2 bytes) */
/* entries */
return TRUE;
}
BOOL rdp_send_client_persistent_key_list_pdu(rdpRdp* rdp)
{
wStream* s;
s = rdp_data_pdu_init(rdp);
rdp_write_client_persistent_key_list_pdu(s, rdp->settings);
wStream* s = rdp_data_pdu_init(rdp);
if (!s)
return FALSE;
if (!rdp_write_client_persistent_key_list_pdu(s, rdp->settings))
{
Stream_Free(s, TRUE);
return FALSE;
}
return rdp_send_data_pdu(rdp, s, DATA_PDU_TYPE_BITMAP_CACHE_PERSISTENT_LIST, rdp->mcs->userId);
}
BOOL rdp_recv_client_font_list_pdu(wStream* s)
{
if (Stream_GetRemainingLength(s) < 8)
return FALSE;
/* 2.2.1.18.1 Font List PDU Data (TS_FONT_LIST_PDU) */
Stream_Seek(s, 8);
return TRUE;
/* 2.2.1.18 Client Font List PDU */
return Stream_SafeSeek(s, 8);
}
static void rdp_write_client_font_list_pdu(wStream* s, UINT16 flags)
BOOL rdp_recv_client_persistent_key_list_pdu(wStream* s)
{
BYTE flags;
size_t count = 0;
UINT16 cache, x;
/* 2.2.1.17.1 Persistent Key List PDU Data (TS_BITMAPCACHE_PERSISTENT_LIST_PDU) */
if (Stream_GetRemainingLength(s) < 21)
return FALSE;
/* Read numEntriesCacheX for variable length data in PDU */
for (x = 0; x < 5; x++)
{
Stream_Read_UINT16(s, cache);
count += cache;
}
/* Skip totalEntriesCacheX */
if (!Stream_SafeSeek(s, 10))
return FALSE;
Stream_Read_UINT8(s, flags);
/* Skip padding */
if (!Stream_SafeSeek(s, 3))
return FALSE;
/* Skip actual entries sent by client */
return Stream_SafeSeek(s, count * sizeof(UINT64));
}
static BOOL rdp_write_client_font_list_pdu(wStream* s, UINT16 flags)
{
if (Stream_GetRemainingCapacity(s) < 8)
return FALSE;
Stream_Write_UINT16(s, 0); /* numberFonts (2 bytes) */
Stream_Write_UINT16(s, 0); /* totalNumFonts (2 bytes) */
Stream_Write_UINT16(s, flags); /* listFlags (2 bytes) */
Stream_Write_UINT16(s, 50); /* entrySize (2 bytes) */
return TRUE;
}
BOOL rdp_send_client_font_list_pdu(rdpRdp* rdp, UINT16 flags)
{
wStream* s = rdp_data_pdu_init(rdp);
rdp_write_client_font_list_pdu(s, flags);
if (!s)
return FALSE;
if (!rdp_write_client_font_list_pdu(s, flags))
{
Stream_Free(s, TRUE);
return FALSE;
}
return rdp_send_data_pdu(rdp, s, DATA_PDU_TYPE_FONT_LIST, rdp->mcs->userId);
}
@ -247,8 +330,14 @@ BOOL rdp_recv_client_font_map_pdu(rdpRdp* rdp, wStream* s)
BOOL rdp_send_server_font_map_pdu(rdpRdp* rdp)
{
wStream* s;
s = rdp_data_pdu_init(rdp);
wStream* s = rdp_data_pdu_init(rdp);
if (!s)
return FALSE;
if (Stream_GetRemainingCapacity(s) < 8)
{
Stream_Free(s, TRUE);
return FALSE;
}
Stream_Write_UINT16(s, 0); /* numberEntries (2 bytes) */
Stream_Write_UINT16(s, 0); /* totalNumEntries (2 bytes) */
Stream_Write_UINT16(s, FONTLIST_FIRST | FONTLIST_LAST); /* mapFlags (2 bytes) */
@ -314,15 +403,18 @@ BOOL rdp_recv_deactivate_all(rdpRdp* rdp, wStream* s)
BOOL rdp_send_deactivate_all(rdpRdp* rdp)
{
wStream* s = rdp_send_stream_pdu_init(rdp);
BOOL status;
BOOL status = FALSE;
if (!s)
return FALSE;
if (Stream_GetRemainingCapacity(s) < 7)
goto fail;
Stream_Write_UINT32(s, rdp->settings->ShareId); /* shareId (4 bytes) */
Stream_Write_UINT16(s, 1); /* lengthSourceDescriptor (2 bytes) */
Stream_Write_UINT8(s, 0); /* sourceDescriptor (should be 0x00) */
status = rdp_send_pdu(rdp, s, PDU_TYPE_DEACTIVATE_ALL, rdp->mcs->userId);
fail:
Stream_Release(s);
return status;
}
@ -384,3 +476,12 @@ BOOL rdp_server_accept_client_font_list_pdu(rdpRdp* rdp, wStream* s)
return TRUE;
}
BOOL rdp_server_accept_client_persistent_key_list_pdu(rdpRdp* rdp, wStream* s)
{
if (!rdp_recv_client_persistent_key_list_pdu(s))
return FALSE;
// TODO: Actually do something with this
return TRUE;
}

View File

@ -55,5 +55,6 @@ FREERDP_LOCAL BOOL rdp_recv_font_map_pdu(rdpRdp* rdp, wStream* s);
FREERDP_LOCAL BOOL rdp_server_accept_client_control_pdu(rdpRdp* rdp, wStream* s);
FREERDP_LOCAL BOOL rdp_server_accept_client_font_list_pdu(rdpRdp* rdp, wStream* s);
FREERDP_LOCAL BOOL rdp_server_accept_client_persistent_key_list_pdu(rdpRdp* rdp, wStream* s);
#endif /* FREERDP_LIB_CORE_ACTIVATION_H */

View File

@ -734,7 +734,8 @@ BOOL mcs_send_connect_initial(rdpMcs* mcs)
if (length > UINT16_MAX)
goto out;
Stream_SetPosition(s, bm);
tpkt_write_header(s, (UINT16)length);
if (!tpkt_write_header(s, (UINT16)length))
goto out;
tpdu_write_data(s);
Stream_SetPosition(s, em);
Stream_SealLength(s);
@ -796,11 +797,11 @@ BOOL mcs_recv_connect_response(rdpMcs* mcs, wStream* s)
BOOL mcs_send_connect_response(rdpMcs* mcs)
{
size_t length;
int status;
wStream* s;
int status = -1;
wStream* s = NULL;
size_t bm, em;
wStream* gcc_CCrsp;
wStream* server_data;
wStream* gcc_CCrsp = NULL;
wStream* server_data = NULL;
if (!mcs)
return FALSE;
@ -814,14 +815,14 @@ BOOL mcs_send_connect_response(rdpMcs* mcs)
}
if (!gcc_write_server_data_blocks(server_data, mcs))
goto error_data_blocks;
goto out;
gcc_CCrsp = Stream_New(NULL, 512 + Stream_Capacity(server_data));
if (!gcc_CCrsp)
{
WLog_ERR(TAG, "Stream_New failed!");
goto error_data_blocks;
goto out;
}
gcc_write_conference_create_response(gcc_CCrsp, server_data);
@ -831,36 +832,31 @@ BOOL mcs_send_connect_response(rdpMcs* mcs)
if (!s)
{
WLog_ERR(TAG, "Stream_New failed!");
goto error_stream_s;
goto out;
}
bm = Stream_GetPosition(s);
Stream_Seek(s, 7);
if (!mcs_write_connect_response(s, mcs, gcc_CCrsp))
goto error_write_connect_response;
goto out;
em = Stream_GetPosition(s);
length = (em - bm);
if (length > UINT16_MAX)
goto error_write_connect_response;
goto out;
Stream_SetPosition(s, bm);
tpkt_write_header(s, (UINT16)length);
if (!tpkt_write_header(s, (UINT16)length))
goto out;
tpdu_write_data(s);
Stream_SetPosition(s, em);
Stream_SealLength(s);
status = transport_write(mcs->transport, s);
out:
Stream_Free(s, TRUE);
Stream_Free(gcc_CCrsp, TRUE);
Stream_Free(server_data, TRUE);
return (status < 0) ? FALSE : TRUE;
error_write_connect_response:
Stream_Free(s, TRUE);
error_stream_s:
Stream_Free(gcc_CCrsp, TRUE);
error_data_blocks:
Stream_Free(server_data, TRUE);
return FALSE;
}
/**

View File

@ -1067,17 +1067,15 @@ BOOL nego_send_negotiation_response(rdpNego* nego)
em = Stream_GetPosition(s);
Stream_SetPosition(s, bm);
tpkt_write_header(s, length);
tpdu_write_connection_confirm(s, length - 5);
Stream_SetPosition(s, em);
Stream_SealLength(s);
if (transport_write(nego->transport, s) < 0)
status = tpkt_write_header(s, length);
if (status)
{
Stream_Free(s, TRUE);
return FALSE;
}
tpdu_write_connection_confirm(s, length - 5);
Stream_SetPosition(s, em);
Stream_SealLength(s);
status = (transport_write(nego->transport, s) >= 0);
}
Stream_Free(s, TRUE);
if (status)

View File

@ -300,7 +300,8 @@ static BOOL peer_recv_data_pdu(freerdp_peer* client, wStream* s, UINT16 totalLen
break;
case DATA_PDU_TYPE_BITMAP_CACHE_PERSISTENT_LIST:
/* TODO: notify server bitmap cache data */
if (!rdp_server_accept_client_persistent_key_list_pdu(client->context->rdp, s))
return FALSE;
break;
case DATA_PDU_TYPE_FONT_LIST:
@ -385,6 +386,7 @@ static int peer_recv_tpkt_pdu(freerdp_peer* client, wStream* s)
client->settings->PduSource = pduSource;
WLog_DBG(TAG, "Received %s", pdu_type_to_str(pduType));
switch (pduType)
{
case PDU_TYPE_DATA:
@ -424,9 +426,9 @@ static int peer_recv_tpkt_pdu(freerdp_peer* client, wStream* s)
if (!freerdp_channel_peer_process(client, s, channelId))
return -1;
}
if (!tpkt_ensure_stream_consumed(s, length))
return -1;
return 0;
}

View File

@ -110,9 +110,9 @@ const char* data_pdu_type_to_string(UINT8 type)
}
static BOOL rdp_read_flow_control_pdu(wStream* s, UINT16* type, UINT16* channel_id);
static void rdp_write_share_control_header(wStream* s, UINT16 length, UINT16 type,
static BOOL rdp_write_share_control_header(wStream* s, UINT16 length, UINT16 type,
UINT16 channel_id);
static void rdp_write_share_data_header(wStream* s, UINT16 length, BYTE type, UINT32 share_id);
static BOOL rdp_write_share_data_header(wStream* s, UINT16 length, BYTE type, UINT32 share_id);
/**
* Read RDP Security Header.\n
@ -199,13 +199,18 @@ BOOL rdp_read_share_control_header(wStream* s, UINT16* tpktLength, UINT16* remai
return TRUE;
}
void rdp_write_share_control_header(wStream* s, UINT16 length, UINT16 type, UINT16 channel_id)
BOOL rdp_write_share_control_header(wStream* s, UINT16 length, UINT16 type, UINT16 channel_id)
{
if (length < RDP_PACKET_HEADER_MAX_LENGTH)
return FALSE;
if (Stream_GetRemainingCapacity(s) < 6)
return FALSE;
length -= RDP_PACKET_HEADER_MAX_LENGTH;
/* Share Control Header */
Stream_Write_UINT16(s, length); /* totalLength */
Stream_Write_UINT16(s, type | 0x10); /* pduType */
Stream_Write_UINT16(s, channel_id); /* pduSource */
return TRUE;
}
BOOL rdp_read_share_data_header(wStream* s, UINT16* length, BYTE* type, UINT32* shareId,
@ -225,11 +230,16 @@ BOOL rdp_read_share_data_header(wStream* s, UINT16* length, BYTE* type, UINT32*
return TRUE;
}
void rdp_write_share_data_header(wStream* s, UINT16 length, BYTE type, UINT32 share_id)
BOOL rdp_write_share_data_header(wStream* s, UINT16 length, BYTE type, UINT32 share_id)
{
length -= RDP_PACKET_HEADER_MAX_LENGTH;
length -= RDP_SHARE_CONTROL_HEADER_LENGTH;
length -= RDP_SHARE_DATA_HEADER_LENGTH;
const size_t headerLen = RDP_PACKET_HEADER_MAX_LENGTH + RDP_SHARE_CONTROL_HEADER_LENGTH +
RDP_SHARE_DATA_HEADER_LENGTH;
if (length < headerLen)
return FALSE;
length -= headerLen;
if (Stream_GetRemainingCapacity(s) < 12)
return FALSE;
/* Share Data Header */
Stream_Write_UINT32(s, share_id); /* shareId (4 bytes) */
Stream_Write_UINT8(s, 0); /* pad1 (1 byte) */
@ -238,6 +248,7 @@ void rdp_write_share_data_header(wStream* s, UINT16 length, BYTE type, UINT32 sh
Stream_Write_UINT8(s, type); /* pduType2, Data PDU Type (1 byte) */
Stream_Write_UINT8(s, 0); /* compressedType (1 byte) */
Stream_Write_UINT16(s, 0); /* compressedLength (2 bytes) */
return TRUE;
}
static BOOL rdp_security_stream_init(rdpRdp* rdp, wStream* s, BOOL sec_header)
@ -669,7 +680,8 @@ BOOL rdp_send_pdu(rdpRdp* rdp, wStream* s, UINT16 type, UINT16 channel_id)
sec_bytes = rdp_get_sec_bytes(rdp, 0);
sec_hold = Stream_GetPosition(s);
Stream_Seek(s, sec_bytes);
rdp_write_share_control_header(s, length - sec_bytes, type, channel_id);
if (!rdp_write_share_control_header(s, length - sec_bytes, type, channel_id))
return FALSE;
Stream_SetPosition(s, sec_hold);
if (!rdp_security_stream_out(rdp, s, length, 0, &pad))
@ -705,8 +717,10 @@ BOOL rdp_send_data_pdu(rdpRdp* rdp, wStream* s, BYTE type, UINT16 channel_id)
sec_bytes = rdp_get_sec_bytes(rdp, 0);
sec_hold = Stream_GetPosition(s);
Stream_Seek(s, sec_bytes);
rdp_write_share_control_header(s, length - sec_bytes, PDU_TYPE_DATA, channel_id);
rdp_write_share_data_header(s, length - sec_bytes, type, rdp->settings->ShareId);
if (!rdp_write_share_control_header(s, length - sec_bytes, PDU_TYPE_DATA, channel_id))
goto fail;
if (!rdp_write_share_data_header(s, length - sec_bytes, type, rdp->settings->ShareId))
goto fail;
Stream_SetPosition(s, sec_hold);
if (!rdp_security_stream_out(rdp, s, length, 0, &pad))
@ -1256,7 +1270,7 @@ BOOL rdp_decrypt(rdpRdp* rdp, wStream* s, UINT16* pLength, UINT16 securityFlags)
return TRUE;
}
static const char* pdu_type_to_str(UINT16 pduType)
const char* pdu_type_to_str(UINT16 pduType)
{
static char buffer[1024] = { 0 };
switch (pduType)

View File

@ -231,7 +231,6 @@ FREERDP_LOCAL BOOL rdp_set_io_callbacks(rdpRdp* rdp, const rdpTransportIo* io_ca
#define RDP_TAG FREERDP_TAG("core.rdp")
#ifdef WITH_DEBUG_RDP
#define DEBUG_RDP(...) WLog_DBG(RDP_TAG, __VA_ARGS__)
const char* data_pdu_type_to_string(UINT8 type);
#else
#define DEBUG_RDP(...) \
do \
@ -239,6 +238,9 @@ const char* data_pdu_type_to_string(UINT8 type);
} while (0)
#endif
const char* data_pdu_type_to_string(UINT8 type);
const char* pdu_type_to_str(UINT16 pduType);
BOOL rdp_decrypt(rdpRdp* rdp, wStream* s, UINT16* pLength, UINT16 securityFlags);
BOOL rdp_set_error_info(rdpRdp* rdp, UINT32 errorInfo);

View File

@ -148,9 +148,12 @@ BOOL tpkt_ensure_stream_consumed_(wStream* s, UINT16 length, const char* fkt)
* @param length
*/
void tpkt_write_header(wStream* s, UINT16 length)
BOOL tpkt_write_header(wStream* s, UINT16 length)
{
if (Stream_GetRemainingCapacity(s) < 4)
return FALSE;
Stream_Write_UINT8(s, 3); /* version */
Stream_Write_UINT8(s, 0); /* reserved */
Stream_Write_UINT16_BE(s, length); /* length */
return TRUE;
}

View File

@ -30,7 +30,7 @@
FREERDP_LOCAL BOOL tpkt_verify_header(wStream* s);
FREERDP_LOCAL BOOL tpkt_read_header(wStream* s, UINT16* length);
FREERDP_LOCAL void tpkt_write_header(wStream* s, UINT16 length);
FREERDP_LOCAL BOOL tpkt_write_header(wStream* s, UINT16 length);
#define tpkt_ensure_stream_consumed(s, length) \
tpkt_ensure_stream_consumed_((s), (length), __FUNCTION__)
FREERDP_LOCAL BOOL tpkt_ensure_stream_consumed_(wStream* s, UINT16 length, const char* fkt);