From 70fab69347f78f9f50f218f77cae7df0dd281b2d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Moreau?= Date: Wed, 11 Feb 2015 14:27:29 -0500 Subject: [PATCH] libfreerdp-core: gateway connection refactoring --- libfreerdp/core/gateway/ncacn_http.c | 14 +- libfreerdp/core/gateway/rpc.c | 18 ++- libfreerdp/core/gateway/rpc.h | 12 +- libfreerdp/core/gateway/rpc_client.c | 8 +- libfreerdp/core/gateway/tsg.c | 188 +++++++++++++++------------ libfreerdp/core/nla.c | 15 +-- libfreerdp/core/rdp.c | 3 - libfreerdp/core/transport.c | 30 ++--- libfreerdp/core/transport.h | 2 +- 9 files changed, 155 insertions(+), 135 deletions(-) diff --git a/libfreerdp/core/gateway/ncacn_http.c b/libfreerdp/core/gateway/ncacn_http.c index 591e130a7..1f46819af 100644 --- a/libfreerdp/core/gateway/ncacn_http.c +++ b/libfreerdp/core/gateway/ncacn_http.c @@ -129,14 +129,22 @@ int rpc_ncacn_http_recv_in_channel_response(rdpRpc* rpc, HttpResponse* response) int rpc_ncacn_http_ntlm_init(rdpRpc* rpc, TSG_CHANNEL channel) { + rdpTls* tls = NULL; rdpNtlm* ntlm = NULL; + rdpContext* context = rpc->context; rdpSettings* settings = rpc->settings; - freerdp* instance = (freerdp*) rpc->settings->instance; + freerdp* instance = context->instance; if (channel == TSG_CHANNEL_IN) + { ntlm = rpc->NtlmHttpIn->ntlm; + tls = rpc->VirtualConnection->DefaultInChannel->tls; + } else if (channel == TSG_CHANNEL_OUT) + { ntlm = rpc->NtlmHttpOut->ntlm; + tls = rpc->VirtualConnection->DefaultOutChannel->tls; + } if (!settings->GatewayPassword || !settings->GatewayUsername || !strlen(settings->GatewayPassword) || !strlen(settings->GatewayUsername)) @@ -149,7 +157,7 @@ int rpc_ncacn_http_ntlm_init(rdpRpc* rpc, TSG_CHANNEL channel) if (!proceed) { connectErrorCode = CANCELEDBYUSER; - freerdp_set_last_error(instance->context, FREERDP_ERROR_CONNECT_CANCELLED); + freerdp_set_last_error(context, FREERDP_ERROR_CONNECT_CANCELLED); return 0; } @@ -163,7 +171,7 @@ int rpc_ncacn_http_ntlm_init(rdpRpc* rpc, TSG_CHANNEL channel) } if (!ntlm_client_init(ntlm, TRUE, settings->GatewayUsername, - settings->GatewayDomain, settings->GatewayPassword, rpc->TlsIn->Bindings)) + settings->GatewayDomain, settings->GatewayPassword, tls->Bindings)) { return 0; } diff --git a/libfreerdp/core/gateway/rpc.c b/libfreerdp/core/gateway/rpc.c index a282a61c3..aa098e08f 100644 --- a/libfreerdp/core/gateway/rpc.c +++ b/libfreerdp/core/gateway/rpc.c @@ -393,8 +393,9 @@ BOOL rpc_get_stub_data_info(rdpRpc* rpc, BYTE* buffer, UINT32* offset, UINT32* l int rpc_out_read(rdpRpc* rpc, BYTE* data, int length) { int status; + RpcOutChannel* outChannel = rpc->VirtualConnection->DefaultOutChannel; - status = BIO_read(rpc->TlsOut->bio, data, length); + status = BIO_read(outChannel->tls->bio, data, length); if (status > 0) { @@ -404,7 +405,7 @@ int rpc_out_read(rdpRpc* rpc, BYTE* data, int length) return status; } - if (BIO_should_retry(rpc->TlsOut->bio)) + if (BIO_should_retry(outChannel->tls->bio)) return 0; return -1; @@ -413,14 +414,20 @@ int rpc_out_read(rdpRpc* rpc, BYTE* data, int length) int rpc_out_write(rdpRpc* rpc, const BYTE* data, int length) { int status; - status = tls_write_all(rpc->TlsOut, data, length); + RpcOutChannel* outChannel = rpc->VirtualConnection->DefaultOutChannel; + + status = tls_write_all(outChannel->tls, data, length); + return status; } int rpc_in_write(rdpRpc* rpc, const BYTE* data, int length) { int status; - status = tls_write_all(rpc->TlsIn, data, length); + RpcInChannel* inChannel = rpc->VirtualConnection->DefaultInChannel; + + status = tls_write_all(inChannel->tls, data, length); + return status; } @@ -776,6 +783,7 @@ rdpRpc* rpc_new(rdpTransport* transport) rpc->StubFragCount = 0; rpc->rpc_vers = 5; rpc->rpc_vers_minor = 0; + /* little-endian data representation */ rpc->packed_drep[0] = 0x10; rpc->packed_drep[1] = 0x00; @@ -783,9 +791,9 @@ rdpRpc* rpc_new(rdpTransport* transport) rpc->packed_drep[3] = 0x00; rpc->max_xmit_frag = 0x0FF8; rpc->max_recv_frag = 0x0FF8; + rpc->ReceiveWindow = 0x00010000; rpc->ChannelLifetime = 0x40000000; - rpc->ChannelLifetimeSet = 0; rpc->KeepAliveInterval = 300000; rpc->CurrentKeepAliveInterval = rpc->KeepAliveInterval; rpc->CurrentKeepAliveTime = 0; diff --git a/libfreerdp/core/gateway/rpc.h b/libfreerdp/core/gateway/rpc.h index fc0250d31..1a0df9fe4 100644 --- a/libfreerdp/core/gateway/rpc.h +++ b/libfreerdp/core/gateway/rpc.h @@ -619,6 +619,9 @@ struct rpc_in_channel { /* Sending Channel */ + rdpTcp* tcp; + rdpTls* tls; + CLIENT_IN_CHANNEL_STATE State; UINT32 PlugState; @@ -651,6 +654,9 @@ typedef enum _CLIENT_OUT_CHANNEL_STATE CLIENT_OUT_CHANNEL_STATE; struct rpc_out_channel { + rdpTcp* tcp; + rdpTls* tls; + /* Receiving Channel */ CLIENT_OUT_CHANNEL_STATE State; @@ -724,9 +730,6 @@ struct rdp_rpc UINT32 result; - rdpTls* TlsIn; - rdpTls* TlsOut; - rdpNtlm* ntlm; int SendSeqNum; @@ -753,10 +756,7 @@ struct rdp_rpc UINT16 max_recv_frag; UINT32 ReceiveWindow; - UINT32 ChannelLifetime; - UINT32 ChannelLifetimeSet; - UINT32 KeepAliveInterval; UINT32 CurrentKeepAliveTime; UINT32 CurrentKeepAliveInterval; diff --git a/libfreerdp/core/gateway/rpc_client.c b/libfreerdp/core/gateway/rpc_client.c index d3f6adcd8..a6387ce27 100644 --- a/libfreerdp/core/gateway/rpc_client.c +++ b/libfreerdp/core/gateway/rpc_client.c @@ -540,7 +540,7 @@ int rpc_client_out_channel_recv(rdpRpc* rpc) if (outChannel->State < CLIENT_OUT_CHANNEL_STATE_OPENED) { - response = http_response_recv(rpc->TlsOut); + response = http_response_recv(outChannel->tls); if (!response) return -1; @@ -594,7 +594,7 @@ int rpc_client_out_channel_recv(rdpRpc* rpc) { /* Receive OUT channel response */ - response = http_response_recv(rpc->TlsOut); + response = http_response_recv(outChannel->tls); if (!response) return -1; @@ -645,14 +645,14 @@ int rpc_client_in_channel_recv(rdpRpc* rpc) inChannel = rpc->VirtualConnection->DefaultInChannel; outChannel = rpc->VirtualConnection->DefaultOutChannel; - BIO_get_event(rpc->TlsIn->bio, &InChannelEvent); + BIO_get_event(inChannel->tls->bio, &InChannelEvent); if (WaitForSingleObject(InChannelEvent, 0) != WAIT_OBJECT_0) return 1; if (inChannel->State < CLIENT_IN_CHANNEL_STATE_OPENED) { - response = http_response_recv(rpc->TlsIn); + response = http_response_recv(inChannel->tls); if (!response) return -1; diff --git a/libfreerdp/core/gateway/tsg.c b/libfreerdp/core/gateway/tsg.c index bb45fd593..6aa7e9425 100644 --- a/libfreerdp/core/gateway/tsg.c +++ b/libfreerdp/core/gateway/tsg.c @@ -1412,91 +1412,18 @@ int tsg_check(rdpTsg* tsg) BOOL tsg_connect(rdpTsg* tsg, const char* hostname, UINT16 port, int timeout) { - int tls_status; + int tlsStatus; HANDLE events[2]; rdpRpc* rpc = tsg->rpc; + RpcInChannel* inChannel; + RpcOutChannel* outChannel; + RpcVirtualConnection* connection; rdpSettings* settings = rpc->settings; rdpTransport* transport = rpc->transport; rdpContext* context = rpc->context; - transport->layer = TRANSPORT_LAYER_TSG; - transport->SplitInputOutput = TRUE; - - transport->TcpIn = freerdp_tcp_new(settings); - transport->TcpOut = freerdp_tcp_new(settings); - - if (!freerdp_tcp_connect(transport->TcpIn, settings->GatewayHostname, settings->GatewayPort, timeout) || - !freerdp_tcp_set_blocking_mode(transport->TcpIn, FALSE)) - return FALSE; - - if (!freerdp_tcp_connect(transport->TcpOut, settings->GatewayHostname, settings->GatewayPort, timeout) || - !freerdp_tcp_set_blocking_mode(transport->TcpOut, FALSE)) - return FALSE; - - tsg->transport = transport; - transport->tsg = tsg; - - transport->SplitInputOutput = TRUE; - - transport->TlsIn = tls_new(settings); - - if (!transport->TlsIn) - return FALSE; - - transport->TlsOut = tls_new(settings); - - if (!transport->TlsOut) - return FALSE; - - /* put a decent default value for gateway port */ - if (!settings->GatewayPort) - settings->GatewayPort = 443; - - transport->TlsIn->hostname = transport->TlsOut->hostname = settings->GatewayHostname; - transport->TlsIn->port = transport->TlsOut->port = settings->GatewayPort; - - transport->TlsIn->isGatewayTransport = TRUE; - tls_status = tls_connect(transport->TlsIn, transport->TcpIn->bufferedBio); - - if (tls_status < 1) - { - if (tls_status < 0) - { - if (!freerdp_get_last_error(context)) - freerdp_set_last_error(context, FREERDP_ERROR_TLS_CONNECT_FAILED); - } - else - { - if (!freerdp_get_last_error(context)) - freerdp_set_last_error(context, FREERDP_ERROR_CONNECT_CANCELLED); - } - - return FALSE; - } - - transport->TlsOut->isGatewayTransport = TRUE; - tls_status = tls_connect(transport->TlsOut, transport->TcpOut->bufferedBio); - - if (tls_status < 1) - { - if (tls_status < 0) - { - if (!freerdp_get_last_error(context)) - freerdp_set_last_error(context, FREERDP_ERROR_TLS_CONNECT_FAILED); - } - else - { - if (!freerdp_get_last_error(context)) - freerdp_set_last_error(context, FREERDP_ERROR_CONNECT_CANCELLED); - } - - return FALSE; - } - tsg->Port = port; - - rpc->TlsIn = transport->TlsIn; - rpc->TlsOut = transport->TlsOut; + tsg->transport = transport; free(tsg->Hostname); tsg->Hostname = NULL; @@ -1506,14 +1433,84 @@ BOOL tsg_connect(rdpTsg* tsg, const char* hostname, UINT16 port, int timeout) tsg->MachineName = NULL; ConvertToUnicode(CP_UTF8, 0, settings->ComputerName, -1, &tsg->MachineName, 0); + connection = rpc->VirtualConnection; + inChannel = connection->DefaultInChannel; + outChannel = connection->DefaultOutChannel; + + inChannel->tcp = freerdp_tcp_new(settings); + outChannel->tcp = freerdp_tcp_new(settings); + + if (!freerdp_tcp_connect(inChannel->tcp, settings->GatewayHostname, settings->GatewayPort, timeout) || + !freerdp_tcp_set_blocking_mode(inChannel->tcp, FALSE)) + return FALSE; + + if (!freerdp_tcp_connect(outChannel->tcp, settings->GatewayHostname, settings->GatewayPort, timeout) || + !freerdp_tcp_set_blocking_mode(outChannel->tcp, FALSE)) + return FALSE; + + inChannel->tls = tls_new(settings); + + if (!inChannel->tls) + return FALSE; + + outChannel->tls = tls_new(settings); + + if (!outChannel->tls) + return FALSE; + + /* put a decent default value for gateway port */ + if (!settings->GatewayPort) + settings->GatewayPort = 443; + + inChannel->tls->hostname = outChannel->tls->hostname = settings->GatewayHostname; + inChannel->tls->port = outChannel->tls->port = settings->GatewayPort; + + inChannel->tls->isGatewayTransport = TRUE; + tlsStatus = tls_connect(inChannel->tls, inChannel->tcp->bufferedBio); + + if (tlsStatus < 1) + { + if (tlsStatus < 0) + { + if (!freerdp_get_last_error(context)) + freerdp_set_last_error(context, FREERDP_ERROR_TLS_CONNECT_FAILED); + } + else + { + if (!freerdp_get_last_error(context)) + freerdp_set_last_error(context, FREERDP_ERROR_CONNECT_CANCELLED); + } + + return FALSE; + } + + outChannel->tls->isGatewayTransport = TRUE; + tlsStatus = tls_connect(outChannel->tls, outChannel->tcp->bufferedBio); + + if (tlsStatus < 1) + { + if (tlsStatus < 0) + { + if (!freerdp_get_last_error(context)) + freerdp_set_last_error(context, FREERDP_ERROR_TLS_CONNECT_FAILED); + } + else + { + if (!freerdp_get_last_error(context)) + freerdp_set_last_error(context, FREERDP_ERROR_CONNECT_CANCELLED); + } + + return FALSE; + } + if (!rpc_connect(rpc)) { WLog_ERR(TAG, "rpc_connect error!"); return FALSE; } - BIO_get_event(rpc->TlsIn->bio, &events[0]); - BIO_get_event(rpc->TlsOut->bio, &events[1]); + BIO_get_event(inChannel->tls->bio, &events[0]); + BIO_get_event(outChannel->tls->bio, &events[1]); while (tsg->state != TSG_STATE_PIPE_CREATED) { @@ -1522,18 +1519,28 @@ BOOL tsg_connect(rdpTsg* tsg, const char* hostname, UINT16 port, int timeout) if (tsg_check(tsg) < 0) { WLog_ERR(TAG, "tsg_check failure"); - rpc->transport->layer = TRANSPORT_LAYER_CLOSED; + transport->layer = TRANSPORT_LAYER_CLOSED; return FALSE; } } WLog_INFO(TAG, "TS Gateway Connection Success"); - tsg->transport->GatewayEvent = tsg->rpc->client->PipeEvent; tsg->bio = BIO_new(BIO_s_tsg()); - tsg->bio->ptr = tsg; + + if (!tsg->bio) + return FALSE; + + tsg->bio->ptr = (void*) tsg; transport->frontBio = tsg->bio; + transport->TcpIn = inChannel->tcp; + transport->TlsIn = inChannel->tls; + transport->TcpOut = outChannel->tcp; + transport->TlsOut = outChannel->tls; + transport->GatewayEvent = rpc->client->PipeEvent; + transport->SplitInputOutput = TRUE; + transport->layer = TRANSPORT_LAYER_TSG; return TRUE; } @@ -1679,6 +1686,8 @@ void tsg_free(rdpTsg* tsg) { if (tsg) { + rdpTransport* transport = tsg->transport; + if (tsg->bio) { BIO_free(tsg->bio); @@ -1693,6 +1702,19 @@ void tsg_free(rdpTsg* tsg) free(tsg->Hostname); free(tsg->MachineName); + + if (transport->TlsIn) + tls_free(transport->TlsIn); + + if (transport->TcpIn) + freerdp_tcp_free(transport->TcpIn); + + if (transport->TlsOut) + tls_free(transport->TlsOut); + + if (transport->TcpOut) + freerdp_tcp_free(transport->TcpOut); + free(tsg); } } diff --git a/libfreerdp/core/nla.c b/libfreerdp/core/nla.c index 35ffc6c7e..39cdc7b92 100644 --- a/libfreerdp/core/nla.c +++ b/libfreerdp/core/nla.c @@ -190,15 +190,9 @@ int credssp_ntlm_client_init(rdpCredssp* credssp) (char*) credssp->identity.User, (char*) credssp->identity.Domain, (char*) credssp->identity.Password); #endif - if (credssp->transport->layer == TRANSPORT_LAYER_TLS) - { - tls = credssp->transport->TlsIn; - } - else if (credssp->transport->layer == TRANSPORT_LAYER_TSG_TLS) - { - tls = credssp->transport->TsgTls; - } - else + tls = credssp->transport->tls; + + if (!tls) { WLog_ERR(TAG, "Unknown NLA transport layer"); return 0; @@ -211,8 +205,7 @@ int credssp_ntlm_client_init(rdpCredssp* credssp) sprintf(spn, "%s%s", TERMSRV_SPN_PREFIX, settings->ServerHostname); #ifdef UNICODE credssp->ServicePrincipalName = (LPTSTR) malloc(length * 2 + 2); - MultiByteToWideChar(CP_UTF8, 0, spn, length, - (LPWSTR) credssp->ServicePrincipalName, length); + MultiByteToWideChar(CP_UTF8, 0, spn, length, (LPWSTR) credssp->ServicePrincipalName, length); free(spn); #else credssp->ServicePrincipalName = spn; diff --git a/libfreerdp/core/rdp.c b/libfreerdp/core/rdp.c index 7bfd31a9b..a5971b206 100644 --- a/libfreerdp/core/rdp.c +++ b/libfreerdp/core/rdp.c @@ -1338,8 +1338,6 @@ rdpRdp* rdp_new(rdpContext* context) if (!rdp->transport) goto out_free_settings; - - rdp->transport->rdp = rdp; rdp->license = license_new(rdp); if (!rdp->license) @@ -1482,7 +1480,6 @@ void rdp_reset(rdpRdp* rdp) transport_free(rdp->transport); rdp->transport = transport_new(context); - rdp->transport->rdp = rdp; rdp->license = license_new(rdp); rdp->nego = nego_new(rdp->transport); rdp->mcs = mcs_new(rdp->transport); diff --git a/libfreerdp/core/transport.c b/libfreerdp/core/transport.c index 376441501..b5aa2aef2 100644 --- a/libfreerdp/core/transport.c +++ b/libfreerdp/core/transport.c @@ -109,18 +109,6 @@ BOOL transport_disconnect(rdpTransport* transport) tsg_free(transport->tsg); transport->tsg = NULL; - - if (transport->TlsIn) - tls_free(transport->TlsIn); - - if (transport->TcpIn) - freerdp_tcp_free(transport->TcpIn); - - if (transport->TlsOut) - tls_free(transport->TlsOut); - - if (transport->TcpOut) - freerdp_tcp_free(transport->TcpOut); } else { @@ -156,7 +144,7 @@ BOOL transport_connect_tls(rdpTransport* transport) rdpContext* context = transport->context; rdpSettings* settings = transport->settings; - if (transport->layer == TRANSPORT_LAYER_TSG) + if (transport->GatewayEnabled) { transport->TsgTls = tls_new(transport->settings); transport->layer = TRANSPORT_LAYER_TSG_TLS; @@ -171,6 +159,8 @@ BOOL transport_connect_tls(rdpTransport* transport) transport->layer = TRANSPORT_LAYER_TLS; } + transport->tls = targetTls; + targetTls->hostname = settings->ServerHostname; targetTls->port = settings->ServerPort; @@ -280,6 +270,8 @@ BOOL transport_tsg_connect(rdpTransport* transport, const char* hostname, UINT16 if (!tsg) return FALSE; + transport->tsg = tsg; + if (!tsg_connect(tsg, hostname, port, timeout)) return FALSE; @@ -330,12 +322,14 @@ BOOL transport_accept_rdp(rdpTransport* transport) BOOL transport_accept_tls(rdpTransport* transport) { + rdpSettings* settings = transport->settings; + if (!transport->TlsIn) transport->TlsIn = tls_new(transport->settings); transport->layer = TRANSPORT_LAYER_TLS; - if (!tls_accept(transport->TlsIn, transport->TcpIn->bufferedBio, transport->settings->CertificateFile, transport->settings->PrivateKeyFile)) + if (!tls_accept(transport->TlsIn, transport->TcpIn->bufferedBio, settings->CertificateFile, settings->PrivateKeyFile)) return FALSE; transport->frontBio = transport->TlsIn->bio; @@ -344,10 +338,8 @@ BOOL transport_accept_tls(rdpTransport* transport) BOOL transport_accept_nla(rdpTransport* transport) { - freerdp* instance; - rdpSettings* settings; - settings = transport->settings; - instance = (freerdp*) settings->instance; + rdpSettings* settings = transport->settings; + freerdp* instance = (freerdp*) settings->instance; if (!transport->TlsIn) transport->TlsIn = tls_new(transport->settings); @@ -913,7 +905,7 @@ static void* transport_client_thread(void* arg) HANDLE handles[64]; rdpTransport* transport = (rdpTransport*) arg; rdpContext* context = transport->context; - rdpRdp* rdp = (rdpRdp*) transport->rdp; + rdpRdp* rdp = context->rdp; WLog_DBG(TAG, "Starting transport thread"); diff --git a/libfreerdp/core/transport.h b/libfreerdp/core/transport.h index a2b0ceff0..c2f862788 100644 --- a/libfreerdp/core/transport.h +++ b/libfreerdp/core/transport.h @@ -57,6 +57,7 @@ struct rdp_transport TRANSPORT_LAYER layer; BIO* frontBio; rdpTsg* tsg; + rdpTls* tls; rdpTcp* TcpIn; rdpTcp* TcpOut; rdpTls* TlsIn; @@ -82,7 +83,6 @@ struct rdp_transport BOOL GatewayEnabled; CRITICAL_SECTION ReadLock; CRITICAL_SECTION WriteLock; - void* rdp; }; wStream* transport_send_stream_init(rdpTransport* transport, int size);