gateway: Add processing of consent and service messages with HTTP gateway

This commit is contained in:
Martin Fleisz 2020-07-30 15:22:40 +02:00 committed by akallabeth
parent fde4867574
commit e8c99f3a00

View File

@ -151,22 +151,22 @@ typedef struct
{
UINT32 code;
const char* name;
} t_err_mapping;
} t_flag_mapping;
static const t_err_mapping tunnel_response_fields_present[] = {
static const t_flag_mapping tunnel_response_fields_present[] = {
{ HTTP_TUNNEL_RESPONSE_FIELD_TUNNEL_ID, "HTTP_TUNNEL_RESPONSE_FIELD_TUNNEL_ID" },
{ HTTP_TUNNEL_RESPONSE_FIELD_CAPS, "HTTP_TUNNEL_RESPONSE_FIELD_CAPS" },
{ HTTP_TUNNEL_RESPONSE_FIELD_SOH_REQ, "HTTP_TUNNEL_RESPONSE_FIELD_SOH_REQ" },
{ HTTP_TUNNEL_RESPONSE_FIELD_CONSENT_MSG, "HTTP_TUNNEL_RESPONSE_FIELD_CONSENT_MSG" }
};
static const t_err_mapping channel_response_fields_present[] = {
static const t_flag_mapping channel_response_fields_present[] = {
{ HTTP_CHANNEL_RESPONSE_FIELD_CHANNELID, "HTTP_CHANNEL_RESPONSE_FIELD_CHANNELID" },
{ HTTP_CHANNEL_RESPONSE_OPTIONAL, "HTTP_CHANNEL_RESPONSE_OPTIONAL" },
{ HTTP_CHANNEL_RESPONSE_FIELD_UDPPORT, "HTTP_CHANNEL_RESPONSE_FIELD_UDPPORT" }
};
static const t_err_mapping tunnel_authorization_response_fields_present[] = {
static const t_flag_mapping tunnel_authorization_response_fields_present[] = {
{ HTTP_TUNNEL_AUTH_RESPONSE_FIELD_REDIR_FLAGS, "HTTP_TUNNEL_AUTH_RESPONSE_FIELD_REDIR_FLAGS" },
{ HTTP_TUNNEL_AUTH_RESPONSE_FIELD_IDLE_TIMEOUT,
"HTTP_TUNNEL_AUTH_RESPONSE_FIELD_IDLE_TIMEOUT" },
@ -174,15 +174,23 @@ static const t_err_mapping tunnel_authorization_response_fields_present[] = {
"HTTP_TUNNEL_AUTH_RESPONSE_FIELD_SOH_RESPONSE" }
};
static const t_err_mapping extended_auth[] = {
static const t_flag_mapping extended_auth[] = {
{ HTTP_EXTENDED_AUTH_NONE, "HTTP_EXTENDED_AUTH_NONE" },
{ HTTP_EXTENDED_AUTH_SC, "HTTP_EXTENDED_AUTH_SC" },
{ HTTP_EXTENDED_AUTH_PAA, "HTTP_EXTENDED_AUTH_PAA" },
{ HTTP_EXTENDED_AUTH_SSPI_NTLM, "HTTP_EXTENDED_AUTH_SSPI_NTLM" }
};
static const char* fields_present_to_string(UINT16 fieldsPresent, const t_err_mapping* map,
size_t elements)
static const t_flag_mapping capabilities_enum[] = {
{ HTTP_CAPABILITY_TYPE_QUAR_SOH, "HTTP_CAPABILITY_TYPE_QUAR_SOH" },
{ HTTP_CAPABILITY_IDLE_TIMEOUT, "HTTP_CAPABILITY_IDLE_TIMEOUT" },
{ HTTP_CAPABILITY_MESSAGING_CONSENT_SIGN, "HTTP_CAPABILITY_MESSAGING_CONSENT_SIGN" },
{ HTTP_CAPABILITY_MESSAGING_SERVICE_MSG, "HTTP_CAPABILITY_MESSAGING_SERVICE_MSG" },
{ HTTP_CAPABILITY_REAUTH, "HTTP_CAPABILITY_REAUTH" },
{ HTTP_CAPABILITY_UDP_TRANSPORT, "HTTP_CAPABILITY_UDP_TRANSPORT" }
};
static const char* flags_to_string(UINT32 flags, const t_flag_mapping* map, size_t elements)
{
size_t x = 0;
static char buffer[1024] = { 0 };
@ -194,30 +202,30 @@ static const char* fields_present_to_string(UINT16 fieldsPresent, const t_err_ma
if (buffer[0] != '\0')
strcat(buffer, "|");
if ((map[x].code & fieldsPresent) != 0)
if ((map[x].code & flags) != 0)
strcat(buffer, map[x].name);
}
sprintf_s(fields, ARRAYSIZE(fields), " [%04" PRIx16 "]", fieldsPresent);
sprintf_s(fields, ARRAYSIZE(fields), " [%04" PRIx32 "]", flags);
strcat(buffer, fields);
return buffer;
}
static const char* channel_response_fields_present_to_string(UINT16 fieldsPresent)
{
return fields_present_to_string(fieldsPresent, channel_response_fields_present,
return flags_to_string(fieldsPresent, channel_response_fields_present,
ARRAYSIZE(channel_response_fields_present));
}
static const char* tunnel_response_fields_present_to_string(UINT16 fieldsPresent)
{
return fields_present_to_string(fieldsPresent, tunnel_response_fields_present,
return flags_to_string(fieldsPresent, tunnel_response_fields_present,
ARRAYSIZE(tunnel_response_fields_present));
}
static const char* tunnel_authorization_response_fields_present_to_string(UINT16 fieldsPresent)
{
return fields_present_to_string(fieldsPresent, tunnel_authorization_response_fields_present,
return flags_to_string(fieldsPresent, tunnel_authorization_response_fields_present,
ARRAYSIZE(tunnel_authorization_response_fields_present));
}
@ -226,7 +234,38 @@ static const char* extended_auth_to_string(UINT16 auth)
if (auth == HTTP_EXTENDED_AUTH_NONE)
return "HTTP_EXTENDED_AUTH_NONE [0x0000]";
return fields_present_to_string(auth, extended_auth, ARRAYSIZE(extended_auth));
return flags_to_string(auth, extended_auth, ARRAYSIZE(extended_auth));
}
static const char* capabilities_enum_to_string(UINT32 capabilities)
{
return flags_to_string(capabilities, capabilities_enum, ARRAYSIZE(capabilities_enum));
}
static BOOL rdg_read_http_unicode_string(wStream* s, WCHAR** string, UINT16* lengthInBytes)
{
WCHAR* str;
UINT16 strLenBytes;
/* Read length of the string */
if (Stream_GetRemainingLength(s) < 4)
return FALSE;
Stream_Read_UINT16(s, strLenBytes);
/* Remember position of our string */
Stream_GetPointer(s, str);
/* seek past the string - if this fails something is wrong */
if (!Stream_SafeSeek(s, strLenBytes))
return FALSE;
/* return the string data (if wanted) */
if (string)
*string = str;
if (lengthInBytes)
*lengthInBytes = strLenBytes;
return TRUE;
}
static BOOL rdg_write_packet(rdpRdg* rdg, wStream* sPacket)
@ -357,6 +396,9 @@ static BOOL rdg_send_tunnel_request(rdpRdg* rdg)
UINT16 fieldsPresent = 0;
WCHAR* PAACookie = NULL;
int PAACookieLen = 0;
const UINT32 capabilities = HTTP_CAPABILITY_TYPE_QUAR_SOH |
HTTP_CAPABILITY_MESSAGING_CONSENT_SIGN |
HTTP_CAPABILITY_MESSAGING_SERVICE_MSG;
if (rdg->extAuth == HTTP_EXTENDED_AUTH_PAA)
{
@ -384,7 +426,7 @@ static BOOL rdg_send_tunnel_request(rdpRdg* rdg)
Stream_Write_UINT16(s, PKT_TYPE_TUNNEL_CREATE); /* Type (2 bytes) */
Stream_Write_UINT16(s, 0); /* Reserved (2 bytes) */
Stream_Write_UINT32(s, packetSize); /* PacketLength (4 bytes) */
Stream_Write_UINT32(s, HTTP_CAPABILITY_TYPE_QUAR_SOH); /* CapabilityFlags (4 bytes) */
Stream_Write_UINT32(s, capabilities); /* CapabilityFlags (4 bytes) */
Stream_Write_UINT16(s, fieldsPresent); /* FieldsPresent (2 bytes) */
Stream_Write_UINT16(s, 0); /* Reserved (2 bytes), must be 0 */
@ -669,6 +711,76 @@ static BOOL rdg_process_handshake_response(rdpRdg* rdg, wStream* s)
return rdg_send_tunnel_request(rdg);
}
static BOOL rdg_process_tunnel_response_optional(rdpRdg* rdg, wStream* s, UINT16 fieldsPresent)
{
if (fieldsPresent & HTTP_TUNNEL_RESPONSE_FIELD_TUNNEL_ID)
{
/* Seek over tunnelId (4 bytes) */
if (!Stream_SafeSeek(s, 4))
{
WLog_ERR(TAG, "[%s] Short packet %" PRIuz ", expected 4", __FUNCTION__,
Stream_GetRemainingLength(s));
return FALSE;
}
}
if (fieldsPresent & HTTP_TUNNEL_RESPONSE_FIELD_CAPS)
{
UINT32 caps;
if (Stream_GetRemainingLength(s) < 4)
{
WLog_ERR(TAG, "[%s] Short packet %" PRIuz ", expected 4", __FUNCTION__,
Stream_GetRemainingLength(s));
return FALSE;
}
Stream_Read_UINT32(s, caps);
WLog_DBG(TAG, "capabilities=%s", capabilities_enum_to_string(caps));
}
if (fieldsPresent & HTTP_TUNNEL_RESPONSE_FIELD_SOH_REQ)
{
UINT16 certLen;
/* Seek over nonce (20 bytes) */
if (!Stream_SafeSeek(s, 20))
{
WLog_ERR(TAG, "[%s] Short packet %" PRIuz ", expected 20", __FUNCTION__,
Stream_GetRemainingLength(s));
return FALSE;
}
/* Read serverCert */
if (!rdg_read_http_unicode_string(s, NULL, NULL))
{
WLog_ERR(TAG, "[%s] Failed to read string", __FUNCTION__);
return FALSE;
}
}
if (fieldsPresent & HTTP_TUNNEL_RESPONSE_FIELD_CONSENT_MSG)
{
WCHAR* msg;
UINT16 msgLenBytes;
rdpContext* context = rdg->context;
assert(context);
assert(context->instance);
/* Read message string and invoke callback */
if (!rdg_read_http_unicode_string(s, &msg, &msgLenBytes))
{
WLog_ERR(TAG, "[%s] Failed to read string", __FUNCTION__);
return FALSE;
}
return IFCALLRESULT(TRUE, context->instance->PresentGatewayMessage, context->instance,
TSG_ASYNC_MESSAGE_CONSENT_MESSAGE, TRUE, TRUE, msgLenBytes, msg);
}
return TRUE;
}
static BOOL rdg_process_tunnel_response(rdpRdg* rdg, wStream* s)
{
UINT16 serverVersion, fieldsPresent;
@ -703,6 +815,9 @@ static BOOL rdg_process_tunnel_response(rdpRdg* rdg, wStream* s)
return FALSE;
}
if (!rdg_process_tunnel_response_optional(rdg, s, fieldsPresent))
return FALSE;
return rdg_send_tunnel_authorization(rdg);
}
@ -1310,6 +1425,25 @@ static BOOL rdg_process_keep_alive_packet(rdpRdg* rdg)
return (status < 0 ? FALSE : TRUE);
}
static BOOL rdg_process_service_message(rdpRdg* rdg, wStream* s)
{
const WCHAR* msg;
UINT16 msgLenBytes;
rdpContext* context = rdg->context;
assert(context);
assert(context->instance);
/* Read message string */
if (!rdg_read_http_unicode_string(s, &msg, &msgLenBytes))
{
WLog_ERR(TAG, "[%s] Failed to read string", __FUNCTION__);
return FALSE;
}
return IFCALLRESULT(TRUE, context->instance->PresentGatewayMessage, context->instance,
TSG_ASYNC_MESSAGE_SERVICE_MESSAGE, TRUE, FALSE, msgLenBytes, msg);
}
static BOOL rdg_process_unknown_packet(rdpRdg* rdg, int type)
{
WINPR_UNUSED(rdg);
@ -1362,6 +1496,8 @@ static BOOL rdg_process_control_packet(rdpRdg* rdg, int type, size_t packetLengt
return FALSE;
}
}
Stream_SetPosition(s, 0);
}
switch (type)
@ -1378,6 +1514,16 @@ static BOOL rdg_process_control_packet(rdpRdg* rdg, int type, size_t packetLengt
LeaveCriticalSection(&rdg->writeSection);
break;
case PKT_TYPE_SERVICE_MESSAGE:
if (!s)
{
WLog_ERR(TAG, "[%s] PKT_TYPE_SERVICE_MESSAGE requires payload but none was sent",
__FUNCTION__);
return FALSE;
}
status = rdg_process_service_message(rdg, s);
break;
default:
status = rdg_process_unknown_packet(rdg, type);
break;