From ad7be5a4ee1ede7c7e9634e19b994732c72a847a Mon Sep 17 00:00:00 2001 From: Martin Haimberger Date: Fri, 25 Oct 2013 05:41:01 -0700 Subject: [PATCH 01/16] improved wlog so new logger inhertit the loglevel of the root logger --- winpr/libwinpr/utils/wlog/wlog.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/winpr/libwinpr/utils/wlog/wlog.c b/winpr/libwinpr/utils/wlog/wlog.c index c40ca2b23..6df27a5ea 100644 --- a/winpr/libwinpr/utils/wlog/wlog.c +++ b/winpr/libwinpr/utils/wlog/wlog.c @@ -261,7 +261,7 @@ int WLog_ParseName(wLog* log, LPCSTR name) return 0; } -wLog* WLog_New(LPCSTR name) +wLog* WLog_New(LPCSTR name , wLog* rootLogger) { wLog* log; char* env; @@ -284,7 +284,12 @@ wLog* WLog_New(LPCSTR name) log->Appender = NULL; - log->Level = WLOG_WARN; + if (rootLogger) { + log->Level = rootLogger->Level; + } else { + log->Level = WLOG_WARN; + } + nSize = GetEnvironmentVariableA("WLOG_LEVEL", NULL, 0); @@ -351,7 +356,7 @@ wLog* WLog_GetRoot() if (!g_RootLog) { - g_RootLog = WLog_New(""); + g_RootLog = WLog_New("",NULL); g_RootLog->IsRoot = TRUE; logAppenderType = WLOG_APPENDER_CONSOLE; @@ -430,7 +435,7 @@ wLog* WLog_Get(LPCSTR name) if (!log) { - log = WLog_New(name); + log = WLog_New(name,root); WLog_AddChild(root, log); } From e51b9b0c039b2fe238316a1b8db2e512cea7d7b2 Mon Sep 17 00:00:00 2001 From: Bernhard Miklautz Date: Thu, 31 Oct 2013 10:19:55 +0100 Subject: [PATCH 02/16] winpr-thread: fixed issue with commands starting with / --- winpr/libwinpr/thread/process.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/winpr/libwinpr/thread/process.c b/winpr/libwinpr/thread/process.c index e88c3e323..514d1152c 100644 --- a/winpr/libwinpr/thread/process.c +++ b/winpr/libwinpr/thread/process.c @@ -140,7 +140,7 @@ char* FindApplicationPath(char* application) return NULL; if (application[0] == '/') - return application; + return strdup(application); nSize = GetEnvironmentVariableA("PATH", NULL, 0); @@ -183,7 +183,7 @@ BOOL _CreateProcessExA(HANDLE hToken, DWORD dwLogonFlags, int numArgs; LPSTR* pArgs; char** envp; - char* filename; + char* filename = NULL; WINPR_THREAD* thread; WINPR_PROCESS* process; WINPR_ACCESS_TOKEN* token; From 9f42b41f4e5eca35fcf95818e0de9f471b6962b4 Mon Sep 17 00:00:00 2001 From: Bernhard Miklautz Date: Thu, 31 Oct 2013 10:43:59 +0100 Subject: [PATCH 03/16] winpr/thread: use _strdup instead of strdup --- winpr/libwinpr/thread/process.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/winpr/libwinpr/thread/process.c b/winpr/libwinpr/thread/process.c index 514d1152c..f27567b9a 100644 --- a/winpr/libwinpr/thread/process.c +++ b/winpr/libwinpr/thread/process.c @@ -140,7 +140,7 @@ char* FindApplicationPath(char* application) return NULL; if (application[0] == '/') - return strdup(application); + return _strdup(application); nSize = GetEnvironmentVariableA("PATH", NULL, 0); From 813a26a2122f20deed91ae62521201dcc44c7d5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Moreau?= Date: Mon, 4 Nov 2013 12:40:29 -0500 Subject: [PATCH 04/16] libfreerdp-core: change transport thread --- libfreerdp/core/transport.c | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/libfreerdp/core/transport.c b/libfreerdp/core/transport.c index cac2080f1..659a2cb9c 100644 --- a/libfreerdp/core/transport.c +++ b/libfreerdp/core/transport.c @@ -727,7 +727,6 @@ int transport_write(rdpTransport* transport, wStream* s) return status; } - void transport_get_fds(rdpTransport* transport, void** rfds, int* rcount) { void* pfd; @@ -955,7 +954,7 @@ static void* transport_client_thread(void* arg) { DWORD status; DWORD nCount; - HANDLE events[32]; + HANDLE handles[8]; freerdp* instance; rdpContext* context; rdpTransport* transport; @@ -969,21 +968,32 @@ static void* transport_client_thread(void* arg) context = instance->context; assert(NULL != instance->context); + + nCount = 0; + handles[nCount++] = transport->stopEvent; + handles[nCount++] = transport->connectedEvent; + + status = WaitForMultipleObjects(nCount, handles, FALSE, INFINITE); + + if (status == WAIT_OBJECT_0) + { + ExitThread(0); + return NULL; + } while (1) { nCount = 0; - events[nCount++] = transport->stopEvent; - events[nCount] = transport->connectedEvent; + handles[nCount++] = transport->stopEvent; - status = WaitForMultipleObjects(nCount + 1, events, FALSE, INFINITE); + status = WaitForMultipleObjects(nCount, handles, FALSE, INFINITE); if (status == WAIT_OBJECT_0) break; - transport_get_read_handles(transport, (HANDLE*) &events, &nCount); + transport_get_read_handles(transport, (HANDLE*) &handles, &nCount); - status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE); + status = WaitForMultipleObjects(nCount, handles, FALSE, INFINITE); if (status == WAIT_OBJECT_0) break; @@ -993,7 +1003,6 @@ static void* transport_client_thread(void* arg) } ExitThread(0); - return NULL; } From 1f31fd9ae170bf8e85c2f0cc2c7a528e479f74c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Moreau?= Date: Mon, 4 Nov 2013 14:16:59 -0500 Subject: [PATCH 05/16] libfreerdp-core: fix deadlock in transport thread --- libfreerdp/core/transport.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/libfreerdp/core/transport.c b/libfreerdp/core/transport.c index 659a2cb9c..deb9a5c9c 100644 --- a/libfreerdp/core/transport.c +++ b/libfreerdp/core/transport.c @@ -986,11 +986,6 @@ static void* transport_client_thread(void* arg) nCount = 0; handles[nCount++] = transport->stopEvent; - status = WaitForMultipleObjects(nCount, handles, FALSE, INFINITE); - - if (status == WAIT_OBJECT_0) - break; - transport_get_read_handles(transport, (HANDLE*) &handles, &nCount); status = WaitForMultipleObjects(nCount, handles, FALSE, INFINITE); From 3d339b04d977b97562c73690f4b6104389459142 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Moreau?= Date: Mon, 4 Nov 2013 15:52:29 -0500 Subject: [PATCH 06/16] libfreerdp-core: modify parsing functions to return int instead of BOOL to propagate session redirection return code --- libfreerdp/core/connection.c | 41 ++++++++++++++------------ libfreerdp/core/connection.h | 6 ++-- libfreerdp/core/license.c | 28 ++++++++++-------- libfreerdp/core/license.h | 2 +- libfreerdp/core/rdp.c | 21 ++++++------- libfreerdp/core/rdp.h | 2 +- libfreerdp/core/redirection.c | 55 ++++++++++++++++++++++------------- libfreerdp/core/redirection.h | 3 +- libfreerdp/core/transport.c | 7 +++++ 9 files changed, 94 insertions(+), 71 deletions(-) diff --git a/libfreerdp/core/connection.c b/libfreerdp/core/connection.c index 7cdf86be4..220c1352c 100644 --- a/libfreerdp/core/connection.c +++ b/libfreerdp/core/connection.c @@ -598,15 +598,19 @@ BOOL rdp_client_connect_mcs_channel_join_confirm(rdpRdp* rdp, wStream* s) return TRUE; } -BOOL rdp_client_connect_license(rdpRdp* rdp, wStream* s) +int rdp_client_connect_license(rdpRdp* rdp, wStream* s) { - if (!license_recv(rdp->license, s)) - return FALSE; + int status; + + status = license_recv(rdp->license, s); + + if (status < 0) + return status; if (rdp->license->state == LICENSE_STATE_ABORTED) { fprintf(stderr, "license connection sequence aborted.\n"); - return FALSE; + return -1; } if (rdp->license->state == LICENSE_STATE_COMPLETED) @@ -614,10 +618,10 @@ BOOL rdp_client_connect_license(rdpRdp* rdp, wStream* s) rdp_client_transition_to_state(rdp, CONNECTION_STATE_CAPABILITIES_EXCHANGE); } - return TRUE; + return 0; } -BOOL rdp_client_connect_demand_active(rdpRdp* rdp, wStream* s) +int rdp_client_connect_demand_active(rdpRdp* rdp, wStream* s) { BYTE* mark; UINT16 width; @@ -631,24 +635,23 @@ BOOL rdp_client_connect_demand_active(rdpRdp* rdp, wStream* s) if (!rdp_recv_demand_active(rdp, s)) { UINT16 channelId; + Stream_SetPointer(s, mark); rdp_recv_get_active_header(rdp, s, &channelId); + /* Was Stream_Seek(s, RDP_PACKET_HEADER_MAX_LENGTH); * but the headers aren't always that length, * so that could result in a bad offset. */ - if (!rdp_recv_out_of_sequence_pdu(rdp, s)) - return FALSE; - - return TRUE; + return rdp_recv_out_of_sequence_pdu(rdp, s); } if (rdp->disconnect) - return TRUE; + return 0; if (!rdp_send_confirm_active(rdp)) - return FALSE; + return -1; input_register_client_callbacks(rdp->input); @@ -666,7 +669,7 @@ BOOL rdp_client_connect_demand_active(rdpRdp* rdp, wStream* s) return rdp_client_connect_finalize(rdp); } -BOOL rdp_client_connect_finalize(rdpRdp* rdp) +int rdp_client_connect_finalize(rdpRdp* rdp) { /** * [MS-RDPBCGR] 1.3.1.1 - 8. @@ -675,13 +678,13 @@ BOOL rdp_client_connect_finalize(rdpRdp* rdp) */ if (!rdp_send_client_synchronize_pdu(rdp)) - return FALSE; + return -1; if (!rdp_send_client_control_pdu(rdp, CTRLACTION_COOPERATE)) - return FALSE; + return -1; if (!rdp_send_client_control_pdu(rdp, CTRLACTION_REQUEST_CONTROL)) - return FALSE; + return -1; /** * [MS-RDPBCGR] 2.2.1.17 * Client persistent key list must be sent if a bitmap is @@ -692,13 +695,13 @@ BOOL rdp_client_connect_finalize(rdpRdp* rdp) if (!rdp->deactivation_reactivation && rdp->settings->BitmapCachePersistEnabled) { if (!rdp_send_client_persistent_key_list_pdu(rdp)) - return FALSE; + return -1; } if (!rdp_send_client_font_list_pdu(rdp, FONTLIST_FIRST | FONTLIST_LAST)) - return FALSE; + return -1; - return TRUE; + return 0; } int rdp_client_transition_to_state(rdpRdp* rdp, int state) diff --git a/libfreerdp/core/connection.h b/libfreerdp/core/connection.h index b23e398cc..828e79227 100644 --- a/libfreerdp/core/connection.h +++ b/libfreerdp/core/connection.h @@ -52,9 +52,9 @@ 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); BOOL rdp_client_connect_mcs_channel_join_confirm(rdpRdp* rdp, wStream* s); -BOOL rdp_client_connect_license(rdpRdp* rdp, wStream* s); -BOOL rdp_client_connect_demand_active(rdpRdp* rdp, wStream* s); -BOOL rdp_client_connect_finalize(rdpRdp* rdp); +int rdp_client_connect_license(rdpRdp* rdp, wStream* s); +int rdp_client_connect_demand_active(rdpRdp* rdp, wStream* s); +int rdp_client_connect_finalize(rdpRdp* rdp); int rdp_client_transition_to_state(rdpRdp* rdp, int state); BOOL rdp_server_accept_nego(rdpRdp* rdp, wStream* s); diff --git a/libfreerdp/core/license.c b/libfreerdp/core/license.c index 04de4d81e..e26e5e0fd 100644 --- a/libfreerdp/core/license.c +++ b/libfreerdp/core/license.c @@ -229,7 +229,7 @@ BOOL license_send(rdpLicense* license, wStream* s, BYTE type) * @return if the operation completed successfully */ -BOOL license_recv(rdpLicense* license, wStream* s) +int license_recv(rdpLicense* license, wStream* s) { BYTE flags; BYTE bMsgType; @@ -241,37 +241,41 @@ BOOL license_recv(rdpLicense* license, wStream* s) if (!rdp_read_header(license->rdp, s, &length, &channelId)) { fprintf(stderr, "Incorrect RDP header.\n"); - return FALSE; + return -1; } if (!rdp_read_security_header(s, &securityFlags)) - return FALSE; + return -1; if (securityFlags & SEC_ENCRYPT) { if (!rdp_decrypt(license->rdp, s, length - 4, securityFlags)) { fprintf(stderr, "rdp_decrypt failed\n"); - return FALSE; + return -1; } } if (!(securityFlags & SEC_LICENSE_PKT)) { + int status; + if (!(securityFlags & SEC_ENCRYPT)) Stream_Rewind(s, RDP_SECURITY_HEADER_LENGTH); - if (rdp_recv_out_of_sequence_pdu(license->rdp, s) != TRUE) + status = rdp_recv_out_of_sequence_pdu(license->rdp, s); + + if (status < 0) { fprintf(stderr, "Unexpected license packet.\n"); - return FALSE; + return status; } - return TRUE; + return 0; } if (!license_read_preamble(s, &bMsgType, &flags, &wMsgSize)) /* preamble (4 bytes) */ - return FALSE; + return -1; DEBUG_LICENSE("Receiving %s Packet", LICENSE_MESSAGE_STRINGS[bMsgType & 0x1F]); @@ -279,13 +283,13 @@ BOOL license_recv(rdpLicense* license, wStream* s) { case LICENSE_REQUEST: if (!license_read_license_request_packet(license, s)) - return FALSE; + return -1; license_send_new_license_request_packet(license); break; case PLATFORM_CHALLENGE: if (!license_read_platform_challenge_packet(license, s)) - return FALSE; + return -1; license_send_platform_challenge_response_packet(license); break; @@ -299,7 +303,7 @@ BOOL license_recv(rdpLicense* license, wStream* s) case ERROR_ALERT: if (!license_read_error_alert_packet(license, s)) - return FALSE; + return -1; break; default: @@ -307,7 +311,7 @@ BOOL license_recv(rdpLicense* license, wStream* s) return FALSE; } - return TRUE; + return 0; } void license_generate_randoms(rdpLicense* license) diff --git a/libfreerdp/core/license.h b/libfreerdp/core/license.h index 423b85a3f..516604f81 100644 --- a/libfreerdp/core/license.h +++ b/libfreerdp/core/license.h @@ -200,7 +200,7 @@ struct rdp_license SCOPE_LIST* ScopeList; }; -BOOL license_recv(rdpLicense* license, wStream* s); +int license_recv(rdpLicense* license, wStream* s); BOOL license_send(rdpLicense* license, wStream* s, BYTE type); wStream* license_send_stream_init(rdpLicense* license); diff --git a/libfreerdp/core/rdp.c b/libfreerdp/core/rdp.c index d40bc5672..69e964e18 100644 --- a/libfreerdp/core/rdp.c +++ b/libfreerdp/core/rdp.c @@ -672,18 +672,18 @@ int rdp_recv_data_pdu(rdpRdp* rdp, wStream* s) return 0; } -BOOL rdp_recv_out_of_sequence_pdu(rdpRdp* rdp, wStream* s) +int rdp_recv_out_of_sequence_pdu(rdpRdp* rdp, wStream* s) { UINT16 type; UINT16 length; UINT16 channelId; if (!rdp_read_share_control_header(s, &length, &type, &channelId)) - return FALSE; + return -1; if (type == PDU_TYPE_DATA) { - return (rdp_recv_data_pdu(rdp, s) < 0) ? FALSE : TRUE; + return rdp_recv_data_pdu(rdp, s); } else if (type == PDU_TYPE_SERVER_REDIRECTION) { @@ -691,7 +691,7 @@ BOOL rdp_recv_out_of_sequence_pdu(rdpRdp* rdp, wStream* s) } else { - return FALSE; + return -1; } } @@ -815,8 +815,8 @@ static int rdp_recv_tpkt_pdu(rdpRdp* rdp, wStream* s) * - no share control header, nor the 2 byte pad */ Stream_Rewind(s, 2); - rdp_recv_enhanced_security_redirection_packet(rdp, s); - return 1; /* 1 = redirection */ + + return rdp_recv_enhanced_security_redirection_packet(rdp, s); } } @@ -854,8 +854,7 @@ static int rdp_recv_tpkt_pdu(rdpRdp* rdp, wStream* s) break; case PDU_TYPE_SERVER_REDIRECTION: - if (!rdp_recv_enhanced_security_redirection_packet(rdp, s)) - return -1; + return rdp_recv_enhanced_security_redirection_packet(rdp, s); break; default: @@ -928,13 +927,11 @@ static int rdp_recv_callback(rdpTransport* transport, wStream* s, void* extra) break; case CONNECTION_STATE_LICENSING: - if (!rdp_client_connect_license(rdp, s)) - status = -1; + status = rdp_client_connect_license(rdp, s); break; case CONNECTION_STATE_CAPABILITIES_EXCHANGE: - if (!rdp_client_connect_demand_active(rdp, s)) - status = -1; + status = rdp_client_connect_demand_active(rdp, s); break; case CONNECTION_STATE_FINALIZATION: diff --git a/libfreerdp/core/rdp.h b/libfreerdp/core/rdp.h index c5b9d1c86..9fece7007 100644 --- a/libfreerdp/core/rdp.h +++ b/libfreerdp/core/rdp.h @@ -191,7 +191,7 @@ BOOL rdp_send(rdpRdp* rdp, wStream* s, UINT16 channel_id); int rdp_send_channel_data(rdpRdp* rdp, int channel_id, BYTE* data, int size); -BOOL rdp_recv_out_of_sequence_pdu(rdpRdp* rdp, wStream* s); +int rdp_recv_out_of_sequence_pdu(rdpRdp* rdp, wStream* s); void rdp_set_blocking_mode(rdpRdp* rdp, BOOL blocking); int rdp_check_fds(rdpRdp* rdp); diff --git a/libfreerdp/core/redirection.c b/libfreerdp/core/redirection.c index c1722d2e3..6dbdd9e6b 100644 --- a/libfreerdp/core/redirection.c +++ b/libfreerdp/core/redirection.c @@ -175,7 +175,7 @@ BOOL rdp_recv_server_redirection_pdu(rdpRdp* rdp, wStream* s) rdpRedirection* redirection = rdp->redirection; if (Stream_GetRemainingLength(s) < 12) - return FALSE; + return -1; Stream_Read_UINT16(s, flags); /* flags (2 bytes) */ Stream_Read_UINT16(s, length); /* length (2 bytes) */ @@ -192,18 +192,18 @@ BOOL rdp_recv_server_redirection_pdu(rdpRdp* rdp, wStream* s) if (redirection->flags & LB_TARGET_NET_ADDRESS) { if (!rdp_redirection_read_string(s, &(redirection->TargetNetAddress))) - return FALSE; + return -1; } if (redirection->flags & LB_LOAD_BALANCE_INFO) { if (Stream_GetRemainingLength(s) < 4) - return FALSE; + return -1; Stream_Read_UINT32(s, redirection->LoadBalanceInfoLength); if (Stream_GetRemainingLength(s) < redirection->LoadBalanceInfoLength) - return FALSE; + return -1; redirection->LoadBalanceInfo = (BYTE*) malloc(redirection->LoadBalanceInfoLength); Stream_Read(s, redirection->LoadBalanceInfo, redirection->LoadBalanceInfoLength); @@ -216,7 +216,7 @@ BOOL rdp_recv_server_redirection_pdu(rdpRdp* rdp, wStream* s) if (redirection->flags & LB_USERNAME) { if (!rdp_redirection_read_string(s, &(redirection->Username))) - return FALSE; + return -1; WLog_Print(redirection->log, WLOG_DEBUG, "Username: %s", redirection->Username); } @@ -233,7 +233,7 @@ BOOL rdp_recv_server_redirection_pdu(rdpRdp* rdp, wStream* s) { /* Note: length (hopefully) includes double zero termination */ if (Stream_GetRemainingLength(s) < 4) - return FALSE; + return -1; Stream_Read_UINT32(s, redirection->PasswordLength); redirection->Password = (BYTE*) malloc(redirection->PasswordLength); @@ -248,7 +248,7 @@ BOOL rdp_recv_server_redirection_pdu(rdpRdp* rdp, wStream* s) if (redirection->flags & LB_TARGET_FQDN) { if (!rdp_redirection_read_string(s, &(redirection->TargetFQDN))) - return FALSE; + return -1; WLog_Print(redirection->log, WLOG_DEBUG, "TargetFQDN: %s", redirection->TargetFQDN); } @@ -256,7 +256,7 @@ BOOL rdp_recv_server_redirection_pdu(rdpRdp* rdp, wStream* s) if (redirection->flags & LB_TARGET_NETBIOS_NAME) { if (!rdp_redirection_read_string(s, &(redirection->TargetNetBiosName))) - return FALSE; + return -1; WLog_Print(redirection->log, WLOG_DEBUG, "TargetNetBiosName: %s", redirection->TargetNetBiosName); } @@ -264,12 +264,12 @@ BOOL rdp_recv_server_redirection_pdu(rdpRdp* rdp, wStream* s) if (redirection->flags & LB_CLIENT_TSV_URL) { if (Stream_GetRemainingLength(s) < 4) - return FALSE; + return -1; Stream_Read_UINT32(s, redirection->TsvUrlLength); if (Stream_GetRemainingLength(s) < redirection->TsvUrlLength) - return FALSE; + return -1; redirection->TsvUrl = (BYTE*) malloc(redirection->TsvUrlLength); Stream_Read(s, redirection->TsvUrl, redirection->TsvUrlLength); @@ -287,7 +287,7 @@ BOOL rdp_recv_server_redirection_pdu(rdpRdp* rdp, wStream* s) UINT32 targetNetAddressesLength; if (Stream_GetRemainingLength(s) < 8) - return FALSE; + return -1; Stream_Read_UINT32(s, targetNetAddressesLength); @@ -309,24 +309,37 @@ BOOL rdp_recv_server_redirection_pdu(rdpRdp* rdp, wStream* s) } if (!Stream_SafeSeek(s, 8)) /* pad (8 bytes) */ - return FALSE; + return -1; if (redirection->flags & LB_NOREDIRECT) - return TRUE; - else - return rdp_client_redirect(rdp); + return 0; + + return rdp_client_redirect(rdp); } -BOOL rdp_recv_redirection_packet(rdpRdp* rdp, wStream* s) +int rdp_recv_redirection_packet(rdpRdp* rdp, wStream* s) { - return rdp_recv_server_redirection_pdu(rdp, s); + int status = 0; + status = rdp_recv_server_redirection_pdu(rdp, s); + return status; } -BOOL rdp_recv_enhanced_security_redirection_packet(rdpRdp* rdp, wStream* s) +int rdp_recv_enhanced_security_redirection_packet(rdpRdp* rdp, wStream* s) { - return Stream_SafeSeek(s, 2) && /* pad2Octets (2 bytes) */ - rdp_recv_server_redirection_pdu(rdp, s) && - Stream_SafeSeek(s, 1); /* pad2Octets (1 byte) */ + int status = 0; + + if (!Stream_SafeSeek(s, 2)) /* pad2Octets (2 bytes) */ + return -1; + + status = rdp_recv_server_redirection_pdu(rdp, s); + + if (status < 0) + return status; + + if (!Stream_SafeSeek(s, 1)) /* pad2Octets (1 byte) */ + return -1; + + return status; } rdpRedirection* redirection_new() diff --git a/libfreerdp/core/redirection.h b/libfreerdp/core/redirection.h index d8f6a6584..4451027eb 100644 --- a/libfreerdp/core/redirection.h +++ b/libfreerdp/core/redirection.h @@ -50,8 +50,7 @@ struct rdp_redirection char** TargetNetAddresses; }; -BOOL rdp_recv_redirection_packet(rdpRdp* rdp, wStream* s); -BOOL rdp_recv_enhanced_security_redirection_packet(rdpRdp* rdp, wStream* s); +int rdp_recv_enhanced_security_redirection_packet(rdpRdp* rdp, wStream* s); int rdp_redirection_apply_settings(rdpRdp* rdp); diff --git a/libfreerdp/core/transport.c b/libfreerdp/core/transport.c index deb9a5c9c..af6a7d0f6 100644 --- a/libfreerdp/core/transport.c +++ b/libfreerdp/core/transport.c @@ -969,6 +969,8 @@ static void* transport_client_thread(void* arg) context = instance->context; assert(NULL != instance->context); + WLog_Print(transport->log, WLOG_DEBUG, "Starting transport thread"); + nCount = 0; handles[nCount++] = transport->stopEvent; handles[nCount++] = transport->connectedEvent; @@ -977,10 +979,13 @@ static void* transport_client_thread(void* arg) if (status == WAIT_OBJECT_0) { + WLog_Print(transport->log, WLOG_DEBUG, "Terminating transport thread"); ExitThread(0); return NULL; } + WLog_Print(transport->log, WLOG_DEBUG, "Asynchronous transport activated"); + while (1) { nCount = 0; @@ -997,6 +1002,8 @@ static void* transport_client_thread(void* arg) break; } + WLog_Print(transport->log, WLOG_DEBUG, "Terminating transport thread"); + ExitThread(0); return NULL; } From 870e52ed1d6255c0ff692d03df333e4335bc564e Mon Sep 17 00:00:00 2001 From: Zhang Zhaolong Date: Tue, 5 Nov 2013 10:52:17 +0800 Subject: [PATCH 07/16] Add cliprdr on windows. File clipping is not supported yet. --- channels/cliprdr/client/cliprdr_format.c | 1 + channels/cliprdr/client/cliprdr_main.c | 13 +- client/Windows/wf_cliprdr.c | 544 ++++++++++++++++++++++- client/Windows/wf_cliprdr.h | 34 ++ client/Windows/wf_interface.c | 14 + client/Windows/wf_interface.h | 2 + include/freerdp/client/cliprdr.h | 20 +- include/freerdp/message.h | 4 +- libfreerdp/utils/event.c | 6 + 9 files changed, 622 insertions(+), 16 deletions(-) diff --git a/channels/cliprdr/client/cliprdr_format.c b/channels/cliprdr/client/cliprdr_format.c index b3c8fdcd7..a32ce8e49 100644 --- a/channels/cliprdr/client/cliprdr_format.c +++ b/channels/cliprdr/client/cliprdr_format.c @@ -227,6 +227,7 @@ void cliprdr_process_format_list(cliprdrPlugin* cliprdr, wStream* s, UINT32 data cb_event->raw_format_data = (BYTE*) malloc(dataLen); memcpy(cb_event->raw_format_data, Stream_Pointer(s), dataLen); cb_event->raw_format_data_size = dataLen; + cb_event->raw_format_unicode = (msgFlags & CB_ASCII_NAMES) ? FALSE : TRUE; } if (cliprdr->use_long_format_names) diff --git a/channels/cliprdr/client/cliprdr_main.c b/channels/cliprdr/client/cliprdr_main.c index 8475b5c74..16520be9a 100644 --- a/channels/cliprdr/client/cliprdr_main.c +++ b/channels/cliprdr/client/cliprdr_main.c @@ -110,6 +110,7 @@ static void cliprdr_process_general_capability(cliprdrPlugin* cliprdr, wStream* { UINT32 version; UINT32 generalFlags; + RDP_CB_CLIP_CAPS *caps_event; Stream_Read_UINT32(s, version); /* version (4 bytes) */ Stream_Read_UINT32(s, generalFlags); /* generalFlags (4 bytes) */ @@ -120,6 +121,9 @@ static void cliprdr_process_general_capability(cliprdrPlugin* cliprdr, wStream* cliprdr_print_general_capability_flags(generalFlags); #endif + caps_event = (RDP_CB_CLIP_CAPS *)freerdp_event_new(CliprdrChannel_Class, CliprdrChannel_ClipCaps, NULL, NULL); + caps_event->capabilities = generalFlags; + if (generalFlags & CB_USE_LONG_FORMAT_NAMES) cliprdr->use_long_format_names = TRUE; @@ -133,6 +137,9 @@ static void cliprdr_process_general_capability(cliprdrPlugin* cliprdr, wStream* cliprdr->can_lock_clipdata = TRUE; cliprdr->received_caps = TRUE; + + svc_plugin_send_event((rdpSvcPlugin *)cliprdr, (wMessage *)caps_event); + } static void cliprdr_process_clip_caps(cliprdrPlugin* cliprdr, wStream* s, UINT16 length, UINT16 flags) @@ -188,14 +195,14 @@ static void cliprdr_send_clip_caps(cliprdrPlugin* cliprdr) static void cliprdr_process_monitor_ready(cliprdrPlugin* cliprdr, wStream* s, UINT16 length, UINT16 flags) { - wMessage* event; + RDP_CB_MONITOR_READY_EVENT* event; if (cliprdr->received_caps) cliprdr_send_clip_caps(cliprdr); - event = freerdp_event_new(CliprdrChannel_Class, CliprdrChannel_MonitorReady, NULL, NULL); + event = (RDP_CB_MONITOR_READY_EVENT *)freerdp_event_new(CliprdrChannel_Class, CliprdrChannel_MonitorReady, NULL, NULL); - svc_plugin_send_event((rdpSvcPlugin*) cliprdr, event); + svc_plugin_send_event((rdpSvcPlugin*) cliprdr, (wMessage *)event); } static void cliprdr_process_receive(rdpSvcPlugin* plugin, wStream* s) diff --git a/client/Windows/wf_cliprdr.c b/client/Windows/wf_cliprdr.c index 78bb02dd4..1cd11aaae 100644 --- a/client/Windows/wf_cliprdr.c +++ b/client/Windows/wf_cliprdr.c @@ -21,6 +21,7 @@ #include "config.h" #endif +#include #include #include @@ -29,54 +30,575 @@ #include "wf_cliprdr.h" +/* this macro will update _p pointer */ +#define Read_UINT32(_p, _v) do { _v = \ + (UINT32)(*_p) + \ + (((UINT32)(*(_p + 1))) << 8) + \ + (((UINT32)(*(_p + 2))) << 16) + \ + (((UINT32)(*(_p + 3))) << 24); \ + _p += 4; } while (0) + +/* this macro will NOT update _p pointer */ +#define Write_UINT32(_p, _v) do { \ + *(_p) = (_v) & 0xFF; \ + *(_p + 1) = ((_v) >> 8) & 0xFF; \ + *(_p + 2) = ((_v) >> 16) & 0xFF; \ + *(_p + 3) = ((_v) >> 24) & 0xFF; } while (0) + + +static UINT32 get_local_format_id_by_name(cliprdrContext *cliprdr, void *format_name) +{ + formatMapping *map; + int i; + + for (i = 0; i < cliprdr->map_size; i++) { + map = &cliprdr->format_mappings[i]; + if ((cliprdr->capabilities & CAPS_USE_LONG_FORMAT_NAMES) != 0) { + if (map->name) { + if (memcmp(map->name, format_name, wcslen((LPCWSTR)format_name)) == 0) + return map->local_format_id; + } + } + } + + return 0; +} + +static UINT32 get_remote_format_id(cliprdrContext *cliprdr, UINT32 local_format) +{ + formatMapping *map; + int i; + + for (i = 0; i < cliprdr->map_size; i++) { + map = &cliprdr->format_mappings[i]; + if (map->local_format_id == local_format) { + return map->remote_format_id; + } + } + + return 0; +} + +static void map_ensure_capacity(cliprdrContext *cliprdr) +{ + if (cliprdr->map_size >= cliprdr->map_capacity) { + cliprdr->format_mappings = (formatMapping *)realloc(cliprdr->format_mappings, + cliprdr->map_capacity * 2); + cliprdr->map_capacity *= 2; + } +} + +static void clear_format_map(cliprdrContext *cliprdr) +{ + formatMapping *map; + int i; + + if (cliprdr->format_mappings) { + for (i = 0; i < cliprdr->map_size; i++) { + map = &cliprdr->format_mappings[i]; + map->remote_format_id = 0; + map->local_format_id = 0; + + if (map->name) { + free(map->name); + map->name = NULL; + } + } + } + + cliprdr->map_size= 0; +} + +static void cliprdr_send_format_list(cliprdrContext *cliprdr) +{ + RDP_CB_FORMAT_LIST_EVENT *cliprdr_event; + BYTE *format_data; + int format = 0; + int data_size; + int format_count; + int len = 0; + int namelen; + + if (!OpenClipboard(cliprdr->hwndClipboard)) { + DEBUG_CLIPRDR("OpenClipboard failed with 0x%x", GetLastError()); + return; + } + + format_count = CountClipboardFormats(); + data_size = format_count * (4 + MAX_PATH * 2); + + format_data = (BYTE *)calloc(1, data_size); + assert(format_data != NULL); + + while (format = EnumClipboardFormats(format)) { + Write_UINT32(format_data + len, format); + len += 4; + if ((cliprdr->capabilities & CAPS_USE_LONG_FORMAT_NAMES) != 0) { + if (format >= CF_MAX) { + namelen = GetClipboardFormatNameW(format, (LPWSTR)(format_data + len), MAX_PATH); + len += namelen * sizeof(WCHAR); + } + len += 2; /* end of Unicode string */ + } else { + ZeroMemory(format_data + len, 32); + if (format >= CF_MAX) { + static wchar_t wName[MAX_PATH] = {0}; + + ZeroMemory(wName, MAX_PATH*2); + GetClipboardFormatNameW(format, wName, MAX_PATH); + memcpy(format_data + len, wName, 32); /* truncate the long name to 32 bytes */ + } + len += 32; + } + } + + CloseClipboard(); + + cliprdr_event = (RDP_CB_FORMAT_LIST_EVENT *) freerdp_event_new(CliprdrChannel_Class, + CliprdrChannel_FormatList, NULL, NULL); + + cliprdr_event->raw_format_data = (BYTE *)calloc(1, len); + assert(cliprdr_event->raw_format_data != NULL); + + CopyMemory(cliprdr_event->raw_format_data, format_data, len); + cliprdr_event->raw_format_data_size = len; + + free(format_data); + + freerdp_channels_send_event(cliprdr->channels, (wMessage *) cliprdr_event); +} + +int cliprdr_send_data_request(cliprdrContext *cliprdr, UINT32 format) +{ + RDP_CB_DATA_REQUEST_EVENT *cliprdr_event; + int ret; + + cliprdr_event = (RDP_CB_DATA_REQUEST_EVENT *)freerdp_event_new(CliprdrChannel_Class, + CliprdrChannel_DataRequest, NULL, NULL); + + if (!cliprdr_event) + return -1; + + cliprdr_event->format = get_remote_format_id(cliprdr, format); + + ret = freerdp_channels_send_event(cliprdr->channels, (wMessage *)cliprdr_event); + + if (ret != 0) + return -1; + + WaitForSingleObject(cliprdr->response_data_event, INFINITE); + ResetEvent(cliprdr->response_data_event); + + return 0; +} + +static LRESULT CALLBACK cliprdr_proc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) +{ + static cliprdrContext *cliprdr = NULL; + + switch (Msg) { + case WM_CREATE: + cliprdr = (cliprdrContext *)((CREATESTRUCT *)lParam)->lpCreateParams; + cliprdr->hwndNextViewer = SetClipboardViewer(hWnd); + + if (cliprdr->hwndNextViewer == NULL && GetLastError() != 0) { + DEBUG_CLIPRDR("error: SetClipboardViewer failed with 0x%0x.", GetLastError()); + } + cliprdr->hwndClipboard = hWnd; + break; + + case WM_CLOSE: + ChangeClipboardChain(hWnd, cliprdr->hwndNextViewer); + break; + + case WM_CHANGECBCHAIN: + if (cliprdr->hwndNextViewer == (HWND)wParam) { + cliprdr->hwndNextViewer = (HWND)lParam; + } else if (cliprdr->hwndNextViewer != NULL) { + SendMessage(cliprdr->hwndNextViewer, Msg, wParam, lParam); + } + break; + + case WM_DRAWCLIPBOARD: + if (cliprdr->channel_initialized) { + if (GetClipboardOwner() != cliprdr->hwndClipboard) { + if (!cliprdr->hmem) { + cliprdr->hmem = GlobalFree(cliprdr->hmem); + } + cliprdr_send_format_list(cliprdr); + } + } + if (cliprdr->hwndNextViewer != NULL && cliprdr->hwndNextViewer != hWnd) + SendMessage(cliprdr->hwndNextViewer, Msg, wParam, lParam); + break; + + case WM_RENDERALLFORMATS: + /* discard all contexts in clipboard */ + if (!OpenClipboard(cliprdr->hwndClipboard)) { + DEBUG_CLIPRDR("OpenClipboard failed with 0x%x", GetLastError()); + break; + } + EmptyClipboard(); + CloseClipboard(); + break; + + case WM_RENDERFORMAT: + if (cliprdr_send_data_request(cliprdr, (UINT32)wParam) != 0) { + DEBUG_CLIPRDR("error: cliprdr_send_data_request failed."); + break; + } + + if (SetClipboardData(wParam, cliprdr->hmem) == NULL) { + DEBUG_CLIPRDR("SetClipboardData failed with 0x%x", GetLastError()); + cliprdr->hmem = GlobalFree(cliprdr->hmem); + } + /* Note: GlobalFree() is not needed when success */ + break; + + case WM_CLIPBOARDUPDATE: + case WM_DESTROYCLIPBOARD: + case WM_ASKCBFORMATNAME: + case WM_HSCROLLCLIPBOARD: + case WM_PAINTCLIPBOARD: + case WM_SIZECLIPBOARD: + case WM_VSCROLLCLIPBOARD: + default: + return DefWindowProc(hWnd, Msg, wParam, lParam); + } + + return 0; +} +static int create_cliprdr_window(cliprdrContext *cliprdr) +{ + WNDCLASSEX wnd_cls; + + ZeroMemory(&wnd_cls, sizeof(WNDCLASSEX)); + wnd_cls.cbSize = sizeof(WNDCLASSEX); + wnd_cls.style = CS_OWNDC; + wnd_cls.lpfnWndProc = cliprdr_proc; + wnd_cls.cbClsExtra = 0; + wnd_cls.cbWndExtra = 0; + wnd_cls.hIcon = NULL; + wnd_cls.hCursor = NULL; + wnd_cls.hbrBackground = NULL; + wnd_cls.lpszMenuName = NULL; + wnd_cls.lpszClassName = L"ClipboardHiddenMessageProcessor"; + wnd_cls.hInstance = GetModuleHandle(NULL); + wnd_cls.hIconSm = NULL; + RegisterClassEx(&wnd_cls); + + cliprdr->hwndClipboard = CreateWindowEx(WS_EX_LEFT, + L"ClipboardHiddenMessageProcessor", + L"rdpclip", + 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, GetModuleHandle(NULL), cliprdr); + + if (cliprdr->hwndClipboard == NULL) { + DEBUG_CLIPRDR("error: CreateWindowEx failed with %x.", GetLastError()); + return -1; + } + + return 0; +} + +static void *cliprdr_thread_func(void *arg) +{ + cliprdrContext *cliprdr = (cliprdrContext *)arg; + BOOL mcode; + MSG msg; + int ret; + HRESULT result; + + if ((ret = create_cliprdr_window(cliprdr)) != 0) { + DEBUG_CLIPRDR("error: create clipboard window failed."); + return NULL; + } + + while ((mcode = GetMessage(&msg, 0, 0, 0) != 0)) { + if (mcode == -1) { + DEBUG_CLIPRDR("error: clipboard thread GetMessage failed."); + break; + } else { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + } + + return NULL; +} + void wf_cliprdr_init(wfContext* wfc, rdpChannels* channels) { + cliprdrContext *cliprdr; + wfc->cliprdr_context = (cliprdrContext *) calloc(1, sizeof(cliprdrContext)); + cliprdr = (cliprdrContext *) wfc->cliprdr_context; + assert(cliprdr != NULL); + + cliprdr->channels = channels; + cliprdr->channel_initialized = FALSE; + + cliprdr->map_capacity = 32; + cliprdr->map_size = 0; + + cliprdr->format_mappings = (formatMapping *)calloc(1, sizeof(formatMapping) * cliprdr->map_capacity); + assert(cliprdr->format_mappings != NULL); + + cliprdr->response_data_event = CreateEvent(NULL, TRUE, FALSE, L"response_data_event"); + assert(cliprdr->response_data_event != NULL); + + cliprdr->cliprdr_thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)cliprdr_thread_func, cliprdr, 0, NULL); + assert(cliprdr->cliprdr_thread != NULL); + + return; } void wf_cliprdr_uninit(wfContext* wfc) { + cliprdrContext *cliprdr = (cliprdrContext *) wfc->cliprdr_context; + if (!cliprdr) + return; + + if (cliprdr->hwndClipboard) + PostMessage(cliprdr->hwndClipboard, WM_QUIT, 0, 0); + + if (cliprdr->cliprdr_thread) { + WaitForSingleObject(cliprdr->cliprdr_thread, INFINITE); + CloseHandle(cliprdr->cliprdr_thread); + } + + if (cliprdr->response_data_event) + CloseHandle(cliprdr->response_data_event); + + clear_format_map(cliprdr); + + if (cliprdr->format_mappings) + free(cliprdr->format_mappings); + + free(cliprdr); } -static void wf_cliprdr_process_cb_monitor_ready_event(wfContext* wfc) +static void wf_cliprdr_process_cb_clip_caps_event(wfContext *wfc, RDP_CB_CLIP_CAPS *caps_event) { + cliprdrContext *cliprdr = (cliprdrContext *)wfc->cliprdr_context; + cliprdr->capabilities = caps_event->capabilities; } -static void wf_cliprdr_process_cb_data_request_event(wfContext* wfc, RDP_CB_DATA_REQUEST_EVENT* event) +static void wf_cliprdr_process_cb_monitor_ready_event(wfContext *wfc, RDP_CB_MONITOR_READY_EVENT *ready_event) { + cliprdrContext *cliprdr = (cliprdrContext *)wfc->cliprdr_context; + cliprdr->channel_initialized = TRUE; + + cliprdr_send_format_list(wfc->cliprdr_context); } -static void wf_cliprdr_process_cb_format_list_event(wfContext* wfc, RDP_CB_FORMAT_LIST_EVENT* event) +static void wf_cliprdr_process_cb_data_request_event(wfContext *wfc, RDP_CB_DATA_REQUEST_EVENT *event) { + cliprdrContext *cliprdr = (cliprdrContext *)wfc->cliprdr_context; + RDP_CB_DATA_RESPONSE_EVENT *responce_event; + HANDLE hClipdata; + int size = 0; + char *buff = NULL; + char *globlemem = NULL; + UINT32 local_format; + local_format = event->format; + + if (local_format == 0x9) { /* FORMAT_ID_PALETTE */ + /* TODO: implement this */ + DEBUG_CLIPRDR("FORMAT_ID_PALETTE is not supported yet."); + } else if (local_format == 0x3) { /* FORMAT_ID_MATEFILE */ + /* TODO: implement this */ + DEBUG_CLIPRDR("FORMAT_ID_MATEFILE is not supported yet."); + } else if (local_format == RegisterClipboardFormatW(L"FileGroupDescriptorW")) { + /* TODO: implement this */ + DEBUG_CLIPRDR("FileGroupDescriptorW is not supported yet."); + } else { + if (!OpenClipboard(cliprdr->hwndClipboard)) { + DEBUG_CLIPRDR("OpenClipboard failed with 0x%x", GetLastError()); + return; + } + + hClipdata = GetClipboardData(event->format); + if (!hClipdata) { + DEBUG_CLIPRDR("GetClipboardData failed."); + CloseClipboard(); + return; + } + + globlemem = (char *)GlobalLock(hClipdata); + size = GlobalSize(hClipdata); + + buff = (char *)malloc(size); + memcpy(buff, globlemem, size); + + GlobalUnlock(hClipdata); + + CloseClipboard(); + } + + responce_event = (RDP_CB_DATA_RESPONSE_EVENT *)freerdp_event_new(CliprdrChannel_Class, + CliprdrChannel_DataResponse, NULL, NULL); + + responce_event->data = (BYTE *)buff; + responce_event->size = size; + + freerdp_channels_send_event(cliprdr->channels, (wMessage *) responce_event); + + /* Note: don't free buff here. */ } -static void wf_cliprdr_process_cb_data_response_event(wfContext* wfc, RDP_CB_DATA_RESPONSE_EVENT* event) +static void wf_cliprdr_process_cb_format_list_event(wfContext *wfc, RDP_CB_FORMAT_LIST_EVENT *event) { + cliprdrContext *cliprdr = (cliprdrContext *)wfc->cliprdr_context; + UINT32 left_size = event->raw_format_data_size; + int i = 0; + BYTE *p; + BYTE* end_mark; + BOOL format_forbidden = FALSE; + /* ignore the formats member in event struct, only parsing raw_format_data */ + + p = event->raw_format_data; + end_mark = p + event->raw_format_data_size; + + clear_format_map(cliprdr); + + if ((cliprdr->capabilities & CAPS_USE_LONG_FORMAT_NAMES) != 0) { + while (left_size >= 6) { + formatMapping *map; + BYTE* tmp; + int name_len; + + map = &cliprdr->format_mappings[i++]; + + Read_UINT32(p, map->remote_format_id); + + /* get name_len */ + for (tmp = p, name_len = 0; tmp + 1 < end_mark; tmp += 2, name_len += 2) { + if (*((unsigned short*) tmp) == 0) + break; + } + + if (name_len > 0) { + map->name = malloc(name_len + 2); + memcpy(map->name, p, name_len + 2); + + map->local_format_id = RegisterClipboardFormatW((LPCWSTR)map->name); + } else { + map->local_format_id = map->remote_format_id; + } + + left_size -= name_len + 4 + 2; + p += name_len + 2; /* p's already +4 when Read_UINT32() is called. */ + + cliprdr->map_size++; + + map_ensure_capacity(cliprdr); + } + } else { + int k; + + for (k = 0; k < event->raw_format_data_size / 36; k++) { + formatMapping *map; + int name_len; + + map = &cliprdr->format_mappings[i++]; + + Read_UINT32(p, map->remote_format_id); + + if (event->raw_format_unicode) { + /* get name_len, in bytes, if the file name is truncated, no terminated null will be included. */ + for (name_len = 0; name_len < 32; name_len += 2) { + if (*((unsigned short*) (p + name_len)) == 0) + break; + } + + if (name_len > 0) { + map->name = calloc(1, name_len + 2); + memcpy(map->name, p, name_len); + map->local_format_id = RegisterClipboardFormatW((LPCWSTR)map->name); + } else { + map->local_format_id = map->remote_format_id; + } + } else { + /* get name_len, in bytes, if the file name is truncated, no terminated null will be included. */ + for (name_len = 0; name_len < 32; name_len += 1) { + if (*((unsigned char*) (p + name_len)) == 0) + break; + } + + if (name_len > 0) { + map->name = calloc(1, name_len + 1); + memcpy(map->name, p, name_len); + map->local_format_id = RegisterClipboardFormatA((LPCSTR)map->name); + } else { + map->local_format_id = map->remote_format_id; + } + } + + p += 32; /* p's already +4 when Read_UINT32() is called. */ + cliprdr->map_size++; + map_ensure_capacity(cliprdr); + } + } + + if (!OpenClipboard(cliprdr->hwndClipboard)) { + DEBUG_CLIPRDR("OpenClipboard failed with 0x%x", GetLastError()); + return; + } + + if (!EmptyClipboard()) { + DEBUG_CLIPRDR("EmptyClipboard failed with 0x%x", GetLastError()); + CloseClipboard(); + return; + } + + for (i = 0; i < cliprdr->map_size; i++) { + SetClipboardData(cliprdr->format_mappings[i].local_format_id, NULL); + } + + CloseClipboard(); } -void wf_process_cliprdr_event(wfContext* wfc, wMessage* event) +static void wf_cliprdr_process_cb_data_response_event(wfContext *wfc, RDP_CB_DATA_RESPONSE_EVENT *event) { - switch (GetMessageType(event->id)) - { + cliprdrContext *cliprdr = (cliprdrContext *)wfc->cliprdr_context; + HANDLE hMem; + char *buff; + + hMem = GlobalAlloc(GMEM_FIXED, event->size); + buff = (char *) GlobalLock(hMem); + memcpy(buff, event->data, event->size); + GlobalUnlock(hMem); + + cliprdr->hmem = hMem; + SetEvent(cliprdr->response_data_event); +} + +void wf_process_cliprdr_event(wfContext *wfc, wMessage *event) +{ + switch (GetMessageType(event->id)) { + case CliprdrChannel_ClipCaps: + wf_cliprdr_process_cb_clip_caps_event(wfc, (RDP_CB_CLIP_CAPS *)event); + break; + case CliprdrChannel_MonitorReady: - wf_cliprdr_process_cb_monitor_ready_event(wfc); + wf_cliprdr_process_cb_monitor_ready_event(wfc, (RDP_CB_MONITOR_READY_EVENT *)event); break; case CliprdrChannel_FormatList: - wf_cliprdr_process_cb_format_list_event(wfc, (RDP_CB_FORMAT_LIST_EVENT*) event); + wf_cliprdr_process_cb_format_list_event(wfc, (RDP_CB_FORMAT_LIST_EVENT *) event); break; case CliprdrChannel_DataRequest: - wf_cliprdr_process_cb_data_request_event(wfc, (RDP_CB_DATA_REQUEST_EVENT*) event); + wf_cliprdr_process_cb_data_request_event(wfc, (RDP_CB_DATA_REQUEST_EVENT *) event); break; case CliprdrChannel_DataResponse: - wf_cliprdr_process_cb_data_response_event(wfc, (RDP_CB_DATA_RESPONSE_EVENT*) event); + wf_cliprdr_process_cb_data_response_event(wfc, (RDP_CB_DATA_RESPONSE_EVENT *) event); break; default: diff --git a/client/Windows/wf_cliprdr.h b/client/Windows/wf_cliprdr.h index 96a26e1be..09e220ccf 100644 --- a/client/Windows/wf_cliprdr.h +++ b/client/Windows/wf_cliprdr.h @@ -21,6 +21,40 @@ #include "wf_interface.h" +#ifdef WITH_DEBUG_CLIPRDR +#define DEBUG_CLIPRDR(fmt, ...) DEBUG_CLASS(WIN_CLIPRDR, fmt, ## __VA_ARGS__) +#else +#define DEBUG_CLIPRDR(fmt, ...) DEBUG_NULL(fmt, ## __VA_ARGS__) +#endif + +typedef struct format_mapping formatMapping; +struct format_mapping { + UINT32 remote_format_id; + UINT32 local_format_id; + void *name; /* Unicode or ASCII characters with NULL terminate */ +}; + +typedef struct cliprdr_context cliprdrContext; +struct cliprdr_context { + rdpChannels *channels; + + UINT32 capabilities; + + formatMapping *format_mappings; + int map_capacity; + int map_size; + + UINT32 request_format; + BOOL channel_initialized; + + HWND hwndClipboard; + HWND hwndNextViewer; + + HANDLE cliprdr_thread; + HANDLE hmem; + HANDLE response_data_event; +}; + void wf_cliprdr_init(wfContext* wfc, rdpChannels* channels); void wf_cliprdr_uninit(wfContext* wfc); void wf_process_cliprdr_event(wfContext* wfc, wMessage* event); diff --git a/client/Windows/wf_interface.c b/client/Windows/wf_interface.c index 87abe188d..3ad3ce439 100644 --- a/client/Windows/wf_interface.c +++ b/client/Windows/wf_interface.c @@ -533,12 +533,26 @@ int wf_receive_channel_data(freerdp* instance, int channelId, BYTE* data, int si void wf_process_channel_event(rdpChannels* channels, freerdp* instance) { + wfContext* wfc; wMessage* event; + wfc = (wfContext*) instance->context; event = freerdp_channels_pop_event(channels); if (event) + { + switch (GetMessageClass(event->id)) + { + case CliprdrChannel_Class: + wf_process_cliprdr_event(wfc, event); + break; + + default: + break; + } + freerdp_event_free(event); + } } BOOL wf_get_fds(freerdp* instance, void** rfds, int* rcount, void** wfds, int* wcount) diff --git a/client/Windows/wf_interface.h b/client/Windows/wf_interface.h index 028e1a853..62c477803 100644 --- a/client/Windows/wf_interface.h +++ b/client/Windows/wf_interface.h @@ -63,6 +63,7 @@ struct wf_pointer }; typedef struct wf_pointer wfPointer; +typedef struct cliprdr_context cliprdrContext; struct wf_context { rdpContext context; @@ -130,6 +131,7 @@ struct wf_context int yMinScroll; // minimum vertical scroll value int yCurrentScroll; // current vertical scroll value int yMaxScroll; // maximum vertical scroll value + cliprdrContext *cliprdr_context; }; typedef struct wf_context wfContext; diff --git a/include/freerdp/client/cliprdr.h b/include/freerdp/client/cliprdr.h index 6cf137eab..e7aa94195 100644 --- a/include/freerdp/client/cliprdr.h +++ b/include/freerdp/client/cliprdr.h @@ -99,7 +99,24 @@ typedef struct _CLIPRDR_FORMAT_NAME CLIPRDR_FORMAT_NAME; /** * Clipboard Events */ -typedef wMessage RDP_CB_MONITOR_READY_EVENT; +#define CAPS_USE_LONG_FORMAT_NAMES 0x00000002 +#define CAPS_STREAM_FILECLIP_ENABLED 0x00000004 +#define CAPS_FILECLIP_NO_FILE_PATH 0x00000008 +#define CAPS_CAN_LOCK_CLIPDATA 0x00000010 + +struct _RDP_CB_CLIP_CAPS +{ + wMessage event; + UINT32 capabilities; +}; +typedef struct _RDP_CB_CLIP_CAPS RDP_CB_CLIP_CAPS; + +struct _RDP_CB_MONITOR_READY_EVENT +{ + wMessage event; + UINT32 capabilities; +}; +typedef struct _RDP_CB_MONITOR_READY_EVENT RDP_CB_MONITOR_READY_EVENT; struct _RDP_CB_FORMAT_LIST_EVENT { @@ -108,6 +125,7 @@ struct _RDP_CB_FORMAT_LIST_EVENT UINT16 num_formats; BYTE* raw_format_data; UINT32 raw_format_data_size; + BOOL raw_format_unicode; }; typedef struct _RDP_CB_FORMAT_LIST_EVENT RDP_CB_FORMAT_LIST_EVENT; diff --git a/include/freerdp/message.h b/include/freerdp/message.h index e275849b4..cd81bb766 100644 --- a/include/freerdp/message.h +++ b/include/freerdp/message.h @@ -260,11 +260,13 @@ #define CliprdrChannel_FormatList 2 #define CliprdrChannel_DataRequest 3 #define CliprdrChannel_DataResponse 4 +#define CliprdrChannel_ClipCaps 5 #define FREERDP_CLIPRDR_CHANNEL_MONITOR_READY MakeMessageId(CliprdrChannel, MonitorReady) -#define FREERDP_CLIPRDR_CHANNEL_FORMAT_LIST MakeMessageId(CliprdrChannel, FormatList) +#define FREERDP_CLIPRDR_CHANNEL_FORMAT_LIST MakeMessageId(CliprdrChannel, FormatList) #define FREERDP_CLIPRDR_CHANNEL_DATA_REQUEST MakeMessageId(CliprdrChannel, DataRequest) #define FREERDP_CLIPRDR_CHANNEL_DATA_RESPONSE MakeMessageId(CliprdrChannel, DataResponse) +#define FREERDP_CLIPRDR_CHANNEL_CLIP_CAPS MakeMessageId(CliprdrChannel, ClipCaps) /** * Multimedia Redirection Channel diff --git a/libfreerdp/utils/event.c b/libfreerdp/utils/event.c index 60c62b03e..738aa1c29 100644 --- a/libfreerdp/utils/event.c +++ b/libfreerdp/utils/event.c @@ -67,6 +67,12 @@ static wMessage* freerdp_cliprdr_event_new(UINT16 event_type) ZeroMemory(event.v, sizeof(RDP_CB_DATA_RESPONSE_EVENT)); event.m->id = MakeMessageId(CliprdrChannel, DataResponse); break; + + case CliprdrChannel_ClipCaps: + event.v = malloc(sizeof(RDP_CB_CLIP_CAPS)); + ZeroMemory(event.v, sizeof(RDP_CB_CLIP_CAPS)); + event.m->id = MakeMessageId(CliprdrChannel, ClipCaps); + break; } return event.v; From 9921e519a9ab06a514932ef617f673db3c6a2eca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Moreau?= Date: Tue, 5 Nov 2013 11:49:42 -0500 Subject: [PATCH 08/16] mfreerdp: fix termination of MacFreeRDP --- client/Mac/MRDPView.m | 14 ++-- client/Mac/mf_client.m | 124 +++++++++++++++--------------------- libfreerdp/core/transport.c | 4 +- 3 files changed, 60 insertions(+), 82 deletions(-) diff --git a/client/Mac/MRDPView.m b/client/Mac/MRDPView.m index 33ed73cc4..64da92414 100644 --- a/client/Mac/MRDPView.m +++ b/client/Mac/MRDPView.m @@ -170,6 +170,7 @@ DWORD mac_client_thread(void* param) mfContext* mfc = (mfContext*) context; freerdp* instance = context->instance; MRDPView* view = mfc->view; + rdpSettings* settings = context->settings; status = freerdp_connect(context->instance); @@ -185,17 +186,17 @@ DWORD mac_client_thread(void* param) events[nCount++] = mfc->stopEvent; - if (instance->settings->AsyncUpdate) + if (settings->AsyncUpdate) { events[nCount++] = update_event = freerdp_get_message_queue_event_handle(instance, FREERDP_UPDATE_MESSAGE_QUEUE); } - if (instance->settings->AsyncInput) + if (settings->AsyncInput) { events[nCount++] = input_event = freerdp_get_message_queue_event_handle(instance, FREERDP_INPUT_MESSAGE_QUEUE); } - if (instance->settings->AsyncChannels) + if (settings->AsyncChannels) { events[nCount++] = channels_event = freerdp_channels_get_event_handle(instance); } @@ -206,10 +207,11 @@ DWORD mac_client_thread(void* param) if (WaitForSingleObject(mfc->stopEvent, 0) == WAIT_OBJECT_0) { + freerdp_disconnect(instance); break; } - if (instance->settings->AsyncUpdate) + if (settings->AsyncUpdate) { if (WaitForSingleObject(update_event, 0) == WAIT_OBJECT_0) { @@ -217,7 +219,7 @@ DWORD mac_client_thread(void* param) } } - if (instance->settings->AsyncInput) + if (settings->AsyncInput) { if (WaitForSingleObject(input_event, 0) == WAIT_OBJECT_0) { @@ -225,7 +227,7 @@ DWORD mac_client_thread(void* param) } } - if (instance->settings->AsyncChannels) + if (settings->AsyncChannels) { if (WaitForSingleObject(channels_event, 0) == WAIT_OBJECT_0) { diff --git a/client/Mac/mf_client.m b/client/Mac/mf_client.m index f6b6d8dcf..6354546fb 100755 --- a/client/Mac/mf_client.m +++ b/client/Mac/mf_client.m @@ -46,12 +46,12 @@ int mfreerdp_client_start(rdpContext* context) MRDPView* view; mfContext* mfc = (mfContext*) context; - if (mfc->view == NULL) - { - // view not specified beforehand. Create view dynamically - mfc->view = [[MRDPView alloc] initWithFrame : NSMakeRect(0, 0, context->settings->DesktopWidth, context->settings->DesktopHeight)]; - mfc->view_ownership = TRUE; - } + if (mfc->view == NULL) + { + // view not specified beforehand. Create view dynamically + mfc->view = [[MRDPView alloc] initWithFrame : NSMakeRect(0, 0, context->settings->DesktopWidth, context->settings->DesktopHeight)]; + mfc->view_ownership = TRUE; + } view = (MRDPView*) mfc->view; [view rdpStart:context]; @@ -62,45 +62,22 @@ int mfreerdp_client_start(rdpContext* context) int mfreerdp_client_stop(rdpContext* context) { mfContext* mfc = (mfContext*) context; - - if (context->settings->AsyncUpdate) + + if (mfc->thread) { - wMessageQueue* queue; - queue = freerdp_get_message_queue(context->instance, FREERDP_UPDATE_MESSAGE_QUEUE); - if (queue) - { - MessageQueue_PostQuit(queue, 0); - } - } - else if (context->settings->AsyncInput) - { - wMessageQueue* queue; - queue = freerdp_get_message_queue(context->instance, FREERDP_INPUT_MESSAGE_QUEUE); - if (queue) - { - MessageQueue_PostQuit(queue, 0); - } - } - else - { - mfc->disconnect = TRUE; + SetEvent(mfc->stopEvent); + WaitForSingleObject(mfc->thread, INFINITE); + CloseHandle(mfc->thread); + mfc->thread = NULL; } - if (mfc->thread) - { - SetEvent(mfc->stopEvent); - WaitForSingleObject(mfc->thread, INFINITE); - CloseHandle(mfc->thread); - mfc->thread = NULL; - } - - if (mfc->view_ownership) - { - MRDPView* view = (MRDPView*) mfc->view; - [view releaseResources]; - [view release]; - mfc->view = nil; - } + if (mfc->view_ownership) + { + MRDPView* view = (MRDPView*) mfc->view; + [view releaseResources]; + [view release]; + mfc->view = nil; + } return 0; } @@ -112,22 +89,21 @@ int mfreerdp_client_new(freerdp* instance, rdpContext* context) mfc = (mfContext*) instance->context; - mfc->stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + mfc->stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL); - context->instance->PreConnect = mac_pre_connect; - context->instance->PostConnect = mac_post_connect; - context->instance->ReceiveChannelData = mac_receive_channel_data; - context->instance->Authenticate = mac_authenticate; + context->instance->PreConnect = mac_pre_connect; + context->instance->PostConnect = mac_post_connect; + context->instance->ReceiveChannelData = mac_receive_channel_data; + context->instance->Authenticate = mac_authenticate; - context->channels = freerdp_channels_new(); + context->channels = freerdp_channels_new(); settings = instance->settings; - settings->AsyncUpdate = TRUE; - settings->AsyncInput = TRUE; + settings->AsyncUpdate = TRUE; + settings->AsyncInput = TRUE; settings->AsyncChannels = TRUE; settings->AsyncTransport = TRUE; - settings->RedirectClipboard = TRUE; settings->OsMajorType = OSMAJORTYPE_MACINTOSH; settings->OsMinorType = OSMINORTYPE_MACINTOSH; @@ -195,35 +171,35 @@ void freerdp_client_mouse_event(rdpContext* cfc, DWORD flags, int x, int y) void mf_scale_mouse_event(void* context, rdpInput* input, UINT16 flags, UINT16 x, UINT16 y) { - mfContext* mfc = (mfContext*) context; + mfContext* mfc = (mfContext*) context; MRDPView* view = (MRDPView*) mfc->view; - - int ww, wh, dw, dh; - + + int ww, wh, dw, dh; + ww = mfc->client_width; wh = mfc->client_height; dw = mfc->context.settings->DesktopWidth; - dh = mfc->context.settings->DesktopHeight; - + dh = mfc->context.settings->DesktopHeight; + // Convert to windows coordinates y = [view frame].size.height - y; - - if (!mfc->context.settings->SmartSizing || ((ww == dw) && (wh == dh))) - { - y = y + mfc->yCurrentScroll; - - if (wh != dh) - { - y -= (dh - wh); - } - - input->MouseEvent(input, flags, x + mfc->xCurrentScroll, y); - } - else - { - y = y * dh / wh + mfc->yCurrentScroll; - input->MouseEvent(input, flags, x * dw / ww + mfc->xCurrentScroll, y); - } + + if (!mfc->context.settings->SmartSizing || ((ww == dw) && (wh == dh))) + { + y = y + mfc->yCurrentScroll; + + if (wh != dh) + { + y -= (dh - wh); + } + + input->MouseEvent(input, flags, x + mfc->xCurrentScroll, y); + } + else + { + y = y * dh / wh + mfc->yCurrentScroll; + input->MouseEvent(input, flags, x * dw / ww + mfc->xCurrentScroll, y); + } } int RdpClientEntry(RDP_CLIENT_ENTRY_POINTS* pEntryPoints) diff --git a/libfreerdp/core/transport.c b/libfreerdp/core/transport.c index af6a7d0f6..70ff6c069 100644 --- a/libfreerdp/core/transport.c +++ b/libfreerdp/core/transport.c @@ -977,7 +977,7 @@ static void* transport_client_thread(void* arg) status = WaitForMultipleObjects(nCount, handles, FALSE, INFINITE); - if (status == WAIT_OBJECT_0) + if (WaitForSingleObject(transport->stopEvent, 0) == WAIT_OBJECT_0) { WLog_Print(transport->log, WLOG_DEBUG, "Terminating transport thread"); ExitThread(0); @@ -995,7 +995,7 @@ static void* transport_client_thread(void* arg) status = WaitForMultipleObjects(nCount, handles, FALSE, INFINITE); - if (status == WAIT_OBJECT_0) + if (WaitForSingleObject(transport->stopEvent, 0) == WAIT_OBJECT_0) break; if (!freerdp_check_fds(instance)) From bccd0750e8839490328df58a68734d16e7d34692 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Moreau?= Date: Mon, 4 Nov 2013 23:45:19 -0500 Subject: [PATCH 09/16] libfreerdp-client: fix memory leaks in settings accessors --- client/common/file.c | 33 ++++++++++++++++++++++++++++++- libfreerdp/common/settings.c | 38 ++++++++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+), 1 deletion(-) diff --git a/client/common/file.c b/client/common/file.c index 35b0b1341..4ca74fea6 100644 --- a/client/common/file.c +++ b/client/common/file.c @@ -481,6 +481,7 @@ BOOL freerdp_client_parse_rdp_file_buffer(rdpFile* file, BYTE* buffer, size_t si BOOL freerdp_client_parse_rdp_file(rdpFile* file, const char* name) { + BOOL status; BYTE* buffer; FILE* fp = NULL; size_t read_size; @@ -521,7 +522,11 @@ BOOL freerdp_client_parse_rdp_file(rdpFile* file, const char* name) buffer[file_size] = '\0'; buffer[file_size + 1] = '\0'; - return freerdp_client_parse_rdp_file_buffer(file, buffer, file_size); + status = freerdp_client_parse_rdp_file_buffer(file, buffer, file_size); + + free(buffer); + + return status; } #define WRITE_ALL_SETTINGS TRUE @@ -966,6 +971,12 @@ BOOL freerdp_client_populate_settings_from_rdp_file(rdpFile* file, rdpSettings* return TRUE; } +void freerdp_client_file_string_check_free(LPSTR str) +{ + if (~((size_t) str)) + free(str); +} + rdpFile* freerdp_client_rdp_file_new() { rdpFile* file; @@ -1000,6 +1011,26 @@ void freerdp_client_rdp_file_free(rdpFile* file) free(file->argv); } + freerdp_client_file_string_check_free(file->Username); + freerdp_client_file_string_check_free(file->Domain); + freerdp_client_file_string_check_free(file->FullAddress); + freerdp_client_file_string_check_free(file->AlternateFullAddress); + freerdp_client_file_string_check_free(file->UsbDevicesToRedirect); + freerdp_client_file_string_check_free(file->LoadBalanceInfo); + freerdp_client_file_string_check_free(file->RemoteApplicationName); + freerdp_client_file_string_check_free(file->RemoteApplicationIcon); + freerdp_client_file_string_check_free(file->RemoteApplicationProgram); + freerdp_client_file_string_check_free(file->RemoteApplicationFile); + freerdp_client_file_string_check_free(file->RemoteApplicationGuid); + freerdp_client_file_string_check_free(file->RemoteApplicationCmdLine); + freerdp_client_file_string_check_free(file->AlternateShell); + freerdp_client_file_string_check_free(file->ShellWorkingDirectory); + freerdp_client_file_string_check_free(file->GatewayHostname); + freerdp_client_file_string_check_free(file->KdcProxyName); + freerdp_client_file_string_check_free(file->DrivesToRedirect); + freerdp_client_file_string_check_free(file->DevicesToRedirect); + freerdp_client_file_string_check_free(file->WinPosStr); + free(file); } } diff --git a/libfreerdp/common/settings.c b/libfreerdp/common/settings.c index 16fe998ba..e97a5b090 100644 --- a/libfreerdp/common/settings.c +++ b/libfreerdp/common/settings.c @@ -2237,154 +2237,192 @@ int freerdp_set_param_string(rdpSettings* settings, int id, const char* param) switch (id) { case FreeRDP_ServerHostname: + free(settings->ServerHostname); settings->ServerHostname = _strdup(param); break; case FreeRDP_Username: + free(settings->Username); settings->Username = _strdup(param); break; case FreeRDP_Password: + free(settings->Password); settings->Password = _strdup(param); break; case FreeRDP_Domain: + free(settings->Domain); settings->Domain = _strdup(param); break; case FreeRDP_ClientHostname: + free(settings->ClientHostname); settings->ClientHostname = _strdup(param); break; case FreeRDP_ClientProductId: + free(settings->ClientProductId); settings->ClientProductId = _strdup(param); break; case FreeRDP_AlternateShell: + free(settings->AlternateShell); settings->AlternateShell = _strdup(param); break; case FreeRDP_ShellWorkingDirectory: + free(settings->ShellWorkingDirectory); settings->ShellWorkingDirectory = _strdup(param); break; case FreeRDP_ClientAddress: + free(settings->ClientAddress); settings->ClientAddress = _strdup(param); break; case FreeRDP_ClientDir: + free(settings->ClientDir); settings->ClientDir = _strdup(param); break; case FreeRDP_DynamicDSTTimeZoneKeyName: + free(settings->DynamicDSTTimeZoneKeyName); settings->DynamicDSTTimeZoneKeyName = _strdup(param); break; case FreeRDP_PreconnectionBlob: + free(settings->PreconnectionBlob); settings->PreconnectionBlob = _strdup(param); break; case FreeRDP_KerberosKdc: + free(settings->KerberosKdc); settings->KerberosKdc = _strdup(param); break; case FreeRDP_KerberosRealm: + free(settings->KerberosRealm); settings->KerberosRealm = _strdup(param); break; case FreeRDP_CertificateName: + free(settings->CertificateName); settings->CertificateName = _strdup(param); break; case FreeRDP_CertificateFile: + free(settings->CertificateFile); settings->CertificateFile = _strdup(param); break; case FreeRDP_PrivateKeyFile: + free(settings->PrivateKeyFile); settings->PrivateKeyFile = _strdup(param); break; case FreeRDP_RdpKeyFile: + free(settings->RdpKeyFile); settings->RdpKeyFile = _strdup(param); break; case FreeRDP_WindowTitle: + free(settings->WindowTitle); settings->WindowTitle = _strdup(param); break; case FreeRDP_ComputerName: + free(settings->ComputerName); settings->ComputerName = _strdup(param); break; case FreeRDP_ConnectionFile: + free(settings->ConnectionFile); settings->ConnectionFile = _strdup(param); break; case FreeRDP_HomePath: + free(settings->HomePath); settings->HomePath = _strdup(param); break; case FreeRDP_ConfigPath: + free(settings->ConfigPath); settings->ConfigPath = _strdup(param); break; case FreeRDP_CurrentPath: + free(settings->CurrentPath); settings->CurrentPath = _strdup(param); break; case FreeRDP_DumpRemoteFxFile: + free(settings->DumpRemoteFxFile); settings->DumpRemoteFxFile = _strdup(param); break; case FreeRDP_PlayRemoteFxFile: + free(settings->PlayRemoteFxFile); settings->PlayRemoteFxFile = _strdup(param); break; case FreeRDP_GatewayHostname: + free(settings->GatewayHostname); settings->GatewayHostname = _strdup(param); break; case FreeRDP_GatewayUsername: + free(settings->GatewayUsername); settings->GatewayUsername = _strdup(param); break; case FreeRDP_GatewayPassword: + free(settings->GatewayPassword); settings->GatewayPassword = _strdup(param); break; case FreeRDP_GatewayDomain: + free(settings->GatewayDomain); settings->GatewayDomain = _strdup(param); break; case FreeRDP_RemoteApplicationName: + free(settings->RemoteApplicationName); settings->RemoteApplicationName = _strdup(param); break; case FreeRDP_RemoteApplicationIcon: + free(settings->RemoteApplicationIcon); settings->RemoteApplicationIcon = _strdup(param); break; case FreeRDP_RemoteApplicationProgram: + free(settings->RemoteApplicationProgram); settings->RemoteApplicationProgram = _strdup(param); break; case FreeRDP_RemoteApplicationFile: + free(settings->RemoteApplicationFile); settings->RemoteApplicationFile = _strdup(param); break; case FreeRDP_RemoteApplicationGuid: + free(settings->RemoteApplicationGuid); settings->RemoteApplicationGuid = _strdup(param); break; case FreeRDP_RemoteApplicationCmdLine: + free(settings->RemoteApplicationCmdLine); settings->RemoteApplicationCmdLine = _strdup(param); break; case FreeRDP_ImeFileName: + free(settings->ImeFileName); settings->ImeFileName = _strdup(param); break; case FreeRDP_DrivesToRedirect: + free(settings->DrivesToRedirect); settings->DrivesToRedirect = _strdup(param); break; From f38c73b6c182f38c9bf01e2156da556a6e070be2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Moreau?= Date: Tue, 5 Nov 2013 19:44:26 -0500 Subject: [PATCH 10/16] libwinpr-security: fix exporting of target --- winpr/libwinpr/security/CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/winpr/libwinpr/security/CMakeLists.txt b/winpr/libwinpr/security/CMakeLists.txt index aad728d3d..b8dfd8b00 100644 --- a/winpr/libwinpr/security/CMakeLists.txt +++ b/winpr/libwinpr/security/CMakeLists.txt @@ -34,10 +34,10 @@ set_target_properties(${MODULE_NAME} PROPERTIES VERSION ${WINPR_VERSION_FULL} SO if(MONOLITHIC_BUILD) else() - install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR}) + install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR} EXPORT WinPRTargets) endif() -set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "WinPR" EXPORT WinPRTargets) +set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "WinPR") if(BUILD_TESTING) add_subdirectory(test) From a3d0e271b564cd346ee59c998ed8cbe13cb4399f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Moreau?= Date: Wed, 6 Nov 2013 01:51:55 -0500 Subject: [PATCH 11/16] freerdp: add restricted admin option --- client/common/cmdline.c | 6 ++++++ include/freerdp/settings.h | 4 +++- libfreerdp/common/settings.c | 8 ++++++++ libfreerdp/core/connection.c | 1 + libfreerdp/core/nego.c | 21 +++++++++++++++++++-- libfreerdp/core/nego.h | 5 +++++ libfreerdp/core/nla.c | 21 +++++++++++++++++++++ libfreerdp/core/settings.c | 2 ++ 8 files changed, 65 insertions(+), 3 deletions(-) diff --git a/client/common/cmdline.c b/client/common/cmdline.c index 6c28fdfeb..c38d6a9ce 100644 --- a/client/common/cmdline.c +++ b/client/common/cmdline.c @@ -51,6 +51,7 @@ COMMAND_LINE_ARGUMENT_A args[] = { "kbd-subtype", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, "Keyboard subtype" }, { "kbd-fn-key", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, "Keyboard function key count" }, { "admin", COMMAND_LINE_VALUE_FLAG, NULL, NULL, NULL, -1, "console", "Admin (or console) session" }, + { "restricted-admin", COMMAND_LINE_VALUE_FLAG, NULL, NULL, NULL, -1, "restrictedAdmin", "Restricted admin mode" }, { "multimon", COMMAND_LINE_VALUE_OPTIONAL, NULL, NULL, NULL, -1, NULL, "Use multiple monitors" }, { "workarea", COMMAND_LINE_VALUE_FLAG, NULL, NULL, NULL, -1, NULL, "Use available work area" }, { "monitors", COMMAND_LINE_VALUE_REQUIRED, "<0,1,2...>", NULL, NULL, -1, NULL, "Select monitors to use" }, @@ -1231,6 +1232,11 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, { settings->ConsoleSession = TRUE; } + CommandLineSwitchCase(arg, "restricted-admin") + { + settings->ConsoleSession = TRUE; + settings->RestrictedAdminModeRequired = TRUE; + } CommandLineSwitchCase(arg, "kbd") { int id; diff --git a/include/freerdp/settings.h b/include/freerdp/settings.h index 153dcbdb1..384440407 100644 --- a/include/freerdp/settings.h +++ b/include/freerdp/settings.h @@ -562,6 +562,7 @@ typedef struct _RDPDR_PARALLEL RDPDR_PARALLEL; #define FreeRDP_SelectedProtocol 1094 #define FreeRDP_NegotiationFlags 1095 #define FreeRDP_NegotiateSecurityLayer 1096 +#define FreeRDP_RestrictedAdminModeRequired 1097 #define FreeRDP_MstscCookieMode 1152 #define FreeRDP_CookieMaxLength 1153 #define FreeRDP_PreconnectionId 1154 @@ -907,7 +908,8 @@ struct rdp_settings ALIGN64 UINT32 SelectedProtocol; /* 1094 */ ALIGN64 UINT32 NegotiationFlags; /* 1095 */ ALIGN64 BOOL NegotiateSecurityLayer; /* 1096 */ - UINT64 padding1152[1152 - 1097]; /* 1097 */ + ALIGN64 BOOL RestrictedAdminModeRequired; /* 1097 */ + UINT64 padding1152[1152 - 1098]; /* 1098 */ /* Connection Cookie */ ALIGN64 BOOL MstscCookieMode; /* 1152 */ diff --git a/libfreerdp/common/settings.c b/libfreerdp/common/settings.c index e97a5b090..83419807e 100644 --- a/libfreerdp/common/settings.c +++ b/libfreerdp/common/settings.c @@ -649,6 +649,10 @@ BOOL freerdp_get_param_bool(rdpSettings* settings, int id) return settings->NegotiateSecurityLayer; break; + case FreeRDP_RestrictedAdminModeRequired: + return settings->RestrictedAdminModeRequired; + break; + case FreeRDP_MstscCookieMode: return settings->MstscCookieMode; break; @@ -1109,6 +1113,10 @@ int freerdp_set_param_bool(rdpSettings* settings, int id, BOOL param) settings->NegotiateSecurityLayer = param; break; + case FreeRDP_RestrictedAdminModeRequired: + settings->RestrictedAdminModeRequired = param; + break; + case FreeRDP_MstscCookieMode: settings->MstscCookieMode = param; break; diff --git a/libfreerdp/core/connection.c b/libfreerdp/core/connection.c index 220c1352c..e84bb8e29 100644 --- a/libfreerdp/core/connection.c +++ b/libfreerdp/core/connection.c @@ -228,6 +228,7 @@ BOOL rdp_client_connect(rdpRdp* rdp) nego_set_preconnection_blob(rdp->nego, settings->PreconnectionBlob); nego_set_negotiation_enabled(rdp->nego, settings->NegotiateSecurityLayer); + nego_set_restricted_admin_mode_required(rdp->nego, settings->RestrictedAdminModeRequired); nego_enable_rdp(rdp->nego, settings->RdpSecurity); nego_enable_tls(rdp->nego, settings->TlsSecurity); diff --git a/libfreerdp/core/nego.c b/libfreerdp/core/nego.c index b2562b08e..9c4f91327 100644 --- a/libfreerdp/core/nego.c +++ b/libfreerdp/core/nego.c @@ -669,6 +669,7 @@ BOOL nego_send_negotiation_request(rdpNego* nego) wStream* s; int length; int bm, em; + BYTE flags = 0; int cookie_length; s = Stream_New(NULL, 512); @@ -703,8 +704,12 @@ BOOL nego_send_negotiation_request(rdpNego* nego) if ((nego->requested_protocols > PROTOCOL_RDP) || (nego->sendNegoData)) { /* RDP_NEG_DATA must be present for TLS and NLA */ + + if (nego->RestrictedAdminModeRequired) + flags |= RESTRICTED_ADMIN_MODE_REQUIRED; + Stream_Write_UINT8(s, TYPE_RDP_NEG_REQ); - Stream_Write_UINT8(s, 0); /* flags, must be set to zero */ + Stream_Write_UINT8(s, flags); Stream_Write_UINT16(s, 8); /* RDP_NEG_DATA length (8) */ Stream_Write_UINT32(s, nego->requested_protocols); /* requestedProtocols */ length += 8; @@ -1016,6 +1021,18 @@ void nego_set_negotiation_enabled(rdpNego* nego, BOOL NegotiateSecurityLayer) nego->NegotiateSecurityLayer = NegotiateSecurityLayer; } +/** + * Enable restricted admin mode. + * @param nego pointer to the negotiation structure + * @param enable_restricted whether to enable security layer negotiation (TRUE for enabled, FALSE for disabled) + */ + +void nego_set_restricted_admin_mode_required(rdpNego* nego, BOOL RestrictedAdminModeRequired) +{ + DEBUG_NEGO("Enabling restricted admin mode: %s", RestrictedAdminModeRequired ? "TRUE" : "FALSE"); + nego->RestrictedAdminModeRequired = RestrictedAdminModeRequired; +} + /** * Enable RDP security protocol. * @param nego pointer to the negotiation structure @@ -1033,13 +1050,13 @@ void nego_enable_rdp(rdpNego* nego, BOOL enable_rdp) * @param nego pointer to the negotiation structure * @param enable_tls whether to enable TLS + RDP protocol (TRUE for enabled, FALSE for disabled) */ + void nego_enable_tls(rdpNego* nego, BOOL enable_tls) { DEBUG_NEGO("Enabling TLS security: %s", enable_tls ? "TRUE" : "FALSE"); nego->enabled_protocols[PROTOCOL_TLS] = enable_tls; } - /** * Enable NLA security protocol. * @param nego pointer to the negotiation structure diff --git a/libfreerdp/core/nego.h b/libfreerdp/core/nego.h index 7d3e08b4f..d82257fc7 100644 --- a/libfreerdp/core/nego.h +++ b/libfreerdp/core/nego.h @@ -84,6 +84,9 @@ enum RDP_NEG_MSG #define PRECONNECTION_PDU_V1 1 #define PRECONNECTION_PDU_V2 2 +#define RESTRICTED_ADMIN_MODE_REQUIRED 0x01 +#define CORRELATION_INFO_PRESENT 0x08 + struct rdp_nego { int port; @@ -106,6 +109,7 @@ struct rdp_nego UINT32 requested_protocols; BOOL NegotiateSecurityLayer; BYTE enabled_protocols[16]; + BOOL RestrictedAdminModeRequired; rdpTransport* transport; }; @@ -137,6 +141,7 @@ void nego_free(rdpNego* nego); void nego_init(rdpNego* nego); void nego_set_target(rdpNego* nego, char* hostname, int port); void nego_set_negotiation_enabled(rdpNego* nego, BOOL NegotiateSecurityLayer_enabled); +void nego_set_restricted_admin_mode_required(rdpNego* nego, BOOL RestrictedAdminModeRequired); void nego_enable_rdp(rdpNego* nego, BOOL enable_rdp); void nego_enable_tls(rdpNego* nego, BOOL enable_tls); void nego_enable_nla(rdpNego* nego, BOOL enable_nla); diff --git a/libfreerdp/core/nla.c b/libfreerdp/core/nla.c index 9fa35b42b..56a3e519d 100644 --- a/libfreerdp/core/nla.c +++ b/libfreerdp/core/nla.c @@ -939,6 +939,20 @@ void credssp_encode_ts_credentials(rdpCredssp* credssp) { wStream* s; int length; + int DomainLength; + int UserLength; + int PasswordLength; + + DomainLength = credssp->identity.DomainLength; + UserLength = credssp->identity.UserLength; + PasswordLength = credssp->identity.PasswordLength; + + if (credssp->settings->RestrictedAdminModeRequired) + { + credssp->identity.DomainLength = 0; + credssp->identity.UserLength = 0; + credssp->identity.PasswordLength = 0; + } length = ber_sizeof_sequence(credssp_sizeof_ts_credentials(credssp)); sspi_SecBufferAlloc(&credssp->ts_credentials, length); @@ -946,6 +960,13 @@ void credssp_encode_ts_credentials(rdpCredssp* credssp) s = Stream_New(credssp->ts_credentials.pvBuffer, length); credssp_write_ts_credentials(credssp, s); + if (credssp->settings->RestrictedAdminModeRequired) + { + credssp->identity.DomainLength = DomainLength; + credssp->identity.UserLength = UserLength; + credssp->identity.PasswordLength = PasswordLength; + } + Stream_Free(s, FALSE); } diff --git a/libfreerdp/core/settings.c b/libfreerdp/core/settings.c index 700b0f277..9dbaf834a 100644 --- a/libfreerdp/core/settings.c +++ b/libfreerdp/core/settings.c @@ -223,6 +223,7 @@ rdpSettings* freerdp_settings_new(DWORD flags) settings->TlsSecurity = TRUE; settings->RdpSecurity = TRUE; settings->NegotiateSecurityLayer = TRUE; + settings->RestrictedAdminModeRequired = FALSE; settings->MstscCookieMode = FALSE; settings->CookieMaxLength = DEFAULT_COOKIE_MAX_LENGTH; settings->ClientBuild = 2600; @@ -614,6 +615,7 @@ rdpSettings* freerdp_settings_clone(rdpSettings* settings) _settings->ExtSecurity = settings->ExtSecurity; /* 1091 */ _settings->Authentication = settings->Authentication; /* 1092 */ _settings->NegotiateSecurityLayer = settings->NegotiateSecurityLayer; /* 1096 */ + _settings->RestrictedAdminModeRequired = settings->RestrictedAdminModeRequired; /* 1097 */ _settings->MstscCookieMode = settings->MstscCookieMode; /* 1152 */ _settings->SendPreconnectionPdu = settings->SendPreconnectionPdu; /* 1156 */ _settings->IgnoreCertificate = settings->IgnoreCertificate; /* 1408 */ From b8a1f7d6c08bfcc69e000e062a63d46488e9d251 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Moreau?= Date: Wed, 6 Nov 2013 10:02:58 -0500 Subject: [PATCH 12/16] freerdp: implement restricted admin mode pass-the-hash option --- client/common/cmdline.c | 7 ++++ include/freerdp/settings.h | 4 ++- libfreerdp/common/settings.c | 9 +++++ libfreerdp/core/nla.c | 48 ++++++++++++++++++++++++- libfreerdp/core/settings.c | 2 ++ winpr/libwinpr/sspi/NTLM/ntlm_compute.c | 36 ++++++++++++++++++- winpr/libwinpr/sspi/sspi.c | 12 ++++--- winpr/libwinpr/sspi/sspi.h | 5 +++ 8 files changed, 116 insertions(+), 7 deletions(-) diff --git a/client/common/cmdline.c b/client/common/cmdline.c index c38d6a9ce..d772c0fe1 100644 --- a/client/common/cmdline.c +++ b/client/common/cmdline.c @@ -52,6 +52,7 @@ COMMAND_LINE_ARGUMENT_A args[] = { "kbd-fn-key", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, "Keyboard function key count" }, { "admin", COMMAND_LINE_VALUE_FLAG, NULL, NULL, NULL, -1, "console", "Admin (or console) session" }, { "restricted-admin", COMMAND_LINE_VALUE_FLAG, NULL, NULL, NULL, -1, "restrictedAdmin", "Restricted admin mode" }, + { "pth", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, "pass-the-hash", "Pass the hash (restricted admin mode)" }, { "multimon", COMMAND_LINE_VALUE_OPTIONAL, NULL, NULL, NULL, -1, NULL, "Use multiple monitors" }, { "workarea", COMMAND_LINE_VALUE_FLAG, NULL, NULL, NULL, -1, NULL, "Use available work area" }, { "monitors", COMMAND_LINE_VALUE_REQUIRED, "<0,1,2...>", NULL, NULL, -1, NULL, "Select monitors to use" }, @@ -1237,6 +1238,12 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, settings->ConsoleSession = TRUE; settings->RestrictedAdminModeRequired = TRUE; } + CommandLineSwitchCase(arg, "pth") + { + settings->ConsoleSession = TRUE; + settings->RestrictedAdminModeRequired = TRUE; + settings->PasswordHash = _strdup(arg->Value); + } CommandLineSwitchCase(arg, "kbd") { int id; diff --git a/include/freerdp/settings.h b/include/freerdp/settings.h index 384440407..59481d9dd 100644 --- a/include/freerdp/settings.h +++ b/include/freerdp/settings.h @@ -476,6 +476,7 @@ typedef struct _RDPDR_PARALLEL RDPDR_PARALLEL; #define FreeRDP_Username 21 #define FreeRDP_Password 22 #define FreeRDP_Domain 23 +#define FreeRDP_PasswordHash 24 #define FreeRDP_RdpVersion 128 #define FreeRDP_DesktopWidth 129 #define FreeRDP_DesktopHeight 130 @@ -760,7 +761,8 @@ struct rdp_settings ALIGN64 char* Username; /* 21 */ ALIGN64 char* Password; /* 22 */ ALIGN64 char* Domain; /* 23 */ - UINT64 padding0064[64 - 24]; /* 24 */ + ALIGN64 char* PasswordHash; /* 24 */ + UINT64 padding0064[64 - 25]; /* 25 */ UINT64 padding0128[128 - 64]; /* 64 */ /** diff --git a/libfreerdp/common/settings.c b/libfreerdp/common/settings.c index 83419807e..ba0bea378 100644 --- a/libfreerdp/common/settings.c +++ b/libfreerdp/common/settings.c @@ -2096,6 +2096,10 @@ char* freerdp_get_param_string(rdpSettings* settings, int id) return settings->Domain; break; + case FreeRDP_PasswordHash: + return settings->PasswordHash; + break; + case FreeRDP_ClientHostname: return settings->ClientHostname; break; @@ -2264,6 +2268,11 @@ int freerdp_set_param_string(rdpSettings* settings, int id, const char* param) settings->Domain = _strdup(param); break; + case FreeRDP_PasswordHash: + free(settings->PasswordHash); + settings->PasswordHash = _strdup(param); + break; + case FreeRDP_ClientHostname: free(settings->ClientHostname); settings->ClientHostname = _strdup(param); diff --git a/libfreerdp/core/nla.c b/libfreerdp/core/nla.c index 56a3e519d..5e1a2feec 100644 --- a/libfreerdp/core/nla.c +++ b/libfreerdp/core/nla.c @@ -113,20 +113,39 @@ int credssp_ntlm_client_init(rdpCredssp* credssp) { char* spn; int length; + BOOL PromptPassword; rdpTls* tls = NULL; freerdp* instance; rdpSettings* settings; + PromptPassword = FALSE; settings = credssp->settings; instance = (freerdp*) settings->instance; - if ((settings->Password == NULL ) || (settings->Username == NULL) + if ((!settings->Password) || (!settings->Username) || (!strlen(settings->Password)) || (!strlen(settings->Username))) + { + PromptPassword = TRUE; + } + +#ifndef _WIN32 + if (PromptPassword) + { + if (settings->RestrictedAdminModeRequired) + { + if ((settings->PasswordHash) && (strlen(settings->PasswordHash) > 0)) + PromptPassword = FALSE; + } + } +#endif + + if (PromptPassword) { if (instance->Authenticate) { BOOL proceed = instance->Authenticate(instance, &settings->Username, &settings->Password, &settings->Domain); + if (!proceed) return 0; } @@ -134,6 +153,33 @@ int credssp_ntlm_client_init(rdpCredssp* credssp) sspi_SetAuthIdentity(&(credssp->identity), settings->Username, settings->Domain, settings->Password); +#ifndef _WIN32 + { + SEC_WINNT_AUTH_IDENTITY* identity = &(credssp->identity); + + if (settings->RestrictedAdminModeRequired) + { + if (settings->PasswordHash) + { + if (strlen(settings->PasswordHash) == 32) + { + if (identity->Password) + free(identity->Password); + + identity->PasswordLength = ConvertToUnicode(CP_UTF8, 0, + settings->PasswordHash, -1, &identity->Password, 0) - 1; + + /** + * Multiply password hash length by 64 to obtain a length exceeding + * the maximum (256) and use it this for hash identification in WinPR. + */ + identity->PasswordLength = 32 * 64; /* 2048 */ + } + } + } + } +#endif + #ifdef WITH_DEBUG_NLA _tprintf(_T("User: %s Domain: %s Password: %s\n"), (char*) credssp->identity.User, (char*) credssp->identity.Domain, (char*) credssp->identity.Password); diff --git a/libfreerdp/core/settings.c b/libfreerdp/core/settings.c index 9dbaf834a..5870e49b5 100644 --- a/libfreerdp/core/settings.c +++ b/libfreerdp/core/settings.c @@ -445,6 +445,7 @@ rdpSettings* freerdp_settings_clone(rdpSettings* settings) _settings->Username = _strdup(settings->Username); /* 21 */ _settings->Password = _strdup(settings->Password); /* 22 */ _settings->Domain = _strdup(settings->Domain); /* 23 */ + _settings->PasswordHash = _strdup(settings->PasswordHash); /* 24 */ //_settings->ClientHostname = _strdup(settings->ClientHostname); /* 134 */ //_settings->ClientProductId = _strdup(settings->ClientProductId); /* 135 */ _settings->AlternateShell = _strdup(settings->AlternateShell); /* 640 */ @@ -780,6 +781,7 @@ void freerdp_settings_free(rdpSettings* settings) free(settings->Username); free(settings->Password); free(settings->Domain); + free(settings->PasswordHash); free(settings->AlternateShell); free(settings->ShellWorkingDirectory); free(settings->ComputerName); diff --git a/winpr/libwinpr/sspi/NTLM/ntlm_compute.c b/winpr/libwinpr/sspi/NTLM/ntlm_compute.c index 5bd0a81a5..fb77c8c1f 100644 --- a/winpr/libwinpr/sspi/NTLM/ntlm_compute.c +++ b/winpr/libwinpr/sspi/NTLM/ntlm_compute.c @@ -282,9 +282,43 @@ void ntlm_fetch_ntlm_v2_hash(NTLM_CONTEXT* context, char* hash) SamClose(sam); } +void ntlm_convert_password_hash(NTLM_CONTEXT* context, BYTE* hash) +{ + int i, hn, ln; + char* PasswordHash = NULL; + UINT32 PasswordHashLength = 0; + + /* Password contains a password hash of length (PasswordLength / SSPI_CREDENTIALS_HASH_LENGTH_FACTOR) */ + + PasswordHashLength = context->identity.PasswordLength / SSPI_CREDENTIALS_HASH_LENGTH_FACTOR; + ConvertFromUnicode(CP_UTF8, 0, context->identity.Password, PasswordHashLength, &PasswordHash, 0, NULL, NULL); + CharUpperBuffA(PasswordHash, PasswordHashLength); + + for (i = 0; i < 32; i += 2) + { + hn = PasswordHash[i] > '9' ? PasswordHash[i] - 'A' + 10 : PasswordHash[i] - '0'; + ln = PasswordHash[i + 1] > '9' ? PasswordHash[i + 1] - 'A' + 10 : PasswordHash[i + 1] - '0'; + hash[i / 2] = (hn << 4) | ln; + } + + free(PasswordHash); +} + void ntlm_compute_ntlm_v2_hash(NTLM_CONTEXT* context, char* hash) { - if (context->identity.PasswordLength > 0) + if (context->identity.PasswordLength > 256) + { + BYTE PasswordHash[16]; + + /* Special case for WinPR: password hash */ + ntlm_convert_password_hash(context, PasswordHash); + + NTOWFv2FromHashW(PasswordHash, + (LPWSTR) context->identity.User, context->identity.UserLength * 2, + (LPWSTR) context->identity.Domain, context->identity.DomainLength * 2, + (BYTE*) hash); + } + else if (context->identity.PasswordLength > 0) { NTOWFv2W((LPWSTR) context->identity.Password, context->identity.PasswordLength * 2, (LPWSTR) context->identity.User, context->identity.UserLength * 2, diff --git a/winpr/libwinpr/sspi/sspi.c b/winpr/libwinpr/sspi/sspi.c index 1869baca4..4922756ee 100644 --- a/winpr/libwinpr/sspi/sspi.c +++ b/winpr/libwinpr/sspi/sspi.c @@ -192,11 +192,10 @@ CREDENTIALS* sspi_CredentialsNew() CREDENTIALS* credentials; credentials = (CREDENTIALS*) malloc(sizeof(CREDENTIALS)); - ZeroMemory(credentials, sizeof(CREDENTIALS)); - if (credentials != NULL) + if (credentials) { - + ZeroMemory(credentials, sizeof(CREDENTIALS)); } return credentials; @@ -319,7 +318,7 @@ void sspi_SetAuthIdentity(SEC_WINNT_AUTH_IDENTITY* identity, char* user, char* d identity->DomainLength = 0; } - if (password != NULL) + if (password) { identity->PasswordLength = ConvertToUnicode(CP_UTF8, 0, password, -1, &identity->Password, 0) - 1; } @@ -366,12 +365,17 @@ void sspi_CopyAuthIdentity(SEC_WINNT_AUTH_IDENTITY* identity, SEC_WINNT_AUTH_IDE identity->PasswordLength = srcIdentity->PasswordLength; + if (identity->PasswordLength > 256) + identity->PasswordLength /= SSPI_CREDENTIALS_HASH_LENGTH_FACTOR; + if (identity->PasswordLength > 0) { identity->Password = (UINT16*) malloc((identity->PasswordLength + 1) * sizeof(WCHAR)); CopyMemory(identity->Password, srcIdentity->Password, identity->PasswordLength * sizeof(WCHAR)); identity->Password[identity->PasswordLength] = 0; } + + identity->PasswordLength = srcIdentity->PasswordLength; } PSecBuffer sspi_FindSecBuffer(PSecBufferDesc pMessage, ULONG BufferType) diff --git a/winpr/libwinpr/sspi/sspi.h b/winpr/libwinpr/sspi/sspi.h index dab63578b..60f5e0508 100644 --- a/winpr/libwinpr/sspi/sspi.h +++ b/winpr/libwinpr/sspi/sspi.h @@ -24,8 +24,13 @@ #define SCHANNEL_CB_MAX_TOKEN 0x00006000 +#define SSPI_CREDENTIALS_PASSWORD_HASH 0x00000001 + +#define SSPI_CREDENTIALS_HASH_LENGTH_FACTOR 64 + struct _CREDENTIALS { + DWORD flags; SEC_WINNT_AUTH_IDENTITY identity; }; typedef struct _CREDENTIALS CREDENTIALS; From a0161a12ac78598a3ad30798e1faf660dd8a9f93 Mon Sep 17 00:00:00 2001 From: Bernhard Miklautz Date: Wed, 6 Nov 2013 17:29:33 +0100 Subject: [PATCH 13/16] moved version information to freerdp/version.h fixed #1465 --- .gitignore | 1 + CMakeLists.txt | 1 + client/common/cmdline.c | 1 + config.h.in | 9 --------- include/CMakeLists.txt | 2 ++ include/freerdp/version.h.in | 32 ++++++++++++++++++++++++++++++++ libfreerdp/core/freerdp.c | 1 + 7 files changed, 38 insertions(+), 9 deletions(-) create mode 100644 include/freerdp/version.h.in diff --git a/.gitignore b/.gitignore index e56bbf257..cc98e1a28 100755 --- a/.gitignore +++ b/.gitignore @@ -17,6 +17,7 @@ _CPack_Packages LICENSE.txt external/* !external/README +include/freerdp/version.h *.a.objlist.cmake *.a.objlist diff --git a/CMakeLists.txt b/CMakeLists.txt index a5052f103..05af4336d 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -462,6 +462,7 @@ set(FREERDP_EXTENSION_PATH "${CMAKE_INSTALL_FULL_LIBDIR}/freerdp/extensions") # Include directories include_directories(${CMAKE_CURRENT_BINARY_DIR}) +include_directories(${CMAKE_CURRENT_BINARY_DIR}/include) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include) # Configure files diff --git a/client/common/cmdline.c b/client/common/cmdline.c index 19ea41010..5d4365a33 100644 --- a/client/common/cmdline.c +++ b/client/common/cmdline.c @@ -33,6 +33,7 @@ #include #include +#include #include "compatibility.h" diff --git a/config.h.in b/config.h.in index d1eac49c1..839ec0da0 100755 --- a/config.h.in +++ b/config.h.in @@ -1,15 +1,6 @@ #ifndef __CONFIG_H #define __CONFIG_H -#define FREERDP_VERSION_MAJOR ${FREERDP_VERSION_MAJOR} -#define FREERDP_VERSION_MINOR ${FREERDP_VERSION_MINOR} -#define FREERDP_VERSION_REVISION ${FREERDP_VERSION_REVISION} -#define FREERDP_VERSION_SUFFIX "${FREERDP_VERSION_SUFFIX}" -#define FREERDP_API_VERSION "${FREERDP_API_VERSION}" -#define FREERDP_VERSION "${FREERDP_VERSION}" -#define FREERDP_VERSION_FULL "${FREERDP_VERSION_FULL}" -#define GIT_REVISION "${GIT_REVISION}" - #define FREERDP_DATA_PATH "${FREERDP_DATA_PATH}" #define FREERDP_KEYMAP_PATH "${FREERDP_KEYMAP_PATH}" #define FREERDP_PLUGIN_PATH "${FREERDP_PLUGIN_PATH}" diff --git a/include/CMakeLists.txt b/include/CMakeLists.txt index ec64d17ac..033a46349 100644 --- a/include/CMakeLists.txt +++ b/include/CMakeLists.txt @@ -17,6 +17,8 @@ # See the License for the specific language governing permissions and # limitations under the License. +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/freerdp/version.h.in ${CMAKE_CURRENT_BINARY_DIR}/freerdp/version.h) + file(GLOB FREERDP_HEADERS "freerdp/*.h") install(FILES ${FREERDP_HEADERS} DESTINATION include/freerdp COMPONENT headers) diff --git a/include/freerdp/version.h.in b/include/freerdp/version.h.in new file mode 100644 index 000000000..e16fd0ce6 --- /dev/null +++ b/include/freerdp/version.h.in @@ -0,0 +1,32 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Version includes + * + * Copyright 2013 Thinstuff Technologies GmbH + * Copyright 2013 Bernhard Miklautz + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef _FREERDP_VERSION_H_ +#define _FREERDP_VERSION_H_ + +#define FREERDP_VERSION_MAJOR ${FREERDP_VERSION_MAJOR} +#define FREERDP_VERSION_MINOR ${FREERDP_VERSION_MINOR} +#define FREERDP_VERSION_REVISION ${FREERDP_VERSION_REVISION} +#define FREERDP_VERSION_SUFFIX "${FREERDP_VERSION_SUFFIX}" +#define FREERDP_API_VERSION "${FREERDP_API_VERSION}" +#define FREERDP_VERSION "${FREERDP_VERSION}" +#define FREERDP_VERSION_FULL "${FREERDP_VERSION_FULL}" +#define GIT_REVISION "${GIT_REVISION}" + +#endif // _FREERDP_VERSION_H_ diff --git a/libfreerdp/core/freerdp.c b/libfreerdp/core/freerdp.c index b0b865180..852743bac 100644 --- a/libfreerdp/core/freerdp.c +++ b/libfreerdp/core/freerdp.c @@ -39,6 +39,7 @@ #include #include #include +#include /* connectErrorCode is 'extern' in error.h. See comment there.*/ From c9f49162bd1dbc170cbb068f14e17deb43434941 Mon Sep 17 00:00:00 2001 From: Bernhard Miklautz Date: Wed, 6 Nov 2013 17:44:17 +0100 Subject: [PATCH 14/16] install version.h --- include/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/include/CMakeLists.txt b/include/CMakeLists.txt index 033a46349..5e06eaa0f 100644 --- a/include/CMakeLists.txt +++ b/include/CMakeLists.txt @@ -21,6 +21,7 @@ configure_file(${CMAKE_CURRENT_SOURCE_DIR}/freerdp/version.h.in ${CMAKE_CURRENT_ file(GLOB FREERDP_HEADERS "freerdp/*.h") install(FILES ${FREERDP_HEADERS} DESTINATION include/freerdp COMPONENT headers) +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/freerdp/version.h DESTINATION include/freerdp COMPONENT headers) install(DIRECTORY freerdp/cache DESTINATION include/freerdp COMPONENT headers FILES_MATCHING PATTERN "*.h") install(DIRECTORY freerdp/codec DESTINATION include/freerdp COMPONENT headers FILES_MATCHING PATTERN "*.h") From 4fa03e644e2f3738666e8857cae57db4249a548e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Moreau?= Date: Wed, 6 Nov 2013 13:00:10 -0500 Subject: [PATCH 15/16] client: fix loading of external static virtual channels with /vc option --- client/common/cmdline.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/common/cmdline.c b/client/common/cmdline.c index d772c0fe1..12f07e176 100644 --- a/client/common/cmdline.c +++ b/client/common/cmdline.c @@ -1760,7 +1760,7 @@ int freerdp_client_load_static_channel_addin(rdpChannels* channels, rdpSettings* { void* entry; - entry = freerdp_load_channel_addin_entry(name, NULL, NULL, 0); + entry = freerdp_load_channel_addin_entry(name, NULL, NULL, FREERDP_ADDIN_CHANNEL_STATIC); if (entry) { From 3c44ff9c8398f624540d5103d9e67a38213e2ee2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Moreau?= Date: Wed, 6 Nov 2013 14:31:33 -0500 Subject: [PATCH 16/16] channels/rdpsnd: fix bug in rdpsnd and rdpdr deinitialization --- channels/rdpsnd/client/rdpsnd_main.c | 64 ++++++++----------- .../utils/collections/ListDictionary.c | 2 +- 2 files changed, 28 insertions(+), 38 deletions(-) diff --git a/channels/rdpsnd/client/rdpsnd_main.c b/channels/rdpsnd/client/rdpsnd_main.c index 4706cf99f..08495c043 100644 --- a/channels/rdpsnd/client/rdpsnd_main.c +++ b/channels/rdpsnd/client/rdpsnd_main.c @@ -740,31 +740,6 @@ static void rdpsnd_process_connect(rdpsndPlugin* rdpsnd) } } -static void rdpsnd_process_terminate(rdpsndPlugin* rdpsnd) -{ - if (rdpsnd->device) - IFCALL(rdpsnd->device->Free, rdpsnd->device); - - MessageQueue_PostQuit(rdpsnd->MsgPipe->Out, 0); - - WaitForSingleObject(rdpsnd->ScheduleThread, INFINITE); - CloseHandle(rdpsnd->ScheduleThread); - - if (rdpsnd->subsystem) - free(rdpsnd->subsystem); - - if (rdpsnd->device_name) - free(rdpsnd->device_name); - - rdpsnd_free_audio_formats(rdpsnd->ServerFormats, rdpsnd->NumberOfServerFormats); - rdpsnd->NumberOfServerFormats = 0; - rdpsnd->ServerFormats = NULL; - - rdpsnd_free_audio_formats(rdpsnd->ClientFormats, rdpsnd->NumberOfClientFormats); - rdpsnd->NumberOfClientFormats = 0; - rdpsnd->ClientFormats = NULL; -} - /****************************************************************************************/ @@ -951,26 +926,41 @@ static void rdpsnd_virtual_channel_event_connected(rdpsndPlugin* plugin, void* p (LPTHREAD_START_ROUTINE) rdpsnd_virtual_channel_client_thread, (void*) plugin, 0, NULL); } -static void rdpsnd_virtual_channel_event_terminated(rdpsndPlugin* plugin) +static void rdpsnd_virtual_channel_event_terminated(rdpsndPlugin* rdpsnd) { - MessagePipe_PostQuit(plugin->MsgPipe, 0); - WaitForSingleObject(plugin->thread, INFINITE); + MessagePipe_PostQuit(rdpsnd->MsgPipe, 0); + WaitForSingleObject(rdpsnd->thread, INFINITE); - MessagePipe_Free(plugin->MsgPipe); - CloseHandle(plugin->thread); + MessagePipe_Free(rdpsnd->MsgPipe); + CloseHandle(rdpsnd->thread); - plugin->channelEntryPoints.pVirtualChannelClose(plugin->OpenHandle); + rdpsnd->channelEntryPoints.pVirtualChannelClose(rdpsnd->OpenHandle); - if (plugin->data_in) + if (rdpsnd->data_in) { - Stream_Free(plugin->data_in, TRUE); - plugin->data_in = NULL; + Stream_Free(rdpsnd->data_in, TRUE); + rdpsnd->data_in = NULL; } - rdpsnd_process_terminate(plugin); + if (rdpsnd->device) + IFCALL(rdpsnd->device->Free, rdpsnd->device); - rdpsnd_remove_open_handle_data(plugin->OpenHandle); - rdpsnd_remove_init_handle_data(plugin->InitHandle); + if (rdpsnd->subsystem) + free(rdpsnd->subsystem); + + if (rdpsnd->device_name) + free(rdpsnd->device_name); + + rdpsnd_free_audio_formats(rdpsnd->ServerFormats, rdpsnd->NumberOfServerFormats); + rdpsnd->NumberOfServerFormats = 0; + rdpsnd->ServerFormats = NULL; + + rdpsnd_free_audio_formats(rdpsnd->ClientFormats, rdpsnd->NumberOfClientFormats); + rdpsnd->NumberOfClientFormats = 0; + rdpsnd->ClientFormats = NULL; + + rdpsnd_remove_open_handle_data(rdpsnd->OpenHandle); + rdpsnd_remove_init_handle_data(rdpsnd->InitHandle); } static void rdpsnd_virtual_channel_init_event(void* pInitHandle, UINT32 event, void* pData, UINT32 dataLength) diff --git a/winpr/libwinpr/utils/collections/ListDictionary.c b/winpr/libwinpr/utils/collections/ListDictionary.c index d1df02125..bef4f0757 100644 --- a/winpr/libwinpr/utils/collections/ListDictionary.c +++ b/winpr/libwinpr/utils/collections/ListDictionary.c @@ -206,7 +206,7 @@ void ListDictionary_Clear(wListDictionary* listDictionary) { nextItem = item->next; if (listDictionary->object.fnObjectFree) - listDictionary->object.fnObjectFree(item); + listDictionary->object.fnObjectFree(item->value); free(item); item = nextItem; }