libfreerdp-core: add more IN/OUT gateway channel states

This commit is contained in:
Marc-André Moreau 2015-02-03 16:33:45 -05:00
parent 7b25f9130b
commit 1bf0e2ee03
8 changed files with 200 additions and 96 deletions

View File

@ -101,20 +101,14 @@ int rpc_ncacn_http_send_in_channel_request(rdpRpc* rpc)
return (status > 0) ? 1 : -1;
}
int rpc_ncacn_http_recv_in_channel_response(rdpRpc* rpc)
int rpc_ncacn_http_recv_in_channel_response(rdpRpc* rpc, HttpResponse* response)
{
int status = -1;
char* token64 = NULL;
HttpResponse* response;
int ntlmTokenLength = 0;
BYTE* ntlmTokenData = NULL;
rdpNtlm* ntlm = rpc->NtlmHttpIn->ntlm;
response = http_response_recv(rpc->TlsIn);
if (!response)
return -1;
if (ListDictionary_Contains(response->Authenticates, "NTLM"))
{
token64 = ListDictionary_GetItemValue(response->Authenticates, "NTLM");
@ -203,35 +197,6 @@ void rpc_ncacn_http_ntlm_uninit(rdpRpc* rpc, TSG_CHANNEL channel)
}
}
BOOL rpc_ntlm_http_in_connect(rdpRpc* rpc)
{
BOOL status = FALSE;
if (rpc_ncacn_http_ntlm_init(rpc, TSG_CHANNEL_IN) < 0)
goto out;
/* Send IN Channel Request */
if (rpc_ncacn_http_send_in_channel_request(rpc) < 0)
goto out;
/* Receive IN Channel Response */
if (rpc_ncacn_http_recv_in_channel_response(rpc) < 0)
goto out;
/* Send IN Channel Request */
if (rpc_ncacn_http_send_in_channel_request(rpc) < 0)
goto out;
status = TRUE;
out:
rpc_ncacn_http_ntlm_uninit(rpc, TSG_CHANNEL_IN);
return status;
}
int rpc_ncacn_http_send_out_channel_request(rdpRpc* rpc)
{
wStream* s;
@ -256,20 +221,14 @@ int rpc_ncacn_http_send_out_channel_request(rdpRpc* rpc)
return (status > 0) ? 1 : -1;
}
int rpc_ncacn_http_recv_out_channel_response(rdpRpc* rpc)
int rpc_ncacn_http_recv_out_channel_response(rdpRpc* rpc, HttpResponse* response)
{
int status = -1;
char* token64 = NULL;
HttpResponse* response;
int ntlmTokenLength = 0;
BYTE* ntlmTokenData = NULL;
rdpNtlm* ntlm = rpc->NtlmHttpOut->ntlm;
response = http_response_recv(rpc->TlsOut);
if (!response)
return -1;
if (ListDictionary_Contains(response->Authenticates, "NTLM"))
{
token64 = ListDictionary_GetItemValue(response->Authenticates, "NTLM");
@ -312,41 +271,6 @@ int rpc_http_send_replacement_out_channel_request(rdpRpc* rpc)
return (status > 0) ? 1 : -1;
}
BOOL rpc_ntlm_http_out_connect(rdpRpc* rpc)
{
BOOL status = FALSE;
if (rpc_ncacn_http_ntlm_init(rpc, TSG_CHANNEL_OUT) < 0)
goto out;
/* Send OUT Channel Request */
if (rpc_ncacn_http_send_out_channel_request(rpc) < 0)
{
WLog_ERR(TAG, "rpc_ncacn_http_send_out_channel_request failure");
goto out;
}
/* Receive OUT Channel Response */
if (rpc_ncacn_http_recv_out_channel_response(rpc) < 0)
{
WLog_ERR(TAG, "rpc_ncacn_http_recv_out_channel_response failure");
goto out;
}
/* Send OUT Channel Request */
if (rpc_ncacn_http_send_out_channel_request(rpc) < 0)
{
WLog_ERR(TAG, "rpc_ncacn_http_send_out_channel_request failure");
goto out;
}
status = TRUE;
out:
rpc_ncacn_http_ntlm_uninit(rpc, TSG_CHANNEL_OUT);
return status;
}
void rpc_ntlm_http_init_channel(rdpRpc* rpc, rdpNtlmHttp* ntlm_http, TSG_CHANNEL channel)
{
if (channel == TSG_CHANNEL_IN)
@ -363,11 +287,13 @@ void rpc_ntlm_http_init_channel(rdpRpc* rpc, rdpNtlmHttp* ntlm_http, TSG_CHANNEL
if (channel == TSG_CHANNEL_IN)
{
http_context_set_pragma(ntlm_http->context, "ResourceTypeUuid=44e265dd-7daf-42cd-8560-3cdb6e7a2729");
http_context_set_pragma(ntlm_http->context,
"ResourceTypeUuid=44e265dd-7daf-42cd-8560-3cdb6e7a2729");
}
else if (channel == TSG_CHANNEL_OUT)
{
http_context_set_pragma(ntlm_http->context, "ResourceTypeUuid=44e265dd-7daf-42cd-8560-3cdb6e7a2729, "
http_context_set_pragma(ntlm_http->context,
"ResourceTypeUuid=44e265dd-7daf-42cd-8560-3cdb6e7a2729, "
"SessionId=fbd9c34f-397d-471d-a109-1b08cc554624");
}
}

View File

@ -26,17 +26,19 @@
#include <freerdp/crypto/tls.h>
#include <freerdp/crypto/crypto.h>
#include <winpr/stream.h>
#include "rpc.h"
#include "http.h"
int rpc_ncacn_http_ntlm_init(rdpRpc* rpc, TSG_CHANNEL channel);
void rpc_ncacn_http_ntlm_uninit(rdpRpc* rpc, TSG_CHANNEL channel);
BOOL rpc_ntlm_http_out_connect(rdpRpc* rpc);
BOOL rpc_ntlm_http_in_connect(rdpRpc* rpc);
int rpc_ncacn_http_send_in_channel_request(rdpRpc* rpc);
int rpc_ncacn_http_recv_in_channel_response(rdpRpc* rpc, HttpResponse* response);
int rpc_ncacn_http_send_out_channel_request(rdpRpc* rpc);
int rpc_ncacn_http_recv_out_channel_response(rdpRpc* rpc, HttpResponse* response);
void rpc_ntlm_http_init_channel(rdpRpc* rpc, rdpNtlmHttp* ntlm_http, TSG_CHANNEL channel);

View File

@ -31,14 +31,11 @@ typedef struct rdp_ntlm_http rdpNtlmHttp;
#include "rts.h"
#include "http.h"
#include <time.h>
#include <winpr/sspi.h>
#include <freerdp/types.h>
#include <freerdp/settings.h>
#include <freerdp/crypto/tls.h>
#include <freerdp/crypto/crypto.h>
#include <winpr/sspi.h>
#include <winpr/print.h>
#include <winpr/stream.h>

View File

@ -469,6 +469,98 @@ out_free_pdu:
return -1;
}
int rpc_client_in_channel_transition_to_state(RpcInChannel* inChannel, CLIENT_IN_CHANNEL_STATE state)
{
int status = 1;
const char* str = "CLIENT_IN_CHANNEL_STATE_UNKNOWN";
switch (state)
{
case CLIENT_IN_CHANNEL_STATE_INITIAL:
str = "CLIENT_IN_CHANNEL_STATE_INITIAL";
break;
case CLIENT_IN_CHANNEL_STATE_CONNECTED:
str = "CLIENT_IN_CHANNEL_STATE_CONNECTED";
break;
case CLIENT_IN_CHANNEL_STATE_SECURITY:
str = "CLIENT_IN_CHANNEL_STATE_SECURITY";
break;
case CLIENT_IN_CHANNEL_STATE_NEGOTIATED:
str = "CLIENT_IN_CHANNEL_STATE_NEGOTIATED";
break;
case CLIENT_IN_CHANNEL_STATE_OPENED:
str = "CLIENT_IN_CHANNEL_STATE_OPENED";
break;
case CLIENT_IN_CHANNEL_STATE_OPENED_A4W:
str = "CLIENT_IN_CHANNEL_STATE_OPENED_A4W";
break;
case CLIENT_IN_CHANNEL_STATE_FINAL:
str = "CLIENT_IN_CHANNEL_STATE_FINAL";
break;
}
inChannel->State = state;
WLog_DBG(TAG, "%s", str);
return status;
}
int rpc_client_out_channel_transition_to_state(RpcOutChannel* outChannel, CLIENT_OUT_CHANNEL_STATE state)
{
int status = 1;
const char* str = "CLIENT_OUT_CHANNEL_STATE_UNKNOWN";
switch (state)
{
case CLIENT_OUT_CHANNEL_STATE_INITIAL:
str = "CLIENT_OUT_CHANNEL_STATE_INITIAL";
break;
case CLIENT_OUT_CHANNEL_STATE_CONNECTED:
str = "CLIENT_OUT_CHANNEL_STATE_CONNECTED";
break;
case CLIENT_OUT_CHANNEL_STATE_SECURITY:
str = "CLIENT_OUT_CHANNEL_STATE_SECURITY";
break;
case CLIENT_OUT_CHANNEL_STATE_NEGOTIATED:
str = "CLIENT_OUT_CHANNEL_STATE_NEGOTIATED";
break;
case CLIENT_OUT_CHANNEL_STATE_OPENED:
str = "CLIENT_OUT_CHANNEL_STATE_OPENED";
break;
case CLIENT_OUT_CHANNEL_STATE_OPENED_A6W:
str = "CLIENT_OUT_CHANNEL_STATE_OPENED_A6W";
break;
case CLIENT_OUT_CHANNEL_STATE_OPENED_A10W:
str = "CLIENT_OUT_CHANNEL_STATE_OPENED_A10W";
break;
case CLIENT_OUT_CHANNEL_STATE_OPENED_B3W:
str = "CLIENT_OUT_CHANNEL_STATE_OPENED_B3W";
break;
case CLIENT_OUT_CHANNEL_STATE_FINAL:
str = "CLIENT_OUT_CHANNEL_STATE_FINAL";
break;
}
outChannel->State = state;
WLog_DBG(TAG, "%s", str);
return status;
}
int rpc_client_virtual_connection_transition_to_state(rdpRpc* rpc,
RpcVirtualConnection* connection, VIRTUAL_CONNECTION_STATE state)
{

View File

@ -606,6 +606,9 @@ typedef struct rpc_ping_originator RpcPingOriginator;
enum _CLIENT_IN_CHANNEL_STATE
{
CLIENT_IN_CHANNEL_STATE_INITIAL,
CLIENT_IN_CHANNEL_STATE_CONNECTED,
CLIENT_IN_CHANNEL_STATE_SECURITY,
CLIENT_IN_CHANNEL_STATE_NEGOTIATED,
CLIENT_IN_CHANNEL_STATE_OPENED,
CLIENT_IN_CHANNEL_STATE_OPENED_A4W,
CLIENT_IN_CHANNEL_STATE_FINAL
@ -635,6 +638,9 @@ typedef struct rpc_in_channel RpcInChannel;
enum _CLIENT_OUT_CHANNEL_STATE
{
CLIENT_OUT_CHANNEL_STATE_INITIAL,
CLIENT_OUT_CHANNEL_STATE_CONNECTED,
CLIENT_OUT_CHANNEL_STATE_SECURITY,
CLIENT_OUT_CHANNEL_STATE_NEGOTIATED,
CLIENT_OUT_CHANNEL_STATE_OPENED,
CLIENT_OUT_CHANNEL_STATE_OPENED_A6W,
CLIENT_OUT_CHANNEL_STATE_OPENED_A10W,
@ -773,6 +779,9 @@ int rpc_in_write(rdpRpc* rpc, const BYTE* data, int length);
BOOL rpc_get_stub_data_info(rdpRpc* rpc, BYTE* header, UINT32* offset, UINT32* length);
int rpc_client_in_channel_transition_to_state(RpcInChannel* inChannel, CLIENT_IN_CHANNEL_STATE state);
int rpc_client_out_channel_transition_to_state(RpcOutChannel* outChannel, CLIENT_OUT_CHANNEL_STATE state);
int rpc_client_virtual_connection_transition_to_state(rdpRpc* rpc,
RpcVirtualConnection* connection, VIRTUAL_CONNECTION_STATE state);

View File

@ -174,7 +174,7 @@ int rpc_client_recv_pdu(rdpRpc* rpc, RPC_PDU* pdu)
rpcconn_rts_hdr_t* rts;
rdpTsg* tsg = rpc->transport->tsg;
if (rpc->State < RPC_CLIENT_STATE_ESTABLISHED)
if (rpc->VirtualConnection->State < VIRTUAL_CONNECTION_STATE_OPENED)
{
switch (rpc->VirtualConnection->State)
{

View File

@ -88,12 +88,49 @@ BOOL rts_connect(rdpRpc* rpc)
rpc_client_virtual_connection_transition_to_state(rpc,
rpc->VirtualConnection, VIRTUAL_CONNECTION_STATE_INITIAL);
if (!rpc_ntlm_http_out_connect(rpc))
rpc_client_out_channel_transition_to_state(rpc->VirtualConnection->DefaultOutChannel,
CLIENT_OUT_CHANNEL_STATE_CONNECTED);
if (rpc_ncacn_http_ntlm_init(rpc, TSG_CHANNEL_OUT) < 0)
return FALSE;
/* Send OUT Channel Request */
if (rpc_ncacn_http_send_out_channel_request(rpc) < 0)
{
WLog_ERR(TAG, "rpc_out_connect_http error!");
WLog_ERR(TAG, "rpc_ncacn_http_send_out_channel_request failure");
return FALSE;
}
rpc_client_out_channel_transition_to_state(rpc->VirtualConnection->DefaultOutChannel,
CLIENT_OUT_CHANNEL_STATE_SECURITY);
/* Receive OUT Channel Response */
response = http_response_recv(rpc->TlsOut);
if (!response)
return FALSE;
if (rpc_ncacn_http_recv_out_channel_response(rpc, response) < 0)
{
WLog_ERR(TAG, "rpc_ncacn_http_recv_out_channel_response failure");
return FALSE;
}
/* Send OUT Channel Request */
if (rpc_ncacn_http_send_out_channel_request(rpc) < 0)
{
WLog_ERR(TAG, "rpc_ncacn_http_send_out_channel_request failure");
return FALSE;
}
rpc_ncacn_http_ntlm_uninit(rpc, TSG_CHANNEL_OUT);
rpc_client_out_channel_transition_to_state(rpc->VirtualConnection->DefaultOutChannel,
CLIENT_OUT_CHANNEL_STATE_NEGOTIATED);
/* Send CONN/A1 PDU over OUT channel */
if (rts_send_CONN_A1_pdu(rpc) < 0)
@ -102,12 +139,52 @@ BOOL rts_connect(rdpRpc* rpc)
return FALSE;
}
if (!rpc_ntlm_http_in_connect(rpc))
rpc_client_out_channel_transition_to_state(rpc->VirtualConnection->DefaultOutChannel,
CLIENT_OUT_CHANNEL_STATE_OPENED);
rpc_client_in_channel_transition_to_state(rpc->VirtualConnection->DefaultInChannel,
CLIENT_IN_CHANNEL_STATE_CONNECTED);
if (rpc_ncacn_http_ntlm_init(rpc, TSG_CHANNEL_IN) < 0)
return FALSE;
/* Send IN Channel Request */
if (rpc_ncacn_http_send_in_channel_request(rpc) < 0)
{
WLog_ERR(TAG, "rpc_in_connect_http error!");
WLog_ERR(TAG, "rpc_ncacn_http_send_in_channel_request failure");
return FALSE;
}
rpc_client_in_channel_transition_to_state(rpc->VirtualConnection->DefaultInChannel,
CLIENT_IN_CHANNEL_STATE_SECURITY);
/* Receive IN Channel Response */
response = http_response_recv(rpc->TlsIn);
if (!response)
return FALSE;
if (rpc_ncacn_http_recv_in_channel_response(rpc, response) < 0)
{
WLog_ERR(TAG, "rpc_ncacn_http_recv_in_channel_response failure");
return FALSE;
}
/* Send IN Channel Request */
if (rpc_ncacn_http_send_in_channel_request(rpc) < 0)
{
WLog_ERR(TAG, "rpc_ncacn_http_send_in_channel_request failure");
return FALSE;
}
rpc_ncacn_http_ntlm_uninit(rpc, TSG_CHANNEL_IN);
rpc_client_in_channel_transition_to_state(rpc->VirtualConnection->DefaultInChannel,
CLIENT_IN_CHANNEL_STATE_NEGOTIATED);
/* Send CONN/B1 PDU over IN channel */
if (rts_send_CONN_B1_pdu(rpc) < 0)
@ -116,6 +193,9 @@ BOOL rts_connect(rdpRpc* rpc)
return FALSE;
}
rpc_client_in_channel_transition_to_state(rpc->VirtualConnection->DefaultInChannel,
CLIENT_IN_CHANNEL_STATE_OPENED);
rpc_client_virtual_connection_transition_to_state(rpc,
rpc->VirtualConnection, VIRTUAL_CONNECTION_STATE_OUT_CHANNEL_WAIT);
@ -138,9 +218,7 @@ BOOL rts_connect(rdpRpc* rpc)
if (response->StatusCode == HTTP_STATUS_DENIED)
{
if (!connectErrorCode)
{
connectErrorCode = AUTHENTICATIONERROR;
}
if (!freerdp_get_last_error(context))
{

View File

@ -1434,9 +1434,9 @@ BOOL tsg_connect(rdpTsg* tsg, const char* hostname, UINT16 port)
{
if (WaitForSingleObject(ReadEvent, 100) == WAIT_OBJECT_0)
{
if (rpc_client_recv(rpc) < 0)
if (tsg_check(tsg) < 0)
{
WLog_ERR(TAG, "tsg_connect: rpc_client_recv failure");
WLog_ERR(TAG, "tsg_check failure");
rpc->transport->layer = TRANSPORT_LAYER_CLOSED;
return FALSE;
}