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; UINT32 code;
const char* name; 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_TUNNEL_ID, "HTTP_TUNNEL_RESPONSE_FIELD_TUNNEL_ID" },
{ HTTP_TUNNEL_RESPONSE_FIELD_CAPS, "HTTP_TUNNEL_RESPONSE_FIELD_CAPS" }, { 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_SOH_REQ, "HTTP_TUNNEL_RESPONSE_FIELD_SOH_REQ" },
{ HTTP_TUNNEL_RESPONSE_FIELD_CONSENT_MSG, "HTTP_TUNNEL_RESPONSE_FIELD_CONSENT_MSG" } { 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_FIELD_CHANNELID, "HTTP_CHANNEL_RESPONSE_FIELD_CHANNELID" },
{ HTTP_CHANNEL_RESPONSE_OPTIONAL, "HTTP_CHANNEL_RESPONSE_OPTIONAL" }, { HTTP_CHANNEL_RESPONSE_OPTIONAL, "HTTP_CHANNEL_RESPONSE_OPTIONAL" },
{ HTTP_CHANNEL_RESPONSE_FIELD_UDPPORT, "HTTP_CHANNEL_RESPONSE_FIELD_UDPPORT" } { 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_REDIR_FLAGS, "HTTP_TUNNEL_AUTH_RESPONSE_FIELD_REDIR_FLAGS" },
{ HTTP_TUNNEL_AUTH_RESPONSE_FIELD_IDLE_TIMEOUT, { HTTP_TUNNEL_AUTH_RESPONSE_FIELD_IDLE_TIMEOUT,
"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" } "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_NONE, "HTTP_EXTENDED_AUTH_NONE" },
{ HTTP_EXTENDED_AUTH_SC, "HTTP_EXTENDED_AUTH_SC" }, { HTTP_EXTENDED_AUTH_SC, "HTTP_EXTENDED_AUTH_SC" },
{ HTTP_EXTENDED_AUTH_PAA, "HTTP_EXTENDED_AUTH_PAA" }, { HTTP_EXTENDED_AUTH_PAA, "HTTP_EXTENDED_AUTH_PAA" },
{ HTTP_EXTENDED_AUTH_SSPI_NTLM, "HTTP_EXTENDED_AUTH_SSPI_NTLM" } { HTTP_EXTENDED_AUTH_SSPI_NTLM, "HTTP_EXTENDED_AUTH_SSPI_NTLM" }
}; };
static const char* fields_present_to_string(UINT16 fieldsPresent, const t_err_mapping* map, static const t_flag_mapping capabilities_enum[] = {
size_t elements) { 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; size_t x = 0;
static char buffer[1024] = { 0 }; static char buffer[1024] = { 0 };
@ -194,31 +202,31 @@ static const char* fields_present_to_string(UINT16 fieldsPresent, const t_err_ma
if (buffer[0] != '\0') if (buffer[0] != '\0')
strcat(buffer, "|"); strcat(buffer, "|");
if ((map[x].code & fieldsPresent) != 0) if ((map[x].code & flags) != 0)
strcat(buffer, map[x].name); strcat(buffer, map[x].name);
} }
sprintf_s(fields, ARRAYSIZE(fields), " [%04" PRIx16 "]", fieldsPresent); sprintf_s(fields, ARRAYSIZE(fields), " [%04" PRIx32 "]", flags);
strcat(buffer, fields); strcat(buffer, fields);
return buffer; return buffer;
} }
static const char* channel_response_fields_present_to_string(UINT16 fieldsPresent) 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)); ARRAYSIZE(channel_response_fields_present));
} }
static const char* tunnel_response_fields_present_to_string(UINT16 fieldsPresent) 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)); ARRAYSIZE(tunnel_response_fields_present));
} }
static const char* tunnel_authorization_response_fields_present_to_string(UINT16 fieldsPresent) 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)); ARRAYSIZE(tunnel_authorization_response_fields_present));
} }
static const char* extended_auth_to_string(UINT16 auth) static const char* extended_auth_to_string(UINT16 auth)
@ -226,7 +234,38 @@ static const char* extended_auth_to_string(UINT16 auth)
if (auth == HTTP_EXTENDED_AUTH_NONE) if (auth == HTTP_EXTENDED_AUTH_NONE)
return "HTTP_EXTENDED_AUTH_NONE [0x0000]"; 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) static BOOL rdg_write_packet(rdpRdg* rdg, wStream* sPacket)
@ -357,6 +396,9 @@ static BOOL rdg_send_tunnel_request(rdpRdg* rdg)
UINT16 fieldsPresent = 0; UINT16 fieldsPresent = 0;
WCHAR* PAACookie = NULL; WCHAR* PAACookie = NULL;
int PAACookieLen = 0; 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) if (rdg->extAuth == HTTP_EXTENDED_AUTH_PAA)
{ {
@ -381,12 +423,12 @@ static BOOL rdg_send_tunnel_request(rdpRdg* rdg)
return FALSE; return FALSE;
} }
Stream_Write_UINT16(s, PKT_TYPE_TUNNEL_CREATE); /* Type (2 bytes) */ Stream_Write_UINT16(s, PKT_TYPE_TUNNEL_CREATE); /* Type (2 bytes) */
Stream_Write_UINT16(s, 0); /* Reserved (2 bytes) */ Stream_Write_UINT16(s, 0); /* Reserved (2 bytes) */
Stream_Write_UINT32(s, packetSize); /* PacketLength (4 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, fieldsPresent); /* FieldsPresent (2 bytes) */
Stream_Write_UINT16(s, 0); /* Reserved (2 bytes), must be 0 */ Stream_Write_UINT16(s, 0); /* Reserved (2 bytes), must be 0 */
if (PAACookie) if (PAACookie)
{ {
@ -669,6 +711,76 @@ static BOOL rdg_process_handshake_response(rdpRdg* rdg, wStream* s)
return rdg_send_tunnel_request(rdg); 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) static BOOL rdg_process_tunnel_response(rdpRdg* rdg, wStream* s)
{ {
UINT16 serverVersion, fieldsPresent; UINT16 serverVersion, fieldsPresent;
@ -703,6 +815,9 @@ static BOOL rdg_process_tunnel_response(rdpRdg* rdg, wStream* s)
return FALSE; return FALSE;
} }
if (!rdg_process_tunnel_response_optional(rdg, s, fieldsPresent))
return FALSE;
return rdg_send_tunnel_authorization(rdg); return rdg_send_tunnel_authorization(rdg);
} }
@ -1310,6 +1425,25 @@ static BOOL rdg_process_keep_alive_packet(rdpRdg* rdg)
return (status < 0 ? FALSE : TRUE); 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) static BOOL rdg_process_unknown_packet(rdpRdg* rdg, int type)
{ {
WINPR_UNUSED(rdg); WINPR_UNUSED(rdg);
@ -1362,6 +1496,8 @@ static BOOL rdg_process_control_packet(rdpRdg* rdg, int type, size_t packetLengt
return FALSE; return FALSE;
} }
} }
Stream_SetPosition(s, 0);
} }
switch (type) switch (type)
@ -1378,6 +1514,16 @@ static BOOL rdg_process_control_packet(rdpRdg* rdg, int type, size_t packetLengt
LeaveCriticalSection(&rdg->writeSection); LeaveCriticalSection(&rdg->writeSection);
break; 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: default:
status = rdg_process_unknown_packet(rdg, type); status = rdg_process_unknown_packet(rdg, type);
break; break;