diff --git a/client/common/file.c b/client/common/file.c index fecfe54c2..769108e35 100644 --- a/client/common/file.c +++ b/client/common/file.c @@ -832,6 +832,10 @@ BOOL freerdp_client_populate_settings_from_rdp_file(rdpFile* file, rdpSettings* if (file->GatewayUsageMethod == TSC_PROXY_MODE_DIRECT) freerdp_set_param_bool(settings, FreeRDP_GatewayEnabled, TRUE); + else if (file->GatewayUsageMethod == TSC_PROXY_MODE_DETECT) + freerdp_set_param_bool(settings, FreeRDP_GatewayEnabled, TRUE); + else if (file->GatewayUsageMethod == TSC_PROXY_MODE_DEFAULT) + freerdp_set_param_bool(settings, FreeRDP_GatewayEnabled, TRUE); else if (file->GatewayUsageMethod == TSC_PROXY_MODE_NONE_DETECT) freerdp_set_param_bool(settings, FreeRDP_GatewayEnabled, FALSE); } diff --git a/include/freerdp/crypto/tls.h b/include/freerdp/crypto/tls.h index 7e9aca995..a18597308 100644 --- a/include/freerdp/crypto/tls.h +++ b/include/freerdp/crypto/tls.h @@ -39,9 +39,12 @@ typedef struct rdp_tls rdpTls; struct rdp_tls { SSL* ssl; + BIO* bio; + void* tsg; int sockfd; SSL_CTX* ctx; BYTE* PublicKey; + BIO_METHOD* methods; DWORD PublicKeyLength; rdpSettings* settings; SecPkgContext_Bindings* Bindings; diff --git a/libfreerdp/core/connection.c b/libfreerdp/core/connection.c index 2e2de425f..97030a760 100644 --- a/libfreerdp/core/connection.c +++ b/libfreerdp/core/connection.c @@ -209,14 +209,6 @@ BOOL rdp_client_connect(rdpRdp* rdp) nego_set_cookie(rdp->nego, cookie); free(cookie); - - settings->RdpSecurity = TRUE; - settings->TlsSecurity = FALSE; - settings->NlaSecurity = FALSE; - settings->ExtSecurity = FALSE; - - //settings->TlsSecurity = TRUE; - //settings->NlaSecurity = TRUE; } else { diff --git a/libfreerdp/core/gateway/rpc_client.c b/libfreerdp/core/gateway/rpc_client.c index f58a7db2c..502ea9dad 100644 --- a/libfreerdp/core/gateway/rpc_client.c +++ b/libfreerdp/core/gateway/rpc_client.c @@ -161,7 +161,7 @@ int rpc_client_on_fragment_received_event(rdpRpc* rpc) if (StubLength == 4) { //fprintf(stderr, "Ignoring TsProxySendToServer Response\n"); - printf("Got stub length 4 with flags %d and callid %d\n", header->common.pfc_flags, header->common.call_id); + //printf("Got stub length 4 with flags %d and callid %d\n", header->common.pfc_flags, header->common.call_id); /* received a disconnect request from the server? */ if ((header->common.call_id == rpc->PipeCallId) && (header->common.pfc_flags & PFC_LAST_FRAG)) diff --git a/libfreerdp/core/nego.c b/libfreerdp/core/nego.c index 2e97d059d..448aff7bb 100644 --- a/libfreerdp/core/nego.c +++ b/libfreerdp/core/nego.c @@ -43,11 +43,16 @@ static const char* const NEGO_STATE_STRINGS[] = "NEGO_STATE_FINAL" }; -static const char PROTOCOL_SECURITY_STRINGS[4][4] = +static const char PROTOCOL_SECURITY_STRINGS[9][4] = { "RDP", "TLS", "NLA", + "UNK", + "UNK", + "UNK", + "UNK", + "UNK", "EXT" }; diff --git a/libfreerdp/core/nla.c b/libfreerdp/core/nla.c index 2978a2a79..34cbc3784 100644 --- a/libfreerdp/core/nla.c +++ b/libfreerdp/core/nla.c @@ -137,8 +137,18 @@ int credssp_ntlm_client_init(rdpCredssp* credssp) (char*) credssp->identity.User, (char*) credssp->identity.Domain, (char*) credssp->identity.Password); #endif - sspi_SecBufferAlloc(&credssp->PublicKey, credssp->transport->TlsIn->PublicKeyLength); - CopyMemory(credssp->PublicKey.pvBuffer, credssp->transport->TlsIn->PublicKey, credssp->transport->TlsIn->PublicKeyLength); + rdpTls *tls = NULL; + 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 { + fprintf(stderr, "Unknown NLA transport layer\n"); + return 0; + } + + sspi_SecBufferAlloc(&credssp->PublicKey, tls->PublicKeyLength); + CopyMemory(credssp->PublicKey.pvBuffer, tls->PublicKey, tls->PublicKeyLength); length = sizeof(TERMSRV_SPN_PREFIX) + strlen(settings->ServerHostname); diff --git a/libfreerdp/core/transport.c b/libfreerdp/core/transport.c index e06e92893..e87516472 100644 --- a/libfreerdp/core/transport.c +++ b/libfreerdp/core/transport.c @@ -77,7 +77,7 @@ BOOL transport_disconnect(rdpTransport* transport) if (transport->layer == TRANSPORT_LAYER_TLS) status &= tls_disconnect(transport->TlsIn); - if (transport->layer == TRANSPORT_LAYER_TSG) + if (transport->layer == TRANSPORT_LAYER_TSG || transport->layer == TRANSPORT_LAYER_TSG_TLS) { tsg_disconnect(transport->tsg); } @@ -104,10 +104,126 @@ BOOL transport_connect_rdp(rdpTransport* transport) return TRUE; } +long transport_bio_tsg_callback(BIO* bio, int mode, const char* argp, int argi, long argl, long ret) +{ + return 1; +} + +static int transport_bio_tsg_write(BIO* bio, const char* buf, int num) +{ + int status; + rdpTsg* tsg; + + tsg = (rdpTsg*) bio->ptr; + status = tsg_write(tsg, (BYTE*) buf, num); + + BIO_clear_retry_flags(bio); + + if (status <= 0) + { + BIO_set_retry_write(bio); + } + + return num; +} + +static int transport_bio_tsg_read(BIO* bio, char* buf, int size) +{ + int status; + rdpTsg* tsg; + + tsg = (rdpTsg*) bio->ptr; + status = tsg_read(bio->ptr, (BYTE*) buf, size); + + BIO_clear_retry_flags(bio); + + if (status <= 0) + { + BIO_set_retry_read(bio); + } + + return status > 0 ? status : -1; +} + +static int transport_bio_tsg_puts(BIO* bio, const char* str) +{ + return 1; +} + +static int transport_bio_tsg_gets(BIO* bio, char* str, int size) +{ + return 1; +} + +static long transport_bio_tsg_ctrl(BIO* bio, int cmd, long arg1, void* arg2) +{ + if(cmd == BIO_CTRL_FLUSH) { + return 1; + } + return 0; +} + +static int transport_bio_tsg_new(BIO* bio) +{ + bio->init = 1; + bio->num = 0; + bio->ptr = NULL; + bio->flags = 0; + + return 1; +} + +static int transport_bio_tsg_free(BIO* bio) +{ + return 1; +} + +#define BIO_TYPE_TSG 65 + +static BIO_METHOD transport_bio_tsg_methods = +{ + BIO_TYPE_TSG, + "TSGateway", + transport_bio_tsg_write, + transport_bio_tsg_read, + transport_bio_tsg_puts, + transport_bio_tsg_gets, + transport_bio_tsg_ctrl, + transport_bio_tsg_new, + transport_bio_tsg_free, + NULL, +}; + +BIO_METHOD* BIO_s_tsg(void) +{ + return &transport_bio_tsg_methods; +} + BOOL transport_connect_tls(rdpTransport* transport) { if (transport->layer == TRANSPORT_LAYER_TSG) + { + transport->TsgTls = tls_new(transport->settings); + + transport->TsgTls->methods = BIO_s_tsg(); + transport->TsgTls->tsg = (void*) transport->tsg; + + transport->layer = TRANSPORT_LAYER_TSG_TLS; + + if (tls_connect(transport->TsgTls) != TRUE) + { + if (!connectErrorCode) + connectErrorCode = TLSCONNECTERROR; + + tls_free(transport->TsgTls); + + transport->TsgTls = NULL; + + return FALSE; + } + return TRUE; + } if (transport->TlsIn == NULL) transport->TlsIn = tls_new(transport->settings); @@ -141,9 +257,6 @@ BOOL transport_connect_nla(rdpTransport* transport) freerdp* instance; rdpSettings* settings; - if (transport->layer == TRANSPORT_LAYER_TSG) - return TRUE; - if (!transport_connect_tls(transport)) return FALSE; @@ -385,6 +498,9 @@ int transport_read_layer(rdpTransport* transport, UINT8* data, int bytes) status = tcp_read(transport->TcpIn, data + read, bytes - read); else if (transport->layer == TRANSPORT_LAYER_TSG) status = tsg_read(transport->tsg, data + read, bytes - read); + else if (transport->layer == TRANSPORT_LAYER_TSG_TLS) { + status = tls_read(transport->TsgTls, data + read, bytes - read); + } /* blocking means that we can't continue until this is read */ @@ -540,6 +656,8 @@ int transport_write(rdpTransport* transport, wStream* s) status = tcp_write(transport->TcpOut, Stream_Pointer(s), length); else if (transport->layer == TRANSPORT_LAYER_TSG) status = tsg_write(transport->tsg, Stream_Pointer(s), length); + else if (transport->layer == TRANSPORT_LAYER_TSG_TLS) + status = tls_write(transport->TsgTls, Stream_Pointer(s), length); if (status < 0) break; /* error occurred */ @@ -558,6 +676,8 @@ int transport_write(rdpTransport* transport, wStream* s) tls_wait_write(transport->TlsOut); else if (transport->layer == TRANSPORT_LAYER_TCP) tcp_wait_write(transport->TcpOut); + else if (transport->layer == TRANSPORT_LAYER_TSG_TLS) + tls_wait_write(transport->TsgTls); else USleep(transport->SleepInterval); } @@ -784,7 +904,7 @@ BOOL transport_set_blocking_mode(rdpTransport* transport, BOOL blocking) status &= tcp_set_blocking_mode(transport->TcpIn, blocking); } - if (transport->layer == TRANSPORT_LAYER_TSG) + if (transport->layer == TRANSPORT_LAYER_TSG || transport->layer == TRANSPORT_LAYER_TSG_TLS) { tsg_set_blocking_mode(transport->tsg, blocking); } diff --git a/libfreerdp/core/transport.h b/libfreerdp/core/transport.h index bb573b6eb..235e5b3e5 100644 --- a/libfreerdp/core/transport.h +++ b/libfreerdp/core/transport.h @@ -25,6 +25,7 @@ typedef enum TRANSPORT_LAYER_TCP, TRANSPORT_LAYER_TLS, TRANSPORT_LAYER_TSG, + TRANSPORT_LAYER_TSG_TLS, TRANSPORT_LAYER_CLOSED } TRANSPORT_LAYER; @@ -57,6 +58,7 @@ struct rdp_transport rdpTcp* TcpOut; rdpTls* TlsIn; rdpTls* TlsOut; + rdpTls* TsgTls; rdpCredssp* credssp; rdpSettings* settings; UINT32 SleepInterval; diff --git a/libfreerdp/crypto/tls.c b/libfreerdp/crypto/tls.c index 3e089e418..17d41699a 100644 --- a/libfreerdp/crypto/tls.c +++ b/libfreerdp/crypto/tls.c @@ -97,6 +97,14 @@ SecPkgContext_Bindings* tls_get_channel_bindings(X509* cert) return ContextBindings; } +static void tls_ssl_info_callback(const SSL* ssl, int type, int val) +{ + if (type & SSL_CB_HANDSHAKE_START) + { + + } +} + BOOL tls_connect(rdpTls* tls) { CryptoCert cert; @@ -106,7 +114,7 @@ BOOL tls_connect(rdpTls* tls) tls->ctx = SSL_CTX_new(TLSv1_client_method()); - if (tls->ctx == NULL) + if (!tls->ctx) { fprintf(stderr, "SSL_CTX_new failed\n"); return FALSE; @@ -147,16 +155,35 @@ BOOL tls_connect(rdpTls* tls) tls->ssl = SSL_new(tls->ctx); - if (tls->ssl == NULL) + if (!tls->ssl) { fprintf(stderr, "SSL_new failed\n"); return FALSE; } - if (SSL_set_fd(tls->ssl, tls->sockfd) < 1) + if (tls->tsg) { - fprintf(stderr, "SSL_set_fd failed\n"); - return FALSE; + tls->bio = BIO_new(tls->methods); + + if (!tls->bio) + { + fprintf(stderr, "BIO_new failed\n"); + return FALSE; + } + + tls->bio->ptr = tls->tsg; + + SSL_set_bio(tls->ssl, tls->bio, tls->bio); + + SSL_CTX_set_info_callback(tls->ctx, tls_ssl_info_callback); + } + else + { + if (SSL_set_fd(tls->ssl, tls->sockfd) < 1) + { + fprintf(stderr, "SSL_set_fd failed\n"); + return FALSE; + } } connection_status = SSL_connect(tls->ssl);