This commit is contained in:
Marc-André Moreau 2015-02-19 14:11:12 -05:00
commit dfee7710e1
4 changed files with 115 additions and 16 deletions

View File

@ -864,6 +864,57 @@ int rpc_out_channel_connect(RpcOutChannel* outChannel, int timeout)
return 1;
}
int rpc_out_channel_replacement_connect(RpcOutChannel* outChannel, int timeout)
{
HttpResponse* response = NULL;
rdpRpc* rpc = outChannel->rpc;
int status = 0;
/* Connect OUT Channel */
if (rpc_channel_tls_connect((RpcChannel*)outChannel, timeout) < 0)
return -1;
rpc_out_channel_transition_to_state(outChannel, CLIENT_OUT_CHANNEL_STATE_CONNECTED);
if (rpc_ncacn_http_ntlm_init(rpc, (RpcChannel*)outChannel) < 0)
return FALSE;
/* Send OUT Channel Request */
if (rpc_ncacn_http_send_out_channel_request(rpc, outChannel, TRUE) < 0)
{
WLog_ERR(TAG, "rpc_ncacn_http_send_out_channel_request failure");
return FALSE;
}
rpc_out_channel_transition_to_state(outChannel, CLIENT_OUT_CHANNEL_STATE_SECURITY);
/* Receive response. */
response = http_response_recv(outChannel->tls);
if (!response)
return -1;
status = rpc_ncacn_http_recv_out_channel_response(rpc, outChannel, response);
http_response_free(response);
if ( status < 0)
{
WLog_ERR(TAG, "rpc_ncacn_http_recv_out_channel_response failure");
return -1;
}
/* Send OUT Channel Request */
if (rpc_ncacn_http_send_out_channel_request(rpc, outChannel, TRUE) < 0)
{
WLog_ERR(TAG, "rpc_ncacn_http_send_out_channel_request failure");
return -1;
}
return 1;
}
BOOL rpc_connect(rdpRpc* rpc, int timeout)
{
RpcInChannel* inChannel;

View File

@ -779,7 +779,8 @@ RpcInChannel* rpc_client_in_channel_new(rdpRpc* rpc);
void rpc_in_channel_free(RpcInChannel* inChannel);
RpcOutChannel* rpc_out_channel_new(rdpRpc* rpc);
void rpc_client_out_channel_free(RpcOutChannel* outChannel);
int rpc_out_channel_replacement_connect(RpcOutChannel* outChannel, int timeout);
void rpc_out_channel_free(RpcOutChannel* outChannel);
int rpc_in_channel_transition_to_state(RpcInChannel* inChannel, CLIENT_IN_CHANNEL_STATE state);
int rpc_out_channel_transition_to_state(RpcOutChannel* outChannel, CLIENT_OUT_CHANNEL_STATE state);

View File

@ -604,6 +604,9 @@ int rpc_client_out_channel_recv(rdpRpc* rpc)
status = rpc_client_recv_fragment(rpc, fragment);
/* In case the channel recycling completed, reinitialise the local outChannel pointer. */
outChannel = rpc->VirtualConnection->DefaultOutChannel;
if (status < 0)
return status;

View File

@ -805,7 +805,7 @@ int rts_send_OUT_R2_A7_pdu(rdpRpc* rpc)
BYTE* buffer;
rpcconn_rts_hdr_t header;
BYTE* SuccessorChannelCookie;
RpcOutChannel* outChannel = rpc->VirtualConnection->DefaultOutChannel;
RpcInChannel* inChannel = rpc->VirtualConnection->DefaultInChannel;
RpcOutChannel* nextOutChannel = rpc->VirtualConnection->NonDefaultOutChannel;
rts_pdu_header_init(&header);
@ -827,7 +827,7 @@ int rts_send_OUT_R2_A7_pdu(rdpRpc* rpc)
rts_cookie_command_write(&buffer[28], SuccessorChannelCookie); /* SuccessorChannelCookie (20 bytes) */
rts_version_command_write(&buffer[48]); /* Version (8 bytes) */
status = rpc_out_channel_write(outChannel, buffer, header.frag_length);
status = rpc_in_channel_write(inChannel, buffer, header.frag_length);
free(buffer);
@ -839,7 +839,7 @@ int rts_send_OUT_R2_C1_pdu(rdpRpc* rpc)
int status;
BYTE* buffer;
rpcconn_rts_hdr_t header;
RpcOutChannel* outChannel = rpc->VirtualConnection->DefaultOutChannel;
RpcOutChannel* nextOutChannel = rpc->VirtualConnection->NonDefaultOutChannel;
rts_pdu_header_init(&header);
header.frag_length = 24;
@ -856,7 +856,7 @@ int rts_send_OUT_R2_C1_pdu(rdpRpc* rpc)
CopyMemory(buffer, ((BYTE*) &header), 20); /* RTS Header (20 bytes) */
rts_empty_command_write(&buffer[20]); /* Empty command (4 bytes) */
status = rpc_out_channel_write(outChannel, buffer, header.frag_length);
status = rpc_out_channel_write(nextOutChannel, buffer, header.frag_length);
free(buffer);
@ -900,7 +900,7 @@ int rts_send_OUT_R1_A3_pdu(rdpRpc* rpc)
rts_cookie_command_write(&buffer[68], SuccessorChannelCookie); /* SuccessorChannelCookie (20 bytes) */
rts_receive_window_size_command_write(&buffer[88], ReceiveWindowSize); /* ReceiveWindowSize (8 bytes) */
status = rpc_out_channel_write(outChannel, buffer, header.frag_length);
status = rpc_out_channel_write(nextOutChannel, buffer, header.frag_length);
free(buffer);
@ -921,6 +921,12 @@ int rts_recv_OUT_R1_A2_pdu(rdpRpc* rpc, BYTE* buffer, UINT32 length)
WLog_ERR(TAG, "TS Gateway channel recycling is incomplete");
connection->NonDefaultOutChannel = rpc_out_channel_new(rpc);
rpc_out_channel_replacement_connect(connection->NonDefaultOutChannel, 5000);//TODO: check for timeout value.
rts_send_OUT_R1_A3_pdu(rpc);
rpc_out_channel_transition_to_state(connection->NonDefaultOutChannel, CLIENT_OUT_CHANNEL_STATE_OPENED_A6W);
rpc_out_channel_transition_to_state(connection->DefaultOutChannel, CLIENT_OUT_CHANNEL_STATE_OPENED_A6W);
return 1;
}
@ -928,19 +934,28 @@ int rts_recv_OUT_R1_A2_pdu(rdpRpc* rpc, BYTE* buffer, UINT32 length)
int rts_recv_OUT_R2_A6_pdu(rdpRpc* rpc, BYTE* buffer, UINT32 length)
{
int status;
UINT32 offset;
UINT32 Destination = 0;
rpcconn_rts_hdr_t* header = (rpcconn_rts_hdr_t*)buffer;
offset = 24;
offset += rts_destination_command_read(rpc, &buffer[offset], length - offset, &Destination) + 4;
offset += rts_empty_command_read(rpc, &buffer[offset], length - offset) + 4;
WLog_DBG(TAG, "Destination: %d", Destination);
if (rpc->VirtualConnection->DefaultOutChannel->State != CLIENT_OUT_CHANNEL_STATE_OPENED_A6W)
{
/* Wrong state to receive this PDU. */
return -1;
}
status = rts_send_OUT_R2_C1_pdu(rpc);
if (status < 0)
{
return -1;
}
status = rts_send_OUT_R2_A7_pdu(rpc);
if (status < 0)
{
return -1;
}
rpc_out_channel_transition_to_state(rpc->VirtualConnection->NonDefaultOutChannel, CLIENT_OUT_CHANNEL_STATE_OPENED_B3W);
rpc_out_channel_transition_to_state(rpc->VirtualConnection->DefaultOutChannel, CLIENT_OUT_CHANNEL_STATE_OPENED_B3W);
return 1;
}
@ -948,9 +963,30 @@ int rts_recv_OUT_R2_A6_pdu(rdpRpc* rpc, BYTE* buffer, UINT32 length)
int rts_recv_OUT_R2_B3_pdu(rdpRpc* rpc, BYTE* buffer, UINT32 length)
{
UINT32 offset;
RpcOutChannel* temp;
HttpResponse* response;
int status;
offset = 24;
offset += rts_ance_command_read(rpc, &buffer[offset], length - offset) + 4;
if (rpc->VirtualConnection->DefaultOutChannel->State != CLIENT_OUT_CHANNEL_STATE_OPENED_B3W)
{
/* Wrong state to receive this PDU. */
return -1;
}
rpc_out_channel_free(rpc->VirtualConnection->DefaultOutChannel);
rpc->VirtualConnection->DefaultOutChannel = rpc->VirtualConnection->NonDefaultOutChannel;
rpc->VirtualConnection->NonDefaultOutChannel = NULL;
rpc_out_channel_transition_to_state(rpc->VirtualConnection->DefaultOutChannel, CLIENT_OUT_CHANNEL_STATE_OPENED);
response = http_response_recv(rpc->VirtualConnection->DefaultOutChannel->tls);
if (!response)
return -1;
status = rpc_ncacn_http_recv_out_channel_response(rpc, rpc->VirtualConnection->DefaultOutChannel, response);
http_response_free(response);
return 1;
}
@ -985,6 +1021,14 @@ int rts_recv_out_of_sequence_pdu(rdpRpc* rpc, BYTE* buffer, UINT32 length)
status = rts_recv_OUT_R1_A2_pdu(rpc, buffer, length);
break;
case RTS_PDU_OUT_R2_A6:
status = rts_recv_OUT_R2_A6_pdu(rpc, buffer, length);
break;
case RTS_PDU_OUT_R2_B3:
status = rts_recv_OUT_R2_B3_pdu(rpc, buffer, length);
break;
default:
WLog_ERR(TAG, "unimplemented signature id: 0x%08X", SignatureId);
rts_print_pdu_signature(rpc, &signature);