[proxy,rdpdr] added translation layer for rdpdr versions

rdpdr filesystem has 2 different versions and mstsc uses the older one
under certain conditions.
This commit is contained in:
Armin Novak 2023-01-09 14:36:04 +01:00 committed by Martin Fleisz
parent f1e7cc0d48
commit c7868e7a3f
2 changed files with 146 additions and 9 deletions

View File

@ -33,7 +33,7 @@ extern "C"
{
UINT32 DeviceType;
UINT32 DeviceId;
char PreferredDosName[9];
char PreferredDosName[8];
UINT32 DeviceDataLength;
BYTE* DeviceData;
} RdpdrDevice;

View File

@ -587,9 +587,13 @@ static UINT rdpdr_process_server_core_capability_request(pf_channel_client_conte
if (header.CapabilityType < ARRAYSIZE(rdpdr->common.capabilityVersions))
{
WLog_Print(rdpdr->log, WLOG_TRACE, "[%s] capability %s got version %" PRIu32,
__FUNCTION__, rdpdr_cap_type_string(header.CapabilityType), header.Version);
rdpdr->common.capabilityVersions[header.CapabilityType] = header.Version;
if (rdpdr->common.capabilityVersions[header.CapabilityType] > header.Version)
rdpdr->common.capabilityVersions[header.CapabilityType] = header.Version;
WLog_Print(rdpdr->log, WLOG_TRACE,
"[%s] capability %s got version %" PRIu32 ", will use version %" PRIu32,
__FUNCTION__, rdpdr_cap_type_string(header.CapabilityType), header.Version,
rdpdr->common.capabilityVersions[header.CapabilityType]);
}
switch (header.CapabilityType)
@ -743,6 +747,16 @@ static UINT rdpdr_process_client_capability_response(pf_channel_server_context*
UINT error = rdpdr_read_capset_header(rdpdr->log, s, &header);
if (error != CHANNEL_RC_OK)
return error;
if (header.CapabilityType < ARRAYSIZE(rdpdr->common.capabilityVersions))
{
if (rdpdr->common.capabilityVersions[header.CapabilityType] > header.Version)
rdpdr->common.capabilityVersions[header.CapabilityType] = header.Version;
WLog_Print(rdpdr->log, WLOG_TRACE,
"[%s] capability %s got version %" PRIu32 ", will use version %" PRIu32,
__FUNCTION__, rdpdr_cap_type_string(header.CapabilityType), header.Version,
rdpdr->common.capabilityVersions[header.CapabilityType]);
}
switch (header.CapabilityType)
{
@ -1002,6 +1016,121 @@ static UINT rdpdr_process_server_device_announce_response(pf_channel_client_cont
}
#endif
static BOOL pf_channel_rdpdr_rewrite_device_list_to(wStream* s, UINT32 fromVersion,
UINT32 toVersion)
{
BOOL rc = FALSE;
if (fromVersion == toVersion)
{
Stream_SealLength(s);
return TRUE;
}
const size_t cap = Stream_GetRemainingLength(s);
wStream* clone = Stream_New(NULL, cap);
if (!clone)
goto fail;
const size_t pos = Stream_GetPosition(s);
Stream_Copy(s, clone, cap);
Stream_SealLength(clone);
Stream_SetPosition(clone, 0);
Stream_SetPosition(s, pos);
/* Skip device count */
if (!Stream_SafeSeek(s, 4))
goto fail;
UINT32 count = 0;
if (Stream_GetRemainingLength(clone) < 4)
goto fail;
Stream_Read_UINT32(clone, count);
for (UINT32 x = 0; x < count; x++)
{
RdpdrDevice device = { 0 };
const size_t charCount = ARRAYSIZE(device.PreferredDosName);
if (Stream_GetRemainingLength(clone) < 20)
goto fail;
Stream_Read_UINT32(clone, device.DeviceType); /* DeviceType (4 bytes) */
Stream_Read_UINT32(clone, device.DeviceId); /* DeviceId (4 bytes) */
Stream_Read(clone, device.PreferredDosName, charCount); /* PreferredDosName (8 bytes) */
Stream_Read_UINT32(clone, device.DeviceDataLength); /* DeviceDataLength (4 bytes) */
device.DeviceData = Stream_Pointer(clone);
if (!Stream_SafeSeek(clone, device.DeviceDataLength))
goto fail;
if (!Stream_EnsureRemainingCapacity(s, 20))
goto fail;
Stream_Write_UINT32(s, device.DeviceType);
Stream_Write_UINT32(s, device.DeviceId);
Stream_Write(s, device.PreferredDosName, charCount);
if (device.DeviceType == RDPDR_DTYP_FILESYSTEM)
{
if (toVersion == DRIVE_CAPABILITY_VERSION_01)
Stream_Write_UINT32(s, 0); /* No unicode name */
else
{
const size_t datalen = charCount * sizeof(WCHAR);
if (!Stream_EnsureRemainingCapacity(s, datalen + sizeof(UINT32)))
goto fail;
Stream_Write_UINT32(s, datalen);
const SSIZE_T rc = Stream_Write_UTF16_String_From_UTF8(
s, charCount, device.PreferredDosName, charCount - 1, TRUE);
if (rc < 0)
goto fail;
}
}
else
{
Stream_Write_UINT32(s, device.DeviceDataLength);
if (!Stream_EnsureRemainingCapacity(s, device.DeviceDataLength))
goto fail;
Stream_Write(s, device.DeviceData, device.DeviceDataLength);
}
}
Stream_SealLength(s);
rc = TRUE;
fail:
Stream_Free(clone, TRUE);
return rc;
}
static BOOL pf_channel_rdpdr_rewrite_device_list(pf_channel_client_context* rdpdr,
pServerContext* ps, wStream* s, BOOL toServer)
{
WINPR_ASSERT(rdpdr);
WINPR_ASSERT(ps);
if (Stream_Length(s) < 4)
return FALSE;
UINT16 component, packetid;
Stream_SetPosition(s, 0);
Stream_Read_UINT16(s, component);
Stream_Read_UINT16(s, packetid);
if ((component != RDPDR_CTYP_CORE) || (packetid != PAKID_CORE_DEVICELIST_ANNOUNCE))
return TRUE;
const pf_channel_server_context* srv =
HashTable_GetItemValue(ps->interceptContextMap, RDPDR_SVC_CHANNEL_NAME);
if (!srv)
return FALSE;
UINT32 from = srv->common.capabilityVersions[CAP_DRIVE_TYPE];
UINT32 to = rdpdr->common.capabilityVersions[CAP_DRIVE_TYPE];
if (toServer)
{
from = rdpdr->common.capabilityVersions[CAP_DRIVE_TYPE];
to = srv->common.capabilityVersions[CAP_DRIVE_TYPE];
}
return pf_channel_rdpdr_rewrite_device_list_to(s, from, to);
}
static BOOL pf_channel_rdpdr_client_send_to_server(pf_channel_client_context* rdpdr,
pServerContext* ps, wStream* s)
{
@ -1016,6 +1145,8 @@ static BOOL pf_channel_rdpdr_client_send_to_server(pf_channel_client_context* rd
if (server_channel_id == 0)
return TRUE;
if (!pf_channel_rdpdr_rewrite_device_list(rdpdr, ps, s, TRUE))
return FALSE;
size_t len = Stream_Length(s);
Stream_SetPosition(s, len);
rdpdr_dump_send_packet(rdpdr->log, WLOG_TRACE, s, proxy_client_tx);
@ -1127,8 +1258,9 @@ BOOL pf_channel_send_client_queue(pClientContext* pc, pf_channel_client_context*
if (!s)
continue;
const size_t len = Stream_Length(s);
size_t len = Stream_Length(s);
Stream_SetPosition(s, len);
rdpdr_dump_send_packet(rdpdr->log, WLOG_TRACE, s, proxy_server_tx " (queue) ");
WINPR_ASSERT(pc->context.instance->SendChannelData);
if (!pc->context.instance->SendChannelData(pc->context.instance, channelId,
@ -1136,6 +1268,7 @@ BOOL pf_channel_send_client_queue(pClientContext* pc, pf_channel_client_context*
{
CLIENT_TX_LOG(rdpdr->log, WLOG_ERROR, "xxxxxx TODO: Failed to send data!");
}
skip:
Stream_Free(s, TRUE);
}
Queue_Unlock(rdpdr->queue);
@ -1357,11 +1490,13 @@ static BOOL pf_channel_rdpdr_common_context_new(pf_channel_common_context* commo
return TRUE;
}
static BOOL pf_channel_rdpdr_client_pass_message(pClientContext* pc, UINT16 channelId,
const char* channel_name, wStream* s)
static BOOL pf_channel_rdpdr_client_pass_message(pServerContext* ps, pClientContext* pc,
UINT16 channelId, const char* channel_name,
wStream* s)
{
pf_channel_client_context* rdpdr;
WINPR_ASSERT(ps);
WINPR_ASSERT(pc);
rdpdr = HashTable_GetItemValue(pc->interceptContextMap, channel_name);
@ -1369,6 +1504,8 @@ static BOOL pf_channel_rdpdr_client_pass_message(pClientContext* pc, UINT16 chan
return TRUE; /* Ignore data for channels not available on proxy -> server connection */
WINPR_ASSERT(rdpdr->queue);
if (!pf_channel_rdpdr_rewrite_device_list(rdpdr, ps, s, FALSE))
return FALSE;
if (!Queue_Enqueue(rdpdr->queue, s))
return FALSE;
pf_channel_send_client_queue(pc, rdpdr);
@ -1722,13 +1859,13 @@ BOOL pf_channel_rdpdr_server_handle(pServerContext* ps, UINT16 channelId, const
if (!pf_channel_smartcard_client_emulate(pc) ||
!filter_smartcard_device_list_announce_request(rdpdr, s))
{
if (!pf_channel_rdpdr_client_pass_message(pc, channelId, channel_name, s))
if (!pf_channel_rdpdr_client_pass_message(ps, pc, channelId, channel_name, s))
return FALSE;
}
else
return pf_channel_smartcard_server_handle(ps, s);
#else
if (!pf_channel_rdpdr_client_pass_message(pc, channelId, channel_name, s))
if (!pf_channel_rdpdr_client_pass_message(ps, pc, channelId, channel_name, s))
return FALSE;
#endif
break;