mirror of
https://github.com/morgan9e/FreeRDP
synced 2026-04-15 00:44:19 +09:00
Merge pull request #12161 from akallabeth/tsg-fix
[gateway,tsg] fix TSG_PACKET_RESPONSE parsing
This commit is contained in:
@@ -418,8 +418,8 @@ static const COMMAND_LINE_ARGUMENT_A global_cmd_args[] = {
|
||||
{ "scale-device", COMMAND_LINE_VALUE_REQUIRED, "100|140|180", "100", NULL, -1, NULL,
|
||||
"Scaling factor for app store applications" },
|
||||
{ "sec", COMMAND_LINE_VALUE_REQUIRED,
|
||||
"[rdp[:[on|off]]|tls[:[on|off]]|nla[:[on|off]]|ext[:[on|off]]|aad[:[on|off]]]", NULL, NULL,
|
||||
-1, NULL,
|
||||
"rdp[:[on|off]]|tls[:[on|off]]|nla[:[on|off]]|ext[:[on|off]]|aad[:[on|off]]", NULL, NULL, -1,
|
||||
NULL,
|
||||
"Force specific protocol security. e.g. /sec:nla enables NLA and disables all others, while "
|
||||
"/sec:nla:[on|off] just toggles NLA" },
|
||||
#if defined(WITH_FREERDP_DEPRECATED_COMMANDLINE)
|
||||
|
||||
@@ -127,7 +127,7 @@ typedef struct
|
||||
{
|
||||
UINT32 flags;
|
||||
UINT32 reserved;
|
||||
BYTE* responseData;
|
||||
const BYTE* responseData;
|
||||
UINT32 responseDataLen;
|
||||
TSG_REDIRECTION_FLAGS redirectionFlags;
|
||||
} TSG_PACKET_RESPONSE;
|
||||
@@ -219,7 +219,6 @@ struct rdp_tsg
|
||||
rdpRpc* rpc;
|
||||
UINT16 Port;
|
||||
LPWSTR Hostname;
|
||||
LPWSTR MachineName;
|
||||
TSG_STATE state;
|
||||
UINT32 TunnelId;
|
||||
UINT32 ChannelId;
|
||||
@@ -231,6 +230,8 @@ struct rdp_tsg
|
||||
CONTEXT_HANDLE NewTunnelContext;
|
||||
CONTEXT_HANDLE NewChannelContext;
|
||||
wLog* log;
|
||||
TSG_PACKET_QUARENC_RESPONSE CapsResponse;
|
||||
TSG_PACKET_QUARREQUEST QuarreQuest;
|
||||
};
|
||||
|
||||
static BOOL TsProxyReadPacketSTringMessage(wLog* log, wStream* s, uint32_t* index,
|
||||
@@ -372,8 +373,7 @@ static BOOL tsg_ndr_pointer_read(wLog* log, wStream* s, UINT32* index, UINT32* p
|
||||
if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4))
|
||||
return FALSE;
|
||||
|
||||
DWORD val = 0;
|
||||
Stream_Read_UINT32(s, val);
|
||||
const DWORD val = Stream_Get_UINT32(s);
|
||||
if (ptrval)
|
||||
*ptrval = val;
|
||||
|
||||
@@ -397,16 +397,34 @@ static BOOL tsg_ndr_pointer_read(wLog* log, wStream* s, UINT32* index, UINT32* p
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL tsg_ndr_write_conformant_array(WINPR_ATTR_UNUSED wLog* log, wStream* s,
|
||||
const void* data, size_t length)
|
||||
{
|
||||
const size_t pad = length % 4;
|
||||
if ((length > UINT32_MAX) || !Stream_EnsureRemainingCapacity(s, 4ull + length))
|
||||
return FALSE;
|
||||
|
||||
Stream_Write_UINT32(s, WINPR_ASSERTING_INT_CAST(uint32_t, length)); /* MaxCount (4 bytes) */
|
||||
Stream_Write(s, data, length);
|
||||
if (pad != 0)
|
||||
Stream_Zero(s, 4 - pad);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL tsg_ndr_write_string(WINPR_ATTR_UNUSED wLog* log, wStream* s, const WCHAR* str,
|
||||
size_t length)
|
||||
{
|
||||
if (!Stream_EnsureRemainingCapacity(s, 12 + length) || (length > UINT32_MAX))
|
||||
const size_t pad = (length % 2) * sizeof(WCHAR);
|
||||
if ((length > UINT32_MAX) ||
|
||||
!Stream_EnsureRemainingCapacity(s, 12ull + length * sizeof(WCHAR) + pad))
|
||||
return FALSE;
|
||||
|
||||
Stream_Write_UINT32(s, (UINT32)length); /* MaxCount (4 bytes) */
|
||||
Stream_Write_UINT32(s, 0); /* Offset (4 bytes) */
|
||||
Stream_Write_UINT32(s, (UINT32)length); /* ActualCount (4 bytes) */
|
||||
Stream_Write_UTF16_String(s, str, length); /* Array */
|
||||
Stream_Zero(s, pad);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@@ -448,7 +466,9 @@ static BOOL tsg_ndr_read_string(wLog* log, wStream* s, WCHAR** str, UINT32 lengt
|
||||
if (!Stream_CheckAndLogRequiredLengthWLog(log, s, ActualCount * sizeof(WCHAR)))
|
||||
return FALSE;
|
||||
Stream_Seek(s, ActualCount * sizeof(WCHAR));
|
||||
return TRUE;
|
||||
|
||||
const size_t pad = (ActualCount % 2);
|
||||
return Stream_SafeSeek(s, pad * sizeof(WCHAR));
|
||||
}
|
||||
|
||||
static BOOL tsg_ndr_read_packet_header(wLog* log, wStream* s, TSG_PACKET_HEADER* header)
|
||||
@@ -519,9 +539,9 @@ static BOOL tsg_ndr_read_tsg_caps(wLog* log, wStream* s, TSG_PACKET_CAPABILITIES
|
||||
Stream_Read_UINT32(s, caps->capabilityType);
|
||||
if (capabilityType != caps->capabilityType)
|
||||
{
|
||||
WLog_Print(log, WLOG_ERROR, "Inconsistent data, capabilityType %s != %s",
|
||||
tsg_packet_id_to_string(capabilityType),
|
||||
tsg_packet_id_to_string(caps->capabilityType));
|
||||
WLog_Print(log, WLOG_ERROR,
|
||||
"Inconsistent data, capabilityType 0x%08" PRIx32 " != 0x%08" PRIx32,
|
||||
capabilityType, caps->capabilityType);
|
||||
return FALSE;
|
||||
}
|
||||
switch (caps->capabilityType)
|
||||
@@ -714,84 +734,29 @@ static BOOL tsg_ndr_write_reauth(wLog* log, wStream* s, UINT32* index,
|
||||
}
|
||||
}
|
||||
|
||||
static BOOL tsg_ndr_read_packet_response(wLog* log, wStream* s, UINT32* index,
|
||||
TSG_PACKET_RESPONSE* response)
|
||||
static BOOL tsg_ndr_read_packet_redirection_flags(wLog* log, wStream* s,
|
||||
TSG_REDIRECTION_FLAGS* redirectionFlags)
|
||||
{
|
||||
UINT32 ResponseDataPtr = 0;
|
||||
WINPR_ASSERT(redirectionFlags);
|
||||
|
||||
WINPR_ASSERT(response);
|
||||
|
||||
if (!Stream_CheckAndLogRequiredLengthOfSizeWLog(log, s, 2, sizeof(UINT32)))
|
||||
return FALSE;
|
||||
Stream_Read_UINT32(s, response->flags); /* Flags (4 bytes) */
|
||||
Stream_Seek_UINT32(s); /* Reserved (4 bytes) */
|
||||
|
||||
if (response->flags != TSG_PACKET_TYPE_QUARREQUEST)
|
||||
{
|
||||
WLog_Print(log, WLOG_ERROR,
|
||||
"Unexpected Packet Response Flags: 0x%08" PRIX32
|
||||
", Expected TSG_PACKET_TYPE_QUARREQUEST",
|
||||
response->flags);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!tsg_ndr_pointer_read(log, s, index, &ResponseDataPtr, TRUE))
|
||||
if (!Stream_CheckAndLogRequiredLengthOfSizeWLog(log, s, 8, sizeof(UINT32)))
|
||||
return FALSE;
|
||||
|
||||
if (!Stream_CheckAndLogRequiredLengthOfSizeWLog(log, s, 10, sizeof(UINT32)))
|
||||
return FALSE;
|
||||
|
||||
Stream_Read_UINT32(s, response->responseDataLen); /* ResponseDataLength (4 bytes) */
|
||||
Stream_Read_INT32(
|
||||
s, response->redirectionFlags.enableAllRedirections); /* EnableAllRedirections (4 bytes) */
|
||||
Stream_Read_INT32(
|
||||
s,
|
||||
response->redirectionFlags.disableAllRedirections); /* DisableAllRedirections (4 bytes) */
|
||||
Stream_Read_INT32(s, response->redirectionFlags
|
||||
.driveRedirectionDisabled); /* DriveRedirectionDisabled (4 bytes) */
|
||||
Stream_Read_INT32(s,
|
||||
response->redirectionFlags
|
||||
.printerRedirectionDisabled); /* PrinterRedirectionDisabled (4 bytes) */
|
||||
Stream_Read_INT32(
|
||||
s,
|
||||
response->redirectionFlags.portRedirectionDisabled); /* PortRedirectionDisabled (4 bytes) */
|
||||
Stream_Read_INT32(s, response->redirectionFlags.reserved); /* Reserved (4 bytes) */
|
||||
Stream_Read_INT32(
|
||||
s, response->redirectionFlags
|
||||
.clipboardRedirectionDisabled); /* ClipboardRedirectionDisabled (4 bytes) */
|
||||
Stream_Read_INT32(
|
||||
s,
|
||||
response->redirectionFlags.pnpRedirectionDisabled); /* PnpRedirectionDisabled (4 bytes) */
|
||||
|
||||
const UINT32 MaxSizeValue = Stream_Get_UINT32(s); /* (4 bytes) */
|
||||
const UINT32 MaxOffsetValue = Stream_Get_UINT32(s); /* (4 bytes) */
|
||||
|
||||
if (MaxSizeValue != response->responseDataLen)
|
||||
{
|
||||
WLog_Print(log, WLOG_ERROR, "Unexpected size value: %" PRIu32 ", expected: %" PRIu32 "",
|
||||
MaxSizeValue, response->responseDataLen);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (MaxOffsetValue != 0)
|
||||
{
|
||||
WLog_Print(log, WLOG_ERROR, "Unexpected offset value: %" PRIu32 ", expected: 0",
|
||||
MaxOffsetValue);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!Stream_CheckAndLogRequiredLengthWLog(log, s, MaxSizeValue))
|
||||
return FALSE;
|
||||
|
||||
if (MaxSizeValue >= 4)
|
||||
{
|
||||
const UINT32 idleTimeout = Stream_Get_UINT32(s);
|
||||
WLog_Print(log, WLOG_DEBUG, "[IDLE_TIMEOUT] idleTimeout=%" PRIu32 ": TODO: unused",
|
||||
idleTimeout);
|
||||
Stream_Seek(s, MaxSizeValue - 4);
|
||||
}
|
||||
else
|
||||
Stream_Seek(s, MaxSizeValue); /* ResponseData */
|
||||
redirectionFlags->enableAllRedirections =
|
||||
Stream_Get_INT32(s); /* EnableAllRedirections (4 bytes) */
|
||||
redirectionFlags->disableAllRedirections =
|
||||
Stream_Get_INT32(s); /* DisableAllRedirections (4 bytes) */
|
||||
redirectionFlags->driveRedirectionDisabled =
|
||||
Stream_Get_INT32(s); /* DriveRedirectionDisabled (4 bytes) */
|
||||
redirectionFlags->printerRedirectionDisabled =
|
||||
Stream_Get_INT32(s); /* PrinterRedirectionDisabled (4 bytes) */
|
||||
redirectionFlags->portRedirectionDisabled =
|
||||
Stream_Get_INT32(s); /* PortRedirectionDisabled (4 bytes) */
|
||||
redirectionFlags->reserved = Stream_Get_INT32(s); /* Reserved (4 bytes) */
|
||||
redirectionFlags->clipboardRedirectionDisabled =
|
||||
Stream_Get_INT32(s); /* ClipboardRedirectionDisabled (4 bytes) */
|
||||
redirectionFlags->pnpRedirectionDisabled =
|
||||
Stream_Get_INT32(s); /* PnpRedirectionDisabled (4 bytes) */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
@@ -1685,6 +1650,7 @@ static BOOL TsProxyCreateTunnelReadResponse(rdpTsg* tsg, const RPC_PDU* pdu,
|
||||
&packet.tsgPacket.packetCapsResponse, tunnelContext,
|
||||
tunnelId, &tsg->ReauthTunnelContext))
|
||||
goto fail;
|
||||
tsg->CapsResponse = packet.tsgPacket.packetCapsResponse.pktQuarEncResponse;
|
||||
}
|
||||
else if ((packet.packetId == TSG_PACKET_TYPE_QUARENC_RESPONSE) &&
|
||||
(SwitchValue == TSG_PACKET_TYPE_QUARENC_RESPONSE))
|
||||
@@ -1704,6 +1670,8 @@ static BOOL TsProxyCreateTunnelReadResponse(rdpTsg* tsg, const RPC_PDU* pdu,
|
||||
|
||||
if (!tsg_ndr_read_tunnel_context(tsg->log, pdu->s, tunnelContext, tunnelId))
|
||||
goto fail;
|
||||
|
||||
tsg->CapsResponse = packet.tsgPacket.packetQuarEncResponse;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1741,22 +1709,14 @@ fail:
|
||||
|
||||
static BOOL TsProxyAuthorizeTunnelWriteRequest(rdpTsg* tsg, CONTEXT_HANDLE* tunnelContext)
|
||||
{
|
||||
size_t pad = 0;
|
||||
wStream* s = NULL;
|
||||
size_t count = 0;
|
||||
size_t offset = 0;
|
||||
rdpRpc* rpc = NULL;
|
||||
|
||||
if (!tsg || !tsg->rpc || !tunnelContext || !tsg->MachineName)
|
||||
if (!tsg || !tsg->rpc || !tunnelContext)
|
||||
return FALSE;
|
||||
|
||||
count = _wcslen(tsg->MachineName) + 1;
|
||||
if (count > UINT32_MAX)
|
||||
return FALSE;
|
||||
rdpRpc* rpc = tsg->rpc;
|
||||
|
||||
rpc = tsg->rpc;
|
||||
WLog_Print(tsg->log, WLOG_DEBUG, "TsProxyAuthorizeTunnelWriteRequest");
|
||||
s = Stream_New(NULL, 1024 + count * 2);
|
||||
wStream* s = Stream_New(NULL, 1024 + sizeof(WCHAR) * tsg->QuarreQuest.nameLength +
|
||||
tsg->QuarreQuest.dataLen);
|
||||
|
||||
if (!s)
|
||||
return FALSE;
|
||||
@@ -1773,21 +1733,22 @@ static BOOL TsProxyAuthorizeTunnelWriteRequest(rdpTsg* tsg, CONTEXT_HANDLE* tunn
|
||||
Stream_Write_UINT32(s, TSG_PACKET_TYPE_QUARREQUEST); /* SwitchValue (4 bytes) */
|
||||
if (!tsg_ndr_pointer_write(tsg->log, s, &index, 1)) /* PacketQuarRequestPtr (4 bytes) */
|
||||
goto fail;
|
||||
Stream_Write_UINT32(s, 0x00000000); /* Flags (4 bytes) */
|
||||
Stream_Write_UINT32(s, tsg->QuarreQuest.flags); /* Flags (4 bytes) */
|
||||
if (!tsg_ndr_pointer_write(tsg->log, s, &index, 1)) /* MachineNamePtr (4 bytes) */
|
||||
goto fail;
|
||||
Stream_Write_UINT32(s, (UINT32)count); /* NameLength (4 bytes) */
|
||||
Stream_Write_UINT32(s, tsg->QuarreQuest.nameLength); /* NameLength (4 bytes) */
|
||||
if (!tsg_ndr_pointer_write(tsg->log, s, &index, 1)) /* DataPtr (4 bytes) */
|
||||
goto fail;
|
||||
Stream_Write_UINT32(s, 0); /* DataLength (4 bytes) */
|
||||
Stream_Write_UINT32(s, tsg->QuarreQuest.dataLen); /* DataLength (4 bytes) */
|
||||
/* MachineName */
|
||||
if (!tsg_ndr_write_string(tsg->log, s, tsg->MachineName, count))
|
||||
if (!tsg_ndr_write_string(tsg->log, s, tsg->QuarreQuest.machineName,
|
||||
tsg->QuarreQuest.nameLength))
|
||||
goto fail;
|
||||
/* 4-byte alignment */
|
||||
offset = Stream_GetPosition(s);
|
||||
pad = rpc_offset_align(&offset, 4);
|
||||
Stream_Zero(s, pad);
|
||||
Stream_Write_UINT32(s, 0x00000000); /* MaxCount (4 bytes) */
|
||||
/* data */
|
||||
if (!tsg_ndr_write_conformant_array(tsg->log, s, tsg->QuarreQuest.data,
|
||||
tsg->QuarreQuest.dataLen))
|
||||
goto fail;
|
||||
|
||||
Stream_SealLength(s);
|
||||
return rpc_client_write_call(rpc, s, TsProxyAuthorizeTunnelOpnum);
|
||||
fail:
|
||||
@@ -1829,6 +1790,150 @@ static BOOL tsg_redirect_apply(rdpTsg* tsg, const TSG_REDIRECTION_FLAGS* redirec
|
||||
return utils_apply_gateway_policy(tsg->log, context, redirFlags, "TSG");
|
||||
}
|
||||
|
||||
static BOOL tsg_ndr_read_timeout(wLog* log, wStream* s, size_t tlen)
|
||||
{
|
||||
if (!Stream_CheckAndLogRequiredLengthOfSizeWLog(log, s, 1, sizeof(UINT32)))
|
||||
return FALSE;
|
||||
|
||||
if (tlen < sizeof(UINT32))
|
||||
{
|
||||
WLog_Print(log, WLOG_ERROR, "[IDLE_TIMEOUT] array element length %" PRIuz ", expected 4",
|
||||
tlen);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
const UINT32 idleTimeout = Stream_Get_UINT32(s);
|
||||
WLog_Print(log, WLOG_DEBUG, "[IDLE_TIMEOUT] idleTimeout=%" PRIu32 ": TODO: unused",
|
||||
idleTimeout);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL tsg_ndr_read_sohr(wLog* log, wStream* s, size_t slen)
|
||||
{
|
||||
if (slen == 0)
|
||||
{
|
||||
WLog_Print(log, WLOG_DEBUG, "[SOH] array element length %" PRIuz ", skipping read", slen);
|
||||
return TRUE;
|
||||
}
|
||||
if (!Stream_CheckAndLogRequiredLengthOfSizeWLog(log, s, 1, sizeof(UINT32)))
|
||||
return FALSE;
|
||||
|
||||
if (slen != 0)
|
||||
{
|
||||
WLog_Print(log, WLOG_DEBUG, "[SOH] array element length %" PRIuz, slen);
|
||||
}
|
||||
|
||||
const UINT32 len = Stream_Get_UINT32(s);
|
||||
WLog_Print(log, WLOG_DEBUG, "[SOH] len=%" PRIu32 ": TODO: unused", len);
|
||||
if (!Stream_SafeSeek(s, len))
|
||||
return FALSE;
|
||||
|
||||
winpr_HexLogDump(log, WLOG_DEBUG, Stream_Pointer(s), len);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL tsg_ndr_read_packet_response_data(rdpTsg* tsg, wStream* s,
|
||||
const TSG_PACKET_RESPONSE* response)
|
||||
{
|
||||
WINPR_ASSERT(tsg);
|
||||
|
||||
if (!Stream_CheckAndLogRequiredCapacityOfSizeWLog(tsg->log, s, 1, 4))
|
||||
return FALSE;
|
||||
|
||||
const uint32_t arrayMaxLen = Stream_Get_UINT32(s);
|
||||
const size_t len = Stream_GetRemainingLength(s);
|
||||
if (arrayMaxLen != response->responseDataLen)
|
||||
{
|
||||
WLog_Print(tsg->log, WLOG_ERROR,
|
||||
"2.2.9.2.1.5 TSG_PACKET_RESPONSE::responseDataLen=%" PRIu32
|
||||
" != NDR array len %" PRIu32,
|
||||
response->responseDataLen, arrayMaxLen);
|
||||
}
|
||||
if (response->responseDataLen > 0)
|
||||
{
|
||||
if (!Stream_CheckAndLogRequiredCapacityOfSizeWLog(tsg->log, s, 1, 4))
|
||||
return FALSE;
|
||||
|
||||
const uint32_t arrayOffset = Stream_Get_UINT32(s);
|
||||
if (arrayOffset != 0)
|
||||
{
|
||||
WLog_Print(tsg->log, WLOG_ERROR,
|
||||
"2.2.9.2.1.5 TSG_PACKET_RESPONSE array offset != 0: 0x%08" PRIx32,
|
||||
arrayOffset);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
const size_t rem = Stream_GetRemainingLength(s);
|
||||
|
||||
if (tsg->CapsResponse.versionCaps.tsgCaps.capabilityType != TSG_CAPABILITY_TYPE_NAP)
|
||||
{
|
||||
WLog_Print(
|
||||
tsg->log, WLOG_ERROR,
|
||||
"2.2.9.2.1.5 TSG_PACKET_RESPONSE Negotiated Capabilities type is 0x%08" PRIx32
|
||||
", expected TSG_CAPABILITY_TYPE_NAP[0x00000001]",
|
||||
tsg->CapsResponse.versionCaps.tsgCaps.capabilityType);
|
||||
return FALSE;
|
||||
}
|
||||
const UINT32 mask = (TSG_NAP_CAPABILITY_QUAR_SOH | TSG_NAP_CAPABILITY_IDLE_TIMEOUT);
|
||||
const UINT32 val =
|
||||
(tsg->CapsResponse.versionCaps.tsgCaps.tsgPacket.tsgCapNap.capabilities & mask);
|
||||
if ((val == mask) && (tsg->QuarreQuest.dataLen > 0))
|
||||
{
|
||||
if (!tsg_ndr_read_timeout(tsg->log, s, arrayMaxLen))
|
||||
return FALSE;
|
||||
if (!tsg_ndr_read_sohr(tsg->log, s, arrayMaxLen - sizeof(uint32_t)))
|
||||
return FALSE;
|
||||
}
|
||||
else if ((val == TSG_NAP_CAPABILITY_QUAR_SOH) && (tsg->QuarreQuest.dataLen > 0))
|
||||
{
|
||||
if (!tsg_ndr_read_sohr(tsg->log, s, arrayMaxLen))
|
||||
return FALSE;
|
||||
}
|
||||
else if ((val & TSG_NAP_CAPABILITY_IDLE_TIMEOUT) != 0)
|
||||
{
|
||||
if (rem != response->responseDataLen)
|
||||
{
|
||||
WLog_Print(tsg->log, WLOG_ERROR,
|
||||
"2.2.9.2.1.5 TSG_PACKET_RESPONSE::responseDataLen=%" PRIu32
|
||||
", expected 4 bytes and actually got %" PRIuz,
|
||||
response->responseDataLen, rem);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!tsg_ndr_read_timeout(tsg->log, s, arrayMaxLen))
|
||||
return FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
WLog_Print(
|
||||
tsg->log, WLOG_ERROR,
|
||||
"2.2.9.2.1.5 TSG_PACKET_RESPONSE::responseDataLen=%" PRIu32
|
||||
", but neither TSG_NAP_CAPABILITY_QUAR_SOH nor "
|
||||
"TSG_NAP_CAPABILITY_IDLE_TIMEOUT are set, so expecting 0 (actually got %" PRIuz ")",
|
||||
response->responseDataLen, rem);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
else if (len > 0)
|
||||
{
|
||||
WLog_Print(tsg->log, WLOG_ERROR,
|
||||
"2.2.9.2.1.5 TSG_PACKET_RESPONSE::responseDataLen=%" PRIu32
|
||||
", but actually got %" PRIuz,
|
||||
response->responseDataLen, len);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
{
|
||||
const size_t rem = Stream_GetRemainingLength(s);
|
||||
if (rem > 0)
|
||||
{
|
||||
WLog_Print(tsg->log, WLOG_WARN,
|
||||
"2.2.9.2.1.5 TSG_PACKET_RESPONSE %" PRIuz " unhandled bytes remain", rem);
|
||||
}
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL TsProxyAuthorizeTunnelReadResponse(rdpTsg* tsg, const RPC_PDU* pdu)
|
||||
{
|
||||
BOOL rc = FALSE;
|
||||
@@ -1836,7 +1941,7 @@ static BOOL TsProxyAuthorizeTunnelReadResponse(rdpTsg* tsg, const RPC_PDU* pdu)
|
||||
UINT32 index = 0;
|
||||
TSG_PACKET packet = { 0 };
|
||||
UINT32 PacketPtr = 0;
|
||||
UINT32 PacketResponsePtr = 0;
|
||||
UINT32 PacketResponseDataPtr = 0;
|
||||
|
||||
WINPR_ASSERT(tsg);
|
||||
WINPR_ASSERT(pdu);
|
||||
@@ -1871,16 +1976,56 @@ static BOOL TsProxyAuthorizeTunnelReadResponse(rdpTsg* tsg, const RPC_PDU* pdu)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
UINT32 PacketResponsePtr = 0;
|
||||
if (!tsg_ndr_pointer_read(log, pdu->s, &index, &PacketResponsePtr, TRUE))
|
||||
goto fail;
|
||||
|
||||
if (!tsg_ndr_read_packet_response(log, pdu->s, &index, &packet.tsgPacket.packetResponse))
|
||||
if (!Stream_CheckAndLogRequiredLengthWLog(log, pdu->s, 8))
|
||||
goto fail;
|
||||
|
||||
rc = TRUE;
|
||||
packet.tsgPacket.packetResponse.flags = Stream_Get_UINT32(pdu->s);
|
||||
if (packet.tsgPacket.packetResponse.flags != TSG_PACKET_TYPE_QUARREQUEST)
|
||||
{
|
||||
WLog_Print(log, WLOG_ERROR,
|
||||
"Unexpected Packet Response flags: 0x%08" PRIX32
|
||||
", Expected TSG_PACKET_TYPE_QUARREQUEST",
|
||||
packet.tsgPacket.packetResponse.flags);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
packet.tsgPacket.packetResponse.reserved = Stream_Get_UINT32(pdu->s);
|
||||
|
||||
packet.tsgPacket.packetResponse.responseData = NULL;
|
||||
if (!tsg_ndr_pointer_read(log, pdu->s, &index, &PacketResponseDataPtr, FALSE))
|
||||
goto fail;
|
||||
|
||||
packet.tsgPacket.packetResponse.responseDataLen = Stream_Get_UINT32(pdu->s);
|
||||
if (packet.tsgPacket.packetResponse.responseDataLen > 24000)
|
||||
{
|
||||
WLog_Print(log, WLOG_ERROR,
|
||||
"2.2.9.2.1.5 TSG_PACKET_RESPONSE::responseDataLen %" PRIu32 " > maximum(24000)",
|
||||
packet.tsgPacket.packetResponse.responseDataLen);
|
||||
goto fail;
|
||||
}
|
||||
if ((PacketResponseDataPtr == 0) && (packet.tsgPacket.packetResponse.responseDataLen != 0))
|
||||
{
|
||||
WLog_Print(log, WLOG_ERROR,
|
||||
"2.2.9.2.1.5 TSG_PACKET_RESPONSE::responseDataLen %" PRIu32
|
||||
" but responseData = NULL",
|
||||
packet.tsgPacket.packetResponse.responseDataLen);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (!tsg_ndr_read_packet_redirection_flags(log, pdu->s,
|
||||
&packet.tsgPacket.packetResponse.redirectionFlags))
|
||||
goto fail;
|
||||
|
||||
packet.tsgPacket.packetResponse.responseData = Stream_Pointer(pdu->s);
|
||||
if (!tsg_ndr_read_packet_response_data(tsg, pdu->s, &packet.tsgPacket.packetResponse))
|
||||
goto fail;
|
||||
|
||||
rc = tsg_redirect_apply(tsg, &packet.tsgPacket.packetResponse.redirectionFlags);
|
||||
|
||||
if (packet.tsgPacket.packetResponse.flags & TSG_PACKET_TYPE_QUARREQUEST)
|
||||
rc = tsg_redirect_apply(tsg, &packet.tsgPacket.packetResponse.redirectionFlags);
|
||||
fail:
|
||||
return rc;
|
||||
}
|
||||
@@ -2083,7 +2228,7 @@ static BOOL TsProxyCreateChannelWriteRequest(rdpTsg* tsg, CONTEXT_HANDLE* tunnel
|
||||
if (!tsg_ndr_pointer_write(tsg->log, s, &index, 1))
|
||||
goto fail;
|
||||
}
|
||||
if (!tsg_ndr_write_string(tsg->log, s, tsg->Hostname, (UINT32)count))
|
||||
if (!tsg_ndr_write_string(tsg->log, s, tsg->Hostname, count))
|
||||
goto fail;
|
||||
return rpc_client_write_call(rpc, s, TsProxyCreateChannelOpnum);
|
||||
|
||||
@@ -2276,8 +2421,10 @@ static BOOL tsg_transition_to_state(rdpTsg* tsg, TSG_STATE state)
|
||||
return tsg_set_state(tsg, state);
|
||||
}
|
||||
|
||||
static BOOL tsg_initialize_version_caps(TSG_PACKET_VERSIONCAPS* packetVersionCaps)
|
||||
static BOOL tsg_initialize_version_caps(const rdpTsg* tsg,
|
||||
TSG_PACKET_VERSIONCAPS* packetVersionCaps)
|
||||
{
|
||||
WINPR_ASSERT(tsg);
|
||||
WINPR_ASSERT(packetVersionCaps);
|
||||
|
||||
packetVersionCaps->tsgHeader.ComponentId = TS_GATEWAY_TRANSPORT;
|
||||
@@ -2291,17 +2438,27 @@ static BOOL tsg_initialize_version_caps(TSG_PACKET_VERSIONCAPS* packetVersionCap
|
||||
* Using reduced capabilities appears to trigger
|
||||
* TSG_PACKET_TYPE_QUARENC_RESPONSE instead of TSG_PACKET_TYPE_CAPS_RESPONSE
|
||||
*
|
||||
* However, reduced capabilities may break connectivity with servers enforcing features, such as
|
||||
* "Only allow connections from Remote Desktop Services clients that support RD Gateway
|
||||
* messaging"
|
||||
* However, reduced capabilities may break connectivity with servers enforcing features,
|
||||
* such as "Only allow connections from Remote Desktop Services clients that support RD
|
||||
* Gateway messaging"
|
||||
*/
|
||||
|
||||
packetVersionCaps->tsgCaps.tsgPacket.tsgCapNap.capabilities =
|
||||
TSG_NAP_CAPABILITY_QUAR_SOH | TSG_NAP_CAPABILITY_IDLE_TIMEOUT |
|
||||
TSG_MESSAGING_CAP_CONSENT_SIGN | TSG_MESSAGING_CAP_SERVICE_MSG | TSG_MESSAGING_CAP_REAUTH;
|
||||
TSG_NAP_CAPABILITY_IDLE_TIMEOUT | TSG_MESSAGING_CAP_CONSENT_SIGN |
|
||||
TSG_MESSAGING_CAP_SERVICE_MSG | TSG_MESSAGING_CAP_REAUTH;
|
||||
if (tsg->QuarreQuest.dataLen > 0)
|
||||
packetVersionCaps->tsgCaps.tsgPacket.tsgCapNap.capabilities |= TSG_NAP_CAPABILITY_QUAR_SOH;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void resetCaps(rdpTsg* tsg)
|
||||
{
|
||||
WINPR_ASSERT(tsg);
|
||||
const TSG_PACKET_QUARENC_RESPONSE empty = { 0 };
|
||||
tsg->CapsResponse = empty;
|
||||
}
|
||||
|
||||
BOOL tsg_proxy_begin(rdpTsg* tsg)
|
||||
{
|
||||
TSG_PACKET tsgPacket = { 0 };
|
||||
@@ -2309,7 +2466,7 @@ BOOL tsg_proxy_begin(rdpTsg* tsg)
|
||||
WINPR_ASSERT(tsg);
|
||||
|
||||
tsgPacket.packetId = TSG_PACKET_TYPE_VERSIONCAPS;
|
||||
if (!tsg_initialize_version_caps(&tsgPacket.tsgPacket.packetVersionCaps) ||
|
||||
if (!tsg_initialize_version_caps(tsg, &tsgPacket.tsgPacket.packetVersionCaps) ||
|
||||
!TsProxyCreateTunnelWriteRequest(tsg, &tsgPacket))
|
||||
{
|
||||
WLog_Print(tsg->log, WLOG_ERROR, "TsProxyCreateTunnel failure");
|
||||
@@ -2317,6 +2474,8 @@ BOOL tsg_proxy_begin(rdpTsg* tsg)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
resetCaps(tsg);
|
||||
|
||||
return tsg_transition_to_state(tsg, TSG_STATE_INITIAL);
|
||||
}
|
||||
|
||||
@@ -2333,7 +2492,7 @@ static BOOL tsg_proxy_reauth(rdpTsg* tsg)
|
||||
packetReauth->tunnelContext = tsg->ReauthTunnelContext;
|
||||
packetReauth->packetId = TSG_PACKET_TYPE_VERSIONCAPS;
|
||||
|
||||
if (!tsg_initialize_version_caps(&packetReauth->tsgInitialPacket.packetVersionCaps))
|
||||
if (!tsg_initialize_version_caps(tsg, &packetReauth->tsgInitialPacket.packetVersionCaps))
|
||||
return FALSE;
|
||||
|
||||
if (!TsProxyCreateTunnelWriteRequest(tsg, &tsgPacket))
|
||||
@@ -2351,6 +2510,7 @@ static BOOL tsg_proxy_reauth(rdpTsg* tsg)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
resetCaps(tsg);
|
||||
return tsg_transition_to_state(tsg, TSG_STATE_INITIAL);
|
||||
}
|
||||
|
||||
@@ -2689,9 +2849,17 @@ static BOOL tsg_set_hostname(rdpTsg* tsg, const char* hostname)
|
||||
static BOOL tsg_set_machine_name(rdpTsg* tsg, const char* machineName)
|
||||
{
|
||||
WINPR_ASSERT(tsg);
|
||||
free(tsg->MachineName);
|
||||
tsg->MachineName = ConvertUtf8ToWCharAlloc(machineName, NULL);
|
||||
return tsg->MachineName != NULL;
|
||||
|
||||
free(tsg->QuarreQuest.machineName);
|
||||
tsg->QuarreQuest.machineName = NULL;
|
||||
tsg->QuarreQuest.nameLength = 0;
|
||||
if (!machineName)
|
||||
return FALSE;
|
||||
|
||||
size_t size = 0;
|
||||
tsg->QuarreQuest.machineName = ConvertUtf8ToWCharAlloc(machineName, &size);
|
||||
tsg->QuarreQuest.nameLength = WINPR_ASSERTING_INT_CAST(uint32_t, size + 1ull);
|
||||
return tsg->QuarreQuest.machineName && (size > 0);
|
||||
}
|
||||
|
||||
BOOL tsg_connect(rdpTsg* tsg, const char* hostname, UINT16 port, DWORD timeout)
|
||||
@@ -2812,7 +2980,8 @@ BOOL tsg_disconnect(rdpTsg* tsg)
|
||||
* @param[in] data A pointer to the data buffer
|
||||
* @param[in] length length of data
|
||||
*
|
||||
* @return < 0 on error; 0 if not enough data is available (non blocking mode); > 0 bytes to read
|
||||
* @return < 0 on error; 0 if not enough data is available (non blocking mode); > 0 bytes to
|
||||
* read
|
||||
*/
|
||||
|
||||
static int tsg_read(rdpTsg* tsg, BYTE* data, size_t length)
|
||||
@@ -2911,7 +3080,8 @@ void tsg_free(rdpTsg* tsg)
|
||||
{
|
||||
rpc_free(tsg->rpc);
|
||||
free(tsg->Hostname);
|
||||
free(tsg->MachineName);
|
||||
free(tsg->QuarreQuest.machineName);
|
||||
free(tsg->QuarreQuest.data);
|
||||
free(tsg);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user