diff --git a/libfreerdp/core/gateway/ncacn_http.c b/libfreerdp/core/gateway/ncacn_http.c index 5f26c8e3c..23e0a5e0b 100644 --- a/libfreerdp/core/gateway/ncacn_http.c +++ b/libfreerdp/core/gateway/ncacn_http.c @@ -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"); } } diff --git a/libfreerdp/core/gateway/ncacn_http.h b/libfreerdp/core/gateway/ncacn_http.h index 9a070aa6e..4f4eb7604 100644 --- a/libfreerdp/core/gateway/ncacn_http.h +++ b/libfreerdp/core/gateway/ncacn_http.h @@ -26,17 +26,19 @@ #include #include - - #include #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); diff --git a/libfreerdp/core/gateway/ntlm.h b/libfreerdp/core/gateway/ntlm.h index ebe8c8bc2..012d6b61d 100644 --- a/libfreerdp/core/gateway/ntlm.h +++ b/libfreerdp/core/gateway/ntlm.h @@ -31,14 +31,11 @@ typedef struct rdp_ntlm_http rdpNtlmHttp; #include "rts.h" #include "http.h" -#include -#include #include #include #include #include - #include #include #include diff --git a/libfreerdp/core/gateway/rpc.c b/libfreerdp/core/gateway/rpc.c index b782d28a5..306644151 100644 --- a/libfreerdp/core/gateway/rpc.c +++ b/libfreerdp/core/gateway/rpc.c @@ -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) { diff --git a/libfreerdp/core/gateway/rpc.h b/libfreerdp/core/gateway/rpc.h index 3e5f9fb53..9bb2497a9 100644 --- a/libfreerdp/core/gateway/rpc.h +++ b/libfreerdp/core/gateway/rpc.h @@ -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); diff --git a/libfreerdp/core/gateway/rpc_client.c b/libfreerdp/core/gateway/rpc_client.c index b509e5f09..a2ece2bfb 100644 --- a/libfreerdp/core/gateway/rpc_client.c +++ b/libfreerdp/core/gateway/rpc_client.c @@ -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) { diff --git a/libfreerdp/core/gateway/rts.c b/libfreerdp/core/gateway/rts.c index 04b239506..e18fcbb51 100644 --- a/libfreerdp/core/gateway/rts.c +++ b/libfreerdp/core/gateway/rts.c @@ -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)) { diff --git a/libfreerdp/core/gateway/tsg.c b/libfreerdp/core/gateway/tsg.c index 421d37fa6..f21415da8 100644 --- a/libfreerdp/core/gateway/tsg.c +++ b/libfreerdp/core/gateway/tsg.c @@ -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; }