From 2fc5eaeb802b32cdb47e8e551be25e6ca7abc2f7 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Thu, 19 Jan 2023 15:49:05 +0100 Subject: [PATCH] [core] implemented CS_CORE::EarlyCapabilityFlags filter * Added missing definitions for RNS_UD_CS_SUPPORT_SKIP_CHANNELJOIN and RNS_UD_SC_SKIP_CHANNELJOIN_SUPPORTED flags * Updated stringification functions for these flags * Implemented client and server EarlyCapabilityFlags filter for these flags as FreeRDP currently does not implement them. --- include/freerdp/settings.h | 4 +- libfreerdp/core/gcc.c | 161 +++++++++++++++++++++++++++---------- 2 files changed, 121 insertions(+), 44 deletions(-) diff --git a/include/freerdp/settings.h b/include/freerdp/settings.h index 5d9c03b59..539419fcb 100644 --- a/include/freerdp/settings.h +++ b/include/freerdp/settings.h @@ -153,11 +153,13 @@ typedef enum #define RNS_UD_CS_SUPPORT_DYNVC_GFX_PROTOCOL 0x0100 #define RNS_UD_CS_SUPPORT_DYNAMIC_TIME_ZONE 0x0200 #define RNS_UD_CS_SUPPORT_HEARTBEAT_PDU 0x0400 +#define RNS_UD_CS_SUPPORT_SKIP_CHANNELJOIN 0x0800 /* Early Capability Flags (Server to Client) */ -#define RNS_UD_SC_EDGE_ACTIONS_SUPPORTED 0x00000001 +#define RNS_UD_SC_EDGE_ACTIONS_SUPPORTED_V1 0x00000001 #define RNS_UD_SC_DYNAMIC_DST_SUPPORTED 0x00000002 #define RNS_UD_SC_EDGE_ACTIONS_SUPPORTED_V2 0x00000004 +#define RNS_UD_SC_SKIP_CHANNELJOIN_SUPPORTED 0x00000008 /* Cluster Information Flags */ #define REDIRECTION_SUPPORTED 0x00000001 diff --git a/libfreerdp/core/gcc.c b/libfreerdp/core/gcc.c index 43b39cfb6..3bf1a3d74 100644 --- a/libfreerdp/core/gcc.c +++ b/libfreerdp/core/gcc.c @@ -86,49 +86,73 @@ static const rdpSettings* mcs_get_const_settings(const rdpMcs* mcs) return context->settings; } -static void append(char* buffer, size_t size, const char* what) +static char* rdp_early_server_caps_string(UINT32 flags, char* buffer, size_t size) { - winpr_str_append(what, buffer, size, "|"); + char msg[32] = { 0 }; + const UINT32 mask = RNS_UD_SC_EDGE_ACTIONS_SUPPORTED_V1 | RNS_UD_SC_DYNAMIC_DST_SUPPORTED | + RNS_UD_SC_EDGE_ACTIONS_SUPPORTED_V2 | RNS_UD_SC_SKIP_CHANNELJOIN_SUPPORTED; + const UINT32 unknown = flags & (~mask); + + if (flags & RNS_UD_SC_EDGE_ACTIONS_SUPPORTED_V1) + winpr_str_append("RNS_UD_SC_EDGE_ACTIONS_SUPPORTED_V1", buffer, size, "|"); + if (flags & RNS_UD_SC_DYNAMIC_DST_SUPPORTED) + winpr_str_append("RNS_UD_SC_DYNAMIC_DST_SUPPORTED", buffer, size, "|"); + if (flags & RNS_UD_SC_EDGE_ACTIONS_SUPPORTED_V2) + winpr_str_append("RNS_UD_SC_EDGE_ACTIONS_SUPPORTED_V2", buffer, size, "|"); + if (flags & RNS_UD_SC_SKIP_CHANNELJOIN_SUPPORTED) + winpr_str_append("RNS_UD_SC_SKIP_CHANNELJOIN_SUPPORTED", buffer, size, "|"); + + if (unknown != 0) + { + _snprintf(msg, sizeof(msg), "RNS_UD_SC_UNKNOWN[0x%08" PRIx32 "]", unknown); + winpr_str_append(msg, buffer, size, "|"); + } + _snprintf(msg, sizeof(msg), "[0x%08" PRIx32 "]", flags); + winpr_str_append(msg, buffer, size, "|"); + return buffer; } -static const char* rdp_early_caps_string(UINT16 flags, char* buffer, size_t size) +static const char* rdp_early_client_caps_string(UINT32 flags, char* buffer, size_t size) { - char number[32] = { 0 }; - const UINT16 mask = - ~(RNS_UD_CS_SUPPORT_ERRINFO_PDU | RNS_UD_CS_WANT_32BPP_SESSION | - RNS_UD_CS_SUPPORT_STATUSINFO_PDU | RNS_UD_CS_STRONG_ASYMMETRIC_KEYS | - RNS_UD_CS_VALID_CONNECTION_TYPE | RNS_UD_CS_SUPPORT_MONITOR_LAYOUT_PDU | - RNS_UD_CS_SUPPORT_NETCHAR_AUTODETECT | RNS_UD_CS_SUPPORT_DYNVC_GFX_PROTOCOL | - RNS_UD_CS_SUPPORT_DYNAMIC_TIME_ZONE | RNS_UD_CS_SUPPORT_HEARTBEAT_PDU); + char msg[32] = { 0 }; + const UINT32 mask = RNS_UD_CS_SUPPORT_ERRINFO_PDU | RNS_UD_CS_WANT_32BPP_SESSION | + RNS_UD_CS_SUPPORT_STATUSINFO_PDU | RNS_UD_CS_STRONG_ASYMMETRIC_KEYS | + RNS_UD_CS_VALID_CONNECTION_TYPE | RNS_UD_CS_SUPPORT_MONITOR_LAYOUT_PDU | + RNS_UD_CS_SUPPORT_NETCHAR_AUTODETECT | + RNS_UD_CS_SUPPORT_DYNVC_GFX_PROTOCOL | RNS_UD_CS_SUPPORT_DYNAMIC_TIME_ZONE | + RNS_UD_CS_SUPPORT_HEARTBEAT_PDU | RNS_UD_CS_SUPPORT_SKIP_CHANNELJOIN; + const UINT32 unknown = flags & (~mask); if (flags & RNS_UD_CS_SUPPORT_ERRINFO_PDU) - append(buffer, size, "RNS_UD_CS_SUPPORT_ERRINFO_PDU"); + winpr_str_append("RNS_UD_CS_SUPPORT_ERRINFO_PDU", buffer, size, "|"); if (flags & RNS_UD_CS_WANT_32BPP_SESSION) - append(buffer, size, "RNS_UD_CS_WANT_32BPP_SESSION"); + winpr_str_append("RNS_UD_CS_WANT_32BPP_SESSION", buffer, size, "|"); if (flags & RNS_UD_CS_SUPPORT_STATUSINFO_PDU) - append(buffer, size, "RNS_UD_CS_SUPPORT_STATUSINFO_PDU"); + winpr_str_append("RNS_UD_CS_SUPPORT_STATUSINFO_PDU", buffer, size, "|"); if (flags & RNS_UD_CS_STRONG_ASYMMETRIC_KEYS) - append(buffer, size, "RNS_UD_CS_STRONG_ASYMMETRIC_KEYS"); + winpr_str_append("RNS_UD_CS_STRONG_ASYMMETRIC_KEYS", buffer, size, "|"); if (flags & RNS_UD_CS_VALID_CONNECTION_TYPE) - append(buffer, size, "RNS_UD_CS_VALID_CONNECTION_TYPE"); + winpr_str_append("RNS_UD_CS_VALID_CONNECTION_TYPE", buffer, size, "|"); if (flags & RNS_UD_CS_SUPPORT_MONITOR_LAYOUT_PDU) - append(buffer, size, "RNS_UD_CS_SUPPORT_MONITOR_LAYOUT_PDU"); + winpr_str_append("RNS_UD_CS_SUPPORT_MONITOR_LAYOUT_PDU", buffer, size, "|"); if (flags & RNS_UD_CS_SUPPORT_NETCHAR_AUTODETECT) - append(buffer, size, "RNS_UD_CS_SUPPORT_NETCHAR_AUTODETECT"); + winpr_str_append("RNS_UD_CS_SUPPORT_NETCHAR_AUTODETECT", buffer, size, "|"); if (flags & RNS_UD_CS_SUPPORT_DYNVC_GFX_PROTOCOL) - append(buffer, size, "RNS_UD_CS_SUPPORT_DYNVC_GFX_PROTOCOL"); + winpr_str_append("RNS_UD_CS_SUPPORT_DYNVC_GFX_PROTOCOL", buffer, size, "|"); if (flags & RNS_UD_CS_SUPPORT_DYNAMIC_TIME_ZONE) - append(buffer, size, "RNS_UD_CS_SUPPORT_DYNAMIC_TIME_ZONE"); + winpr_str_append("RNS_UD_CS_SUPPORT_DYNAMIC_TIME_ZONE", buffer, size, "|"); if (flags & RNS_UD_CS_SUPPORT_HEARTBEAT_PDU) - append(buffer, size, "RNS_UD_CS_SUPPORT_HEARTBEAT_PDU"); - if (flags & mask) - append(buffer, size, "RNS_UD_UNKNOWN_FLAG"); - if (flags == 0) - append(buffer, size, "NO_FLAG_SET"); - - _snprintf(number, sizeof(number), " [0x%04" PRIx16 "]", flags); - append(buffer, size, number); + winpr_str_append("RNS_UD_CS_SUPPORT_HEARTBEAT_PDU", buffer, size, "|"); + if (flags & RNS_UD_CS_SUPPORT_SKIP_CHANNELJOIN) + winpr_str_append("RNS_UD_CS_SUPPORT_SKIP_CHANNELJOIN", buffer, size, "|"); + if (unknown != 0) + { + _snprintf(msg, sizeof(msg), "RNS_UD_CS_UNKNOWN[0x%08" PRIx32 "]", unknown); + winpr_str_append(msg, buffer, size, "|"); + } + _snprintf(msg, sizeof(msg), "[0x%08" PRIx32 "]", flags); + winpr_str_append(msg, buffer, size, "|"); return buffer; } @@ -829,9 +853,59 @@ BOOL gcc_write_user_data_header(wStream* s, UINT16 type, UINT16 length) return TRUE; } -static UINT16 earlyCapsFromSettings(const rdpSettings* settings) +static UINT32 filterAndLogEarlyServerCapabilityFlags(UINT32 flags) { - UINT16 earlyCapabilityFlags = settings->EarlyCapabilityFlags; + const UINT32 mask = + (RNS_UD_SC_EDGE_ACTIONS_SUPPORTED_V1 | RNS_UD_SC_DYNAMIC_DST_SUPPORTED | + RNS_UD_SC_EDGE_ACTIONS_SUPPORTED_V2); // TODO: Not implemented + // RNS_UD_SC_SKIP_CHANNELJOIN_SUPPORTED + const UINT32 filtered = flags & mask; + const UINT32 unknown = flags & (~mask); + if (unknown != 0) + { + char buffer[256] = { 0 }; + WLog_WARN(TAG, + "TS_UD_SC_CORE::EarlyCapabilityFlags [0x%08" PRIx32 " & 0x%08" PRIx32 + " --> 0x%08" PRIx32 "] filtering %s, feature not implemented", + flags, ~mask, unknown, + rdp_early_server_caps_string(unknown, buffer, sizeof(buffer))); + } + return filtered; +} + +static UINT32 earlyServerCapsFromSettings(const rdpSettings* settings) +{ + UINT32 EarlyCapabilityFlags = settings->EarlyCapabilityFlags; + return filterAndLogEarlyServerCapabilityFlags(EarlyCapabilityFlags); +} + +static UINT16 filterAndLogEarlyClientCapabilityFlags(UINT32 flags) +{ + const UINT32 mask = + (RNS_UD_CS_SUPPORT_ERRINFO_PDU | RNS_UD_CS_WANT_32BPP_SESSION | + RNS_UD_CS_SUPPORT_STATUSINFO_PDU | RNS_UD_CS_STRONG_ASYMMETRIC_KEYS | + RNS_UD_CS_VALID_CONNECTION_TYPE | RNS_UD_CS_SUPPORT_MONITOR_LAYOUT_PDU | + RNS_UD_CS_SUPPORT_NETCHAR_AUTODETECT | RNS_UD_CS_SUPPORT_DYNVC_GFX_PROTOCOL | + RNS_UD_CS_SUPPORT_DYNAMIC_TIME_ZONE | + RNS_UD_CS_SUPPORT_HEARTBEAT_PDU); // unsupported RNS_UD_CS_SUPPORT_SKIP_CHANNELJOIN + const UINT32 filtered = flags & mask; + const UINT32 unknown = flags & ~mask; + if (unknown != 0) + { + char buffer[256] = { 0 }; + WLog_WARN(TAG, + "(TS_UD_CS_CORE)::EarlyCapabilityFlags [0x%08" PRIx32 " & 0x%08" PRIx32 + " --> 0x%08" PRIx32 "] filtering %s, feature not implemented", + flags, ~mask, unknown, + rdp_early_client_caps_string(unknown, buffer, sizeof(buffer))); + } + return filtered; +} + +static UINT16 earlyClientCapsFromSettings(const rdpSettings* settings) +{ + WINPR_ASSERT(settings); + UINT32 earlyCapabilityFlags = settings->EarlyCapabilityFlags; WINPR_ASSERT(settings); if (settings->SupportErrorInfoPdu) @@ -861,7 +935,7 @@ static UINT16 earlyCapsFromSettings(const rdpSettings* settings) if (settings->SupportStatusInfoPdu) earlyCapabilityFlags |= RNS_UD_CS_SUPPORT_STATUSINFO_PDU; - return earlyCapabilityFlags; + return filterAndLogEarlyClientCapabilityFlags(earlyCapabilityFlags); } static BOOL updateEarlyClientCaps(rdpSettings* settings, UINT32 earlyCapabilityFlags, @@ -896,7 +970,9 @@ static BOOL updateEarlyClientCaps(rdpSettings* settings, UINT32 earlyCapabilityF if (!(earlyCapabilityFlags & RNS_UD_CS_VALID_CONNECTION_TYPE)) connectionType = 0; settings->ConnectionType = connectionType; + settings->EarlyCapabilityFlags = earlyCapabilityFlags; + filterAndLogEarlyClientCapabilityFlags(earlyCapabilityFlags); return TRUE; } @@ -909,7 +985,8 @@ static BOOL updateEarlyServerCaps(rdpSettings* settings, UINT32 earlyCapabilityF settings->SupportDynamicTimeZone && (earlyCapabilityFlags & RNS_UD_SC_DYNAMIC_DST_SUPPORTED) ? TRUE : FALSE; - + settings->EarlyCapabilityFlags = earlyCapabilityFlags; + filterAndLogEarlyServerCapabilityFlags(earlyCapabilityFlags); return TRUE; } @@ -1015,7 +1092,6 @@ BOOL gcc_read_client_core_data(wStream* s, rdpMcs* mcs, UINT16 blockLength) break; Stream_Read_UINT16(s, earlyCapabilityFlags); /* earlyCapabilityFlags (2 bytes) */ - settings->EarlyCapabilityFlags = (UINT32)earlyCapabilityFlags; blockLength -= 2; /* clientDigProductId (64 bytes): Contains a value that uniquely identifies the client */ @@ -1149,8 +1225,8 @@ BOOL gcc_read_client_core_data(wStream* s, rdpMcs* mcs, UINT16 blockLength) freerdp_settings_set_uint32(settings, FreeRDP_ColorDepth, clientColorDepth); WLog_DBG(TAG, "Received EarlyCapabilityFlags=%s", - rdp_early_caps_string(earlyCapabilityFlags, buffer, sizeof(buffer))); - settings->EarlyCapabilityFlags = earlyCapabilityFlags; + rdp_early_client_caps_string(earlyCapabilityFlags, buffer, sizeof(buffer))); + return updateEarlyClientCaps(settings, earlyCapabilityFlags, connectionType); } @@ -1216,7 +1292,7 @@ BOOL gcc_write_client_core_data(wStream* s, const rdpMcs* mcs) Stream_Write_UINT32(s, 0); /* serialNumber (should be initialized to 0) */ highColorDepth = MIN(freerdp_settings_get_uint32(settings, FreeRDP_ColorDepth), 24); supportedColorDepths = RNS_UD_24BPP_SUPPORT | RNS_UD_16BPP_SUPPORT | RNS_UD_15BPP_SUPPORT; - earlyCapabilityFlags = earlyCapsFromSettings(settings); + earlyCapabilityFlags = earlyClientCapsFromSettings(settings); connectionType = settings->ConnectionType; @@ -1230,7 +1306,7 @@ BOOL gcc_write_client_core_data(wStream* s, const rdpMcs* mcs) "Sending highColorDepth=0x%04" PRIx16 ", supportedColorDepths=0x%04" PRIx16 ", earlyCapabilityFlags=%s", highColorDepth, supportedColorDepths, - rdp_early_caps_string(earlyCapabilityFlags, buffer, sizeof(buffer))); + rdp_early_client_caps_string(earlyCapabilityFlags, buffer, sizeof(buffer))); Stream_Write_UINT16(s, highColorDepth); /* highColorDepth */ Stream_Write_UINT16(s, supportedColorDepths); /* supportedColorDepths */ Stream_Write_UINT16(s, earlyCapabilityFlags); /* earlyCapabilityFlags */ @@ -1261,6 +1337,7 @@ BOOL gcc_write_client_core_data(wStream* s, const rdpMcs* mcs) BOOL gcc_read_server_core_data(wStream* s, rdpMcs* mcs) { UINT32 serverVersion; + UINT32 EarlyCapabilityFlags = 0; rdpSettings* settings = mcs_get_settings(mcs); WINPR_ASSERT(s); @@ -1281,13 +1358,12 @@ BOOL gcc_read_server_core_data(wStream* s, rdpMcs* mcs) { char buffer[2048] = { 0 }; - Stream_Read_UINT32(s, settings->EarlyCapabilityFlags); /* earlyCapabilityFlags */ + Stream_Read_UINT32(s, EarlyCapabilityFlags); /* earlyCapabilityFlags */ WLog_DBG(TAG, "Received EarlyCapabilityFlags=%s", - rdp_early_caps_string(settings->EarlyCapabilityFlags, buffer, sizeof(buffer))); + rdp_early_client_caps_string(EarlyCapabilityFlags, buffer, sizeof(buffer))); } - return updateEarlyServerCaps(settings, settings->EarlyCapabilityFlags, - settings->ConnectionType); + return updateEarlyServerCaps(settings, EarlyCapabilityFlags, settings->ConnectionType); } /* TODO: This function modifies rdpMcs @@ -1295,7 +1371,6 @@ BOOL gcc_read_server_core_data(wStream* s, rdpMcs* mcs) */ BOOL gcc_write_server_core_data(wStream* s, rdpMcs* mcs) { - UINT32 earlyCapabilityFlags; rdpSettings* settings = mcs_get_settings(mcs); WINPR_ASSERT(s); @@ -1305,11 +1380,11 @@ BOOL gcc_write_server_core_data(wStream* s, rdpMcs* mcs) return FALSE; updateEarlyServerCaps(settings, settings->EarlyCapabilityFlags, settings->ConnectionType); - earlyCapabilityFlags = settings->EarlyCapabilityFlags; + const UINT32 EarlyCapabilityFlags = earlyServerCapsFromSettings(settings); Stream_Write_UINT32(s, settings->RdpVersion); /* version (4 bytes) */ Stream_Write_UINT32(s, settings->RequestedProtocols); /* clientRequestedProtocols (4 bytes) */ - Stream_Write_UINT32(s, earlyCapabilityFlags); /* earlyCapabilityFlags (4 bytes) */ + Stream_Write_UINT32(s, EarlyCapabilityFlags); /* earlyCapabilityFlags (4 bytes) */ return TRUE; }