From fdde017526594eee88a40dbb0794793555c33dea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Moreau?= Date: Thu, 5 Feb 2015 15:10:24 -0500 Subject: [PATCH 1/8] libfreerdp-codec: allow region_uninit to be called multiple times --- libfreerdp/codec/region.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/libfreerdp/codec/region.c b/libfreerdp/codec/region.c index d309388f8..95ce193fa 100644 --- a/libfreerdp/codec/region.c +++ b/libfreerdp/codec/region.c @@ -798,10 +798,12 @@ BOOL region16_intersect_rect(REGION16 *dst, const REGION16 *src, const RECTANGLE void region16_uninit(REGION16 *region) { assert(region); - assert(region->data); - if (region->data->size) - free(region->data); + if (region->data) + { + if (region->data->size) + free(region->data); - region->data = NULL; + region->data = NULL; + } } From 82d58086dbcf82e4b56df3f3f88701ee83b5d01d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Moreau?= Date: Thu, 5 Feb 2015 17:01:56 -0500 Subject: [PATCH 2/8] xfreerdp: partial reconnect fixes --- channels/drdynvc/client/drdynvc_main.c | 5 ++ channels/rdpgfx/client/rdpgfx_main.c | 9 ++- client/X11/cli/xfreerdp.c | 1 - client/X11/xf_client.c | 97 +++++++++++++++++--------- client/X11/xf_gfx.c | 3 - libfreerdp/core/freerdp.c | 35 ++++++++-- libfreerdp/core/rdp.h | 1 + libfreerdp/crypto/tls.c | 15 ++-- 8 files changed, 118 insertions(+), 48 deletions(-) diff --git a/channels/drdynvc/client/drdynvc_main.c b/channels/drdynvc/client/drdynvc_main.c index 086e02069..5ff06dab2 100644 --- a/channels/drdynvc/client/drdynvc_main.c +++ b/channels/drdynvc/client/drdynvc_main.c @@ -283,6 +283,8 @@ void dvcman_free(IWTSVirtualChannelManager* pChannelMgr) free(listener); } + dvcman->num_listeners = 0; + for (i = 0; i < dvcman->num_plugins; i++) { pPlugin = dvcman->plugins[i]; @@ -291,7 +293,10 @@ void dvcman_free(IWTSVirtualChannelManager* pChannelMgr) pPlugin->Terminated(pPlugin); } + dvcman->num_plugins = 0; + StreamPool_Free(dvcman->pool); + free(dvcman); } diff --git a/channels/rdpgfx/client/rdpgfx_main.c b/channels/rdpgfx/client/rdpgfx_main.c index e1ca84051..8e98a6f2c 100644 --- a/channels/rdpgfx/client/rdpgfx_main.c +++ b/channels/rdpgfx/client/rdpgfx_main.c @@ -955,9 +955,16 @@ static int rdpgfx_plugin_terminated(IWTSPlugin* pPlugin) WLog_Print(gfx->log, WLOG_DEBUG, "Terminated"); if (gfx->listener_callback) + { free(gfx->listener_callback); + gfx->listener_callback = NULL; + } - zgfx_context_free(gfx->zgfx); + if (gfx->zgfx) + { + zgfx_context_free(gfx->zgfx); + gfx->zgfx = NULL; + } count = HashTable_GetKeys(gfx->SurfaceTable, &pKeys); diff --git a/client/X11/cli/xfreerdp.c b/client/X11/cli/xfreerdp.c index 3006ad50f..1f46010d4 100644 --- a/client/X11/cli/xfreerdp.c +++ b/client/X11/cli/xfreerdp.c @@ -71,7 +71,6 @@ int main(int argc, char* argv[]) thread = freerdp_client_get_thread(context); WaitForSingleObject(thread, INFINITE); - GetExitCodeThread(thread, &dwExitCode); freerdp_client_stop(context); diff --git a/client/X11/xf_client.c b/client/X11/xf_client.c index c404d424a..1aace96c7 100644 --- a/client/X11/xf_client.c +++ b/client/X11/xf_client.c @@ -203,7 +203,7 @@ void xf_draw_screen(xfContext* xfc, int x, int y, int w, int h) { if (w == 0 || h == 0) { - WLog_WARN(TAG, "invalid width and/or height specified: w=%d h=%d", w, h); + WLog_WARN(TAG, "invalid width and/or height specified: w=%d h=%d", w, h); return; } @@ -788,7 +788,6 @@ int _xf_error_handler(Display* d, XErrorEvent* ev) static void xf_post_disconnect(freerdp* instance) { xfContext* xfc; - rdpChannels* channels = channels = instance->context->channels; if (!instance || !instance->context || !instance->settings) return; @@ -895,7 +894,7 @@ BOOL xf_pre_connect(freerdp* instance) { if (!XInitThreads()) { - WLog_WARN(TAG, "XInitThreads() failure"); + WLog_WARN(TAG, "XInitThreads() failure"); xfc->UseXThreads = FALSE; } } @@ -911,7 +910,7 @@ BOOL xf_pre_connect(freerdp* instance) if (xfc->debug) { - WLog_INFO(TAG, "Enabling X11 debug mode."); + WLog_INFO(TAG, "Enabling X11 debug mode."); XSynchronize(xfc->display, TRUE); _def_error_handler = XSetErrorHandler(_xf_error_handler); } @@ -1127,6 +1126,7 @@ BOOL xf_post_connect(freerdp *instance) palette_cache_register_callbacks(instance->update); instance->update->BitmapUpdate = xf_gdi_bitmap_update; } + instance->update->PlaySound = xf_play_sound; instance->update->SetKeyboardIndicators = xf_keyboard_set_indicators; @@ -1360,39 +1360,44 @@ void* xf_input_thread(void *arg) BOOL xf_auto_reconnect(freerdp* instance) { + UINT32 maxRetries; + UINT32 numRetries = 0; xfContext* xfc = (xfContext*) instance->context; - UINT32 num_retries = 0; - UINT32 max_retries = instance->settings->AutoReconnectMaxRetries; + rdpSettings* settings = xfc->settings; + + maxRetries = settings->AutoReconnectMaxRetries; /* Only auto reconnect on network disconnects. */ if (freerdp_error_info(instance) != 0) return FALSE; /* A network disconnect was detected */ - WLog_INFO(TAG, "Network disconnect!"); + WLog_INFO(TAG, "Network disconnect!"); - if (!instance->settings->AutoReconnectionEnabled) + if (!settings->AutoReconnectionEnabled) { /* No auto-reconnect - just quit */ return FALSE; } /* Perform an auto-reconnect. */ - for (;;) + while (TRUE) { /* Quit retrying if max retries has been exceeded */ - if (num_retries++ >= max_retries) + if (numRetries++ >= maxRetries) { return FALSE; } /* Attempt the next reconnect */ - WLog_INFO(TAG, "Attempting reconnect (%u of %u)", num_retries, max_retries); + WLog_INFO(TAG, "Attempting reconnect (%u of %u)", numRetries, maxRetries); + if (freerdp_reconnect(instance)) { xfc->disconnect = FALSE; return TRUE; } + sleep(5); } @@ -1487,7 +1492,7 @@ void* xf_client_thread(void *param) nCount += freerdp_get_event_handles(context, &handles[nCount]); } - waitStatus = WaitForMultipleObjects(nCount, handles, FALSE, INFINITE); + waitStatus = WaitForMultipleObjects(nCount, handles, FALSE, 100); if (!settings->AsyncTransport) { @@ -1642,9 +1647,13 @@ static int xfreerdp_client_start(rdpContext* context) WLog_ERR(TAG, "error: server hostname was not specified with /v:[:port]"); return -1; } + xfc->disconnect = FALSE; - xfc->thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) xf_client_thread, - context->instance, 0, NULL); + + xfc->thread = CreateThread(NULL, 0, + (LPTHREAD_START_ROUTINE) xf_client_thread, + context->instance, 0, NULL); + return 0; } @@ -1654,8 +1663,10 @@ static int xfreerdp_client_stop(rdpContext* context) if (context->settings->AsyncInput) { - wMessageQueue *queue; + wMessageQueue* queue; + queue = freerdp_get_message_queue(context->instance, FREERDP_INPUT_MESSAGE_QUEUE); + if (queue) MessageQueue_PostQuit(queue, 0); } @@ -1666,6 +1677,7 @@ static int xfreerdp_client_stop(rdpContext* context) if (xfc->thread) { + WaitForSingleObject(xfc->thread, INFINITE); CloseHandle(xfc->thread); xfc->thread = NULL; } @@ -1706,26 +1718,45 @@ static void xfreerdp_client_free(freerdp* instance, rdpContext* context) { xfContext* xfc = (xfContext*) context; - if (context) + if (!context) + return; + + xf_window_free(xfc); + + if (xfc->bitmap_buffer) { - xf_window_free(xfc); - - if (xfc->bitmap_buffer) - _aligned_free(xfc->bitmap_buffer); - - if (xfc->display) - XCloseDisplay(xfc->display); - - if (xfc->x11event) - CloseHandle(xfc->x11event); - - if (context->channels) - { - freerdp_channels_close(context->channels, instance); - freerdp_channels_free(context->channels); - context->channels = NULL; - } + _aligned_free(xfc->bitmap_buffer); + xfc->bitmap_buffer = NULL; } + + if (xfc->display) + { + XCloseDisplay(xfc->display); + xfc->display = NULL; + } + + if (xfc->x11event) + { + CloseHandle(xfc->x11event); + xfc->x11event = NULL; + } + + if (context->channels) + { + freerdp_channels_close(context->channels, instance); + freerdp_channels_free(context->channels); + context->channels = NULL; + } + + if (xfc->mutex) + { + WaitForSingleObject(xfc->mutex, INFINITE); + CloseHandle(xfc->mutex); + xfc->mutex = NULL; + } + + xf_monitors_free(xfc, instance->settings); + gdi_free(instance); } int RdpClientEntry(RDP_CLIENT_ENTRY_POINTS* pEntryPoints) diff --git a/client/X11/xf_gfx.c b/client/X11/xf_gfx.c index 673d046c1..7ac3874c2 100644 --- a/client/X11/xf_gfx.c +++ b/client/X11/xf_gfx.c @@ -890,7 +890,4 @@ void xf_graphics_pipeline_init(xfContext* xfc, RdpgfxClientContext* gfx) void xf_graphics_pipeline_uninit(xfContext* xfc, RdpgfxClientContext* gfx) { region16_uninit(&(xfc->invalidRegion)); - - gfx->custom = NULL; - xfc->gfx = NULL; } diff --git a/libfreerdp/core/freerdp.c b/libfreerdp/core/freerdp.c index 0ee563c7c..1e763dcda 100644 --- a/libfreerdp/core/freerdp.c +++ b/libfreerdp/core/freerdp.c @@ -62,8 +62,8 @@ BOOL freerdp_connect(freerdp* instance) { rdpRdp* rdp; + BOOL status = TRUE; rdpSettings* settings; - BOOL status = FALSE; ConnectionResultEventArgs e; /* We always set the return code to 0 before we start the connect sequence*/ @@ -73,7 +73,10 @@ BOOL freerdp_connect(freerdp* instance) rdp = instance->context->rdp; settings = instance->settings; - IFCALLRET(instance->PreConnect, status, instance); + if (!rdp->reconnect) + { + IFCALLRET(instance->PreConnect, status, instance); + } if (settings->KeyboardLayout == KBD_JAPANESE_INPUT_SYSTEM_MS_IME2002) { @@ -116,7 +119,11 @@ BOOL freerdp_connect(freerdp* instance) instance->update->dump_rfx = TRUE; } - IFCALLRET(instance->PostConnect, status, instance); + if (!rdp->reconnect) + { + IFCALLRET(instance->PostConnect, status, instance); + } + update_post_connect(instance->update); if (!status) @@ -345,9 +352,14 @@ BOOL freerdp_disconnect(freerdp* instance) rdpRdp* rdp; rdp = instance->context->rdp; + rdp_client_disconnect(rdp); update_post_disconnect(instance->update); - IFCALL(instance->PostDisconnect, instance); + + if (!rdp->reconnect) + { + IFCALL(instance->PostDisconnect, instance); + } if (instance->update->pcap_rfx) { @@ -361,8 +373,19 @@ BOOL freerdp_disconnect(freerdp* instance) BOOL freerdp_reconnect(freerdp* instance) { - freerdp_disconnect(instance); - return freerdp_connect(instance); + BOOL status = TRUE; + rdpRdp* rdp = instance->context->rdp; + + rdp->reconnect = TRUE; + + status = freerdp_disconnect(instance); + + if (status) + status = freerdp_connect(instance); + + rdp->reconnect = FALSE; + + return status; } BOOL freerdp_shall_disconnect(freerdp* instance) diff --git a/libfreerdp/core/rdp.h b/libfreerdp/core/rdp.h index fb8531b01..5397f4176 100644 --- a/libfreerdp/core/rdp.h +++ b/libfreerdp/core/rdp.h @@ -169,6 +169,7 @@ struct rdp_rdp BYTE fips_decrypt_key[24]; UINT32 errorInfo; UINT32 finalize_sc_pdus; + BOOL reconnect; BOOL disconnect; BOOL resendFocus; BOOL deactivation_reactivation; diff --git a/libfreerdp/crypto/tls.c b/libfreerdp/crypto/tls.c index 613c185bc..6f8b15202 100644 --- a/libfreerdp/crypto/tls.c +++ b/libfreerdp/crypto/tls.c @@ -582,6 +582,7 @@ BOOL tls_prepare(rdpTls* tls, BIO *underlying, const SSL_METHOD *method, int opt #endif { tls->ctx = SSL_CTX_new(method); + if (!tls->ctx) { WLog_ERR(TAG, "SSL_CTX_new failed"); @@ -593,8 +594,10 @@ BOOL tls_prepare(rdpTls* tls, BIO *underlying, const SSL_METHOD *method, int opt SSL_CTX_set_options(tls->ctx, options); SSL_CTX_set_read_ahead(tls->ctx, 1); - if (tls->settings->PermittedTLSCiphers) { - if(!SSL_CTX_set_cipher_list(tls->ctx, tls->settings->PermittedTLSCiphers)) { + if (tls->settings->PermittedTLSCiphers) + { + if (!SSL_CTX_set_cipher_list(tls->ctx, tls->settings->PermittedTLSCiphers)) + { WLog_ERR(TAG, "SSL_CTX_set_cipher_list %s failed", tls->settings->PermittedTLSCiphers); return FALSE; } @@ -755,8 +758,6 @@ int tls_connect(rdpTls* tls, BIO *underlying) return tls_do_handshake(tls, TRUE); } - - BOOL tls_accept(rdpTls* tls, BIO *underlying, const char* cert_file, const char* privatekey_file) { long options = 0; @@ -1392,6 +1393,12 @@ void tls_free(rdpTls* tls) tls->ctx = NULL; } + if (tls->bio) + { + BIO_free(tls->bio); + tls->bio = NULL; + } + if (tls->PublicKey) { free(tls->PublicKey); From fa06c4d401aa78c900bdcbbe1921679f6d2e2092 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Moreau?= Date: Fri, 6 Feb 2015 14:21:26 -0500 Subject: [PATCH 3/8] libfreerdp-core: improve reconnection --- channels/drdynvc/client/drdynvc_main.c | 18 +++--- client/common/cmdline.c | 20 +++--- include/freerdp/settings.h | 3 +- libfreerdp/core/certificate.c | 43 +++++++++++++ libfreerdp/core/certificate.h | 2 + libfreerdp/core/connection.c | 51 +++++++++------ libfreerdp/core/connection.h | 1 + libfreerdp/core/freerdp.c | 26 ++------ libfreerdp/core/info.c | 67 +++++++++++--------- libfreerdp/core/rdp.c | 68 +++++++++++++++----- libfreerdp/core/rdp.h | 1 - libfreerdp/core/settings.c | 18 +++--- libfreerdp/crypto/tls.c | 86 +++++++++++++------------- 13 files changed, 253 insertions(+), 151 deletions(-) diff --git a/channels/drdynvc/client/drdynvc_main.c b/channels/drdynvc/client/drdynvc_main.c index 5ff06dab2..c499b928c 100644 --- a/channels/drdynvc/client/drdynvc_main.c +++ b/channels/drdynvc/client/drdynvc_main.c @@ -553,7 +553,7 @@ int drdynvc_send(drdynvcPlugin* drdynvc, wStream* s) if (status != CHANNEL_RC_OK) { Stream_Free(s, TRUE); - WLog_ERR(TAG, "VirtualChannelWrite failed with %s [%08X]", + WLog_ERR(TAG, "VirtualChannelWrite failed with %s [%08X]", WTSErrorToString(status), status); } @@ -643,7 +643,7 @@ int drdynvc_write_data(drdynvcPlugin* drdynvc, UINT32 ChannelId, BYTE* data, UIN if (status != CHANNEL_RC_OK) { drdynvc->channel_error = status; - WLog_ERR(TAG, "VirtualChannelWrite failed with %s [%08X]", + WLog_ERR(TAG, "VirtualChannelWrite failed with %s [%08X]", WTSErrorToString(status), status); return 1; } @@ -664,7 +664,7 @@ static int drdynvc_send_capability_response(drdynvcPlugin* drdynvc) if (status != CHANNEL_RC_OK) { - WLog_ERR(TAG, "VirtualChannelWrite failed with %s [%08X]", + WLog_ERR(TAG, "VirtualChannelWrite failed with %s [%08X]", WTSErrorToString(status), status); return 1; } @@ -771,7 +771,7 @@ static int drdynvc_process_create_request(drdynvcPlugin* drdynvc, int Sp, int cb if (status != CHANNEL_RC_OK) { - WLog_ERR(TAG, "VirtualChannelWrite failed with %s [%08X]", + WLog_ERR(TAG, "VirtualChannelWrite failed with %s [%08X]", WTSErrorToString(status), status); return 1; } @@ -835,7 +835,7 @@ static int drdynvc_process_close_request(drdynvcPlugin* drdynvc, int Sp, int cbC if (error != CHANNEL_RC_OK) { - WLog_ERR(TAG, "VirtualChannelWrite failed with %s [%08X]", + WLog_ERR(TAG, "VirtualChannelWrite failed with %s [%08X]", WTSErrorToString(error), error); return 1; } @@ -973,7 +973,7 @@ static void drdynvc_virtual_channel_event_data_received(drdynvcPlugin* drdynvc, { if (Stream_Capacity(data_in) != Stream_GetPosition(data_in)) { - WLog_ERR(TAG, "drdynvc_plugin_process_received: read error"); + WLog_ERR(TAG, "drdynvc_plugin_process_received: read error"); } drdynvc->data_in = NULL; @@ -993,7 +993,7 @@ static VOID VCAPITYPE drdynvc_virtual_channel_open_event(DWORD openHandle, UINT if (!drdynvc) { - WLog_ERR(TAG, "drdynvc_virtual_channel_open_event: error no match"); + WLog_ERR(TAG, "drdynvc_virtual_channel_open_event: error no match"); return; } @@ -1055,7 +1055,7 @@ static void drdynvc_virtual_channel_event_connected(drdynvcPlugin* drdynvc, LPVO if (status != CHANNEL_RC_OK) { - WLog_ERR(TAG, "pVirtualChannelOpen failed with %s [%08X]", + WLog_ERR(TAG, "pVirtualChannelOpen failed with %s [%08X]", WTSErrorToString(status), status); return; } @@ -1130,7 +1130,7 @@ static VOID VCAPITYPE drdynvc_virtual_channel_init_event(LPVOID pInitHandle, UIN if (!drdynvc) { - WLog_ERR(TAG, "drdynvc_virtual_channel_init_event: error no match"); + WLog_ERR(TAG, "drdynvc_virtual_channel_init_event: error no match"); return; } diff --git a/client/common/cmdline.c b/client/common/cmdline.c index 843c5a0f4..ab2d82350 100644 --- a/client/common/cmdline.c +++ b/client/common/cmdline.c @@ -132,8 +132,7 @@ COMMAND_LINE_ARGUMENT_A args[] = { "sec-tls", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueTrue, NULL, -1, NULL, "tls protocol security" }, { "sec-nla", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueTrue, NULL, -1, NULL, "nla protocol security" }, { "sec-ext", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueFalse, NULL, -1, NULL, "nla extended protocol security" }, - { "tls-ciphers", COMMAND_LINE_VALUE_REQUIRED, NULL, NULL, NULL, -1, NULL, "List of permitted openssl ciphers - see ciphers(1)" }, - { "tls-ciphers-netmon", COMMAND_LINE_VALUE_FLAG, NULL, NULL, NULL, -1, NULL, "Use tls ciphers that netmon can parse" }, + { "tls-ciphers", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, "Allowed TLS ciphers" }, { "cert-name", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, "certificate name" }, { "cert-ignore", COMMAND_LINE_VALUE_FLAG, NULL, NULL, NULL, -1, NULL, "ignore certificate" }, { "pcb", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, "Preconnection Blob" }, @@ -1810,11 +1809,18 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, } CommandLineSwitchCase(arg, "tls-ciphers") { - settings->PermittedTLSCiphers = _strdup(arg->Value); - } - CommandLineSwitchCase(arg, "tls-ciphers-netmon") - { - settings->PermittedTLSCiphers = arg->Value ? _strdup("ALL:!ECDH") : NULL; + if (strcmp(arg->Value, "netmon") == 0) + { + settings->AllowedTlsCiphers = _strdup("ALL:!ECDH"); + } + else if (strcmp(arg->Value, "ma") == 0) + { + settings->AllowedTlsCiphers = _strdup("AES128-SHA"); + } + else + { + settings->AllowedTlsCiphers = _strdup(arg->Value); + } } CommandLineSwitchCase(arg, "cert-name") { diff --git a/include/freerdp/settings.h b/include/freerdp/settings.h index c92bc7142..0184decfb 100644 --- a/include/freerdp/settings.h +++ b/include/freerdp/settings.h @@ -615,6 +615,7 @@ typedef struct _RDPDR_PARALLEL RDPDR_PARALLEL; #define FreeRDP_AuthenticationServiceClass 1098 #define FreeRDP_DisableCredentialsDelegation 1099 #define FreeRDP_AuthenticationLevel 1100 +#define FreeRDP_AllowedTlsCiphers 1101 #define FreeRDP_MstscCookieMode 1152 #define FreeRDP_CookieMaxLength 1153 #define FreeRDP_PreconnectionId 1154 @@ -998,7 +999,7 @@ struct rdp_settings ALIGN64 char* AuthenticationServiceClass; /* 1098 */ ALIGN64 BOOL DisableCredentialsDelegation; /* 1099 */ ALIGN64 BOOL AuthenticationLevel; /* 1100 */ - ALIGN64 char* PermittedTLSCiphers; /* 1101 */ + ALIGN64 char* AllowedTlsCiphers; /* 1101 */ UINT64 padding1152[1152 - 1102]; /* 1102 */ /* Connection Cookie */ diff --git a/libfreerdp/core/certificate.c b/libfreerdp/core/certificate.c index b5946e04e..5e623961f 100644 --- a/libfreerdp/core/certificate.c +++ b/libfreerdp/core/certificate.c @@ -773,6 +773,49 @@ void key_free(rdpRsaKey* key) free(key); } +rdpCertificate* certificate_clone(rdpCertificate* certificate) +{ + int index; + rdpCertificate* _certificate = (rdpCertificate*) calloc(1, sizeof(rdpCertificate)); + + if (!_certificate) + return NULL; + + CopyMemory(_certificate, certificate, sizeof(rdpCertificate)); + + if (certificate->cert_info.ModulusLength) + { + _certificate->cert_info.Modulus = (BYTE*) malloc(certificate->cert_info.ModulusLength); + CopyMemory(_certificate->cert_info.Modulus, certificate->cert_info.Modulus, certificate->cert_info.ModulusLength); + _certificate->cert_info.ModulusLength = certificate->cert_info.ModulusLength; + } + + if (certificate->x509_cert_chain) + { + _certificate->x509_cert_chain = (rdpX509CertChain*) malloc(sizeof(rdpX509CertChain)); + CopyMemory(_certificate->x509_cert_chain, certificate->x509_cert_chain, sizeof(rdpX509CertChain)); + + if (certificate->x509_cert_chain->count) + { + _certificate->x509_cert_chain->array = (rdpCertBlob*) calloc(certificate->x509_cert_chain->count, sizeof(rdpCertBlob)); + + for (index = 0; index < certificate->x509_cert_chain->count; index++) + { + _certificate->x509_cert_chain->array[index].length = certificate->x509_cert_chain->array[index].length; + + if (certificate->x509_cert_chain->array[index].length) + { + _certificate->x509_cert_chain->array[index].data = (BYTE*) malloc(certificate->x509_cert_chain->array[index].length); + CopyMemory(_certificate->x509_cert_chain->array[index].data, certificate->x509_cert_chain->array[index].data, + _certificate->x509_cert_chain->array[index].length); + } + } + } + } + + return _certificate; +} + /** * Instantiate new certificate module.\n * @param rdp RDP module diff --git a/libfreerdp/core/certificate.h b/libfreerdp/core/certificate.h index 91cb3e6d0..6b3195f35 100644 --- a/libfreerdp/core/certificate.h +++ b/libfreerdp/core/certificate.h @@ -53,6 +53,8 @@ BOOL certificate_read_server_proprietary_certificate(rdpCertificate* certificate BOOL certificate_read_server_x509_certificate_chain(rdpCertificate* certificate, wStream* s); BOOL certificate_read_server_certificate(rdpCertificate* certificate, BYTE* server_cert, int length); +rdpCertificate* certificate_clone(rdpCertificate* certificate); + rdpCertificate* certificate_new(void); void certificate_free(rdpCertificate* certificate); diff --git a/libfreerdp/core/connection.c b/libfreerdp/core/connection.c index 5d39af6be..be201b7b0 100644 --- a/libfreerdp/core/connection.c +++ b/libfreerdp/core/connection.c @@ -172,7 +172,7 @@ BOOL rdp_client_connect(rdpRdp* rdp) { - BOOL ret; + BOOL status; rdpSettings* settings = rdp->settings; if (rdp->settingsCopy) @@ -213,6 +213,7 @@ BOOL rdp_client_connect(rdpRdp* rdp) cookie_length = domain_length + 1 + user_length; cookie = (char*) malloc(cookie_length + 1); + if (!cookie) return FALSE; @@ -225,15 +226,15 @@ BOOL rdp_client_connect(rdpRdp* rdp) cookie[cookie_length] = '\0'; - ret = nego_set_cookie(rdp->nego, cookie); + status = nego_set_cookie(rdp->nego, cookie); free(cookie); } else { - ret = nego_set_cookie(rdp->nego, settings->Username); + status = nego_set_cookie(rdp->nego, settings->Username); } - if (!ret) + if (!status) return FALSE; nego_set_send_preconnection_pdu(rdp->nego, settings->SendPreconnectionPdu); @@ -269,7 +270,7 @@ BOOL rdp_client_connect(rdpRdp* rdp) freerdp_set_last_error(rdp->context, FREERDP_ERROR_SECURITY_NEGO_CONNECT_FAILED); } - WLog_ERR(TAG, "Error: protocol security negotiation or connection failure"); + WLog_ERR(TAG, "Error: protocol security negotiation or connection failure"); return FALSE; } @@ -297,7 +298,7 @@ BOOL rdp_client_connect(rdpRdp* rdp) freerdp_set_last_error(rdp->context, FREERDP_ERROR_MCS_CONNECT_INITIAL_ERROR); } - WLog_ERR(TAG, "Error: unable to send MCS Connect Initial"); + WLog_ERR(TAG, "Error: unable to send MCS Connect Initial"); return FALSE; } @@ -319,7 +320,7 @@ BOOL rdp_client_connect(rdpRdp* rdp) BOOL rdp_client_disconnect(rdpRdp* rdp) { - BOOL rc; + BOOL status; if (rdp->settingsCopy) { @@ -327,10 +328,13 @@ BOOL rdp_client_disconnect(rdpRdp* rdp) rdp->settingsCopy = NULL; } - rc = nego_disconnect(rdp->nego); + status = nego_disconnect(rdp->nego); + rdp_reset(rdp); + rdp_client_transition_to_state(rdp, CONNECTION_STATE_INITIAL); - return rc; + + return status; } BOOL rdp_client_redirect(rdpRdp* rdp) @@ -381,6 +385,17 @@ BOOL rdp_client_redirect(rdpRdp* rdp) return status; } +BOOL rdp_client_reconnect(rdpRdp* rdp) +{ + BOOL status; + + rdp_client_disconnect(rdp); + + status = rdp_client_connect(rdp); + + return status; +} + static BYTE fips_ivec[8] = { 0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF }; static BOOL rdp_client_establish_keys(rdpRdp* rdp) @@ -631,7 +646,7 @@ BOOL rdp_client_connect_mcs_connect_response(rdpRdp* rdp, wStream* s) { if (!mcs_recv_connect_response(rdp->mcs, s)) { - WLog_ERR(TAG, "rdp_client_connect_mcs_connect_response: mcs_recv_connect_response failed"); + WLog_ERR(TAG, "rdp_client_connect_mcs_connect_response: mcs_recv_connect_response failed"); return FALSE; } @@ -795,7 +810,7 @@ int rdp_client_connect_license(rdpRdp* rdp, wStream* s) if (rdp->license->state == LICENSE_STATE_ABORTED) { - WLog_ERR(TAG, "license connection sequence aborted."); + WLog_ERR(TAG, "license connection sequence aborted."); return -1; } @@ -974,12 +989,12 @@ BOOL rdp_server_accept_nego(rdpRdp* rdp, wStream* s) return FALSE; nego->SelectedProtocol = 0; - WLog_INFO(TAG, "Client Security: NLA:%d TLS:%d RDP:%d", + WLog_INFO(TAG, "Client Security: NLA:%d TLS:%d RDP:%d", (nego->RequestedProtocols & PROTOCOL_NLA) ? 1 : 0, (nego->RequestedProtocols & PROTOCOL_TLS) ? 1 : 0, (nego->RequestedProtocols == PROTOCOL_RDP) ? 1 : 0 ); - WLog_INFO(TAG, "Server Security: NLA:%d TLS:%d RDP:%d", + WLog_INFO(TAG, "Server Security: NLA:%d TLS:%d RDP:%d", settings->NlaSecurity, settings->TlsSecurity, settings->RdpSecurity); if ((settings->NlaSecurity) && (nego->RequestedProtocols & PROTOCOL_NLA)) @@ -996,10 +1011,10 @@ BOOL rdp_server_accept_nego(rdpRdp* rdp, wStream* s) } else { - WLog_ERR(TAG, "Protocol security negotiation failure"); + WLog_ERR(TAG, "Protocol security negotiation failure"); } - WLog_INFO(TAG, "Negotiated Security: NLA:%d TLS:%d RDP:%d", + WLog_INFO(TAG, "Negotiated Security: NLA:%d TLS:%d RDP:%d", (nego->SelectedProtocol & PROTOCOL_NLA) ? 1 : 0, (nego->SelectedProtocol & PROTOCOL_TLS) ? 1 : 0, (nego->SelectedProtocol == PROTOCOL_RDP) ? 1: 0 @@ -1035,12 +1050,12 @@ BOOL rdp_server_accept_mcs_connect_initial(rdpRdp* rdp, wStream* s) if (!mcs_recv_connect_initial(mcs, s)) return FALSE; - WLog_INFO(TAG, "Accepted client: %s", rdp->settings->ClientHostname); - WLog_INFO(TAG, "Accepted channels:"); + WLog_INFO(TAG, "Accepted client: %s", rdp->settings->ClientHostname); + WLog_INFO(TAG, "Accepted channels:"); for (i = 0; i < mcs->channelCount; i++) { - WLog_INFO(TAG, " %s", mcs->channels[i].Name); + WLog_INFO(TAG, " %s", mcs->channels[i].Name); } if (!mcs_send_connect_response(mcs)) diff --git a/libfreerdp/core/connection.h b/libfreerdp/core/connection.h index df26ee787..0efe022ac 100644 --- a/libfreerdp/core/connection.h +++ b/libfreerdp/core/connection.h @@ -49,6 +49,7 @@ enum CONNECTION_STATE BOOL rdp_client_connect(rdpRdp* rdp); BOOL rdp_client_disconnect(rdpRdp* rdp); +BOOL rdp_client_reconnect(rdpRdp* rdp); BOOL rdp_client_redirect(rdpRdp* rdp); BOOL rdp_client_connect_mcs_connect_response(rdpRdp* rdp, wStream* s); BOOL rdp_client_connect_mcs_attach_user_confirm(rdpRdp* rdp, wStream* s); diff --git a/libfreerdp/core/freerdp.c b/libfreerdp/core/freerdp.c index 1e763dcda..f63edfd4e 100644 --- a/libfreerdp/core/freerdp.c +++ b/libfreerdp/core/freerdp.c @@ -73,10 +73,7 @@ BOOL freerdp_connect(freerdp* instance) rdp = instance->context->rdp; settings = instance->settings; - if (!rdp->reconnect) - { - IFCALLRET(instance->PreConnect, status, instance); - } + IFCALLRET(instance->PreConnect, status, instance); if (settings->KeyboardLayout == KBD_JAPANESE_INPUT_SYSTEM_MS_IME2002) { @@ -119,10 +116,7 @@ BOOL freerdp_connect(freerdp* instance) instance->update->dump_rfx = TRUE; } - if (!rdp->reconnect) - { - IFCALLRET(instance->PostConnect, status, instance); - } + IFCALLRET(instance->PostConnect, status, instance); update_post_connect(instance->update); @@ -356,10 +350,7 @@ BOOL freerdp_disconnect(freerdp* instance) rdp_client_disconnect(rdp); update_post_disconnect(instance->update); - if (!rdp->reconnect) - { - IFCALL(instance->PostDisconnect, instance); - } + IFCALL(instance->PostDisconnect, instance); if (instance->update->pcap_rfx) { @@ -373,17 +364,10 @@ BOOL freerdp_disconnect(freerdp* instance) BOOL freerdp_reconnect(freerdp* instance) { - BOOL status = TRUE; + BOOL status; rdpRdp* rdp = instance->context->rdp; - rdp->reconnect = TRUE; - - status = freerdp_disconnect(instance); - - if (status) - status = freerdp_connect(instance); - - rdp->reconnect = FALSE; + status = rdp_client_reconnect(rdp); return status; } diff --git a/libfreerdp/core/info.c b/libfreerdp/core/info.c index 8c847086d..ea28631a7 100644 --- a/libfreerdp/core/info.c +++ b/libfreerdp/core/info.c @@ -57,22 +57,25 @@ static const char* const INFO_TYPE_LOGON_STRINGS[] = BOOL rdp_read_server_auto_reconnect_cookie(wStream* s, rdpSettings* settings) { ARC_SC_PRIVATE_PACKET* autoReconnectCookie; + autoReconnectCookie = settings->ServerAutoReconnectCookie; - if (Stream_GetRemainingLength(s) < 4+4+4+16) + if (Stream_GetRemainingLength(s) < 28) return FALSE; + Stream_Read_UINT32(s, autoReconnectCookie->cbLen); /* cbLen (4 bytes) */ Stream_Read_UINT32(s, autoReconnectCookie->version); /* version (4 bytes) */ Stream_Read_UINT32(s, autoReconnectCookie->logonId); /* LogonId (4 bytes) */ Stream_Read(s, autoReconnectCookie->arcRandomBits, 16); /* arcRandomBits (16 bytes) */ + if ((settings->PrintReconnectCookie) && (autoReconnectCookie->cbLen > 0)) { - char *base64; - base64 = crypto_base64_encode((BYTE *) autoReconnectCookie, - sizeof(ARC_SC_PRIVATE_PACKET)); - WLog_INFO(TAG, "Reconnect-cookie: %s", base64); + char* base64; + base64 = crypto_base64_encode((BYTE*) autoReconnectCookie, sizeof(ARC_SC_PRIVATE_PACKET)); + WLog_INFO(TAG, "Reconnect-cookie: %s", base64); free(base64); } + return TRUE; } @@ -117,6 +120,7 @@ void rdp_write_client_auto_reconnect_cookie(wStream* s, rdpSettings* settings) /* SecurityVerifier = HMAC(AutoReconnectRandom, ClientRandom) */ hmac = crypto_hmac_new(); + ZeroMemory(nullRandom, sizeof(nullRandom)); crypto_hmac_md5_init(hmac, autoReconnectCookie->securityVerifier, 16); @@ -231,35 +235,37 @@ void rdp_write_extended_info_packet(wStream* s, rdpSettings* settings) cbAutoReconnectLen = (int) settings->ServerAutoReconnectCookie->cbLen; - Stream_Write_UINT16(s, clientAddressFamily); /* clientAddressFamily */ + Stream_Write_UINT16(s, clientAddressFamily); /* clientAddressFamily (2 bytes) */ - Stream_Write_UINT16(s, cbClientAddress + 2); /* cbClientAddress */ + Stream_Write_UINT16(s, cbClientAddress + 2); /* cbClientAddress (2 bytes) */ if (cbClientAddress > 0) Stream_Write(s, clientAddress, cbClientAddress); /* clientAddress */ Stream_Write_UINT16(s, 0); - Stream_Write_UINT16(s, cbClientDir + 2); /* cbClientDir */ + Stream_Write_UINT16(s, cbClientDir + 2); /* cbClientDir (2 bytes) */ if (cbClientDir > 0) Stream_Write(s, clientDir, cbClientDir); /* clientDir */ Stream_Write_UINT16(s, 0); - rdp_write_client_time_zone(s, settings); /* clientTimeZone */ + rdp_write_client_time_zone(s, settings); /* clientTimeZone (172 bytes) */ - Stream_Write_UINT32(s, 0); /* clientSessionId, should be set to 0 */ + Stream_Write_UINT32(s, 0); /* clientSessionId (4 bytes), should be set to 0 */ freerdp_performance_flags_make(settings); - Stream_Write_UINT32(s, settings->PerformanceFlags); /* performanceFlags */ + Stream_Write_UINT32(s, settings->PerformanceFlags); /* performanceFlags (4 bytes) */ - Stream_Write_UINT16(s, cbAutoReconnectLen); /* cbAutoReconnectLen */ + Stream_Write_UINT16(s, cbAutoReconnectLen); /* cbAutoReconnectCookie (2 bytes) */ if (cbAutoReconnectLen > 0) { CryptoHmac hmac; ARC_SC_PRIVATE_PACKET* serverCookie; ARC_CS_PRIVATE_PACKET* clientCookie; - WLog_DBG(TAG, "Sending auto reconnect"); + + WLog_DBG(TAG, "Sending auto reconnect cookie"); + serverCookie = settings->ServerAutoReconnectCookie; clientCookie = settings->ClientAutoReconnectCookie; @@ -268,9 +274,10 @@ void rdp_write_extended_info_packet(wStream* s, rdpSettings* settings) clientCookie->logonId = serverCookie->logonId; hmac = crypto_hmac_new(); + if (!hmac) { - WLog_ERR(TAG, "unable to allocate hmac"); + WLog_ERR(TAG, "unable to allocate hmac"); goto out_free; } @@ -278,7 +285,7 @@ void rdp_write_extended_info_packet(wStream* s, rdpSettings* settings) if (settings->SelectedProtocol == PROTOCOL_RDP) { - crypto_hmac_update(hmac, (BYTE*) (settings->ClientRandom), 32); + crypto_hmac_update(hmac, (BYTE*) settings->ClientRandom, 32); } else { @@ -290,16 +297,20 @@ void rdp_write_extended_info_packet(wStream* s, rdpSettings* settings) 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 }; crypto_hmac_update(hmac, zeros, 32); } + crypto_hmac_final(hmac, clientCookie->securityVerifier, 16); rdp_write_client_auto_reconnect_cookie(s, settings); /* autoReconnectCookie */ + + crypto_hmac_free(hmac); + /* mark as used */ settings->ServerAutoReconnectCookie->cbLen = 0; - crypto_hmac_free(hmac); + + Stream_Write_UINT16(s, 0); /* reserved1 (2 bytes) */ + Stream_Write_UINT16(s, 0); /* reserved2 (2 bytes) */ } - /* reserved1 (2 bytes) */ - /* reserved2 (2 bytes) */ out_free: free(clientAddress); free(clientDir); @@ -527,14 +538,14 @@ void rdp_write_info_packet(wStream* s, rdpSettings* settings) cbWorkingDir = ConvertToUnicode(CP_UTF8, 0, settings->RemoteAssistanceSessionId, -1, &workingDirW, 0) * 2; } - Stream_Write_UINT32(s, 0); /* CodePage */ - Stream_Write_UINT32(s, flags); /* flags */ + Stream_Write_UINT32(s, 0); /* CodePage (4 bytes) */ + Stream_Write_UINT32(s, flags); /* flags (4 bytes) */ - Stream_Write_UINT16(s, cbDomain); /* cbDomain */ - Stream_Write_UINT16(s, cbUserName); /* cbUserName */ - Stream_Write_UINT16(s, cbPassword); /* cbPassword */ - Stream_Write_UINT16(s, cbAlternateShell); /* cbAlternateShell */ - Stream_Write_UINT16(s, cbWorkingDir); /* cbWorkingDir */ + Stream_Write_UINT16(s, cbDomain); /* cbDomain (2 bytes) */ + Stream_Write_UINT16(s, cbUserName); /* cbUserName (2 bytes) */ + Stream_Write_UINT16(s, cbPassword); /* cbPassword (2 bytes) */ + Stream_Write_UINT16(s, cbAlternateShell); /* cbAlternateShell (2 bytes) */ + Stream_Write_UINT16(s, cbWorkingDir); /* cbWorkingDir (2 bytes) */ if (cbDomain > 0) Stream_Write(s, domainW, cbDomain); @@ -594,7 +605,7 @@ BOOL rdp_recv_client_info(rdpRdp* rdp, wStream* s) { if (securityFlags & SEC_REDIRECTION_PKT) { - WLog_ERR(TAG, "Error: SEC_REDIRECTION_PKT unsupported"); + WLog_ERR(TAG, "Error: SEC_REDIRECTION_PKT unsupported"); return FALSE; } @@ -602,7 +613,7 @@ BOOL rdp_recv_client_info(rdpRdp* rdp, wStream* s) { if (!rdp_decrypt(rdp, s, length - 4, securityFlags)) { - WLog_ERR(TAG, "rdp_decrypt failed"); + WLog_ERR(TAG, "rdp_decrypt failed"); return FALSE; } } @@ -755,7 +766,7 @@ BOOL rdp_recv_save_session_info(rdpRdp* rdp, wStream* s) return FALSE; Stream_Read_UINT32(s, infoType); /* infoType (4 bytes) */ - //WLog_ERR(TAG, "%s", INFO_TYPE_LOGON_STRINGS[infoType]); + //WLog_ERR(TAG, "%s", INFO_TYPE_LOGON_STRINGS[infoType]); switch (infoType) { diff --git a/libfreerdp/core/rdp.c b/libfreerdp/core/rdp.c index caff45e48..7bfd31a9b 100644 --- a/libfreerdp/core/rdp.c +++ b/libfreerdp/core/rdp.c @@ -654,6 +654,9 @@ BOOL rdp_recv_server_auto_reconnect_status_pdu(rdpRdp* rdp, wStream* s) return FALSE; Stream_Read_UINT32(s, arcStatus); /* arcStatus (4 bytes) */ + + WLog_WARN(TAG, "AutoReconnectStatus: 0x%04X", arcStatus); + return TRUE; } @@ -1424,29 +1427,60 @@ void rdp_reset(rdpRdp* rdp) bulk_reset(rdp->bulk); - crypto_rc4_free(rdp->rc4_decrypt_key); - rdp->rc4_decrypt_key = NULL; - crypto_rc4_free(rdp->rc4_encrypt_key); - rdp->rc4_encrypt_key = NULL; - crypto_des3_free(rdp->fips_encrypt); - rdp->fips_encrypt = NULL; - crypto_des3_free(rdp->fips_decrypt); - rdp->fips_decrypt = NULL; - crypto_hmac_free(rdp->fips_hmac); - rdp->fips_hmac = NULL; + if (rdp->rc4_decrypt_key) + { + crypto_rc4_free(rdp->rc4_decrypt_key); + rdp->rc4_decrypt_key = NULL; + } + + if (rdp->rc4_encrypt_key) + { + crypto_rc4_free(rdp->rc4_encrypt_key); + rdp->rc4_encrypt_key = NULL; + } + + if (rdp->fips_encrypt) + { + crypto_des3_free(rdp->fips_encrypt); + rdp->fips_encrypt = NULL; + } + + if (rdp->fips_decrypt) + { + crypto_des3_free(rdp->fips_decrypt); + rdp->fips_decrypt = NULL; + } + + if (rdp->fips_hmac) + { + crypto_hmac_free(rdp->fips_hmac); + rdp->fips_hmac = NULL; + } + + if (settings->ServerRandom) + { + free(settings->ServerRandom); + settings->ServerRandom = NULL; + settings->ServerRandomLength = 0; + } + + if (settings->ServerCertificate) + { + free(settings->ServerCertificate); + settings->ServerCertificate = NULL; + } + + if (settings->ClientAddress) + { + free(settings->ClientAddress); + settings->ClientAddress = NULL; + } mcs_free(rdp->mcs); nego_free(rdp->nego); license_free(rdp->license); transport_free(rdp->transport); - free(settings->ServerRandom); - settings->ServerRandom = NULL; - free(settings->ServerCertificate); - settings->ServerCertificate = NULL; - free(settings->ClientAddress); - settings->ClientAddress = NULL; - rdp->transport = transport_new(context); rdp->transport->rdp = rdp; rdp->license = license_new(rdp); diff --git a/libfreerdp/core/rdp.h b/libfreerdp/core/rdp.h index 5397f4176..fb8531b01 100644 --- a/libfreerdp/core/rdp.h +++ b/libfreerdp/core/rdp.h @@ -169,7 +169,6 @@ struct rdp_rdp BYTE fips_decrypt_key[24]; UINT32 errorInfo; UINT32 finalize_sc_pdus; - BOOL reconnect; BOOL disconnect; BOOL resendFocus; BOOL deactivation_reactivation; diff --git a/libfreerdp/core/settings.c b/libfreerdp/core/settings.c index 0eecfa27b..35e9ad709 100644 --- a/libfreerdp/core/settings.c +++ b/libfreerdp/core/settings.c @@ -483,6 +483,7 @@ rdpSettings* freerdp_settings_clone(rdpSettings* settings) _settings->RemoteAssistancePassword = _strdup(settings->RemoteAssistancePassword); /* 1027 */ _settings->RemoteAssistanceRCTicket = _strdup(settings->RemoteAssistanceRCTicket); /* 1028 */ _settings->AuthenticationServiceClass = _strdup(settings->AuthenticationServiceClass); /* 1098 */ + _settings->AllowedTlsCiphers = _strdup(settings->AllowedTlsCiphers); /* 1101 */ _settings->PreconnectionBlob = _strdup(settings->PreconnectionBlob); /* 1155 */ _settings->KerberosKdc = _strdup(settings->KerberosKdc); /* 1344 */ _settings->KerberosRealm = _strdup(settings->KerberosRealm); /* 1345 */ @@ -542,12 +543,19 @@ rdpSettings* freerdp_settings_clone(rdpSettings* settings) { _settings->ServerRandom = (BYTE*) malloc(_settings->ServerRandomLength); CopyMemory(_settings->ServerRandom, settings->ServerRandom, _settings->ServerRandomLength); + _settings->ServerRandomLength = settings->ServerRandomLength; } if (_settings->ClientRandomLength) { _settings->ClientRandom = (BYTE*) malloc(_settings->ClientRandomLength); CopyMemory(_settings->ClientRandom, settings->ClientRandom, _settings->ClientRandomLength); + _settings->ClientRandomLength = settings->ClientRandomLength; + } + + if (settings->RdpServerCertificate) + { + _settings->RdpServerCertificate = certificate_clone(settings->RdpServerCertificate); } _settings->ChannelCount = settings->ChannelCount; @@ -608,9 +616,7 @@ rdpSettings* freerdp_settings_clone(rdpSettings* settings) _settings->StaticChannelCount = settings->StaticChannelCount; _settings->StaticChannelArraySize = settings->StaticChannelArraySize; - _settings->StaticChannelArray = (ADDIN_ARGV**) - malloc(sizeof(ADDIN_ARGV*) * _settings->StaticChannelArraySize); - ZeroMemory(_settings->StaticChannelArray, sizeof(ADDIN_ARGV*) * _settings->StaticChannelArraySize); + _settings->StaticChannelArray = (ADDIN_ARGV**) calloc(_settings->StaticChannelArraySize, sizeof(ADDIN_ARGV*)); for (index = 0; index < _settings->StaticChannelCount; index++) { @@ -619,9 +625,7 @@ rdpSettings* freerdp_settings_clone(rdpSettings* settings) _settings->DynamicChannelCount = settings->DynamicChannelCount; _settings->DynamicChannelArraySize = settings->DynamicChannelArraySize; - _settings->DynamicChannelArray = (ADDIN_ARGV**) - malloc(sizeof(ADDIN_ARGV*) * _settings->DynamicChannelArraySize); - ZeroMemory(_settings->DynamicChannelArray, sizeof(ADDIN_ARGV*) * _settings->DynamicChannelArraySize); + _settings->DynamicChannelArray = (ADDIN_ARGV**) calloc(_settings->DynamicChannelArraySize, sizeof(ADDIN_ARGV*)); for (index = 0; index < _settings->DynamicChannelCount; index++) { @@ -651,7 +655,7 @@ void freerdp_settings_free(rdpSettings* settings) free(settings->MonitorDefArray); free(settings->ClientAddress); free(settings->ClientDir); - free(settings->PermittedTLSCiphers); + free(settings->AllowedTlsCiphers); free(settings->CertificateFile); free(settings->PrivateKeyFile); free(settings->ConnectionFile); diff --git a/libfreerdp/crypto/tls.c b/libfreerdp/crypto/tls.c index 6f8b15202..d3a23a56f 100644 --- a/libfreerdp/crypto/tls.c +++ b/libfreerdp/crypto/tls.c @@ -511,7 +511,7 @@ static CryptoCert tls_get_certificate(rdpTls* tls, BOOL peer) if (!remote_cert) { - WLog_ERR(TAG, "failed to get the server TLS certificate"); + WLog_ERR(TAG, "failed to get the server TLS certificate"); return NULL; } @@ -581,11 +581,13 @@ BOOL tls_prepare(rdpTls* tls, BIO *underlying, SSL_METHOD *method, int options, BOOL tls_prepare(rdpTls* tls, BIO *underlying, const SSL_METHOD *method, int options, BOOL clientMode) #endif { + rdpSettings* settings = tls->settings; + tls->ctx = SSL_CTX_new(method); if (!tls->ctx) { - WLog_ERR(TAG, "SSL_CTX_new failed"); + WLog_ERR(TAG, "SSL_CTX_new failed"); return FALSE; } @@ -594,11 +596,11 @@ BOOL tls_prepare(rdpTls* tls, BIO *underlying, const SSL_METHOD *method, int opt SSL_CTX_set_options(tls->ctx, options); SSL_CTX_set_read_ahead(tls->ctx, 1); - if (tls->settings->PermittedTLSCiphers) + if (settings->AllowedTlsCiphers) { - if (!SSL_CTX_set_cipher_list(tls->ctx, tls->settings->PermittedTLSCiphers)) + if (!SSL_CTX_set_cipher_list(tls->ctx, settings->AllowedTlsCiphers)) { - WLog_ERR(TAG, "SSL_CTX_set_cipher_list %s failed", tls->settings->PermittedTLSCiphers); + WLog_ERR(TAG, "SSL_CTX_set_cipher_list %s failed", settings->AllowedTlsCiphers); return FALSE; } } @@ -607,7 +609,7 @@ BOOL tls_prepare(rdpTls* tls, BIO *underlying, const SSL_METHOD *method, int opt if (BIO_get_ssl(tls->bio, &tls->ssl) < 0) { - WLog_ERR(TAG, "unable to retrieve the SSL of the connection"); + WLog_ERR(TAG, "unable to retrieve the SSL of the connection"); return FALSE; } @@ -645,7 +647,7 @@ int tls_do_handshake(rdpTls* tls, BOOL clientMode) if (fd < 0) { - WLog_ERR(TAG, "unable to retrieve BIO fd"); + WLog_ERR(TAG, "unable to retrieve BIO fd"); return -1; } @@ -669,7 +671,7 @@ int tls_do_handshake(rdpTls* tls, BOOL clientMode) #endif if (status < 0) { - WLog_ERR(TAG, "error during select()"); + WLog_ERR(TAG, "error during select()"); return -1; } } @@ -678,21 +680,21 @@ int tls_do_handshake(rdpTls* tls, BOOL clientMode) cert = tls_get_certificate(tls, clientMode); if (!cert) { - WLog_ERR(TAG, "tls_get_certificate failed to return the server certificate."); + WLog_ERR(TAG, "tls_get_certificate failed to return the server certificate."); return -1; } tls->Bindings = tls_get_channel_bindings(cert->px509); if (!tls->Bindings) { - WLog_ERR(TAG, "unable to retrieve bindings"); + WLog_ERR(TAG, "unable to retrieve bindings"); verify_status = -1; goto out; } if (!crypto_cert_get_public_key(cert, &tls->PublicKey, &tls->PublicKeyLength)) { - WLog_ERR(TAG, "crypto_cert_get_public_key failed to return the server public key."); + WLog_ERR(TAG, "crypto_cert_get_public_key failed to return the server public key."); verify_status = -1; goto out; } @@ -707,7 +709,7 @@ int tls_do_handshake(rdpTls* tls, BOOL clientMode) if (verify_status < 1) { - WLog_ERR(TAG, "certificate not trusted, aborting."); + WLog_ERR(TAG, "certificate not trusted, aborting."); tls_disconnect(tls); verify_status = 0; } @@ -804,14 +806,14 @@ BOOL tls_accept(rdpTls* tls, BIO *underlying, const char* cert_file, const char* if (SSL_use_RSAPrivateKey_file(tls->ssl, privatekey_file, SSL_FILETYPE_PEM) <= 0) { - WLog_ERR(TAG, "SSL_CTX_use_RSAPrivateKey_file failed"); - WLog_ERR(TAG, "PrivateKeyFile: %s", privatekey_file); + WLog_ERR(TAG, "SSL_CTX_use_RSAPrivateKey_file failed"); + WLog_ERR(TAG, "PrivateKeyFile: %s", privatekey_file); return FALSE; } if (SSL_use_certificate_file(tls->ssl, cert_file, SSL_FILETYPE_PEM) <= 0) { - WLog_ERR(TAG, "SSL_use_certificate_file failed"); + WLog_ERR(TAG, "SSL_use_certificate_file failed"); return FALSE; } @@ -1097,7 +1099,7 @@ int tls_verify_certificate(rdpTls* tls, CryptoCert cert, char* hostname, int por if (!bio) { - WLog_ERR(TAG, "BIO_new() failure"); + WLog_ERR(TAG, "BIO_new() failure"); return -1; } @@ -1105,7 +1107,7 @@ int tls_verify_certificate(rdpTls* tls, CryptoCert cert, char* hostname, int por if (status < 0) { - WLog_ERR(TAG, "PEM_write_bio_X509 failure: %d", status); + WLog_ERR(TAG, "PEM_write_bio_X509 failure: %d", status); return -1; } @@ -1117,7 +1119,7 @@ int tls_verify_certificate(rdpTls* tls, CryptoCert cert, char* hostname, int por if (status < 0) { - WLog_ERR(TAG, "failed to read certificate"); + WLog_ERR(TAG, "failed to read certificate"); return -1; } @@ -1138,7 +1140,7 @@ int tls_verify_certificate(rdpTls* tls, CryptoCert cert, char* hostname, int por if (status < 0) { - WLog_ERR(TAG, "failed to read certificate"); + WLog_ERR(TAG, "failed to read certificate"); return -1; } @@ -1152,7 +1154,7 @@ int tls_verify_certificate(rdpTls* tls, CryptoCert cert, char* hostname, int por status = instance->VerifyX509Certificate(instance, pemCert, length, hostname, port, tls->isGatewayTransport); } - WLog_ERR(TAG, "(length = %d) status: %d%s", length, status, pemCert); + WLog_ERR(TAG, "(length = %d) status: %d%s", length, status, pemCert); free(pemCert); BIO_free(bio); @@ -1312,18 +1314,18 @@ int tls_verify_certificate(rdpTls* tls, CryptoCert cert, char* hostname, int por void tls_print_certificate_error(char* hostname, char* fingerprint, char *hosts_file) { - WLog_ERR(TAG, "The host key for %s has changed", hostname); - WLog_ERR(TAG, "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); - WLog_ERR(TAG, "@ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @"); - WLog_ERR(TAG, "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); - WLog_ERR(TAG, "IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!"); - WLog_ERR(TAG, "Someone could be eavesdropping on you right now (man-in-the-middle attack)!"); - WLog_ERR(TAG, "It is also possible that a host key has just been changed."); - WLog_ERR(TAG, "The fingerprint for the host key sent by the remote host is%s", fingerprint); - WLog_ERR(TAG, "Please contact your system administrator."); - WLog_ERR(TAG, "Add correct host key in %s to get rid of this message.", hosts_file); - WLog_ERR(TAG, "Host key for %s has changed and you have requested strict checking.", hostname); - WLog_ERR(TAG, "Host key verification failed."); + WLog_ERR(TAG, "The host key for %s has changed", hostname); + WLog_ERR(TAG, "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); + WLog_ERR(TAG, "@ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @"); + WLog_ERR(TAG, "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); + WLog_ERR(TAG, "IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!"); + WLog_ERR(TAG, "Someone could be eavesdropping on you right now (man-in-the-middle attack)!"); + WLog_ERR(TAG, "It is also possible that a host key has just been changed."); + WLog_ERR(TAG, "The fingerprint for the host key sent by the remote host is%s", fingerprint); + WLog_ERR(TAG, "Please contact your system administrator."); + WLog_ERR(TAG, "Add correct host key in %s to get rid of this message.", hosts_file); + WLog_ERR(TAG, "Host key for %s has changed and you have requested strict checking.", hostname); + WLog_ERR(TAG, "Host key verification failed."); } void tls_print_certificate_name_mismatch_error(char* hostname, char* common_name, char** alt_names, int alt_names_count) @@ -1331,24 +1333,24 @@ void tls_print_certificate_name_mismatch_error(char* hostname, char* common_name int index; assert(NULL != hostname); - WLog_ERR(TAG, "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); - WLog_ERR(TAG, "@ WARNING: CERTIFICATE NAME MISMATCH! @"); - WLog_ERR(TAG, "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); - WLog_ERR(TAG, "The hostname used for this connection (%s) ", hostname); - WLog_ERR(TAG, "does not match %s given in the certificate:", alt_names_count < 1 ? "the name" : "any of the names"); - WLog_ERR(TAG, "Common Name (CN):"); - WLog_ERR(TAG, "\t%s", common_name ? common_name : "no CN found in certificate"); + WLog_ERR(TAG, "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); + WLog_ERR(TAG, "@ WARNING: CERTIFICATE NAME MISMATCH! @"); + WLog_ERR(TAG, "@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@"); + WLog_ERR(TAG, "The hostname used for this connection (%s) ", hostname); + WLog_ERR(TAG, "does not match %s given in the certificate:", alt_names_count < 1 ? "the name" : "any of the names"); + WLog_ERR(TAG, "Common Name (CN):"); + WLog_ERR(TAG, "\t%s", common_name ? common_name : "no CN found in certificate"); if (alt_names_count > 0) { assert(NULL != alt_names); - WLog_ERR(TAG, "Alternative names:"); + WLog_ERR(TAG, "Alternative names:"); for (index = 0; index < alt_names_count; index++) { assert(alt_names[index]); - WLog_ERR(TAG, "\t %s", alt_names[index]); + WLog_ERR(TAG, "\t %s", alt_names[index]); } } - WLog_ERR(TAG, "A valid certificate for the wrong name should NOT be trusted!"); + WLog_ERR(TAG, "A valid certificate for the wrong name should NOT be trusted!"); } rdpTls* tls_new(rdpSettings* settings) From 70e2862c5030691738a808d7165ed9448bb7225e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Moreau?= Date: Fri, 6 Feb 2015 15:44:29 -0500 Subject: [PATCH 4/8] libfreerdp-core: improve client core info debug output --- libfreerdp/core/info.c | 107 +++++++++++++++++++++++++++++------------ libfreerdp/core/info.h | 5 ++ 2 files changed, 81 insertions(+), 31 deletions(-) diff --git a/libfreerdp/core/info.c b/libfreerdp/core/info.c index ea28631a7..c60bee6c1 100644 --- a/libfreerdp/core/info.c +++ b/libfreerdp/core/info.c @@ -30,22 +30,15 @@ #include "info.h" -#define TAG FREERDP_TAG("core") +#define TAG FREERDP_TAG("core.info") -#define INFO_TYPE_LOGON 0x00000000 -#define INFO_TYPE_LOGON_LONG 0x00000001 -#define INFO_TYPE_LOGON_PLAIN_NOTIFY 0x00000002 -#define INFO_TYPE_LOGON_EXTENDED_INF 0x00000003 - -/* -static const char* const INFO_TYPE_LOGON_STRINGS[] = +static const char* const INFO_TYPE_LOGON_STRINGS[4] = { "Logon Info V1", "Logon Info V2", "Logon Plain Notify", "Logon Extended Info" }; -*/ /** * Read Server Auto Reconnect Cookie (ARC_SC_PRIVATE_PACKET).\n @@ -56,6 +49,7 @@ static const char* const INFO_TYPE_LOGON_STRINGS[] = BOOL rdp_read_server_auto_reconnect_cookie(wStream* s, rdpSettings* settings) { + BYTE* p; ARC_SC_PRIVATE_PACKET* autoReconnectCookie; autoReconnectCookie = settings->ServerAutoReconnectCookie; @@ -64,9 +58,23 @@ BOOL rdp_read_server_auto_reconnect_cookie(wStream* s, rdpSettings* settings) return FALSE; Stream_Read_UINT32(s, autoReconnectCookie->cbLen); /* cbLen (4 bytes) */ - Stream_Read_UINT32(s, autoReconnectCookie->version); /* version (4 bytes) */ + Stream_Read_UINT32(s, autoReconnectCookie->version); /* Version (4 bytes) */ Stream_Read_UINT32(s, autoReconnectCookie->logonId); /* LogonId (4 bytes) */ - Stream_Read(s, autoReconnectCookie->arcRandomBits, 16); /* arcRandomBits (16 bytes) */ + Stream_Read(s, autoReconnectCookie->arcRandomBits, 16); /* ArcRandomBits (16 bytes) */ + + if (autoReconnectCookie->cbLen != 28) + { + WLog_ERR(TAG, "ServerAutoReconnectCookie.cbLen != 28"); + return FALSE; + } + + p = autoReconnectCookie->arcRandomBits; + + WLog_DBG(TAG, "ServerAutoReconnectCookie: Version: %d LogonId: %d SecurityVerifier: " + "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", + autoReconnectCookie->version, autoReconnectCookie->logonId, + p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], + p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]); if ((settings->PrintReconnectCookie) && (autoReconnectCookie->cbLen > 0)) { @@ -111,6 +119,7 @@ BOOL rdp_read_client_auto_reconnect_cookie(wStream* s, rdpSettings* settings) void rdp_write_client_auto_reconnect_cookie(wStream* s, rdpSettings* settings) { + BYTE* p; CryptoHmac hmac; BYTE nullRandom[32]; BYTE cryptSecurityVerifier[16]; @@ -133,6 +142,14 @@ void rdp_write_client_auto_reconnect_cookie(wStream* s, rdpSettings* settings) crypto_hmac_final(hmac, cryptSecurityVerifier, 16); crypto_hmac_free(hmac); + p = cryptSecurityVerifier; + + WLog_DBG(TAG, "ClientAutoReconnectCookie: Version: %d LogonId: %d ArcRandomBits: " + "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", + autoReconnectCookie->version, autoReconnectCookie->logonId, + p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], + p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]); + Stream_Write_UINT32(s, autoReconnectCookie->cbLen); /* cbLen (4 bytes) */ Stream_Write_UINT32(s, autoReconnectCookie->version); /* version (4 bytes) */ Stream_Write_UINT32(s, autoReconnectCookie->logonId); /* LogonId (4 bytes) */ @@ -651,40 +668,48 @@ BOOL rdp_recv_logon_info_v1(rdpRdp* rdp, wStream* s) { UINT32 cbDomain; UINT32 cbUserName; + UINT32 SessionId; - if (Stream_GetRemainingLength(s) < (4 + 52 + 4 + 512 + 4)) + if (Stream_GetRemainingLength(s) < 576) return FALSE; Stream_Read_UINT32(s, cbDomain); /* cbDomain (4 bytes) */ Stream_Seek(s, 52); /* domain (52 bytes) */ Stream_Read_UINT32(s, cbUserName); /* cbUserName (4 bytes) */ Stream_Seek(s, 512); /* userName (512 bytes) */ - Stream_Seek_UINT32(s); /* sessionId (4 bytes) */ + Stream_Read_UINT32(s, SessionId); /* SessionId (4 bytes) */ + + WLog_DBG(TAG, "LogonInfoV1: SessionId: 0x%04X", SessionId); return TRUE; } BOOL rdp_recv_logon_info_v2(rdpRdp* rdp, wStream* s) { + UINT16 Version; + UINT32 Size; + UINT32 SessionId; UINT32 cbDomain; UINT32 cbUserName; - if (Stream_GetRemainingLength(s) < (2 + 4 + 4 + 4 + 4 + 558)) + if (Stream_GetRemainingLength(s) < 576) return FALSE; - Stream_Seek_UINT16(s); /* version (2 bytes) */ - Stream_Seek_UINT32(s); /* size (4 bytes) */ - Stream_Seek_UINT32(s); /* sessionId (4 bytes) */ + Stream_Read_UINT16(s, Version); /* Version (2 bytes) */ + Stream_Read_UINT32(s, Size); /* Size (4 bytes) */ + Stream_Read_UINT32(s, SessionId); /* SessionId (4 bytes) */ Stream_Read_UINT32(s, cbDomain); /* cbDomain (4 bytes) */ Stream_Read_UINT32(s, cbUserName); /* cbUserName (4 bytes) */ - Stream_Seek(s, 558); /* pad */ + Stream_Seek(s, 558); /* pad (558 bytes) */ - if (Stream_GetRemainingLength(s) < cbDomain+cbUserName) + if (Stream_GetRemainingLength(s) < (cbDomain + cbUserName)) return FALSE; Stream_Seek(s, cbDomain); /* domain */ Stream_Seek(s, cbUserName); /* userName */ + WLog_DBG(TAG, "LogonInfoV2: SessionId: 0x%04X", SessionId); + return TRUE; } @@ -693,7 +718,9 @@ BOOL rdp_recv_logon_plain_notify(rdpRdp* rdp, wStream* s) if (Stream_GetRemainingLength(s) < 576) return FALSE; - Stream_Seek(s, 576); /* pad */ + Stream_Seek(s, 576); /* pad (576 bytes) */ + + WLog_DBG(TAG, "LogonPlainNotify"); return TRUE; } @@ -709,6 +736,9 @@ BOOL rdp_recv_logon_error_info(rdpRdp* rdp, wStream* s) Stream_Read_UINT32(s, errorNotificationData); /* errorNotificationData (4 bytes) */ Stream_Read_UINT32(s, errorNotificationType); /* errorNotificationType (4 bytes) */ + WLog_DBG(TAG, "LogonErrorInfo: Data: 0x%04X Type: 0x%04X", + errorNotificationData, errorNotificationType); + IFCALL(rdp->instance->LogonErrorInfo, rdp->instance, errorNotificationData, errorNotificationType); return TRUE; @@ -723,9 +753,14 @@ BOOL rdp_recv_logon_info_extended(rdpRdp* rdp, wStream* s) if (Stream_GetRemainingLength(s) < 6) return FALSE; - Stream_Read_UINT16(s, Length); /* The total size in bytes of this structure */ + Stream_Read_UINT16(s, Length); /* Length (2 bytes) */ Stream_Read_UINT32(s, fieldsPresent); /* fieldsPresent (4 bytes) */ + if (Stream_GetRemainingLength(s) < (Length - 6)) + return FALSE; + + WLog_DBG(TAG, "LogonInfoExtended: fieldsPresent: 0x%04X", fieldsPresent); + /* logonFields */ if (fieldsPresent & LOGON_EX_AUTORECONNECTCOOKIE) @@ -735,7 +770,7 @@ BOOL rdp_recv_logon_info_extended(rdpRdp* rdp, wStream* s) Stream_Read_UINT32(s, cbFieldData); /* cbFieldData (4 bytes) */ - if (rdp_read_server_auto_reconnect_cookie(s, rdp->settings) == FALSE) + if (!rdp_read_server_auto_reconnect_cookie(s, rdp->settings)) return FALSE; } @@ -746,14 +781,14 @@ BOOL rdp_recv_logon_info_extended(rdpRdp* rdp, wStream* s) Stream_Read_UINT32(s, cbFieldData); /* cbFieldData (4 bytes) */ - if (rdp_recv_logon_error_info(rdp, s) == FALSE) + if (!rdp_recv_logon_error_info(rdp, s)) return FALSE; } if (Stream_GetRemainingLength(s) < 570) return FALSE; - Stream_Seek(s, 570); /* pad */ + Stream_Seek(s, 570); /* pad (570 bytes) */ return TRUE; } @@ -761,31 +796,41 @@ BOOL rdp_recv_logon_info_extended(rdpRdp* rdp, wStream* s) BOOL rdp_recv_save_session_info(rdpRdp* rdp, wStream* s) { UINT32 infoType; + BOOL status = FALSE; if (Stream_GetRemainingLength(s) < 4) return FALSE; - Stream_Read_UINT32(s, infoType); /* infoType (4 bytes) */ - //WLog_ERR(TAG, "%s", INFO_TYPE_LOGON_STRINGS[infoType]); + Stream_Read_UINT32(s, infoType); /* infoType (4 bytes) */ switch (infoType) { case INFO_TYPE_LOGON: - return rdp_recv_logon_info_v1(rdp, s); + status = rdp_recv_logon_info_v1(rdp, s); + break; case INFO_TYPE_LOGON_LONG: - return rdp_recv_logon_info_v2(rdp, s); + status = rdp_recv_logon_info_v2(rdp, s); + break; case INFO_TYPE_LOGON_PLAIN_NOTIFY: - return rdp_recv_logon_plain_notify(rdp, s); + status = rdp_recv_logon_plain_notify(rdp, s); + break; case INFO_TYPE_LOGON_EXTENDED_INF: - return rdp_recv_logon_info_extended(rdp, s); + status = rdp_recv_logon_info_extended(rdp, s); + break; default: break; } - return TRUE; + if (!status) + { + WLog_DBG(TAG, "SaveSessionInfo error: infoType: %s (%d)", + infoType < 4 ? INFO_TYPE_LOGON_STRINGS[infoType % 4] : "Unknown", infoType); + } + + return status; } diff --git a/libfreerdp/core/info.h b/libfreerdp/core/info.h index 0e98dde3c..f7839188f 100644 --- a/libfreerdp/core/info.h +++ b/libfreerdp/core/info.h @@ -26,6 +26,11 @@ #include +#define INFO_TYPE_LOGON 0x00000000 +#define INFO_TYPE_LOGON_LONG 0x00000001 +#define INFO_TYPE_LOGON_PLAIN_NOTIFY 0x00000002 +#define INFO_TYPE_LOGON_EXTENDED_INF 0x00000003 + /* Client Address Family */ #define ADDRESS_FAMILY_INET 0x0002 #define ADDRESS_FAMILY_INET6 0x0017 From 9a8f87739618b30a8dfc2172c1d99525d7ca1dc1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Moreau?= Date: Fri, 6 Feb 2015 16:37:28 -0500 Subject: [PATCH 5/8] libfreerdp-core: fix auto reconnect cookie security verifier computation --- libfreerdp/core/info.c | 82 +++++++++++++++--------------------------- 1 file changed, 28 insertions(+), 54 deletions(-) diff --git a/libfreerdp/core/info.c b/libfreerdp/core/info.c index c60bee6c1..4e59ee811 100644 --- a/libfreerdp/core/info.c +++ b/libfreerdp/core/info.c @@ -120,29 +120,11 @@ BOOL rdp_read_client_auto_reconnect_cookie(wStream* s, rdpSettings* settings) void rdp_write_client_auto_reconnect_cookie(wStream* s, rdpSettings* settings) { BYTE* p; - CryptoHmac hmac; - BYTE nullRandom[32]; - BYTE cryptSecurityVerifier[16]; ARC_CS_PRIVATE_PACKET* autoReconnectCookie; + autoReconnectCookie = settings->ClientAutoReconnectCookie; - /* SecurityVerifier = HMAC(AutoReconnectRandom, ClientRandom) */ - - hmac = crypto_hmac_new(); - - ZeroMemory(nullRandom, sizeof(nullRandom)); - - crypto_hmac_md5_init(hmac, autoReconnectCookie->securityVerifier, 16); - - if (settings->ClientRandomLength > 0) - crypto_hmac_update(hmac, settings->ClientRandom, settings->ClientRandomLength); - else - crypto_hmac_update(hmac, nullRandom, sizeof(nullRandom)); - - crypto_hmac_final(hmac, cryptSecurityVerifier, 16); - crypto_hmac_free(hmac); - - p = cryptSecurityVerifier; + p = autoReconnectCookie->securityVerifier; WLog_DBG(TAG, "ClientAutoReconnectCookie: Version: %d LogonId: %d ArcRandomBits: " "%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X", @@ -153,7 +135,7 @@ void rdp_write_client_auto_reconnect_cookie(wStream* s, rdpSettings* settings) Stream_Write_UINT32(s, autoReconnectCookie->cbLen); /* cbLen (4 bytes) */ Stream_Write_UINT32(s, autoReconnectCookie->version); /* version (4 bytes) */ Stream_Write_UINT32(s, autoReconnectCookie->logonId); /* LogonId (4 bytes) */ - Stream_Write(s, cryptSecurityVerifier, 16); /* SecurityVerifier */ + Stream_Write(s, autoReconnectCookie->securityVerifier, 16); /* SecurityVerifier (16 bytes) */ } /** @@ -242,7 +224,7 @@ void rdp_write_extended_info_packet(wStream* s, rdpSettings* settings) int cbClientAddress; WCHAR* clientDir = NULL; int cbClientDir; - int cbAutoReconnectLen; + int cbAutoReconnectCookie; clientAddressFamily = settings->IPv6Enabled ? ADDRESS_FAMILY_INET6 : ADDRESS_FAMILY_INET; @@ -250,7 +232,7 @@ void rdp_write_extended_info_packet(wStream* s, rdpSettings* settings) cbClientDir = ConvertToUnicode(CP_UTF8, 0, settings->ClientDir, -1, &clientDir, 0) * 2; - cbAutoReconnectLen = (int) settings->ServerAutoReconnectCookie->cbLen; + cbAutoReconnectCookie = (int) settings->ServerAutoReconnectCookie->cbLen; Stream_Write_UINT16(s, clientAddressFamily); /* clientAddressFamily (2 bytes) */ @@ -273,22 +255,33 @@ void rdp_write_extended_info_packet(wStream* s, rdpSettings* settings) freerdp_performance_flags_make(settings); Stream_Write_UINT32(s, settings->PerformanceFlags); /* performanceFlags (4 bytes) */ - Stream_Write_UINT16(s, cbAutoReconnectLen); /* cbAutoReconnectCookie (2 bytes) */ + Stream_Write_UINT16(s, cbAutoReconnectCookie); /* cbAutoReconnectCookie (2 bytes) */ - if (cbAutoReconnectLen > 0) + if (cbAutoReconnectCookie > 0) { CryptoHmac hmac; + BYTE ClientRandom[32]; + BYTE AutoReconnectRandom[32]; ARC_SC_PRIVATE_PACKET* serverCookie; ARC_CS_PRIVATE_PACKET* clientCookie; - WLog_DBG(TAG, "Sending auto reconnect cookie"); + /* SecurityVerifier = HMAC(AutoReconnectRandom, ClientRandom) */ serverCookie = settings->ServerAutoReconnectCookie; clientCookie = settings->ClientAutoReconnectCookie; - clientCookie->cbLen = serverCookie->cbLen; + clientCookie->cbLen = 28; clientCookie->version = serverCookie->version; clientCookie->logonId = serverCookie->logonId; + ZeroMemory(clientCookie->securityVerifier, 16); + + ZeroMemory(AutoReconnectRandom, sizeof(AutoReconnectRandom)); + CopyMemory(AutoReconnectRandom, serverCookie->arcRandomBits, 16); + + ZeroMemory(ClientRandom, sizeof(ClientRandom)); + + if (settings->SelectedProtocol == PROTOCOL_RDP) + CopyMemory(ClientRandom, settings->ClientRandom, settings->ClientRandomLength); hmac = crypto_hmac_new(); @@ -298,31 +291,12 @@ void rdp_write_extended_info_packet(wStream* s, rdpSettings* settings) goto out_free; } - crypto_hmac_md5_init(hmac, serverCookie->arcRandomBits, 16); - - if (settings->SelectedProtocol == PROTOCOL_RDP) - { - crypto_hmac_update(hmac, (BYTE*) settings->ClientRandom, 32); - } - else - { - /* Anthony Tong's version had 16 zeroes here; I'm not sure why. - * I do know that 16 did not reconnect correctly vs Win2008RDVH, - * and 32 did. - */ - const BYTE zeros[32] = { 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0, - 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0 }; - crypto_hmac_update(hmac, zeros, 32); - } - + crypto_hmac_md5_init(hmac, AutoReconnectRandom, 16); + crypto_hmac_update(hmac, ClientRandom, 32); crypto_hmac_final(hmac, clientCookie->securityVerifier, 16); - - rdp_write_client_auto_reconnect_cookie(s, settings); /* autoReconnectCookie */ - crypto_hmac_free(hmac); - /* mark as used */ - settings->ServerAutoReconnectCookie->cbLen = 0; + rdp_write_client_auto_reconnect_cookie(s, settings); /* autoReconnectCookie */ Stream_Write_UINT16(s, 0); /* reserved1 (2 bytes) */ Stream_Write_UINT16(s, 0); /* reserved2 (2 bytes) */ @@ -369,11 +343,11 @@ BOOL rdp_read_info_packet(wStream* s, rdpSettings* settings) settings->CompressionLevel = CompressionLevel; } - Stream_Read_UINT16(s, cbDomain); /* cbDomain */ - Stream_Read_UINT16(s, cbUserName); /* cbUserName */ - Stream_Read_UINT16(s, cbPassword); /* cbPassword */ - Stream_Read_UINT16(s, cbAlternateShell); /* cbAlternateShell */ - Stream_Read_UINT16(s, cbWorkingDir); /* cbWorkingDir */ + Stream_Read_UINT16(s, cbDomain); /* cbDomain (2 bytes) */ + Stream_Read_UINT16(s, cbUserName); /* cbUserName (2 bytes) */ + Stream_Read_UINT16(s, cbPassword); /* cbPassword (2 bytes) */ + Stream_Read_UINT16(s, cbAlternateShell); /* cbAlternateShell (2 bytes) */ + Stream_Read_UINT16(s, cbWorkingDir); /* cbWorkingDir (2 bytes) */ if (Stream_GetRemainingLength(s) < (size_t) (cbDomain + 2)) return FALSE; From b2d0aa128fe880349e5da31125e3d913fd4dc2f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Moreau?= Date: Fri, 6 Feb 2015 16:55:21 -0500 Subject: [PATCH 6/8] libfreerdp-core: refactor client info pdu functions --- libfreerdp/core/info.c | 130 ++++++++++++++++++++++------------------- libfreerdp/core/info.h | 21 +++---- 2 files changed, 79 insertions(+), 72 deletions(-) diff --git a/libfreerdp/core/info.c b/libfreerdp/core/info.c index 4e59ee811..948206a10 100644 --- a/libfreerdp/core/info.c +++ b/libfreerdp/core/info.c @@ -40,6 +40,46 @@ static const char* const INFO_TYPE_LOGON_STRINGS[4] = "Logon Extended Info" }; +BOOL rdp_compute_client_auto_reconnect_cookie(rdpRdp* rdp) +{ + CryptoHmac hmac; + BYTE ClientRandom[32]; + BYTE AutoReconnectRandom[32]; + ARC_SC_PRIVATE_PACKET* serverCookie; + ARC_CS_PRIVATE_PACKET* clientCookie; + rdpSettings* settings = rdp->settings; + + serverCookie = settings->ServerAutoReconnectCookie; + clientCookie = settings->ClientAutoReconnectCookie; + + clientCookie->cbLen = 28; + clientCookie->version = serverCookie->version; + clientCookie->logonId = serverCookie->logonId; + ZeroMemory(clientCookie->securityVerifier, 16); + + ZeroMemory(AutoReconnectRandom, sizeof(AutoReconnectRandom)); + CopyMemory(AutoReconnectRandom, serverCookie->arcRandomBits, 16); + + ZeroMemory(ClientRandom, sizeof(ClientRandom)); + + if (settings->SelectedProtocol == PROTOCOL_RDP) + CopyMemory(ClientRandom, settings->ClientRandom, settings->ClientRandomLength); + + hmac = crypto_hmac_new(); + + if (!hmac) + return FALSE; + + /* SecurityVerifier = HMAC_MD5(AutoReconnectRandom, ClientRandom) */ + + crypto_hmac_md5_init(hmac, AutoReconnectRandom, 16); + crypto_hmac_update(hmac, ClientRandom, 32); + crypto_hmac_final(hmac, clientCookie->securityVerifier, 16); + crypto_hmac_free(hmac); + + return TRUE; +} + /** * Read Server Auto Reconnect Cookie (ARC_SC_PRIVATE_PACKET).\n * @msdn{cc240540} @@ -47,10 +87,11 @@ static const char* const INFO_TYPE_LOGON_STRINGS[4] = * @param settings settings */ -BOOL rdp_read_server_auto_reconnect_cookie(wStream* s, rdpSettings* settings) +BOOL rdp_read_server_auto_reconnect_cookie(rdpRdp* rdp, wStream* s) { BYTE* p; ARC_SC_PRIVATE_PACKET* autoReconnectCookie; + rdpSettings* settings = rdp->settings; autoReconnectCookie = settings->ServerAutoReconnectCookie; @@ -94,9 +135,11 @@ BOOL rdp_read_server_auto_reconnect_cookie(wStream* s, rdpSettings* settings) * @param settings settings */ -BOOL rdp_read_client_auto_reconnect_cookie(wStream* s, rdpSettings* settings) +BOOL rdp_read_client_auto_reconnect_cookie(rdpRdp* rdp, wStream* s) { ARC_CS_PRIVATE_PACKET* autoReconnectCookie; + rdpSettings* settings = rdp->settings; + autoReconnectCookie = settings->ClientAutoReconnectCookie; if (Stream_GetRemainingLength(s) < 28) @@ -117,10 +160,11 @@ BOOL rdp_read_client_auto_reconnect_cookie(wStream* s, rdpSettings* settings) * @param settings settings */ -void rdp_write_client_auto_reconnect_cookie(wStream* s, rdpSettings* settings) +void rdp_write_client_auto_reconnect_cookie(rdpRdp* rdp, wStream* s) { BYTE* p; ARC_CS_PRIVATE_PACKET* autoReconnectCookie; + rdpSettings* settings = rdp->settings; autoReconnectCookie = settings->ClientAutoReconnectCookie; @@ -145,18 +189,19 @@ void rdp_write_client_auto_reconnect_cookie(wStream* s, rdpSettings* settings) * @param settings settings */ -BOOL rdp_read_extended_info_packet(wStream* s, rdpSettings* settings) +BOOL rdp_read_extended_info_packet(rdpRdp* rdp, wStream* s) { UINT16 clientAddressFamily; UINT16 cbClientAddress; UINT16 cbClientDir; UINT16 cbAutoReconnectLen; + rdpSettings* settings = rdp->settings; if (Stream_GetRemainingLength(s) < 4) return FALSE; - Stream_Read_UINT16(s, clientAddressFamily); /* clientAddressFamily */ - Stream_Read_UINT16(s, cbClientAddress); /* cbClientAddress */ + Stream_Read_UINT16(s, clientAddressFamily); /* clientAddressFamily (2 bytes) */ + Stream_Read_UINT16(s, cbClientAddress); /* cbClientAddress (2 bytes) */ settings->IPv6Enabled = (clientAddressFamily == ADDRESS_FAMILY_INET6 ? TRUE : FALSE); @@ -175,7 +220,7 @@ BOOL rdp_read_extended_info_packet(wStream* s, rdpSettings* settings) if (Stream_GetRemainingLength(s) < 2) return FALSE; - Stream_Read_UINT16(s, cbClientDir); /* cbClientDir */ + Stream_Read_UINT16(s, cbClientDir); /* cbClientDir (2 bytes) */ if (Stream_GetRemainingLength(s) < cbClientDir) return FALSE; @@ -195,14 +240,14 @@ BOOL rdp_read_extended_info_packet(wStream* s, rdpSettings* settings) if (Stream_GetRemainingLength(s) < 10) return FALSE; - Stream_Seek_UINT32(s); /* clientSessionId, should be set to 0 */ - Stream_Read_UINT32(s, settings->PerformanceFlags); /* performanceFlags */ + Stream_Seek_UINT32(s); /* clientSessionId (4 bytes), should be set to 0 */ + Stream_Read_UINT32(s, settings->PerformanceFlags); /* performanceFlags (4 bytes) */ freerdp_performance_flags_split(settings); - Stream_Read_UINT16(s, cbAutoReconnectLen); /* cbAutoReconnectLen */ + Stream_Read_UINT16(s, cbAutoReconnectLen); /* cbAutoReconnectLen (2 bytes) */ if (cbAutoReconnectLen > 0) - return rdp_read_client_auto_reconnect_cookie(s, settings); /* autoReconnectCookie */ + return rdp_read_client_auto_reconnect_cookie(rdp, s); /* autoReconnectCookie */ /* reserved1 (2 bytes) */ /* reserved2 (2 bytes) */ @@ -217,7 +262,7 @@ BOOL rdp_read_extended_info_packet(wStream* s, rdpSettings* settings) * @param settings settings */ -void rdp_write_extended_info_packet(wStream* s, rdpSettings* settings) +void rdp_write_extended_info_packet(rdpRdp* rdp, wStream* s) { int clientAddressFamily; WCHAR* clientAddress = NULL; @@ -225,6 +270,7 @@ void rdp_write_extended_info_packet(wStream* s, rdpSettings* settings) WCHAR* clientDir = NULL; int cbClientDir; int cbAutoReconnectCookie; + rdpSettings* settings = rdp->settings; clientAddressFamily = settings->IPv6Enabled ? ADDRESS_FAMILY_INET6 : ADDRESS_FAMILY_INET; @@ -259,50 +305,14 @@ void rdp_write_extended_info_packet(wStream* s, rdpSettings* settings) if (cbAutoReconnectCookie > 0) { - CryptoHmac hmac; - BYTE ClientRandom[32]; - BYTE AutoReconnectRandom[32]; - ARC_SC_PRIVATE_PACKET* serverCookie; - ARC_CS_PRIVATE_PACKET* clientCookie; + rdp_compute_client_auto_reconnect_cookie(rdp); - /* SecurityVerifier = HMAC(AutoReconnectRandom, ClientRandom) */ - - serverCookie = settings->ServerAutoReconnectCookie; - clientCookie = settings->ClientAutoReconnectCookie; - - clientCookie->cbLen = 28; - clientCookie->version = serverCookie->version; - clientCookie->logonId = serverCookie->logonId; - ZeroMemory(clientCookie->securityVerifier, 16); - - ZeroMemory(AutoReconnectRandom, sizeof(AutoReconnectRandom)); - CopyMemory(AutoReconnectRandom, serverCookie->arcRandomBits, 16); - - ZeroMemory(ClientRandom, sizeof(ClientRandom)); - - if (settings->SelectedProtocol == PROTOCOL_RDP) - CopyMemory(ClientRandom, settings->ClientRandom, settings->ClientRandomLength); - - hmac = crypto_hmac_new(); - - if (!hmac) - { - WLog_ERR(TAG, "unable to allocate hmac"); - goto out_free; - } - - crypto_hmac_md5_init(hmac, AutoReconnectRandom, 16); - crypto_hmac_update(hmac, ClientRandom, 32); - crypto_hmac_final(hmac, clientCookie->securityVerifier, 16); - crypto_hmac_free(hmac); - - rdp_write_client_auto_reconnect_cookie(s, settings); /* autoReconnectCookie */ + rdp_write_client_auto_reconnect_cookie(rdp, s); /* autoReconnectCookie */ Stream_Write_UINT16(s, 0); /* reserved1 (2 bytes) */ Stream_Write_UINT16(s, 0); /* reserved2 (2 bytes) */ } -out_free: free(clientAddress); free(clientDir); } @@ -314,7 +324,7 @@ out_free: * @param settings settings */ -BOOL rdp_read_info_packet(wStream* s, rdpSettings* settings) +BOOL rdp_read_info_packet(rdpRdp* rdp, wStream* s) { UINT32 flags; UINT16 cbDomain; @@ -323,12 +333,13 @@ BOOL rdp_read_info_packet(wStream* s, rdpSettings* settings) UINT16 cbAlternateShell; UINT16 cbWorkingDir; UINT32 CompressionLevel; + rdpSettings* settings = rdp->settings; if (Stream_GetRemainingLength(s) < 18) return FALSE; - Stream_Seek_UINT32(s); /* CodePage */ - Stream_Read_UINT32(s, flags); /* flags */ + Stream_Seek_UINT32(s); /* CodePage (4 bytes ) */ + Stream_Read_UINT32(s, flags); /* flags (4 bytes) */ settings->AudioCapture = ((flags & INFO_AUDIOCAPTURE) ? TRUE : FALSE); settings->AudioPlayback = ((flags & INFO_NOAUDIOPLAYBACK) ? FALSE : TRUE); @@ -400,7 +411,7 @@ BOOL rdp_read_info_packet(wStream* s, rdpSettings* settings) Stream_Seek(s, 2); if (settings->RdpVersion >= 5) - return rdp_read_extended_info_packet(s, settings); /* extraInfo */ + return rdp_read_extended_info_packet(rdp, s); /* extraInfo */ return TRUE; } @@ -412,7 +423,7 @@ BOOL rdp_read_info_packet(wStream* s, rdpSettings* settings) * @param settings settings */ -void rdp_write_info_packet(wStream* s, rdpSettings* settings) +void rdp_write_info_packet(rdpRdp* rdp, wStream* s) { UINT32 flags; WCHAR* domainW = NULL; @@ -426,6 +437,7 @@ void rdp_write_info_packet(wStream* s, rdpSettings* settings) WCHAR* workingDirW = NULL; int cbWorkingDir = 0; BOOL usedPasswordCookie = FALSE; + rdpSettings* settings = rdp->settings; flags = INFO_MOUSE | INFO_UNICODE | @@ -567,7 +579,7 @@ void rdp_write_info_packet(wStream* s, rdpSettings* settings) free(passwordW); if (settings->RdpVersion >= 5) - rdp_write_extended_info_packet(s, settings); /* extraInfo */ + rdp_write_extended_info_packet(rdp, s); /* extraInfo */ } /** @@ -610,7 +622,7 @@ BOOL rdp_recv_client_info(rdpRdp* rdp, wStream* s) } } - return rdp_read_info_packet(s, rdp->settings); + return rdp_read_info_packet(rdp, s); } /** @@ -629,7 +641,7 @@ BOOL rdp_send_client_info(rdpRdp* rdp) s = Stream_New(NULL, 2048); rdp_init_stream(rdp, s); - rdp_write_info_packet(s, rdp->settings); + rdp_write_info_packet(rdp, s); status = rdp_send(rdp, s, MCS_GLOBAL_CHANNEL_ID); @@ -744,7 +756,7 @@ BOOL rdp_recv_logon_info_extended(rdpRdp* rdp, wStream* s) Stream_Read_UINT32(s, cbFieldData); /* cbFieldData (4 bytes) */ - if (!rdp_read_server_auto_reconnect_cookie(s, rdp->settings)) + if (!rdp_read_server_auto_reconnect_cookie(rdp, s)) return FALSE; } diff --git a/libfreerdp/core/info.h b/libfreerdp/core/info.h index f7839188f..82bc9dac2 100644 --- a/libfreerdp/core/info.h +++ b/libfreerdp/core/info.h @@ -72,19 +72,14 @@ #define LOGON_FAILED_OTHER 0x00000002 #define LOGON_WARNING 0x00000003 -void rdp_read_system_time(wStream* s, SYSTEM_TIME* system_time); -void rdp_write_system_time(wStream* s, SYSTEM_TIME* system_time); -void rdp_get_client_time_zone(wStream* s, rdpSettings* settings); -BOOL rdp_read_client_time_zone(wStream* s, rdpSettings* settings); -void rdp_write_client_time_zone(wStream* s, rdpSettings* settings); -BOOL rdp_read_server_auto_reconnect_cookie(wStream* s, rdpSettings* settings); -BOOL rdp_read_client_auto_reconnect_cookie(wStream* s, rdpSettings* settings); -void rdp_write_client_auto_reconnect_cookie(wStream* s, rdpSettings* settings); -void rdp_write_auto_reconnect_cookie(wStream* s, rdpSettings* settings); -BOOL rdp_read_extended_info_packet(wStream* s, rdpSettings* settings); -void rdp_write_extended_info_packet(wStream* s, rdpSettings* settings); -BOOL rdp_read_info_packet(wStream* s, rdpSettings* settings); -void rdp_write_info_packet(wStream* s, rdpSettings* settings); +BOOL rdp_read_server_auto_reconnect_cookie(rdpRdp* rdp, wStream* s); +BOOL rdp_read_client_auto_reconnect_cookie(rdpRdp* rdp, wStream* s); +void rdp_write_client_auto_reconnect_cookie(rdpRdp* rdp, wStream* s); +void rdp_write_auto_reconnect_cookie(rdpRdp* rdp, wStream* s); +BOOL rdp_read_extended_info_packet(rdpRdp* rdp, wStream* s); +void rdp_write_extended_info_packet(rdpRdp* rdp, wStream* s); +BOOL rdp_read_info_packet(rdpRdp* rdp, wStream* s); +void rdp_write_info_packet(rdpRdp* rdp, wStream* s); BOOL rdp_recv_client_info(rdpRdp* rdp, wStream* s); BOOL rdp_send_client_info(rdpRdp* rdp); BOOL rdp_recv_save_session_info(rdpRdp* rdp, wStream* s); From 3258c887a4e32126896efde814f549884a2ded86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Moreau?= Date: Fri, 6 Feb 2015 17:35:14 -0500 Subject: [PATCH 7/8] libfreerdp-core: add channel reconnect --- channels/drdynvc/client/drdynvc_main.c | 9 +++++---- channels/rdpgfx/client/rdpgfx_main.c | 7 ++----- libfreerdp/common/settings.c | 3 +++ libfreerdp/core/client.c | 13 ++++++++----- libfreerdp/core/client.h | 2 +- libfreerdp/core/connection.c | 6 ++++++ 6 files changed, 25 insertions(+), 15 deletions(-) diff --git a/channels/drdynvc/client/drdynvc_main.c b/channels/drdynvc/client/drdynvc_main.c index c499b928c..9b76ebb90 100644 --- a/channels/drdynvc/client/drdynvc_main.c +++ b/channels/drdynvc/client/drdynvc_main.c @@ -1083,7 +1083,7 @@ static void drdynvc_virtual_channel_event_connected(drdynvcPlugin* drdynvc, LPVO static void drdynvc_virtual_channel_event_disconnected(drdynvcPlugin* drdynvc) { - UINT rc; + UINT status; MessageQueue_PostQuit(drdynvc->queue, 0); WaitForSingleObject(drdynvc->thread, INFINITE); @@ -1094,11 +1094,12 @@ static void drdynvc_virtual_channel_event_disconnected(drdynvcPlugin* drdynvc) drdynvc->queue = NULL; drdynvc->thread = NULL; - rc = drdynvc->channelEntryPoints.pVirtualChannelClose(drdynvc->OpenHandle); - if (CHANNEL_RC_OK != rc) + status = drdynvc->channelEntryPoints.pVirtualChannelClose(drdynvc->OpenHandle); + + if (status != CHANNEL_RC_OK) { WLog_ERR(TAG, "pVirtualChannelClose failed with %s [%08X]", - WTSErrorToString(rc), rc); + WTSErrorToString(status), status); } if (drdynvc->data_in) diff --git a/channels/rdpgfx/client/rdpgfx_main.c b/channels/rdpgfx/client/rdpgfx_main.c index 8e98a6f2c..875a84a8e 100644 --- a/channels/rdpgfx/client/rdpgfx_main.c +++ b/channels/rdpgfx/client/rdpgfx_main.c @@ -22,9 +22,6 @@ #endif #include -#include -#include -#include #include #include @@ -1131,8 +1128,8 @@ int DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints) if (!gfx->zgfx) { - free (gfx); - free (context); + free(gfx); + free(context); return -1; } diff --git a/libfreerdp/common/settings.c b/libfreerdp/common/settings.c index 872581431..6c07d1514 100644 --- a/libfreerdp/common/settings.c +++ b/libfreerdp/common/settings.c @@ -503,17 +503,20 @@ ADDIN_ARGV* freerdp_dynamic_channel_clone(ADDIN_ARGV* channel) ADDIN_ARGV* _channel = NULL; _channel = (ADDIN_ARGV*) malloc(sizeof(ADDIN_ARGV)); + if (!_channel) return NULL; _channel->argc = channel->argc; _channel->argv = (char**) malloc(sizeof(char*) * channel->argc); + if (!_channel->argv) goto out_free; for (index = 0; index < _channel->argc; index++) { _channel->argv[index] = _strdup(channel->argv[index]); + if (!_channel->argv[index]) goto out_release_args; } diff --git a/libfreerdp/core/client.c b/libfreerdp/core/client.c index 111a3215e..81f5e6dfe 100644 --- a/libfreerdp/core/client.c +++ b/libfreerdp/core/client.c @@ -202,7 +202,7 @@ int freerdp_channels_post_connect(rdpChannels* channels, freerdp* instance) int hostnameLength; CHANNEL_CLIENT_DATA* pChannelClientData; - channels->is_connected = 1; + channels->connected = 1; hostname = instance->settings->ServerHostname; hostnameLength = (int) strlen(hostname); @@ -413,7 +413,10 @@ int freerdp_channels_disconnect(rdpChannels* channels, freerdp* instance) CHANNEL_OPEN_DATA* pChannelOpenData; CHANNEL_CLIENT_DATA* pChannelClientData; - channels->is_connected = 0; + if (!channels->connected) + return 0; + + channels->connected = 0; freerdp_channels_check_fds(channels, instance); /* tell all libraries we are shutting down */ @@ -498,7 +501,7 @@ UINT VCAPITYPE FreeRDP_VirtualChannelInit(LPVOID* ppInitHandle, PCHANNEL_DEF pCh if (!pChannel) return CHANNEL_RC_BAD_CHANNEL; - if (channels->is_connected) + if (channels->connected) return CHANNEL_RC_ALREADY_CONNECTED; if (versionRequested != VIRTUAL_CHANNEL_VERSION_WIN2000) @@ -571,7 +574,7 @@ UINT VCAPITYPE FreeRDP_VirtualChannelOpen(LPVOID pInitHandle, LPDWORD pOpenHandl if (!pChannelOpenEventProc) return CHANNEL_RC_BAD_PROC; - if (!channels->is_connected) + if (!channels->connected) return CHANNEL_RC_NOT_CONNECTED; pChannelOpenData = freerdp_channels_find_channel_open_data_by_name(channels, pChannelName); @@ -623,7 +626,7 @@ UINT VCAPITYPE FreeRDP_VirtualChannelWrite(DWORD openHandle, LPVOID pData, ULONG if (!channels) return CHANNEL_RC_BAD_CHANNEL_HANDLE; - if (!channels->is_connected) + if (!channels->connected) return CHANNEL_RC_NOT_CONNECTED; if (!pData) diff --git a/libfreerdp/core/client.h b/libfreerdp/core/client.h index 4d4c395f3..7a87c8f33 100644 --- a/libfreerdp/core/client.h +++ b/libfreerdp/core/client.h @@ -96,7 +96,7 @@ struct rdp_channels rdpSettings* settings; /* true once freerdp_channels_post_connect is called */ - int is_connected; + BOOL connected; /* used for locating the channels for a given instance */ freerdp* instance; diff --git a/libfreerdp/core/connection.c b/libfreerdp/core/connection.c index be201b7b0..5841b3dee 100644 --- a/libfreerdp/core/connection.c +++ b/libfreerdp/core/connection.c @@ -388,11 +388,17 @@ BOOL rdp_client_redirect(rdpRdp* rdp) BOOL rdp_client_reconnect(rdpRdp* rdp) { BOOL status; + rdpContext* context = rdp->context; + rdpChannels* channels = context->channels; + freerdp_channels_disconnect(channels, context->instance); rdp_client_disconnect(rdp); status = rdp_client_connect(rdp); + if (status) + freerdp_channels_post_connect(channels, context->instance); + return status; } From 8b524021f19cb0914966a7607773ae2561a4234d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Moreau?= Date: Fri, 6 Feb 2015 17:46:15 -0500 Subject: [PATCH 8/8] xfreerdp: fix egfx multimon on reconnect --- client/X11/xf_gfx.c | 226 ++++++++++++++++++++++++++++++++---------- client/X11/xf_gfx.h | 20 ++++ client/X11/xfreerdp.h | 3 +- 3 files changed, 194 insertions(+), 55 deletions(-) diff --git a/client/X11/xf_gfx.c b/client/X11/xf_gfx.c index 7ac3874c2..22a98acc6 100644 --- a/client/X11/xf_gfx.c +++ b/client/X11/xf_gfx.c @@ -26,58 +26,87 @@ #define TAG CLIENT_TAG("x11") +static int xf_call_for_each_surface(xfContext* xfc, wArrayList* surfaceList, int (*processSurface)(xfContext*, xfGfxSurface*, void*), void* param) +{ + int status = 1; + int surfaceIndex; + RdpgfxClientContext* context = xfc->gfx; + + /* Iterating backwards to be able to remove surfaces from the list */ + surfaceIndex = ArrayList_Count(surfaceList) - 1; + + for (; surfaceIndex >= 0; surfaceIndex--) + { + UINT32 surfaceId; + xfGfxSurface* surface; + + surfaceId = (UINT32) (ULONG_PTR) ArrayList_GetItem(xfc->gfxMappedSurfaceIds, surfaceIndex); + surface = (xfGfxSurface*) context->GetSurfaceData(context, surfaceId); + + if (!surface) + { + ArrayList_RemoveAt(surfaceList, surfaceIndex); + continue; + } + + if (processSurface(xfc, surface, param) < 0) + status = -1; + } + + return status; +} + +static int do_clearInvalidRegion(xfContext* xfc, xfGfxSurface* surface, void* param) +{ + region16_clear(&surface->invalidRegion); + + return 1; +} + int xf_ResetGraphics(RdpgfxClientContext* context, RDPGFX_RESET_GRAPHICS_PDU* resetGraphics) { xfContext* xfc = (xfContext*) context->custom; freerdp_client_codecs_reset(xfc->codecs, FREERDP_CODEC_ALL); - region16_uninit(&(xfc->invalidRegion)); - region16_init(&(xfc->invalidRegion)); + xf_call_for_each_surface(xfc, xfc->gfxMappedSurfaceIds, do_clearInvalidRegion, NULL); xfc->graphicsReset = TRUE; return 1; } -int xf_OutputUpdate(xfContext* xfc) +int xf_OutputUpdate(xfContext* xfc, xfGfxSurface* surface) { UINT16 width, height; - xfGfxSurface* surface; + UINT32 surfaceX, surfaceY; RECTANGLE_16 surfaceRect; const RECTANGLE_16* extents; - if (!xfc->graphicsReset) - return 1; + surfaceX = surface->mapping.output.originX; + surfaceY = surface->mapping.output.originY; - surface = (xfGfxSurface*) xfc->gfx->GetSurfaceData(xfc->gfx, xfc->outputSurfaceId); - - if (!surface) - return -1; - - surfaceRect.left = 0; - surfaceRect.top = 0; - surfaceRect.right = xfc->width; - surfaceRect.bottom = xfc->height; - - region16_intersect_rect(&(xfc->invalidRegion), &(xfc->invalidRegion), &surfaceRect); + surfaceRect.left = surfaceX; + surfaceRect.top = surfaceY; + surfaceRect.right = surfaceX + surface->width; + surfaceRect.bottom = surfaceY + surface->height; XSetClipMask(xfc->display, xfc->gc, None); XSetFunction(xfc->display, xfc->gc, GXcopy); XSetFillStyle(xfc->display, xfc->gc, FillSolid); - if (!region16_is_empty(&(xfc->invalidRegion))) + if (!region16_is_empty(&surface->invalidRegion)) { - extents = region16_extents(&(xfc->invalidRegion)); + extents = region16_extents(&surface->invalidRegion); width = extents->right - extents->left; height = extents->bottom - extents->top; - if (width > xfc->width) - width = xfc->width; + if (width > surface->width) + width = surface->width; - if (height > xfc->height) - height = xfc->height; + if (height > surface->height) + height = surface->height; if (surface->stage) { @@ -89,7 +118,7 @@ int xf_OutputUpdate(xfContext* xfc) if (xfc->settings->SmartSizing || xfc->settings->MultiTouchGestures) { XPutImage(xfc->display, xfc->primary, xfc->gc, surface->image, - extents->left, extents->top, extents->left, extents->top, width, height); + extents->left, extents->top, extents->left + surfaceX, extents->top + surfaceY, width, height); xf_draw_screen(xfc, extents->left, extents->top, width, height); } @@ -97,11 +126,11 @@ int xf_OutputUpdate(xfContext* xfc) #endif { XPutImage(xfc->display, xfc->drawable, xfc->gc, surface->image, - extents->left, extents->top, extents->left, extents->top, width, height); + extents->left, extents->top, extents->left + surfaceX, extents->top + surfaceY, width, height); } } - region16_clear(&(xfc->invalidRegion)); + region16_clear(&surface->invalidRegion); XSetClipMask(xfc->display, xfc->gc, None); XSync(xfc->display, True); @@ -109,8 +138,78 @@ int xf_OutputUpdate(xfContext* xfc) return 1; } +static int xf_UpdateSurface(xfContext* xfc, xfGfxSurface* surface, void* param) +{ + int status = 1; + + switch (surface->mapping.mode) + { + case GFX_MAP_OUTPUT: + status = xf_OutputUpdate(xfc, surface); + break; + + case GFX_MAP_NONE: + break; + } + + return status; +} + +int xf_UpdateSurfaces(xfContext* xfc) +{ + if (!xfc->graphicsReset) + return 1; + + return xf_call_for_each_surface(xfc, xfc->gfxMappedSurfaceIds, xf_UpdateSurface, NULL); +} + +BOOL xf_MappedSurfaceRect(xfContext* xfc, xfGfxSurface* surface, RECTANGLE_16* rect) +{ + BOOL mapped = FALSE; + + switch (surface->mapping.mode) + { + case GFX_MAP_OUTPUT: + mapped = TRUE; + rect->left = surface->mapping.output.originX; + rect->top = surface->mapping.output.originY; + rect->right = surface->mapping.output.originX + surface->width; + rect->bottom = surface->mapping.output.originY + surface->height; + break; + + case GFX_MAP_NONE: + break; + } + + return mapped; +} + +static int do_OutputExpose(xfContext* xfc, xfGfxSurface* surface, void* param) +{ + RECTANGLE_16 surfaceRect; + RECTANGLE_16 intersection; + RECTANGLE_16* invalidRect = param; + + if (!xf_MappedSurfaceRect(xfc, surface, &surfaceRect)) + return -1; + + if (rectangles_intersection(invalidRect, &surfaceRect, &intersection)) + { + /* Invalid rects are specified relative to surface origin */ + intersection.left -= surfaceRect.left; + intersection.top -= surfaceRect.top; + intersection.right -= surfaceRect.left; + intersection.bottom -= surfaceRect.top; + + region16_union_rect(&surface->invalidRegion, &surface->invalidRegion, &intersection); + } + + return 1; +} + int xf_OutputExpose(xfContext* xfc, int x, int y, int width, int height) { + int status = 1; RECTANGLE_16 invalidRect; invalidRect.left = x; @@ -118,11 +217,13 @@ int xf_OutputExpose(xfContext* xfc, int x, int y, int width, int height) invalidRect.right = x + width; invalidRect.bottom = y + height; - region16_union_rect(&(xfc->invalidRegion), &(xfc->invalidRegion), &invalidRect); + if (xf_call_for_each_surface(xfc, xfc->gfxMappedSurfaceIds, do_OutputExpose, &invalidRect) < 0) + status = -1; - xf_OutputUpdate(xfc); + if (xf_UpdateSurfaces(xfc) < 0) + status = -1; - return 1; + return status; } int xf_StartFrame(RdpgfxClientContext* context, RDPGFX_START_FRAME_PDU* startFrame) @@ -138,7 +239,7 @@ int xf_EndFrame(RdpgfxClientContext* context, RDPGFX_END_FRAME_PDU* endFrame) { xfContext* xfc = (xfContext*) context->custom; - xf_OutputUpdate(xfc); + xf_UpdateSurfaces(xfc); xfc->inGfxFrame = FALSE; @@ -163,10 +264,10 @@ int xf_SurfaceCommand_Uncompressed(xfContext* xfc, RdpgfxClientContext* context, invalidRect.right = cmd->right; invalidRect.bottom = cmd->bottom; - region16_union_rect(&(xfc->invalidRegion), &(xfc->invalidRegion), &invalidRect); + region16_union_rect(&surface->invalidRegion, &surface->invalidRegion, &invalidRect); if (!xfc->inGfxFrame) - xf_OutputUpdate(xfc); + xf_UpdateSurfaces(xfc); return 1; } @@ -238,7 +339,7 @@ int xf_SurfaceCommand_RemoteFX(xfContext* xfc, RdpgfxClientContext* context, RDP nXDst, nYDst, nWidth, nHeight, tile->data, PIXEL_FORMAT_XRGB32, 64 * 4, 0, 0, NULL); - region16_union_rect(&(xfc->invalidRegion), &(xfc->invalidRegion), &updateRects[j]); + region16_union_rect(&surface->invalidRegion, &surface->invalidRegion, &updateRects[j]); } region16_uninit(&updateRegion); @@ -249,7 +350,7 @@ int xf_SurfaceCommand_RemoteFX(xfContext* xfc, RdpgfxClientContext* context, RDP region16_uninit(&clippingRects); if (!xfc->inGfxFrame) - xf_OutputUpdate(xfc); + xf_UpdateSurfaces(xfc); return 1; } @@ -284,10 +385,10 @@ int xf_SurfaceCommand_ClearCodec(xfContext* xfc, RdpgfxClientContext* context, R invalidRect.right = cmd->right; invalidRect.bottom = cmd->bottom; - region16_union_rect(&(xfc->invalidRegion), &(xfc->invalidRegion), &invalidRect); + region16_union_rect(&surface->invalidRegion, &surface->invalidRegion, &invalidRect); if (!xfc->inGfxFrame) - xf_OutputUpdate(xfc); + xf_UpdateSurfaces(xfc); return 1; } @@ -316,10 +417,10 @@ int xf_SurfaceCommand_Planar(xfContext* xfc, RdpgfxClientContext* context, RDPGF invalidRect.right = cmd->right; invalidRect.bottom = cmd->bottom; - region16_union_rect(&(xfc->invalidRegion), &(xfc->invalidRegion), &invalidRect); + region16_union_rect(&surface->invalidRegion, &surface->invalidRegion, &invalidRect); if (!xfc->inGfxFrame) - xf_OutputUpdate(xfc); + xf_UpdateSurfaces(xfc); return 1; } @@ -364,11 +465,11 @@ int xf_SurfaceCommand_H264(xfContext* xfc, RdpgfxClientContext* context, RDPGFX_ for (i = 0; i < meta->numRegionRects; i++) { - region16_union_rect(&(xfc->invalidRegion), &(xfc->invalidRegion), (RECTANGLE_16*) &(meta->regionRects[i])); + region16_union_rect(&surface->invalidRegion, &surface->invalidRegion, (RECTANGLE_16*) &(meta->regionRects[i])); } if (!xfc->inGfxFrame) - xf_OutputUpdate(xfc); + xf_UpdateSurfaces(xfc); return 1; } @@ -397,10 +498,10 @@ int xf_SurfaceCommand_Alpha(xfContext* xfc, RdpgfxClientContext* context, RDPGFX invalidRect.right = cmd->right; invalidRect.bottom = cmd->bottom; - region16_union_rect(&(xfc->invalidRegion), &(xfc->invalidRegion), &invalidRect); + region16_union_rect(&surface->invalidRegion, &surface->invalidRegion, &invalidRect); if (!xfc->inGfxFrame) - xf_OutputUpdate(xfc); + xf_UpdateSurfaces(xfc); return 1; } @@ -487,7 +588,7 @@ int xf_SurfaceCommand_Progressive(xfContext* xfc, RdpgfxClientContext* context, surface->scanline, nXDst, nYDst, nWidth, nHeight, tile->data, PIXEL_FORMAT_XRGB32, 64 * 4, nXSrc, nYSrc, NULL); - region16_union_rect(&(xfc->invalidRegion), &(xfc->invalidRegion), &updateRects[j]); + region16_union_rect(&surface->invalidRegion, &surface->invalidRegion, &updateRects[j]); } region16_uninit(&updateRegion); @@ -496,7 +597,7 @@ int xf_SurfaceCommand_Progressive(xfContext* xfc, RdpgfxClientContext* context, region16_uninit(&clippingRects); if (!xfc->inGfxFrame) - xf_OutputUpdate(xfc); + xf_UpdateSurfaces(xfc); return 1; } @@ -607,6 +708,10 @@ int xf_CreateSurface(RdpgfxClientContext* context, RDPGFX_CREATE_SURFACE_PDU* cr (char*) surface->stage, surface->width, surface->height, xfc->scanline_pad, surface->stageStep); } + surface->mapping.mode = GFX_MAP_NONE; + + region16_init(&surface->invalidRegion); + context->SetSurfaceData(context, surface->surfaceId, (void*) surface); return 1; @@ -624,9 +729,11 @@ int xf_DeleteSurface(RdpgfxClientContext* context, RDPGFX_DELETE_SURFACE_PDU* de XFree(surface->image); _aligned_free(surface->data); _aligned_free(surface->stage); + region16_uninit(&surface->invalidRegion); free(surface); } + ArrayList_Remove(xfc->gfxMappedSurfaceIds, (void*) (ULONG_PTR) deleteSurface->surfaceId); context->SetSurfaceData(context, deleteSurface->surfaceId, NULL); if (xfc->codecs->progressive) @@ -673,11 +780,11 @@ int xf_SolidFill(RdpgfxClientContext* context, RDPGFX_SOLID_FILL_PDU* solidFill) freerdp_image_fill(surface->data, surface->format, surface->scanline, rect->left, rect->top, nWidth, nHeight, color); - region16_union_rect(&(xfc->invalidRegion), &(xfc->invalidRegion), &invalidRect); + region16_union_rect(&surface->invalidRegion, &surface->invalidRegion, &invalidRect); } if (!xfc->inGfxFrame) - xf_OutputUpdate(xfc); + xf_UpdateSurfaces(xfc); return 1; } @@ -733,11 +840,11 @@ int xf_SurfaceToSurface(RdpgfxClientContext* context, RDPGFX_SURFACE_TO_SURFACE_ invalidRect.right = destPt->x + rectSrc->right; invalidRect.bottom = destPt->y + rectSrc->bottom; - region16_union_rect(&(xfc->invalidRegion), &(xfc->invalidRegion), &invalidRect); + region16_union_rect(&surfaceDst->invalidRegion, &surfaceDst->invalidRegion, &invalidRect); } if (!xfc->inGfxFrame) - xf_OutputUpdate(xfc); + xf_UpdateSurfaces(xfc); return 1; } @@ -818,11 +925,11 @@ int xf_CacheToSurface(RdpgfxClientContext* context, RDPGFX_CACHE_TO_SURFACE_PDU* invalidRect.right = destPt->x + cacheEntry->width - 1; invalidRect.bottom = destPt->y + cacheEntry->height - 1; - region16_union_rect(&(xfc->invalidRegion), &(xfc->invalidRegion), &invalidRect); + region16_union_rect(&surface->invalidRegion, &surface->invalidRegion, &invalidRect); } if (!xfc->inGfxFrame) - xf_OutputUpdate(xfc); + xf_UpdateSurfaces(xfc); return 1; } @@ -851,9 +958,18 @@ int xf_EvictCacheEntry(RdpgfxClientContext* context, RDPGFX_EVICT_CACHE_ENTRY_PD int xf_MapSurfaceToOutput(RdpgfxClientContext* context, RDPGFX_MAP_SURFACE_TO_OUTPUT_PDU* surfaceToOutput) { + xfGfxSurface* surface; xfContext* xfc = (xfContext*) context->custom; - xfc->outputSurfaceId = surfaceToOutput->surfaceId; + surface = (xfGfxSurface*) context->GetSurfaceData(context, surfaceToOutput->surfaceId); + + surface->mapping.mode = GFX_MAP_OUTPUT; + surface->mapping.output.originX = surfaceToOutput->outputOriginX; + surface->mapping.output.originY = surfaceToOutput->outputOriginY; + + region16_clear(&surface->invalidRegion); + + ArrayList_Add(xfc->gfxMappedSurfaceIds, (void*) (ULONG_PTR) surfaceToOutput->surfaceId); return 1; } @@ -884,10 +1000,14 @@ void xf_graphics_pipeline_init(xfContext* xfc, RdpgfxClientContext* gfx) gfx->MapSurfaceToOutput = xf_MapSurfaceToOutput; gfx->MapSurfaceToWindow = xf_MapSurfaceToWindow; - region16_init(&(xfc->invalidRegion)); + xfc->gfxMappedSurfaceIds = ArrayList_New(FALSE); } void xf_graphics_pipeline_uninit(xfContext* xfc, RdpgfxClientContext* gfx) { - region16_uninit(&(xfc->invalidRegion)); + if (xfc->gfxMappedSurfaceIds) + { + ArrayList_Free(xfc->gfxMappedSurfaceIds); + xfc->gfxMappedSurfaceIds = NULL; + } } diff --git a/client/X11/xf_gfx.h b/client/X11/xf_gfx.h index 06039a8cf..b20ea6727 100644 --- a/client/X11/xf_gfx.h +++ b/client/X11/xf_gfx.h @@ -25,6 +25,13 @@ #include +enum xf_gfx_mapping_mode +{ + GFX_MAP_NONE, + GFX_MAP_OUTPUT +}; +typedef enum xf_gfx_mapping_mode xfGfxMappingMode; + struct xf_gfx_surface { UINT16 surfaceId; @@ -37,6 +44,19 @@ struct xf_gfx_surface int scanline; int stageStep; UINT32 format; + struct + { + xfGfxMappingMode mode; + union + { + struct + { + UINT32 originX; + UINT32 originY; + } output; + }; + } mapping; + REGION16 invalidRegion; }; typedef struct xf_gfx_surface xfGfxSurface; diff --git a/client/X11/xfreerdp.h b/client/X11/xfreerdp.h index 7ae3a373e..a12f4b297 100644 --- a/client/X11/xfreerdp.h +++ b/client/X11/xfreerdp.h @@ -122,10 +122,9 @@ struct xf_context UINT32 bitmap_size; BYTE* bitmap_buffer; BYTE* primary_buffer; - REGION16 invalidRegion; BOOL inGfxFrame; BOOL graphicsReset; - UINT16 outputSurfaceId; + wArrayList* gfxMappedSurfaceIds; BOOL frame_begin; UINT16 frame_x1;