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] 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)