libfreerdp-core: remove usage of magic 60-byte pad in TsProxyCreateTunnelWriteRequest
This commit is contained in:
parent
9406ac188c
commit
4f173ae52a
@ -26,8 +26,6 @@
|
||||
#include <winpr/stream.h>
|
||||
#include <winpr/string.h>
|
||||
|
||||
|
||||
|
||||
#ifdef HAVE_VALGRIND_MEMCHECK_H
|
||||
#include <valgrind/memcheck.h>
|
||||
#endif
|
||||
|
@ -21,11 +21,8 @@
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <winpr/crt.h>
|
||||
|
||||
#include <freerdp/log.h>
|
||||
|
||||
#include "rpc_client.h"
|
||||
@ -51,8 +48,6 @@ const p_uuid_t TSGU_UUID =
|
||||
{ 0x3C, 0xDB, 0x6E, 0x7A, 0x27, 0x29 } /* node[6] */
|
||||
};
|
||||
|
||||
#define TSGU_SYNTAX_IF_VERSION 0x00030001
|
||||
|
||||
const p_uuid_t NDR_UUID =
|
||||
{
|
||||
0x8A885D04, /* time_low */
|
||||
@ -63,8 +58,6 @@ const p_uuid_t NDR_UUID =
|
||||
{ 0x08, 0x00, 0x2B, 0x10, 0x48, 0x60 } /* node[6] */
|
||||
};
|
||||
|
||||
#define NDR_SYNTAX_IF_VERSION 0x00000002
|
||||
|
||||
const p_uuid_t BTFN_UUID =
|
||||
{
|
||||
0x6CB71C2C, /* time_low */
|
||||
@ -75,8 +68,6 @@ const p_uuid_t BTFN_UUID =
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } /* node[6] */
|
||||
};
|
||||
|
||||
#define BTFN_SYNTAX_IF_VERSION 0x00000001
|
||||
|
||||
/**
|
||||
* SECURE_BIND: RPC bind PDU with sec_trailer and auth_token. Auth_token is generated by calling
|
||||
* the implementation equivalent of the abstract GSS_Init_sec_context call. Upon receiving that, the
|
||||
@ -149,12 +140,11 @@ int rpc_send_bind_pdu(rdpRpc* rpc)
|
||||
}
|
||||
|
||||
if (!ntlm_client_init(rpc->ntlm, FALSE, settings->GatewayUsername, settings->GatewayDomain, settings->GatewayPassword, NULL) ||
|
||||
!ntlm_client_make_spn(rpc->ntlm, NULL, settings->GatewayHostname) ||
|
||||
!ntlm_authenticate(rpc->ntlm)
|
||||
)
|
||||
!ntlm_client_make_spn(rpc->ntlm, NULL, settings->GatewayHostname) || !ntlm_authenticate(rpc->ntlm))
|
||||
return -1;
|
||||
|
||||
bind_pdu = (rpcconn_bind_hdr_t*) calloc(1, sizeof(rpcconn_bind_hdr_t));
|
||||
|
||||
if (!bind_pdu)
|
||||
return -1;
|
||||
|
||||
@ -175,7 +165,8 @@ int rpc_send_bind_pdu(rdpRpc* rpc)
|
||||
bind_pdu->p_context_elem.reserved = 0;
|
||||
bind_pdu->p_context_elem.reserved2 = 0;
|
||||
|
||||
bind_pdu->p_context_elem.p_cont_elem = malloc(sizeof(p_cont_elem_t) * bind_pdu->p_context_elem.n_context_elem);
|
||||
bind_pdu->p_context_elem.p_cont_elem = calloc(bind_pdu->p_context_elem.n_context_elem, sizeof(p_cont_elem_t));
|
||||
|
||||
if (!bind_pdu->p_context_elem.p_cont_elem)
|
||||
return -1;
|
||||
|
||||
@ -188,6 +179,10 @@ int rpc_send_bind_pdu(rdpRpc* rpc)
|
||||
p_cont_elem->abstract_syntax.if_version = TSGU_SYNTAX_IF_VERSION;
|
||||
|
||||
p_cont_elem->transfer_syntaxes = malloc(sizeof(p_syntax_id_t));
|
||||
|
||||
if (!p_cont_elem->transfer_syntaxes)
|
||||
return -1;
|
||||
|
||||
CopyMemory(&(p_cont_elem->transfer_syntaxes[0].if_uuid), &NDR_UUID, sizeof(p_uuid_t));
|
||||
p_cont_elem->transfer_syntaxes[0].if_version = NDR_SYNTAX_IF_VERSION;
|
||||
|
||||
@ -200,6 +195,10 @@ int rpc_send_bind_pdu(rdpRpc* rpc)
|
||||
p_cont_elem->abstract_syntax.if_version = TSGU_SYNTAX_IF_VERSION;
|
||||
|
||||
p_cont_elem->transfer_syntaxes = malloc(sizeof(p_syntax_id_t));
|
||||
|
||||
if (!p_cont_elem->transfer_syntaxes)
|
||||
return -1;
|
||||
|
||||
CopyMemory(&(p_cont_elem->transfer_syntaxes[0].if_uuid), &BTFN_UUID, sizeof(p_uuid_t));
|
||||
p_cont_elem->transfer_syntaxes[0].if_version = BTFN_SYNTAX_IF_VERSION;
|
||||
|
||||
@ -235,6 +234,7 @@ int rpc_send_bind_pdu(rdpRpc* rpc)
|
||||
length = bind_pdu->frag_length;
|
||||
|
||||
clientCall = rpc_client_call_new(bind_pdu->call_id, 0);
|
||||
|
||||
if (!clientCall)
|
||||
{
|
||||
free(buffer);
|
||||
@ -293,6 +293,9 @@ int rpc_recv_bind_ack_pdu(rdpRpc* rpc, BYTE* buffer, UINT32 length)
|
||||
rpc->ntlm->inputBuffer[0].cbBuffer = header->common.auth_length;
|
||||
rpc->ntlm->inputBuffer[0].pvBuffer = malloc(header->common.auth_length);
|
||||
|
||||
if (!rpc->ntlm->inputBuffer[0].pvBuffer)
|
||||
return -1;
|
||||
|
||||
auth_data = buffer + (header->common.frag_length - header->common.auth_length);
|
||||
CopyMemory(rpc->ntlm->inputBuffer[0].pvBuffer, auth_data, header->common.auth_length);
|
||||
|
||||
|
@ -24,6 +24,15 @@
|
||||
|
||||
#include <winpr/wtypes.h>
|
||||
|
||||
const p_uuid_t TSGU_UUID;
|
||||
#define TSGU_SYNTAX_IF_VERSION 0x00030001
|
||||
|
||||
const p_uuid_t NDR_UUID;
|
||||
#define NDR_SYNTAX_IF_VERSION 0x00000002
|
||||
|
||||
const p_uuid_t BTFN_UUID;
|
||||
#define BTFN_SYNTAX_IF_VERSION 0x00000001
|
||||
|
||||
int rpc_send_bind_pdu(rdpRpc* rpc);
|
||||
int rpc_recv_bind_ack_pdu(rdpRpc* rpc, BYTE* buffer, UINT32 length);
|
||||
int rpc_send_rpc_auth_3_pdu(rdpRpc* rpc);
|
||||
|
@ -120,89 +120,33 @@ int rpc_client_receive_pipe_read(rdpRpc* rpc, BYTE* buffer, size_t length)
|
||||
}
|
||||
|
||||
int rpc_client_on_pdu_received_event(rdpRpc* rpc, RPC_PDU* pdu)
|
||||
{
|
||||
RpcClientCall* call;
|
||||
|
||||
if (pdu->Type != PTYPE_RESPONSE)
|
||||
{
|
||||
Queue_Enqueue(rpc->client->ReceiveQueue, pdu);
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
call = rpc_client_call_find_by_id(rpc, pdu->CallId);
|
||||
|
||||
if (call->OpNum != TsProxySetupReceivePipeOpnum)
|
||||
{
|
||||
Queue_Enqueue(rpc->client->ReceiveQueue, pdu);
|
||||
}
|
||||
else
|
||||
{
|
||||
rpc_client_receive_pipe_write(rpc, Stream_Buffer(pdu->s), Stream_Length(pdu->s));
|
||||
rpc_client_receive_pool_return(rpc, pdu);
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int rpc_client_on_fragment_received_event(rdpRpc* rpc, wStream* fragment)
|
||||
{
|
||||
BYTE* buffer;
|
||||
RPC_PDU* pdu;
|
||||
UINT32 StubOffset;
|
||||
UINT32 StubLength;
|
||||
RpcClientCall* call;
|
||||
rpcconn_hdr_t* header;
|
||||
|
||||
if (!rpc->client->pdu)
|
||||
rpc->client->pdu = rpc_client_receive_pool_take(rpc);
|
||||
|
||||
buffer = (BYTE*) Stream_Buffer(fragment);
|
||||
header = (rpcconn_hdr_t*) Stream_Buffer(fragment);
|
||||
|
||||
if (rpc->State < RPC_CLIENT_STATE_CONTEXT_NEGOTIATED)
|
||||
if (header->common.ptype == PTYPE_RESPONSE)
|
||||
{
|
||||
rpc->client->pdu->Flags = 0;
|
||||
rpc->client->pdu->Type = header->common.ptype;
|
||||
rpc->client->pdu->CallId = header->common.call_id;
|
||||
Stream_EnsureCapacity(rpc->client->pdu->s, Stream_Length(fragment));
|
||||
Stream_Write(rpc->client->pdu->s, buffer, Stream_Length(fragment));
|
||||
Stream_SealLength(rpc->client->pdu->s);
|
||||
rpc_client_on_pdu_received_event(rpc, rpc->client->pdu);
|
||||
rpc->client->pdu = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
switch (header->common.ptype)
|
||||
{
|
||||
case PTYPE_RTS:
|
||||
|
||||
if (rpc->VirtualConnection->State < VIRTUAL_CONNECTION_STATE_OPENED)
|
||||
{
|
||||
WLog_ERR(TAG, "warning: unhandled RTS PDU");
|
||||
return 0;
|
||||
}
|
||||
|
||||
WLog_DBG(TAG, "Receiving Out-of-Sequence RTS PDU");
|
||||
rts_recv_out_of_sequence_pdu(rpc, buffer, header->common.frag_length);
|
||||
return 0;
|
||||
|
||||
case PTYPE_FAULT:
|
||||
rpc_recv_fault_pdu(header);
|
||||
return -1;
|
||||
|
||||
case PTYPE_RESPONSE:
|
||||
break;
|
||||
|
||||
default:
|
||||
WLog_ERR(TAG, "unexpected RPC PDU type %d", header->common.ptype);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* PTYPE_RESPONSE */
|
||||
|
||||
rpc->VirtualConnection->DefaultOutChannel->BytesReceived += header->common.frag_length;
|
||||
rpc->VirtualConnection->DefaultOutChannel->ReceiverAvailableWindow -= header->common.frag_length;
|
||||
|
||||
if (rpc->VirtualConnection->DefaultOutChannel->ReceiverAvailableWindow < (rpc->ReceiveWindow / 2))
|
||||
{
|
||||
rts_send_flow_control_ack_pdu(rpc);
|
||||
}
|
||||
|
||||
if (!rpc_get_stub_data_info(rpc, buffer, &StubOffset, &StubLength))
|
||||
{
|
||||
WLog_ERR(TAG, "expected stub");
|
||||
@ -237,33 +181,102 @@ int rpc_client_on_fragment_received_event(rdpRpc* rpc, wStream* fragment)
|
||||
rpc->StubCallId, header->common.call_id, rpc->StubFragCount);
|
||||
}
|
||||
|
||||
Stream_EnsureCapacity(rpc->client->pdu->s, header->response.alloc_hint);
|
||||
Stream_Write(rpc->client->pdu->s, &buffer[StubOffset], StubLength);
|
||||
rpc->StubFragCount++;
|
||||
call = rpc_client_call_find_by_id(rpc, rpc->StubCallId);
|
||||
|
||||
if (rpc->VirtualConnection->DefaultOutChannel->ReceiverAvailableWindow < (rpc->ReceiveWindow / 2))
|
||||
if (!call)
|
||||
return -1;
|
||||
|
||||
if (call->OpNum != TsProxySetupReceivePipeOpnum)
|
||||
{
|
||||
rts_send_flow_control_ack_pdu(rpc);
|
||||
}
|
||||
if (!rpc->client->pdu)
|
||||
rpc->client->pdu = rpc_client_receive_pool_take(rpc);
|
||||
|
||||
/**
|
||||
* If alloc_hint is set to a nonzero value and a request or a response is fragmented into multiple
|
||||
* PDUs, implementations of these extensions SHOULD set the alloc_hint field in every PDU to be the
|
||||
* combined stub data length of all remaining fragment PDUs.
|
||||
*/
|
||||
pdu = rpc->client->pdu;
|
||||
|
||||
Stream_EnsureCapacity(pdu->s, header->response.alloc_hint);
|
||||
Stream_Write(pdu->s, &buffer[StubOffset], StubLength);
|
||||
rpc->StubFragCount++;
|
||||
|
||||
if (header->response.alloc_hint == StubLength)
|
||||
{
|
||||
rpc->client->pdu->Flags = RPC_PDU_FLAG_STUB;
|
||||
rpc->client->pdu->Type = PTYPE_RESPONSE;
|
||||
rpc->client->pdu->CallId = rpc->StubCallId;
|
||||
Stream_SealLength(rpc->client->pdu->s);
|
||||
pdu->Flags = RPC_PDU_FLAG_STUB;
|
||||
pdu->Type = PTYPE_RESPONSE;
|
||||
pdu->CallId = rpc->StubCallId;
|
||||
Stream_SealLength(pdu->s);
|
||||
rpc_client_on_pdu_received_event(rpc, pdu);
|
||||
rpc->client->pdu = NULL;
|
||||
rpc->StubFragCount = 0;
|
||||
rpc->StubCallId = 0;
|
||||
rpc_client_on_pdu_received_event(rpc, rpc->client->pdu);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
rpc_client_receive_pipe_write(rpc, &buffer[StubOffset], (size_t) StubLength);
|
||||
rpc->StubFragCount++;
|
||||
|
||||
if (header->response.alloc_hint == StubLength)
|
||||
{
|
||||
rpc->StubFragCount = 0;
|
||||
rpc->StubCallId = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
else if (header->common.ptype == PTYPE_RTS)
|
||||
{
|
||||
if (rpc->State < RPC_CLIENT_STATE_CONTEXT_NEGOTIATED)
|
||||
{
|
||||
if (!rpc->client->pdu)
|
||||
rpc->client->pdu = rpc_client_receive_pool_take(rpc);
|
||||
|
||||
pdu = rpc->client->pdu;
|
||||
|
||||
pdu->Flags = 0;
|
||||
pdu->Type = header->common.ptype;
|
||||
pdu->CallId = header->common.call_id;
|
||||
Stream_EnsureCapacity(pdu->s, Stream_Length(fragment));
|
||||
Stream_Write(pdu->s, buffer, Stream_Length(fragment));
|
||||
Stream_SealLength(pdu->s);
|
||||
rpc_client_on_pdu_received_event(rpc, pdu);
|
||||
rpc->client->pdu = NULL;
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (rpc->VirtualConnection->State < VIRTUAL_CONNECTION_STATE_OPENED)
|
||||
WLog_ERR(TAG, "warning: unhandled RTS PDU");
|
||||
|
||||
WLog_DBG(TAG, "Receiving Out-of-Sequence RTS PDU");
|
||||
rts_recv_out_of_sequence_pdu(rpc, buffer, header->common.frag_length);
|
||||
}
|
||||
}
|
||||
else if (header->common.ptype == PTYPE_BIND_ACK)
|
||||
{
|
||||
if (!rpc->client->pdu)
|
||||
rpc->client->pdu = rpc_client_receive_pool_take(rpc);
|
||||
|
||||
pdu = rpc->client->pdu;
|
||||
|
||||
pdu->Flags = 0;
|
||||
pdu->Type = header->common.ptype;
|
||||
pdu->CallId = header->common.call_id;
|
||||
Stream_EnsureCapacity(pdu->s, Stream_Length(fragment));
|
||||
Stream_Write(pdu->s, buffer, Stream_Length(fragment));
|
||||
Stream_SealLength(pdu->s);
|
||||
rpc_client_on_pdu_received_event(rpc, pdu);
|
||||
rpc->client->pdu = NULL;
|
||||
return 0;
|
||||
}
|
||||
else if (header->common.ptype == PTYPE_FAULT)
|
||||
{
|
||||
rpc_recv_fault_pdu(header);
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
WLog_ERR(TAG, "unexpected RPC PDU type 0x%04X", header->common.ptype);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -342,8 +355,8 @@ int rpc_client_on_read_event(rdpRpc* rpc)
|
||||
Stream_SetPosition(rpc->client->ReceiveFragment, 0);
|
||||
}
|
||||
|
||||
if (WaitForSingleObject(Queue_Event(rpc->client->SendQueue), 0) == WAIT_OBJECT_0)
|
||||
break;
|
||||
//if (WaitForSingleObject(Queue_Event(rpc->client->SendQueue), 0) == WAIT_OBJECT_0)
|
||||
// break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -22,16 +22,15 @@
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/ndr.h>
|
||||
#include <winpr/error.h>
|
||||
#include <winpr/print.h>
|
||||
#include <winpr/stream.h>
|
||||
|
||||
#include <freerdp/log.h>
|
||||
|
||||
#include "rpc_bind.h"
|
||||
#include "rpc_client.h"
|
||||
#include "tsg.h"
|
||||
|
||||
@ -43,16 +42,6 @@
|
||||
* RPC NDR Interface Reference: http://msdn.microsoft.com/en-us/library/windows/desktop/hh802752/
|
||||
*/
|
||||
|
||||
/* this might be a verification trailer */
|
||||
|
||||
BYTE TsProxyCreateTunnelUnknownTrailerBytes[60] =
|
||||
{
|
||||
0x8A, 0xE3, 0x13, 0x71, 0x02, 0xF4, 0x36, 0x71, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00, 0x00, 0x00,
|
||||
0x02, 0x40, 0x28, 0x00, 0xDD, 0x65, 0xE2, 0x44, 0xAF, 0x7D, 0xCD, 0x42, 0x85, 0x60, 0x3C, 0xDB,
|
||||
0x6E, 0x7A, 0x27, 0x29, 0x01, 0x00, 0x03, 0x00, 0x04, 0x5D, 0x88, 0x8A, 0xEB, 0x1C, 0xC9, 0x11,
|
||||
0x9F, 0xE8, 0x08, 0x00, 0x2B, 0x10, 0x48, 0x60, 0x02, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
DWORD TsProxySendToServer(handle_t IDL_handle, byte pRpcMessage[], UINT32 count, UINT32* lengths)
|
||||
{
|
||||
wStream* s;
|
||||
@ -68,6 +57,7 @@ DWORD TsProxySendToServer(handle_t IDL_handle, byte pRpcMessage[], UINT32 count,
|
||||
UINT32 buffer3Length;
|
||||
UINT32 numBuffers = 0;
|
||||
UINT32 totalDataBytes = 0;
|
||||
|
||||
tsg = (rdpTsg*) IDL_handle;
|
||||
buffer1Length = buffer2Length = buffer3Length = 0;
|
||||
|
||||
@ -186,7 +176,47 @@ BOOL TsProxyCreateTunnelWriteRequest(rdpTsg* tsg)
|
||||
*/
|
||||
|
||||
*((UINT32*) &buffer[44]) = NapCapabilities; /* capabilities */
|
||||
CopyMemory(&buffer[48], TsProxyCreateTunnelUnknownTrailerBytes, 60);
|
||||
|
||||
//CopyMemory(&buffer[48], TsProxyCreateTunnelUnknownTrailerBytes, 60);
|
||||
|
||||
/**
|
||||
* The following 60-byte structure is apparently undocumented,
|
||||
* but parts of it can be matched to known C706 data structures.
|
||||
*/
|
||||
|
||||
/*
|
||||
* 8-byte constant (8A E3 13 71 02 F4 36 71) also observed here:
|
||||
* http://lists.samba.org/archive/cifs-protocol/2010-July/001543.html
|
||||
*/
|
||||
|
||||
buffer[48] = 0x8A;
|
||||
buffer[49] = 0xE3;
|
||||
buffer[50] = 0x13;
|
||||
buffer[51] = 0x71;
|
||||
buffer[52] = 0x02;
|
||||
buffer[53] = 0xF4;
|
||||
buffer[54] = 0x36;
|
||||
buffer[55] = 0x71;
|
||||
|
||||
*((UINT32*) &buffer[56]) = 0x00040001; /* 1.4 (version?) */
|
||||
*((UINT32*) &buffer[60]) = 0x00000001; /* 1 (element count?) */
|
||||
|
||||
/* p_cont_list_t */
|
||||
|
||||
buffer[64] = 2; /* ncontext_elem */
|
||||
buffer[65] = 0x40; /* reserved1 */
|
||||
*((UINT16*) &buffer[66]) = 0x0028; /* reserved2 */
|
||||
|
||||
/* p_syntax_id_t */
|
||||
|
||||
CopyMemory(&buffer[68], &TSGU_UUID, sizeof(p_uuid_t));
|
||||
*((UINT32*) &buffer[84]) = TSGU_SYNTAX_IF_VERSION;
|
||||
|
||||
/* p_syntax_id_t */
|
||||
|
||||
CopyMemory(&buffer[88], &NDR_UUID, sizeof(p_uuid_t));
|
||||
*((UINT32*) &buffer[104]) = NDR_SYNTAX_IF_VERSION;
|
||||
|
||||
status = rpc_write(rpc, buffer, length, TsProxyCreateTunnelOpnum);
|
||||
|
||||
if (status <= 0)
|
||||
|
Loading…
Reference in New Issue
Block a user