libfreerdp-core: implement RPC response stub data reassembly
This commit is contained in:
parent
fbacea6bad
commit
6cad536d34
@ -56,7 +56,7 @@ COMMAND_LINE_ARGUMENT_A args[] =
|
||||
{ "u", COMMAND_LINE_VALUE_REQUIRED, "[<domain>\\]<user> or <user>[@<domain>]", NULL, NULL, -1, NULL, "Username" },
|
||||
{ "p", COMMAND_LINE_VALUE_REQUIRED, "<password>", NULL, NULL, -1, NULL, "Password" },
|
||||
{ "d", COMMAND_LINE_VALUE_REQUIRED, "<domain>", NULL, NULL, -1, NULL, "Domain" },
|
||||
{ "g", COMMAND_LINE_VALUE_REQUIRED, "<gateway>[:port]", NULL, NULL, -1, NULL, "Gateway Hostname" },
|
||||
{ "g", COMMAND_LINE_VALUE_OPTIONAL, "<gateway>[:port]", NULL, NULL, -1, NULL, "Gateway Hostname" },
|
||||
{ "gu", COMMAND_LINE_VALUE_REQUIRED, "[<domain>\\]<user> or <user>[@<domain>]", NULL, NULL, -1, NULL, "Gateway username" },
|
||||
{ "gp", COMMAND_LINE_VALUE_REQUIRED, "<password>", NULL, NULL, -1, NULL, "Gateway password" },
|
||||
{ "gd", COMMAND_LINE_VALUE_REQUIRED, "<domain>", NULL, NULL, -1, NULL, "Gateway domain" },
|
||||
@ -697,7 +697,7 @@ int freerdp_client_parse_command_line_arguments(int argc, char** argv, rdpSettin
|
||||
|
||||
do
|
||||
{
|
||||
if (!(arg->Flags & COMMAND_LINE_VALUE_PRESENT))
|
||||
if (!(arg->Flags & COMMAND_LINE_ARGUMENT_PRESENT))
|
||||
continue;
|
||||
|
||||
CommandLineSwitchStart(arg)
|
||||
@ -820,19 +820,26 @@ int freerdp_client_parse_command_line_arguments(int argc, char** argv, rdpSettin
|
||||
}
|
||||
CommandLineSwitchCase(arg, "g")
|
||||
{
|
||||
p = strchr(arg->Value, ':');
|
||||
|
||||
if (p)
|
||||
if (arg->Flags & COMMAND_LINE_VALUE_PRESENT)
|
||||
{
|
||||
length = p - arg->Value;
|
||||
settings->GatewayPort = atoi(&p[1]);
|
||||
settings->GatewayHostname = (char*) malloc(length + 1);
|
||||
strncpy(settings->GatewayHostname, arg->Value, length);
|
||||
settings->GatewayHostname[length] = '\0';
|
||||
p = strchr(arg->Value, ':');
|
||||
|
||||
if (p)
|
||||
{
|
||||
length = p - arg->Value;
|
||||
settings->GatewayPort = atoi(&p[1]);
|
||||
settings->GatewayHostname = (char*) malloc(length + 1);
|
||||
strncpy(settings->GatewayHostname, arg->Value, length);
|
||||
settings->GatewayHostname[length] = '\0';
|
||||
}
|
||||
else
|
||||
{
|
||||
settings->GatewayHostname = _strdup(arg->Value);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
settings->GatewayHostname = _strdup(arg->Value);
|
||||
settings->GatewayHostname = _strdup(settings->ServerHostname);
|
||||
}
|
||||
|
||||
settings->GatewayUsageMethod = TRUE;
|
||||
|
@ -555,18 +555,36 @@ BOOL rpc_send_bind_pdu(rdpRpc* rpc)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Maximum Transmit/Receive Fragment Size Negotiation
|
||||
*
|
||||
* The client determines, and then sends in the bind PDU, its desired maximum size for transmitting fragments,
|
||||
* and its desired maximum receive fragment size. Similarly, the server determines its desired maximum sizes
|
||||
* for transmitting and receiving fragments. Transmit and receive sizes may be different to help preserve buffering.
|
||||
* When the server receives the client’s values, it sets its operational transmit size to the minimum of the client’s
|
||||
* receive size (from the bind PDU) and its own desired transmit size. Then it sets its actual receive size to the
|
||||
* minimum of the client’s transmit size (from the bind) and its own desired receive size. The server then returns its
|
||||
* operational values in the bind_ack PDU. The client then sets its operational values from the received bind_ack PDU.
|
||||
* The received transmit size becomes the client’s receive size, and the received receive size becomes the client’s
|
||||
* transmit size. Either party may use receive buffers larger than negotiated — although this will not provide any
|
||||
* advantage — but may not transmit larger fragments than negotiated.
|
||||
*/
|
||||
|
||||
int rpc_recv_bind_ack_pdu(rdpRpc* rpc)
|
||||
{
|
||||
int status;
|
||||
BYTE* auth_data;
|
||||
rpcconn_hdr_t* header;
|
||||
|
||||
status = rpc_recv_pdu(rpc);
|
||||
status = rpc_recv_pdu_fragment(rpc);
|
||||
|
||||
if (status > 0)
|
||||
{
|
||||
header = (rpcconn_hdr_t*) rpc->buffer;
|
||||
|
||||
rpc->max_recv_frag = header->bind_ack.max_xmit_frag;
|
||||
rpc->max_xmit_frag = header->bind_ack.max_recv_frag;
|
||||
|
||||
rpc->ntlm->inputBuffer.cbBuffer = header->common.auth_length;
|
||||
rpc->ntlm->inputBuffer.pvBuffer = malloc(header->common.auth_length);
|
||||
|
||||
@ -858,7 +876,7 @@ int rpc_recv_pdu_header(rdpRpc* rpc, BYTE* header)
|
||||
return bytesRead;
|
||||
}
|
||||
|
||||
int rpc_recv_pdu(rdpRpc* rpc)
|
||||
int rpc_recv_pdu_fragment(rdpRpc* rpc)
|
||||
{
|
||||
int status;
|
||||
int headerLength;
|
||||
@ -901,17 +919,6 @@ int rpc_recv_pdu(rdpRpc* rpc)
|
||||
bytesRead += status;
|
||||
}
|
||||
|
||||
printf("header->common.pfc_flags: 0x%04X\n", header->common.pfc_flags);
|
||||
|
||||
if (header->common.pfc_flags)
|
||||
{
|
||||
if (!(header->common.pfc_flags & PFC_LAST_FRAG))
|
||||
{
|
||||
printf("Fragmented PDU\n");
|
||||
rpc_pdu_header_print(header);
|
||||
}
|
||||
}
|
||||
|
||||
if (header->common.ptype == PTYPE_RTS) /* RTS PDU */
|
||||
{
|
||||
if (rpc->VirtualConnection->State < VIRTUAL_CONNECTION_STATE_OPENED)
|
||||
@ -919,7 +926,7 @@ int rpc_recv_pdu(rdpRpc* rpc)
|
||||
|
||||
printf("Receiving Out-of-Sequence RTS PDU\n");
|
||||
rts_recv_out_of_sequence_pdu(rpc);
|
||||
return rpc_recv_pdu(rpc);
|
||||
return rpc_recv_pdu_fragment(rpc);
|
||||
}
|
||||
else if (header->common.ptype == PTYPE_FAULT)
|
||||
{
|
||||
@ -930,14 +937,16 @@ int rpc_recv_pdu(rdpRpc* rpc)
|
||||
rpc->VirtualConnection->DefaultOutChannel->BytesReceived += header->common.frag_length;
|
||||
rpc->VirtualConnection->DefaultOutChannel->ReceiverAvailableWindow -= header->common.frag_length;
|
||||
|
||||
#if 0
|
||||
printf("BytesReceived: %d ReceiverAvailableWindow: %d ReceiveWindow: %d\n",
|
||||
rpc->VirtualConnection->DefaultOutChannel->BytesReceived,
|
||||
rpc->VirtualConnection->DefaultOutChannel->ReceiverAvailableWindow,
|
||||
rpc->ReceiveWindow);
|
||||
#endif
|
||||
|
||||
if (rpc->VirtualConnection->DefaultOutChannel->ReceiverAvailableWindow < (rpc->ReceiveWindow / 2))
|
||||
{
|
||||
printf("Sending Flow Control Ack PDU\n");
|
||||
//printf("Sending Flow Control Ack PDU\n");
|
||||
rts_send_flow_control_ack_pdu(rpc);
|
||||
}
|
||||
|
||||
@ -950,6 +959,63 @@ int rpc_recv_pdu(rdpRpc* rpc)
|
||||
return header->common.frag_length;
|
||||
}
|
||||
|
||||
int rpc_recv_pdu(rdpRpc* rpc)
|
||||
{
|
||||
int status;
|
||||
UINT32 StubOffset;
|
||||
UINT32 StubLength;
|
||||
rpcconn_hdr_t* header;
|
||||
|
||||
status = rpc_recv_pdu_fragment(rpc);
|
||||
|
||||
header = (rpcconn_hdr_t*) rpc->buffer;
|
||||
|
||||
if (header->common.ptype != PTYPE_RESPONSE)
|
||||
{
|
||||
printf("rpc_recv_pdu: unexpected ptype 0x%02X\n", header->common.ptype);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!rpc_get_stub_data_info(rpc, rpc->buffer, &StubOffset, &StubLength))
|
||||
{
|
||||
printf("rpc_recv_pdu: expected stub\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (header->response.alloc_hint > rpc->StubSize)
|
||||
{
|
||||
rpc->StubSize = header->response.alloc_hint;
|
||||
rpc->StubBuffer = (BYTE*) realloc(rpc->StubBuffer, rpc->StubSize);
|
||||
}
|
||||
|
||||
CopyMemory(&rpc->StubBuffer[rpc->StubOffset], &rpc->buffer[StubOffset], StubLength);
|
||||
rpc->StubOffset += StubLength;
|
||||
rpc->StubFragCount++;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
|
||||
//printf("Receiving Fragment #%d FragStubLength: %d FragLength: %d AllocHint: %d StubOffset: %d\n",
|
||||
// rpc->StubFragCount, StubLength, header->common.frag_length, header->response.alloc_hint, rpc->StubOffset);
|
||||
|
||||
if ((header->response.alloc_hint == StubLength))
|
||||
{
|
||||
//printf("Reassembled PDU (%d):\n", rpc->StubOffset);
|
||||
//freerdp_hexdump(rpc->StubBuffer, rpc->StubOffset);
|
||||
|
||||
rpc->StubLength = rpc->StubOffset;
|
||||
rpc->StubOffset = 0;
|
||||
rpc->StubFragCount = 0;
|
||||
|
||||
return rpc->StubLength;
|
||||
}
|
||||
|
||||
return rpc_recv_pdu(rpc);
|
||||
}
|
||||
|
||||
int rpc_tsg_write(rdpRpc* rpc, BYTE* data, int length, UINT16 opnum)
|
||||
{
|
||||
int status;
|
||||
@ -1238,6 +1304,12 @@ rdpRpc* rpc_new(rdpTransport* transport)
|
||||
rpc->length = 20;
|
||||
rpc->buffer = (BYTE*) malloc(rpc->length);
|
||||
|
||||
rpc->StubOffset = 0;
|
||||
rpc->StubSize = 20;
|
||||
rpc->StubLength = 0;
|
||||
rpc->StubFragCount = 0;
|
||||
rpc->StubBuffer = (BYTE*) malloc(rpc->length);
|
||||
|
||||
rpc->rpc_vers = 5;
|
||||
rpc->rpc_vers_minor = 0;
|
||||
|
||||
|
@ -684,6 +684,12 @@ struct rdp_rpc
|
||||
BYTE* buffer;
|
||||
UINT32 length;
|
||||
|
||||
BYTE* StubBuffer;
|
||||
UINT32 StubSize;
|
||||
UINT32 StubLength;
|
||||
UINT32 StubOffset;
|
||||
UINT32 StubFragCount;
|
||||
|
||||
BYTE rpc_vers;
|
||||
BYTE rpc_vers_minor;
|
||||
BYTE packed_drep[4];
|
||||
@ -722,6 +728,7 @@ int rpc_in_write(rdpRpc* rpc, BYTE* data, int length);
|
||||
BOOL rpc_get_stub_data_info(rdpRpc* rpc, BYTE* header, UINT32* offset, UINT32* length);
|
||||
int rpc_recv_pdu_header(rdpRpc* rpc, BYTE* header);
|
||||
|
||||
int rpc_recv_pdu_fragment(rdpRpc* rpc);
|
||||
int rpc_recv_pdu(rdpRpc* rpc);
|
||||
|
||||
int rpc_tsg_write(rdpRpc* rpc, BYTE* data, int length, UINT16 opnum);
|
||||
|
@ -1328,7 +1328,7 @@ int rts_recv_pdu(rdpRpc* rpc)
|
||||
int status;
|
||||
rpcconn_rts_hdr_t* rts;
|
||||
|
||||
status = rpc_recv_pdu(rpc);
|
||||
status = rpc_recv_pdu_fragment(rpc);
|
||||
|
||||
if (status > 0)
|
||||
{
|
||||
|
@ -247,7 +247,7 @@ BOOL TsProxyCreateTunnelReadResponse(rdpTsg* tsg)
|
||||
PTSG_PACKET_CAPS_RESPONSE packetCapsResponse;
|
||||
PTSG_PACKET_QUARENC_RESPONSE packetQuarEncResponse;
|
||||
|
||||
status = rpc_recv_pdu(rpc);
|
||||
status = rpc_recv_pdu_fragment(rpc);
|
||||
|
||||
if (status <= 0)
|
||||
return FALSE;
|
||||
@ -296,6 +296,9 @@ BOOL TsProxyCreateTunnelReadResponse(rdpTsg* tsg)
|
||||
count = *((UINT32*) &buffer[offset]); /* ActualCount (4 bytes) */
|
||||
offset += 4;
|
||||
|
||||
printf("CertChain (%d)\n", ((count + 1) * 2));
|
||||
freerdp_hexdump(&buffer[offset], ((count + 1) * 2));
|
||||
|
||||
/*
|
||||
* CertChainData is a wide character string, and the count is
|
||||
* given in characters excluding the null terminator, therefore:
|
||||
@ -397,6 +400,9 @@ BOOL TsProxyCreateTunnelReadResponse(rdpTsg* tsg)
|
||||
count = *((UINT32*) &buffer[offset]); /* ActualCount (4 bytes) */
|
||||
offset += 4;
|
||||
|
||||
printf("CertChain (%d)\n", ((count + 1) * 2));
|
||||
freerdp_hexdump(&buffer[offset], ((count + 1) * 2));
|
||||
|
||||
/*
|
||||
* CertChainData is a wide character string, and the count is
|
||||
* given in characters excluding the null terminator, therefore:
|
||||
@ -406,6 +412,8 @@ BOOL TsProxyCreateTunnelReadResponse(rdpTsg* tsg)
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("CertChain (%d)\n", 0);
|
||||
|
||||
Pointer = *((UINT32*) &buffer[offset]); /* Ptr (4 bytes): 0x00020008 */
|
||||
offset += 4;
|
||||
}
|
||||
@ -576,7 +584,7 @@ BOOL TsProxyAuthorizeTunnelReadResponse(rdpTsg* tsg)
|
||||
rdpRpc* rpc = tsg->rpc;
|
||||
PTSG_PACKET_RESPONSE packetResponse;
|
||||
|
||||
status = rpc_recv_pdu(rpc);
|
||||
status = rpc_recv_pdu_fragment(rpc);
|
||||
|
||||
if (status <= 0)
|
||||
return FALSE;
|
||||
@ -808,7 +816,7 @@ BOOL TsProxyCreateChannelReadResponse(rdpTsg* tsg)
|
||||
UINT32 length;
|
||||
rdpRpc* rpc = tsg->rpc;
|
||||
|
||||
status = rpc_recv_pdu(rpc);
|
||||
status = rpc_recv_pdu_fragment(rpc);
|
||||
|
||||
if (status < 0)
|
||||
return FALSE;
|
||||
@ -905,7 +913,7 @@ BOOL TsProxySetupReceivePipeReadResponse(rdpTsg* tsg)
|
||||
UINT32 length;
|
||||
rdpRpc* rpc = tsg->rpc;
|
||||
|
||||
status = rpc_recv_pdu(rpc);
|
||||
status = rpc_recv_pdu_fragment(rpc);
|
||||
|
||||
if (status < 0)
|
||||
return FALSE;
|
||||
@ -1120,13 +1128,9 @@ int tsg_read(rdpTsg* tsg, BYTE* data, UINT32 length)
|
||||
|
||||
if (tsg->PendingPdu)
|
||||
{
|
||||
rpcconn_common_hdr_t* header;
|
||||
|
||||
header = (rpcconn_common_hdr_t*) rpc->buffer;
|
||||
|
||||
CopyLength = (tsg->BytesAvailable > length) ? length : tsg->BytesAvailable;
|
||||
|
||||
CopyMemory(data, &rpc->buffer[tsg->StubOffset + tsg->BytesRead], CopyLength);
|
||||
CopyMemory(data, &rpc->StubBuffer[tsg->BytesRead], CopyLength);
|
||||
tsg->BytesAvailable -= CopyLength;
|
||||
tsg->BytesRead += CopyLength;
|
||||
|
||||
@ -1137,31 +1141,21 @@ int tsg_read(rdpTsg* tsg, BYTE* data, UINT32 length)
|
||||
}
|
||||
else
|
||||
{
|
||||
rpcconn_response_hdr_t* header;
|
||||
|
||||
status = rpc_recv_pdu(rpc);
|
||||
|
||||
header = (rpcconn_response_hdr_t*) rpc->buffer;
|
||||
|
||||
if (!rpc_get_stub_data_info(rpc, rpc->buffer, &tsg->StubOffset, &tsg->StubLength))
|
||||
{
|
||||
printf("tsg_read error: expected stub\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (header->alloc_hint == 4)
|
||||
if (rpc->StubLength == 4)
|
||||
{
|
||||
DEBUG_TSG("Ignoring TsProxySetupReceivePipe Response");
|
||||
return tsg_read(tsg, data, length);
|
||||
}
|
||||
|
||||
tsg->PendingPdu = TRUE;
|
||||
tsg->BytesAvailable = tsg->StubLength;
|
||||
tsg->BytesAvailable = rpc->StubLength;
|
||||
tsg->BytesRead = 0;
|
||||
|
||||
CopyLength = (tsg->BytesAvailable > length) ? length : tsg->BytesAvailable;
|
||||
|
||||
CopyMemory(data, &rpc->buffer[tsg->StubOffset + tsg->BytesRead], CopyLength);
|
||||
CopyMemory(data, &rpc->StubBuffer[tsg->BytesRead], CopyLength);
|
||||
tsg->BytesAvailable -= CopyLength;
|
||||
tsg->BytesRead += CopyLength;
|
||||
|
||||
|
@ -237,6 +237,8 @@ int CommandLineParseArgumentsA(int argc, LPCSTR* argv, COMMAND_LINE_ARGUMENT_A*
|
||||
if (!value && (options[j].Flags & COMMAND_LINE_VALUE_REQUIRED))
|
||||
return COMMAND_LINE_ERROR_MISSING_VALUE;
|
||||
|
||||
options[j].Flags |= COMMAND_LINE_ARGUMENT_PRESENT;
|
||||
|
||||
if (value)
|
||||
{
|
||||
options[j].Value = value;
|
||||
|
Loading…
x
Reference in New Issue
Block a user