From d39a7ba5c38e3ba3b99b1558dc2ab0970cbfb0c5 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Thu, 21 Oct 2021 08:30:50 +0200 Subject: [PATCH 001/496] Stable 2.0 backports (#7366) * Fixed typo in changelog * Fix FIPS mode support and build with OpenSSL 3.0 FreeRDP fails to build with OpenSSL 3.0 because of usage of the `FIPS_mode` and `FIPS_mode_set` functions, which were removed there. Just a note that the FIPS mode is not supported by OpenSSL 1.1.* although the mentioned functions are still there (see https://wiki.openssl.org/index.php/FIPS_modules). Let's make FreeRDP build with OpenSSL 3.0 and fix the FIPS mode support. See: https://bugzilla.redhat.com/show_bug.cgi?id=1952937 (cherry picked from commit 26bf2816c3e0daeaf524c47cf0fcda8ae13b65ad) * winpr: avoid calling FIPS_mode() with OpenSSL 3.0 Fixes: 26bf2816c3e0daeaf524c47cf0fcda8ae13b65ad (cherry picked from commit 0c81c73c8d770fd5ffbc541dc176da515b66686b) * winpr/crypto: Load legacy provider to fix rc4 with OpenSSL 3.0 (#7210) * winpr/crypto: Exit cleanly when EVP_EncryptInit_ex fails The `EVP_EncryptInit_ex` function may fail in certain configurations. Consequently, FreeRDP segfaults in `EVP_CIPHER_CTX_set_key_length`. Let's handle the `EVP_EncryptInit_ex` failures and exit cleanly in such case. * winpr/crypto: Load legacy provider to fix rc4 with OpenSSL 3.0 Currently, the `EVP_EncryptInit_ex` function fails for rc4 with OpenSSL 3.0. This is becuase rc4 is provided by the legacy provider which is not loaded by default. Let's explicitly load the legacy provider to make FreeRDP work with OpenSSL 3.0. Relates: https://github.com/openssl/openssl/issues/14392 Fixes: https://github.com/FreeRDP/FreeRDP/issues/6604 (cherry picked from commit 67f3fff2c8bef678809572248276e6008532da43) Conflicts: winpr/libwinpr/crypto/cipher.c * Fix TestUnicodeConversion on big endian machines (#7219) Wide character literals are stored in native byte order. Use an array of bytes as a reference instead. Fixes: https://github.com/FreeRDP/FreeRDP/issues/6968 (cherry picked from commit 5208a67ea77d8c69048756e32a8612bc1e064f88) * Fixed async-input quit * Fix data write on usb channel * Bitmap update fix (#7349) * Added checks for bitmap width and heigth values Data received from the server might have invalid values for bitmap with or height. Abort parsing if such a value is found. Reported by Sunglin from the Knownsec 404 team & 0103 sec team * Added checks for glyph width & height * Fixed #7363: Length checks in ConvertUTF8toUTF16 (cherry picked from commit 623a77258a1610b6e37616f4613d1eb793edf4aa) * Implemented missing TSG debug functions (cherry picked from commit c06c4638061b0305a269dbb8f7c87009cf886f02) * Refactored RPC gateway parser Utilize wStream instead of custom binary parsing code, add proper input validation. Reported by Sunglin from the Knownsec 404 team & 0103 sec team (cherry picked from commit f0b44da67c09488178000725ff9f2729ccfdf9fe) * Replaced chmod with safer fchmod * Use fchmod so the file may not change underneath * Add unit tests for SetFileAttributesA * Add warning logs for unsupported flags (cherry picked from commit c8571dd5fd42e6c462ef5db692bce6adb4b67c8d) * Updated changelog and version * Added more explicit warning for deprecated command line * Add exit codes for more errors (cherry picked from commit aa4c3dfb8a60a5b6c7a50d330e33ca1e0724bf3a) * Updated changelog. Co-authored-by: Ondrej Holy Co-authored-by: Mike Gilbert Co-authored-by: Ondrej Holy Co-authored-by: Ian Weir --- CMakeLists.txt | 2 +- ChangeLog | 18 + client/Android/android_freerdp.c | 2 +- client/X11/xf_client.c | 80 +- client/X11/xfreerdp.h | 27 +- client/common/cmdline.c | 3 + libfreerdp/core/gateway/ncacn_http.c | 6 +- libfreerdp/core/gateway/rdg.c | 77 +- libfreerdp/core/gateway/rpc.c | 134 +- libfreerdp/core/gateway/rpc.h | 18 +- libfreerdp/core/gateway/rpc_bind.c | 253 +- libfreerdp/core/gateway/rpc_bind.h | 2 +- libfreerdp/core/gateway/rpc_client.c | 265 ++- libfreerdp/core/gateway/rpc_client.h | 3 +- libfreerdp/core/gateway/rpc_fault.c | 48 +- libfreerdp/core/gateway/rts.c | 2085 +++++++++++++---- libfreerdp/core/gateway/rts.h | 29 +- libfreerdp/core/gateway/rts_signature.c | 127 +- libfreerdp/core/gateway/rts_signature.h | 8 +- libfreerdp/core/gateway/tsg.c | 543 ++++- libfreerdp/core/orders.c | 14 + libfreerdp/core/surface.c | 45 + libfreerdp/core/update.c | 7 + winpr/CMakeLists.txt | 2 +- winpr/libwinpr/crt/utf.c | 4 +- winpr/libwinpr/file/generic.c | 88 +- winpr/libwinpr/file/test/CMakeLists.txt | 106 +- .../file/test/TestSetFileAttributes.c | 149 ++ 28 files changed, 3120 insertions(+), 1025 deletions(-) create mode 100644 winpr/libwinpr/file/test/TestSetFileAttributes.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 918d211f3002..a0687025ae42 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -85,7 +85,7 @@ if ($ENV{BUILD_NUMBER}) endif() set(WITH_LIBRARY_VERSIONING "ON") -set(RAW_VERSION_STRING "2.4.0") +set(RAW_VERSION_STRING "2.4.1") if(EXISTS "${CMAKE_SOURCE_DIR}/.source_tag") file(READ ${CMAKE_SOURCE_DIR}/.source_tag RAW_VERSION_STRING) elseif(USE_VERSION_FROM_GIT_TAG) diff --git a/ChangeLog b/ChangeLog index 1389c23b607e..266238305bc2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,21 @@ +# 2021-10-20 Version 2.4.1 + +Noteworthy changes: +* Refactored RPC gateway parsing code +* OpenSSL 3.0 compatibility fixes +* USB redirection: fixed transfer lengths + +Fixed issues: +* #7363: Length checks in ConvertUTF8toUTF16 +* #7349: Added checks for bitmap width and heigth values + +Important notes: +* CVE-2021-41159: Improper client input validation for gateway connections allows to overwrite memory +* CVE-2021-41160: Improper region checks in all clients allow out of bound write to memory + +For a complete and detailed change log since the last release run: +git log 2.4.0..2.4.1 + # 2021-07-27 Version 2.4.0 Noteworthy changes: diff --git a/client/Android/android_freerdp.c b/client/Android/android_freerdp.c index 4546f41c5592..7a4686a5a07f 100644 --- a/client/Android/android_freerdp.c +++ b/client/Android/android_freerdp.c @@ -56,7 +56,7 @@ #define TAG CLIENT_TAG("android") /* Defines the JNI version supported by this library. */ -#define FREERDP_JNI_VERSION "2.4.0" +#define FREERDP_JNI_VERSION "2.4.1" static void android_OnChannelConnectedEventHandler(void* context, ChannelConnectedEventArgs* e) { diff --git a/client/X11/xf_client.c b/client/X11/xf_client.c index 114dc6d88ee1..78852a745ef8 100644 --- a/client/X11/xf_client.c +++ b/client/X11/xf_client.c @@ -1512,6 +1512,84 @@ static DWORD WINAPI xf_client_thread(LPVOID param) else if (freerdp_get_last_error(instance->context) == FREERDP_ERROR_SECURITY_NEGO_CONNECT_FAILED) exit_code = XF_EXIT_NEGO_FAILURE; + else if (freerdp_get_last_error(instance->context) == + FREERDP_ERROR_CONNECT_LOGON_FAILURE) + exit_code = XF_EXIT_LOGON_FAILURE; + else if (freerdp_get_last_error(instance->context) == + FREERDP_ERROR_CONNECT_ACCOUNT_LOCKED_OUT) + exit_code = XF_EXIT_ACCOUNT_LOCKED_OUT; + else if (freerdp_get_last_error(instance->context) == + FREERDP_ERROR_PRE_CONNECT_FAILED) + exit_code = XF_EXIT_PRE_CONNECT_FAILED; + else if (freerdp_get_last_error(instance->context) == + FREERDP_ERROR_CONNECT_UNDEFINED) + exit_code = XF_EXIT_CONNECT_UNDEFINED; + else if (freerdp_get_last_error(instance->context) == + FREERDP_ERROR_POST_CONNECT_FAILED) + exit_code = XF_EXIT_POST_CONNECT_FAILED; + else if (freerdp_get_last_error(instance->context) == + FREERDP_ERROR_DNS_ERROR) + exit_code = XF_EXIT_DNS_ERROR; + else if (freerdp_get_last_error(instance->context) == + FREERDP_ERROR_DNS_NAME_NOT_FOUND) + exit_code = XF_EXIT_DNS_NAME_NOT_FOUND; + else if (freerdp_get_last_error(instance->context) == + FREERDP_ERROR_CONNECT_FAILED) + exit_code = XF_EXIT_CONNECT_FAILED; + else if (freerdp_get_last_error(instance->context) == + FREERDP_ERROR_MCS_CONNECT_INITIAL_ERROR) + exit_code = XF_EXIT_MCS_CONNECT_INITIAL_ERROR; + else if (freerdp_get_last_error(instance->context) == + FREERDP_ERROR_TLS_CONNECT_FAILED) + exit_code = XF_EXIT_TLS_CONNECT_FAILED; + else if (freerdp_get_last_error(instance->context) == + FREERDP_ERROR_INSUFFICIENT_PRIVILEGES) + exit_code = XF_EXIT_INSUFFICIENT_PRIVILEGES; + else if (freerdp_get_last_error(instance->context) == + FREERDP_ERROR_CONNECT_CANCELLED) + exit_code = XF_EXIT_CONNECT_CANCELLED; + else if (freerdp_get_last_error(instance->context) == + FREERDP_ERROR_SECURITY_NEGO_CONNECT_FAILED) + exit_code = XF_EXIT_SECURITY_NEGO_CONNECT_FAILED; + else if (freerdp_get_last_error(instance->context) == + FREERDP_ERROR_CONNECT_TRANSPORT_FAILED) + exit_code = XF_EXIT_CONNECT_TRANSPORT_FAILED; + else if (freerdp_get_last_error(instance->context) == + FREERDP_ERROR_CONNECT_PASSWORD_EXPIRED) + exit_code = XF_EXIT_CONNECT_PASSWORD_EXPIRED; + else if (freerdp_get_last_error(instance->context) == + FREERDP_ERROR_CONNECT_PASSWORD_MUST_CHANGE) + exit_code = XF_EXIT_CONNECT_PASSWORD_MUST_CHANGE; + else if (freerdp_get_last_error(instance->context) == + FREERDP_ERROR_CONNECT_KDC_UNREACHABLE) + exit_code = XF_EXIT_CONNECT_KDC_UNREACHABLE; + else if (freerdp_get_last_error(instance->context) == + FREERDP_ERROR_CONNECT_ACCOUNT_DISABLED) + exit_code = XF_EXIT_CONNECT_ACCOUNT_DISABLED; + else if (freerdp_get_last_error(instance->context) == + FREERDP_ERROR_CONNECT_PASSWORD_CERTAINLY_EXPIRED) + exit_code = XF_EXIT_CONNECT_PASSWORD_CERTAINLY_EXPIRED; + else if (freerdp_get_last_error(instance->context) == + FREERDP_ERROR_CONNECT_CLIENT_REVOKED) + exit_code = XF_EXIT_CONNECT_CLIENT_REVOKED; + else if (freerdp_get_last_error(instance->context) == + FREERDP_ERROR_CONNECT_WRONG_PASSWORD) + exit_code = XF_EXIT_CONNECT_WRONG_PASSWORD; + else if (freerdp_get_last_error(instance->context) == + FREERDP_ERROR_CONNECT_ACCESS_DENIED) + exit_code = XF_EXIT_CONNECT_ACCESS_DENIED; + else if (freerdp_get_last_error(instance->context) == + FREERDP_ERROR_CONNECT_ACCOUNT_RESTRICTION) + exit_code = XF_EXIT_CONNECT_ACCOUNT_RESTRICTION; + else if (freerdp_get_last_error(instance->context) == + FREERDP_ERROR_CONNECT_ACCOUNT_EXPIRED) + exit_code = XF_EXIT_CONNECT_ACCOUNT_EXPIRED; + else if (freerdp_get_last_error(instance->context) == + FREERDP_ERROR_CONNECT_LOGON_TYPE_NOT_GRANTED) + exit_code = XF_EXIT_CONNECT_LOGON_TYPE_NOT_GRANTED; + else if (freerdp_get_last_error(instance->context) == + FREERDP_ERROR_CONNECT_NO_OR_MISSING_CREDENTIALS) + exit_code = XF_EXIT_CONNECT_NO_OR_MISSING_CREDENTIALS; else exit_code = XF_EXIT_CONN_FAILED; } @@ -1676,7 +1754,7 @@ static DWORD WINAPI xf_client_thread(LPVOID param) DWORD xf_exit_code_from_disconnect_reason(DWORD reason) { - if (reason == 0 || (reason >= XF_EXIT_PARSE_ARGUMENTS && reason <= XF_EXIT_NEGO_FAILURE)) + if (reason == 0 || (reason >= XF_EXIT_PARSE_ARGUMENTS && reason <= XF_EXIT_CONNECT_NO_OR_MISSING_CREDENTIALS)) return reason; /* License error set */ else if (reason >= 0x100 && reason <= 0x10A) diff --git a/client/X11/xfreerdp.h b/client/X11/xfreerdp.h index b4488489ab0e..636e60ad1d5b 100644 --- a/client/X11/xfreerdp.h +++ b/client/X11/xfreerdp.h @@ -318,7 +318,32 @@ enum XF_EXIT_CODE XF_EXIT_CONN_FAILED = 131, XF_EXIT_AUTH_FAILURE = 132, XF_EXIT_NEGO_FAILURE = 133, - + XF_EXIT_LOGON_FAILURE = 134, + XF_EXIT_ACCOUNT_LOCKED_OUT = 135, + XF_EXIT_PRE_CONNECT_FAILED = 136, + XF_EXIT_CONNECT_UNDEFINED = 137, + XF_EXIT_POST_CONNECT_FAILED = 138, + XF_EXIT_DNS_ERROR = 139, + XF_EXIT_DNS_NAME_NOT_FOUND = 140, + XF_EXIT_CONNECT_FAILED = 141, + XF_EXIT_MCS_CONNECT_INITIAL_ERROR = 142, + XF_EXIT_TLS_CONNECT_FAILED = 143, + XF_EXIT_INSUFFICIENT_PRIVILEGES = 144, + XF_EXIT_CONNECT_CANCELLED = 145, + XF_EXIT_SECURITY_NEGO_CONNECT_FAILED = 146, + XF_EXIT_CONNECT_TRANSPORT_FAILED = 147, + XF_EXIT_CONNECT_PASSWORD_EXPIRED = 148, + XF_EXIT_CONNECT_PASSWORD_MUST_CHANGE = 149, + XF_EXIT_CONNECT_KDC_UNREACHABLE = 150, + XF_EXIT_CONNECT_ACCOUNT_DISABLED = 151, + XF_EXIT_CONNECT_PASSWORD_CERTAINLY_EXPIRED = 152, + XF_EXIT_CONNECT_CLIENT_REVOKED = 153, + XF_EXIT_CONNECT_WRONG_PASSWORD = 154, + XF_EXIT_CONNECT_ACCESS_DENIED = 155, + XF_EXIT_CONNECT_ACCOUNT_RESTRICTION = 156, + XF_EXIT_CONNECT_ACCOUNT_EXPIRED = 157, + XF_EXIT_CONNECT_LOGON_TYPE_NOT_GRANTED = 158, + XF_EXIT_CONNECT_NO_OR_MISSING_CREDENTIALS = 159, XF_EXIT_UNKNOWN = 255, }; diff --git a/client/common/cmdline.c b/client/common/cmdline.c index 6982eefe35a4..e6b3e55d89ea 100644 --- a/client/common/cmdline.c +++ b/client/common/cmdline.c @@ -1606,7 +1606,10 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, #if !defined(DEFINE_NO_DEPRECATED) if (compatibility) { + WLog_WARN(TAG, "----------------------------------------"); WLog_WARN(TAG, "Using deprecated command-line interface!"); + WLog_WARN(TAG, "This will be removed with FreeRDP 3!"); + WLog_WARN(TAG, "----------------------------------------"); return freerdp_client_parse_old_command_line_arguments(argc, argv, settings); } else diff --git a/libfreerdp/core/gateway/ncacn_http.c b/libfreerdp/core/gateway/ncacn_http.c index cffb378ebe44..f288a0f3cb76 100644 --- a/libfreerdp/core/gateway/ncacn_http.c +++ b/libfreerdp/core/gateway/ncacn_http.c @@ -105,7 +105,7 @@ BOOL rpc_ncacn_http_send_in_channel_request(RpcChannel* inChannel) BOOL rpc_ncacn_http_recv_in_channel_response(RpcChannel* inChannel, HttpResponse* response) { const char* token64 = NULL; - int ntlmTokenLength = 0; + size_t ntlmTokenLength = 0; BYTE* ntlmTokenData = NULL; rdpNtlm* ntlm; @@ -121,6 +121,7 @@ BOOL rpc_ncacn_http_recv_in_channel_response(RpcChannel* inChannel, HttpResponse if (ntlmTokenData && ntlmTokenLength) return ntlm_client_set_input_buffer(ntlm, FALSE, ntlmTokenData, ntlmTokenLength); + free(ntlmTokenData); return TRUE; } @@ -258,7 +259,7 @@ BOOL rpc_ncacn_http_send_out_channel_request(RpcChannel* outChannel, BOOL replac BOOL rpc_ncacn_http_recv_out_channel_response(RpcChannel* outChannel, HttpResponse* response) { const char* token64 = NULL; - int ntlmTokenLength = 0; + size_t ntlmTokenLength = 0; BYTE* ntlmTokenData = NULL; rdpNtlm* ntlm; @@ -274,5 +275,6 @@ BOOL rpc_ncacn_http_recv_out_channel_response(RpcChannel* outChannel, HttpRespon if (ntlmTokenData && ntlmTokenLength) return ntlm_client_set_input_buffer(ntlm, FALSE, ntlmTokenData, ntlmTokenLength); + free(ntlmTokenData); return TRUE; } diff --git a/libfreerdp/core/gateway/rdg.c b/libfreerdp/core/gateway/rdg.c index f9ed725015cb..72019ede8e2e 100644 --- a/libfreerdp/core/gateway/rdg.c +++ b/libfreerdp/core/gateway/rdg.c @@ -139,6 +139,7 @@ typedef struct WEBSOCKET_STATE state; wStream* responseStreamBuffer; } rdg_http_websocket_context; + typedef enum _CHUNK_STATE { ChunkStateLenghHeader, @@ -358,12 +359,15 @@ static BOOL rdg_write_chunked(BIO* bio, wStream* sPacket) len = Stream_Length(sChunk); if (len > INT_MAX) + { + Stream_Free(sChunk, TRUE); return FALSE; + } status = BIO_write(bio, Stream_Buffer(sChunk), (int)len); Stream_Free(sChunk, TRUE); - if (status != len) + if (status != (SSIZE_T)len) return FALSE; return TRUE; @@ -437,7 +441,7 @@ static BOOL rdg_write_websocket(BIO* bio, wStream* sPacket, WEBSOCKET_OPCODE opc status = BIO_write(bio, Stream_Buffer(sWS), Stream_Length(sWS)); Stream_Free(sWS, TRUE); - if (status != fullLen) + if (status != (SSIZE_T)fullLen) return FALSE; return TRUE; @@ -559,11 +563,13 @@ static BOOL rdg_websocket_reply_close(BIO* bio, wStream* s) { uint16_t data; Stream_Read_UINT16(s, data); - Stream_Write_UINT16(s, data ^ maskingKey1); + Stream_Write_UINT16(closeFrame, data ^ maskingKey1); } Stream_SealLength(closeFrame); status = BIO_write(bio, Stream_Buffer(closeFrame), Stream_Length(closeFrame)); + Stream_Free(closeFrame, TRUE); + /* server MUST close socket now. The server is not allowed anymore to * send frames but if he does, nothing bad would happen */ if (status < 0) @@ -742,7 +748,6 @@ static int rdg_websocket_read(BIO* bio, BYTE* pBuffer, size_t size, TAG, "Websocket Server sends data with masking key. This is against RFC 6455."); return -1; } - break; case WebSocketStatePayload: { status = rdg_websocket_handle_payload(bio, pBuffer, size, encodingContext); @@ -761,6 +766,7 @@ static int rdg_websocket_read(BIO* bio, BYTE* pBuffer, size_t size, /* should be unreachable */ return -1; } + static int rdg_chuncked_read(BIO* bio, BYTE* pBuffer, size_t size, rdg_http_encoding_chunked_context* encodingContext) { @@ -832,9 +838,7 @@ static int rdg_chuncked_read(BIO* bio, BYTE* pBuffer, size_t size, else return (effectiveDataLen > 0 ? effectiveDataLen : status); } - *dst = '\0'; - /* strtoul is tricky, error are reported via errno, we also need * to ensure the result does not overflow */ errno = 0; @@ -868,10 +872,12 @@ static int rdg_socket_read(BIO* bio, BYTE* pBuffer, size_t size, rdg_http_encoding_context* encodingContext) { assert(encodingContext != NULL); + if (encodingContext->isWebsocketTransport) { return rdg_websocket_read(bio, pBuffer, size, &encodingContext->context.websocket); } + switch (encodingContext->httpTransferEncoding) { case TransferEncodingIdentity: @@ -881,7 +887,6 @@ static int rdg_socket_read(BIO* bio, BYTE* pBuffer, size_t size, default: return -1; } - return -1; /* should not be reached */ } static BOOL rdg_read_all(rdpTls* tls, BYTE* buffer, size_t size, @@ -893,7 +898,6 @@ static BOOL rdg_read_all(rdpTls* tls, BYTE* buffer, size_t size, while (readCount < size) { int status = rdg_socket_read(tls->bio, pBuffer, size - readCount, transferEncoding); - if (status <= 0) { if (!BIO_should_retry(tls->bio)) @@ -1169,7 +1173,7 @@ static wStream* rdg_build_http_request(rdpRdg* rdg, const char* method, goto out; } - http_request_set_transfer_encoding(request, transferEncoding); + http_request_set_transfer_encoding(request, transferEncoding); s = http_request_write(rdg->http, request); out: @@ -1186,7 +1190,7 @@ static BOOL rdg_handle_ntlm_challenge(rdpNtlm* ntlm, HttpResponse* response) BOOL continueNeeded = FALSE; size_t len; const char* token64 = NULL; - int ntlmTokenLength = 0; + size_t ntlmTokenLength = 0; BYTE* ntlmTokenData = NULL; long StatusCode; @@ -1852,7 +1856,6 @@ static BOOL rdg_establish_data_connection(rdpRdg* rdg, rdpTls* tls, const char* rdg->transferEncoding.context.websocket.responseStreamBuffer = NULL; return TRUE; - break; default: return FALSE; } @@ -1899,6 +1902,9 @@ static BOOL rdg_tunnel_connect(rdpRdg* rdg) if (!status) { + assert(rdg); + assert(rdg->context); + assert(rdg->context->rdp); rdg->context->rdp->transport->layer = TRANSPORT_LAYER_CLOSED; return FALSE; } @@ -1937,6 +1943,9 @@ BOOL rdg_connect(rdpRdg* rdg, DWORD timeout, BOOL* rpcFallback) if (!status) { + assert(rdg); + assert(rdg->context); + assert(rdg->context->rdp); rdg->context->rdp->transport->layer = TRANSPORT_LAYER_CLOSED; return FALSE; } @@ -2013,7 +2022,7 @@ static int rdg_write_websocket_data_packet(rdpRdg* rdg, const BYTE* buf, int isi /* mask as much as possible with 32bit access */ for (streamPos = 0; streamPos + 4 <= isize; streamPos += 4) { - uint32_t masked = *((uint32_t*)((BYTE*)buf + streamPos)) ^ maskingKey; + uint32_t masked = *((const uint32_t*)((const BYTE*)buf + streamPos)) ^ maskingKey; Stream_Write_UINT32(sWS, masked); } @@ -2021,7 +2030,7 @@ static int rdg_write_websocket_data_packet(rdpRdg* rdg, const BYTE* buf, int isi for (; streamPos < isize; streamPos++) { BYTE* partialMask = (BYTE*)(&maskingKey) + streamPos % 4; - BYTE masked = *((BYTE*)((BYTE*)buf + streamPos)) ^ *partialMask; + BYTE masked = *((const BYTE*)((const BYTE*)buf + streamPos)) ^ *partialMask; Stream_Write_UINT8(sWS, masked); } @@ -2068,7 +2077,10 @@ static int rdg_write_chunked_data_packet(rdpRdg* rdg, const BYTE* buf, int isize len = Stream_Length(sChunk); if (len > INT_MAX) + { + Stream_Free(sChunk, TRUE); return -1; + } status = tls_write_all(rdg->tlsIn, Stream_Buffer(sChunk), (int)len); Stream_Free(sChunk, TRUE); @@ -2089,8 +2101,6 @@ static int rdg_write_data_packet(rdpRdg* rdg, const BYTE* buf, int isize) } else return rdg_write_chunked_data_packet(rdg, buf, isize); - - return -1; } static BOOL rdg_process_close_packet(rdpRdg* rdg, wStream* s) @@ -2402,10 +2412,10 @@ static int rdg_bio_gets(BIO* bio, char* str, int size) return -2; } -static long rdg_bio_ctrl(BIO* bio, int cmd, long arg1, void* arg2) +static long rdg_bio_ctrl(BIO* in_bio, int cmd, long arg1, void* arg2) { long status = -1; - rdpRdg* rdg = (rdpRdg*)BIO_get_data(bio); + rdpRdg* rdg = (rdpRdg*)BIO_get_data(in_bio); rdpTls* tlsOut = rdg->tlsOut; rdpTls* tlsIn = rdg->tlsIn; @@ -2422,42 +2432,42 @@ static long rdg_bio_ctrl(BIO* bio, int cmd, long arg1, void* arg2) } else if (cmd == BIO_C_READ_BLOCKED) { - BIO* bio = tlsOut->bio; - status = BIO_read_blocked(bio); + BIO* cbio = tlsOut->bio; + status = BIO_read_blocked(cbio); } else if (cmd == BIO_C_WRITE_BLOCKED) { - BIO* bio = tlsIn->bio; + BIO* cbio = tlsIn->bio; if (rdg->transferEncoding.isWebsocketTransport) - bio = tlsOut->bio; + cbio = tlsOut->bio; - status = BIO_write_blocked(bio); + status = BIO_write_blocked(cbio); } else if (cmd == BIO_C_WAIT_READ) { int timeout = (int)arg1; - BIO* bio = tlsOut->bio; + BIO* cbio = tlsOut->bio; - if (BIO_read_blocked(bio)) - return BIO_wait_read(bio, timeout); - else if (BIO_write_blocked(bio)) - return BIO_wait_write(bio, timeout); + if (BIO_read_blocked(cbio)) + return BIO_wait_read(cbio, timeout); + else if (BIO_write_blocked(cbio)) + return BIO_wait_write(cbio, timeout); else status = 1; } else if (cmd == BIO_C_WAIT_WRITE) { int timeout = (int)arg1; - BIO* bio = tlsIn->bio; + BIO* cbio = tlsIn->bio; if (rdg->transferEncoding.isWebsocketTransport) - bio = tlsOut->bio; + cbio = tlsOut->bio; - if (BIO_write_blocked(bio)) - status = BIO_wait_write(bio, timeout); - else if (BIO_read_blocked(bio)) - status = BIO_wait_read(bio, timeout); + if (BIO_write_blocked(cbio)) + status = BIO_wait_write(cbio, timeout); + else if (BIO_read_blocked(cbio)) + status = BIO_wait_read(cbio, timeout); else status = 1; } @@ -2619,6 +2629,7 @@ void rdg_free(rdpRdg* rdg) BIO_free_all(rdg->frontBio); DeleteCriticalSection(&rdg->writeSection); + if (rdg->transferEncoding.isWebsocketTransport) { if (rdg->transferEncoding.context.websocket.responseStreamBuffer != NULL) diff --git a/libfreerdp/core/gateway/rpc.c b/libfreerdp/core/gateway/rpc.c index c5f85922e07b..4d6bf9222c67 100644 --- a/libfreerdp/core/gateway/rpc.c +++ b/libfreerdp/core/gateway/rpc.c @@ -24,6 +24,7 @@ #endif #include +#include #include #include #include @@ -46,6 +47,7 @@ #include "rpc_client.h" #include "rpc.h" +#include "rts.h" #define TAG FREERDP_TAG("core.gateway.rpc") @@ -88,8 +90,10 @@ static const char* PTYPE_STRINGS[] = { "PTYPE_REQUEST", "PTYPE_PING", * */ -void rpc_pdu_header_print(rpcconn_hdr_t* header) +void rpc_pdu_header_print(const rpcconn_hdr_t* header) { + assert(header); + WLog_INFO(TAG, "rpc_vers: %" PRIu8 "", header->common.rpc_vers); WLog_INFO(TAG, "rpc_vers_minor: %" PRIu8 "", header->common.rpc_vers_minor); @@ -139,26 +143,30 @@ void rpc_pdu_header_print(rpcconn_hdr_t* header) } } -void rpc_pdu_header_init(rdpRpc* rpc, rpcconn_common_hdr_t* header) +rpcconn_common_hdr_t rpc_pdu_header_init(const rdpRpc* rpc) { - header->rpc_vers = rpc->rpc_vers; - header->rpc_vers_minor = rpc->rpc_vers_minor; - header->packed_drep[0] = rpc->packed_drep[0]; - header->packed_drep[1] = rpc->packed_drep[1]; - header->packed_drep[2] = rpc->packed_drep[2]; - header->packed_drep[3] = rpc->packed_drep[3]; + rpcconn_common_hdr_t header = { 0 }; + assert(rpc); + + header.rpc_vers = rpc->rpc_vers; + header.rpc_vers_minor = rpc->rpc_vers_minor; + header.packed_drep[0] = rpc->packed_drep[0]; + header.packed_drep[1] = rpc->packed_drep[1]; + header.packed_drep[2] = rpc->packed_drep[2]; + header.packed_drep[3] = rpc->packed_drep[3]; + return header; } -UINT32 rpc_offset_align(UINT32* offset, UINT32 alignment) +size_t rpc_offset_align(size_t* offset, size_t alignment) { - UINT32 pad; + size_t pad; pad = *offset; *offset = (*offset + alignment - 1) & ~(alignment - 1); pad = *offset - pad; return pad; } -UINT32 rpc_offset_pad(UINT32* offset, UINT32 pad) +size_t rpc_offset_pad(size_t* offset, size_t pad) { *offset += pad; return pad; @@ -239,64 +247,67 @@ UINT32 rpc_offset_pad(UINT32* offset, UINT32 pad) * */ -BOOL rpc_get_stub_data_info(rdpRpc* rpc, BYTE* buffer, UINT32* offset, UINT32* length) +BOOL rpc_get_stub_data_info(const rpcconn_hdr_t* header, size_t* poffset, size_t* length) { - UINT32 alloc_hint = 0; - rpcconn_hdr_t* header; + size_t used = 0; + size_t offset = 0; + BOOL rc = FALSE; UINT32 frag_length; UINT32 auth_length; - UINT32 auth_pad_length; + UINT32 auth_pad_length = 0; UINT32 sec_trailer_offset; - rpc_sec_trailer* sec_trailer; - *offset = RPC_COMMON_FIELDS_LENGTH; - header = ((rpcconn_hdr_t*)buffer); + const rpc_sec_trailer* sec_trailer = NULL; + + assert(header); + assert(poffset); + assert(length); + + offset = RPC_COMMON_FIELDS_LENGTH; switch (header->common.ptype) { case PTYPE_RESPONSE: - *offset += 8; - rpc_offset_align(offset, 8); - alloc_hint = header->response.alloc_hint; + offset += 8; + rpc_offset_align(&offset, 8); + sec_trailer = &header->response.auth_verifier; break; case PTYPE_REQUEST: - *offset += 4; - rpc_offset_align(offset, 8); - alloc_hint = header->request.alloc_hint; + offset += 4; + rpc_offset_align(&offset, 8); + sec_trailer = &header->request.auth_verifier; break; case PTYPE_RTS: - *offset += 4; + offset += 4; break; default: WLog_ERR(TAG, "Unknown PTYPE: 0x%02" PRIX8 "", header->common.ptype); - return FALSE; + goto fail; } - if (!length) - return TRUE; + frag_length = header->common.frag_length; + auth_length = header->common.auth_length; + + if (poffset) + *poffset = offset; - if (header->common.ptype == PTYPE_REQUEST) + /* The fragment must be larger than the authentication trailer */ + used = offset + auth_length + 8ull; + if (sec_trailer) { - UINT32 sec_trailer_offset; - sec_trailer_offset = header->common.frag_length - header->common.auth_length - 8; - *length = sec_trailer_offset - *offset; - return TRUE; + auth_pad_length = sec_trailer->auth_pad_length; + used += sec_trailer->auth_pad_length; } - frag_length = header->common.frag_length; - auth_length = header->common.auth_length; + if (frag_length < used) + goto fail; + + if (!length) + return TRUE; + sec_trailer_offset = frag_length - auth_length - 8; - sec_trailer = (rpc_sec_trailer*)&buffer[sec_trailer_offset]; - auth_pad_length = sec_trailer->auth_pad_length; -#if 0 - WLog_DBG(TAG, - "sec_trailer: type: %"PRIu8" level: %"PRIu8" pad_length: %"PRIu8" reserved: %"PRIu8" context_id: %"PRIu32"", - sec_trailer->auth_type, sec_trailer->auth_level, - sec_trailer->auth_pad_length, sec_trailer->auth_reserved, - sec_trailer->auth_context_id); -#endif /** * According to [MS-RPCE], auth_pad_length is the number of padding @@ -310,18 +321,21 @@ BOOL rpc_get_stub_data_info(rdpRpc* rpc, BYTE* buffer, UINT32* offset, UINT32* l auth_length, (frag_length - (sec_trailer_offset + 8))); } - *length = frag_length - auth_length - 24 - 8 - auth_pad_length; - return TRUE; + *length = sec_trailer_offset - auth_pad_length - offset; + + rc = TRUE; +fail: + return rc; } SSIZE_T rpc_channel_read(RpcChannel* channel, wStream* s, size_t length) { int status; - if (!channel) + if (!channel || (length > INT32_MAX)) return -1; - status = BIO_read(channel->tls->bio, Stream_Pointer(s), length); + status = BIO_read(channel->tls->bio, Stream_Pointer(s), (INT32)length); if (status > 0) { @@ -340,10 +354,10 @@ SSIZE_T rpc_channel_write(RpcChannel* channel, const BYTE* data, size_t length) { int status; - if (!channel) + if (!channel || (length > INT32_MAX)) return -1; - status = tls_write_all(channel->tls, data, length); + status = tls_write_all(channel->tls, data, (INT32)length); return status; } @@ -629,7 +643,7 @@ static void rpc_virtual_connection_free(RpcVirtualConnection* connection) free(connection); } -static BOOL rpc_channel_tls_connect(RpcChannel* channel, int timeout) +static BOOL rpc_channel_tls_connect(RpcChannel* channel, UINT32 timeout) { int sockfd; rdpTls* tls; @@ -719,7 +733,7 @@ static BOOL rpc_channel_tls_connect(RpcChannel* channel, int timeout) return TRUE; } -static int rpc_in_channel_connect(RpcInChannel* inChannel, int timeout) +static int rpc_in_channel_connect(RpcInChannel* inChannel, UINT32 timeout) { rdpContext* context; @@ -814,7 +828,7 @@ int rpc_out_channel_replacement_connect(RpcOutChannel* outChannel, int timeout) return 1; } -BOOL rpc_connect(rdpRpc* rpc, int timeout) +BOOL rpc_connect(rdpRpc* rpc, UINT32 timeout) { RpcInChannel* inChannel; RpcOutChannel* outChannel; @@ -840,7 +854,15 @@ BOOL rpc_connect(rdpRpc* rpc, int timeout) rdpRpc* rpc_new(rdpTransport* transport) { - rdpRpc* rpc = (rdpRpc*)calloc(1, sizeof(rdpRpc)); + rdpContext* context; + rdpRpc* rpc; + + assert(transport); + + context = transport->context; + assert(context); + + rpc = (rdpRpc*)calloc(1, sizeof(rdpRpc)); if (!rpc) return NULL; @@ -848,7 +870,7 @@ rdpRpc* rpc_new(rdpTransport* transport) rpc->State = RPC_CLIENT_STATE_INITIAL; rpc->transport = transport; rpc->settings = transport->settings; - rpc->context = transport->context; + rpc->context = context; rpc->SendSeqNum = 0; rpc->ntlm = ntlm_new(); @@ -873,7 +895,7 @@ rdpRpc* rpc_new(rdpTransport* transport) rpc->CurrentKeepAliveInterval = rpc->KeepAliveInterval; rpc->CurrentKeepAliveTime = 0; rpc->CallId = 2; - rpc->client = rpc_client_new(rpc->context, rpc->max_recv_frag); + rpc->client = rpc_client_new(context, rpc->max_recv_frag); if (!rpc->client) goto out_free; diff --git a/libfreerdp/core/gateway/rpc.h b/libfreerdp/core/gateway/rpc.h index 1a58fe450a4e..26eebf131a42 100644 --- a/libfreerdp/core/gateway/rpc.h +++ b/libfreerdp/core/gateway/rpc.h @@ -73,7 +73,6 @@ typedef struct _RPC_PDU #include "../tcp.h" #include "../transport.h" -#include "rts.h" #include "http.h" #include "ntlm.h" @@ -525,7 +524,8 @@ typedef struct rpcconn_common_hdr_t header; } rpcconn_shutdown_hdr_t; -typedef union { +typedef union +{ rpcconn_common_hdr_t common; rpcconn_alter_context_hdr_t alter_context; rpcconn_alter_context_response_hdr_t alter_context_response; @@ -767,14 +767,14 @@ struct rdp_rpc RpcVirtualConnection* VirtualConnection; }; -FREERDP_LOCAL void rpc_pdu_header_print(rpcconn_hdr_t* header); -FREERDP_LOCAL void rpc_pdu_header_init(rdpRpc* rpc, rpcconn_common_hdr_t* header); +FREERDP_LOCAL void rpc_pdu_header_print(const rpcconn_hdr_t* header); +FREERDP_LOCAL rpcconn_common_hdr_t rpc_pdu_header_init(const rdpRpc* rpc); -FREERDP_LOCAL UINT32 rpc_offset_align(UINT32* offset, UINT32 alignment); -FREERDP_LOCAL UINT32 rpc_offset_pad(UINT32* offset, UINT32 pad); +FREERDP_LOCAL size_t rpc_offset_align(size_t* offset, size_t alignment); +FREERDP_LOCAL size_t rpc_offset_pad(size_t* offset, size_t pad); -FREERDP_LOCAL BOOL rpc_get_stub_data_info(rdpRpc* rpc, BYTE* header, UINT32* offset, - UINT32* length); +FREERDP_LOCAL BOOL rpc_get_stub_data_info(const rpcconn_hdr_t* header, size_t* offset, + size_t* length); FREERDP_LOCAL SSIZE_T rpc_channel_write(RpcChannel* channel, const BYTE* data, size_t length); @@ -794,7 +794,7 @@ FREERDP_LOCAL BOOL rpc_virtual_connection_transition_to_state(rdpRpc* rpc, RpcVirtualConnection* connection, VIRTUAL_CONNECTION_STATE state); -FREERDP_LOCAL BOOL rpc_connect(rdpRpc* rpc, int timeout); +FREERDP_LOCAL BOOL rpc_connect(rdpRpc* rpc, UINT32 timeout); FREERDP_LOCAL rdpRpc* rpc_new(rdpTransport* transport); FREERDP_LOCAL void rpc_free(rdpRpc* rpc); diff --git a/libfreerdp/core/gateway/rpc_bind.c b/libfreerdp/core/gateway/rpc_bind.c index 98ed9a9dc55c..bdf54d5a0b63 100644 --- a/libfreerdp/core/gateway/rpc_bind.c +++ b/libfreerdp/core/gateway/rpc_bind.c @@ -22,11 +22,14 @@ #endif #include +#include #include #include "rpc_client.h" +#include "rts.h" + #include "rpc_bind.h" #define TAG FREERDP_TAG("core.gateway.rpc") @@ -106,18 +109,32 @@ int rpc_send_bind_pdu(rdpRpc* rpc) { BOOL continueNeeded = FALSE; int status = -1; - BYTE* buffer = NULL; + wStream* buffer = NULL; UINT32 offset; - UINT32 length; RpcClientCall* clientCall; p_cont_elem_t* p_cont_elem; - rpcconn_bind_hdr_t* bind_pdu = NULL; + rpcconn_bind_hdr_t bind_pdu = { 0 }; BOOL promptPassword = FALSE; - rdpSettings* settings = rpc->settings; - freerdp* instance = (freerdp*)settings->instance; - RpcVirtualConnection* connection = rpc->VirtualConnection; - RpcInChannel* inChannel = connection->DefaultInChannel; + rdpSettings* settings; + freerdp* instance; + RpcVirtualConnection* connection; + RpcInChannel* inChannel; const SecBuffer* sbuffer = NULL; + + assert(rpc); + + settings = rpc->settings; + assert(settings); + + instance = (freerdp*)settings->instance; + assert(instance); + + connection = rpc->VirtualConnection; + + assert(connection); + + inChannel = connection->DefaultInChannel; + WLog_DBG(TAG, "Sending Bind PDU"); ntlm_free(rpc->ntlm); rpc->ntlm = ntlm_new(); @@ -180,36 +197,31 @@ int rpc_send_bind_pdu(rdpRpc* rpc) if (!continueNeeded) goto fail; - bind_pdu = (rpcconn_bind_hdr_t*)calloc(1, sizeof(rpcconn_bind_hdr_t)); - - if (!bind_pdu) - goto fail; - sbuffer = ntlm_client_get_output_buffer(rpc->ntlm); if (!sbuffer) goto fail; - rpc_pdu_header_init(rpc, &bind_pdu->header); - bind_pdu->header.auth_length = (UINT16)sbuffer->cbBuffer; - bind_pdu->auth_verifier.auth_value = sbuffer->pvBuffer; - bind_pdu->header.ptype = PTYPE_BIND; - bind_pdu->header.pfc_flags = + bind_pdu.header = rpc_pdu_header_init(rpc); + bind_pdu.header.auth_length = (UINT16)sbuffer->cbBuffer; + bind_pdu.auth_verifier.auth_value = sbuffer->pvBuffer; + bind_pdu.header.ptype = PTYPE_BIND; + bind_pdu.header.pfc_flags = PFC_FIRST_FRAG | PFC_LAST_FRAG | PFC_SUPPORT_HEADER_SIGN | PFC_CONC_MPX; - bind_pdu->header.call_id = 2; - bind_pdu->max_xmit_frag = rpc->max_xmit_frag; - bind_pdu->max_recv_frag = rpc->max_recv_frag; - bind_pdu->assoc_group_id = 0; - bind_pdu->p_context_elem.n_context_elem = 2; - bind_pdu->p_context_elem.reserved = 0; - bind_pdu->p_context_elem.reserved2 = 0; - bind_pdu->p_context_elem.p_cont_elem = - calloc(bind_pdu->p_context_elem.n_context_elem, sizeof(p_cont_elem_t)); - - if (!bind_pdu->p_context_elem.p_cont_elem) + bind_pdu.header.call_id = 2; + bind_pdu.max_xmit_frag = rpc->max_xmit_frag; + bind_pdu.max_recv_frag = rpc->max_recv_frag; + bind_pdu.assoc_group_id = 0; + bind_pdu.p_context_elem.n_context_elem = 2; + bind_pdu.p_context_elem.reserved = 0; + bind_pdu.p_context_elem.reserved2 = 0; + bind_pdu.p_context_elem.p_cont_elem = + calloc(bind_pdu.p_context_elem.n_context_elem, sizeof(p_cont_elem_t)); + + if (!bind_pdu.p_context_elem.p_cont_elem) goto fail; - p_cont_elem = &bind_pdu->p_context_elem.p_cont_elem[0]; + p_cont_elem = &bind_pdu.p_context_elem.p_cont_elem[0]; p_cont_elem->p_cont_id = 0; p_cont_elem->n_transfer_syn = 1; p_cont_elem->reserved = 0; @@ -222,7 +234,7 @@ int rpc_send_bind_pdu(rdpRpc* rpc) CopyMemory(&(p_cont_elem->transfer_syntaxes[0].if_uuid), &NDR_UUID, sizeof(p_uuid_t)); p_cont_elem->transfer_syntaxes[0].if_version = NDR_SYNTAX_IF_VERSION; - p_cont_elem = &bind_pdu->p_context_elem.p_cont_elem[1]; + p_cont_elem = &bind_pdu.p_context_elem.p_cont_elem[1]; p_cont_elem->p_cont_id = 1; p_cont_elem->n_transfer_syn = 1; p_cont_elem->reserved = 0; @@ -236,32 +248,23 @@ int rpc_send_bind_pdu(rdpRpc* rpc) CopyMemory(&(p_cont_elem->transfer_syntaxes[0].if_uuid), &BTFN_UUID, sizeof(p_uuid_t)); p_cont_elem->transfer_syntaxes[0].if_version = BTFN_SYNTAX_IF_VERSION; offset = 116; - bind_pdu->auth_verifier.auth_pad_length = rpc_offset_align(&offset, 4); - bind_pdu->auth_verifier.auth_type = RPC_C_AUTHN_WINNT; - bind_pdu->auth_verifier.auth_level = RPC_C_AUTHN_LEVEL_PKT_INTEGRITY; - bind_pdu->auth_verifier.auth_reserved = 0x00; - bind_pdu->auth_verifier.auth_context_id = 0x00000000; - offset += (8 + bind_pdu->header.auth_length); - bind_pdu->header.frag_length = offset; - buffer = (BYTE*)malloc(bind_pdu->header.frag_length); + + bind_pdu.auth_verifier.auth_type = RPC_C_AUTHN_WINNT; + bind_pdu.auth_verifier.auth_level = RPC_C_AUTHN_LEVEL_PKT_INTEGRITY; + bind_pdu.auth_verifier.auth_reserved = 0x00; + bind_pdu.auth_verifier.auth_context_id = 0x00000000; + offset += (8 + bind_pdu.header.auth_length); + bind_pdu.header.frag_length = offset; + + buffer = Stream_New(NULL, bind_pdu.header.frag_length); if (!buffer) goto fail; - CopyMemory(buffer, bind_pdu, 24); - CopyMemory(&buffer[24], &bind_pdu->p_context_elem, 4); - CopyMemory(&buffer[28], &bind_pdu->p_context_elem.p_cont_elem[0], 24); - CopyMemory(&buffer[52], bind_pdu->p_context_elem.p_cont_elem[0].transfer_syntaxes, 20); - CopyMemory(&buffer[72], &bind_pdu->p_context_elem.p_cont_elem[1], 24); - CopyMemory(&buffer[96], bind_pdu->p_context_elem.p_cont_elem[1].transfer_syntaxes, 20); - offset = 116; - rpc_offset_pad(&offset, bind_pdu->auth_verifier.auth_pad_length); - CopyMemory(&buffer[offset], &bind_pdu->auth_verifier.auth_type, 8); - CopyMemory(&buffer[offset + 8], bind_pdu->auth_verifier.auth_value, - bind_pdu->header.auth_length); - offset += (8 + bind_pdu->header.auth_length); - length = bind_pdu->header.frag_length; - clientCall = rpc_client_call_new(bind_pdu->header.call_id, 0); + if (!rts_write_pdu_bind(buffer, &bind_pdu)) + goto fail; + + clientCall = rpc_client_call_new(bind_pdu.header.call_id, 0); if (!clientCall) goto fail; @@ -272,22 +275,19 @@ int rpc_send_bind_pdu(rdpRpc* rpc) goto fail; } - status = rpc_in_channel_send_pdu(inChannel, buffer, length); + Stream_SealLength(buffer); + status = rpc_in_channel_send_pdu(inChannel, Stream_Buffer(buffer), Stream_Length(buffer)); fail: - if (bind_pdu) + if (bind_pdu.p_context_elem.p_cont_elem) { - if (bind_pdu->p_context_elem.p_cont_elem) - { - free(bind_pdu->p_context_elem.p_cont_elem[0].transfer_syntaxes); - free(bind_pdu->p_context_elem.p_cont_elem[1].transfer_syntaxes); - } - - free(bind_pdu->p_context_elem.p_cont_elem); + free(bind_pdu.p_context_elem.p_cont_elem[0].transfer_syntaxes); + free(bind_pdu.p_context_elem.p_cont_elem[1].transfer_syntaxes); } - free(bind_pdu); - free(buffer); + free(bind_pdu.p_context_elem.p_cont_elem); + + Stream_Free(buffer, TRUE); return (status > 0) ? 1 : -1; } @@ -317,31 +317,47 @@ int rpc_send_bind_pdu(rdpRpc* rpc) * example. */ -int rpc_recv_bind_ack_pdu(rdpRpc* rpc, BYTE* buffer, UINT32 length) +BOOL rpc_recv_bind_ack_pdu(rdpRpc* rpc, wStream* s) { + BOOL rc = FALSE; BOOL continueNeeded = FALSE; - BYTE* auth_data; - rpcconn_hdr_t* header; - header = (rpcconn_hdr_t*)buffer; + const BYTE* auth_data; + size_t pos, end; + rpcconn_hdr_t header = { 0 }; + + assert(rpc); + assert(rpc->ntlm); + assert(s); + + pos = Stream_GetPosition(s); + if (!rts_read_pdu_header(s, &header)) + goto fail; + WLog_DBG(TAG, "Receiving BindAck PDU"); - if (!rpc || !rpc->ntlm) - return -1; + rpc->max_recv_frag = header.bind_ack.max_xmit_frag; + rpc->max_xmit_frag = header.bind_ack.max_recv_frag; - rpc->max_recv_frag = header->bind_ack.max_xmit_frag; - rpc->max_xmit_frag = header->bind_ack.max_recv_frag; - auth_data = buffer + (header->common.frag_length - header->common.auth_length); + /* Get the correct offset in the input data and pass that on as input buffer. + * rts_read_pdu_header did already do consistency checks */ + end = Stream_GetPosition(s); + Stream_SetPosition(s, pos + header.common.frag_length - header.common.auth_length); + auth_data = Stream_Pointer(s); + Stream_SetPosition(s, end); - if (!ntlm_client_set_input_buffer(rpc->ntlm, TRUE, auth_data, header->common.auth_length)) - return -1; + if (!ntlm_client_set_input_buffer(rpc->ntlm, TRUE, auth_data, header.common.auth_length)) + goto fail; if (!ntlm_authenticate(rpc->ntlm, &continueNeeded)) - return -1; + goto fail; if (continueNeeded) - return -1; + goto fail; - return (int)length; + rc = TRUE; +fail: + rts_free_pdu_header(&header, FALSE); + return rc; } /** @@ -354,68 +370,63 @@ int rpc_recv_bind_ack_pdu(rdpRpc* rpc, BYTE* buffer, UINT32 length) int rpc_send_rpc_auth_3_pdu(rdpRpc* rpc) { int status = -1; - BYTE* buffer; - UINT32 offset; - UINT32 length; + wStream* buffer; + size_t offset; const SecBuffer* sbuffer; RpcClientCall* clientCall; - rpcconn_rpc_auth_3_hdr_t* auth_3_pdu; - RpcVirtualConnection* connection = rpc->VirtualConnection; - RpcInChannel* inChannel = connection->DefaultInChannel; - WLog_DBG(TAG, "Sending RpcAuth3 PDU"); - auth_3_pdu = (rpcconn_rpc_auth_3_hdr_t*)calloc(1, sizeof(rpcconn_rpc_auth_3_hdr_t)); + rpcconn_rpc_auth_3_hdr_t auth_3_pdu = { 0 }; + RpcVirtualConnection* connection; + RpcInChannel* inChannel; - if (!auth_3_pdu) - return -1; + assert(rpc); + + connection = rpc->VirtualConnection; + assert(connection); + + inChannel = connection->DefaultInChannel; + assert(inChannel); + + WLog_DBG(TAG, "Sending RpcAuth3 PDU"); sbuffer = ntlm_client_get_output_buffer(rpc->ntlm); if (!sbuffer) - { - free(auth_3_pdu); return -1; - } - rpc_pdu_header_init(rpc, &auth_3_pdu->header); - auth_3_pdu->header.auth_length = (UINT16)sbuffer->cbBuffer; - auth_3_pdu->auth_verifier.auth_value = sbuffer->pvBuffer; - auth_3_pdu->header.ptype = PTYPE_RPC_AUTH_3; - auth_3_pdu->header.pfc_flags = PFC_FIRST_FRAG | PFC_LAST_FRAG | PFC_CONC_MPX; - auth_3_pdu->header.call_id = 2; - auth_3_pdu->max_xmit_frag = rpc->max_xmit_frag; - auth_3_pdu->max_recv_frag = rpc->max_recv_frag; + auth_3_pdu.header = rpc_pdu_header_init(rpc); + auth_3_pdu.header.auth_length = (UINT16)sbuffer->cbBuffer; + auth_3_pdu.auth_verifier.auth_value = sbuffer->pvBuffer; + auth_3_pdu.header.ptype = PTYPE_RPC_AUTH_3; + auth_3_pdu.header.pfc_flags = PFC_FIRST_FRAG | PFC_LAST_FRAG | PFC_CONC_MPX; + auth_3_pdu.header.call_id = 2; + auth_3_pdu.max_xmit_frag = rpc->max_xmit_frag; + auth_3_pdu.max_recv_frag = rpc->max_recv_frag; offset = 20; - auth_3_pdu->auth_verifier.auth_pad_length = rpc_offset_align(&offset, 4); - auth_3_pdu->auth_verifier.auth_type = RPC_C_AUTHN_WINNT; - auth_3_pdu->auth_verifier.auth_level = RPC_C_AUTHN_LEVEL_PKT_INTEGRITY; - auth_3_pdu->auth_verifier.auth_reserved = 0x00; - auth_3_pdu->auth_verifier.auth_context_id = 0x00000000; - offset += (8 + auth_3_pdu->header.auth_length); - auth_3_pdu->header.frag_length = offset; - buffer = (BYTE*)malloc(auth_3_pdu->header.frag_length); + auth_3_pdu.auth_verifier.auth_pad_length = rpc_offset_align(&offset, 4); + auth_3_pdu.auth_verifier.auth_type = RPC_C_AUTHN_WINNT; + auth_3_pdu.auth_verifier.auth_level = RPC_C_AUTHN_LEVEL_PKT_INTEGRITY; + auth_3_pdu.auth_verifier.auth_reserved = 0x00; + auth_3_pdu.auth_verifier.auth_context_id = 0x00000000; + offset += (8 + auth_3_pdu.header.auth_length); + auth_3_pdu.header.frag_length = offset; + + buffer = Stream_New(NULL, auth_3_pdu.header.frag_length); if (!buffer) - { - free(auth_3_pdu); return -1; - } - CopyMemory(buffer, auth_3_pdu, 20); - offset = 20; - rpc_offset_pad(&offset, auth_3_pdu->auth_verifier.auth_pad_length); - CopyMemory(&buffer[offset], &auth_3_pdu->auth_verifier.auth_type, 8); - CopyMemory(&buffer[offset + 8], auth_3_pdu->auth_verifier.auth_value, - auth_3_pdu->header.auth_length); - offset += (8 + auth_3_pdu->header.auth_length); - length = auth_3_pdu->header.frag_length; - clientCall = rpc_client_call_new(auth_3_pdu->header.call_id, 0); + if (!rts_write_pdu_auth3(buffer, &auth_3_pdu)) + goto fail; + + clientCall = rpc_client_call_new(auth_3_pdu.header.call_id, 0); if (ArrayList_Add(rpc->client->ClientCallList, clientCall) >= 0) { - status = rpc_in_channel_send_pdu(inChannel, buffer, length); + Stream_SealLength(buffer); + status = rpc_in_channel_send_pdu(inChannel, Stream_Buffer(buffer), Stream_Length(buffer)); } - free(auth_3_pdu); - free(buffer); +fail: + Stream_Free(buffer, TRUE); return (status > 0) ? 1 : -1; } diff --git a/libfreerdp/core/gateway/rpc_bind.h b/libfreerdp/core/gateway/rpc_bind.h index 759555f07a73..69758e5219cd 100644 --- a/libfreerdp/core/gateway/rpc_bind.h +++ b/libfreerdp/core/gateway/rpc_bind.h @@ -35,7 +35,7 @@ FREERDP_LOCAL extern const p_uuid_t BTFN_UUID; #define BTFN_SYNTAX_IF_VERSION 0x00000001 FREERDP_LOCAL int rpc_send_bind_pdu(rdpRpc* rpc); -FREERDP_LOCAL int rpc_recv_bind_ack_pdu(rdpRpc* rpc, BYTE* buffer, UINT32 length); +FREERDP_LOCAL BOOL rpc_recv_bind_ack_pdu(rdpRpc* rpc, wStream* s); FREERDP_LOCAL int rpc_send_rpc_auth_3_pdu(rdpRpc* rpc); #endif /* FREERDP_LIB_CORE_GATEWAY_RPC_BIND_H */ diff --git a/libfreerdp/core/gateway/rpc_client.c b/libfreerdp/core/gateway/rpc_client.c index 845bbe4b8598..fb32d3c5ed80 100644 --- a/libfreerdp/core/gateway/rpc_client.c +++ b/libfreerdp/core/gateway/rpc_client.c @@ -24,6 +24,7 @@ #include #include +#include #include #include #include @@ -35,6 +36,8 @@ #include "rpc_bind.h" #include "rpc_fault.h" #include "rpc_client.h" +#include "rts_signature.h" + #include "../rdp.h" #include "../proxy.h" @@ -99,7 +102,7 @@ static int rpc_client_receive_pipe_write(RpcClient* client, const BYTE* buffer, int rpc_client_receive_pipe_read(RpcClient* client, BYTE* buffer, size_t length) { int index = 0; - int status = 0; + size_t status = 0; int nchunks = 0; DataChunk chunks[2]; @@ -122,7 +125,10 @@ int rpc_client_receive_pipe_read(RpcClient* client, BYTE* buffer, size_t length) ResetEvent(client->PipeEvent); LeaveCriticalSection(&(client->PipeLock)); - return status; + + if (status > INT_MAX) + return -1; + return (int)status; } static int rpc_client_transition_to_state(rdpRpc* rpc, RPC_CLIENT_STATE state) @@ -173,8 +179,15 @@ static int rpc_client_transition_to_state(rdpRpc* rpc, RPC_CLIENT_STATE state) static int rpc_client_recv_pdu(rdpRpc* rpc, RPC_PDU* pdu) { int status = -1; - rpcconn_rts_hdr_t* rts; - rdpTsg* tsg = rpc->transport->tsg; + rdpTsg* tsg; + + assert(rpc); + assert(pdu); + + Stream_SealLength(pdu->s); + Stream_SetPosition(pdu->s, 0); + + tsg = rpc->transport->tsg; if (rpc->VirtualConnection->State < VIRTUAL_CONNECTION_STATE_OPENED) { @@ -187,17 +200,13 @@ static int rpc_client_recv_pdu(rdpRpc* rpc, RPC_PDU* pdu) break; case VIRTUAL_CONNECTION_STATE_WAIT_A3W: - rts = (rpcconn_rts_hdr_t*)Stream_Buffer(pdu->s); - - if (!rts_match_pdu_signature(&RTS_PDU_CONN_A3_SIGNATURE, rts)) + if (!rts_match_pdu_signature(&RTS_PDU_CONN_A3_SIGNATURE, pdu->s, NULL)) { WLog_ERR(TAG, "unexpected RTS PDU: Expected CONN/A3"); return -1; } - status = rts_recv_CONN_A3_pdu(rpc, Stream_Buffer(pdu->s), Stream_Length(pdu->s)); - - if (status < 0) + if (!rts_recv_CONN_A3_pdu(rpc, pdu->s)) { WLog_ERR(TAG, "rts_recv_CONN_A3_pdu failure"); return -1; @@ -209,17 +218,13 @@ static int rpc_client_recv_pdu(rdpRpc* rpc, RPC_PDU* pdu) break; case VIRTUAL_CONNECTION_STATE_WAIT_C2: - rts = (rpcconn_rts_hdr_t*)Stream_Buffer(pdu->s); - - if (!rts_match_pdu_signature(&RTS_PDU_CONN_C2_SIGNATURE, rts)) + if (!rts_match_pdu_signature(&RTS_PDU_CONN_C2_SIGNATURE, pdu->s, NULL)) { WLog_ERR(TAG, "unexpected RTS PDU: Expected CONN/C2"); return -1; } - status = rts_recv_CONN_C2_pdu(rpc, Stream_Buffer(pdu->s), Stream_Length(pdu->s)); - - if (status < 0) + if (!rts_recv_CONN_C2_pdu(rpc, pdu->s)) { WLog_ERR(TAG, "rts_recv_CONN_C2_pdu failure"); return -1; @@ -252,7 +257,7 @@ static int rpc_client_recv_pdu(rdpRpc* rpc, RPC_PDU* pdu) { if (pdu->Type == PTYPE_BIND_ACK) { - if (rpc_recv_bind_ack_pdu(rpc, Stream_Buffer(pdu->s), Stream_Length(pdu->s)) <= 0) + if (!rpc_recv_bind_ack_pdu(rpc, pdu->s)) { WLog_ERR(TAG, "rpc_recv_bind_ack_pdu failure"); return -1; @@ -301,90 +306,117 @@ static int rpc_client_recv_pdu(rdpRpc* rpc, RPC_PDU* pdu) static int rpc_client_recv_fragment(rdpRpc* rpc, wStream* fragment) { - BYTE* buffer; + int rc = -1; RPC_PDU* pdu; - UINT32 StubOffset; - UINT32 StubLength; + size_t StubOffset; + size_t StubLength; RpcClientCall* call; - rpcconn_hdr_t* header; + rpcconn_hdr_t header = { 0 }; + + assert(rpc); + assert(rpc->client); + assert(fragment); + pdu = rpc->client->pdu; - buffer = (BYTE*)Stream_Buffer(fragment); - header = (rpcconn_hdr_t*)Stream_Buffer(fragment); + assert(pdu); + + Stream_SealLength(fragment); + Stream_SetPosition(fragment, 0); - if (header->common.ptype == PTYPE_RESPONSE) + if (!rts_read_pdu_header(fragment, &header)) + goto fail; + + if (header.common.ptype == PTYPE_RESPONSE) { - rpc->VirtualConnection->DefaultOutChannel->BytesReceived += header->common.frag_length; + rpc->VirtualConnection->DefaultOutChannel->BytesReceived += header.common.frag_length; rpc->VirtualConnection->DefaultOutChannel->ReceiverAvailableWindow -= - header->common.frag_length; + header.common.frag_length; if (rpc->VirtualConnection->DefaultOutChannel->ReceiverAvailableWindow < (rpc->ReceiveWindow / 2)) { - if (rts_send_flow_control_ack_pdu(rpc) < 0) - return -1; + if (!rts_send_flow_control_ack_pdu(rpc)) + goto fail; } - if (!rpc_get_stub_data_info(rpc, buffer, &StubOffset, &StubLength)) + if (!rpc_get_stub_data_info(&header, &StubOffset, &StubLength)) { WLog_ERR(TAG, "expected stub"); - return -1; + goto fail; } if (StubLength == 4) { - if ((header->common.call_id == rpc->PipeCallId) && - (header->common.pfc_flags & PFC_LAST_FRAG)) + if ((header.common.call_id == rpc->PipeCallId) && + (header.common.pfc_flags & PFC_LAST_FRAG)) { /* End of TsProxySetupReceivePipe */ TerminateEventArgs e; - rpc->result = *((UINT32*)&buffer[StubOffset]); - freerdp_abort_connect(rpc->context->instance); - tsg_set_state(rpc->transport->tsg, TSG_STATE_TUNNEL_CLOSE_PENDING); + rdpContext* context = rpc->transport->context; + rdpTsg* tsg = rpc->transport->tsg; + + assert(context); + + if (Stream_Length(fragment) < StubOffset + 4) + goto fail; + Stream_SetPosition(fragment, StubOffset); + Stream_Read_UINT32(fragment, rpc->result); + + freerdp_abort_connect(context->instance); + tsg_set_state(tsg, TSG_STATE_TUNNEL_CLOSE_PENDING); EventArgsInit(&e, "freerdp"); e.code = 0; - PubSub_OnTerminate(rpc->context->pubSub, rpc->context, &e); - return 0; + PubSub_OnTerminate(context->pubSub, context, &e); + rc = 0; + goto success; } - if (header->common.call_id != rpc->PipeCallId) + if (header.common.call_id != rpc->PipeCallId) { /* Ignoring non-TsProxySetupReceivePipe Response */ - return 0; + rc = 0; + goto success; } } if (rpc->StubFragCount == 0) - rpc->StubCallId = header->common.call_id; + rpc->StubCallId = header.common.call_id; - if (rpc->StubCallId != header->common.call_id) + if (rpc->StubCallId != header.common.call_id) { WLog_ERR(TAG, "invalid call_id: actual: %" PRIu32 ", expected: %" PRIu32 ", frag_count: %" PRIu32 "", - rpc->StubCallId, header->common.call_id, rpc->StubFragCount); + rpc->StubCallId, header.common.call_id, rpc->StubFragCount); } call = rpc_client_call_find_by_id(rpc->client, rpc->StubCallId); if (!call) - return -1; + goto fail; if (call->OpNum != TsProxySetupReceivePipeOpnum) { - if (!Stream_EnsureCapacity(pdu->s, header->response.alloc_hint)) - return -1; + const rpcconn_response_hdr_t* response = + (const rpcconn_response_hdr_t*)&header.response; + if (!Stream_EnsureCapacity(pdu->s, response->alloc_hint)) + goto fail; + + if (Stream_Length(fragment) < StubOffset + StubLength) + goto fail; - Stream_Write(pdu->s, &buffer[StubOffset], StubLength); + Stream_SetPosition(fragment, StubOffset); + Stream_Write(pdu->s, Stream_Pointer(fragment), StubLength); rpc->StubFragCount++; - if (header->response.alloc_hint == StubLength) + if (response->alloc_hint == StubLength) { pdu->Flags = RPC_PDU_FLAG_STUB; pdu->Type = PTYPE_RESPONSE; pdu->CallId = rpc->StubCallId; - Stream_SealLength(pdu->s); + if (rpc_client_recv_pdu(rpc, pdu) < 0) - return -1; + goto fail; rpc_pdu_reset(pdu); rpc->StubFragCount = 0; rpc->StubCallId = 0; @@ -392,75 +424,84 @@ static int rpc_client_recv_fragment(rdpRpc* rpc, wStream* fragment) } else { - rpc_client_receive_pipe_write(rpc->client, &buffer[StubOffset], (size_t)StubLength); + const rpcconn_response_hdr_t* response = &header.response; + if (Stream_Length(fragment) < StubOffset + StubLength) + goto fail; + Stream_SetPosition(fragment, StubOffset); + rpc_client_receive_pipe_write(rpc->client, Stream_Pointer(fragment), + (size_t)StubLength); rpc->StubFragCount++; - if (header->response.alloc_hint == StubLength) + if (response->alloc_hint == StubLength) { rpc->StubFragCount = 0; rpc->StubCallId = 0; } } - return 1; + goto success; } - else if (header->common.ptype == PTYPE_RTS) + else if (header.common.ptype == PTYPE_RTS) { if (rpc->State < RPC_CLIENT_STATE_CONTEXT_NEGOTIATED) { pdu->Flags = 0; - pdu->Type = header->common.ptype; - pdu->CallId = header->common.call_id; + pdu->Type = header.common.ptype; + pdu->CallId = header.common.call_id; if (!Stream_EnsureCapacity(pdu->s, Stream_Length(fragment))) - return -1; + goto fail; - Stream_Write(pdu->s, buffer, Stream_Length(fragment)); - Stream_SealLength(pdu->s); + Stream_Write(pdu->s, Stream_Buffer(fragment), Stream_Length(fragment)); if (rpc_client_recv_pdu(rpc, pdu) < 0) - return -1; + goto fail; rpc_pdu_reset(pdu); } else { - if (rts_recv_out_of_sequence_pdu(rpc, buffer, header->common.frag_length) < 0) - return -1; + if (!rts_recv_out_of_sequence_pdu(rpc, fragment, &header)) + goto fail; } - return 1; + goto success; } - else if (header->common.ptype == PTYPE_BIND_ACK) + else if (header.common.ptype == PTYPE_BIND_ACK) { pdu->Flags = 0; - pdu->Type = header->common.ptype; - pdu->CallId = header->common.call_id; + pdu->Type = header.common.ptype; + pdu->CallId = header.common.call_id; if (!Stream_EnsureCapacity(pdu->s, Stream_Length(fragment))) - return -1; + goto fail; - Stream_Write(pdu->s, buffer, Stream_Length(fragment)); - Stream_SealLength(pdu->s); + Stream_Write(pdu->s, Stream_Buffer(fragment), Stream_Length(fragment)); if (rpc_client_recv_pdu(rpc, pdu) < 0) - return -1; + goto fail; rpc_pdu_reset(pdu); - return 1; + goto success; } - else if (header->common.ptype == PTYPE_FAULT) + else if (header.common.ptype == PTYPE_FAULT) { - rpc_recv_fault_pdu(header->fault.status); - return -1; + const rpcconn_fault_hdr_t* fault = (const rpcconn_fault_hdr_t*)&header.fault; + rpc_recv_fault_pdu(fault->status); + goto fail; } else { - WLog_ERR(TAG, "unexpected RPC PDU type 0x%02" PRIX8 "", header->common.ptype); - return -1; + WLog_ERR(TAG, "unexpected RPC PDU type 0x%02" PRIX8 "", header.common.ptype); + goto fail; } - return 1; +success: + rc = (rc < 0) ? 1 : 0; /* In case of default error return change to 1, otherwise we already set + the return code */ +fail: + rts_free_pdu_header(&header, FALSE); + return rc; } static int rpc_client_default_out_channel_recv(rdpRpc* rpc) @@ -510,7 +551,7 @@ static int rpc_client_default_out_channel_recv(rdpRpc* rpc) /* Send CONN/A1 PDU over OUT channel */ - if (rts_send_CONN_A1_pdu(rpc) < 0) + if (!rts_send_CONN_A1_pdu(rpc)) { http_response_free(response); WLog_ERR(TAG, "rpc_send_CONN_A1_pdu error!"); @@ -550,7 +591,8 @@ static int rpc_client_default_out_channel_recv(rdpRpc* rpc) if (statusCode == HTTP_STATUS_DENIED) { - freerdp_set_last_error_if_not(rpc->context, FREERDP_ERROR_AUTHENTICATION_FAILED); + rdpContext* context = rpc->context; + freerdp_set_last_error_if_not(context, FREERDP_ERROR_AUTHENTICATION_FAILED); } http_response_free(response); @@ -564,12 +606,13 @@ static int rpc_client_default_out_channel_recv(rdpRpc* rpc) } else { - wStream* fragment; - rpcconn_common_hdr_t* header; - fragment = rpc->client->ReceiveFragment; + wStream* fragment = rpc->client->ReceiveFragment; while (1) { + size_t pos; + rpcconn_common_hdr_t header = { 0 }; + while (Stream_GetPosition(fragment) < RPC_COMMON_FIELDS_LENGTH) { status = rpc_channel_read(&outChannel->common, fragment, @@ -582,22 +625,27 @@ static int rpc_client_default_out_channel_recv(rdpRpc* rpc) return 0; } - header = (rpcconn_common_hdr_t*)Stream_Buffer(fragment); + pos = Stream_GetPosition(fragment); + Stream_SetPosition(fragment, 0); - if (header->frag_length > rpc->max_recv_frag) + /* Ignore errors, the PDU might not be complete. */ + rts_read_common_pdu_header(fragment, &header); + Stream_SetPosition(fragment, pos); + + if (header.frag_length > rpc->max_recv_frag) { WLog_ERR(TAG, "rpc_client_recv: invalid fragment size: %" PRIu16 " (max: %" PRIu16 ")", - header->frag_length, rpc->max_recv_frag); + header.frag_length, rpc->max_recv_frag); winpr_HexDump(TAG, WLOG_ERROR, Stream_Buffer(fragment), Stream_GetPosition(fragment)); return -1; } - while (Stream_GetPosition(fragment) < header->frag_length) + while (Stream_GetPosition(fragment) < header.frag_length) { status = rpc_channel_read(&outChannel->common, fragment, - header->frag_length - Stream_GetPosition(fragment)); + header.frag_length - Stream_GetPosition(fragment)); if (status < 0) { @@ -605,14 +653,12 @@ static int rpc_client_default_out_channel_recv(rdpRpc* rpc) return -1; } - if (Stream_GetPosition(fragment) < header->frag_length) + if (Stream_GetPosition(fragment) < header.frag_length) return 0; } { /* complete fragment received */ - Stream_SealLength(fragment); - Stream_SetPosition(fragment, 0); status = rpc_client_recv_fragment(rpc, fragment); if (status < 0) @@ -664,10 +710,10 @@ static int rpc_client_nondefault_out_channel_recv(rdpRpc* rpc) if (rpc_ncacn_http_send_out_channel_request(&nextOutChannel->common, TRUE)) { rpc_ncacn_http_ntlm_uninit(&nextOutChannel->common); - status = rts_send_OUT_R1_A3_pdu(rpc); - if (status >= 0) + if (rts_send_OUT_R1_A3_pdu(rpc)) { + status = 1; rpc_out_channel_transition_to_state( nextOutChannel, CLIENT_OUT_CHANNEL_STATE_OPENED_A6W); } @@ -688,11 +734,14 @@ static int rpc_client_nondefault_out_channel_recv(rdpRpc* rpc) break; + case CLIENT_OUT_CHANNEL_STATE_INITIAL: + case CLIENT_OUT_CHANNEL_STATE_CONNECTED: + case CLIENT_OUT_CHANNEL_STATE_NEGOTIATED: default: WLog_ERR(TAG, "rpc_client_nondefault_out_channel_recv: Unexpected message %08" PRIx32, nextOutChannel->State); - return -1; + status = -1; } http_response_free(response); @@ -770,7 +819,7 @@ int rpc_client_in_channel_recv(rdpRpc* rpc) /* Send CONN/B1 PDU over IN channel */ - if (rts_send_CONN_B1_pdu(rpc) < 0) + if (!rts_send_CONN_B1_pdu(rpc)) { WLog_ERR(TAG, "rpc_send_CONN_B1_pdu error!"); http_response_free(response); @@ -811,8 +860,8 @@ int rpc_client_in_channel_recv(rdpRpc* rpc) RpcClientCall* rpc_client_call_find_by_id(RpcClient* client, UINT32 CallId) { - int index; - int count; + size_t index; + size_t count; RpcClientCall* clientCall = NULL; if (!client) @@ -857,18 +906,23 @@ static void rpc_array_client_call_free(void* call) rpc_client_call_free((RpcClientCall*)call); } -int rpc_in_channel_send_pdu(RpcInChannel* inChannel, BYTE* buffer, UINT32 length) +int rpc_in_channel_send_pdu(RpcInChannel* inChannel, const BYTE* buffer, size_t length) { - int status; + SSIZE_T status; RpcClientCall* clientCall; - rpcconn_common_hdr_t* header; + wStream s; + rpcconn_common_hdr_t header = { 0 }; + status = rpc_channel_write(&inChannel->common, buffer, length); if (status <= 0) return -1; - header = (rpcconn_common_hdr_t*)buffer; - clientCall = rpc_client_call_find_by_id(inChannel->common.client, header->call_id); + Stream_StaticInit(&s, buffer, length); + if (!rts_read_common_pdu_header(&s, &header)) + return -1; + + clientCall = rpc_client_call_find_by_id(inChannel->common.client, header.call_id); clientCall->State = RPC_CLIENT_CALL_STATE_DISPATCHED; /* @@ -878,7 +932,7 @@ int rpc_in_channel_send_pdu(RpcInChannel* inChannel, BYTE* buffer, UINT32 length * variables specified by this abstract data model. */ - if (header->ptype == PTYPE_REQUEST) + if (header.ptype == PTYPE_REQUEST) { inChannel->BytesSent += status; inChannel->SenderAvailableWindow -= status; @@ -889,7 +943,7 @@ int rpc_in_channel_send_pdu(RpcInChannel* inChannel, BYTE* buffer, UINT32 length BOOL rpc_client_write_call(rdpRpc* rpc, wStream* s, UINT16 opnum) { - UINT32 offset; + size_t offset; BYTE* buffer = NULL; UINT32 stub_data_pad; SecBuffer Buffers[2] = { 0 }; @@ -937,7 +991,7 @@ BOOL rpc_client_write_call(rdpRpc* rpc, wStream* s, UINT16 opnum) if (size < 0) goto fail; - rpc_pdu_header_init(rpc, &request_pdu.header); + request_pdu.header = rpc_pdu_header_init(rpc); request_pdu.header.ptype = PTYPE_REQUEST; request_pdu.header.pfc_flags = PFC_FIRST_FRAG | PFC_LAST_FRAG; request_pdu.header.auth_length = (UINT16)size; @@ -1026,7 +1080,7 @@ static BOOL rpc_client_resolve_gateway(rdpSettings* settings, char** host, UINT1 const char* peerHostname = freerdp_settings_get_string(settings, FreeRDP_GatewayHostname); const char* proxyUsername = freerdp_settings_get_string(settings, FreeRDP_GatewayUsername); const char* proxyPassword = freerdp_settings_get_string(settings, FreeRDP_GatewayPassword); - *port = freerdp_settings_get_uint32(settings, FreeRDP_GatewayPort); + *port = (UINT16)freerdp_settings_get_uint32(settings, FreeRDP_GatewayPort); *isProxy = proxy_prepare(settings, &peerHostname, port, &proxyUsername, &proxyPassword); result = freerdp_tcp_resolve_host(peerHostname, *port, 0); @@ -1084,9 +1138,6 @@ RpcClient* rpc_client_new(rdpContext* context, UINT32 max_recv_frag) goto fail; obj = ArrayList_Object(client->ClientCallList); - if (!obj) - goto fail; - obj->fnObjectFree = rpc_array_client_call_free; return client; fail: diff --git a/libfreerdp/core/gateway/rpc_client.h b/libfreerdp/core/gateway/rpc_client.h index af0b8ce13c51..7b509def0e56 100644 --- a/libfreerdp/core/gateway/rpc_client.h +++ b/libfreerdp/core/gateway/rpc_client.h @@ -31,7 +31,8 @@ FREERDP_LOCAL RpcClientCall* rpc_client_call_find_by_id(RpcClient* client, UINT3 FREERDP_LOCAL RpcClientCall* rpc_client_call_new(UINT32 CallId, UINT32 OpNum); FREERDP_LOCAL void rpc_client_call_free(RpcClientCall* client_call); -FREERDP_LOCAL int rpc_in_channel_send_pdu(RpcInChannel* inChannel, BYTE* buffer, UINT32 length); +FREERDP_LOCAL int rpc_in_channel_send_pdu(RpcInChannel* inChannel, const BYTE* buffer, + size_t length); FREERDP_LOCAL int rpc_client_in_channel_recv(rdpRpc* rpc); FREERDP_LOCAL int rpc_client_out_channel_recv(rdpRpc* rpc); diff --git a/libfreerdp/core/gateway/rpc_fault.c b/libfreerdp/core/gateway/rpc_fault.c index dcf59d62ba5b..12d466cd9380 100644 --- a/libfreerdp/core/gateway/rpc_fault.c +++ b/libfreerdp/core/gateway/rpc_fault.c @@ -154,8 +154,7 @@ static const RPC_FAULT_CODE RPC_FAULT_CODES[] = { DEFINE_RPC_FAULT_CODE(RPC_S_COOKIE_AUTH_FAILED, CAT_GATEWAY), DEFINE_RPC_FAULT_CODE(RPC_S_GROUP_MEMBER_NOT_FOUND, CAT_GATEWAY), DEFINE_RPC_FAULT_CODE(EPT_S_CANT_CREATE, CAT_GATEWAY), - DEFINE_RPC_FAULT_CODE(RPC_S_INVALID_OBJECT, CAT_GATEWAY), - { 0, NULL, NULL } + DEFINE_RPC_FAULT_CODE(RPC_S_INVALID_OBJECT, CAT_GATEWAY) }; static const RPC_FAULT_CODE RPC_TSG_FAULT_CODES[] = { @@ -207,8 +206,7 @@ static const RPC_FAULT_CODE RPC_TSG_FAULT_CODES[] = { { HRESULT_CODE(E_PROXY_REAUTH_NAP_FAILED), "E_PROXY_REAUTH_NAP_FAILED", CAT_GATEWAY }, { HRESULT_CODE(E_PROXY_CONNECTIONABORTED), "E_PROXY_CONNECTIONABORTED", CAT_GATEWAY }, { HRESULT_CODE(E_PROXY_NOCERTAVAILABLE), "E_PROXY_NOCERTAVAILABLE", CAT_GATEWAY }, - { HRESULT_CODE(RPC_S_CALL_CANCELLED), "RPC_S_CALL_CANCELLED", CAT_GATEWAY }, - { 0, NULL, NULL } + { HRESULT_CODE(RPC_S_CALL_CANCELLED), "RPC_S_CALL_CANCELLED", CAT_GATEWAY } }; /** @@ -361,29 +359,32 @@ const char* rpc_error_to_string(UINT32 code) size_t index; static char buffer[1024]; - for (index = 0; RPC_FAULT_CODES[index].name != NULL; index++) + for (index = 0; index < ARRAYSIZE(RPC_FAULT_CODES); index++) { - if (RPC_FAULT_CODES[index].code == code) + const RPC_FAULT_CODE* const current = &RPC_FAULT_CODES[index]; + if (current->code == code) { - sprintf_s(buffer, ARRAYSIZE(buffer), "%s", RPC_FAULT_CODES[index].name); + sprintf_s(buffer, ARRAYSIZE(buffer), "%s", current->name); goto out; } } - for (index = 0; RPC_TSG_FAULT_CODES[index].name != NULL; index++) + for (index = 0; index < ARRAYSIZE(RPC_TSG_FAULT_CODES); index++) { - if (RPC_TSG_FAULT_CODES[index].code == code) + const RPC_FAULT_CODE* const current = &RPC_TSG_FAULT_CODES[index]; + if (current->code == code) { - sprintf_s(buffer, ARRAYSIZE(buffer), "%s", RPC_TSG_FAULT_CODES[index].name); + sprintf_s(buffer, ARRAYSIZE(buffer), "%s", current->name); goto out; } } - for (index = 0; RPC_TSG_FAULT_CODES[index].name != NULL; index++) + for (index = 0; index < ARRAYSIZE(RPC_TSG_FAULT_CODES); index++) { - if (RPC_TSG_FAULT_CODES[index].code == HRESULT_CODE(code)) + const RPC_FAULT_CODE* const current = &RPC_TSG_FAULT_CODES[index]; + if (current->code == HRESULT_CODE(code)) { - sprintf_s(buffer, ARRAYSIZE(buffer), "%s", RPC_TSG_FAULT_CODES[index].name); + sprintf_s(buffer, ARRAYSIZE(buffer), "%s", current->name); goto out; } } @@ -397,22 +398,25 @@ const char* rpc_error_to_category(UINT32 code) { size_t index; - for (index = 0; RPC_FAULT_CODES[index].category != NULL; index++) + for (index = 0; index < ARRAYSIZE(RPC_FAULT_CODES); index++) { - if (RPC_FAULT_CODES[index].code == code) - return RPC_FAULT_CODES[index].category; + const RPC_FAULT_CODE* const current = &RPC_FAULT_CODES[index]; + if (current->code == code) + return current->category; } - for (index = 0; RPC_TSG_FAULT_CODES[index].category != NULL; index++) + for (index = 0; index < ARRAYSIZE(RPC_TSG_FAULT_CODES); index++) { - if (RPC_TSG_FAULT_CODES[index].code == code) - return RPC_TSG_FAULT_CODES[index].category; + const RPC_FAULT_CODE* const current = &RPC_TSG_FAULT_CODES[index]; + if (current->code == code) + return current->category; } - for (index = 0; RPC_TSG_FAULT_CODES[index].category != NULL; index++) + for (index = 0; index < ARRAYSIZE(RPC_TSG_FAULT_CODES); index++) { - if (RPC_TSG_FAULT_CODES[index].code == HRESULT_CODE(code)) - return RPC_TSG_FAULT_CODES[index].category; + const RPC_FAULT_CODE* const current = &RPC_TSG_FAULT_CODES[index]; + if (current->code == HRESULT_CODE(code)) + return current->category; } return "UNKNOWN"; diff --git a/libfreerdp/core/gateway/rts.c b/libfreerdp/core/gateway/rts.c index c003b1ea07ac..ccbe0becaddf 100644 --- a/libfreerdp/core/gateway/rts.c +++ b/libfreerdp/core/gateway/rts.c @@ -21,6 +21,7 @@ #include "config.h" #endif +#include #include #include #include @@ -29,6 +30,7 @@ #include "ncacn_http.h" #include "rpc_client.h" +#include "rts_signature.h" #include "rts.h" @@ -67,545 +69,1643 @@ * */ +static const char* rts_pdu_ptype_to_string(UINT32 ptype) +{ + switch (ptype) + { + case PTYPE_REQUEST: + return "PTYPE_REQUEST"; + case PTYPE_PING: + return "PTYPE_PING"; + case PTYPE_RESPONSE: + return "PTYPE_RESPONSE"; + case PTYPE_FAULT: + return "PTYPE_FAULT"; + case PTYPE_WORKING: + return "PTYPE_WORKING"; + case PTYPE_NOCALL: + return "PTYPE_NOCALL"; + case PTYPE_REJECT: + return "PTYPE_REJECT"; + case PTYPE_ACK: + return "PTYPE_ACK"; + case PTYPE_CL_CANCEL: + return "PTYPE_CL_CANCEL"; + case PTYPE_FACK: + return "PTYPE_FACK"; + case PTYPE_CANCEL_ACK: + return "PTYPE_CANCEL_ACK"; + case PTYPE_BIND: + return "PTYPE_BIND"; + case PTYPE_BIND_ACK: + return "PTYPE_BIND_ACK"; + case PTYPE_BIND_NAK: + return "PTYPE_BIND_NAK"; + case PTYPE_ALTER_CONTEXT: + return "PTYPE_ALTER_CONTEXT"; + case PTYPE_ALTER_CONTEXT_RESP: + return "PTYPE_ALTER_CONTEXT_RESP"; + case PTYPE_RPC_AUTH_3: + return "PTYPE_RPC_AUTH_3"; + case PTYPE_SHUTDOWN: + return "PTYPE_SHUTDOWN"; + case PTYPE_CO_CANCEL: + return "PTYPE_CO_CANCEL"; + case PTYPE_ORPHANED: + return "PTYPE_ORPHANED"; + case PTYPE_RTS: + return "PTYPE_RTS"; + default: + return "UNKNOWN"; + } +} static rpcconn_rts_hdr_t rts_pdu_header_init(void) { - rpcconn_rts_hdr_t header = { 0 }; - header.header.rpc_vers = 5; - header.header.rpc_vers_minor = 0; - header.header.ptype = PTYPE_RTS; - header.header.packed_drep[0] = 0x10; - header.header.packed_drep[1] = 0x00; - header.header.packed_drep[2] = 0x00; - header.header.packed_drep[3] = 0x00; - header.header.pfc_flags = PFC_FIRST_FRAG | PFC_LAST_FRAG; - header.header.auth_length = 0; - header.header.call_id = 0; + rpcconn_rts_hdr_t header = { 0 }; + header.header.rpc_vers = 5; + header.header.rpc_vers_minor = 0; + header.header.ptype = PTYPE_RTS; + header.header.packed_drep[0] = 0x10; + header.header.packed_drep[1] = 0x00; + header.header.packed_drep[2] = 0x00; + header.header.packed_drep[3] = 0x00; + header.header.pfc_flags = PFC_FIRST_FRAG | PFC_LAST_FRAG; + header.header.auth_length = 0; + header.header.call_id = 0; + + return header; +} + +static BOOL rts_align_stream(wStream* s, size_t alignment) +{ + size_t pos, pad; + + assert(s); + assert(alignment > 0); + + pos = Stream_GetPosition(s); + pad = rpc_offset_align(&pos, alignment); + return Stream_SafeSeek(s, pad); +} + +static char* sdup(const void* src, size_t length) +{ + char* dst; + assert(src || (length == 0)); + if (length == 0) + return NULL; + + dst = calloc(length + 1, sizeof(char)); + if (!dst) + return NULL; + memcpy(dst, src, length); + return dst; +} + +static BOOL rts_write_common_pdu_header(wStream* s, const rpcconn_common_hdr_t* header) +{ + assert(s); + assert(header); + if (!Stream_EnsureRemainingCapacity(s, sizeof(rpcconn_common_hdr_t))) + return FALSE; + + Stream_Write_UINT8(s, header->rpc_vers); + Stream_Write_UINT8(s, header->rpc_vers_minor); + Stream_Write_UINT8(s, header->ptype); + Stream_Write_UINT8(s, header->pfc_flags); + Stream_Write(s, header->packed_drep, ARRAYSIZE(header->packed_drep)); + Stream_Write_UINT16(s, header->frag_length); + Stream_Write_UINT16(s, header->auth_length); + Stream_Write_UINT32(s, header->call_id); + return TRUE; +} + +BOOL rts_read_common_pdu_header(wStream* s, rpcconn_common_hdr_t* header) +{ + size_t left; + assert(s); + assert(header); + + if (Stream_GetRemainingLength(s) < sizeof(rpcconn_common_hdr_t)) + return FALSE; + + Stream_Read_UINT8(s, header->rpc_vers); + Stream_Read_UINT8(s, header->rpc_vers_minor); + Stream_Read_UINT8(s, header->ptype); + Stream_Read_UINT8(s, header->pfc_flags); + Stream_Read(s, header->packed_drep, ARRAYSIZE(header->packed_drep)); + Stream_Read_UINT16(s, header->frag_length); + Stream_Read_UINT16(s, header->auth_length); + Stream_Read_UINT32(s, header->call_id); + + if (header->frag_length < sizeof(rpcconn_common_hdr_t)) + return FALSE; + + left = Stream_GetRemainingLength(s); + if (left < header->frag_length - sizeof(rpcconn_common_hdr_t)) + return FALSE; + + return TRUE; +} + +static BOOL rts_read_auth_verifier_no_checks(wStream* s, auth_verifier_co_t* auth, + const rpcconn_common_hdr_t* header, size_t* startPos) +{ + assert(s); + assert(auth); + assert(header); + + assert(header->frag_length > header->auth_length); + + if (startPos) + *startPos = Stream_GetPosition(s); + + /* Read the auth verifier and check padding matches frag_length */ + { + const size_t expected = header->frag_length - header->auth_length - 8; + + Stream_SetPosition(s, expected); + if (Stream_GetRemainingLength(s) < sizeof(auth_verifier_co_t)) + return FALSE; + + Stream_Read_UINT8(s, auth->auth_type); + Stream_Read_UINT8(s, auth->auth_level); + Stream_Read_UINT8(s, auth->auth_pad_length); + Stream_Read_UINT8(s, auth->auth_reserved); + Stream_Read_UINT32(s, auth->auth_context_id); + } + + if (header->auth_length != 0) + { + const void* ptr = Stream_Pointer(s); + if (!Stream_SafeSeek(s, header->auth_length)) + return FALSE; + auth->auth_value = (BYTE*)sdup(ptr, header->auth_length); + if (auth->auth_value == NULL) + return FALSE; + } + + return TRUE; +} + +static BOOL rts_read_auth_verifier(wStream* s, auth_verifier_co_t* auth, + const rpcconn_common_hdr_t* header) +{ + size_t pos; + assert(s); + assert(auth); + assert(header); + + if (!rts_read_auth_verifier_no_checks(s, auth, header, &pos)) + return FALSE; + + { + const size_t expected = header->frag_length - header->auth_length - 8; + assert(pos + auth->auth_pad_length == expected); + } + + return TRUE; +} + +static BOOL rts_read_auth_verifier_with_stub(wStream* s, auth_verifier_co_t* auth, + rpcconn_common_hdr_t* header) +{ + size_t pos; + size_t alloc_hint = 0; + BYTE** ptr = NULL; + + if (!rts_read_auth_verifier_no_checks(s, auth, header, &pos)) + return FALSE; + + switch (header->ptype) + { + case PTYPE_FAULT: + { + rpcconn_fault_hdr_t* hdr = (rpcconn_fault_hdr_t*)header; + alloc_hint = hdr->alloc_hint; + ptr = &hdr->stub_data; + } + break; + case PTYPE_RESPONSE: + { + rpcconn_response_hdr_t* hdr = (rpcconn_response_hdr_t*)header; + alloc_hint = hdr->alloc_hint; + ptr = &hdr->stub_data; + } + break; + case PTYPE_REQUEST: + { + rpcconn_request_hdr_t* hdr = (rpcconn_request_hdr_t*)header; + alloc_hint = hdr->alloc_hint; + ptr = &hdr->stub_data; + } + break; + default: + return FALSE; + } + + if (alloc_hint > 0) + { + const size_t size = + header->frag_length - header->auth_length - 8 - auth->auth_pad_length - pos; + const void* src = Stream_Buffer(s) + pos; + + *ptr = (BYTE*)sdup(src, size); + if (!*ptr) + return FALSE; + } + + return TRUE; +} + +static void rts_free_auth_verifier(auth_verifier_co_t* auth) +{ + if (!auth) + return; + free(auth->auth_value); +} + +static BOOL rts_write_auth_verifier(wStream* s, const auth_verifier_co_t* auth, + const rpcconn_common_hdr_t* header) +{ + size_t pos; + UINT8 auth_pad_length = 0; + + assert(s); + assert(auth); + assert(header); + + /* Align start to a multiple of 4 */ + pos = Stream_GetPosition(s); + if ((pos % 4) != 0) + { + auth_pad_length = 4 - (pos % 4); + if (!Stream_EnsureRemainingCapacity(s, auth_pad_length)) + return FALSE; + Stream_Zero(s, auth_pad_length); + } + + assert(header->frag_length + 8ull > header->auth_length); + { + size_t pos = Stream_GetPosition(s); + size_t expected = header->frag_length - header->auth_length - 8; + + assert(pos == expected); + } + + if (!Stream_EnsureRemainingCapacity(s, sizeof(auth_verifier_co_t))) + return FALSE; + + Stream_Write_UINT8(s, auth->auth_type); + Stream_Write_UINT8(s, auth->auth_level); + Stream_Write_UINT8(s, auth_pad_length); + Stream_Write_UINT8(s, 0); /* auth->auth_reserved */ + Stream_Write_UINT32(s, auth->auth_context_id); + + if (!Stream_EnsureRemainingCapacity(s, header->auth_length)) + return FALSE; + Stream_Write(s, auth->auth_value, header->auth_length); + return TRUE; +} + +static BOOL rts_read_version(wStream* s, p_rt_version_t* version) +{ + assert(s); + assert(version); + + if (Stream_GetRemainingLength(s) < 2 * sizeof(UINT8)) + return FALSE; + Stream_Read_UINT8(s, version->major); + Stream_Read_UINT8(s, version->minor); + return TRUE; +} + +void rts_free_supported_versions(p_rt_versions_supported_t* versions) +{ + if (!versions) + return; + free(versions->p_protocols); + versions->p_protocols = NULL; +} + +static BOOL rts_read_supported_versions(wStream* s, p_rt_versions_supported_t* versions) +{ + BYTE x; + + assert(s); + assert(versions); + + if (Stream_GetRemainingLength(s) < sizeof(UINT8)) + return FALSE; + + Stream_Read_UINT8(s, versions->n_protocols); /* count */ + + if (versions->n_protocols > 0) + { + versions->p_protocols = calloc(versions->n_protocols, sizeof(p_rt_version_t)); + if (!versions->p_protocols) + return FALSE; + } + for (x = 0; x < versions->n_protocols; x++) + { + p_rt_version_t* version = &versions->p_protocols[x]; + if (!rts_read_version(s, version)) /* size_is(n_protocols) */ + { + rts_free_supported_versions(versions); + return FALSE; + } + } + + return TRUE; +} + +static BOOL rts_read_port_any(wStream* s, port_any_t* port) +{ + const void* ptr; + + assert(s); + assert(port); + + if (Stream_GetRemainingLength(s) < sizeof(UINT16)) + return FALSE; + + Stream_Read_UINT16(s, port->length); + if (port->length == 0) + return TRUE; + + ptr = Stream_Pointer(s); + if (!Stream_SafeSeek(s, port->length)) + return FALSE; + port->port_spec = sdup(ptr, port->length); + return port->port_spec != NULL; +} + +static void rts_free_port_any(port_any_t* port) +{ + if (!port) + return; + free(port->port_spec); +} + +static BOOL rts_read_uuid(wStream* s, p_uuid_t* uuid) +{ + assert(s); + assert(uuid); + + if (Stream_GetRemainingLength(s) < sizeof(p_uuid_t)) + return FALSE; + + Stream_Read_UINT32(s, uuid->time_low); + Stream_Read_UINT16(s, uuid->time_mid); + Stream_Read_UINT16(s, uuid->time_hi_and_version); + Stream_Read_UINT8(s, uuid->clock_seq_hi_and_reserved); + Stream_Read_UINT8(s, uuid->clock_seq_low); + Stream_Read(s, uuid->node, ARRAYSIZE(uuid->node)); + return TRUE; +} + +static BOOL rts_write_uuid(wStream* s, const p_uuid_t* uuid) +{ + assert(s); + assert(uuid); + + if (!Stream_EnsureRemainingCapacity(s, sizeof(p_uuid_t))) + return FALSE; + + Stream_Write_UINT32(s, uuid->time_low); + Stream_Write_UINT16(s, uuid->time_mid); + Stream_Write_UINT16(s, uuid->time_hi_and_version); + Stream_Write_UINT8(s, uuid->clock_seq_hi_and_reserved); + Stream_Write_UINT8(s, uuid->clock_seq_low); + Stream_Write(s, uuid->node, ARRAYSIZE(uuid->node)); + return TRUE; +} + +static p_syntax_id_t* rts_syntax_id_new(size_t count) +{ + return calloc(count, sizeof(p_syntax_id_t)); +} + +static void rts_syntax_id_free(p_syntax_id_t* ptr) +{ + free(ptr); +} + +static BOOL rts_read_syntax_id(wStream* s, p_syntax_id_t* syntax_id) +{ + assert(s); + assert(syntax_id); + + if (!rts_read_uuid(s, &syntax_id->if_uuid)) + return FALSE; + + if (Stream_GetRemainingLength(s) < 4) + return FALSE; + + Stream_Read_UINT32(s, syntax_id->if_version); + return TRUE; +} + +static BOOL rts_write_syntax_id(wStream* s, const p_syntax_id_t* syntax_id) +{ + assert(s); + assert(syntax_id); + + if (!rts_write_uuid(s, &syntax_id->if_uuid)) + return FALSE; + + if (!Stream_EnsureRemainingCapacity(s, 4)) + return FALSE; + + Stream_Write_UINT32(s, syntax_id->if_version); + return TRUE; +} + +p_cont_elem_t* rts_context_elem_new(size_t count) +{ + p_cont_elem_t* ctx = calloc(count, sizeof(p_cont_elem_t)); + return ctx; +} + +void rts_context_elem_free(p_cont_elem_t* ptr) +{ + if (!ptr) + return; + rts_syntax_id_free(ptr->transfer_syntaxes); + free(ptr); +} + +static BOOL rts_read_context_elem(wStream* s, p_cont_elem_t* element) +{ + BYTE x; + assert(s); + assert(element); + + if (Stream_GetRemainingLength(s) < 4) + return FALSE; + + Stream_Read_UINT16(s, element->p_cont_id); + Stream_Read_UINT8(s, element->n_transfer_syn); /* number of items */ + Stream_Read_UINT8(s, element->reserved); /* alignment pad, m.b.z. */ + + if (!rts_read_syntax_id(s, &element->abstract_syntax)) /* transfer syntax list */ + return FALSE; + + if (element->n_transfer_syn > 0) + { + element->transfer_syntaxes = rts_syntax_id_new(element->n_transfer_syn); + if (!element->transfer_syntaxes) + return FALSE; + for (x = 0; x < element->n_transfer_syn; x++) + { + p_syntax_id_t* syn = &element->transfer_syntaxes[x]; + if (!rts_read_syntax_id(s, syn)) /* size_is(n_transfer_syn) */ + return FALSE; + } + } + + return TRUE; +} + +static BOOL rts_write_context_elem(wStream* s, const p_cont_elem_t* element) +{ + BYTE x; + assert(s); + assert(element); + + if (!Stream_EnsureRemainingCapacity(s, 4)) + return FALSE; + Stream_Write_UINT16(s, element->p_cont_id); + Stream_Write_UINT8(s, element->n_transfer_syn); /* number of items */ + Stream_Write_UINT8(s, element->reserved); /* alignment pad, m.b.z. */ + if (!rts_write_syntax_id(s, &element->abstract_syntax)) /* transfer syntax list */ + return FALSE; + + for (x = 0; x < element->n_transfer_syn; x++) + { + const p_syntax_id_t* syn = &element->transfer_syntaxes[x]; + if (!rts_write_syntax_id(s, syn)) /* size_is(n_transfer_syn) */ + return FALSE; + } + + return TRUE; +} + +static BOOL rts_read_context_list(wStream* s, p_cont_list_t* list) +{ + BYTE x; + + assert(s); + assert(list); + + if (Stream_GetRemainingLength(s) < 4) + return FALSE; + Stream_Read_UINT8(s, list->n_context_elem); /* number of items */ + Stream_Read_UINT8(s, list->reserved); /* alignment pad, m.b.z. */ + Stream_Read_UINT16(s, list->reserved2); /* alignment pad, m.b.z. */ + + if (list->n_context_elem > 0) + { + list->p_cont_elem = rts_context_elem_new(list->n_context_elem); + if (!list->p_cont_elem) + return FALSE; + for (x = 0; x < list->n_context_elem; x++) + { + p_cont_elem_t* element = &list->p_cont_elem[x]; + if (!rts_read_context_elem(s, element)) + return FALSE; + } + } + return TRUE; +} + +static void rts_free_context_list(p_cont_list_t* list) +{ + if (!list) + return; + rts_context_elem_free(list->p_cont_elem); +} + +static BOOL rts_write_context_list(wStream* s, const p_cont_list_t* list) +{ + BYTE x; + + assert(s); + assert(list); + + if (!Stream_EnsureRemainingCapacity(s, 4)) + return FALSE; + Stream_Write_UINT8(s, list->n_context_elem); /* number of items */ + Stream_Write_UINT8(s, 0); /* alignment pad, m.b.z. */ + Stream_Write_UINT16(s, 0); /* alignment pad, m.b.z. */ + + for (x = 0; x < list->n_context_elem; x++) + { + const p_cont_elem_t* element = &list->p_cont_elem[x]; + if (!rts_write_context_elem(s, element)) + return FALSE; + } + return TRUE; +} + +static p_result_t* rts_result_new(size_t count) +{ + return calloc(count, sizeof(p_result_t)); +} + +static void rts_result_free(p_result_t* results) +{ + if (!results) + return; + free(results); +} + +static BOOL rts_read_result(wStream* s, p_result_t* result) +{ + assert(s); + assert(result); + + if (Stream_GetRemainingLength(s) < 2) + return FALSE; + Stream_Read_UINT16(s, result->result); + Stream_Read_UINT16(s, result->reason); + + return rts_read_syntax_id(s, &result->transfer_syntax); +} + +static void rts_free_result(p_result_t* result) +{ + if (!result) + return; +} + +static BOOL rts_read_result_list(wStream* s, p_result_list_t* list) +{ + BYTE x; + + assert(s); + assert(list); + + if (Stream_GetRemainingLength(s) < 4) + return FALSE; + Stream_Read_UINT8(s, list->n_results); /* count */ + Stream_Read_UINT8(s, list->reserved); /* alignment pad, m.b.z. */ + Stream_Read_UINT16(s, list->reserved2); /* alignment pad, m.b.z. */ + + if (list->n_results > 0) + { + list->p_results = rts_result_new(list->n_results); + if (!list->p_results) + return FALSE; + + for (x = 0; x < list->n_results; x++) + { + p_result_t* result = &list->p_results[x]; /* size_is(n_results) */ + if (!rts_read_result(s, result)) + return FALSE; + } + } + + return TRUE; +} + +static void rts_free_result_list(p_result_list_t* list) +{ + BYTE x; + + if (!list) + return; + for (x = 0; x < list->n_results; x++) + { + p_result_t* result = &list->p_results[x]; + rts_free_result(result); + } + rts_result_free(list->p_results); +} + +static void rts_free_pdu_alter_context(rpcconn_alter_context_hdr_t* ctx) +{ + if (!ctx) + return; + + rts_free_context_list(&ctx->p_context_elem); + rts_free_auth_verifier(&ctx->auth_verifier); +} + +static BOOL rts_read_pdu_alter_context(wStream* s, rpcconn_alter_context_hdr_t* ctx) +{ + assert(s); + assert(ctx); + + if (Stream_GetRemainingLength(s) < + sizeof(rpcconn_alter_context_hdr_t) - sizeof(rpcconn_common_hdr_t)) + return FALSE; + + Stream_Read_UINT16(s, ctx->max_xmit_frag); + Stream_Read_UINT16(s, ctx->max_recv_frag); + Stream_Read_UINT32(s, ctx->assoc_group_id); + + if (!rts_read_context_list(s, &ctx->p_context_elem)) + return FALSE; + + if (!rts_read_auth_verifier(s, &ctx->auth_verifier, &ctx->header)) + return FALSE; + + return TRUE; +} + +static BOOL rts_read_pdu_alter_context_response(wStream* s, + rpcconn_alter_context_response_hdr_t* ctx) +{ + assert(s); + assert(ctx); + + if (Stream_GetRemainingLength(s) < + sizeof(rpcconn_alter_context_response_hdr_t) - sizeof(rpcconn_common_hdr_t)) + return FALSE; + Stream_Read_UINT16(s, ctx->max_xmit_frag); + Stream_Read_UINT16(s, ctx->max_recv_frag); + Stream_Read_UINT32(s, ctx->assoc_group_id); + + if (!rts_read_port_any(s, &ctx->sec_addr)) + return FALSE; + + if (!rts_align_stream(s, 4)) + return FALSE; + + if (!rts_read_result_list(s, &ctx->p_result_list)) + return FALSE; + + if (!rts_read_auth_verifier(s, &ctx->auth_verifier, &ctx->header)) + return FALSE; + + return TRUE; +} + +static void rts_free_pdu_alter_context_response(rpcconn_alter_context_response_hdr_t* ctx) +{ + if (!ctx) + return; + + rts_free_port_any(&ctx->sec_addr); + rts_free_result_list(&ctx->p_result_list); + rts_free_auth_verifier(&ctx->auth_verifier); +} + +static BOOL rts_read_pdu_bind(wStream* s, rpcconn_bind_hdr_t* ctx) +{ + assert(s); + assert(ctx); + + if (Stream_GetRemainingLength(s) < sizeof(rpcconn_bind_hdr_t) - sizeof(rpcconn_common_hdr_t)) + return FALSE; + Stream_Read_UINT16(s, ctx->max_xmit_frag); + Stream_Read_UINT16(s, ctx->max_recv_frag); + Stream_Read_UINT32(s, ctx->assoc_group_id); + + if (!rts_read_context_list(s, &ctx->p_context_elem)) + return FALSE; + + if (!rts_read_auth_verifier(s, &ctx->auth_verifier, &ctx->header)) + return FALSE; + + return TRUE; +} + +static void rts_free_pdu_bind(rpcconn_bind_hdr_t* ctx) +{ + if (!ctx) + return; + rts_free_context_list(&ctx->p_context_elem); + rts_free_auth_verifier(&ctx->auth_verifier); +} + +static BOOL rts_read_pdu_bind_ack(wStream* s, rpcconn_bind_ack_hdr_t* ctx) +{ + assert(s); + assert(ctx); + + if (Stream_GetRemainingLength(s) < + sizeof(rpcconn_bind_ack_hdr_t) - sizeof(rpcconn_common_hdr_t)) + return FALSE; + Stream_Read_UINT16(s, ctx->max_xmit_frag); + Stream_Read_UINT16(s, ctx->max_recv_frag); + Stream_Read_UINT32(s, ctx->assoc_group_id); + + if (!rts_read_port_any(s, &ctx->sec_addr)) + return FALSE; + + if (!rts_align_stream(s, 4)) + return FALSE; + + if (!rts_read_result_list(s, &ctx->p_result_list)) + return FALSE; + + return rts_read_auth_verifier(s, &ctx->auth_verifier, &ctx->header); +} + +static void rts_free_pdu_bind_ack(rpcconn_bind_ack_hdr_t* ctx) +{ + if (!ctx) + return; + rts_free_port_any(&ctx->sec_addr); + rts_free_result_list(&ctx->p_result_list); + rts_free_auth_verifier(&ctx->auth_verifier); +} + +static BOOL rts_read_pdu_bind_nak(wStream* s, rpcconn_bind_nak_hdr_t* ctx) +{ + assert(s); + assert(ctx); + + if (Stream_GetRemainingLength(s) < + sizeof(rpcconn_bind_nak_hdr_t) - sizeof(rpcconn_common_hdr_t)) + return FALSE; + Stream_Read_UINT16(s, ctx->provider_reject_reason); + return rts_read_supported_versions(s, &ctx->versions); +} + +static void rts_free_pdu_bind_nak(rpcconn_bind_nak_hdr_t* ctx) +{ + if (!ctx) + return; + + rts_free_supported_versions(&ctx->versions); +} + +static BOOL rts_read_pdu_auth3(wStream* s, rpcconn_rpc_auth_3_hdr_t* ctx) +{ + assert(s); + assert(ctx); + + if (Stream_GetRemainingLength(s) < + sizeof(rpcconn_rpc_auth_3_hdr_t) - sizeof(rpcconn_common_hdr_t)) + return FALSE; + Stream_Read_UINT16(s, ctx->max_xmit_frag); + Stream_Read_UINT16(s, ctx->max_recv_frag); + + return rts_read_auth_verifier(s, &ctx->auth_verifier, &ctx->header); +} + +static void rts_free_pdu_auth3(rpcconn_rpc_auth_3_hdr_t* ctx) +{ + if (!ctx) + return; + rts_free_auth_verifier(&ctx->auth_verifier); +} + +static BOOL rts_read_pdu_fault(wStream* s, rpcconn_fault_hdr_t* ctx) +{ + assert(s); + assert(ctx); + + if (Stream_GetRemainingLength(s) < sizeof(rpcconn_fault_hdr_t) - sizeof(rpcconn_common_hdr_t)) + return FALSE; + Stream_Read_UINT32(s, ctx->alloc_hint); + Stream_Read_UINT16(s, ctx->p_cont_id); + Stream_Read_UINT8(s, ctx->cancel_count); + Stream_Read_UINT8(s, ctx->reserved); + Stream_Read_UINT32(s, ctx->status); + + return rts_read_auth_verifier_with_stub(s, &ctx->auth_verifier, &ctx->header); +} + +static void rts_free_pdu_fault(rpcconn_fault_hdr_t* ctx) +{ + if (!ctx) + return; + rts_free_auth_verifier(&ctx->auth_verifier); +} + +static BOOL rts_read_pdu_cancel_ack(wStream* s, rpcconn_cancel_hdr_t* ctx) +{ + assert(s); + assert(ctx); + + if (Stream_GetRemainingLength(s) < sizeof(rpcconn_cancel_hdr_t) - sizeof(rpcconn_common_hdr_t)) + return FALSE; + return rts_read_auth_verifier(s, &ctx->auth_verifier, &ctx->header); +} + +static void rts_free_pdu_cancel_ack(rpcconn_cancel_hdr_t* ctx) +{ + if (!ctx) + return; + rts_free_auth_verifier(&ctx->auth_verifier); +} + +static BOOL rts_read_pdu_orphaned(wStream* s, rpcconn_orphaned_hdr_t* ctx) +{ + assert(s); + assert(ctx); + + if (Stream_GetRemainingLength(s) < + sizeof(rpcconn_orphaned_hdr_t) - sizeof(rpcconn_common_hdr_t)) + return FALSE; + return rts_read_auth_verifier(s, &ctx->auth_verifier, &ctx->header); +} + +static void rts_free_pdu_orphaned(rpcconn_orphaned_hdr_t* ctx) +{ + if (!ctx) + return; + rts_free_auth_verifier(&ctx->auth_verifier); +} + +static BOOL rts_read_pdu_request(wStream* s, rpcconn_request_hdr_t* ctx) +{ + assert(s); + assert(ctx); + + if (Stream_GetRemainingLength(s) < sizeof(rpcconn_request_hdr_t) - sizeof(rpcconn_common_hdr_t)) + return FALSE; + Stream_Read_UINT32(s, ctx->alloc_hint); + Stream_Read_UINT16(s, ctx->p_cont_id); + Stream_Read_UINT16(s, ctx->opnum); + if (!rts_read_uuid(s, &ctx->object)) + return FALSE; + + return rts_read_auth_verifier_with_stub(s, &ctx->auth_verifier, &ctx->header); +} + +static void rts_free_pdu_request(rpcconn_request_hdr_t* ctx) +{ + if (!ctx) + return; + rts_free_auth_verifier(&ctx->auth_verifier); +} + +static BOOL rts_read_pdu_response(wStream* s, rpcconn_response_hdr_t* ctx) +{ + assert(s); + assert(ctx); + + if (Stream_GetRemainingLength(s) < + sizeof(rpcconn_response_hdr_t) - sizeof(rpcconn_common_hdr_t)) + return FALSE; + Stream_Read_UINT32(s, ctx->alloc_hint); + Stream_Read_UINT16(s, ctx->p_cont_id); + Stream_Read_UINT8(s, ctx->cancel_count); + Stream_Read_UINT8(s, ctx->reserved); + + if (!rts_align_stream(s, 8)) + return FALSE; + + return rts_read_auth_verifier_with_stub(s, &ctx->auth_verifier, &ctx->header); +} + +static void rts_free_pdu_response(rpcconn_response_hdr_t* ctx) +{ + if (!ctx) + return; + free(ctx->stub_data); + rts_free_auth_verifier(&ctx->auth_verifier); +} + +static BOOL rts_read_pdu_rts(wStream* s, rpcconn_rts_hdr_t* ctx) +{ + assert(s); + assert(ctx); + + if (Stream_GetRemainingLength(s) < sizeof(rpcconn_rts_hdr_t) - sizeof(rpcconn_common_hdr_t)) + return FALSE; + + Stream_Read_UINT16(s, ctx->Flags); + Stream_Read_UINT16(s, ctx->NumberOfCommands); + return TRUE; +} + +static void rts_free_pdu_rts(rpcconn_rts_hdr_t* ctx) +{ + WINPR_UNUSED(ctx); +} + +void rts_free_pdu_header(rpcconn_hdr_t* header, BOOL allocated) +{ + if (!header) + return; + + switch (header->common.ptype) + { + case PTYPE_ALTER_CONTEXT: + rts_free_pdu_alter_context(&header->alter_context); + break; + case PTYPE_ALTER_CONTEXT_RESP: + rts_free_pdu_alter_context_response(&header->alter_context_response); + break; + case PTYPE_BIND: + rts_free_pdu_bind(&header->bind); + break; + case PTYPE_BIND_ACK: + rts_free_pdu_bind_ack(&header->bind_ack); + break; + case PTYPE_BIND_NAK: + rts_free_pdu_bind_nak(&header->bind_nak); + break; + case PTYPE_RPC_AUTH_3: + rts_free_pdu_auth3(&header->rpc_auth_3); + break; + case PTYPE_CANCEL_ACK: + rts_free_pdu_cancel_ack(&header->cancel); + break; + case PTYPE_FAULT: + rts_free_pdu_fault(&header->fault); + break; + case PTYPE_ORPHANED: + rts_free_pdu_orphaned(&header->orphaned); + break; + case PTYPE_REQUEST: + rts_free_pdu_request(&header->request); + break; + case PTYPE_RESPONSE: + rts_free_pdu_response(&header->response); + break; + case PTYPE_RTS: + rts_free_pdu_rts(&header->rts); + break; + /* No extra fields */ + case PTYPE_SHUTDOWN: + break; + + /* not handled */ + case PTYPE_PING: + case PTYPE_WORKING: + case PTYPE_NOCALL: + case PTYPE_REJECT: + case PTYPE_ACK: + case PTYPE_CL_CANCEL: + case PTYPE_FACK: + case PTYPE_CO_CANCEL: + default: + break; + } + + if (allocated) + free(header); +} + +BOOL rts_read_pdu_header(wStream* s, rpcconn_hdr_t* header) +{ + BOOL rc = FALSE; + assert(s); + assert(header); + + if (!rts_read_common_pdu_header(s, &header->common)) + return FALSE; + + WLog_DBG(TAG, "Reading PDU type %s", rts_pdu_ptype_to_string(header->common.ptype)); + fflush(stdout); + switch (header->common.ptype) + { + case PTYPE_ALTER_CONTEXT: + rc = rts_read_pdu_alter_context(s, &header->alter_context); + break; + case PTYPE_ALTER_CONTEXT_RESP: + rc = rts_read_pdu_alter_context_response(s, &header->alter_context_response); + break; + case PTYPE_BIND: + rc = rts_read_pdu_bind(s, &header->bind); + break; + case PTYPE_BIND_ACK: + rc = rts_read_pdu_bind_ack(s, &header->bind_ack); + break; + case PTYPE_BIND_NAK: + rc = rts_read_pdu_bind_nak(s, &header->bind_nak); + break; + case PTYPE_RPC_AUTH_3: + rc = rts_read_pdu_auth3(s, &header->rpc_auth_3); + break; + case PTYPE_CANCEL_ACK: + rc = rts_read_pdu_cancel_ack(s, &header->cancel); + break; + case PTYPE_FAULT: + rc = rts_read_pdu_fault(s, &header->fault); + break; + case PTYPE_ORPHANED: + rc = rts_read_pdu_orphaned(s, &header->orphaned); + break; + case PTYPE_REQUEST: + rc = rts_read_pdu_request(s, &header->request); + break; + case PTYPE_RESPONSE: + rc = rts_read_pdu_response(s, &header->response); + break; + case PTYPE_RTS: + rc = rts_read_pdu_rts(s, &header->rts); + break; + case PTYPE_SHUTDOWN: + rc = TRUE; /* No extra fields */ + break; + + /* not handled */ + case PTYPE_PING: + case PTYPE_WORKING: + case PTYPE_NOCALL: + case PTYPE_REJECT: + case PTYPE_ACK: + case PTYPE_CL_CANCEL: + case PTYPE_FACK: + case PTYPE_CO_CANCEL: + default: + break; + } + + return rc; +} + +static BOOL rts_write_pdu_header(wStream* s, const rpcconn_rts_hdr_t* header) +{ + assert(s); + assert(header); + if (!Stream_EnsureRemainingCapacity(s, sizeof(rpcconn_rts_hdr_t))) + return FALSE; - return header; + if (!rts_write_common_pdu_header(s, &header->header)) + return FALSE; + + Stream_Write_UINT16(s, header->Flags); + Stream_Write_UINT16(s, header->NumberOfCommands); + return TRUE; } -static int rts_receive_window_size_command_read(rdpRpc* rpc, BYTE* buffer, UINT32 length, +static int rts_receive_window_size_command_read(rdpRpc* rpc, wStream* buffer, UINT32* ReceiveWindowSize) { + UINT32 val; + + assert(rpc); + assert(buffer); + + if (Stream_GetRemainingLength(buffer) < 4) + return -1; + Stream_Read_UINT32(buffer, val); if (ReceiveWindowSize) - *ReceiveWindowSize = *((UINT32*)&buffer[0]); /* ReceiveWindowSize (4 bytes) */ + *ReceiveWindowSize = val; /* ReceiveWindowSize (4 bytes) */ return 4; } -static int rts_receive_window_size_command_write(BYTE* buffer, UINT32 ReceiveWindowSize) +static BOOL rts_receive_window_size_command_write(wStream* s, UINT32 ReceiveWindowSize) { - if (buffer) - { - *((UINT32*)&buffer[0]) = RTS_CMD_RECEIVE_WINDOW_SIZE; /* CommandType (4 bytes) */ - *((UINT32*)&buffer[4]) = ReceiveWindowSize; /* ReceiveWindowSize (4 bytes) */ - } + assert(s); + + if (!Stream_EnsureRemainingCapacity(s, 2 * sizeof(UINT32))) + return FALSE; - return 8; + Stream_Write_UINT32(s, RTS_CMD_RECEIVE_WINDOW_SIZE); /* CommandType (4 bytes) */ + Stream_Write_UINT32(s, ReceiveWindowSize); /* ReceiveWindowSize (4 bytes) */ + + return TRUE; } -static int rts_flow_control_ack_command_read(rdpRpc* rpc, BYTE* buffer, UINT32 length, - UINT32* BytesReceived, UINT32* AvailableWindow, - BYTE* ChannelCookie) +static int rts_flow_control_ack_command_read(rdpRpc* rpc, wStream* buffer, UINT32* BytesReceived, + UINT32* AvailableWindow, BYTE* ChannelCookie) { + UINT32 val; + assert(rpc); + assert(buffer); + /* Ack (24 bytes) */ + if (Stream_GetRemainingLength(buffer) < 24) + return -1; + + Stream_Read_UINT32(buffer, val); if (BytesReceived) - *BytesReceived = *((UINT32*)&buffer[0]); /* BytesReceived (4 bytes) */ + *BytesReceived = val; /* BytesReceived (4 bytes) */ + Stream_Read_UINT32(buffer, val); if (AvailableWindow) - *AvailableWindow = *((UINT32*)&buffer[4]); /* AvailableWindow (4 bytes) */ + *AvailableWindow = val; /* AvailableWindow (4 bytes) */ if (ChannelCookie) - CopyMemory(ChannelCookie, &buffer[8], 16); /* ChannelCookie (16 bytes) */ - + Stream_Read(buffer, ChannelCookie, 16); /* ChannelCookie (16 bytes) */ + else + Stream_Seek(buffer, 16); return 24; } -static int rts_flow_control_ack_command_write(BYTE* buffer, UINT32 BytesReceived, - UINT32 AvailableWindow, BYTE* ChannelCookie) +static BOOL rts_flow_control_ack_command_write(wStream* s, UINT32 BytesReceived, + UINT32 AvailableWindow, BYTE* ChannelCookie) { - if (buffer) - { - *((UINT32*)&buffer[0]) = RTS_CMD_FLOW_CONTROL_ACK; /* CommandType (4 bytes) */ - /* Ack (24 bytes) */ - *((UINT32*)&buffer[4]) = BytesReceived; /* BytesReceived (4 bytes) */ - *((UINT32*)&buffer[8]) = AvailableWindow; /* AvailableWindow (4 bytes) */ - CopyMemory(&buffer[12], ChannelCookie, 16); /* ChannelCookie (16 bytes) */ - } + assert(s); - return 28; -} + if (!Stream_EnsureRemainingCapacity(s, 28)) + return FALSE; -static int rts_connection_timeout_command_read(rdpRpc* rpc, BYTE* buffer, UINT32 length, - UINT32* ConnectionTimeout) -{ - if (ConnectionTimeout) - *ConnectionTimeout = *((UINT32*)&buffer[0]); /* ConnectionTimeout (4 bytes) */ + Stream_Write_UINT32(s, RTS_CMD_FLOW_CONTROL_ACK); /* CommandType (4 bytes) */ + Stream_Write_UINT32(s, BytesReceived); /* BytesReceived (4 bytes) */ + Stream_Write_UINT32(s, AvailableWindow); /* AvailableWindow (4 bytes) */ + Stream_Write(s, ChannelCookie, 16); /* ChannelCookie (16 bytes) */ - return 4; + return TRUE; } -static int rts_connection_timeout_command_write(BYTE* buffer, UINT32 ConnectionTimeout) +static BOOL rts_connection_timeout_command_read(rdpRpc* rpc, wStream* buffer, + UINT32* ConnectionTimeout) { - if (buffer) - { - *((UINT32*)&buffer[0]) = RTS_CMD_CONNECTION_TIMEOUT; /* CommandType (4 bytes) */ - *((UINT32*)&buffer[4]) = ConnectionTimeout; /* ConnectionTimeout (4 bytes) */ - } + UINT32 val; + assert(rpc); + assert(buffer); - return 8; -} + if (Stream_GetRemainingLength(buffer) < 4) + return FALSE; -static int rts_cookie_command_read(rdpRpc* rpc, BYTE* buffer, UINT32 length) -{ - /* Cookie (16 bytes) */ - return 16; + Stream_Read_UINT32(buffer, val); + if (ConnectionTimeout) + *ConnectionTimeout = val; /* ConnectionTimeout (4 bytes) */ + + return TRUE; } -static int rts_cookie_command_write(BYTE* buffer, BYTE* Cookie) +static BOOL rts_cookie_command_write(wStream* s, const BYTE* Cookie) { - if (buffer) - { - *((UINT32*)&buffer[0]) = RTS_CMD_COOKIE; /* CommandType (4 bytes) */ - CopyMemory(&buffer[4], Cookie, 16); /* Cookie (16 bytes) */ - } + assert(s); - return 20; -} + if (!Stream_EnsureRemainingCapacity(s, 20)) + return FALSE; -static int rts_channel_lifetime_command_read(rdpRpc* rpc, BYTE* buffer, UINT32 length) -{ - /* ChannelLifetime (4 bytes) */ - return 4; + Stream_Write_UINT32(s, RTS_CMD_COOKIE); /* CommandType (4 bytes) */ + Stream_Write(s, Cookie, 16); /* Cookie (16 bytes) */ + + return TRUE; } -static int rts_channel_lifetime_command_write(BYTE* buffer, UINT32 ChannelLifetime) +static BOOL rts_channel_lifetime_command_write(wStream* s, UINT32 ChannelLifetime) { - if (buffer) - { - *((UINT32*)&buffer[0]) = RTS_CMD_CHANNEL_LIFETIME; /* CommandType (4 bytes) */ - *((UINT32*)&buffer[4]) = ChannelLifetime; /* ChannelLifetime (4 bytes) */ - } + assert(s); - return 8; -} + if (!Stream_EnsureRemainingCapacity(s, 8)) + return FALSE; + Stream_Write_UINT32(s, RTS_CMD_CHANNEL_LIFETIME); /* CommandType (4 bytes) */ + Stream_Write_UINT32(s, ChannelLifetime); /* ChannelLifetime (4 bytes) */ -static int rts_client_keepalive_command_read(rdpRpc* rpc, BYTE* buffer, UINT32 length) -{ - /* ClientKeepalive (4 bytes) */ - return 4; + return TRUE; } -static int rts_client_keepalive_command_write(BYTE* buffer, UINT32 ClientKeepalive) +static BOOL rts_client_keepalive_command_write(wStream* s, UINT32 ClientKeepalive) { + assert(s); + + if (!Stream_EnsureRemainingCapacity(s, 8)) + return FALSE; /** * An unsigned integer that specifies the keep-alive interval, in milliseconds, * that this connection is configured to use. This value MUST be 0 or in the inclusive * range of 60,000 through 4,294,967,295. If it is 0, it MUST be interpreted as 300,000. */ - if (buffer) - { - *((UINT32*)&buffer[0]) = RTS_CMD_CLIENT_KEEPALIVE; /* CommandType (4 bytes) */ - *((UINT32*)&buffer[4]) = ClientKeepalive; /* ClientKeepalive (4 bytes) */ - } - return 8; -} + Stream_Write_UINT32(s, RTS_CMD_CLIENT_KEEPALIVE); /* CommandType (4 bytes) */ + Stream_Write_UINT32(s, ClientKeepalive); /* ClientKeepalive (4 bytes) */ -static int rts_version_command_read(rdpRpc* rpc, BYTE* buffer, UINT32 length) -{ - /* Version (4 bytes) */ - return 4; + return TRUE; } -static int rts_version_command_write(BYTE* buffer) +static BOOL rts_version_command_read(rdpRpc* rpc, wStream* buffer) { - if (buffer) - { - *((UINT32*)&buffer[0]) = RTS_CMD_VERSION; /* CommandType (4 bytes) */ - *((UINT32*)&buffer[4]) = 1; /* Version (4 bytes) */ - } + assert(rpc); + assert(buffer); - return 8; -} + if (!Stream_SafeSeek(buffer, 4)) + return FALSE; -static int rts_empty_command_read(rdpRpc* rpc, BYTE* buffer, UINT32 length) -{ - return 0; + /* Version (4 bytes) */ + return TRUE; } -static int rts_empty_command_write(BYTE* buffer) +static BOOL rts_version_command_write(wStream* buffer) { - if (buffer) - { - *((UINT32*)&buffer[0]) = RTS_CMD_EMPTY; /* CommandType (4 bytes) */ - } - - return 4; -} + assert(buffer); -static SSIZE_T rts_padding_command_read(const BYTE* buffer, size_t length) -{ - UINT32 ConformanceCount; - ConformanceCount = *((UINT32*)&buffer[0]); /* ConformanceCount (4 bytes) */ - /* Padding (variable) */ - return ConformanceCount + 4; -} + if (Stream_GetRemainingCapacity(buffer) < 8) + return FALSE; -static int rts_padding_command_write(BYTE* buffer, UINT32 ConformanceCount) -{ - if (buffer) - { - *((UINT32*)&buffer[0]) = RTS_CMD_PADDING; /* CommandType (4 bytes) */ - *((UINT32*)&buffer[4]) = ConformanceCount; /* ConformanceCount (4 bytes) */ - ZeroMemory(&buffer[8], ConformanceCount); /* Padding (variable) */ - } + Stream_Write_UINT32(buffer, RTS_CMD_VERSION); /* CommandType (4 bytes) */ + Stream_Write_UINT32(buffer, 1); /* Version (4 bytes) */ - return 8 + ConformanceCount; + return TRUE; } -static int rts_negative_ance_command_read(rdpRpc* rpc, BYTE* buffer, UINT32 length) +static BOOL rts_empty_command_write(wStream* s) { - return 0; -} + assert(s); -static int rts_negative_ance_command_write(BYTE* buffer) -{ - if (buffer) - { - *((UINT32*)&buffer[0]) = RTS_CMD_NEGATIVE_ANCE; /* CommandType (4 bytes) */ - } + if (!Stream_EnsureRemainingCapacity(s, 8)) + return FALSE; - return 4; -} + Stream_Write_UINT32(s, RTS_CMD_EMPTY); /* CommandType (4 bytes) */ -static int rts_ance_command_read(rdpRpc* rpc, BYTE* buffer, UINT32 length) -{ - return 0; + return TRUE; } -static int rts_ance_command_write(BYTE* buffer) +static BOOL rts_padding_command_read(wStream* s, size_t* length) { - if (buffer) - { - *((UINT32*)&buffer[0]) = RTS_CMD_ANCE; /* CommandType (4 bytes) */ - } - - return 4; + UINT32 ConformanceCount; + assert(s); + assert(length); + if (Stream_GetRemainingLength(s) < 4) + return FALSE; + Stream_Read_UINT32(s, ConformanceCount); /* ConformanceCount (4 bytes) */ + *length = ConformanceCount + 4; + return TRUE; } -static SSIZE_T rts_client_address_command_read(const BYTE* buffer, size_t length) +static BOOL rts_client_address_command_read(wStream* s, size_t* length) { UINT32 AddressType; - AddressType = *((UINT32*)&buffer[0]); /* AddressType (4 bytes) */ + + assert(s); + assert(length); + + if (Stream_GetRemainingLength(s) < 4) + return FALSE; + Stream_Read_UINT32(s, AddressType); /* AddressType (4 bytes) */ if (AddressType == 0) { /* ClientAddress (4 bytes) */ /* padding (12 bytes) */ - return 4 + 4 + 12; + *length = 4 + 4 + 12; } else { /* ClientAddress (16 bytes) */ /* padding (12 bytes) */ - return 4 + 16 + 12; + *length = 4 + 16 + 12; } + return TRUE; } -static int rts_client_address_command_write(BYTE* buffer, UINT32 AddressType, BYTE* ClientAddress) +static BOOL rts_association_group_id_command_write(wStream* s, const BYTE* AssociationGroupId) { - if (buffer) - { - *((UINT32*)&buffer[0]) = RTS_CMD_CLIENT_ADDRESS; /* CommandType (4 bytes) */ - *((UINT32*)&buffer[4]) = AddressType; /* AddressType (4 bytes) */ - } + assert(s); - if (AddressType == 0) - { - if (buffer) - { - CopyMemory(&buffer[8], ClientAddress, 4); /* ClientAddress (4 bytes) */ - ZeroMemory(&buffer[12], 12); /* padding (12 bytes) */ - } - - return 24; - } - else - { - if (buffer) - { - CopyMemory(&buffer[8], ClientAddress, 16); /* ClientAddress (16 bytes) */ - ZeroMemory(&buffer[24], 12); /* padding (12 bytes) */ - } + if (!Stream_EnsureRemainingCapacity(s, 20)) + return FALSE; - return 36; - } -} + Stream_Write_UINT32(s, RTS_CMD_ASSOCIATION_GROUP_ID); /* CommandType (4 bytes) */ + Stream_Write(s, AssociationGroupId, 16); /* AssociationGroupId (16 bytes) */ -static int rts_association_group_id_command_read(rdpRpc* rpc, BYTE* buffer, UINT32 length) -{ - /* AssociationGroupId (16 bytes) */ - return 16; + return TRUE; } -static int rts_association_group_id_command_write(BYTE* buffer, BYTE* AssociationGroupId) +static int rts_destination_command_read(rdpRpc* rpc, wStream* buffer, UINT32* Destination) { - if (buffer) - { - *((UINT32*)&buffer[0]) = RTS_CMD_ASSOCIATION_GROUP_ID; /* CommandType (4 bytes) */ - CopyMemory(&buffer[4], AssociationGroupId, 16); /* AssociationGroupId (16 bytes) */ - } - - return 20; -} + UINT32 val; + assert(rpc); + assert(buffer); -static int rts_destination_command_read(rdpRpc* rpc, BYTE* buffer, UINT32 length, - UINT32* Destination) -{ + if (Stream_GetRemainingLength(buffer) < 4) + return -1; + Stream_Read_UINT32(buffer, val); if (Destination) - *Destination = *((UINT32*)&buffer[0]); /* Destination (4 bytes) */ + *Destination = val; /* Destination (4 bytes) */ return 4; } -static int rts_destination_command_write(BYTE* buffer, UINT32 Destination) +static BOOL rts_destination_command_write(wStream* s, UINT32 Destination) { - if (buffer) - { - *((UINT32*)&buffer[0]) = RTS_CMD_DESTINATION; /* CommandType (4 bytes) */ - *((UINT32*)&buffer[4]) = Destination; /* Destination (4 bytes) */ - } - - return 8; -} + assert(s); -static int rts_ping_traffic_sent_notify_command_read(rdpRpc* rpc, BYTE* buffer, UINT32 length) -{ - /* PingTrafficSent (4 bytes) */ - return 4; -} + if (!Stream_EnsureRemainingCapacity(s, 8)) + return FALSE; -static int rts_ping_traffic_sent_notify_command_write(BYTE* buffer, UINT32 PingTrafficSent) -{ - if (buffer) - { - *((UINT32*)&buffer[0]) = RTS_CMD_PING_TRAFFIC_SENT_NOTIFY; /* CommandType (4 bytes) */ - *((UINT32*)&buffer[4]) = PingTrafficSent; /* PingTrafficSent (4 bytes) */ - } + Stream_Write_UINT32(s, RTS_CMD_DESTINATION); /* CommandType (4 bytes) */ + Stream_Write_UINT32(s, Destination); /* Destination (4 bytes) */ - return 8; + return TRUE; } void rts_generate_cookie(BYTE* cookie) { + assert(cookie); winpr_RAND(cookie, 16); } +static BOOL rts_send_buffer(RpcChannel* channel, wStream* s, size_t frag_length) +{ + BOOL status = FALSE; + SSIZE_T rc; + + assert(channel); + assert(s); + + Stream_SealLength(s); + if (Stream_Length(s) < sizeof(rpcconn_common_hdr_t)) + goto fail; + if (Stream_Length(s) != frag_length) + goto fail; + + rc = rpc_channel_write(channel, Stream_Buffer(s), Stream_Length(s)); + if (rc < 0) + goto fail; + if ((size_t)rc != Stream_Length(s)) + goto fail; + status = TRUE; +fail: + return status; +} + /* CONN/A Sequence */ -int rts_send_CONN_A1_pdu(rdpRpc* rpc) +BOOL rts_send_CONN_A1_pdu(rdpRpc* rpc) { - int status; - BYTE* buffer; + BOOL status = FALSE; + wStream* buffer; rpcconn_rts_hdr_t header = rts_pdu_header_init(); UINT32 ReceiveWindowSize; BYTE* OUTChannelCookie; BYTE* VirtualConnectionCookie; - RpcVirtualConnection* connection = rpc->VirtualConnection; - RpcOutChannel* outChannel = connection->DefaultOutChannel; + RpcVirtualConnection* connection; + RpcOutChannel* outChannel; + + assert(rpc); + + connection = rpc->VirtualConnection; + assert(connection); + + outChannel = connection->DefaultOutChannel; + assert(outChannel); header.header.frag_length = 76; header.Flags = RTS_FLAG_NONE; header.NumberOfCommands = 4; + WLog_DBG(TAG, "Sending CONN/A1 RTS PDU"); VirtualConnectionCookie = (BYTE*)&(connection->Cookie); OUTChannelCookie = (BYTE*)&(outChannel->common.Cookie); ReceiveWindowSize = outChannel->ReceiveWindow; - buffer = (BYTE*)malloc(header.header.frag_length); + + buffer = Stream_New(NULL, header.header.frag_length); if (!buffer) return -1; - CopyMemory(buffer, ((BYTE*)&header), 20); /* RTS Header (20 bytes) */ - rts_version_command_write(&buffer[20]); /* Version (8 bytes) */ - rts_cookie_command_write(&buffer[28], - VirtualConnectionCookie); /* VirtualConnectionCookie (20 bytes) */ - rts_cookie_command_write(&buffer[48], OUTChannelCookie); /* OUTChannelCookie (20 bytes) */ - rts_receive_window_size_command_write(&buffer[68], - ReceiveWindowSize); /* ReceiveWindowSize (8 bytes) */ - status = rpc_channel_write(&outChannel->common, buffer, header.header.frag_length); - free(buffer); - return (status > 0) ? 1 : -1; + if (!rts_write_pdu_header(buffer, &header)) /* RTS Header (20 bytes) */ + goto fail; + status = rts_version_command_write(buffer); /* Version (8 bytes) */ + if (!status) + goto fail; + status = rts_cookie_command_write( + buffer, VirtualConnectionCookie); /* VirtualConnectionCookie (20 bytes) */ + if (!status) + goto fail; + status = rts_cookie_command_write(buffer, OUTChannelCookie); /* OUTChannelCookie (20 bytes) */ + if (!status) + goto fail; + status = rts_receive_window_size_command_write( + buffer, ReceiveWindowSize); /* ReceiveWindowSize (8 bytes) */ + if (!status) + goto fail; + status = rts_send_buffer(&outChannel->common, buffer, header.header.frag_length); +fail: + Stream_Free(buffer, TRUE); + return status; } -int rts_recv_CONN_A3_pdu(rdpRpc* rpc, BYTE* buffer, UINT32 length) +BOOL rts_recv_CONN_A3_pdu(rdpRpc* rpc, wStream* buffer) { + BOOL rc; UINT32 ConnectionTimeout; - rts_connection_timeout_command_read(rpc, &buffer[24], length - 24, &ConnectionTimeout); + + if (!Stream_SafeSeek(buffer, 24)) + return FALSE; + + rc = rts_connection_timeout_command_read(rpc, buffer, &ConnectionTimeout); + if (!rc) + return rc; + WLog_DBG(TAG, "Receiving CONN/A3 RTS PDU: ConnectionTimeout: %" PRIu32 "", ConnectionTimeout); + + assert(rpc); + assert(rpc->VirtualConnection); + assert(rpc->VirtualConnection->DefaultInChannel); + rpc->VirtualConnection->DefaultInChannel->PingOriginator.ConnectionTimeout = ConnectionTimeout; - return 1; + return TRUE; } /* CONN/B Sequence */ -int rts_send_CONN_B1_pdu(rdpRpc* rpc) +BOOL rts_send_CONN_B1_pdu(rdpRpc* rpc) { - int status; - BYTE* buffer; - UINT32 length; + BOOL status = FALSE; + wStream* buffer; rpcconn_rts_hdr_t header = rts_pdu_header_init(); BYTE* INChannelCookie; BYTE* AssociationGroupId; BYTE* VirtualConnectionCookie; - RpcVirtualConnection* connection = rpc->VirtualConnection; - RpcInChannel* inChannel = connection->DefaultInChannel; + RpcVirtualConnection* connection; + RpcInChannel* inChannel; + + assert(rpc); + + connection = rpc->VirtualConnection; + assert(connection); + + inChannel = connection->DefaultInChannel; + assert(inChannel); header.header.frag_length = 104; header.Flags = RTS_FLAG_NONE; header.NumberOfCommands = 6; + WLog_DBG(TAG, "Sending CONN/B1 RTS PDU"); + VirtualConnectionCookie = (BYTE*)&(connection->Cookie); INChannelCookie = (BYTE*)&(inChannel->common.Cookie); AssociationGroupId = (BYTE*)&(connection->AssociationGroupId); - buffer = (BYTE*)malloc(header.header.frag_length); + buffer = Stream_New(NULL, header.header.frag_length); if (!buffer) - return -1; - - CopyMemory(buffer, ((BYTE*)&header), 20); /* RTS Header (20 bytes) */ - rts_version_command_write(&buffer[20]); /* Version (8 bytes) */ - rts_cookie_command_write(&buffer[28], - VirtualConnectionCookie); /* VirtualConnectionCookie (20 bytes) */ - rts_cookie_command_write(&buffer[48], INChannelCookie); /* INChannelCookie (20 bytes) */ - rts_channel_lifetime_command_write(&buffer[68], - rpc->ChannelLifetime); /* ChannelLifetime (8 bytes) */ - rts_client_keepalive_command_write(&buffer[76], - rpc->KeepAliveInterval); /* ClientKeepalive (8 bytes) */ - rts_association_group_id_command_write(&buffer[84], - AssociationGroupId); /* AssociationGroupId (20 bytes) */ - length = header.header.frag_length; - status = rpc_channel_write(&inChannel->common, buffer, length); - free(buffer); - return (status > 0) ? 1 : -1; + goto fail; + if (!rts_write_pdu_header(buffer, &header)) /* RTS Header (20 bytes) */ + goto fail; + if (!rts_version_command_write(buffer)) /* Version (8 bytes) */ + goto fail; + if (!rts_cookie_command_write(buffer, + VirtualConnectionCookie)) /* VirtualConnectionCookie (20 bytes) */ + goto fail; + if (!rts_cookie_command_write(buffer, INChannelCookie)) /* INChannelCookie (20 bytes) */ + goto fail; + if (!rts_channel_lifetime_command_write(buffer, + rpc->ChannelLifetime)) /* ChannelLifetime (8 bytes) */ + goto fail; + if (!rts_client_keepalive_command_write(buffer, + rpc->KeepAliveInterval)) /* ClientKeepalive (8 bytes) */ + goto fail; + if (!rts_association_group_id_command_write( + buffer, AssociationGroupId)) /* AssociationGroupId (20 bytes) */ + goto fail; + status = rts_send_buffer(&inChannel->common, buffer, header.header.frag_length); +fail: + Stream_Free(buffer, TRUE); + return status; } /* CONN/C Sequence */ -int rts_recv_CONN_C2_pdu(rdpRpc* rpc, BYTE* buffer, UINT32 length) +BOOL rts_recv_CONN_C2_pdu(rdpRpc* rpc, wStream* buffer) { - UINT32 offset; + BOOL rc; UINT32 ReceiveWindowSize; UINT32 ConnectionTimeout; - offset = 24; - offset += rts_version_command_read(rpc, &buffer[offset], length - offset) + 4; - offset += rts_receive_window_size_command_read(rpc, &buffer[offset], length - offset, - &ReceiveWindowSize) + - 4; - offset += rts_connection_timeout_command_read(rpc, &buffer[offset], length - offset, - &ConnectionTimeout) + - 4; + + assert(rpc); + assert(buffer); + + if (!Stream_SafeSeek(buffer, 24)) + return FALSE; + + rc = rts_version_command_read(rpc, buffer); + if (rc < 0) + return rc; + rc = rts_receive_window_size_command_read(rpc, buffer, &ReceiveWindowSize); + if (rc < 0) + return rc; + rc = rts_connection_timeout_command_read(rpc, buffer, &ConnectionTimeout); + if (rc < 0) + return rc; WLog_DBG(TAG, "Receiving CONN/C2 RTS PDU: ConnectionTimeout: %" PRIu32 " ReceiveWindowSize: %" PRIu32 "", ConnectionTimeout, ReceiveWindowSize); + + assert(rpc); + assert(rpc->VirtualConnection); + assert(rpc->VirtualConnection->DefaultInChannel); + rpc->VirtualConnection->DefaultInChannel->PingOriginator.ConnectionTimeout = ConnectionTimeout; rpc->VirtualConnection->DefaultInChannel->PeerReceiveWindow = ReceiveWindowSize; - return 1; + return TRUE; } /* Out-of-Sequence PDUs */ -static int rts_send_keep_alive_pdu(rdpRpc* rpc) +BOOL rts_send_flow_control_ack_pdu(rdpRpc* rpc) { - int status; - BYTE* buffer; - UINT32 length; + BOOL status = FALSE; + wStream* buffer; rpcconn_rts_hdr_t header = rts_pdu_header_init(); - RpcInChannel* inChannel = rpc->VirtualConnection->DefaultInChannel; + UINT32 BytesReceived; + UINT32 AvailableWindow; + BYTE* ChannelCookie; + RpcVirtualConnection* connection; + RpcInChannel* inChannel; + RpcOutChannel* outChannel; - header.header.frag_length = 28; - header.Flags = RTS_FLAG_OTHER_CMD; - header.NumberOfCommands = 1; - WLog_DBG(TAG, "Sending Keep-Alive RTS PDU"); - buffer = (BYTE*)malloc(header.header.frag_length); + assert(rpc); - if (!buffer) - return -1; + connection = rpc->VirtualConnection; + assert(connection); - CopyMemory(buffer, ((BYTE*)&header), 20); /* RTS Header (20 bytes) */ - rts_client_keepalive_command_write( - &buffer[20], rpc->CurrentKeepAliveInterval); /* ClientKeepAlive (8 bytes) */ - length = header.header.frag_length; - status = rpc_channel_write(&inChannel->common, buffer, length); - free(buffer); - return (status > 0) ? 1 : -1; -} + inChannel = connection->DefaultInChannel; + assert(inChannel); -int rts_send_flow_control_ack_pdu(rdpRpc* rpc) -{ - int status; - BYTE* buffer; - UINT32 length; - rpcconn_rts_hdr_t header = rts_pdu_header_init(); - UINT32 BytesReceived; - UINT32 AvailableWindow; - BYTE* ChannelCookie; - RpcVirtualConnection* connection = rpc->VirtualConnection; - RpcInChannel* inChannel = connection->DefaultInChannel; - RpcOutChannel* outChannel = connection->DefaultOutChannel; + outChannel = connection->DefaultOutChannel; + assert(outChannel); header.header.frag_length = 56; header.Flags = RTS_FLAG_OTHER_CMD; header.NumberOfCommands = 2; + WLog_DBG(TAG, "Sending FlowControlAck RTS PDU"); + BytesReceived = outChannel->BytesReceived; AvailableWindow = outChannel->AvailableWindowAdvertised; ChannelCookie = (BYTE*)&(outChannel->common.Cookie); outChannel->ReceiverAvailableWindow = outChannel->AvailableWindowAdvertised; - buffer = (BYTE*)malloc(header.header.frag_length); + buffer = Stream_New(NULL, header.header.frag_length); if (!buffer) - return -1; + goto fail; + + if (!rts_write_pdu_header(buffer, &header)) /* RTS Header (20 bytes) */ + goto fail; + if (!rts_destination_command_write(buffer, FDOutProxy)) /* Destination Command (8 bytes) */ + goto fail; - CopyMemory(buffer, ((BYTE*)&header), 20); /* RTS Header (20 bytes) */ - rts_destination_command_write(&buffer[20], FDOutProxy); /* Destination Command (8 bytes) */ /* FlowControlAck Command (28 bytes) */ - rts_flow_control_ack_command_write(&buffer[28], BytesReceived, AvailableWindow, ChannelCookie); - length = header.header.frag_length; - status = rpc_channel_write(&inChannel->common, buffer, length); - free(buffer); - return (status > 0) ? 1 : -1; + if (!rts_flow_control_ack_command_write(buffer, BytesReceived, AvailableWindow, ChannelCookie)) + goto fail; + + status = rts_send_buffer(&inChannel->common, buffer, header.header.frag_length); +fail: + Stream_Free(buffer, TRUE); + return status; } -static int rts_recv_flow_control_ack_pdu(rdpRpc* rpc, BYTE* buffer, UINT32 length) +static int rts_recv_flow_control_ack_pdu(rdpRpc* rpc, wStream* buffer) { - UINT32 offset; + int rc; UINT32 BytesReceived; UINT32 AvailableWindow; - BYTE ChannelCookie[16]; - offset = 24; - offset += - rts_flow_control_ack_command_read(rpc, &buffer[offset], length - offset, &BytesReceived, - &AvailableWindow, (BYTE*)&ChannelCookie) + - 4; + BYTE ChannelCookie[16] = { 0 }; + + rc = rts_flow_control_ack_command_read(rpc, buffer, &BytesReceived, &AvailableWindow, + (BYTE*)&ChannelCookie); + if (rc < 0) + return rc; WLog_ERR(TAG, "Receiving FlowControlAck RTS PDU: BytesReceived: %" PRIu32 " AvailableWindow: %" PRIu32 "", BytesReceived, AvailableWindow); + + assert(rpc->VirtualConnection); + assert(rpc->VirtualConnection->DefaultInChannel); + rpc->VirtualConnection->DefaultInChannel->SenderAvailableWindow = AvailableWindow - (rpc->VirtualConnection->DefaultInChannel->BytesSent - BytesReceived); return 1; } -static int rts_recv_flow_control_ack_with_destination_pdu(rdpRpc* rpc, BYTE* buffer, UINT32 length) +static int rts_recv_flow_control_ack_with_destination_pdu(rdpRpc* rpc, wStream* buffer) { - UINT32 offset; + int rc; UINT32 Destination; UINT32 BytesReceived; UINT32 AvailableWindow; - BYTE ChannelCookie[16]; + BYTE ChannelCookie[16] = { 0 }; /** * When the sender receives a FlowControlAck RTS PDU, it MUST use the following formula to * recalculate its Sender AvailableWindow variable: @@ -622,16 +1722,23 @@ static int rts_recv_flow_control_ack_with_destination_pdu(rdpRpc* rpc, BYTE* buf * structure in the PDU received. * */ - offset = 24; - offset += rts_destination_command_read(rpc, &buffer[offset], length - offset, &Destination) + 4; - offset += - rts_flow_control_ack_command_read(rpc, &buffer[offset], length - offset, &BytesReceived, - &AvailableWindow, (BYTE*)&ChannelCookie) + - 4; + + rc = rts_destination_command_read(rpc, buffer, &Destination); + if (rc < 0) + return rc; + + rc = rts_flow_control_ack_command_read(rpc, buffer, &BytesReceived, &AvailableWindow, + ChannelCookie); + if (rc < 0) + return rc; + WLog_DBG(TAG, "Receiving FlowControlAckWithDestination RTS PDU: BytesReceived: %" PRIu32 " AvailableWindow: %" PRIu32 "", BytesReceived, AvailableWindow); + + assert(rpc->VirtualConnection); + assert(rpc->VirtualConnection->DefaultInChannel); rpc->VirtualConnection->DefaultInChannel->SenderAvailableWindow = AvailableWindow - (rpc->VirtualConnection->DefaultInChannel->BytesSent - BytesReceived); return 1; @@ -639,31 +1746,41 @@ static int rts_recv_flow_control_ack_with_destination_pdu(rdpRpc* rpc, BYTE* buf static int rts_send_ping_pdu(rdpRpc* rpc) { - int status; - BYTE* buffer; - UINT32 length; + BOOL status = FALSE; + wStream* buffer; rpcconn_rts_hdr_t header = rts_pdu_header_init(); - RpcInChannel* inChannel = rpc->VirtualConnection->DefaultInChannel; + RpcInChannel* inChannel; + + assert(rpc); + assert(rpc->VirtualConnection); + + inChannel = rpc->VirtualConnection->DefaultInChannel; + assert(inChannel); header.header.frag_length = 20; header.Flags = RTS_FLAG_PING; header.NumberOfCommands = 0; + WLog_DBG(TAG, "Sending Ping RTS PDU"); - buffer = (BYTE*)malloc(header.header.frag_length); + buffer = Stream_New(NULL, header.header.frag_length); if (!buffer) - return -1; - - CopyMemory(buffer, ((BYTE*)&header), 20); /* RTS Header (20 bytes) */ - length = header.header.frag_length; - status = rpc_channel_write(&inChannel->common, buffer, length); - free(buffer); - return (status > 0) ? 1 : -1; + goto fail; + + if (!rts_write_pdu_header(buffer, &header)) /* RTS Header (20 bytes) */ + goto fail; + status = rts_send_buffer(&inChannel->common, buffer, header.header.frag_length); +fail: + Stream_Free(buffer, TRUE); + return (status) ? 1 : -1; } -SSIZE_T rts_command_length(UINT32 CommandType, const BYTE* buffer, size_t length) +BOOL rts_command_length(UINT32 CommandType, wStream* s, size_t* length) { - int CommandLength = 0; + size_t padding = 0; + size_t CommandLength = 0; + + assert(s); switch (CommandType) { @@ -700,7 +1817,8 @@ SSIZE_T rts_command_length(UINT32 CommandType, const BYTE* buffer, size_t length break; case RTS_CMD_PADDING: /* variable-size */ - CommandLength = rts_padding_command_read(buffer, length); + if (!rts_padding_command_read(s, &padding)) + return FALSE; break; case RTS_CMD_NEGATIVE_ANCE: @@ -712,7 +1830,8 @@ SSIZE_T rts_command_length(UINT32 CommandType, const BYTE* buffer, size_t length break; case RTS_CMD_CLIENT_ADDRESS: /* variable-size */ - CommandLength = rts_client_address_command_read(buffer, length); + if (!rts_client_address_command_read(s, &CommandLength)) + return FALSE; break; case RTS_CMD_ASSOCIATION_GROUP_ID: @@ -729,118 +1848,176 @@ SSIZE_T rts_command_length(UINT32 CommandType, const BYTE* buffer, size_t length default: WLog_ERR(TAG, "Error: Unknown RTS Command Type: 0x%" PRIx32 "", CommandType); - return -1; + return FALSE; } - return CommandLength; + CommandLength += padding; + if (Stream_GetRemainingLength(s) < CommandLength) + return FALSE; + + if (length) + *length = CommandLength; + return TRUE; } static int rts_send_OUT_R2_A7_pdu(rdpRpc* rpc) { - int status; - BYTE* buffer; + BOOL status = FALSE; + wStream* buffer; rpcconn_rts_hdr_t header = rts_pdu_header_init(); BYTE* SuccessorChannelCookie; - RpcInChannel* inChannel = rpc->VirtualConnection->DefaultInChannel; - RpcOutChannel* nextOutChannel = rpc->VirtualConnection->NonDefaultOutChannel; + RpcInChannel* inChannel; + RpcOutChannel* nextOutChannel; + + assert(rpc); + assert(rpc->VirtualConnection); + + inChannel = rpc->VirtualConnection->DefaultInChannel; + assert(inChannel); + + nextOutChannel = rpc->VirtualConnection->NonDefaultOutChannel; + assert(nextOutChannel); header.header.frag_length = 56; header.Flags = RTS_FLAG_OUT_CHANNEL; header.NumberOfCommands = 3; + WLog_DBG(TAG, "Sending OUT_R2/A7 RTS PDU"); + SuccessorChannelCookie = (BYTE*)&(nextOutChannel->common.Cookie); - buffer = (BYTE*)malloc(header.header.frag_length); + buffer = Stream_New(NULL, header.header.frag_length); if (!buffer) return -1; - CopyMemory(buffer, ((BYTE*)&header), 20); /* RTS Header (20 bytes) */ - rts_destination_command_write(&buffer[20], FDServer); /* Destination (8 bytes)*/ - rts_cookie_command_write(&buffer[28], - SuccessorChannelCookie); /* SuccessorChannelCookie (20 bytes) */ - rts_version_command_write(&buffer[48]); /* Version (8 bytes) */ - status = rpc_channel_write(&inChannel->common, buffer, header.header.frag_length); - free(buffer); - return (status > 0) ? 1 : -1; + if (!rts_write_pdu_header(buffer, &header)) /* RTS Header (20 bytes) */ + goto fail; + if (!rts_destination_command_write(buffer, FDServer)) /* Destination (8 bytes)*/ + goto fail; + if (!rts_cookie_command_write(buffer, + SuccessorChannelCookie)) /* SuccessorChannelCookie (20 bytes) */ + goto fail; + if (!rts_version_command_write(buffer)) /* Version (8 bytes) */ + goto fail; + status = rts_send_buffer(&inChannel->common, buffer, header.header.frag_length); +fail: + Stream_Free(buffer, TRUE); + return (status) ? 1 : -1; } static int rts_send_OUT_R2_C1_pdu(rdpRpc* rpc) { - int status; - BYTE* buffer; + BOOL status = FALSE; + wStream* buffer; rpcconn_rts_hdr_t header = rts_pdu_header_init(); - RpcOutChannel* nextOutChannel = rpc->VirtualConnection->NonDefaultOutChannel; + RpcOutChannel* nextOutChannel; + + assert(rpc); + assert(rpc->VirtualConnection); + + nextOutChannel = rpc->VirtualConnection->NonDefaultOutChannel; + assert(nextOutChannel); header.header.frag_length = 24; header.Flags = RTS_FLAG_PING; header.NumberOfCommands = 1; + WLog_DBG(TAG, "Sending OUT_R2/C1 RTS PDU"); - buffer = (BYTE*)malloc(header.header.frag_length); + buffer = Stream_New(NULL, header.header.frag_length); if (!buffer) return -1; - CopyMemory(buffer, ((BYTE*)&header), 20); /* RTS Header (20 bytes) */ - rts_empty_command_write(&buffer[20]); /* Empty command (4 bytes) */ - status = rpc_channel_write(&nextOutChannel->common, buffer, header.header.frag_length); - free(buffer); - return (status > 0) ? 1 : -1; + if (!rts_write_pdu_header(buffer, &header)) /* RTS Header (20 bytes) */ + goto fail; + + if (!rts_empty_command_write(buffer)) /* Empty command (4 bytes) */ + goto fail; + status = rts_send_buffer(&nextOutChannel->common, buffer, header.header.frag_length); +fail: + Stream_Free(buffer, TRUE); + return (status) ? 1 : -1; } -int rts_send_OUT_R1_A3_pdu(rdpRpc* rpc) +BOOL rts_send_OUT_R1_A3_pdu(rdpRpc* rpc) { - int status; - BYTE* buffer; + BOOL status = FALSE; + wStream* buffer; rpcconn_rts_hdr_t header = rts_pdu_header_init(); UINT32 ReceiveWindowSize; BYTE* VirtualConnectionCookie; BYTE* PredecessorChannelCookie; BYTE* SuccessorChannelCookie; - RpcVirtualConnection* connection = rpc->VirtualConnection; - RpcOutChannel* outChannel = connection->DefaultOutChannel; - RpcOutChannel* nextOutChannel = connection->NonDefaultOutChannel; + RpcVirtualConnection* connection; + RpcOutChannel* outChannel; + RpcOutChannel* nextOutChannel; + + assert(rpc); + + connection = rpc->VirtualConnection; + assert(connection); + + outChannel = connection->DefaultOutChannel; + assert(outChannel); + + nextOutChannel = connection->NonDefaultOutChannel; + assert(nextOutChannel); header.header.frag_length = 96; header.Flags = RTS_FLAG_RECYCLE_CHANNEL; header.NumberOfCommands = 5; + WLog_DBG(TAG, "Sending OUT_R1/A3 RTS PDU"); + VirtualConnectionCookie = (BYTE*)&(connection->Cookie); PredecessorChannelCookie = (BYTE*)&(outChannel->common.Cookie); SuccessorChannelCookie = (BYTE*)&(nextOutChannel->common.Cookie); ReceiveWindowSize = outChannel->ReceiveWindow; - buffer = (BYTE*)malloc(header.header.frag_length); + buffer = Stream_New(NULL, header.header.frag_length); if (!buffer) return -1; - CopyMemory(buffer, ((BYTE*)&header), 20); /* RTS Header (20 bytes) */ - rts_version_command_write(&buffer[20]); /* Version (8 bytes) */ - rts_cookie_command_write(&buffer[28], - VirtualConnectionCookie); /* VirtualConnectionCookie (20 bytes) */ - rts_cookie_command_write(&buffer[48], - PredecessorChannelCookie); /* PredecessorChannelCookie (20 bytes) */ - rts_cookie_command_write(&buffer[68], - SuccessorChannelCookie); /* SuccessorChannelCookie (20 bytes) */ - rts_receive_window_size_command_write(&buffer[88], - ReceiveWindowSize); /* ReceiveWindowSize (8 bytes) */ - status = rpc_channel_write(&nextOutChannel->common, buffer, header.header.frag_length); - free(buffer); - return (status > 0) ? 1 : -1; + if (!rts_write_pdu_header(buffer, &header)) /* RTS Header (20 bytes) */ + goto fail; + if (!rts_version_command_write(buffer)) /* Version (8 bytes) */ + goto fail; + if (!rts_cookie_command_write(buffer, + VirtualConnectionCookie)) /* VirtualConnectionCookie (20 bytes) */ + goto fail; + if (!rts_cookie_command_write( + buffer, PredecessorChannelCookie)) /* PredecessorChannelCookie (20 bytes) */ + goto fail; + if (!rts_cookie_command_write(buffer, + SuccessorChannelCookie)) /* SuccessorChannelCookie (20 bytes) */ + goto fail; + if (!rts_receive_window_size_command_write(buffer, + ReceiveWindowSize)) /* ReceiveWindowSize (8 bytes) */ + goto fail; + + status = rts_send_buffer(&nextOutChannel->common, buffer, header.header.frag_length); +fail: + Stream_Free(buffer, TRUE); + return status; } -static int rts_recv_OUT_R1_A2_pdu(rdpRpc* rpc, BYTE* buffer, UINT32 length) +static int rts_recv_OUT_R1_A2_pdu(rdpRpc* rpc, wStream* buffer) { int status; - UINT32 offset; UINT32 Destination = 0; - RpcVirtualConnection* connection = rpc->VirtualConnection; + RpcVirtualConnection* connection; + assert(rpc); + assert(buffer); + + connection = rpc->VirtualConnection; + assert(connection); + WLog_DBG(TAG, "Receiving OUT R1/A2 RTS PDU"); - offset = 24; - if (length < offset) - return -1; + status = rts_destination_command_read(rpc, buffer, &Destination); + if (status < 0) + return status; - rts_destination_command_read(rpc, &buffer[offset], length - offset, &Destination); connection->NonDefaultOutChannel = rpc_out_channel_new(rpc); if (!connection->NonDefaultOutChannel) @@ -859,10 +2036,17 @@ static int rts_recv_OUT_R1_A2_pdu(rdpRpc* rpc, BYTE* buffer, UINT32 length) return 1; } -static int rts_recv_OUT_R2_A6_pdu(rdpRpc* rpc, BYTE* buffer, UINT32 length) +static int rts_recv_OUT_R2_A6_pdu(rdpRpc* rpc, wStream* buffer) { int status; - RpcVirtualConnection* connection = rpc->VirtualConnection; + RpcVirtualConnection* connection; + + assert(rpc); + assert(buffer); + + connection = rpc->VirtualConnection; + assert(connection); + WLog_DBG(TAG, "Receiving OUT R2/A6 RTS PDU"); status = rts_send_OUT_R2_C1_pdu(rpc); @@ -887,47 +2071,59 @@ static int rts_recv_OUT_R2_A6_pdu(rdpRpc* rpc, BYTE* buffer, UINT32 length) return 1; } -static int rts_recv_OUT_R2_B3_pdu(rdpRpc* rpc, BYTE* buffer, UINT32 length) +static int rts_recv_OUT_R2_B3_pdu(rdpRpc* rpc, wStream* buffer) { - RpcVirtualConnection* connection = rpc->VirtualConnection; + RpcVirtualConnection* connection; + + assert(rpc); + assert(buffer); + + connection = rpc->VirtualConnection; + assert(connection); + WLog_DBG(TAG, "Receiving OUT R2/B3 RTS PDU"); rpc_out_channel_transition_to_state(connection->DefaultOutChannel, CLIENT_OUT_CHANNEL_STATE_RECYCLED); return 1; } -int rts_recv_out_of_sequence_pdu(rdpRpc* rpc, BYTE* buffer, UINT32 length) +BOOL rts_recv_out_of_sequence_pdu(rdpRpc* rpc, wStream* buffer, const rpcconn_hdr_t* header) { - int status = -1; + BOOL status = FALSE; UINT32 SignatureId; - rpcconn_rts_hdr_t* rts; - RtsPduSignature signature; + size_t length, total; + RtsPduSignature signature = { 0 }; RpcVirtualConnection* connection; - if (!rpc || !buffer) - return -1; + assert(rpc); + assert(buffer); + assert(header); + + total = Stream_Length(buffer); + length = header->common.frag_length; + if (total < length) + return FALSE; connection = rpc->VirtualConnection; if (!connection) - return -1; - - rts = (rpcconn_rts_hdr_t*)buffer; + return FALSE; - if (!rts_extract_pdu_signature(&signature, rts)) - return -1; + if (!rts_extract_pdu_signature(&signature, buffer, header)) + return FALSE; SignatureId = rts_identify_pdu_signature(&signature, NULL); - if (rts_match_pdu_signature(&RTS_PDU_FLOW_CONTROL_ACK_SIGNATURE, rts)) + if (rts_match_pdu_signature(&RTS_PDU_FLOW_CONTROL_ACK_SIGNATURE, buffer, header)) { - status = rts_recv_flow_control_ack_pdu(rpc, buffer, length); + status = rts_recv_flow_control_ack_pdu(rpc, buffer); } - else if (rts_match_pdu_signature(&RTS_PDU_FLOW_CONTROL_ACK_WITH_DESTINATION_SIGNATURE, rts)) + else if (rts_match_pdu_signature(&RTS_PDU_FLOW_CONTROL_ACK_WITH_DESTINATION_SIGNATURE, buffer, + header)) { - status = rts_recv_flow_control_ack_with_destination_pdu(rpc, buffer, length); + status = rts_recv_flow_control_ack_with_destination_pdu(rpc, buffer); } - else if (rts_match_pdu_signature(&RTS_PDU_PING_SIGNATURE, rts)) + else if (rts_match_pdu_signature(&RTS_PDU_PING_SIGNATURE, buffer, header)) { status = rts_send_ping_pdu(rpc); } @@ -935,28 +2131,28 @@ int rts_recv_out_of_sequence_pdu(rdpRpc* rpc, BYTE* buffer, UINT32 length) { if (connection->DefaultOutChannel->State == CLIENT_OUT_CHANNEL_STATE_OPENED) { - if (rts_match_pdu_signature(&RTS_PDU_OUT_R1_A2_SIGNATURE, rts)) + if (rts_match_pdu_signature(&RTS_PDU_OUT_R1_A2_SIGNATURE, buffer, header)) { - status = rts_recv_OUT_R1_A2_pdu(rpc, buffer, length); + status = rts_recv_OUT_R1_A2_pdu(rpc, buffer); } } else if (connection->DefaultOutChannel->State == CLIENT_OUT_CHANNEL_STATE_OPENED_A6W) { - if (rts_match_pdu_signature(&RTS_PDU_OUT_R2_A6_SIGNATURE, rts)) + if (rts_match_pdu_signature(&RTS_PDU_OUT_R2_A6_SIGNATURE, buffer, header)) { - status = rts_recv_OUT_R2_A6_pdu(rpc, buffer, length); + status = rts_recv_OUT_R2_A6_pdu(rpc, buffer); } } else if (connection->DefaultOutChannel->State == CLIENT_OUT_CHANNEL_STATE_OPENED_B3W) { - if (rts_match_pdu_signature(&RTS_PDU_OUT_R2_B3_SIGNATURE, rts)) + if (rts_match_pdu_signature(&RTS_PDU_OUT_R2_B3_SIGNATURE, buffer, header)) { - status = rts_recv_OUT_R2_B3_pdu(rpc, buffer, length); + status = rts_recv_OUT_R2_B3_pdu(rpc, buffer); } } } - if (status < 0) + if (!status) { WLog_ERR(TAG, "error parsing RTS PDU with signature id: 0x%08" PRIX32 "", SignatureId); rts_print_pdu_signature(&signature); @@ -964,3 +2160,42 @@ int rts_recv_out_of_sequence_pdu(rdpRpc* rpc, BYTE* buffer, UINT32 length) return status; } + +BOOL rts_write_pdu_auth3(wStream* s, const rpcconn_rpc_auth_3_hdr_t* auth) +{ + assert(s); + assert(auth); + + if (!rts_write_common_pdu_header(s, &auth->header)) + return FALSE; + + if (!Stream_EnsureRemainingCapacity(s, 2 * sizeof(UINT16))) + return FALSE; + + Stream_Write_UINT16(s, auth->max_xmit_frag); + Stream_Write_UINT16(s, auth->max_recv_frag); + + return rts_write_auth_verifier(s, &auth->auth_verifier, &auth->header); +} + +BOOL rts_write_pdu_bind(wStream* s, const rpcconn_bind_hdr_t* bind) +{ + + assert(s); + assert(bind); + + if (!rts_write_common_pdu_header(s, &bind->header)) + return FALSE; + + if (!Stream_EnsureRemainingCapacity(s, 8)) + return FALSE; + + Stream_Write_UINT16(s, bind->max_xmit_frag); + Stream_Write_UINT16(s, bind->max_recv_frag); + Stream_Write_UINT32(s, bind->assoc_group_id); + + if (!rts_write_context_list(s, &bind->p_context_elem)) + return FALSE; + + return rts_write_auth_verifier(s, &bind->auth_verifier, &bind->header); +} diff --git a/libfreerdp/core/gateway/rts.h b/libfreerdp/core/gateway/rts.h index ccc4cfd18bca..01a66a781013 100644 --- a/libfreerdp/core/gateway/rts.h +++ b/libfreerdp/core/gateway/rts.h @@ -24,12 +24,14 @@ #include "config.h" #endif -#include "rpc.h" +#include #include #include #include +#include "rpc.h" + #define RTS_FLAG_NONE 0x0000 #define RTS_FLAG_PING 0x0001 #define RTS_FLAG_OTHER_CMD 0x0002 @@ -79,21 +81,28 @@ FREERDP_LOCAL void rts_generate_cookie(BYTE* cookie); -FREERDP_LOCAL SSIZE_T rts_command_length(UINT32 CommandType, const BYTE* buffer, size_t length); +FREERDP_LOCAL BOOL rts_write_pdu_auth3(wStream* s, const rpcconn_rpc_auth_3_hdr_t* auth); +FREERDP_LOCAL BOOL rts_write_pdu_bind(wStream* s, const rpcconn_bind_hdr_t* bind); + +FREERDP_LOCAL BOOL rts_read_pdu_header(wStream* s, rpcconn_hdr_t* header); +FREERDP_LOCAL void rts_free_pdu_header(rpcconn_hdr_t* header, BOOL allocated); + +FREERDP_LOCAL BOOL rts_read_common_pdu_header(wStream* s, rpcconn_common_hdr_t* header); -FREERDP_LOCAL int rts_send_CONN_A1_pdu(rdpRpc* rpc); -FREERDP_LOCAL int rts_recv_CONN_A3_pdu(rdpRpc* rpc, BYTE* buffer, UINT32 length); +FREERDP_LOCAL BOOL rts_command_length(UINT32 CommandType, wStream* s, size_t* length); -FREERDP_LOCAL int rts_send_CONN_B1_pdu(rdpRpc* rpc); +FREERDP_LOCAL BOOL rts_send_CONN_A1_pdu(rdpRpc* rpc); +FREERDP_LOCAL BOOL rts_recv_CONN_A3_pdu(rdpRpc* rpc, wStream* buffer); -FREERDP_LOCAL int rts_recv_CONN_C2_pdu(rdpRpc* rpc, BYTE* buffer, UINT32 length); +FREERDP_LOCAL BOOL rts_send_CONN_B1_pdu(rdpRpc* rpc); -FREERDP_LOCAL int rts_send_OUT_R1_A3_pdu(rdpRpc* rpc); +FREERDP_LOCAL BOOL rts_recv_CONN_C2_pdu(rdpRpc* rpc, wStream* buffer); -FREERDP_LOCAL int rts_send_flow_control_ack_pdu(rdpRpc* rpc); +FREERDP_LOCAL BOOL rts_send_OUT_R1_A3_pdu(rdpRpc* rpc); -FREERDP_LOCAL int rts_recv_out_of_sequence_pdu(rdpRpc* rpc, BYTE* buffer, UINT32 length); +FREERDP_LOCAL BOOL rts_send_flow_control_ack_pdu(rdpRpc* rpc); -#include "rts_signature.h" +FREERDP_LOCAL BOOL rts_recv_out_of_sequence_pdu(rdpRpc* rpc, wStream* buffer, + const rpcconn_hdr_t* header); #endif /* FREERDP_LIB_CORE_GATEWAY_RTS_H */ diff --git a/libfreerdp/core/gateway/rts_signature.c b/libfreerdp/core/gateway/rts_signature.c index 4d605f041689..b9319d185ce9 100644 --- a/libfreerdp/core/gateway/rts_signature.c +++ b/libfreerdp/core/gateway/rts_signature.c @@ -17,6 +17,9 @@ * limitations under the License. */ +#include +#include + #include #include "rts_signature.h" @@ -276,90 +279,74 @@ static const RTS_PDU_SIGNATURE_ENTRY RTS_PDU_SIGNATURE_TABLE[] = { { RTS_PDU_PING, TRUE, &RTS_PDU_PING_SIGNATURE, "Ping" }, { RTS_PDU_FLOW_CONTROL_ACK, TRUE, &RTS_PDU_FLOW_CONTROL_ACK_SIGNATURE, "FlowControlAck" }, { RTS_PDU_FLOW_CONTROL_ACK_WITH_DESTINATION, TRUE, - &RTS_PDU_FLOW_CONTROL_ACK_WITH_DESTINATION_SIGNATURE, "FlowControlAckWithDestination" }, - - { 0, FALSE, NULL, NULL } + &RTS_PDU_FLOW_CONTROL_ACK_WITH_DESTINATION_SIGNATURE, "FlowControlAckWithDestination" } }; -BOOL rts_match_pdu_signature(const RtsPduSignature* signature, const rpcconn_rts_hdr_t* rts) +BOOL rts_match_pdu_signature(const RtsPduSignature* signature, wStream* src, + const rpcconn_hdr_t* header) { - UINT16 i; - int status; - const BYTE* buffer; - UINT32 length; - UINT32 offset; - UINT32 CommandType; - UINT32 CommandLength; - - if (!signature || !rts) - return FALSE; + RtsPduSignature extracted = { 0 }; - if (rts->Flags != signature->Flags) - return FALSE; + assert(signature); + assert(src); - if (rts->NumberOfCommands != signature->NumberOfCommands) + if (!rts_extract_pdu_signature(&extracted, src, header)) return FALSE; - buffer = (const BYTE*)rts; - offset = RTS_PDU_HEADER_LENGTH; - length = rts->header.frag_length - offset; - - for (i = 0; i < rts->NumberOfCommands; i++) - { - CommandType = *((UINT32*)&buffer[offset]); /* CommandType (4 bytes) */ - offset += 4; - - if (CommandType != signature->CommandTypes[i]) - return FALSE; + return memcmp(signature, &extracted, sizeof(extracted)) == 0; +} - status = rts_command_length(CommandType, &buffer[offset], length); +BOOL rts_extract_pdu_signature(RtsPduSignature* signature, wStream* src, + const rpcconn_hdr_t* header) +{ + BOOL rc = FALSE; + UINT16 i; + wStream tmp; + rpcconn_hdr_t rheader = { 0 }; + const rpcconn_rts_hdr_t* rts; - if (status < 0) - return FALSE; + assert(signature); + assert(src); - CommandLength = (UINT32)status; - offset += CommandLength; - length = rts->header.frag_length - offset; + Stream_StaticInit(&tmp, Stream_Pointer(src), Stream_GetRemainingLength(src)); + if (!header) + { + if (!rts_read_pdu_header(&tmp, &rheader)) + goto fail; + header = &rheader; } - - return TRUE; -} - -BOOL rts_extract_pdu_signature(RtsPduSignature* signature, const rpcconn_rts_hdr_t* rts) -{ - int i; - int status; - BYTE* buffer; - UINT32 length; - UINT32 offset; - UINT32 CommandType; - UINT32 CommandLength; - - if (!signature || !rts) - return FALSE; + rts = &header->rts; + if (rts->header.frag_length < sizeof(rpcconn_rts_hdr_t)) + goto fail; signature->Flags = rts->Flags; signature->NumberOfCommands = rts->NumberOfCommands; - buffer = (BYTE*)rts; - offset = RTS_PDU_HEADER_LENGTH; - length = rts->header.frag_length - offset; for (i = 0; i < rts->NumberOfCommands; i++) { - CommandType = *((UINT32*)&buffer[offset]); /* CommandType (4 bytes) */ - offset += 4; - signature->CommandTypes[i] = CommandType; - status = rts_command_length(CommandType, &buffer[offset], length); + UINT32 CommandType; + size_t CommandLength; + + if (Stream_GetRemainingLength(&tmp) < 4) + goto fail; + + Stream_Read_UINT32(&tmp, CommandType); /* CommandType (4 bytes) */ - if (status < 0) - return FALSE; + /* We only need this for comparison against known command types */ + if (i < ARRAYSIZE(signature->CommandTypes)) + signature->CommandTypes[i] = CommandType; - CommandLength = (UINT32)status; - offset += CommandLength; - length = rts->header.frag_length - offset; + if (!rts_command_length(CommandType, &tmp, &CommandLength)) + goto fail; + if (!Stream_SafeSeek(&tmp, CommandLength)) + goto fail; } - return TRUE; + rc = TRUE; +fail: + rts_free_pdu_header(&rheader, FALSE); + Stream_Free(&tmp, FALSE); + return rc; } UINT32 rts_identify_pdu_signature(const RtsPduSignature* signature, @@ -367,11 +354,15 @@ UINT32 rts_identify_pdu_signature(const RtsPduSignature* signature, { size_t i, j; - for (i = 0; RTS_PDU_SIGNATURE_TABLE[i].SignatureId != 0; i++) + if (entry) + *entry = NULL; + + for (i = 0; i < ARRAYSIZE(RTS_PDU_SIGNATURE_TABLE); i++) { - const RtsPduSignature* pSignature = RTS_PDU_SIGNATURE_TABLE[i].Signature; + const RTS_PDU_SIGNATURE_ENTRY* current = &RTS_PDU_SIGNATURE_TABLE[i]; + const RtsPduSignature* pSignature = current->Signature; - if (!RTS_PDU_SIGNATURE_TABLE[i].SignatureClient) + if (!current->SignatureClient) continue; if (signature->Flags != pSignature->Flags) @@ -387,9 +378,9 @@ UINT32 rts_identify_pdu_signature(const RtsPduSignature* signature, } if (entry) - *entry = &RTS_PDU_SIGNATURE_TABLE[i]; + *entry = current; - return RTS_PDU_SIGNATURE_TABLE[i].SignatureId; + return current->SignatureId; } return 0; diff --git a/libfreerdp/core/gateway/rts_signature.h b/libfreerdp/core/gateway/rts_signature.h index 2c43cdc1b898..31f0e810056c 100644 --- a/libfreerdp/core/gateway/rts_signature.h +++ b/libfreerdp/core/gateway/rts_signature.h @@ -178,10 +178,10 @@ FREERDP_LOCAL extern const RtsPduSignature RTS_PDU_PING_SIGNATURE; FREERDP_LOCAL extern const RtsPduSignature RTS_PDU_FLOW_CONTROL_ACK_SIGNATURE; FREERDP_LOCAL extern const RtsPduSignature RTS_PDU_FLOW_CONTROL_ACK_WITH_DESTINATION_SIGNATURE; -FREERDP_LOCAL BOOL rts_match_pdu_signature(const RtsPduSignature* signature, - const rpcconn_rts_hdr_t* rts); -FREERDP_LOCAL BOOL rts_extract_pdu_signature(RtsPduSignature* signature, - const rpcconn_rts_hdr_t* rts); +FREERDP_LOCAL BOOL rts_match_pdu_signature(const RtsPduSignature* signature, wStream* s, + const rpcconn_hdr_t* header); +FREERDP_LOCAL BOOL rts_extract_pdu_signature(RtsPduSignature* signature, wStream* s, + const rpcconn_hdr_t* header); FREERDP_LOCAL UINT32 rts_identify_pdu_signature(const RtsPduSignature* signature, const RTS_PDU_SIGNATURE_ENTRY** entry); FREERDP_LOCAL BOOL rts_print_pdu_signature(const RtsPduSignature* signature); diff --git a/libfreerdp/core/gateway/tsg.c b/libfreerdp/core/gateway/tsg.c index 9d01c9fdd6a0..c03f266f2bf3 100644 --- a/libfreerdp/core/gateway/tsg.c +++ b/libfreerdp/core/gateway/tsg.c @@ -24,6 +24,7 @@ #include "config.h" #endif +#include #include #include #include @@ -39,13 +40,14 @@ #define TAG FREERDP_TAG("core.gateway.tsg") +#define TSG_CAPABILITY_TYPE_NAP 0x00000001 + #define TSG_PACKET_TYPE_HEADER 0x00004844 #define TSG_PACKET_TYPE_VERSIONCAPS 0x00005643 #define TSG_PACKET_TYPE_QUARCONFIGREQUEST 0x00005143 #define TSG_PACKET_TYPE_QUARREQUEST 0x00005152 #define TSG_PACKET_TYPE_RESPONSE 0x00005052 #define TSG_PACKET_TYPE_QUARENC_RESPONSE 0x00004552 -#define TSG_CAPABILITY_TYPE_NAP 0x00000001 #define TSG_PACKET_TYPE_CAPS_RESPONSE 0x00004350 #define TSG_PACKET_TYPE_MSGREQUEST_PACKET 0x00004752 #define TSG_PACKET_TYPE_MESSAGE_PACKET 0x00004750 @@ -222,7 +224,6 @@ struct rdp_tsg UINT32 TunnelId; UINT32 ChannelId; BOOL reauthSequence; - rdpSettings* settings; rdpTransport* transport; UINT64 ReauthTunnelContext; CONTEXT_HANDLE TunnelContext; @@ -311,16 +312,35 @@ static BOOL tsg_print(char** buffer, size_t* len, const char* fmt, ...) static BOOL tsg_packet_header_to_string(char** buffer, size_t* length, const TSG_PACKET_HEADER* header) { + assert(buffer); + assert(length); + assert(header); + return tsg_print(buffer, length, "header { ComponentId=0x%04" PRIx16 ", PacketId=0x%04" PRIx16 " }", header->ComponentId, header->PacketId); } +static BOOL tsg_type_capability_nap_to_string(char** buffer, size_t* length, + const TSG_CAPABILITY_NAP* cur) +{ + assert(buffer); + assert(length); + assert(cur); + + return tsg_print(buffer, length, "%s { capabilities=0x%08" PRIx32 " }", + tsg_packet_id_to_string(TSG_CAPABILITY_TYPE_NAP), cur->capabilities); +} + static BOOL tsg_packet_capabilities_to_string(char** buffer, size_t* length, const TSG_PACKET_CAPABILITIES* caps, UINT32 numCaps) { UINT32 x; + assert(buffer); + assert(length); + assert(caps); + if (!tsg_print(buffer, length, "capabilities { ")) return FALSE; @@ -330,9 +350,7 @@ static BOOL tsg_packet_capabilities_to_string(char** buffer, size_t* length, switch (cur->capabilityType) { case TSG_CAPABILITY_TYPE_NAP: - if (!tsg_print(buffer, length, "%s { capabilities=0x%08" PRIx32 " }", - tsg_packet_id_to_string(cur->capabilityType), - cur->tsgPacket.tsgCapNap.capabilities)) + if (!tsg_type_capability_nap_to_string(buffer, length, &cur->tsgPacket.tsgCapNap)) return FALSE; break; default: @@ -347,6 +365,10 @@ static BOOL tsg_packet_capabilities_to_string(char** buffer, size_t* length, static BOOL tsg_packet_versioncaps_to_string(char** buffer, size_t* length, const TSG_PACKET_VERSIONCAPS* caps) { + assert(buffer); + assert(length); + assert(caps); + if (!tsg_print(buffer, length, "versioncaps { ")) return FALSE; if (!tsg_packet_header_to_string(buffer, length, &caps->tsgHeader)) @@ -368,6 +390,281 @@ static BOOL tsg_packet_versioncaps_to_string(char** buffer, size_t* length, return tsg_print(buffer, length, " }"); } +static BOOL tsg_packet_quarconfigrequest_to_string(char** buffer, size_t* length, + const TSG_PACKET_QUARCONFIGREQUEST* caps) +{ + assert(buffer); + assert(length); + assert(caps); + + if (!tsg_print(buffer, length, "quarconfigrequest { ")) + return FALSE; + + if (!tsg_print(buffer, length, " ")) + return FALSE; + + if (!tsg_print(buffer, length, " flags=0x%08" PRIx32, caps->flags)) + return FALSE; + + return tsg_print(buffer, length, " }"); +} + +static BOOL tsg_packet_quarrequest_to_string(char** buffer, size_t* length, + const TSG_PACKET_QUARREQUEST* caps) +{ + BOOL rc = FALSE; + char* name = NULL; + char* strdata = NULL; + + assert(buffer); + assert(length); + assert(caps); + + if (!tsg_print(buffer, length, "quarrequest { ")) + return FALSE; + + if (!tsg_print(buffer, length, " ")) + return FALSE; + + if (caps->nameLength > 0) + { + if (caps->nameLength > INT_MAX) + return FALSE; + if (ConvertFromUnicode(CP_UTF8, 0, caps->machineName, (int)caps->nameLength, &name, 0, NULL, + NULL) < 0) + return FALSE; + } + + strdata = winpr_BinToHexString(caps->data, caps->dataLen, TRUE); + if (strdata || (caps->dataLen == 0)) + rc = tsg_print(buffer, length, + " flags=0x%08" PRIx32 ", machineName=%s [%" PRIu32 "], data[%" PRIu32 "]=%s", + caps->flags, name, caps->nameLength, caps->dataLen, strdata); + free(name); + free(strdata); + if (!rc) + return FALSE; + + return tsg_print(buffer, length, " }"); +} + +static const char* tsg_bool_to_string(BOOL val) +{ + if (val) + return "true"; + return "false"; +} + +static const char* tsg_redirection_flags_to_string(char* buffer, size_t size, + const TSG_REDIRECTION_FLAGS* flags) +{ + assert(buffer || (size == 0)); + assert(flags); + + _snprintf(buffer, size, + "enableAllRedirections=%s, disableAllRedirections=%s, driveRedirectionDisabled=%s, " + "printerRedirectionDisabled=%s, portRedirectionDisabled=%s, reserved=%s, " + "clipboardRedirectionDisabled=%s, pnpRedirectionDisabled=%s", + tsg_bool_to_string(flags->enableAllRedirections), + tsg_bool_to_string(flags->disableAllRedirections), + tsg_bool_to_string(flags->driveRedirectionDisabled), + tsg_bool_to_string(flags->printerRedirectionDisabled), + tsg_bool_to_string(flags->portRedirectionDisabled), + tsg_bool_to_string(flags->reserved), + tsg_bool_to_string(flags->clipboardRedirectionDisabled), + tsg_bool_to_string(flags->pnpRedirectionDisabled)); + return buffer; +} + +static BOOL tsg_packet_response_to_string(char** buffer, size_t* length, + const TSG_PACKET_RESPONSE* caps) +{ + BOOL rc = FALSE; + char* strdata = NULL; + char tbuffer[8192] = { 0 }; + + assert(buffer); + assert(length); + assert(caps); + + if (!tsg_print(buffer, length, "response { ")) + return FALSE; + + if (!tsg_print(buffer, length, " ")) + return FALSE; + + strdata = winpr_BinToHexString(caps->responseData, caps->responseDataLen, TRUE); + if (strdata || (caps->responseDataLen == 0)) + rc = tsg_print( + buffer, length, + " flags=0x%08" PRIx32 ", reserved=0x%08" PRIx32 ", responseData[%" PRIu32 + "]=%s, redirectionFlags={ %s }", + caps->flags, caps->reserved, caps->responseDataLen, strdata, + tsg_redirection_flags_to_string(tbuffer, ARRAYSIZE(tbuffer), &caps->redirectionFlags)); + free(strdata); + if (!rc) + return FALSE; + + return tsg_print(buffer, length, " }"); +} + +static BOOL tsg_packet_quarenc_response_to_string(char** buffer, size_t* length, + const TSG_PACKET_QUARENC_RESPONSE* caps) +{ + BOOL rc = FALSE; + char* strdata = NULL; + RPC_CSTR uuid; + char tbuffer[8192] = { 0 }; + size_t size = ARRAYSIZE(tbuffer); + char* ptbuffer = tbuffer; + + assert(buffer); + assert(length); + assert(caps); + + if (!tsg_print(buffer, length, "quarenc_response { ")) + return FALSE; + + if (!tsg_print(buffer, length, " ")) + return FALSE; + + if (caps->certChainLen > 0) + { + if (caps->certChainLen > INT_MAX) + return FALSE; + if (ConvertFromUnicode(CP_UTF8, 0, caps->certChainData, (int)caps->certChainLen, &strdata, + 0, NULL, NULL) <= 0) + return FALSE; + } + + tsg_packet_versioncaps_to_string(&ptbuffer, &size, caps->versionCaps); + UuidToStringA(&caps->nonce, &uuid); + if (strdata || (caps->certChainLen == 0)) + rc = + tsg_print(buffer, length, + " flags=0x%08" PRIx32 ", certChain[%" PRIu32 "]=%s, nonce=%s, versionCaps=%s", + caps->flags, caps->certChainLen, strdata, uuid, tbuffer); + free(strdata); + free(uuid); + if (!rc) + return FALSE; + + return tsg_print(buffer, length, " }"); +} + +static BOOL tsg_packet_message_response_to_string(char** buffer, size_t* length, + const TSG_PACKET_MSG_RESPONSE* caps) +{ + assert(buffer); + assert(length); + assert(caps); + + if (!tsg_print(buffer, length, "msg_response { ")) + return FALSE; + + if (!tsg_print(buffer, length, + " msgID=0x%08" PRIx32 ", msgType=0x%08" PRIx32 ", isMsgPresent=%" PRId32, + caps->msgID, caps->msgType, caps->isMsgPresent)) + return FALSE; + + return tsg_print(buffer, length, " }"); +} + +static BOOL tsg_packet_caps_response_to_string(char** buffer, size_t* length, + const TSG_PACKET_CAPS_RESPONSE* caps) +{ + assert(buffer); + assert(length); + assert(caps); + + if (!tsg_print(buffer, length, "caps_response { ")) + return FALSE; + + if (!tsg_packet_quarenc_response_to_string(buffer, length, &caps->pktQuarEncResponse)) + return FALSE; + + if (!tsg_packet_message_response_to_string(buffer, length, &caps->pktConsentMessage)) + return FALSE; + + return tsg_print(buffer, length, " }"); +} + +static BOOL tsg_packet_message_request_to_string(char** buffer, size_t* length, + const TSG_PACKET_MSG_REQUEST* caps) +{ + assert(buffer); + assert(length); + assert(caps); + + if (!tsg_print(buffer, length, "caps_message_request { ")) + return FALSE; + + if (!tsg_print(buffer, length, " maxMessagesPerBatch=%" PRIu32, caps->maxMessagesPerBatch)) + return FALSE; + + return tsg_print(buffer, length, " }"); +} + +static BOOL tsg_packet_auth_to_string(char** buffer, size_t* length, const TSG_PACKET_AUTH* caps) +{ + BOOL rc = FALSE; + char* strdata = NULL; + assert(buffer); + assert(length); + assert(caps); + + if (!tsg_print(buffer, length, "caps_message_request { ")) + return FALSE; + + if (!tsg_packet_versioncaps_to_string(buffer, length, &caps->tsgVersionCaps)) + return FALSE; + + strdata = winpr_BinToHexString(caps->cookie, caps->cookieLen, TRUE); + if (strdata || (caps->cookieLen == 0)) + rc = tsg_print(buffer, length, " cookie[%" PRIu32 "]=%s", caps->cookieLen, strdata); + free(strdata); + if (!rc) + return FALSE; + + return tsg_print(buffer, length, " }"); +} + +static BOOL tsg_packet_reauth_to_string(char** buffer, size_t* length, + const TSG_PACKET_REAUTH* caps) +{ + BOOL rc = FALSE; + assert(buffer); + assert(length); + assert(caps); + + if (!tsg_print(buffer, length, "caps_message_request { ")) + return FALSE; + + if (!tsg_print(buffer, length, " tunnelContext=0x%016" PRIx64 ", packetId=%s [0x%08" PRIx32 "]", + caps->tunnelContext, tsg_packet_id_to_string(caps->packetId), caps->packetId)) + return FALSE; + + switch (caps->packetId) + { + case TSG_PACKET_TYPE_VERSIONCAPS: + rc = tsg_packet_versioncaps_to_string(buffer, length, + caps->tsgInitialPacket.packetVersionCaps); + break; + case TSG_PACKET_TYPE_AUTH: + rc = tsg_packet_auth_to_string(buffer, length, caps->tsgInitialPacket.packetAuth); + break; + default: + rc = tsg_print(buffer, length, "TODO: Unhandled packet type %s [0x%08" PRIx32 "]", + tsg_packet_id_to_string(caps->packetId), caps->packetId); + break; + } + + if (!rc) + return FALSE; + + return tsg_print(buffer, length, " }"); +} + static const char* tsg_packet_to_string(const TSG_PACKET* packet) { size_t len = 8192; @@ -390,43 +687,45 @@ static const char* tsg_packet_to_string(const TSG_PACKET* packet) goto fail; break; case TSG_PACKET_TYPE_QUARCONFIGREQUEST: - if (!tsg_print(&buffer, &len, "TODO")) + if (!tsg_packet_quarconfigrequest_to_string(&buffer, &len, + packet->tsgPacket.packetQuarConfigRequest)) goto fail; break; case TSG_PACKET_TYPE_QUARREQUEST: - if (!tsg_print(&buffer, &len, "TODO")) + if (!tsg_packet_quarrequest_to_string(&buffer, &len, + packet->tsgPacket.packetQuarRequest)) goto fail; break; case TSG_PACKET_TYPE_RESPONSE: - if (!tsg_print(&buffer, &len, "TODO")) + if (!tsg_packet_response_to_string(&buffer, &len, packet->tsgPacket.packetResponse)) goto fail; break; case TSG_PACKET_TYPE_QUARENC_RESPONSE: - if (!tsg_print(&buffer, &len, "TODO")) - goto fail; - break; - case TSG_CAPABILITY_TYPE_NAP: - if (!tsg_print(&buffer, &len, "TODO")) + if (!tsg_packet_quarenc_response_to_string(&buffer, &len, + packet->tsgPacket.packetQuarEncResponse)) goto fail; break; case TSG_PACKET_TYPE_CAPS_RESPONSE: - if (!tsg_print(&buffer, &len, "TODO")) + if (!tsg_packet_caps_response_to_string(&buffer, &len, + packet->tsgPacket.packetCapsResponse)) goto fail; break; case TSG_PACKET_TYPE_MSGREQUEST_PACKET: - if (!tsg_print(&buffer, &len, "TODO")) + if (!tsg_packet_message_request_to_string(&buffer, &len, + packet->tsgPacket.packetMsgRequest)) goto fail; break; case TSG_PACKET_TYPE_MESSAGE_PACKET: - if (!tsg_print(&buffer, &len, "TODO")) + if (!tsg_packet_message_response_to_string(&buffer, &len, + packet->tsgPacket.packetMsgResponse)) goto fail; break; case TSG_PACKET_TYPE_AUTH: - if (!tsg_print(&buffer, &len, "TODO")) + if (!tsg_packet_auth_to_string(&buffer, &len, packet->tsgPacket.packetAuth)) goto fail; break; case TSG_PACKET_TYPE_REAUTH: - if (!tsg_print(&buffer, &len, "TODO")) + if (!tsg_packet_reauth_to_string(&buffer, &len, packet->tsgPacket.packetReauth)) goto fail; break; default: @@ -500,7 +799,7 @@ static int TsProxySendToServer(handle_t IDL_handle, const byte pRpcMessage[], UI { wStream* s; rdpTsg* tsg; - int length; + size_t length; const byte* buffer1 = NULL; const byte* buffer2 = NULL; const byte* buffer3 = NULL; @@ -536,7 +835,9 @@ static int TsProxySendToServer(handle_t IDL_handle, const byte pRpcMessage[], UI totalDataBytes += lengths[2] + 4; } - length = 28 + totalDataBytes; + length = 28ull + totalDataBytes; + if (length > INT_MAX) + return -1; s = Stream_New(NULL, length); if (!s) @@ -572,7 +873,7 @@ static int TsProxySendToServer(handle_t IDL_handle, const byte pRpcMessage[], UI if (!rpc_client_write_call(tsg->rpc, s, TsProxySendToServerOpnum)) return -1; - return length; + return (int)length; } /** @@ -725,12 +1026,19 @@ static BOOL TsProxyCreateTunnelReadResponse(rdpTsg* tsg, RPC_PDU* pdu, UINT32 SwitchValue; UINT32 MessageSwitchValue = 0; UINT32 IsMessagePresent; + rdpContext* context; PTSG_PACKET_CAPABILITIES tsgCaps = NULL; PTSG_PACKET_VERSIONCAPS versionCaps = NULL; TSG_PACKET_STRING_MESSAGE packetStringMessage; PTSG_PACKET_CAPS_RESPONSE packetCapsResponse = NULL; PTSG_PACKET_QUARENC_RESPONSE packetQuarEncResponse = NULL; + assert(tsg); + assert(tsg->rpc); + + context = tsg->rpc->context; + assert(context); + if (!pdu) return FALSE; @@ -877,8 +1185,8 @@ static BOOL TsProxyCreateTunnelReadResponse(rdpTsg* tsg, RPC_PDU* pdu, if (Stream_GetRemainingLength(pdu->s) < 16) goto fail; - Stream_Read_UINT32(pdu->s, packetStringMessage.isDisplayMandatory); - Stream_Read_UINT32(pdu->s, packetStringMessage.isConsentMandatory); + Stream_Read_INT32(pdu->s, packetStringMessage.isDisplayMandatory); + Stream_Read_INT32(pdu->s, packetStringMessage.isConsentMandatory); Stream_Read_UINT32(pdu->s, packetStringMessage.msgBytes); Stream_Read_UINT32(pdu->s, Pointer); @@ -907,16 +1215,15 @@ static BOOL TsProxyCreateTunnelReadResponse(rdpTsg* tsg, RPC_PDU* pdu, goto fail; } - if (tsg->rpc && tsg->rpc->context && tsg->rpc->context->instance) + if (context->instance) { - rc = IFCALLRESULT(TRUE, tsg->rpc->context->instance->PresentGatewayMessage, - tsg->rpc->context->instance, - TSG_ASYNC_MESSAGE_CONSENT_MESSAGE - ? GATEWAY_MESSAGE_CONSENT - : TSG_ASYNC_MESSAGE_SERVICE_MESSAGE, - packetStringMessage.isDisplayMandatory != 0, - packetStringMessage.isConsentMandatory != 0, - packetStringMessage.msgBytes, packetStringMessage.msgBuffer); + rc = IFCALLRESULT( + TRUE, context->instance->PresentGatewayMessage, context->instance, + TSG_ASYNC_MESSAGE_CONSENT_MESSAGE ? GATEWAY_MESSAGE_CONSENT + : TSG_ASYNC_MESSAGE_SERVICE_MESSAGE, + packetStringMessage.isDisplayMandatory != 0, + packetStringMessage.isConsentMandatory != 0, packetStringMessage.msgBytes, + packetStringMessage.msgBuffer); if (!rc) goto fail; } @@ -1079,16 +1386,19 @@ static BOOL TsProxyCreateTunnelReadResponse(rdpTsg* tsg, RPC_PDU* pdu, static BOOL TsProxyAuthorizeTunnelWriteRequest(rdpTsg* tsg, CONTEXT_HANDLE* tunnelContext) { - UINT32 pad; + size_t pad; wStream* s; size_t count; - UINT32 offset; + size_t offset; rdpRpc* rpc; if (!tsg || !tsg->rpc || !tunnelContext || !tsg->MachineName) return FALSE; count = _wcslen(tsg->MachineName) + 1; + if (count > UINT32_MAX) + return FALSE; + rpc = tsg->rpc; WLog_DBG(TAG, "TsProxyAuthorizeTunnelWriteRequest"); s = Stream_New(NULL, 1024 + count * 2); @@ -1105,13 +1415,13 @@ static BOOL TsProxyAuthorizeTunnelWriteRequest(rdpTsg* tsg, CONTEXT_HANDLE* tunn Stream_Write_UINT32(s, 0x00020000); /* PacketQuarRequestPtr (4 bytes) */ Stream_Write_UINT32(s, 0x00000000); /* Flags (4 bytes) */ Stream_Write_UINT32(s, 0x00020004); /* MachineNamePtr (4 bytes) */ - Stream_Write_UINT32(s, count); /* NameLength (4 bytes) */ + Stream_Write_UINT32(s, (UINT32)count); /* NameLength (4 bytes) */ Stream_Write_UINT32(s, 0x00020008); /* DataPtr (4 bytes) */ Stream_Write_UINT32(s, 0); /* DataLength (4 bytes) */ /* MachineName */ - Stream_Write_UINT32(s, count); /* MaxCount (4 bytes) */ + Stream_Write_UINT32(s, (UINT32)count); /* MaxCount (4 bytes) */ Stream_Write_UINT32(s, 0); /* Offset (4 bytes) */ - Stream_Write_UINT32(s, count); /* ActualCount (4 bytes) */ + Stream_Write_UINT32(s, (UINT32)count); /* ActualCount (4 bytes) */ Stream_Write_UTF16_String(s, tsg->MachineName, count); /* Array */ /* 4-byte alignment */ offset = Stream_GetPosition(s); @@ -1122,7 +1432,7 @@ static BOOL TsProxyAuthorizeTunnelWriteRequest(rdpTsg* tsg, CONTEXT_HANDLE* tunn return rpc_client_write_call(rpc, s, TsProxyAuthorizeTunnelOpnum); } -static BOOL TsProxyAuthorizeTunnelReadResponse(rdpTsg* tsg, RPC_PDU* pdu) +static BOOL TsProxyAuthorizeTunnelReadResponse(RPC_PDU* pdu) { BOOL rc = FALSE; UINT32 Pointer; @@ -1184,25 +1494,24 @@ static BOOL TsProxyAuthorizeTunnelReadResponse(rdpTsg* tsg, RPC_PDU* pdu) Stream_Seek_UINT32(pdu->s); /* Reserved (4 bytes) */ Stream_Read_UINT32(pdu->s, Pointer); /* ResponseDataPtr (4 bytes) */ Stream_Read_UINT32(pdu->s, packetResponse->responseDataLen); /* ResponseDataLength (4 bytes) */ - Stream_Read_UINT32(pdu->s, packetResponse->redirectionFlags - .enableAllRedirections); /* EnableAllRedirections (4 bytes) */ - Stream_Read_UINT32(pdu->s, packetResponse->redirectionFlags - .disableAllRedirections); /* DisableAllRedirections (4 bytes) */ - Stream_Read_UINT32(pdu->s, - packetResponse->redirectionFlags - .driveRedirectionDisabled); /* DriveRedirectionDisabled (4 bytes) */ - Stream_Read_UINT32(pdu->s, - packetResponse->redirectionFlags - .printerRedirectionDisabled); /* PrinterRedirectionDisabled (4 bytes) */ - Stream_Read_UINT32(pdu->s, - packetResponse->redirectionFlags - .portRedirectionDisabled); /* PortRedirectionDisabled (4 bytes) */ - Stream_Read_UINT32(pdu->s, packetResponse->redirectionFlags.reserved); /* Reserved (4 bytes) */ - Stream_Read_UINT32( + Stream_Read_INT32(pdu->s, packetResponse->redirectionFlags + .enableAllRedirections); /* EnableAllRedirections (4 bytes) */ + Stream_Read_INT32(pdu->s, packetResponse->redirectionFlags + .disableAllRedirections); /* DisableAllRedirections (4 bytes) */ + Stream_Read_INT32(pdu->s, + packetResponse->redirectionFlags + .driveRedirectionDisabled); /* DriveRedirectionDisabled (4 bytes) */ + Stream_Read_INT32(pdu->s, + packetResponse->redirectionFlags + .printerRedirectionDisabled); /* PrinterRedirectionDisabled (4 bytes) */ + Stream_Read_INT32(pdu->s, packetResponse->redirectionFlags + .portRedirectionDisabled); /* PortRedirectionDisabled (4 bytes) */ + Stream_Read_INT32(pdu->s, packetResponse->redirectionFlags.reserved); /* Reserved (4 bytes) */ + Stream_Read_INT32( pdu->s, packetResponse->redirectionFlags .clipboardRedirectionDisabled); /* ClipboardRedirectionDisabled (4 bytes) */ - Stream_Read_UINT32(pdu->s, packetResponse->redirectionFlags - .pnpRedirectionDisabled); /* PnpRedirectionDisabled (4 bytes) */ + Stream_Read_INT32(pdu->s, packetResponse->redirectionFlags + .pnpRedirectionDisabled); /* PnpRedirectionDisabled (4 bytes) */ Stream_Read_UINT32(pdu->s, SizeValue); /* (4 bytes) */ if (SizeValue != packetResponse->responseDataLen) @@ -1302,11 +1611,18 @@ static BOOL TsProxyMakeTunnelCallReadResponse(rdpTsg* tsg, RPC_PDU* pdu) UINT32 Pointer; UINT32 SwitchValue; TSG_PACKET packet; + rdpContext* context; char* messageText = NULL; TSG_PACKET_MSG_RESPONSE packetMsgResponse = { 0 }; TSG_PACKET_STRING_MESSAGE packetStringMessage = { 0 }; TSG_PACKET_REAUTH_MESSAGE packetReauthMessage = { 0 }; + assert(tsg); + assert(tsg->rpc); + + context = tsg->rpc->context; + assert(context); + /* This is an asynchronous response */ if (!pdu) @@ -1356,10 +1672,10 @@ static BOOL TsProxyMakeTunnelCallReadResponse(rdpTsg* tsg, RPC_PDU* pdu) WLog_INFO(TAG, "Consent Message: %s", messageText); free(messageText); - if (tsg->rpc && tsg->rpc->context && tsg->rpc->context->instance) + if (context->instance) { - rc = IFCALLRESULT(TRUE, tsg->rpc->context->instance->PresentGatewayMessage, - tsg->rpc->context->instance, GATEWAY_MESSAGE_CONSENT, + rc = IFCALLRESULT(TRUE, context->instance->PresentGatewayMessage, context->instance, + GATEWAY_MESSAGE_CONSENT, packetStringMessage.isDisplayMandatory != 0, packetStringMessage.isConsentMandatory != 0, packetStringMessage.msgBytes, packetStringMessage.msgBuffer); @@ -1377,10 +1693,10 @@ static BOOL TsProxyMakeTunnelCallReadResponse(rdpTsg* tsg, RPC_PDU* pdu) WLog_INFO(TAG, "Service Message: %s", messageText); free(messageText); - if (tsg->rpc && tsg->rpc->context && tsg->rpc->context->instance) + if (context->instance) { - rc = IFCALLRESULT(TRUE, tsg->rpc->context->instance->PresentGatewayMessage, - tsg->rpc->context->instance, GATEWAY_MESSAGE_SERVICE, + rc = IFCALLRESULT(TRUE, context->instance->PresentGatewayMessage, context->instance, + GATEWAY_MESSAGE_SERVICE, packetStringMessage.isDisplayMandatory != 0, packetStringMessage.isConsentMandatory != 0, packetStringMessage.msgBytes, packetStringMessage.msgBuffer); @@ -1432,6 +1748,8 @@ static BOOL TsProxyCreateChannelWriteRequest(rdpTsg* tsg, CONTEXT_HANDLE* tunnel rpc = tsg->rpc; count = _wcslen(tsg->Hostname) + 1; + if (count > UINT32_MAX) + return FALSE; s = Stream_New(NULL, 60 + count * 2); if (!s) @@ -1451,15 +1769,15 @@ static BOOL TsProxyCreateChannelWriteRequest(rdpTsg* tsg, CONTEXT_HANDLE* tunnel Stream_Write_UINT16(s, tsg->Port); /* PortNumber (0xD3D = 3389) (2 bytes) */ Stream_Write_UINT32(s, 0x00000001); /* NumResourceNames (4 bytes) */ Stream_Write_UINT32(s, 0x00020004); /* ResourceNamePtr (4 bytes) */ - Stream_Write_UINT32(s, count); /* MaxCount (4 bytes) */ + Stream_Write_UINT32(s, (UINT32)count); /* MaxCount (4 bytes) */ Stream_Write_UINT32(s, 0); /* Offset (4 bytes) */ - Stream_Write_UINT32(s, count); /* ActualCount (4 bytes) */ + Stream_Write_UINT32(s, (UINT32)count); /* ActualCount (4 bytes) */ Stream_Write_UTF16_String(s, tsg->Hostname, count); /* Array */ return rpc_client_write_call(rpc, s, TsProxyCreateChannelOpnum); } -static BOOL TsProxyCreateChannelReadResponse(rdpTsg* tsg, RPC_PDU* pdu, - CONTEXT_HANDLE* channelContext, UINT32* channelId) +static BOOL TsProxyCreateChannelReadResponse(RPC_PDU* pdu, CONTEXT_HANDLE* channelContext, + UINT32* channelId) { BOOL rc = FALSE; WLog_DBG(TAG, "TsProxyCreateChannelReadResponse"); @@ -1507,7 +1825,7 @@ static BOOL TsProxyCloseChannelWriteRequest(rdpTsg* tsg, CONTEXT_HANDLE* context return rpc_client_write_call(rpc, s, TsProxyCloseChannelOpnum); } -static BOOL TsProxyCloseChannelReadResponse(rdpTsg* tsg, RPC_PDU* pdu, CONTEXT_HANDLE* context) +static BOOL TsProxyCloseChannelReadResponse(RPC_PDU* pdu, CONTEXT_HANDLE* context) { BOOL rc = FALSE; WLog_DBG(TAG, "TsProxyCloseChannelReadResponse"); @@ -1554,7 +1872,7 @@ static BOOL TsProxyCloseTunnelWriteRequest(rdpTsg* tsg, CONTEXT_HANDLE* context) return rpc_client_write_call(rpc, s, TsProxyCloseTunnelOpnum); } -static BOOL TsProxyCloseTunnelReadResponse(rdpTsg* tsg, RPC_PDU* pdu, CONTEXT_HANDLE* context) +static BOOL TsProxyCloseTunnelReadResponse(RPC_PDU* pdu, CONTEXT_HANDLE* context) { BOOL rc = FALSE; WLog_DBG(TAG, "TsProxyCloseTunnelReadResponse"); @@ -1705,8 +2023,6 @@ BOOL tsg_recv_pdu(rdpTsg* tsg, RPC_PDU* pdu) return FALSE; rpc = tsg->rpc; - Stream_SealLength(pdu->s); - Stream_SetPosition(pdu->s, 0); if (!(pdu->Flags & RPC_PDU_FLAG_STUB)) { @@ -1745,7 +2061,7 @@ BOOL tsg_recv_pdu(rdpTsg* tsg, RPC_PDU* pdu) CONTEXT_HANDLE* TunnelContext; TunnelContext = (tsg->reauthSequence) ? &tsg->NewTunnelContext : &tsg->TunnelContext; - if (!TsProxyAuthorizeTunnelReadResponse(tsg, pdu)) + if (!TsProxyAuthorizeTunnelReadResponse(pdu)) { WLog_ERR(TAG, "TsProxyAuthorizeTunnelReadResponse failure"); return FALSE; @@ -1794,7 +2110,7 @@ BOOL tsg_recv_pdu(rdpTsg* tsg, RPC_PDU* pdu) { CONTEXT_HANDLE ChannelContext; - if (!TsProxyCreateChannelReadResponse(tsg, pdu, &ChannelContext, &tsg->ChannelId)) + if (!TsProxyCreateChannelReadResponse(pdu, &ChannelContext, &tsg->ChannelId)) { WLog_ERR(TAG, "TsProxyCreateChannelReadResponse failure"); return FALSE; @@ -1867,7 +2183,7 @@ BOOL tsg_recv_pdu(rdpTsg* tsg, RPC_PDU* pdu) { CONTEXT_HANDLE ChannelContext; - if (!TsProxyCloseChannelReadResponse(tsg, pdu, &ChannelContext)) + if (!TsProxyCloseChannelReadResponse(pdu, &ChannelContext)) { WLog_ERR(TAG, "TsProxyCloseChannelReadResponse failure"); return FALSE; @@ -1879,7 +2195,7 @@ BOOL tsg_recv_pdu(rdpTsg* tsg, RPC_PDU* pdu) { CONTEXT_HANDLE TunnelContext; - if (!TsProxyCloseTunnelReadResponse(tsg, pdu, &TunnelContext)) + if (!TsProxyCloseTunnelReadResponse(pdu, &TunnelContext)) { WLog_ERR(TAG, "TsProxyCloseTunnelReadResponse failure"); return FALSE; @@ -1894,7 +2210,7 @@ BOOL tsg_recv_pdu(rdpTsg* tsg, RPC_PDU* pdu) { CONTEXT_HANDLE ChannelContext; - if (!TsProxyCloseChannelReadResponse(tsg, pdu, &ChannelContext)) + if (!TsProxyCloseChannelReadResponse(pdu, &ChannelContext)) { WLog_ERR(TAG, "TsProxyCloseChannelReadResponse failure"); return FALSE; @@ -1924,7 +2240,7 @@ BOOL tsg_recv_pdu(rdpTsg* tsg, RPC_PDU* pdu) { CONTEXT_HANDLE TunnelContext; - if (!TsProxyCloseTunnelReadResponse(tsg, pdu, &TunnelContext)) + if (!TsProxyCloseTunnelReadResponse(pdu, &TunnelContext)) { WLog_ERR(TAG, "TsProxyCloseTunnelReadResponse failure"); return FALSE; @@ -2033,10 +2349,25 @@ BOOL tsg_connect(rdpTsg* tsg, const char* hostname, UINT16 port, DWORD timeout) { UINT64 looptimeout = timeout * 1000ULL; DWORD nCount; - HANDLE events[64]; - rdpRpc* rpc = tsg->rpc; - rdpSettings* settings = rpc->settings; - rdpTransport* transport = rpc->transport; + HANDLE events[MAXIMUM_WAIT_OBJECTS] = { 0 }; + rdpRpc* rpc; + rdpContext* context; + rdpSettings* settings; + rdpTransport* transport; + + assert(tsg); + + rpc = tsg->rpc; + assert(rpc); + + transport = rpc->transport; + assert(transport); + + context = tsg->rpc->context; + assert(context); + + settings = context->settings; + tsg->Port = port; tsg->transport = transport; @@ -2055,7 +2386,7 @@ BOOL tsg_connect(rdpTsg* tsg, const char* hostname, UINT16 port, DWORD timeout) return FALSE; } - nCount = tsg_get_event_handles(tsg, events, 64); + nCount = tsg_get_event_handles(tsg, events, ARRAYSIZE(events)); if (nCount == 0) return FALSE; @@ -2138,7 +2469,7 @@ BOOL tsg_disconnect(rdpTsg* tsg) * @return < 0 on error; 0 if not enough data is available (non blocking mode); > 0 bytes to read */ -static int tsg_read(rdpTsg* tsg, BYTE* data, UINT32 length) +static int tsg_read(rdpTsg* tsg, BYTE* data, size_t length) { rdpRpc* rpc; int status = 0; @@ -2156,7 +2487,7 @@ static int tsg_read(rdpTsg* tsg, BYTE* data, UINT32 length) do { - status = rpc_client_receive_pipe_read(rpc->client, data, (size_t)length); + status = rpc_client_receive_pipe_read(rpc->client, data, length); if (status < 0) return -1; @@ -2206,7 +2537,7 @@ static int tsg_write(rdpTsg* tsg, const BYTE* data, UINT32 length) if (status < 0) return -1; - return length; + return (int)length; } rdpTsg* tsg_new(rdpTransport* transport) @@ -2218,7 +2549,6 @@ rdpTsg* tsg_new(rdpTransport* transport) return NULL; tsg->transport = transport; - tsg->settings = transport->settings; tsg->rpc = rpc_new(tsg->transport); if (!tsg->rpc) @@ -2246,7 +2576,10 @@ static int transport_bio_tsg_write(BIO* bio, const char* buf, int num) int status; rdpTsg* tsg = (rdpTsg*)BIO_get_data(bio); BIO_clear_flags(bio, BIO_FLAGS_WRITE); - status = tsg_write(tsg, (BYTE*)buf, num); + + if (num < 0) + return -1; + status = tsg_write(tsg, (const BYTE*)buf, (UINT32)num); if (status < 0) { @@ -2278,7 +2611,7 @@ static int transport_bio_tsg_read(BIO* bio, char* buf, int size) } BIO_clear_flags(bio, BIO_FLAGS_READ); - status = tsg_read(tsg, (BYTE*)buf, size); + status = tsg_read(tsg, (BYTE*)buf, (size_t)size); if (status < 0) { @@ -2300,17 +2633,22 @@ static int transport_bio_tsg_read(BIO* bio, char* buf, int size) static int transport_bio_tsg_puts(BIO* bio, const char* str) { + WINPR_UNUSED(bio); + WINPR_UNUSED(str); return 1; } static int transport_bio_tsg_gets(BIO* bio, char* str, int size) { + WINPR_UNUSED(bio); + WINPR_UNUSED(str); + WINPR_UNUSED(size); return 1; } static long transport_bio_tsg_ctrl(BIO* bio, int cmd, long arg1, void* arg2) { - int status = -1; + long status = -1; rdpTsg* tsg = (rdpTsg*)BIO_get_data(bio); RpcVirtualConnection* connection = tsg->rpc->VirtualConnection; RpcInChannel* inChannel = connection->DefaultInChannel; @@ -2339,27 +2677,27 @@ static long transport_bio_tsg_ctrl(BIO* bio, int cmd, long arg1, void* arg2) case BIO_C_READ_BLOCKED: { - BIO* bio = outChannel->common.bio; - status = BIO_read_blocked(bio); + BIO* cbio = outChannel->common.bio; + status = BIO_read_blocked(cbio); } break; case BIO_C_WRITE_BLOCKED: { - BIO* bio = inChannel->common.bio; - status = BIO_write_blocked(bio); + BIO* cbio = inChannel->common.bio; + status = BIO_write_blocked(cbio); } break; case BIO_C_WAIT_READ: { int timeout = (int)arg1; - BIO* bio = outChannel->common.bio; + BIO* cbio = outChannel->common.bio; - if (BIO_read_blocked(bio)) - return BIO_wait_read(bio, timeout); - else if (BIO_write_blocked(bio)) - return BIO_wait_write(bio, timeout); + if (BIO_read_blocked(cbio)) + return BIO_wait_read(cbio, timeout); + else if (BIO_write_blocked(cbio)) + return BIO_wait_write(cbio, timeout); else status = 1; } @@ -2368,12 +2706,12 @@ static long transport_bio_tsg_ctrl(BIO* bio, int cmd, long arg1, void* arg2) case BIO_C_WAIT_WRITE: { int timeout = (int)arg1; - BIO* bio = inChannel->common.bio; + BIO* cbio = inChannel->common.bio; - if (BIO_write_blocked(bio)) - status = BIO_wait_write(bio, timeout); - else if (BIO_read_blocked(bio)) - status = BIO_wait_read(bio, timeout); + if (BIO_write_blocked(cbio)) + status = BIO_wait_write(cbio, timeout); + else if (BIO_read_blocked(cbio)) + status = BIO_wait_read(cbio, timeout); else status = 1; } @@ -2388,6 +2726,7 @@ static long transport_bio_tsg_ctrl(BIO* bio, int cmd, long arg1, void* arg2) static int transport_bio_tsg_new(BIO* bio) { + assert(bio); BIO_set_init(bio, 1); BIO_set_flags(bio, BIO_FLAGS_SHOULD_RETRY); return 1; @@ -2395,6 +2734,8 @@ static int transport_bio_tsg_new(BIO* bio) static int transport_bio_tsg_free(BIO* bio) { + assert(bio); + WINPR_UNUSED(bio); return 1; } diff --git a/libfreerdp/core/orders.c b/libfreerdp/core/orders.c index 0e14bbe6aef4..34ccbb7b01ce 100644 --- a/libfreerdp/core/orders.c +++ b/libfreerdp/core/orders.c @@ -1881,6 +1881,13 @@ static BOOL update_read_fast_glyph_order(wStream* s, const ORDER_INFO* orderInfo !update_read_2byte_unsigned(&sub, &glyph->cy)) return FALSE; + if ((glyph->cx == 0) || (glyph->cy == 0)) + { + WLog_ERR(TAG, "GLYPH_DATA_V2::cx=%" PRIu32 ", GLYPH_DATA_V2::cy=%" PRIu32, + glyph->cx, glyph->cy); + return FALSE; + } + glyph->cb = Stream_GetRemainingLength(&sub); if (glyph->cb > 0) { @@ -2867,6 +2874,13 @@ update_read_create_offscreen_bitmap_order(wStream* s, Stream_Read_UINT16(s, create_offscreen_bitmap->cy); /* cy (2 bytes) */ deleteList = &(create_offscreen_bitmap->deleteList); + if ((create_offscreen_bitmap->cx == 0) || (create_offscreen_bitmap->cy == 0)) + { + WLog_ERR(TAG, "Invalid OFFSCREEN_DELETE_LIST: cx=%" PRIu16 ", cy=%" PRIu16, + create_offscreen_bitmap->cx, create_offscreen_bitmap->cy); + return FALSE; + } + if (deleteListPresent) { UINT32 i; diff --git a/libfreerdp/core/surface.c b/libfreerdp/core/surface.c index d5c709885509..ca89d230cf44 100644 --- a/libfreerdp/core/surface.c +++ b/libfreerdp/core/surface.c @@ -21,6 +21,8 @@ #include "config.h" #endif +#include + #include #include @@ -62,6 +64,13 @@ static BOOL update_recv_surfcmd_bitmap_ex(wStream* s, TS_BITMAP_DATA_EX* bmp) Stream_Read_UINT16(s, bmp->height); Stream_Read_UINT32(s, bmp->bitmapDataLength); + if ((bmp->width == 0) || (bmp->height == 0)) + { + WLog_ERR(TAG, "invalid size value width=%" PRIu16 ", height=%" PRIu16, bmp->width, + bmp->height); + return FALSE; + } + if ((bmp->bpp < 1) || (bmp->bpp > 32)) { WLog_ERR(TAG, "invalid bpp value %" PRIu32 "", bmp->bpp); @@ -85,6 +94,39 @@ static BOOL update_recv_surfcmd_bitmap_ex(wStream* s, TS_BITMAP_DATA_EX* bmp) return TRUE; } +static BOOL update_recv_surfcmd_is_rect_valid(const rdpContext* context, + const SURFACE_BITS_COMMAND* cmd) +{ + assert(context); + assert(context->settings); + assert(cmd); + + /* We need a rectangle with left/top being smaller than right/bottom. + * Also do not allow empty rectangles. */ + if ((cmd->destTop >= cmd->destBottom) || (cmd->destLeft >= cmd->destRight)) + { + WLog_WARN(TAG, + "Empty surface bits command rectangle: %" PRIu16 "x%" PRIu16 "-%" PRIu16 + "x%" PRIu16, + cmd->destLeft, cmd->destTop, cmd->destRight, cmd->destBottom); + return FALSE; + } + + /* The rectangle needs to fit into our session size */ + if ((cmd->destRight > context->settings->DesktopWidth) || + (cmd->destBottom > context->settings->DesktopHeight)) + { + WLog_WARN(TAG, + "Invalid surface bits command rectangle: %" PRIu16 "x%" PRIu16 "-%" PRIu16 + "x%" PRIu16 " does not fit %" PRIu32 "x%" PRIu32, + cmd->destLeft, cmd->destTop, cmd->destRight, cmd->destBottom, + context->settings->DesktopWidth, context->settings->DesktopHeight); + return FALSE; + } + + return TRUE; +} + static BOOL update_recv_surfcmd_surface_bits(rdpUpdate* update, wStream* s, UINT16 cmdType) { SURFACE_BITS_COMMAND cmd = { 0 }; @@ -98,6 +140,9 @@ static BOOL update_recv_surfcmd_surface_bits(rdpUpdate* update, wStream* s, UINT Stream_Read_UINT16(s, cmd.destRight); Stream_Read_UINT16(s, cmd.destBottom); + if (!update_recv_surfcmd_is_rect_valid(update->context, &cmd)) + goto fail; + if (!update_recv_surfcmd_bitmap_ex(s, &cmd.bmp)) goto fail; diff --git a/libfreerdp/core/update.c b/libfreerdp/core/update.c index ebb82fc2df7e..e137c3de8a29 100644 --- a/libfreerdp/core/update.c +++ b/libfreerdp/core/update.c @@ -99,6 +99,13 @@ static BOOL update_read_bitmap_data(rdpUpdate* update, wStream* s, BITMAP_DATA* Stream_Read_UINT16(s, bitmapData->flags); Stream_Read_UINT16(s, bitmapData->bitmapLength); + if ((bitmapData->width == 0) || (bitmapData->height == 0)) + { + WLog_ERR(TAG, "Invalid BITMAP_DATA: width=%" PRIu16 ", height=%" PRIu16, bitmapData->width, + bitmapData->height); + return FALSE; + } + if (bitmapData->flags & BITMAP_COMPRESSION) { if (!(bitmapData->flags & NO_BITMAP_COMPRESSION_HDR)) diff --git a/winpr/CMakeLists.txt b/winpr/CMakeLists.txt index 0cb8845b0d60..036b50f83325 100644 --- a/winpr/CMakeLists.txt +++ b/winpr/CMakeLists.txt @@ -51,7 +51,7 @@ if (NOT WIN32) endif() # Soname versioning -set(RAW_VERSION_STRING "2.4.0") +set(RAW_VERSION_STRING "2.4.1") if(EXISTS "${CMAKE_SOURCE_DIR}/.source_tag") file(READ ${CMAKE_SOURCE_DIR}/.source_tag RAW_VERSION_STRING) elseif(USE_VERSION_FROM_GIT_TAG) diff --git a/winpr/libwinpr/crt/utf.c b/winpr/libwinpr/crt/utf.c index 8c8d2a841487..2cbc5987b6b4 100644 --- a/winpr/libwinpr/crt/utf.c +++ b/winpr/libwinpr/crt/utf.c @@ -582,7 +582,7 @@ ConversionResult ConvertUTF8toUTF16(const BYTE** sourceStart, const BYTE* source ch -= offsetsFromUTF8[extraBytesToRead]; - if ((target >= end) && (!computeLength)) + if ((target * sizeof(WCHAR) >= end) && (!computeLength)) { source -= (extraBytesToRead + 1); /* Back up source pointer! */ result = targetExhausted; @@ -633,7 +633,7 @@ ConversionResult ConvertUTF8toUTF16(const BYTE** sourceStart, const BYTE* source else { /* target is a character in range 0xFFFF - 0x10FFFF. */ - if ((target + 1 >= end) && (!computeLength)) + if (((target + 1) * sizeof(WCHAR) >= end) && (!computeLength)) { source -= (extraBytesToRead + 1); /* Back up source pointer! */ result = targetExhausted; diff --git a/winpr/libwinpr/file/generic.c b/winpr/libwinpr/file/generic.c index 1f8bf9935f50..aa53f68fc755 100644 --- a/winpr/libwinpr/file/generic.c +++ b/winpr/libwinpr/file/generic.c @@ -539,15 +539,80 @@ DWORD WINAPI GetFileAttributesW(LPCWSTR lpFileName) return ret; } +static char* append(char* buffer, size_t size, const char* append) +{ + const size_t len = strnlen(buffer, size); + if (len == 0) + _snprintf(buffer, size, "%s", append); + else + { + strcat(buffer, "|"); + strcat(buffer, append); + } + + return buffer; +} + +static const char* flagsToStr(char* buffer, size_t size, DWORD flags) +{ + char strflags[32] = { 0 }; + if (flags & FILE_ATTRIBUTE_READONLY) + append(buffer, size, "FILE_ATTRIBUTE_READONLY"); + if (flags & FILE_ATTRIBUTE_HIDDEN) + append(buffer, size, "FILE_ATTRIBUTE_HIDDEN"); + if (flags & FILE_ATTRIBUTE_SYSTEM) + append(buffer, size, "FILE_ATTRIBUTE_SYSTEM"); + if (flags & FILE_ATTRIBUTE_DIRECTORY) + append(buffer, size, "FILE_ATTRIBUTE_DIRECTORY"); + if (flags & FILE_ATTRIBUTE_ARCHIVE) + append(buffer, size, "FILE_ATTRIBUTE_ARCHIVE"); + if (flags & FILE_ATTRIBUTE_DEVICE) + append(buffer, size, "FILE_ATTRIBUTE_DEVICE"); + if (flags & FILE_ATTRIBUTE_NORMAL) + append(buffer, size, "FILE_ATTRIBUTE_NORMAL"); + if (flags & FILE_ATTRIBUTE_TEMPORARY) + append(buffer, size, "FILE_ATTRIBUTE_TEMPORARY"); + if (flags & FILE_ATTRIBUTE_SPARSE_FILE) + append(buffer, size, "FILE_ATTRIBUTE_SPARSE_FILE"); + if (flags & FILE_ATTRIBUTE_REPARSE_POINT) + append(buffer, size, "FILE_ATTRIBUTE_REPARSE_POINT"); + if (flags & FILE_ATTRIBUTE_COMPRESSED) + append(buffer, size, "FILE_ATTRIBUTE_COMPRESSED"); + if (flags & FILE_ATTRIBUTE_OFFLINE) + append(buffer, size, "FILE_ATTRIBUTE_OFFLINE"); + if (flags & FILE_ATTRIBUTE_NOT_CONTENT_INDEXED) + append(buffer, size, "FILE_ATTRIBUTE_NOT_CONTENT_INDEXED"); + if (flags & FILE_ATTRIBUTE_ENCRYPTED) + append(buffer, size, "FILE_ATTRIBUTE_ENCRYPTED"); + if (flags & FILE_ATTRIBUTE_VIRTUAL) + append(buffer, size, "FILE_ATTRIBUTE_VIRTUAL"); + + _snprintf(strflags, sizeof(strflags), " [0x%08" PRIx32 "]", flags); + strcat(buffer, strflags); + return buffer; +} + BOOL SetFileAttributesA(LPCSTR lpFileName, DWORD dwFileAttributes) { struct stat st; + int fd; + BOOL rc = FALSE; - if (stat(lpFileName, &st) != 0) + if (dwFileAttributes & ~FILE_ATTRIBUTE_READONLY) { - return FALSE; + char buffer[8192] = { 0 }; + const char* flags = + flagsToStr(buffer, sizeof(buffer), dwFileAttributes & ~FILE_ATTRIBUTE_READONLY); + WLog_WARN(TAG, "[%s] Unsupported flags %s, ignoring!", __FUNCTION__, flags); } + fd = open(lpFileName, O_RDONLY); + if (fd < 0) + return FALSE; + + if (fstat(fd, &st) != 0) + goto fail; + if (dwFileAttributes & FILE_ATTRIBUTE_READONLY) { st.st_mode &= ~(S_IWUSR | S_IWGRP | S_IWOTH); @@ -557,12 +622,13 @@ BOOL SetFileAttributesA(LPCSTR lpFileName, DWORD dwFileAttributes) st.st_mode |= S_IWUSR; } - if (chmod(lpFileName, st.st_mode) != 0) - { - return FALSE; - } + if (fchmod(fd, st.st_mode) != 0) + goto fail; - return TRUE; + rc = TRUE; +fail: + close(fd); + return rc; } BOOL SetFileAttributesW(LPCWSTR lpFileName, DWORD dwFileAttributes) @@ -570,6 +636,14 @@ BOOL SetFileAttributesW(LPCWSTR lpFileName, DWORD dwFileAttributes) BOOL ret; LPSTR lpCFileName; + if (dwFileAttributes & ~FILE_ATTRIBUTE_READONLY) + { + char buffer[8192] = { 0 }; + const char* flags = + flagsToStr(buffer, sizeof(buffer), dwFileAttributes & ~FILE_ATTRIBUTE_READONLY); + WLog_WARN(TAG, "[%s] Unsupported flags %s, ignoring!", __FUNCTION__, flags); + } + if (ConvertFromUnicode(CP_UTF8, 0, lpFileName, -1, &lpCFileName, 0, NULL, NULL) <= 0) { SetLastError(ERROR_NOT_ENOUGH_MEMORY); diff --git a/winpr/libwinpr/file/test/CMakeLists.txt b/winpr/libwinpr/file/test/CMakeLists.txt index c7015c67087d..3999271105c8 100644 --- a/winpr/libwinpr/file/test/CMakeLists.txt +++ b/winpr/libwinpr/file/test/CMakeLists.txt @@ -1,54 +1,58 @@ -set(MODULE_NAME "TestFile") -set(MODULE_PREFIX "TEST_FILE") +if (NOT WIN32) + set(MODULE_NAME "TestFile") + set(MODULE_PREFIX "TEST_FILE") + + set(${MODULE_PREFIX}_DRIVER ${MODULE_NAME}.c) + + set(${MODULE_PREFIX}_TESTS + TestFileCreateFile.c + TestFileDeleteFile.c + TestFileReadFile.c + TestSetFileAttributes.c + TestFileWriteFile.c + TestFilePatternMatch.c + TestFileFindFirstFile.c + TestFileFindFirstFileEx.c + TestFileFindNextFile.c + TestFileGetStdHandle.c + ) + + create_test_sourcelist(${MODULE_PREFIX}_SRCS + ${${MODULE_PREFIX}_DRIVER} + ${${MODULE_PREFIX}_TESTS}) + + add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS}) + + target_link_libraries(${MODULE_NAME} winpr) + + set_target_properties(${MODULE_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${TESTING_OUTPUT_DIRECTORY}") + + if(NOT MSVC) + set(TEST_AREA "${TESTING_OUTPUT_DIRECTORY}/${MODULE_NAME}Area") + else() + set(TEST_AREA "${TESTING_OUTPUT_DIRECTORY}/${CMAKE_BUILD_TYPE}/${MODULE_NAME}Area") + endif() + + file(MAKE_DIRECTORY "${TEST_AREA}") + file(WRITE "${TEST_AREA}/TestFile1" "TestFile1") + file(WRITE "${TEST_AREA}/TestFile2" "TestFile2") + file(WRITE "${TEST_AREA}/TestFile3" "TestFile3") + file(MAKE_DIRECTORY "${TEST_AREA}/TestDirectory1") + file(WRITE "${TEST_AREA}/TestDirectory1/TestDirectory1File1" "TestDirectory1File1") + file(MAKE_DIRECTORY "${TEST_AREA}/TestDirectory2") + file(WRITE "${TEST_AREA}/TestDirectory2/TestDirectory2File1" "TestDirectory2File1") + file(WRITE "${TEST_AREA}/TestDirectory2/TestDirectory2File2" "TestDirectory2File2") + file(MAKE_DIRECTORY "${TEST_AREA}/TestDirectory3") + file(WRITE "${TEST_AREA}/TestDirectory3/TestDirectory3File1" "TestDirectory3File1") + file(WRITE "${TEST_AREA}/TestDirectory3/TestDirectory3File2" "TestDirectory3File2") + file(WRITE "${TEST_AREA}/TestDirectory3/TestDirectory3File3" "TestDirectory3File3") + + foreach(test ${${MODULE_PREFIX}_TESTS}) + get_filename_component(TestName ${test} NAME_WE) + add_test(${TestName} ${TESTING_OUTPUT_DIRECTORY}/${MODULE_NAME} ${TestName} ${TEST_AREA}) + endforeach() + + set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "WinPR/Test") -set(${MODULE_PREFIX}_DRIVER ${MODULE_NAME}.c) - -set(${MODULE_PREFIX}_TESTS - TestFileCreateFile.c - TestFileDeleteFile.c - TestFileReadFile.c - TestFileWriteFile.c - TestFilePatternMatch.c - TestFileFindFirstFile.c - TestFileFindFirstFileEx.c - TestFileFindNextFile.c - TestFileGetStdHandle.c -) - -create_test_sourcelist(${MODULE_PREFIX}_SRCS - ${${MODULE_PREFIX}_DRIVER} - ${${MODULE_PREFIX}_TESTS}) - -add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS}) - -target_link_libraries(${MODULE_NAME} winpr) - -set_target_properties(${MODULE_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${TESTING_OUTPUT_DIRECTORY}") - -if(NOT MSVC) - set(TEST_AREA "${TESTING_OUTPUT_DIRECTORY}/${MODULE_NAME}Area") -else() - set(TEST_AREA "${TESTING_OUTPUT_DIRECTORY}/${CMAKE_BUILD_TYPE}/${MODULE_NAME}Area") endif() - -file(MAKE_DIRECTORY "${TEST_AREA}") -file(WRITE "${TEST_AREA}/TestFile1" "TestFile1") -file(WRITE "${TEST_AREA}/TestFile2" "TestFile2") -file(WRITE "${TEST_AREA}/TestFile3" "TestFile3") -file(MAKE_DIRECTORY "${TEST_AREA}/TestDirectory1") -file(WRITE "${TEST_AREA}/TestDirectory1/TestDirectory1File1" "TestDirectory1File1") -file(MAKE_DIRECTORY "${TEST_AREA}/TestDirectory2") -file(WRITE "${TEST_AREA}/TestDirectory2/TestDirectory2File1" "TestDirectory2File1") -file(WRITE "${TEST_AREA}/TestDirectory2/TestDirectory2File2" "TestDirectory2File2") -file(MAKE_DIRECTORY "${TEST_AREA}/TestDirectory3") -file(WRITE "${TEST_AREA}/TestDirectory3/TestDirectory3File1" "TestDirectory3File1") -file(WRITE "${TEST_AREA}/TestDirectory3/TestDirectory3File2" "TestDirectory3File2") -file(WRITE "${TEST_AREA}/TestDirectory3/TestDirectory3File3" "TestDirectory3File3") - -foreach(test ${${MODULE_PREFIX}_TESTS}) - get_filename_component(TestName ${test} NAME_WE) - add_test(${TestName} ${TESTING_OUTPUT_DIRECTORY}/${MODULE_NAME} ${TestName} ${TEST_AREA}) -endforeach() - -set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "WinPR/Test") diff --git a/winpr/libwinpr/file/test/TestSetFileAttributes.c b/winpr/libwinpr/file/test/TestSetFileAttributes.c new file mode 100644 index 000000000000..e81c89c82e15 --- /dev/null +++ b/winpr/libwinpr/file/test/TestSetFileAttributes.c @@ -0,0 +1,149 @@ + +#include +#include +#include +#include +#include +#include +#include + +static const DWORD allflags[] = { + 0, + FILE_ATTRIBUTE_READONLY, + FILE_ATTRIBUTE_HIDDEN, + FILE_ATTRIBUTE_SYSTEM, + FILE_ATTRIBUTE_DIRECTORY, + FILE_ATTRIBUTE_ARCHIVE, + FILE_ATTRIBUTE_DEVICE, + FILE_ATTRIBUTE_NORMAL, + FILE_ATTRIBUTE_TEMPORARY, + FILE_ATTRIBUTE_SPARSE_FILE, + FILE_ATTRIBUTE_REPARSE_POINT, + FILE_ATTRIBUTE_COMPRESSED, + FILE_ATTRIBUTE_OFFLINE, + FILE_ATTRIBUTE_NOT_CONTENT_INDEXED, + FILE_ATTRIBUTE_ENCRYPTED, + FILE_ATTRIBUTE_VIRTUAL, + FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM, + FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_DEVICE | + FILE_ATTRIBUTE_NORMAL, + FILE_ATTRIBUTE_TEMPORARY | FILE_ATTRIBUTE_SPARSE_FILE | FILE_ATTRIBUTE_REPARSE_POINT | + FILE_ATTRIBUTE_COMPRESSED | FILE_ATTRIBUTE_OFFLINE, + FILE_ATTRIBUTE_NOT_CONTENT_INDEXED | FILE_ATTRIBUTE_ENCRYPTED | FILE_ATTRIBUTE_VIRTUAL +}; + +static BOOL test_SetFileAttributesA(void) +{ + BOOL rc = FALSE; + HANDLE handle; + DWORD x; + const DWORD flags[] = { 0, FILE_ATTRIBUTE_READONLY }; + char* name = GetKnownSubPath(KNOWN_PATH_TEMP, "afsklhjwe4oq5iu432oijrlkejadlkhjaklhfdkahfd"); + if (!name) + goto fail; + + for (x = 0; x < ARRAYSIZE(allflags); x++) + { + const DWORD flag = allflags[x]; + rc = SetFileAttributesA(NULL, flag); + if (rc) + goto fail; + + rc = SetFileAttributesA(name, flag); + if (rc) + goto fail; + } + + handle = CreateFileA(name, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_NEW, + FILE_ATTRIBUTE_NORMAL, NULL); + if (handle == INVALID_HANDLE_VALUE) + goto fail; + CloseHandle(handle); + + for (x = 0; x < ARRAYSIZE(flags); x++) + { + DWORD attr; + const DWORD flag = flags[x]; + rc = SetFileAttributesA(name, flag); + if (!rc) + goto fail; + + attr = GetFileAttributesA(name); + if (flag != 0) + { + if ((attr & flag) == 0) + goto fail; + } + } + +fail: + DeleteFileA(name); + free(name); + return rc; +} + +static BOOL test_SetFileAttributesW(void) +{ + BOOL rc = FALSE; + WCHAR* name = NULL; + HANDLE handle; + DWORD x; + const DWORD flags[] = { 0, FILE_ATTRIBUTE_READONLY }; + char* base = GetKnownSubPath(KNOWN_PATH_TEMP, "afsklhjwe4oq5iu432oijrlkejadlkhjaklhfdkahfd"); + if (!base) + goto fail; + + ConvertToUnicode(CP_UTF8, 0, base, -1, &name, 0); + + for (x = 0; x < ARRAYSIZE(allflags); x++) + { + const DWORD flag = allflags[x]; + rc = SetFileAttributesW(NULL, flag); + if (rc) + goto fail; + + rc = SetFileAttributesW(name, flag); + if (rc) + goto fail; + } + + handle = CreateFileW(name, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_NEW, + FILE_ATTRIBUTE_NORMAL, NULL); + if (handle == INVALID_HANDLE_VALUE) + goto fail; + CloseHandle(handle); + + for (x = 0; x < ARRAYSIZE(flags); x++) + { + DWORD attr; + const DWORD flag = flags[x]; + rc = SetFileAttributesW(name, flag); + if (!rc) + goto fail; + + attr = GetFileAttributesW(name); + if (flag != 0) + { + if ((attr & flag) == 0) + goto fail; + } + } + +fail: + DeleteFileW(name); + free(name); + free(base); + return rc; +} + +int TestSetFileAttributes(int argc, char* argv[]) +{ + WINPR_UNUSED(argc); + WINPR_UNUSED(argv); + + if (!test_SetFileAttributesA()) + return -1; + if (!test_SetFileAttributesW()) + return -1; + return 0; +} From 2d48b7f5b3cca49224badc7672c70fd7e52a594a Mon Sep 17 00:00:00 2001 From: Mike Gilbert Date: Sun, 24 Oct 2021 10:04:38 -0400 Subject: [PATCH 002/496] channels/rdpei: avoid calling free() on contactPoints array This was fixed on master as part of 268bc2e8ef7b76887d14d50702bb8446ce15a4c1. Backporting that change seems like too much for the stable branch. See https://github.com/FreeRDP/FreeRDP/issues/7396. --- channels/rdpei/client/rdpei_main.c | 1 - 1 file changed, 1 deletion(-) diff --git a/channels/rdpei/client/rdpei_main.c b/channels/rdpei/client/rdpei_main.c index f20d58a1368b..1d95054a02de 100644 --- a/channels/rdpei/client/rdpei_main.c +++ b/channels/rdpei/client/rdpei_main.c @@ -1386,7 +1386,6 @@ UINT DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints) return CHANNEL_RC_OK; error_out: free(context); - free(rdpei->contactPoints); free(rdpei); return error; } From 101fe1d8778ada83e44033a747ec98377da570a7 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Fri, 5 Nov 2021 12:25:45 +0100 Subject: [PATCH 003/496] Ignore redirection password in case of smartcard auth (cherry picked from commit 11d1c0308b42ad68472810d1d243398b4807ef50) --- libfreerdp/core/info.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libfreerdp/core/info.c b/libfreerdp/core/info.c index 3f8afaef26db..f31b736d7bbb 100644 --- a/libfreerdp/core/info.c +++ b/libfreerdp/core/info.c @@ -711,7 +711,9 @@ static BOOL rdp_write_info_packet(rdpRdp* rdp, wStream* s) if (!settings->RemoteAssistanceMode) { - if (settings->RedirectionPassword && settings->RedirectionPasswordLength > 0) + /* Ignore redirection password if we´re using smartcard and have the pin as password */ + if (((flags & INFO_PASSWORD_IS_SC_PIN) == 0) && settings->RedirectionPassword && + (settings->RedirectionPasswordLength > 0)) { union { BYTE* bp; From ada22bc925361a182842db3de34cb856c45490fe Mon Sep 17 00:00:00 2001 From: akallabeth Date: Fri, 5 Nov 2021 12:52:02 +0100 Subject: [PATCH 004/496] Incremented android build version. --- client/Android/Studio/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/Android/Studio/build.gradle b/client/Android/Studio/build.gradle index 745c99f55c70..2d0abd32d725 100644 --- a/client/Android/Studio/build.gradle +++ b/client/Android/Studio/build.gradle @@ -29,7 +29,7 @@ def getVersionName = { -> ext { versionName = properties.get('VERSION_NAME', getVersionName()) - versionCode = properties.get('VERSION_CODE', 22) + versionCode = properties.get('VERSION_CODE', 25) compileApi = properties.get('COMPILE_API', 30) targetApi = properties.get('TARGET_API', 30) minApi = properties.get('MIN_API', 21) From ce5ebec8324a1ff606443189cc8099b13335adf9 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Fri, 5 Nov 2021 12:53:26 +0100 Subject: [PATCH 005/496] Updated changelog. --- ChangeLog | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/ChangeLog b/ChangeLog index 266238305bc2..d1cb9cf44dc3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,15 @@ +# 20xx-xx-xx Version 2.x.x + +Noteworthy changes: +* Fixed smartcard login in case a redirection occurs the pin was lost + +Fixed issues: + +Important notes: + +For a complete and detailed change log since the last release run: +git log 2.4.1..2.x.x + # 2021-10-20 Version 2.4.1 Noteworthy changes: From 2ddb22f7a453f3429b3246ca8ffa1ff2c31fe71d Mon Sep 17 00:00:00 2001 From: akallabeth Date: Fri, 12 Nov 2021 11:24:38 +0100 Subject: [PATCH 006/496] Fixed #7436: Datatype mismatch to crypto_base64_decode --- libfreerdp/core/gateway/rdg.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libfreerdp/core/gateway/rdg.c b/libfreerdp/core/gateway/rdg.c index 72019ede8e2e..44de2c137c9d 100644 --- a/libfreerdp/core/gateway/rdg.c +++ b/libfreerdp/core/gateway/rdg.c @@ -1190,7 +1190,7 @@ static BOOL rdg_handle_ntlm_challenge(rdpNtlm* ntlm, HttpResponse* response) BOOL continueNeeded = FALSE; size_t len; const char* token64 = NULL; - size_t ntlmTokenLength = 0; + int ntlmTokenLength = 0; BYTE* ntlmTokenData = NULL; long StatusCode; From 403402607214092d20277af3aa959ce87768580a Mon Sep 17 00:00:00 2001 From: akallabeth Date: Fri, 12 Nov 2021 16:01:39 +0100 Subject: [PATCH 007/496] Fixed #7436: Datatype mismatch --- libfreerdp/core/gateway/ncacn_http.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libfreerdp/core/gateway/ncacn_http.c b/libfreerdp/core/gateway/ncacn_http.c index f288a0f3cb76..75da83d62d4e 100644 --- a/libfreerdp/core/gateway/ncacn_http.c +++ b/libfreerdp/core/gateway/ncacn_http.c @@ -105,7 +105,7 @@ BOOL rpc_ncacn_http_send_in_channel_request(RpcChannel* inChannel) BOOL rpc_ncacn_http_recv_in_channel_response(RpcChannel* inChannel, HttpResponse* response) { const char* token64 = NULL; - size_t ntlmTokenLength = 0; + int ntlmTokenLength = 0; BYTE* ntlmTokenData = NULL; rdpNtlm* ntlm; @@ -259,7 +259,7 @@ BOOL rpc_ncacn_http_send_out_channel_request(RpcChannel* outChannel, BOOL replac BOOL rpc_ncacn_http_recv_out_channel_response(RpcChannel* outChannel, HttpResponse* response) { const char* token64 = NULL; - size_t ntlmTokenLength = 0; + int ntlmTokenLength = 0; BYTE* ntlmTokenData = NULL; rdpNtlm* ntlm; From bfbef39759b9641a4fab8b75b9243c48cb0789ac Mon Sep 17 00:00:00 2001 From: Theo Buehler Date: Sun, 23 May 2021 15:03:45 +0200 Subject: [PATCH 008/496] Fix build for upcoming LibreSSL version SSL will become opaque in LibreSSL 3.4.x, hence the code reaching inside it will result in build breakage. This was done at the time for lack of BIO_up_ref() support, which has been available since LibreSSL 2.7.0, so adjust the relevant #ifdefs accordingly. (cherry picked from commit ad0b6c377d02f95a0d3ffc640eb74bc8e738e3d9) --- libfreerdp/crypto/tls.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/libfreerdp/crypto/tls.c b/libfreerdp/crypto/tls.c index d72998ab216a..fee8db5bd406 100644 --- a/libfreerdp/crypto/tls.c +++ b/libfreerdp/crypto/tls.c @@ -323,7 +323,8 @@ static long bio_rdp_tls_ctrl(BIO* bio, int cmd, long num, void* ptr) case BIO_CTRL_PUSH: if (next_bio && (next_bio != ssl_rbio)) { -#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) +#if OPENSSL_VERSION_NUMBER < 0x10100000L || \ + (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x2070000fL) SSL_set_bio(tls->ssl, next_bio, next_bio); CRYPTO_add(&(bio->next_bio->references), 1, CRYPTO_LOCK_BIO); #else @@ -347,7 +348,8 @@ static long bio_rdp_tls_ctrl(BIO* bio, int cmd, long num, void* ptr) if (ssl_rbio != ssl_wbio) BIO_free_all(ssl_wbio); -#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) +#if OPENSSL_VERSION_NUMBER < 0x10100000L || \ + (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x2070000fL) if (next_bio) CRYPTO_add(&(bio->next_bio->references), -1, CRYPTO_LOCK_BIO); @@ -387,7 +389,8 @@ static long bio_rdp_tls_ctrl(BIO* bio, int cmd, long num, void* ptr) BIO_push(ssl_rbio, next_bio); BIO_set_next(bio, ssl_rbio); -#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) +#if OPENSSL_VERSION_NUMBER < 0x10100000L || \ + (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x2070000fL) CRYPTO_add(&(ssl_rbio->references), 1, CRYPTO_LOCK_BIO); #else BIO_up_ref(ssl_rbio); From 2704397db7ec9068098ec5849e2b0b927b39959a Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Wed, 17 Nov 2021 09:52:54 +0100 Subject: [PATCH 009/496] Updated ChangeLog --- ChangeLog | 1 + 1 file changed, 1 insertion(+) diff --git a/ChangeLog b/ChangeLog index d1cb9cf44dc3..c0292cc4a766 100644 --- a/ChangeLog +++ b/ChangeLog @@ -2,6 +2,7 @@ Noteworthy changes: * Fixed smartcard login in case a redirection occurs the pin was lost +* Backported LibreSSL compatibility patches Fixed issues: From c54c846b59f397846835fe2a7cca05abd771f81f Mon Sep 17 00:00:00 2001 From: akallabeth Date: Tue, 10 Nov 2020 10:11:03 +0100 Subject: [PATCH 010/496] Added stack trace on signal. (cherry picked from commit cf49e4bfa8d855ab1758fbb7ff14eb44094854e5) --- libfreerdp/utils/signal.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/libfreerdp/utils/signal.c b/libfreerdp/utils/signal.c index 0510ef4eecb9..b529b7823c4e 100644 --- a/libfreerdp/utils/signal.c +++ b/libfreerdp/utils/signal.c @@ -43,6 +43,7 @@ int freerdp_handle_signals(void) #else #include +#include volatile sig_atomic_t terminal_needs_reset = 0; int terminal_fildes = 0; @@ -53,8 +54,15 @@ static void fatal_handler(int signum) { struct sigaction default_sigaction; sigset_t this_mask; - WLog_INFO(TAG, "Caught signal '%s' [%d]", strsignal(signum), signum); + static BOOL recursive = FALSE; + if (!recursive) + { + recursive = TRUE; + WLog_ERR(TAG, "Caught signal '%s' [%d]", strsignal(signum), signum); + + winpr_log_backtrace(TAG, WLOG_ERROR, 20); + } if (terminal_needs_reset) tcsetattr(terminal_fildes, TCSAFLUSH, &orig_flags); From d9bad571bd7b9ee9c44f4ca1cb2d4a91e93e4cac Mon Sep 17 00:00:00 2001 From: akallabeth Date: Mon, 22 Nov 2021 11:38:59 +0100 Subject: [PATCH 011/496] Updated changelog --- ChangeLog | 1 + 1 file changed, 1 insertion(+) diff --git a/ChangeLog b/ChangeLog index c0292cc4a766..8548b893aa82 100644 --- a/ChangeLog +++ b/ChangeLog @@ -3,6 +3,7 @@ Noteworthy changes: * Fixed smartcard login in case a redirection occurs the pin was lost * Backported LibreSSL compatibility patches +* Backported signal handler backtrace Fixed issues: From 39eda039d77081222192e7be40998c34abfc4388 Mon Sep 17 00:00:00 2001 From: Ondrej Holy Date: Thu, 18 Nov 2021 11:14:04 +0100 Subject: [PATCH 012/496] winpr/crypto: Do not load legacy provider from RC4 This partially reverts commit 67f3fff2. The legacy provider is now loaded from the `winpr_InitializeSSL` function, so it is not needed to load it from the `winpr_RC4_New` function again. (cherry picked from commit beface192f031fd40f5d86d6cf8d25d98a62a7b2) --- winpr/libwinpr/crypto/cipher.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/winpr/libwinpr/crypto/cipher.c b/winpr/libwinpr/crypto/cipher.c index e2477f39e058..41725ab18d83 100644 --- a/winpr/libwinpr/crypto/cipher.c +++ b/winpr/libwinpr/crypto/cipher.c @@ -29,9 +29,6 @@ #include #include #include -#if defined(OPENSSL_VERSION_MAJOR) && (OPENSSL_VERSION_MAJOR >= 3) -#include -#endif #endif #ifdef WITH_MBEDTLS @@ -61,11 +58,6 @@ static WINPR_RC4_CTX* winpr_RC4_New_Internal(const BYTE* key, size_t keylen, BOO if (keylen > INT_MAX) return NULL; -#if defined(OPENSSL_VERSION_MAJOR) && (OPENSSL_VERSION_MAJOR >= 3) - if (OSSL_PROVIDER_load(NULL, "legacy") == NULL) - return NULL; -#endif - if (!(ctx = (WINPR_RC4_CTX*)EVP_CIPHER_CTX_new())) return NULL; From 34ddfc5348d29237dee7bde67e3f66cfbf41ea5f Mon Sep 17 00:00:00 2001 From: Ondrej Holy Date: Tue, 16 Nov 2021 16:31:36 +0100 Subject: [PATCH 013/496] winpr/ssl: Fix capitalization in log messages The log messages contained the `ENabled` string, which looks weird to me. Let's change that to `enabled`. (cherry picked from commit bff510a48935431d357783c8ca1f6e6d393988c3) --- winpr/libwinpr/utils/ssl.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/winpr/libwinpr/utils/ssl.c b/winpr/libwinpr/utils/ssl.c index 74ef156e7b07..f409c458b756 100644 --- a/winpr/libwinpr/utils/ssl.c +++ b/winpr/libwinpr/utils/ssl.c @@ -242,7 +242,7 @@ static BOOL winpr_enable_fips(DWORD flags) WLog_ERR(TAG, "Openssl fips mode not available on openssl versions less than 1.0.1!"); return FALSE; #else - WLog_DBG(TAG, "Ensuring openssl fips mode is ENabled"); + WLog_DBG(TAG, "Ensuring openssl fips mode is enabled"); #if defined(OPENSSL_VERSION_MAJOR) && (OPENSSL_VERSION_MAJOR >= 3) if (!EVP_default_properties_is_fips_enabled(NULL)) @@ -255,10 +255,10 @@ static BOOL winpr_enable_fips(DWORD flags) #else if (FIPS_mode_set(1)) #endif - WLog_INFO(TAG, "Openssl fips mode ENabled!"); + WLog_INFO(TAG, "Openssl fips mode enabled!"); else { - WLog_ERR(TAG, "Openssl fips mode ENable failed!"); + WLog_ERR(TAG, "Openssl fips mode enable failed!"); return FALSE; } } From d6466ad0c4c37c9b7a610e898ee4df32096edc88 Mon Sep 17 00:00:00 2001 From: Ondrej Holy Date: Tue, 16 Nov 2021 16:22:55 +0100 Subject: [PATCH 014/496] winpr/ssl: Call the winpr_enable_fips function only once The `winpr_enable_fips` function is called twice from the `winpr_InitializeSSL` function after commit 49936a7b. I believe this is a bug, which might lead to some undesired behavior. Let's call that only once. (cherry picked from commit 554952a0bcd0e67e4a378a8d2219031e2601559a) --- winpr/libwinpr/utils/ssl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/winpr/libwinpr/utils/ssl.c b/winpr/libwinpr/utils/ssl.c index f409c458b756..0fce0496cf22 100644 --- a/winpr/libwinpr/utils/ssl.c +++ b/winpr/libwinpr/utils/ssl.c @@ -306,7 +306,7 @@ static BOOL CALLBACK _winpr_openssl_initialize(PINIT_ONCE once, PVOID param, PVO #endif g_winpr_openssl_initialized_by_winpr = TRUE; - return winpr_enable_fips(flags); + return TRUE; } /* exported functions */ From 9640ba50d45b37607b5bf595087a89c3f3994edc Mon Sep 17 00:00:00 2001 From: Ondrej Holy Date: Tue, 16 Nov 2021 16:12:33 +0100 Subject: [PATCH 015/496] winpr/ssl: Load legacy provider when initializing OpenSSL 3.0 With OpenSSL 3.O, FreeRDP log contains errors like: ``` 4036740A4C7F0000:error:0308010C:digital envelope routines: inner_evp_generic_fetch:unsupported:crypto/evp/evp_fetch.c:346: Global default library context, Algorithm (MD4 : 85), Properties () ``` This leads to connection failures in some cases. This is because algorithms like MD4 are now part of the legacy provider, which is not loaded by default. Let's explicitly load that provider. With this change, also the other provides has to be explicitely loaded. (cherry picked from commit 1783d65541ba5d23c27dbda76b835868f482c996) --- winpr/libwinpr/utils/ssl.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/winpr/libwinpr/utils/ssl.c b/winpr/libwinpr/utils/ssl.c index 0fce0496cf22..301f9401cece 100644 --- a/winpr/libwinpr/utils/ssl.c +++ b/winpr/libwinpr/utils/ssl.c @@ -33,6 +33,10 @@ #include #include +#if defined(OPENSSL_VERSION_MAJOR) && (OPENSSL_VERSION_MAJOR >= 3) +#include +#endif + #include "../log.h" #define TAG WINPR_TAG("utils.ssl") @@ -245,6 +249,7 @@ static BOOL winpr_enable_fips(DWORD flags) WLog_DBG(TAG, "Ensuring openssl fips mode is enabled"); #if defined(OPENSSL_VERSION_MAJOR) && (OPENSSL_VERSION_MAJOR >= 3) + OSSL_PROVIDER_load(NULL, "fips"); if (!EVP_default_properties_is_fips_enabled(NULL)) #else if (FIPS_mode() != 1) @@ -305,6 +310,13 @@ static BOOL CALLBACK _winpr_openssl_initialize(PINIT_ONCE once, PVOID param, PVO return FALSE; #endif + +#if defined(OPENSSL_VERSION_MAJOR) && (OPENSSL_VERSION_MAJOR >= 3) + /* The legacy provider is needed for MD4. */ + OSSL_PROVIDER_load(NULL, "legacy"); + OSSL_PROVIDER_load(NULL, "default"); +#endif + g_winpr_openssl_initialized_by_winpr = TRUE; return TRUE; } From 3a842a63839a5f73c140517d410a0012aef6400a Mon Sep 17 00:00:00 2001 From: Ely Ronnen Date: Sun, 28 Nov 2021 18:51:16 +0200 Subject: [PATCH 016/496] fixing android pointer not initialized when calling realloc (cherry picked from commit 4053ac37f38f9ca9c63a8cb5cf5430cb8aa5bb2f) --- client/Android/android_freerdp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/Android/android_freerdp.c b/client/Android/android_freerdp.c index 7a4686a5a07f..78205c7519c0 100644 --- a/client/Android/android_freerdp.c +++ b/client/Android/android_freerdp.c @@ -288,7 +288,7 @@ static BOOL android_Pointer_SetDefault(rdpContext* context) static BOOL android_register_pointer(rdpGraphics* graphics) { - rdpPointer pointer; + rdpPointer pointer = { 0 }; if (!graphics) return FALSE; From f4f7ebed121a9992d426e316ffba2bd9714f1f8f Mon Sep 17 00:00:00 2001 From: akallabeth Date: Mon, 29 Nov 2021 07:53:18 +0100 Subject: [PATCH 017/496] Updated changelog. --- ChangeLog | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ChangeLog b/ChangeLog index 8548b893aa82..146e00bf771a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -4,8 +4,10 @@ Noteworthy changes: * Fixed smartcard login in case a redirection occurs the pin was lost * Backported LibreSSL compatibility patches * Backported signal handler backtrace +* Backported OpenSSL 3.0 support Fixed issues: +* Backport #7466: Android android_register_pointer missing initialization Important notes: From 6b8558f3fa6643b6aee35137ff1bdfcfc8c5d7c0 Mon Sep 17 00:00:00 2001 From: Steve Pronovost Date: Sat, 16 Oct 2021 11:39:34 -0700 Subject: [PATCH 018/496] Fix protocol violation when uploading large ICON When uploading large ICON (96x96), we end up growing the stream mid-update. Stream_EnsureCapacity end up reallocating the stream with a larger capacity to accomodate the large ICON size, but in doing so, also updating the sealed length for the data currently in the stream. This breaks the assumption between update_begin_paint and update_end_paint where the sealed lenght is used to keep track of the location where we need to update the orders counts after we're done accumulating update. As a result of the growth and lost of that location, the number of orders is written to the wrong location and the resulting stream is invalid which result in a protocol violation and a connection drop. The current fix uses a new offsetOrder in the update object to keep track of where update_end_paint needs to write the number of orders contained. I think a better fix would be for Stream_EnsureCapacity to preserve the sealead length of the stream on growth, but this has a much more significant impact and careful analysis needs to be done to ensure this doesn't violate other assumption. Need to follow up with FreeRDP developer to get their take on this one. --- include/freerdp/update.h | 1 + libfreerdp/core/update.c | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/include/freerdp/update.h b/include/freerdp/update.h index d2797a28e320..ec5336a26069 100644 --- a/include/freerdp/update.h +++ b/include/freerdp/update.h @@ -254,6 +254,7 @@ struct rdp_update wStream* us; UINT16 numberOrders; + size_t offsetOrders; /* the offset to patch numberOrders in the stream */ BOOL combineUpdates; rdpBounds currentBounds; rdpBounds previousBounds; diff --git a/libfreerdp/core/update.c b/libfreerdp/core/update.c index e137c3de8a29..448726ecf77d 100644 --- a/libfreerdp/core/update.c +++ b/libfreerdp/core/update.c @@ -931,6 +931,7 @@ static BOOL _update_begin_paint(rdpContext* context) return FALSE; Stream_SealLength(s); + Stream_GetLength(s, update->offsetOrders); Stream_Seek(s, 2); /* numberOrders (2 bytes) */ update->combineUpdates = TRUE; update->numberOrders = 0; @@ -941,16 +942,14 @@ static BOOL _update_begin_paint(rdpContext* context) static BOOL _update_end_paint(rdpContext* context) { wStream* s; - int headerLength; rdpUpdate* update = context->update; if (!update->us) return FALSE; s = update->us; - headerLength = Stream_Length(s); Stream_SealLength(s); - Stream_SetPosition(s, headerLength); + Stream_SetPosition(s, update->offsetOrders); Stream_Write_UINT16(s, update->numberOrders); /* numberOrders (2 bytes) */ Stream_SetPosition(s, Stream_Length(s)); @@ -962,6 +961,7 @@ static BOOL _update_end_paint(rdpContext* context) update->combineUpdates = FALSE; update->numberOrders = 0; + update->offsetOrders = 0; update->us = NULL; Stream_Free(s, TRUE); return TRUE; From 4f15d5c72a82d6a3149a8ef83c152f32fc49e3aa Mon Sep 17 00:00:00 2001 From: Steve Pronovost Date: Sat, 16 Oct 2021 12:04:33 -0700 Subject: [PATCH 019/496] Fix protocol violation in Display Control Virtual Channel Extension Length field of DISPLAYCONTROL_HEADER must include the size of the header itself. See MS-RDPEDISP 2.2.1.1 DISPLAYCONTROL_HEADER. --- channels/disp/server/disp_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/channels/disp/server/disp_main.c b/channels/disp/server/disp_main.c index 5340165b937b..a764acd1841d 100644 --- a/channels/disp/server/disp_main.c +++ b/channels/disp/server/disp_main.c @@ -58,7 +58,7 @@ static wStream* disp_server_single_packet_new(UINT32 type, UINT32 length) } header.type = type; - header.length = length; + header.length = DISPLAY_CONTROL_HEADER_LENGTH + length; if ((error = disp_write_header(s, &header))) { From e4e3456e688f5bf27d6346c46a2e540456584594 Mon Sep 17 00:00:00 2001 From: Martin Fleisz Date: Mon, 18 Jan 2021 10:24:01 +0100 Subject: [PATCH 020/496] locale: Fix keyboard detection on MacOS (cherry picked from commit 68dfa353b8a08c0dde043afde6e2b735eefb8952) --- include/freerdp/locale/locale.h | 4 + libfreerdp/locale/CMakeLists.txt | 10 ++ libfreerdp/locale/keyboard.c | 11 +- libfreerdp/locale/keyboard_apple.c | 244 +++++++++++++++++++++++++++++ libfreerdp/locale/keyboard_apple.h | 28 ++++ 5 files changed, 296 insertions(+), 1 deletion(-) create mode 100644 libfreerdp/locale/keyboard_apple.c create mode 100644 libfreerdp/locale/keyboard_apple.h diff --git a/include/freerdp/locale/locale.h b/include/freerdp/locale/locale.h index 54ab2c66033b..6647bb22c28f 100644 --- a/include/freerdp/locale/locale.h +++ b/include/freerdp/locale/locale.h @@ -62,6 +62,7 @@ #define BRETON 0x047E #define BULGARIAN 0x0402 #define CATALAN 0x0403 +#define CHEROKEE 0x045C #define CHINESE_TAIWAN 0x0404 #define CHINESE_PRC 0x0804 #define CHINESE_HONG_KONG 0x0C04 @@ -113,12 +114,14 @@ #define GREEK 0x0408 #define GREENLANDIC 0x046F #define GUJARATI 0x0447 +#define HAWAIIAN 0x0475 #define HEBREW 0x040D #define HINDI 0x0439 #define HUNGARIAN 0x040E #define ICELANDIC 0x040F #define IGBO 0x0470 #define INDONESIAN 0x0421 +#define INUKTITUT 0x045D #define IRISH 0x083C #define ITALIAN_STANDARD 0x0410 #define ITALIAN_SWISS 0x0810 @@ -146,6 +149,7 @@ #define MARATHI 0x044E #define MOHAWK 0x047C #define MONGOLIAN 0x0450 +#define MYANMAR 0x0455 #define NEPALI 0x0461 #define NORWEGIAN_BOKMAL 0x0414 #define NORWEGIAN_NYNORSK 0x0814 diff --git a/libfreerdp/locale/CMakeLists.txt b/libfreerdp/locale/CMakeLists.txt index 1a300f22f2ab..9c74e20dcd9c 100644 --- a/libfreerdp/locale/CMakeLists.txt +++ b/libfreerdp/locale/CMakeLists.txt @@ -38,10 +38,20 @@ set(${MODULE_PREFIX}_SUN_SRCS keyboard_sun.c keyboard_sun.h) +set(${MODULE_PREFIX}_APPLE_SRCS + keyboard_apple.c + keyboard_apple.h) + if(CMAKE_SYSTEM_NAME MATCHES Solaris) set(WITH_SUN true) endif() +if(APPLE AND (NOT IOS)) + set(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_SRCS} ${${MODULE_PREFIX}_APPLE_SRCS}) + find_library(CARBON Carbon) + freerdp_library_add(${CARBON}) +endif() + if(WITH_X11) freerdp_definition_add(-DWITH_X11) freerdp_include_directory_add(${X11_INCLUDE_DIRS}) diff --git a/libfreerdp/locale/keyboard.c b/libfreerdp/locale/keyboard.c index eca0d635cd8c..4c5ae03e49e9 100644 --- a/libfreerdp/locale/keyboard.c +++ b/libfreerdp/locale/keyboard.c @@ -32,6 +32,10 @@ #include "liblocale.h" +#if defined(__MACOSX__) +#include "keyboard_apple.h" +#endif + #ifdef WITH_X11 #include "keyboard_x11.h" @@ -64,6 +68,11 @@ int freerdp_detect_keyboard(DWORD* keyboardLayoutId) *keyboardLayoutId = ((DWORD)GetKeyboardLayout(0) >> 16) & 0x0000FFFF; #endif +#if defined(__MACOSX__) + if (*keyboardLayoutId == 0) + freerdp_detect_keyboard_layout_from_cf(keyboardLayoutId); +#endif + #ifdef WITH_X11 if (*keyboardLayoutId == 0) freerdp_detect_keyboard_layout_from_xkb(keyboardLayoutId); @@ -148,7 +157,7 @@ DWORD freerdp_keyboard_init(DWORD keyboardLayoutId) for (keycode = 0; keycode < ARRAYSIZE(VIRTUAL_SCANCODE_TO_X11_KEYCODE); keycode++) { VIRTUAL_SCANCODE_TO_X11_KEYCODE - [RDP_SCANCODE_CODE(X11_KEYCODE_TO_VIRTUAL_SCANCODE[keycode])] + [RDP_SCANCODE_CODE(X11_KEYCODE_TO_VIRTUAL_SCANCODE[keycode])] [RDP_SCANCODE_EXTENDED(X11_KEYCODE_TO_VIRTUAL_SCANCODE[keycode]) ? 1 : 0] = keycode; } diff --git a/libfreerdp/locale/keyboard_apple.c b/libfreerdp/locale/keyboard_apple.c new file mode 100644 index 000000000000..d0d59216e52e --- /dev/null +++ b/libfreerdp/locale/keyboard_apple.c @@ -0,0 +1,244 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Apple Core Foundation Keyboard Mapping + * + * Copyright 2021 Thincast Technologies GmbH + * Copyright 2021 Martin Fleisz + * + * 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include + +#include "liblocale.h" + +#include +#include + +#include "keyboard_apple.h" + +struct KEYBOARD_LAYOUT_MAPPING_ +{ + const char* inputSourceId; /* Apple input source id (com.apple.keylayout or inputmethod) */ + DWORD code; /* mapped rdp keyboard layout id */ +}; +typedef struct KEYBOARD_LAYOUT_MAPPING_ KEYBOARD_LAYOUT_MAPPING; + +static const KEYBOARD_LAYOUT_MAPPING KEYBOARD_MAPPING_TABLE[] = { + { "com.apple.inputmethod.Kotoeri.Japanese", JAPANESE }, + { "com.apple.inputmethod.Kotoeri.Japanese.FullWidthRoman", JAPANESE }, + { "com.apple.inputmethod.Kotoeri.Japanese.HalfWidthKana", JAPANESE }, + { "com.apple.inputmethod.Kotoeri.Japanese.Katakana", JAPANESE }, + { "com.apple.inputmethod.Kotoeri.Katakana", JAPANESE }, + { "com.apple.inputmethod.Kotoeri.Roman", JAPANESE }, + { "com.apple.inputmethod.kotoeri.Ainu", JAPANESE }, + { "com.apple.keylayout.2SetHangul", KOREAN }, + { "com.apple.keylayout.390Hangul", KOREAN }, + { "com.apple.keylayout.3SetHangul", KOREAN }, + { "com.apple.keylayout.AfghanDari", DARI }, + { "com.apple.keylayout.AfghanPashto", PASHTO }, + { "com.apple.keylayout.AfghanUzbek", UZBEK_LATIN }, + { "com.apple.keylayout.Arabic", ARABIC_EGYPT }, + { "com.apple.keylayout.Arabic-QWERTY", ARABIC_EGYPT }, + { "com.apple.keylayout.ArabicPC", ARABIC_EGYPT }, + { "com.apple.keylayout.Armenian-HMQWERTY", ARMENIAN }, + { "com.apple.keylayout.Armenian-WesternQWERTY", ARMENIAN }, + { "com.apple.keylayout.Australian", ENGLISH_AUSTRALIAN }, + { "com.apple.keylayout.Austrian", GERMAN_AUSTRIAN }, + { "com.apple.keylayout.Azeri", AZERI_LATIN }, + { "com.apple.keylayout.Bangla", BENGALI_INDIA }, + { "com.apple.keylayout.Bangla-QWERTY", BENGALI_INDIA }, + { "com.apple.keylayout.Belgian", DUTCH_BELGIAN }, + { "com.apple.keylayout.Brazilian", PORTUGUESE_BRAZILIAN }, + { "com.apple.keylayout.British", ENGLISH_UNITED_KINGDOM }, + { "com.apple.keylayout.British-PC", ENGLISH_UNITED_KINGDOM }, + { "com.apple.keylayout.Bulgarian", BULGARIAN }, + { "com.apple.keylayout.Bulgarian-Phonetic", BULGARIAN }, + { "com.apple.keylayout.Byelorussian", BELARUSIAN }, + { "com.apple.keylayout.Canadian", ENGLISH_CANADIAN }, + { "com.apple.keylayout.Canadian-CSA", FRENCH_CANADIAN }, + { "com.apple.keylayout.CangjieKeyboard", CHINESE_TAIWAN }, + { "com.apple.keylayout.Cherokee-Nation", CHEROKEE }, + { "com.apple.keylayout.Cherokee-QWERTY", CHEROKEE }, + { "com.apple.keylayout.Colemak", ENGLISH_UNITED_STATES }, + { "com.apple.keylayout.Croatian", CROATIAN }, + { "com.apple.keylayout.Croatian-PC", CROATIAN }, + { "com.apple.keylayout.Czech", CZECH }, + { "com.apple.keylayout.Czech-QWERTY", CZECH }, + { "com.apple.keylayout.DVORAK-QWERTYCMD", ENGLISH_UNITED_STATES }, + { "com.apple.keylayout.Danish", DANISH }, + { "com.apple.keylayout.Devanagari", HINDI }, + { "com.apple.keylayout.Devanagari-QWERTY", HINDI }, + { "com.apple.keylayout.Dutch", DUTCH_STANDARD }, + { "com.apple.keylayout.Dvorak", ENGLISH_UNITED_STATES }, + { "com.apple.keylayout.Dvorak-Left", ENGLISH_UNITED_STATES }, + { "com.apple.keylayout.Dvorak-Right", ENGLISH_UNITED_STATES }, + { "com.apple.keylayout.Estonian", ESTONIAN }, + { "com.apple.keylayout.Faroese", FAEROESE }, + { "com.apple.keylayout.Finnish", FINNISH }, + { "com.apple.keylayout.FinnishExtended", FINNISH }, + { "com.apple.keylayout.FinnishSami-PC", FINNISH }, + { "com.apple.keylayout.French", FRENCH_STANDARD }, + { "com.apple.keylayout.French-PC", FRENCH_STANDARD }, + { "com.apple.keylayout.French-numerical", FRENCH_STANDARD }, + { "com.apple.keylayout.GJCRomaja", ENGLISH_UNITED_STATES }, + { "com.apple.keylayout.Georgian-QWERTY", GEORGIAN }, + { "com.apple.keylayout.German", GERMAN_STANDARD }, + { "com.apple.keylayout.Greek", GREEK }, + { "com.apple.keylayout.GreekPolytonic", GREEK }, + { "com.apple.keylayout.Gujarati", GUJARATI }, + { "com.apple.keylayout.Gujarati-QWERTY", GUJARATI }, + { "com.apple.keylayout.Gurmukhi", PUNJABI }, + { "com.apple.keylayout.Gurmukhi-QWERTY", PUNJABI }, + { "com.apple.keylayout.HNCRomaja", ENGLISH_UNITED_STATES }, + { "com.apple.keylayout.Hawaiian", HAWAIIAN }, + { "com.apple.keylayout.Hebrew", HEBREW }, + { "com.apple.keylayout.Hebrew-PC", HEBREW }, + { "com.apple.keylayout.Hebrew-QWERTY", HEBREW }, + { "com.apple.keylayout.Hungarian", HUNGARIAN }, + { "com.apple.keylayout.Hungarian-QWERTY", HUNGARIAN }, + { "com.apple.keylayout.Icelandic", ICELANDIC }, + { "com.apple.keylayout.Inuktitut-Nunavut", INUKTITUT }, + { "com.apple.keylayout.Inuktitut-Nutaaq", INUKTITUT }, + { "com.apple.keylayout.Inuktitut-QWERTY", INUKTITUT }, + { "com.apple.keylayout.InuttitutNunavik", INUKTITUT }, + { "com.apple.keylayout.Irish", ENGLISH_IRELAND }, + { "com.apple.keylayout.IrishExtended", IRISH }, + { "com.apple.keylayout.Italian", ITALIAN_STANDARD }, + { "com.apple.keylayout.Italian-Pro", ITALIAN_STANDARD }, + { "com.apple.keylayout.Jawi-QWERTY", ARABIC_SAUDI_ARABIA }, + { "com.apple.keylayout.Kannada", KANNADA }, + { "com.apple.keylayout.Kannada-QWERTY", KANNADA }, + { "com.apple.keylayout.Kazakh", KAZAKH }, + { "com.apple.keylayout.Khmer", KHMER }, + { "com.apple.keylayout.Latvian", LATVIAN }, + { "com.apple.keylayout.Lithuanian", LITHUANIAN }, + { "com.apple.keylayout.Macedonian", MACEDONIAN }, + { "com.apple.keylayout.Malayalam", MALAYALAM }, + { "com.apple.keylayout.Malayalam-QWERTY", MALAYALAM }, + { "com.apple.keylayout.Maltese", MALTESE }, + { "com.apple.keylayout.Maori", MAORI }, + { "com.apple.keylayout.Myanmar-QWERTY", MYANMAR }, + { "com.apple.keylayout.Nepali", NEPALI }, + { "com.apple.keylayout.NorthernSami", SAMI_NORTHERN_NORWAY }, + { "com.apple.keylayout.Norwegian", NORWEGIAN_BOKMAL }, + { "com.apple.keylayout.NorwegianExtended", NORWEGIAN_BOKMAL }, + { "com.apple.keylayout.NorwegianSami-PC", NORWEGIAN_BOKMAL }, + { "com.apple.keylayout.Oriya", ORIYA }, + { "com.apple.keylayout.Persian", FARSI }, + { "com.apple.keylayout.Persian-ISIRI2901", FARSI }, + { "com.apple.keylayout.Polish", POLISH }, + { "com.apple.keylayout.PolishPro", POLISH }, + { "com.apple.keylayout.Portuguese", PORTUGUESE_STANDARD }, + { "com.apple.keylayout.Romanian", ROMANIAN }, + { "com.apple.keylayout.Romanian-Standard", ROMANIAN }, + { "com.apple.keylayout.Russian", RUSSIAN }, + { "com.apple.keylayout.Russian-Phonetic", RUSSIAN }, + { "com.apple.keylayout.RussianWin", RUSSIAN }, + { "com.apple.keylayout.Sami-PC", SAMI_NORTHERN_SWEDEN }, + { "com.apple.keylayout.Serbian", SERBIAN_CYRILLIC_BOSNIA_HERZEGOVINA }, + { "com.apple.keylayout.Serbian-Latin", SERBIAN_LATIN_BOSNIA_HERZEGOVINA }, + { "com.apple.keylayout.Sinhala", SINHALA }, + { "com.apple.keylayout.Sinhala-QWERTY", SINHALA }, + { "com.apple.keylayout.Slovak", SLOVAK }, + { "com.apple.keylayout.Slovak-QWERTY", SLOVAK }, + { "com.apple.keylayout.Slovenian", SLOVENIAN }, + { "com.apple.keylayout.Spanish", SPANISH_TRADITIONAL_SORT }, + { "com.apple.keylayout.Spanish-ISO", SPANISH_MODERN_SORT }, + { "com.apple.keylayout.Swedish", SWEDISH }, + { "com.apple.keylayout.Swedish-Pro", SWEDISH }, + { "com.apple.keylayout.SwedishSami-PC", SWEDISH }, + { "com.apple.keylayout.SwissFrench", FRENCH_SWISS }, + { "com.apple.keylayout.SwissGerman", GERMAN_SWISS }, + { "com.apple.keylayout.Telugu", TELUGU }, + { "com.apple.keylayout.Telugu-QWERTY", TELUGU }, + { "com.apple.keylayout.Thai", THAI }, + { "com.apple.keylayout.Thai-PattaChote", THAI }, + { "com.apple.keylayout.Tibetan-QWERTY", TIBETAN_PRC }, + { "com.apple.keylayout.Tibetan-Wylie", TIBETAN_PRC }, + { "com.apple.keylayout.TibetanOtaniUS", TIBETAN_PRC }, + { "com.apple.keylayout.Turkish", TURKISH }, + { "com.apple.keylayout.Turkish-QWERTY", TURKISH }, + { "com.apple.keylayout.Turkish-QWERTY-PC", TURKISH }, + { "com.apple.keylayout.US", ENGLISH_UNITED_STATES }, + { "com.apple.keylayout.USExtended", ENGLISH_UNITED_STATES }, + { "com.apple.keylayout.USInternational-PC", ENGLISH_UNITED_STATES }, + { "com.apple.keylayout.Ukrainian", UKRAINIAN }, + { "com.apple.keylayout.Ukrainian-PC", UKRAINIAN }, + { "com.apple.keylayout.UnicodeHexInput", ENGLISH_UNITED_STATES }, + { "com.apple.keylayout.Urdu", URDU }, + { "com.apple.keylayout.Uyghur", UIGHUR }, + { "com.apple.keylayout.Vietnamese", VIETNAMESE }, + { "com.apple.keylayout.Welsh", WELSH } +}; + +int freerdp_detect_keyboard_layout_from_cf(DWORD* keyboardLayoutId) +{ + int i; + CFIndex length; + char* inputSourceId = NULL; + CFStringRef inputSourceIdRef; + TISInputSourceRef inputSrc = TISCopyCurrentKeyboardLayoutInputSource(); + if (!inputSrc) + { + DEBUG_KBD("Failed to get current keyboard layout input source!"); + return 0; + } + + /* get current input source id */ + inputSourceIdRef = (CFStringRef)TISGetInputSourceProperty(inputSrc, kTISPropertyInputSourceID); + if (!inputSourceIdRef) + { + DEBUG_KBD("Failed to get input source id!"); + goto done; + } + + /* convert it to a C-string */ + length = CFStringGetLength(inputSourceIdRef); + length = CFStringGetMaximumSizeForEncoding(length, kCFStringEncodingUTF8) + 1; + inputSourceId = (char*)malloc(length); + if (!inputSourceId) + { + DEBUG_KBD("Failed to allocate string buffer!"); + goto done; + } + + if (!CFStringGetCString(inputSourceIdRef, inputSourceId, length, kCFStringEncodingUTF8)) + { + DEBUG_KBD("Failed to convert CFString to C-string!"); + goto done; + } + + /* Search for the id in the mapping table */ + for (i = 0; i < ARRAYSIZE(KEYBOARD_MAPPING_TABLE); ++i) + { + if (strcmp(inputSourceId, KEYBOARD_MAPPING_TABLE[i].inputSourceId) == 0) + { + *keyboardLayoutId = KEYBOARD_MAPPING_TABLE[i].code; + break; + } + } + +done: + free(inputSourceId); + CFRelease(inputSrc); + if (*keyboardLayoutId > 0) + return *keyboardLayoutId; + + return 0; +} diff --git a/libfreerdp/locale/keyboard_apple.h b/libfreerdp/locale/keyboard_apple.h new file mode 100644 index 000000000000..cd3c3e7beca7 --- /dev/null +++ b/libfreerdp/locale/keyboard_apple.h @@ -0,0 +1,28 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Apple Core Foundation Keyboard Mapping + * + * Copyright 2021 Thincast Technologies GmbH + * Copyright 2021 Martin Fleisz + * + * 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_LOCALE_KEYBOARD_APPLE_H +#define FREERDP_LOCALE_KEYBOARD_APPLE_H + +#include + +FREERDP_LOCAL int freerdp_detect_keyboard_layout_from_cf(DWORD* keyboardLayoutId); + +#endif /* FREERDP_LOCALE_KEYBOARD_APPLE_H */ From bdcc13f96fee5a9badc6c2e147b3e6cece891393 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Wed, 22 Dec 2021 08:53:25 +0100 Subject: [PATCH 021/496] Fixed size checks for locale detection. Reported by George Zaytsev from Positive Technologies (cherry picked from commit 8d5127cf06d57774a45f421afd551a39b849aedb) --- libfreerdp/locale/locale.c | 191 ++++++++++++++++++++++++------------- 1 file changed, 125 insertions(+), 66 deletions(-) diff --git a/libfreerdp/locale/locale.c b/libfreerdp/locale/locale.c index 97ae9e469645..e7c6d00782d9 100644 --- a/libfreerdp/locale/locale.c +++ b/libfreerdp/locale/locale.c @@ -3,6 +3,8 @@ * Microsoft Locales * * Copyright 2009-2012 Marc-Andre Moreau + * Copyright 2021 Thincast Technologies GmbH + * Copyright 2021 Martin Fleisz * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,22 +23,32 @@ #include "config.h" #endif +#if defined(__APPLE__) +#include +#include +#endif + #include #include #include #include +#include #include #include "liblocale.h" #include +#define LOCALE_LANGUAGE_LEN 6 +#define LOCALE_COUNTRY_LEN 10 + struct _SYSTEM_LOCALE { - char language[4]; /* Two or three letter language code */ - char country[10]; /* Two or three letter country code (Sometimes with Cyrl_ prefix) */ - DWORD code; /* 32-bit unsigned integer corresponding to the locale */ + char language[LOCALE_LANGUAGE_LEN]; /* Two or three letter language code */ + char country[LOCALE_COUNTRY_LEN]; /* Two or three letter country code (Sometimes with Cyrl_ + prefix) */ + DWORD code; /* 32-bit unsigned integer corresponding to the locale */ }; typedef struct _SYSTEM_LOCALE SYSTEM_LOCALE; @@ -642,77 +654,118 @@ static const LOCALE_KEYBOARD_LAYOUTS LOCALE_KEYBOARD_LAYOUTS_TABLE[] = { { XHOSA, { 0x00000409, 0x00000409, 0x0, 0x0, 0x0 } }, }; -static BOOL freerdp_get_system_language_and_country_codes(char* language, char* country) +static BOOL freerdp_get_system_language_and_country_codes(char* language, size_t languageLen, + char* country, size_t countryLen) { - int dot; - DWORD nSize; - int underscore; - char* env_lang = NULL; - LPCSTR lang = "LANG"; - /* LANG = _. */ - nSize = GetEnvironmentVariableA(lang, NULL, 0); - - if (!nSize) - return FALSE; /* LANG environment variable was not set */ - - env_lang = (char*)malloc(nSize); - - if (!env_lang) - return FALSE; + assert(language); + assert(languageLen > 0); + assert(country); + assert(countryLen); - if (GetEnvironmentVariableA(lang, env_lang, nSize) != - nSize - 1) /* Get locale from environment variable LANG */ +#if defined(__APPLE__) { - free(env_lang); - return FALSE; - } + CFIndex strSize; + CFStringRef langRef, countryRef; + CFLocaleRef localeRef = CFLocaleCopyCurrent(); + if (!localeRef) + return FALSE; + + langRef = (CFStringRef)CFLocaleGetValue(localeRef, kCFLocaleLanguageCode); + countryRef = (CFStringRef)CFLocaleGetValue(localeRef, kCFLocaleCountryCode); + if (!langRef || !countryRef) + { + CFRelease(localeRef); + return FALSE; + } - underscore = strcspn(env_lang, "_"); + if (!CFStringGetCString(langRef, language, languageLen, kCFStringEncodingUTF8) || + !CFStringGetCString(countryRef, country, countryLen, kCFStringEncodingUTF8)) + { + CFRelease(localeRef); + return FALSE; + } - if (underscore > 3) - { - free(env_lang); - return FALSE; /* The language name should not be more than 3 letters long */ + CFRelease(localeRef); + return TRUE; } - else +#else { - /* Get language code */ - strncpy(language, env_lang, underscore); - language[underscore] = '\0'; - } + int dot; + DWORD nSize; + int underscore; + char* env_lang = NULL; + LPCSTR lang = "LANG"; + /* LANG = _. */ + nSize = GetEnvironmentVariableA(lang, NULL, 0); - dot = strcspn(env_lang, "."); + if (!nSize) + return FALSE; /* LANG environment variable was not set */ + + env_lang = (char*)malloc(nSize); + + if (!env_lang) + return FALSE; + + if (GetEnvironmentVariableA(lang, env_lang, nSize) != + nSize - 1) /* Get locale from environment variable LANG */ + { + free(env_lang); + return FALSE; + } + + underscore = strcspn(env_lang, "_"); + + if (underscore > 3) + { + free(env_lang); + return FALSE; /* The language name should not be more than 3 letters long */ + } + else + { + /* Get language code */ + size_t len = MIN(languageLen - 1, underscore); + strncpy(language, env_lang, len); + language[len] = '\0'; + } + + dot = strcspn(env_lang, "."); + + /* Get country code */ + if (dot > underscore) + { + size_t len = MIN(countryLen - 1, dot - underscore - 1); + strncpy(country, &env_lang[underscore + 1], len); + country[len] = '\0'; + } + else + { + free(env_lang); + return FALSE; /* Invalid locale */ + } - /* Get country code */ - if (dot > underscore) - { - strncpy(country, &env_lang[underscore + 1], dot - underscore - 1); - country[dot - underscore - 1] = '\0'; - } - else - { free(env_lang); - return FALSE; /* Invalid locale */ + return TRUE; } - - free(env_lang); - return TRUE; +#endif } -static SYSTEM_LOCALE* freerdp_detect_system_locale(void) +static const SYSTEM_LOCALE* freerdp_detect_system_locale(void) { size_t i; - char language[4]; - char country[10]; - SYSTEM_LOCALE* locale = NULL; - freerdp_get_system_language_and_country_codes(language, country); + char language[LOCALE_LANGUAGE_LEN] = { 0 }; + char country[LOCALE_COUNTRY_LEN] = { 0 }; + const SYSTEM_LOCALE* locale = NULL; + + freerdp_get_system_language_and_country_codes(language, ARRAYSIZE(language), country, + ARRAYSIZE(country)); for (i = 0; i < ARRAYSIZE(SYSTEM_LOCALE_TABLE); i++) { - if ((strcmp(language, SYSTEM_LOCALE_TABLE[i].language) == 0) && - (strcmp(country, SYSTEM_LOCALE_TABLE[i].country) == 0)) + const SYSTEM_LOCALE* current = &SYSTEM_LOCALE_TABLE[i]; + + if ((strcmp(language, current->language) == 0) && (strcmp(country, current->country) == 0)) { - locale = (SYSTEM_LOCALE*)&SYSTEM_LOCALE_TABLE[i]; + locale = current; break; } } @@ -722,7 +775,7 @@ static SYSTEM_LOCALE* freerdp_detect_system_locale(void) DWORD freerdp_get_system_locale_id(void) { - SYSTEM_LOCALE* locale; + const SYSTEM_LOCALE* locale; locale = freerdp_detect_system_locale(); if (locale != NULL) @@ -737,8 +790,10 @@ const char* freerdp_get_system_locale_name_from_id(DWORD localeId) for (index = 0; index < ARRAYSIZE(LOCALE_NAME_TABLE); index++) { - if (localeId == LOCALE_NAME_TABLE[index].localeId) - return LOCALE_NAME_TABLE[index].name; + const LOCALE_NAME* const current = &LOCALE_NAME_TABLE[index]; + + if (localeId == current->localeId) + return current->name; } return NULL; @@ -747,10 +802,12 @@ const char* freerdp_get_system_locale_name_from_id(DWORD localeId) int freerdp_detect_keyboard_layout_from_system_locale(DWORD* keyboardLayoutId) { size_t i, j; - char language[4]; - char country[10]; - SYSTEM_LOCALE* locale; - freerdp_get_system_language_and_country_codes(language, country); + char language[LOCALE_LANGUAGE_LEN] = { 0 }; + char country[LOCALE_COUNTRY_LEN] = { 0 }; + const SYSTEM_LOCALE* locale; + + freerdp_get_system_language_and_country_codes(language, ARRAYSIZE(language), country, + ARRAYSIZE(country)); if ((strcmp(language, "C") == 0) || (strcmp(language, "POSIX") == 0)) { @@ -767,22 +824,24 @@ int freerdp_detect_keyboard_layout_from_system_locale(DWORD* keyboardLayoutId) for (i = 0; i < ARRAYSIZE(LOCALE_KEYBOARD_LAYOUTS_TABLE); i++) { - if (LOCALE_KEYBOARD_LAYOUTS_TABLE[i].locale == locale->code) + const LOCALE_KEYBOARD_LAYOUTS* const current = &LOCALE_KEYBOARD_LAYOUTS_TABLE[i]; + + if (current->locale == locale->code) { /* Locale found in list of default keyboard layouts */ for (j = 0; j < 5; j++) { - if (LOCALE_KEYBOARD_LAYOUTS_TABLE[i].keyboardLayouts[j] == ENGLISH_UNITED_STATES) + if (current->keyboardLayouts[j] == ENGLISH_UNITED_STATES) { continue; /* Skip, try to get a more localized keyboard layout */ } - else if (LOCALE_KEYBOARD_LAYOUTS_TABLE[i].keyboardLayouts[j] == 0) + else if (current->keyboardLayouts[j] == 0) { break; /* No more keyboard layouts */ } else { - *keyboardLayoutId = LOCALE_KEYBOARD_LAYOUTS_TABLE[i].keyboardLayouts[j]; + *keyboardLayoutId = current->keyboardLayouts[j]; return 0; } } From ce2c783016a4e77086019760f7379394569998a4 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Wed, 22 Dec 2021 09:04:04 +0100 Subject: [PATCH 022/496] Fixed file name pattern checks in freerdp_channels_list_dynamic_addins Reported by George Zaytsev from Positive Technologies (cherry picked from commit 359bee229c95cbf008cdb32a62bd304e44857b8a) --- channels/client/addin.c | 83 ++++++++++++++++++++++++++++++++++------- 1 file changed, 70 insertions(+), 13 deletions(-) diff --git a/channels/client/addin.c b/channels/client/addin.c index cd6f90e991c3..db32ff83cc28 100644 --- a/channels/client/addin.c +++ b/channels/client/addin.c @@ -231,10 +231,8 @@ static FREERDP_ADDIN** freerdp_channels_list_dynamic_addins(LPCSTR pszName, LPCS do { - char* p[5]; - FREERDP_ADDIN* pAddin; - nDashes = 0; - pAddin = (FREERDP_ADDIN*)calloc(1, sizeof(FREERDP_ADDIN)); + BOOL used = FALSE; + FREERDP_ADDIN* pAddin = (FREERDP_ADDIN*)calloc(1, sizeof(FREERDP_ADDIN)); if (!pAddin) { @@ -242,57 +240,116 @@ static FREERDP_ADDIN** freerdp_channels_list_dynamic_addins(LPCSTR pszName, LPCS goto error_out; } + nDashes = 0; for (index = 0; FindData.cFileName[index]; index++) nDashes += (FindData.cFileName[index] == '-') ? 1 : 0; if (nDashes == 1) { + size_t len; + char* p[2] = { 0 }; /* -client. */ p[0] = FindData.cFileName; p[1] = strchr(p[0], '-') + 1; - strncpy(pAddin->cName, p[0], (p[1] - p[0]) - 1); + + len = p[1] - p[0]; + if (len < 1) + { + WLog_WARN(TAG, "Skipping file '%s', invalid format", FindData.cFileName); + goto skip; + } + strncpy(pAddin->cName, p[0], MIN(ARRAYSIZE(pAddin->cName), len - 1)); + pAddin->dwFlags = FREERDP_ADDIN_CLIENT; pAddin->dwFlags |= FREERDP_ADDIN_DYNAMIC; pAddin->dwFlags |= FREERDP_ADDIN_NAME; ppAddins[nAddins++] = pAddin; + + used = TRUE; } else if (nDashes == 2) { + size_t len; + char* p[4] = { 0 }; /* -client-. */ p[0] = FindData.cFileName; p[1] = strchr(p[0], '-') + 1; p[2] = strchr(p[1], '-') + 1; p[3] = strchr(p[2], '.') + 1; - strncpy(pAddin->cName, p[0], (p[1] - p[0]) - 1); - strncpy(pAddin->cSubsystem, p[2], (p[3] - p[2]) - 1); + + len = p[1] - p[0]; + if (len < 1) + { + WLog_WARN(TAG, "Skipping file '%s', invalid format", FindData.cFileName); + goto skip; + } + strncpy(pAddin->cName, p[0], MIN(ARRAYSIZE(pAddin->cName), len - 1)); + + len = p[3] - p[2]; + if (len < 1) + { + WLog_WARN(TAG, "Skipping file '%s', invalid format", FindData.cFileName); + goto skip; + } + strncpy(pAddin->cSubsystem, p[2], MIN(ARRAYSIZE(pAddin->cSubsystem), len - 1)); + pAddin->dwFlags = FREERDP_ADDIN_CLIENT; pAddin->dwFlags |= FREERDP_ADDIN_DYNAMIC; pAddin->dwFlags |= FREERDP_ADDIN_NAME; pAddin->dwFlags |= FREERDP_ADDIN_SUBSYSTEM; ppAddins[nAddins++] = pAddin; + + used = TRUE; } else if (nDashes == 3) { + size_t len; + char* p[5] = { 0 }; /* -client--. */ p[0] = FindData.cFileName; p[1] = strchr(p[0], '-') + 1; p[2] = strchr(p[1], '-') + 1; p[3] = strchr(p[2], '-') + 1; p[4] = strchr(p[3], '.') + 1; - strncpy(pAddin->cName, p[0], (p[1] - p[0]) - 1); - strncpy(pAddin->cSubsystem, p[2], (p[3] - p[2]) - 1); - strncpy(pAddin->cType, p[3], (p[4] - p[3]) - 1); + + len = p[1] - p[0]; + if (len < 1) + { + WLog_WARN(TAG, "Skipping file '%s', invalid format", FindData.cFileName); + goto skip; + } + strncpy(pAddin->cName, p[0], MIN(ARRAYSIZE(pAddin->cName), len - 1)); + + len = p[3] - p[2]; + if (len < 1) + { + WLog_WARN(TAG, "Skipping file '%s', invalid format", FindData.cFileName); + goto skip; + } + strncpy(pAddin->cSubsystem, p[2], MIN(ARRAYSIZE(pAddin->cSubsystem), len - 1)); + + len = p[4] - p[3]; + if (len < 1) + { + WLog_WARN(TAG, "Skipping file '%s', invalid format", FindData.cFileName); + goto skip; + } + strncpy(pAddin->cType, p[3], MIN(ARRAYSIZE(pAddin->cType), len - 1)); + pAddin->dwFlags = FREERDP_ADDIN_CLIENT; pAddin->dwFlags |= FREERDP_ADDIN_DYNAMIC; pAddin->dwFlags |= FREERDP_ADDIN_NAME; pAddin->dwFlags |= FREERDP_ADDIN_SUBSYSTEM; pAddin->dwFlags |= FREERDP_ADDIN_TYPE; ppAddins[nAddins++] = pAddin; + + used = TRUE; } - else - { + + skip: + if (!used) free(pAddin); - } + } while (FindNextFileA(hFind, &FindData)); FindClose(hFind); From e4bdf2aaf39b70b6d945ba68ea3de8903bb79c6a Mon Sep 17 00:00:00 2001 From: akallabeth Date: Wed, 22 Dec 2021 09:12:49 +0100 Subject: [PATCH 023/496] Fixed RegQueryValueExA * Set lpType if not NULL * Set lpcbData only if not NULL Reported by George Zaytsev from Positive Technologies (cherry picked from commit 98cfb19de028a52ffcc0c106e742f3153b5c06cd) --- winpr/libwinpr/registry/registry.c | 43 ++++++++++++++++++++++++++---- 1 file changed, 38 insertions(+), 5 deletions(-) diff --git a/winpr/libwinpr/registry/registry.c b/winpr/libwinpr/registry/registry.c index 726233e3def2..b2b04d3b3602 100644 --- a/winpr/libwinpr/registry/registry.c +++ b/winpr/libwinpr/registry/registry.c @@ -34,7 +34,9 @@ #include #include #include + #include +#include #include "registry_reg.h" @@ -271,24 +273,48 @@ LONG RegQueryValueExA(HKEY hKey, LPCSTR lpValueName, LPDWORD lpReserved, LPDWORD RegKey* key; RegVal* pValue; + WINPR_UNUSED(lpReserved); + key = (RegKey*)hKey; + assert(key); + pValue = key->values; while (pValue != NULL) { if (strcmp(pValue->name, lpValueName) == 0) { + if (lpType) + *lpType = pValue->type; + if (pValue->type == REG_DWORD) { DWORD* pData = (DWORD*)lpData; - if (pData != NULL) + if (lpcbData) { - *pData = pValue->data.dword; + DWORD size = *lpcbData; + *lpcbData = sizeof(DWORD); + if (pData) + { + if (size < *lpcbData) + return ERROR_MORE_DATA; + } } - *lpcbData = sizeof(DWORD); + if (pData != NULL) + { + DWORD size; + assert(lpcbData); + size = *lpcbData; + *lpcbData = sizeof(DWORD); + if (size < sizeof(DWORD)) + return ERROR_MORE_DATA; + *pData = pValue->data.dword; + } + else if (lpcbData != NULL) + *lpcbData = sizeof(DWORD); return ERROR_SUCCESS; } else if (pValue->type == REG_SZ) @@ -300,11 +326,18 @@ LONG RegQueryValueExA(HKEY hKey, LPCSTR lpValueName, LPDWORD lpReserved, LPDWORD if (pData != NULL) { + DWORD size; + assert(lpcbData); + + size = *lpcbData; + *lpcbData = length; + if (size < length) + return ERROR_MORE_DATA; memcpy(pData, pValue->data.string, length); pData[length] = '\0'; } - - *lpcbData = (UINT32)length; + else if (lpcbData) + *lpcbData = (UINT32)length; return ERROR_SUCCESS; } From 039c924595afa7429e21100081762bfad2e3b95b Mon Sep 17 00:00:00 2001 From: akallabeth Date: Wed, 22 Dec 2021 09:32:11 +0100 Subject: [PATCH 024/496] Fixed reg_load_val Reported by George Zaytsev from Positive Technologies (cherry picked from commit 5dbf739bf9cef77b4fdb3f2f97f10b406664dbe8) --- winpr/libwinpr/registry/registry_reg.c | 175 ++++++++++++++++--------- 1 file changed, 116 insertions(+), 59 deletions(-) diff --git a/winpr/libwinpr/registry/registry_reg.c b/winpr/libwinpr/registry/registry_reg.c index 353e490c113f..2f92b61dec63 100644 --- a/winpr/libwinpr/registry/registry_reg.c +++ b/winpr/libwinpr/registry/registry_reg.c @@ -27,6 +27,7 @@ #include #include +#include #include #include @@ -52,25 +53,45 @@ static struct reg_data_type REG_DATA_TYPE_TABLE[] = { { "\"", 1, REG_SZ }, { "hex:", 4, REG_BINARY }, { "hex(2):\"", 8, REG_EXPAND_SZ }, { "hex(7):\"", 8, REG_MULTI_SZ }, - { "hex(b):\"", 8, REG_QWORD }, - { NULL, 0, 0 } }; - -static char* REG_DATA_TYPE_STRINGS[] = { "REG_NONE", - "REG_SZ", - "REG_EXPAND_SZ", - "REG_BINARY", - "REG_DWORD", - "REG_DWORD_BIG_ENDIAN", - "REG_LINK", - "REG_MULTI_SZ", - "REG_RESOURCE_LIST", - "REG_FULL_RESOURCE_DESCRIPTOR", - "REG_RESOURCE_REQUIREMENTS_LIST", - "REG_QWORD" }; + { "hex(b):\"", 8, REG_QWORD } }; + +static char* reg_data_type_string(DWORD type) +{ + switch (type) + { + case REG_NONE: + return "REG_NONE"; + case REG_SZ: + return "REG_SZ"; + case REG_EXPAND_SZ: + return "REG_EXPAND_SZ"; + case REG_BINARY: + return "REG_BINARY"; + case REG_DWORD: + return "REG_DWORD"; + case REG_DWORD_BIG_ENDIAN: + return "REG_DWORD_BIG_ENDIAN"; + case REG_LINK: + return "REG_LINK"; + case REG_MULTI_SZ: + return "REG_MULTI_SZ"; + case REG_RESOURCE_LIST: + return "REG_RESOURCE_LIST"; + case REG_FULL_RESOURCE_DESCRIPTOR: + return "REG_FULL_RESOURCE_DESCRIPTOR"; + case REG_RESOURCE_REQUIREMENTS_LIST: + return "REG_RESOURCE_REQUIREMENTS_LIST"; + case REG_QWORD: + return "REG_QWORD"; + default: + return "REG_UNKNOWN"; + } +} static void reg_load_start(Reg* reg) { INT64 file_size; + assert(reg); _fseeki64(reg->fp, 0, SEEK_END); file_size = _ftelli64(reg->fp); _fseeki64(reg->fp, 0, SEEK_SET); @@ -81,12 +102,12 @@ static void reg_load_start(Reg* reg) if (file_size < 1) return; - reg->buffer = (char*)malloc(file_size + 2); + reg->buffer = (char*)malloc((size_t)file_size + 2); if (!reg->buffer) return; - if (fread(reg->buffer, file_size, 1, reg->fp) != 1) + if (fread(reg->buffer, (size_t)file_size, 1, reg->fp) != 1) { free(reg->buffer); reg->buffer = NULL; @@ -113,12 +134,16 @@ static void reg_load_finish(Reg* reg) static RegVal* reg_load_value(Reg* reg, RegKey* key) { int index; - char* p[5]; - int length; - char* name; + char* p[5] = { 0 }; + size_t length; + char* name = NULL; char* type; char* data; - RegVal* value; + RegVal* value = NULL; + + assert(reg); + assert(key); + p[0] = reg->line + 1; p[1] = strstr(p[0], "\"="); p[2] = p[1] + 2; @@ -131,65 +156,81 @@ static RegVal* reg_load_value(Reg* reg, RegKey* key) data = p[3] + 1; length = p[1] - p[0]; - name = (char*)malloc(length + 1); + if (length < 1) + goto fail; + + name = (char*)calloc(length + 1, sizeof(char)); if (!name) - return NULL; + goto fail; memcpy(name, p[0], length); - name[length] = '\0'; - value = (RegVal*)malloc(sizeof(RegVal)); + value = (RegVal*)calloc(1, sizeof(RegVal)); if (!value) - { - free(name); - return NULL; - } + goto fail; value->name = name; value->type = REG_NONE; value->next = value->prev = NULL; - for (index = 0; REG_DATA_TYPE_TABLE[index].length > 0; index++) + for (index = 0; index < ARRAYSIZE(REG_DATA_TYPE_TABLE); index++) { - if (strncmp(type, REG_DATA_TYPE_TABLE[index].tag, REG_DATA_TYPE_TABLE[index].length) == 0) + const struct reg_data_type* current = ®_DATA_TYPE_TABLE[index]; + assert(current->tag); + assert(current->length > 0); + assert(current->type != REG_NONE); + + if (strncmp(type, current->tag, current->length) == 0) { - value->type = REG_DATA_TYPE_TABLE[index].type; + value->type = current->type; break; } } - if (value->type == REG_DWORD) + switch (value->type) { - unsigned long val; - errno = 0; - val = strtoul(data, NULL, 16); - - if ((errno != 0) || (val > UINT32_MAX)) + case REG_DWORD: { - free(value); - free(name); - return NULL; - } + unsigned long val; + errno = 0; + val = strtoul(data, NULL, 16); - value->data.dword = val; - } - else if (value->type == REG_SZ) - { - p[4] = strchr(data, '"'); - p[4][0] = '\0'; - value->data.string = _strdup(data); + if ((errno != 0) || (val > UINT32_MAX)) + goto fail; - if (!value->data.string) + value->data.dword = (DWORD)val; + } + break; + case REG_SZ: { - free(value); - free(name); - return NULL; + size_t len, cmp; + char* end; + char* start = strchr(data, '"'); + if (!start) + goto fail; + + /* Check for terminating quote, check it is the last symbol */ + len = strlen(start); + end = strchr(start + 1, '"'); + if (!end) + goto fail; + cmp = end - start + 1; + if (len != cmp) + goto fail; + if (start[0] == '"') + start++; + if (end[0] == '"') + end[0] = '\0'; + value->data.string = _strdup(start); + + if (!value->data.string) + goto fail; } - } - else - { - WLog_ERR(TAG, "unimplemented format: %s", REG_DATA_TYPE_STRINGS[value->type]); + break; + default: + WLog_ERR(TAG, "unimplemented format: %s", reg_data_type_string(value->type)); + break; } if (!key->values) @@ -210,6 +251,11 @@ static RegVal* reg_load_value(Reg* reg, RegKey* key) } return value; + +fail: + free(value); + free(name); + return NULL; } static BOOL reg_load_has_next_line(Reg* reg) @@ -233,6 +279,7 @@ static char* reg_load_get_next_line(Reg* reg) static char* reg_load_peek_next_line(Reg* reg) { + assert(reg); return reg->next_line; } @@ -241,7 +288,10 @@ static void reg_insert_key(Reg* reg, RegKey* key, RegKey* subkey) char* name; char* path; char* save; - int length; + size_t length; + assert(reg); + assert(key); + assert(subkey); path = _strdup(subkey->name); if (!path) @@ -277,6 +327,8 @@ static RegKey* reg_load_key(Reg* reg, RegKey* key) int length; char* line; RegKey* subkey; + assert(reg); + assert(key); p[0] = reg->line + 1; p[1] = strrchr(p[0], ']'); subkey = (RegKey*)malloc(sizeof(RegKey)); @@ -354,6 +406,8 @@ static void reg_load(Reg* reg) static void reg_unload_value(Reg* reg, RegVal* value) { + assert(reg); + assert(value); if (value->type == REG_DWORD) { } @@ -363,7 +417,7 @@ static void reg_unload_value(Reg* reg, RegVal* value) } else { - WLog_ERR(TAG, "unimplemented format: %s", REG_DATA_TYPE_STRINGS[value->type]); + WLog_ERR(TAG, "unimplemented format: %s", reg_data_type_string(value->type)); } free(value); @@ -373,6 +427,8 @@ static void reg_unload_key(Reg* reg, RegKey* key) { RegVal* pValue; RegVal* pValueNext; + assert(reg); + assert(key); pValue = key->values; while (pValue != NULL) @@ -390,6 +446,7 @@ static void reg_unload(Reg* reg) { RegKey* pKey; RegKey* pKeyNext; + assert(reg); pKey = reg->root_key->subkeys; while (pKey != NULL) From 84efc70a18c8e8e8ec0c0574b2995c003fe6359c Mon Sep 17 00:00:00 2001 From: akallabeth Date: Wed, 22 Dec 2021 10:51:50 +0100 Subject: [PATCH 025/496] Fixed const warning in opensl es backend (cherry picked from commit b5d85696f6b9c4702b2cdb9106c33851093c840e) --- channels/audin/client/opensles/audin_opensl_es.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/channels/audin/client/opensles/audin_opensl_es.c b/channels/audin/client/opensles/audin_opensl_es.c index 4e3efdeb2f97..87393ad36397 100644 --- a/channels/audin/client/opensles/audin_opensl_es.c +++ b/channels/audin/client/opensles/audin_opensl_es.c @@ -248,7 +248,7 @@ static UINT audin_opensles_parse_addin_args(AudinOpenSLESDevice* device, ADDIN_A { UINT status; DWORD flags; - COMMAND_LINE_ARGUMENT_A* arg; + const COMMAND_LINE_ARGUMENT_A* arg; AudinOpenSLESDevice* opensles = (AudinOpenSLESDevice*)device; COMMAND_LINE_ARGUMENT_A audin_opensles_args[] = { { "dev", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, From bbeb3e08eb8b17d5e416f2d68604c2fc55871bdd Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Wed, 2 Jun 2021 16:51:49 +0200 Subject: [PATCH 026/496] Added adjustable tcp connect timeout (cherry picked from commit 2a91afb0cf1be3ad765da11329ed0e5333da0bdc) --- include/freerdp/settings.h | 33 ++++++++++--------- libfreerdp/common/settings_getters.c | 7 ++++ libfreerdp/common/settings_str.c | 1 + libfreerdp/core/nego.c | 14 +++++--- libfreerdp/core/settings.c | 12 ++++--- libfreerdp/core/tcp.c | 6 ++-- .../core/test/settings_property_lists.h | 1 + 7 files changed, 46 insertions(+), 28 deletions(-) diff --git a/include/freerdp/settings.h b/include/freerdp/settings.h index 26adb624e292..3b7a13896c36 100644 --- a/include/freerdp/settings.h +++ b/include/freerdp/settings.h @@ -894,6 +894,7 @@ typedef struct _RDPDR_PARALLEL RDPDR_PARALLEL; #define FreeRDP_TcpKeepAliveDelay (5192) #define FreeRDP_TcpKeepAliveInterval (5193) #define FreeRDP_TcpAckTimeout (5194) +#define FreeRDP_TcpConnectTimeout (5197) /** * FreeRDP Settings Data Structure @@ -1342,20 +1343,20 @@ struct rdp_settings /* Input Capabilities */ ALIGN64 char* KeyboardRemappingList; /* 2622 */ - ALIGN64 UINT32 KeyboardCodePage; /* 2623 */ - ALIGN64 UINT32 KeyboardLayout; /* 2624 */ - ALIGN64 UINT32 KeyboardType; /* 2625 */ - ALIGN64 UINT32 KeyboardSubType; /* 2626 */ - ALIGN64 UINT32 KeyboardFunctionKey; /* 2627 */ - ALIGN64 char* ImeFileName; /* 2628 */ - ALIGN64 BOOL UnicodeInput; /* 2629 */ - ALIGN64 BOOL FastPathInput; /* 2630 */ - ALIGN64 BOOL MultiTouchInput; /* 2631 */ - ALIGN64 BOOL MultiTouchGestures; /* 2632 */ - ALIGN64 UINT32 KeyboardHook; /* 2633 */ - ALIGN64 BOOL HasHorizontalWheel; /* 2634 */ - ALIGN64 BOOL HasExtendedMouseEvent; /* 2635 */ - UINT64 padding2688[2688 - 2636]; /* 2636 */ + ALIGN64 UINT32 KeyboardCodePage; /* 2623 */ + ALIGN64 UINT32 KeyboardLayout; /* 2624 */ + ALIGN64 UINT32 KeyboardType; /* 2625 */ + ALIGN64 UINT32 KeyboardSubType; /* 2626 */ + ALIGN64 UINT32 KeyboardFunctionKey; /* 2627 */ + ALIGN64 char* ImeFileName; /* 2628 */ + ALIGN64 BOOL UnicodeInput; /* 2629 */ + ALIGN64 BOOL FastPathInput; /* 2630 */ + ALIGN64 BOOL MultiTouchInput; /* 2631 */ + ALIGN64 BOOL MultiTouchGestures; /* 2632 */ + ALIGN64 UINT32 KeyboardHook; /* 2633 */ + ALIGN64 BOOL HasHorizontalWheel; /* 2634 */ + ALIGN64 BOOL HasExtendedMouseEvent; /* 2635 */ + UINT64 padding2688[2688 - 2636]; /* 2636 */ /* Brush Capabilities */ ALIGN64 UINT32 BrushSupportLevel; /* 2688 */ @@ -1545,7 +1546,9 @@ struct rdp_settings ALIGN64 UINT32 TcpKeepAliveDelay; /* 5192 */ ALIGN64 UINT32 TcpKeepAliveInterval; /* 5193 */ ALIGN64 UINT32 TcpAckTimeout; /* 5194 */ - UINT64 padding5312[5312 - 5195]; /* 5195 */ + UINT64 padding5197[5197 - 5195]; /* 5195 */ + ALIGN64 UINT32 TcpConnectTimeout; /* 5197 */ + UINT64 padding5312[5312 - 5198]; /* 5198 */ /** * WARNING: End of ABI stable zone! diff --git a/libfreerdp/common/settings_getters.c b/libfreerdp/common/settings_getters.c index 2a34bb80fca9..a3ce8e9611e5 100644 --- a/libfreerdp/common/settings_getters.c +++ b/libfreerdp/common/settings_getters.c @@ -1570,6 +1570,9 @@ UINT32 freerdp_settings_get_uint32(const rdpSettings* settings, size_t id) case FreeRDP_TcpAckTimeout: return settings->TcpAckTimeout; + case FreeRDP_TcpConnectTimeout: + return settings->TcpConnectTimeout; + case FreeRDP_TcpKeepAliveDelay: return settings->TcpKeepAliveDelay; @@ -2021,6 +2024,10 @@ BOOL freerdp_settings_set_uint32(rdpSettings* settings, size_t id, UINT32 val) settings->TcpAckTimeout = val; break; + case FreeRDP_TcpConnectTimeout: + settings->TcpConnectTimeout = val; + break; + case FreeRDP_TcpKeepAliveDelay: settings->TcpKeepAliveDelay = val; break; diff --git a/libfreerdp/common/settings_str.c b/libfreerdp/common/settings_str.c index b7b8def722e9..9a545f25d2d0 100644 --- a/libfreerdp/common/settings_str.c +++ b/libfreerdp/common/settings_str.c @@ -285,6 +285,7 @@ static const struct settings_str_entry settings_map[] = { { FreeRDP_StaticChannelCount, 3, "FreeRDP_StaticChannelCount" }, { FreeRDP_TargetNetAddressCount, 3, "FreeRDP_TargetNetAddressCount" }, { FreeRDP_TcpAckTimeout, 3, "FreeRDP_TcpAckTimeout" }, + { FreeRDP_TcpConnectTimeout, 3, "FreeRDP_TcpConnectTimeout" }, { FreeRDP_TcpKeepAliveDelay, 3, "FreeRDP_TcpKeepAliveDelay" }, { FreeRDP_TcpKeepAliveInterval, 3, "FreeRDP_TcpKeepAliveInterval" }, { FreeRDP_TcpKeepAliveRetries, 3, "FreeRDP_TcpKeepAliveRetries" }, diff --git a/libfreerdp/core/nego.c b/libfreerdp/core/nego.c index 8357ff9abe53..ac4e93f7c6ab 100644 --- a/libfreerdp/core/nego.c +++ b/libfreerdp/core/nego.c @@ -277,6 +277,9 @@ static BOOL nego_tcp_connect(rdpNego* nego) { if (!nego->TcpConnected) { + const UINT32 TcpConnectTimeout = freerdp_settings_get_uint32( + nego->transport->context->settings, FreeRDP_TcpConnectTimeout); + if (nego->GatewayEnabled) { if (nego->GatewayBypassLocal) @@ -286,20 +289,21 @@ static BOOL nego_tcp_connect(rdpNego* nego) "Detecting if host can be reached locally. - This might take some time."); WLog_INFO(TAG, "To disable auto detection use /gateway-usage-method:direct"); transport_set_gateway_enabled(nego->transport, FALSE); - nego->TcpConnected = - transport_connect(nego->transport, nego->hostname, nego->port, 1); + nego->TcpConnected = transport_connect(nego->transport, nego->hostname, nego->port, + TcpConnectTimeout); } if (!nego->TcpConnected) { transport_set_gateway_enabled(nego->transport, TRUE); - nego->TcpConnected = - transport_connect(nego->transport, nego->hostname, nego->port, 15); + nego->TcpConnected = transport_connect(nego->transport, nego->hostname, nego->port, + TcpConnectTimeout); } } else { - nego->TcpConnected = transport_connect(nego->transport, nego->hostname, nego->port, 15); + nego->TcpConnected = + transport_connect(nego->transport, nego->hostname, nego->port, TcpConnectTimeout); } } diff --git a/libfreerdp/core/settings.c b/libfreerdp/core/settings.c index eb425dd958cd..d0c2b56f3303 100644 --- a/libfreerdp/core/settings.c +++ b/libfreerdp/core/settings.c @@ -547,11 +547,13 @@ rdpSettings* freerdp_settings_new(DWORD flags) if (!settings->DynamicChannelArray) goto out_fail; - settings->TcpKeepAlive = TRUE; - settings->TcpKeepAliveRetries = 3; - settings->TcpKeepAliveDelay = 5; - settings->TcpKeepAliveInterval = 2; - settings->TcpAckTimeout = 9000; + if (!freerdp_settings_set_bool(settings, FreeRDP_TcpKeepAlive, TRUE) || + !freerdp_settings_set_uint32(settings, FreeRDP_TcpKeepAliveRetries, 3) || + !freerdp_settings_set_uint32(settings, FreeRDP_TcpKeepAliveDelay, 5) || + !freerdp_settings_set_uint32(settings, FreeRDP_TcpKeepAliveInterval, 2) || + !freerdp_settings_set_uint32(settings, FreeRDP_TcpAckTimeout, 9000) || + !freerdp_settings_set_uint32(settings, FreeRDP_TcpConnectTimeout, 15000)) + goto out_fail; if (!settings->ServerMode) { diff --git a/libfreerdp/core/tcp.c b/libfreerdp/core/tcp.c index ef5f7b1939f3..60b4211b59cb 100644 --- a/libfreerdp/core/tcp.c +++ b/libfreerdp/core/tcp.c @@ -801,14 +801,14 @@ static BOOL freerdp_tcp_is_hostname_resolvable(rdpContext* context, const char* } static BOOL freerdp_tcp_connect_timeout(rdpContext* context, int sockfd, struct sockaddr* addr, - socklen_t addrlen, int timeout) + socklen_t addrlen, UINT32 timeout) { BOOL rc = FALSE; HANDLE handles[2]; int status = 0; int count = 0; u_long arg = 0; - DWORD tout = (timeout > 0) ? (DWORD)timeout * 1000U : INFINITE; + DWORD tout = (timeout > 0) ? timeout : INFINITE; handles[count] = CreateEvent(NULL, TRUE, FALSE, NULL); @@ -894,7 +894,7 @@ static void peer_free(t_peer* peer) } static int freerdp_tcp_connect_multi(rdpContext* context, char** hostnames, UINT32* ports, - UINT32 count, int port, int timeout) + UINT32 count, UINT16 port, UINT32 timeout) { UINT32 index; UINT32 sindex = count; diff --git a/libfreerdp/core/test/settings_property_lists.h b/libfreerdp/core/test/settings_property_lists.h index ff35a7ec8801..db8e5ed8e290 100644 --- a/libfreerdp/core/test/settings_property_lists.h +++ b/libfreerdp/core/test/settings_property_lists.h @@ -282,6 +282,7 @@ static const size_t uint32_list_indices[] = { FreeRDP_StaticChannelCount, FreeRDP_TargetNetAddressCount, FreeRDP_TcpAckTimeout, + FreeRDP_TcpConnectTimeout, FreeRDP_TcpKeepAliveDelay, FreeRDP_TcpKeepAliveInterval, FreeRDP_TcpKeepAliveRetries, From 4fb46521171782751caa05fbab906384b679567a Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Mon, 10 Jan 2022 12:22:18 +0100 Subject: [PATCH 027/496] Fixed #7529: Adjust windows client update area When scrollbars are used, the update area needs to be adjusted. (cherry picked from commit be5ace11232b279382bdc741576642b3c678a830) --- client/Windows/wf_client.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/client/Windows/wf_client.c b/client/Windows/wf_client.c index f61f0c8d2517..5ee059402c14 100644 --- a/client/Windows/wf_client.c +++ b/client/Windows/wf_client.c @@ -118,6 +118,18 @@ static BOOL wf_end_paint(rdpContext* context) updateRect.top = extents->top; updateRect.right = extents->right; updateRect.bottom = extents->bottom; + + if (wfc->xScrollVisible) + { + updateRect.left -= MIN(updateRect.left, wfc->xCurrentScroll); + updateRect.right -= MIN(updateRect.right, wfc->xCurrentScroll); + } + if (wfc->yScrollVisible) + { + updateRect.top -= MIN(updateRect.top, wfc->yCurrentScroll); + updateRect.bottom -= MIN(updateRect.bottom, wfc->yCurrentScroll); + } + InvalidateRect(wfc->hwnd, &updateRect, FALSE); if (wfc->rail) From 365e615c86f247aaec4b70e0bb3a71d30a0e1d40 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Mon, 10 Jan 2022 15:33:39 +0100 Subject: [PATCH 028/496] Harden registry function emulation (cherry picked from commit bc61badf4c06c147b1dbe0c87a6c884496734057) --- winpr/libwinpr/registry/registry.c | 15 ++- winpr/libwinpr/registry/registry_reg.c | 149 ++++++++++++++----------- winpr/libwinpr/registry/registry_reg.h | 5 +- 3 files changed, 93 insertions(+), 76 deletions(-) diff --git a/winpr/libwinpr/registry/registry.c b/winpr/libwinpr/registry/registry.c index b2b04d3b3602..b91b75271792 100644 --- a/winpr/libwinpr/registry/registry.c +++ b/winpr/libwinpr/registry/registry.c @@ -42,12 +42,10 @@ static Reg* instance = NULL; -static Reg* RegGetInstance() +static Reg* RegGetInstance(void) { if (!instance) - { instance = reg_open(1); - } return instance; } @@ -215,18 +213,23 @@ LONG RegOpenKeyExW(HKEY hKey, LPCWSTR lpSubKey, DWORD ulOptions, REGSAM samDesir LONG RegOpenKeyExA(HKEY hKey, LPCSTR lpSubKey, DWORD ulOptions, REGSAM samDesired, PHKEY phkResult) { - Reg* reg; RegKey* pKey; - reg = RegGetInstance(); + Reg* reg = RegGetInstance(); if (!reg) return -1; + if (hKey != HKEY_LOCAL_MACHINE) + return ERROR_FILE_NOT_FOUND; + + WINPR_ASSERT(reg->root_key); pKey = reg->root_key->subkeys; while (pKey != NULL) { - if (_stricmp(pKey->subname, lpSubKey) == 0) + WINPR_ASSERT(lpSubKey); + + if (pKey->subname && (_stricmp(pKey->subname, lpSubKey) == 0)) { *phkResult = (HKEY)pKey; return ERROR_SUCCESS; diff --git a/winpr/libwinpr/registry/registry_reg.c b/winpr/libwinpr/registry/registry_reg.c index 2f92b61dec63..f1f86e9a3360 100644 --- a/winpr/libwinpr/registry/registry_reg.c +++ b/winpr/libwinpr/registry/registry_reg.c @@ -36,12 +36,14 @@ #include "../log.h" #define TAG WINPR_TAG("registry") +#define WINPR_ASSERT assert + #define WINPR_HKLM_HIVE "/etc/winpr/HKLM.reg" struct reg_data_type { char* tag; - int length; + size_t length; DWORD type; }; @@ -88,35 +90,36 @@ static char* reg_data_type_string(DWORD type) } } -static void reg_load_start(Reg* reg) +static BOOL reg_load_start(Reg* reg) { + char* buffer; INT64 file_size; - assert(reg); + + WINPR_ASSERT(reg); + WINPR_ASSERT(reg->fp); + _fseeki64(reg->fp, 0, SEEK_END); file_size = _ftelli64(reg->fp); _fseeki64(reg->fp, 0, SEEK_SET); reg->line = NULL; reg->next_line = NULL; - reg->buffer = NULL; if (file_size < 1) - return; + return FALSE; - reg->buffer = (char*)malloc((size_t)file_size + 2); + buffer = (char*)realloc(reg->buffer, (size_t)file_size + 2); - if (!reg->buffer) - return; + if (!buffer) + return FALSE; + reg->buffer = buffer; if (fread(reg->buffer, (size_t)file_size, 1, reg->fp) != 1) - { - free(reg->buffer); - reg->buffer = NULL; - return; - } + return FALSE; reg->buffer[file_size] = '\n'; reg->buffer[file_size + 1] = '\0'; reg->next_line = strtok(reg->buffer, "\n"); + return TRUE; } static void reg_load_finish(Reg* reg) @@ -133,7 +136,7 @@ static void reg_load_finish(Reg* reg) static RegVal* reg_load_value(Reg* reg, RegKey* key) { - int index; + size_t index; char* p[5] = { 0 }; size_t length; char* name = NULL; @@ -141,11 +144,15 @@ static RegVal* reg_load_value(Reg* reg, RegKey* key) char* data; RegVal* value = NULL; - assert(reg); - assert(key); + WINPR_ASSERT(reg); + WINPR_ASSERT(key); + WINPR_ASSERT(reg->line); p[0] = reg->line + 1; p[1] = strstr(p[0], "\"="); + if (!p[1]) + return NULL; + p[2] = p[1] + 2; type = p[2]; @@ -154,8 +161,11 @@ static RegVal* reg_load_value(Reg* reg, RegKey* key) else p[3] = strchr(p[2], ':'); + if (!p[3]) + return NULL; + data = p[3] + 1; - length = p[1] - p[0]; + length = (size_t)(p[1] - p[0]); if (length < 1) goto fail; @@ -172,14 +182,13 @@ static RegVal* reg_load_value(Reg* reg, RegKey* key) value->name = name; value->type = REG_NONE; - value->next = value->prev = NULL; for (index = 0; index < ARRAYSIZE(REG_DATA_TYPE_TABLE); index++) { const struct reg_data_type* current = ®_DATA_TYPE_TABLE[index]; - assert(current->tag); - assert(current->length > 0); - assert(current->type != REG_NONE); + WINPR_ASSERT(current->tag); + WINPR_ASSERT(current->length > 0); + WINPR_ASSERT(current->type != REG_NONE); if (strncmp(type, current->tag, current->length) == 0) { @@ -279,7 +288,7 @@ static char* reg_load_get_next_line(Reg* reg) static char* reg_load_peek_next_line(Reg* reg) { - assert(reg); + WINPR_ASSERT(reg); return reg->next_line; } @@ -288,10 +297,12 @@ static void reg_insert_key(Reg* reg, RegKey* key, RegKey* subkey) char* name; char* path; char* save; - size_t length; - assert(reg); - assert(key); - assert(subkey); + + WINPR_ASSERT(reg); + WINPR_ASSERT(key); + WINPR_ASSERT(subkey); + WINPR_ASSERT(subkey->name); + path = _strdup(subkey->name); if (!path) @@ -303,7 +314,7 @@ static void reg_insert_key(Reg* reg, RegKey* key, RegKey* subkey) { if (strcmp(key->name, name) == 0) { - length = strlen(name); + size_t length = strlen(name); name += length + 1; subkey->subname = _strdup(name); @@ -324,21 +335,24 @@ static void reg_insert_key(Reg* reg, RegKey* key, RegKey* subkey) static RegKey* reg_load_key(Reg* reg, RegKey* key) { char* p[2]; - int length; - char* line; + size_t length; RegKey* subkey; - assert(reg); - assert(key); + + WINPR_ASSERT(reg); + WINPR_ASSERT(key); + + WINPR_ASSERT(reg->line); p[0] = reg->line + 1; p[1] = strrchr(p[0], ']'); - subkey = (RegKey*)malloc(sizeof(RegKey)); + if (!p[1]) + return NULL; + + subkey = (RegKey*)calloc(1, sizeof(RegKey)); if (!subkey) return NULL; - subkey->values = NULL; - subkey->prev = subkey->next = NULL; - length = p[1] - p[0]; + length = (size_t)(p[1] - p[0]); subkey->name = (char*)malloc(length + 1); if (!subkey->name) @@ -352,7 +366,7 @@ static RegKey* reg_load_key(Reg* reg, RegKey* key) while (reg_load_has_next_line(reg)) { - line = reg_load_peek_next_line(reg); + char* line = reg_load_peek_next_line(reg); if (line[0] == '[') break; @@ -406,18 +420,21 @@ static void reg_load(Reg* reg) static void reg_unload_value(Reg* reg, RegVal* value) { - assert(reg); - assert(value); - if (value->type == REG_DWORD) - { - } - else if (value->type == REG_SZ) - { - free(value->data.string); - } - else + WINPR_ASSERT(reg); + WINPR_ASSERT(value); + + switch (value->type) { - WLog_ERR(TAG, "unimplemented format: %s", reg_data_type_string(value->type)); + case REG_DWORD: + { + } + break; + case REG_SZ: + free(value->data.string); + break; + default: + WLog_ERR(TAG, "unimplemented format: %s", reg_data_type_string(value->type)); + break; } free(value); @@ -426,14 +443,15 @@ static void reg_unload_value(Reg* reg, RegVal* value) static void reg_unload_key(Reg* reg, RegKey* key) { RegVal* pValue; - RegVal* pValueNext; - assert(reg); - assert(key); + + WINPR_ASSERT(reg); + WINPR_ASSERT(key); + pValue = key->values; while (pValue != NULL) { - pValueNext = pValue->next; + RegVal* pValueNext = pValue->next; reg_unload_value(reg, pValue); pValue = pValueNext; } @@ -445,13 +463,14 @@ static void reg_unload_key(Reg* reg, RegKey* key) static void reg_unload(Reg* reg) { RegKey* pKey; - RegKey* pKeyNext; - assert(reg); + + WINPR_ASSERT(reg); + WINPR_ASSERT(reg->root_key); pKey = reg->root_key->subkeys; while (pKey != NULL) { - pKeyNext = pKey->next; + RegKey* pKeyNext = pKey->next; reg_unload_key(reg, pKey); pKey = pKeyNext; } @@ -461,8 +480,7 @@ static void reg_unload(Reg* reg) Reg* reg_open(BOOL read_only) { - Reg* reg; - reg = (Reg*)malloc(sizeof(Reg)); + Reg* reg = (Reg*)calloc(1, sizeof(Reg)); if (!reg) return NULL; @@ -471,9 +489,7 @@ Reg* reg_open(BOOL read_only) reg->filename = WINPR_HKLM_HIVE; if (reg->read_only) - { reg->fp = winpr_fopen(reg->filename, "r"); - } else { reg->fp = winpr_fopen(reg->filename, "r+"); @@ -483,25 +499,22 @@ Reg* reg_open(BOOL read_only) } if (!reg->fp) - { - free(reg); - return NULL; - } + goto fail; - reg->root_key = (RegKey*)malloc(sizeof(RegKey)); + reg->root_key = (RegKey*)calloc(1, sizeof(RegKey)); if (!reg->root_key) - { - fclose(reg->fp); - free(reg); - return NULL; - } + goto fail; reg->root_key->values = NULL; reg->root_key->subkeys = NULL; reg->root_key->name = "HKEY_LOCAL_MACHINE"; reg_load(reg); return reg; + +fail: + reg_close(reg); + return NULL; } void reg_close(Reg* reg) diff --git a/winpr/libwinpr/registry/registry_reg.h b/winpr/libwinpr/registry/registry_reg.h index 90db136b42cc..ab3b34f3b411 100644 --- a/winpr/libwinpr/registry/registry_reg.h +++ b/winpr/libwinpr/registry/registry_reg.h @@ -30,7 +30,7 @@ struct _reg FILE* fp; char* line; char* next_line; - int line_length; + size_t line_length; char* buffer; char* filename; BOOL read_only; @@ -44,7 +44,8 @@ struct _reg_val RegVal* prev; RegVal* next; - union reg_data { + union reg_data + { DWORD dword; char* string; } data; From e3d74098c568aa7a6f55a5a907e5ed97238a7e14 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Mon, 10 Jan 2022 16:02:54 +0100 Subject: [PATCH 029/496] Fixed verbose debug messages in registry (cherry picked from commit 6446b717ad124b775231b00e76c8acaedc95761b) --- winpr/libwinpr/registry/registry_reg.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/winpr/libwinpr/registry/registry_reg.c b/winpr/libwinpr/registry/registry_reg.c index f1f86e9a3360..eb2f608d2c19 100644 --- a/winpr/libwinpr/registry/registry_reg.c +++ b/winpr/libwinpr/registry/registry_reg.c @@ -316,7 +316,8 @@ static void reg_insert_key(Reg* reg, RegKey* key, RegKey* subkey) { size_t length = strlen(name); name += length + 1; - subkey->subname = _strdup(name); + if (name) + subkey->subname = _strdup(name); /* TODO: free allocated memory in error case */ if (!subkey->subname) @@ -425,15 +426,10 @@ static void reg_unload_value(Reg* reg, RegVal* value) switch (value->type) { - case REG_DWORD: - { - } - break; case REG_SZ: free(value->data.string); break; default: - WLog_ERR(TAG, "unimplemented format: %s", reg_data_type_string(value->type)); break; } From 7f57ce1ac0f9d3b18ffadff475b9908be09c05c0 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Mon, 10 Jan 2022 16:09:57 +0100 Subject: [PATCH 030/496] Fixed reg_insert_key (cherry picked from commit a613f9eb05f7786ad53395496f7018d6b2dd8fd5) --- winpr/libwinpr/registry/registry_reg.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/winpr/libwinpr/registry/registry_reg.c b/winpr/libwinpr/registry/registry_reg.c index eb2f608d2c19..264cbb3510ec 100644 --- a/winpr/libwinpr/registry/registry_reg.c +++ b/winpr/libwinpr/registry/registry_reg.c @@ -294,9 +294,9 @@ static char* reg_load_peek_next_line(Reg* reg) static void reg_insert_key(Reg* reg, RegKey* key, RegKey* subkey) { - char* name; - char* path; - char* save; + char* name = NULL; + char* path = NULL; + char* save = NULL; WINPR_ASSERT(reg); WINPR_ASSERT(key); @@ -314,10 +314,8 @@ static void reg_insert_key(Reg* reg, RegKey* key, RegKey* subkey) { if (strcmp(key->name, name) == 0) { - size_t length = strlen(name); - name += length + 1; - if (name) - subkey->subname = _strdup(name); + if (save) + subkey->subname = _strdup(save); /* TODO: free allocated memory in error case */ if (!subkey->subname) From 0d227b5019063abf159ecb22b191859f4417edc6 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Mon, 10 Jan 2022 17:04:49 +0100 Subject: [PATCH 031/496] Fixed reg_unload: ignore empty root_key (cherry picked from commit 327935dfaf1b95de62f6b94704f2adcefacd6b1b) --- winpr/libwinpr/registry/registry_reg.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/winpr/libwinpr/registry/registry_reg.c b/winpr/libwinpr/registry/registry_reg.c index 264cbb3510ec..9fd31a3ccfc9 100644 --- a/winpr/libwinpr/registry/registry_reg.c +++ b/winpr/libwinpr/registry/registry_reg.c @@ -459,17 +459,19 @@ static void reg_unload(Reg* reg) RegKey* pKey; WINPR_ASSERT(reg); - WINPR_ASSERT(reg->root_key); - pKey = reg->root_key->subkeys; - - while (pKey != NULL) + if (reg->root_key) { - RegKey* pKeyNext = pKey->next; - reg_unload_key(reg, pKey); - pKey = pKeyNext; - } + pKey = reg->root_key->subkeys; + + while (pKey != NULL) + { + RegKey* pKeyNext = pKey->next; + reg_unload_key(reg, pKey); + pKey = pKeyNext; + } - free(reg->root_key); + free(reg->root_key); + } } Reg* reg_open(BOOL read_only) From 9a60293cccdc96949c9e0289c2dba8ba78750be4 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Mon, 10 Jan 2022 17:13:24 +0100 Subject: [PATCH 032/496] Fixed reg_close (cherry picked from commit f411eaf47f44d673a8538770d103a793749cecd6) --- winpr/libwinpr/registry/registry_reg.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/winpr/libwinpr/registry/registry_reg.c b/winpr/libwinpr/registry/registry_reg.c index 9fd31a3ccfc9..511d92790705 100644 --- a/winpr/libwinpr/registry/registry_reg.c +++ b/winpr/libwinpr/registry/registry_reg.c @@ -518,7 +518,8 @@ void reg_close(Reg* reg) if (reg) { reg_unload(reg); - fclose(reg->fp); + if (reg->fp) + fclose(reg->fp); free(reg); } } From 56c527dc8043228524d4bf645bf090bfdc8bbbb1 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Tue, 11 Jan 2022 08:09:56 +0100 Subject: [PATCH 033/496] Replaced WINPR_ASSERT with assert for backport. --- winpr/libwinpr/registry/registry.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/winpr/libwinpr/registry/registry.c b/winpr/libwinpr/registry/registry.c index b91b75271792..e0c148b5a61b 100644 --- a/winpr/libwinpr/registry/registry.c +++ b/winpr/libwinpr/registry/registry.c @@ -222,12 +222,12 @@ LONG RegOpenKeyExA(HKEY hKey, LPCSTR lpSubKey, DWORD ulOptions, REGSAM samDesire if (hKey != HKEY_LOCAL_MACHINE) return ERROR_FILE_NOT_FOUND; - WINPR_ASSERT(reg->root_key); + assert(reg->root_key); pKey = reg->root_key->subkeys; while (pKey != NULL) { - WINPR_ASSERT(lpSubKey); + assert(lpSubKey); if (pKey->subname && (_stricmp(pKey->subname, lpSubKey) == 0)) { From 569bee2161c4674f9c554176dad5522cfa0a55e1 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Tue, 11 Jan 2022 08:45:49 +0100 Subject: [PATCH 034/496] Fixed leaks and type mismatches for wayland client (cherry picked from commit 366c893d2af44df61e6303146a106df58515f9b9) --- client/Wayland/wlf_cliprdr.c | 43 +++++++++++++++++++++++++++++++----- client/Wayland/wlfreerdp.c | 9 +++++--- 2 files changed, 43 insertions(+), 9 deletions(-) diff --git a/client/Wayland/wlf_cliprdr.c b/client/Wayland/wlf_cliprdr.c index 0762cfa3deaf..0f0195d7cd52 100644 --- a/client/Wayland/wlf_cliprdr.c +++ b/client/Wayland/wlf_cliprdr.c @@ -80,6 +80,7 @@ struct wlf_clipboard FILE* responseFile; UINT32 responseFormat; const char* responseMime; + CRITICAL_SECTION lock; }; static BOOL wlf_mime_is_text(const char* mime) @@ -275,7 +276,7 @@ BOOL wlf_cliprdr_handle_event(wfClipboard* clipboard, const UwacClipboardEvent* return TRUE; case UWAC_EVENT_CLIPBOARD_OFFER: - WLog_Print(clipboard->log, WLOG_INFO, "client announces mime %s", event->mime); + WLog_Print(clipboard->log, WLOG_DEBUG, "client announces mime %s", event->mime); wlf_cliprdr_add_client_format(clipboard, event->mime); return TRUE; @@ -387,6 +388,8 @@ static void wlf_cliprdr_transfer_data(UwacSeat* seat, void* context, const char* wfClipboard* clipboard = (wfClipboard*)context; size_t x; WINPR_UNUSED(seat); + + EnterCriticalSection(&clipboard->lock); clipboard->responseMime = NULL; for (x = 0; x < ARRAYSIZE(mime_html); x++) @@ -427,6 +430,8 @@ static void wlf_cliprdr_transfer_data(UwacSeat* seat, void* context, const char* if (clipboard->responseMime != NULL) { + if (clipboard->responseFile != NULL) + fclose(clipboard->responseFile); clipboard->responseFile = fdopen(fd, "w"); if (clipboard->responseFile) @@ -436,6 +441,7 @@ static void wlf_cliprdr_transfer_data(UwacSeat* seat, void* context, const char* "failed to open clipboard file descriptor for MIME %s", clipboard->responseMime); } + LeaveCriticalSection(&clipboard->lock); } static void wlf_cliprdr_cancel_data(UwacSeat* seat, void* context) @@ -673,6 +679,8 @@ wlf_cliprdr_server_format_data_response(CliprdrClientContext* context, const WCHAR* wdata = (const WCHAR*)formatDataResponse->requestedFormatData; wfClipboard* clipboard = (wfClipboard*)context->custom; + EnterCriticalSection(&clipboard->lock); + if (size > INT_MAX * sizeof(WCHAR)) return ERROR_INTERNAL_ERROR; @@ -694,10 +702,16 @@ wlf_cliprdr_server_format_data_response(CliprdrClientContext* context, break; } - fwrite(data, 1, size, clipboard->responseFile); - fclose(clipboard->responseFile); + if (clipboard->responseFile) + { + fwrite(data, 1, size, clipboard->responseFile); + fclose(clipboard->responseFile); + clipboard->responseFile = NULL; + } rc = CHANNEL_RC_OK; free(cdata); + + LeaveCriticalSection(&clipboard->lock); return rc; } @@ -829,17 +843,24 @@ static UINT wlf_cliprdr_clipboard_file_range_failure(wClipboardDelegate* delegat wfClipboard* wlf_clipboard_new(wlfContext* wfc) { rdpChannels* channels; - wfClipboard* clipboard; + wfClipboard* clipboard = (wfClipboard*)calloc(1, sizeof(wfClipboard)); - if (!(clipboard = (wfClipboard*)calloc(1, sizeof(wfClipboard)))) - return NULL; + if (!clipboard) + goto fail; + InitializeCriticalSection(&clipboard->lock); clipboard->wfc = wfc; channels = wfc->context.channels; clipboard->log = WLog_Get(TAG); clipboard->channels = channels; clipboard->system = ClipboardCreate(); + if (!clipboard->system) + goto fail; + clipboard->delegate = ClipboardGetDelegate(clipboard->system); + if (!clipboard->delegate) + goto fail; + clipboard->delegate->custom = clipboard; /* TODO: set up a filesystem base path for local URI */ /* clipboard->delegate->basePath = "file:///tmp/foo/bar/gaga"; */ @@ -848,6 +869,10 @@ wfClipboard* wlf_clipboard_new(wlfContext* wfc) clipboard->delegate->ClipboardFileRangeSuccess = wlf_cliprdr_clipboard_file_range_success; clipboard->delegate->ClipboardFileRangeFailure = wlf_cliprdr_clipboard_file_range_failure; return clipboard; + +fail: + wlf_clipboard_free(clipboard); + return NULL; } void wlf_clipboard_free(wfClipboard* clipboard) @@ -858,6 +883,12 @@ void wlf_clipboard_free(wfClipboard* clipboard) wlf_cliprdr_free_server_formats(clipboard); wlf_cliprdr_free_client_formats(clipboard); ClipboardDestroy(clipboard->system); + + EnterCriticalSection(&clipboard->lock); + if (clipboard->responseFile) + fclose(clipboard->responseFile); + LeaveCriticalSection(&clipboard->lock); + DeleteCriticalSection(&clipboard->lock); free(clipboard); } diff --git a/client/Wayland/wlfreerdp.c b/client/Wayland/wlfreerdp.c index aca7342118c8..ac8e772306d3 100644 --- a/client/Wayland/wlfreerdp.c +++ b/client/Wayland/wlfreerdp.c @@ -331,12 +331,15 @@ static BOOL handle_uwac_events(freerdp* instance, UwacDisplay* display) break; case UWAC_EVENT_FRAME_DONE: + { + UwacReturnCode r; EnterCriticalSection(&context->critical); - rc = UwacWindowSubmitBuffer(context->window, false); + r = UwacWindowSubmitBuffer(context->window, false); LeaveCriticalSection(&context->critical); - if (rc != UWAC_SUCCESS) + if (r != UWAC_SUCCESS) return FALSE; - break; + } + break; case UWAC_EVENT_POINTER_ENTER: if (!wlf_handle_pointer_enter(instance, &event.mouse_enter_leave)) From 2b34d6290ae5832cf1f608a292d32c994446e3f2 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Wed, 12 Jan 2022 09:27:24 +0100 Subject: [PATCH 035/496] API: Move offsetOrders to end of struct rdp_update: It is not officially part of the stable API zone, but just be sure nothing breaks --- include/freerdp/update.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/freerdp/update.h b/include/freerdp/update.h index ec5336a26069..71cb15580e72 100644 --- a/include/freerdp/update.h +++ b/include/freerdp/update.h @@ -254,7 +254,6 @@ struct rdp_update wStream* us; UINT16 numberOrders; - size_t offsetOrders; /* the offset to patch numberOrders in the stream */ BOOL combineUpdates; rdpBounds currentBounds; rdpBounds previousBounds; @@ -264,6 +263,7 @@ struct rdp_update * fills BITMAP_DATA struct members: flags, cbCompMainBodySize and cbCompFirstRowSize. */ BOOL autoCalculateBitmapData; + size_t offsetOrders; /* the offset to patch numberOrders in the stream */ }; #endif /* FREERDP_UPDATE_H */ From fd4876a087d63cf2b7adcb8d100bf2ab08fd4cc7 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Mon, 10 Jan 2022 12:08:45 +0100 Subject: [PATCH 036/496] Updated changelog --- CMakeLists.txt | 2 +- ChangeLog | 10 ++++++++-- client/Android/Studio/build.gradle | 2 +- client/Android/android_freerdp.c | 2 +- winpr/CMakeLists.txt | 2 +- 5 files changed, 12 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a0687025ae42..22c0347c4f05 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -85,7 +85,7 @@ if ($ENV{BUILD_NUMBER}) endif() set(WITH_LIBRARY_VERSIONING "ON") -set(RAW_VERSION_STRING "2.4.1") +set(RAW_VERSION_STRING "2.5.0") if(EXISTS "${CMAKE_SOURCE_DIR}/.source_tag") file(READ ${CMAKE_SOURCE_DIR}/.source_tag RAW_VERSION_STRING) elseif(USE_VERSION_FROM_GIT_TAG) diff --git a/ChangeLog b/ChangeLog index 146e00bf771a..bf4e50034e10 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,18 +1,24 @@ -# 20xx-xx-xx Version 2.x.x +# 2022-01-12 Version 2.5.0 Noteworthy changes: * Fixed smartcard login in case a redirection occurs the pin was lost +* Backported windows client drawing fixes +* Backported improved macOS keyboard layout detection +* Backported TcpConnectTimeout * Backported LibreSSL compatibility patches * Backported signal handler backtrace * Backported OpenSSL 3.0 support Fixed issues: +* Backport #7539: Wayland client clipboard issues +* Backport #7509: Various fixes regarding registry emulation, addin loader + and updated locale detection * Backport #7466: Android android_register_pointer missing initialization Important notes: For a complete and detailed change log since the last release run: -git log 2.4.1..2.x.x +git log 2.4.1..2.5.0 # 2021-10-20 Version 2.4.1 diff --git a/client/Android/Studio/build.gradle b/client/Android/Studio/build.gradle index 2d0abd32d725..cb52a54d923f 100644 --- a/client/Android/Studio/build.gradle +++ b/client/Android/Studio/build.gradle @@ -29,7 +29,7 @@ def getVersionName = { -> ext { versionName = properties.get('VERSION_NAME', getVersionName()) - versionCode = properties.get('VERSION_CODE', 25) + versionCode = properties.get('VERSION_CODE', 26) compileApi = properties.get('COMPILE_API', 30) targetApi = properties.get('TARGET_API', 30) minApi = properties.get('MIN_API', 21) diff --git a/client/Android/android_freerdp.c b/client/Android/android_freerdp.c index 78205c7519c0..2cdc020c2f67 100644 --- a/client/Android/android_freerdp.c +++ b/client/Android/android_freerdp.c @@ -56,7 +56,7 @@ #define TAG CLIENT_TAG("android") /* Defines the JNI version supported by this library. */ -#define FREERDP_JNI_VERSION "2.4.1" +#define FREERDP_JNI_VERSION "2.5.0" static void android_OnChannelConnectedEventHandler(void* context, ChannelConnectedEventArgs* e) { diff --git a/winpr/CMakeLists.txt b/winpr/CMakeLists.txt index 036b50f83325..620f9a78b161 100644 --- a/winpr/CMakeLists.txt +++ b/winpr/CMakeLists.txt @@ -51,7 +51,7 @@ if (NOT WIN32) endif() # Soname versioning -set(RAW_VERSION_STRING "2.4.1") +set(RAW_VERSION_STRING "2.5.0") if(EXISTS "${CMAKE_SOURCE_DIR}/.source_tag") file(READ ${CMAKE_SOURCE_DIR}/.source_tag RAW_VERSION_STRING) elseif(USE_VERSION_FROM_GIT_TAG) From 8cb12fb0ea613f39b1123f64a04b6fb2a5851605 Mon Sep 17 00:00:00 2001 From: Christian Plattner Date: Wed, 12 Jan 2022 13:39:24 +0100 Subject: [PATCH 037/496] Reject invalid android build configuration Without this patch, the default build configuration will be picked silently and continuous integration does not detect any problem --- scripts/android-build-common.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/android-build-common.sh b/scripts/android-build-common.sh index 11fda6765ff4..05ef16af4ea7 100644 --- a/scripts/android-build-common.sh +++ b/scripts/android-build-common.sh @@ -83,7 +83,7 @@ function common_parse_arguments { key="$1" case $key in --conf) - source "$2" + source "$2" || exit 1 shift ;; From 84dd5910d86145ae9c5d872cc8127274b5fc8da4 Mon Sep 17 00:00:00 2001 From: Ely Ronnen Date: Sat, 4 Dec 2021 20:33:10 +0200 Subject: [PATCH 038/496] add ffmpeg option to android build script (cherry picked from commit cdb7563cf7749b30ecb6129981279ad79d7264cb) --- CMakeLists.txt | 1 - scripts/android-build-freerdp.sh | 18 ++++++++++++++++++ scripts/android-build-release.conf | 1 + 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 22c0347c4f05..2e3d30217307 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -808,7 +808,6 @@ if(ANDROID) set(PULSE_FEATURE_TYPE "DISABLED") set(CUPS_FEATURE_TYPE "DISABLED") set(PCSC_FEATURE_TYPE "DISABLED") - set(FFMPEG_FEATURE_TYPE "DISABLED") set(VAAPI_FEATURE_TYPE "DISABLED") set(OPENSLES_FEATURE_TYPE "REQUIRED") endif() diff --git a/scripts/android-build-freerdp.sh b/scripts/android-build-freerdp.sh index 40f26f2f2af7..0f2189d11a06 100755 --- a/scripts/android-build-freerdp.sh +++ b/scripts/android-build-freerdp.sh @@ -7,6 +7,7 @@ OPENSSL_TAG=master WITH_JPEG=0 WITH_OPENH264=0 WITH_OPENSSL=0 +WITH_FFMPEG=0 SRC_DIR=$(dirname "${BASH_SOURCE[0]}") SRC_DIR=$(realpath "$SRC_DIR") @@ -43,6 +44,14 @@ do ANDROID_NDK_OPENH264=$1 shift ;; + --ffmpeg) + WITH_FFMPEG=1 + shift + ;; + --ffmpeg-path) + FFMPEG_PATH="$2" + shift + ;; --openssl) WITH_OPENSSL=1 shift @@ -133,6 +142,15 @@ do CMAKE_CMD_ARGS="$CMAKE_CMD_ARGS -DWITH_OPENH264=ON" else CMAKE_CMD_ARGS="$CMAKE_CMD_ARGS -DWITH_OPENH264=OFF" + fi + if [ $WITH_FFMPEG -ne 0 ]; + then + CMAKE_CMD_ARGS="$CMAKE_CMD_ARGS -DWITH_FFMPEG=ON" + CMAKE_CMD_ARGS="$CMAKE_CMD_ARGS -DAVCODEC_INCLUDE_DIRS=$FFMPEG_PATH/$ARCH/include -DAVCODEC_LIBRARY_DIRS=$FFMPEG_PATH/$ARCH/lib" + CMAKE_CMD_ARGS="$CMAKE_CMD_ARGS -DAVUTIL_INCLUDE_DIRS=$FFMPEG_PATH/$ARCH/include -DAVUTIL_LIBRARY_DIRS=$FFMPEG_PATH/$ARCH/lib" + CMAKE_CMD_ARGS="$CMAKE_CMD_ARGS -DSWRESAMPLE_INCLUDE_DIRS=$FFMPEG_PATH/$ARCH/include -DSWRESAMPLE_LIBRARY_DIRS=$FFMPEG_PATH/$ARCH/lib" + else + CMAKE_CMD_ARGS="$CMAKE_CMD_ARGS -DWITH_FFMPEG=OFF" fi if [ $WITH_OPENSSL -ne 0 ]; then diff --git a/scripts/android-build-release.conf b/scripts/android-build-release.conf index 51ca44df9324..0009ed3058f9 100644 --- a/scripts/android-build-release.conf +++ b/scripts/android-build-release.conf @@ -10,6 +10,7 @@ # create seperate configurations for each NDK API level # and architecture you want to support. WITH_JPEG=0 +WITH_FFMPEG=0 WITH_OPENH264=1 WITH_OPENSSL=1 BUILD_DEPS=1 From 146717ee3c283d1e17afd3e992a0d06cab88c87e Mon Sep 17 00:00:00 2001 From: Ely Ronnen Date: Mon, 20 Dec 2021 17:59:18 +0200 Subject: [PATCH 039/496] adding ffmpeg build script (cherry picked from commit 450aa65227033ab21f12ec10bfaed2b2e7702057) --- scripts/android-build-ffmpeg.sh | 178 +++++++++++++++++++++++++++++++ scripts/android-build-freerdp.sh | 18 ++-- 2 files changed, 189 insertions(+), 7 deletions(-) create mode 100755 scripts/android-build-ffmpeg.sh diff --git a/scripts/android-build-ffmpeg.sh b/scripts/android-build-ffmpeg.sh new file mode 100755 index 000000000000..3e40582ceb41 --- /dev/null +++ b/scripts/android-build-ffmpeg.sh @@ -0,0 +1,178 @@ +#!/bin/bash + +SCM_URL=https://github.com/FFmpeg/FFmpeg +SCM_TAG=n4.4.1 + +OLD_PATH=$PATH + +source $(dirname "${BASH_SOURCE[0]}")/android-build-common.sh + +function get_toolchain() { + HOST_OS=$(uname -s) + case ${HOST_OS} in + Darwin) HOST_OS=darwin;; + Linux) HOST_OS=linux;; + FreeBsd) HOST_OS=freebsd;; + CYGWIN*|*_NT-*) HOST_OS=cygwin;; + esac + + HOST_ARCH=$(uname -m) + case ${HOST_ARCH} in + i?86) HOST_ARCH=x86;; + x86_64|amd64) HOST_ARCH=x86_64;; + esac + + echo "${HOST_OS}-${HOST_ARCH}" +} + +function get_build_host() { + case ${ARCH} in + armeabi-v7a) + echo "arm-linux-androideabi" + ;; + arm64-v8a) + echo "aarch64-linux-android" + ;; + x86) + echo "i686-linux-android" + ;; + x86_64) + echo "x86_64-linux-android" + ;; + esac +} + +function get_clang_target_host() { + case ${ARCH} in + armeabi-v7a) + echo "armv7a-linux-androideabi${NDK_TARGET}" + ;; + arm64-v8a) + echo "aarch64-linux-android${NDK_TARGET}" + ;; + x86) + echo "i686-linux-android${NDK_TARGET}" + ;; + x86_64) + echo "x86_64-linux-android${NDK_TARGET}" + ;; + esac +} + +function get_arch_specific_ldflags() { + case ${ARCH} in + armeabi-v7a) + echo "-march=armv7-a -mfpu=neon -mfloat-abi=softfp -Wl,--fix-cortex-a8" + ;; + arm64-v8a) + echo "-march=armv8-a" + ;; + x86) + echo "-march=i686" + ;; + x86_64) + echo "-march=x86-64" + ;; + esac +} + +function set_toolchain_clang_paths { + TOOLCHAIN=$(get_toolchain) + + common_run export PATH=$PATH:${ANDROID_NDK}/toolchains/llvm/prebuilt/${TOOLCHAIN}/bin + AR=llvm-ar + NM=llvm-nm + RANLIB=llvm-ranlib + STRIP=llvm-strip + CC=$(get_clang_target_host)-clang + CXX=$(get_clang_target_host)-clang++ + + case ${ARCH} in + arm64-v8a) + common_run export ac_cv_c_bigendian=no + ;; + esac +} + +function build { + echo "Building FFmpeg architecture $1..." + BASE=$(pwd) + common_run cd $BUILD_SRC + + BUILD_HOST=$(get_build_host) + set_toolchain_clang_paths + LDFLAGS=$(get_arch_specific_ldflags) + + PATH=$ANDROID_NDK:$PATH + common_run ./configure \ + --cross-prefix="${BUILD_HOST}-" \ + --sysroot="${ANDROID_NDK}/toolchains/llvm/prebuilt/${TOOLCHAIN}/sysroot" \ + --arch="${TARGET_ARCH}" \ + --cpu="${TARGET_CPU}" \ + --cc="${CC}" \ + --cxx="${CXX}" \ + --ar="${AR}" \ + --nm="${NM}" \ + --ranlib="${RANLIB}" \ + --strip="${STRIP}" \ + --extra-ldflags="${LDFLAGS}" \ + --prefix="${BUILD_DST}/${ARCH}" \ + --pkg-config="${HOST_PKG_CONFIG_PATH}" \ + --target-os=android \ + ${ARCH_OPTIONS} \ + --enable-cross-compile \ + --enable-pic \ + --enable-jni --enable-mediacodec \ + --enable-shared \ + --disable-stripping \ + --disable-programs --disable-doc --disable-avdevice --disable-avfilter --disable-avformat --disable-swscale + + common_run make clean + common_run make -j + common_run make install +} + +# Run the main program. +common_parse_arguments $@ +common_check_requirements +common_update $SCM_URL $SCM_TAG $BUILD_SRC + +HOST_PKG_CONFIG_PATH=`command -v pkg-config` +if [ -z ${HOST_PKG_CONFIG_PATH} ]; then + echo "(*) pkg-config command not found\n" + exit 1 +fi + + +for ARCH in $BUILD_ARCH +do + case ${ARCH} in + armeabi-v7a) + TARGET_CPU="armv7-a" + TARGET_ARCH="armv7-a" + ARCH_OPTIONS=" --enable-neon --enable-asm --enable-inline-asm" + ;; + arm64-v8a) + TARGET_CPU="armv8-a" + TARGET_ARCH="aarch64" + ARCH_OPTIONS=" --enable-neon --enable-asm --enable-inline-asm" + ;; + x86) + TARGET_CPU="i686" + TARGET_ARCH="i686" + + # asm disabled due to this ticker https://trac.ffmpeg.org/ticket/4928 + ARCH_OPTIONS=" --disable-neon --disable-asm --disable-inline-asm" + ;; + x86_64) + TARGET_CPU="x86_64" + TARGET_ARCH="x86_64" + ARCH_OPTIONS=" --disable-neon --enable-asm --enable-inline-asm" + ;; + esac + + build + common_run cp -L $BUILD_DST/$ARCH/lib/*.so $BUILD_DST/$ARCH/ + + common_run export PATH=$OLD_PATH +done diff --git a/scripts/android-build-freerdp.sh b/scripts/android-build-freerdp.sh index 0f2189d11a06..a2c85e8ce314 100755 --- a/scripts/android-build-freerdp.sh +++ b/scripts/android-build-freerdp.sh @@ -3,6 +3,7 @@ JPEG_TAG=master OPENH264_TAG=master OPENSSL_TAG=master +FFMPEG_TAG=n4.4.1 WITH_JPEG=0 WITH_OPENH264=0 @@ -48,10 +49,6 @@ do WITH_FFMPEG=1 shift ;; - --ffmpeg-path) - FFMPEG_PATH="$2" - shift - ;; --openssl) WITH_OPENSSL=1 shift @@ -145,10 +142,17 @@ do fi if [ $WITH_FFMPEG -ne 0 ]; then + if [ $BUILD_DEPS -ne 0 ]; + then + common_run bash $SCRIPT_PATH/android-build-ffmpeg.sh \ + --src $BUILD_SRC/ffmpeg --dst $BUILD_DST \ + --sdk "$ANDROID_SDK" \ + --ndk "$ANDROID_NDK" \ + --arch $ARCH \ + --target $NDK_TARGET \ + --tag $FFMPEG_TAG + fi CMAKE_CMD_ARGS="$CMAKE_CMD_ARGS -DWITH_FFMPEG=ON" - CMAKE_CMD_ARGS="$CMAKE_CMD_ARGS -DAVCODEC_INCLUDE_DIRS=$FFMPEG_PATH/$ARCH/include -DAVCODEC_LIBRARY_DIRS=$FFMPEG_PATH/$ARCH/lib" - CMAKE_CMD_ARGS="$CMAKE_CMD_ARGS -DAVUTIL_INCLUDE_DIRS=$FFMPEG_PATH/$ARCH/include -DAVUTIL_LIBRARY_DIRS=$FFMPEG_PATH/$ARCH/lib" - CMAKE_CMD_ARGS="$CMAKE_CMD_ARGS -DSWRESAMPLE_INCLUDE_DIRS=$FFMPEG_PATH/$ARCH/include -DSWRESAMPLE_LIBRARY_DIRS=$FFMPEG_PATH/$ARCH/lib" else CMAKE_CMD_ARGS="$CMAKE_CMD_ARGS -DWITH_FFMPEG=OFF" fi From 53eb0de39f1162703a76b1a1c9de2d9b12939401 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Thu, 13 Jan 2022 08:23:44 +0100 Subject: [PATCH 040/496] Updated android build configuration Use FFMPEG instead of OpenH264 for newer NDK compatibility (cherry picked from commit d07cb696a924c1b149c2c006c9b7cb72bc21d9cc) --- scripts/android-build-32.conf | 6 ++++-- scripts/android-build-64.conf | 2 ++ scripts/android-build-release.conf | 7 ++++--- scripts/android-build.conf | 4 +++- 4 files changed, 13 insertions(+), 6 deletions(-) diff --git a/scripts/android-build-32.conf b/scripts/android-build-32.conf index 4bafb2388ed8..d7be812b41b6 100644 --- a/scripts/android-build-32.conf +++ b/scripts/android-build-32.conf @@ -10,15 +10,17 @@ # create seperate configurations for each NDK API level # and architecture you want to support. WITH_JPEG=0 -WITH_OPENH264=1 +WITH_OPENH264=0 WITH_OPENSSL=1 +WITH_FFMPEG=1 BUILD_DEPS=1 DEPS_ONLY=0 NDK_TARGET=21 JPEG_TAG=master OPENH264_TAG=v1.8.0 # NOTE: NDK r15c or earlier needed in --openh624-ndk for v1.8.0 -OPENSSL_TAG=OpenSSL_1_1_1j +OPENSSL_TAG=OpenSSL_1_1_1m +FFMPEG_TAG=n4.4.1 SRC_DIR=$SCRIPT_PATH/.. BUILD_DST=$SCRIPT_PATH/../client/Android/Studio/freeRDPCore/src/main/jniLibs diff --git a/scripts/android-build-64.conf b/scripts/android-build-64.conf index a3dcf711d434..9cfe26111795 100644 --- a/scripts/android-build-64.conf +++ b/scripts/android-build-64.conf @@ -12,6 +12,7 @@ WITH_JPEG=0 WITH_OPENH264=1 WITH_OPENSSL=1 +WITH_FFMPEG=1 BUILD_DEPS=1 DEPS_ONLY=0 NDK_TARGET=21 @@ -19,6 +20,7 @@ NDK_TARGET=21 JPEG_TAG=master OPENH264_TAG=v1.8.0 # NOTE: NDK r15c or earlier needed in --openh624-ndk for v1.8.0 OPENSSL_TAG=OpenSSL_1_1_1j +FFMPEG_TAG=n4.4.1 SRC_DIR=$SCRIPT_PATH/.. BUILD_DST=$SCRIPT_PATH/../client/Android/Studio/freeRDPCore/src/main/jniLibs diff --git a/scripts/android-build-release.conf b/scripts/android-build-release.conf index 0009ed3058f9..1c8f7a14b093 100644 --- a/scripts/android-build-release.conf +++ b/scripts/android-build-release.conf @@ -10,16 +10,17 @@ # create seperate configurations for each NDK API level # and architecture you want to support. WITH_JPEG=0 -WITH_FFMPEG=0 -WITH_OPENH264=1 +WITH_OPENH264=0 WITH_OPENSSL=1 +WITH_FFMPEG=1 BUILD_DEPS=1 DEPS_ONLY=0 NDK_TARGET=21 JPEG_TAG=master OPENH264_TAG=v1.8.0 # NOTE: NDK r15c or earlier needed in --openh624-ndk for v1.8.0 -OPENSSL_TAG=OpenSSL_1_1_1h +OPENSSL_TAG=OpenSSL_1_1_1m +FFMPEG_TAG=n4.4.1 SRC_DIR=$SCRIPT_PATH/.. BUILD_DST=$SCRIPT_PATH/../client/Android/Studio/freeRDPCore/src/main/jniLibs diff --git a/scripts/android-build.conf b/scripts/android-build.conf index c8eb40c42c06..726449ebc175 100644 --- a/scripts/android-build.conf +++ b/scripts/android-build.conf @@ -12,13 +12,15 @@ WITH_JPEG=0 WITH_OPENH264=0 WITH_OPENSSL=1 +WITH_FFMPEG=1 BUILD_DEPS=1 DEPS_ONLY=0 NDK_TARGET=26 JPEG_TAG=master OPENH264_TAG=v1.8.0 # NOTE: NDK r15c or earlier needed in --openh624-ndk for v1.8.0 -OPENSSL_TAG=OpenSSL_1_1_1j +OPENSSL_TAG=OpenSSL_1_1_1m +FFMPEG_TAG=n4.4.1 SRC_DIR=$SCRIPT_PATH/.. BUILD_DST=$SCRIPT_PATH/../client/Android/Studio/freeRDPCore/src/main/jniLibs From a87c2a28fec4c0f78b04620137ea779dab862def Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Mon, 24 Jan 2022 09:12:02 +0100 Subject: [PATCH 041/496] Fixed missing ffmpeg deprecation guard (cherry picked from commit 3303a2feafd675e89969a4296a47b213389b9d1a) --- libfreerdp/codec/dsp_ffmpeg.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libfreerdp/codec/dsp_ffmpeg.c b/libfreerdp/codec/dsp_ffmpeg.c index 0af3cf4fc61a..6bbfe1454171 100644 --- a/libfreerdp/codec/dsp_ffmpeg.c +++ b/libfreerdp/codec/dsp_ffmpeg.c @@ -667,7 +667,9 @@ BOOL freerdp_dsp_ffmpeg_decode(FREERDP_DSP_CONTEXT* context, const AUDIO_FORMAT* if (!context || !srcFormat || !data || !out || context->encoder) return FALSE; +#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(58, 133, 100) av_init_packet(context->packet); +#endif context->packet->data = (uint8_t*)data; context->packet->size = length; return ffmpeg_decode(context->context, context->packet, context->frame, context->rcontext, From 95b0759febc2fefcf52006d381337918ab6671e5 Mon Sep 17 00:00:00 2001 From: David Runge Date: Mon, 24 Jan 2022 19:47:29 +0100 Subject: [PATCH 042/496] Guard avcodec_register_all() calls {channels/tsmf/client/ffmpeg/tsmf,libfreerdp/codec/dsp}_ffmpeg.c: Guard calls to `avcodec_register_all()` against use beyond `AV_VERSION_INT(58, 10, 100)`, where upstream ffmpeg made it obsolete. (cherry picked from commit 811d94c742b33d1e6de33f7e84c794d8bae26d3a) --- channels/tsmf/client/ffmpeg/tsmf_ffmpeg.c | 2 ++ libfreerdp/codec/dsp_ffmpeg.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/channels/tsmf/client/ffmpeg/tsmf_ffmpeg.c b/channels/tsmf/client/ffmpeg/tsmf_ffmpeg.c index 0444ad07bed3..cf0aa9ba172a 100644 --- a/channels/tsmf/client/ffmpeg/tsmf_ffmpeg.c +++ b/channels/tsmf/client/ffmpeg/tsmf_ffmpeg.c @@ -615,7 +615,9 @@ static void tsmf_ffmpeg_free(ITSMFDecoder* decoder) static INIT_ONCE g_Initialized = INIT_ONCE_STATIC_INIT; static BOOL CALLBACK InitializeAvCodecs(PINIT_ONCE once, PVOID param, PVOID* context) { +#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(58, 10, 100) avcodec_register_all(); +#endif return TRUE; } diff --git a/libfreerdp/codec/dsp_ffmpeg.c b/libfreerdp/codec/dsp_ffmpeg.c index 6bbfe1454171..086c797a2953 100644 --- a/libfreerdp/codec/dsp_ffmpeg.c +++ b/libfreerdp/codec/dsp_ffmpeg.c @@ -571,7 +571,9 @@ BOOL freerdp_dsp_ffmpeg_supports_format(const AUDIO_FORMAT* format, BOOL encode) FREERDP_DSP_CONTEXT* freerdp_dsp_ffmpeg_context_new(BOOL encode) { FREERDP_DSP_CONTEXT* context; +#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(58, 10, 100) avcodec_register_all(); +#endif context = calloc(1, sizeof(FREERDP_DSP_CONTEXT)); if (!context) From de953357019f2eda7c91c830dfaf49391ee94ac4 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Tue, 25 Jan 2022 12:27:17 +0100 Subject: [PATCH 043/496] Added support for getpwuid_r, replaced duplicate code * Use GetUserNameExA to get current user name when required. * Add support for getpwuid_r if available (cherry picked from commit 8a155db877d944579e2182a33cbe13b94399573c) --- CMakeLists.txt | 1 + channels/rdpdr/client/rdpdr_main.c | 11 +++-- client/X11/xf_client.c | 15 ++----- config.h.in | 1 + winpr/libwinpr/sspicli/sspicli.c | 71 +++++++++++++++++++++--------- 5 files changed, 62 insertions(+), 37 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2e3d30217307..c4ce21a05afe 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -652,6 +652,7 @@ if(UNIX OR CYGWIN) include(CheckFunctionExists) check_function_exists(getlogin_r HAVE_GETLOGIN_R) + check_function_exists(getpwuid_r HAVE_GETPWUID_R) else() set(X11_FEATURE_TYPE "DISABLED") set(WAYLAND_FEATURE_TYPE "DISABLED") diff --git a/channels/rdpdr/client/rdpdr_main.c b/channels/rdpdr/client/rdpdr_main.c index 617ea4287052..3a04fe3e67c0 100644 --- a/channels/rdpdr/client/rdpdr_main.c +++ b/channels/rdpdr/client/rdpdr_main.c @@ -33,6 +33,8 @@ #include #include +#include + #include #include #include @@ -591,16 +593,13 @@ static BOOL isAutomountLocation(const char* path) { const size_t nrLocations = sizeof(automountLocations) / sizeof(automountLocations[0]); size_t x; - char buffer[MAX_PATH]; + char buffer[MAX_PATH] = { 0 }; uid_t uid = getuid(); char uname[MAX_PATH] = { 0 }; + ULONG size = sizeof(uname) - 1; -#ifndef HAVE_GETLOGIN_R - strncpy(uname, getlogin(), sizeof(uname)); -#else - if (getlogin_r(uname, sizeof(uname)) != 0) + if (!GetUserNameExA(NameSamCompatible, uname, &size)) return FALSE; -#endif if (!path) return FALSE; diff --git a/client/X11/xf_client.c b/client/X11/xf_client.c index 78852a745ef8..4bdad53db997 100644 --- a/client/X11/xf_client.c +++ b/client/X11/xf_client.c @@ -27,6 +27,7 @@ #endif #include +#include #include #include @@ -1183,20 +1184,12 @@ static BOOL xf_pre_connect(freerdp* instance) if (!settings->Username && !settings->CredentialsFromStdin && !settings->SmartcardLogon) { - int rc; char login_name[MAX_PATH] = { 0 }; + ULONG size = sizeof(login_name) - 1; -#ifdef HAVE_GETLOGIN_R - rc = getlogin_r(login_name, sizeof(login_name)); -#else - strncpy(login_name, getlogin(), sizeof(login_name)); - rc = 0; -#endif - if (rc == 0) + if (GetUserNameExA(NameSamCompatible, login_name, &size)) { - settings->Username = _strdup(login_name); - - if (!settings->Username) + if (!freerdp_settings_set_string(settings, FreeRDP_Username, login_name)) return FALSE; WLog_INFO(TAG, "No user name set. - Using login name: %s", settings->Username); diff --git a/config.h.in b/config.h.in index 2264e5952aeb..a21f3cbc0cbc 100644 --- a/config.h.in +++ b/config.h.in @@ -25,6 +25,7 @@ #cmakedefine HAVE_VALGRIND_MEMCHECK_H #cmakedefine HAVE_EXECINFO_H #cmakedefine HAVE_GETLOGIN_R +#cmakedefine HAVE_GETPWUID_R /* Features */ #cmakedefine SWRESAMPLE_FOUND diff --git a/winpr/libwinpr/sspicli/sspicli.c b/winpr/libwinpr/sspicli/sspicli.c index 039416994137..eb138d54f229 100644 --- a/winpr/libwinpr/sspicli/sspicli.c +++ b/winpr/libwinpr/sspicli/sspicli.c @@ -21,8 +21,11 @@ #include "config.h" #endif +#include #include +#define WINPR_ASSERT(x) assert(x) + /** * sspicli.dll: * @@ -60,6 +63,12 @@ #include #endif +#if defined(HAVE_GETPWUID_R) +#include +#include +#include +#endif + #include #include @@ -200,30 +209,30 @@ BOOL LogonUserExW(LPCWSTR lpszUsername, LPCWSTR lpszDomain, LPCWSTR lpszPassword BOOL GetUserNameExA(EXTENDED_NAME_FORMAT NameFormat, LPSTR lpNameBuffer, PULONG nSize) { - size_t length; - char login[MAX_PATH]; - switch (NameFormat) { case NameSamCompatible: -#ifndef HAVE_GETLOGIN_R - strncpy(login, getlogin(), sizeof(login)); -#else - if (getlogin_r(login, sizeof(login)) != 0) +#if defined(HAVE_GETPWUID_R) + { + int rc; + struct passwd pwd = { 0 }; + struct passwd* result = NULL; + uid_t uid = getuid(); + + rc = getpwuid_r(uid, &pwd, lpNameBuffer, *nSize, &result); + if (rc != 0) + return FALSE; + if (result == NULL) return FALSE; + } +#elif defined(HAVE_GETLOGIN_R) + if (getlogin_r(lpNameBuffer, *nSize) != 0) + return FALSE; +#else + strncpy(lpNameBuffer, getlogin(), *nSize); #endif - length = strlen(login); - - if (*nSize >= length) - { - CopyMemory(lpNameBuffer, login, length + 1); - return TRUE; - } - else - { - *nSize = length + 1; - } - + if (*nSize > 1) + *nSize = strnlen(lpNameBuffer, *nSize - 1) + 1; break; case NameFullyQualifiedDN: @@ -245,7 +254,29 @@ BOOL GetUserNameExA(EXTENDED_NAME_FORMAT NameFormat, LPSTR lpNameBuffer, PULONG BOOL GetUserNameExW(EXTENDED_NAME_FORMAT NameFormat, LPWSTR lpNameBuffer, PULONG nSize) { - return 0; + int res; + BOOL rc = FALSE; + char* name; + + WINPR_ASSERT(nSize); + WINPR_ASSERT(lpNameBuffer); + + name = calloc(1, *nSize + 1); + if (!name) + goto fail; + + if (!GetUserNameExA(NameFormat, name, nSize)) + goto fail; + + res = ConvertToUnicode(CP_UTF8, 0, name, -1, &lpNameBuffer, *nSize); + if (res < 0) + goto fail; + + *nSize = res + 1; + rc = TRUE; +fail: + free(name); + return rc; } #endif From 15d49289985b196dee92510e52df6f40c2fd6827 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Tue, 25 Jan 2022 13:22:36 +0100 Subject: [PATCH 044/496] Fixed return value of GetUserNameExA (cherry picked from commit 3a671326771b00487cb387867728f460a1126134) --- winpr/libwinpr/sspicli/sspicli.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/winpr/libwinpr/sspicli/sspicli.c b/winpr/libwinpr/sspicli/sspicli.c index eb138d54f229..5a13b99bebbc 100644 --- a/winpr/libwinpr/sspicli/sspicli.c +++ b/winpr/libwinpr/sspicli/sspicli.c @@ -209,6 +209,9 @@ BOOL LogonUserExW(LPCWSTR lpszUsername, LPCWSTR lpszDomain, LPCWSTR lpszPassword BOOL GetUserNameExA(EXTENDED_NAME_FORMAT NameFormat, LPSTR lpNameBuffer, PULONG nSize) { + WINPR_ASSERT(lpNameBuffer); + WINPR_ASSERT(nSize); + switch (NameFormat) { case NameSamCompatible: @@ -231,9 +234,8 @@ BOOL GetUserNameExA(EXTENDED_NAME_FORMAT NameFormat, LPSTR lpNameBuffer, PULONG #else strncpy(lpNameBuffer, getlogin(), *nSize); #endif - if (*nSize > 1) - *nSize = strnlen(lpNameBuffer, *nSize - 1) + 1; - break; + *nSize = strnlen(lpNameBuffer, *nSize); + return TRUE; case NameFullyQualifiedDN: case NameDisplay: From d98e59237a64b3ab1099c384cb9de2f1a1fafe1f Mon Sep 17 00:00:00 2001 From: james Date: Tue, 25 Jan 2022 22:28:27 +0800 Subject: [PATCH 045/496] Fix hotplug (cherry picked from commit d5bd834e674fb737c095862e8365284154739ee3) --- channels/rdpdr/client/rdpdr_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/channels/rdpdr/client/rdpdr_main.c b/channels/rdpdr/client/rdpdr_main.c index 3a04fe3e67c0..eac0a2e447ee 100644 --- a/channels/rdpdr/client/rdpdr_main.c +++ b/channels/rdpdr/client/rdpdr_main.c @@ -655,7 +655,7 @@ static void handle_mountpoint(hotplug_dev* dev_array, size_t* size, const char* if (isAutomountLocation(mountpoint) && (*size < MAX_USB_DEVICES)) { dev_array[*size].path = _strdup(mountpoint); - dev_array[*size + 1].to_add = TRUE; + dev_array[*size].to_add = TRUE; (*size)++; } } From 8adbb187be4a17b7e5b6100eb62078a7021cae24 Mon Sep 17 00:00:00 2001 From: Ely Ronnen Date: Fri, 7 Jan 2022 16:08:45 +0200 Subject: [PATCH 046/496] adding mediacodec h264 implementation using NDK (cherry picked from commit afe6cc10bd4541e0ee7cf3e30d0b510060b22e99) --- CMakeLists.txt | 2 +- cmake/ConfigOptions.cmake | 2 + config.h.in | 1 + libfreerdp/CMakeLists.txt | 5 + libfreerdp/codec/h264.c | 7 + libfreerdp/codec/h264_mediacodec.c | 375 +++++++++++++++++++++++++++++ 6 files changed, 391 insertions(+), 1 deletion(-) create mode 100644 libfreerdp/codec/h264_mediacodec.c diff --git a/CMakeLists.txt b/CMakeLists.txt index c4ce21a05afe..9d921100029a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -917,7 +917,7 @@ if(MBEDTLS_FOUND) add_definitions("-DWITH_MBEDTLS") endif() -if (WITH_X264 OR WITH_OPENH264 OR WITH_MEDIA_FOUNDATION OR WITH_FFMPEG) +if (WITH_OPENH264 OR WITH_MEDIA_FOUNDATION OR WITH_FFMPEG OR WITH_MEDIACODEC) set(WITH_GFX_H264 ON) else() set(WITH_GFX_H264 OFF) diff --git a/cmake/ConfigOptions.cmake b/cmake/ConfigOptions.cmake index 1a6a359b7e9e..27fdbfe943f9 100644 --- a/cmake/ConfigOptions.cmake +++ b/cmake/ConfigOptions.cmake @@ -176,6 +176,8 @@ option(DEFINE_NO_DEPRECATED "Compile without legacy functions and symbols" OFF) if (ANDROID) include(ConfigOptionsAndroid) +else() + option(WITH_MEDIACODEC "Use MediaCodec API" OFF) endif(ANDROID) if (IOS) diff --git a/config.h.in b/config.h.in index a21f3cbc0cbc..bd4946118f64 100644 --- a/config.h.in +++ b/config.h.in @@ -67,6 +67,7 @@ #cmakedefine WITH_X264 #cmakedefine WITH_OPENCL #cmakedefine WITH_MEDIA_FOUNDATION +#cmakedefine WITH_MEDIACODEC #cmakedefine WITH_VAAPI diff --git a/libfreerdp/CMakeLists.txt b/libfreerdp/CMakeLists.txt index e3a410316be5..31c924b0387a 100644 --- a/libfreerdp/CMakeLists.txt +++ b/libfreerdp/CMakeLists.txt @@ -244,6 +244,11 @@ if(WIN32 AND WITH_MEDIA_FOUNDATION) set(CODEC_SRCS ${CODEC_SRCS} codec/h264_mf.c) endif() +if(ANDROID AND WITH_MEDIACODEC) + set(CODEC_SRCS ${CODEC_SRCS} codec/h264_mediacodec.c) + freerdp_library_add("libmediandk.so") +endif() + freerdp_module_add(${CODEC_SRCS}) if(BUILD_TESTING) diff --git a/libfreerdp/codec/h264.c b/libfreerdp/codec/h264.c index 00b812b2921c..bbdfd3f21adb 100644 --- a/libfreerdp/codec/h264.c +++ b/libfreerdp/codec/h264.c @@ -500,6 +500,13 @@ static BOOL CALLBACK h264_register_subsystems(PINIT_ONCE once, PVOID param, PVOI i++; } #endif +#ifdef WITH_MEDIACODEC + { + extern H264_CONTEXT_SUBSYSTEM g_Subsystem_mediacodec; + subSystems[i] = &g_Subsystem_mediacodec; + i++; + } +#endif #ifdef WITH_OPENH264 { extern H264_CONTEXT_SUBSYSTEM g_Subsystem_OpenH264; diff --git a/libfreerdp/codec/h264_mediacodec.c b/libfreerdp/codec/h264_mediacodec.c new file mode 100644 index 000000000000..bb4f9d9316bd --- /dev/null +++ b/libfreerdp/codec/h264_mediacodec.c @@ -0,0 +1,375 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * H.264 Bitmap Compression + * + * Copyright 2022 Ely Ronnen + * + * 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. + */ + +#include +#include +#include + +#include +#include + +#include "h264.h" + +const int COLOR_FormatYUV420Planar = 19; +const int COLOR_FormatYUV420Flexible = 0x7f420888; + +struct _H264_CONTEXT_MEDIACODEC +{ + AMediaCodec* decoder; + AMediaFormat* inputFormat; + AMediaFormat* outputFormat; + int32_t width; + int32_t height; + ssize_t currentOutputBufferIndex; +}; + +typedef struct _H264_CONTEXT_MEDIACODEC H264_CONTEXT_MEDIACODEC; + +static void set_mediacodec_format(H264_CONTEXT* h264, AMediaFormat** formatVariable, AMediaFormat* newFormat) +{ + media_status_t status = AMEDIA_OK; + + if (*formatVariable != NULL) + { + status = AMediaFormat_delete(*formatVariable); + if (status != AMEDIA_OK) + { + WLog_Print(h264->log, WLOG_ERROR, "Error AMediaFormat_delete %d", status); + } + } + + *formatVariable = newFormat; +} + +static void release_current_outputbuffer(H264_CONTEXT* h264) +{ + H264_CONTEXT_MEDIACODEC* sys = (H264_CONTEXT_MEDIACODEC*)h264->pSystemData; + media_status_t status = AMEDIA_OK; + + if (sys->currentOutputBufferIndex < 0) + { + return; + } + + status = AMediaCodec_releaseOutputBuffer(sys->decoder, sys->currentOutputBufferIndex, FALSE); + if (status != AMEDIA_OK) + { + WLog_Print(h264->log, WLOG_ERROR, "Error AMediaCodec_releaseOutputBuffer %d", status); + } + + sys->currentOutputBufferIndex = -1; +} + +static int mediacodec_compress(H264_CONTEXT* h264, const BYTE** pSrcYuv, const UINT32* pStride, + BYTE** ppDstData, UINT32* pDstSize) +{ + WLog_Print(h264->log, WLOG_ERROR, "MediaCodec is not supported as an encoder"); + return -1; +} + +static int mediacodec_decompress(H264_CONTEXT* h264, const BYTE* pSrcData, UINT32 SrcSize) +{ + H264_CONTEXT_MEDIACODEC* sys = (H264_CONTEXT_MEDIACODEC*)h264->pSystemData; + ssize_t inputBufferId = -1; + size_t inputBufferSize, outputBufferSize; + uint8_t* inputBuffer; + media_status_t status; + const char* media_format; + BYTE** pYUVData = h264->pYUVData; + UINT32* iStride = h264->iStride; + + release_current_outputbuffer(h264); + + if (sys->width == 0) + { + int32_t width = h264->width; + int32_t height = h264->height; + if (width % 16 != 0) + width += 16 - width % 16; + if (height % 16 != 0) + height += 16 - height % 16; + + WLog_Print(h264->log, WLOG_INFO, "MediaCodec setting width and height [%d,%d]", width, height); + AMediaFormat_setInt32(sys->inputFormat, AMEDIAFORMAT_KEY_WIDTH, width); + AMediaFormat_setInt32(sys->inputFormat, AMEDIAFORMAT_KEY_HEIGHT, height); + + status = AMediaCodec_setParameters(sys->decoder, sys->inputFormat); + if (status != AMEDIA_OK) + { + WLog_Print(h264->log, WLOG_ERROR, "AMediaCodec_setParameters failed: %d", status); + return -1; + } + + sys->width = width; + sys->height = height; + } + + while (true) + { + inputBufferId = AMediaCodec_dequeueInputBuffer(sys->decoder, -1); + if (inputBufferId < 0) + { + WLog_Print(h264->log, WLOG_ERROR, "AMediaCodec_dequeueInputBuffer failed [%d]", inputBufferId); + // TODO: sleep? + continue; + } + + inputBuffer = AMediaCodec_getInputBuffer(sys->decoder, inputBufferId, &inputBufferSize); + if (inputBuffer == NULL) + { + WLog_Print(h264->log, WLOG_ERROR, "AMediaCodec_getInputBuffer failed"); + return -1; + } + + if (SrcSize > inputBufferSize) + { + WLog_Print(h264->log, WLOG_ERROR, "MediaCodec input buffer size is too small: got [%d] but wanted [%d]", inputBufferSize, SrcSize); + return -1; + } + + memcpy(inputBuffer, pSrcData, SrcSize); + status = AMediaCodec_queueInputBuffer(sys->decoder, inputBufferId, 0, SrcSize, 0, 0); + if (status != AMEDIA_OK) + { + WLog_Print(h264->log, WLOG_ERROR, "Error AMediaCodec_queueInputBuffer %d", status); + return -1; + } + + while (true) + { + AMediaCodecBufferInfo bufferInfo; + ssize_t outputBufferId = AMediaCodec_dequeueOutputBuffer(sys->decoder, &bufferInfo, -1); + if (outputBufferId >= 0) + { + sys->currentOutputBufferIndex = outputBufferId; + + uint8_t* outputBuffer; + outputBuffer = AMediaCodec_getOutputBuffer(sys->decoder, outputBufferId, &outputBufferSize); + sys->currentOutputBufferIndex = outputBufferId; + + if (outputBufferSize != (sys->width * sys->height + ((sys->width + 1) / 2) * ((sys->height + 1) / 2) * 2)) + { + WLog_Print(h264->log, WLOG_ERROR, "Error unexpected output buffer size %d", outputBufferSize); + return -1; + } + + // TODO: work with AImageReader and get AImage object instead of COLOR_FormatYUV420Planar buffer. + iStride[0] = sys->width; + iStride[1] = (sys->width + 1) / 2; + iStride[2] = (sys->width + 1) / 2; + pYUVData[0] = outputBuffer; + pYUVData[1] = outputBuffer + iStride[0] * sys->height; + pYUVData[2] = outputBuffer + iStride[0] * sys->height + iStride[1] * ((sys->height + 1) / 2); + break; + } + else if (outputBufferId == AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED) + { + AMediaFormat* outputFormat; + outputFormat = AMediaCodec_getOutputFormat(sys->decoder); + if (outputFormat == NULL) + { + WLog_Print(h264->log, WLOG_ERROR, "AMediaCodec_getOutputFormat failed"); + return -1; + } + set_mediacodec_format(h264, &sys->outputFormat, outputFormat); + + media_format = AMediaFormat_toString(sys->outputFormat); + if (media_format == NULL) + { + WLog_Print(h264->log, WLOG_ERROR, "AMediaFormat_toString failed"); + return -1; + } + } + else if (outputBufferId == AMEDIACODEC_INFO_TRY_AGAIN_LATER) + { + WLog_Print(h264->log, WLOG_WARN, "AMediaCodec_dequeueOutputBuffer need to try again later"); + // TODO: sleep? + } + else if (outputBufferId == AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED) + { + WLog_Print(h264->log, WLOG_WARN, "AMediaCodec_dequeueOutputBuffer returned deprecated value AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED, ignoring"); + } + else + { + WLog_Print(h264->log, WLOG_ERROR, "AMediaCodec_dequeueOutputBuffer returned unknown value [%d]", outputBufferId); + return -1; + } + } + + break; + } + + return 1; +} + +static void mediacodec_uninit(H264_CONTEXT* h264) +{ + H264_CONTEXT_MEDIACODEC* sys = (H264_CONTEXT_MEDIACODEC*)h264->pSystemData; + media_status_t status = AMEDIA_OK; + + WLog_Print(h264->log, WLOG_INFO, "Uninitializing MediaCodec"); + + if (!sys) + return; + + + if (sys->decoder != NULL) + { + release_current_outputbuffer(h264); + status = AMediaCodec_stop(sys->decoder); + if (status != AMEDIA_OK) + { + WLog_Print(h264->log, WLOG_ERROR, "Error AMediaCodec_stop %d", status); + } + + status = AMediaCodec_delete(sys->decoder); + if (status != AMEDIA_OK) + { + WLog_Print(h264->log, WLOG_ERROR, "Error AMediaCodec_delete %d", status); + } + + sys->decoder = NULL; + } + + set_mediacodec_format(h264, &sys->inputFormat, NULL); + set_mediacodec_format(h264, &sys->outputFormat, NULL); + + free(sys); + h264->pSystemData = NULL; +} + +static BOOL mediacodec_init(H264_CONTEXT* h264) +{ + H264_CONTEXT_MEDIACODEC* sys; + media_status_t status; + char* codec_name, *media_format; + AMediaFormat* inputFormat, *outputFormat; + + if (h264->Compressor) + { + WLog_Print(h264->log, WLOG_ERROR, "MediaCodec is not supported as an encoder"); + goto EXCEPTION; + } + + WLog_Print(h264->log, WLOG_INFO, "Initializing MediaCodec"); + + sys = (H264_CONTEXT_MEDIACODEC*)calloc(1, sizeof(H264_CONTEXT_MEDIACODEC)); + + if (!sys) + { + goto EXCEPTION; + } + + h264->pSystemData = (void*)sys; + + sys->currentOutputBufferIndex = -1; + sys->width = sys->height = 0; // update when we're given the height and width + sys->decoder = AMediaCodec_createDecoderByType("video/avc"); + if (sys->decoder == NULL) + { + WLog_Print(h264->log, WLOG_ERROR, "AMediaCodec_createCodecByName failed"); + goto EXCEPTION; + } + + status = AMediaCodec_getName(sys->decoder, &codec_name); + if (status != AMEDIA_OK) + { + WLog_Print(h264->log, WLOG_ERROR, "AMediaCodec_getName failed: %d", status); + goto EXCEPTION; + } + + WLog_Print(h264->log, WLOG_INFO, "MediaCodec using video/avc codec [%s]", codec_name); + AMediaCodec_releaseName(sys->decoder, codec_name); + + sys->inputFormat = AMediaFormat_new(); + if (sys->inputFormat == NULL) + { + WLog_Print(h264->log, WLOG_ERROR, "AMediaFormat_new failed"); + goto EXCEPTION; + } + + AMediaFormat_setString(sys->inputFormat, AMEDIAFORMAT_KEY_MIME, "video/avc"); + AMediaFormat_setInt32(sys->inputFormat, AMEDIAFORMAT_KEY_WIDTH, sys->width); + AMediaFormat_setInt32(sys->inputFormat, AMEDIAFORMAT_KEY_HEIGHT, sys->height); + AMediaFormat_setInt32(sys->inputFormat, AMEDIAFORMAT_KEY_COLOR_FORMAT, COLOR_FormatYUV420Planar); + + media_format = AMediaFormat_toString(sys->inputFormat); + if (media_format == NULL) + { + WLog_Print(h264->log, WLOG_ERROR, "AMediaFormat_toString failed"); + goto EXCEPTION; + } + + status = AMediaCodec_configure(sys->decoder, sys->inputFormat, NULL, NULL, 0); + if (status != AMEDIA_OK) + { + WLog_Print(h264->log, WLOG_ERROR, "AMediaCodec_configure failed: %d", status); + goto EXCEPTION; + } + + + inputFormat = AMediaCodec_getInputFormat(sys->decoder); + if (inputFormat == NULL) + { + WLog_Print(h264->log, WLOG_ERROR, "AMediaCodec_getInputFormat failed"); + return -1; + } + set_mediacodec_format(h264, &sys->inputFormat, inputFormat); + + media_format = AMediaFormat_toString(sys->inputFormat); + if (media_format == NULL) + { + WLog_Print(h264->log, WLOG_ERROR, "AMediaFormat_toString failed"); + goto EXCEPTION; + } + WLog_Print(h264->log, WLOG_INFO, "Using MediaCodec with input MediaFormat [%s]", media_format); + + outputFormat = AMediaCodec_getOutputFormat(sys->decoder); + if (outputFormat == NULL) + { + WLog_Print(h264->log, WLOG_ERROR, "AMediaCodec_getOutputFormat failed"); + return -1; + } + set_mediacodec_format(h264, &sys->outputFormat, outputFormat); + + media_format = AMediaFormat_toString(sys->outputFormat); + if (media_format == NULL) + { + WLog_Print(h264->log, WLOG_ERROR, "AMediaFormat_toString failed"); + goto EXCEPTION; + } + WLog_Print(h264->log, WLOG_INFO, "Using MediaCodec with output MediaFormat [%s]", media_format); + + + WLog_Print(h264->log, WLOG_INFO, "Starting MediaCodec"); + status = AMediaCodec_start(sys->decoder); + if (status != AMEDIA_OK) + { + WLog_Print(h264->log, WLOG_ERROR, "AMediaCodec_start failed %d", status); + goto EXCEPTION; + } + + return TRUE; +EXCEPTION: + mediacodec_uninit(h264); + return FALSE; +} + +H264_CONTEXT_SUBSYSTEM g_Subsystem_mediacodec = { "MediaCodec", mediacodec_init, mediacodec_uninit, + mediacodec_decompress, mediacodec_compress }; From 27a955a78092dcda0e4b49a8dc76c42a393c2574 Mon Sep 17 00:00:00 2001 From: Ely Ronnen Date: Tue, 25 Jan 2022 15:45:45 +0200 Subject: [PATCH 047/496] import libmediandk.so dynamically (cherry picked from commit 5fbaeea42580d494dc3002207d957509638d0692) --- libfreerdp/CMakeLists.txt | 1 - libfreerdp/codec/h264_mediacodec.c | 194 ++++++++++++++++++++++++----- 2 files changed, 164 insertions(+), 31 deletions(-) diff --git a/libfreerdp/CMakeLists.txt b/libfreerdp/CMakeLists.txt index 31c924b0387a..0ec7a53f7e28 100644 --- a/libfreerdp/CMakeLists.txt +++ b/libfreerdp/CMakeLists.txt @@ -246,7 +246,6 @@ endif() if(ANDROID AND WITH_MEDIACODEC) set(CODEC_SRCS ${CODEC_SRCS} codec/h264_mediacodec.c) - freerdp_library_add("libmediandk.so") endif() freerdp_module_add(${CODEC_SRCS}) diff --git a/libfreerdp/codec/h264_mediacodec.c b/libfreerdp/codec/h264_mediacodec.c index bb4f9d9316bd..3cecc26809ed 100644 --- a/libfreerdp/codec/h264_mediacodec.c +++ b/libfreerdp/codec/h264_mediacodec.c @@ -18,6 +18,8 @@ */ #include +#include + #include #include @@ -26,6 +28,28 @@ #include "h264.h" +typedef AMediaFormat* (*AMediaFormat_new_t)(); +typedef media_status_t (*AMediaFormat_delete_t)(AMediaFormat*); +typedef const char* (*AMediaFormat_toString_t)(AMediaFormat*); +typedef void (*AMediaFormat_setInt32_t)(AMediaFormat*, const char*, int32_t); +typedef void (*AMediaFormat_setString_t)(AMediaFormat*, const char*, const char*); +typedef AMediaCodec* (*AMediaCodec_createDecoderByType_t)(const char *); +typedef media_status_t (*AMediaCodec_delete_t)(AMediaCodec*); +typedef media_status_t (*AMediaCodec_configure_t)(AMediaCodec*, const AMediaFormat*, ANativeWindow*, AMediaCrypto *, uint32_t); +typedef media_status_t (*AMediaCodec_start_t)(AMediaCodec*); +typedef media_status_t (*AMediaCodec_stop_t)(AMediaCodec*); +typedef uint8_t* (*AMediaCodec_getInputBuffer_t)(AMediaCodec*, size_t, size_t *); +typedef uint8_t* (*AMediaCodec_getOutputBuffer_t)(AMediaCodec*, size_t, size_t *); +typedef ssize_t (*AMediaCodec_dequeueInputBuffer_t)(AMediaCodec*, int64_t); +typedef media_status_t (*AMediaCodec_queueInputBuffer_t)(AMediaCodec*, size_t, ssize_t, size_t, uint64_t, uint32_t); +typedef ssize_t (*AMediaCodec_dequeueOutputBuffer_t)(AMediaCodec*, AMediaCodecBufferInfo *, int64_t); +typedef AMediaFormat* (*AMediaCodec_getOutputFormat_t)(AMediaCodec*); +typedef media_status_t (*AMediaCodec_releaseOutputBuffer_t)(AMediaCodec*, size_t, bool); +typedef media_status_t (*AMediaCodec_setParameters_t)(AMediaCodec *, const AMediaFormat*); // 26 +typedef media_status_t (*AMediaCodec_getName_t)(AMediaCodec*, char**); // 28 +typedef void (*AMediaCodec_releaseName_t)(AMediaCodec*, char*); // 28 +typedef AMediaFormat* (*AMediaCodec_getInputFormat_t)(AMediaCodec*); // 28 + const int COLOR_FormatYUV420Planar = 19; const int COLOR_FormatYUV420Flexible = 0x7f420888; @@ -37,17 +61,119 @@ struct _H264_CONTEXT_MEDIACODEC int32_t width; int32_t height; ssize_t currentOutputBufferIndex; + + // libmediandk.so imports + HMODULE mediandkLibrary; + + AMediaFormat_new_t fnAMediaFormat_new; + AMediaFormat_delete_t fnAMediaFormat_delete; + AMediaFormat_toString_t fnAMediaFormat_toString; + AMediaFormat_setInt32_t fnAMediaFormat_setInt32; + AMediaFormat_setString_t fnAMediaFormat_setString; + AMediaCodec_createDecoderByType_t fnAMediaCodec_createDecoderByType; + AMediaCodec_delete_t fnAMediaCodec_delete; + AMediaCodec_configure_t fnAMediaCodec_configure; + AMediaCodec_start_t fnAMediaCodec_start; + AMediaCodec_stop_t fnAMediaCodec_stop; + AMediaCodec_getInputBuffer_t fnAMediaCodec_getInputBuffer; + AMediaCodec_getOutputBuffer_t fnAMediaCodec_getOutputBuffer; + AMediaCodec_dequeueInputBuffer_t fnAMediaCodec_dequeueInputBuffer; + AMediaCodec_queueInputBuffer_t fnAMediaCodec_queueInputBuffer; + AMediaCodec_dequeueOutputBuffer_t fnAMediaCodec_dequeueOutputBuffer; + AMediaCodec_getOutputFormat_t fnAMediaCodec_getOutputFormat; + AMediaCodec_releaseOutputBuffer_t fnAMediaCodec_releaseOutputBuffer; + AMediaCodec_setParameters_t fnAMediaCodec_setParameters; + AMediaCodec_getName_t fnAMediaCodec_getName; + AMediaCodec_releaseName_t fnAMediaCodec_releaseName; + AMediaCodec_getInputFormat_t fnAMediaCodec_getInputFormat; + + const char* gAMediaFormatKeyMime; + const char* gAMediaFormatKeyWidth; + const char* gAMediaFormatKeyHeight; + const char* gAMediaFormatKeyColorFormat; }; typedef struct _H264_CONTEXT_MEDIACODEC H264_CONTEXT_MEDIACODEC; +static int load_libmediandk(H264_CONTEXT* h264) +{ + H264_CONTEXT_MEDIACODEC* sys = (H264_CONTEXT_MEDIACODEC*)h264->pSystemData; + WLog_Print(h264->log, WLOG_INFO, "MediaCodec Loading libmediandk.so"); + + sys->mediandkLibrary = LoadLibraryA("libmediandk.so"); + if (sys->mediandkLibrary == NULL) + { + WLog_Print(h264->log, WLOG_ERROR, "Error loading libmediandk.so"); + return -1; + } + +#define RESOLVE_MEDIANDK_FUNC(name) \ + sys->fn##name = GetProcAddress(sys->mediandkLibrary, #name); \ + if (sys->fn##name == NULL) \ + { \ + WLog_Print(h264->log, WLOG_ERROR, "Error resolving function " #name " from libmediandk.so"); \ + return -1; \ + } + + const char **temp = NULL; +#define RESOLVE_MEDIANDK_VARIABLE(member, exported) \ + temp = GetProcAddress(sys->mediandkLibrary, exported); \ + if (temp == NULL) \ + { \ + WLog_Print(h264->log, WLOG_ERROR, "Error resolving variable " exported " from libmediandk.so"); \ + return -1; \ + } \ + sys->member = *temp; + + RESOLVE_MEDIANDK_FUNC(AMediaFormat_new); + RESOLVE_MEDIANDK_FUNC(AMediaFormat_delete); + RESOLVE_MEDIANDK_FUNC(AMediaFormat_toString); + RESOLVE_MEDIANDK_FUNC(AMediaFormat_setInt32); + RESOLVE_MEDIANDK_FUNC(AMediaFormat_setString); + RESOLVE_MEDIANDK_FUNC(AMediaCodec_createDecoderByType); + RESOLVE_MEDIANDK_FUNC(AMediaCodec_delete); + RESOLVE_MEDIANDK_FUNC(AMediaCodec_configure); + RESOLVE_MEDIANDK_FUNC(AMediaCodec_start); + RESOLVE_MEDIANDK_FUNC(AMediaCodec_stop); + RESOLVE_MEDIANDK_FUNC(AMediaCodec_getInputBuffer); + RESOLVE_MEDIANDK_FUNC(AMediaCodec_getOutputBuffer); + RESOLVE_MEDIANDK_FUNC(AMediaCodec_dequeueInputBuffer); + RESOLVE_MEDIANDK_FUNC(AMediaCodec_queueInputBuffer); + RESOLVE_MEDIANDK_FUNC(AMediaCodec_dequeueOutputBuffer); + RESOLVE_MEDIANDK_FUNC(AMediaCodec_getOutputFormat); + RESOLVE_MEDIANDK_FUNC(AMediaCodec_releaseOutputBuffer); + RESOLVE_MEDIANDK_FUNC(AMediaCodec_setParameters); + RESOLVE_MEDIANDK_FUNC(AMediaCodec_getName); + RESOLVE_MEDIANDK_FUNC(AMediaCodec_releaseName); + RESOLVE_MEDIANDK_FUNC(AMediaCodec_getInputFormat); + + RESOLVE_MEDIANDK_VARIABLE(gAMediaFormatKeyMime, "AMEDIAFORMAT_KEY_MIME"); + RESOLVE_MEDIANDK_VARIABLE(gAMediaFormatKeyWidth, "AMEDIAFORMAT_KEY_WIDTH"); + RESOLVE_MEDIANDK_VARIABLE(gAMediaFormatKeyHeight, "AMEDIAFORMAT_KEY_HEIGHT"); + RESOLVE_MEDIANDK_VARIABLE(gAMediaFormatKeyColorFormat, "AMEDIAFORMAT_KEY_COLOR_FORMAT"); + + return 0; +} + +static void unload_libmediandk(H264_CONTEXT* h264) +{ + H264_CONTEXT_MEDIACODEC* sys = (H264_CONTEXT_MEDIACODEC*)h264->pSystemData; + if (NULL == sys->mediandkLibrary) + { + return; + } + + FreeLibrary(sys->mediandkLibrary); +} + static void set_mediacodec_format(H264_CONTEXT* h264, AMediaFormat** formatVariable, AMediaFormat* newFormat) { + H264_CONTEXT_MEDIACODEC* sys = (H264_CONTEXT_MEDIACODEC*)h264->pSystemData; media_status_t status = AMEDIA_OK; if (*formatVariable != NULL) { - status = AMediaFormat_delete(*formatVariable); + status = sys->fnAMediaFormat_delete(*formatVariable); if (status != AMEDIA_OK) { WLog_Print(h264->log, WLOG_ERROR, "Error AMediaFormat_delete %d", status); @@ -67,7 +193,7 @@ static void release_current_outputbuffer(H264_CONTEXT* h264) return; } - status = AMediaCodec_releaseOutputBuffer(sys->decoder, sys->currentOutputBufferIndex, FALSE); + status = sys->fnAMediaCodec_releaseOutputBuffer(sys->decoder, sys->currentOutputBufferIndex, FALSE); if (status != AMEDIA_OK) { WLog_Print(h264->log, WLOG_ERROR, "Error AMediaCodec_releaseOutputBuffer %d", status); @@ -106,10 +232,10 @@ static int mediacodec_decompress(H264_CONTEXT* h264, const BYTE* pSrcData, UINT3 height += 16 - height % 16; WLog_Print(h264->log, WLOG_INFO, "MediaCodec setting width and height [%d,%d]", width, height); - AMediaFormat_setInt32(sys->inputFormat, AMEDIAFORMAT_KEY_WIDTH, width); - AMediaFormat_setInt32(sys->inputFormat, AMEDIAFORMAT_KEY_HEIGHT, height); + sys->fnAMediaFormat_setInt32(sys->inputFormat, sys->gAMediaFormatKeyWidth, width); + sys->fnAMediaFormat_setInt32(sys->inputFormat, sys->gAMediaFormatKeyHeight, height); - status = AMediaCodec_setParameters(sys->decoder, sys->inputFormat); + status = sys->fnAMediaCodec_setParameters(sys->decoder, sys->inputFormat); if (status != AMEDIA_OK) { WLog_Print(h264->log, WLOG_ERROR, "AMediaCodec_setParameters failed: %d", status); @@ -122,7 +248,7 @@ static int mediacodec_decompress(H264_CONTEXT* h264, const BYTE* pSrcData, UINT3 while (true) { - inputBufferId = AMediaCodec_dequeueInputBuffer(sys->decoder, -1); + inputBufferId = sys->fnAMediaCodec_dequeueInputBuffer(sys->decoder, -1); if (inputBufferId < 0) { WLog_Print(h264->log, WLOG_ERROR, "AMediaCodec_dequeueInputBuffer failed [%d]", inputBufferId); @@ -130,7 +256,7 @@ static int mediacodec_decompress(H264_CONTEXT* h264, const BYTE* pSrcData, UINT3 continue; } - inputBuffer = AMediaCodec_getInputBuffer(sys->decoder, inputBufferId, &inputBufferSize); + inputBuffer = sys->fnAMediaCodec_getInputBuffer(sys->decoder, inputBufferId, &inputBufferSize); if (inputBuffer == NULL) { WLog_Print(h264->log, WLOG_ERROR, "AMediaCodec_getInputBuffer failed"); @@ -144,7 +270,7 @@ static int mediacodec_decompress(H264_CONTEXT* h264, const BYTE* pSrcData, UINT3 } memcpy(inputBuffer, pSrcData, SrcSize); - status = AMediaCodec_queueInputBuffer(sys->decoder, inputBufferId, 0, SrcSize, 0, 0); + status = sys->fnAMediaCodec_queueInputBuffer(sys->decoder, inputBufferId, 0, SrcSize, 0, 0); if (status != AMEDIA_OK) { WLog_Print(h264->log, WLOG_ERROR, "Error AMediaCodec_queueInputBuffer %d", status); @@ -154,13 +280,13 @@ static int mediacodec_decompress(H264_CONTEXT* h264, const BYTE* pSrcData, UINT3 while (true) { AMediaCodecBufferInfo bufferInfo; - ssize_t outputBufferId = AMediaCodec_dequeueOutputBuffer(sys->decoder, &bufferInfo, -1); + ssize_t outputBufferId = sys->fnAMediaCodec_dequeueOutputBuffer(sys->decoder, &bufferInfo, -1); if (outputBufferId >= 0) { sys->currentOutputBufferIndex = outputBufferId; uint8_t* outputBuffer; - outputBuffer = AMediaCodec_getOutputBuffer(sys->decoder, outputBufferId, &outputBufferSize); + outputBuffer = sys->fnAMediaCodec_getOutputBuffer(sys->decoder, outputBufferId, &outputBufferSize); sys->currentOutputBufferIndex = outputBufferId; if (outputBufferSize != (sys->width * sys->height + ((sys->width + 1) / 2) * ((sys->height + 1) / 2) * 2)) @@ -181,7 +307,7 @@ static int mediacodec_decompress(H264_CONTEXT* h264, const BYTE* pSrcData, UINT3 else if (outputBufferId == AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED) { AMediaFormat* outputFormat; - outputFormat = AMediaCodec_getOutputFormat(sys->decoder); + outputFormat = sys->fnAMediaCodec_getOutputFormat(sys->decoder); if (outputFormat == NULL) { WLog_Print(h264->log, WLOG_ERROR, "AMediaCodec_getOutputFormat failed"); @@ -189,7 +315,7 @@ static int mediacodec_decompress(H264_CONTEXT* h264, const BYTE* pSrcData, UINT3 } set_mediacodec_format(h264, &sys->outputFormat, outputFormat); - media_format = AMediaFormat_toString(sys->outputFormat); + media_format = sys->fnAMediaFormat_toString(sys->outputFormat); if (media_format == NULL) { WLog_Print(h264->log, WLOG_ERROR, "AMediaFormat_toString failed"); @@ -232,13 +358,13 @@ static void mediacodec_uninit(H264_CONTEXT* h264) if (sys->decoder != NULL) { release_current_outputbuffer(h264); - status = AMediaCodec_stop(sys->decoder); + status = sys->fnAMediaCodec_stop(sys->decoder); if (status != AMEDIA_OK) { WLog_Print(h264->log, WLOG_ERROR, "Error AMediaCodec_stop %d", status); } - status = AMediaCodec_delete(sys->decoder); + status = sys->fnAMediaCodec_delete(sys->decoder); if (status != AMEDIA_OK) { WLog_Print(h264->log, WLOG_ERROR, "Error AMediaCodec_delete %d", status); @@ -250,6 +376,8 @@ static void mediacodec_uninit(H264_CONTEXT* h264) set_mediacodec_format(h264, &sys->inputFormat, NULL); set_mediacodec_format(h264, &sys->outputFormat, NULL); + unload_libmediandk(h264); + free(sys); h264->pSystemData = NULL; } @@ -258,7 +386,8 @@ static BOOL mediacodec_init(H264_CONTEXT* h264) { H264_CONTEXT_MEDIACODEC* sys; media_status_t status; - char* codec_name, *media_format; + const char* media_format; + char* codec_name; AMediaFormat* inputFormat, *outputFormat; if (h264->Compressor) @@ -278,16 +407,21 @@ static BOOL mediacodec_init(H264_CONTEXT* h264) h264->pSystemData = (void*)sys; + if (load_libmediandk(h264) < 0) + { + goto EXCEPTION; + } + sys->currentOutputBufferIndex = -1; sys->width = sys->height = 0; // update when we're given the height and width - sys->decoder = AMediaCodec_createDecoderByType("video/avc"); + sys->decoder = sys->fnAMediaCodec_createDecoderByType("video/avc"); if (sys->decoder == NULL) { WLog_Print(h264->log, WLOG_ERROR, "AMediaCodec_createCodecByName failed"); goto EXCEPTION; } - status = AMediaCodec_getName(sys->decoder, &codec_name); + status = sys->fnAMediaCodec_getName(sys->decoder, &codec_name); if (status != AMEDIA_OK) { WLog_Print(h264->log, WLOG_ERROR, "AMediaCodec_getName failed: %d", status); @@ -295,28 +429,28 @@ static BOOL mediacodec_init(H264_CONTEXT* h264) } WLog_Print(h264->log, WLOG_INFO, "MediaCodec using video/avc codec [%s]", codec_name); - AMediaCodec_releaseName(sys->decoder, codec_name); + sys->fnAMediaCodec_releaseName(sys->decoder, codec_name); - sys->inputFormat = AMediaFormat_new(); + sys->inputFormat = sys->fnAMediaFormat_new(); if (sys->inputFormat == NULL) { WLog_Print(h264->log, WLOG_ERROR, "AMediaFormat_new failed"); goto EXCEPTION; } - AMediaFormat_setString(sys->inputFormat, AMEDIAFORMAT_KEY_MIME, "video/avc"); - AMediaFormat_setInt32(sys->inputFormat, AMEDIAFORMAT_KEY_WIDTH, sys->width); - AMediaFormat_setInt32(sys->inputFormat, AMEDIAFORMAT_KEY_HEIGHT, sys->height); - AMediaFormat_setInt32(sys->inputFormat, AMEDIAFORMAT_KEY_COLOR_FORMAT, COLOR_FormatYUV420Planar); + sys->fnAMediaFormat_setString(sys->inputFormat, sys->gAMediaFormatKeyMime, "video/avc"); + sys->fnAMediaFormat_setInt32(sys->inputFormat, sys->gAMediaFormatKeyWidth, sys->width); + sys->fnAMediaFormat_setInt32(sys->inputFormat, sys->gAMediaFormatKeyHeight, sys->height); + sys->fnAMediaFormat_setInt32(sys->inputFormat, sys->gAMediaFormatKeyColorFormat, COLOR_FormatYUV420Planar); - media_format = AMediaFormat_toString(sys->inputFormat); + media_format = sys->fnAMediaFormat_toString(sys->inputFormat); if (media_format == NULL) { WLog_Print(h264->log, WLOG_ERROR, "AMediaFormat_toString failed"); goto EXCEPTION; } - status = AMediaCodec_configure(sys->decoder, sys->inputFormat, NULL, NULL, 0); + status = sys->fnAMediaCodec_configure(sys->decoder, sys->inputFormat, NULL, NULL, 0); if (status != AMEDIA_OK) { WLog_Print(h264->log, WLOG_ERROR, "AMediaCodec_configure failed: %d", status); @@ -324,7 +458,7 @@ static BOOL mediacodec_init(H264_CONTEXT* h264) } - inputFormat = AMediaCodec_getInputFormat(sys->decoder); + inputFormat = sys->fnAMediaCodec_getInputFormat(sys->decoder); if (inputFormat == NULL) { WLog_Print(h264->log, WLOG_ERROR, "AMediaCodec_getInputFormat failed"); @@ -332,7 +466,7 @@ static BOOL mediacodec_init(H264_CONTEXT* h264) } set_mediacodec_format(h264, &sys->inputFormat, inputFormat); - media_format = AMediaFormat_toString(sys->inputFormat); + media_format = sys->fnAMediaFormat_toString(sys->inputFormat); if (media_format == NULL) { WLog_Print(h264->log, WLOG_ERROR, "AMediaFormat_toString failed"); @@ -340,7 +474,7 @@ static BOOL mediacodec_init(H264_CONTEXT* h264) } WLog_Print(h264->log, WLOG_INFO, "Using MediaCodec with input MediaFormat [%s]", media_format); - outputFormat = AMediaCodec_getOutputFormat(sys->decoder); + outputFormat = sys->fnAMediaCodec_getOutputFormat(sys->decoder); if (outputFormat == NULL) { WLog_Print(h264->log, WLOG_ERROR, "AMediaCodec_getOutputFormat failed"); @@ -348,7 +482,7 @@ static BOOL mediacodec_init(H264_CONTEXT* h264) } set_mediacodec_format(h264, &sys->outputFormat, outputFormat); - media_format = AMediaFormat_toString(sys->outputFormat); + media_format = sys->fnAMediaFormat_toString(sys->outputFormat); if (media_format == NULL) { WLog_Print(h264->log, WLOG_ERROR, "AMediaFormat_toString failed"); @@ -358,7 +492,7 @@ static BOOL mediacodec_init(H264_CONTEXT* h264) WLog_Print(h264->log, WLOG_INFO, "Starting MediaCodec"); - status = AMediaCodec_start(sys->decoder); + status = sys->fnAMediaCodec_start(sys->decoder); if (status != AMEDIA_OK) { WLog_Print(h264->log, WLOG_ERROR, "AMediaCodec_start failed %d", status); From 7cc9a10e8e6343a3e885852ba2ecc5ab1c2b5d22 Mon Sep 17 00:00:00 2001 From: Ely Ronnen Date: Tue, 25 Jan 2022 17:35:10 +0200 Subject: [PATCH 048/496] handling small input buffer case (cherry picked from commit 5c2916aa590a8835e3abfc68c689a7f5865c6a85) --- libfreerdp/codec/h264_mediacodec.c | 53 +++++++++++++++++------------- 1 file changed, 30 insertions(+), 23 deletions(-) diff --git a/libfreerdp/codec/h264_mediacodec.c b/libfreerdp/codec/h264_mediacodec.c index 3cecc26809ed..dd718768bb64 100644 --- a/libfreerdp/codec/h264_mediacodec.c +++ b/libfreerdp/codec/h264_mediacodec.c @@ -248,33 +248,40 @@ static int mediacodec_decompress(H264_CONTEXT* h264, const BYTE* pSrcData, UINT3 while (true) { - inputBufferId = sys->fnAMediaCodec_dequeueInputBuffer(sys->decoder, -1); - if (inputBufferId < 0) + UINT32 inputBufferCurrnetOffset = 0; + while (inputBufferCurrnetOffset < SrcSize) { - WLog_Print(h264->log, WLOG_ERROR, "AMediaCodec_dequeueInputBuffer failed [%d]", inputBufferId); - // TODO: sleep? - continue; - } + UINT32 numberOfBytesToCopy = SrcSize - inputBufferCurrnetOffset; + inputBufferId = sys->fnAMediaCodec_dequeueInputBuffer(sys->decoder, -1); + if (inputBufferId < 0) + { + WLog_Print(h264->log, WLOG_ERROR, "AMediaCodec_dequeueInputBuffer failed [%d]", inputBufferId); + // TODO: sleep? + continue; + } - inputBuffer = sys->fnAMediaCodec_getInputBuffer(sys->decoder, inputBufferId, &inputBufferSize); - if (inputBuffer == NULL) - { - WLog_Print(h264->log, WLOG_ERROR, "AMediaCodec_getInputBuffer failed"); - return -1; - } + inputBuffer = sys->fnAMediaCodec_getInputBuffer(sys->decoder, inputBufferId, &inputBufferSize); + if (inputBuffer == NULL) + { + WLog_Print(h264->log, WLOG_ERROR, "AMediaCodec_getInputBuffer failed"); + return -1; + } - if (SrcSize > inputBufferSize) - { - WLog_Print(h264->log, WLOG_ERROR, "MediaCodec input buffer size is too small: got [%d] but wanted [%d]", inputBufferSize, SrcSize); - return -1; - } + if (numberOfBytesToCopy > inputBufferSize) + { + WLog_Print(h264->log, WLOG_WARN, "MediaCodec inputBufferSize: got [%d] but wanted [%d]", inputBufferSize, numberOfBytesToCopy); + numberOfBytesToCopy = inputBufferSize; + } - memcpy(inputBuffer, pSrcData, SrcSize); - status = sys->fnAMediaCodec_queueInputBuffer(sys->decoder, inputBufferId, 0, SrcSize, 0, 0); - if (status != AMEDIA_OK) - { - WLog_Print(h264->log, WLOG_ERROR, "Error AMediaCodec_queueInputBuffer %d", status); - return -1; + memcpy(inputBuffer, pSrcData + inputBufferCurrnetOffset, numberOfBytesToCopy); + inputBufferCurrnetOffset += numberOfBytesToCopy; + + status = sys->fnAMediaCodec_queueInputBuffer(sys->decoder, inputBufferId, 0, numberOfBytesToCopy, 0, 0); + if (status != AMEDIA_OK) + { + WLog_Print(h264->log, WLOG_ERROR, "Error AMediaCodec_queueInputBuffer %d", status); + return -1; + } } while (true) From 32f387bc76ece249a4dc633e19113b02e53fbd3a Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Wed, 26 Jan 2022 09:53:02 +0100 Subject: [PATCH 049/496] Fixed WITH_MEDIACODEC definition (cherry picked from commit 3a6365caad027d04d05dc74577fde3f28848db2a) --- cmake/ConfigOptions.cmake | 2 -- cmake/ConfigOptionsAndroid.cmake | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/cmake/ConfigOptions.cmake b/cmake/ConfigOptions.cmake index 27fdbfe943f9..1a6a359b7e9e 100644 --- a/cmake/ConfigOptions.cmake +++ b/cmake/ConfigOptions.cmake @@ -176,8 +176,6 @@ option(DEFINE_NO_DEPRECATED "Compile without legacy functions and symbols" OFF) if (ANDROID) include(ConfigOptionsAndroid) -else() - option(WITH_MEDIACODEC "Use MediaCodec API" OFF) endif(ANDROID) if (IOS) diff --git a/cmake/ConfigOptionsAndroid.cmake b/cmake/ConfigOptionsAndroid.cmake index 07dd604105f2..b241fabe7a29 100644 --- a/cmake/ConfigOptionsAndroid.cmake +++ b/cmake/ConfigOptionsAndroid.cmake @@ -19,4 +19,4 @@ option(WITH_OPENSLES "Enable sound and microphone redirection using OpenSLES" ON set(ANDROID_APP_TARGET_SDK 21 CACHE STRING "Application target android SDK") set(ANDROID_APP_MIN_SDK 14 CACHE STRING "Application minimum android SDK requirement") - +option(WITH_MEDIACODEC "Use MediaCodec API" ON) From 4101fe3be72dc63b322e74fafa3113062e188920 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Wed, 26 Jan 2022 09:53:26 +0100 Subject: [PATCH 050/496] Added code assertions, fixed loading order (cherry picked from commit 92d56b77f51e855718bcbb66ed581f2e7a829ac9) --- libfreerdp/CMakeLists.txt | 2 +- libfreerdp/codec/h264.c | 14 +- libfreerdp/codec/h264_mediacodec.c | 880 ++++++++++++++++------------- scripts/android-build.conf | 2 +- 4 files changed, 485 insertions(+), 413 deletions(-) diff --git a/libfreerdp/CMakeLists.txt b/libfreerdp/CMakeLists.txt index 0ec7a53f7e28..a121c75e15db 100644 --- a/libfreerdp/CMakeLists.txt +++ b/libfreerdp/CMakeLists.txt @@ -245,7 +245,7 @@ if(WIN32 AND WITH_MEDIA_FOUNDATION) endif() if(ANDROID AND WITH_MEDIACODEC) - set(CODEC_SRCS ${CODEC_SRCS} codec/h264_mediacodec.c) + list(APPEND CODEC_SRCS codec/h264_mediacodec.c) endif() freerdp_module_add(${CODEC_SRCS}) diff --git a/libfreerdp/codec/h264.c b/libfreerdp/codec/h264.c index bbdfd3f21adb..acc951d3f2c0 100644 --- a/libfreerdp/codec/h264.c +++ b/libfreerdp/codec/h264.c @@ -484,7 +484,7 @@ INT32 avc444_decompress(H264_CONTEXT* h264, BYTE op, RECTANGLE_16* regionRects, #define MAX_SUBSYSTEMS 10 static INIT_ONCE subsystems_once = INIT_ONCE_STATIC_INIT; -static H264_CONTEXT_SUBSYSTEM* subSystems[MAX_SUBSYSTEMS]; +static H264_CONTEXT_SUBSYSTEM* subSystems[MAX_SUBSYSTEMS] = { 0 }; #if defined(_WIN32) && defined(WITH_MEDIA_FOUNDATION) extern H264_CONTEXT_SUBSYSTEM g_Subsystem_MF; @@ -493,17 +493,17 @@ extern H264_CONTEXT_SUBSYSTEM g_Subsystem_MF; static BOOL CALLBACK h264_register_subsystems(PINIT_ONCE once, PVOID param, PVOID* context) { int i = 0; - ZeroMemory(subSystems, sizeof(subSystems)); -#if defined(_WIN32) && defined(WITH_MEDIA_FOUNDATION) + +#ifdef WITH_MEDIACODEC { - subSystems[i] = &g_Subsystem_MF; + extern H264_CONTEXT_SUBSYSTEM g_Subsystem_mediacodec; + subSystems[i] = &g_Subsystem_mediacodec; i++; } #endif -#ifdef WITH_MEDIACODEC +#if defined(_WIN32) && defined(WITH_MEDIA_FOUNDATION) { - extern H264_CONTEXT_SUBSYSTEM g_Subsystem_mediacodec; - subSystems[i] = &g_Subsystem_mediacodec; + subSystems[i] = &g_Subsystem_MF; i++; } #endif diff --git a/libfreerdp/codec/h264_mediacodec.c b/libfreerdp/codec/h264_mediacodec.c index dd718768bb64..a4c0e420b7ce 100644 --- a/libfreerdp/codec/h264_mediacodec.c +++ b/libfreerdp/codec/h264_mediacodec.c @@ -28,382 +28,454 @@ #include "h264.h" +#define RESOLVE_MEDIANDK_FUNC(sys, name) \ + { \ + sys->fn##name = GetProcAddress(sys->mediandkLibrary, #name); \ + if (sys->fn##name == NULL) \ + { \ + WLog_Print(h264->log, WLOG_ERROR, \ + "Error resolving function " #name " from libmediandk.so"); \ + return -1; \ + } \ + } + +#define RESOLVE_MEDIANDK_VARIABLE(sys, member, exported) \ + { \ + const char** temp = GetProcAddress(sys->mediandkLibrary, exported); \ + if (temp == NULL) \ + { \ + WLog_Print(h264->log, WLOG_ERROR, \ + "Error resolving variable " exported " from libmediandk.so"); \ + return -1; \ + } \ + sys->member = *temp; \ + } + typedef AMediaFormat* (*AMediaFormat_new_t)(); typedef media_status_t (*AMediaFormat_delete_t)(AMediaFormat*); typedef const char* (*AMediaFormat_toString_t)(AMediaFormat*); typedef void (*AMediaFormat_setInt32_t)(AMediaFormat*, const char*, int32_t); typedef void (*AMediaFormat_setString_t)(AMediaFormat*, const char*, const char*); -typedef AMediaCodec* (*AMediaCodec_createDecoderByType_t)(const char *); +typedef AMediaCodec* (*AMediaCodec_createDecoderByType_t)(const char*); typedef media_status_t (*AMediaCodec_delete_t)(AMediaCodec*); -typedef media_status_t (*AMediaCodec_configure_t)(AMediaCodec*, const AMediaFormat*, ANativeWindow*, AMediaCrypto *, uint32_t); +typedef media_status_t (*AMediaCodec_configure_t)(AMediaCodec*, const AMediaFormat*, ANativeWindow*, + AMediaCrypto*, uint32_t); typedef media_status_t (*AMediaCodec_start_t)(AMediaCodec*); typedef media_status_t (*AMediaCodec_stop_t)(AMediaCodec*); -typedef uint8_t* (*AMediaCodec_getInputBuffer_t)(AMediaCodec*, size_t, size_t *); -typedef uint8_t* (*AMediaCodec_getOutputBuffer_t)(AMediaCodec*, size_t, size_t *); +typedef uint8_t* (*AMediaCodec_getInputBuffer_t)(AMediaCodec*, size_t, size_t*); +typedef uint8_t* (*AMediaCodec_getOutputBuffer_t)(AMediaCodec*, size_t, size_t*); typedef ssize_t (*AMediaCodec_dequeueInputBuffer_t)(AMediaCodec*, int64_t); -typedef media_status_t (*AMediaCodec_queueInputBuffer_t)(AMediaCodec*, size_t, ssize_t, size_t, uint64_t, uint32_t); -typedef ssize_t (*AMediaCodec_dequeueOutputBuffer_t)(AMediaCodec*, AMediaCodecBufferInfo *, int64_t); +typedef media_status_t (*AMediaCodec_queueInputBuffer_t)(AMediaCodec*, size_t, ssize_t, size_t, + uint64_t, uint32_t); +typedef ssize_t (*AMediaCodec_dequeueOutputBuffer_t)(AMediaCodec*, AMediaCodecBufferInfo*, int64_t); typedef AMediaFormat* (*AMediaCodec_getOutputFormat_t)(AMediaCodec*); typedef media_status_t (*AMediaCodec_releaseOutputBuffer_t)(AMediaCodec*, size_t, bool); -typedef media_status_t (*AMediaCodec_setParameters_t)(AMediaCodec *, const AMediaFormat*); // 26 -typedef media_status_t (*AMediaCodec_getName_t)(AMediaCodec*, char**); // 28 -typedef void (*AMediaCodec_releaseName_t)(AMediaCodec*, char*); // 28 -typedef AMediaFormat* (*AMediaCodec_getInputFormat_t)(AMediaCodec*); // 28 +typedef media_status_t (*AMediaCodec_setParameters_t)(AMediaCodec*, const AMediaFormat*); // 26 +typedef media_status_t (*AMediaCodec_getName_t)(AMediaCodec*, char**); // 28 +typedef void (*AMediaCodec_releaseName_t)(AMediaCodec*, char*); // 28 +typedef AMediaFormat* (*AMediaCodec_getInputFormat_t)(AMediaCodec*); // 28 const int COLOR_FormatYUV420Planar = 19; const int COLOR_FormatYUV420Flexible = 0x7f420888; struct _H264_CONTEXT_MEDIACODEC { - AMediaCodec* decoder; - AMediaFormat* inputFormat; - AMediaFormat* outputFormat; - int32_t width; - int32_t height; - ssize_t currentOutputBufferIndex; - - // libmediandk.so imports - HMODULE mediandkLibrary; - - AMediaFormat_new_t fnAMediaFormat_new; - AMediaFormat_delete_t fnAMediaFormat_delete; - AMediaFormat_toString_t fnAMediaFormat_toString; - AMediaFormat_setInt32_t fnAMediaFormat_setInt32; - AMediaFormat_setString_t fnAMediaFormat_setString; - AMediaCodec_createDecoderByType_t fnAMediaCodec_createDecoderByType; - AMediaCodec_delete_t fnAMediaCodec_delete; - AMediaCodec_configure_t fnAMediaCodec_configure; - AMediaCodec_start_t fnAMediaCodec_start; - AMediaCodec_stop_t fnAMediaCodec_stop; - AMediaCodec_getInputBuffer_t fnAMediaCodec_getInputBuffer; - AMediaCodec_getOutputBuffer_t fnAMediaCodec_getOutputBuffer; - AMediaCodec_dequeueInputBuffer_t fnAMediaCodec_dequeueInputBuffer; - AMediaCodec_queueInputBuffer_t fnAMediaCodec_queueInputBuffer; - AMediaCodec_dequeueOutputBuffer_t fnAMediaCodec_dequeueOutputBuffer; - AMediaCodec_getOutputFormat_t fnAMediaCodec_getOutputFormat; - AMediaCodec_releaseOutputBuffer_t fnAMediaCodec_releaseOutputBuffer; - AMediaCodec_setParameters_t fnAMediaCodec_setParameters; - AMediaCodec_getName_t fnAMediaCodec_getName; - AMediaCodec_releaseName_t fnAMediaCodec_releaseName; - AMediaCodec_getInputFormat_t fnAMediaCodec_getInputFormat; - - const char* gAMediaFormatKeyMime; - const char* gAMediaFormatKeyWidth; - const char* gAMediaFormatKeyHeight; - const char* gAMediaFormatKeyColorFormat; + AMediaCodec* decoder; + AMediaFormat* inputFormat; + AMediaFormat* outputFormat; + int32_t width; + int32_t height; + ssize_t currentOutputBufferIndex; + + // libmediandk.so imports + HMODULE mediandkLibrary; + + AMediaFormat_new_t fnAMediaFormat_new; + AMediaFormat_delete_t fnAMediaFormat_delete; + AMediaFormat_toString_t fnAMediaFormat_toString; + AMediaFormat_setInt32_t fnAMediaFormat_setInt32; + AMediaFormat_setString_t fnAMediaFormat_setString; + AMediaCodec_createDecoderByType_t fnAMediaCodec_createDecoderByType; + AMediaCodec_delete_t fnAMediaCodec_delete; + AMediaCodec_configure_t fnAMediaCodec_configure; + AMediaCodec_start_t fnAMediaCodec_start; + AMediaCodec_stop_t fnAMediaCodec_stop; + AMediaCodec_getInputBuffer_t fnAMediaCodec_getInputBuffer; + AMediaCodec_getOutputBuffer_t fnAMediaCodec_getOutputBuffer; + AMediaCodec_dequeueInputBuffer_t fnAMediaCodec_dequeueInputBuffer; + AMediaCodec_queueInputBuffer_t fnAMediaCodec_queueInputBuffer; + AMediaCodec_dequeueOutputBuffer_t fnAMediaCodec_dequeueOutputBuffer; + AMediaCodec_getOutputFormat_t fnAMediaCodec_getOutputFormat; + AMediaCodec_releaseOutputBuffer_t fnAMediaCodec_releaseOutputBuffer; + AMediaCodec_setParameters_t fnAMediaCodec_setParameters; + AMediaCodec_getName_t fnAMediaCodec_getName; + AMediaCodec_releaseName_t fnAMediaCodec_releaseName; + AMediaCodec_getInputFormat_t fnAMediaCodec_getInputFormat; + + const char* gAMediaFormatKeyMime; + const char* gAMediaFormatKeyWidth; + const char* gAMediaFormatKeyHeight; + const char* gAMediaFormatKeyColorFormat; }; typedef struct _H264_CONTEXT_MEDIACODEC H264_CONTEXT_MEDIACODEC; static int load_libmediandk(H264_CONTEXT* h264) { - H264_CONTEXT_MEDIACODEC* sys = (H264_CONTEXT_MEDIACODEC*)h264->pSystemData; - WLog_Print(h264->log, WLOG_INFO, "MediaCodec Loading libmediandk.so"); - - sys->mediandkLibrary = LoadLibraryA("libmediandk.so"); - if (sys->mediandkLibrary == NULL) - { - WLog_Print(h264->log, WLOG_ERROR, "Error loading libmediandk.so"); - return -1; - } - -#define RESOLVE_MEDIANDK_FUNC(name) \ - sys->fn##name = GetProcAddress(sys->mediandkLibrary, #name); \ - if (sys->fn##name == NULL) \ - { \ - WLog_Print(h264->log, WLOG_ERROR, "Error resolving function " #name " from libmediandk.so"); \ - return -1; \ - } - - const char **temp = NULL; -#define RESOLVE_MEDIANDK_VARIABLE(member, exported) \ - temp = GetProcAddress(sys->mediandkLibrary, exported); \ - if (temp == NULL) \ - { \ - WLog_Print(h264->log, WLOG_ERROR, "Error resolving variable " exported " from libmediandk.so"); \ - return -1; \ - } \ - sys->member = *temp; - - RESOLVE_MEDIANDK_FUNC(AMediaFormat_new); - RESOLVE_MEDIANDK_FUNC(AMediaFormat_delete); - RESOLVE_MEDIANDK_FUNC(AMediaFormat_toString); - RESOLVE_MEDIANDK_FUNC(AMediaFormat_setInt32); - RESOLVE_MEDIANDK_FUNC(AMediaFormat_setString); - RESOLVE_MEDIANDK_FUNC(AMediaCodec_createDecoderByType); - RESOLVE_MEDIANDK_FUNC(AMediaCodec_delete); - RESOLVE_MEDIANDK_FUNC(AMediaCodec_configure); - RESOLVE_MEDIANDK_FUNC(AMediaCodec_start); - RESOLVE_MEDIANDK_FUNC(AMediaCodec_stop); - RESOLVE_MEDIANDK_FUNC(AMediaCodec_getInputBuffer); - RESOLVE_MEDIANDK_FUNC(AMediaCodec_getOutputBuffer); - RESOLVE_MEDIANDK_FUNC(AMediaCodec_dequeueInputBuffer); - RESOLVE_MEDIANDK_FUNC(AMediaCodec_queueInputBuffer); - RESOLVE_MEDIANDK_FUNC(AMediaCodec_dequeueOutputBuffer); - RESOLVE_MEDIANDK_FUNC(AMediaCodec_getOutputFormat); - RESOLVE_MEDIANDK_FUNC(AMediaCodec_releaseOutputBuffer); - RESOLVE_MEDIANDK_FUNC(AMediaCodec_setParameters); - RESOLVE_MEDIANDK_FUNC(AMediaCodec_getName); - RESOLVE_MEDIANDK_FUNC(AMediaCodec_releaseName); - RESOLVE_MEDIANDK_FUNC(AMediaCodec_getInputFormat); - - RESOLVE_MEDIANDK_VARIABLE(gAMediaFormatKeyMime, "AMEDIAFORMAT_KEY_MIME"); - RESOLVE_MEDIANDK_VARIABLE(gAMediaFormatKeyWidth, "AMEDIAFORMAT_KEY_WIDTH"); - RESOLVE_MEDIANDK_VARIABLE(gAMediaFormatKeyHeight, "AMEDIAFORMAT_KEY_HEIGHT"); - RESOLVE_MEDIANDK_VARIABLE(gAMediaFormatKeyColorFormat, "AMEDIAFORMAT_KEY_COLOR_FORMAT"); - - return 0; + H264_CONTEXT_MEDIACODEC* sys; + + WINPR_ASSERT(h264); + + sys = (H264_CONTEXT_MEDIACODEC*)h264->pSystemData; + WINPR_ASSERT(sys); + + WLog_Print(h264->log, WLOG_DEBUG, "MediaCodec Loading libmediandk.so"); + + sys->mediandkLibrary = LoadLibraryA("libmediandk.so"); + if (sys->mediandkLibrary == NULL) + { + WLog_Print(h264->log, WLOG_WARN, "Error loading libmediandk.so"); + return -1; + } + + RESOLVE_MEDIANDK_FUNC(sys, AMediaFormat_new); + RESOLVE_MEDIANDK_FUNC(sys, AMediaFormat_delete); + RESOLVE_MEDIANDK_FUNC(sys, AMediaFormat_toString); + RESOLVE_MEDIANDK_FUNC(sys, AMediaFormat_setInt32); + RESOLVE_MEDIANDK_FUNC(sys, AMediaFormat_setString); + RESOLVE_MEDIANDK_FUNC(sys, AMediaCodec_createDecoderByType); + RESOLVE_MEDIANDK_FUNC(sys, AMediaCodec_delete); + RESOLVE_MEDIANDK_FUNC(sys, AMediaCodec_configure); + RESOLVE_MEDIANDK_FUNC(sys, AMediaCodec_start); + RESOLVE_MEDIANDK_FUNC(sys, AMediaCodec_stop); + RESOLVE_MEDIANDK_FUNC(sys, AMediaCodec_getInputBuffer); + RESOLVE_MEDIANDK_FUNC(sys, AMediaCodec_getOutputBuffer); + RESOLVE_MEDIANDK_FUNC(sys, AMediaCodec_dequeueInputBuffer); + RESOLVE_MEDIANDK_FUNC(sys, AMediaCodec_queueInputBuffer); + RESOLVE_MEDIANDK_FUNC(sys, AMediaCodec_dequeueOutputBuffer); + RESOLVE_MEDIANDK_FUNC(sys, AMediaCodec_getOutputFormat); + RESOLVE_MEDIANDK_FUNC(sys, AMediaCodec_releaseOutputBuffer); + RESOLVE_MEDIANDK_FUNC(sys, AMediaCodec_setParameters); + RESOLVE_MEDIANDK_FUNC(sys, AMediaCodec_getName); + RESOLVE_MEDIANDK_FUNC(sys, AMediaCodec_releaseName); + RESOLVE_MEDIANDK_FUNC(sys, AMediaCodec_getInputFormat); + + RESOLVE_MEDIANDK_VARIABLE(sys, gAMediaFormatKeyMime, "AMEDIAFORMAT_KEY_MIME"); + RESOLVE_MEDIANDK_VARIABLE(sys, gAMediaFormatKeyWidth, "AMEDIAFORMAT_KEY_WIDTH"); + RESOLVE_MEDIANDK_VARIABLE(sys, gAMediaFormatKeyHeight, "AMEDIAFORMAT_KEY_HEIGHT"); + RESOLVE_MEDIANDK_VARIABLE(sys, gAMediaFormatKeyColorFormat, "AMEDIAFORMAT_KEY_COLOR_FORMAT"); + + return 0; } static void unload_libmediandk(H264_CONTEXT* h264) { - H264_CONTEXT_MEDIACODEC* sys = (H264_CONTEXT_MEDIACODEC*)h264->pSystemData; - if (NULL == sys->mediandkLibrary) - { - return; - } + H264_CONTEXT_MEDIACODEC* sys; + + WINPR_ASSERT(h264); - FreeLibrary(sys->mediandkLibrary); + sys = (H264_CONTEXT_MEDIACODEC*)h264->pSystemData; + WINPR_ASSERT(sys); + + if (NULL == sys->mediandkLibrary) + { + return; + } + + FreeLibrary(sys->mediandkLibrary); } -static void set_mediacodec_format(H264_CONTEXT* h264, AMediaFormat** formatVariable, AMediaFormat* newFormat) +static void set_mediacodec_format(H264_CONTEXT* h264, AMediaFormat** formatVariable, + AMediaFormat* newFormat) { - H264_CONTEXT_MEDIACODEC* sys = (H264_CONTEXT_MEDIACODEC*)h264->pSystemData; - media_status_t status = AMEDIA_OK; - - if (*formatVariable != NULL) - { - status = sys->fnAMediaFormat_delete(*formatVariable); - if (status != AMEDIA_OK) - { - WLog_Print(h264->log, WLOG_ERROR, "Error AMediaFormat_delete %d", status); - } - } - - *formatVariable = newFormat; + media_status_t status = AMEDIA_OK; + H264_CONTEXT_MEDIACODEC* sys; + + WINPR_ASSERT(h264); + WINPR_ASSERT(formatVariable); + WINPR_ASSERT(newFormat); + + sys = (H264_CONTEXT_MEDIACODEC*)h264->pSystemData; + WINPR_ASSERT(sys); + + if (*formatVariable != NULL) + { + status = sys->fnAMediaFormat_delete(*formatVariable); + if (status != AMEDIA_OK) + { + WLog_Print(h264->log, WLOG_ERROR, "Error AMediaFormat_delete %d", status); + } + } + + *formatVariable = newFormat; } static void release_current_outputbuffer(H264_CONTEXT* h264) { - H264_CONTEXT_MEDIACODEC* sys = (H264_CONTEXT_MEDIACODEC*)h264->pSystemData; - media_status_t status = AMEDIA_OK; + media_status_t status = AMEDIA_OK; + H264_CONTEXT_MEDIACODEC* sys; + + WINPR_ASSERT(h264); + sys = (H264_CONTEXT_MEDIACODEC*)h264->pSystemData; + WINPR_ASSERT(sys); - if (sys->currentOutputBufferIndex < 0) - { - return; - } + if (sys->currentOutputBufferIndex < 0) + { + return; + } - status = sys->fnAMediaCodec_releaseOutputBuffer(sys->decoder, sys->currentOutputBufferIndex, FALSE); - if (status != AMEDIA_OK) - { - WLog_Print(h264->log, WLOG_ERROR, "Error AMediaCodec_releaseOutputBuffer %d", status); - } + status = + sys->fnAMediaCodec_releaseOutputBuffer(sys->decoder, sys->currentOutputBufferIndex, FALSE); + if (status != AMEDIA_OK) + { + WLog_Print(h264->log, WLOG_ERROR, "Error AMediaCodec_releaseOutputBuffer %d", status); + } - sys->currentOutputBufferIndex = -1; + sys->currentOutputBufferIndex = -1; } static int mediacodec_compress(H264_CONTEXT* h264, const BYTE** pSrcYuv, const UINT32* pStride, BYTE** ppDstData, UINT32* pDstSize) { - WLog_Print(h264->log, WLOG_ERROR, "MediaCodec is not supported as an encoder"); - return -1; + WINPR_ASSERT(h264); + WINPR_ASSERT(pSrcYuv); + WINPR_ASSERT(pStride); + WINPR_ASSERT(ppDstData); + WINPR_ASSERT(pDstSize); + + WLog_Print(h264->log, WLOG_ERROR, "MediaCodec is not supported as an encoder"); + return -1; } static int mediacodec_decompress(H264_CONTEXT* h264, const BYTE* pSrcData, UINT32 SrcSize) { - H264_CONTEXT_MEDIACODEC* sys = (H264_CONTEXT_MEDIACODEC*)h264->pSystemData; - ssize_t inputBufferId = -1; - size_t inputBufferSize, outputBufferSize; - uint8_t* inputBuffer; - media_status_t status; - const char* media_format; - BYTE** pYUVData = h264->pYUVData; - UINT32* iStride = h264->iStride; - - release_current_outputbuffer(h264); - - if (sys->width == 0) - { - int32_t width = h264->width; - int32_t height = h264->height; - if (width % 16 != 0) - width += 16 - width % 16; - if (height % 16 != 0) - height += 16 - height % 16; - - WLog_Print(h264->log, WLOG_INFO, "MediaCodec setting width and height [%d,%d]", width, height); - sys->fnAMediaFormat_setInt32(sys->inputFormat, sys->gAMediaFormatKeyWidth, width); - sys->fnAMediaFormat_setInt32(sys->inputFormat, sys->gAMediaFormatKeyHeight, height); - - status = sys->fnAMediaCodec_setParameters(sys->decoder, sys->inputFormat); - if (status != AMEDIA_OK) - { - WLog_Print(h264->log, WLOG_ERROR, "AMediaCodec_setParameters failed: %d", status); - return -1; - } - - sys->width = width; - sys->height = height; - } - - while (true) - { - UINT32 inputBufferCurrnetOffset = 0; - while (inputBufferCurrnetOffset < SrcSize) - { - UINT32 numberOfBytesToCopy = SrcSize - inputBufferCurrnetOffset; - inputBufferId = sys->fnAMediaCodec_dequeueInputBuffer(sys->decoder, -1); - if (inputBufferId < 0) - { - WLog_Print(h264->log, WLOG_ERROR, "AMediaCodec_dequeueInputBuffer failed [%d]", inputBufferId); - // TODO: sleep? - continue; - } - - inputBuffer = sys->fnAMediaCodec_getInputBuffer(sys->decoder, inputBufferId, &inputBufferSize); - if (inputBuffer == NULL) - { - WLog_Print(h264->log, WLOG_ERROR, "AMediaCodec_getInputBuffer failed"); - return -1; - } - - if (numberOfBytesToCopy > inputBufferSize) - { - WLog_Print(h264->log, WLOG_WARN, "MediaCodec inputBufferSize: got [%d] but wanted [%d]", inputBufferSize, numberOfBytesToCopy); - numberOfBytesToCopy = inputBufferSize; - } - - memcpy(inputBuffer, pSrcData + inputBufferCurrnetOffset, numberOfBytesToCopy); - inputBufferCurrnetOffset += numberOfBytesToCopy; - - status = sys->fnAMediaCodec_queueInputBuffer(sys->decoder, inputBufferId, 0, numberOfBytesToCopy, 0, 0); - if (status != AMEDIA_OK) - { - WLog_Print(h264->log, WLOG_ERROR, "Error AMediaCodec_queueInputBuffer %d", status); - return -1; - } - } - - while (true) - { - AMediaCodecBufferInfo bufferInfo; - ssize_t outputBufferId = sys->fnAMediaCodec_dequeueOutputBuffer(sys->decoder, &bufferInfo, -1); - if (outputBufferId >= 0) - { - sys->currentOutputBufferIndex = outputBufferId; - - uint8_t* outputBuffer; - outputBuffer = sys->fnAMediaCodec_getOutputBuffer(sys->decoder, outputBufferId, &outputBufferSize); - sys->currentOutputBufferIndex = outputBufferId; - - if (outputBufferSize != (sys->width * sys->height + ((sys->width + 1) / 2) * ((sys->height + 1) / 2) * 2)) - { - WLog_Print(h264->log, WLOG_ERROR, "Error unexpected output buffer size %d", outputBufferSize); - return -1; - } - - // TODO: work with AImageReader and get AImage object instead of COLOR_FormatYUV420Planar buffer. - iStride[0] = sys->width; - iStride[1] = (sys->width + 1) / 2; - iStride[2] = (sys->width + 1) / 2; - pYUVData[0] = outputBuffer; - pYUVData[1] = outputBuffer + iStride[0] * sys->height; - pYUVData[2] = outputBuffer + iStride[0] * sys->height + iStride[1] * ((sys->height + 1) / 2); - break; - } - else if (outputBufferId == AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED) - { - AMediaFormat* outputFormat; - outputFormat = sys->fnAMediaCodec_getOutputFormat(sys->decoder); - if (outputFormat == NULL) - { - WLog_Print(h264->log, WLOG_ERROR, "AMediaCodec_getOutputFormat failed"); - return -1; - } - set_mediacodec_format(h264, &sys->outputFormat, outputFormat); - - media_format = sys->fnAMediaFormat_toString(sys->outputFormat); - if (media_format == NULL) - { - WLog_Print(h264->log, WLOG_ERROR, "AMediaFormat_toString failed"); - return -1; - } - } - else if (outputBufferId == AMEDIACODEC_INFO_TRY_AGAIN_LATER) - { - WLog_Print(h264->log, WLOG_WARN, "AMediaCodec_dequeueOutputBuffer need to try again later"); - // TODO: sleep? - } - else if (outputBufferId == AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED) - { - WLog_Print(h264->log, WLOG_WARN, "AMediaCodec_dequeueOutputBuffer returned deprecated value AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED, ignoring"); - } - else - { - WLog_Print(h264->log, WLOG_ERROR, "AMediaCodec_dequeueOutputBuffer returned unknown value [%d]", outputBufferId); - return -1; - } - } - - break; - } - - return 1; + ssize_t inputBufferId = -1; + size_t inputBufferSize, outputBufferSize; + uint8_t* inputBuffer; + media_status_t status; + const char* media_format; + BYTE** pYUVData; + UINT32* iStride; + H264_CONTEXT_MEDIACODEC* sys; + + WINPR_ASSERT(h264); + WINPR_ASSERT(pSrcData); + + sys = (H264_CONTEXT_MEDIACODEC*)h264->pSystemData; + WINPR_ASSERT(sys); + + pYUVData = h264->pYUVData; + WINPR_ASSERT(pYUVData); + + iStride = h264->iStride; + WINPR_ASSERT(iStride); + + release_current_outputbuffer(h264); + + if (sys->width == 0) + { + int32_t width = h264->width; + int32_t height = h264->height; + if (width % 16 != 0) + width += 16 - width % 16; + if (height % 16 != 0) + height += 16 - height % 16; + + WLog_Print(h264->log, WLOG_DEBUG, "MediaCodec setting width and height [%d,%d]", width, + height); + sys->fnAMediaFormat_setInt32(sys->inputFormat, sys->gAMediaFormatKeyWidth, width); + sys->fnAMediaFormat_setInt32(sys->inputFormat, sys->gAMediaFormatKeyHeight, height); + + status = sys->fnAMediaCodec_setParameters(sys->decoder, sys->inputFormat); + if (status != AMEDIA_OK) + { + WLog_Print(h264->log, WLOG_ERROR, "AMediaCodec_setParameters failed: %d", status); + return -1; + } + + sys->width = width; + sys->height = height; + } + + while (true) + { + UINT32 inputBufferCurrnetOffset = 0; + while (inputBufferCurrnetOffset < SrcSize) + { + UINT32 numberOfBytesToCopy = SrcSize - inputBufferCurrnetOffset; + inputBufferId = sys->fnAMediaCodec_dequeueInputBuffer(sys->decoder, -1); + if (inputBufferId < 0) + { + WLog_Print(h264->log, WLOG_ERROR, "AMediaCodec_dequeueInputBuffer failed [%d]", + inputBufferId); + // TODO: sleep? + continue; + } + + inputBuffer = + sys->fnAMediaCodec_getInputBuffer(sys->decoder, inputBufferId, &inputBufferSize); + if (inputBuffer == NULL) + { + WLog_Print(h264->log, WLOG_ERROR, "AMediaCodec_getInputBuffer failed"); + return -1; + } + + if (numberOfBytesToCopy > inputBufferSize) + { + WLog_Print(h264->log, WLOG_WARN, + "MediaCodec inputBufferSize: got [%d] but wanted [%d]", inputBufferSize, + numberOfBytesToCopy); + numberOfBytesToCopy = inputBufferSize; + } + + memcpy(inputBuffer, pSrcData + inputBufferCurrnetOffset, numberOfBytesToCopy); + inputBufferCurrnetOffset += numberOfBytesToCopy; + + status = sys->fnAMediaCodec_queueInputBuffer(sys->decoder, inputBufferId, 0, + numberOfBytesToCopy, 0, 0); + if (status != AMEDIA_OK) + { + WLog_Print(h264->log, WLOG_ERROR, "Error AMediaCodec_queueInputBuffer %d", status); + return -1; + } + } + + while (true) + { + AMediaCodecBufferInfo bufferInfo; + ssize_t outputBufferId = + sys->fnAMediaCodec_dequeueOutputBuffer(sys->decoder, &bufferInfo, -1); + if (outputBufferId >= 0) + { + sys->currentOutputBufferIndex = outputBufferId; + + uint8_t* outputBuffer; + outputBuffer = sys->fnAMediaCodec_getOutputBuffer(sys->decoder, outputBufferId, + &outputBufferSize); + sys->currentOutputBufferIndex = outputBufferId; + + if (outputBufferSize != (sys->width * sys->height + + ((sys->width + 1) / 2) * ((sys->height + 1) / 2) * 2)) + { + WLog_Print(h264->log, WLOG_ERROR, "Error unexpected output buffer size %d", + outputBufferSize); + return -1; + } + + // TODO: work with AImageReader and get AImage object instead of + // COLOR_FormatYUV420Planar buffer. + iStride[0] = sys->width; + iStride[1] = (sys->width + 1) / 2; + iStride[2] = (sys->width + 1) / 2; + pYUVData[0] = outputBuffer; + pYUVData[1] = outputBuffer + iStride[0] * sys->height; + pYUVData[2] = + outputBuffer + iStride[0] * sys->height + iStride[1] * ((sys->height + 1) / 2); + break; + } + else if (outputBufferId == AMEDIACODEC_INFO_OUTPUT_FORMAT_CHANGED) + { + AMediaFormat* outputFormat; + outputFormat = sys->fnAMediaCodec_getOutputFormat(sys->decoder); + if (outputFormat == NULL) + { + WLog_Print(h264->log, WLOG_ERROR, "AMediaCodec_getOutputFormat failed"); + return -1; + } + set_mediacodec_format(h264, &sys->outputFormat, outputFormat); + + media_format = sys->fnAMediaFormat_toString(sys->outputFormat); + if (media_format == NULL) + { + WLog_Print(h264->log, WLOG_ERROR, "AMediaFormat_toString failed"); + return -1; + } + } + else if (outputBufferId == AMEDIACODEC_INFO_TRY_AGAIN_LATER) + { + WLog_Print(h264->log, WLOG_WARN, + "AMediaCodec_dequeueOutputBuffer need to try again later"); + // TODO: sleep? + } + else if (outputBufferId == AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED) + { + WLog_Print(h264->log, WLOG_WARN, + "AMediaCodec_dequeueOutputBuffer returned deprecated value " + "AMEDIACODEC_INFO_OUTPUT_BUFFERS_CHANGED, ignoring"); + } + else + { + WLog_Print(h264->log, WLOG_ERROR, + "AMediaCodec_dequeueOutputBuffer returned unknown value [%d]", + outputBufferId); + return -1; + } + } + + break; + } + + return 1; } static void mediacodec_uninit(H264_CONTEXT* h264) { - H264_CONTEXT_MEDIACODEC* sys = (H264_CONTEXT_MEDIACODEC*)h264->pSystemData; - media_status_t status = AMEDIA_OK; - - WLog_Print(h264->log, WLOG_INFO, "Uninitializing MediaCodec"); + media_status_t status = AMEDIA_OK; + H264_CONTEXT_MEDIACODEC* sys; - if (!sys) - return; + WINPR_ASSERT(h264); + sys = (H264_CONTEXT_MEDIACODEC*)h264->pSystemData; - if (sys->decoder != NULL) - { - release_current_outputbuffer(h264); - status = sys->fnAMediaCodec_stop(sys->decoder); - if (status != AMEDIA_OK) - { - WLog_Print(h264->log, WLOG_ERROR, "Error AMediaCodec_stop %d", status); - } + WLog_Print(h264->log, WLOG_DEBUG, "Uninitializing MediaCodec"); - status = sys->fnAMediaCodec_delete(sys->decoder); - if (status != AMEDIA_OK) - { - WLog_Print(h264->log, WLOG_ERROR, "Error AMediaCodec_delete %d", status); - } + if (!sys) + return; - sys->decoder = NULL; - } + if (sys->decoder != NULL) + { + release_current_outputbuffer(h264); + status = sys->fnAMediaCodec_stop(sys->decoder); + if (status != AMEDIA_OK) + { + WLog_Print(h264->log, WLOG_ERROR, "Error AMediaCodec_stop %d", status); + } + + status = sys->fnAMediaCodec_delete(sys->decoder); + if (status != AMEDIA_OK) + { + WLog_Print(h264->log, WLOG_ERROR, "Error AMediaCodec_delete %d", status); + } + + sys->decoder = NULL; + } - set_mediacodec_format(h264, &sys->inputFormat, NULL); - set_mediacodec_format(h264, &sys->outputFormat, NULL); + set_mediacodec_format(h264, &sys->inputFormat, NULL); + set_mediacodec_format(h264, &sys->outputFormat, NULL); - unload_libmediandk(h264); + unload_libmediandk(h264); - free(sys); + free(sys); h264->pSystemData = NULL; } static BOOL mediacodec_init(H264_CONTEXT* h264) { - H264_CONTEXT_MEDIACODEC* sys; - media_status_t status; - const char* media_format; - char* codec_name; - AMediaFormat* inputFormat, *outputFormat; + H264_CONTEXT_MEDIACODEC* sys; + media_status_t status; + const char* media_format; + char* codec_name; + AMediaFormat *inputFormat, *outputFormat; - if (h264->Compressor) - { - WLog_Print(h264->log, WLOG_ERROR, "MediaCodec is not supported as an encoder"); - goto EXCEPTION; - } + WINPR_ASSERT(h264); - WLog_Print(h264->log, WLOG_INFO, "Initializing MediaCodec"); + if (h264->Compressor) + { + WLog_Print(h264->log, WLOG_ERROR, "MediaCodec is not supported as an encoder"); + goto EXCEPTION; + } + + WLog_Print(h264->log, WLOG_DEBUG, "Initializing MediaCodec"); sys = (H264_CONTEXT_MEDIACODEC*)calloc(1, sizeof(H264_CONTEXT_MEDIACODEC)); @@ -414,103 +486,103 @@ static BOOL mediacodec_init(H264_CONTEXT* h264) h264->pSystemData = (void*)sys; - if (load_libmediandk(h264) < 0) - { - goto EXCEPTION; - } - - sys->currentOutputBufferIndex = -1; - sys->width = sys->height = 0; // update when we're given the height and width - sys->decoder = sys->fnAMediaCodec_createDecoderByType("video/avc"); - if (sys->decoder == NULL) - { - WLog_Print(h264->log, WLOG_ERROR, "AMediaCodec_createCodecByName failed"); - goto EXCEPTION; - } - - status = sys->fnAMediaCodec_getName(sys->decoder, &codec_name); - if (status != AMEDIA_OK) - { - WLog_Print(h264->log, WLOG_ERROR, "AMediaCodec_getName failed: %d", status); - goto EXCEPTION; - } - - WLog_Print(h264->log, WLOG_INFO, "MediaCodec using video/avc codec [%s]", codec_name); - sys->fnAMediaCodec_releaseName(sys->decoder, codec_name); - - sys->inputFormat = sys->fnAMediaFormat_new(); - if (sys->inputFormat == NULL) - { - WLog_Print(h264->log, WLOG_ERROR, "AMediaFormat_new failed"); - goto EXCEPTION; - } - - sys->fnAMediaFormat_setString(sys->inputFormat, sys->gAMediaFormatKeyMime, "video/avc"); - sys->fnAMediaFormat_setInt32(sys->inputFormat, sys->gAMediaFormatKeyWidth, sys->width); - sys->fnAMediaFormat_setInt32(sys->inputFormat, sys->gAMediaFormatKeyHeight, sys->height); - sys->fnAMediaFormat_setInt32(sys->inputFormat, sys->gAMediaFormatKeyColorFormat, COLOR_FormatYUV420Planar); - - media_format = sys->fnAMediaFormat_toString(sys->inputFormat); - if (media_format == NULL) - { - WLog_Print(h264->log, WLOG_ERROR, "AMediaFormat_toString failed"); - goto EXCEPTION; - } - - status = sys->fnAMediaCodec_configure(sys->decoder, sys->inputFormat, NULL, NULL, 0); - if (status != AMEDIA_OK) - { - WLog_Print(h264->log, WLOG_ERROR, "AMediaCodec_configure failed: %d", status); - goto EXCEPTION; - } - - - inputFormat = sys->fnAMediaCodec_getInputFormat(sys->decoder); - if (inputFormat == NULL) - { - WLog_Print(h264->log, WLOG_ERROR, "AMediaCodec_getInputFormat failed"); - return -1; - } - set_mediacodec_format(h264, &sys->inputFormat, inputFormat); - - media_format = sys->fnAMediaFormat_toString(sys->inputFormat); - if (media_format == NULL) - { - WLog_Print(h264->log, WLOG_ERROR, "AMediaFormat_toString failed"); - goto EXCEPTION; - } - WLog_Print(h264->log, WLOG_INFO, "Using MediaCodec with input MediaFormat [%s]", media_format); - - outputFormat = sys->fnAMediaCodec_getOutputFormat(sys->decoder); - if (outputFormat == NULL) - { - WLog_Print(h264->log, WLOG_ERROR, "AMediaCodec_getOutputFormat failed"); - return -1; - } - set_mediacodec_format(h264, &sys->outputFormat, outputFormat); - - media_format = sys->fnAMediaFormat_toString(sys->outputFormat); - if (media_format == NULL) - { - WLog_Print(h264->log, WLOG_ERROR, "AMediaFormat_toString failed"); - goto EXCEPTION; - } - WLog_Print(h264->log, WLOG_INFO, "Using MediaCodec with output MediaFormat [%s]", media_format); - - - WLog_Print(h264->log, WLOG_INFO, "Starting MediaCodec"); - status = sys->fnAMediaCodec_start(sys->decoder); - if (status != AMEDIA_OK) - { - WLog_Print(h264->log, WLOG_ERROR, "AMediaCodec_start failed %d", status); - goto EXCEPTION; - } - - return TRUE; + if (load_libmediandk(h264) < 0) + { + goto EXCEPTION; + } + + sys->currentOutputBufferIndex = -1; + sys->width = sys->height = 0; // update when we're given the height and width + sys->decoder = sys->fnAMediaCodec_createDecoderByType("video/avc"); + if (sys->decoder == NULL) + { + WLog_Print(h264->log, WLOG_ERROR, "AMediaCodec_createCodecByName failed"); + goto EXCEPTION; + } + + status = sys->fnAMediaCodec_getName(sys->decoder, &codec_name); + if (status != AMEDIA_OK) + { + WLog_Print(h264->log, WLOG_ERROR, "AMediaCodec_getName failed: %d", status); + goto EXCEPTION; + } + + WLog_Print(h264->log, WLOG_DEBUG, "MediaCodec using video/avc codec [%s]", codec_name); + sys->fnAMediaCodec_releaseName(sys->decoder, codec_name); + + sys->inputFormat = sys->fnAMediaFormat_new(); + if (sys->inputFormat == NULL) + { + WLog_Print(h264->log, WLOG_ERROR, "AMediaFormat_new failed"); + goto EXCEPTION; + } + + sys->fnAMediaFormat_setString(sys->inputFormat, sys->gAMediaFormatKeyMime, "video/avc"); + sys->fnAMediaFormat_setInt32(sys->inputFormat, sys->gAMediaFormatKeyWidth, sys->width); + sys->fnAMediaFormat_setInt32(sys->inputFormat, sys->gAMediaFormatKeyHeight, sys->height); + sys->fnAMediaFormat_setInt32(sys->inputFormat, sys->gAMediaFormatKeyColorFormat, + COLOR_FormatYUV420Planar); + + media_format = sys->fnAMediaFormat_toString(sys->inputFormat); + if (media_format == NULL) + { + WLog_Print(h264->log, WLOG_ERROR, "AMediaFormat_toString failed"); + goto EXCEPTION; + } + + status = sys->fnAMediaCodec_configure(sys->decoder, sys->inputFormat, NULL, NULL, 0); + if (status != AMEDIA_OK) + { + WLog_Print(h264->log, WLOG_ERROR, "AMediaCodec_configure failed: %d", status); + goto EXCEPTION; + } + + inputFormat = sys->fnAMediaCodec_getInputFormat(sys->decoder); + if (inputFormat == NULL) + { + WLog_Print(h264->log, WLOG_ERROR, "AMediaCodec_getInputFormat failed"); + return -1; + } + set_mediacodec_format(h264, &sys->inputFormat, inputFormat); + + media_format = sys->fnAMediaFormat_toString(sys->inputFormat); + if (media_format == NULL) + { + WLog_Print(h264->log, WLOG_ERROR, "AMediaFormat_toString failed"); + goto EXCEPTION; + } + WLog_Print(h264->log, WLOG_DEBUG, "Using MediaCodec with input MediaFormat [%s]", media_format); + + outputFormat = sys->fnAMediaCodec_getOutputFormat(sys->decoder); + if (outputFormat == NULL) + { + WLog_Print(h264->log, WLOG_ERROR, "AMediaCodec_getOutputFormat failed"); + return -1; + } + set_mediacodec_format(h264, &sys->outputFormat, outputFormat); + + media_format = sys->fnAMediaFormat_toString(sys->outputFormat); + if (media_format == NULL) + { + WLog_Print(h264->log, WLOG_ERROR, "AMediaFormat_toString failed"); + goto EXCEPTION; + } + WLog_Print(h264->log, WLOG_DEBUG, "Using MediaCodec with output MediaFormat [%s]", + media_format); + + WLog_Print(h264->log, WLOG_DEBUG, "Starting MediaCodec"); + status = sys->fnAMediaCodec_start(sys->decoder); + if (status != AMEDIA_OK) + { + WLog_Print(h264->log, WLOG_ERROR, "AMediaCodec_start failed %d", status); + goto EXCEPTION; + } + + return TRUE; EXCEPTION: mediacodec_uninit(h264); return FALSE; } H264_CONTEXT_SUBSYSTEM g_Subsystem_mediacodec = { "MediaCodec", mediacodec_init, mediacodec_uninit, - mediacodec_decompress, mediacodec_compress }; + mediacodec_decompress, mediacodec_compress }; diff --git a/scripts/android-build.conf b/scripts/android-build.conf index 726449ebc175..9ef3eec56784 100644 --- a/scripts/android-build.conf +++ b/scripts/android-build.conf @@ -12,7 +12,7 @@ WITH_JPEG=0 WITH_OPENH264=0 WITH_OPENSSL=1 -WITH_FFMPEG=1 +WITH_FFMPEG=0 BUILD_DEPS=1 DEPS_ONLY=0 NDK_TARGET=26 From 4744643dc189a5fc325230e2f50689ad365ff5df Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Wed, 26 Jan 2022 10:11:05 +0100 Subject: [PATCH 051/496] Fixed statement expressions and missing goto (cherry picked from commit adcec5d9285f514870fa47b744e9cc6df72b245b) --- libfreerdp/codec/h264_mediacodec.c | 131 +++++++++++++++++++++-------- 1 file changed, 95 insertions(+), 36 deletions(-) diff --git a/libfreerdp/codec/h264_mediacodec.c b/libfreerdp/codec/h264_mediacodec.c index a4c0e420b7ce..693d0e7e44a3 100644 --- a/libfreerdp/codec/h264_mediacodec.c +++ b/libfreerdp/codec/h264_mediacodec.c @@ -29,29 +29,36 @@ #include "h264.h" #define RESOLVE_MEDIANDK_FUNC(sys, name) \ - { \ + ({ \ + BOOL rc = TRUE; \ sys->fn##name = GetProcAddress(sys->mediandkLibrary, #name); \ if (sys->fn##name == NULL) \ { \ WLog_Print(h264->log, WLOG_ERROR, \ "Error resolving function " #name " from libmediandk.so"); \ - return -1; \ + rc = FALSE; \ } \ - } + rc; \ + }) #define RESOLVE_MEDIANDK_VARIABLE(sys, member, exported) \ - { \ + ({ \ + BOOL rc = FALSE; \ const char** temp = GetProcAddress(sys->mediandkLibrary, exported); \ if (temp == NULL) \ { \ WLog_Print(h264->log, WLOG_ERROR, \ "Error resolving variable " exported " from libmediandk.so"); \ - return -1; \ } \ - sys->member = *temp; \ - } + else \ + { \ + sys->member = *temp; \ + rc = TRUE; \ + } \ + rc; \ + }) -typedef AMediaFormat* (*AMediaFormat_new_t)(); +typedef AMediaFormat* (*AMediaFormat_new_t)(void); typedef media_status_t (*AMediaFormat_delete_t)(AMediaFormat*); typedef const char* (*AMediaFormat_toString_t)(AMediaFormat*); typedef void (*AMediaFormat_setInt32_t)(AMediaFormat*, const char*, int32_t); @@ -122,6 +129,7 @@ typedef struct _H264_CONTEXT_MEDIACODEC H264_CONTEXT_MEDIACODEC; static int load_libmediandk(H264_CONTEXT* h264) { + BOOL rc; H264_CONTEXT_MEDIACODEC* sys; WINPR_ASSERT(h264); @@ -138,32 +146,83 @@ static int load_libmediandk(H264_CONTEXT* h264) return -1; } - RESOLVE_MEDIANDK_FUNC(sys, AMediaFormat_new); - RESOLVE_MEDIANDK_FUNC(sys, AMediaFormat_delete); - RESOLVE_MEDIANDK_FUNC(sys, AMediaFormat_toString); - RESOLVE_MEDIANDK_FUNC(sys, AMediaFormat_setInt32); - RESOLVE_MEDIANDK_FUNC(sys, AMediaFormat_setString); - RESOLVE_MEDIANDK_FUNC(sys, AMediaCodec_createDecoderByType); - RESOLVE_MEDIANDK_FUNC(sys, AMediaCodec_delete); - RESOLVE_MEDIANDK_FUNC(sys, AMediaCodec_configure); - RESOLVE_MEDIANDK_FUNC(sys, AMediaCodec_start); - RESOLVE_MEDIANDK_FUNC(sys, AMediaCodec_stop); - RESOLVE_MEDIANDK_FUNC(sys, AMediaCodec_getInputBuffer); - RESOLVE_MEDIANDK_FUNC(sys, AMediaCodec_getOutputBuffer); - RESOLVE_MEDIANDK_FUNC(sys, AMediaCodec_dequeueInputBuffer); - RESOLVE_MEDIANDK_FUNC(sys, AMediaCodec_queueInputBuffer); - RESOLVE_MEDIANDK_FUNC(sys, AMediaCodec_dequeueOutputBuffer); - RESOLVE_MEDIANDK_FUNC(sys, AMediaCodec_getOutputFormat); - RESOLVE_MEDIANDK_FUNC(sys, AMediaCodec_releaseOutputBuffer); - RESOLVE_MEDIANDK_FUNC(sys, AMediaCodec_setParameters); - RESOLVE_MEDIANDK_FUNC(sys, AMediaCodec_getName); - RESOLVE_MEDIANDK_FUNC(sys, AMediaCodec_releaseName); - RESOLVE_MEDIANDK_FUNC(sys, AMediaCodec_getInputFormat); - - RESOLVE_MEDIANDK_VARIABLE(sys, gAMediaFormatKeyMime, "AMEDIAFORMAT_KEY_MIME"); - RESOLVE_MEDIANDK_VARIABLE(sys, gAMediaFormatKeyWidth, "AMEDIAFORMAT_KEY_WIDTH"); - RESOLVE_MEDIANDK_VARIABLE(sys, gAMediaFormatKeyHeight, "AMEDIAFORMAT_KEY_HEIGHT"); - RESOLVE_MEDIANDK_VARIABLE(sys, gAMediaFormatKeyColorFormat, "AMEDIAFORMAT_KEY_COLOR_FORMAT"); + rc = RESOLVE_MEDIANDK_FUNC(sys, AMediaFormat_new); + if (!rc) + return -1; + rc = RESOLVE_MEDIANDK_FUNC(sys, AMediaFormat_delete); + if (!rc) + return -1; + rc = RESOLVE_MEDIANDK_FUNC(sys, AMediaFormat_toString); + if (!rc) + return -1; + rc = RESOLVE_MEDIANDK_FUNC(sys, AMediaFormat_setInt32); + if (!rc) + return -1; + rc = RESOLVE_MEDIANDK_FUNC(sys, AMediaFormat_setString); + if (!rc) + return -1; + rc = RESOLVE_MEDIANDK_FUNC(sys, AMediaCodec_createDecoderByType); + if (!rc) + return -1; + rc = RESOLVE_MEDIANDK_FUNC(sys, AMediaCodec_delete); + if (!rc) + return -1; + rc = RESOLVE_MEDIANDK_FUNC(sys, AMediaCodec_configure); + if (!rc) + return -1; + rc = RESOLVE_MEDIANDK_FUNC(sys, AMediaCodec_start); + if (!rc) + return -1; + rc = RESOLVE_MEDIANDK_FUNC(sys, AMediaCodec_stop); + if (!rc) + return -1; + rc = RESOLVE_MEDIANDK_FUNC(sys, AMediaCodec_getInputBuffer); + if (!rc) + return -1; + rc = RESOLVE_MEDIANDK_FUNC(sys, AMediaCodec_getOutputBuffer); + if (!rc) + return -1; + rc = RESOLVE_MEDIANDK_FUNC(sys, AMediaCodec_dequeueInputBuffer); + if (!rc) + return -1; + rc = RESOLVE_MEDIANDK_FUNC(sys, AMediaCodec_queueInputBuffer); + if (!rc) + return -1; + rc = RESOLVE_MEDIANDK_FUNC(sys, AMediaCodec_dequeueOutputBuffer); + if (!rc) + return -1; + rc = RESOLVE_MEDIANDK_FUNC(sys, AMediaCodec_getOutputFormat); + if (!rc) + return -1; + rc = RESOLVE_MEDIANDK_FUNC(sys, AMediaCodec_releaseOutputBuffer); + if (!rc) + return -1; + rc = RESOLVE_MEDIANDK_FUNC(sys, AMediaCodec_setParameters); + if (!rc) + return -1; + rc = RESOLVE_MEDIANDK_FUNC(sys, AMediaCodec_getName); + if (!rc) + return -1; + rc = RESOLVE_MEDIANDK_FUNC(sys, AMediaCodec_releaseName); + if (!rc) + return -1; + rc = RESOLVE_MEDIANDK_FUNC(sys, AMediaCodec_getInputFormat); + if (!rc) + return -1; + + rc = RESOLVE_MEDIANDK_VARIABLE(sys, gAMediaFormatKeyMime, "AMEDIAFORMAT_KEY_MIME"); + if (!rc) + return -1; + rc = RESOLVE_MEDIANDK_VARIABLE(sys, gAMediaFormatKeyWidth, "AMEDIAFORMAT_KEY_WIDTH"); + if (!rc) + return -1; + rc = RESOLVE_MEDIANDK_VARIABLE(sys, gAMediaFormatKeyHeight, "AMEDIAFORMAT_KEY_HEIGHT"); + if (!rc) + return -1; + rc = RESOLVE_MEDIANDK_VARIABLE(sys, gAMediaFormatKeyColorFormat, + "AMEDIAFORMAT_KEY_COLOR_FORMAT"); + if (!rc) + return -1; return 0; } @@ -541,7 +600,7 @@ static BOOL mediacodec_init(H264_CONTEXT* h264) if (inputFormat == NULL) { WLog_Print(h264->log, WLOG_ERROR, "AMediaCodec_getInputFormat failed"); - return -1; + goto EXCEPTION; } set_mediacodec_format(h264, &sys->inputFormat, inputFormat); @@ -557,7 +616,7 @@ static BOOL mediacodec_init(H264_CONTEXT* h264) if (outputFormat == NULL) { WLog_Print(h264->log, WLOG_ERROR, "AMediaCodec_getOutputFormat failed"); - return -1; + goto EXCEPTION; } set_mediacodec_format(h264, &sys->outputFormat, outputFormat); From f41a4656d82ccc6376d72657a6edf23d757df5f8 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Wed, 26 Jan 2022 10:11:58 +0100 Subject: [PATCH 052/496] Added missing include (cherry picked from commit 4867dea562b3fab2788153a1e338011d1fbc8d35) --- libfreerdp/codec/h264_mediacodec.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libfreerdp/codec/h264_mediacodec.c b/libfreerdp/codec/h264_mediacodec.c index 693d0e7e44a3..a803d1f5da5c 100644 --- a/libfreerdp/codec/h264_mediacodec.c +++ b/libfreerdp/codec/h264_mediacodec.c @@ -18,6 +18,7 @@ */ #include +#include #include #include @@ -28,6 +29,8 @@ #include "h264.h" +#define WINPR_ASSERT(x) assert(x) + #define RESOLVE_MEDIANDK_FUNC(sys, name) \ ({ \ BOOL rc = TRUE; \ From c8c2ca26e92a1f06d37d49109b39d9b6042b6aa0 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Wed, 26 Jan 2022 10:25:35 +0100 Subject: [PATCH 053/496] Updated changelog --- ChangeLog | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/ChangeLog b/ChangeLog index bf4e50034e10..c710916a225f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,20 @@ +# 2022-XX-YY Version 2.X.Y + +Noteworthy changes: +* Android FFMPEG support + +Fixed issues: +* Backported #7574: FFMPEG 5.0 support +* Backported #7578: FFMPEG 5.0 support +* Backported #7580: Fixed device hotplugging +* Backported #7583: GetUserNameExA: Prefer getpwuid_r over getlogin_r over getlogin +* Backported #7585: Android Mediacodec support + +Important notes: + +For a complete and detailed change log since the last release run: +git log 2.5.0..2.X.Y + # 2022-01-12 Version 2.5.0 Noteworthy changes: From f703947f56c584ebfff4d30eb6d8de7c070a426f Mon Sep 17 00:00:00 2001 From: akallabeth Date: Thu, 13 Jan 2022 15:37:06 +0100 Subject: [PATCH 054/496] Updated android build dependencies (cherry picked from commit aa89d01af45367b29ba6e3c20c7a23230cfb50c2) --- .../aFreeRDP/src/main/AndroidManifest.xml | 2 + client/Android/Studio/build.gradle | 12 +++--- .../Android/Studio/freeRDPCore/build.gradle | 7 +++- .../freeRDPCore/src/main/AndroidManifest.xml | 7 ++++ .../freerdpcore/services/LibFreeRDP.java | 42 ++++++++++++------- .../gradle/wrapper/gradle-wrapper.properties | 2 +- 6 files changed, 49 insertions(+), 23 deletions(-) diff --git a/client/Android/Studio/aFreeRDP/src/main/AndroidManifest.xml b/client/Android/Studio/aFreeRDP/src/main/AndroidManifest.xml index 7d7558d52c63..8c46bc9fe6d3 100644 --- a/client/Android/Studio/aFreeRDP/src/main/AndroidManifest.xml +++ b/client/Android/Studio/aFreeRDP/src/main/AndroidManifest.xml @@ -14,6 +14,7 @@ ext { versionName = properties.get('VERSION_NAME', getVersionName()) versionCode = properties.get('VERSION_CODE', 26) - compileApi = properties.get('COMPILE_API', 30) - targetApi = properties.get('TARGET_API', 30) + compileApi = properties.get('COMPILE_API', 31) + targetApi = properties.get('TARGET_API', 31) minApi = properties.get('MIN_API', 21) - toolsVersion = properties.get('TOOLS_VERSION', '30.0.3') + toolsVersion = properties.get('TOOLS_VERSION', '31.0.0') println '----------------- Project configuration -------------------' println 'VERSION_NAME: ' + versionName @@ -49,17 +49,17 @@ ext { buildscript { repositories { - jcenter() + mavenCentral() google() } dependencies { - classpath 'com.android.tools.build:gradle:4.1.2' + classpath 'com.android.tools.build:gradle:7.0.4' } } allprojects { repositories { - jcenter() + mavenCentral() google() } } diff --git a/client/Android/Studio/freeRDPCore/build.gradle b/client/Android/Studio/freeRDPCore/build.gradle index 713ad3722c96..2afb7037be8f 100644 --- a/client/Android/Studio/freeRDPCore/build.gradle +++ b/client/Android/Studio/freeRDPCore/build.gradle @@ -8,8 +8,6 @@ android { minSdkVersion rootProject.ext.minApi targetSdkVersion rootProject.ext.targetApi vectorDrawables.useSupportLibrary = true - versionCode = rootProject.ext.versionCode - versionName = rootProject.ext.versionName } buildTypes { @@ -22,6 +20,11 @@ android { renderscriptDebuggable true } } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + ndkVersion '23.1.7779620' } dependencies { diff --git a/client/Android/Studio/freeRDPCore/src/main/AndroidManifest.xml b/client/Android/Studio/freeRDPCore/src/main/AndroidManifest.xml index ef59325d2f3a..34613339f535 100644 --- a/client/Android/Studio/freeRDPCore/src/main/AndroidManifest.xml +++ b/client/Android/Studio/freeRDPCore/src/main/AndroidManifest.xml @@ -22,6 +22,7 @@ @@ -49,6 +50,7 @@ @@ -61,11 +63,13 @@ diff --git a/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/services/LibFreeRDP.java b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/services/LibFreeRDP.java index 66f8cff6aa81..2add27050491 100644 --- a/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/services/LibFreeRDP.java +++ b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/services/LibFreeRDP.java @@ -23,27 +23,19 @@ import com.freerdp.freerdpcore.presentation.ApplicationSettingsActivity; import java.util.ArrayList; +import java.util.List; public class LibFreeRDP { private static final String TAG = "LibFreeRDP"; private static EventListener listener; - private static boolean mHasH264 = true; + private static boolean mHasH264 = false; private static final LongSparseArray mInstanceState = new LongSparseArray<>(); - static + private static boolean tryLoad(String[] libraries) { - final String h264 = "openh264"; - final String[] libraries = { h264, - "freerdp-openssl", - "ssl", - "crypto", - "jpeg", - "winpr2", - "freerdp2", - "freerdp-client2", - "freerdp-android2" }; + boolean success = false; final String LD_PATH = System.getProperty("java.library.path"); for (String lib : libraries) @@ -52,15 +44,37 @@ public class LibFreeRDP { Log.v(TAG, "Trying to load library " + lib + " from LD_PATH: " + LD_PATH); System.loadLibrary(lib); + success = true; } catch (UnsatisfiedLinkError e) { Log.e(TAG, "Failed to load library " + lib + ": " + e.toString()); - if (lib.equals(h264)) + success = false; + break; + } + } + + return success; + } + + private static boolean tryLoad(String library) { - mHasH264 = false; + return tryLoad(new String[] { library }); } + static + { + mHasH264 = tryLoad("openh264"); + if (!mHasH264) + mHasH264 = tryLoad("avcodec"); + + try + { + System.loadLibrary("freerdp-android3"); } + catch (UnsatisfiedLinkError e) + { + Log.e(TAG, "Failed to load library: " + e.toString()); + throw e; } } diff --git a/client/Android/Studio/gradle/wrapper/gradle-wrapper.properties b/client/Android/Studio/gradle/wrapper/gradle-wrapper.properties index cbba7b087961..6b5305e2178a 100644 --- a/client/Android/Studio/gradle/wrapper/gradle-wrapper.properties +++ b/client/Android/Studio/gradle/wrapper/gradle-wrapper.properties @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-bin.zip From f676cfab1c0b9c036da82fd50dd377ccdc2b306b Mon Sep 17 00:00:00 2001 From: akallabeth Date: Thu, 13 Jan 2022 15:37:49 +0100 Subject: [PATCH 055/496] Enabled swscale for android build (cherry picked from commit 198548e3fb0830e2e34ac170cf4c349e81a36612) --- scripts/android-build-ffmpeg.sh | 2 +- scripts/android-build-freerdp.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/android-build-ffmpeg.sh b/scripts/android-build-ffmpeg.sh index 3e40582ceb41..ea9c6980d80f 100755 --- a/scripts/android-build-ffmpeg.sh +++ b/scripts/android-build-ffmpeg.sh @@ -125,7 +125,7 @@ function build { --enable-jni --enable-mediacodec \ --enable-shared \ --disable-stripping \ - --disable-programs --disable-doc --disable-avdevice --disable-avfilter --disable-avformat --disable-swscale + --disable-programs --disable-doc --disable-avdevice --disable-avfilter --disable-avformat common_run make clean common_run make -j diff --git a/scripts/android-build-freerdp.sh b/scripts/android-build-freerdp.sh index a2c85e8ce314..5ca9525e55dc 100755 --- a/scripts/android-build-freerdp.sh +++ b/scripts/android-build-freerdp.sh @@ -152,7 +152,7 @@ do --target $NDK_TARGET \ --tag $FFMPEG_TAG fi - CMAKE_CMD_ARGS="$CMAKE_CMD_ARGS -DWITH_FFMPEG=ON" + CMAKE_CMD_ARGS="$CMAKE_CMD_ARGS -DWITH_FFMPEG=ON -DWITH_SWCALE=ON" else CMAKE_CMD_ARGS="$CMAKE_CMD_ARGS -DWITH_FFMPEG=OFF" fi From 1cfd6585454655481aa5aed74c4964c11b03e047 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Thu, 13 Jan 2022 17:19:54 +0100 Subject: [PATCH 056/496] Updated build tools (cherry picked from commit 4f451fe61742d2655ca25968972756a55f2b2146) --- client/Android/Studio/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/Android/Studio/build.gradle b/client/Android/Studio/build.gradle index de1a179cd963..5d32b4f71eaa 100644 --- a/client/Android/Studio/build.gradle +++ b/client/Android/Studio/build.gradle @@ -33,7 +33,7 @@ ext { compileApi = properties.get('COMPILE_API', 31) targetApi = properties.get('TARGET_API', 31) minApi = properties.get('MIN_API', 21) - toolsVersion = properties.get('TOOLS_VERSION', '31.0.0') + toolsVersion = properties.get('TOOLS_VERSION', '31.0.3') println '----------------- Project configuration -------------------' println 'VERSION_NAME: ' + versionName From e586bace2195f67c5ed72afa9a1ab30b23fecbdf Mon Sep 17 00:00:00 2001 From: akallabeth Date: Fri, 14 Jan 2022 09:51:36 +0100 Subject: [PATCH 057/496] Fixed #7541: maximum resolution, removed unused strings (cherry picked from commit 29f2e52618d3e1ea9d0da25538dca9523e97c3c2) --- .../Studio/freeRDPCore/src/main/res/values-ja/strings.xml | 1 - .../Studio/freeRDPCore/src/main/res/xml/screen_settings.xml | 4 ++-- .../freeRDPCore/src/main/res/xml/screen_settings_3g.xml | 4 ++-- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/client/Android/Studio/freeRDPCore/src/main/res/values-ja/strings.xml b/client/Android/Studio/freeRDPCore/src/main/res/values-ja/strings.xml index 39561c693fff..d4cd51f05cee 100644 --- a/client/Android/Studio/freeRDPCore/src/main/res/values-ja/strings.xml +++ b/client/Android/Studio/freeRDPCore/src/main/res/values-ja/strings.xml @@ -115,7 +115,6 @@ 遠隔実行するプログラム 作業フォルダ Async channel - Async transport Async input Async update コンソールモード diff --git a/client/Android/Studio/freeRDPCore/src/main/res/xml/screen_settings.xml b/client/Android/Studio/freeRDPCore/src/main/res/xml/screen_settings.xml index d5016f7be7ba..9666f8dd0336 100644 --- a/client/Android/Studio/freeRDPCore/src/main/res/xml/screen_settings.xml +++ b/client/Android/Studio/freeRDPCore/src/main/res/xml/screen_settings.xml @@ -28,14 +28,14 @@ android:title="@string/settings_width" android:singleLine="true" freerdp:bounds_default="640" - freerdp:bounds_max="2048" + freerdp:bounds_max="65536" freerdp:bounds_min="640" /> diff --git a/client/Android/Studio/freeRDPCore/src/main/res/xml/screen_settings_3g.xml b/client/Android/Studio/freeRDPCore/src/main/res/xml/screen_settings_3g.xml index c9db098fc5f0..79a9f0f7db3f 100644 --- a/client/Android/Studio/freeRDPCore/src/main/res/xml/screen_settings_3g.xml +++ b/client/Android/Studio/freeRDPCore/src/main/res/xml/screen_settings_3g.xml @@ -28,14 +28,14 @@ android:singleLine="true" android:title="@string/settings_width" freerdp:bounds_default="640" - freerdp:bounds_max="2048" + freerdp:bounds_max="65536" freerdp:bounds_min="640" /> From 12357dbe81047a6f1a9511f043427db08599f189 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Fri, 14 Jan 2022 09:52:13 +0100 Subject: [PATCH 058/496] Fixed build tool version (cherry picked from commit abcc0fcf9e646c8393cb397121dfed8f0507ce35) --- client/Android/Studio/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/Android/Studio/build.gradle b/client/Android/Studio/build.gradle index 5d32b4f71eaa..de1a179cd963 100644 --- a/client/Android/Studio/build.gradle +++ b/client/Android/Studio/build.gradle @@ -33,7 +33,7 @@ ext { compileApi = properties.get('COMPILE_API', 31) targetApi = properties.get('TARGET_API', 31) minApi = properties.get('MIN_API', 21) - toolsVersion = properties.get('TOOLS_VERSION', '31.0.3') + toolsVersion = properties.get('TOOLS_VERSION', '31.0.0') println '----------------- Project configuration -------------------' println 'VERSION_NAME: ' + versionName From 3e3e1f0293fa5e678b890eaece3c3c861ccc0d27 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Fri, 14 Jan 2022 13:12:09 +0100 Subject: [PATCH 059/496] Skip library version from android glue library --- client/Android/CMakeLists.txt | 2 +- .../main/java/com/freerdp/freerdpcore/services/LibFreeRDP.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/client/Android/CMakeLists.txt b/client/Android/CMakeLists.txt index 7fcdb6354a92..b3473a98af7e 100644 --- a/client/Android/CMakeLists.txt +++ b/client/Android/CMakeLists.txt @@ -48,7 +48,7 @@ set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} winpr freerdp freerdp-client) set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} dl) set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} jnigraphics) -set_target_properties(${MODULE_NAME} PROPERTIES OUTPUT_NAME ${MODULE_NAME}${FREERDP_API_VERSION}) +#set_target_properties(${MODULE_NAME} PROPERTIES OUTPUT_NAME ${MODULE_NAME}${FREERDP_API_VERSION}) target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR} COMPONENT libraries EXPORT AndroidTargets) diff --git a/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/services/LibFreeRDP.java b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/services/LibFreeRDP.java index 2add27050491..211afa196f4a 100644 --- a/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/services/LibFreeRDP.java +++ b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/services/LibFreeRDP.java @@ -69,7 +69,7 @@ private static boolean tryLoad(String library) try { - System.loadLibrary("freerdp-android3"); + System.loadLibrary("freerdp-android"); } catch (UnsatisfiedLinkError e) { From 6ea43d1d73dfc56a393496717b5356bd705063cc Mon Sep 17 00:00:00 2001 From: akallabeth Date: Fri, 14 Jan 2022 13:14:17 +0100 Subject: [PATCH 060/496] Increased required android version to 6.0 (API 23) There are library loader issues with OpenSSL below that API version. (Undefined symbols most likely due to versioning mismatches of the OpenSSL build) --- client/Android/Studio/build.gradle | 2 +- scripts/android-build-release.conf | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/client/Android/Studio/build.gradle b/client/Android/Studio/build.gradle index de1a179cd963..f83d3b43b14f 100644 --- a/client/Android/Studio/build.gradle +++ b/client/Android/Studio/build.gradle @@ -32,7 +32,7 @@ ext { versionCode = properties.get('VERSION_CODE', 26) compileApi = properties.get('COMPILE_API', 31) targetApi = properties.get('TARGET_API', 31) - minApi = properties.get('MIN_API', 21) + minApi = properties.get('MIN_API', 23) toolsVersion = properties.get('TOOLS_VERSION', '31.0.0') println '----------------- Project configuration -------------------' diff --git a/scripts/android-build-release.conf b/scripts/android-build-release.conf index 1c8f7a14b093..d1834efbe5ec 100644 --- a/scripts/android-build-release.conf +++ b/scripts/android-build-release.conf @@ -15,7 +15,7 @@ WITH_OPENSSL=1 WITH_FFMPEG=1 BUILD_DEPS=1 DEPS_ONLY=0 -NDK_TARGET=21 +NDK_TARGET=23 JPEG_TAG=master OPENH264_TAG=v1.8.0 # NOTE: NDK r15c or earlier needed in --openh624-ndk for v1.8.0 From 56bc23a3ac83fc14fad2b390a43136579e887cdc Mon Sep 17 00:00:00 2001 From: akallabeth Date: Sun, 16 Jan 2022 14:25:07 +0100 Subject: [PATCH 061/496] Fixed missing ARCH argument to build FFMPEG --- scripts/android-build-ffmpeg.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/android-build-ffmpeg.sh b/scripts/android-build-ffmpeg.sh index ea9c6980d80f..066b18ccaf9a 100755 --- a/scripts/android-build-ffmpeg.sh +++ b/scripts/android-build-ffmpeg.sh @@ -171,7 +171,7 @@ do ;; esac - build + build $ARCH common_run cp -L $BUILD_DST/$ARCH/lib/*.so $BUILD_DST/$ARCH/ common_run export PATH=$OLD_PATH From 004a56d5595c217fb78882984a8511fbf93288e3 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Sun, 16 Jan 2022 14:36:32 +0100 Subject: [PATCH 062/496] Fixed typo in android build script --- scripts/android-build-freerdp.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/android-build-freerdp.sh b/scripts/android-build-freerdp.sh index 5ca9525e55dc..eb5eeba20f50 100755 --- a/scripts/android-build-freerdp.sh +++ b/scripts/android-build-freerdp.sh @@ -152,9 +152,9 @@ do --target $NDK_TARGET \ --tag $FFMPEG_TAG fi - CMAKE_CMD_ARGS="$CMAKE_CMD_ARGS -DWITH_FFMPEG=ON -DWITH_SWCALE=ON" + CMAKE_CMD_ARGS="$CMAKE_CMD_ARGS -DWITH_FFMPEG=ON -DWITH_SWSCALE=ON -DWITH_DSP_FFMPEG=ON" else - CMAKE_CMD_ARGS="$CMAKE_CMD_ARGS -DWITH_FFMPEG=OFF" + CMAKE_CMD_ARGS="$CMAKE_CMD_ARGS -DWITH_FFMPEG=OFF -DWITH_SWSCALE=OFF -DWITH_DSP_FFMPEG=OFF" fi if [ $WITH_OPENSSL -ne 0 ]; then From 85e598d6bb47a6781cf77c7eaaf6659476e7b154 Mon Sep 17 00:00:00 2001 From: Hans-Peter Jansen Date: Tue, 14 Sep 2021 10:54:58 +0200 Subject: [PATCH 063/496] Remove unused codec x264 (cherry picked from commit 310bb7ae6b9bd57aeb96cd470aa4fe0f122d21c0) --- .travis.yml | 1 - CMakeLists.txt | 5 ----- config.h.in | 1 - 3 files changed, 7 deletions(-) diff --git a/.travis.yml b/.travis.yml index 615a6d47a6d7..b5dc259aaefd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -41,7 +41,6 @@ addons: - libgsm1-dev - libavcodec-dev - libavutil-dev - - libx264-dev - libxext-dev - ninja-build - libsystemd-dev diff --git a/CMakeLists.txt b/CMakeLists.txt index 9d921100029a..0ed4682e7ef5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -720,10 +720,6 @@ set(JPEG_FEATURE_TYPE "OPTIONAL") set(JPEG_FEATURE_PURPOSE "codec") set(JPEG_FEATURE_DESCRIPTION "use JPEG library") -set(X264_FEATURE_TYPE "OPTIONAL") -set(X264_FEATURE_PURPOSE "codec") -set(X264_FEATURE_DESCRIPTION "use x264 library") - set(OPENH264_FEATURE_TYPE "OPTIONAL") set(OPENH264_FEATURE_PURPOSE "codec") set(OPENH264_FEATURE_DESCRIPTION "use OpenH264 library") @@ -831,7 +827,6 @@ find_feature(PCSC ${PCSC_FEATURE_TYPE} ${PCSC_FEATURE_PURPOSE} ${PCSC_FEATURE_DE find_feature(FFmpeg ${FFMPEG_FEATURE_TYPE} ${FFMPEG_FEATURE_PURPOSE} ${FFMPEG_FEATURE_DESCRIPTION}) find_feature(JPEG ${JPEG_FEATURE_TYPE} ${JPEG_FEATURE_PURPOSE} ${JPEG_FEATURE_DESCRIPTION}) -find_feature(x264 ${X264_FEATURE_TYPE} ${X264_FEATURE_PURPOSE} ${X264_FEATURE_DESCRIPTION}) find_feature(OpenH264 ${OPENH264_FEATURE_TYPE} ${OPENH264_FEATURE_PURPOSE} ${OPENH264_FEATURE_DESCRIPTION}) find_feature(OpenCL ${OPENCL_FEATURE_TYPE} ${OPENCL_FEATURE_PURPOSE} ${OPENCL_FEATURE_DESCRIPTION}) find_feature(GSM ${GSM_FEATURE_TYPE} ${GSM_FEATURE_PURPOSE} ${GSM_FEATURE_DESCRIPTION}) diff --git a/config.h.in b/config.h.in index bd4946118f64..26fd7ba7da09 100644 --- a/config.h.in +++ b/config.h.in @@ -64,7 +64,6 @@ #cmakedefine WITH_FFMPEG #cmakedefine WITH_DSP_EXPERIMENTAL #cmakedefine WITH_DSP_FFMPEG -#cmakedefine WITH_X264 #cmakedefine WITH_OPENCL #cmakedefine WITH_MEDIA_FOUNDATION #cmakedefine WITH_MEDIACODEC From 4b73d86880dc42f53a52a3869a48c49222d27790 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Wed, 26 Jan 2022 10:57:28 +0100 Subject: [PATCH 064/496] Removed x264 related files from build --- cmake/Findx264.cmake | 33 ---------- libfreerdp/CMakeLists.txt | 6 -- libfreerdp/codec/h264.c | 7 --- libfreerdp/codec/h264_x264.c | 117 ----------------------------------- 4 files changed, 163 deletions(-) delete mode 100644 cmake/Findx264.cmake delete mode 100644 libfreerdp/codec/h264_x264.c diff --git a/cmake/Findx264.cmake b/cmake/Findx264.cmake deleted file mode 100644 index f8df4754eeed..000000000000 --- a/cmake/Findx264.cmake +++ /dev/null @@ -1,33 +0,0 @@ - -if (X264_INCLUDE_DIR AND X264_LIBRARY) - set(X264_FIND_QUIETLY TRUE) -endif (X264_INCLUDE_DIR AND X264_LIBRARY) - -find_path(X264_INCLUDE_DIR NAMES x264.h - PATH_SUFFIXES include - HINTS ${X264_ROOT}) -find_library(X264_LIBRARY - NAMES x264 - PATH_SUFFIXES lib - HINTS ${X264_ROOT}) - -include(FindPackageHandleStandardArgs) -FIND_PACKAGE_HANDLE_STANDARD_ARGS(x264 DEFAULT_MSG X264_LIBRARY X264_INCLUDE_DIR) - -if (X264_INCLUDE_DIR AND X264_LIBRARY) - set(X264_FOUND TRUE) - set(X264_LIBRARIES ${X264_LIBRARY}) -endif (X264_INCLUDE_DIR AND X264_LIBRARY) - -if (X264_FOUND) - if (NOT X264_FIND_QUIETLY) - message(STATUS "Found x264: ${X264_LIBRARIES}") - endif (NOT X264_FIND_QUIETLY) -else (X264_FOUND) - if (X264_FIND_REQUIRED) - message(FATAL_ERROR "x264 was not found") - endif(X264_FIND_REQUIRED) -endif (X264_FOUND) - -mark_as_advanced(X264_INCLUDE_DIR X264_LIBRARY) - diff --git a/libfreerdp/CMakeLists.txt b/libfreerdp/CMakeLists.txt index a121c75e15db..5b7461498bfe 100644 --- a/libfreerdp/CMakeLists.txt +++ b/libfreerdp/CMakeLists.txt @@ -220,12 +220,6 @@ if(WITH_JPEG) freerdp_library_add(${JPEG_LIBRARIES}) endif() -if(WITH_X264) - set(CODEC_SRCS ${CODEC_SRCS} codec/h264_x264.c) - freerdp_include_directory_add(${X264_INCLUDE_DIR}) - freerdp_library_add(${X264_LIBRARIES}) -endif() - if(WITH_OPENH264) set(CODEC_SRCS ${CODEC_SRCS} codec/h264_openh264.c) freerdp_include_directory_add(${OPENH264_INCLUDE_DIR}) diff --git a/libfreerdp/codec/h264.c b/libfreerdp/codec/h264.c index acc951d3f2c0..36b5a7cba8d7 100644 --- a/libfreerdp/codec/h264.c +++ b/libfreerdp/codec/h264.c @@ -520,13 +520,6 @@ static BOOL CALLBACK h264_register_subsystems(PINIT_ONCE once, PVOID param, PVOI subSystems[i] = &g_Subsystem_libavcodec; i++; } -#endif -#ifdef WITH_X264 - { - extern H264_CONTEXT_SUBSYSTEM g_Subsystem_x264; - subSystems[i] = &g_Subsystem_x264; - i++; - } #endif return i > 0; } diff --git a/libfreerdp/codec/h264_x264.c b/libfreerdp/codec/h264_x264.c deleted file mode 100644 index c3600946c9b1..000000000000 --- a/libfreerdp/codec/h264_x264.c +++ /dev/null @@ -1,117 +0,0 @@ -/** - * FreeRDP: A Remote Desktop Protocol Implementation - * H.264 Bitmap Compression - * - * Copyright 2015 Marc-André Moreau - * - * 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. - */ - -#define NAL_UNKNOWN X264_NAL_UNKNOWN -#define NAL_SLICE X264_NAL_SLICE -#define NAL_SLICE_DPA X264_NAL_SLICE_DPA -#define NAL_SLICE_DPB X264_NAL_SLICE_DPB -#define NAL_SLICE_DPC X264_NAL_SLICE_DPC -#define NAL_SLICE_IDR X264_NAL_SLICE_IDR -#define NAL_SEI X264_NAL_SEI -#define NAL_SPS X264_NAL_SPS -#define NAL_PPS X264_NAL_PPS -#define NAL_AUD X264_NAL_AUD -#define NAL_FILLER X264_NAL_FILLER - -#define NAL_PRIORITY_DISPOSABLE X264_NAL_PRIORITY_DISPOSABLE -#define NAL_PRIORITY_LOW X264_NAL_PRIORITY_LOW -#define NAL_PRIORITY_HIGH X264_NAL_PRIORITY_HIGH -#define NAL_PRIORITY_HIGHEST X264_NAL_PRIORITY_HIGHEST - -#include -#include -#include - -#error "X264 backend not implemented, please review your configuration!" - -struct _H264_CONTEXT_X264 -{ - void* dummy; -}; -typedef struct _H264_CONTEXT_X264 H264_CONTEXT_X264; - -static int x264_decompress(H264_CONTEXT* h264, BYTE* pSrcData, UINT32 SrcSize) -{ - // H264_CONTEXT_X264* sys = (H264_CONTEXT_X264*) h264->pSystemData; - return -1; -} - -static int x264_compress(H264_CONTEXT* h264, const BYTE** ppSrcYuv, const UINT32* pStride, - BYTE** ppDstData, UINT32* pDstSize) -{ - // H264_CONTEXT_X264* sys = (H264_CONTEXT_X264*) h264->pSystemData; - return -1; -} - -static void x264_uninit(H264_CONTEXT* h264) -{ - H264_CONTEXT_X264* sys = (H264_CONTEXT_X264*)h264->pSystemData; - - if (sys) - { - free(sys); - h264->pSystemData = NULL; - } -} - -static BOOL x264_init(H264_CONTEXT* h264) -{ - H264_CONTEXT_X264* sys; - h264->numSystemData = 1; - sys = (H264_CONTEXT_X264*)calloc(h264->numSystemData, sizeof(H264_CONTEXT_X264)); - - if (!sys) - { - goto EXCEPTION; - } - - h264->pSystemData = (void*)sys; - - if (h264->Compressor) - { - } - else - { - } - - return TRUE; -EXCEPTION: - x264_uninit(h264); - return FALSE; -} - -H264_CONTEXT_SUBSYSTEM g_Subsystem_x264 = { "x264", x264_init, x264_uninit, x264_decompress, - x264_compress }; - -#undef NAL_UNKNOWN -#undef NAL_SLICE -#undef NAL_SLICE_DPA -#undef NAL_SLICE_DPB -#undef NAL_SLICE_DPC -#undef NAL_SLICE_IDR -#undef NAL_SEI -#undef NAL_SPS -#undef NAL_PPS -#undef NAL_AUD -#undef NAL_FILLER - -#undef NAL_PRIORITY_DISPOSABLE -#undef NAL_PRIORITY_LOW -#undef NAL_PRIORITY_HIGH -#undef NAL_PRIORITY_HIGHEST From 00900c5cbb9a43c32456116e431ff2be13c0f5dd Mon Sep 17 00:00:00 2001 From: akallabeth Date: Fri, 14 Jan 2022 10:15:17 +0100 Subject: [PATCH 065/496] Updated version and changelog. --- CMakeLists.txt | 2 +- ChangeLog | 9 ++++++--- client/Android/Studio/build.gradle | 2 +- client/Android/Studio/freeRDPCore/build.gradle | 7 ++----- client/Android/android_freerdp.c | 2 +- winpr/CMakeLists.txt | 2 +- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 0ed4682e7ef5..d7a9cdbd136f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -85,7 +85,7 @@ if ($ENV{BUILD_NUMBER}) endif() set(WITH_LIBRARY_VERSIONING "ON") -set(RAW_VERSION_STRING "2.5.0") +set(RAW_VERSION_STRING "2.5.1") if(EXISTS "${CMAKE_SOURCE_DIR}/.source_tag") file(READ ${CMAKE_SOURCE_DIR}/.source_tag RAW_VERSION_STRING) elseif(USE_VERSION_FROM_GIT_TAG) diff --git a/ChangeLog b/ChangeLog index c710916a225f..d9bb8c4f68c9 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,9 +1,12 @@ -# 2022-XX-YY Version 2.X.Y +# 2022-XX-YY Version 2.5.1 Noteworthy changes: -* Android FFMPEG support +* Backported android FFMPEG build scripts +* Updated android build dependencies Fixed issues: +* Backported #7293: Remove unused codec x264 +* Backported #7541: Allow resolutions larger 2048x2048 * Backported #7574: FFMPEG 5.0 support * Backported #7578: FFMPEG 5.0 support * Backported #7580: Fixed device hotplugging @@ -13,7 +16,7 @@ Fixed issues: Important notes: For a complete and detailed change log since the last release run: -git log 2.5.0..2.X.Y +git log 2.5.0..2.5.1 # 2022-01-12 Version 2.5.0 diff --git a/client/Android/Studio/build.gradle b/client/Android/Studio/build.gradle index f83d3b43b14f..313e404a9223 100644 --- a/client/Android/Studio/build.gradle +++ b/client/Android/Studio/build.gradle @@ -29,7 +29,7 @@ def getVersionName = { -> ext { versionName = properties.get('VERSION_NAME', getVersionName()) - versionCode = properties.get('VERSION_CODE', 26) + versionCode = properties.get('VERSION_CODE', 27) compileApi = properties.get('COMPILE_API', 31) targetApi = properties.get('TARGET_API', 31) minApi = properties.get('MIN_API', 23) diff --git a/client/Android/Studio/freeRDPCore/build.gradle b/client/Android/Studio/freeRDPCore/build.gradle index 2afb7037be8f..713ad3722c96 100644 --- a/client/Android/Studio/freeRDPCore/build.gradle +++ b/client/Android/Studio/freeRDPCore/build.gradle @@ -8,6 +8,8 @@ android { minSdkVersion rootProject.ext.minApi targetSdkVersion rootProject.ext.targetApi vectorDrawables.useSupportLibrary = true + versionCode = rootProject.ext.versionCode + versionName = rootProject.ext.versionName } buildTypes { @@ -20,11 +22,6 @@ android { renderscriptDebuggable true } } - compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 - } - ndkVersion '23.1.7779620' } dependencies { diff --git a/client/Android/android_freerdp.c b/client/Android/android_freerdp.c index 2cdc020c2f67..ea259edbe364 100644 --- a/client/Android/android_freerdp.c +++ b/client/Android/android_freerdp.c @@ -56,7 +56,7 @@ #define TAG CLIENT_TAG("android") /* Defines the JNI version supported by this library. */ -#define FREERDP_JNI_VERSION "2.5.0" +#define FREERDP_JNI_VERSION "2.5.1" static void android_OnChannelConnectedEventHandler(void* context, ChannelConnectedEventArgs* e) { diff --git a/winpr/CMakeLists.txt b/winpr/CMakeLists.txt index 620f9a78b161..400357b3de98 100644 --- a/winpr/CMakeLists.txt +++ b/winpr/CMakeLists.txt @@ -51,7 +51,7 @@ if (NOT WIN32) endif() # Soname versioning -set(RAW_VERSION_STRING "2.5.0") +set(RAW_VERSION_STRING "2.5.1") if(EXISTS "${CMAKE_SOURCE_DIR}/.source_tag") file(READ ${CMAKE_SOURCE_DIR}/.source_tag RAW_VERSION_STRING) elseif(USE_VERSION_FROM_GIT_TAG) From 3dfe3e8b57e00c4fcf36715e90e659705f4c01bc Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Wed, 26 Jan 2022 12:09:40 +0100 Subject: [PATCH 066/496] Fixed too eager assert. (cherry picked from commit 2ed5a6912b73cec62e32194ee95431698faef206) --- libfreerdp/codec/h264_mediacodec.c | 1 - 1 file changed, 1 deletion(-) diff --git a/libfreerdp/codec/h264_mediacodec.c b/libfreerdp/codec/h264_mediacodec.c index a803d1f5da5c..ba207e5e56df 100644 --- a/libfreerdp/codec/h264_mediacodec.c +++ b/libfreerdp/codec/h264_mediacodec.c @@ -255,7 +255,6 @@ static void set_mediacodec_format(H264_CONTEXT* h264, AMediaFormat** formatVaria WINPR_ASSERT(h264); WINPR_ASSERT(formatVariable); - WINPR_ASSERT(newFormat); sys = (H264_CONTEXT_MEDIACODEC*)h264->pSystemData; WINPR_ASSERT(sys); From d807f6dbbc46b221764b9a0ff6a23656b7dbcee1 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Wed, 26 Jan 2022 12:09:50 +0100 Subject: [PATCH 067/496] Added better way to check for H264 support * Added a function that actually tests, if H264 is working. (cherry picked from commit 95db33af44d68d1c7a08c3675e6c41694214d3bf) --- .../freerdpcore/services/LibFreeRDP.java | 33 ++++++++++++++++--- client/Android/android_freerdp.c | 13 +++++++- 2 files changed, 40 insertions(+), 6 deletions(-) diff --git a/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/services/LibFreeRDP.java b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/services/LibFreeRDP.java index 211afa196f4a..0f4a92188a6e 100644 --- a/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/services/LibFreeRDP.java +++ b/client/Android/Studio/freeRDPCore/src/main/java/com/freerdp/freerdpcore/services/LibFreeRDP.java @@ -24,6 +24,10 @@ import java.util.ArrayList; import java.util.List; +import java.util.Objects; +import java.util.regex.MatchResult; +import java.util.regex.Matcher; +import java.util.regex.Pattern; public class LibFreeRDP { @@ -63,14 +67,31 @@ private static boolean tryLoad(String library) } static { - mHasH264 = tryLoad("openh264"); - if (!mHasH264) - mHasH264 = tryLoad("avcodec"); - try { System.loadLibrary("freerdp-android"); - } + String version = freerdp_get_jni_version(); + Pattern pattern = Pattern.compile("^(\\d+)\\.(\\d+)\\.(\\d+).*"); + Matcher matcher = pattern.matcher(version); + if (!matcher.matches() || (matcher.groupCount() < 3)) + throw new RuntimeException("APK broken: native library version " + version + + " does not meet requirements!"); + int major = Integer.parseInt(Objects.requireNonNull(matcher.group(1))); + int minor = Integer.parseInt(Objects.requireNonNull(matcher.group(2))); + int patch = Integer.parseInt(Objects.requireNonNull(matcher.group(3))); + + if (major > 2) + mHasH264 = freerdp_has_h264(); + else if (minor > 5) + mHasH264 = freerdp_has_h264(); + else if ((minor == 5) && (patch >= 1)) + mHasH264 = freerdp_has_h264(); + else + throw new RuntimeException("APK broken: native library version " + version + + " does not meet requirements!"); + Log.i(TAG, "Successfully loaded native library. H264 is " + + (mHasH264 ? "supported" : "not available")); + } catch (UnsatisfiedLinkError e) { Log.e(TAG, "Failed to load library: " + e.toString()); @@ -83,6 +104,8 @@ public static boolean hasH264Support() return mHasH264; } + private static native boolean freerdp_has_h264(); + private static native String freerdp_get_jni_version(); private static native String freerdp_get_version(); diff --git a/client/Android/android_freerdp.c b/client/Android/android_freerdp.c index ea259edbe364..bab8f80c775b 100644 --- a/client/Android/android_freerdp.c +++ b/client/Android/android_freerdp.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -1024,6 +1025,15 @@ static jstring JNICALL jni_freerdp_get_jni_version(JNIEnv* env, jclass cls) return (*env)->NewStringUTF(env, FREERDP_JNI_VERSION); } +static jboolean JNICALL jni_freerdp_has_h264(JNIEnv* env, jclass cls) +{ + H264_CONTEXT* ctx = h264_context_new(FALSE); + if (!ctx) + return JNI_FALSE; + h264_context_free(ctx); + return JNI_TRUE; +} + static jstring JNICALL jni_freerdp_get_version(JNIEnv* env, jclass cls) { return (*env)->NewStringUTF(env, freerdp_get_version_string()); @@ -1062,7 +1072,8 @@ static JNINativeMethod methods[] = { { "freerdp_send_cursor_event", "(JIII)Z", &jni_freerdp_send_cursor_event }, { "freerdp_send_key_event", "(JIZ)Z", &jni_freerdp_send_key_event }, { "freerdp_send_unicodekey_event", "(JIZ)Z", &jni_freerdp_send_unicodekey_event }, - { "freerdp_send_clipboard_data", "(JLjava/lang/String;)Z", &jni_freerdp_send_clipboard_data } + { "freerdp_send_clipboard_data", "(JLjava/lang/String;)Z", &jni_freerdp_send_clipboard_data }, + { "freerdp_has_h264", "()Z", &jni_freerdp_has_h264 } }; static jclass gJavaActivityClass = NULL; From 53671014357da644a09caa19431baa2b62d5c55d Mon Sep 17 00:00:00 2001 From: dance Date: Wed, 26 Jan 2022 19:52:35 +0300 Subject: [PATCH 068/496] wayland: fixed memory corruption issue (write to free'd memory) pass window and buffer index to buffer_release listener, so that it fetches actual pointer to released buffer by wayland, instead of directly passing a pointer to the UwacBuffer, which could result in heap-use-after-free --- uwac/libuwac/uwac-priv.h | 8 ++++++++ uwac/libuwac/uwac-window.c | 14 +++++++++++--- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/uwac/libuwac/uwac-priv.h b/uwac/libuwac/uwac-priv.h index aed38986afe3..cbc570409eae 100644 --- a/uwac/libuwac/uwac-priv.h +++ b/uwac/libuwac/uwac-priv.h @@ -255,6 +255,14 @@ struct uwac_window int pointer_current_cursor; }; +/**@brief data to pass to wl_buffer release listener */ +struct uwac_buffer_release_data +{ + UwacWindow* window; + int bufferIdx; +}; +typedef struct uwac_buffer_release_data UwacBufferReleaseData; + /* in uwa-display.c */ UwacEvent* UwacDisplayNewEvent(UwacDisplay* d, int type); int UwacDisplayWatchFd(UwacDisplay* display, int fd, uint32_t events, UwacTask* task); diff --git a/uwac/libuwac/uwac-window.c b/uwac/libuwac/uwac-window.c index bf70af2f1d87..8e6f08dba62f 100644 --- a/uwac/libuwac/uwac-window.c +++ b/uwac/libuwac/uwac-window.c @@ -46,7 +46,8 @@ static int bppFromShmFormat(enum wl_shm_format format) static void buffer_release(void* data, struct wl_buffer* buffer) { - UwacBuffer* uwacBuffer = (UwacBuffer*)data; + UwacBufferReleaseData* releaseData = data; + UwacBuffer* uwacBuffer = &releaseData->window->buffers[releaseData->bufferIdx]; uwacBuffer->used = false; } @@ -64,7 +65,10 @@ static void UwacWindowDestroyBuffers(UwacWindow* w) #else region16_uninit(&buffer->damage); #endif + UwacBufferReleaseData* releaseData = + (UwacBufferReleaseData*)wl_buffer_get_user_data(buffer->wayland_buffer); wl_buffer_destroy(buffer->wayland_buffer); + free(releaseData); munmap(buffer->data, buffer->size); } @@ -342,7 +346,8 @@ int UwacWindowShmAllocBuffers(UwacWindow* w, int nbuffers, int allocSize, uint32 for (i = 0; i < nbuffers; i++) { - UwacBuffer* buffer = &w->buffers[w->nbuffers + i]; + int bufferIdx = w->nbuffers + i; + UwacBuffer* buffer = &w->buffers[bufferIdx]; #ifdef HAVE_PIXMAN_REGION pixman_region32_init(&buffer->damage); #else @@ -352,7 +357,10 @@ int UwacWindowShmAllocBuffers(UwacWindow* w, int nbuffers, int allocSize, uint32 buffer->size = allocSize; buffer->wayland_buffer = wl_shm_pool_create_buffer(pool, allocSize * i, width, height, w->stride, format); - wl_buffer_add_listener(buffer->wayland_buffer, &buffer_listener, buffer); + UwacBufferReleaseData* listener_data = xmalloc(sizeof(UwacBufferReleaseData)); + listener_data->window = w; + listener_data->bufferIdx = bufferIdx; + wl_buffer_add_listener(buffer->wayland_buffer, &buffer_listener, listener_data); } wl_shm_pool_destroy(pool); From 4743cf58f215e777a6ce741e5ab76cfa506ac213 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Thu, 27 Jan 2022 09:28:35 +0100 Subject: [PATCH 069/496] Updated changelog --- ChangeLog | 1 + 1 file changed, 1 insertion(+) diff --git a/ChangeLog b/ChangeLog index d9bb8c4f68c9..231c81174957 100644 --- a/ChangeLog +++ b/ChangeLog @@ -5,6 +5,7 @@ Noteworthy changes: * Updated android build dependencies Fixed issues: +* Backported #7426: Wayland memory corruption * Backported #7293: Remove unused codec x264 * Backported #7541: Allow resolutions larger 2048x2048 * Backported #7574: FFMPEG 5.0 support From 1527cfcd2c5e2c865c6066c3810437a99f30a49b Mon Sep 17 00:00:00 2001 From: zbstao Date: Thu, 27 Jan 2022 16:21:48 +0800 Subject: [PATCH 070/496] Added pduLength check in rdpgfx_read_header function if pduLength is zero will lead to an infinite loop in rdpgfx_recv_pdu function. (cherry picked from commit 5b8db18f260a38d73a30b212718fd6d7e103bc5b) --- channels/rdpgfx/rdpgfx_common.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/channels/rdpgfx/rdpgfx_common.c b/channels/rdpgfx/rdpgfx_common.c index 79bbc9e787d9..b10ea8221491 100644 --- a/channels/rdpgfx/rdpgfx_common.c +++ b/channels/rdpgfx/rdpgfx_common.c @@ -1,4 +1,5 @@ /** +/** * FreeRDP: A Remote Desktop Protocol Implementation * Graphics Pipeline Extension * @@ -119,6 +120,13 @@ UINT rdpgfx_read_header(wStream* s, RDPGFX_HEADER* header) Stream_Read_UINT16(s, header->cmdId); /* cmdId (2 bytes) */ Stream_Read_UINT16(s, header->flags); /* flags (2 bytes) */ Stream_Read_UINT32(s, header->pduLength); /* pduLength (4 bytes) */ + + if (header->pduLength < 8) + { + WLog_ERR(TAG, "header->pduLength %u less than 8!", header->pduLength); + return CHANNEL_RC_NO_MEMORY; + } + return CHANNEL_RC_OK; } From 26f871b3e212b85438cd9212a008dc87fc5d8a45 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Thu, 27 Jan 2022 09:50:35 +0100 Subject: [PATCH 071/496] Added plausibility checks and assert to rdpgfx_read_header (cherry picked from commit 6f154da1ae85c16726ab09995ac90eb7db251cd5) --- channels/rdpgfx/rdpgfx_common.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/channels/rdpgfx/rdpgfx_common.c b/channels/rdpgfx/rdpgfx_common.c index b10ea8221491..09f713af6f3f 100644 --- a/channels/rdpgfx/rdpgfx_common.c +++ b/channels/rdpgfx/rdpgfx_common.c @@ -25,9 +25,12 @@ #endif #include +#include #include #include +#define WINPR_ASSERT(x) assert(x) + #define TAG CHANNELS_TAG("rdpgfx.common") #include "rdpgfx_common.h" @@ -111,6 +114,9 @@ const char* rdpgfx_get_codec_id_string(UINT16 codecId) */ UINT rdpgfx_read_header(wStream* s, RDPGFX_HEADER* header) { + WINPR_ASSERT(s); + WINPR_ASSERT(header); + if (Stream_GetRemainingLength(s) < 8) { WLog_ERR(TAG, "calloc failed!"); @@ -121,11 +127,11 @@ UINT rdpgfx_read_header(wStream* s, RDPGFX_HEADER* header) Stream_Read_UINT16(s, header->flags); /* flags (2 bytes) */ Stream_Read_UINT32(s, header->pduLength); /* pduLength (4 bytes) */ - if (header->pduLength < 8) - { + if ((header->pduLength < 8) || (Stream_GetRemainingLength(s) < (header->pduLength - 8))) + { WLog_ERR(TAG, "header->pduLength %u less than 8!", header->pduLength); - return CHANNEL_RC_NO_MEMORY; - } + return ERROR_INVALID_DATA; + } return CHANNEL_RC_OK; } From aa3631db0aa61cdd44bc2b9b2196a1c51eacf06e Mon Sep 17 00:00:00 2001 From: Martin Fleisz Date: Fri, 13 Nov 2020 11:46:06 +0100 Subject: [PATCH 072/496] channel/rdpdr: Fix hotplug for drive redirection on Windows The path was incorrectly cut of after the drive letter causing hot plugged drives to show up empty and disconnecting the client if the device was removed later on. (cherry picked from commit 763f239bf09811af7febb75bd3c8881099e42e3a) --- channels/rdpdr/client/rdpdr_main.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/channels/rdpdr/client/rdpdr_main.c b/channels/rdpdr/client/rdpdr_main.c index eac0a2e447ee..309d24c74bc8 100644 --- a/channels/rdpdr/client/rdpdr_main.c +++ b/channels/rdpdr/client/rdpdr_main.c @@ -206,7 +206,6 @@ LRESULT CALLBACK hotplug_proc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) drive.Type = RDPDR_DTYP_FILESYSTEM; drive.Path = drive_path; - drive_path[1] = '\0'; drive.automount = TRUE; drive.Name = drive_name; devman_load_device_service(rdpdr->devman, @@ -585,7 +584,6 @@ static DWORD WINAPI drive_hotplug_thread_func(LPVOID arg) #else - static const char* automountLocations[] = { "/run/user/%lu/gvfs", "/run/media/%s", "/media/%s", "/media", "/mnt" }; From 1c1dd915604555d9d9de66938aed0bf930478ce5 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Mon, 11 Oct 2021 15:45:36 +0200 Subject: [PATCH 073/496] [audin] Always reset dsp_context before open (#7342) (cherry picked from commit 834fdf0046d8a76a12a66937ff92293b5ac75d6d) --- channels/audin/client/audin_main.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/channels/audin/client/audin_main.c b/channels/audin/client/audin_main.c index a5b941679dbf..81a6e8fcd9f8 100644 --- a/channels/audin/client/audin_main.c +++ b/channels/audin/client/audin_main.c @@ -444,11 +444,8 @@ static BOOL audin_open_device(AUDIN_PLUGIN* audin, AUDIN_CHANNEL_CALLBACK* callb return FALSE; } - if (!supported) - { - if (!freerdp_dsp_context_reset(audin->dsp_context, audin->format)) - return FALSE; - } + if (!freerdp_dsp_context_reset(audin->dsp_context, audin->format)) + return FALSE; IFCALLRET(audin->device->Open, error, audin->device, audin_receive_wave_data, callback); From 548e96d3bca37298ba56bd844783dcfa64f5d7d5 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Thu, 27 Jan 2022 15:32:52 +0100 Subject: [PATCH 074/496] Update nAvgBytesPerSec in audin_winmm_set_format The format channel count and alignment may have changed. Update nAvgBytesPerSec accordingly (cherry picked from commit c6e84c4929c7c735fe39dc125a6732ca1f812fd7) --- channels/audin/client/winmm/audin_winmm.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/channels/audin/client/winmm/audin_winmm.c b/channels/audin/client/winmm/audin_winmm.c index 92a778504ee0..753867284717 100644 --- a/channels/audin/client/winmm/audin_winmm.c +++ b/channels/audin/client/winmm/audin_winmm.c @@ -345,7 +345,9 @@ static UINT audin_winmm_set_format(IAudinDevice* device, const AUDIO_FORMAT* for if (ppwfx->nBlockAlign != 2) { ppwfx->nBlockAlign = 2; + ppwfx->nAvgBytesPerSec = ppwfx->nSamplesPerSec * ppwfx->nBlockAlign; } + if (!test_format_supported(ppwfx)) return ERROR_INVALID_PARAMETER; winmm->pwfx_cur = ppwfx; From 9299d2fce1b8488b2b5a2a39ad117d4b4ffd344b Mon Sep 17 00:00:00 2001 From: akallabeth Date: Fri, 28 Jan 2022 09:07:35 +0100 Subject: [PATCH 075/496] Fix #7586: Update size of tile cache if required. (#7603) (cherry picked from commit e0660ba694831256b013f644fe0604c216a9aa39) --- libfreerdp/codec/progressive.c | 45 ++++++++++++++++++++++++++++------ 1 file changed, 37 insertions(+), 8 deletions(-) diff --git a/libfreerdp/codec/progressive.c b/libfreerdp/codec/progressive.c index 08b8199e724f..60343b881a93 100644 --- a/libfreerdp/codec/progressive.c +++ b/libfreerdp/codec/progressive.c @@ -23,6 +23,7 @@ #include "config.h" #endif +#include #include #include #include @@ -40,6 +41,8 @@ #include "rfx_types.h" #include "progressive.h" +#define WINPR_ASSERT(x) assert(x) + #define TAG FREERDP_TAG("codec.progressive") struct _RFX_PROGRESSIVE_UPGRADE_STATE @@ -434,6 +437,36 @@ static INLINE BOOL progressive_tile_allocate(RFX_PROGRESSIVE_TILE* tile) return rc; } +static BOOL progressive_allocate_tile_cache(PROGRESSIVE_SURFACE_CONTEXT* surface) +{ + size_t oldIndex; + + WINPR_ASSERT(surface); + WINPR_ASSERT(surface->gridSize > 0); + + oldIndex = surface->gridSize; + if (surface->tiles) + surface->gridSize *= 2; + + { + void* tmp = realloc(surface->tiles, surface->gridSize * sizeof(RFX_PROGRESSIVE_TILE)); + if (!tmp) + return FALSE; + surface->tiles = tmp; + memset(&surface->tiles[oldIndex], 0, + (surface->gridSize - oldIndex) * sizeof(RFX_PROGRESSIVE_TILE)); + } + { + void* tmp = realloc(surface->updatedTileIndices, surface->gridSize * sizeof(UINT32)); + if (!tmp) + return FALSE; + surface->updatedTileIndices = tmp; + memset(&surface->updatedTileIndices[oldIndex], 0, + (surface->gridSize - oldIndex) * sizeof(UINT32)); + } + return TRUE; +} + static PROGRESSIVE_SURFACE_CONTEXT* progressive_surface_context_new(UINT16 surfaceId, UINT32 width, UINT32 height) { @@ -450,14 +483,10 @@ static PROGRESSIVE_SURFACE_CONTEXT* progressive_surface_context_new(UINT16 surfa surface->gridWidth = (width + (64 - width % 64)) / 64; surface->gridHeight = (height + (64 - height % 64)) / 64; surface->gridSize = surface->gridWidth * surface->gridHeight; - surface->tiles = (RFX_PROGRESSIVE_TILE*)calloc(surface->gridSize, sizeof(RFX_PROGRESSIVE_TILE)); - surface->updatedTileIndices = (UINT32*)calloc(surface->gridSize, sizeof(UINT32)); - if (!surface->tiles || !surface->updatedTileIndices) + if (!progressive_allocate_tile_cache(surface)) { - free(surface->updatedTileIndices); - free(surface->tiles); - free(surface); + progressive_surface_context_free(surface); return NULL; } for (x = 0; x < surface->gridSize; x++) @@ -549,8 +578,8 @@ static BOOL progressive_surface_tile_replace(PROGRESSIVE_SURFACE_CONTEXT* surfac } if (surface->numUpdatedTiles >= surface->gridSize) { - WLog_ERR(TAG, "Invalid total tile count, maximum %" PRIu32, surface->gridSize); - return FALSE; + if (!progressive_allocate_tile_cache(surface)) + return FALSE; } region->tiles[region->usedTiles++] = t; From a633ae35327712d316f40e692a5ed7d06bccef5e Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Mon, 14 Feb 2022 08:12:09 +0100 Subject: [PATCH 076/496] Fixed #7636: GetStringUTFLength requires jstring argument (cherry picked from commit f46f48dcd601bf1a4defa09efea398cd2976b86f) --- client/Android/android_freerdp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/Android/android_freerdp.c b/client/Android/android_freerdp.c index bab8f80c775b..178a22f7d7ab 100644 --- a/client/Android/android_freerdp.c +++ b/client/Android/android_freerdp.c @@ -997,7 +997,7 @@ static jboolean JNICALL jni_freerdp_send_clipboard_data(JNIEnv* env, jclass cls, ANDROID_EVENT* event; freerdp* inst = (freerdp*)instance; const jbyte* data = jdata != NULL ? (*env)->GetStringUTFChars(env, jdata, NULL) : NULL; - const size_t data_length = data ? (*env)->GetStringUTFLength(env, data) : 0; + const size_t data_length = data ? (*env)->GetStringUTFLength(env, jdata) : 0; jboolean ret = JNI_FALSE; event = (ANDROID_EVENT*)android_event_clipboard_new((void*)data, data_length); From e480e97ea0bd5fd5f550e9c85e42e728808eb419 Mon Sep 17 00:00:00 2001 From: Hiroshi Ota Date: Sun, 13 Feb 2022 08:21:47 +0900 Subject: [PATCH 077/496] Fix missing KBD_JAPANESE condition (cherry picked from commit 18e8a67f753e17487492492f4190fc791701877d) --- libfreerdp/core/freerdp.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libfreerdp/core/freerdp.c b/libfreerdp/core/freerdp.c index 2ce9cf771432..a070d0c8426c 100644 --- a/libfreerdp/core/freerdp.c +++ b/libfreerdp/core/freerdp.c @@ -181,7 +181,8 @@ BOOL freerdp_connect(freerdp* instance) if (status) status2 = freerdp_channels_pre_connect(instance->context->channels, instance); - if (settings->KeyboardLayout == KBD_JAPANESE_INPUT_SYSTEM_MS_IME2002) + if (settings->KeyboardLayout == KBD_JAPANESE || + settings->KeyboardLayout == KBD_JAPANESE_INPUT_SYSTEM_MS_IME2002) { settings->KeyboardType = 7; settings->KeyboardSubType = 2; From 9f081069d83852d7e744ec8349581396a0655a6c Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Mon, 14 Feb 2022 09:09:13 +0100 Subject: [PATCH 078/496] Fixed possible leaks in TestSynchMultipleThreads (cherry picked from commit 1947629b8e4904ccf856318221349e111349a713) --- .../synch/test/TestSynchMultipleThreads.c | 66 +++++++++++-------- 1 file changed, 37 insertions(+), 29 deletions(-) diff --git a/winpr/libwinpr/synch/test/TestSynchMultipleThreads.c b/winpr/libwinpr/synch/test/TestSynchMultipleThreads.c index b0bf8f212031..30086d4329f0 100644 --- a/winpr/libwinpr/synch/test/TestSynchMultipleThreads.c +++ b/winpr/libwinpr/synch/test/TestSynchMultipleThreads.c @@ -1,15 +1,14 @@ - #include #include #include #include -#define THREADS 24 +#define THREADS 8 static DWORD WINAPI test_thread(LPVOID arg) { - long timeout = 100 + (rand() % 1000); + long timeout = 30 + (rand() % 100); WINPR_UNUSED(arg); Sleep(timeout); ExitThread(0); @@ -22,7 +21,7 @@ static int start_threads(DWORD count, HANDLE* threads) for (i = 0; i < count; i++) { - threads[i] = CreateThread(NULL, 0, test_thread, NULL, 0, NULL); + threads[i] = CreateThread(NULL, 0, test_thread, NULL, CREATE_SUSPENDED, NULL); if (!threads[i]) { @@ -31,38 +30,45 @@ static int start_threads(DWORD count, HANDLE* threads) } } + for (i = 0; i < count; i++) + ResumeThread(threads[i]); return 0; } static int close_threads(DWORD count, HANDLE* threads) { + int rc = 0; DWORD i; for (i = 0; i < count; i++) { + if (!threads[i]) + continue; + if (!CloseHandle(threads[i])) { fprintf(stderr, "%s: CloseHandle [%" PRIu32 "] failure\n", __FUNCTION__, i); - return -1; + rc = -1; } + threads[i] = NULL; } - return 0; + return rc; } static BOOL TestWaitForAll(void) { BOOL rc = FALSE; DWORD ret; - HANDLE threads[THREADS]; + HANDLE threads[THREADS] = { 0 }; /* WaitForAll, timeout */ if (start_threads(THREADS, threads)) { fprintf(stderr, "%s: start_threads failed\n", __FUNCTION__); - return FALSE; + goto fail; } - ret = WaitForMultipleObjects(THREADS, threads, TRUE, 50); + ret = WaitForMultipleObjects(THREADS, threads, TRUE, 10); if (ret != WAIT_TIMEOUT) { fprintf(stderr, "%s: WaitForMultipleObjects bWaitAll, timeout 50 failed, ret=%d\n", @@ -76,14 +82,14 @@ static BOOL TestWaitForAll(void) goto fail; } + rc = TRUE; +fail: if (close_threads(THREADS, threads)) { fprintf(stderr, "%s: close_threads failed\n", __FUNCTION__); return FALSE; } - rc = TRUE; -fail: return rc; } @@ -91,12 +97,12 @@ static BOOL TestWaitOne(void) { BOOL rc = FALSE; DWORD ret; - HANDLE threads[THREADS]; + HANDLE threads[THREADS] = { 0 }; /* WaitForAll, timeout */ if (start_threads(THREADS, threads)) { fprintf(stderr, "%s: start_threads failed\n", __FUNCTION__); - return FALSE; + goto fail; } ret = WaitForMultipleObjects(THREADS, threads, FALSE, INFINITE); @@ -112,14 +118,14 @@ static BOOL TestWaitOne(void) goto fail; } + rc = TRUE; +fail: if (close_threads(THREADS, threads)) { fprintf(stderr, "%s: close_threads failed\n", __FUNCTION__); return FALSE; } - rc = TRUE; -fail: return rc; } @@ -127,15 +133,15 @@ static BOOL TestWaitOneTimeout(void) { BOOL rc = FALSE; DWORD ret; - HANDLE threads[THREADS]; + HANDLE threads[THREADS] = { 0 }; /* WaitForAll, timeout */ if (start_threads(THREADS, threads)) { fprintf(stderr, "%s: start_threads failed\n", __FUNCTION__); - return FALSE; + goto fail; } - ret = WaitForMultipleObjects(THREADS, threads, FALSE, 50); + ret = WaitForMultipleObjects(THREADS, threads, FALSE, 1); if (ret != WAIT_TIMEOUT) { fprintf(stderr, "%s: WaitForMultipleObjects timeout 50 failed, ret=%d\n", __FUNCTION__, @@ -148,15 +154,14 @@ static BOOL TestWaitOneTimeout(void) fprintf(stderr, "%s: WaitForMultipleObjects bWaitAll, INFINITE failed\n", __FUNCTION__); goto fail; } - + rc = TRUE; +fail: if (close_threads(THREADS, threads)) { fprintf(stderr, "%s: close_threads failed\n", __FUNCTION__); return FALSE; } - rc = TRUE; -fail: return rc; } @@ -164,12 +169,12 @@ static BOOL TestWaitOneTimeoutMultijoin(void) { BOOL rc = FALSE; DWORD ret, i; - HANDLE threads[THREADS]; + HANDLE threads[THREADS] = { 0 }; /* WaitForAll, timeout */ if (start_threads(THREADS, threads)) { fprintf(stderr, "%s: start_threads failed\n", __FUNCTION__); - return FALSE; + goto fail; } for (i = 0; i < THREADS; i++) @@ -177,7 +182,7 @@ static BOOL TestWaitOneTimeoutMultijoin(void) ret = WaitForMultipleObjects(THREADS, threads, FALSE, 0); if (ret != WAIT_TIMEOUT) { - fprintf(stderr, "%s: WaitForMultipleObjects timeout 50 failed, ret=%d\n", __FUNCTION__, + fprintf(stderr, "%s: WaitForMultipleObjects timeout 0 failed, ret=%d\n", __FUNCTION__, ret); goto fail; } @@ -189,34 +194,37 @@ static BOOL TestWaitOneTimeoutMultijoin(void) goto fail; } + rc = TRUE; +fail: if (close_threads(THREADS, threads)) { fprintf(stderr, "%s: close_threads failed\n", __FUNCTION__); return FALSE; } - rc = TRUE; -fail: return rc; } static BOOL TestDetach(void) { - HANDLE threads[THREADS]; + BOOL rc = FALSE; + HANDLE threads[THREADS] = { 0 }; /* WaitForAll, timeout */ if (start_threads(THREADS, threads)) { fprintf(stderr, "%s: start_threads failed\n", __FUNCTION__); - return FALSE; + goto fail; } + rc = TRUE; +fail: if (close_threads(THREADS, threads)) { fprintf(stderr, "%s: close_threads failed\n", __FUNCTION__); return FALSE; } - return TRUE; + return rc; } int TestSynchMultipleThreads(int argc, char* argv[]) From b369517e98360706d9252d1ca3a030af56a1cb42 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Mon, 14 Feb 2022 10:05:28 +0100 Subject: [PATCH 079/496] Fixed HexStrToBin, respect const input --- winpr/libwinpr/utils/sam.c | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/winpr/libwinpr/utils/sam.c b/winpr/libwinpr/utils/sam.c index 094475fe9ffb..7270bf69d587 100644 --- a/winpr/libwinpr/utils/sam.c +++ b/winpr/libwinpr/utils/sam.c @@ -173,23 +173,29 @@ static void SamLookupFinish(WINPR_SAM* sam) static void HexStrToBin(const char* str, BYTE* bin, size_t length) { size_t i; - CharUpperBuffA(str, length * 2); for (i = 0; i < length; i++) { - bin[i] = 0; + char cur = str[2 * i]; + char curNext = str[2 * i + 1]; + BYTE* curBin = &bin[i]; - if ((str[i * 2] >= '0') && (str[i * 2] <= '9')) - bin[i] |= (str[i * 2] - '0') << 4; + CharUpperBuffA(&cur, 1); + CharUpperBuffA(&curNext, 1); - if ((str[i * 2] >= 'A') && (str[i * 2] <= 'F')) - bin[i] |= (str[i * 2] - 'A' + 10) << 4; + *curBin = 0; - if ((str[i * 2 + 1] >= '0') && (str[i * 2 + 1] <= '9')) - bin[i] |= (str[i * 2 + 1] - '0'); + if ((cur >= '0') && (cur <= '9')) + *curBin |= (cur - '0') << 4; - if ((str[i * 2 + 1] >= 'A') && (str[i * 2 + 1] <= 'F')) - bin[i] |= (str[i * 2 + 1] - 'A' + 10); + if ((cur >= 'A') && (cur <= 'F')) + *curBin |= (cur - 'A' + 10) << 4; + + if ((curNext >= '0') && (curNext <= '9')) + *curBin |= (curNext - '0'); + + if ((curNext >= 'A') && (curNext <= 'F')) + *curBin |= (curNext - 'A' + 10); } } From ab935d94ef27790df7afe95b0fb0406a2d8fdfcd Mon Sep 17 00:00:00 2001 From: akallabeth Date: Thu, 17 Feb 2022 09:11:50 +0100 Subject: [PATCH 080/496] Fixed ICU include directories (cherry picked from commit b790b67ee4cd80e1138e128b04d8c45bbba03301) --- winpr/libwinpr/crt/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/winpr/libwinpr/crt/CMakeLists.txt b/winpr/libwinpr/crt/CMakeLists.txt index a2d0dda3e35d..c1645b91352a 100644 --- a/winpr/libwinpr/crt/CMakeLists.txt +++ b/winpr/libwinpr/crt/CMakeLists.txt @@ -30,7 +30,7 @@ endif(NOT WITH_ICU) if (WITH_ICU) find_package(ICU REQUIRED i18n uc io) - include_directories(${ICU_INCLUDE_DIRS}) + winpr_include_directory_add(${ICU_INCLUDE_DIRS}) winpr_library_add_private(${ICU_LIBRARIES}) endif (WITH_ICU) From 409ed441c1ddd8aae7e39563709731871bd25b35 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Thu, 17 Feb 2022 09:12:45 +0100 Subject: [PATCH 081/496] Make mac native client build configuratble (cherry picked from commit 32e01fe652dad7c2452f3ad040b591816aa48748) --- client/CMakeLists.txt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/client/CMakeLists.txt b/client/CMakeLists.txt index 7cba44e944e2..af7606bab7a3 100644 --- a/client/CMakeLists.txt +++ b/client/CMakeLists.txt @@ -43,7 +43,10 @@ if(FREERDP_VENDOR AND WITH_CLIENT) add_subdirectory(iOS) endif() else() - add_subdirectory(Mac) + option(WITH_CLIENT_MAC "Build native mac client" ON) + if (WITH_CLIENT_MAC) + add_subdirectory(Mac) + endif() endif() endif() From 55f3889a31d88dbdd4a02a43e5240412c3c5b9fd Mon Sep 17 00:00:00 2001 From: akallabeth Date: Wed, 19 Jan 2022 09:14:29 +0100 Subject: [PATCH 082/496] Added Advanced Input Channel (cherry picked from commit 98b06b4639a2fa6b511908d96282cd405b557f47) --- channels/ainput/CMakeLists.txt | 27 ++ channels/ainput/ChannelOptions.cmake | 13 + channels/ainput/client/CMakeLists.txt | 34 +++ channels/ainput/client/ainput_main.c | 303 +++++++++++++++++++ channels/ainput/client/ainput_main.h | 43 +++ channels/ainput/server/CMakeLists.txt | 27 ++ channels/ainput/server/ainput_main.c | 420 ++++++++++++++++++++++++++ channels/server/channels.c | 12 + config.h.in | 3 + include/freerdp/channels/ainput.h | 60 ++++ include/freerdp/client/ainput.h | 38 +++ include/freerdp/server/ainput.h | 88 ++++++ 12 files changed, 1068 insertions(+) create mode 100644 channels/ainput/CMakeLists.txt create mode 100644 channels/ainput/ChannelOptions.cmake create mode 100644 channels/ainput/client/CMakeLists.txt create mode 100644 channels/ainput/client/ainput_main.c create mode 100644 channels/ainput/client/ainput_main.h create mode 100644 channels/ainput/server/CMakeLists.txt create mode 100644 channels/ainput/server/ainput_main.c create mode 100644 include/freerdp/channels/ainput.h create mode 100644 include/freerdp/client/ainput.h create mode 100644 include/freerdp/server/ainput.h diff --git a/channels/ainput/CMakeLists.txt b/channels/ainput/CMakeLists.txt new file mode 100644 index 000000000000..b1d1a6a4a8af --- /dev/null +++ b/channels/ainput/CMakeLists.txt @@ -0,0 +1,27 @@ +# FreeRDP: A Remote Desktop Protocol Implementation +# FreeRDP cmake build script +# +# Copyright 2022 Armin Novak +# Copyright 2022 Thincast Technologies GmbH +# +# 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. + +define_channel("ainput") + +if(WITH_CLIENT_CHANNELS) + add_channel_client(${MODULE_PREFIX} ${CHANNEL_NAME}) +endif() + +if(WITH_SERVER_CHANNELS) + add_channel_server(${MODULE_PREFIX} ${CHANNEL_NAME}) +endif() diff --git a/channels/ainput/ChannelOptions.cmake b/channels/ainput/ChannelOptions.cmake new file mode 100644 index 000000000000..eafc6c0f5939 --- /dev/null +++ b/channels/ainput/ChannelOptions.cmake @@ -0,0 +1,13 @@ + +set(OPTION_DEFAULT OFF) +set(OPTION_CLIENT_DEFAULT ON) +set(OPTION_SERVER_DEFAULT ON) + +define_channel_options(NAME "ainput" TYPE "dynamic" + DESCRIPTION "Advanced Input Virtual Channel Extension" + SPECIFICATIONS "[XXXXX]" + DEFAULT ${OPTION_DEFAULT}) + +define_channel_client_options(${OPTION_CLIENT_DEFAULT}) +define_channel_server_options(${OPTION_SERVER_DEFAULT}) + diff --git a/channels/ainput/client/CMakeLists.txt b/channels/ainput/client/CMakeLists.txt new file mode 100644 index 000000000000..4cf2d22735b4 --- /dev/null +++ b/channels/ainput/client/CMakeLists.txt @@ -0,0 +1,34 @@ +# FreeRDP: A Remote Desktop Protocol Implementation +# FreeRDP cmake build script +# +# Copyright 2022 Armin Novak +# Copyright 2022 Thincast Technologies GmbH +# +# 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. + +define_channel_client("ainput") + +set(${MODULE_PREFIX}_SRCS + ainput_main.c + ainput_main.h) + +include_directories(..) + +add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} TRUE "DVCPluginEntry") + +if (WITH_DEBUG_SYMBOLS AND MSVC AND NOT BUILTIN_CHANNELS AND BUILD_SHARED_LIBS) + install(FILES ${PROJECT_BINARY_DIR}/${MODULE_NAME}.pdb DESTINATION ${FREERDP_ADDIN_PATH} COMPONENT symbols) +endif() + +target_link_libraries(${MODULE_NAME} winpr) +set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Channels/${CHANNEL_NAME}/Client") diff --git a/channels/ainput/client/ainput_main.c b/channels/ainput/client/ainput_main.c new file mode 100644 index 000000000000..1951b0c2e5af --- /dev/null +++ b/channels/ainput/client/ainput_main.c @@ -0,0 +1,303 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Advanced Input Virtual Channel Extension + * + * Copyright 2022 Armin Novak + * Copyright 2022 Thincast Technologies GmbH + * + * 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include + +#include +#include +#include + +#include "ainput_main.h" +#include +#include +#include + +#define WINPR_ASSERT(x) assert(x) + +#define TAG CHANNELS_TAG("ainput.client") + +typedef struct AINPUT_CHANNEL_CALLBACK_ AINPUT_CHANNEL_CALLBACK; +struct AINPUT_CHANNEL_CALLBACK_ +{ + IWTSVirtualChannelCallback iface; + + IWTSPlugin* plugin; + IWTSVirtualChannelManager* channel_mgr; + IWTSVirtualChannel* channel; +}; + +typedef struct AINPUT_LISTENER_CALLBACK_ AINPUT_LISTENER_CALLBACK; +struct AINPUT_LISTENER_CALLBACK_ +{ + IWTSListenerCallback iface; + + IWTSPlugin* plugin; + IWTSVirtualChannelManager* channel_mgr; + AINPUT_CHANNEL_CALLBACK* channel_callback; +}; + +typedef struct AINPUT_PLUGIN_ AINPUT_PLUGIN; +struct AINPUT_PLUGIN_ +{ + IWTSPlugin iface; + + AINPUT_LISTENER_CALLBACK* listener_callback; + IWTSListener* listener; + UINT32 MajorVersion; + UINT32 MinorVersion; + BOOL initialized; +}; + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT ainput_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, wStream* data) +{ + UINT16 type; + AINPUT_PLUGIN* ainput; + AINPUT_CHANNEL_CALLBACK* callback = (AINPUT_CHANNEL_CALLBACK*)pChannelCallback; + + WINPR_ASSERT(callback); + WINPR_ASSERT(data); + + ainput = (AINPUT_PLUGIN*)callback->plugin; + WINPR_ASSERT(ainput); + + if (Stream_GetRemainingLength(data) < 2) + return ERROR_NO_DATA; + Stream_Read_UINT16(data, type); + switch (type) + { + case MSG_AINPUT_VERSION: + if (Stream_GetRemainingLength(data) < 8) + return ERROR_NO_DATA; + Stream_Read_UINT32(data, ainput->MajorVersion); + Stream_Read_UINT32(data, ainput->MinorVersion); + break; + default: + WLog_WARN(TAG, "Received unsupported message type 0x%04" PRIx16, type); + break; + } + + return CHANNEL_RC_OK; +} + +static UINT ainput_send_input_event(AInputClientContext* context, UINT64 flags, INT32 x, INT32 y) +{ + AINPUT_PLUGIN* ainput; + AINPUT_CHANNEL_CALLBACK* callback; + BYTE buffer[32] = { 0 }; + wStream sbuffer = { 0 }; + wStream* s = Stream_StaticInit(&sbuffer, buffer, sizeof(buffer)); + + WINPR_ASSERT(s); + WINPR_ASSERT(context); + + ainput = (AINPUT_PLUGIN*)context->handle; + WINPR_ASSERT(ainput); + WINPR_ASSERT(ainput->listener_callback); + + if (ainput->MajorVersion != AINPUT_VERSION_MAJOR) + { + WLog_WARN(TAG, "Unsupported channel version %" PRIu32 ".%" PRIu32 ", aborting.", + ainput->MajorVersion, ainput->MinorVersion); + return CHANNEL_RC_UNSUPPORTED_VERSION; + } + callback = ainput->listener_callback->channel_callback; + WINPR_ASSERT(callback); + + /* Message type */ + Stream_Write_UINT16(s, MSG_AINPUT_MOUSE); + + /* Event data */ + Stream_Write_UINT64(s, flags); + Stream_Write_INT32(s, x); + Stream_Write_INT32(s, y); + Stream_SealLength(s); + + /* ainput back what we have received. AINPUT does not have any message IDs. */ + WINPR_ASSERT(callback->channel); + WINPR_ASSERT(callback->channel->Write); + return callback->channel->Write(callback->channel, (ULONG)Stream_Length(s), Stream_Buffer(s), + NULL); +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT ainput_on_close(IWTSVirtualChannelCallback* pChannelCallback) +{ + AINPUT_CHANNEL_CALLBACK* callback = (AINPUT_CHANNEL_CALLBACK*)pChannelCallback; + + free(callback); + + return CHANNEL_RC_OK; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT ainput_on_new_channel_connection(IWTSListenerCallback* pListenerCallback, + IWTSVirtualChannel* pChannel, BYTE* Data, + BOOL* pbAccept, + IWTSVirtualChannelCallback** ppCallback) +{ + AINPUT_CHANNEL_CALLBACK* callback; + AINPUT_LISTENER_CALLBACK* listener_callback = (AINPUT_LISTENER_CALLBACK*)pListenerCallback; + + WINPR_ASSERT(listener_callback); + WINPR_UNUSED(Data); + WINPR_UNUSED(pbAccept); + + callback = (AINPUT_CHANNEL_CALLBACK*)calloc(1, sizeof(AINPUT_CHANNEL_CALLBACK)); + + if (!callback) + { + WLog_ERR(TAG, "calloc failed!"); + return CHANNEL_RC_NO_MEMORY; + } + + callback->iface.OnDataReceived = ainput_on_data_received; + callback->iface.OnClose = ainput_on_close; + callback->plugin = listener_callback->plugin; + callback->channel_mgr = listener_callback->channel_mgr; + callback->channel = pChannel; + listener_callback->channel_callback = callback; + + *ppCallback = &callback->iface; + + return CHANNEL_RC_OK; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT ainput_plugin_initialize(IWTSPlugin* pPlugin, IWTSVirtualChannelManager* pChannelMgr) +{ + UINT status; + AINPUT_PLUGIN* ainput = (AINPUT_PLUGIN*)pPlugin; + + WINPR_ASSERT(ainput); + + if (ainput->initialized) + { + WLog_ERR(TAG, "[%s] channel initialized twice, aborting", AINPUT_DVC_CHANNEL_NAME); + return ERROR_INVALID_DATA; + } + ainput->listener_callback = + (AINPUT_LISTENER_CALLBACK*)calloc(1, sizeof(AINPUT_LISTENER_CALLBACK)); + + if (!ainput->listener_callback) + { + WLog_ERR(TAG, "calloc failed!"); + return CHANNEL_RC_NO_MEMORY; + } + + ainput->listener_callback->iface.OnNewChannelConnection = ainput_on_new_channel_connection; + ainput->listener_callback->plugin = pPlugin; + ainput->listener_callback->channel_mgr = pChannelMgr; + + status = pChannelMgr->CreateListener(pChannelMgr, AINPUT_DVC_CHANNEL_NAME, 0, + &ainput->listener_callback->iface, &ainput->listener); + + ainput->listener->pInterface = ainput->iface.pInterface; + ainput->initialized = status == CHANNEL_RC_OK; + return status; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT ainput_plugin_terminated(IWTSPlugin* pPlugin) +{ + AINPUT_PLUGIN* ainput = (AINPUT_PLUGIN*)pPlugin; + if (ainput && ainput->listener_callback) + { + IWTSVirtualChannelManager* mgr = ainput->listener_callback->channel_mgr; + if (mgr) + IFCALL(mgr->DestroyListener, mgr, ainput->listener); + } + if (ainput) + { + free(ainput->listener_callback); + free(ainput->iface.pInterface); + } + free(ainput); + + return CHANNEL_RC_OK; +} + +#ifdef BUILTIN_CHANNELS +#define DVCPluginEntry ainput_DVCPluginEntry +#else +#define DVCPluginEntry FREERDP_API DVCPluginEntry +#endif + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +UINT DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints) +{ + UINT status = CHANNEL_RC_OK; + AINPUT_PLUGIN* ainput = (AINPUT_PLUGIN*)pEntryPoints->GetPlugin(pEntryPoints, "ainput"); + + if (!ainput) + { + AInputClientContext* context = (AInputClientContext*)calloc(1, sizeof(AInputClientContext)); + ainput = (AINPUT_PLUGIN*)calloc(1, sizeof(AINPUT_PLUGIN)); + + if (!ainput || !context) + { + free(context); + free(ainput); + + WLog_ERR(TAG, "calloc failed!"); + return CHANNEL_RC_NO_MEMORY; + } + + ainput->iface.Initialize = ainput_plugin_initialize; + ainput->iface.Terminated = ainput_plugin_terminated; + + context->handle = (void*)ainput; + context->AInputSendInputEvent = ainput_send_input_event; + ainput->iface.pInterface = (void*)context; + + status = pEntryPoints->RegisterPlugin(pEntryPoints, AINPUT_CHANNEL_NAME, &ainput->iface); + } + + return status; +} diff --git a/channels/ainput/client/ainput_main.h b/channels/ainput/client/ainput_main.h new file mode 100644 index 000000000000..8a19ad91b7aa --- /dev/null +++ b/channels/ainput/client/ainput_main.h @@ -0,0 +1,43 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Advanced Input Virtual Channel Extension + * + * Copyright 2022 Armin Novak + * Copyright 2022 Thincast Technologies GmbH + * + * 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_CHANNEL_AINPUT_CLIENT_MAIN_H +#define FREERDP_CHANNEL_AINPUT_CLIENT_MAIN_H + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include +#include + +#define DVC_TAG CHANNELS_TAG("ainput.client") +#ifdef WITH_DEBUG_DVC +#define DEBUG_DVC(...) WLog_DBG(DVC_TAG, __VA_ARGS__) +#else +#define DEBUG_DVC(...) \ + do \ + { \ + } while (0) +#endif + +#endif /* FREERDP_CHANNEL_AINPUT_CLIENT_MAIN_H */ diff --git a/channels/ainput/server/CMakeLists.txt b/channels/ainput/server/CMakeLists.txt new file mode 100644 index 000000000000..59be263a707b --- /dev/null +++ b/channels/ainput/server/CMakeLists.txt @@ -0,0 +1,27 @@ +# FreeRDP: A Remote Desktop Protocol Implementation +# FreeRDP cmake build script +# +# Copyright 2022 Armin Novak +# Copyright 2022 Thincast Technologies GmbH +# +# 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. + +define_channel_server("ainput") + +set(${MODULE_PREFIX}_SRCS + ainput_main.c) + +add_channel_server_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE "DVCPluginEntry") + +target_link_libraries(${MODULE_NAME} freerdp) +set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Channels/${CHANNEL_NAME}/Server") diff --git a/channels/ainput/server/ainput_main.c b/channels/ainput/server/ainput_main.c new file mode 100644 index 000000000000..c0eeac4c9754 --- /dev/null +++ b/channels/ainput/server/ainput_main.c @@ -0,0 +1,420 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Advanced Input Virtual Channel Extension + * + * Copyright 2022 Armin Novak + * Copyright 2022 Thincast Technologies GmbH + * + * 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#define WINPR_ASSERT(x) assert(x) + +#define TAG CHANNELS_TAG("ainput.server") + +typedef struct ainput_server_ +{ + ainput_server_context context; + + BOOL opened; + + HANDLE stopEvent; + + HANDLE thread; + void* ainput_channel; + + DWORD SessionId; + +} ainput_server; + +static BOOL ainput_server_is_open(ainput_server_context* context) +{ + ainput_server* ainput = (ainput_server*)context; + + WINPR_ASSERT(ainput); + return ainput->thread != NULL; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT ainput_server_open_channel(ainput_server* ainput) +{ + DWORD Error; + HANDLE hEvent; + DWORD StartTick; + DWORD BytesReturned = 0; + PULONG pSessionId = NULL; + + WINPR_ASSERT(ainput); + + if (WTSQuerySessionInformationA(ainput->context.vcm, WTS_CURRENT_SESSION, WTSSessionId, + (LPSTR*)&pSessionId, &BytesReturned) == FALSE) + { + WLog_ERR(TAG, "WTSQuerySessionInformationA failed!"); + return ERROR_INTERNAL_ERROR; + } + + ainput->SessionId = (DWORD)*pSessionId; + WTSFreeMemory(pSessionId); + hEvent = WTSVirtualChannelManagerGetEventHandle(ainput->context.vcm); + StartTick = GetTickCount(); + + while (ainput->ainput_channel == NULL) + { + if (WaitForSingleObject(hEvent, 1000) == WAIT_FAILED) + { + Error = GetLastError(); + WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "!", Error); + return Error; + } + + ainput->ainput_channel = WTSVirtualChannelOpenEx(ainput->SessionId, AINPUT_DVC_CHANNEL_NAME, + WTS_CHANNEL_OPTION_DYNAMIC); + + if (ainput->ainput_channel) + break; + + Error = GetLastError(); + + if (Error == ERROR_NOT_FOUND) + break; + + if (GetTickCount() - StartTick > 5000) + break; + } + + return ainput->ainput_channel ? CHANNEL_RC_OK : ERROR_INTERNAL_ERROR; +} + +static UINT ainput_server_send_version(ainput_server* ainput, wStream* s) +{ + ULONG written; + WINPR_ASSERT(ainput); + WINPR_ASSERT(s); + + Stream_SetPosition(s, 0); + if (!Stream_EnsureCapacity(s, 10)) + return ERROR_OUTOFMEMORY; + + Stream_Write_UINT16(s, MSG_AINPUT_VERSION); + Stream_Write_UINT32(s, AINPUT_VERSION_MAJOR); /* Version (4 bytes) */ + Stream_Write_UINT32(s, AINPUT_VERSION_MINOR); /* Version (4 bytes) */ + + WINPR_ASSERT(Stream_GetPosition(s) <= ULONG_MAX); + if (!WTSVirtualChannelWrite(ainput->ainput_channel, (PCHAR)Stream_Buffer(s), + (ULONG)Stream_GetPosition(s), &written)) + { + WLog_ERR(TAG, "WTSVirtualChannelWrite failed!"); + return ERROR_INTERNAL_ERROR; + } + + return CHANNEL_RC_OK; +} + +static UINT ainput_server_recv_mouse_event(ainput_server* ainput, wStream* s) +{ + UINT error = CHANNEL_RC_OK; + UINT64 flags; + INT32 x, y; + + WINPR_ASSERT(ainput); + WINPR_ASSERT(s); + + if (Stream_GetRemainingLength(s) < 16) + return ERROR_NO_DATA; + + Stream_Read_UINT64(s, flags); + Stream_Read_INT32(s, x); + Stream_Read_INT32(s, y); + IFCALLRET(ainput->context.MouseEvent, error, &ainput->context, flags, x, y); + + return error; +} +static DWORD WINAPI ainput_server_thread_func(LPVOID arg) +{ + wStream* s; + void* buffer; + DWORD nCount; + HANDLE events[8] = { 0 }; + BOOL ready = FALSE; + HANDLE ChannelEvent; + DWORD BytesReturned = 0; + ainput_server* ainput = (ainput_server*)arg; + UINT error; + DWORD status; + + WINPR_ASSERT(ainput); + + if ((error = ainput_server_open_channel(ainput))) + { + WLog_ERR(TAG, "ainput_server_open_channel failed with error %" PRIu32 "!", error); + goto out; + } + + buffer = NULL; + BytesReturned = 0; + ChannelEvent = NULL; + + if (WTSVirtualChannelQuery(ainput->ainput_channel, WTSVirtualEventHandle, &buffer, + &BytesReturned) == TRUE) + { + if (BytesReturned == sizeof(HANDLE)) + CopyMemory(&ChannelEvent, buffer, sizeof(HANDLE)); + + WTSFreeMemory(buffer); + } + + nCount = 0; + events[nCount++] = ainput->stopEvent; + events[nCount++] = ChannelEvent; + + while (1) + { + status = WaitForMultipleObjects(nCount, events, FALSE, 100); + + if (status == WAIT_FAILED) + { + error = GetLastError(); + WLog_ERR(TAG, "WaitForMultipleObjects failed with error %" PRIu32 "", error); + break; + } + + if (status == WAIT_OBJECT_0) + { + if (error) + WLog_ERR(TAG, "OpenResult failed with error %" PRIu32 "!", error); + + break; + } + + if (WTSVirtualChannelQuery(ainput->ainput_channel, WTSVirtualChannelReady, &buffer, + &BytesReturned) == FALSE) + { + if (error) + WLog_ERR(TAG, "OpenResult failed with error %" PRIu32 "!", error); + + break; + } + + ready = *((BOOL*)buffer); + WTSFreeMemory(buffer); + + if (ready) + { + if (error) + WLog_ERR(TAG, "OpenResult failed with error %" PRIu32 "!", error); + + break; + } + } + + s = Stream_New(NULL, 4096); + + if (!s) + { + WLog_ERR(TAG, "Stream_New failed!"); + WTSVirtualChannelClose(ainput->ainput_channel); + ExitThread(ERROR_NOT_ENOUGH_MEMORY); + return ERROR_NOT_ENOUGH_MEMORY; + } + + if (ready) + { + if ((error = ainput_server_send_version(ainput, s))) + { + WLog_ERR(TAG, "audin_server_send_version failed with error %" PRIu32 "!", error); + goto out_capacity; + } + } + + while (ready) + { + UINT16 MessageId; + status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE); + + if (status == WAIT_FAILED) + { + error = GetLastError(); + WLog_ERR(TAG, "WaitForMultipleObjects failed with error %" PRIu32 "", error); + break; + } + + if (status == WAIT_OBJECT_0) + break; + + Stream_SetPosition(s, 0); + WTSVirtualChannelRead(ainput->ainput_channel, 0, NULL, 0, &BytesReturned); + + if (BytesReturned < 2) + continue; + + if (!Stream_EnsureRemainingCapacity(s, BytesReturned)) + { + WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!"); + error = CHANNEL_RC_NO_MEMORY; + break; + } + + if (WTSVirtualChannelRead(ainput->ainput_channel, 0, (PCHAR)Stream_Buffer(s), + (ULONG)Stream_Capacity(s), &BytesReturned) == FALSE) + { + WLog_ERR(TAG, "WTSVirtualChannelRead failed!"); + error = ERROR_INTERNAL_ERROR; + break; + } + + Stream_SetLength(s, BytesReturned); + Stream_Read_UINT16(s, MessageId); + + switch (MessageId) + { + case MSG_AINPUT_MOUSE: + error = ainput_server_recv_mouse_event(ainput, s); + break; + + default: + WLog_ERR(TAG, "audin_server_thread_func: unknown MessageId %" PRIu8 "", MessageId); + break; + } + + if (error) + { + WLog_ERR(TAG, "Response failed with error %" PRIu32 "!", error); + break; + } + } + +out_capacity: + Stream_Free(s, TRUE); + +out: + WTSVirtualChannelClose(ainput->ainput_channel); + ainput->ainput_channel = NULL; + + if (error && ainput->context.rdpcontext) + setChannelError(ainput->context.rdpcontext, error, + "ainput_server_thread_func reported an error"); + + ExitThread(error); + return error; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT ainput_server_open(ainput_server_context* context) +{ + ainput_server* ainput = (ainput_server*)context; + + WINPR_ASSERT(ainput); + + if (ainput->thread == NULL) + { + ainput->stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + if (!ainput->stopEvent) + { + WLog_ERR(TAG, "CreateEvent failed!"); + return ERROR_INTERNAL_ERROR; + } + + ainput->thread = CreateThread(NULL, 0, ainput_server_thread_func, ainput, 0, NULL); + if (!ainput->thread) + { + WLog_ERR(TAG, "CreateEvent failed!"); + CloseHandle(ainput->stopEvent); + ainput->stopEvent = NULL; + return ERROR_INTERNAL_ERROR; + } + } + + return CHANNEL_RC_OK; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT ainput_server_close(ainput_server_context* context) +{ + UINT error = CHANNEL_RC_OK; + ainput_server* ainput = (ainput_server*)context; + + WINPR_ASSERT(ainput); + + if (ainput->thread) + { + SetEvent(ainput->stopEvent); + + if (WaitForSingleObject(ainput->thread, INFINITE) == WAIT_FAILED) + { + error = GetLastError(); + WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "", error); + return error; + } + + CloseHandle(ainput->thread); + CloseHandle(ainput->stopEvent); + ainput->thread = NULL; + ainput->stopEvent = NULL; + } + + return error; +} + +ainput_server_context* ainput_server_context_new(HANDLE vcm) +{ + ainput_server* ainput = (ainput_server*)calloc(1, sizeof(ainput_server)); + + if (!ainput) + return NULL; + + ainput->context.vcm = vcm; + ainput->context.Open = ainput_server_open; + ainput->context.IsOpen = ainput_server_is_open; + ainput->context.Close = ainput_server_close; + + return &ainput->context; +} + +void ainput_server_context_free(ainput_server_context* context) +{ + ainput_server* ainput = (ainput_server*)context; + if (ainput) + ainput_server_close(context); + free(ainput); +} diff --git a/channels/server/channels.c b/channels/server/channels.c index 40c55eeccb13..3714c5ec75ee 100644 --- a/channels/server/channels.c +++ b/channels/server/channels.c @@ -53,6 +53,12 @@ #include #include +#if defined(CHANNEL_AINPUT_SERVER) +#include +#endif + +extern void freerdp_channels_dummy(void); + void freerdp_channels_dummy(void) { audin_server_context* audin; @@ -91,6 +97,12 @@ void freerdp_channels_dummy(void) rdpgfx_server_context_free(rdpgfx); disp = disp_server_context_new(NULL); disp_server_context_free(disp); +#if defined(CHANNEL_AINPUT_SERVER) + { + ainput_server_context* ainput = ainput_server_context_new(NULL); + ainput_server_context_free(ainput); + } +#endif } /** diff --git a/config.h.in b/config.h.in index 26fd7ba7da09..1f35d682b106 100644 --- a/config.h.in +++ b/config.h.in @@ -75,6 +75,9 @@ #cmakedefine WITH_RDPDR /* Channels */ +#cmakedefine CHANNEL_AINPUT +#cmakedefine CHANNEL_AINPUT_CLIENT +#cmakedefine CHANNEL_AINPUT_SERVER #cmakedefine CHANNEL_AUDIN #cmakedefine CHANNEL_AUDIN_CLIENT #cmakedefine CHANNEL_AUDIN_SERVER diff --git a/include/freerdp/channels/ainput.h b/include/freerdp/channels/ainput.h new file mode 100644 index 000000000000..269d9ec3b277 --- /dev/null +++ b/include/freerdp/channels/ainput.h @@ -0,0 +1,60 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Audio Input Redirection Virtual Channel + * + * Copyright 2022 Armin Novak + * Copyright 2022 Thincast Technologies GmbH + * + * 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_CHANNEL_AINPUT_H +#define FREERDP_CHANNEL_AINPUT_H + +#include +#include +#include + +#define AINPUT_CHANNEL_NAME "ainput" +#define AINPUT_DVC_CHANNEL_NAME "FreeRDP::Advanced::Input" + +typedef enum +{ + MSG_AINPUT_VERSION = 0x01, + MSG_AINPUT_MOUSE = 0x02 +} eAInputMsgType; + +typedef enum +{ + AINPUT_FLAGS_WHEEL = 0x0001, + AINPUT_FLAGS_MOVE = 0x0004, + AINPUT_FLAGS_DOWN = 0x0008, + + AINPUT_FLAGS_REL = 0x0010, + + /* Pointer Flags */ + AINPUT_FLAGS_BUTTON1 = 0x1000, /* left */ + AINPUT_FLAGS_BUTTON2 = 0x2000, /* right */ + AINPUT_FLAGS_BUTTON3 = 0x4000, /* middle */ + + /* Extended Pointer Flags */ + AINPUT_XFLAGS_BUTTON1 = 0x0100, + AINPUT_XFLAGS_BUTTON2 = 0x0200 +} AInputEventFlags; + +typedef struct ainput_client_context AInputClientContext; + +#define AINPUT_VERSION_MAJOR 1 +#define AINPUT_VERSION_MINOR 0 + +#endif /* FREERDP_CHANNEL_AINPUT_H */ diff --git a/include/freerdp/client/ainput.h b/include/freerdp/client/ainput.h new file mode 100644 index 000000000000..14474835e7aa --- /dev/null +++ b/include/freerdp/client/ainput.h @@ -0,0 +1,38 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Display Update Virtual Channel Extension + * + * Copyright 2013 Marc-Andre Moreau + * Copyright 2015 Thincast Technologies GmbH + * Copyright 2015 DI (FH) Martin Haimberger + * + * 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_CHANNEL_AINPUT_CLIENT_AINPUT_H +#define FREERDP_CHANNEL_AINPUT_CLIENT_AINPUT_H + +#include + +typedef UINT (*pcAInputSendInputEvent)(AInputClientContext* context, UINT64 flags, INT32 x, + INT32 y); + +struct ainput_client_context +{ + void* handle; + void* custom; + + pcAInputSendInputEvent AInputSendInputEvent; +}; + +#endif /* FREERDP_CHANNEL_AINPUT_CLIENT_AINPUT_H */ diff --git a/include/freerdp/server/ainput.h b/include/freerdp/server/ainput.h new file mode 100644 index 000000000000..aca091bb4a70 --- /dev/null +++ b/include/freerdp/server/ainput.h @@ -0,0 +1,88 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * AInput Virtual Channel Extension + * + * Copyright 2022 Armin Novak + * Copyright 2022 Thincast Technologies GmbH + * + * 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_CHANNEL_AINPUT_SERVER_H +#define FREERDP_CHANNEL_AINPUT_SERVER_H + +#include + +typedef enum AINPUT_SERVER_OPEN_RESULT +{ + AINPUT_SERVER_OPEN_RESULT_OK = 0, + AINPUT_SERVER_OPEN_RESULT_CLOSED = 1, + AINPUT_SERVER_OPEN_RESULT_NOTSUPPORTED = 2, + AINPUT_SERVER_OPEN_RESULT_ERROR = 3 +} AINPUT_SERVER_OPEN_RESULT; + +typedef struct _ainput_server_context ainput_server_context; + +typedef UINT (*psAInputServerOpen)(ainput_server_context* context); +typedef UINT (*psAInputServerClose)(ainput_server_context* context); +typedef BOOL (*psAInputServerIsOpen)(ainput_server_context* context); + +typedef UINT (*psAInputServerOpenResult)(ainput_server_context* context, + AINPUT_SERVER_OPEN_RESULT result); +typedef UINT (*psAInputServerMouseEvent)(ainput_server_context* context, UINT64 flags, INT32 x, + INT32 y); + +struct _ainput_server_context +{ + HANDLE vcm; + + /* Server self-defined pointer. */ + void* data; + + /*** APIs called by the server. ***/ + /** + * Open the ainput channel. + */ + psAInputServerOpen Open; + /** + * Close the ainput channel. + */ + psAInputServerClose Close; + /** + * Status of the ainput channel. + */ + psAInputServerIsOpen IsOpen; + + /*** Callbacks registered by the server. ***/ + + /** + * Receive ainput mouse event PDU. + */ + psAInputServerMouseEvent MouseEvent; + + rdpContext* rdpcontext; +}; + +#ifdef __cplusplus +extern "C" +{ +#endif + + FREERDP_API ainput_server_context* ainput_server_context_new(HANDLE vcm); + FREERDP_API void ainput_server_context_free(ainput_server_context* context); + +#ifdef __cplusplus +} +#endif + +#endif /* FREERDP_CHANNEL_AINPUT_SERVER_H */ From d866de5069f38cec53521e8fb4b2dc7169b23f93 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Wed, 26 Jan 2022 14:21:53 +0100 Subject: [PATCH 083/496] Extended AINPUT API: * Each event now has a timestamp * Relative and absolute events are sent simultaneously * Added a flag indicating relative events are available (cherry picked from commit deb8ef46dbdedefe22e22fc70665f80279f407b0) --- channels/ainput/client/ainput_main.c | 16 ++++- channels/ainput/common/ainput_common.h | 81 ++++++++++++++++++++++++++ channels/ainput/server/ainput_main.c | 13 ++++- include/freerdp/channels/ainput.h | 1 + include/freerdp/server/ainput.h | 4 +- 5 files changed, 109 insertions(+), 6 deletions(-) create mode 100644 channels/ainput/common/ainput_common.h diff --git a/channels/ainput/client/ainput_main.c b/channels/ainput/client/ainput_main.c index 1951b0c2e5af..bf4ce2644d1b 100644 --- a/channels/ainput/client/ainput_main.c +++ b/channels/ainput/client/ainput_main.c @@ -28,12 +28,15 @@ #include #include #include +#include #include "ainput_main.h" #include #include #include +#include "../common/ainput_common.h" + #define WINPR_ASSERT(x) assert(x) #define TAG CHANNELS_TAG("ainput.client") @@ -111,12 +114,16 @@ static UINT ainput_send_input_event(AInputClientContext* context, UINT64 flags, AINPUT_PLUGIN* ainput; AINPUT_CHANNEL_CALLBACK* callback; BYTE buffer[32] = { 0 }; + UINT64 time; wStream sbuffer = { 0 }; - wStream* s = Stream_StaticInit(&sbuffer, buffer, sizeof(buffer)); + wStream* s = &sbuffer; + + Stream_StaticInit(&sbuffer, buffer, sizeof(buffer)); WINPR_ASSERT(s); WINPR_ASSERT(context); + time = GetTickCount64(); ainput = (AINPUT_PLUGIN*)context->handle; WINPR_ASSERT(ainput); WINPR_ASSERT(ainput->listener_callback); @@ -130,10 +137,17 @@ static UINT ainput_send_input_event(AInputClientContext* context, UINT64 flags, callback = ainput->listener_callback->channel_callback; WINPR_ASSERT(callback); + { + char buffer[128] = { 0 }; + WLog_VRB(TAG, "[%s] sending timestamp=0x%08" PRIx64 ", flags=%s, %" PRId32 "x%" PRId32, + __FUNCTION__, time, ainput_flags_to_string(flags, buffer, sizeof(buffer)), x, y); + } + /* Message type */ Stream_Write_UINT16(s, MSG_AINPUT_MOUSE); /* Event data */ + Stream_Write_UINT64(s, time); Stream_Write_UINT64(s, flags); Stream_Write_INT32(s, x); Stream_Write_INT32(s, y); diff --git a/channels/ainput/common/ainput_common.h b/channels/ainput/common/ainput_common.h new file mode 100644 index 000000000000..bc1be04b9c76 --- /dev/null +++ b/channels/ainput/common/ainput_common.h @@ -0,0 +1,81 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Audio Input Redirection Virtual Channel + * + * Copyright 2022 Armin Novak + * Copyright 2022 Thincast Technologies GmbH + * + * 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_INT_AINPUT_COMMON_H +#define FREERDP_INT_AINPUT_COMMON_H + +#include +#include + +#include + +static INLINE void ainput_append(char* buffer, size_t size, const char* what, BOOL separator) +{ + size_t have; + size_t toadd; + + assert(buffer || (size == 0)); + assert(what); + + have = strnlen(buffer, size); + toadd = strlen(what); + if (have > 0) + toadd += 1; + + if (size - have < toadd + 1) + return; + + if (have > 0) + strcat(buffer, separator ? "|" : " "); + strcat(buffer, what); +} + +static INLINE const char* ainput_flags_to_string(UINT64 flags, char* buffer, size_t size) +{ + char number[32] = { 0 }; + + if (flags & AINPUT_FLAGS_HAVE_REL) + ainput_append(buffer, size, "AINPUT_FLAGS_HAVE_REL", TRUE); + if (flags & AINPUT_FLAGS_WHEEL) + ainput_append(buffer, size, "AINPUT_FLAGS_WHEEL", TRUE); + if (flags & AINPUT_FLAGS_MOVE) + ainput_append(buffer, size, "AINPUT_FLAGS_MOVE", TRUE); + if (flags & AINPUT_FLAGS_DOWN) + ainput_append(buffer, size, "AINPUT_FLAGS_DOWN", TRUE); + if (flags & AINPUT_FLAGS_REL) + ainput_append(buffer, size, "AINPUT_FLAGS_REL", TRUE); + if (flags & AINPUT_FLAGS_BUTTON1) + ainput_append(buffer, size, "AINPUT_FLAGS_BUTTON1", TRUE); + if (flags & AINPUT_FLAGS_BUTTON2) + ainput_append(buffer, size, "AINPUT_FLAGS_BUTTON2", TRUE); + if (flags & AINPUT_FLAGS_BUTTON3) + ainput_append(buffer, size, "AINPUT_FLAGS_BUTTON3", TRUE); + if (flags & AINPUT_XFLAGS_BUTTON1) + ainput_append(buffer, size, "AINPUT_XFLAGS_BUTTON1", TRUE); + if (flags & AINPUT_XFLAGS_BUTTON2) + ainput_append(buffer, size, "AINPUT_XFLAGS_BUTTON2", TRUE); + + _snprintf(number, sizeof(number), "[0x%08" PRIx64 "]", flags); + ainput_append(buffer, size, number, FALSE); + + return buffer; +} + +#endif /* FREERDP_INT_AINPUT_COMMON_H */ diff --git a/channels/ainput/server/ainput_main.c b/channels/ainput/server/ainput_main.c index c0eeac4c9754..3290db969c19 100644 --- a/channels/ainput/server/ainput_main.c +++ b/channels/ainput/server/ainput_main.c @@ -37,6 +37,8 @@ #include #include +#include "../common/ainput_common.h" + #define WINPR_ASSERT(x) assert(x) #define TAG CHANNELS_TAG("ainput.server") @@ -146,19 +148,24 @@ static UINT ainput_server_send_version(ainput_server* ainput, wStream* s) static UINT ainput_server_recv_mouse_event(ainput_server* ainput, wStream* s) { UINT error = CHANNEL_RC_OK; - UINT64 flags; + UINT64 flags, time; INT32 x, y; + char buffer[128] = { 0 }; WINPR_ASSERT(ainput); WINPR_ASSERT(s); - if (Stream_GetRemainingLength(s) < 16) + if (Stream_GetRemainingLength(s) < 24) return ERROR_NO_DATA; + Stream_Read_UINT64(s, time); Stream_Read_UINT64(s, flags); Stream_Read_INT32(s, x); Stream_Read_INT32(s, y); - IFCALLRET(ainput->context.MouseEvent, error, &ainput->context, flags, x, y); + + WLog_VRB(TAG, "[%s] received: time=0x%08" PRIx64 ", flags=%s, %" PRId32 "x%" PRId32, + __FUNCTION__, time, ainput_flags_to_string(flags, buffer, sizeof(buffer)), x, y); + IFCALLRET(ainput->context.MouseEvent, error, &ainput->context, time, flags, x, y); return error; } diff --git a/include/freerdp/channels/ainput.h b/include/freerdp/channels/ainput.h index 269d9ec3b277..fe9faef3f453 100644 --- a/include/freerdp/channels/ainput.h +++ b/include/freerdp/channels/ainput.h @@ -41,6 +41,7 @@ typedef enum AINPUT_FLAGS_DOWN = 0x0008, AINPUT_FLAGS_REL = 0x0010, + AINPUT_FLAGS_HAVE_REL = 0x0020, /* Pointer Flags */ AINPUT_FLAGS_BUTTON1 = 0x1000, /* left */ diff --git a/include/freerdp/server/ainput.h b/include/freerdp/server/ainput.h index aca091bb4a70..41ed2fe6cde7 100644 --- a/include/freerdp/server/ainput.h +++ b/include/freerdp/server/ainput.h @@ -39,8 +39,8 @@ typedef BOOL (*psAInputServerIsOpen)(ainput_server_context* context); typedef UINT (*psAInputServerOpenResult)(ainput_server_context* context, AINPUT_SERVER_OPEN_RESULT result); -typedef UINT (*psAInputServerMouseEvent)(ainput_server_context* context, UINT64 flags, INT32 x, - INT32 y); +typedef UINT (*psAInputServerMouseEvent)(ainput_server_context* context, UINT64 timestamp, + UINT64 flags, INT32 x, INT32 y); struct _ainput_server_context { From 4541b80e8bb581dd5a3a87d1612066ac602fc269 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Fri, 18 Feb 2022 09:53:50 +0100 Subject: [PATCH 084/496] Add option for external thread to ainput server channel (cherry picked from commit 538cd7cf8fefaf0ff8c916f63c55149c72f16794) --- channels/ainput/server/ainput_main.c | 393 +++++++++++++++++---------- include/freerdp/server/ainput.h | 26 ++ 2 files changed, 282 insertions(+), 137 deletions(-) diff --git a/channels/ainput/server/ainput_main.c b/channels/ainput/server/ainput_main.c index 3290db969c19..670b668726a3 100644 --- a/channels/ainput/server/ainput_main.c +++ b/channels/ainput/server/ainput_main.c @@ -43,7 +43,14 @@ #define TAG CHANNELS_TAG("ainput.server") -typedef struct ainput_server_ +typedef enum +{ + AINPUT_INITIAL, + AINPUT_OPENED, + AINPUT_VERSION_SENT, +} eAInputChannelState; + +typedef struct { ainput_server_context context; @@ -56,14 +63,25 @@ typedef struct ainput_server_ DWORD SessionId; + BOOL isOpened; + BOOL externalThread; + + /* Channel state */ + eAInputChannelState state; + + wStream* buffer; } ainput_server; +static UINT ainput_server_context_poll(ainput_server_context* context); +static BOOL ainput_server_context_handle(ainput_server_context* context, HANDLE* handle); +static UINT ainput_server_context_poll_int(ainput_server_context* context); + static BOOL ainput_server_is_open(ainput_server_context* context) { ainput_server* ainput = (ainput_server*)context; WINPR_ASSERT(ainput); - return ainput->thread != NULL; + return ainput->isOpened; } /** @@ -120,10 +138,14 @@ static UINT ainput_server_open_channel(ainput_server* ainput) return ainput->ainput_channel ? CHANNEL_RC_OK : ERROR_INTERNAL_ERROR; } -static UINT ainput_server_send_version(ainput_server* ainput, wStream* s) +static UINT ainput_server_send_version(ainput_server* ainput) { ULONG written; + wStream* s; + WINPR_ASSERT(ainput); + + s = ainput->buffer; WINPR_ASSERT(s); Stream_SetPosition(s, 0); @@ -169,31 +191,15 @@ static UINT ainput_server_recv_mouse_event(ainput_server* ainput, wStream* s) return error; } -static DWORD WINAPI ainput_server_thread_func(LPVOID arg) + +static HANDLE ainput_server_get_channel_handle(ainput_server* ainput) { - wStream* s; - void* buffer; - DWORD nCount; - HANDLE events[8] = { 0 }; - BOOL ready = FALSE; - HANDLE ChannelEvent; + BYTE* buffer = NULL; DWORD BytesReturned = 0; - ainput_server* ainput = (ainput_server*)arg; - UINT error; - DWORD status; + HANDLE ChannelEvent = NULL; WINPR_ASSERT(ainput); - if ((error = ainput_server_open_channel(ainput))) - { - WLog_ERR(TAG, "ainput_server_open_channel failed with error %" PRIu32 "!", error); - goto out; - } - - buffer = NULL; - BytesReturned = 0; - ChannelEvent = NULL; - if (WTSVirtualChannelQuery(ainput->ainput_channel, WTSVirtualEventHandle, &buffer, &BytesReturned) == TRUE) { @@ -203,130 +209,64 @@ static DWORD WINAPI ainput_server_thread_func(LPVOID arg) WTSFreeMemory(buffer); } - nCount = 0; - events[nCount++] = ainput->stopEvent; - events[nCount++] = ChannelEvent; - - while (1) - { - status = WaitForMultipleObjects(nCount, events, FALSE, 100); - - if (status == WAIT_FAILED) - { - error = GetLastError(); - WLog_ERR(TAG, "WaitForMultipleObjects failed with error %" PRIu32 "", error); - break; - } - - if (status == WAIT_OBJECT_0) - { - if (error) - WLog_ERR(TAG, "OpenResult failed with error %" PRIu32 "!", error); - - break; - } - - if (WTSVirtualChannelQuery(ainput->ainput_channel, WTSVirtualChannelReady, &buffer, - &BytesReturned) == FALSE) - { - if (error) - WLog_ERR(TAG, "OpenResult failed with error %" PRIu32 "!", error); - - break; - } - - ready = *((BOOL*)buffer); - WTSFreeMemory(buffer); - - if (ready) - { - if (error) - WLog_ERR(TAG, "OpenResult failed with error %" PRIu32 "!", error); - - break; - } - } + return ChannelEvent; +} - s = Stream_New(NULL, 4096); +static DWORD WINAPI ainput_server_thread_func(LPVOID arg) +{ + DWORD nCount; + HANDLE events[2] = { 0 }; + ainput_server* ainput = (ainput_server*)arg; + UINT error = CHANNEL_RC_OK; + DWORD status; - if (!s) - { - WLog_ERR(TAG, "Stream_New failed!"); - WTSVirtualChannelClose(ainput->ainput_channel); - ExitThread(ERROR_NOT_ENOUGH_MEMORY); - return ERROR_NOT_ENOUGH_MEMORY; - } + WINPR_ASSERT(ainput); - if (ready) - { - if ((error = ainput_server_send_version(ainput, s))) - { - WLog_ERR(TAG, "audin_server_send_version failed with error %" PRIu32 "!", error); - goto out_capacity; - } - } + nCount = 0; + events[nCount++] = ainput->stopEvent; - while (ready) + while ((error == CHANNEL_RC_OK) && (WaitForSingleObject(events[0], 0) != WAIT_OBJECT_0)) { - UINT16 MessageId; - status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE); - - if (status == WAIT_FAILED) + switch (ainput->state) { - error = GetLastError(); - WLog_ERR(TAG, "WaitForMultipleObjects failed with error %" PRIu32 "", error); - break; - } - - if (status == WAIT_OBJECT_0) - break; - - Stream_SetPosition(s, 0); - WTSVirtualChannelRead(ainput->ainput_channel, 0, NULL, 0, &BytesReturned); - - if (BytesReturned < 2) - continue; - - if (!Stream_EnsureRemainingCapacity(s, BytesReturned)) - { - WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!"); - error = CHANNEL_RC_NO_MEMORY; - break; - } - - if (WTSVirtualChannelRead(ainput->ainput_channel, 0, (PCHAR)Stream_Buffer(s), - (ULONG)Stream_Capacity(s), &BytesReturned) == FALSE) - { - WLog_ERR(TAG, "WTSVirtualChannelRead failed!"); - error = ERROR_INTERNAL_ERROR; - break; - } - - Stream_SetLength(s, BytesReturned); - Stream_Read_UINT16(s, MessageId); - - switch (MessageId) - { - case MSG_AINPUT_MOUSE: - error = ainput_server_recv_mouse_event(ainput, s); + case AINPUT_OPENED: + events[1] = ainput_server_get_channel_handle(ainput); + nCount = 2; + status = WaitForMultipleObjects(nCount, events, FALSE, 100); + switch (status) + { + case WAIT_TIMEOUT: + case WAIT_OBJECT_0 + 1: + case WAIT_OBJECT_0: + error = ainput_server_context_poll_int(&ainput->context); + + case WAIT_FAILED: + default: + error = ERROR_INTERNAL_ERROR; + break; + } + break; + case AINPUT_VERSION_SENT: + status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE); + switch (status) + { + case WAIT_TIMEOUT: + case WAIT_OBJECT_0 + 1: + case WAIT_OBJECT_0: + error = ainput_server_context_poll_int(&ainput->context); + + case WAIT_FAILED: + default: + error = ERROR_INTERNAL_ERROR; + break; + } break; - default: - WLog_ERR(TAG, "audin_server_thread_func: unknown MessageId %" PRIu8 "", MessageId); + error = ainput_server_context_poll_int(&ainput->context); break; } - - if (error) - { - WLog_ERR(TAG, "Response failed with error %" PRIu32 "!", error); - break; - } } -out_capacity: - Stream_Free(s, TRUE); - -out: WTSVirtualChannelClose(ainput->ainput_channel); ainput->ainput_channel = NULL; @@ -349,7 +289,7 @@ static UINT ainput_server_open(ainput_server_context* context) WINPR_ASSERT(ainput); - if (ainput->thread == NULL) + if (!ainput->externalThread && (ainput->thread == NULL)) { ainput->stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL); if (!ainput->stopEvent) @@ -367,6 +307,7 @@ static UINT ainput_server_open(ainput_server_context* context) return ERROR_INTERNAL_ERROR; } } + ainput->isOpened = TRUE; return CHANNEL_RC_OK; } @@ -383,7 +324,7 @@ static UINT ainput_server_close(ainput_server_context* context) WINPR_ASSERT(ainput); - if (ainput->thread) + if (!ainput->externalThread && ainput->thread) { SetEvent(ainput->stopEvent); @@ -399,7 +340,34 @@ static UINT ainput_server_close(ainput_server_context* context) ainput->thread = NULL; ainput->stopEvent = NULL; } + if (ainput->externalThread) + { + if (ainput->state != AINPUT_INITIAL) + { + WTSVirtualChannelClose(ainput->ainput_channel); + ainput->ainput_channel = NULL; + ainput->state = AINPUT_INITIAL; + } + } + ainput->isOpened = FALSE; + + return error; +} + +static UINT ainput_server_initialize(ainput_server_context* context, BOOL externalThread) +{ + UINT error = CHANNEL_RC_OK; + ainput_server* ainput = (ainput_server*)context; + WINPR_ASSERT(ainput); + + if (ainput->isOpened) + { + WLog_WARN(TAG, "Application error: AINPUT channel already initialized, calling in this " + "state is not possible!"); + return ERROR_INVALID_STATE; + } + ainput->externalThread = externalThread; return error; } @@ -414,14 +382,165 @@ ainput_server_context* ainput_server_context_new(HANDLE vcm) ainput->context.Open = ainput_server_open; ainput->context.IsOpen = ainput_server_is_open; ainput->context.Close = ainput_server_close; + ainput->context.Initialize = ainput_server_initialize; + ainput->context.Poll = ainput_server_context_poll; + ainput->context.ChannelHandle = ainput_server_context_handle; + ainput->buffer = Stream_New(NULL, 4096); + if (!ainput->buffer) + goto fail; return &ainput->context; +fail: + ainput_server_context_free(ainput); + return NULL; } void ainput_server_context_free(ainput_server_context* context) { ainput_server* ainput = (ainput_server*)context; if (ainput) + { ainput_server_close(context); + Stream_Free(ainput->buffer, TRUE); + } free(ainput); } + +static UINT ainput_process_message(ainput_server* ainput) +{ + BOOL rc; + UINT error = ERROR_INTERNAL_ERROR; + ULONG BytesReturned; + UINT16 MessageId; + wStream* s; + + WINPR_ASSERT(ainput); + WINPR_ASSERT(ainput->ainput_channel); + + s = ainput->buffer; + WINPR_ASSERT(s); + + Stream_SetPosition(s, 0); + rc = WTSVirtualChannelRead(ainput->ainput_channel, 0, NULL, 0, &BytesReturned); + if (!rc) + goto out; + + if (BytesReturned < 2) + { + error = CHANNEL_RC_OK; + goto out; + } + + if (!Stream_EnsureRemainingCapacity(s, BytesReturned)) + { + WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!"); + error = CHANNEL_RC_NO_MEMORY; + goto out; + } + + if (WTSVirtualChannelRead(ainput->ainput_channel, 0, (PCHAR)Stream_Buffer(s), + (ULONG)Stream_Capacity(s), &BytesReturned) == FALSE) + { + WLog_ERR(TAG, "WTSVirtualChannelRead failed!"); + goto out; + } + + Stream_SetLength(s, BytesReturned); + Stream_Read_UINT16(s, MessageId); + + switch (MessageId) + { + case MSG_AINPUT_MOUSE: + error = ainput_server_recv_mouse_event(ainput, s); + break; + + default: + WLog_ERR(TAG, "audin_server_thread_func: unknown MessageId %" PRIu8 "", MessageId); + break; + } + +out: + if (error) + WLog_ERR(TAG, "Response failed with error %" PRIu32 "!", error); + + return error; +} + +BOOL ainput_server_context_handle(ainput_server_context* context, HANDLE* handle) +{ + ainput_server* ainput = (ainput_server*)context; + WINPR_ASSERT(ainput); + WINPR_ASSERT(handle); + + if (!ainput->externalThread) + return FALSE; + if (ainput->state == AINPUT_INITIAL) + return FALSE; + *handle = ainput_server_get_channel_handle(ainput); + return TRUE; +} + +UINT ainput_server_context_poll_int(ainput_server_context* context) +{ + ainput_server* ainput = (ainput_server*)context; + UINT error = ERROR_INTERNAL_ERROR; + + WINPR_ASSERT(ainput); + + switch (ainput->state) + { + case AINPUT_INITIAL: + error = ainput_server_open_channel(ainput); + if (error) + WLog_ERR(TAG, "ainput_server_open_channel failed with error %" PRIu32 "!", error); + else + ainput->state = AINPUT_OPENED; + break; + case AINPUT_OPENED: + { + BYTE* buffer = NULL; + DWORD BytesReturned = 0; + + if (WTSVirtualChannelQuery(ainput->ainput_channel, WTSVirtualChannelReady, &buffer, + &BytesReturned) != TRUE) + { + WLog_ERR(TAG, "WTSVirtualChannelReady failed,"); + } + else + { + if (*buffer != 0) + { + error = ainput_server_send_version(ainput); + if (error) + WLog_ERR(TAG, "audin_server_send_version failed with error %" PRIu32 "!", + error); + else + ainput->state = AINPUT_VERSION_SENT; + } + else + error = CHANNEL_RC_OK; + } + WTSFreeMemory(buffer); + } + break; + case AINPUT_VERSION_SENT: + error = ainput_process_message(ainput); + break; + + default: + WLog_ERR(TAG, "AINPUT chanel is in invalid state %d", ainput->state); + break; + } + + return error; +} + +UINT ainput_server_context_poll(ainput_server_context* context) +{ + ainput_server* ainput = (ainput_server*)context; + + WINPR_ASSERT(ainput); + if (!ainput->externalThread) + return ERROR_INTERNAL_ERROR; + return ainput_server_context_poll_int(context); +} diff --git a/include/freerdp/server/ainput.h b/include/freerdp/server/ainput.h index 41ed2fe6cde7..39acad118e63 100644 --- a/include/freerdp/server/ainput.h +++ b/include/freerdp/server/ainput.h @@ -33,6 +33,10 @@ typedef enum AINPUT_SERVER_OPEN_RESULT typedef struct _ainput_server_context ainput_server_context; +typedef UINT (*psAInputServerInitialize)(ainput_server_context* context, BOOL externalThread); +typedef UINT (*psAInputServerPoll)(ainput_server_context* context); +typedef BOOL (*psAInputServerChannelHandle)(ainput_server_context* context, HANDLE* handle); + typedef UINT (*psAInputServerOpen)(ainput_server_context* context); typedef UINT (*psAInputServerClose)(ainput_server_context* context); typedef BOOL (*psAInputServerIsOpen)(ainput_server_context* context); @@ -54,6 +58,28 @@ struct _ainput_server_context * Open the ainput channel. */ psAInputServerOpen Open; + + /** + * Optional: Set thread handling. + * When externalThread=TRUE the application is responsible to call + * ainput_server_context_poll periodically to process input events. + * + * Defaults to externalThread=FALSE + */ + psAInputServerInitialize Initialize; + + /** + * @brief Poll When externalThread=TRUE call periodically from your main loop. + * if externalThread=FALSE do not call. + */ + psAInputServerPoll Poll; + + /** + * @brief Poll When externalThread=TRUE call to get a handle to wait for events. + * Will return FALSE until the handle is available. + */ + psAInputServerChannelHandle ChannelHandle; + /** * Close the ainput channel. */ From 5e96f657f64094dc5233784c7569936cfe03ce5d Mon Sep 17 00:00:00 2001 From: Pascal Nowack Date: Tue, 22 Feb 2022 10:09:19 +0100 Subject: [PATCH 085/496] server/disp: Sanitize optional physical monitor size values The server sided handling of the display control channel currently treats the physical monitor size values as obligatory values. When the physical monitor size is invalid according to the documentation, it is supposed to be ignored. However, this is currently not done, leading to an abort of the display control channel handling, when using Remmina, as Remmina does not submit physical-monitor- widths and -heights. Fix this issue by sanitizing the physical monitor size values, instead of handling them as obligatory values, where both the physical with and the physical height must be constrained to the values in the documentation. --- channels/disp/server/disp_main.c | 36 ++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/channels/disp/server/disp_main.c b/channels/disp/server/disp_main.c index a764acd1841d..64e96c301aaa 100644 --- a/channels/disp/server/disp_main.c +++ b/channels/disp/server/disp_main.c @@ -72,6 +72,24 @@ static wStream* disp_server_single_packet_new(UINT32 type, UINT32 length) return NULL; } +static void disp_server_sanitize_monitor_layout(DISPLAY_CONTROL_MONITOR_LAYOUT* monitor) +{ + if (monitor->PhysicalWidth < DISPLAY_CONTROL_MIN_PHYSICAL_MONITOR_WIDTH || + monitor->PhysicalWidth > DISPLAY_CONTROL_MAX_PHYSICAL_MONITOR_WIDTH || + monitor->PhysicalHeight < DISPLAY_CONTROL_MIN_PHYSICAL_MONITOR_HEIGHT || + monitor->PhysicalHeight > DISPLAY_CONTROL_MAX_PHYSICAL_MONITOR_HEIGHT) + { + if (monitor->PhysicalWidth != 0 || monitor->PhysicalHeight != 0) + WLog_DBG( + TAG, + "Sanitizing invalid physical monitor size. Old physical monitor size: [%" PRIu32 + ", %" PRIu32 "]", + monitor->PhysicalWidth, monitor->PhysicalHeight); + + monitor->PhysicalWidth = monitor->PhysicalHeight = 0; + } +} + static BOOL disp_server_is_monitor_layout_valid(DISPLAY_CONTROL_MONITOR_LAYOUT* monitor) { if (monitor->Width < DISPLAY_CONTROL_MIN_MONITOR_WIDTH || @@ -88,22 +106,6 @@ static BOOL disp_server_is_monitor_layout_valid(DISPLAY_CONTROL_MONITOR_LAYOUT* return FALSE; } - if (monitor->PhysicalWidth < DISPLAY_CONTROL_MIN_PHYSICAL_MONITOR_WIDTH || - monitor->PhysicalWidth > DISPLAY_CONTROL_MAX_PHYSICAL_MONITOR_WIDTH) - { - WLog_WARN(TAG, "Received invalid value for monitor->PhysicalWidth: %" PRIu32 "", - monitor->PhysicalWidth); - return FALSE; - } - - if (monitor->PhysicalHeight < DISPLAY_CONTROL_MIN_PHYSICAL_MONITOR_HEIGHT || - monitor->PhysicalHeight > DISPLAY_CONTROL_MAX_PHYSICAL_MONITOR_HEIGHT) - { - WLog_WARN(TAG, "Received invalid value for monitor->Height: %" PRIu32 "", - monitor->PhysicalHeight); - return FALSE; - } - switch (monitor->Orientation) { case ORIENTATION_LANDSCAPE: @@ -183,6 +185,8 @@ static UINT disp_recv_display_control_monitor_layout_pdu(wStream* s, DispServerC Stream_Read_UINT32(s, monitor->Orientation); /* Orientation (4 bytes) */ Stream_Read_UINT32(s, monitor->DesktopScaleFactor); /* DesktopScaleFactor (4 bytes) */ Stream_Read_UINT32(s, monitor->DeviceScaleFactor); /* DeviceScaleFactor (4 bytes) */ + + disp_server_sanitize_monitor_layout(monitor); WLog_DBG(TAG, "\t%d : Flags: 0x%08" PRIX32 " Left/Top: (%" PRId32 ",%" PRId32 ") W/H=%" PRIu32 "x%" PRIu32 ")", From 0c550ec9824d9ba53cdb5b814e14c8051be50683 Mon Sep 17 00:00:00 2001 From: Pascal Nowack Date: Sun, 19 Sep 2021 14:44:23 +0200 Subject: [PATCH 086/496] rdpei/server: Fix PDU length for RDPINPUT_PROTOCOL_V300 When the server supports the protocol version RDPINPUT_PROTOCOL_V300, the additional supportedFeatures field will be present. The pduLength in the RDPINPUT_HEADER should, however, reflect this. So, fix this error by writing the correct PDU length when the supportedFeatures field is present. (cherry picked from commit 1e18b538210b4fd70839472c31c653e56b10c561) --- channels/rdpei/server/rdpei_main.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/channels/rdpei/server/rdpei_main.c b/channels/rdpei/server/rdpei_main.c index 80ab4b638a21..1e2dfe2427cb 100644 --- a/channels/rdpei/server/rdpei_main.c +++ b/channels/rdpei/server/rdpei_main.c @@ -612,6 +612,7 @@ UINT rdpei_server_send_sc_ready_ex(RdpeiServerContext* context, UINT32 version, { ULONG written; RdpeiServerPrivate* priv = context->priv; + UINT32 pduLen = 4; if (priv->automataState != STATE_INITIAL) { @@ -621,14 +622,17 @@ UINT rdpei_server_send_sc_ready_ex(RdpeiServerContext* context, UINT32 version, Stream_SetPosition(priv->outputStream, 0); - if (!Stream_EnsureCapacity(priv->outputStream, RDPINPUT_HEADER_LENGTH + 4)) + if (version >= RDPINPUT_PROTOCOL_V300) + pduLen += 4; + + if (!Stream_EnsureCapacity(priv->outputStream, RDPINPUT_HEADER_LENGTH + pduLen)) { WLog_ERR(TAG, "Stream_EnsureCapacity failed!"); return CHANNEL_RC_NO_MEMORY; } Stream_Write_UINT16(priv->outputStream, EVENTID_SC_READY); - Stream_Write_UINT32(priv->outputStream, RDPINPUT_HEADER_LENGTH + 4); + Stream_Write_UINT32(priv->outputStream, RDPINPUT_HEADER_LENGTH + pduLen); Stream_Write_UINT32(priv->outputStream, version); if (version >= RDPINPUT_PROTOCOL_V300) Stream_Write_UINT32(priv->outputStream, features); From 9e497c22a929c20fe27ee26b0880359130795f98 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Tue, 22 Feb 2022 12:16:50 +0100 Subject: [PATCH 087/496] Updated chanelog and version --- CMakeLists.txt | 2 +- ChangeLog | 6 ++++-- client/Android/android_freerdp.c | 2 +- winpr/CMakeLists.txt | 2 +- 4 files changed, 7 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d7a9cdbd136f..967304e95d2c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -85,7 +85,7 @@ if ($ENV{BUILD_NUMBER}) endif() set(WITH_LIBRARY_VERSIONING "ON") -set(RAW_VERSION_STRING "2.5.1") +set(RAW_VERSION_STRING "2.6.0") if(EXISTS "${CMAKE_SOURCE_DIR}/.source_tag") file(READ ${CMAKE_SOURCE_DIR}/.source_tag RAW_VERSION_STRING) elseif(USE_VERSION_FROM_GIT_TAG) diff --git a/ChangeLog b/ChangeLog index 231c81174957..b7c7c4f105a4 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,10 +1,12 @@ -# 2022-XX-YY Version 2.5.1 +# 2022-02-22 Version 2.6.0 Noteworthy changes: * Backported android FFMPEG build scripts * Updated android build dependencies Fixed issues: +* Backported #7303: Fix PDU length for RDPINPUT_PROTOCOL_V300 +* Backported #7658: Sanitize optional physical monitor size values * Backported #7426: Wayland memory corruption * Backported #7293: Remove unused codec x264 * Backported #7541: Allow resolutions larger 2048x2048 @@ -17,7 +19,7 @@ Fixed issues: Important notes: For a complete and detailed change log since the last release run: -git log 2.5.0..2.5.1 +git log 2.5.0..2.6.0 # 2022-01-12 Version 2.5.0 diff --git a/client/Android/android_freerdp.c b/client/Android/android_freerdp.c index 178a22f7d7ab..246f6913dd93 100644 --- a/client/Android/android_freerdp.c +++ b/client/Android/android_freerdp.c @@ -57,7 +57,7 @@ #define TAG CLIENT_TAG("android") /* Defines the JNI version supported by this library. */ -#define FREERDP_JNI_VERSION "2.5.1" +#define FREERDP_JNI_VERSION "2.6.0" static void android_OnChannelConnectedEventHandler(void* context, ChannelConnectedEventArgs* e) { diff --git a/winpr/CMakeLists.txt b/winpr/CMakeLists.txt index 400357b3de98..3bad25b8cab9 100644 --- a/winpr/CMakeLists.txt +++ b/winpr/CMakeLists.txt @@ -51,7 +51,7 @@ if (NOT WIN32) endif() # Soname versioning -set(RAW_VERSION_STRING "2.5.1") +set(RAW_VERSION_STRING "2.6.0") if(EXISTS "${CMAKE_SOURCE_DIR}/.source_tag") file(READ ${CMAKE_SOURCE_DIR}/.source_tag RAW_VERSION_STRING) elseif(USE_VERSION_FROM_GIT_TAG) From 8a5c034d547c428c512b0a4b840d3a8a4762f989 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Tue, 22 Feb 2022 12:25:57 +0100 Subject: [PATCH 088/496] Fixed duplicate comment warning --- channels/rdpgfx/rdpgfx_common.c | 1 - 1 file changed, 1 deletion(-) diff --git a/channels/rdpgfx/rdpgfx_common.c b/channels/rdpgfx/rdpgfx_common.c index 09f713af6f3f..c0bc0b08f952 100644 --- a/channels/rdpgfx/rdpgfx_common.c +++ b/channels/rdpgfx/rdpgfx_common.c @@ -1,4 +1,3 @@ -/** /** * FreeRDP: A Remote Desktop Protocol Implementation * Graphics Pipeline Extension From b0768032196ba71057303f96bcfa02e64577610d Mon Sep 17 00:00:00 2001 From: akallabeth Date: Mon, 28 Feb 2022 08:07:33 +0100 Subject: [PATCH 089/496] Added openH264 decoder frame flush (cherry picked from commit 366ad75bb4c5a04146b80abf6d16cf257e84a5f7) --- libfreerdp/codec/h264_openh264.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/libfreerdp/codec/h264_openh264.c b/libfreerdp/codec/h264_openh264.c index 5321f30ec14f..9efce29a7b5d 100644 --- a/libfreerdp/codec/h264_openh264.c +++ b/libfreerdp/codec/h264_openh264.c @@ -115,6 +115,21 @@ static int openh264_decompress(H264_CONTEXT* h264, const BYTE* pSrcData, UINT32 } } + if (state != dsErrorFree) + { + WLog_Print(h264->log, WLOG_WARN, "DecodeFrame2 state: 0x%02X", state); + return -2003; + } + +#if OPENH264_MAJOR >= 2 + state = (*sys->pDecoder)->FlushFrame(sys->pDecoder, pYUVData, &sBufferInfo); + if (state != dsErrorFree) + { + WLog_Print(h264->log, WLOG_WARN, "FlushFrame state: 0x%02X", state); + return -2003; + } +#endif + pSystemBuffer = &sBufferInfo.UsrData.sSystemBuffer; iStride[0] = pSystemBuffer->iStride[0]; iStride[1] = pSystemBuffer->iStride[1]; From de805f8565481575b9f0276e129bda714428f930 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Thu, 3 Mar 2022 10:48:15 +0100 Subject: [PATCH 090/496] Decreased logging verbosity for INFO level (cherry picked from commit e6b037385915c6049331260cf41e26a430dfeead) --- client/X11/xf_client.c | 2 +- client/X11/xf_cliprdr.c | 2 +- client/X11/xf_input.c | 14 +++++++------- client/X11/xf_window.c | 2 +- client/common/cmdline.c | 4 ++-- libfreerdp/core/freerdp.c | 2 +- libfreerdp/primitives/primitives.c | 2 +- winpr/libwinpr/clipboard/clipboard.c | 2 +- 8 files changed, 15 insertions(+), 15 deletions(-) diff --git a/client/X11/xf_client.c b/client/X11/xf_client.c index 4bdad53db997..24a03d488b8d 100644 --- a/client/X11/xf_client.c +++ b/client/X11/xf_client.c @@ -1461,7 +1461,7 @@ static BOOL handle_window_events(freerdp* instance) { if (!xf_process_x_events(instance)) { - WLog_INFO(TAG, "Closed from X11"); + WLog_DBG(TAG, "Closed from X11"); return FALSE; } } diff --git a/client/X11/xf_cliprdr.c b/client/X11/xf_cliprdr.c index e08048f88b7e..85a17363c7af 100644 --- a/client/X11/xf_cliprdr.c +++ b/client/X11/xf_cliprdr.c @@ -1570,7 +1570,7 @@ xf_cliprdr_server_format_data_response(CliprdrClientContext* context, { if (SrcSize == 0) { - WLog_INFO(TAG, "skipping, empty data detected!!!"); + WLog_DBG(TAG, "skipping, empty data detected!"); free(clipboard->respond); clipboard->respond = NULL; return CHANNEL_RC_OK; diff --git a/client/X11/xf_input.c b/client/X11/xf_input.c index 9bb417ea5bc1..50a52e0359d1 100644 --- a/client/X11/xf_input.c +++ b/client/X11/xf_input.c @@ -152,8 +152,8 @@ int xf_input_init(xfContext* xfc, Window window) if (xfc->context.settings->MultiTouchInput) { - WLog_INFO(TAG, "%s (%d) \"%s\" id: %d", xf_input_get_class_string(class->type), - class->type, dev->name, dev->deviceid); + WLog_DBG(TAG, "%s (%d) \"%s\" id: %d", xf_input_get_class_string(class->type), + class->type, dev->name, dev->deviceid); } evmasks[nmasks].mask = masks[nmasks]; @@ -166,9 +166,9 @@ int xf_input_init(xfContext* xfc, Window window) { if (xfc->context.settings->MultiTouchInput) { - WLog_INFO(TAG, "%s %s touch device (id: %d, mode: %d), supporting %d touches.", - dev->name, (t->mode == XIDirectTouch) ? "direct" : "dependent", - dev->deviceid, t->mode, t->num_touches); + WLog_DBG(TAG, "%s %s touch device (id: %d, mode: %d), supporting %d touches.", + dev->name, (t->mode == XIDirectTouch) ? "direct" : "dependent", + dev->deviceid, t->mode, t->num_touches); } XISetMask(masks[nmasks], XI_TouchBegin); @@ -182,8 +182,8 @@ int xf_input_init(xfContext* xfc, Window window) if (!touch && (class->type == XIButtonClass) && strcmp(dev->name, "Virtual core pointer")) { - WLog_INFO(TAG, "%s button device (id: %d, mode: %d)", dev->name, dev->deviceid, - t->mode); + WLog_DBG(TAG, "%s button device (id: %d, mode: %d)", dev->name, dev->deviceid, + t->mode); XISetMask(masks[nmasks], XI_ButtonPress); XISetMask(masks[nmasks], XI_ButtonRelease); XISetMask(masks[nmasks], XI_Motion); diff --git a/client/X11/xf_window.c b/client/X11/xf_window.c index 55ea71232a33..5c50a077ba89 100644 --- a/client/X11/xf_window.c +++ b/client/X11/xf_window.c @@ -355,7 +355,7 @@ BOOL xf_GetWindowProperty(xfContext* xfc, Window window, Atom property, int leng if (actual_type == None) { - WLog_INFO(TAG, "Property %lu does not exist", (unsigned long)property); + WLog_DBG(TAG, "Property %lu does not exist", (unsigned long)property); return FALSE; } diff --git a/client/common/cmdline.c b/client/common/cmdline.c index e6b3e55d89ea..15d4813871f2 100644 --- a/client/common/cmdline.c +++ b/client/common/cmdline.c @@ -3499,7 +3499,7 @@ static BOOL freerdp_client_load_static_channel_addin(rdpChannels* channels, rdpS { if (freerdp_channels_client_load_ex(channels, settings, entryEx, data) == 0) { - WLog_INFO(TAG, "loading channelEx %s", name); + WLog_DBG(TAG, "loading channelEx %s", name); return TRUE; } } @@ -3507,7 +3507,7 @@ static BOOL freerdp_client_load_static_channel_addin(rdpChannels* channels, rdpS { if (freerdp_channels_client_load(channels, settings, entry, data) == 0) { - WLog_INFO(TAG, "loading channel %s", name); + WLog_DBG(TAG, "loading channel %s", name); return TRUE; } } diff --git a/libfreerdp/core/freerdp.c b/libfreerdp/core/freerdp.c index a070d0c8426c..d7e54e0d240a 100644 --- a/libfreerdp/core/freerdp.c +++ b/libfreerdp/core/freerdp.c @@ -886,7 +886,7 @@ void freerdp_set_last_error_ex(rdpContext* context, UINT32 lastError, const char if (lastError == FREERDP_ERROR_SUCCESS) { - WLog_INFO(TAG, "%s:%s resetting error state", fkt, __FUNCTION__); + WLog_DBG(TAG, "%s:%s resetting error state", fkt, __FUNCTION__); } else if (context->LastError != FREERDP_ERROR_SUCCESS) { diff --git a/libfreerdp/primitives/primitives.c b/libfreerdp/primitives/primitives.c index 26c6338f6fa9..0a4303d9f051 100644 --- a/libfreerdp/primitives/primitives.c +++ b/libfreerdp/primitives/primitives.c @@ -260,7 +260,7 @@ static BOOL primitives_autodetect_best(primitives_t* prims) /* finally compute the results */ *prims = *best->prims; - WLog_INFO(TAG, "primitives autodetect, using %s", best->name); + WLog_DBG(TAG, "primitives autodetect, using %s", best->name); ret = TRUE; out: if (!ret) diff --git a/winpr/libwinpr/clipboard/clipboard.c b/winpr/libwinpr/clipboard/clipboard.c index 2e88d75bba7f..3c5acd4cca5c 100644 --- a/winpr/libwinpr/clipboard/clipboard.c +++ b/winpr/libwinpr/clipboard/clipboard.c @@ -528,7 +528,7 @@ static void ClipboardInitLocalFileSubsystem(wClipboard* clipboard) #ifdef WITH_WCLIPBOARD_POSIX if (ClipboardInitPosixFileSubsystem(clipboard)) { - WLog_INFO(TAG, "initialized POSIX local file subsystem"); + WLog_DBG(TAG, "initialized POSIX local file subsystem"); return; } else From dd92a7a040108808b15a69af8db4a3295d149eb2 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Thu, 3 Mar 2022 11:16:50 +0100 Subject: [PATCH 091/496] Respect USE_VERSION_FROM_GIT_TAG (cherry picked from commit 20b2d4c7e490160b4f0f279f7cfae47c84948541) --- CMakeLists.txt | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 967304e95d2c..51d67ac3e366 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -111,6 +111,24 @@ else() endif() message("FREERDP_VERSION=${FREERDP_VERSION_FULL}") +if(EXISTS "${PROJECT_SOURCE_DIR}/.source_version" ) + file(READ ${PROJECT_SOURCE_DIR}/.source_version GIT_REVISION) + + string(STRIP ${GIT_REVISION} GIT_REVISION) +elseif(USE_VERSION_FROM_GIT_TAG) + git_get_exact_tag(GIT_REVISION --tags --always) + + if (${GIT_REVISION} STREQUAL "n/a") + git_rev_parse (GIT_REVISION --short) + endif() +endif() + +if (NOT GIT_REVISION) + set(GIT_REVISION ${FREEERDP_VERSION}) +endif() + +message(STATUS "Git Revision ${GIT_REVISION}") + set(FREERDP_INCLUDE_DIR "include/freerdp${FREERDP_VERSION_MAJOR}/") # Compatibility options @@ -147,25 +165,11 @@ if(CCACHE AND WITH_CCACHE) endif() endif(CCACHE AND WITH_CCACHE) -if(EXISTS "${CMAKE_SOURCE_DIR}/.source_version" ) - file(READ ${CMAKE_SOURCE_DIR}/.source_version GIT_REVISION) - - string(STRIP ${GIT_REVISION} GIT_REVISION) -else() - git_get_exact_tag(GIT_REVISION --tags --always) - - if (${GIT_REVISION} STREQUAL "n/a") - git_rev_parse (GIT_REVISION --short) - endif() -endif() - if(CMAKE_CROSSCOMPILING) SET (CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ONLY) endif(CMAKE_CROSSCOMPILING) # /Allow to search the host machine for git/ccache -message(STATUS "Git Revision ${GIT_REVISION}") - # Turn on solution folders (2.8.4+) set_property(GLOBAL PROPERTY USE_FOLDERS ON) From 71f3c3a49b7ffe06a16473858a6ec5566f36d26b Mon Sep 17 00:00:00 2001 From: Bernhard Miklautz Date: Mon, 7 Mar 2022 12:21:04 +0100 Subject: [PATCH 092/496] new: add some basic documentation about version dectction (cherry picked from commit 130fe26e6237ca8ed8e583432dde88804fbc71b4) --- CMakeLists.txt | 2 +- docs/version_detection.md | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 docs/version_detection.md diff --git a/CMakeLists.txt b/CMakeLists.txt index 51d67ac3e366..be3411e13201 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -124,7 +124,7 @@ elseif(USE_VERSION_FROM_GIT_TAG) endif() if (NOT GIT_REVISION) - set(GIT_REVISION ${FREEERDP_VERSION}) + set(GIT_REVISION ${FREERDP_VERSION}) endif() message(STATUS "Git Revision ${GIT_REVISION}") diff --git a/docs/version_detection.md b/docs/version_detection.md new file mode 100644 index 000000000000..0cd3b896306f --- /dev/null +++ b/docs/version_detection.md @@ -0,0 +1,35 @@ +As FreeRDPs is build on different OS with different build tools and methods the +"version detection" has grown historically. +This document quickly describes how it's currently used. + +When doing a `xfreerdp /version` for example the following is shown + +`This is FreeRDP version 3.0.0-dev (c99c4cecddee4e5b914b122bc1531d47a668bb8e)` + +The first part ist the Version as defined in `RAW_VERSION_STRING` and the second part, in braces, +the `GIT_REVISON` of this version. + +`RAW_VERSION_STRING` is very vital as it determines the version used for libraries as well also for +all sub-projects as WinPR. + +As default both variables are equal. + +For nightly or development builds it is often of advantage to have the actual version from git +instead of having the hard coded value set in CMakeLists.txt. For this the cmake variable `USE_VERSION_FROM_GIT_TAG` +can be set. In order for this to work you need a) source checkout and b) git command line utility. +If enabled the information from the last git tag (in the format major.minor.patch-extra like +2.6.0-android12) will be used. + +If you are building FreeRDP and can't use git because it's not available or the source is not in an +git repository - for example when building packages - the files `.source_tag` and `.source_version` +in the top-level source directory can be used. `.source_tag` is equal to `RAW_VERSION_STRING` and +need to contain the version in the same format as the git tag. `.source_version` is used to pre-fill +`GIT_REVISON`. Although mostly used for that it must not contain a git commit or tag - it can be +used to set additional arbitrary information. Our recommendation for packagers is to create +`.source_version` when importing and set it to the upstream commit or tag to simplify issue +tracking. + +As summary the different mechanisms are applied in that order: +* `.source_tag` and `.source_version` if found +* version set from the last git tag if `RAW_VERSION_STRING` is set +* hard coded version in CMakeLists.txt From bd6521ed65cec140feb5626656f007ec27268087 Mon Sep 17 00:00:00 2001 From: Bernhard Miklautz Date: Mon, 7 Mar 2022 12:49:18 +0100 Subject: [PATCH 093/496] new: mention version detection in the ChangeLog --- ChangeLog | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/ChangeLog b/ChangeLog index b7c7c4f105a4..9efdc44c31e6 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,16 @@ +# 2022-xx-yy Version 2.6.x + +Noteworthy changes: + +Fixed issues: +* Backported improved version dection see docs/version_detection.md for details + +Important notes: + +For a complete and detailed change log since the last release run: +git log 2.0.0..2.6.x + + # 2022-02-22 Version 2.6.0 Noteworthy changes: From 334e8a8475aef3bb0dbe84d03554972b34967ad2 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Fri, 4 Mar 2022 09:55:12 +0100 Subject: [PATCH 094/496] Backported rdpsnd channel cleanup fixes --- channels/rdpsnd/client/rdpsnd_main.c | 177 ++++++++++++++++----------- 1 file changed, 106 insertions(+), 71 deletions(-) diff --git a/channels/rdpsnd/client/rdpsnd_main.c b/channels/rdpsnd/client/rdpsnd_main.c index c6d193e2c927..33b0a57898fe 100644 --- a/channels/rdpsnd/client/rdpsnd_main.c +++ b/channels/rdpsnd/client/rdpsnd_main.c @@ -182,7 +182,7 @@ static void rdpsnd_select_supported_audio_formats(rdpsndPlugin* rdpsnd) rdpsnd->ClientFormats = audio_formats_new(rdpsnd->NumberOfServerFormats); - if (!rdpsnd->ClientFormats) + if (!rdpsnd->ClientFormats || !rdpsnd->device) return; for (index = 0; index < rdpsnd->NumberOfServerFormats; index++) @@ -213,6 +213,10 @@ static UINT rdpsnd_send_client_audio_formats(rdpsndPlugin* rdpsnd) UINT16 length; UINT32 dwVolume; UINT16 wNumberOfFormats; + + if (!rdpsnd->device || (!rdpsnd->dynamic && (rdpsnd->OpenHandle == 0))) + return CHANNEL_RC_INITIALIZATION_ERROR; + dwVolume = IFCALLRESULT(0, rdpsnd->device->GetVolume, rdpsnd->device); wNumberOfFormats = rdpsnd->NumberOfClientFormats; length = 4 + 20; @@ -695,7 +699,7 @@ static void rdpsnd_recv_close_pdu(rdpsndPlugin* rdpsnd) */ static UINT rdpsnd_recv_volume_pdu(rdpsndPlugin* rdpsnd, wStream* s) { - BOOL rc; + BOOL rc = FALSE; UINT32 dwVolume; if (Stream_GetRemainingLength(s) < 4) @@ -704,7 +708,8 @@ static UINT rdpsnd_recv_volume_pdu(rdpsndPlugin* rdpsnd, wStream* s) Stream_Read_UINT32(s, dwVolume); WLog_Print(rdpsnd->log, WLOG_DEBUG, "%s Volume: 0x%08" PRIX32 "", rdpsnd_is_dyn_str(rdpsnd->dynamic), dwVolume); - rc = IFCALLRESULT(FALSE, rdpsnd->device->SetVolume, rdpsnd->device, dwVolume); + if (rdpsnd->device) + rc = IFCALLRESULT(FALSE, rdpsnd->device->SetVolume, rdpsnd->device, dwVolume); if (!rc) { @@ -1182,34 +1187,28 @@ static UINT rdpsnd_virtual_channel_event_connected(rdpsndPlugin* rdpsnd, LPVOID UINT32 dataLength) { UINT32 status; + DWORD opened = 0; WINPR_UNUSED(pData); WINPR_UNUSED(dataLength); status = rdpsnd->channelEntryPoints.pVirtualChannelOpenEx( - rdpsnd->InitHandle, &rdpsnd->OpenHandle, rdpsnd->channelDef.name, - rdpsnd_virtual_channel_open_event_ex); + rdpsnd->InitHandle, &opened, rdpsnd->channelDef.name, rdpsnd_virtual_channel_open_event_ex); if (status != CHANNEL_RC_OK) { WLog_ERR(TAG, "%s pVirtualChannelOpenEx failed with %s [%08" PRIX32 "]", rdpsnd_is_dyn_str(rdpsnd->dynamic), WTSErrorToString(status), status); - return status; - } - - rdpsnd->dsp_context = freerdp_dsp_context_new(FALSE); - - if (!rdpsnd->dsp_context) goto fail; + } - rdpsnd->pool = StreamPool_New(TRUE, 4096); - - if (!rdpsnd->pool) + if (rdpsnd_process_connect(rdpsnd) != CHANNEL_RC_OK) goto fail; - return rdpsnd_process_connect(rdpsnd); + rdpsnd->OpenHandle = opened; + return CHANNEL_RC_OK; fail: - freerdp_dsp_context_free(rdpsnd->dsp_context); - StreamPool_Free(rdpsnd->pool); + if (opened != 0) + rdpsnd->channelEntryPoints.pVirtualChannelCloseEx(rdpsnd->InitHandle, opened); return CHANNEL_RC_NO_MEMORY; } @@ -1223,26 +1222,26 @@ static UINT rdpsnd_virtual_channel_event_disconnected(rdpsndPlugin* rdpsnd) { UINT error; - if (rdpsnd->OpenHandle == 0) - return CHANNEL_RC_OK; + if (rdpsnd->OpenHandle != 0) + { + DWORD opened = rdpsnd->OpenHandle; + rdpsnd->OpenHandle = 0; - if (rdpsnd->device) - IFCALL(rdpsnd->device->Close, rdpsnd->device); + if (rdpsnd->device) + IFCALL(rdpsnd->device->Close, rdpsnd->device); - error = - rdpsnd->channelEntryPoints.pVirtualChannelCloseEx(rdpsnd->InitHandle, rdpsnd->OpenHandle); + error = rdpsnd->channelEntryPoints.pVirtualChannelCloseEx(rdpsnd->InitHandle, opened); - if (CHANNEL_RC_OK != error) - { - WLog_ERR(TAG, "%s pVirtualChannelCloseEx failed with %s [%08" PRIX32 "]", - rdpsnd_is_dyn_str(rdpsnd->dynamic), WTSErrorToString(error), error); - return error; + if (CHANNEL_RC_OK != error) + { + WLog_ERR(TAG, "%s pVirtualChannelCloseEx failed with %s [%08" PRIX32 "]", + rdpsnd_is_dyn_str(rdpsnd->dynamic), WTSErrorToString(error), error); + return error; + } } - rdpsnd->OpenHandle = 0; - freerdp_dsp_context_free(rdpsnd->dsp_context); - StreamPool_Return(rdpsnd->pool, rdpsnd->data_in); - StreamPool_Free(rdpsnd->pool); + if (rdpsnd->pool) + StreamPool_Return(rdpsnd->pool, rdpsnd->data_in); audio_formats_free(rdpsnd->ClientFormats, rdpsnd->NumberOfClientFormats); rdpsnd->NumberOfClientFormats = 0; @@ -1266,6 +1265,36 @@ static void _queue_free(void* obj) Stream_Release(s); } +static void free_internals(rdpsndPlugin* rdpsnd) +{ + if (!rdpsnd) + return; + + freerdp_dsp_context_free(rdpsnd->dsp_context); + StreamPool_Free(rdpsnd->pool); + rdpsnd->pool = NULL; + rdpsnd->dsp_context = NULL; +} + +static BOOL allocate_internals(rdpsndPlugin* rdpsnd) +{ + if (!rdpsnd->pool) + { + rdpsnd->pool = StreamPool_New(TRUE, 4096); + if (!rdpsnd->pool) + return FALSE; + } + + if (!rdpsnd->dsp_context) + { + rdpsnd->dsp_context = freerdp_dsp_context_new(FALSE); + if (!rdpsnd->dsp_context) + return FALSE; + } + + return TRUE; +} + static DWORD WINAPI play_thread(LPVOID arg) { UINT error = CHANNEL_RC_OK; @@ -1311,17 +1340,22 @@ static UINT rdpsnd_virtual_channel_event_initialized(rdpsndPlugin* rdpsnd) if (!rdpsnd->queue) return CHANNEL_RC_NO_MEMORY; + if (!allocate_internals(rdpsnd)) + return CHANNEL_RC_NO_MEMORY; + rdpsnd->thread = CreateThread(NULL, 0, play_thread, rdpsnd, 0, NULL); if (!rdpsnd->thread) return CHANNEL_RC_INITIALIZATION_ERROR; + return CHANNEL_RC_OK; } -static void rdpsnd_virtual_channel_event_terminated(rdpsndPlugin* rdpsnd) +void rdpsnd_virtual_channel_event_terminated(rdpsndPlugin* rdpsnd) { if (rdpsnd) { - MessageQueue_PostQuit(rdpsnd->queue, 0); + if (rdpsnd->queue) + MessageQueue_PostQuit(rdpsnd->queue, 0); if (rdpsnd->thread) { WaitForSingleObject(rdpsnd->thread, INFINITE); @@ -1329,6 +1363,7 @@ static void rdpsnd_virtual_channel_event_terminated(rdpsndPlugin* rdpsnd) } MessageQueue_Free(rdpsnd->queue); + free_internals(rdpsnd); audio_formats_free(rdpsnd->fixed_format, 1); free(rdpsnd->subsystem); free(rdpsnd->device_name); @@ -1370,6 +1405,7 @@ static VOID VCAPITYPE rdpsnd_virtual_channel_init_event_ex(LPVOID lpUserParam, L case CHANNEL_EVENT_TERMINATED: rdpsnd_virtual_channel_event_terminated(plugin); + plugin = NULL; break; case CHANNEL_EVENT_ATTACHED: @@ -1401,6 +1437,27 @@ rdpContext* freerdp_rdpsnd_get_context(rdpsndPlugin* plugin) return plugin->rdpcontext; } +static rdpsndPlugin* allocatePlugin(void) +{ + rdpsndPlugin* rdpsnd = (rdpsndPlugin*)calloc(1, sizeof(rdpsndPlugin)); + if (!rdpsnd) + goto fail; + + rdpsnd->fixed_format = audio_format_new(); + if (!rdpsnd->fixed_format) + goto fail; + rdpsnd->log = WLog_Get("com.freerdp.channels.rdpsnd.client"); + if (!rdpsnd->log) + goto fail; + + rdpsnd->attached = TRUE; + return rdpsnd; + +fail: + if (rdpsnd) + audio_format_free(rdpsnd->fixed_format); + return NULL; +} /* rdpsnd is always built-in */ BOOL VCAPITYPE rdpsnd_VirtualChannelEntryEx(PCHANNEL_ENTRY_POINTS pEntryPoints, PVOID pInitHandle) { @@ -1411,12 +1468,11 @@ BOOL VCAPITYPE rdpsnd_VirtualChannelEntryEx(PCHANNEL_ENTRY_POINTS pEntryPoints, if (!pEntryPoints) return FALSE; - rdpsnd = (rdpsndPlugin*)calloc(1, sizeof(rdpsndPlugin)); + rdpsnd = allocatePlugin(); if (!rdpsnd) return FALSE; - rdpsnd->attached = TRUE; rdpsnd->channelDef.options = CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_ENCRYPT_RDP; sprintf_s(rdpsnd->channelDef.name, ARRAYSIZE(rdpsnd->channelDef.name), "rdpsnd"); pEntryPointsEx = (CHANNEL_ENTRY_POINTS_FREERDP_EX*)pEntryPoints; @@ -1427,15 +1483,6 @@ BOOL VCAPITYPE rdpsnd_VirtualChannelEntryEx(PCHANNEL_ENTRY_POINTS pEntryPoints, rdpsnd->rdpcontext = pEntryPointsEx->context; } - rdpsnd->fixed_format = audio_format_new(); - - if (!rdpsnd->fixed_format) - { - free(rdpsnd); - return FALSE; - } - - rdpsnd->log = WLog_Get("com.freerdp.channels.rdpsnd.client"); CopyMemory(&(rdpsnd->channelEntryPoints), pEntryPoints, sizeof(CHANNEL_ENTRY_POINTS_FREERDP_EX)); rdpsnd->InitHandle = pInitHandle; @@ -1447,7 +1494,7 @@ BOOL VCAPITYPE rdpsnd_VirtualChannelEntryEx(PCHANNEL_ENTRY_POINTS pEntryPoints, { WLog_ERR(TAG, "%s pVirtualChannelInitEx failed with %s [%08" PRIX32 "]", rdpsnd_is_dyn_str(FALSE), WTSErrorToString(rc), rc); - free(rdpsnd); + rdpsnd_virtual_channel_event_terminated(rdpsnd); return FALSE; } @@ -1459,19 +1506,10 @@ static UINT rdpsnd_on_open(IWTSVirtualChannelCallback* pChannelCallback) RDPSND_CHANNEL_CALLBACK* callback = (RDPSND_CHANNEL_CALLBACK*)pChannelCallback; rdpsndPlugin* rdpsnd = (rdpsndPlugin*)callback->plugin; - rdpsnd->dsp_context = freerdp_dsp_context_new(FALSE); - if (!rdpsnd->dsp_context) - goto fail; - - rdpsnd->pool = StreamPool_New(TRUE, 4096); - if (!rdpsnd->pool) - goto fail; + if (!allocate_internals(rdpsnd)) + return ERROR_OUTOFMEMORY; return rdpsnd_process_connect(rdpsnd); -fail: - freerdp_dsp_context_free(rdpsnd->dsp_context); - StreamPool_Free(rdpsnd->pool); - return CHANNEL_RC_NO_MEMORY; } static UINT rdpsnd_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, wStream* data) @@ -1479,7 +1517,9 @@ static UINT rdpsnd_on_data_received(IWTSVirtualChannelCallback* pChannelCallback RDPSND_CHANNEL_CALLBACK* callback = (RDPSND_CHANNEL_CALLBACK*)pChannelCallback; rdpsndPlugin* plugin; wStream* copy; - size_t len = Stream_GetRemainingLength(data); + size_t len; + + len = Stream_GetRemainingLength(data); if (!callback || !callback->plugin) return ERROR_INVALID_PARAMETER; @@ -1508,9 +1548,10 @@ static UINT rdpsnd_on_close(IWTSVirtualChannelCallback* pChannelCallback) if (rdpsnd->device) IFCALL(rdpsnd->device->Close, rdpsnd->device); - freerdp_dsp_context_free(rdpsnd->dsp_context); - StreamPool_Return(rdpsnd->pool, rdpsnd->data_in); - StreamPool_Free(rdpsnd->pool); + if (rdpsnd->pool) + { + StreamPool_Return(rdpsnd->pool, rdpsnd->data_in); + } audio_formats_free(rdpsnd->ClientFormats, rdpsnd->NumberOfClientFormats); rdpsnd->NumberOfClientFormats = 0; @@ -1524,6 +1565,7 @@ static UINT rdpsnd_on_close(IWTSVirtualChannelCallback* pChannelCallback) rdpsnd->device = NULL; } + free_internals(rdpsnd); free(pChannelCallback); return CHANNEL_RC_OK; } @@ -1622,7 +1664,7 @@ UINT rdpsnd_DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints) if (!rdpsnd) { - rdpsnd = (rdpsndPlugin*)calloc(1, sizeof(rdpsndPlugin)); + rdpsnd = allocatePlugin(); if (!rdpsnd) { WLog_ERR(TAG, "%s calloc failed!", rdpsnd_is_dyn_str(TRUE)); @@ -1633,14 +1675,10 @@ UINT rdpsnd_DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints) rdpsnd->iface.Connected = NULL; rdpsnd->iface.Disconnected = NULL; rdpsnd->iface.Terminated = rdpsnd_plugin_terminated; - rdpsnd->attached = TRUE; rdpsnd->dynamic = TRUE; - rdpsnd->fixed_format = audio_format_new(); - if (!rdpsnd->fixed_format) - goto fail; - rdpsnd->log = WLog_Get("com.freerdp.channels.rdpsnd.client"); - rdpsnd->channelEntryPoints.pExtendedData = pEntryPoints->GetPluginData(pEntryPoints); + /* user data pointer is not const, cast to avoid warning. */ + rdpsnd->channelEntryPoints.pExtendedData = (void*)pEntryPoints->GetPluginData(pEntryPoints); error = pEntryPoints->RegisterPlugin(pEntryPoints, "rdpsnd", &rdpsnd->iface); } @@ -1650,8 +1688,5 @@ UINT rdpsnd_DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints) return CHANNEL_RC_BAD_CHANNEL; } - return error; -fail: - rdpsnd_plugin_terminated(&rdpsnd->iface); return error; } From 8371d85dc51581e874071624984f5787fc1da825 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Fri, 4 Mar 2022 09:39:56 +0100 Subject: [PATCH 095/496] Unified rdpsnd cleanup code (cherry picked from commit 18db3e1df863aa0bf7c2408abacf9e12d9c597d5) --- channels/rdpsnd/client/rdpsnd_main.c | 41 +++++++++++++++------------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/channels/rdpsnd/client/rdpsnd_main.c b/channels/rdpsnd/client/rdpsnd_main.c index 33b0a57898fe..ebdf93121fc2 100644 --- a/channels/rdpsnd/client/rdpsnd_main.c +++ b/channels/rdpsnd/client/rdpsnd_main.c @@ -1213,6 +1213,25 @@ static UINT rdpsnd_virtual_channel_event_connected(rdpsndPlugin* rdpsnd, LPVOID return CHANNEL_RC_NO_MEMORY; } +static void cleanup_internals(rdpsndPlugin* rdpsnd) +{ + if (!rdpsnd) + return; + + if (rdpsnd->pool) + StreamPool_Return(rdpsnd->pool, rdpsnd->data_in); + + audio_formats_free(rdpsnd->ClientFormats, rdpsnd->NumberOfClientFormats); + audio_formats_free(rdpsnd->ServerFormats, rdpsnd->NumberOfServerFormats); + + rdpsnd->NumberOfClientFormats = 0; + rdpsnd->ClientFormats = NULL; + rdpsnd->NumberOfServerFormats = 0; + rdpsnd->ServerFormats = NULL; + + rdpsnd->data_in = NULL; +} + /** * Function description * @@ -1240,15 +1259,7 @@ static UINT rdpsnd_virtual_channel_event_disconnected(rdpsndPlugin* rdpsnd) } } - if (rdpsnd->pool) - StreamPool_Return(rdpsnd->pool, rdpsnd->data_in); - - audio_formats_free(rdpsnd->ClientFormats, rdpsnd->NumberOfClientFormats); - rdpsnd->NumberOfClientFormats = 0; - rdpsnd->ClientFormats = NULL; - audio_formats_free(rdpsnd->ServerFormats, rdpsnd->NumberOfServerFormats); - rdpsnd->NumberOfServerFormats = 0; - rdpsnd->ServerFormats = NULL; + cleanup_internals(rdpsnd); if (rdpsnd->device) { @@ -1548,17 +1559,9 @@ static UINT rdpsnd_on_close(IWTSVirtualChannelCallback* pChannelCallback) if (rdpsnd->device) IFCALL(rdpsnd->device->Close, rdpsnd->device); - if (rdpsnd->pool) - { - StreamPool_Return(rdpsnd->pool, rdpsnd->data_in); - } - audio_formats_free(rdpsnd->ClientFormats, rdpsnd->NumberOfClientFormats); - rdpsnd->NumberOfClientFormats = 0; - rdpsnd->ClientFormats = NULL; - audio_formats_free(rdpsnd->ServerFormats, rdpsnd->NumberOfServerFormats); - rdpsnd->NumberOfServerFormats = 0; - rdpsnd->ServerFormats = NULL; + cleanup_internals(rdpsnd); + if (rdpsnd->device) { IFCALL(rdpsnd->device->Free, rdpsnd->device); From 658abd5597fc5ef446e0b2066138d22a7b6dd4c9 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Fri, 4 Mar 2022 10:01:50 +0100 Subject: [PATCH 096/496] Updated changelog --- ChangeLog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 9efdc44c31e6..b782c1ea71f3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -4,13 +4,13 @@ Noteworthy changes: Fixed issues: * Backported improved version dection see docs/version_detection.md for details +* Backported various rdpsnd fixes (#7695) Important notes: For a complete and detailed change log since the last release run: git log 2.0.0..2.6.x - # 2022-02-22 Version 2.6.0 Noteworthy changes: From 1e9485e4d970c329b3266705990ad43bf1c5e185 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Mon, 7 Mar 2022 11:40:09 +0100 Subject: [PATCH 097/496] Fixed #7696: Abort freerdp_connect if manually canceled If freerdp_abort_connect is called, set FREERDP_ERROR_CONNECT_CANCELLED This way freerdp_reconnect can distinguish between network issues and user interaction and abort a retry attempt. (cherry picked from commit a6b42ff6c95da02abbcd6e2a5adbd827a704571a) --- libfreerdp/core/CMakeLists.txt | 5 ++- libfreerdp/core/connection.c | 9 ++++-- libfreerdp/core/freerdp.c | 23 +++++++++----- libfreerdp/core/gateway/rpc_client.c | 3 +- libfreerdp/core/rdp.c | 5 +-- libfreerdp/core/tcp.c | 8 ----- libfreerdp/core/utils.c | 47 ++++++++++++++++++++++++++++ libfreerdp/core/utils.h | 30 ++++++++++++++++++ libfreerdp/crypto/tls.c | 2 +- 9 files changed, 110 insertions(+), 22 deletions(-) create mode 100644 libfreerdp/core/utils.c create mode 100644 libfreerdp/core/utils.h diff --git a/libfreerdp/core/CMakeLists.txt b/libfreerdp/core/CMakeLists.txt index f9f830064046..a979d7ad2dd1 100644 --- a/libfreerdp/core/CMakeLists.txt +++ b/libfreerdp/core/CMakeLists.txt @@ -131,7 +131,10 @@ set(${MODULE_PREFIX}_SRCS peer.c peer.h display.c - display.h) + display.h + utils.c + utils.h + ) set(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_SRCS} ${${MODULE_PREFIX}_GATEWAY_SRCS}) diff --git a/libfreerdp/core/connection.c b/libfreerdp/core/connection.c index 143a1cbc521b..a1a01e9b738e 100644 --- a/libfreerdp/core/connection.c +++ b/libfreerdp/core/connection.c @@ -39,6 +39,8 @@ #include #include +#include "utils.h" + #define TAG FREERDP_TAG("core.connection") /** @@ -411,10 +413,13 @@ BOOL rdp_client_disconnect_and_clear(rdpRdp* rdp) return FALSE; context = rdp->context; + + if (freerdp_get_last_error(context) == FREERDP_ERROR_CONNECT_CANCELLED) + return FALSE; + context->LastError = FREERDP_ERROR_SUCCESS; clearChannelError(context); - ResetEvent(context->abortEvent); - return TRUE; + return utils_reset_abort(context); } static BOOL rdp_client_reconnect_channels(rdpRdp* rdp, BOOL redirect) diff --git a/libfreerdp/core/freerdp.c b/libfreerdp/core/freerdp.c index d7e54e0d240a..7d9eba4287e2 100644 --- a/libfreerdp/core/freerdp.c +++ b/libfreerdp/core/freerdp.c @@ -52,6 +52,7 @@ #include #include "settings.h" +#include "utils.h" #define TAG FREERDP_TAG("core") @@ -168,7 +169,9 @@ BOOL freerdp_connect(freerdp* instance) #endif freerdp_set_last_error_log(instance->context, FREERDP_ERROR_SUCCESS); clearChannelError(instance->context); - ResetEvent(instance->context->abortEvent); + if (!utils_reset_abort(instance->context)) + return FALSE; + rdp = instance->context->rdp; settings = instance->settings; @@ -308,7 +311,8 @@ BOOL freerdp_abort_connect(freerdp* instance) if (!instance || !instance->context) return FALSE; - return SetEvent(instance->context->abortEvent); + freerdp_set_last_error_if_not(instance->context, FREERDP_ERROR_CONNECT_CANCELLED); + return utils_abort_connect(instance->context); } BOOL freerdp_get_fds(freerdp* instance, void** rfds, int* rcount, void** wfds, int* wcount) @@ -540,11 +544,16 @@ BOOL freerdp_disconnect_before_reconnect(freerdp* instance) BOOL freerdp_reconnect(freerdp* instance) { - BOOL status; - rdpRdp* rdp = instance->context->rdp; - ResetEvent(instance->context->abortEvent); - status = rdp_client_reconnect(rdp); - return status; + rdpRdp* rdp; + + if (freerdp_get_last_error(instance->context) == FREERDP_ERROR_CONNECT_CANCELLED) + return FALSE; + + rdp = instance->context->rdp; + + if (!utils_reset_abort(instance->context)) + return FALSE; + return rdp_client_reconnect(rdp); } BOOL freerdp_shall_disconnect(freerdp* instance) diff --git a/libfreerdp/core/gateway/rpc_client.c b/libfreerdp/core/gateway/rpc_client.c index fb32d3c5ed80..1ef0c04a627f 100644 --- a/libfreerdp/core/gateway/rpc_client.c +++ b/libfreerdp/core/gateway/rpc_client.c @@ -38,6 +38,7 @@ #include "rpc_client.h" #include "rts_signature.h" +#include "../utils.h" #include "../rdp.h" #include "../proxy.h" @@ -362,7 +363,7 @@ static int rpc_client_recv_fragment(rdpRpc* rpc, wStream* fragment) Stream_SetPosition(fragment, StubOffset); Stream_Read_UINT32(fragment, rpc->result); - freerdp_abort_connect(context->instance); + utils_abort_connect(context); tsg_set_state(tsg, TSG_STATE_TUNNEL_CLOSE_PENDING); EventArgsInit(&e, "freerdp"); e.code = 0; diff --git a/libfreerdp/core/rdp.c b/libfreerdp/core/rdp.c index 7da499e96f9b..610d81e25b4c 100644 --- a/libfreerdp/core/rdp.c +++ b/libfreerdp/core/rdp.c @@ -27,6 +27,7 @@ #include "rdp.h" #include "info.h" +#include "utils.h" #include "redirection.h" #include @@ -414,7 +415,7 @@ BOOL rdp_read_header(rdpRdp* rdp, wStream* s, UINT16* length, UINT16* channelId) { if (code == X224_TPDU_DISCONNECT_REQUEST) { - freerdp_abort_connect(rdp->instance); + utils_abort_connect(rdp->instance->context); return TRUE; } @@ -471,7 +472,7 @@ BOOL rdp_read_header(rdpRdp* rdp, wStream* s, UINT16* length, UINT16* channelId) } WLog_DBG(TAG, "DisconnectProviderUltimatum: reason: %d", reason); - freerdp_abort_connect(rdp->instance); + utils_abort_connect(context); EventArgsInit(&e, "freerdp"); e.code = 0; PubSub_OnTerminate(context->pubSub, context, &e); diff --git a/libfreerdp/core/tcp.c b/libfreerdp/core/tcp.c index 60b4211b59cb..0d0641b823b4 100644 --- a/libfreerdp/core/tcp.c +++ b/libfreerdp/core/tcp.c @@ -844,12 +844,7 @@ static BOOL freerdp_tcp_connect_timeout(rdpContext* context, int sockfd, struct status = WaitForMultipleObjects(count, handles, FALSE, tout); if (WAIT_OBJECT_0 != status) - { - if (status == WAIT_OBJECT_0 + 1) - freerdp_set_last_error_log(context, FREERDP_ERROR_CONNECT_CANCELLED); - goto fail; - } status = recv(sockfd, NULL, 0, 0); @@ -1235,9 +1230,6 @@ int freerdp_tcp_connect(rdpContext* context, rdpSettings* settings, const char* if (WaitForSingleObject(context->abortEvent, 0) == WAIT_OBJECT_0) { close(sockfd); - - freerdp_set_last_error_if_not(context, FREERDP_ERROR_CONNECT_CANCELLED); - return -1; } diff --git a/libfreerdp/core/utils.c b/libfreerdp/core/utils.c new file mode 100644 index 000000000000..6b6770ba5dbd --- /dev/null +++ b/libfreerdp/core/utils.c @@ -0,0 +1,47 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Terminal Server Gateway (utils) + * + * Copyright 2021 Armin Novak + * Copyright 2021 Thincast Technologies GmbH + * + * 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include + +#include +#define TAG FREERDP_TAG("core.gateway.utils") + +#include "utils.h" + +#define WINPR_ASSERT(x) assert(x) + +BOOL utils_abort_connect(rdpContext* context) +{ + WINPR_ASSERT(context); + + return SetEvent(context->abortEvent); +} + +BOOL utils_reset_abort(rdpContext* context) +{ + WINPR_ASSERT(context); + return ResetEvent(context->abortEvent); +} diff --git a/libfreerdp/core/utils.h b/libfreerdp/core/utils.h new file mode 100644 index 000000000000..c7985be6650d --- /dev/null +++ b/libfreerdp/core/utils.h @@ -0,0 +1,30 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Terminal Server Gateway (utils) + * + * Copyright 2021 Armin Novak + * Copyright 2021 Thincast Technologies GmbH + * + * 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_LIB_CORE_UTILS_H +#define FREERDP_LIB_CORE_UTILS_H + +#include +#include + +BOOL utils_reset_abort(rdpContext* context); +BOOL utils_abort_connect(rdpContext* context); + +#endif /* FREERDP_LIB_CORE_UTILS_H */ diff --git a/libfreerdp/crypto/tls.c b/libfreerdp/crypto/tls.c index fee8db5bd406..1990302b7637 100644 --- a/libfreerdp/crypto/tls.c +++ b/libfreerdp/crypto/tls.c @@ -866,7 +866,7 @@ int tls_connect(rdpTls* tls, BIO* underlying) #else if (!tls_prepare(tls, underlying, TLS_client_method(), options, TRUE)) #endif - return FALSE; + return 0; #if !defined(OPENSSL_NO_TLSEXT) && !defined(LIBRESSL_VERSION_NUMBER) SSL_set_tlsext_host_name(tls->ssl, tls->hostname); From 5e4347681d06270ea76be43ed486186868dc655c Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Mon, 7 Mar 2022 14:36:04 +0100 Subject: [PATCH 098/496] Changelog & version --- CMakeLists.txt | 2 +- ChangeLog | 6 ++++-- client/Android/Studio/build.gradle | 2 +- client/Android/android_freerdp.c | 2 +- winpr/CMakeLists.txt | 2 +- 5 files changed, 8 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index be3411e13201..930eee189460 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -85,7 +85,7 @@ if ($ENV{BUILD_NUMBER}) endif() set(WITH_LIBRARY_VERSIONING "ON") -set(RAW_VERSION_STRING "2.6.0") +set(RAW_VERSION_STRING "2.6.1") if(EXISTS "${CMAKE_SOURCE_DIR}/.source_tag") file(READ ${CMAKE_SOURCE_DIR}/.source_tag RAW_VERSION_STRING) elseif(USE_VERSION_FROM_GIT_TAG) diff --git a/ChangeLog b/ChangeLog index b782c1ea71f3..5d32697b6b12 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,15 +1,17 @@ -# 2022-xx-yy Version 2.6.x +# 2022-03-07 Version 2.6.1 Noteworthy changes: +* Decreased logging verbosity, now freerdp is much less verbose by default Fixed issues: +* Backported freerdp_abort_connect during freerdp_connect fix (#7700) * Backported improved version dection see docs/version_detection.md for details * Backported various rdpsnd fixes (#7695) Important notes: For a complete and detailed change log since the last release run: -git log 2.0.0..2.6.x +git log 2.0.0..2.6.1 # 2022-02-22 Version 2.6.0 diff --git a/client/Android/Studio/build.gradle b/client/Android/Studio/build.gradle index 313e404a9223..52985a9b7b3d 100644 --- a/client/Android/Studio/build.gradle +++ b/client/Android/Studio/build.gradle @@ -29,7 +29,7 @@ def getVersionName = { -> ext { versionName = properties.get('VERSION_NAME', getVersionName()) - versionCode = properties.get('VERSION_CODE', 27) + versionCode = properties.get('VERSION_CODE', 28) compileApi = properties.get('COMPILE_API', 31) targetApi = properties.get('TARGET_API', 31) minApi = properties.get('MIN_API', 23) diff --git a/client/Android/android_freerdp.c b/client/Android/android_freerdp.c index 246f6913dd93..e6f957e0e5ad 100644 --- a/client/Android/android_freerdp.c +++ b/client/Android/android_freerdp.c @@ -57,7 +57,7 @@ #define TAG CLIENT_TAG("android") /* Defines the JNI version supported by this library. */ -#define FREERDP_JNI_VERSION "2.6.0" +#define FREERDP_JNI_VERSION "2.6.1" static void android_OnChannelConnectedEventHandler(void* context, ChannelConnectedEventArgs* e) { diff --git a/winpr/CMakeLists.txt b/winpr/CMakeLists.txt index 3bad25b8cab9..7e5860d8c54a 100644 --- a/winpr/CMakeLists.txt +++ b/winpr/CMakeLists.txt @@ -51,7 +51,7 @@ if (NOT WIN32) endif() # Soname versioning -set(RAW_VERSION_STRING "2.6.0") +set(RAW_VERSION_STRING "2.6.1") if(EXISTS "${CMAKE_SOURCE_DIR}/.source_tag") file(READ ${CMAKE_SOURCE_DIR}/.source_tag RAW_VERSION_STRING) elseif(USE_VERSION_FROM_GIT_TAG) From 658a72980f6e93241d927c46cfa664bf2547b8b1 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Mon, 7 Mar 2022 14:48:08 +0100 Subject: [PATCH 099/496] Abort autoreconnect if a user cancel action was triggered. (cherry picked from commit 15e7647f20fd0986ddbc598a30c4d718a2baa1ce) --- client/common/client.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/client/common/client.c b/client/common/client.c index 0cdb636d8943..12317dc10fdf 100644 --- a/client/common/client.c +++ b/client/common/client.c @@ -730,6 +730,7 @@ BOOL client_auto_reconnect(freerdp* instance) BOOL client_auto_reconnect_ex(freerdp* instance, BOOL (*window_events)(freerdp* instance)) { + BOOL retry = TRUE; UINT32 error; UINT32 maxRetries; UINT32 numRetries = 0; @@ -765,7 +766,7 @@ BOOL client_auto_reconnect_ex(freerdp* instance, BOOL (*window_events)(freerdp* } /* Perform an auto-reconnect. */ - while (TRUE) + while (retry) { UINT32 x; @@ -781,12 +782,21 @@ BOOL client_auto_reconnect_ex(freerdp* instance, BOOL (*window_events)(freerdp* if (freerdp_reconnect(instance)) return TRUE; + switch (freerdp_get_last_error(instance)) + { + case FREERDP_ERROR_CONNECT_CANCELLED: + WLog_WARN(TAG, "Autoreconnect aborted by user"); + retry = FALSE; + break; + default: + break; + } for (x = 0; x < 50; x++) { if (!IFCALLRESULT(TRUE, window_events, instance)) return FALSE; - Sleep(100); + Sleep(10); } } From 631e71bebd041fbac2932555f17de050f6def91f Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Tue, 8 Mar 2022 15:01:09 +0100 Subject: [PATCH 100/496] Added more log messages for SurfaceCommand failures (cherry picked from commit c6f204091291990f85c23450778fcab35571eed5) --- libfreerdp/core/surface.c | 40 ++++++++++++++++++++++++++++++++++++--- 1 file changed, 37 insertions(+), 3 deletions(-) diff --git a/libfreerdp/core/surface.c b/libfreerdp/core/surface.c index ca89d230cf44..a99da01f3f55 100644 --- a/libfreerdp/core/surface.c +++ b/libfreerdp/core/surface.c @@ -37,7 +37,11 @@ static BOOL update_recv_surfcmd_bitmap_header_ex(wStream* s, TS_COMPRESSED_BITMA return FALSE; if (Stream_GetRemainingLength(s) < 24) + { + WLog_ERR(TAG, "got %" PRIuz ", expected %" PRIuz " bytes", Stream_GetRemainingLength(s), + 24); return FALSE; + } Stream_Read_UINT32(s, header->highUniqueId); Stream_Read_UINT32(s, header->lowUniqueId); @@ -54,7 +58,11 @@ static BOOL update_recv_surfcmd_bitmap_ex(wStream* s, TS_BITMAP_DATA_EX* bmp) return FALSE; if (Stream_GetRemainingLength(s) < 12) + { + WLog_ERR(TAG, "got %" PRIuz ", expected %" PRIuz " bytes", Stream_GetRemainingLength(s), + 12); return FALSE; + } Stream_Read_UINT8(s, bmp->bpp); Stream_Read_UINT8(s, bmp->flags); @@ -86,7 +94,11 @@ static BOOL update_recv_surfcmd_bitmap_ex(wStream* s, TS_BITMAP_DATA_EX* bmp) } if (Stream_GetRemainingLength(s) < bmp->bitmapDataLength) + { + WLog_ERR(TAG, "expected bitmapDataLength %" PRIu32 ", not enough data", + bmp->bitmapDataLength); return FALSE; + } pos = Stream_GetPosition(s) + bmp->bitmapDataLength; bmp->bitmapData = Stream_Pointer(s); @@ -132,7 +144,10 @@ static BOOL update_recv_surfcmd_surface_bits(rdpUpdate* update, wStream* s, UINT SURFACE_BITS_COMMAND cmd = { 0 }; if (Stream_GetRemainingLength(s) < 8) + { + WLog_ERR(TAG, "got %" PRIuz ", expected %" PRIuz " bytes", Stream_GetRemainingLength(s), 8); goto fail; + } cmd.cmdType = cmdType; Stream_Read_UINT16(s, cmd.destLeft); @@ -152,7 +167,12 @@ static BOOL update_recv_surfcmd_surface_bits(rdpUpdate* update, wStream* s, UINT goto fail; } - return update->SurfaceBits(update->context, &cmd); + if (!update->SurfaceBits(update->context, &cmd)) + { + WLog_DBG(TAG, "update->SurfaceBits implementation failed"); + goto fail; + } + return TRUE; fail: return FALSE; } @@ -162,7 +182,10 @@ static BOOL update_recv_surfcmd_frame_marker(rdpUpdate* update, wStream* s) SURFACE_FRAME_MARKER marker; if (Stream_GetRemainingLength(s) < 6) + { + WLog_ERR(TAG, "got %" PRIuz ", expected %" PRIuz " bytes", Stream_GetRemainingLength(s), 6); return FALSE; + } Stream_Read_UINT16(s, marker.frameAction); Stream_Read_UINT32(s, marker.frameId); @@ -176,7 +199,13 @@ static BOOL update_recv_surfcmd_frame_marker(rdpUpdate* update, wStream* s) return FALSE; } - return update->SurfaceFrameMarker(update->context, &marker); + if (!update->SurfaceFrameMarker(update->context, &marker)) + { + WLog_DBG(TAG, "update->SurfaceFrameMarker implementation failed"); + return FALSE; + } + + return TRUE; } int update_recv_surfcmds(rdpUpdate* update, wStream* s) @@ -246,10 +275,15 @@ static BOOL update_write_surfcmd_bitmap_ex(wStream* s, const TS_BITMAP_DATA_EX* if (!Stream_EnsureRemainingCapacity(s, 12)) return FALSE; + if (bmp->codecID > UINT8_MAX) + { + WLog_ERR(TAG, "Invalid TS_BITMAP_DATA_EX::codecID=0x%04" PRIx16 "", bmp->codecID); + return FALSE; + } Stream_Write_UINT8(s, bmp->bpp); Stream_Write_UINT8(s, bmp->flags); Stream_Write_UINT8(s, 0); /* reserved1, reserved2 */ - Stream_Write_UINT8(s, bmp->codecID); + Stream_Write_UINT8(s, (UINT8)bmp->codecID); Stream_Write_UINT16(s, bmp->width); Stream_Write_UINT16(s, bmp->height); Stream_Write_UINT32(s, bmp->bitmapDataLength); From 79207e6700e83ffcbd707985086bb3a6dc06dfb9 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Tue, 8 Mar 2022 15:21:23 +0100 Subject: [PATCH 101/496] rfx_process_message verbose error log (cherry picked from commit c194a68b1bb44af3a180d7bdad678655bd673dc9) --- libfreerdp/codec/rfx.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/libfreerdp/codec/rfx.c b/libfreerdp/codec/rfx.c index 8c65e7508370..b41c15794daa 100644 --- a/libfreerdp/codec/rfx.c +++ b/libfreerdp/codec/rfx.c @@ -1071,7 +1071,10 @@ BOOL rfx_process_message(RFX_CONTEXT* context, const BYTE* data, UINT32 length, UINT8 channelId; if (Stream_GetRemainingLength(s) < 2) + { + WLog_ERR(TAG, "extraBlockLen too small(%" PRIuz ")", Stream_GetRemainingLength(s)); return FALSE; + } extraBlockLen = 2; Stream_Read_UINT8(s, codecId); /* codecId (1 byte) must be set to 0x01 */ @@ -1212,6 +1215,9 @@ BOOL rfx_process_message(RFX_CONTEXT* context, const BYTE* data, UINT32 length, NULL, FREERDP_FLIP_NONE)) { region16_uninit(&updateRegion); + WLog_ERR(TAG, + "nbUpdateRectx[% " PRIu32 " (%" PRIu32 ")] freerdp_image_copy failed", + j, nbUpdateRects); return FALSE; } @@ -1226,6 +1232,7 @@ BOOL rfx_process_message(RFX_CONTEXT* context, const BYTE* data, UINT32 length, return TRUE; } + WLog_ERR(TAG, "%s failed", __FUNCTION__); return FALSE; } From baf35cece9ff369d27deae1fed23d56907d82c31 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Thu, 29 Jul 2021 13:26:05 +0200 Subject: [PATCH 102/496] Implemented #4341: Default to /network:auto If no arguments are supplied, default to the behaviour of /network:auto. This ensures the default experience is using the best available graphics options. As soon as any /network, /bpp, /rfx, /gfx, ... argument is used only use these. (cherry picked from commit d3168a1436eefe6864727991b18e458c2d6c87b3) --- client/common/cmdline.c | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/client/common/cmdline.c b/client/common/cmdline.c index 15d4813871f2..453a38c5f0d3 100644 --- a/client/common/cmdline.c +++ b/client/common/cmdline.c @@ -27,6 +27,8 @@ #include #include +#include + #include #include #include @@ -46,6 +48,8 @@ #include "cmdline.h" #include + +#define WINPR_ASSERT(x) assert(x) #define TAG CLIENT_TAG("common.cmdline") static BOOL freerdp_client_print_codepages(const char* arg) @@ -1567,6 +1571,28 @@ static BOOL parseSizeValue(const char* input, unsigned long* v1, unsigned long* return TRUE; } +static BOOL prepare_default_settings(rdpSettings* settings, const COMMAND_LINE_ARGUMENT_A* args, + BOOL rdp_file) +{ + size_t x; + const char* arguments[] = { "network", "gfx", "rfx", "bpp" }; + WINPR_ASSERT(settings); + WINPR_ASSERT(args); + + if (rdp_file) + return FALSE; + + for (x = 0; x < ARRAYSIZE(arguments); x++) + { + const char* arg = arguments[x]; + COMMAND_LINE_ARGUMENT_A* p = CommandLineFindArgumentA(args, arg); + if (p && (p->Flags & COMMAND_LINE_ARGUMENT_PRESENT)) + return FALSE; + } + + return freerdp_set_connection_type(settings, CONNECTION_TYPE_AUTODETECT); +} + int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, int argc, char** argv, BOOL allowUnknown) { @@ -1637,6 +1663,8 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, if (status < 0) return status; + + prepare_default_settings(settings, largs, ext); } CommandLineFindArgumentA(largs, "v"); From 6462eca724a886e8c1abb5b41955108023d1c1e6 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Wed, 9 Mar 2022 09:01:11 +0100 Subject: [PATCH 103/496] Workaround for [MS-RDPBCGR] 2.2.9.2.3 Frame Marker Command (TS_FRAME_MARKER) Connections with windows 2016 and 2019 sometimes receive short frame marker. Ignore these to prevent disconnects (cherry picked from commit 91ef44ed35c99c409d39f6c480592f8601b45e35) --- libfreerdp/core/surface.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/libfreerdp/core/surface.c b/libfreerdp/core/surface.c index a99da01f3f55..e288799f1602 100644 --- a/libfreerdp/core/surface.c +++ b/libfreerdp/core/surface.c @@ -181,14 +181,21 @@ static BOOL update_recv_surfcmd_frame_marker(rdpUpdate* update, wStream* s) { SURFACE_FRAME_MARKER marker; - if (Stream_GetRemainingLength(s) < 6) + if (Stream_GetRemainingLength(s) < 2) { WLog_ERR(TAG, "got %" PRIuz ", expected %" PRIuz " bytes", Stream_GetRemainingLength(s), 6); return FALSE; } Stream_Read_UINT16(s, marker.frameAction); - Stream_Read_UINT32(s, marker.frameId); + if (Stream_GetRemainingLength(s) < 4) + WLog_WARN(TAG, + "[SERVER-BUG]: got %" PRIuz ", expected %" PRIuz + " bytes. [MS-RDPBCGR] 2.2.9.2.3 Frame Marker Command (TS_FRAME_MARKER) is " + "missing frameId, ignoring", + Stream_GetRemainingLength(s), 4); + else + Stream_Read_UINT32(s, marker.frameId); WLog_Print(update->log, WLOG_DEBUG, "SurfaceFrameMarker: action: %s (%" PRIu32 ") id: %" PRIu32 "", (!marker.frameAction) ? "Begin" : "End", marker.frameAction, marker.frameId); From 1c91d66a50b2f3f602765fddd1ed2767c427a8fe Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Wed, 9 Mar 2022 15:35:47 +0100 Subject: [PATCH 104/496] Changelog --- ChangeLog | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 5d32697b6b12..608c697b883a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,7 +1,19 @@ +# 2022-XX-YY Version 2.X.Y + +Noteworthy changes: + +Fixed issues: +* Backported #6786: Use /network:auto by default +* Backported #7714: Workaround for broken surface frame marker + +Important notes: + +For a complete and detailed change log since the last release run: +git log 2.6.1..2.X.Y + # 2022-03-07 Version 2.6.1 Noteworthy changes: -* Decreased logging verbosity, now freerdp is much less verbose by default Fixed issues: * Backported freerdp_abort_connect during freerdp_connect fix (#7700) From 76660aab19020f45d398fe42100351960ad40bb2 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Wed, 9 Jun 2021 13:05:33 +0200 Subject: [PATCH 105/496] Added WINPR_ASSERT Added a WinPR macro that can be used for WinPR and FreeRDP to replace standard C assert. It is more verbose and logs issues to WLog which makes it easier for us to trace problems in the field. (cherry picked from commit b435e6db9b21bfe0a456a38f086f51151d3c20ad) --- winpr/include/winpr/assert.h | 49 ++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) create mode 100644 winpr/include/winpr/assert.h diff --git a/winpr/include/winpr/assert.h b/winpr/include/winpr/assert.h new file mode 100644 index 000000000000..724f82b971b7 --- /dev/null +++ b/winpr/include/winpr/assert.h @@ -0,0 +1,49 @@ +/** + * WinPR: Windows Portable Runtime + * Runtime ASSERT macros + * + * Copyright 2021 Armin Novak + * Copyright 2021 Thincast Technologies GmbH + * + * 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 WINPR_ASSERT_H +#define WINPR_ASSERT_H + +#include +#include +#include +#include + +#define WINPR_ASSERT(cond) \ + do \ + { \ + if (!(cond)) \ + { \ + WLog_FATAL("com.freerdp.winpr.assert", "%s [%s:%s:%" PRIuz "]", #cond, __FILE__, \ + __FUNCTION__, __LINE__); \ + abort(); \ + } \ + } while (0) + +#ifdef __cplusplus +extern "C" +{ +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* WINPR_ERROR_H */ From f522bcb63a8d2f272b1f50f5ba19617345f55259 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Thu, 10 Jun 2021 08:57:40 +0200 Subject: [PATCH 106/496] Added option do disable WINPR_ASSERT (cherry picked from commit 3a75228242401de96eaf66222e77a72a40dc3b40) --- winpr/CMakeLists.txt | 6 ++++++ winpr/include/winpr/assert.h | 7 +++++++ 2 files changed, 13 insertions(+) diff --git a/winpr/CMakeLists.txt b/winpr/CMakeLists.txt index 7e5860d8c54a..1827a0aafd83 100644 --- a/winpr/CMakeLists.txt +++ b/winpr/CMakeLists.txt @@ -21,6 +21,12 @@ project(WinPR C) set(CMAKE_COLOR_MAKEFILE ON) +option(WITH_VERBOSE_WINPR_ASSERT "Compile with verbose WINPR_ASSERT." ON) + +if (WITH_VERBOSE_WINPR_ASSERT) + add_definitions(-DWITH_VERBOSE_WINPR_ASSERT) +endif() + if(FREERDP_VERSION) set(FREERDP_BUILD 1) endif() diff --git a/winpr/include/winpr/assert.h b/winpr/include/winpr/assert.h index 724f82b971b7..ae9deb2e7da3 100644 --- a/winpr/include/winpr/assert.h +++ b/winpr/include/winpr/assert.h @@ -26,6 +26,7 @@ #include #include +#if WITH_VERBOSE_WINPR_ASSERT #define WINPR_ASSERT(cond) \ do \ { \ @@ -36,6 +37,12 @@ abort(); \ } \ } while (0) +#else +#define WINPR_ASSERT(cond) \ + do \ + { \ + } while (0) +#endif #ifdef __cplusplus extern "C" From 83dffd0009b4d8b7b241c621b6aff4efe12a0380 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Wed, 16 Jun 2021 13:11:07 +0200 Subject: [PATCH 107/496] Improve WINPR_ASSERT, log backtrace (cherry picked from commit 9e94f1dace7295e506e01b9ece59d77f62343e3c) --- winpr/include/winpr/assert.h | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/winpr/include/winpr/assert.h b/winpr/include/winpr/assert.h index ae9deb2e7da3..03f2ff2b7002 100644 --- a/winpr/include/winpr/assert.h +++ b/winpr/include/winpr/assert.h @@ -25,17 +25,19 @@ #include #include #include +#include -#if WITH_VERBOSE_WINPR_ASSERT -#define WINPR_ASSERT(cond) \ - do \ - { \ - if (!(cond)) \ - { \ - WLog_FATAL("com.freerdp.winpr.assert", "%s [%s:%s:%" PRIuz "]", #cond, __FILE__, \ - __FUNCTION__, __LINE__); \ - abort(); \ - } \ +#if defined(WITH_VERBOSE_WINPR_ASSERT) && (WITH_VERBOSE_WINPR_ASSERT != 0) +#define WINPR_ASSERT(cond) \ + do \ + { \ + if (!(cond)) \ + { \ + const char* tag = "com.freerdp.winpr.assert"; \ + WLog_FATAL(tag, "%s [%s:%s:%" PRIuz "]", #cond, __FILE__, __FUNCTION__, __LINE__); \ + winpr_log_backtrace(tag, WLOG_FATAL, 20); \ + abort(); \ + } \ } while (0) #else #define WINPR_ASSERT(cond) \ From e675ffcb35e3211b9424c8a067494057b803b935 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Tue, 1 Feb 2022 08:17:43 +0100 Subject: [PATCH 108/496] Fixed warnings from WLOG_ASSERT (cherry picked from commit 02896b0656de693a7014cc8ca6ff12de1d9ffabd) --- winpr/include/winpr/assert.h | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/winpr/include/winpr/assert.h b/winpr/include/winpr/assert.h index 03f2ff2b7002..b8530bf2b636 100644 --- a/winpr/include/winpr/assert.h +++ b/winpr/include/winpr/assert.h @@ -28,16 +28,19 @@ #include #if defined(WITH_VERBOSE_WINPR_ASSERT) && (WITH_VERBOSE_WINPR_ASSERT != 0) -#define WINPR_ASSERT(cond) \ - do \ - { \ - if (!(cond)) \ - { \ - const char* tag = "com.freerdp.winpr.assert"; \ - WLog_FATAL(tag, "%s [%s:%s:%" PRIuz "]", #cond, __FILE__, __FUNCTION__, __LINE__); \ - winpr_log_backtrace(tag, WLOG_FATAL, 20); \ - abort(); \ - } \ +#define WINPR_ASSERT(cond) \ + do \ + { \ + if (!(cond)) \ + { \ + static wLog* _log_cached_ptr = NULL; \ + if (!_log_cached_ptr) \ + _log_cached_ptr = WLog_Get("com.freerdp.winpr.assert"); \ + WLog_Print(_log_cached_ptr, WLOG_FATAL, "%s [%s:%s:%" PRIuz "]", #cond, __FILE__, \ + __FUNCTION__, __LINE__); \ + winpr_log_backtrace_ex(_log_cached_ptr, WLOG_FATAL, 20); \ + abort(); \ + } \ } while (0) #else #define WINPR_ASSERT(cond) \ From 0089ce25b48535e081e9680bf4f2bb9d7e0d0534 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Tue, 1 Feb 2022 11:49:12 +0100 Subject: [PATCH 109/496] Removed cached wlog pointer (cherry picked from commit 77580466ae31c93af63c55e4cb56b297c01093f3) --- winpr/include/winpr/assert.h | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/winpr/include/winpr/assert.h b/winpr/include/winpr/assert.h index b8530bf2b636..0cef84132892 100644 --- a/winpr/include/winpr/assert.h +++ b/winpr/include/winpr/assert.h @@ -33,9 +33,7 @@ { \ if (!(cond)) \ { \ - static wLog* _log_cached_ptr = NULL; \ - if (!_log_cached_ptr) \ - _log_cached_ptr = WLog_Get("com.freerdp.winpr.assert"); \ + wLog* _log_cached_ptr = WLog_Get("com.freerdp.winpr.assert"); \ WLog_Print(_log_cached_ptr, WLOG_FATAL, "%s [%s:%s:%" PRIuz "]", #cond, __FILE__, \ __FUNCTION__, __LINE__); \ winpr_log_backtrace_ex(_log_cached_ptr, WLOG_FATAL, 20); \ From 2008751c04bc7b51c8737f161c09ad17ae56838e Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Mon, 28 Mar 2022 11:33:38 +0200 Subject: [PATCH 110/496] Replaced WINPR_ASSERT defines, use include --- channels/ainput/client/ainput_main.c | 4 +--- channels/ainput/server/ainput_main.c | 4 +--- channels/rdpgfx/rdpgfx_common.c | 4 +--- client/common/cmdline.c | 4 +--- libfreerdp/codec/h264_mediacodec.c | 4 +--- libfreerdp/codec/progressive.c | 4 +--- libfreerdp/core/utils.c | 4 +--- winpr/libwinpr/registry/registry_reg.c | 4 +--- winpr/libwinpr/sspicli/sspicli.c | 4 +--- 9 files changed, 9 insertions(+), 27 deletions(-) diff --git a/channels/ainput/client/ainput_main.c b/channels/ainput/client/ainput_main.c index bf4ce2644d1b..d8eb8ec594b6 100644 --- a/channels/ainput/client/ainput_main.c +++ b/channels/ainput/client/ainput_main.c @@ -26,7 +26,7 @@ #include #include -#include +#include #include #include @@ -37,8 +37,6 @@ #include "../common/ainput_common.h" -#define WINPR_ASSERT(x) assert(x) - #define TAG CHANNELS_TAG("ainput.client") typedef struct AINPUT_CHANNEL_CALLBACK_ AINPUT_CHANNEL_CALLBACK; diff --git a/channels/ainput/server/ainput_main.c b/channels/ainput/server/ainput_main.c index 670b668726a3..bc1737ee1846 100644 --- a/channels/ainput/server/ainput_main.c +++ b/channels/ainput/server/ainput_main.c @@ -27,7 +27,7 @@ #include #include -#include +#include #include #include #include @@ -39,8 +39,6 @@ #include "../common/ainput_common.h" -#define WINPR_ASSERT(x) assert(x) - #define TAG CHANNELS_TAG("ainput.server") typedef enum diff --git a/channels/rdpgfx/rdpgfx_common.c b/channels/rdpgfx/rdpgfx_common.c index c0bc0b08f952..03fc97c1226b 100644 --- a/channels/rdpgfx/rdpgfx_common.c +++ b/channels/rdpgfx/rdpgfx_common.c @@ -24,12 +24,10 @@ #endif #include -#include +#include #include #include -#define WINPR_ASSERT(x) assert(x) - #define TAG CHANNELS_TAG("rdpgfx.common") #include "rdpgfx_common.h" diff --git a/client/common/cmdline.c b/client/common/cmdline.c index 453a38c5f0d3..da53f85138fe 100644 --- a/client/common/cmdline.c +++ b/client/common/cmdline.c @@ -24,10 +24,9 @@ #endif #include -#include #include -#include +#include #include #include @@ -49,7 +48,6 @@ #include -#define WINPR_ASSERT(x) assert(x) #define TAG CLIENT_TAG("common.cmdline") static BOOL freerdp_client_print_codepages(const char* arg) diff --git a/libfreerdp/codec/h264_mediacodec.c b/libfreerdp/codec/h264_mediacodec.c index ba207e5e56df..9caec04b4a27 100644 --- a/libfreerdp/codec/h264_mediacodec.c +++ b/libfreerdp/codec/h264_mediacodec.c @@ -18,7 +18,7 @@ */ #include -#include +#include #include #include @@ -29,8 +29,6 @@ #include "h264.h" -#define WINPR_ASSERT(x) assert(x) - #define RESOLVE_MEDIANDK_FUNC(sys, name) \ ({ \ BOOL rc = TRUE; \ diff --git a/libfreerdp/codec/progressive.c b/libfreerdp/codec/progressive.c index 60343b881a93..5fc98f1690bd 100644 --- a/libfreerdp/codec/progressive.c +++ b/libfreerdp/codec/progressive.c @@ -23,7 +23,7 @@ #include "config.h" #endif -#include +#include #include #include #include @@ -41,8 +41,6 @@ #include "rfx_types.h" #include "progressive.h" -#define WINPR_ASSERT(x) assert(x) - #define TAG FREERDP_TAG("codec.progressive") struct _RFX_PROGRESSIVE_UPGRADE_STATE diff --git a/libfreerdp/core/utils.c b/libfreerdp/core/utils.c index 6b6770ba5dbd..72432a2b9fff 100644 --- a/libfreerdp/core/utils.c +++ b/libfreerdp/core/utils.c @@ -22,7 +22,7 @@ #include "config.h" #endif -#include +#include #include @@ -31,8 +31,6 @@ #include "utils.h" -#define WINPR_ASSERT(x) assert(x) - BOOL utils_abort_connect(rdpContext* context) { WINPR_ASSERT(context); diff --git a/winpr/libwinpr/registry/registry_reg.c b/winpr/libwinpr/registry/registry_reg.c index 511d92790705..3867b066fecc 100644 --- a/winpr/libwinpr/registry/registry_reg.c +++ b/winpr/libwinpr/registry/registry_reg.c @@ -27,7 +27,7 @@ #include #include -#include +#include #include #include @@ -36,8 +36,6 @@ #include "../log.h" #define TAG WINPR_TAG("registry") -#define WINPR_ASSERT assert - #define WINPR_HKLM_HIVE "/etc/winpr/HKLM.reg" struct reg_data_type diff --git a/winpr/libwinpr/sspicli/sspicli.c b/winpr/libwinpr/sspicli/sspicli.c index 5a13b99bebbc..1d491b874fbb 100644 --- a/winpr/libwinpr/sspicli/sspicli.c +++ b/winpr/libwinpr/sspicli/sspicli.c @@ -21,11 +21,9 @@ #include "config.h" #endif -#include +#include #include -#define WINPR_ASSERT(x) assert(x) - /** * sspicli.dll: * From 732e94628945c2c218968c80b3a7a041b0b8a6e9 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Mon, 28 Mar 2022 11:34:24 +0200 Subject: [PATCH 111/496] Updated changelog --- ChangeLog | 1 + 1 file changed, 1 insertion(+) diff --git a/ChangeLog b/ChangeLog index 608c697b883a..3e41b9f389b1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,7 @@ # 2022-XX-YY Version 2.X.Y Noteworthy changes: +* Backported WINPR_ASSERT to ease future backports Fixed issues: * Backported #6786: Use /network:auto by default From c6bd48f9265da174863861a1289aba5ef7d8eb7e Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Tue, 15 Mar 2022 15:19:41 +0100 Subject: [PATCH 112/496] Use GetComputerName instead of gethostname (cherry picked from commit 82165d95a925a775f2f895518dba8ff6f1a732d1) --- channels/rdpdr/client/rdpdr_main.c | 6 +++++- libfreerdp/core/settings.c | 6 ++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/channels/rdpdr/client/rdpdr_main.c b/channels/rdpdr/client/rdpdr_main.c index 309d24c74bc8..681ebced990e 100644 --- a/channels/rdpdr/client/rdpdr_main.c +++ b/channels/rdpdr/client/rdpdr_main.c @@ -31,6 +31,7 @@ #include #include +#include #include #include @@ -1114,7 +1115,10 @@ static UINT rdpdr_send_client_name_request(rdpdrPlugin* rdpdr) size_t computerNameLenW; if (!rdpdr->computerName[0]) - gethostname(rdpdr->computerName, sizeof(rdpdr->computerName) - 1); + { + DWORD size = sizeof(rdpdr->computerName) - 1; + GetComputerNameA(rdpdr->computerName, &size); + } computerNameLenW = ConvertToUnicode(CP_UTF8, 0, rdpdr->computerName, -1, &computerNameW, 0) * 2; s = Stream_New(NULL, 16 + computerNameLenW + 2); diff --git a/libfreerdp/core/settings.c b/libfreerdp/core/settings.c index d0c2b56f3303..bd259d674a51 100644 --- a/libfreerdp/core/settings.c +++ b/libfreerdp/core/settings.c @@ -405,8 +405,10 @@ rdpSettings* freerdp_settings_new(DWORD flags) if (!settings->ClientHostname) goto out_fail; - - gethostname(settings->ClientHostname, 31); + DWORD size = 31; + GetComputerNameA(ClientHostname, &size); + if (!freerdp_settings_set_string(settings, FreeRDP_ClientHostname, ClientHostname)) + goto out_fail; settings->ClientHostname[31] = 0; settings->ColorPointerFlag = TRUE; settings->LargePointerFlag = (LARGE_POINTER_FLAG_96x96 | LARGE_POINTER_FLAG_384x384); From f1d9faa7fc30ae42f722047550c489690ff87049 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Mon, 14 Mar 2022 14:50:32 +0100 Subject: [PATCH 113/496] Refactored WinPR::NTLM * added assertions * added log messages * removed code duplication (cherry picked from commit 813966da1a44acff1385de058dd89a8be93d2d1c) --- winpr/libwinpr/sspi/NTLM/ntlm.c | 230 +++-- winpr/libwinpr/sspi/NTLM/ntlm.h | 18 +- winpr/libwinpr/sspi/NTLM/ntlm_av_pairs.c | 65 +- winpr/libwinpr/sspi/NTLM/ntlm_av_pairs.h | 4 +- winpr/libwinpr/sspi/NTLM/ntlm_compute.c | 468 +++++---- winpr/libwinpr/sspi/NTLM/ntlm_compute.h | 31 +- winpr/libwinpr/sspi/NTLM/ntlm_message.c | 1114 ++++++++++++++-------- winpr/libwinpr/sspi/NTLM/ntlm_message.h | 8 +- winpr/libwinpr/sspi/test/TestNTLM.c | 19 +- 9 files changed, 1252 insertions(+), 705 deletions(-) diff --git a/winpr/libwinpr/sspi/NTLM/ntlm.c b/winpr/libwinpr/sspi/NTLM/ntlm.c index 95603718dee7..c0af65b898f0 100644 --- a/winpr/libwinpr/sspi/NTLM/ntlm.c +++ b/winpr/libwinpr/sspi/NTLM/ntlm.c @@ -49,6 +49,8 @@ static int ntlm_SetContextWorkstation(NTLM_CONTEXT* context, char* Workstation) DWORD nSize = 0; CHAR* computerName; + WINPR_ASSERT(context); + if (!Workstation) { if (GetComputerNameExA(ComputerNameNetBIOS, NULL, &nSize) || @@ -91,6 +93,8 @@ static int ntlm_SetContextWorkstation(NTLM_CONTEXT* context, char* Workstation) static int ntlm_SetContextServicePrincipalNameW(NTLM_CONTEXT* context, LPWSTR ServicePrincipalName) { + WINPR_ASSERT(context); + if (!ServicePrincipalName) { context->ServicePrincipalName.Buffer = NULL; @@ -116,6 +120,8 @@ static int ntlm_SetContextTargetName(NTLM_CONTEXT* context, char* TargetName) DWORD nSize = 0; CHAR* computerName = NULL; + WINPR_ASSERT(context); + if (!name) { if (GetComputerNameExA(ComputerNameNetBIOS, NULL, &nSize) || @@ -254,7 +260,7 @@ static NTLM_CONTEXT* ntlm_ContextNew(void) context->NegotiateFlags = 0; context->LmCompatibilityLevel = 3; - context->state = NTLM_STATE_INITIAL; + ntlm_change_state(context, NTLM_STATE_INITIAL); FillMemory(context->MachineID, sizeof(context->MachineID), 0xAA); if (context->NTLMv2) @@ -414,79 +420,87 @@ ntlm_AcceptSecurityContext(PCredHandle phCredential, PCtxtHandle phContext, PSec sspi_SecureHandleSetUpperPointer(phNewContext, (void*)NTLM_PACKAGE_NAME); } - if (context->state == NTLM_STATE_INITIAL) + switch (ntlm_get_state(context)) { - context->state = NTLM_STATE_NEGOTIATE; - - if (!pInput) - return SEC_E_INVALID_TOKEN; - - if (pInput->cBuffers < 1) - return SEC_E_INVALID_TOKEN; - - input_buffer = sspi_FindSecBuffer(pInput, SECBUFFER_TOKEN); + case NTLM_STATE_INITIAL: + { + ntlm_change_state(context, NTLM_STATE_NEGOTIATE); - if (!input_buffer) - return SEC_E_INVALID_TOKEN; + if (!pInput) + return SEC_E_INVALID_TOKEN; - if (input_buffer->cbBuffer < 1) - return SEC_E_INVALID_TOKEN; + if (pInput->cBuffers < 1) + return SEC_E_INVALID_TOKEN; - status = ntlm_read_NegotiateMessage(context, input_buffer); + input_buffer = sspi_FindSecBuffer(pInput, SECBUFFER_TOKEN); - if (context->state == NTLM_STATE_CHALLENGE) - { - if (!pOutput) + if (!input_buffer) return SEC_E_INVALID_TOKEN; - if (pOutput->cBuffers < 1) + if (input_buffer->cbBuffer < 1) return SEC_E_INVALID_TOKEN; - output_buffer = sspi_FindSecBuffer(pOutput, SECBUFFER_TOKEN); + status = ntlm_read_NegotiateMessage(context, input_buffer); + if (status != SEC_I_CONTINUE_NEEDED) + return status; - if (!output_buffer->BufferType) - return SEC_E_INVALID_TOKEN; + if (ntlm_get_state(context) == NTLM_STATE_CHALLENGE) + { + if (!pOutput) + return SEC_E_INVALID_TOKEN; - if (output_buffer->cbBuffer < 1) - return SEC_E_INSUFFICIENT_MEMORY; + if (pOutput->cBuffers < 1) + return SEC_E_INVALID_TOKEN; - return ntlm_write_ChallengeMessage(context, output_buffer); - } + output_buffer = sspi_FindSecBuffer(pOutput, SECBUFFER_TOKEN); - return SEC_E_OUT_OF_SEQUENCE; - } - else if (context->state == NTLM_STATE_AUTHENTICATE) - { - if (!pInput) - return SEC_E_INVALID_TOKEN; + if (!output_buffer->BufferType) + return SEC_E_INVALID_TOKEN; - if (pInput->cBuffers < 1) - return SEC_E_INVALID_TOKEN; + if (output_buffer->cbBuffer < 1) + return SEC_E_INSUFFICIENT_MEMORY; - input_buffer = sspi_FindSecBuffer(pInput, SECBUFFER_TOKEN); + return ntlm_write_ChallengeMessage(context, output_buffer); + } - if (!input_buffer) - return SEC_E_INVALID_TOKEN; + return SEC_E_OUT_OF_SEQUENCE; + } + break; + case NTLM_STATE_AUTHENTICATE: + { + if (!pInput) + return SEC_E_INVALID_TOKEN; - if (input_buffer->cbBuffer < 1) - return SEC_E_INVALID_TOKEN; + if (pInput->cBuffers < 1) + return SEC_E_INVALID_TOKEN; - status = ntlm_read_AuthenticateMessage(context, input_buffer); + input_buffer = sspi_FindSecBuffer(pInput, SECBUFFER_TOKEN); - if (pOutput) - { - ULONG i; + if (!input_buffer) + return SEC_E_INVALID_TOKEN; + + if (input_buffer->cbBuffer < 1) + return SEC_E_INVALID_TOKEN; - for (i = 0; i < pOutput->cBuffers; i++) + status = ntlm_read_AuthenticateMessage(context, input_buffer); + + if (pOutput) { - pOutput->pBuffers[i].cbBuffer = 0; - pOutput->pBuffers[i].BufferType = SECBUFFER_TOKEN; + ULONG i; + + for (i = 0; i < pOutput->cBuffers; i++) + { + pOutput->pBuffers[i].cbBuffer = 0; + pOutput->pBuffers[i].BufferType = SECBUFFER_TOKEN; + } } - } - return status; + return status; + } + break; + default: + break; } - return SEC_E_OUT_OF_SEQUENCE; } @@ -540,7 +554,7 @@ static SECURITY_STATUS SEC_ENTRY ntlm_InitializeSecurityContextW( sspi_SecureHandleSetUpperPointer(phNewContext, (void*)NTLM_PACKAGE_NAME); } - if ((!pInput) || (context->state == NTLM_STATE_AUTHENTICATE)) + if ((!pInput) || (ntlm_get_state(context) == NTLM_STATE_AUTHENTICATE)) { if (!pOutput) return SEC_E_INVALID_TOKEN; @@ -556,10 +570,10 @@ static SECURITY_STATUS SEC_ENTRY ntlm_InitializeSecurityContextW( if (output_buffer->cbBuffer < 1) return SEC_E_INVALID_TOKEN; - if (context->state == NTLM_STATE_INITIAL) - context->state = NTLM_STATE_NEGOTIATE; + if (ntlm_get_state(context) == NTLM_STATE_INITIAL) + ntlm_change_state(context, NTLM_STATE_NEGOTIATE); - if (context->state == NTLM_STATE_NEGOTIATE) + if (ntlm_get_state(context) == NTLM_STATE_NEGOTIATE) return ntlm_write_NegotiateMessage(context, output_buffer); return SEC_E_OUT_OF_SEQUENCE; @@ -585,7 +599,7 @@ static SECURITY_STATUS SEC_ENTRY ntlm_InitializeSecurityContextW( context->Bindings.Bindings = (SEC_CHANNEL_BINDINGS*)channel_bindings->pvBuffer; } - if (context->state == NTLM_STATE_CHALLENGE) + if (ntlm_get_state(context) == NTLM_STATE_CHALLENGE) { status = ntlm_read_ChallengeMessage(context, input_buffer); @@ -603,7 +617,7 @@ static SECURITY_STATUS SEC_ENTRY ntlm_InitializeSecurityContextW( if (output_buffer->cbBuffer < 1) return SEC_E_INSUFFICIENT_MEMORY; - if (context->state == NTLM_STATE_AUTHENTICATE) + if (ntlm_get_state(context) == NTLM_STATE_AUTHENTICATE) return ntlm_write_AuthenticateMessage(context, output_buffer); } @@ -672,7 +686,12 @@ static SECURITY_STATUS SEC_ENTRY ntlm_DeleteSecurityContext(PCtxtHandle phContex SECURITY_STATUS ntlm_computeProofValue(NTLM_CONTEXT* ntlm, SecBuffer* ntproof) { BYTE* blob; - SecBuffer* target = &ntlm->ChallengeTargetInfo; + SecBuffer* target; + + WINPR_ASSERT(ntlm); + WINPR_ASSERT(ntproof); + + target = &ntlm->ChallengeTargetInfo; if (!sspi_SecBufferAlloc(ntproof, 36 + target->cbBuffer)) return SEC_E_INSUFFICIENT_MEMORY; @@ -693,8 +712,13 @@ SECURITY_STATUS ntlm_computeProofValue(NTLM_CONTEXT* ntlm, SecBuffer* ntproof) SECURITY_STATUS ntlm_computeMicValue(NTLM_CONTEXT* ntlm, SecBuffer* micvalue) { BYTE* blob; - ULONG msgSize = ntlm->NegotiateMessage.cbBuffer + ntlm->ChallengeMessage.cbBuffer + - ntlm->AuthenticateMessage.cbBuffer; + ULONG msgSize; + + WINPR_ASSERT(ntlm); + WINPR_ASSERT(micvalue); + + msgSize = ntlm->NegotiateMessage.cbBuffer + ntlm->ChallengeMessage.cbBuffer + + ntlm->AuthenticateMessage.cbBuffer; if (!sspi_SecBufferAlloc(micvalue, msgSize)) return SEC_E_INSUFFICIENT_MEMORY; @@ -969,8 +993,8 @@ static SECURITY_STATUS SEC_ENTRY ntlm_EncryptMessage(PCtxtHandle phContext, ULON void* data; UINT32 SeqNo; UINT32 value; - BYTE digest[WINPR_MD5_DIGEST_LENGTH]; - BYTE checksum[8]; + BYTE digest[WINPR_MD5_DIGEST_LENGTH] = { 0 }; + BYTE checksum[8] = { 0 }; BYTE* signature; ULONG version = 1; WINPR_HMAC_CTX* hmac; @@ -1066,12 +1090,12 @@ static SECURITY_STATUS SEC_ENTRY ntlm_DecryptMessage(PCtxtHandle phContext, PSec void* data; UINT32 SeqNo; UINT32 value; - BYTE digest[WINPR_MD5_DIGEST_LENGTH]; - BYTE checksum[8]; + BYTE digest[WINPR_MD5_DIGEST_LENGTH] = { 0 }; + BYTE checksum[8] = { 0 }; UINT32 version = 1; WINPR_HMAC_CTX* hmac; NTLM_CONTEXT* context; - BYTE expected_signature[WINPR_MD5_DIGEST_LENGTH]; + BYTE expected_signature[WINPR_MD5_DIGEST_LENGTH] = { 0 }; PSecBuffer data_buffer = NULL; PSecBuffer signature_buffer = NULL; SeqNo = (UINT32)MessageSeqNo; @@ -1258,3 +1282,81 @@ const SecPkgInfoW NTLM_SecPkgInfoW = { NTLM_SecPkgInfoW_Name, /* Name */ NTLM_SecPkgInfoW_Comment /* Comment */ }; + +char* ntlm_negotiate_flags_string(char* buffer, size_t size, UINT32 flags) +{ + int x; + if (!buffer || (size == 0)) + return buffer; + + for (x = 0; x < 31; x++) + { + size_t len = strnlen(buffer, size); + if (flags & x) + { + const char* str = ntlm_get_negotiate_string(1 << x); + size_t flen = strlen(str); + if (len > 0) + { + if (size - len < 1) + break; + strcat(buffer, "|"); + len++; + } + + if (size - len < flen) + break; + strcat(buffer, str); + } + } + return buffer; +} + +const char* ntlm_message_type_string(UINT32 messageType) +{ + switch (messageType) + { + case MESSAGE_TYPE_NEGOTIATE: + return "MESSAGE_TYPE_NEGOTIATE"; + case MESSAGE_TYPE_CHALLENGE: + return "MESSAGE_TYPE_CHALLENGE"; + case MESSAGE_TYPE_AUTHENTICATE: + return "MESSAGE_TYPE_AUTHENTICATE"; + default: + return "MESSAGE_TYPE_UNKNOWN"; + } +} + +const char* ntlm_state_string(NTLM_STATE state) +{ + switch (state) + { + case NTLM_STATE_INITIAL: + return "NTLM_STATE_INITIAL"; + case NTLM_STATE_NEGOTIATE: + return "NTLM_STATE_NEGOTIATE"; + case NTLM_STATE_CHALLENGE: + return "NTLM_STATE_CHALLENGE"; + case NTLM_STATE_AUTHENTICATE: + return "NTLM_STATE_AUTHENTICATE"; + case NTLM_STATE_COMPLETION: + return "NTLM_STATE_COMPLETION"; + case NTLM_STATE_FINAL: + return "NTLM_STATE_FINAL"; + default: + return "NTLM_STATE_UNKNOWN"; + } +} +void ntlm_change_state(NTLM_CONTEXT* ntlm, NTLM_STATE state) +{ + WINPR_ASSERT(ntlm); + WLog_DBG(TAG, "change state from %s to %s", ntlm_state_string(ntlm->state), + ntlm_state_string(state)); + ntlm->state = state; +} + +NTLM_STATE ntlm_get_state(NTLM_CONTEXT* ntlm) +{ + WINPR_ASSERT(ntlm); + return ntlm->state; +} diff --git a/winpr/libwinpr/sspi/NTLM/ntlm.h b/winpr/libwinpr/sspi/NTLM/ntlm.h index c6216ea41a43..d4db9ebe0053 100644 --- a/winpr/libwinpr/sspi/NTLM/ntlm.h +++ b/winpr/libwinpr/sspi/NTLM/ntlm.h @@ -176,8 +176,7 @@ typedef struct _NTLM_MESSAGE_HEADER NTLM_MESSAGE_HEADER; struct _NTLM_NEGOTIATE_MESSAGE { - BYTE Signature[8]; - UINT32 MessageType; + NTLM_MESSAGE_HEADER header; UINT32 NegotiateFlags; NTLM_VERSION_INFO Version; NTLM_MESSAGE_FIELDS DomainName; @@ -187,8 +186,7 @@ typedef struct _NTLM_NEGOTIATE_MESSAGE NTLM_NEGOTIATE_MESSAGE; struct _NTLM_CHALLENGE_MESSAGE { - BYTE Signature[8]; - UINT32 MessageType; + NTLM_MESSAGE_HEADER header; UINT32 NegotiateFlags; BYTE ServerChallenge[8]; BYTE Reserved[8]; @@ -200,8 +198,7 @@ typedef struct _NTLM_CHALLENGE_MESSAGE NTLM_CHALLENGE_MESSAGE; struct _NTLM_AUTHENTICATE_MESSAGE { - BYTE Signature[8]; - UINT32 MessageType; + NTLM_MESSAGE_HEADER header; UINT32 NegotiateFlags; NTLM_VERSION_INFO Version; NTLM_MESSAGE_FIELDS DomainName; @@ -251,7 +248,7 @@ struct _NTLM_CONTEXT NTLM_NEGOTIATE_MESSAGE NEGOTIATE_MESSAGE; NTLM_CHALLENGE_MESSAGE CHALLENGE_MESSAGE; NTLM_AUTHENTICATE_MESSAGE AUTHENTICATE_MESSAGE; - UINT32 MessageIntegrityCheckOffset; + size_t MessageIntegrityCheckOffset; SecBuffer NegotiateMessage; SecBuffer ChallengeMessage; SecBuffer AuthenticateMessage; @@ -280,6 +277,13 @@ struct _NTLM_CONTEXT }; typedef struct _NTLM_CONTEXT NTLM_CONTEXT; +char* ntlm_negotiate_flags_string(char* buffer, size_t size, UINT32 flags); +const char* ntlm_message_type_string(UINT32 messageType); + +const char* ntlm_state_string(NTLM_STATE state); +void ntlm_change_state(NTLM_CONTEXT* ntlm, NTLM_STATE state); +NTLM_STATE ntlm_get_state(NTLM_CONTEXT* ntlm); + SECURITY_STATUS ntlm_computeProofValue(NTLM_CONTEXT* ntlm, SecBuffer* ntproof); SECURITY_STATUS ntlm_computeMicValue(NTLM_CONTEXT* ntlm, SecBuffer* micvalue); diff --git a/winpr/libwinpr/sspi/NTLM/ntlm_av_pairs.c b/winpr/libwinpr/sspi/NTLM/ntlm_av_pairs.c index 47669bb2e8aa..9b2efd37a96b 100644 --- a/winpr/libwinpr/sspi/NTLM/ntlm_av_pairs.c +++ b/winpr/libwinpr/sspi/NTLM/ntlm_av_pairs.c @@ -21,12 +21,13 @@ #include "config.h" #endif -#include +#include #include "ntlm.h" #include "../sspi.h" #include +#include #include #include #include @@ -75,8 +76,8 @@ static const char* get_av_pair_string(UINT16 pair) return "MsvAvSingleHost"; case MsvAvTargetName: return "MsvAvTargetName"; - case MsvChannelBindings: - return "MsvChannelBindings"; + case MsvAvChannelBindings: + return "MsvAvChannelBindings"; default: return "UNKNOWN"; } @@ -87,11 +88,13 @@ static NTLM_AV_PAIR* ntlm_av_pair_next(NTLM_AV_PAIR* pAvPairList, size_t* pcbAvP static INLINE void ntlm_av_pair_set_id(NTLM_AV_PAIR* pAvPair, UINT16 id) { + WINPR_ASSERT(pAvPair); Data_Write_UINT16(&pAvPair->AvId, id); } static INLINE void ntlm_av_pair_set_len(NTLM_AV_PAIR* pAvPair, UINT16 len) { + WINPR_ASSERT(pAvPair); Data_Write_UINT16(&pAvPair->AvLen, len); } @@ -124,6 +127,7 @@ static INLINE BOOL ntlm_av_pair_get_id(const NTLM_AV_PAIR* pAvPair, size_t size, ULONG ntlm_av_pair_list_length(NTLM_AV_PAIR* pAvPairList, size_t cbAvPairList) { + size_t size; size_t cbAvPair; NTLM_AV_PAIR* pAvPair; @@ -131,7 +135,9 @@ ULONG ntlm_av_pair_list_length(NTLM_AV_PAIR* pAvPairList, size_t cbAvPairList) if (!pAvPair) return 0; - return ((PBYTE)pAvPair - (PBYTE)pAvPairList) + sizeof(NTLM_AV_PAIR); + size = ((PBYTE)pAvPair - (PBYTE)pAvPairList) + sizeof(NTLM_AV_PAIR); + WINPR_ASSERT(size <= ULONG_MAX); + return (ULONG)size; } static INLINE BOOL ntlm_av_pair_get_len(const NTLM_AV_PAIR* pAvPair, size_t size, size_t* pAvLen) @@ -149,6 +155,7 @@ static INLINE BOOL ntlm_av_pair_get_len(const NTLM_AV_PAIR* pAvPair, size_t size return TRUE; } +#ifdef WITH_DEBUG_NTLM void ntlm_print_av_pair_list(NTLM_AV_PAIR* pAvPairList, size_t cbAvPairList) { UINT16 pair; @@ -158,19 +165,20 @@ void ntlm_print_av_pair_list(NTLM_AV_PAIR* pAvPairList, size_t cbAvPairList) if (!ntlm_av_pair_check(pAvPair, cbAvPair)) return; - WLog_INFO(TAG, "AV_PAIRs ="); + WLog_VRB(TAG, "AV_PAIRs ="); while (pAvPair && ntlm_av_pair_get_id(pAvPair, cbAvPair, &pair) && (pair != MsvAvEOL)) { size_t cbLen = 0; ntlm_av_pair_get_len(pAvPair, cbAvPair, &cbLen); - WLog_INFO(TAG, "\t%s AvId: %" PRIu16 " AvLen: %" PRIu16 "", get_av_pair_string(pair), pair); - winpr_HexDump(TAG, WLOG_INFO, ntlm_av_pair_get_value_pointer(pAvPair), cbLen); + WLog_VRB(TAG, "\t%s AvId: %" PRIu16 " AvLen: %" PRIu16 "", get_av_pair_string(pair), pair); + winpr_HexDump(TAG, WLOG_TRACE, ntlm_av_pair_get_value_pointer(pAvPair), cbLen); pAvPair = ntlm_av_pair_next(pAvPair, &cbAvPair); } } +#endif static ULONG ntlm_av_pair_list_size(ULONG AvPairsCount, ULONG AvPairsValueLength) { @@ -180,6 +188,7 @@ static ULONG ntlm_av_pair_list_size(ULONG AvPairsCount, ULONG AvPairsValueLength PBYTE ntlm_av_pair_get_value_pointer(NTLM_AV_PAIR* pAvPair) { + WINPR_ASSERT(pAvPair); return (PBYTE)pAvPair + sizeof(NTLM_AV_PAIR); } @@ -259,11 +268,11 @@ static BOOL ntlm_av_pair_add(NTLM_AV_PAIR* pAvPairList, size_t cbAvPairList, NTL if (!pAvPair || cbAvPair < 2 * sizeof(NTLM_AV_PAIR) + AvLen) return FALSE; - ntlm_av_pair_set_id(pAvPair, AvId); + ntlm_av_pair_set_id(pAvPair, (UINT16)AvId); ntlm_av_pair_set_len(pAvPair, AvLen); if (AvLen) { - assert(Value != NULL); + WINPR_ASSERT(Value != NULL); CopyMemory(ntlm_av_pair_get_value_pointer(pAvPair), Value, AvLen); } @@ -286,8 +295,9 @@ static BOOL ntlm_av_pair_add_copy(NTLM_AV_PAIR* pAvPairList, size_t cbAvPairList if (!ntlm_av_pair_get_len(pAvPair, cbAvPair, &avLen)) return FALSE; + WINPR_ASSERT(avLen <= UINT16_MAX); return ntlm_av_pair_add(pAvPairList, cbAvPairList, pair, - ntlm_av_pair_get_value_pointer(pAvPair), avLen); + ntlm_av_pair_get_value_pointer(pAvPair), (UINT16)avLen); } static int ntlm_get_target_computer_name(PUNICODE_STRING pName, COMPUTER_NAME_FORMAT type) @@ -297,6 +307,8 @@ static int ntlm_get_target_computer_name(PUNICODE_STRING pName, COMPUTER_NAME_FO DWORD nSize = 0; CHAR* computerName; + WINPR_ASSERT(pName); + if (GetComputerNameExA(ComputerNameNetBIOS, NULL, &nSize) || GetLastError() != ERROR_MORE_DATA) return -1; @@ -394,6 +406,9 @@ static void ntlm_compute_channel_bindings(NTLM_CONTEXT* context) BYTE* ChannelBindingToken; UINT32 ChannelBindingTokenLength; SEC_CHANNEL_BINDINGS* ChannelBindings; + + WINPR_ASSERT(context); + ZeroMemory(context->ChannelBindingsHash, WINPR_MD5_DIGEST_LENGTH); ChannelBindings = context->Bindings.Bindings; @@ -436,6 +451,7 @@ static void ntlm_compute_channel_bindings(NTLM_CONTEXT* context) static void ntlm_compute_single_host_data(NTLM_CONTEXT* context) { + WINPR_ASSERT(context); /** * The Single_Host_Data structure allows a client to send machine-specific information * within an authentication exchange to services on the same machine. The client can @@ -451,10 +467,10 @@ static void ntlm_compute_single_host_data(NTLM_CONTEXT* context) FillMemory(context->SingleHostData.MachineID, 32, 0xAA); } -int ntlm_construct_challenge_target_info(NTLM_CONTEXT* context) +BOOL ntlm_construct_challenge_target_info(NTLM_CONTEXT* context) { - int rc = -1; - int length; + BOOL rc = FALSE; + ULONG length; ULONG AvPairsCount; ULONG AvPairsLength; NTLM_AV_PAIR* pAvPairList; @@ -464,6 +480,8 @@ int ntlm_construct_challenge_target_info(NTLM_CONTEXT* context) UNICODE_STRING DnsDomainName = { 0 }; UNICODE_STRING DnsComputerName = { 0 }; + WINPR_ASSERT(context); + if (ntlm_get_target_computer_name(&NbDomainName, ComputerNameNetBIOS) < 0) goto fail; @@ -516,7 +534,7 @@ int ntlm_construct_challenge_target_info(NTLM_CONTEXT* context) sizeof(context->Timestamp))) goto fail; - rc = 1; + rc = TRUE; fail: ntlm_free_unicode_string(&NbDomainName); ntlm_free_unicode_string(&NbComputerName); @@ -525,7 +543,7 @@ int ntlm_construct_challenge_target_info(NTLM_CONTEXT* context) return rc; } -int ntlm_construct_authenticate_target_info(NTLM_CONTEXT* context) +BOOL ntlm_construct_authenticate_target_info(NTLM_CONTEXT* context) { ULONG size; ULONG AvPairsCount; @@ -546,6 +564,9 @@ int ntlm_construct_authenticate_target_info(NTLM_CONTEXT* context) size_t cbAvDnsTreeName; size_t cbChallengeTargetInfo; size_t cbAuthenticateTargetInfo; + + WINPR_ASSERT(context); + AvPairsCount = 1; AvPairsValueLength = 0; ChallengeTargetInfo = (NTLM_AV_PAIR*)context->ChallengeTargetInfo.pvBuffer; @@ -635,7 +656,7 @@ int ntlm_construct_authenticate_target_info(NTLM_CONTEXT* context) * SEC_CHANNEL_BINDINGS structure * http://msdn.microsoft.com/en-us/library/windows/desktop/dd919963/ */ - AvPairsCount++; /* MsvChannelBindings */ + AvPairsCount++; /* MsvAvChannelBindings */ AvPairsValueLength += 16; ntlm_compute_channel_bindings(context); @@ -714,15 +735,17 @@ int ntlm_construct_authenticate_target_info(NTLM_CONTEXT* context) if (context->SendSingleHostData) { + WINPR_ASSERT(context->SingleHostData.Size <= UINT16_MAX); if (!ntlm_av_pair_add(AuthenticateTargetInfo, cbAuthenticateTargetInfo, MsvAvSingleHost, - (PBYTE)&context->SingleHostData, context->SingleHostData.Size)) + (PBYTE)&context->SingleHostData, + (UINT16)context->SingleHostData.Size)) goto fail; } if (!context->SuppressExtendedProtection) { - if (!ntlm_av_pair_add(AuthenticateTargetInfo, cbAuthenticateTargetInfo, MsvChannelBindings, - context->ChannelBindingsHash, 16)) + if (!ntlm_av_pair_add(AuthenticateTargetInfo, cbAuthenticateTargetInfo, + MsvAvChannelBindings, context->ChannelBindingsHash, 16)) goto fail; if (context->ServicePrincipalName.Length > 0) @@ -745,8 +768,8 @@ int ntlm_construct_authenticate_target_info(NTLM_CONTEXT* context) ZeroMemory(AvEOL, sizeof(NTLM_AV_PAIR)); } - return 1; + return TRUE; fail: sspi_SecBufferFree(&context->AuthenticateTargetInfo); - return -1; + return FALSE; } diff --git a/winpr/libwinpr/sspi/NTLM/ntlm_av_pairs.h b/winpr/libwinpr/sspi/NTLM/ntlm_av_pairs.h index ac228a86972e..82d2364b215a 100644 --- a/winpr/libwinpr/sspi/NTLM/ntlm_av_pairs.h +++ b/winpr/libwinpr/sspi/NTLM/ntlm_av_pairs.h @@ -30,7 +30,7 @@ PBYTE ntlm_av_pair_get_value_pointer(NTLM_AV_PAIR* pAvPair); NTLM_AV_PAIR* ntlm_av_pair_get(NTLM_AV_PAIR* pAvPairList, size_t cbAvPairList, NTLM_AV_ID AvId, size_t* pcbAvPairListRemaining); -int ntlm_construct_challenge_target_info(NTLM_CONTEXT* context); -int ntlm_construct_authenticate_target_info(NTLM_CONTEXT* context); +BOOL ntlm_construct_challenge_target_info(NTLM_CONTEXT* context); +BOOL ntlm_construct_authenticate_target_info(NTLM_CONTEXT* context); #endif /* WINPR_SSPI_NTLM_AV_PAIRS_H */ diff --git a/winpr/libwinpr/sspi/NTLM/ntlm_compute.c b/winpr/libwinpr/sspi/NTLM/ntlm_compute.c index dbd7f7fb0e06..5360a2c16389 100644 --- a/winpr/libwinpr/sspi/NTLM/ntlm_compute.c +++ b/winpr/libwinpr/sspi/NTLM/ntlm_compute.c @@ -21,7 +21,7 @@ #include "config.h" #endif -#include +#include #include "ntlm.h" #include "../sspi.h" @@ -38,16 +38,10 @@ #include "../../log.h" #define TAG WINPR_TAG("sspi.NTLM") -const char LM_MAGIC[] = "KGS!@#$%"; - -static const char NTLM_CLIENT_SIGN_MAGIC[] = - "session key to client-to-server signing key magic constant"; -static const char NTLM_SERVER_SIGN_MAGIC[] = - "session key to server-to-client signing key magic constant"; -static const char NTLM_CLIENT_SEAL_MAGIC[] = - "session key to client-to-server sealing key magic constant"; -static const char NTLM_SERVER_SEAL_MAGIC[] = - "session key to server-to-client sealing key magic constant"; +static char NTLM_CLIENT_SIGN_MAGIC[] = "session key to client-to-server signing key magic constant"; +static char NTLM_SERVER_SIGN_MAGIC[] = "session key to server-to-client signing key magic constant"; +static char NTLM_CLIENT_SEAL_MAGIC[] = "session key to client-to-server sealing key magic constant"; +static char NTLM_SERVER_SEAL_MAGIC[] = "session key to server-to-client sealing key magic constant"; static const BYTE NTLM_NULL_BUFFER[16] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; @@ -58,16 +52,21 @@ static const BYTE NTLM_NULL_BUFFER[16] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0 * @param s */ -void ntlm_get_version_info(NTLM_VERSION_INFO* versionInfo) +BOOL ntlm_get_version_info(NTLM_VERSION_INFO* versionInfo) { - OSVERSIONINFOA osVersionInfo; + OSVERSIONINFOA osVersionInfo = { 0 }; + + WINPR_ASSERT(versionInfo); + osVersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA); - GetVersionExA(&osVersionInfo); + if (!GetVersionExA(&osVersionInfo)) + return FALSE; versionInfo->ProductMajorVersion = (UINT8)osVersionInfo.dwMajorVersion; versionInfo->ProductMinorVersion = (UINT8)osVersionInfo.dwMinorVersion; versionInfo->ProductBuild = (UINT16)osVersionInfo.dwBuildNumber; ZeroMemory(versionInfo->Reserved, sizeof(versionInfo->Reserved)); versionInfo->NTLMRevisionCurrent = NTLMSSP_REVISION_W2K3; + return TRUE; } /** @@ -76,17 +75,24 @@ void ntlm_get_version_info(NTLM_VERSION_INFO* versionInfo) * @param s */ -int ntlm_read_version_info(wStream* s, NTLM_VERSION_INFO* versionInfo) +BOOL ntlm_read_version_info(wStream* s, NTLM_VERSION_INFO* versionInfo) { + WINPR_ASSERT(s); + WINPR_ASSERT(versionInfo); + if (Stream_GetRemainingLength(s) < 8) - return -1; + { + WLog_ERR(TAG, "NTLM_VERSION_INFO short header %" PRIuz ", expected %" PRIuz, + Stream_GetRemainingLength(s), 8); + return FALSE; + } Stream_Read_UINT8(s, versionInfo->ProductMajorVersion); /* ProductMajorVersion (1 byte) */ Stream_Read_UINT8(s, versionInfo->ProductMinorVersion); /* ProductMinorVersion (1 byte) */ Stream_Read_UINT16(s, versionInfo->ProductBuild); /* ProductBuild (2 bytes) */ Stream_Read(s, versionInfo->Reserved, sizeof(versionInfo->Reserved)); /* Reserved (3 bytes) */ Stream_Read_UINT8(s, versionInfo->NTLMRevisionCurrent); /* NTLMRevisionCurrent (1 byte) */ - return 1; + return TRUE; } /** @@ -95,13 +101,24 @@ int ntlm_read_version_info(wStream* s, NTLM_VERSION_INFO* versionInfo) * @param s */ -void ntlm_write_version_info(wStream* s, NTLM_VERSION_INFO* versionInfo) +BOOL ntlm_write_version_info(wStream* s, const NTLM_VERSION_INFO* versionInfo) { + WINPR_ASSERT(s); + WINPR_ASSERT(versionInfo); + + if (Stream_GetRemainingCapacity(s) < 5 + sizeof(versionInfo->Reserved)) + { + WLog_ERR(TAG, "NTLM_VERSION_INFO short header %" PRIuz ", expected %" PRIuz, + Stream_GetRemainingCapacity(s), 5 + sizeof(versionInfo->Reserved)); + return FALSE; + } + Stream_Write_UINT8(s, versionInfo->ProductMajorVersion); /* ProductMajorVersion (1 byte) */ Stream_Write_UINT8(s, versionInfo->ProductMinorVersion); /* ProductMinorVersion (1 byte) */ Stream_Write_UINT16(s, versionInfo->ProductBuild); /* ProductBuild (2 bytes) */ Stream_Write(s, versionInfo->Reserved, sizeof(versionInfo->Reserved)); /* Reserved (3 bytes) */ Stream_Write_UINT8(s, versionInfo->NTLMRevisionCurrent); /* NTLMRevisionCurrent (1 byte) */ + return TRUE; } /** @@ -109,23 +126,33 @@ void ntlm_write_version_info(wStream* s, NTLM_VERSION_INFO* versionInfo) * VERSION @msdn{cc236654} * @param s */ - -void ntlm_print_version_info(NTLM_VERSION_INFO* versionInfo) +#ifdef WITH_DEBUG_NTLM +void ntlm_print_version_info(const NTLM_VERSION_INFO* versionInfo) { - WLog_INFO(TAG, "VERSION ={"); - WLog_INFO(TAG, "\tProductMajorVersion: %" PRIu8 "", versionInfo->ProductMajorVersion); - WLog_INFO(TAG, "\tProductMinorVersion: %" PRIu8 "", versionInfo->ProductMinorVersion); - WLog_INFO(TAG, "\tProductBuild: %" PRIu16 "", versionInfo->ProductBuild); - WLog_INFO(TAG, "\tReserved: 0x%02" PRIX8 "%02" PRIX8 "%02" PRIX8 "", versionInfo->Reserved[0], - versionInfo->Reserved[1], versionInfo->Reserved[2]); - WLog_INFO(TAG, "\tNTLMRevisionCurrent: 0x%02" PRIX8 "", versionInfo->NTLMRevisionCurrent); + WINPR_ASSERT(versionInfo); + + WLog_VRB(TAG, "VERSION ={"); + WLog_VRB(TAG, "\tProductMajorVersion: %" PRIu8 "", versionInfo->ProductMajorVersion); + WLog_VRB(TAG, "\tProductMinorVersion: %" PRIu8 "", versionInfo->ProductMinorVersion); + WLog_VRB(TAG, "\tProductBuild: %" PRIu16 "", versionInfo->ProductBuild); + WLog_VRB(TAG, "\tReserved: 0x%02" PRIX8 "%02" PRIX8 "%02" PRIX8 "", versionInfo->Reserved[0], + versionInfo->Reserved[1], versionInfo->Reserved[2]); + WLog_VRB(TAG, "\tNTLMRevisionCurrent: 0x%02" PRIX8 "", versionInfo->NTLMRevisionCurrent); } +#endif -static int ntlm_read_ntlm_v2_client_challenge(wStream* s, NTLMv2_CLIENT_CHALLENGE* challenge) +static BOOL ntlm_read_ntlm_v2_client_challenge(wStream* s, NTLMv2_CLIENT_CHALLENGE* challenge) { size_t size; + WINPR_ASSERT(s); + WINPR_ASSERT(challenge); + if (Stream_GetRemainingLength(s) < 28) - return -1; + { + WLog_ERR(TAG, "NTLMv2_CLIENT_CHALLENGE expected 28bytes, got %" PRIuz "bytes", + Stream_GetRemainingLength(s)); + return FALSE; + } Stream_Read_UINT8(s, challenge->RespType); Stream_Read_UINT8(s, challenge->HiRespType); @@ -137,21 +164,39 @@ static int ntlm_read_ntlm_v2_client_challenge(wStream* s, NTLMv2_CLIENT_CHALLENG size = Stream_Length(s) - Stream_GetPosition(s); if (size > UINT32_MAX) - return -1; + { + WLog_ERR(TAG, "NTLMv2_CLIENT_CHALLENGE::cbAvPairs too large, got %" PRIuz "bytes", size); + return FALSE; + } - challenge->cbAvPairs = size; + challenge->cbAvPairs = (UINT32)size; challenge->AvPairs = (NTLM_AV_PAIR*)malloc(challenge->cbAvPairs); if (!challenge->AvPairs) - return -1; + { + WLog_ERR(TAG, "NTLMv2_CLIENT_CHALLENGE::AvPairs failed to allocate %" PRIu32 "bytes", + challenge->cbAvPairs); + return FALSE; + } Stream_Read(s, challenge->AvPairs, size); - return 1; + return TRUE; } -static int ntlm_write_ntlm_v2_client_challenge(wStream* s, NTLMv2_CLIENT_CHALLENGE* challenge) +static BOOL ntlm_write_ntlm_v2_client_challenge(wStream* s, + const NTLMv2_CLIENT_CHALLENGE* challenge) { ULONG length; + + WINPR_ASSERT(s); + WINPR_ASSERT(challenge); + + if (Stream_GetRemainingCapacity(s) < 28) + { + WLog_ERR(TAG, "NTLMv2_CLIENT_CHALLENGE expected 28bytes, have %" PRIuz "bytes", + Stream_GetRemainingCapacity(s)); + return FALSE; + } Stream_Write_UINT8(s, challenge->RespType); Stream_Write_UINT8(s, challenge->HiRespType); Stream_Write_UINT16(s, challenge->Reserved1); @@ -160,20 +205,44 @@ static int ntlm_write_ntlm_v2_client_challenge(wStream* s, NTLMv2_CLIENT_CHALLEN Stream_Write(s, challenge->ClientChallenge, 8); Stream_Write_UINT32(s, challenge->Reserved3); length = ntlm_av_pair_list_length(challenge->AvPairs, challenge->cbAvPairs); + if (Stream_GetRemainingCapacity(s) < length) + { + WLog_ERR(TAG, + "NTLMv2_CLIENT_CHALLENGE::AvPairs expected %" PRIu32 "bytes, have %" PRIuz "bytes", + length, Stream_GetRemainingCapacity(s)); + return FALSE; + } Stream_Write(s, challenge->AvPairs, length); - return 1; + return TRUE; } -int ntlm_read_ntlm_v2_response(wStream* s, NTLMv2_RESPONSE* response) +BOOL ntlm_read_ntlm_v2_response(wStream* s, NTLMv2_RESPONSE* response) { + WINPR_ASSERT(s); + WINPR_ASSERT(response); + if (Stream_GetRemainingLength(s) < 16) - return -1; + { + WLog_ERR(TAG, "NTLMv2_RESPONSE expected 16bytes, have %" PRIuz "bytes", + Stream_GetRemainingLength(s)); + + return FALSE; + } Stream_Read(s, response->Response, 16); return ntlm_read_ntlm_v2_client_challenge(s, &(response->Challenge)); } -int ntlm_write_ntlm_v2_response(wStream* s, NTLMv2_RESPONSE* response) +BOOL ntlm_write_ntlm_v2_response(wStream* s, const NTLMv2_RESPONSE* response) { + WINPR_ASSERT(s); + WINPR_ASSERT(response); + + if (Stream_GetRemainingCapacity(s) < 16) + { + WLog_ERR(TAG, "NTLMv2_RESPONSE expected 16bytes, have %" PRIuz "bytes", + Stream_GetRemainingCapacity(s)); + return FALSE; + } Stream_Write(s, response->Response, 16); return ntlm_write_ntlm_v2_client_challenge(s, &(response->Challenge)); } @@ -185,8 +254,11 @@ int ntlm_write_ntlm_v2_response(wStream* s, NTLMv2_RESPONSE* response) void ntlm_current_time(BYTE* timestamp) { - FILETIME filetime; - ULARGE_INTEGER time64; + FILETIME filetime = { 0 }; + ULARGE_INTEGER time64 = { 0 }; + + WINPR_ASSERT(timestamp); + GetSystemTimeAsFileTime(&filetime); time64.u.LowPart = filetime.dwLowDateTime; time64.u.HighPart = filetime.dwHighDateTime; @@ -200,6 +272,8 @@ void ntlm_current_time(BYTE* timestamp) void ntlm_generate_timestamp(NTLM_CONTEXT* context) { + WINPR_ASSERT(context); + if (memcmp(context->ChallengeTimestamp, NTLM_NULL_BUFFER, 8) != 0) CopyMemory(context->Timestamp, context->ChallengeTimestamp, 8); else @@ -210,7 +284,12 @@ static int ntlm_fetch_ntlm_v2_hash(NTLM_CONTEXT* context, BYTE* hash) { WINPR_SAM* sam; WINPR_SAM_ENTRY* entry; - SSPI_CREDENTIALS* credentials = context->credentials; + SSPI_CREDENTIALS* credentials; + + WINPR_ASSERT(context); + WINPR_ASSERT(hash); + + credentials = context->credentials; sam = SamOpen(context->SamFile, TRUE); if (!sam) @@ -223,7 +302,7 @@ static int ntlm_fetch_ntlm_v2_hash(NTLM_CONTEXT* context, BYTE* hash) if (entry) { #ifdef WITH_DEBUG_NTLM - WLog_DBG(TAG, "NTLM Hash:"); + WLog_VRB(TAG, "NTLM Hash:"); winpr_HexDump(TAG, WLOG_DEBUG, entry->NtHash, 16); #endif NTOWFv2FromHashW(entry->NtHash, (LPWSTR)credentials->identity.User, @@ -240,7 +319,7 @@ static int ntlm_fetch_ntlm_v2_hash(NTLM_CONTEXT* context, BYTE* hash) if (entry) { #ifdef WITH_DEBUG_NTLM - WLog_DBG(TAG, "NTLM Hash:"); + WLog_VRB(TAG, "NTLM Hash:"); winpr_HexDump(TAG, WLOG_DEBUG, entry->NtHash, 16); #endif NTOWFv2FromHashW(entry->NtHash, (LPWSTR)credentials->identity.User, @@ -256,71 +335,82 @@ static int ntlm_fetch_ntlm_v2_hash(NTLM_CONTEXT* context, BYTE* hash) WLog_ERR(TAG, "Error: Could not find user in SAM database"); return 0; } - - SamClose(sam); - return 1; } static int ntlm_convert_password_hash(NTLM_CONTEXT* context, BYTE* hash) { int status; - int i, hn, ln; + int i; char* PasswordHash = NULL; - UINT32 PasswordHashLength = 0; - SSPI_CREDENTIALS* credentials = context->credentials; + INT64 PasswordHashLength = 0; + SSPI_CREDENTIALS* credentials; + + WINPR_ASSERT(context); + WINPR_ASSERT(hash); + + credentials = context->credentials; /* Password contains a password hash of length (PasswordLength - * SSPI_CREDENTIALS_HASH_LENGTH_OFFSET) */ PasswordHashLength = credentials->identity.PasswordLength - SSPI_CREDENTIALS_HASH_LENGTH_OFFSET; + WINPR_ASSERT(PasswordHashLength >= 0); + WINPR_ASSERT(PasswordHashLength <= INT_MAX); status = ConvertFromUnicode(CP_UTF8, 0, (LPCWSTR)credentials->identity.Password, - PasswordHashLength, &PasswordHash, 0, NULL, NULL); + (int)PasswordHashLength, &PasswordHash, 0, NULL, NULL); if (status <= 0) return -1; - CharUpperBuffA(PasswordHash, PasswordHashLength); + CharUpperBuffA(PasswordHash, (DWORD)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; + BYTE hn = + (BYTE)(PasswordHash[i] > '9' ? PasswordHash[i] - 'A' + 10 : PasswordHash[i] - '0'); + BYTE ln = (BYTE)(PasswordHash[i + 1] > '9' ? PasswordHash[i + 1] - 'A' + 10 + : PasswordHash[i + 1] - '0'); + hash[i / 2] = (BYTE)((hn << 4) | ln); } free(PasswordHash); return 1; } -static int ntlm_compute_ntlm_v2_hash(NTLM_CONTEXT* context, BYTE* hash) +static BOOL ntlm_compute_ntlm_v2_hash(NTLM_CONTEXT* context, BYTE* hash) { - SSPI_CREDENTIALS* credentials = context->credentials; + SSPI_CREDENTIALS* credentials; + + WINPR_ASSERT(context); + WINPR_ASSERT(hash); + + credentials = context->credentials; #ifdef WITH_DEBUG_NTLM if (credentials) { - WLog_DBG(TAG, "Password (length = %" PRIu32 ")", credentials->identity.PasswordLength * 2); - winpr_HexDump(TAG, WLOG_DEBUG, (BYTE*)credentials->identity.Password, + WLog_VRB(TAG, "Password (length = %" PRIu32 ")", credentials->identity.PasswordLength * 2); + winpr_HexDump(TAG, WLOG_TRACE, (BYTE*)credentials->identity.Password, credentials->identity.PasswordLength * 2); - WLog_DBG(TAG, "Username (length = %" PRIu32 ")", credentials->identity.UserLength * 2); - winpr_HexDump(TAG, WLOG_DEBUG, (BYTE*)credentials->identity.User, + WLog_VRB(TAG, "Username (length = %" PRIu32 ")", credentials->identity.UserLength * 2); + winpr_HexDump(TAG, WLOG_TRACE, (BYTE*)credentials->identity.User, credentials->identity.UserLength * 2); - WLog_DBG(TAG, "Domain (length = %" PRIu32 ")", credentials->identity.DomainLength * 2); - winpr_HexDump(TAG, WLOG_DEBUG, (BYTE*)credentials->identity.Domain, + WLog_VRB(TAG, "Domain (length = %" PRIu32 ")", credentials->identity.DomainLength * 2); + winpr_HexDump(TAG, WLOG_TRACE, (BYTE*)credentials->identity.Domain, credentials->identity.DomainLength * 2); } else - WLog_DBG(TAG, "Strange, NTLM_CONTEXT is missing valid credentials..."); + WLog_VRB(TAG, "Strange, NTLM_CONTEXT is missing valid credentials..."); - WLog_DBG(TAG, "Workstation (length = %" PRIu16 ")", context->Workstation.Length); - winpr_HexDump(TAG, WLOG_DEBUG, (BYTE*)context->Workstation.Buffer, context->Workstation.Length); - WLog_DBG(TAG, "NTOWFv2, NTLMv2 Hash"); - winpr_HexDump(TAG, WLOG_DEBUG, context->NtlmV2Hash, WINPR_MD5_DIGEST_LENGTH); + WLog_VRB(TAG, "Workstation (length = %" PRIu16 ")", context->Workstation.Length); + winpr_HexDump(TAG, WLOG_TRACE, (BYTE*)context->Workstation.Buffer, context->Workstation.Length); + WLog_VRB(TAG, "NTOWFv2, NTLMv2 Hash"); + winpr_HexDump(TAG, WLOG_TRACE, context->NtlmV2Hash, WINPR_MD5_DIGEST_LENGTH); #endif if (memcmp(context->NtlmV2Hash, NTLM_NULL_BUFFER, 16) != 0) - return 1; + return TRUE; if (!credentials) - return -1; + return FALSE; else if (memcmp(context->NtlmHash, NTLM_NULL_BUFFER, 16) != 0) { NTOWFv2FromHashW(context->NtlmHash, (LPWSTR)credentials->identity.User, @@ -331,7 +421,7 @@ static int ntlm_compute_ntlm_v2_hash(NTLM_CONTEXT* context, BYTE* hash) { /* Special case for WinPR: password hash */ if (ntlm_convert_password_hash(context, context->NtlmHash) < 0) - return -1; + return FALSE; NTOWFv2FromHashW(context->NtlmHash, (LPWSTR)credentials->identity.User, credentials->identity.UserLength * 2, (LPWSTR)credentials->identity.Domain, @@ -350,55 +440,57 @@ static int ntlm_compute_ntlm_v2_hash(NTLM_CONTEXT* context, BYTE* hash) SecBuffer proofValue, micValue; if (ntlm_computeProofValue(context, &proofValue) != SEC_E_OK) - return -1; + return FALSE; if (ntlm_computeMicValue(context, &micValue) != SEC_E_OK) { sspi_SecBufferFree(&proofValue); - return -1; + return FALSE; } ret = context->HashCallback(context->HashCallbackArg, &credentials->identity, &proofValue, context->EncryptedRandomSessionKey, - (&context->AUTHENTICATE_MESSAGE)->MessageIntegrityCheck, - &micValue, hash); + context->AUTHENTICATE_MESSAGE.MessageIntegrityCheck, &micValue, + hash); sspi_SecBufferFree(&proofValue); sspi_SecBufferFree(&micValue); - return ret ? 1 : -1; + return ret ? TRUE : FALSE; } else if (context->UseSamFileDatabase) { return ntlm_fetch_ntlm_v2_hash(context, hash); } - return 1; + return TRUE; } -int ntlm_compute_lm_v2_response(NTLM_CONTEXT* context) +BOOL ntlm_compute_lm_v2_response(NTLM_CONTEXT* context) { BYTE* response; - BYTE value[WINPR_MD5_DIGEST_LENGTH]; + BYTE value[WINPR_MD5_DIGEST_LENGTH] = { 0 }; + + WINPR_ASSERT(context); if (context->LmCompatibilityLevel < 2) { if (!sspi_SecBufferAlloc(&context->LmChallengeResponse, 24)) - return -1; + return FALSE; ZeroMemory(context->LmChallengeResponse.pvBuffer, 24); - return 1; + return TRUE; } /* Compute the NTLMv2 hash */ - if (ntlm_compute_ntlm_v2_hash(context, context->NtlmV2Hash) < 0) - return -1; + if (!ntlm_compute_ntlm_v2_hash(context, context->NtlmV2Hash)) + return FALSE; /* Concatenate the server and client challenges */ CopyMemory(value, context->ServerChallenge, 8); CopyMemory(&value[8], context->ClientChallenge, 8); if (!sspi_SecBufferAlloc(&context->LmChallengeResponse, 24)) - return -1; + return FALSE; response = (BYTE*)context->LmChallengeResponse.pvBuffer; /* Compute the HMAC-MD5 hash of the resulting value using the NTLMv2 hash as the key */ @@ -407,7 +499,7 @@ int ntlm_compute_lm_v2_response(NTLM_CONTEXT* context) /* Concatenate the resulting HMAC-MD5 hash and the client challenge, giving us the LMv2 response * (24 bytes) */ CopyMemory(&response[16], context->ClientChallenge, 8); - return 1; + return TRUE; } /** @@ -417,13 +509,17 @@ int ntlm_compute_lm_v2_response(NTLM_CONTEXT* context) * @param NTLM context */ -int ntlm_compute_ntlm_v2_response(NTLM_CONTEXT* context) +BOOL ntlm_compute_ntlm_v2_response(NTLM_CONTEXT* context) { BYTE* blob; SecBuffer ntlm_v2_temp = { 0 }; SecBuffer ntlm_v2_temp_chal = { 0 }; - PSecBuffer TargetInfo = &context->ChallengeTargetInfo; - int ret = -1; + PSecBuffer TargetInfo; + + WINPR_ASSERT(context); + + TargetInfo = &context->ChallengeTargetInfo; + BOOL ret = FALSE; if (!sspi_SecBufferAlloc(&ntlm_v2_temp, TargetInfo->cbBuffer + 28)) goto exit; @@ -432,7 +528,7 @@ int ntlm_compute_ntlm_v2_response(NTLM_CONTEXT* context) blob = (BYTE*)ntlm_v2_temp.pvBuffer; /* Compute the NTLMv2 hash */ - if (ntlm_compute_ntlm_v2_hash(context, (BYTE*)context->NtlmV2Hash) < 0) + if (!ntlm_compute_ntlm_v2_hash(context, (BYTE*)context->NtlmV2Hash)) goto exit; /* Construct temp */ @@ -445,8 +541,8 @@ int ntlm_compute_ntlm_v2_response(NTLM_CONTEXT* context) /* Reserved3 (4 bytes) */ CopyMemory(&blob[28], TargetInfo->pvBuffer, TargetInfo->cbBuffer); #ifdef WITH_DEBUG_NTLM - WLog_DBG(TAG, "NTLMv2 Response Temp Blob"); - winpr_HexDump(TAG, WLOG_DEBUG, ntlm_v2_temp.pvBuffer, ntlm_v2_temp.cbBuffer); + WLog_VRB(TAG, "NTLMv2 Response Temp Blob"); + winpr_HexDump(TAG, WLOG_TRACE, ntlm_v2_temp.pvBuffer, ntlm_v2_temp.cbBuffer); #endif /* Concatenate server challenge with temp */ @@ -473,7 +569,7 @@ int ntlm_compute_ntlm_v2_response(NTLM_CONTEXT* context) winpr_HMAC(WINPR_MD_MD5, (BYTE*)context->NtlmV2Hash, WINPR_MD5_DIGEST_LENGTH, context->NtProofString, WINPR_MD5_DIGEST_LENGTH, context->SessionBaseKey, WINPR_MD5_DIGEST_LENGTH); - ret = 1; + ret = TRUE; exit: sspi_SecBufferFree(&ntlm_v2_temp); sspi_SecBufferFree(&ntlm_v2_temp_chal); @@ -488,7 +584,7 @@ int ntlm_compute_ntlm_v2_response(NTLM_CONTEXT* context) * @param ciphertext cipher text */ -void ntlm_rc4k(BYTE* key, int length, BYTE* plaintext, BYTE* ciphertext) +void ntlm_rc4k(BYTE* key, size_t length, BYTE* plaintext, BYTE* ciphertext) { WINPR_RC4_CTX* rc4 = winpr_RC4_New(key, 16); @@ -506,9 +602,11 @@ void ntlm_rc4k(BYTE* key, int length, BYTE* plaintext, BYTE* ciphertext) void ntlm_generate_client_challenge(NTLM_CONTEXT* context) { + WINPR_ASSERT(context); + /* ClientChallenge is used in computation of LMv2 and NTLMv2 responses */ - if (memcmp(context->ClientChallenge, NTLM_NULL_BUFFER, 8) == 0) - winpr_RAND(context->ClientChallenge, 8); + if (memcmp(context->ClientChallenge, NTLM_NULL_BUFFER, sizeof(context->ClientChallenge)) == 0) + winpr_RAND(context->ClientChallenge, sizeof(context->ClientChallenge)); } /** @@ -518,8 +616,10 @@ void ntlm_generate_client_challenge(NTLM_CONTEXT* context) void ntlm_generate_server_challenge(NTLM_CONTEXT* context) { - if (memcmp(context->ServerChallenge, NTLM_NULL_BUFFER, 8) == 0) - winpr_RAND(context->ServerChallenge, 8); + WINPR_ASSERT(context); + + if (memcmp(context->ServerChallenge, NTLM_NULL_BUFFER, sizeof(context->ServerChallenge)) == 0) + winpr_RAND(context->ServerChallenge, sizeof(context->ServerChallenge)); } /** @@ -530,8 +630,11 @@ void ntlm_generate_server_challenge(NTLM_CONTEXT* context) void ntlm_generate_key_exchange_key(NTLM_CONTEXT* context) { + WINPR_ASSERT(context); + WINPR_ASSERT(sizeof(context->KeyExchangeKey) == sizeof(context->SessionBaseKey)); + /* In NTLMv2, KeyExchangeKey is the 128-bit SessionBaseKey */ - CopyMemory(context->KeyExchangeKey, context->SessionBaseKey, 16); + CopyMemory(context->KeyExchangeKey, context->SessionBaseKey, sizeof(context->KeyExchangeKey)); } /** @@ -541,7 +644,8 @@ void ntlm_generate_key_exchange_key(NTLM_CONTEXT* context) void ntlm_generate_random_session_key(NTLM_CONTEXT* context) { - winpr_RAND(context->RandomSessionKey, 16); + WINPR_ASSERT(context); + winpr_RAND(context->RandomSessionKey, sizeof(context->RandomSessionKey)); } /** @@ -551,7 +655,11 @@ void ntlm_generate_random_session_key(NTLM_CONTEXT* context) void ntlm_generate_exported_session_key(NTLM_CONTEXT* context) { - CopyMemory(context->ExportedSessionKey, context->RandomSessionKey, 16); + WINPR_ASSERT(context); + WINPR_ASSERT(sizeof(context->ExportedSessionKey) == sizeof(context->RandomSessionKey)); + + CopyMemory(context->ExportedSessionKey, context->RandomSessionKey, + sizeof(context->ExportedSessionKey)); } /** @@ -563,6 +671,7 @@ void ntlm_encrypt_random_session_key(NTLM_CONTEXT* context) { /* In NTLMv2, EncryptedRandomSessionKey is the ExportedSessionKey RC4-encrypted with the * KeyExchangeKey */ + WINPR_ASSERT(context); ntlm_rc4k(context->KeyExchangeKey, 16, context->RandomSessionKey, context->EncryptedRandomSessionKey); } @@ -574,6 +683,8 @@ void ntlm_encrypt_random_session_key(NTLM_CONTEXT* context) void ntlm_decrypt_random_session_key(NTLM_CONTEXT* context) { + WINPR_ASSERT(context); + /* In NTLMv2, EncryptedRandomSessionKey is the ExportedSessionKey RC4-encrypted with the * KeyExchangeKey */ @@ -583,10 +694,18 @@ void ntlm_decrypt_random_session_key(NTLM_CONTEXT* context) * AUTHENTICATE_MESSAGE.EncryptedRandomSessionKey) else Set RandomSessionKey to KeyExchangeKey */ if (context->NegotiateKeyExchange) - ntlm_rc4k(context->KeyExchangeKey, 16, context->EncryptedRandomSessionKey, - context->RandomSessionKey); + { + WINPR_ASSERT(sizeof(context->EncryptedRandomSessionKey) == + sizeof(context->RandomSessionKey)); + ntlm_rc4k(context->KeyExchangeKey, sizeof(context->EncryptedRandomSessionKey), + context->EncryptedRandomSessionKey, context->RandomSessionKey); + } else - CopyMemory(context->RandomSessionKey, context->KeyExchangeKey, 16); + { + WINPR_ASSERT(sizeof(context->RandomSessionKey) == sizeof(context->KeyExchangeKey)); + CopyMemory(context->RandomSessionKey, context->KeyExchangeKey, + sizeof(context->RandomSessionKey)); + } } /** @@ -597,29 +716,32 @@ void ntlm_decrypt_random_session_key(NTLM_CONTEXT* context) * @param signing_key Destination signing key */ -static int ntlm_generate_signing_key(BYTE* exported_session_key, PSecBuffer sign_magic, - BYTE* signing_key) +static BOOL ntlm_generate_signing_key(BYTE* exported_session_key, const SecBuffer* sign_magic, + BYTE* signing_key) { - int length; - BYTE* value; + BOOL rc = FALSE; + size_t length; + BYTE* value = NULL; + + WINPR_ASSERT(exported_session_key); + WINPR_ASSERT(sign_magic); + WINPR_ASSERT(signing_key); + length = WINPR_MD5_DIGEST_LENGTH + sign_magic->cbBuffer; value = (BYTE*)malloc(length); if (!value) - return -1; + goto out; /* Concatenate ExportedSessionKey with sign magic */ CopyMemory(value, exported_session_key, WINPR_MD5_DIGEST_LENGTH); CopyMemory(&value[WINPR_MD5_DIGEST_LENGTH], sign_magic->pvBuffer, sign_magic->cbBuffer); - if (!winpr_Digest(WINPR_MD_MD5, value, length, signing_key, WINPR_MD5_DIGEST_LENGTH)) - { - free(value); - return -1; - } + rc = winpr_Digest(WINPR_MD_MD5, value, length, signing_key, WINPR_MD5_DIGEST_LENGTH); +out: free(value); - return 1; + return rc; } /** @@ -628,12 +750,13 @@ static int ntlm_generate_signing_key(BYTE* exported_session_key, PSecBuffer sign * @param NTLM context */ -void ntlm_generate_client_signing_key(NTLM_CONTEXT* context) +BOOL ntlm_generate_client_signing_key(NTLM_CONTEXT* context) { - SecBuffer signMagic; - signMagic.pvBuffer = (void*)NTLM_CLIENT_SIGN_MAGIC; - signMagic.cbBuffer = sizeof(NTLM_CLIENT_SIGN_MAGIC); - ntlm_generate_signing_key(context->ExportedSessionKey, &signMagic, context->ClientSigningKey); + const SecBuffer signMagic = { sizeof(NTLM_CLIENT_SIGN_MAGIC), 0, NTLM_CLIENT_SIGN_MAGIC }; + + WINPR_ASSERT(context); + return ntlm_generate_signing_key(context->ExportedSessionKey, &signMagic, + context->ClientSigningKey); } /** @@ -642,45 +765,13 @@ void ntlm_generate_client_signing_key(NTLM_CONTEXT* context) * @param NTLM context */ -void ntlm_generate_server_signing_key(NTLM_CONTEXT* context) +BOOL ntlm_generate_server_signing_key(NTLM_CONTEXT* context) { - SecBuffer signMagic; - signMagic.pvBuffer = (void*)NTLM_SERVER_SIGN_MAGIC; - signMagic.cbBuffer = sizeof(NTLM_SERVER_SIGN_MAGIC); - ntlm_generate_signing_key(context->ExportedSessionKey, &signMagic, context->ServerSigningKey); -} - -/** - * Generate sealing key. - * @msdn{cc236712} - * @param exported_session_key ExportedSessionKey - * @param seal_magic Seal magic string - * @param sealing_key Destination sealing key - */ + const SecBuffer signMagic = { sizeof(NTLM_SERVER_SIGN_MAGIC), 0, NTLM_SERVER_SIGN_MAGIC }; -static int ntlm_generate_sealing_key(BYTE* exported_session_key, PSecBuffer seal_magic, - BYTE* sealing_key) -{ - BYTE* p; - SecBuffer buffer; - - if (!sspi_SecBufferAlloc(&buffer, WINPR_MD5_DIGEST_LENGTH + seal_magic->cbBuffer)) - return -1; - - p = (BYTE*)buffer.pvBuffer; - /* Concatenate ExportedSessionKey with seal magic */ - CopyMemory(p, exported_session_key, WINPR_MD5_DIGEST_LENGTH); - CopyMemory(&p[WINPR_MD5_DIGEST_LENGTH], seal_magic->pvBuffer, seal_magic->cbBuffer); - - if (!winpr_Digest(WINPR_MD_MD5, buffer.pvBuffer, buffer.cbBuffer, sealing_key, - WINPR_MD5_DIGEST_LENGTH)) - { - sspi_SecBufferFree(&buffer); - return -1; - } - - sspi_SecBufferFree(&buffer); - return 1; + WINPR_ASSERT(context); + return ntlm_generate_signing_key(context->ExportedSessionKey, &signMagic, + context->ServerSigningKey); } /** @@ -689,12 +780,13 @@ static int ntlm_generate_sealing_key(BYTE* exported_session_key, PSecBuffer seal * @param NTLM context */ -void ntlm_generate_client_sealing_key(NTLM_CONTEXT* context) +BOOL ntlm_generate_client_sealing_key(NTLM_CONTEXT* context) { - SecBuffer sealMagic; - sealMagic.pvBuffer = (void*)NTLM_CLIENT_SEAL_MAGIC; - sealMagic.cbBuffer = sizeof(NTLM_CLIENT_SEAL_MAGIC); - ntlm_generate_signing_key(context->ExportedSessionKey, &sealMagic, context->ClientSealingKey); + const SecBuffer sealMagic = { sizeof(NTLM_CLIENT_SEAL_MAGIC), 0, NTLM_CLIENT_SEAL_MAGIC }; + + WINPR_ASSERT(context); + return ntlm_generate_signing_key(context->ExportedSessionKey, &sealMagic, + context->ClientSealingKey); } /** @@ -703,12 +795,13 @@ void ntlm_generate_client_sealing_key(NTLM_CONTEXT* context) * @param NTLM context */ -void ntlm_generate_server_sealing_key(NTLM_CONTEXT* context) +BOOL ntlm_generate_server_sealing_key(NTLM_CONTEXT* context) { - SecBuffer sealMagic; - sealMagic.pvBuffer = (void*)NTLM_SERVER_SEAL_MAGIC; - sealMagic.cbBuffer = sizeof(NTLM_SERVER_SEAL_MAGIC); - ntlm_generate_signing_key(context->ExportedSessionKey, &sealMagic, context->ServerSealingKey); + const SecBuffer sealMagic = { sizeof(NTLM_SERVER_SEAL_MAGIC), 0, NTLM_SERVER_SEAL_MAGIC }; + + WINPR_ASSERT(context); + return ntlm_generate_signing_key(context->ExportedSessionKey, &sealMagic, + context->ServerSealingKey); } /** @@ -718,14 +811,17 @@ void ntlm_generate_server_sealing_key(NTLM_CONTEXT* context) void ntlm_init_rc4_seal_states(NTLM_CONTEXT* context) { + WINPR_ASSERT(context); if (context->server) { context->SendSigningKey = context->ServerSigningKey; context->RecvSigningKey = context->ClientSigningKey; context->SendSealingKey = context->ClientSealingKey; context->RecvSealingKey = context->ServerSealingKey; - context->SendRc4Seal = winpr_RC4_New(context->ServerSealingKey, 16); - context->RecvRc4Seal = winpr_RC4_New(context->ClientSealingKey, 16); + context->SendRc4Seal = + winpr_RC4_New(context->ServerSealingKey, sizeof(context->ServerSealingKey)); + context->RecvRc4Seal = + winpr_RC4_New(context->ClientSealingKey, sizeof(context->ClientSealingKey)); } else { @@ -733,22 +829,29 @@ void ntlm_init_rc4_seal_states(NTLM_CONTEXT* context) context->RecvSigningKey = context->ServerSigningKey; context->SendSealingKey = context->ServerSealingKey; context->RecvSealingKey = context->ClientSealingKey; - context->SendRc4Seal = winpr_RC4_New(context->ClientSealingKey, 16); - context->RecvRc4Seal = winpr_RC4_New(context->ServerSealingKey, 16); + context->SendRc4Seal = + winpr_RC4_New(context->ClientSealingKey, sizeof(context->ClientSealingKey)); + context->RecvRc4Seal = + winpr_RC4_New(context->ServerSealingKey, sizeof(context->ServerSealingKey)); } } -void ntlm_compute_message_integrity_check(NTLM_CONTEXT* context, BYTE* mic, UINT32 size) +BOOL ntlm_compute_message_integrity_check(NTLM_CONTEXT* context, BYTE* mic, UINT32 size) { + BOOL rc = FALSE; /* * Compute the HMAC-MD5 hash of ConcatenationOf(NEGOTIATE_MESSAGE, * CHALLENGE_MESSAGE, AUTHENTICATE_MESSAGE) using the ExportedSessionKey */ WINPR_HMAC_CTX* hmac = winpr_HMAC_New(); - assert(size >= WINPR_MD5_DIGEST_LENGTH); + WINPR_ASSERT(context); + WINPR_ASSERT(mic); + WINPR_ASSERT(size >= WINPR_MD5_DIGEST_LENGTH); + + memset(mic, 0, size); if (!hmac) - return; + return FALSE; if (winpr_HMAC_Init(hmac, WINPR_MD_MD5, context->ExportedSessionKey, WINPR_MD5_DIGEST_LENGTH)) { @@ -756,10 +859,27 @@ void ntlm_compute_message_integrity_check(NTLM_CONTEXT* context, BYTE* mic, UINT context->NegotiateMessage.cbBuffer); winpr_HMAC_Update(hmac, (BYTE*)context->ChallengeMessage.pvBuffer, context->ChallengeMessage.cbBuffer); - winpr_HMAC_Update(hmac, (BYTE*)context->AuthenticateMessage.pvBuffer, - context->AuthenticateMessage.cbBuffer); + + if (context->MessageIntegrityCheckOffset > 0) + { + const BYTE* auth = (BYTE*)context->AuthenticateMessage.pvBuffer; + const BYTE data[WINPR_MD5_DIGEST_LENGTH] = { 0 }; + const size_t rest = context->MessageIntegrityCheckOffset + sizeof(data); + + WINPR_ASSERT(rest <= context->AuthenticateMessage.cbBuffer); + winpr_HMAC_Update(hmac, &auth[0], context->MessageIntegrityCheckOffset); + winpr_HMAC_Update(hmac, data, sizeof(data)); + winpr_HMAC_Update(hmac, &auth[rest], context->AuthenticateMessage.cbBuffer - rest); + } + else + { + winpr_HMAC_Update(hmac, (BYTE*)context->AuthenticateMessage.pvBuffer, + context->AuthenticateMessage.cbBuffer); + } winpr_HMAC_Final(hmac, mic, WINPR_MD5_DIGEST_LENGTH); + rc = TRUE; } winpr_HMAC_Free(hmac); + return rc; } diff --git a/winpr/libwinpr/sspi/NTLM/ntlm_compute.h b/winpr/libwinpr/sspi/NTLM/ntlm_compute.h index 47f6c5dc84b4..a5572b504fa2 100644 --- a/winpr/libwinpr/sspi/NTLM/ntlm_compute.h +++ b/winpr/libwinpr/sspi/NTLM/ntlm_compute.h @@ -24,13 +24,16 @@ #include "ntlm_av_pairs.h" -void ntlm_get_version_info(NTLM_VERSION_INFO* versionInfo); -int ntlm_read_version_info(wStream* s, NTLM_VERSION_INFO* versionInfo); -void ntlm_write_version_info(wStream* s, NTLM_VERSION_INFO* versionInfo); -void ntlm_print_version_info(NTLM_VERSION_INFO* versionInfo); +BOOL ntlm_get_version_info(NTLM_VERSION_INFO* versionInfo); +BOOL ntlm_read_version_info(wStream* s, NTLM_VERSION_INFO* versionInfo); +BOOL ntlm_write_version_info(wStream* s, const NTLM_VERSION_INFO* versionInfo); -int ntlm_read_ntlm_v2_response(wStream* s, NTLMv2_RESPONSE* response); -int ntlm_write_ntlm_v2_response(wStream* s, NTLMv2_RESPONSE* response); +#ifdef WITH_DEBUG_NTLM +void ntlm_print_version_info(const NTLM_VERSION_INFO* versionInfo); +#endif + +BOOL ntlm_read_ntlm_v2_response(wStream* s, NTLMv2_RESPONSE* response); +BOOL ntlm_write_ntlm_v2_response(wStream* s, const NTLMv2_RESPONSE* response); void ntlm_output_target_name(NTLM_CONTEXT* context); void ntlm_output_channel_bindings(NTLM_CONTEXT* context); @@ -38,10 +41,10 @@ void ntlm_output_channel_bindings(NTLM_CONTEXT* context); void ntlm_current_time(BYTE* timestamp); void ntlm_generate_timestamp(NTLM_CONTEXT* context); -int ntlm_compute_lm_v2_response(NTLM_CONTEXT* context); -int ntlm_compute_ntlm_v2_response(NTLM_CONTEXT* context); +BOOL ntlm_compute_lm_v2_response(NTLM_CONTEXT* context); +BOOL ntlm_compute_ntlm_v2_response(NTLM_CONTEXT* context); -void ntlm_rc4k(BYTE* key, int length, BYTE* plaintext, BYTE* ciphertext); +void ntlm_rc4k(BYTE* key, size_t length, BYTE* plaintext, BYTE* ciphertext); void ntlm_generate_client_challenge(NTLM_CONTEXT* context); void ntlm_generate_server_challenge(NTLM_CONTEXT* context); void ntlm_generate_key_exchange_key(NTLM_CONTEXT* context); @@ -50,12 +53,12 @@ void ntlm_generate_exported_session_key(NTLM_CONTEXT* context); void ntlm_encrypt_random_session_key(NTLM_CONTEXT* context); void ntlm_decrypt_random_session_key(NTLM_CONTEXT* context); -void ntlm_generate_client_signing_key(NTLM_CONTEXT* context); -void ntlm_generate_server_signing_key(NTLM_CONTEXT* context); -void ntlm_generate_client_sealing_key(NTLM_CONTEXT* context); -void ntlm_generate_server_sealing_key(NTLM_CONTEXT* context); +BOOL ntlm_generate_client_signing_key(NTLM_CONTEXT* context); +BOOL ntlm_generate_server_signing_key(NTLM_CONTEXT* context); +BOOL ntlm_generate_client_sealing_key(NTLM_CONTEXT* context); +BOOL ntlm_generate_server_sealing_key(NTLM_CONTEXT* context); void ntlm_init_rc4_seal_states(NTLM_CONTEXT* context); -void ntlm_compute_message_integrity_check(NTLM_CONTEXT* context, BYTE* mic, UINT32 size); +BOOL ntlm_compute_message_integrity_check(NTLM_CONTEXT* context, BYTE* mic, UINT32 size); #endif /* WINPR_AUTH_NTLM_COMPUTE_H */ diff --git a/winpr/libwinpr/sspi/NTLM/ntlm_message.c b/winpr/libwinpr/sspi/NTLM/ntlm_message.c index 7502ecfc2bf0..7f3779d16c60 100644 --- a/winpr/libwinpr/sspi/NTLM/ntlm_message.c +++ b/winpr/libwinpr/sspi/NTLM/ntlm_message.c @@ -25,6 +25,7 @@ #include "../sspi.h" #include +#include #include #include #include @@ -33,140 +34,369 @@ #include "ntlm_message.h" -#include "../log.h" +#include "../../log.h" #define TAG WINPR_TAG("sspi.NTLM") static const char NTLM_SIGNATURE[8] = { 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0' }; -#ifdef WITH_DEBUG_NTLM -static const char* const NTLM_NEGOTIATE_STRINGS[] = { "NTLMSSP_NEGOTIATE_56", - "NTLMSSP_NEGOTIATE_KEY_EXCH", - "NTLMSSP_NEGOTIATE_128", - "NTLMSSP_RESERVED1", - "NTLMSSP_RESERVED2", - "NTLMSSP_RESERVED3", - "NTLMSSP_NEGOTIATE_VERSION", - "NTLMSSP_RESERVED4", - "NTLMSSP_NEGOTIATE_TARGET_INFO", - "NTLMSSP_REQUEST_NON_NT_SESSION_KEY", - "NTLMSSP_RESERVED5", - "NTLMSSP_NEGOTIATE_IDENTIFY", - "NTLMSSP_NEGOTIATE_EXTENDED_SESSION_SECURITY", - "NTLMSSP_RESERVED6", - "NTLMSSP_TARGET_TYPE_SERVER", - "NTLMSSP_TARGET_TYPE_DOMAIN", - "NTLMSSP_NEGOTIATE_ALWAYS_SIGN", - "NTLMSSP_RESERVED7", - "NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED", - "NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED", - "NTLMSSP_NEGOTIATE_ANONYMOUS", - "NTLMSSP_RESERVED8", - "NTLMSSP_NEGOTIATE_NTLM", - "NTLMSSP_RESERVED9", - "NTLMSSP_NEGOTIATE_LM_KEY", - "NTLMSSP_NEGOTIATE_DATAGRAM", - "NTLMSSP_NEGOTIATE_SEAL", - "NTLMSSP_NEGOTIATE_SIGN", - "NTLMSSP_RESERVED10", - "NTLMSSP_REQUEST_TARGET", - "NTLMSSP_NEGOTIATE_OEM", - "NTLMSSP_NEGOTIATE_UNICODE" }; +const char* ntlm_get_negotiate_string(UINT32 flag) +{ + if (flag & NTLMSSP_NEGOTIATE_56) + return "NTLMSSP_NEGOTIATE_56"; + if (flag & NTLMSSP_NEGOTIATE_KEY_EXCH) + return "NTLMSSP_NEGOTIATE_KEY_EXCH"; + if (flag & NTLMSSP_NEGOTIATE_128) + return "NTLMSSP_NEGOTIATE_128"; + if (flag & NTLMSSP_RESERVED1) + return "NTLMSSP_RESERVED1"; + if (flag & NTLMSSP_RESERVED2) + return "NTLMSSP_RESERVED2"; + if (flag & NTLMSSP_RESERVED3) + return "NTLMSSP_RESERVED3"; + if (flag & NTLMSSP_NEGOTIATE_VERSION) + return "NTLMSSP_NEGOTIATE_VERSION"; + if (flag & NTLMSSP_RESERVED4) + return "NTLMSSP_RESERVED4"; + if (flag & NTLMSSP_NEGOTIATE_TARGET_INFO) + return "NTLMSSP_NEGOTIATE_TARGET_INFO"; + if (flag & NTLMSSP_REQUEST_NON_NT_SESSION_KEY) + return "NTLMSSP_REQUEST_NON_NT_SESSION_KEY"; + if (flag & NTLMSSP_RESERVED5) + return "NTLMSSP_RESERVED5"; + if (flag & NTLMSSP_NEGOTIATE_IDENTIFY) + return "NTLMSSP_NEGOTIATE_IDENTIFY"; + if (flag & NTLMSSP_NEGOTIATE_EXTENDED_SESSION_SECURITY) + return "NTLMSSP_NEGOTIATE_EXTENDED_SESSION_SECURITY"; + if (flag & NTLMSSP_RESERVED6) + return "NTLMSSP_RESERVED6"; + if (flag & NTLMSSP_TARGET_TYPE_SERVER) + return "NTLMSSP_TARGET_TYPE_SERVER"; + if (flag & NTLMSSP_TARGET_TYPE_DOMAIN) + return "NTLMSSP_TARGET_TYPE_DOMAIN"; + if (flag & NTLMSSP_NEGOTIATE_ALWAYS_SIGN) + return "NTLMSSP_NEGOTIATE_ALWAYS_SIGN"; + if (flag & NTLMSSP_RESERVED7) + return "NTLMSSP_RESERVED7"; + if (flag & NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED) + return "NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED"; + if (flag & NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED) + return "NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED"; + if (flag & NTLMSSP_NEGOTIATE_ANONYMOUS) + return "NTLMSSP_NEGOTIATE_ANONYMOUS"; + if (flag & NTLMSSP_RESERVED8) + return "NTLMSSP_RESERVED8"; + if (flag & NTLMSSP_NEGOTIATE_NTLM) + return "NTLMSSP_NEGOTIATE_NTLM"; + if (flag & NTLMSSP_RESERVED9) + return "NTLMSSP_RESERVED9"; + if (flag & NTLMSSP_NEGOTIATE_LM_KEY) + return "NTLMSSP_NEGOTIATE_LM_KEY"; + if (flag & NTLMSSP_NEGOTIATE_DATAGRAM) + return "NTLMSSP_NEGOTIATE_DATAGRAM"; + if (flag & NTLMSSP_NEGOTIATE_SEAL) + return "NTLMSSP_NEGOTIATE_SEAL"; + if (flag & NTLMSSP_NEGOTIATE_SIGN) + return "NTLMSSP_NEGOTIATE_SIGN"; + if (flag & NTLMSSP_RESERVED10) + return "NTLMSSP_RESERVED10"; + if (flag & NTLMSSP_REQUEST_TARGET) + return "NTLMSSP_REQUEST_TARGET"; + if (flag & NTLMSSP_NEGOTIATE_OEM) + return "NTLMSSP_NEGOTIATE_OEM"; + if (flag & NTLMSSP_NEGOTIATE_UNICODE) + return "NTLMSSP_NEGOTIATE_UNICODE"; + return "NTLMSSP_NEGOTIATE_UNKNOWN"; +} + +#if defined(WITH_DEBUG_NTLM) +static void ntlm_print_message_fields(const NTLM_MESSAGE_FIELDS* fields, const char* name) +{ + WINPR_ASSERT(fields); + WINPR_ASSERT(name); + + WLog_VRB(TAG, "%s (Len: %" PRIu16 " MaxLen: %" PRIu16 " BufferOffset: %" PRIu32 ")", name, + fields->Len, fields->MaxLen, fields->BufferOffset); + + if (fields->Len > 0) + winpr_HexDump(TAG, WLOG_TRACE, fields->Buffer, fields->Len); +} static void ntlm_print_negotiate_flags(UINT32 flags) { int i; - const char* str; - WLog_INFO(TAG, "negotiateFlags \"0x%08" PRIX32 "\"", flags); + + WLog_VRB(TAG, "negotiateFlags \"0x%08" PRIX32 "\"", flags); for (i = 31; i >= 0; i--) { if ((flags >> i) & 1) { - str = NTLM_NEGOTIATE_STRINGS[(31 - i)]; - WLog_INFO(TAG, "\t%s (%d),", str, (31 - i)); + const char* str = ntlm_get_negotiate_string(1 << i); + WLog_VRB(TAG, "\t%s (%d),", str, (31 - i)); } } } + +static void ntlm_print_negotiate_message(const SecBuffer* NegotiateMessage, + const NTLM_NEGOTIATE_MESSAGE* message) +{ + WINPR_ASSERT(NegotiateMessage); + WINPR_ASSERT(message); + + WLog_VRB(TAG, "NEGOTIATE_MESSAGE (length = %" PRIu32 ")", NegotiateMessage->cbBuffer); + winpr_HexDump(TAG, WLOG_TRACE, NegotiateMessage->pvBuffer, NegotiateMessage->cbBuffer); + ntlm_print_negotiate_flags(message->NegotiateFlags); + + if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION) + ntlm_print_version_info(&(message->Version)); +} + +static void ntlm_print_challenge_message(const SecBuffer* ChallengeMessage, + const NTLM_CHALLENGE_MESSAGE* message, + const SecBuffer* ChallengeTargetInfo) +{ + WINPR_ASSERT(ChallengeMessage); + WINPR_ASSERT(message); + + WLog_VRB(TAG, "CHALLENGE_MESSAGE (length = %" PRIu32 ")", ChallengeMessage->cbBuffer); + winpr_HexDump(TAG, WLOG_TRACE, ChallengeMessage->pvBuffer, ChallengeMessage->cbBuffer); + ntlm_print_negotiate_flags(message->NegotiateFlags); + + if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION) + ntlm_print_version_info(&(message->Version)); + + ntlm_print_message_fields(&(message->TargetName), "TargetName"); + ntlm_print_message_fields(&(message->TargetInfo), "TargetInfo"); + + if (ChallengeTargetInfo && (ChallengeTargetInfo->cbBuffer > 0)) + { + WLog_VRB(TAG, "ChallengeTargetInfo (%" PRIu32 "):", ChallengeTargetInfo->cbBuffer); + ntlm_print_av_pair_list(ChallengeTargetInfo->pvBuffer, ChallengeTargetInfo->cbBuffer); + } +} + +static void ntlm_print_authenticate_message(const SecBuffer* AuthenticateMessage, + const NTLM_AUTHENTICATE_MESSAGE* message, UINT32 flags, + const SecBuffer* AuthenticateTargetInfo) +{ + WINPR_ASSERT(AuthenticateMessage); + WINPR_ASSERT(message); + + WLog_VRB(TAG, "AUTHENTICATE_MESSAGE (length = %" PRIu32 ")", AuthenticateMessage->cbBuffer); + winpr_HexDump(TAG, WLOG_TRACE, AuthenticateMessage->pvBuffer, AuthenticateMessage->cbBuffer); + ntlm_print_negotiate_flags(message->NegotiateFlags); + + if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION) + ntlm_print_version_info(&(message->Version)); + + if (AuthenticateTargetInfo && (AuthenticateTargetInfo->cbBuffer > 0)) + { + WLog_VRB(TAG, "AuthenticateTargetInfo (%" PRIu32 "):", AuthenticateTargetInfo->cbBuffer); + ntlm_print_av_pair_list(AuthenticateTargetInfo->pvBuffer, AuthenticateTargetInfo->cbBuffer); + } + + ntlm_print_message_fields(&(message->DomainName), "DomainName"); + ntlm_print_message_fields(&(message->UserName), "UserName"); + ntlm_print_message_fields(&(message->Workstation), "Workstation"); + ntlm_print_message_fields(&(message->LmChallengeResponse), "LmChallengeResponse"); + ntlm_print_message_fields(&(message->NtChallengeResponse), "NtChallengeResponse"); + ntlm_print_message_fields(&(message->EncryptedRandomSessionKey), "EncryptedRandomSessionKey"); + + if (flags & MSV_AV_FLAGS_MESSAGE_INTEGRITY_CHECK) + { + WLog_VRB(TAG, "MessageIntegrityCheck (length = 16)"); + winpr_HexDump(TAG, WLOG_TRACE, message->MessageIntegrityCheck, + sizeof(message->MessageIntegrityCheck)); + } +} + +static void ntlm_print_authentication_complete(const NTLM_CONTEXT* context) +{ + WINPR_ASSERT(context); + + WLog_VRB(TAG, "ClientChallenge"); + winpr_HexDump(TAG, WLOG_TRACE, context->ClientChallenge, 8); + WLog_VRB(TAG, "ServerChallenge"); + winpr_HexDump(TAG, WLOG_TRACE, context->ServerChallenge, 8); + WLog_VRB(TAG, "SessionBaseKey"); + winpr_HexDump(TAG, WLOG_TRACE, context->SessionBaseKey, 16); + WLog_VRB(TAG, "KeyExchangeKey"); + winpr_HexDump(TAG, WLOG_TRACE, context->KeyExchangeKey, 16); + WLog_VRB(TAG, "ExportedSessionKey"); + winpr_HexDump(TAG, WLOG_TRACE, context->ExportedSessionKey, 16); + WLog_VRB(TAG, "RandomSessionKey"); + winpr_HexDump(TAG, WLOG_TRACE, context->RandomSessionKey, 16); + WLog_VRB(TAG, "ClientSigningKey"); + winpr_HexDump(TAG, WLOG_TRACE, context->ClientSigningKey, 16); + WLog_VRB(TAG, "ClientSealingKey"); + winpr_HexDump(TAG, WLOG_TRACE, context->ClientSealingKey, 16); + WLog_VRB(TAG, "ServerSigningKey"); + winpr_HexDump(TAG, WLOG_TRACE, context->ServerSigningKey, 16); + WLog_VRB(TAG, "ServerSealingKey"); + winpr_HexDump(TAG, WLOG_TRACE, context->ServerSealingKey, 16); + WLog_VRB(TAG, "Timestamp"); + winpr_HexDump(TAG, WLOG_TRACE, context->Timestamp, 8); +} #endif -static int ntlm_read_message_header(wStream* s, NTLM_MESSAGE_HEADER* header) +static BOOL ntlm_read_message_header(wStream* s, NTLM_MESSAGE_HEADER* header, UINT32 expected) { + WINPR_ASSERT(s); + WINPR_ASSERT(header); + if (Stream_GetRemainingLength(s) < 12) - return -1; + { + WLog_ERR(TAG, "Short NTLM_MESSAGE_HEADER::header %" PRIuz ", expected 12", + Stream_GetRemainingLength(s)); + return FALSE; + } Stream_Read(s, header->Signature, 8); Stream_Read_UINT32(s, header->MessageType); if (strncmp((char*)header->Signature, NTLM_SIGNATURE, 8) != 0) - return -1; + { + WLog_ERR(TAG, "NTLM_MESSAGE_HEADER Invalid signature, got %s, expected %s", + header->Signature, NTLM_SIGNATURE); + return FALSE; + } - return 1; + if (header->MessageType != expected) + { + WLog_ERR(TAG, "NTLM_MESSAGE_HEADER Invalid message tyep, got %s, expected %s", + ntlm_message_type_string(header->MessageType), ntlm_message_type_string(expected)); + return FALSE; + } + + return TRUE; } -static void ntlm_write_message_header(wStream* s, NTLM_MESSAGE_HEADER* header) +static BOOL ntlm_write_message_header(wStream* s, const NTLM_MESSAGE_HEADER* header) { + WINPR_ASSERT(s); + WINPR_ASSERT(header); + + if (Stream_GetRemainingCapacity(s) < sizeof(NTLM_SIGNATURE) + 4) + { + WLog_ERR(TAG, "Short NTLM_MESSAGE_HEADER::header %" PRIuz ", expected 12", + Stream_GetRemainingCapacity(s)); + return FALSE; + } + Stream_Write(s, header->Signature, sizeof(NTLM_SIGNATURE)); Stream_Write_UINT32(s, header->MessageType); + + return TRUE; } -static void ntlm_populate_message_header(NTLM_MESSAGE_HEADER* header, UINT32 MessageType) +static BOOL ntlm_populate_message_header(NTLM_MESSAGE_HEADER* header, UINT32 MessageType) { + WINPR_ASSERT(header); + CopyMemory(header->Signature, NTLM_SIGNATURE, sizeof(NTLM_SIGNATURE)); header->MessageType = MessageType; + return TRUE; } -static int ntlm_read_message_fields(wStream* s, NTLM_MESSAGE_FIELDS* fields) +static BOOL ntlm_read_message_fields(wStream* s, NTLM_MESSAGE_FIELDS* fields) { + WINPR_ASSERT(s); + WINPR_ASSERT(fields); + if (Stream_GetRemainingLength(s) < 8) - return -1; + { + WLog_ERR(TAG, "Short NTLM_MESSAGE_FIELDS::header %" PRIuz ", expected %" PRIuz, + Stream_GetRemainingLength(s), 8); + return FALSE; + } Stream_Read_UINT16(s, fields->Len); /* Len (2 bytes) */ Stream_Read_UINT16(s, fields->MaxLen); /* MaxLen (2 bytes) */ Stream_Read_UINT32(s, fields->BufferOffset); /* BufferOffset (4 bytes) */ - return 1; + return TRUE; } -static void ntlm_write_message_fields(wStream* s, NTLM_MESSAGE_FIELDS* fields) +static BOOL ntlm_write_message_fields(wStream* s, const NTLM_MESSAGE_FIELDS* fields) { + UINT16 MaxLen; + WINPR_ASSERT(s); + WINPR_ASSERT(fields); + + MaxLen = fields->MaxLen; if (fields->MaxLen < 1) - fields->MaxLen = fields->Len; + MaxLen = fields->Len; + if (Stream_GetRemainingCapacity(s) < 8) + { + WLog_ERR(TAG, "Short NTLM_MESSAGE_FIELDS::header %" PRIuz ", expected %" PRIuz, + Stream_GetRemainingCapacity(s), 8); + return FALSE; + } Stream_Write_UINT16(s, fields->Len); /* Len (2 bytes) */ - Stream_Write_UINT16(s, fields->MaxLen); /* MaxLen (2 bytes) */ + Stream_Write_UINT16(s, MaxLen); /* MaxLen (2 bytes) */ Stream_Write_UINT32(s, fields->BufferOffset); /* BufferOffset (4 bytes) */ + return TRUE; } -static int ntlm_read_message_fields_buffer(wStream* s, NTLM_MESSAGE_FIELDS* fields) +static BOOL ntlm_read_message_fields_buffer(wStream* s, NTLM_MESSAGE_FIELDS* fields) { + WINPR_ASSERT(s); + WINPR_ASSERT(fields); + if (fields->Len > 0) { const UINT32 offset = fields->BufferOffset + fields->Len; if (fields->BufferOffset > UINT32_MAX - fields->Len) - return -1; + { + WLog_ERR(TAG, + "NTLM_MESSAGE_FIELDS::BufferOffset %" PRIu32 + " too large, maximum allowed is %" PRIu32, + fields->BufferOffset, UINT32_MAX - fields->Len); + return FALSE; + } if (offset > Stream_Length(s)) - return -1; + { + WLog_ERR(TAG, + "NTLM_MESSAGE_FIELDS::Buffer offset %" PRIu32 " beyond received data %" PRIuz, + offset, Stream_Length(s)); + return FALSE; + } fields->Buffer = (PBYTE)malloc(fields->Len); if (!fields->Buffer) - return -1; + { + WLog_ERR(TAG, "NTLM_MESSAGE_FIELDS::Buffer allocation of %" PRIu16 "bytes failed", + fields->Len); + return FALSE; + } Stream_SetPosition(s, fields->BufferOffset); Stream_Read(s, fields->Buffer, fields->Len); } - return 1; + return TRUE; } -static void ntlm_write_message_fields_buffer(wStream* s, NTLM_MESSAGE_FIELDS* fields) +static BOOL ntlm_write_message_fields_buffer(wStream* s, const NTLM_MESSAGE_FIELDS* fields) { + WINPR_ASSERT(s); + WINPR_ASSERT(fields); + if (fields->Len > 0) { Stream_SetPosition(s, fields->BufferOffset); + if (Stream_GetRemainingCapacity(s) < fields->Len) + { + WLog_ERR(TAG, "Short NTLM_MESSAGE_FIELDS::Len %" PRIuz ", expected %" PRIu16, + Stream_GetRemainingCapacity(s), fields->Len); + return FALSE; + } Stream_Write(s, fields->Buffer, fields->Len); } + return TRUE; } static void ntlm_free_message_fields_buffer(NTLM_MESSAGE_FIELDS* fields) @@ -184,122 +414,196 @@ static void ntlm_free_message_fields_buffer(NTLM_MESSAGE_FIELDS* fields) } } -#ifdef WITH_DEBUG_NTLM -static void ntlm_print_message_fields(NTLM_MESSAGE_FIELDS* fields, const char* name) +static BOOL ntlm_read_negotiate_flags(wStream* s, UINT32* flags, UINT32 required, const char* name) { - WLog_DBG(TAG, "%s (Len: %" PRIu16 " MaxLen: %" PRIu16 " BufferOffset: %" PRIu32 ")", name, - fields->Len, fields->MaxLen, fields->BufferOffset); + UINT32 NegotiateFlags = 0; + WINPR_ASSERT(s); + WINPR_ASSERT(flags); + WINPR_ASSERT(name); - if (fields->Len > 0) - winpr_HexDump(TAG, WLOG_DEBUG, fields->Buffer, fields->Len); + if (Stream_GetRemainingLength(s) < 4) + { + WLog_ERR(TAG, "%s::NegotiateFlags expected 4bytes, have %" PRIuz "bytes", name, + Stream_GetRemainingLength(s)); + return FALSE; + } + + Stream_Read_UINT32(s, NegotiateFlags); /* NegotiateFlags (4 bytes) */ + + if ((NegotiateFlags & required) != required) + { + WLog_ERR(TAG, "%s::NegotiateFlags invalid flags 0x08%" PRIx32 ", 0x%08" PRIx32 " required", + name, NegotiateFlags, required); + return FALSE; + } + *flags = NegotiateFlags; + return TRUE; +} + +static BOOL ntlm_write_negotiate_flags(wStream* s, UINT32 flags, const char* name) +{ + WINPR_ASSERT(s); + WINPR_ASSERT(name); + + if (Stream_GetRemainingCapacity(s) < 4) + { + WLog_ERR(TAG, "%s::NegotiateFlags expected 4bytes, have %" PRIuz "bytes", name, + Stream_GetRemainingCapacity(s)); + return FALSE; + } + + Stream_Write_UINT32(s, flags); /* NegotiateFlags (4 bytes) */ + return TRUE; +} + +static BOOL ntlm_read_message_integrity_check(wStream* s, size_t* offset, BYTE* data, size_t size, + const char* name) +{ + WINPR_ASSERT(s); + WINPR_ASSERT(offset); + WINPR_ASSERT(data); + WINPR_ASSERT(size == WINPR_MD5_DIGEST_LENGTH); + WINPR_ASSERT(name); + + *offset = Stream_GetPosition(s); + + if (Stream_GetRemainingLength(s) < size) + { + WLog_ERR(TAG, + "%s::MessageIntegrityCheckOffset expected %" PRIuz "bytes, got " + "%" PRIuz "byets", + name, size, Stream_GetRemainingLength(s)); + return FALSE; + } + + Stream_Read(s, data, size); + return TRUE; +} + +static BOOL ntlm_write_message_integrity_check(wStream* s, size_t offset, const BYTE* data, + size_t size, const char* name) +{ + size_t pos; + + WINPR_ASSERT(s); + WINPR_ASSERT(data); + WINPR_ASSERT(size == WINPR_MD5_DIGEST_LENGTH); + WINPR_ASSERT(name); + + pos = Stream_GetPosition(s); + + if (offset + size > Stream_Capacity(s)) + { + WLog_ERR(TAG, + "%s::MessageIntegrityCheck invalid offset[length] %" PRIuz "[%" PRIuz + "], got %" PRIuz, + name, offset, size, Stream_GetRemainingCapacity(s)); + return FALSE; + } + Stream_SetPosition(s, offset); + if (Stream_GetRemainingCapacity(s) < size) + { + WLog_ERR(TAG, "%s::MessageIntegrityCheck expected %" PRIuz "bytes, got %" PRIuz "bytes", + name, size, Stream_GetRemainingCapacity(s)); + return FALSE; + } + + Stream_Write(s, data, size); + Stream_SetPosition(s, pos); + return TRUE; } -#endif SECURITY_STATUS ntlm_read_NegotiateMessage(NTLM_CONTEXT* context, PSecBuffer buffer) { + wStream sbuffer; wStream* s; size_t length; + const NTLM_NEGOTIATE_MESSAGE empty = { 0 }; NTLM_NEGOTIATE_MESSAGE* message; + + WINPR_ASSERT(context); + WINPR_ASSERT(buffer); + message = &context->NEGOTIATE_MESSAGE; - ZeroMemory(message, sizeof(NTLM_NEGOTIATE_MESSAGE)); - s = Stream_New((BYTE*)buffer->pvBuffer, buffer->cbBuffer); + WINPR_ASSERT(message); + + *message = empty; + + s = Stream_StaticConstInit(&sbuffer, buffer->pvBuffer, buffer->cbBuffer); if (!s) return SEC_E_INTERNAL_ERROR; - if (ntlm_read_message_header(s, (NTLM_MESSAGE_HEADER*)message) < 0) - { - Stream_Free(s, FALSE); + if (!ntlm_read_message_header(s, &message->header, MESSAGE_TYPE_NEGOTIATE)) return SEC_E_INVALID_TOKEN; - } - if (message->MessageType != MESSAGE_TYPE_NEGOTIATE) - { - Stream_Free(s, FALSE); + if (!ntlm_read_negotiate_flags(s, &message->NegotiateFlags, + NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_NTLM | + NTLMSSP_NEGOTIATE_UNICODE, + "NTLM_NEGOTIATE_MESSAGE")) return SEC_E_INVALID_TOKEN; - } - - if (Stream_GetRemainingLength(s) < 4) - { - Stream_Free(s, FALSE); - return SEC_E_INVALID_TOKEN; - } - Stream_Read_UINT32(s, message->NegotiateFlags); /* NegotiateFlags (4 bytes) */ - - if (!((message->NegotiateFlags & NTLMSSP_REQUEST_TARGET) && - (message->NegotiateFlags & NTLMSSP_NEGOTIATE_NTLM) && - (message->NegotiateFlags & NTLMSSP_NEGOTIATE_UNICODE))) - { - Stream_Free(s, FALSE); - return SEC_E_INVALID_TOKEN; - } context->NegotiateFlags = message->NegotiateFlags; /* only set if NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED is set */ - - if (ntlm_read_message_fields(s, &(message->DomainName)) < 0) /* DomainNameFields (8 bytes) */ + // if (context->NegotiateFlags & NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED) { - Stream_Free(s, FALSE); - return SEC_E_INVALID_TOKEN; + if (!ntlm_read_message_fields(s, &(message->DomainName))) /* DomainNameFields (8 bytes) */ + return SEC_E_INVALID_TOKEN; } /* only set if NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED is set */ - - if (ntlm_read_message_fields(s, &(message->Workstation)) < 0) /* WorkstationFields (8 bytes) */ + // if (context->NegotiateFlags & NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED) { - Stream_Free(s, FALSE); - return SEC_E_INVALID_TOKEN; + if (!ntlm_read_message_fields(s, &(message->Workstation))) /* WorkstationFields (8 bytes) */ + return SEC_E_INVALID_TOKEN; } if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION) { - if (ntlm_read_version_info(s, &(message->Version)) < 0) /* Version (8 bytes) */ - { - Stream_Free(s, FALSE); + if (!ntlm_read_version_info(s, &(message->Version))) /* Version (8 bytes) */ return SEC_E_INVALID_TOKEN; - } } length = Stream_GetPosition(s); - buffer->cbBuffer = length; + WINPR_ASSERT(length <= ULONG_MAX); + buffer->cbBuffer = (ULONG)length; - if (!sspi_SecBufferAlloc(&context->NegotiateMessage, length)) - { - Stream_Free(s, FALSE); + if (!sspi_SecBufferAlloc(&context->NegotiateMessage, (ULONG)length)) return SEC_E_INTERNAL_ERROR; - } CopyMemory(context->NegotiateMessage.pvBuffer, buffer->pvBuffer, buffer->cbBuffer); context->NegotiateMessage.BufferType = buffer->BufferType; -#ifdef WITH_DEBUG_NTLM - WLog_DBG(TAG, "NEGOTIATE_MESSAGE (length = %" PRIu32 ")", context->NegotiateMessage.cbBuffer); - winpr_HexDump(TAG, WLOG_DEBUG, context->NegotiateMessage.pvBuffer, - context->NegotiateMessage.cbBuffer); - ntlm_print_negotiate_flags(message->NegotiateFlags); - - if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION) - ntlm_print_version_info(&(message->Version)); - +#if defined(WITH_DEBUG_NTLM) + ntlm_print_negotiate_message(&context->NegotiateMessage, message); #endif - context->state = NTLM_STATE_CHALLENGE; - Stream_Free(s, FALSE); + ntlm_change_state(context, NTLM_STATE_CHALLENGE); return SEC_I_CONTINUE_NEEDED; } SECURITY_STATUS ntlm_write_NegotiateMessage(NTLM_CONTEXT* context, PSecBuffer buffer) { + wStream sbuffer; wStream* s; size_t length; + const NTLM_NEGOTIATE_MESSAGE empty = { 0 }; NTLM_NEGOTIATE_MESSAGE* message; + + WINPR_ASSERT(context); + WINPR_ASSERT(buffer); + message = &context->NEGOTIATE_MESSAGE; - ZeroMemory(message, sizeof(NTLM_NEGOTIATE_MESSAGE)); - s = Stream_New((BYTE*)buffer->pvBuffer, buffer->cbBuffer); + WINPR_ASSERT(message); + + *message = empty; + + s = Stream_StaticInit(&sbuffer, buffer->pvBuffer, buffer->cbBuffer); if (!s) return SEC_E_INTERNAL_ERROR; - ntlm_populate_message_header((NTLM_MESSAGE_HEADER*)message, MESSAGE_TYPE_NEGOTIATE); + if (!ntlm_populate_message_header(&message->header, MESSAGE_TYPE_NEGOTIATE)) + return SEC_E_INTERNAL_ERROR; if (context->NTLMv2) { @@ -329,96 +633,101 @@ SECURITY_STATUS ntlm_write_NegotiateMessage(NTLM_CONTEXT* context, PSecBuffer bu context->NegotiateFlags = message->NegotiateFlags; /* Message Header (12 bytes) */ - ntlm_write_message_header(s, (NTLM_MESSAGE_HEADER*)message); - Stream_Write_UINT32(s, message->NegotiateFlags); /* NegotiateFlags (4 bytes) */ + if (!ntlm_write_message_header(s, &message->header)) + return SEC_E_INTERNAL_ERROR; + + if (!ntlm_write_negotiate_flags(s, message->NegotiateFlags, "NTLM_NEGOTIATE_MESSAGE")) + return SEC_E_INTERNAL_ERROR; + /* only set if NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED is set */ /* DomainNameFields (8 bytes) */ - ntlm_write_message_fields(s, &(message->DomainName)); + if (!ntlm_write_message_fields(s, &(message->DomainName))) + return SEC_E_INTERNAL_ERROR; + /* only set if NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED is set */ /* WorkstationFields (8 bytes) */ - ntlm_write_message_fields(s, &(message->Workstation)); + if (!ntlm_write_message_fields(s, &(message->Workstation))) + return SEC_E_INTERNAL_ERROR; if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION) - ntlm_write_version_info(s, &(message->Version)); + { + if (!ntlm_write_version_info(s, &(message->Version))) + return SEC_E_INTERNAL_ERROR; + } length = Stream_GetPosition(s); - buffer->cbBuffer = length; + WINPR_ASSERT(length <= ULONG_MAX); + buffer->cbBuffer = (ULONG)length; - if (!sspi_SecBufferAlloc(&context->NegotiateMessage, length)) - { - Stream_Free(s, FALSE); + if (!sspi_SecBufferAlloc(&context->NegotiateMessage, (ULONG)length)) return SEC_E_INTERNAL_ERROR; - } CopyMemory(context->NegotiateMessage.pvBuffer, buffer->pvBuffer, buffer->cbBuffer); context->NegotiateMessage.BufferType = buffer->BufferType; -#ifdef WITH_DEBUG_NTLM - WLog_DBG(TAG, "NEGOTIATE_MESSAGE (length = %d)", length); - winpr_HexDump(TAG, WLOG_DEBUG, Stream_Buffer(s), length); - - if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION) - ntlm_print_version_info(&(message->Version)); - +#if defined(WITH_DEBUG_NTLM) + ntlm_print_negotiate_message(&context->NegotiateMessage, message); #endif - context->state = NTLM_STATE_CHALLENGE; - Stream_Free(s, FALSE); + ntlm_change_state(context, NTLM_STATE_CHALLENGE); return SEC_I_CONTINUE_NEEDED; } SECURITY_STATUS ntlm_read_ChallengeMessage(NTLM_CONTEXT* context, PSecBuffer buffer) { SECURITY_STATUS status = SEC_E_INVALID_TOKEN; + wStream sbuffer; wStream* s; size_t length; size_t StartOffset; size_t PayloadOffset; NTLM_AV_PAIR* AvTimestamp; + const NTLM_CHALLENGE_MESSAGE empty = { 0 }; NTLM_CHALLENGE_MESSAGE* message; + if (!context || !buffer) return SEC_E_INTERNAL_ERROR; ntlm_generate_client_challenge(context); message = &context->CHALLENGE_MESSAGE; - ZeroMemory(message, sizeof(NTLM_CHALLENGE_MESSAGE)); - s = Stream_New((BYTE*)buffer->pvBuffer, buffer->cbBuffer); + WINPR_ASSERT(message); + + *message = empty; + + s = Stream_StaticConstInit(&sbuffer, buffer->pvBuffer, buffer->cbBuffer); if (!s) return SEC_E_INTERNAL_ERROR; StartOffset = Stream_GetPosition(s); - if (ntlm_read_message_header(s, (NTLM_MESSAGE_HEADER*)message) < 0) + if (!ntlm_read_message_header(s, &message->header, MESSAGE_TYPE_CHALLENGE)) goto fail; - if (message->MessageType != MESSAGE_TYPE_CHALLENGE) + if (!ntlm_read_message_fields(s, &(message->TargetName))) /* TargetNameFields (8 bytes) */ goto fail; - if (ntlm_read_message_fields(s, &(message->TargetName)) < 0) /* TargetNameFields (8 bytes) */ - goto fail; - - if (Stream_GetRemainingLength(s) < 4) + if (!ntlm_read_negotiate_flags(s, &message->NegotiateFlags, 0, "NTLM_CHALLENGE_MESSAGE")) goto fail; - Stream_Read_UINT32(s, message->NegotiateFlags); /* NegotiateFlags (4 bytes) */ context->NegotiateFlags = message->NegotiateFlags; - if (Stream_GetRemainingLength(s) < 8) + if (Stream_GetRemainingLength(s) < 16) + { + WLog_ERR(TAG, + "NTLM_CHALLENGE_MESSAGE::ServerChallenge expected 16bytes, got %" PRIuz "bytes", + Stream_GetRemainingLength(s)); goto fail; + } Stream_Read(s, message->ServerChallenge, 8); /* ServerChallenge (8 bytes) */ CopyMemory(context->ServerChallenge, message->ServerChallenge, 8); - - if (Stream_GetRemainingLength(s) < 8) - goto fail; - Stream_Read(s, message->Reserved, 8); /* Reserved (8 bytes), should be ignored */ - if (ntlm_read_message_fields(s, &(message->TargetInfo)) < 0) /* TargetInfoFields (8 bytes) */ + if (!ntlm_read_message_fields(s, &(message->TargetInfo))) /* TargetInfoFields (8 bytes) */ goto fail; if (context->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION) { - if (ntlm_read_version_info(s, &(message->Version)) < 0) /* Version (8 bytes) */ + if (!ntlm_read_version_info(s, &(message->Version))) /* Version (8 bytes) */ goto fail; } @@ -428,7 +737,7 @@ SECURITY_STATUS ntlm_read_ChallengeMessage(NTLM_CONTEXT* context, PSecBuffer buf status = SEC_E_INTERNAL_ERROR; if (message->TargetName.Len > 0) { - if (ntlm_read_message_fields_buffer(s, &(message->TargetName)) < 0) + if (!ntlm_read_message_fields_buffer(s, &(message->TargetName))) goto fail; } @@ -436,7 +745,7 @@ SECURITY_STATUS ntlm_read_ChallengeMessage(NTLM_CONTEXT* context, PSecBuffer buf { size_t cbAvTimestamp; - if (ntlm_read_message_fields_buffer(s, &(message->TargetInfo)) < 0) + if (!ntlm_read_message_fields_buffer(s, &(message->TargetInfo))) goto fail; context->ChallengeTargetInfo.pvBuffer = message->TargetInfo.Buffer; @@ -462,36 +771,19 @@ SECURITY_STATUS ntlm_read_ChallengeMessage(NTLM_CONTEXT* context, PSecBuffer buf if (length > buffer->cbBuffer) goto fail; - if (!sspi_SecBufferAlloc(&context->ChallengeMessage, length)) + if (!sspi_SecBufferAlloc(&context->ChallengeMessage, (ULONG)length)) goto fail; if (context->ChallengeMessage.pvBuffer) CopyMemory(context->ChallengeMessage.pvBuffer, Stream_Buffer(s) + StartOffset, length); -#ifdef WITH_DEBUG_NTLM - WLog_DBG(TAG, "CHALLENGE_MESSAGE (length = %d)", length); - winpr_HexDump(TAG, WLOG_DEBUG, context->ChallengeMessage.pvBuffer, - context->ChallengeMessage.cbBuffer); - ntlm_print_negotiate_flags(context->NegotiateFlags); - - if (context->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION) - ntlm_print_version_info(&(message->Version)); - - ntlm_print_message_fields(&(message->TargetName), "TargetName"); - ntlm_print_message_fields(&(message->TargetInfo), "TargetInfo"); - - if (context->ChallengeTargetInfo.cbBuffer > 0) - { - WLog_DBG(TAG, "ChallengeTargetInfo (%" PRIu32 "):", context->ChallengeTargetInfo.cbBuffer); - ntlm_print_av_pair_list(context->ChallengeTargetInfo.pvBuffer, - context->ChallengeTargetInfo.cbBuffer); - } - +#if defined(WITH_DEBUG_NTLM) + ntlm_print_challenge_message(&context->ChallengeMessage, message, NULL); #endif /* AV_PAIRs */ if (context->NTLMv2) { - if (ntlm_construct_authenticate_target_info(context) < 0) + if (!ntlm_construct_authenticate_target_info(context)) goto fail; sspi_SecBufferFree(&context->ChallengeTargetInfo); @@ -501,10 +793,10 @@ SECURITY_STATUS ntlm_read_ChallengeMessage(NTLM_CONTEXT* context, PSecBuffer buf ntlm_generate_timestamp(context); /* Timestamp */ - if (ntlm_compute_lm_v2_response(context) < 0) /* LmChallengeResponse */ + if (!ntlm_compute_lm_v2_response(context)) /* LmChallengeResponse */ goto fail; - if (ntlm_compute_ntlm_v2_response(context) < 0) /* NtChallengeResponse */ + if (!ntlm_compute_ntlm_v2_response(context)) /* NtChallengeResponse */ goto fail; ntlm_generate_key_exchange_key(context); /* KeyExchangeKey */ @@ -512,54 +804,45 @@ SECURITY_STATUS ntlm_read_ChallengeMessage(NTLM_CONTEXT* context, PSecBuffer buf ntlm_generate_exported_session_key(context); /* ExportedSessionKey */ ntlm_encrypt_random_session_key(context); /* EncryptedRandomSessionKey */ /* Generate signing keys */ - ntlm_generate_client_signing_key(context); - ntlm_generate_server_signing_key(context); + if (!ntlm_generate_client_signing_key(context)) + goto fail; + if (!ntlm_generate_server_signing_key(context)) + goto fail; /* Generate sealing keys */ - ntlm_generate_client_sealing_key(context); - ntlm_generate_server_sealing_key(context); + if (!ntlm_generate_client_sealing_key(context)) + goto fail; + if (!ntlm_generate_server_sealing_key(context)) + goto fail; /* Initialize RC4 seal state using client sealing key */ ntlm_init_rc4_seal_states(context); -#ifdef WITH_DEBUG_NTLM - WLog_DBG(TAG, "ClientChallenge"); - winpr_HexDump(TAG, WLOG_DEBUG, context->ClientChallenge, 8); - WLog_DBG(TAG, "ServerChallenge"); - winpr_HexDump(TAG, WLOG_DEBUG, context->ServerChallenge, 8); - WLog_DBG(TAG, "SessionBaseKey"); - winpr_HexDump(TAG, WLOG_DEBUG, context->SessionBaseKey, 16); - WLog_DBG(TAG, "KeyExchangeKey"); - winpr_HexDump(TAG, WLOG_DEBUG, context->KeyExchangeKey, 16); - WLog_DBG(TAG, "ExportedSessionKey"); - winpr_HexDump(TAG, WLOG_DEBUG, context->ExportedSessionKey, 16); - WLog_DBG(TAG, "RandomSessionKey"); - winpr_HexDump(TAG, WLOG_DEBUG, context->RandomSessionKey, 16); - WLog_DBG(TAG, "ClientSigningKey"); - winpr_HexDump(TAG, WLOG_DEBUG, context->ClientSigningKey, 16); - WLog_DBG(TAG, "ClientSealingKey"); - winpr_HexDump(TAG, WLOG_DEBUG, context->ClientSealingKey, 16); - WLog_DBG(TAG, "ServerSigningKey"); - winpr_HexDump(TAG, WLOG_DEBUG, context->ServerSigningKey, 16); - WLog_DBG(TAG, "ServerSealingKey"); - winpr_HexDump(TAG, WLOG_DEBUG, context->ServerSealingKey, 16); - WLog_DBG(TAG, "Timestamp"); - winpr_HexDump(TAG, WLOG_DEBUG, context->Timestamp, 8); +#if defined(WITH_DEBUG_NTLM) + ntlm_print_authentication_complete(context); #endif - context->state = NTLM_STATE_AUTHENTICATE; + ntlm_change_state(context, NTLM_STATE_AUTHENTICATE); status = SEC_I_CONTINUE_NEEDED; fail: ntlm_free_message_fields_buffer(&(message->TargetName)); - Stream_Free(s, FALSE); return status; } SECURITY_STATUS ntlm_write_ChallengeMessage(NTLM_CONTEXT* context, PSecBuffer buffer) { + wStream sbuffer; wStream* s; size_t length; UINT32 PayloadOffset; + const NTLM_CHALLENGE_MESSAGE empty = { 0 }; NTLM_CHALLENGE_MESSAGE* message; + + WINPR_ASSERT(context); + WINPR_ASSERT(buffer); + message = &context->CHALLENGE_MESSAGE; - ZeroMemory(message, sizeof(NTLM_CHALLENGE_MESSAGE)); - s = Stream_New((BYTE*)buffer->pvBuffer, buffer->cbBuffer); + WINPR_ASSERT(message); + + *message = empty; + + s = Stream_StaticInit(&sbuffer, buffer->pvBuffer, buffer->cbBuffer); if (!s) return SEC_E_INTERNAL_ERROR; @@ -568,17 +851,17 @@ SECURITY_STATUS ntlm_write_ChallengeMessage(NTLM_CONTEXT* context, PSecBuffer bu ntlm_generate_server_challenge(context); /* Server Challenge */ ntlm_generate_timestamp(context); /* Timestamp */ - if (ntlm_construct_challenge_target_info(context) < 0) /* TargetInfo */ - { - Stream_Free(s, FALSE); + if (!ntlm_construct_challenge_target_info(context)) /* TargetInfo */ return SEC_E_INTERNAL_ERROR; - } CopyMemory(message->ServerChallenge, context->ServerChallenge, 8); /* ServerChallenge */ message->NegotiateFlags = context->NegotiateFlags; - ntlm_populate_message_header((NTLM_MESSAGE_HEADER*)message, MESSAGE_TYPE_CHALLENGE); + if (!ntlm_populate_message_header(&message->header, MESSAGE_TYPE_CHALLENGE)) + return SEC_E_INTERNAL_ERROR; + /* Message Header (12 bytes) */ - ntlm_write_message_header(s, (NTLM_MESSAGE_HEADER*)message); + if (!ntlm_write_message_header(s, &message->header)) + return SEC_E_INTERNAL_ERROR; if (message->NegotiateFlags & NTLMSSP_REQUEST_TARGET) { @@ -602,99 +885,119 @@ SECURITY_STATUS ntlm_write_ChallengeMessage(NTLM_CONTEXT* context, PSecBuffer bu message->TargetName.BufferOffset = PayloadOffset; message->TargetInfo.BufferOffset = message->TargetName.BufferOffset + message->TargetName.Len; /* TargetNameFields (8 bytes) */ - ntlm_write_message_fields(s, &(message->TargetName)); - Stream_Write_UINT32(s, message->NegotiateFlags); /* NegotiateFlags (4 bytes) */ + if (!ntlm_write_message_fields(s, &(message->TargetName))) + return SEC_E_INTERNAL_ERROR; + + if (!ntlm_write_negotiate_flags(s, message->NegotiateFlags, "NTLM_CHALLENGE_MESSAGE")) + return SEC_E_INTERNAL_ERROR; + + if (Stream_GetRemainingCapacity(s) < 16) + { + WLog_ERR(TAG, + "NTLM_CHALLENGE_MESSAGE::ServerChallenge expected 16bytes, got %" PRIuz "bytes", + Stream_GetRemainingCapacity(s)); + return SEC_E_INTERNAL_ERROR; + } + Stream_Write(s, message->ServerChallenge, 8); /* ServerChallenge (8 bytes) */ Stream_Write(s, message->Reserved, 8); /* Reserved (8 bytes), should be ignored */ + /* TargetInfoFields (8 bytes) */ - ntlm_write_message_fields(s, &(message->TargetInfo)); + if (!ntlm_write_message_fields(s, &(message->TargetInfo))) + return SEC_E_INTERNAL_ERROR; if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION) - ntlm_write_version_info(s, &(message->Version)); /* Version (8 bytes) */ + { + if (!ntlm_write_version_info(s, &(message->Version))) /* Version (8 bytes) */ + return SEC_E_INTERNAL_ERROR; + } /* Payload (variable) */ - if (message->NegotiateFlags & NTLMSSP_REQUEST_TARGET) - ntlm_write_message_fields_buffer(s, &(message->TargetName)); + { + if (!ntlm_write_message_fields_buffer(s, &(message->TargetName))) + return SEC_E_INTERNAL_ERROR; + } if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_TARGET_INFO) - ntlm_write_message_fields_buffer(s, &(message->TargetInfo)); + { + if (!ntlm_write_message_fields_buffer(s, &(message->TargetInfo))) + return SEC_E_INTERNAL_ERROR; + } length = Stream_GetPosition(s); - buffer->cbBuffer = length; + WINPR_ASSERT(length <= ULONG_MAX); + buffer->cbBuffer = (ULONG)length; - if (!sspi_SecBufferAlloc(&context->ChallengeMessage, length)) - { - Stream_Free(s, FALSE); + if (!sspi_SecBufferAlloc(&context->ChallengeMessage, (ULONG)length)) return SEC_E_INTERNAL_ERROR; - } CopyMemory(context->ChallengeMessage.pvBuffer, Stream_Buffer(s), length); -#ifdef WITH_DEBUG_NTLM - WLog_DBG(TAG, "CHALLENGE_MESSAGE (length = %d)", length); - winpr_HexDump(TAG, WLOG_DEBUG, context->ChallengeMessage.pvBuffer, - context->ChallengeMessage.cbBuffer); - ntlm_print_negotiate_flags(message->NegotiateFlags); - - if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION) - ntlm_print_version_info(&(message->Version)); - - ntlm_print_message_fields(&(message->TargetName), "TargetName"); - ntlm_print_message_fields(&(message->TargetInfo), "TargetInfo"); +#if defined(WITH_DEBUG_NTLM) + ntlm_print_challenge_message(&context->ChallengeMessage, message, + &context->ChallengeTargetInfo); #endif - context->state = NTLM_STATE_AUTHENTICATE; - Stream_Free(s, FALSE); + ntlm_change_state(context, NTLM_STATE_AUTHENTICATE); return SEC_I_CONTINUE_NEEDED; } SECURITY_STATUS ntlm_read_AuthenticateMessage(NTLM_CONTEXT* context, PSecBuffer buffer) { SECURITY_STATUS status = SEC_E_INVALID_TOKEN; + wStream sbuffer; wStream* s; size_t length; UINT32 flags = 0; NTLM_AV_PAIR* AvFlags = NULL; - UINT32 PayloadBufferOffset; + size_t PayloadBufferOffset; + const NTLM_AUTHENTICATE_MESSAGE empty = { 0 }; NTLM_AUTHENTICATE_MESSAGE* message; - SSPI_CREDENTIALS* credentials = context->credentials; + SSPI_CREDENTIALS* credentials; + + WINPR_ASSERT(context); + WINPR_ASSERT(buffer); + + credentials = context->credentials; + WINPR_ASSERT(credentials); message = &context->AUTHENTICATE_MESSAGE; - ZeroMemory(message, sizeof(NTLM_AUTHENTICATE_MESSAGE)); - s = Stream_New((BYTE*)buffer->pvBuffer, buffer->cbBuffer); + WINPR_ASSERT(message); + + *message = empty; + + s = Stream_StaticConstInit(&sbuffer, buffer->pvBuffer, buffer->cbBuffer); if (!s) return SEC_E_INTERNAL_ERROR; - if (ntlm_read_message_header(s, (NTLM_MESSAGE_HEADER*)message) < 0) + if (!ntlm_read_message_header(s, &message->header, MESSAGE_TYPE_AUTHENTICATE)) goto fail; - if (message->MessageType != MESSAGE_TYPE_AUTHENTICATE) + if (!ntlm_read_message_fields( + s, &(message->LmChallengeResponse))) /* LmChallengeResponseFields (8 bytes) */ goto fail; - if (ntlm_read_message_fields(s, &(message->LmChallengeResponse)) < - 0) /* LmChallengeResponseFields (8 bytes) */ + if (!ntlm_read_message_fields( + s, &(message->NtChallengeResponse))) /* NtChallengeResponseFields (8 bytes) */ goto fail; - if (ntlm_read_message_fields(s, &(message->NtChallengeResponse)) < - 0) /* NtChallengeResponseFields (8 bytes) */ + if (!ntlm_read_message_fields(s, &(message->DomainName))) /* DomainNameFields (8 bytes) */ goto fail; - if (ntlm_read_message_fields(s, &(message->DomainName)) < 0) /* DomainNameFields (8 bytes) */ + if (!ntlm_read_message_fields(s, &(message->UserName))) /* UserNameFields (8 bytes) */ goto fail; - if (ntlm_read_message_fields(s, &(message->UserName)) < 0) /* UserNameFields (8 bytes) */ + if (!ntlm_read_message_fields(s, &(message->Workstation))) /* WorkstationFields (8 bytes) */ goto fail; - if (ntlm_read_message_fields(s, &(message->Workstation)) < 0) /* WorkstationFields (8 bytes) */ + if (!ntlm_read_message_fields( + s, + &(message->EncryptedRandomSessionKey))) /* EncryptedRandomSessionKeyFields (8 bytes) */ goto fail; - if (ntlm_read_message_fields(s, &(message->EncryptedRandomSessionKey)) < - 0) /* EncryptedRandomSessionKeyFields (8 bytes) */ + if (!ntlm_read_negotiate_flags(s, &message->NegotiateFlags, 0, "NTLM_AUTHENTICATE_MESSAGE")) goto fail; - if (Stream_GetRemainingLength(s) < 4) - goto fail; - Stream_Read_UINT32(s, message->NegotiateFlags); /* NegotiateFlags (4 bytes) */ context->NegotiateKeyExchange = (message->NegotiateFlags & NTLMSSP_NEGOTIATE_KEY_EXCH) ? TRUE : FALSE; @@ -704,44 +1007,48 @@ SECURITY_STATUS ntlm_read_AuthenticateMessage(NTLM_CONTEXT* context, PSecBuffer if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION) { - if (ntlm_read_version_info(s, &(message->Version)) < 0) /* Version (8 bytes) */ + if (!ntlm_read_version_info(s, &(message->Version))) /* Version (8 bytes) */ goto fail; } PayloadBufferOffset = Stream_GetPosition(s); status = SEC_E_INTERNAL_ERROR; - if (ntlm_read_message_fields_buffer(s, &(message->DomainName)) < 0) /* DomainName */ + if (!ntlm_read_message_fields_buffer(s, &(message->DomainName))) /* DomainName */ goto fail; - if (ntlm_read_message_fields_buffer(s, &(message->UserName)) < 0) /* UserName */ + if (!ntlm_read_message_fields_buffer(s, &(message->UserName))) /* UserName */ goto fail; - if (ntlm_read_message_fields_buffer(s, &(message->Workstation)) < 0) /* Workstation */ - goto fail; + if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED) + { + if (!ntlm_read_message_fields_buffer(s, &(message->Workstation))) /* Workstation */ + goto fail; + } - if (ntlm_read_message_fields_buffer(s, &(message->LmChallengeResponse)) < - 0) /* LmChallengeResponse */ - goto fail; + if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_LM_KEY) + { + if (!ntlm_read_message_fields_buffer( + s, &(message->LmChallengeResponse))) /* LmChallengeResponse */ + goto fail; + } - if (ntlm_read_message_fields_buffer(s, &(message->NtChallengeResponse)) < - 0) /* NtChallengeResponse */ + if (!ntlm_read_message_fields_buffer(s, + &(message->NtChallengeResponse))) /* NtChallengeResponse */ goto fail; if (message->NtChallengeResponse.Len > 0) { - int rc; size_t cbAvFlags; - wStream* snt = - Stream_New(message->NtChallengeResponse.Buffer, message->NtChallengeResponse.Len); + wStream ssbuffer; + wStream* snt = Stream_StaticConstInit(&ssbuffer, message->NtChallengeResponse.Buffer, + message->NtChallengeResponse.Len); if (!snt) goto fail; status = SEC_E_INVALID_TOKEN; - rc = ntlm_read_ntlm_v2_response(snt, &(context->NTLMv2Response)); - Stream_Free(snt, FALSE); - if (rc < 0) + if (!ntlm_read_ntlm_v2_response(snt, &(context->NTLMv2Response))) goto fail; status = SEC_E_INTERNAL_ERROR; @@ -759,8 +1066,8 @@ SECURITY_STATUS ntlm_read_AuthenticateMessage(NTLM_CONTEXT* context, PSecBuffer Data_Read_UINT32(ntlm_av_pair_get_value_pointer(AvFlags), flags); } - if (ntlm_read_message_fields_buffer(s, &(message->EncryptedRandomSessionKey)) < - 0) /* EncryptedRandomSessionKey */ + if (!ntlm_read_message_fields_buffer( + s, &(message->EncryptedRandomSessionKey))) /* EncryptedRandomSessionKey */ goto fail; if (message->EncryptedRandomSessionKey.Len > 0) @@ -773,51 +1080,28 @@ SECURITY_STATUS ntlm_read_AuthenticateMessage(NTLM_CONTEXT* context, PSecBuffer } length = Stream_GetPosition(s); + WINPR_ASSERT(length <= ULONG_MAX); - if (!sspi_SecBufferAlloc(&context->AuthenticateMessage, length)) + if (!sspi_SecBufferAlloc(&context->AuthenticateMessage, (ULONG)length)) goto fail; CopyMemory(context->AuthenticateMessage.pvBuffer, Stream_Buffer(s), length); - buffer->cbBuffer = length; + buffer->cbBuffer = (ULONG)length; Stream_SetPosition(s, PayloadBufferOffset); if (flags & MSV_AV_FLAGS_MESSAGE_INTEGRITY_CHECK) { - context->MessageIntegrityCheckOffset = (UINT32)Stream_GetPosition(s); - status = SEC_E_INVALID_TOKEN; - if (Stream_GetRemainingLength(s) < 16) + if (!ntlm_read_message_integrity_check( + s, &context->MessageIntegrityCheckOffset, message->MessageIntegrityCheck, + sizeof(message->MessageIntegrityCheck), "NTLM_AUTHENTICATE_MESSAGE")) goto fail; - - Stream_Read(s, message->MessageIntegrityCheck, 16); } status = SEC_E_INTERNAL_ERROR; -#ifdef WITH_DEBUG_NTLM - WLog_DBG(TAG, "AUTHENTICATE_MESSAGE (length = %" PRIu32 ")", - context->AuthenticateMessage.cbBuffer); - winpr_HexDump(TAG, WLOG_DEBUG, context->AuthenticateMessage.pvBuffer, - context->AuthenticateMessage.cbBuffer); - - if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION) - ntlm_print_version_info(&(message->Version)); - - ntlm_print_message_fields(&(message->DomainName), "DomainName"); - ntlm_print_message_fields(&(message->UserName), "UserName"); - ntlm_print_message_fields(&(message->Workstation), "Workstation"); - ntlm_print_message_fields(&(message->LmChallengeResponse), "LmChallengeResponse"); - ntlm_print_message_fields(&(message->NtChallengeResponse), "NtChallengeResponse"); - ntlm_print_message_fields(&(message->EncryptedRandomSessionKey), "EncryptedRandomSessionKey"); - ntlm_print_av_pair_list(context->NTLMv2Response.Challenge.AvPairs, - context->NTLMv2Response.Challenge.cbAvPairs); - - if (flags & MSV_AV_FLAGS_MESSAGE_INTEGRITY_CHECK) - { - WLog_DBG(TAG, "MessageIntegrityCheck:"); - winpr_HexDump(TAG, WLOG_DEBUG, message->MessageIntegrityCheck, 16); - } - +#if defined(WITH_DEBUG_NTLM) + ntlm_print_authenticate_message(&context->AuthenticateMessage, message, flags, NULL); #endif if (message->UserName.Len > 0) @@ -843,13 +1127,11 @@ SECURITY_STATUS ntlm_read_AuthenticateMessage(NTLM_CONTEXT* context, PSecBuffer credentials->identity.DomainLength = message->DomainName.Len / 2; } - Stream_Free(s, FALSE); /* Computations beyond this point require the NTLM hash of the password */ - context->state = NTLM_STATE_COMPLETION; + ntlm_change_state(context, NTLM_STATE_COMPLETION); return SEC_I_COMPLETE_NEEDED; fail: - Stream_Free(s, FALSE); return status; } @@ -862,14 +1144,26 @@ SECURITY_STATUS ntlm_read_AuthenticateMessage(NTLM_CONTEXT* context, PSecBuffer SECURITY_STATUS ntlm_write_AuthenticateMessage(NTLM_CONTEXT* context, PSecBuffer buffer) { + wStream sbuffer; wStream* s; size_t length; UINT32 PayloadBufferOffset; + const NTLM_AUTHENTICATE_MESSAGE empty = { 0 }; NTLM_AUTHENTICATE_MESSAGE* message; - SSPI_CREDENTIALS* credentials = context->credentials; + SSPI_CREDENTIALS* credentials; + + WINPR_ASSERT(context); + WINPR_ASSERT(buffer); + + credentials = context->credentials; + WINPR_ASSERT(credentials); + message = &context->AUTHENTICATE_MESSAGE; - ZeroMemory(message, sizeof(NTLM_AUTHENTICATE_MESSAGE)); - s = Stream_New((BYTE*)buffer->pvBuffer, buffer->cbBuffer); + WINPR_ASSERT(message); + + *message = empty; + + s = Stream_StaticInit(&sbuffer, buffer->pvBuffer, buffer->cbBuffer); if (!s) return SEC_E_INTERNAL_ERROR; @@ -948,95 +1242,103 @@ SECURITY_STATUS ntlm_write_AuthenticateMessage(NTLM_CONTEXT* context, PSecBuffer message->LmChallengeResponse.BufferOffset + message->LmChallengeResponse.Len; message->EncryptedRandomSessionKey.BufferOffset = message->NtChallengeResponse.BufferOffset + message->NtChallengeResponse.Len; - ntlm_populate_message_header((NTLM_MESSAGE_HEADER*)message, MESSAGE_TYPE_AUTHENTICATE); - ntlm_write_message_header(s, (NTLM_MESSAGE_HEADER*)message); /* Message Header (12 bytes) */ - ntlm_write_message_fields( - s, &(message->LmChallengeResponse)); /* LmChallengeResponseFields (8 bytes) */ - ntlm_write_message_fields( - s, &(message->NtChallengeResponse)); /* NtChallengeResponseFields (8 bytes) */ - ntlm_write_message_fields(s, &(message->DomainName)); /* DomainNameFields (8 bytes) */ - ntlm_write_message_fields(s, &(message->UserName)); /* UserNameFields (8 bytes) */ - ntlm_write_message_fields(s, &(message->Workstation)); /* WorkstationFields (8 bytes) */ - ntlm_write_message_fields( - s, &(message->EncryptedRandomSessionKey)); /* EncryptedRandomSessionKeyFields (8 bytes) */ - Stream_Write_UINT32(s, message->NegotiateFlags); /* NegotiateFlags (4 bytes) */ + if (!ntlm_populate_message_header(&message->header, MESSAGE_TYPE_AUTHENTICATE)) + return SEC_E_INVALID_TOKEN; + if (!ntlm_write_message_header(s, &message->header)) /* Message Header (12 bytes) */ + return SEC_E_INTERNAL_ERROR; + if (!ntlm_write_message_fields( + s, &(message->LmChallengeResponse))) /* LmChallengeResponseFields (8 bytes) */ + return SEC_E_INTERNAL_ERROR; + if (!ntlm_write_message_fields( + s, &(message->NtChallengeResponse))) /* NtChallengeResponseFields (8 bytes) */ + return SEC_E_INTERNAL_ERROR; + if (!ntlm_write_message_fields(s, &(message->DomainName))) /* DomainNameFields (8 bytes) */ + return SEC_E_INTERNAL_ERROR; + if (!ntlm_write_message_fields(s, &(message->UserName))) /* UserNameFields (8 bytes) */ + return SEC_E_INTERNAL_ERROR; + if (!ntlm_write_message_fields(s, &(message->Workstation))) /* WorkstationFields (8 bytes) */ + return SEC_E_INTERNAL_ERROR; + if (!ntlm_write_message_fields( + s, + &(message->EncryptedRandomSessionKey))) /* EncryptedRandomSessionKeyFields (8 bytes) */ + return SEC_E_INTERNAL_ERROR; + if (!ntlm_write_negotiate_flags(s, message->NegotiateFlags, "NTLM_AUTHENTICATE_MESSAGE")) + return SEC_E_INTERNAL_ERROR; if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION) - ntlm_write_version_info(s, &(message->Version)); /* Version (8 bytes) */ + { + if (!ntlm_write_version_info(s, &(message->Version))) /* Version (8 bytes) */ + return SEC_E_INTERNAL_ERROR; + } if (context->UseMIC) { - context->MessageIntegrityCheckOffset = (UINT32)Stream_GetPosition(s); - Stream_Zero(s, 16); /* Message Integrity Check (16 bytes) */ + const BYTE data[WINPR_MD5_DIGEST_LENGTH] = { 0 }; + + context->MessageIntegrityCheckOffset = Stream_GetPosition(s); + if (!ntlm_write_message_integrity_check(s, Stream_GetPosition(s), data, sizeof(data), + "NTLM_AUTHENTICATE_MESSAGE")) + return SEC_E_INTERNAL_ERROR; } if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED) - ntlm_write_message_fields_buffer(s, &(message->DomainName)); /* DomainName */ + { + if (!ntlm_write_message_fields_buffer(s, &(message->DomainName))) /* DomainName */ + return SEC_E_INTERNAL_ERROR; + } - ntlm_write_message_fields_buffer(s, &(message->UserName)); /* UserName */ + if (!ntlm_write_message_fields_buffer(s, &(message->UserName))) /* UserName */ + return SEC_E_INTERNAL_ERROR; if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED) - ntlm_write_message_fields_buffer(s, &(message->Workstation)); /* Workstation */ + { + if (!ntlm_write_message_fields_buffer(s, &(message->Workstation))) /* Workstation */ + return SEC_E_INTERNAL_ERROR; + } - ntlm_write_message_fields_buffer(s, &(message->LmChallengeResponse)); /* LmChallengeResponse */ - ntlm_write_message_fields_buffer(s, &(message->NtChallengeResponse)); /* NtChallengeResponse */ + if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_LM_KEY) + { + if (!ntlm_write_message_fields_buffer( + s, &(message->LmChallengeResponse))) /* LmChallengeResponse */ + return SEC_E_INTERNAL_ERROR; + } + if (!ntlm_write_message_fields_buffer( + s, &(message->NtChallengeResponse))) /* NtChallengeResponse */ + return SEC_E_INTERNAL_ERROR; if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_KEY_EXCH) - ntlm_write_message_fields_buffer( - s, &(message->EncryptedRandomSessionKey)); /* EncryptedRandomSessionKey */ + { + if (!ntlm_write_message_fields_buffer( + s, &(message->EncryptedRandomSessionKey))) /* EncryptedRandomSessionKey */ + return SEC_E_INTERNAL_ERROR; + } length = Stream_GetPosition(s); + WINPR_ASSERT(length <= ULONG_MAX); - if (!sspi_SecBufferAlloc(&context->AuthenticateMessage, length)) - { - Stream_Free(s, FALSE); + if (!sspi_SecBufferAlloc(&context->AuthenticateMessage, (ULONG)length)) return SEC_E_INTERNAL_ERROR; - } CopyMemory(context->AuthenticateMessage.pvBuffer, Stream_Buffer(s), length); - buffer->cbBuffer = length; + buffer->cbBuffer = (ULONG)length; if (context->UseMIC) { /* Message Integrity Check */ - ntlm_compute_message_integrity_check(context, message->MessageIntegrityCheck, 16); - Stream_SetPosition(s, context->MessageIntegrityCheckOffset); - Stream_Write(s, message->MessageIntegrityCheck, 16); - Stream_SetPosition(s, length); - } - -#ifdef WITH_DEBUG_NTLM - WLog_DBG(TAG, "AUTHENTICATE_MESSAGE (length = %d)", length); - winpr_HexDump(TAG, WLOG_DEBUG, Stream_Buffer(s), length); - ntlm_print_negotiate_flags(message->NegotiateFlags); - - if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_VERSION) - ntlm_print_version_info(&(message->Version)); - - if (context->AuthenticateTargetInfo.cbBuffer > 0) - { - WLog_DBG(TAG, - "AuthenticateTargetInfo (%" PRIu32 "):", context->AuthenticateTargetInfo.cbBuffer); - ntlm_print_av_pair_list(context->AuthenticateTargetInfo.pvBuffer, - context->AuthenticateTargetInfo.cbBuffer); - } - - ntlm_print_message_fields(&(message->DomainName), "DomainName"); - ntlm_print_message_fields(&(message->UserName), "UserName"); - ntlm_print_message_fields(&(message->Workstation), "Workstation"); - ntlm_print_message_fields(&(message->LmChallengeResponse), "LmChallengeResponse"); - ntlm_print_message_fields(&(message->NtChallengeResponse), "NtChallengeResponse"); - ntlm_print_message_fields(&(message->EncryptedRandomSessionKey), "EncryptedRandomSessionKey"); - - if (context->UseMIC) - { - WLog_DBG(TAG, "MessageIntegrityCheck (length = 16)"); - winpr_HexDump(TAG, WLOG_DEBUG, message->MessageIntegrityCheck, 16); + ntlm_compute_message_integrity_check(context, message->MessageIntegrityCheck, + sizeof(message->MessageIntegrityCheck)); + if (!ntlm_write_message_integrity_check( + s, context->MessageIntegrityCheckOffset, message->MessageIntegrityCheck, + sizeof(message->MessageIntegrityCheck), "NTLM_AUTHENTICATE_MESSAGE")) + return SEC_E_INTERNAL_ERROR; } +#if defined(WITH_DEBUG_NTLM) + ntlm_print_authenticate_message(&context->AuthenticateMessage, message, + context->UseMIC ? MSV_AV_FLAGS_MESSAGE_INTEGRITY_CHECK : 0, + &context->AuthenticateTargetInfo); #endif - context->state = NTLM_STATE_FINAL; - Stream_Free(s, FALSE); + ntlm_change_state(context, NTLM_STATE_FINAL); return SEC_E_OK; } @@ -1046,25 +1348,26 @@ SECURITY_STATUS ntlm_server_AuthenticateComplete(NTLM_CONTEXT* context) size_t cbAvFlags; NTLM_AV_PAIR* AvFlags = NULL; NTLM_AUTHENTICATE_MESSAGE* message; - BYTE messageIntegrityCheck[16]; if (!context) return SEC_E_INVALID_PARAMETER; - if (context->state != NTLM_STATE_COMPLETION) + if (ntlm_get_state(context) != NTLM_STATE_COMPLETION) return SEC_E_OUT_OF_SEQUENCE; message = &context->AUTHENTICATE_MESSAGE; + WINPR_ASSERT(message); + AvFlags = ntlm_av_pair_get(context->NTLMv2Response.Challenge.AvPairs, context->NTLMv2Response.Challenge.cbAvPairs, MsvAvFlags, &cbAvFlags); if (AvFlags) Data_Read_UINT32(ntlm_av_pair_get_value_pointer(AvFlags), flags); - if (ntlm_compute_lm_v2_response(context) < 0) /* LmChallengeResponse */ + if (!ntlm_compute_lm_v2_response(context)) /* LmChallengeResponse */ return SEC_E_INTERNAL_ERROR; - if (ntlm_compute_ntlm_v2_response(context) < 0) /* NtChallengeResponse */ + if (!ntlm_compute_ntlm_v2_response(context)) /* NtChallengeResponse */ return SEC_E_INTERNAL_ERROR; /* KeyExchangeKey */ @@ -1076,16 +1379,16 @@ SECURITY_STATUS ntlm_server_AuthenticateComplete(NTLM_CONTEXT* context) if (flags & MSV_AV_FLAGS_MESSAGE_INTEGRITY_CHECK) { - ZeroMemory( - &((PBYTE)context->AuthenticateMessage.pvBuffer)[context->MessageIntegrityCheckOffset], - 16); + BYTE messageIntegrityCheck[16] = { 0 }; + ntlm_compute_message_integrity_check(context, messageIntegrityCheck, sizeof(messageIntegrityCheck)); CopyMemory( &((PBYTE)context->AuthenticateMessage.pvBuffer)[context->MessageIntegrityCheckOffset], - message->MessageIntegrityCheck, 16); + message->MessageIntegrityCheck, sizeof(message->MessageIntegrityCheck)); - if (memcmp(messageIntegrityCheck, message->MessageIntegrityCheck, 16) != 0) + if (memcmp(messageIntegrityCheck, message->MessageIntegrityCheck, + sizeof(message->MessageIntegrityCheck)) != 0) { WLog_ERR(TAG, "Message Integrity Check (MIC) verification failed!"); #ifdef WITH_DEBUG_NTLM @@ -1111,7 +1414,7 @@ SECURITY_STATUS ntlm_server_AuthenticateComplete(NTLM_CONTEXT* context) */ #ifdef WITH_DEBUG_NTLM - WLog_DBG(TAG, "No MIC present, using NtProofString for verification."); + WLog_VRB(TAG, "No MIC present, using NtProofString for verification."); #endif if (memcmp(context->NTLMv2Response.Response, context->NtProofString, 16) != 0) @@ -1129,38 +1432,21 @@ SECURITY_STATUS ntlm_server_AuthenticateComplete(NTLM_CONTEXT* context) } /* Generate signing keys */ - ntlm_generate_client_signing_key(context); - ntlm_generate_server_signing_key(context); + if (!ntlm_generate_client_signing_key(context)) + return SEC_E_INTERNAL_ERROR; + if (!ntlm_generate_server_signing_key(context)) + return SEC_E_INTERNAL_ERROR; /* Generate sealing keys */ - ntlm_generate_client_sealing_key(context); - ntlm_generate_server_sealing_key(context); + if (!ntlm_generate_client_sealing_key(context)) + return SEC_E_INTERNAL_ERROR; + if (!ntlm_generate_server_sealing_key(context)) + return SEC_E_INTERNAL_ERROR; /* Initialize RC4 seal state */ ntlm_init_rc4_seal_states(context); -#ifdef WITH_DEBUG_NTLM - WLog_DBG(TAG, "ClientChallenge"); - winpr_HexDump(TAG, WLOG_DEBUG, context->ClientChallenge, 8); - WLog_DBG(TAG, "ServerChallenge"); - winpr_HexDump(TAG, WLOG_DEBUG, context->ServerChallenge, 8); - WLog_DBG(TAG, "SessionBaseKey"); - winpr_HexDump(TAG, WLOG_DEBUG, context->SessionBaseKey, 16); - WLog_DBG(TAG, "KeyExchangeKey"); - winpr_HexDump(TAG, WLOG_DEBUG, context->KeyExchangeKey, 16); - WLog_DBG(TAG, "ExportedSessionKey"); - winpr_HexDump(TAG, WLOG_DEBUG, context->ExportedSessionKey, 16); - WLog_DBG(TAG, "RandomSessionKey"); - winpr_HexDump(TAG, WLOG_DEBUG, context->RandomSessionKey, 16); - WLog_DBG(TAG, "ClientSigningKey"); - winpr_HexDump(TAG, WLOG_DEBUG, context->ClientSigningKey, 16); - WLog_DBG(TAG, "ClientSealingKey"); - winpr_HexDump(TAG, WLOG_DEBUG, context->ClientSealingKey, 16); - WLog_DBG(TAG, "ServerSigningKey"); - winpr_HexDump(TAG, WLOG_DEBUG, context->ServerSigningKey, 16); - WLog_DBG(TAG, "ServerSealingKey"); - winpr_HexDump(TAG, WLOG_DEBUG, context->ServerSealingKey, 16); - WLog_DBG(TAG, "Timestamp"); - winpr_HexDump(TAG, WLOG_DEBUG, context->Timestamp, 8); +#if defined(WITH_DEBUG_NTLM) + ntlm_print_authentication_complete(context); #endif - context->state = NTLM_STATE_FINAL; + ntlm_change_state(context, NTLM_STATE_FINAL); ntlm_free_message_fields_buffer(&(message->DomainName)); ntlm_free_message_fields_buffer(&(message->UserName)); ntlm_free_message_fields_buffer(&(message->Workstation)); diff --git a/winpr/libwinpr/sspi/NTLM/ntlm_message.h b/winpr/libwinpr/sspi/NTLM/ntlm_message.h index 100d95a8ec08..58ff35dd5a6a 100644 --- a/winpr/libwinpr/sspi/NTLM/ntlm_message.h +++ b/winpr/libwinpr/sspi/NTLM/ntlm_message.h @@ -23,12 +23,14 @@ #include "ntlm.h" SECURITY_STATUS ntlm_read_NegotiateMessage(NTLM_CONTEXT* context, PSecBuffer buffer); -SECURITY_STATUS ntlm_write_NegotiateMessage(NTLM_CONTEXT* context, PSecBuffer buffer); +SECURITY_STATUS ntlm_write_NegotiateMessage(NTLM_CONTEXT* context, const PSecBuffer buffer); SECURITY_STATUS ntlm_read_ChallengeMessage(NTLM_CONTEXT* context, PSecBuffer buffer); -SECURITY_STATUS ntlm_write_ChallengeMessage(NTLM_CONTEXT* context, PSecBuffer buffer); +SECURITY_STATUS ntlm_write_ChallengeMessage(NTLM_CONTEXT* context, const PSecBuffer buffer); SECURITY_STATUS ntlm_read_AuthenticateMessage(NTLM_CONTEXT* context, PSecBuffer buffer); -SECURITY_STATUS ntlm_write_AuthenticateMessage(NTLM_CONTEXT* context, PSecBuffer buffer); +SECURITY_STATUS ntlm_write_AuthenticateMessage(NTLM_CONTEXT* context, const PSecBuffer buffer); SECURITY_STATUS ntlm_server_AuthenticateComplete(NTLM_CONTEXT* context); +const char* ntlm_get_negotiate_string(UINT32 flag); + #endif /* WINPR_SSPI_NTLM_MESSAGE_H */ diff --git a/winpr/libwinpr/sspi/test/TestNTLM.c b/winpr/libwinpr/sspi/test/TestNTLM.c index 82d266fe6031..9260bf0df647 100644 --- a/winpr/libwinpr/sspi/test/TestNTLM.c +++ b/winpr/libwinpr/sspi/test/TestNTLM.c @@ -467,18 +467,15 @@ void test_ntlm_server_free(TEST_NTLM_SERVER* ntlm) free(ntlm); } -int TestNTLM(int argc, char* argv[]) +static BOOL test_default(void) { int status; - int rc = -1; + BOOL rc = FALSE; PSecBuffer pSecBuffer; TEST_NTLM_CLIENT* client = NULL; TEST_NTLM_SERVER* server = NULL; BOOL DynamicTest = TRUE; - WINPR_UNUSED(argc); - WINPR_UNUSED(argv); - /** * Client Initialization */ @@ -684,7 +681,7 @@ int TestNTLM(int argc, char* argv[]) goto fail; } - rc = 0; + rc = TRUE; fail: /** @@ -694,3 +691,13 @@ int TestNTLM(int argc, char* argv[]) test_ntlm_server_free(server); return rc; } + +int TestNTLM(int argc, char* argv[]) +{ + WINPR_UNUSED(argc); + WINPR_UNUSED(argv); + + if (!test_default()) + return -1; + return 0; +} From 34e851209a742a67604191759730bef3c332ebcd Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Tue, 22 Mar 2022 09:51:08 +0100 Subject: [PATCH 114/496] Removed unnecessary assert (cherry picked from commit 4b1427639a9e29f911d92c0f33175e191cd5a503) --- winpr/libwinpr/sspi/NTLM/ntlm_compute.c | 1 - 1 file changed, 1 deletion(-) diff --git a/winpr/libwinpr/sspi/NTLM/ntlm_compute.c b/winpr/libwinpr/sspi/NTLM/ntlm_compute.c index 5360a2c16389..202240b13f48 100644 --- a/winpr/libwinpr/sspi/NTLM/ntlm_compute.c +++ b/winpr/libwinpr/sspi/NTLM/ntlm_compute.c @@ -656,7 +656,6 @@ void ntlm_generate_random_session_key(NTLM_CONTEXT* context) void ntlm_generate_exported_session_key(NTLM_CONTEXT* context) { WINPR_ASSERT(context); - WINPR_ASSERT(sizeof(context->ExportedSessionKey) == sizeof(context->RandomSessionKey)); CopyMemory(context->ExportedSessionKey, context->RandomSessionKey, sizeof(context->ExportedSessionKey)); From 269ebb8cada3fef6b6cabfa5a1ea98ff4abbb99e Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Mon, 28 Mar 2022 10:32:08 +0200 Subject: [PATCH 115/496] Fixed NTLM flag handling * NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED and NTLMSSP_NEGOTIATE_DOMAIN_SUPPLIED * Problem with clients not supporting NTLMSSP_NEGOTIATE_LM_KEY * Improve logging (cherry picked from commit 3c657d58cd0e7c2398b5488902ecf77bdb2eb8d8) --- winpr/libwinpr/sspi/NTLM/ntlm.c | 35 ++++++++++++++----------- winpr/libwinpr/sspi/NTLM/ntlm_message.c | 26 +++++++++++++----- 2 files changed, 39 insertions(+), 22 deletions(-) diff --git a/winpr/libwinpr/sspi/NTLM/ntlm.c b/winpr/libwinpr/sspi/NTLM/ntlm.c index c0af65b898f0..e18fea2470aa 100644 --- a/winpr/libwinpr/sspi/NTLM/ntlm.c +++ b/winpr/libwinpr/sspi/NTLM/ntlm.c @@ -1289,26 +1289,31 @@ char* ntlm_negotiate_flags_string(char* buffer, size_t size, UINT32 flags) if (!buffer || (size == 0)) return buffer; - for (x = 0; x < 31; x++) - { - size_t len = strnlen(buffer, size); - if (flags & x) + snprintf(buffer, size, "[0x%08" PRIx32 "] ", flags); + + for (x = 0; x < 31; x++) { - const char* str = ntlm_get_negotiate_string(1 << x); - size_t flen = strlen(str); - if (len > 0) + const UINT32 mask = 1 << x; + size_t len = strnlen(buffer, size); + if (flags & mask) { - if (size - len < 1) + const char* str = ntlm_get_negotiate_string(mask); + const size_t flen = strlen(str); + + if ((len > 0) && (buffer[len - 1] != ' ')) + { + if (size - len < 1) + break; + strcat(buffer, "|"); + len++; + } + + if (size - len < flen) break; - strcat(buffer, "|"); - len++; + strcat(buffer, str); } - - if (size - len < flen) - break; - strcat(buffer, str); } - } + return buffer; } diff --git a/winpr/libwinpr/sspi/NTLM/ntlm_message.c b/winpr/libwinpr/sspi/NTLM/ntlm_message.c index 7f3779d16c60..442b9fe7392e 100644 --- a/winpr/libwinpr/sspi/NTLM/ntlm_message.c +++ b/winpr/libwinpr/sspi/NTLM/ntlm_message.c @@ -417,6 +417,7 @@ static void ntlm_free_message_fields_buffer(NTLM_MESSAGE_FIELDS* fields) static BOOL ntlm_read_negotiate_flags(wStream* s, UINT32* flags, UINT32 required, const char* name) { UINT32 NegotiateFlags = 0; + char buffer[1024] = { 0 }; WINPR_ASSERT(s); WINPR_ASSERT(flags); WINPR_ASSERT(name); @@ -436,12 +437,16 @@ static BOOL ntlm_read_negotiate_flags(wStream* s, UINT32* flags, UINT32 required name, NegotiateFlags, required); return FALSE; } + + WLog_DBG(TAG, "Read flags %s", + ntlm_negotiate_flags_string(buffer, ARRAYSIZE(buffer), NegotiateFlags)); *flags = NegotiateFlags; return TRUE; } static BOOL ntlm_write_negotiate_flags(wStream* s, UINT32 flags, const char* name) { + char buffer[1024] = { 0 }; WINPR_ASSERT(s); WINPR_ASSERT(name); @@ -452,6 +457,7 @@ static BOOL ntlm_write_negotiate_flags(wStream* s, UINT32 flags, const char* nam return FALSE; } + WLog_DBG(TAG, "Write flags %s", ntlm_negotiate_flags_string(buffer, ARRAYSIZE(buffer), flags)); Stream_Write_UINT32(s, flags); /* NegotiateFlags (4 bytes) */ return TRUE; } @@ -565,6 +571,12 @@ SECURITY_STATUS ntlm_read_NegotiateMessage(NTLM_CONTEXT* context, PSecBuffer buf return SEC_E_INVALID_TOKEN; } + if (!ntlm_read_message_fields_buffer(s, &message->DomainName)) + return SEC_E_INVALID_TOKEN; + + if (!ntlm_read_message_fields_buffer(s, &message->Workstation)) + return SEC_E_INVALID_TOKEN; + length = Stream_GetPosition(s); WINPR_ASSERT(length <= ULONG_MAX); buffer->cbBuffer = (ULONG)length; @@ -1020,11 +1032,8 @@ SECURITY_STATUS ntlm_read_AuthenticateMessage(NTLM_CONTEXT* context, PSecBuffer if (!ntlm_read_message_fields_buffer(s, &(message->UserName))) /* UserName */ goto fail; - if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_WORKSTATION_SUPPLIED) - { - if (!ntlm_read_message_fields_buffer(s, &(message->Workstation))) /* Workstation */ - goto fail; - } + if (!ntlm_read_message_fields_buffer(s, &(message->Workstation))) /* Workstation */ + goto fail; if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_LM_KEY) { @@ -1364,8 +1373,11 @@ SECURITY_STATUS ntlm_server_AuthenticateComplete(NTLM_CONTEXT* context) if (AvFlags) Data_Read_UINT32(ntlm_av_pair_get_value_pointer(AvFlags), flags); - if (!ntlm_compute_lm_v2_response(context)) /* LmChallengeResponse */ - return SEC_E_INTERNAL_ERROR; + if (context->NegotiateFlags & NTLMSSP_NEGOTIATE_LM_KEY) + { + if (!ntlm_compute_lm_v2_response(context)) /* LmChallengeResponse */ + return SEC_E_INTERNAL_ERROR; + } if (!ntlm_compute_ntlm_v2_response(context)) /* NtChallengeResponse */ return SEC_E_INTERNAL_ERROR; From 061edc109fb1a4e161094adc6915eae84801611c Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Mon, 28 Mar 2022 12:08:59 +0200 Subject: [PATCH 116/496] Fixed backport compile problems --- libfreerdp/core/settings.c | 10 ++-------- winpr/libwinpr/sspi/NTLM/ntlm.c | 1 + winpr/libwinpr/sspi/NTLM/ntlm.h | 2 +- winpr/libwinpr/sspi/NTLM/ntlm_message.c | 18 +++++++++++++++--- 4 files changed, 19 insertions(+), 12 deletions(-) diff --git a/libfreerdp/core/settings.c b/libfreerdp/core/settings.c index bd259d674a51..f4b58780517b 100644 --- a/libfreerdp/core/settings.c +++ b/libfreerdp/core/settings.c @@ -401,15 +401,9 @@ rdpSettings* freerdp_settings_new(DWORD flags) if (!settings->ClientProductId) goto out_fail; - settings->ClientHostname = calloc(1, 32); - - if (!settings->ClientHostname) - goto out_fail; - DWORD size = 31; - GetComputerNameA(ClientHostname, &size); - if (!freerdp_settings_set_string(settings, FreeRDP_ClientHostname, ClientHostname)) + if (!freerdp_settings_set_string(settings, FreeRDP_ClientHostname, settings->ComputerName)) goto out_fail; - settings->ClientHostname[31] = 0; + settings->ColorPointerFlag = TRUE; settings->LargePointerFlag = (LARGE_POINTER_FLAG_96x96 | LARGE_POINTER_FLAG_384x384); settings->PointerCacheSize = 20; diff --git a/winpr/libwinpr/sspi/NTLM/ntlm.c b/winpr/libwinpr/sspi/NTLM/ntlm.c index e18fea2470aa..22c8af9edb67 100644 --- a/winpr/libwinpr/sspi/NTLM/ntlm.c +++ b/winpr/libwinpr/sspi/NTLM/ntlm.c @@ -22,6 +22,7 @@ #endif #include +#include #include #include #include diff --git a/winpr/libwinpr/sspi/NTLM/ntlm.h b/winpr/libwinpr/sspi/NTLM/ntlm.h index d4db9ebe0053..a9fe5c2b0b5b 100644 --- a/winpr/libwinpr/sspi/NTLM/ntlm.h +++ b/winpr/libwinpr/sspi/NTLM/ntlm.h @@ -89,7 +89,7 @@ enum _NTLM_AV_ID MsvAvTimestamp, MsvAvSingleHost, MsvAvTargetName, - MsvChannelBindings + MsvAvChannelBindings }; typedef enum _NTLM_AV_ID NTLM_AV_ID; diff --git a/winpr/libwinpr/sspi/NTLM/ntlm_message.c b/winpr/libwinpr/sspi/NTLM/ntlm_message.c index 442b9fe7392e..0a546d4f6213 100644 --- a/winpr/libwinpr/sspi/NTLM/ntlm_message.c +++ b/winpr/libwinpr/sspi/NTLM/ntlm_message.c @@ -37,6 +37,18 @@ #include "../../log.h" #define TAG WINPR_TAG("sspi.NTLM") +static wStream* Stream_StaticConstInit(wStream* buffer, const BYTE* data, size_t size) +{ + Stream_StaticInit(buffer, data, size); + return buffer; +} + +static wStream* Stream_StaticInit2(wStream* buffer, BYTE* data, size_t size) +{ + Stream_StaticInit(buffer, data, size); + return buffer; +} + static const char NTLM_SIGNATURE[8] = { 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0' }; const char* ntlm_get_negotiate_string(UINT32 flag) @@ -609,7 +621,7 @@ SECURITY_STATUS ntlm_write_NegotiateMessage(NTLM_CONTEXT* context, PSecBuffer bu *message = empty; - s = Stream_StaticInit(&sbuffer, buffer->pvBuffer, buffer->cbBuffer); + s = Stream_StaticInit2(&sbuffer, buffer->pvBuffer, buffer->cbBuffer); if (!s) return SEC_E_INTERNAL_ERROR; @@ -854,7 +866,7 @@ SECURITY_STATUS ntlm_write_ChallengeMessage(NTLM_CONTEXT* context, PSecBuffer bu *message = empty; - s = Stream_StaticInit(&sbuffer, buffer->pvBuffer, buffer->cbBuffer); + s = Stream_StaticInit2(&sbuffer, buffer->pvBuffer, buffer->cbBuffer); if (!s) return SEC_E_INTERNAL_ERROR; @@ -1172,7 +1184,7 @@ SECURITY_STATUS ntlm_write_AuthenticateMessage(NTLM_CONTEXT* context, PSecBuffer *message = empty; - s = Stream_StaticInit(&sbuffer, buffer->pvBuffer, buffer->cbBuffer); + s = Stream_StaticInit2(&sbuffer, buffer->pvBuffer, buffer->cbBuffer); if (!s) return SEC_E_INTERNAL_ERROR; From 49780f6306da7f0dec670c125679a15dbc368d7b Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Mon, 28 Mar 2022 12:09:24 +0200 Subject: [PATCH 117/496] Updated changelog --- ChangeLog | 1 + 1 file changed, 1 insertion(+) diff --git a/ChangeLog b/ChangeLog index 3e41b9f389b1..14c8bd562c1f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,7 @@ # 2022-XX-YY Version 2.X.Y Noteworthy changes: +* Backported various NTLM fixes * Backported WINPR_ASSERT to ease future backports Fixed issues: From 311558c964626701bd19b2e216cbe85a5df25377 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Tue, 30 Nov 2021 08:52:31 +0100 Subject: [PATCH 118/496] Fixed missing return check (cherry picked from commit 46c78cf0f07180258928c16e804aab8bca866a62) --- winpr/libwinpr/sspi/NTLM/ntlm.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/winpr/libwinpr/sspi/NTLM/ntlm.c b/winpr/libwinpr/sspi/NTLM/ntlm.c index 22c8af9edb67..98a130bac259 100644 --- a/winpr/libwinpr/sspi/NTLM/ntlm.c +++ b/winpr/libwinpr/sspi/NTLM/ntlm.c @@ -604,6 +604,9 @@ static SECURITY_STATUS SEC_ENTRY ntlm_InitializeSecurityContextW( { status = ntlm_read_ChallengeMessage(context, input_buffer); + if (status != SEC_I_CONTINUE_NEEDED) + return status; + if (!pOutput) return SEC_E_INVALID_TOKEN; From c8dced590560fcf7dda974d4216c48197ad86de2 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Mon, 28 Mar 2022 11:52:52 +0200 Subject: [PATCH 119/496] Fixed windows build (_snpnrintf) (cherry picked from commit 6cccc95691ae015e9f30121a3d70f9286724413f) --- winpr/libwinpr/sspi/NTLM/ntlm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/winpr/libwinpr/sspi/NTLM/ntlm.c b/winpr/libwinpr/sspi/NTLM/ntlm.c index 98a130bac259..372e6fb9957e 100644 --- a/winpr/libwinpr/sspi/NTLM/ntlm.c +++ b/winpr/libwinpr/sspi/NTLM/ntlm.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -1293,7 +1294,7 @@ char* ntlm_negotiate_flags_string(char* buffer, size_t size, UINT32 flags) if (!buffer || (size == 0)) return buffer; - snprintf(buffer, size, "[0x%08" PRIx32 "] ", flags); + _snprintf(buffer, size, "[0x%08" PRIx32 "] ", flags); for (x = 0; x < 31; x++) { From 5249f61b7235becd602fd68ef6a2dc8efd21a6f7 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Mon, 28 Mar 2022 12:58:19 +0200 Subject: [PATCH 120/496] Fixed missing field read. (cherry picked from commit cb538114ed0e0739ccc6c65754462265ba1072ed) --- winpr/libwinpr/sspi/NTLM/ntlm_message.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/winpr/libwinpr/sspi/NTLM/ntlm_message.c b/winpr/libwinpr/sspi/NTLM/ntlm_message.c index 0a546d4f6213..ccb2e1078642 100644 --- a/winpr/libwinpr/sspi/NTLM/ntlm_message.c +++ b/winpr/libwinpr/sspi/NTLM/ntlm_message.c @@ -51,6 +51,8 @@ static wStream* Stream_StaticInit2(wStream* buffer, BYTE* data, size_t size) static const char NTLM_SIGNATURE[8] = { 'N', 'T', 'L', 'M', 'S', 'S', 'P', '\0' }; +static void ntlm_free_message_fields_buffer(NTLM_MESSAGE_FIELDS* fields); + const char* ntlm_get_negotiate_string(UINT32 flag) { if (flag & NTLMSSP_NEGOTIATE_56) @@ -322,6 +324,8 @@ static BOOL ntlm_read_message_fields(wStream* s, NTLM_MESSAGE_FIELDS* fields) return FALSE; } + ntlm_free_message_fields_buffer(fields); + Stream_Read_UINT16(s, fields->Len); /* Len (2 bytes) */ Stream_Read_UINT16(s, fields->MaxLen); /* MaxLen (2 bytes) */ Stream_Read_UINT32(s, fields->BufferOffset); /* BufferOffset (4 bytes) */ @@ -411,7 +415,7 @@ static BOOL ntlm_write_message_fields_buffer(wStream* s, const NTLM_MESSAGE_FIEL return TRUE; } -static void ntlm_free_message_fields_buffer(NTLM_MESSAGE_FIELDS* fields) +void ntlm_free_message_fields_buffer(NTLM_MESSAGE_FIELDS* fields) { if (fields) { @@ -1047,12 +1051,9 @@ SECURITY_STATUS ntlm_read_AuthenticateMessage(NTLM_CONTEXT* context, PSecBuffer if (!ntlm_read_message_fields_buffer(s, &(message->Workstation))) /* Workstation */ goto fail; - if (message->NegotiateFlags & NTLMSSP_NEGOTIATE_LM_KEY) - { - if (!ntlm_read_message_fields_buffer( - s, &(message->LmChallengeResponse))) /* LmChallengeResponse */ - goto fail; - } + if (!ntlm_read_message_fields_buffer(s, + &(message->LmChallengeResponse))) /* LmChallengeResponse */ + goto fail; if (!ntlm_read_message_fields_buffer(s, &(message->NtChallengeResponse))) /* NtChallengeResponse */ From a923f59c2023fcfc84751d836defe4cafbdcaac7 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Wed, 6 Apr 2022 10:10:07 +0200 Subject: [PATCH 121/496] Fixed #7745: Progressive surface cleanup (cherry picked from commit edcb8284e79e1bf96e6e908f869b2d4985657cfa) --- libfreerdp/codec/progressive.c | 50 +++++++++++----------------------- 1 file changed, 16 insertions(+), 34 deletions(-) diff --git a/libfreerdp/codec/progressive.c b/libfreerdp/codec/progressive.c index 5fc98f1690bd..a9e39d2c824e 100644 --- a/libfreerdp/codec/progressive.c +++ b/libfreerdp/codec/progressive.c @@ -368,13 +368,11 @@ static INLINE PROGRESSIVE_SURFACE_CONTEXT* progressive_get_surface_data(PROGRESSIVE_CONTEXT* progressive, UINT16 surfaceId) { void* key = (void*)(((ULONG_PTR)surfaceId) + 1); - void* pData = NULL; if (!progressive) return NULL; - pData = HashTable_GetItemValue(progressive->SurfaceContexts, key); - return pData; + return HashTable_GetItemValue(progressive->SurfaceContexts, key); } static void progressive_tile_free(RFX_PROGRESSIVE_TILE* tile) @@ -387,10 +385,14 @@ static void progressive_tile_free(RFX_PROGRESSIVE_TILE* tile) } } -static void progressive_surface_context_free(PROGRESSIVE_SURFACE_CONTEXT* surface) +static void progressive_surface_context_free(void* ptr) { + PROGRESSIVE_SURFACE_CONTEXT* surface = ptr; UINT32 index; + if (!surface) + return; + for (index = 0; index < surface->gridSize; index++) { RFX_PROGRESSIVE_TILE* tile = &(surface->tiles[index]); @@ -610,13 +612,7 @@ INT32 progressive_create_surface_context(PROGRESSIVE_CONTEXT* progressive, UINT1 int progressive_delete_surface_context(PROGRESSIVE_CONTEXT* progressive, UINT16 surfaceId) { - PROGRESSIVE_SURFACE_CONTEXT* surface = progressive_get_surface_data(progressive, surfaceId); - - if (surface) - { - progressive_set_surface_data(progressive, surfaceId, NULL); - progressive_surface_context_free(surface); - } + progressive_set_surface_data(progressive, surfaceId, NULL); return 1; } @@ -1111,7 +1107,7 @@ static INLINE INT16 progressive_rfx_srl_read(RFX_PROGRESSIVE_UPGRADE_STATE* stat if (k) { bs->mask = ((1 << k) - 1); - state->nz = ((bs->accumulator >> (32 - k)) & bs->mask); + state->nz = ((bs->accumulator >> (32u - k)) & bs->mask); BitStream_Shift(bs, k); } @@ -1663,6 +1659,9 @@ static void CALLBACK progressive_process_tiles_tile_work_callback(PTP_CALLBACK_I { PROGRESSIVE_TILE_PROCESS_WORK_PARAM* param = (PROGRESSIVE_TILE_PROCESS_WORK_PARAM*)context; + WINPR_UNUSED(instance); + WINPR_UNUSED(work); + switch (param->tile->blockType) { case PROGRESSIVE_WBT_TILE_SIMPLE: @@ -2398,8 +2397,8 @@ INT32 progressive_decompress_ex(PROGRESSIVE_CONTEXT* progressive, const BYTE* pS { RECTANGLE_16 clippingRect; const RFX_RECT* rect = &(region->rects[i]); - clippingRect.left = nXDst + rect->x; - clippingRect.top = nYDst + rect->y; + clippingRect.left = (UINT16)nXDst + rect->x; + clippingRect.top = (UINT16)nYDst + rect->y; clippingRect.right = clippingRect.left + rect->width; clippingRect.bottom = clippingRect.top + rect->height; region16_union_rect(&clippingRects, &clippingRects, &clippingRect); @@ -2742,6 +2741,8 @@ PROGRESSIVE_CONTEXT* progressive_context_new(BOOL Compressor) if (!progressive_context_reset(progressive)) goto fail; + progressive->SurfaceContexts->valueFree = progressive_surface_context_free; + return progressive; fail: progressive_context_free(progressive); @@ -2750,11 +2751,6 @@ PROGRESSIVE_CONTEXT* progressive_context_new(BOOL Compressor) void progressive_context_free(PROGRESSIVE_CONTEXT* progressive) { - int count; - int index; - ULONG_PTR* pKeys = NULL; - PROGRESSIVE_SURFACE_CONTEXT* surface; - if (!progressive) return; @@ -2763,21 +2759,7 @@ void progressive_context_free(PROGRESSIVE_CONTEXT* progressive) rfx_context_free(progressive->rfx_context); BufferPool_Free(progressive->bufferPool); - - if (progressive->SurfaceContexts) - { - count = HashTable_GetKeys(progressive->SurfaceContexts, &pKeys); - - for (index = 0; index < count; index++) - { - surface = (PROGRESSIVE_SURFACE_CONTEXT*)HashTable_GetItemValue( - progressive->SurfaceContexts, (void*)pKeys[index]); - progressive_surface_context_free(surface); - } - - free(pKeys); - HashTable_Free(progressive->SurfaceContexts); - } + HashTable_Free(progressive->SurfaceContexts); free(progressive); } From b836f72dedfdfc4d72441a82cb4810418faca83f Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Wed, 6 Apr 2022 10:45:06 +0200 Subject: [PATCH 122/496] Updated changelog --- ChangeLog | 1 + 1 file changed, 1 insertion(+) diff --git a/ChangeLog b/ChangeLog index 14c8bd562c1f..f051626f4473 100644 --- a/ChangeLog +++ b/ChangeLog @@ -7,6 +7,7 @@ Noteworthy changes: Fixed issues: * Backported #6786: Use /network:auto by default * Backported #7714: Workaround for broken surface frame marker +* Backported #7745: GFX progressive double free Important notes: From ce8616c0dc2773d4f3377a47e599849d1456cf03 Mon Sep 17 00:00:00 2001 From: Alexandru Bagu Date: Wed, 3 Nov 2021 06:11:36 -0400 Subject: [PATCH 123/496] Urbrdc fix (#7417) * fix libusb libusb_device usage (manually unref required usb devices, versus freeing all when we still hold references to the ones we want) * disabled detach_kernel_driver & attach_kernel_driver on win32 since libusb does not support them * fixed libusb async event handling * add log for transfer request error * Update libusb_udevice.c * refactor code --- channels/urbdrc/client/data_transfer.c | 7 + .../urbdrc/client/libusb/libusb_udevice.c | 129 ++++++++++-------- .../urbdrc/client/libusb/libusb_udevman.c | 10 +- 3 files changed, 87 insertions(+), 59 deletions(-) diff --git a/channels/urbdrc/client/data_transfer.c b/channels/urbdrc/client/data_transfer.c index 9a44e6e09116..698796126922 100644 --- a/channels/urbdrc/client/data_transfer.c +++ b/channels/urbdrc/client/data_transfer.c @@ -1749,6 +1749,13 @@ static UINT urbdrc_process_transfer_request(IUDEVICE* pdev, URBDRC_CHANNEL_CALLB break; } + if (error) + { + WLog_Print(urbdrc->log, WLOG_WARN, + "USB transfer request URB Function %08" PRIx32 " failed with %08" PRIx32, + URB_Function, error); + } + return error; } diff --git a/channels/urbdrc/client/libusb/libusb_udevice.c b/channels/urbdrc/client/libusb/libusb_udevice.c index aa69890aed8d..1322a4f3902c 100644 --- a/channels/urbdrc/client/libusb/libusb_udevice.c +++ b/channels/urbdrc/client/libusb/libusb_udevice.c @@ -490,17 +490,19 @@ static LIBUSB_DEVICE* udev_get_libusb_dev(libusb_context* context, uint8_t bus_n for (i = 0; i < total_device; i++) { - uint8_t cbus = libusb_get_bus_number(libusb_list[i]); - uint8_t caddr = libusb_get_device_address(libusb_list[i]); - - if ((bus_number == cbus) && (dev_number == caddr)) + LIBUSB_DEVICE* dev = libusb_list[i]; + if ((bus_number == libusb_get_bus_number(dev)) && + (dev_number == libusb_get_device_address(dev))) { - device = libusb_list[i]; - break; + device = dev; + } + else + { + libusb_unref_device(dev); } } - libusb_free_device_list(libusb_list, 1); + libusb_free_device_list(libusb_list, 0); return device; } @@ -522,7 +524,6 @@ static LIBUSB_DEVICE_DESCRIPTOR* udev_new_descript(URBDRC_PLUGIN* urbdrc, LIBUSB return descriptor; } - static int libusb_udev_select_interface(IUDEVICE* idev, BYTE InterfaceNumber, BYTE AlternateSetting) { int error = 0, diff = 0; @@ -1012,6 +1013,9 @@ static BOOL libusb_udev_detach_kernel_driver(IUDEVICE* idev) if (!pdev || !pdev->LibusbConfig || !pdev->libusb_handle || !pdev->urbdrc) return FALSE; +#ifdef _WIN32 + return TRUE; +#else urbdrc = pdev->urbdrc; if ((pdev->status & URBDRC_DEVICE_DETACH_KERNEL) == 0) @@ -1032,6 +1036,7 @@ static BOOL libusb_udev_detach_kernel_driver(IUDEVICE* idev) } return TRUE; +#endif } static BOOL libusb_udev_attach_kernel_driver(IUDEVICE* idev) @@ -1048,12 +1053,14 @@ static BOOL libusb_udev_attach_kernel_driver(IUDEVICE* idev) log_libusb_result(pdev->urbdrc->log, WLOG_DEBUG, "libusb_release_interface", err); +#ifndef _WIN32 if (err != LIBUSB_ERROR_NO_DEVICE) { err = libusb_attach_kernel_driver(pdev->libusb_handle, i); log_libusb_result(pdev->urbdrc->log, WLOG_DEBUG, "libusb_attach_kernel_driver if=%d", err, i); } +#endif } return TRUE; @@ -1474,6 +1481,7 @@ static void udev_free(IUDEVICE* idev) ArrayList_Free(udev->request_queue); /* free the config descriptor that send from windows */ msusb_msconfig_free(udev->MsConfig); + libusb_unref_device(udev->libusb_dev); libusb_close(udev->libusb_handle); libusb_close(udev->hub_handle); free(udev->devDescriptor); @@ -1522,8 +1530,8 @@ static void udev_load_interface(UDEVICE* pdev) pdev->iface.free = udev_free; } -static int udev_get_hub_handle(URBDRC_PLUGIN* urbdrc, libusb_context* ctx, UDEVICE* pdev, - UINT16 bus_number, UINT16 dev_number) +static int udev_get_device_handle(URBDRC_PLUGIN* urbdrc, libusb_context* ctx, UDEVICE* pdev, + UINT16 bus_number, UINT16 dev_number) { int error; ssize_t i, total_device; @@ -1535,21 +1543,19 @@ static int udev_get_hub_handle(URBDRC_PLUGIN* urbdrc, libusb_context* ctx, UDEVI for (i = 0; i < total_device; i++) { - LIBUSB_DEVICE_HANDLE* handle; - uint8_t cbus = libusb_get_bus_number(libusb_list[i]); - uint8_t caddr = libusb_get_device_address(libusb_list[i]); + LIBUSB_DEVICE* dev = libusb_list[i]; - if ((bus_number != cbus) || (dev_number != caddr)) + if ((bus_number != libusb_get_bus_number(dev)) || + (dev_number != libusb_get_device_address(dev))) continue; - error = libusb_open(libusb_list[i], &handle); + error = libusb_open(dev, &pdev->libusb_handle); if (log_libusb_result(urbdrc->log, WLOG_ERROR, "libusb_open", error)) break; /* get port number */ - error = libusb_get_port_numbers(libusb_list[i], port_numbers, sizeof(port_numbers)); - libusb_close(handle); + error = libusb_get_port_numbers(dev, port_numbers, sizeof(port_numbers)); if (error < 1) { @@ -1567,29 +1573,40 @@ static int udev_get_hub_handle(URBDRC_PLUGIN* urbdrc, libusb_context* ctx, UDEVI WLog_Print(urbdrc->log, WLOG_DEBUG, " DevPath: %s", pdev->path); break; } + libusb_free_device_list(libusb_list, 1); + + if (error < 0) + return -1; + return 0; +} + +static int udev_get_hub_handle(URBDRC_PLUGIN* urbdrc, libusb_context* ctx, UDEVICE* pdev, + UINT16 bus_number, UINT16 dev_number) +{ + int error; + ssize_t i, total_device; + LIBUSB_DEVICE** libusb_list; + LIBUSB_DEVICE_HANDLE* handle; + total_device = libusb_get_device_list(ctx, &libusb_list); /* Look for device hub. */ - if (error == 0) - { - error = -1; + error = -1; - for (i = 0; i < total_device; i++) - { - LIBUSB_DEVICE_HANDLE* handle; - uint8_t cbus = libusb_get_bus_number(libusb_list[i]); - uint8_t caddr = libusb_get_device_address(libusb_list[i]); + for (i = 0; i < total_device; i++) + { + LIBUSB_DEVICE* dev = libusb_list[i]; - if ((bus_number != cbus) || (1 != caddr)) /* Root hub allways first on bus. */ - continue; + if ((bus_number != libusb_get_bus_number(dev)) || + (1 != libusb_get_device_address(dev))) /* Root hub allways first on bus. */ + continue; - WLog_Print(urbdrc->log, WLOG_DEBUG, " Open hub: %" PRIu16 "", bus_number); - error = libusb_open(libusb_list[i], &handle); + WLog_Print(urbdrc->log, WLOG_DEBUG, " Open hub: %" PRIu16 "", bus_number); + error = libusb_open(dev, &handle); - if (!log_libusb_result(urbdrc->log, WLOG_ERROR, "libusb_open", error)) - pdev->hub_handle = handle; + if (!log_libusb_result(urbdrc->log, WLOG_ERROR, "libusb_open", error)) + pdev->hub_handle = handle; - break; - } + break; } libusb_free_device_list(libusb_list, 1); @@ -1640,30 +1657,26 @@ static IUDEVICE* udev_init(URBDRC_PLUGIN* urbdrc, libusb_context* context, LIBUS if (urbdrc->listener_callback) udev_set_channelManager(&pdev->iface, urbdrc->listener_callback->channel_mgr); - /* Get HUB handle */ - status = udev_get_hub_handle(urbdrc, context, pdev, bus_number, dev_number); - - if (status < 0) - pdev->hub_handle = NULL; - + /* Get DEVICE handle */ + status = udev_get_device_handle(urbdrc, context, pdev, bus_number, dev_number); + if (status != LIBUSB_SUCCESS) { struct libusb_device_descriptor desc; - const uint8_t bus = libusb_get_bus_number(pdev->libusb_dev); const uint8_t port = libusb_get_port_number(pdev->libusb_dev); - const uint8_t addr = libusb_get_device_address(pdev->libusb_dev); libusb_get_device_descriptor(pdev->libusb_dev, &desc); - status = libusb_open(pdev->libusb_dev, &pdev->libusb_handle); - - if (status != LIBUSB_SUCCESS) - { - log_libusb_result(urbdrc->log, WLOG_ERROR, - "libusb_open [b=0x%02X,p=0x%02X,a=0x%02X,VID=0x%04X,PID=0x%04X]", - status, bus, port, addr, desc.idVendor, desc.idProduct); - goto fail; - } + log_libusb_result(urbdrc->log, WLOG_ERROR, + "libusb_open [b=0x%02X,p=0x%02X,a=0x%02X,VID=0x%04X,PID=0x%04X]", status, + bus_number, port, dev_number, desc.idVendor, desc.idProduct); + goto fail; } + /* Get HUB handle */ + status = udev_get_hub_handle(urbdrc, context, pdev, bus_number, dev_number); + + if (status < 0) + pdev->hub_handle = NULL; + pdev->devDescriptor = udev_new_descript(urbdrc, pdev->libusb_dev); if (!pdev->devDescriptor) @@ -1734,8 +1747,6 @@ size_t udev_new_by_id(URBDRC_PLUGIN* urbdrc, libusb_context* ctx, UINT16 idVendo { LIBUSB_DEVICE** libusb_list; UDEVICE** array; - UINT16 bus_number; - UINT16 dev_number; ssize_t i, total_device; size_t num = 0; @@ -1752,23 +1763,27 @@ size_t udev_new_by_id(URBDRC_PLUGIN* urbdrc, libusb_context* ctx, UINT16 idVendo for (i = 0; i < total_device; i++) { - LIBUSB_DEVICE_DESCRIPTOR* descriptor = udev_new_descript(urbdrc, libusb_list[i]); + LIBUSB_DEVICE* dev = libusb_list[i]; + LIBUSB_DEVICE_DESCRIPTOR* descriptor = udev_new_descript(urbdrc, dev); if ((descriptor->idVendor == idVendor) && (descriptor->idProduct == idProduct)) { - bus_number = libusb_get_bus_number(libusb_list[i]); - dev_number = libusb_get_device_address(libusb_list[i]); - array[num] = (PUDEVICE)udev_init(urbdrc, ctx, libusb_list[i], bus_number, dev_number); + array[num] = (PUDEVICE)udev_init(urbdrc, ctx, dev, libusb_get_bus_number(dev), + libusb_get_device_address(dev)); if (array[num] != NULL) num++; } + else + { + libusb_unref_device(dev); + } free(descriptor); } fail: - libusb_free_device_list(libusb_list, 1); + libusb_free_device_list(libusb_list, 0); *devArray = (IUDEVICE**)array; return num; } diff --git a/channels/urbdrc/client/libusb/libusb_udevman.c b/channels/urbdrc/client/libusb/libusb_udevman.c index 1638b8c13f2f..edfe74f415d6 100644 --- a/channels/urbdrc/client/libusb/libusb_udevman.c +++ b/channels/urbdrc/client/libusb/libusb_udevman.c @@ -195,6 +195,12 @@ static size_t udevman_register_udevice(IUDEVMAN* idevman, BYTE bus_number, BYTE /* register all device that match pid vid */ num = udev_new_by_id(urbdrc, udevman->context, idVendor, idProduct, &devArray); + if (num == 0) + { + WLog_Print(urbdrc->log, WLOG_WARN, + "Could not find or redirect any usb devices by id %04x:%04x", idVendor, idProduct); + } + for (i = 0; i < num; i++) { UINT32 id; @@ -834,7 +840,7 @@ static BOOL poll_libusb_events(UDEVMAN* udevman) { int rc = LIBUSB_SUCCESS; struct timeval tv = { 0, 500 }; - if (libusb_try_lock_events(udevman->context)) + if (libusb_try_lock_events(udevman->context) == 0) { if (libusb_event_handling_ok(udevman->context)) { @@ -921,7 +927,7 @@ UINT freerdp_urbdrc_client_subsystem_entry(PFREERDP_URBDRC_SERVICE_ENTRY_POINTS udevman->next_device_id = BASE_USBDEVICE_NUM; udevman->iface.plugin = pEntryPoints->plugin; rc = libusb_init(&udevman->context); - + if (rc != LIBUSB_SUCCESS) goto fail; From 9ab0667b5470cd16227a2212b57bfc7a71a31043 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Thu, 7 Apr 2022 09:50:04 +0200 Subject: [PATCH 124/496] Fix #7785: Missed GatewayHttpUseWebsockets initialization In backport #6877 this was missed. --- libfreerdp/core/settings.c | 1 + 1 file changed, 1 insertion(+) diff --git a/libfreerdp/core/settings.c b/libfreerdp/core/settings.c index f4b58780517b..6a7b9900c48c 100644 --- a/libfreerdp/core/settings.c +++ b/libfreerdp/core/settings.c @@ -488,6 +488,7 @@ rdpSettings* freerdp_settings_new(DWORD flags) settings->GatewayRpcTransport = TRUE; settings->GatewayHttpTransport = TRUE; settings->GatewayUdpTransport = TRUE; + settings->GatewayHttpUseWebsockets = TRUE; settings->FastPathInput = TRUE; settings->FastPathOutput = TRUE; settings->LongCredentialsSupported = TRUE; From 2b65b7cb123cc5c9950aa1bf4a136dae63349951 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Tue, 20 Jul 2021 10:57:28 +0200 Subject: [PATCH 125/496] Fixed FFMPEG detection without pkgconfig (cherry picked from commit 2c31c367598863d73c3c5cc3a8b93bfebe2dfb60) --- cmake/FindFFmpeg.cmake | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/cmake/FindFFmpeg.cmake b/cmake/FindFFmpeg.cmake index 78d9bf6ab1e2..ffa16412accd 100644 --- a/cmake/FindFFmpeg.cmake +++ b/cmake/FindFFmpeg.cmake @@ -27,12 +27,20 @@ find_library(AVUTIL_LIBRARY avutil PATHS ${AVUTIL_LIBRARY_DIRS}) # swresample find_path(SWRESAMPLE_INCLUDE_DIR libswresample/swresample.h PATHS ${SWRESAMPLE_INCLUDE_DIRS}) -find_library(SWRESAMPLE_LIBRARY swresample PATHS ${SWRESAMPLE_LIBRARY_DIRS}) +find_library(SWRESAMPLE_LIBRARY NAMES swresample swresample-3 PATHS ${SWRESAMPLE_LIBRARY_DIRS}) + +if (SWRESAMPLE_INCLUDE_DIR AND SWRESAMPLE_LIBRARY) + set(SWRESAMPLE_FOUND ON) +endif() # avresample find_path(AVRESAMPLE_INCLUDE_DIR libavresample/avresample.h PATHS ${AVRESAMPLE_INCLUDE_DIRS}) find_library(AVRESAMPLE_LIBRARY avresample PATHS ${AVRESAMPLE_LIBRARY_DIRS}) +if (AVRESAMPLE_INCLUDE_DIR AND AVRESAMPLE_LIBRARY) + set(AVRESAMPLE_FOUND ON) +endif() + if (AVCODEC_INCLUDE_DIR AND AVCODEC_LIBRARY) set(AVCODEC_FOUND TRUE) endif(AVCODEC_INCLUDE_DIR AND AVCODEC_LIBRARY) From 572c63a9f1880bbdff323192eef560bd52d66600 Mon Sep 17 00:00:00 2001 From: Kazuki Oikawa Date: Sat, 19 Mar 2022 21:19:41 +0900 Subject: [PATCH 126/496] Supports 10bit X11 color (BGRX32 only) (cherry picked from commit 8a86a4e8d98a26b7724640081302c7596e962a6e) --- client/X11/xf_graphics.c | 2 ++ include/freerdp/codec/color.h | 21 +++++++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/client/X11/xf_graphics.c b/client/X11/xf_graphics.c index 8de32c5572a7..11c6d59b1923 100644 --- a/client/X11/xf_graphics.c +++ b/client/X11/xf_graphics.c @@ -729,6 +729,8 @@ UINT32 xf_get_local_color_format(xfContext* xfc, BOOL aligned) if (xfc->depth == 32) DstFormat = (!invert) ? PIXEL_FORMAT_RGBA32 : PIXEL_FORMAT_BGRA32; + else if (xfc->depth == 30) + DstFormat = (!invert) ? PIXEL_FORMAT_RGBX32_DEPTH30 : PIXEL_FORMAT_BGRX32_DEPTH30; else if (xfc->depth == 24) { if (aligned) diff --git a/include/freerdp/codec/color.h b/include/freerdp/codec/color.h index 42cb104d1c61..5d3e27904780 100644 --- a/include/freerdp/codec/color.h +++ b/include/freerdp/codec/color.h @@ -68,6 +68,8 @@ #define PIXEL_FORMAT_BGRX32 FREERDP_PIXEL_FORMAT(32, FREERDP_PIXEL_FORMAT_TYPE_BGRA, 0, 8, 8, 8) #define PIXEL_FORMAT_RGBA32 FREERDP_PIXEL_FORMAT(32, FREERDP_PIXEL_FORMAT_TYPE_RGBA, 8, 8, 8, 8) #define PIXEL_FORMAT_RGBX32 FREERDP_PIXEL_FORMAT(32, FREERDP_PIXEL_FORMAT_TYPE_RGBA, 0, 8, 8, 8) +#define PIXEL_FORMAT_BGRX32_DEPTH30 FREERDP_PIXEL_FORMAT(32, FREERDP_PIXEL_FORMAT_TYPE_BGRA, 0, 10, 10, 10) +#define PIXEL_FORMAT_RGBX32_DEPTH30 FREERDP_PIXEL_FORMAT(32, FREERDP_PIXEL_FORMAT_TYPE_RGBA, 0, 10, 10, 10) /* 24bpp formats */ #define PIXEL_FORMAT_RGB24 FREERDP_PIXEL_FORMAT(24, FREERDP_PIXEL_FORMAT_TYPE_ARGB, 0, 8, 8, 8) @@ -149,6 +151,12 @@ extern "C" case PIXEL_FORMAT_RGBX32: return "PIXEL_FORMAT_RGBX32"; + case PIXEL_FORMAT_BGRX32_DEPTH30: + return "PIXEL_FORMAT_BGRX32_DEPTH30"; + + case PIXEL_FORMAT_RGBX32_DEPTH30: + return "PIXEL_FORMAT_RGBX32_DEPTH30"; + /* 24bpp formats */ case PIXEL_FORMAT_RGB24: return "PIXEL_FORMAT_RGB24"; @@ -607,6 +615,7 @@ extern "C" UINT32 _g = g; UINT32 _b = b; UINT32 _a = a; + UINT32 t; switch (format) { @@ -635,6 +644,18 @@ extern "C" case PIXEL_FORMAT_BGRX32: return (_b << 24) | (_g << 16) | (_r << 8) | _a; + case PIXEL_FORMAT_RGBX32_DEPTH30: + // TODO: Not tested + t = (_r << 22) | (_g << 12) | (_b << 2); + // NOTE: Swapping byte-order because WriteColor written UINT32 in big-endian + return ((t & 0xff) << 24) | (((t >> 8) & 0xff) << 16) | (((t >> 16) & 0xff) << 8) | (t >> 24); + + case PIXEL_FORMAT_BGRX32_DEPTH30: + // NOTE: Swapping b and r channel (unknown reason) + t = (_r << 22) | (_g << 12) | (_b << 2); + // NOTE: Swapping byte-order because WriteColor written UINT32 in big-endian + return ((t & 0xff) << 24) | (((t >> 8) & 0xff) << 16) | (((t >> 16) & 0xff) << 8) | (t >> 24); + /* 24bpp formats */ case PIXEL_FORMAT_RGB24: return (_r << 16) | (_g << 8) | _b; From 62937807eec969e36958bbc5a64534595e9925fd Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Tue, 19 Apr 2022 08:38:09 +0200 Subject: [PATCH 127/496] Changelog --- ChangeLog | 1 + 1 file changed, 1 insertion(+) diff --git a/ChangeLog b/ChangeLog index f051626f4473..7706fa574cc1 100644 --- a/ChangeLog +++ b/ChangeLog @@ -7,6 +7,7 @@ Noteworthy changes: Fixed issues: * Backported #6786: Use /network:auto by default * Backported #7714: Workaround for broken surface frame marker +* Backported #7733: Support 10bit X11 color (BGRX32 only) * Backported #7745: GFX progressive double free Important notes: From 0f9efe19720ff8d56589d8ae0b34ba04a07b6d1c Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Tue, 19 Apr 2022 14:35:50 +0200 Subject: [PATCH 128/496] Fixed /gt:xxx settings * Disable websocket support with RPC * Use settings getter/setter (cherry picked from commit 882b91d98671fd072e96889587f4b98cc2ce4ff5) --- client/common/cmdline.c | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/client/common/cmdline.c b/client/common/cmdline.c index da53f85138fe..77fcf81849d9 100644 --- a/client/common/cmdline.c +++ b/client/common/cmdline.c @@ -2291,8 +2291,10 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, { if (_stricmp(arg->Value, "rpc") == 0) { - settings->GatewayRpcTransport = TRUE; - settings->GatewayHttpTransport = FALSE; + if (!freerdp_settings_set_bool(settings, FreeRDP_GatewayRpcTransport, TRUE) || + !freerdp_settings_set_bool(settings, FreeRDP_GatewayHttpTransport, FALSE) || + !freerdp_settings_set_bool(settings, FreeRDP_GatewayHttpUseWebsockets, FALSE)) + return COMMAND_LINE_ERROR_UNEXPECTED_VALUE; } else { @@ -2301,21 +2303,24 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, { *c++ = '\0'; if (_stricmp(c, "no-websockets") != 0) - { return COMMAND_LINE_ERROR_UNEXPECTED_VALUE; - } - freerdp_settings_set_bool(settings, FreeRDP_GatewayHttpUseWebsockets, FALSE); + + if (!freerdp_settings_set_bool(settings, FreeRDP_GatewayHttpUseWebsockets, + FALSE)) + return COMMAND_LINE_ERROR_UNEXPECTED_VALUE; } if (_stricmp(arg->Value, "http") == 0) { - settings->GatewayRpcTransport = FALSE; - settings->GatewayHttpTransport = TRUE; + if (!freerdp_settings_set_bool(settings, FreeRDP_GatewayRpcTransport, FALSE) || + !freerdp_settings_set_bool(settings, FreeRDP_GatewayHttpTransport, TRUE)) + return COMMAND_LINE_ERROR_UNEXPECTED_VALUE; } else if (_stricmp(arg->Value, "auto") == 0) { - settings->GatewayRpcTransport = TRUE; - settings->GatewayHttpTransport = TRUE; + if (!freerdp_settings_set_bool(settings, FreeRDP_GatewayRpcTransport, TRUE) || + !freerdp_settings_set_bool(settings, FreeRDP_GatewayHttpTransport, TRUE)) + return COMMAND_LINE_ERROR_UNEXPECTED_VALUE; } } } From 0a6b999c5655d07b5653894b24a840c08838e304 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Tue, 19 Apr 2022 14:45:59 +0200 Subject: [PATCH 129/496] Updated Changelog --- ChangeLog | 1 + 1 file changed, 1 insertion(+) diff --git a/ChangeLog b/ChangeLog index 7706fa574cc1..d3108e7cde72 100644 --- a/ChangeLog +++ b/ChangeLog @@ -9,6 +9,7 @@ Fixed issues: * Backported #7714: Workaround for broken surface frame marker * Backported #7733: Support 10bit X11 color (BGRX32 only) * Backported #7745: GFX progressive double free +* Backported #7808: Disable websockets with /gt:rpc Important notes: From f773d9759d6b00af3099f4665253fc6021f8ee41 Mon Sep 17 00:00:00 2001 From: Steve Pronovost Date: Sat, 16 Oct 2021 11:53:05 -0700 Subject: [PATCH 130/496] Update header with missing flag Added definition for TS_RAIL_CLIENTSTATUS_GET_APPID_RESPONSE_EX_SUPPORTED. --- include/freerdp/rail.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/freerdp/rail.h b/include/freerdp/rail.h index 019aff89a11a..e532082bed05 100644 --- a/include/freerdp/rail.h +++ b/include/freerdp/rail.h @@ -142,6 +142,7 @@ enum SPI_MASK #define TS_RAIL_CLIENTSTATUS_HIGH_DPI_ICONS_SUPPORTED 0x00000020 #define TS_RAIL_CLIENTSTATUS_APPBAR_REMOTING_SUPPORTED 0x00000040 #define TS_RAIL_CLIENTSTATUS_POWER_DISPLAY_REQUEST_SUPPORTED 0x00000080 +#define TS_RAIL_CLIENTSTATUS_GET_APPID_RESPONSE_EX_SUPPORTED 0x00000100 #define TS_RAIL_CLIENTSTATUS_BIDIRECTIONAL_CLOAK_SUPPORTED 0x00000200 /* Server Move/Size Start PDU */ From 66ff8cf2adc2851a94e7a22f2e40ca30c332d7b1 Mon Sep 17 00:00:00 2001 From: Steve Pronovost Date: Sat, 16 Oct 2021 11:55:46 -0700 Subject: [PATCH 131/496] Added support for AUDIO_PLAYBACK_DVC Support audio on dynamic channel. Please refer to MS-RDPEA. --- channels/rdpsnd/server/rdpsnd_main.c | 36 ++++++++++++++++++++++++---- channels/rdpsnd/server/rdpsnd_main.h | 1 + include/freerdp/server/rdpsnd.h | 3 +++ 3 files changed, 36 insertions(+), 4 deletions(-) diff --git a/channels/rdpsnd/server/rdpsnd_main.c b/channels/rdpsnd/server/rdpsnd_main.c index be0ca149f33b..537aef66697f 100644 --- a/channels/rdpsnd/server/rdpsnd_main.c +++ b/channels/rdpsnd/server/rdpsnd_main.c @@ -673,12 +673,40 @@ static UINT rdpsnd_server_start(RdpsndServerContext* context) DWORD bytesReturned; RdpsndServerPrivate* priv = context->priv; UINT error = ERROR_INTERNAL_ERROR; - priv->ChannelHandle = WTSVirtualChannelOpen(context->vcm, WTS_CURRENT_SESSION, "rdpsnd"); + PULONG pSessionId = NULL; - if (!priv->ChannelHandle) + priv->SessionId = WTS_CURRENT_SESSION; + + if (context->use_dynamic_virtual_channel) { - WLog_ERR(TAG, "WTSVirtualChannelOpen failed!"); - return ERROR_INTERNAL_ERROR; + if (WTSQuerySessionInformationA(context->vcm, WTS_CURRENT_SESSION, WTSSessionId, + (LPSTR*)&pSessionId, &bytesReturned)) + { + priv->SessionId = (DWORD)*pSessionId; + WTSFreeMemory(pSessionId); + priv->ChannelHandle = (HANDLE)WTSVirtualChannelOpenEx( + priv->SessionId, "AUDIO_PLAYBACK_DVC", WTS_CHANNEL_OPTION_DYNAMIC); + if (!priv->ChannelHandle) + { + WLog_ERR(TAG, "Open audio dynamic virtual channel (AUDIO_PLAYBACK_DVC) failed!"); + return ERROR_INTERNAL_ERROR; + } + } + else + { + WLog_ERR(TAG, "WTSQuerySessionInformationA failed!"); + return ERROR_INTERNAL_ERROR; + } + } + else + { + priv->ChannelHandle = + WTSVirtualChannelOpen(context->vcm, WTS_CURRENT_SESSION, "rdpsnd"); + if (!priv->ChannelHandle) + { + WLog_ERR(TAG, "Open audio static virtual channel (rdpsnd) failed!"); + return ERROR_INTERNAL_ERROR; + } } if (!WTSVirtualChannelQuery(priv->ChannelHandle, WTSVirtualEventHandle, &buffer, diff --git a/channels/rdpsnd/server/rdpsnd_main.h b/channels/rdpsnd/server/rdpsnd_main.h index f058abbc71ba..9849273ea4d0 100644 --- a/channels/rdpsnd/server/rdpsnd_main.h +++ b/channels/rdpsnd/server/rdpsnd_main.h @@ -39,6 +39,7 @@ struct _rdpsnd_server_private HANDLE StopEvent; HANDLE channelEvent; void* ChannelHandle; + DWORD SessionId; BOOL waitingHeader; DWORD expectedBytes; diff --git a/include/freerdp/server/rdpsnd.h b/include/freerdp/server/rdpsnd.h index fa83473596b4..b83a63610f74 100644 --- a/include/freerdp/server/rdpsnd.h +++ b/include/freerdp/server/rdpsnd.h @@ -119,6 +119,9 @@ struct _rdpsnd_server_context UINT16 clientVersion; rdpContext* rdpcontext; + + /* Server to request to use dynamic virtual channel. */ + BOOL use_dynamic_virtual_channel; }; #ifdef __cplusplus From 4308d8e91e77b95c1c7a71edf06382b760936b51 Mon Sep 17 00:00:00 2001 From: 2fly2 Date: Fri, 22 Apr 2022 11:18:26 +0800 Subject: [PATCH 132/496] fix x11 black RAIL window when connect to server 2019 Signed-off-by: 2fly2 (cherry picked from commit cb66a4c0df5f46f7f7d27d1673996dac51edd6e1) --- client/X11/xf_client.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/client/X11/xf_client.c b/client/X11/xf_client.c index 24a03d488b8d..c2704a4b1291 100644 --- a/client/X11/xf_client.c +++ b/client/X11/xf_client.c @@ -1384,7 +1384,10 @@ static int xf_logon_error_info(freerdp* instance, UINT32 data, UINT32 type) const char* str_data = freerdp_get_logon_error_info_data(data); const char* str_type = freerdp_get_logon_error_info_type(type); WLog_INFO(TAG, "Logon Error Info %s [%s]", str_data, str_type); - xf_rail_disable_remoteapp_mode(xfc); + if(type != LOGON_MSG_SESSION_CONTINUE) + { + xf_rail_disable_remoteapp_mode(xfc); + } return 1; } From e8010231c8e491ea236385a755b7d0607102fe20 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Fri, 22 Apr 2022 10:17:54 +0200 Subject: [PATCH 133/496] Changelog --- ChangeLog | 1 + 1 file changed, 1 insertion(+) diff --git a/ChangeLog b/ChangeLog index d3108e7cde72..073283f413d7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -10,6 +10,7 @@ Fixed issues: * Backported #7733: Support 10bit X11 color (BGRX32 only) * Backported #7745: GFX progressive double free * Backported #7808: Disable websockets with /gt:rpc +* Backported #7815: RAIL expect LOGON_MSG_SESSION_CONTINUE Important notes: From 70bd7f010f90be41ccadf8c2649536848a0e87e0 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Thu, 29 Jul 2021 15:20:20 +0200 Subject: [PATCH 134/496] Update default android build config Remove x86 and x86_64 to bring down pr build times (cherry picked from commit 7e7394d905d70b55de7594c01ff110a73a3aae23) --- scripts/android-build.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/android-build.conf b/scripts/android-build.conf index 9ef3eec56784..5f470a5e37f6 100644 --- a/scripts/android-build.conf +++ b/scripts/android-build.conf @@ -28,4 +28,4 @@ BUILD_SRC=$SRC_DIR/build CMAKE_BUILD_TYPE=Debug -BUILD_ARCH="armeabi-v7a x86 arm64-v8a x86_64" +BUILD_ARCH="armeabi-v7a arm64-v8a" From 52f3e5139f7c75258b95ac49f53b8ca49e63f1e2 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Fri, 22 Apr 2022 14:42:11 +0200 Subject: [PATCH 135/496] Cleaned up ntlm_fetch_ntlm_v2_hash (cherry picked from commit 4661492e5a617199457c8074bad22f766a116cdc) --- winpr/libwinpr/sspi/NTLM/ntlm_compute.c | 58 +++++++++++-------------- 1 file changed, 25 insertions(+), 33 deletions(-) diff --git a/winpr/libwinpr/sspi/NTLM/ntlm_compute.c b/winpr/libwinpr/sspi/NTLM/ntlm_compute.c index 202240b13f48..4e33aedec0e9 100644 --- a/winpr/libwinpr/sspi/NTLM/ntlm_compute.c +++ b/winpr/libwinpr/sspi/NTLM/ntlm_compute.c @@ -280,10 +280,11 @@ void ntlm_generate_timestamp(NTLM_CONTEXT* context) ntlm_current_time(context->Timestamp); } -static int ntlm_fetch_ntlm_v2_hash(NTLM_CONTEXT* context, BYTE* hash) +static BOOL ntlm_fetch_ntlm_v2_hash(NTLM_CONTEXT* context, BYTE* hash) { - WINPR_SAM* sam; - WINPR_SAM_ENTRY* entry; + BOOL rc = FALSE; + WINPR_SAM* sam = NULL; + WINPR_SAM_ENTRY* entry = NULL; SSPI_CREDENTIALS* credentials; WINPR_ASSERT(context); @@ -293,48 +294,39 @@ static int ntlm_fetch_ntlm_v2_hash(NTLM_CONTEXT* context, BYTE* hash) sam = SamOpen(context->SamFile, TRUE); if (!sam) - return -1; + goto fail; entry = SamLookupUserW( - sam, (LPWSTR)credentials->identity.User, credentials->identity.UserLength * 2, - (LPWSTR)credentials->identity.Domain, credentials->identity.DomainLength * 2); + sam, (LPWSTR)credentials->identity.User, credentials->identity.UserLength * sizeof(WCHAR), + (LPWSTR)credentials->identity.Domain, credentials->identity.DomainLength * sizeof(WCHAR)); - if (entry) + if (!entry) { -#ifdef WITH_DEBUG_NTLM - WLog_VRB(TAG, "NTLM Hash:"); - winpr_HexDump(TAG, WLOG_DEBUG, entry->NtHash, 16); -#endif - NTOWFv2FromHashW(entry->NtHash, (LPWSTR)credentials->identity.User, - credentials->identity.UserLength * 2, (LPWSTR)credentials->identity.Domain, - credentials->identity.DomainLength * 2, (BYTE*)hash); - SamFreeEntry(sam, entry); - SamClose(sam); - return 1; + entry = SamLookupUserW(sam, (LPWSTR)credentials->identity.User, + credentials->identity.UserLength * sizeof(WCHAR), NULL, 0); } - entry = SamLookupUserW(sam, (LPWSTR)credentials->identity.User, - credentials->identity.UserLength * 2, NULL, 0); + if (!entry) + goto fail; - if (entry) - { #ifdef WITH_DEBUG_NTLM WLog_VRB(TAG, "NTLM Hash:"); winpr_HexDump(TAG, WLOG_DEBUG, entry->NtHash, 16); #endif - NTOWFv2FromHashW(entry->NtHash, (LPWSTR)credentials->identity.User, - credentials->identity.UserLength * 2, (LPWSTR)credentials->identity.Domain, - credentials->identity.DomainLength * 2, (BYTE*)hash); - SamFreeEntry(sam, entry); - SamClose(sam); - return 1; - } - else - { - SamClose(sam); + NTOWFv2FromHashW(entry->NtHash, (LPWSTR)credentials->identity.User, + credentials->identity.UserLength * sizeof(WCHAR), + (LPWSTR)credentials->identity.Domain, + credentials->identity.DomainLength * sizeof(WCHAR), (BYTE*)hash); + + rc = TRUE; + +fail: + SamFreeEntry(sam, entry); + SamClose(sam); + if (!rc) WLog_ERR(TAG, "Error: Could not find user in SAM database"); - return 0; - } + + return rc; } static int ntlm_convert_password_hash(NTLM_CONTEXT* context, BYTE* hash) From 97957fcde0278aec709bd489140b6c708fb914af Mon Sep 17 00:00:00 2001 From: akarl Date: Sun, 24 Apr 2022 21:16:52 +0200 Subject: [PATCH 136/496] Implement BIO_CTRL_GET_KTLS_SEND and BIO_CTRL_GET_KTLS_SEND Openssl 3.0 requires to respond to this controls. According to there documentation it should not need them, but in practice openssl's own source is full of places where negative return values are not checked. (cherry picked from commit 9d7c20ce8fe50bd6de54e7480b5096761a510daf) --- libfreerdp/core/gateway/rdg.c | 18 +++++++++++++++++- libfreerdp/core/gateway/tsg.c | 9 ++++++++- 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/libfreerdp/core/gateway/rdg.c b/libfreerdp/core/gateway/rdg.c index 44de2c137c9d..6b998c8d9b78 100644 --- a/libfreerdp/core/gateway/rdg.c +++ b/libfreerdp/core/gateway/rdg.c @@ -2483,7 +2483,23 @@ static long rdg_bio_ctrl(BIO* in_bio, int cmd, long arg1, void* arg2) */ status = BIO_ctrl(tlsOut->bio, cmd, arg1, arg2); } - +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + else if (cmd == BIO_CTRL_GET_KTLS_SEND) + { + /* Even though BIO_get_ktls_send says that returning negative values is valid + * openssl internal sources are full of if(!BIO_get_ktls_send && ) stuff. This has some + * nasty sideeffects. return 0 as proper no KTLS offloading flag + */ + status = 0; + } + else if (cmd == BIO_CTRL_GET_KTLS_RECV) + { + /* Even though BIO_get_ktls_recv says that returning negative values is valid + * there is no reason to trust trust negative values are implemented right everywhere + */ + status = 0; + } +#endif return status; } diff --git a/libfreerdp/core/gateway/tsg.c b/libfreerdp/core/gateway/tsg.c index c03f266f2bf3..70fdf9e275ba 100644 --- a/libfreerdp/core/gateway/tsg.c +++ b/libfreerdp/core/gateway/tsg.c @@ -2716,7 +2716,14 @@ static long transport_bio_tsg_ctrl(BIO* bio, int cmd, long arg1, void* arg2) status = 1; } break; - +#if OPENSSL_VERSION_NUMBER >= 0x30000000L + case BIO_CTRL_GET_KTLS_SEND: + status = 0; + break; + case BIO_CTRL_GET_KTLS_RECV: + status = 0; + break; +#endif default: break; } From c263ff19ec07dcaa420c69fecc21335e49a9524a Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Mon, 25 Apr 2022 09:06:58 +0200 Subject: [PATCH 137/496] Updated changelog --- ChangeLog | 1 + 1 file changed, 1 insertion(+) diff --git a/ChangeLog b/ChangeLog index 073283f413d7..b0d7fa3e0084 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,7 @@ # 2022-XX-YY Version 2.X.Y Noteworthy changes: +* Backported OpenSSL3 gateway support (#7822) * Backported various NTLM fixes * Backported WINPR_ASSERT to ease future backports From 32b8db3025a3d3ec91c0d501c5009d43d248dabc Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Mon, 25 Apr 2022 14:28:26 +0200 Subject: [PATCH 138/496] Added missing WINPR_API --- include/freerdp/crypto/crypto.h | 6 +++--- winpr/include/winpr/crypto.h | 24 +++++++++++++----------- winpr/include/winpr/locale.h | 12 ++++++------ winpr/include/winpr/smartcard.h | 6 +++--- 4 files changed, 25 insertions(+), 23 deletions(-) diff --git a/include/freerdp/crypto/crypto.h b/include/freerdp/crypto/crypto.h index 33f1a1e3ff7b..3138362cf1b4 100644 --- a/include/freerdp/crypto/crypto.h +++ b/include/freerdp/crypto/crypto.h @@ -88,9 +88,9 @@ extern "C" DWORD* PublicKeyLength); #define TSSK_KEY_LENGTH 64 - extern const BYTE tssk_modulus[]; - extern const BYTE tssk_privateExponent[]; - extern const BYTE tssk_exponent[]; + WINPR_API extern const BYTE tssk_modulus[]; + WINPR_API extern const BYTE tssk_privateExponent[]; + WINPR_API extern const BYTE tssk_exponent[]; FREERDP_API int crypto_rsa_public_encrypt(const BYTE* input, int length, UINT32 key_length, const BYTE* modulus, const BYTE* exponent, diff --git a/winpr/include/winpr/crypto.h b/winpr/include/winpr/crypto.h index 67c2d99894b4..c550719ced7c 100644 --- a/winpr/include/winpr/crypto.h +++ b/winpr/include/winpr/crypto.h @@ -472,8 +472,8 @@ typedef const CERT_CONTEXT* PCCERT_CONTEXT; #define CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE \ (CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE_ID << CERT_SYSTEM_STORE_LOCATION_SHIFT) -HCERTSTORE CertOpenStore(LPCSTR lpszStoreProvider, DWORD dwMsgAndCertEncodingType, - HCRYPTPROV_LEGACY hCryptProv, DWORD dwFlags, const void* pvPara); +WINPR_API HCERTSTORE CertOpenStore(LPCSTR lpszStoreProvider, DWORD dwMsgAndCertEncodingType, + HCRYPTPROV_LEGACY hCryptProv, DWORD dwFlags, const void* pvPara); WINPR_API HCERTSTORE CertOpenSystemStoreW(HCRYPTPROV_LEGACY hProv, LPCWSTR szSubsystemProtocol); WINPR_API HCERTSTORE CertOpenSystemStoreA(HCRYPTPROV_LEGACY hProv, LPCSTR szSubsystemProtocol); @@ -597,15 +597,17 @@ extern "C" #define CRYPT_STRING_NOCRLF 0x40000000 #define CRYPT_STRING_NOCR 0x80000000 -BOOL CryptStringToBinaryW(LPCWSTR pszString, DWORD cchString, DWORD dwFlags, BYTE* pbBinary, - DWORD* pcbBinary, DWORD* pdwSkip, DWORD* pdwFlags); -BOOL CryptStringToBinaryA(LPCSTR pszString, DWORD cchString, DWORD dwFlags, BYTE* pbBinary, - DWORD* pcbBinary, DWORD* pdwSkip, DWORD* pdwFlags); - -BOOL CryptBinaryToStringW(CONST BYTE* pbBinary, DWORD cbBinary, DWORD dwFlags, LPWSTR pszString, - DWORD* pcchString); -BOOL CryptBinaryToStringA(CONST BYTE* pbBinary, DWORD cbBinary, DWORD dwFlags, LPSTR pszString, - DWORD* pcchString); +WINPR_API BOOL CryptStringToBinaryW(LPCWSTR pszString, DWORD cchString, DWORD dwFlags, + BYTE* pbBinary, DWORD* pcbBinary, DWORD* pdwSkip, + DWORD* pdwFlags); +WINPR_API BOOL CryptStringToBinaryA(LPCSTR pszString, DWORD cchString, DWORD dwFlags, + BYTE* pbBinary, DWORD* pcbBinary, DWORD* pdwSkip, + DWORD* pdwFlags); + +WINPR_API BOOL CryptBinaryToStringW(CONST BYTE* pbBinary, DWORD cbBinary, DWORD dwFlags, + LPWSTR pszString, DWORD* pcchString); +WINPR_API BOOL CryptBinaryToStringA(CONST BYTE* pbBinary, DWORD cbBinary, DWORD dwFlags, + LPSTR pszString, DWORD* pcchString); #ifdef UNICODE #define CryptStringToBinary CryptStringToBinaryW diff --git a/winpr/include/winpr/locale.h b/winpr/include/winpr/locale.h index 45ef81bb9a79..af776dd0d4a9 100644 --- a/winpr/include/winpr/locale.h +++ b/winpr/include/winpr/locale.h @@ -484,13 +484,13 @@ extern "C" { #endif - DWORD WINAPI FormatMessageA(DWORD dwFlags, LPCVOID lpSource, DWORD dwMessageId, - DWORD dwLanguageId, LPSTR lpBuffer, DWORD nSize, - va_list* Arguments); + WINPR_API DWORD WINAPI FormatMessageA(DWORD dwFlags, LPCVOID lpSource, DWORD dwMessageId, + DWORD dwLanguageId, LPSTR lpBuffer, DWORD nSize, + va_list* Arguments); - DWORD WINAPI FormatMessageW(DWORD dwFlags, LPCVOID lpSource, DWORD dwMessageId, - DWORD dwLanguageId, LPWSTR lpBuffer, DWORD nSize, - va_list* Arguments); + WINPR_API DWORD WINAPI FormatMessageW(DWORD dwFlags, LPCVOID lpSource, DWORD dwMessageId, + DWORD dwLanguageId, LPWSTR lpBuffer, DWORD nSize, + va_list* Arguments); #ifdef UNICODE #define FormatMessage FormatMessageW diff --git a/winpr/include/winpr/smartcard.h b/winpr/include/winpr/smartcard.h index e19a6ee02889..b040f0ad7063 100644 --- a/winpr/include/winpr/smartcard.h +++ b/winpr/include/winpr/smartcard.h @@ -590,9 +590,9 @@ extern "C" { #endif - extern const SCARD_IO_REQUEST g_rgSCardT0Pci; - extern const SCARD_IO_REQUEST g_rgSCardT1Pci; - extern const SCARD_IO_REQUEST g_rgSCardRawPci; + WINPR_API extern const SCARD_IO_REQUEST g_rgSCardT0Pci; + WINPR_API extern const SCARD_IO_REQUEST g_rgSCardT1Pci; + WINPR_API extern const SCARD_IO_REQUEST g_rgSCardRawPci; #define SCARD_PCI_T0 (&g_rgSCardT0Pci) #define SCARD_PCI_T1 (&g_rgSCardT1Pci) From 40ee5d3bcc70343af6c0300d71968858c1f1948f Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Mon, 25 Apr 2022 14:51:56 +0200 Subject: [PATCH 139/496] Updated for 2.7.0 release --- CMakeLists.txt | 2 +- ChangeLog | 4 ++-- client/Android/Studio/build.gradle | 2 +- client/Android/android_freerdp.c | 2 +- winpr/CMakeLists.txt | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 930eee189460..172832f8fc35 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -85,7 +85,7 @@ if ($ENV{BUILD_NUMBER}) endif() set(WITH_LIBRARY_VERSIONING "ON") -set(RAW_VERSION_STRING "2.6.1") +set(RAW_VERSION_STRING "2.7.0") if(EXISTS "${CMAKE_SOURCE_DIR}/.source_tag") file(READ ${CMAKE_SOURCE_DIR}/.source_tag RAW_VERSION_STRING) elseif(USE_VERSION_FROM_GIT_TAG) diff --git a/ChangeLog b/ChangeLog index b0d7fa3e0084..ad92d8bebc49 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,4 @@ -# 2022-XX-YY Version 2.X.Y +# 2022-04-25 Version 2.7.0 Noteworthy changes: * Backported OpenSSL3 gateway support (#7822) @@ -16,7 +16,7 @@ Fixed issues: Important notes: For a complete and detailed change log since the last release run: -git log 2.6.1..2.X.Y +git log 2.6.1..2.7.0 # 2022-03-07 Version 2.6.1 diff --git a/client/Android/Studio/build.gradle b/client/Android/Studio/build.gradle index 52985a9b7b3d..aa7d1f7bda78 100644 --- a/client/Android/Studio/build.gradle +++ b/client/Android/Studio/build.gradle @@ -29,7 +29,7 @@ def getVersionName = { -> ext { versionName = properties.get('VERSION_NAME', getVersionName()) - versionCode = properties.get('VERSION_CODE', 28) + versionCode = properties.get('VERSION_CODE', 29) compileApi = properties.get('COMPILE_API', 31) targetApi = properties.get('TARGET_API', 31) minApi = properties.get('MIN_API', 23) diff --git a/client/Android/android_freerdp.c b/client/Android/android_freerdp.c index e6f957e0e5ad..aa98474a9c11 100644 --- a/client/Android/android_freerdp.c +++ b/client/Android/android_freerdp.c @@ -57,7 +57,7 @@ #define TAG CLIENT_TAG("android") /* Defines the JNI version supported by this library. */ -#define FREERDP_JNI_VERSION "2.6.1" +#define FREERDP_JNI_VERSION "2.7.0" static void android_OnChannelConnectedEventHandler(void* context, ChannelConnectedEventArgs* e) { diff --git a/winpr/CMakeLists.txt b/winpr/CMakeLists.txt index 1827a0aafd83..d8a40da1ae92 100644 --- a/winpr/CMakeLists.txt +++ b/winpr/CMakeLists.txt @@ -57,7 +57,7 @@ if (NOT WIN32) endif() # Soname versioning -set(RAW_VERSION_STRING "2.6.1") +set(RAW_VERSION_STRING "2.7.0") if(EXISTS "${CMAKE_SOURCE_DIR}/.source_tag") file(READ ${CMAKE_SOURCE_DIR}/.source_tag RAW_VERSION_STRING) elseif(USE_VERSION_FROM_GIT_TAG) From 396ed987d100f1433e4b8c6973226deb53e93489 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Guillaume=20D=C3=A9murg=C3=A9?= Date: Fri, 12 Nov 2021 11:57:03 +0100 Subject: [PATCH 140/496] Added app_id on wayland client (cherry picked from commit eaae90998c0297b64c10ab62ddadc1fbb0f4c34e) --- client/Wayland/wlfreerdp.c | 2 ++ uwac/include/uwac/uwac.h | 14 +++++++++++--- uwac/libuwac/uwac-window.c | 6 ++++++ 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/client/Wayland/wlfreerdp.c b/client/Wayland/wlfreerdp.c index ac8e772306d3..c7a9fca59b6e 100644 --- a/client/Wayland/wlfreerdp.c +++ b/client/Wayland/wlfreerdp.c @@ -225,6 +225,7 @@ static BOOL wl_post_connect(freerdp* instance) wlfContext* context; rdpSettings* settings; char* title = "FreeRDP"; + char* app_id = "wlfreerdp"; UINT32 w, h; if (!instance || !instance->context) @@ -266,6 +267,7 @@ static BOOL wl_post_connect(freerdp* instance) UwacWindowSetFullscreenState(window, NULL, instance->context->settings->Fullscreen); UwacWindowSetTitle(window, title); + UwacWindowSetAppId(window, app_id); UwacWindowSetOpaqueRegion(context->window, 0, 0, w, h); instance->update->BeginPaint = wl_begin_paint; instance->update->EndPaint = wl_end_paint; diff --git a/uwac/include/uwac/uwac.h b/uwac/include/uwac/uwac.h index 8bd37d44de92..c3ad12cf149d 100644 --- a/uwac/include/uwac/uwac.h +++ b/uwac/include/uwac/uwac.h @@ -551,10 +551,18 @@ extern "C" UWAC_API void UwacWindowSetTitle(UwacWindow* window, const char* name); /** + * Sets the app id of the UwacWindow * - * @param display - * @param timeout - * @return + * @param window the UwacWindow + * @param app_id app id + */ + UWAC_API void UwacWindowSetAppId(UwacWindow* window, const char* app_id); + + /** Dispatch the display + * + * @param display The display to dispatch + * @param timeout The maximum time to wait in milliseconds (-1 == infinite). + * @return 1 for success, 0 if display not running, -1 on failure */ UWAC_API int UwacDisplayDispatch(UwacDisplay* display, int timeout); diff --git a/uwac/libuwac/uwac-window.c b/uwac/libuwac/uwac-window.c index 8e6f08dba62f..4600ad7fe37d 100644 --- a/uwac/libuwac/uwac-window.c +++ b/uwac/libuwac/uwac-window.c @@ -817,3 +817,9 @@ void UwacWindowSetTitle(UwacWindow* window, const char* name) else if (window->shell_surface) wl_shell_surface_set_title(window->shell_surface, name); } + +void UwacWindowSetAppId(UwacWindow* window, const char* app_id) +{ + if (window->xdg_toplevel) + xdg_toplevel_set_app_id(window->xdg_toplevel, app_id); +} From 0cc152af3b2dc056933b85c53a7cd96b20913b10 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Wed, 27 Apr 2022 07:31:54 +0200 Subject: [PATCH 141/496] Updated changelog --- ChangeLog | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/ChangeLog b/ChangeLog index ad92d8bebc49..c502470054be 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +# 20xx-xx-xx Version 2.x.x + +Noteworthy changes: + +Fixed issues: +* Backported #7440: wlfreerdp appid + # 2022-04-25 Version 2.7.0 Noteworthy changes: From 4ca275d468e2a9b8525bbc4ba197a1ddc3a98d04 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Wed, 27 Apr 2022 13:33:08 +0200 Subject: [PATCH 142/496] Refactor thread condition logic * Add better return value checks * Combine logic blocks in structs * Add (easier to read) static functions for blocks * Use condition variables only in combination with BOOL (cherry picked from commit a77038a0c78c62f63bb7372821de89074e5607a3) --- winpr/libwinpr/thread/thread.c | 429 ++++++++++++++++++++++++--------- winpr/libwinpr/thread/thread.h | 58 +++-- 2 files changed, 349 insertions(+), 138 deletions(-) diff --git a/winpr/libwinpr/thread/thread.c b/winpr/libwinpr/thread/thread.c index e671b6490458..3b95d1def216 100644 --- a/winpr/libwinpr/thread/thread.c +++ b/winpr/libwinpr/thread/thread.c @@ -24,7 +24,7 @@ #include "config.h" #endif -#include +#include #include @@ -98,7 +98,10 @@ #define TAG WINPR_TAG("thread") static WINPR_THREAD mainThread; + +#if defined(WITH_THREAD_LIST) static wListDictionary* thread_list = NULL; +#endif static BOOL ThreadCloseHandle(HANDLE handle); static void cleanup_handle(void* obj); @@ -126,14 +129,190 @@ static int ThreadGetFd(HANDLE handle) return pThread->event.fds[0]; } +#define run_mutex_init(fkt, mux, arg) run_mutex_init_(fkt, #fkt, mux, arg) +static BOOL run_mutex_init_(int (*fkt)(pthread_mutex_t*, const pthread_mutexattr_t*), + const char* name, pthread_mutex_t* mutex, + const pthread_mutexattr_t* mutexattr) +{ + int rc; + + WINPR_ASSERT(fkt); + WINPR_ASSERT(mutex); + + rc = fkt(mutex, mutexattr); + if (rc != 0) + { + WLog_WARN(TAG, "[%s] failed with [%s]", name, strerror(rc)); + } + return rc == 0; +} + +#define run_mutex_fkt(fkt, mux) run_mutex_fkt_(fkt, #fkt, mux) +static BOOL run_mutex_fkt_(int (*fkt)(pthread_mutex_t* mux), const char* name, + pthread_mutex_t* mutex) +{ + int rc; + + WINPR_ASSERT(fkt); + WINPR_ASSERT(mutex); + + rc = fkt(mutex); + if (rc != 0) + { + WLog_WARN(TAG, "[%s] failed with [%s]", name, strerror(rc)); + } + return rc == 0; +} + +#define run_cond_init(fkt, cond, arg) run_cond_init_(fkt, #fkt, cond, arg) +static BOOL run_cond_init_(int (*fkt)(pthread_cond_t*, const pthread_condattr_t*), const char* name, + pthread_cond_t* condition, const pthread_condattr_t* conditionattr) +{ + int rc; + + WINPR_ASSERT(fkt); + WINPR_ASSERT(condition); + + rc = fkt(condition, conditionattr); + if (rc != 0) + { + WLog_WARN(TAG, "[%s] failed with [%s]", name, strerror(rc)); + } + return rc == 0; +} + +#define run_cond_fkt(fkt, cond) run_cond_fkt_(fkt, #fkt, cond) +static BOOL run_cond_fkt_(int (*fkt)(pthread_cond_t* mux), const char* name, + pthread_cond_t* condition) +{ + int rc; + + WINPR_ASSERT(fkt); + WINPR_ASSERT(condition); + + rc = fkt(condition); + if (rc != 0) + { + WLog_WARN(TAG, "[%s] failed with [%s]", name, strerror(rc)); + } + return rc == 0; +} + +static int pthread_mutex_checked_unlock(pthread_mutex_t* mutex) +{ + WINPR_ASSERT(mutex); + WINPR_ASSERT(pthread_mutex_trylock(mutex) == EBUSY); + return pthread_mutex_unlock(mutex); +} + +static BOOL mux_condition_bundle_init(mux_condition_bundle* bundle) +{ + WINPR_ASSERT(bundle); + + bundle->val = FALSE; + if (!run_mutex_init(pthread_mutex_init, &bundle->mux, NULL)) + return FALSE; + + if (!run_cond_init(pthread_cond_init, &bundle->cond, NULL)) + return FALSE; + return TRUE; +} + +static void mux_condition_bundle_uninit(mux_condition_bundle* bundle) +{ + mux_condition_bundle empty = { 0 }; + + WINPR_ASSERT(bundle); + + run_cond_fkt(pthread_cond_destroy, &bundle->cond); + run_mutex_fkt(pthread_mutex_destroy, &bundle->mux); + *bundle = empty; +} + +static BOOL mux_condition_bundle_signal(mux_condition_bundle* bundle) +{ + BOOL rc = TRUE; + WINPR_ASSERT(bundle); + + if (!run_mutex_fkt(pthread_mutex_lock, &bundle->mux)) + return FALSE; + bundle->val = TRUE; + if (!run_cond_fkt(pthread_cond_signal, &bundle->cond)) + rc = FALSE; + if (!run_mutex_fkt(pthread_mutex_checked_unlock, &bundle->mux)) + rc = FALSE; + return rc; +} + +static BOOL mux_condition_bundle_lock(mux_condition_bundle* bundle) +{ + WINPR_ASSERT(bundle); + return run_mutex_fkt(pthread_mutex_lock, &bundle->mux); +} + +static BOOL mux_condition_bundle_unlock(mux_condition_bundle* bundle) +{ + WINPR_ASSERT(bundle); + return run_mutex_fkt(pthread_mutex_checked_unlock, &bundle->mux); +} + +static BOOL mux_condition_bundle_wait(mux_condition_bundle* bundle, const char* name) +{ + BOOL rc = FALSE; + + WINPR_ASSERT(bundle); + WINPR_ASSERT(name); + WINPR_ASSERT(pthread_mutex_trylock(&bundle->mux) == EBUSY); + + while (!bundle->val) + { + int r = pthread_cond_wait(&bundle->cond, &bundle->mux); + if (r != 0) + { + WLog_ERR(TAG, "failed to wait for %s [%s]", name, strerror(r)); + switch (r) + { + case ENOTRECOVERABLE: + case EPERM: + case ETIMEDOUT: + case EINVAL: + goto fail; + + default: + break; + } + } + } + + rc = bundle->val; + +fail: + return rc; +} + +static BOOL signal_thread_ready(WINPR_THREAD* thread) +{ + WINPR_ASSERT(thread); + + return mux_condition_bundle_signal(&thread->isCreated); +} + +static BOOL signal_thread_is_running(WINPR_THREAD* thread) +{ + WINPR_ASSERT(thread); + + return mux_condition_bundle_signal(&thread->isRunning); +} + static DWORD ThreadCleanupHandle(HANDLE handle) { + DWORD status = WAIT_FAILED; WINPR_THREAD* thread = (WINPR_THREAD*)handle; if (!ThreadIsHandled(handle)) return WAIT_FAILED; - if (pthread_mutex_lock(&thread->mutex)) + if (!run_mutex_fkt(pthread_mutex_lock, &thread->mutex)) return WAIT_FAILED; if (!thread->joined) @@ -144,17 +323,19 @@ static DWORD ThreadCleanupHandle(HANDLE handle) if (status != 0) { WLog_ERR(TAG, "pthread_join failure: [%d] %s", status, strerror(status)); - pthread_mutex_unlock(&thread->mutex); - return WAIT_FAILED; + goto fail; } else thread->joined = TRUE; } - if (pthread_mutex_unlock(&thread->mutex)) + status = WAIT_OBJECT_0; + +fail: + if (!run_mutex_fkt(pthread_mutex_checked_unlock, &thread->mutex)) return WAIT_FAILED; - return WAIT_OBJECT_0; + return status; } static HANDLE_OPS ops = { ThreadIsHandled, @@ -218,7 +399,8 @@ static void dump_thread(WINPR_THREAD* thread) free(msg); } - +#else + WINPR_UNUSED(thread); #endif } @@ -236,6 +418,7 @@ static BOOL reset_event(WINPR_THREAD* thread) return winpr_event_reset(&thread->event); } +#if defined(WITH_THREAD_LIST) static BOOL thread_compare(const void* a, const void* b) { const pthread_t* p1 = a; @@ -243,12 +426,13 @@ static BOOL thread_compare(const void* a, const void* b) BOOL rc = pthread_equal(*p1, *p2); return rc; } +#endif static INIT_ONCE threads_InitOnce = INIT_ONCE_STATIC_INIT; static pthread_t mainThreadId; static DWORD currentThreadTlsIndex = TLS_OUT_OF_INDEXES; -BOOL initializeThreads(PINIT_ONCE InitOnce, PVOID Parameter, PVOID* Context) +static BOOL initializeThreads(PINIT_ONCE InitOnce, PVOID Parameter, PVOID* Context) { if (!apc_init(&mainThread.apc)) { @@ -265,10 +449,54 @@ BOOL initializeThreads(PINIT_ONCE InitOnce, PVOID Parameter, PVOID* Context) WLog_ERR(TAG, "Major bug, unable to allocate a TLS value for currentThread"); } +#if defined(WITH_THREAD_LIST) + thread_list = ListDictionary_New(TRUE); + + if (!thread_list) + { + WLog_ERR(TAG, "Couldn't create global thread list"); + goto error_thread_list; + } + + thread_list->objectKey.fnObjectEquals = thread_compare; +#endif + out: return TRUE; } +static BOOL signal_and_wait_for_ready(WINPR_THREAD* thread) +{ + BOOL res = FALSE; + + WINPR_ASSERT(thread); + + if (!mux_condition_bundle_lock(&thread->isRunning)) + return FALSE; + + if (!signal_thread_ready(thread)) + goto fail; + + if (!mux_condition_bundle_wait(&thread->isRunning, "threadIsRunning")) + goto fail; + +#if defined(WITH_THREAD_LIST) + if (!ListDictionary_Contains(thread_list, &thread->thread)) + { + WLog_ERR(TAG, "Thread not in thread_list, startup failed!"); + goto fail; + } +#endif + + res = TRUE; + +fail: + if (!mux_condition_bundle_unlock(&thread->isRunning)) + return FALSE; + + return res; +} + /* Thread launcher function responsible for registering * cleanup handlers and calling pthread_exit, if not done * in thread function. */ @@ -296,23 +524,9 @@ static void* thread_launcher(void* arg) goto exit; } - if (pthread_mutex_lock(&thread->threadIsReadyMutex)) + if (!signal_and_wait_for_ready(thread)) goto exit; - if (!ListDictionary_Contains(thread_list, &thread->thread)) - { - if (pthread_cond_wait(&thread->threadIsReady, &thread->threadIsReadyMutex) != 0) - { - WLog_ERR(TAG, "The thread could not be made ready"); - pthread_mutex_unlock(&thread->threadIsReadyMutex); - goto exit; - } - } - - if (pthread_mutex_unlock(&thread->threadIsReadyMutex)) - goto exit; - - assert(ListDictionary_Contains(thread_list, &thread->thread)); rc = fkt(thread->lpParameter); exit: @@ -325,6 +539,8 @@ static void* thread_launcher(void* arg) set_event(thread); + signal_thread_ready(thread); + if (thread->detached || !thread->started) cleanup_handle(thread); } @@ -334,7 +550,14 @@ static void* thread_launcher(void* arg) static BOOL winpr_StartThread(WINPR_THREAD* thread) { - pthread_attr_t attr; + BOOL rc = FALSE; + BOOL locked = FALSE; + pthread_attr_t attr = { 0 }; + + if (!mux_condition_bundle_lock(&thread->isCreated)) + return FALSE; + locked = TRUE; + pthread_attr_init(&attr); pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE); @@ -344,35 +567,44 @@ static BOOL winpr_StartThread(WINPR_THREAD* thread) thread->started = TRUE; reset_event(thread); +#if defined(WITH_THREAD_LIST) + if (!ListDictionary_Add(thread_list, &thread->thread, thread)) + { + WLog_ERR(TAG, "failed to add the thread to the thread list"); + goto error; + } +#endif + if (pthread_create(&thread->thread, &attr, thread_launcher, thread)) goto error; - if (pthread_mutex_lock(&thread->threadIsReadyMutex)) + if (!mux_condition_bundle_wait(&thread->isCreated, "threadIsCreated")) goto error; - if (!ListDictionary_Add(thread_list, &thread->thread, thread)) - { - WLog_ERR(TAG, "failed to add the thread to the thread list"); - pthread_mutex_unlock(&thread->threadIsReadyMutex); + locked = FALSE; + if (!mux_condition_bundle_unlock(&thread->isCreated)) goto error; - } - if (pthread_cond_signal(&thread->threadIsReady) != 0) + if (!signal_thread_is_running(thread)) { WLog_ERR(TAG, "failed to signal the thread was ready"); - pthread_mutex_unlock(&thread->threadIsReadyMutex); goto error; } - if (pthread_mutex_unlock(&thread->threadIsReadyMutex)) - goto error; - - pthread_attr_destroy(&attr); - dump_thread(thread); - return TRUE; + rc = TRUE; error: + if (locked) + { + if (!mux_condition_bundle_unlock(&thread->isCreated)) + rc = FALSE; + } + pthread_attr_destroy(&attr); - return FALSE; + + if (rc) + dump_thread(thread); + + return rc; } HANDLE CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes, SIZE_T dwStackSize, @@ -380,8 +612,7 @@ HANDLE CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes, SIZE_T dwStackSize DWORD dwCreationFlags, LPDWORD lpThreadId) { HANDLE handle; - WINPR_THREAD* thread; - thread = (WINPR_THREAD*)calloc(1, sizeof(WINPR_THREAD)); + WINPR_THREAD* thread = (WINPR_THREAD*)calloc(1, sizeof(WINPR_THREAD)); if (!thread) return NULL; @@ -399,104 +630,66 @@ HANDLE CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes, SIZE_T dwStackSize if (!winpr_event_init(&thread->event)) { WLog_ERR(TAG, "failed to create event"); - goto error_event; + goto fail; } - if (pthread_mutex_init(&thread->mutex, NULL) != 0) + if (!run_mutex_init(pthread_mutex_init, &thread->mutex, NULL)) { WLog_ERR(TAG, "failed to initialize thread mutex"); - goto error_mutex; + goto fail; } if (!apc_init(&thread->apc)) { WLog_ERR(TAG, "failed to initialize APC"); - goto error_APC; + goto fail; } - if (pthread_mutex_init(&thread->threadIsReadyMutex, NULL) != 0) - { - WLog_ERR(TAG, "failed to initialize a mutex for a condition variable"); - goto error_thread_ready_mutex; - } - - if (pthread_cond_init(&thread->threadIsReady, NULL) != 0) - { - WLog_ERR(TAG, "failed to initialize a condition variable"); - goto error_thread_ready; - } + if (!mux_condition_bundle_init(&thread->isCreated)) + goto fail; + if (!mux_condition_bundle_init(&thread->isRunning)) + goto fail; WINPR_HANDLE_SET_TYPE_AND_MODE(thread, HANDLE_TYPE_THREAD, WINPR_FD_READ); handle = (HANDLE)thread; - if (!thread_list) - { - InitOnceExecuteOnce(&threads_InitOnce, initializeThreads, NULL, NULL); - thread_list = ListDictionary_New(TRUE); - - if (!thread_list) - { - WLog_ERR(TAG, "Couldn't create global thread list"); - goto error_thread_list; - } - - thread_list->objectKey.fnObjectEquals = thread_compare; - } + InitOnceExecuteOnce(&threads_InitOnce, initializeThreads, NULL, NULL); if (!(dwCreationFlags & CREATE_SUSPENDED)) { if (!winpr_StartThread(thread)) - goto error_thread_list; + goto fail; } else { if (!set_event(thread)) - goto error_thread_list; + goto fail; } return handle; -error_thread_list: - pthread_cond_destroy(&thread->threadIsReady); -error_thread_ready: - pthread_mutex_destroy(&thread->threadIsReadyMutex); -error_thread_ready_mutex: - apc_uninit(&thread->apc); -error_APC: - pthread_mutex_destroy(&thread->mutex); -error_mutex: - winpr_event_uninit(&thread->event); -error_event: - free(thread); +fail: + cleanup_handle(thread); return NULL; } void cleanup_handle(void* obj) { - int rc; WINPR_THREAD* thread = (WINPR_THREAD*)obj; + if (!thread) + return; if (!apc_uninit(&thread->apc)) WLog_ERR(TAG, "failed to destroy APC"); - rc = pthread_cond_destroy(&thread->threadIsReady); - if (rc) - WLog_ERR(TAG, "failed to destroy thread->threadIsReady [%d] %s (%d)", rc, strerror(errno), - errno); - - rc = pthread_mutex_destroy(&thread->threadIsReadyMutex); - if (rc) - WLog_ERR(TAG, "failed to destroy thread->threadIsReadyMutex [%d] %s (%d)", rc, - strerror(errno), errno); - - rc = pthread_mutex_destroy(&thread->mutex); - if (rc) - WLog_ERR(TAG, "failed to destroy thread->mutex [%d] %s (%d)", rc, strerror(errno), errno); + mux_condition_bundle_uninit(&thread->isCreated); + mux_condition_bundle_uninit(&thread->isRunning); + run_mutex_fkt(pthread_mutex_destroy, &thread->mutex); winpr_event_uninit(&thread->event); - if (thread_list && ListDictionary_Contains(thread_list, &thread->thread)) - ListDictionary_Remove(thread_list, &thread->thread); - +#if defined(WITH_THREAD_LIST) + ListDictionary_Remove(thread_list, &thread->thread); +#endif #if defined(WITH_DEBUG_THREADS) if (thread->create_stack) @@ -513,6 +706,7 @@ BOOL ThreadCloseHandle(HANDLE handle) { WINPR_THREAD* thread = (WINPR_THREAD*)handle; +#if defined(WITH_THREAD_LIST) if (!thread_list) { WLog_ERR(TAG, "Thread list does not exist, check call!"); @@ -526,6 +720,7 @@ BOOL ThreadCloseHandle(HANDLE handle) else { ListDictionary_Lock(thread_list); +#endif dump_thread(thread); if ((thread->started) && (WaitForSingleObject(thread, 0) != WAIT_OBJECT_0)) @@ -539,14 +734,10 @@ BOOL ThreadCloseHandle(HANDLE handle) cleanup_handle(thread); } +#if defined(WITH_THREAD_LIST) ListDictionary_Unlock(thread_list); - - if (ListDictionary_Count(thread_list) < 1) - { - ListDictionary_Free(thread_list); - thread_list = NULL; - } } +#endif return TRUE; } @@ -562,6 +753,7 @@ HANDLE CreateRemoteThread(HANDLE hProcess, LPSECURITY_ATTRIBUTES lpThreadAttribu VOID ExitThread(DWORD dwExitCode) { +#if defined(WITH_THREAD_LIST) DWORD rc; pthread_t tid = pthread_self(); @@ -586,7 +778,7 @@ VOID ExitThread(DWORD dwExitCode) WINPR_THREAD* thread; ListDictionary_Lock(thread_list); thread = ListDictionary_GetItemValue(thread_list, &tid); - assert(thread); + WINPR_ASSERT(thread); thread->exited = TRUE; thread->dwExitCode = dwExitCode; #if defined(WITH_DEBUG_THREADS) @@ -601,6 +793,9 @@ VOID ExitThread(DWORD dwExitCode) pthread_exit((void*)(size_t)rc); } +#else + WINPR_UNUSED(dwExitCode); +#endif } BOOL GetExitCodeThread(HANDLE hThread, LPDWORD lpExitCode) @@ -657,7 +852,7 @@ typedef struct ULONG_PTR completionArg; } UserApcItem; -void userAPC(LPVOID arg) +static void userAPC(LPVOID arg) { UserApcItem* userApc = (UserApcItem*)arg; @@ -670,7 +865,6 @@ DWORD QueueUserAPC(PAPCFUNC pfnAPC, HANDLE hThread, ULONG_PTR dwData) { ULONG Type; WINPR_HANDLE* Object; - WINPR_THREAD* thread; WINPR_APC_ITEM* apc; UserApcItem* apcItem; @@ -683,7 +877,6 @@ DWORD QueueUserAPC(PAPCFUNC pfnAPC, HANDLE hThread, ULONG_PTR dwData) SetLastError(ERROR_INVALID_PARAMETER); return (DWORD)0; } - thread = (WINPR_THREAD*)Object; apcItem = calloc(1, sizeof(*apcItem)); if (!apcItem) @@ -715,21 +908,21 @@ DWORD ResumeThread(HANDLE hThread) thread = (WINPR_THREAD*)Object; - if (pthread_mutex_lock(&thread->mutex)) + if (!run_mutex_fkt(pthread_mutex_lock, &thread->mutex)) return (DWORD)-1; if (!thread->started) { if (!winpr_StartThread(thread)) { - pthread_mutex_unlock(&thread->mutex); + run_mutex_fkt(pthread_mutex_checked_unlock, &thread->mutex); return (DWORD)-1; } } else WLog_WARN(TAG, "Thread already started!"); - if (pthread_mutex_unlock(&thread->mutex)) + if (!run_mutex_fkt(pthread_mutex_checked_unlock, &thread->mutex)) return (DWORD)-1; return 0; @@ -767,7 +960,7 @@ BOOL TerminateThread(HANDLE hThread, DWORD dwExitCode) thread->exited = TRUE; thread->dwExitCode = dwExitCode; - if (pthread_mutex_lock(&thread->mutex)) + if (!run_mutex_fkt(pthread_mutex_lock, &thread->mutex)) return FALSE; #ifndef ANDROID @@ -776,16 +969,16 @@ BOOL TerminateThread(HANDLE hThread, DWORD dwExitCode) WLog_ERR(TAG, "Function not supported on this platform!"); #endif - if (pthread_mutex_unlock(&thread->mutex)) + if (!run_mutex_fkt(pthread_mutex_checked_unlock, &thread->mutex)) return FALSE; set_event(thread); return TRUE; } -#if defined(WITH_DEBUG_THREADS) VOID DumpThreadHandles(void) { +#if defined(WITH_DEBUG_THREADS) char** msg; size_t used, i; void* stack = winpr_backtrace(20); @@ -801,6 +994,7 @@ VOID DumpThreadHandles(void) winpr_backtrace_free(stack); WLog_DBG(TAG, "---------------- Start Dumping thread handles -----------"); +#if defined(WITH_THREAD_LIST) if (!thread_list) { WLog_DBG(TAG, "All threads properly shut down and disposed of."); @@ -844,8 +1038,9 @@ VOID DumpThreadHandles(void) free(keys); ListDictionary_Unlock(thread_list); } +#endif WLog_DBG(TAG, "---------------- End Dumping thread handles -------------"); -} #endif +} #endif diff --git a/winpr/libwinpr/thread/thread.h b/winpr/libwinpr/thread/thread.h index f187e263093b..a533685e6585 100644 --- a/winpr/libwinpr/thread/thread.h +++ b/winpr/libwinpr/thread/thread.h @@ -32,47 +32,63 @@ #include "../synch/event.h" #include "apc.h" +#ifdef __GNUC__ +#define ALIGN64 __attribute__((aligned(8))) +#else +#ifdef _WIN32 +#define ALIGN64 __declspec(align(8)) +#else +#define ALIGN64 +#endif +#endif + typedef void* (*pthread_start_routine)(void*); typedef struct winpr_APC_item WINPR_APC_ITEM; +typedef struct +{ + ALIGN64 pthread_mutex_t mux; + ALIGN64 pthread_cond_t cond; + ALIGN64 BOOL val; +} mux_condition_bundle; + struct winpr_thread { WINPR_HANDLE_DEF(); - BOOL started; - WINPR_EVENT_IMPL event; - BOOL mainProcess; - BOOL detached; - BOOL joined; - BOOL exited; - DWORD dwExitCode; - pthread_t thread; - SIZE_T dwStackSize; - LPVOID lpParameter; - pthread_mutex_t mutex; - pthread_mutex_t threadIsReadyMutex; - pthread_cond_t threadIsReady; - LPTHREAD_START_ROUTINE lpStartAddress; - LPSECURITY_ATTRIBUTES lpThreadAttributes; - APC_QUEUE apc; + ALIGN64 BOOL started; + ALIGN64 WINPR_EVENT_IMPL event; + ALIGN64 BOOL mainProcess; + ALIGN64 BOOL detached; + ALIGN64 BOOL joined; + ALIGN64 BOOL exited; + ALIGN64 DWORD dwExitCode; + ALIGN64 pthread_t thread; + ALIGN64 SIZE_T dwStackSize; + ALIGN64 LPVOID lpParameter; + ALIGN64 pthread_mutex_t mutex; + mux_condition_bundle isRunning; + mux_condition_bundle isCreated; + ALIGN64 LPTHREAD_START_ROUTINE lpStartAddress; + ALIGN64 LPSECURITY_ATTRIBUTES lpThreadAttributes; + ALIGN64 APC_QUEUE apc; #if defined(WITH_DEBUG_THREADS) - void* create_stack; - void* exit_stack; + ALIGN64 void* create_stack; + ALIGN64 void* exit_stack; #endif }; typedef struct winpr_thread WINPR_THREAD; WINPR_THREAD* winpr_GetCurrentThread(VOID); -struct winpr_process +typedef struct { WINPR_HANDLE_DEF(); pid_t pid; int status; DWORD dwExitCode; -}; -typedef struct winpr_process WINPR_PROCESS; +} WINPR_PROCESS; #endif From 4385dc4f7a1d7342c4cef194d31c82a01b8cca0a Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Wed, 27 Apr 2022 17:06:48 +0200 Subject: [PATCH 143/496] Do not mark WinPR implementation of ExitThread as noreturn --- winpr/include/winpr/thread.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/winpr/include/winpr/thread.h b/winpr/include/winpr/thread.h index 4e603b3dcacf..c7961e90da9e 100644 --- a/winpr/include/winpr/thread.h +++ b/winpr/include/winpr/thread.h @@ -207,7 +207,7 @@ extern "C" LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId); - WINPR_API DECLSPEC_NORETURN VOID ExitThread(DWORD dwExitCode); + WINPR_API VOID ExitThread(DWORD dwExitCode); WINPR_API BOOL GetExitCodeThread(HANDLE hThread, LPDWORD lpExitCode); WINPR_API HANDLE _GetCurrentThread(void); From 8b0900c0a6ccf7a94a69059e6554dd22bd55eb44 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Wed, 27 Apr 2022 17:08:24 +0200 Subject: [PATCH 144/496] Changelog --- ChangeLog | 1 + 1 file changed, 1 insertion(+) diff --git a/ChangeLog b/ChangeLog index c502470054be..618ce1a8243e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -4,6 +4,7 @@ Noteworthy changes: Fixed issues: * Backported #7440: wlfreerdp appid +* Backported #7833: Refactored WinPR thread locking # 2022-04-25 Version 2.7.0 From e31caf096454a893f36d7759cd0fa9739a10e649 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Mon, 20 Sep 2021 08:57:08 +0200 Subject: [PATCH 145/496] Fixed leak in TestPipeCreateNamedPipeOverlapped. (cherry picked from commit 1ee8370f28f1f3542d2559ae23ad670434b303b6) --- .../pipe/test/TestPipeCreateNamedPipeOverlapped.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/winpr/libwinpr/pipe/test/TestPipeCreateNamedPipeOverlapped.c b/winpr/libwinpr/pipe/test/TestPipeCreateNamedPipeOverlapped.c index 6c8d3be2e29c..ba6d80133007 100644 --- a/winpr/libwinpr/pipe/test/TestPipeCreateNamedPipeOverlapped.c +++ b/winpr/libwinpr/pipe/test/TestPipeCreateNamedPipeOverlapped.c @@ -19,7 +19,7 @@ static BYTE CLIENT_MESSAGE[PIPE_BUFFER_SIZE]; static BOOL bClientSuccess = FALSE; static BOOL bServerSuccess = FALSE; -static HANDLE serverReadyEvent; +static HANDLE serverReadyEvent = NULL; static LPTSTR lpszPipeName = _T("\\\\.\\pipe\\winpr_test_pipe_overlapped"); @@ -332,8 +332,8 @@ static DWORD WINAPI named_pipe_server_thread(LPVOID arg) int TestPipeCreateNamedPipeOverlapped(int argc, char* argv[]) { - HANDLE ClientThread; - HANDLE ServerThread; + HANDLE ClientThread = NULL; + HANDLE ServerThread = NULL; int result = -1; FillMemory(SERVER_MESSAGE, PIPE_BUFFER_SIZE, 0xAA); @@ -372,6 +372,13 @@ int TestPipeCreateNamedPipeOverlapped(int argc, char* argv[]) out: + if (ClientThread) + CloseHandle(ClientThread); + if (ServerThread) + CloseHandle(ServerThread); + if (serverReadyEvent) + CloseHandle(serverReadyEvent); + #ifndef _WIN32 if (result == 0) { From c6c867613296a912eacef38cb660891b8d080310 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Mon, 20 Sep 2021 08:50:05 +0200 Subject: [PATCH 146/496] Cleaned up NamedPipeOverlapped test. (cherry picked from commit aeb2415af95d596fba924b52de4bb3b5c842cf49) --- .../pipe/test/TestPipeCreateNamedPipeOverlapped.c | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/winpr/libwinpr/pipe/test/TestPipeCreateNamedPipeOverlapped.c b/winpr/libwinpr/pipe/test/TestPipeCreateNamedPipeOverlapped.c index ba6d80133007..ba2fce09a074 100644 --- a/winpr/libwinpr/pipe/test/TestPipeCreateNamedPipeOverlapped.c +++ b/winpr/libwinpr/pipe/test/TestPipeCreateNamedPipeOverlapped.c @@ -30,11 +30,13 @@ static DWORD WINAPI named_pipe_client_thread(LPVOID arg) HANDLE hNamedPipe = NULL; BYTE* lpReadBuffer = NULL; BOOL fSuccess = FALSE; - OVERLAPPED overlapped; + OVERLAPPED overlapped = { 0 }; DWORD nNumberOfBytesToRead; DWORD nNumberOfBytesToWrite; DWORD NumberOfBytesTransferred; + WINPR_UNUSED(arg); + status = WaitForSingleObject(serverReadyEvent, PIPE_TIMEOUT_MS); if (status != WAIT_OBJECT_0) { @@ -43,8 +45,6 @@ static DWORD WINAPI named_pipe_client_thread(LPVOID arg) } /* 1: initialize overlapped structure */ - - ZeroMemory(&overlapped, sizeof(OVERLAPPED)); if (!(hEvent = CreateEvent(NULL, TRUE, FALSE, NULL))) { printf("client: CreateEvent failure: %" PRIu32 "\n", GetLastError()); @@ -159,16 +159,16 @@ static DWORD WINAPI named_pipe_server_thread(LPVOID arg) HANDLE hEvent = NULL; HANDLE hNamedPipe = NULL; BYTE* lpReadBuffer = NULL; - OVERLAPPED overlapped; + OVERLAPPED overlapped = { 0 }; BOOL fSuccess = FALSE; BOOL fConnected = FALSE; DWORD nNumberOfBytesToRead; DWORD nNumberOfBytesToWrite; DWORD NumberOfBytesTransferred; - /* 1: initialize overlapped structure */ + WINPR_UNUSED(arg); - ZeroMemory(&overlapped, sizeof(OVERLAPPED)); + /* 1: initialize overlapped structure */ if (!(hEvent = CreateEvent(NULL, TRUE, FALSE, NULL))) { printf("server: CreateEvent failure: %" PRIu32 "\n", GetLastError()); @@ -349,8 +349,7 @@ int TestPipeCreateNamedPipeOverlapped(int argc, char* argv[]) printf("CreateThread (client) failed: %" PRIu32 "\n", GetLastError()); goto out; } - if (!(ServerThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)named_pipe_server_thread, - NULL, 0, NULL))) + if (!(ServerThread = CreateThread(NULL, 0, named_pipe_server_thread, NULL, 0, NULL))) { printf("CreateThread (server) failed: %" PRIu32 "\n", GetLastError()); goto out; From b5dbe5f14dc6d2c47e86557dd68eba4aa2ca30af Mon Sep 17 00:00:00 2001 From: 2fly2 Date: Wed, 27 Apr 2022 17:37:57 +0800 Subject: [PATCH 147/496] fix restore a maximized window when it is minimized Signed-off-by: 2fly2 (cherry picked from commit ee8cf9e02387f0531918bf5a4bb0419c414cc37a) --- client/X11/xf_event.c | 2 +- client/X11/xf_window.c | 6 ++++++ client/X11/xf_window.h | 3 +++ 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/client/X11/xf_event.c b/client/X11/xf_event.c index 99577b1a1233..5138d16ed615 100644 --- a/client/X11/xf_event.c +++ b/client/X11/xf_event.c @@ -766,7 +766,7 @@ static BOOL xf_event_MapNotify(xfContext* xfc, const XMapEvent* event, BOOL app) * Doing this here would inhibit the ability to restore a maximized window * that is minimized back to the maximized state */ - xf_rail_send_client_system_command(xfc, appWindow->windowId, SC_RESTORE); + // xf_rail_send_client_system_command(xfc, appWindow->windowId, SC_RESTORE); appWindow->is_mapped = TRUE; } } diff --git a/client/X11/xf_window.c b/client/X11/xf_window.c index 5c50a077ba89..810cac30c51e 100644 --- a/client/X11/xf_window.c +++ b/client/X11/xf_window.c @@ -775,6 +775,9 @@ int xf_AppWindowCreate(xfContext* xfc, xfAppWindow* appWindow) appWindow->is_mapped = FALSE; appWindow->is_transient = FALSE; appWindow->rail_state = 0; + appWindow->maxVert = FALSE; + appWindow->maxHorz = FALSE; + appWindow->minimized = FALSE; appWindow->rail_ignore_configure = FALSE; appWindow->handle = XCreateWindow(xfc->display, RootWindowOfScreen(xfc->screen), appWindow->x, appWindow->y, appWindow->width, appWindow->height, 0, @@ -937,11 +940,14 @@ void xf_ShowWindow(xfContext* xfc, xfAppWindow* appWindow, BYTE state) break; case WINDOW_SHOW_MINIMIZED: + appWindow->minimized = TRUE; XIconifyWindow(xfc->display, appWindow->handle, xfc->screen_number); break; case WINDOW_SHOW_MAXIMIZED: /* Set the window as maximized */ + appWindow->maxHorz = TRUE; + appWindow->maxVert = TRUE; xf_SendClientEvent(xfc, appWindow->handle, xfc->_NET_WM_STATE, 4, _NET_WM_STATE_ADD, xfc->_NET_WM_STATE_MAXIMIZED_VERT, xfc->_NET_WM_STATE_MAXIMIZED_HORZ, 0); diff --git a/client/X11/xf_window.h b/client/X11/xf_window.h index 3adaa3c7f567..9f55ac761cd7 100644 --- a/client/X11/xf_window.h +++ b/client/X11/xf_window.h @@ -137,6 +137,9 @@ struct xf_app_window BOOL is_transient; xfLocalMove local_move; BYTE rail_state; + BOOL maxVert; + BOOL maxHorz; + BOOL minimized; BOOL rail_ignore_configure; }; From f392f6de2ef14a7f0533d3edebc21036cf03fa27 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Wed, 27 Apr 2022 18:19:53 +0200 Subject: [PATCH 148/496] Changelog --- ChangeLog | 1 + 1 file changed, 1 insertion(+) diff --git a/ChangeLog b/ChangeLog index 618ce1a8243e..eddd6f9ea70b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -4,6 +4,7 @@ Noteworthy changes: Fixed issues: * Backported #7440: wlfreerdp appid +* Backported #7832: RAIL window restore * Backported #7833: Refactored WinPR thread locking # 2022-04-25 Version 2.7.0 From fb50329a9d5fda094d1a7896fa17bc9b85b43f94 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Wed, 27 Apr 2022 18:27:55 +0200 Subject: [PATCH 149/496] Fixed #7837: Overallocate zgfx output buffers Some decoders require additional byte alignment to prevent out of bound reads (cherry picked from commit ce60606e190ceb72ef2ea92fe32e419cb9dd447e) --- libfreerdp/codec/zgfx.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/libfreerdp/codec/zgfx.c b/libfreerdp/codec/zgfx.c index 1a2878bd9a6a..20fbd3545711 100644 --- a/libfreerdp/codec/zgfx.c +++ b/libfreerdp/codec/zgfx.c @@ -363,6 +363,17 @@ static BOOL zgfx_decompress_segment(ZGFX_CONTEXT* zgfx, wStream* stream, size_t return TRUE; } +/* Allocate the buffers a bit larger. + * + * Due to optimizations some h264 decoders will read data beyond + * the actual available data, so ensure that it will never be a + * out of bounds read. + */ +static BYTE* aligned_zgfx_malloc(size_t size) +{ + return malloc(size + 64); +} + int zgfx_decompress(ZGFX_CONTEXT* zgfx, const BYTE* pSrcData, UINT32 SrcSize, BYTE** ppDstData, UINT32* pDstSize, UINT32 flags) { @@ -386,7 +397,7 @@ int zgfx_decompress(ZGFX_CONTEXT* zgfx, const BYTE* pSrcData, UINT32 SrcSize, BY *ppDstData = NULL; if (zgfx->OutputCount > 0) - *ppDstData = (BYTE*)malloc(zgfx->OutputCount); + *ppDstData = aligned_zgfx_malloc(zgfx->OutputCount); if (!*ppDstData) goto fail; @@ -412,7 +423,7 @@ int zgfx_decompress(ZGFX_CONTEXT* zgfx, const BYTE* pSrcData, UINT32 SrcSize, BY if (Stream_GetRemainingLength(stream) < segmentCount * sizeof(UINT32)) goto fail; - pConcatenated = (BYTE*)malloc(uncompressedSize); + pConcatenated = aligned_zgfx_malloc(uncompressedSize); if (!pConcatenated) goto fail; From 1695685403153952da0514fd42ad3c42946f0d47 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Wed, 27 Apr 2022 18:30:14 +0200 Subject: [PATCH 150/496] Updated changelog --- ChangeLog | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index eddd6f9ea70b..72cc881f3080 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,8 +1,9 @@ # 20xx-xx-xx Version 2.x.x Noteworthy changes: - + Fixed issues: +* Fixed #7837: Prevent out of bound reads for FFMPEG * Backported #7440: wlfreerdp appid * Backported #7832: RAIL window restore * Backported #7833: Refactored WinPR thread locking From dfd5abc42be3c4b91061243beb54d546b963e9e3 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Wed, 27 Apr 2022 21:44:40 +0200 Subject: [PATCH 151/496] Follow up to #7832: Add NULL checks (cherry picked from commit 8b9ab80ef4f246befe4977f56e6e3cdfc2ecd7a7) --- client/X11/xf_event.c | 58 +++++++++++++++++++++++++++++++++--------- client/X11/xf_window.c | 4 +++ 2 files changed, 50 insertions(+), 12 deletions(-) diff --git a/client/X11/xf_event.c b/client/X11/xf_event.c index 5138d16ed615..747e818b6172 100644 --- a/client/X11/xf_event.c +++ b/client/X11/xf_event.c @@ -24,6 +24,8 @@ #include #include +#include + #include #include @@ -759,7 +761,7 @@ static BOOL xf_event_MapNotify(xfContext* xfc, const XMapEvent* event, BOOL app) { appWindow = xf_AppWindowFromX11Window(xfc, event->window); - if (appWindow) + if (appWindow && (appWindow->rail_state == WINDOW_SHOW)) { /* local restore event */ /* This is now handled as part of the PropertyNotify @@ -777,6 +779,10 @@ static BOOL xf_event_MapNotify(xfContext* xfc, const XMapEvent* event, BOOL app) static BOOL xf_event_UnmapNotify(xfContext* xfc, const XUnmapEvent* event, BOOL app) { xfAppWindow* appWindow; + + WINPR_ASSERT(xfc); + WINPR_ASSERT(event); + xf_keyboard_release_all_keypress(xfc); if (!app) @@ -796,6 +802,9 @@ static BOOL xf_event_UnmapNotify(xfContext* xfc, const XUnmapEvent* event, BOOL static BOOL xf_event_PropertyNotify(xfContext* xfc, const XPropertyEvent* event, BOOL app) { + WINPR_ASSERT(xfc); + WINPR_ASSERT(event); + /* * This section handles sending the appropriate commands to the rail server * when the window has been minimized, maximized, restored locally @@ -830,18 +839,27 @@ static BOOL xf_event_PropertyNotify(xfContext* xfc, const XPropertyEvent* event, if (status) { + if (appWindow) + { + appWindow->maxVert = FALSE; + appWindow->maxHorz = FALSE; + } for (i = 0; i < nitems; i++) { if ((Atom)((UINT16**)prop)[i] == XInternAtom(xfc->display, "_NET_WM_STATE_MAXIMIZED_VERT", False)) { maxVert = TRUE; + if (appWindow) + appWindow->maxVert = TRUE; } if ((Atom)((UINT16**)prop)[i] == XInternAtom(xfc->display, "_NET_WM_STATE_MAXIMIZED_HORZ", False)) { maxHorz = TRUE; + if (appWindow) + appWindow->maxHorz = TRUE; } } @@ -858,9 +876,17 @@ static BOOL xf_event_PropertyNotify(xfContext* xfc, const XPropertyEvent* event, { /* If the window is in the iconic state */ if (((UINT32)*prop == 3)) + { minimized = TRUE; + if (appWindow) + appWindow->minimized = TRUE; + } else + { minimized = FALSE; + if (appWindow) + appWindow->minimized = FALSE; + } minimizedChanged = TRUE; XFree(prop); @@ -869,22 +895,30 @@ static BOOL xf_event_PropertyNotify(xfContext* xfc, const XPropertyEvent* event, if (app) { - if (maxVert && maxHorz && !minimized && - (appWindow->rail_state != WINDOW_SHOW_MAXIMIZED)) + WINPR_ASSERT(appWindow); + if (appWindow->maxVert && appWindow->maxHorz && !appWindow->minimized) { - appWindow->rail_state = WINDOW_SHOW_MAXIMIZED; - xf_rail_send_client_system_command(xfc, appWindow->windowId, SC_MAXIMIZE); + if (appWindow->rail_state != WINDOW_SHOW_MAXIMIZED) + { + appWindow->rail_state = WINDOW_SHOW_MAXIMIZED; + xf_rail_send_client_system_command(xfc, appWindow->windowId, SC_MAXIMIZE); + } } - else if (minimized && (appWindow->rail_state != WINDOW_SHOW_MINIMIZED)) + else if (appWindow->minimized) { - appWindow->rail_state = WINDOW_SHOW_MINIMIZED; - xf_rail_send_client_system_command(xfc, appWindow->windowId, SC_MINIMIZE); + if (appWindow->rail_state != WINDOW_SHOW_MINIMIZED) + { + appWindow->rail_state = WINDOW_SHOW_MINIMIZED; + xf_rail_send_client_system_command(xfc, appWindow->windowId, SC_MINIMIZE); + } } - else if (!minimized && !maxVert && !maxHorz && (appWindow->rail_state != WINDOW_SHOW) && - (appWindow->rail_state != WINDOW_HIDE)) + else { - appWindow->rail_state = WINDOW_SHOW; - xf_rail_send_client_system_command(xfc, appWindow->windowId, SC_RESTORE); + if (appWindow->rail_state != WINDOW_SHOW && appWindow->rail_state != WINDOW_HIDE) + { + appWindow->rail_state = WINDOW_SHOW; + xf_rail_send_client_system_command(xfc, appWindow->windowId, SC_RESTORE); + } } } else if (minimizedChanged) diff --git a/client/X11/xf_window.c b/client/X11/xf_window.c index 810cac30c51e..9b5b1c4a6061 100644 --- a/client/X11/xf_window.c +++ b/client/X11/xf_window.c @@ -36,6 +36,7 @@ #include #include +#include #include #include #include @@ -933,6 +934,9 @@ void xf_MoveWindow(xfContext* xfc, xfAppWindow* appWindow, int x, int y, int wid void xf_ShowWindow(xfContext* xfc, xfAppWindow* appWindow, BYTE state) { + WINPR_ASSERT(xfc); + WINPR_ASSERT(appWindow); + switch (state) { case WINDOW_HIDE: From 50bc2d59e881ff70ccb148f28ffe41e6d0cbbe13 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Wed, 7 Jul 2021 08:58:02 +0200 Subject: [PATCH 152/496] Fixed #7158: detection of arm neon. (cherry picked from commit 6e075a6a7dda9ca32be730c947af785080f92aa5) --- CMakeLists.txt | 6 ++++++ libfreerdp/CMakeLists.txt | 7 ++++++- libfreerdp/codec/rfx_neon.c | 4 ++-- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 172832f8fc35..bfdb7a82683f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -598,6 +598,12 @@ if(ANDROID) set (WITH_NEON OFF) endif() + if(ANDROID_ABI STREQUAL arm64-v8a) + # https://github.com/android/ndk/issues/910 + add_definitions(-D__ARM_NEON) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mfloat-abi=softfp") + endif() + if("${CMAKE_BUILD_TYPE}" STREQUAL "Debug") add_definitions(-DNDK_DEBUG=1) diff --git a/libfreerdp/CMakeLists.txt b/libfreerdp/CMakeLists.txt index 5b7461498bfe..0b55388168e0 100644 --- a/libfreerdp/CMakeLists.txt +++ b/libfreerdp/CMakeLists.txt @@ -211,7 +211,12 @@ if(FAAC_FOUND) endif() if(WITH_NEON) - set_source_files_properties(${CODEC_NEON_SRCS} PROPERTIES COMPILE_FLAGS "-mfpu=neon -Wno-unused-variable" ) + check_symbol_exists("_M_AMD64" "" MSVC_ARM64) + check_symbol_exists("__aarch64__" "" ARCH_ARM64) + + if (NOT MSVC_ARM64 AND NOT ARCH_ARM64) + set_source_files_properties(${CODEC_NEON_SRCS} PROPERTIES COMPILE_FLAGS "-mfpu=neon" ) + endif() set(CODEC_SRCS ${CODEC_SRCS} ${CODEC_NEON_SRCS}) endif() diff --git a/libfreerdp/codec/rfx_neon.c b/libfreerdp/codec/rfx_neon.c index c98955adeedf..8a9bd8bcf1c8 100644 --- a/libfreerdp/codec/rfx_neon.c +++ b/libfreerdp/codec/rfx_neon.c @@ -21,7 +21,7 @@ #include "config.h" #endif -#if defined(__ARM_NEON__) +#if defined(__ARM_NEON) #include #include @@ -241,4 +241,4 @@ void rfx_init_neon(RFX_CONTEXT* context) } } -#endif // __ARM_NEON__ +#endif // __ARM_NEON From 8ab59693849f048b1ffe2c9a7e4d52d9090227a2 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Fri, 29 Apr 2022 12:12:12 +0200 Subject: [PATCH 153/496] Simplified CMake variable names (cherry picked from commit bab6e3b3166e9d1737a03b71335edadd437cdadb) --- winpr/libwinpr/utils/CMakeLists.txt | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/winpr/libwinpr/utils/CMakeLists.txt b/winpr/libwinpr/utils/CMakeLists.txt index 2027a607520b..b19d7bddbfbc 100644 --- a/winpr/libwinpr/utils/CMakeLists.txt +++ b/winpr/libwinpr/utils/CMakeLists.txt @@ -17,7 +17,7 @@ set(CMAKE_INCLUDE_CURRENT_DIR ON) -set(${MODULE_PREFIX}_COLLECTIONS_SRCS +set(COLLECTIONS_SRCS collections/Queue.c collections/Stack.c collections/PubSub.c @@ -35,11 +35,11 @@ set(${MODULE_PREFIX}_COLLECTIONS_SRCS collections/MessageQueue.c collections/MessagePipe.c) -set(${MODULE_PREFIX}_LODEPNG_SRCS +set(LODEPNG_SRCS lodepng/lodepng.c lodepng/lodepng.h) -set(${MODULE_PREFIX}_TRIO_SRCS +set(TRIO_SRCS trio/strio.h trio/trio.c trio/trio.h @@ -67,7 +67,7 @@ if (LIBSYSTEMD_FOUND) winpr_library_add_private(${LIBSYSTEMD_LIBRARY}) endif() -set(${MODULE_PREFIX}_WLOG_SRCS +set(WLOG_SRCS wlog/wlog.c wlog/wlog.h wlog/Layout.c @@ -97,7 +97,7 @@ set(${MODULE_PREFIX}_WLOG_SRCS ) -set(${MODULE_PREFIX}_SRCS +set(SRCS ini.c sam.c ntlm.c @@ -114,11 +114,11 @@ if (ANDROID) include_directories(${CMAKE_CURRENT_SOURCE_DIR}) endif() -winpr_module_add(${${MODULE_PREFIX}_SRCS} - ${${MODULE_PREFIX}_COLLECTIONS_SRCS} - ${${MODULE_PREFIX}_LODEPNG_SRCS} - ${${MODULE_PREFIX}_TRIO_SRCS} - ${${MODULE_PREFIX}_WLOG_SRCS}) +winpr_module_add(${SRCS} + ${COLLECTIONS_SRCS} + ${LODEPNG_SRCS} + ${TRIO_SRCS} + ${WLOG_SRCS}) winpr_include_directory_add( "lodepng" From 979e063581512a867d1587964013afc6eea17f8f Mon Sep 17 00:00:00 2001 From: akallabeth Date: Fri, 29 Apr 2022 11:38:46 +0200 Subject: [PATCH 154/496] Moved execinfo backtrace to own file --- winpr/libwinpr/utils/CMakeLists.txt | 6 ++ winpr/libwinpr/utils/debug.c | 81 ++++++------------------ winpr/libwinpr/utils/execinfo/debug.c | 88 +++++++++++++++++++++++++++ winpr/libwinpr/utils/execinfo/debug.h | 40 ++++++++++++ 4 files changed, 154 insertions(+), 61 deletions(-) create mode 100644 winpr/libwinpr/utils/execinfo/debug.c create mode 100644 winpr/libwinpr/utils/execinfo/debug.h diff --git a/winpr/libwinpr/utils/CMakeLists.txt b/winpr/libwinpr/utils/CMakeLists.txt index b19d7bddbfbc..18ee4887019a 100644 --- a/winpr/libwinpr/utils/CMakeLists.txt +++ b/winpr/libwinpr/utils/CMakeLists.txt @@ -114,6 +114,12 @@ if (ANDROID) include_directories(${CMAKE_CURRENT_SOURCE_DIR}) endif() +if (HAVE_EXECINFO_H) + list(APPEND SRCS + execinfo/debug.c + execinfo/debug.h) +endif() + winpr_module_add(${SRCS} ${COLLECTIONS_SRCS} ${LODEPNG_SRCS} diff --git a/winpr/libwinpr/utils/debug.c b/winpr/libwinpr/utils/debug.c index 503f4afe1505..e09dacd8870c 100644 --- a/winpr/libwinpr/utils/debug.c +++ b/winpr/libwinpr/utils/debug.c @@ -27,7 +27,7 @@ #include #if defined(HAVE_EXECINFO_H) -#include +#include #endif #if defined(ANDROID) @@ -79,15 +79,6 @@ static const char* support_msg = "Invalid stacktrace buffer! check if platform is supported!"; -#if defined(HAVE_EXECINFO_H) -typedef struct -{ - void** buffer; - size_t max; - size_t used; -} t_execinfo; -#endif - #if defined(_WIN32) || defined(_WIN64) typedef struct { @@ -259,15 +250,10 @@ USHORT RtlCaptureStackBackTrace(ULONG FramesToSkip, ULONG FramesToCapture, PVOID void winpr_backtrace_free(void* buffer) { if (!buffer) - { - LOGF(support_msg); return; - } #if defined(HAVE_EXECINFO_H) - t_execinfo* data = (t_execinfo*)buffer; - free(data->buffer); - free(data); + winpr_execinfo_backtrace_free(buffer); #elif defined(ANDROID) t_corkscrew_data* data = (t_corkscrew_data*)buffer; free(data->buffer); @@ -286,22 +272,7 @@ void winpr_backtrace_free(void* buffer) void* winpr_backtrace(DWORD size) { #if defined(HAVE_EXECINFO_H) - t_execinfo* data = calloc(1, sizeof(t_execinfo)); - - if (!data) - return NULL; - - data->buffer = calloc(size, sizeof(void*)); - - if (!data->buffer) - { - free(data); - return NULL; - } - - data->max = size; - data->used = backtrace(data->buffer, size); - return data; + return winpr_execinfo_backtrace(size); #elif defined(ANDROID) t_corkscrew_data* data = calloc(1, sizeof(t_corkscrew_data)); @@ -357,15 +328,7 @@ char** winpr_backtrace_symbols(void* buffer, size_t* used) } #if defined(HAVE_EXECINFO_H) - t_execinfo* data = (t_execinfo*)buffer; - - if (!data) - return NULL; - - if (used) - *used = data->used; - - return backtrace_symbols(data->buffer, data->used); + return winpr_execinfo_backtrace_symbols(buffer, used); #elif defined(ANDROID) t_corkscrew_data* data = (t_corkscrew_data*)buffer; @@ -478,24 +441,18 @@ void winpr_backtrace_symbols_fd(void* buffer, int fd) } #if defined(HAVE_EXECINFO_H) - t_execinfo* data = (t_execinfo*)buffer; - - if (!data) - return; - - backtrace_symbols_fd(data->buffer, data->used, fd); -#elif defined(_WIN32) || defined(_WIN64) || defined(ANDROID) + winpr_execinfo_backtrace_symbols_fd(buffer, fd); +#elif !defined(ANDROID) { - DWORD i; - size_t used; - char** lines; - lines = winpr_backtrace_symbols(buffer, &used); + size_t i; + size_t used = 0; + char** lines = winpr_backtrace_symbols(buffer, &used); - if (lines) - { - for (i = 0; i < used; i++) - write(fd, lines[i], strlen(lines[i])); - } + if (!lines) + return; + + for (i = 0; i < used; i++) + write(fd, lines[i], (unsigned)strnlen(lines[i], UINT32_MAX)); } #else LOGF(support_msg); @@ -527,7 +484,9 @@ void winpr_log_backtrace_ex(wLog* log, DWORD level, DWORD size) for (x = 0; x < used; x++) WLog_Print(log, level, "%" PRIuz ": %s\n", x, msg[x]); } - + free(msg); + +fail: winpr_backtrace_free(stack); } @@ -552,11 +511,11 @@ char* winpr_strerror(DWORD dw, char* dmsg, size_t size) if (rc) { #if defined(UNICODE) - WideCharToMultiByte(CP_ACP, 0, msg, rc, dmsg, size - 1, NULL, NULL); + WideCharToMultiByte(CP_ACP, 0, msg, rc, dmsg, (int)MIN(size - 1, INT_MAX), NULL, NULL); #else /* defined(UNICODE) */ - memcpy(dmsg, msg, min(rc, size - 1)); + memcpy(dmsg, msg, MIN(rc, size - 1)); #endif /* defined(UNICODE) */ - dmsg[min(rc, size - 1)] = 0; + dmsg[MIN(rc, size - 1)] = 0; #ifdef FORMAT_MESSAGE_ALLOCATE_BUFFER LocalFree(msg); #else diff --git a/winpr/libwinpr/utils/execinfo/debug.c b/winpr/libwinpr/utils/execinfo/debug.c new file mode 100644 index 000000000000..509d1f7d71b9 --- /dev/null +++ b/winpr/libwinpr/utils/execinfo/debug.c @@ -0,0 +1,88 @@ +/** + * WinPR: Windows Portable Runtime + * Debugging Utils + * + * Copyright 2014 Armin Novak + * Copyright 2014 Thincast Technologies GmbH + * + * 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. + */ + +#include +#include + +#include + +#include "debug.h" + +typedef struct +{ + void** buffer; + size_t max; + size_t used; +} t_execinfo; + +void winpr_execinfo_backtrace_free(void* buffer) +{ + t_execinfo* data = (t_execinfo*)buffer; + if (!data) + return; + + free(data->buffer); + free(data); +} + +void* winpr_execinfo_backtrace(DWORD size) +{ + t_execinfo* data = calloc(1, sizeof(t_execinfo)); + + if (!data) + return NULL; + + data->buffer = calloc(size, sizeof(void*)); + + if (!data->buffer) + { + free(data); + return NULL; + } + + data->max = size; + data->used = backtrace(data->buffer, size); + return data; +} + +char** winpr_execinfo_backtrace_symbols(void* buffer, size_t* used) +{ + t_execinfo* data = (t_execinfo*)buffer; + if (used) + *used = 0; + + if (!data) + return NULL; + + if (used) + *used = data->used; + + return backtrace_symbols(data->buffer, data->used); +} + +void winpr_execinfo_backtrace_symbols_fd(void* buffer, int fd) +{ + t_execinfo* data = (t_execinfo*)buffer; + + if (!data) + return; + + backtrace_symbols_fd(data->buffer, data->used, fd); +} diff --git a/winpr/libwinpr/utils/execinfo/debug.h b/winpr/libwinpr/utils/execinfo/debug.h new file mode 100644 index 000000000000..aaf7748a3daa --- /dev/null +++ b/winpr/libwinpr/utils/execinfo/debug.h @@ -0,0 +1,40 @@ +/** + * WinPR: Windows Portable Runtime + * WinPR Debugging helpers + * + * Copyright 2022 Armin Novak + * Copyright 2022 Thincast Technologies GmbH + * + * 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 WINPR_DEBUG_EXECINFO_H +#define WINPR_DEBUG_EXECINFO_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include + + void* winpr_execinfo_backtrace(DWORD size); + void winpr_execinfo_backtrace_free(void* buffer); + char** winpr_execinfo_backtrace_symbols(void* buffer, size_t* used); + void winpr_execinfo_backtrace_symbols_fd(void* buffer, int fd); + +#ifdef __cplusplus +} +#endif + +#endif /* WINPR_DEBUG_EXECINFO_H */ From aeeeee00bd30acc24e35e789fcb1176bce7cf2ed Mon Sep 17 00:00:00 2001 From: akallabeth Date: Fri, 29 Apr 2022 11:51:18 +0200 Subject: [PATCH 155/496] Moved windows backtrace to own file (cherry picked from commit ca8c9ea7b90710a411c91e4d60af8d32f2af0650) --- winpr/libwinpr/utils/CMakeLists.txt | 6 + winpr/libwinpr/utils/debug.c | 165 +------------------------- winpr/libwinpr/utils/windows/debug.c | 169 +++++++++++++++++++++++++++ winpr/libwinpr/utils/windows/debug.h | 40 +++++++ 4 files changed, 220 insertions(+), 160 deletions(-) create mode 100644 winpr/libwinpr/utils/windows/debug.c create mode 100644 winpr/libwinpr/utils/windows/debug.h diff --git a/winpr/libwinpr/utils/CMakeLists.txt b/winpr/libwinpr/utils/CMakeLists.txt index 18ee4887019a..609c48fc6774 100644 --- a/winpr/libwinpr/utils/CMakeLists.txt +++ b/winpr/libwinpr/utils/CMakeLists.txt @@ -114,6 +114,12 @@ if (ANDROID) include_directories(${CMAKE_CURRENT_SOURCE_DIR}) endif() +if (WIN32) + list(APPEND SRCS + windows/debug.c + windows/debug.h) +endif() + if (HAVE_EXECINFO_H) list(APPEND SRCS execinfo/debug.c diff --git a/winpr/libwinpr/utils/debug.c b/winpr/libwinpr/utils/debug.c index e09dacd8870c..b11d33f92120 100644 --- a/winpr/libwinpr/utils/debug.c +++ b/winpr/libwinpr/utils/debug.c @@ -35,10 +35,7 @@ #endif #if defined(_WIN32) || defined(_WIN64) -#include -#include -#include -#define write _write +#include #endif #include @@ -79,15 +76,6 @@ static const char* support_msg = "Invalid stacktrace buffer! check if platform is supported!"; -#if defined(_WIN32) || defined(_WIN64) -typedef struct -{ - PVOID* stack; - ULONG used; - ULONG max; -} t_win_stack; -#endif - #if defined(ANDROID) #include #include @@ -203,47 +191,6 @@ void load_library(void) fkt = NULL; } } -#endif - -#if defined(_WIN32) && (NTDDI_VERSION <= NTDDI_WINXP) - -typedef USHORT(WINAPI* PRTL_CAPTURE_STACK_BACK_TRACE_FN)(ULONG FramesToSkip, ULONG FramesToCapture, - PVOID* BackTrace, PULONG BackTraceHash); - -static HMODULE g_NTDLL_Library = NULL; -static BOOL g_RtlCaptureStackBackTrace_Detected = FALSE; -static BOOL g_RtlCaptureStackBackTrace_Available = FALSE; -static PRTL_CAPTURE_STACK_BACK_TRACE_FN g_pRtlCaptureStackBackTrace = NULL; - -USHORT RtlCaptureStackBackTrace(ULONG FramesToSkip, ULONG FramesToCapture, PVOID* BackTrace, - PULONG BackTraceHash) -{ - if (!g_RtlCaptureStackBackTrace_Detected) - { - g_NTDLL_Library = LoadLibraryA("kernel32.dll"); - - if (g_NTDLL_Library) - { - g_pRtlCaptureStackBackTrace = (PRTL_CAPTURE_STACK_BACK_TRACE_FN)GetProcAddress( - g_NTDLL_Library, "RtlCaptureStackBackTrace"); - g_RtlCaptureStackBackTrace_Available = (g_pRtlCaptureStackBackTrace) ? TRUE : FALSE; - } - else - { - g_RtlCaptureStackBackTrace_Available = FALSE; - } - - g_RtlCaptureStackBackTrace_Detected = TRUE; - } - - if (g_RtlCaptureStackBackTrace_Available) - { - return (*g_pRtlCaptureStackBackTrace)(FramesToSkip, FramesToCapture, BackTrace, - BackTraceHash); - } - - return 0; -} #endif @@ -259,11 +206,7 @@ void winpr_backtrace_free(void* buffer) free(data->buffer); free(data); #elif defined(_WIN32) || defined(_WIN64) - { - t_win_stack* data = (t_win_stack*)buffer; - free(data->stack); - free(data); - } + winpr_win_backtrace_free(buffer); #else LOGF(support_msg); #endif @@ -292,24 +235,7 @@ void* winpr_backtrace(DWORD size) data->used = fkt->unwind_backtrace(data->buffer, 0, size); return data; #elif (defined(_WIN32) || defined(_WIN64)) && !defined(_UWP) - HANDLE process = GetCurrentProcess(); - t_win_stack* data = calloc(1, sizeof(t_win_stack)); - - if (!data) - return NULL; - - data->max = size; - data->stack = calloc(data->max, sizeof(PVOID)); - - if (!data->stack) - { - free(data); - return NULL; - } - - SymInitialize(process, NULL, TRUE); - data->used = RtlCaptureStackBackTrace(2, size, data->stack, NULL); - return data; + return winpr_win_backtrace(size); #else LOGF(support_msg); return NULL; @@ -377,55 +303,7 @@ char** winpr_backtrace_symbols(void* buffer, size_t* used) } #elif (defined(_WIN32) || defined(_WIN64)) && !defined(_UWP) - { - size_t i; - size_t line_len = 1024; - HANDLE process = GetCurrentProcess(); - t_win_stack* data = (t_win_stack*)buffer; - size_t array_size = data->used * sizeof(char*); - size_t lines_size = data->used * line_len; - char** vlines = calloc(1, array_size + lines_size); - SYMBOL_INFO* symbol = calloc(1, sizeof(SYMBOL_INFO) + line_len * sizeof(char)); - IMAGEHLP_LINE64* line = (IMAGEHLP_LINE64*)calloc(1, sizeof(IMAGEHLP_LINE64)); - - if (!vlines || !symbol || !line) - { - free(vlines); - free(symbol); - free(line); - return NULL; - } - - line->SizeOfStruct = sizeof(IMAGEHLP_LINE64); - symbol->MaxNameLen = line_len; - symbol->SizeOfStruct = sizeof(SYMBOL_INFO); - - /* Set the pointers in the allocated buffer's initial array section */ - for (i = 0; i < data->used; i++) - vlines[i] = (char*)vlines + array_size + i * line_len; - - for (i = 0; i < data->used; i++) - { - DWORD64 address = (DWORD64)(data->stack[i]); - DWORD displacement; - SymFromAddr(process, address, 0, symbol); - - if (SymGetLineFromAddr64(process, address, &displacement, line)) - { - sprintf_s(vlines[i], line_len, "%016" PRIx64 ": %s in %s:%" PRIu32, symbol->Address, - symbol->Name, line->FileName, line->LineNumber); - } - else - sprintf_s(vlines[i], line_len, "%016" PRIx64 ": %s", symbol->Address, symbol->Name); - } - - if (used) - *used = data->used; - - free(symbol); - free(line); - return vlines; - } + return winpr_win_backtrace_symbols(buffer, used); #else LOGF(support_msg); return NULL; @@ -493,40 +371,7 @@ void winpr_log_backtrace_ex(wLog* log, DWORD level, DWORD size) char* winpr_strerror(DWORD dw, char* dmsg, size_t size) { #if defined(_WIN32) - DWORD rc; - DWORD nSize = 0; - DWORD dwFlags = 0; - LPTSTR msg = NULL; - BOOL alloc = FALSE; - dwFlags = FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS; -#ifdef FORMAT_MESSAGE_ALLOCATE_BUFFER - alloc = TRUE; - dwFlags |= FORMAT_MESSAGE_ALLOCATE_BUFFER; -#else - nSize = (DWORD)(size * 2); - msg = (LPTSTR)calloc(nSize, sizeof(TCHAR)); -#endif - rc = FormatMessage(dwFlags, NULL, dw, 0, alloc ? (LPTSTR)&msg : msg, nSize, NULL); - - if (rc) - { -#if defined(UNICODE) - WideCharToMultiByte(CP_ACP, 0, msg, rc, dmsg, (int)MIN(size - 1, INT_MAX), NULL, NULL); -#else /* defined(UNICODE) */ - memcpy(dmsg, msg, MIN(rc, size - 1)); -#endif /* defined(UNICODE) */ - dmsg[MIN(rc, size - 1)] = 0; -#ifdef FORMAT_MESSAGE_ALLOCATE_BUFFER - LocalFree(msg); -#else - free(msg); -#endif - } - else - { - _snprintf(dmsg, size, "FAILURE: 0x%08" PRIX32 "", GetLastError()); - } - + return winpr_win_strerror(dw, dmsg, size); #else /* defined(_WIN32) */ _snprintf(dmsg, size, "%s", strerror(dw)); #endif /* defined(_WIN32) */ diff --git a/winpr/libwinpr/utils/windows/debug.c b/winpr/libwinpr/utils/windows/debug.c new file mode 100644 index 000000000000..41545c75b177 --- /dev/null +++ b/winpr/libwinpr/utils/windows/debug.c @@ -0,0 +1,169 @@ +/** + * WinPR: Windows Portable Runtime + * Debugging Utils + * + * Copyright 2014 Armin Novak + * Copyright 2014 Thincast Technologies GmbH + * + * 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. + */ + +#include +#include + +#include +#include +#include + +#include "debug.h" + +#ifndef MIN +#define MIN(a, b) (a) < (b) ? (a) : (b) +#endif + +typedef struct +{ + PVOID* stack; + ULONG used; + ULONG max; +} t_win_stack; + +void winpr_win_backtrace_free(void* buffer) +{ + t_win_stack* data = (t_win_stack*)buffer; + if (!data) + return; + + free(data->stack); + free(data); +} + +void* winpr_win_backtrace(DWORD size) +{ + HANDLE process = GetCurrentProcess(); + t_win_stack* data = calloc(1, sizeof(t_win_stack)); + + if (!data) + return NULL; + + data->max = size; + data->stack = calloc(data->max, sizeof(PVOID)); + + if (!data->stack) + { + free(data); + return NULL; + } + + SymInitialize(process, NULL, TRUE); + data->used = RtlCaptureStackBackTrace(2, size, data->stack, NULL); + return data; +} + +char** winpr_win_backtrace_symbols(void* buffer, size_t* used) +{ + if (used) + *used = 0; + + if (!buffer) + return NULL; + + { + size_t i; + size_t line_len = 1024; + HANDLE process = GetCurrentProcess(); + t_win_stack* data = (t_win_stack*)buffer; + size_t array_size = data->used * sizeof(char*); + size_t lines_size = data->used * line_len; + char** vlines = calloc(1, array_size + lines_size); + SYMBOL_INFO* symbol = calloc(1, sizeof(SYMBOL_INFO) + line_len * sizeof(char)); + IMAGEHLP_LINE64* line = (IMAGEHLP_LINE64*)calloc(1, sizeof(IMAGEHLP_LINE64)); + + if (!vlines || !symbol || !line) + { + free(vlines); + free(symbol); + free(line); + return NULL; + } + + line->SizeOfStruct = sizeof(IMAGEHLP_LINE64); + symbol->MaxNameLen = (ULONG)line_len; + symbol->SizeOfStruct = sizeof(SYMBOL_INFO); + + /* Set the pointers in the allocated buffer's initial array section */ + for (i = 0; i < data->used; i++) + vlines[i] = (char*)vlines + array_size + i * line_len; + + for (i = 0; i < data->used; i++) + { + DWORD64 address = (DWORD64)(data->stack[i]); + DWORD displacement; + SymFromAddr(process, address, 0, symbol); + + if (SymGetLineFromAddr64(process, address, &displacement, line)) + { + sprintf_s(vlines[i], line_len, "%016" PRIx64 ": %s in %s:%" PRIu32, symbol->Address, + symbol->Name, line->FileName, line->LineNumber); + } + else + sprintf_s(vlines[i], line_len, "%016" PRIx64 ": %s", symbol->Address, symbol->Name); + } + + if (used) + *used = data->used; + + free(symbol); + free(line); + return vlines; + } +} + +char* winpr_win_strerror(DWORD dw, char* dmsg, size_t size) +{ + DWORD rc; + DWORD nSize = 0; + DWORD dwFlags = 0; + LPTSTR msg = NULL; + BOOL alloc = FALSE; + dwFlags = FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS; +#ifdef FORMAT_MESSAGE_ALLOCATE_BUFFER + alloc = TRUE; + dwFlags |= FORMAT_MESSAGE_ALLOCATE_BUFFER; +#else + nSize = (DWORD)(size * 2); + msg = (LPTSTR)calloc(nSize, sizeof(TCHAR)); +#endif + rc = FormatMessage(dwFlags, NULL, dw, 0, alloc ? (LPTSTR)&msg : msg, nSize, NULL); + + if (rc) + { +#if defined(UNICODE) + WideCharToMultiByte(CP_ACP, 0, msg, rc, dmsg, (int)MIN(size - 1, INT_MAX), NULL, NULL); +#else /* defined(UNICODE) */ + memcpy(dmsg, msg, MIN(rc, size - 1)); +#endif /* defined(UNICODE) */ + dmsg[MIN(rc, size - 1)] = 0; +#ifdef FORMAT_MESSAGE_ALLOCATE_BUFFER + LocalFree(msg); +#else + free(msg); +#endif + } + else + { + _snprintf(dmsg, size, "FAILURE: 0x%08" PRIX32 "", GetLastError()); + } + + return dmsg; +} diff --git a/winpr/libwinpr/utils/windows/debug.h b/winpr/libwinpr/utils/windows/debug.h new file mode 100644 index 000000000000..c36b87a58412 --- /dev/null +++ b/winpr/libwinpr/utils/windows/debug.h @@ -0,0 +1,40 @@ +/** + * WinPR: Windows Portable Runtime + * WinPR Debugging helpers + * + * Copyright 2022 Armin Novak + * Copyright 2022 Thincast Technologies GmbH + * + * 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 WINPR_DEBUG_WIN_H +#define WINPR_DEBUG_WIN_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include + + void* winpr_win_backtrace(DWORD size); + void winpr_win_backtrace_free(void* buffer); + char** winpr_win_backtrace_symbols(void* buffer, size_t* used); + char* winpr_win_strerror(DWORD dw, char* dmsg, size_t size); + +#ifdef __cplusplus +} +#endif + +#endif /* WINPR_DEBUG_WIN_H */ From b4554ce916ad76653e7e8db7f590fa8e9c450d5d Mon Sep 17 00:00:00 2001 From: akallabeth Date: Fri, 29 Apr 2022 11:56:35 +0200 Subject: [PATCH 156/496] Moved corkscrew backtrace to own file (cherry picked from commit 3ef29a3275fe3c82df4525d30f7995b17075abe4) --- winpr/libwinpr/utils/CMakeLists.txt | 6 + winpr/libwinpr/utils/corkscrew/debug.c | 262 +++++++++++++++++++++++++ winpr/libwinpr/utils/corkscrew/debug.h | 40 ++++ winpr/libwinpr/utils/debug.c | 196 +----------------- 4 files changed, 316 insertions(+), 188 deletions(-) create mode 100644 winpr/libwinpr/utils/corkscrew/debug.c create mode 100644 winpr/libwinpr/utils/corkscrew/debug.h diff --git a/winpr/libwinpr/utils/CMakeLists.txt b/winpr/libwinpr/utils/CMakeLists.txt index 609c48fc6774..032c432cbd37 100644 --- a/winpr/libwinpr/utils/CMakeLists.txt +++ b/winpr/libwinpr/utils/CMakeLists.txt @@ -114,6 +114,12 @@ if (ANDROID) include_directories(${CMAKE_CURRENT_SOURCE_DIR}) endif() +if (HAVE_CORKSCREW) + list(APPEND SRCS + corkscrew/debug.c + corkscrew/debug.h) +endif() + if (WIN32) list(APPEND SRCS windows/debug.c diff --git a/winpr/libwinpr/utils/corkscrew/debug.c b/winpr/libwinpr/utils/corkscrew/debug.c new file mode 100644 index 000000000000..0034fc9b3f09 --- /dev/null +++ b/winpr/libwinpr/utils/corkscrew/debug.c @@ -0,0 +1,262 @@ +/** + * WinPR: Windows Portable Runtime + * Debugging Utils + * + * Copyright 2014 Armin Novak + * Copyright 2014 Thincast Technologies GmbH + * + * 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. + */ + +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include + +#include "debug.h" + +#define TAG "com.winpr.utils.debug" +#define LOGT(...) \ + do \ + { \ + WLog_Print(WLog_Get(TAG), WLOG_TRACE, __VA_ARGS__); \ + } while (0) +#define LOGD(...) \ + do \ + { \ + WLog_Print(WLog_Get(TAG), WLOG_DEBUG, __VA_ARGS__); \ + } while (0) +#define LOGI(...) \ + do \ + { \ + WLog_Print(WLog_Get(TAG), WLOG_INFO, __VA_ARGS__); \ + } while (0) +#define LOGW(...) \ + do \ + { \ + WLog_Print(WLog_Get(TAG), WLOG_WARN, __VA_ARGS__); \ + } while (0) +#define LOGE(...) \ + do \ + { \ + WLog_Print(WLog_Get(TAG), WLOG_ERROR, __VA_ARGS__); \ + } while (0) +#define LOGF(...) \ + do \ + { \ + WLog_Print(WLog_Get(TAG), WLOG_FATAL, __VA_ARGS__); \ + } while (0) + +static const char* support_msg = "Invalid stacktrace buffer! check if platform is supported!"; + +typedef struct +{ + backtrace_frame_t* buffer; + size_t max; + size_t used; +} t_corkscrew_data; + +typedef struct +{ + void* hdl; + ssize_t (*unwind_backtrace)(backtrace_frame_t* backtrace, size_t ignore_depth, + size_t max_depth); + ssize_t (*unwind_backtrace_thread)(pid_t tid, backtrace_frame_t* backtrace, size_t ignore_depth, + size_t max_depth); + ssize_t (*unwind_backtrace_ptrace)(pid_t tid, const ptrace_context_t* context, + backtrace_frame_t* backtrace, size_t ignore_depth, + size_t max_depth); + void (*get_backtrace_symbols)(const backtrace_frame_t* backtrace, size_t frames, + backtrace_symbol_t* backtrace_symbols); + void (*get_backtrace_symbols_ptrace)(const ptrace_context_t* context, + const backtrace_frame_t* backtrace, size_t frames, + backtrace_symbol_t* backtrace_symbols); + void (*free_backtrace_symbols)(backtrace_symbol_t* backtrace_symbols, size_t frames); + void (*format_backtrace_line)(unsigned frameNumber, const backtrace_frame_t* frame, + const backtrace_symbol_t* symbol, char* buffer, + size_t bufferSize); +} t_corkscrew; + +static pthread_once_t initialized = PTHREAD_ONCE_INIT; +static t_corkscrew* fkt = NULL; + +void load_library(void) +{ + static t_corkscrew lib; + { + lib.hdl = dlopen("libcorkscrew.so", RTLD_LAZY); + + if (!lib.hdl) + { + LOGF("dlopen error %s", dlerror()); + goto fail; + } + + lib.unwind_backtrace = dlsym(lib.hdl, "unwind_backtrace"); + + if (!lib.unwind_backtrace) + { + LOGF("dlsym error %s", dlerror()); + goto fail; + } + + lib.unwind_backtrace_thread = dlsym(lib.hdl, "unwind_backtrace_thread"); + + if (!lib.unwind_backtrace_thread) + { + LOGF("dlsym error %s", dlerror()); + goto fail; + } + + lib.unwind_backtrace_ptrace = dlsym(lib.hdl, "unwind_backtrace_ptrace"); + + if (!lib.unwind_backtrace_ptrace) + { + LOGF("dlsym error %s", dlerror()); + goto fail; + } + + lib.get_backtrace_symbols = dlsym(lib.hdl, "get_backtrace_symbols"); + + if (!lib.get_backtrace_symbols) + { + LOGF("dlsym error %s", dlerror()); + goto fail; + } + + lib.get_backtrace_symbols_ptrace = dlsym(lib.hdl, "get_backtrace_symbols_ptrace"); + + if (!lib.get_backtrace_symbols_ptrace) + { + LOGF("dlsym error %s", dlerror()); + goto fail; + } + + lib.free_backtrace_symbols = dlsym(lib.hdl, "free_backtrace_symbols"); + + if (!lib.free_backtrace_symbols) + { + LOGF("dlsym error %s", dlerror()); + goto fail; + } + + lib.format_backtrace_line = dlsym(lib.hdl, "format_backtrace_line"); + + if (!lib.format_backtrace_line) + { + LOGF("dlsym error %s", dlerror()); + goto fail; + } + + fkt = &lib; + return; + } +fail: +{ + if (lib.hdl) + dlclose(lib.hdl); + + fkt = NULL; +} +} + +void winpr_corkscrew_backtrace_free(void* buffer) +{ + t_corkscrew_data* data = (t_corkscrew_data*)buffer; + if (!data) + return; + + free(data->buffer); + free(data); +} + +void* winpr_corkscrew_backtrace(DWORD size) +{ + t_corkscrew_data* data = calloc(1, sizeof(t_corkscrew_data)); + + if (!data) + return NULL; + + data->buffer = calloc(size, sizeof(backtrace_frame_t)); + + if (!data->buffer) + { + free(data); + return NULL; + } + + pthread_once(&initialized, load_library); + data->max = size; + data->used = fkt->unwind_backtrace(data->buffer, 0, size); + return data; +} + +char** winpr_corkscrew_backtrace_symbols(void* buffer, size_t* used) +{ + t_corkscrew_data* data = (t_corkscrew_data*)buffer; + if (used) + *used = 0; + + if (!data) + return NULL; + + pthread_once(&initialized, load_library); + + if (!fkt) + { + LOGF(support_msg); + return NULL; + } + else + { + size_t line_len = (data->max > 1024) ? data->max : 1024; + size_t i; + size_t array_size = data->used * sizeof(char*); + size_t lines_size = data->used * line_len; + char** vlines = calloc(1, array_size + lines_size); + backtrace_symbol_t* symbols = calloc(data->used, sizeof(backtrace_symbol_t)); + + if (!vlines || !symbols) + { + free(vlines); + free(symbols); + return NULL; + } + + /* Set the pointers in the allocated buffer's initial array section */ + for (i = 0; i < data->used; i++) + vlines[i] = (char*)vlines + array_size + i * line_len; + + fkt->get_backtrace_symbols(data->buffer, data->used, symbols); + + for (i = 0; i < data->used; i++) + fkt->format_backtrace_line(i, &data->buffer[i], &symbols[i], vlines[i], line_len); + + fkt->free_backtrace_symbols(symbols, data->used); + free(symbols); + + if (used) + *used = data->used; + + return vlines; + } +} + diff --git a/winpr/libwinpr/utils/corkscrew/debug.h b/winpr/libwinpr/utils/corkscrew/debug.h new file mode 100644 index 000000000000..e98b9bd531df --- /dev/null +++ b/winpr/libwinpr/utils/corkscrew/debug.h @@ -0,0 +1,40 @@ +/** + * WinPR: Windows Portable Runtime + * WinPR Debugging helpers + * + * Copyright 2022 Armin Novak + * Copyright 2022 Thincast Technologies GmbH + * + * 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 WINPR_DEBUG_CORKSCREW_H +#define WINPR_DEBUG_CORKSCREW_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include + + void* winpr_corkscrew_backtrace(DWORD size); + void winpr_corkscrew_backtrace_free(void* buffer); + char** winpr_corkscrew_backtrace_symbols(void* buffer, size_t* used); + void winpr_corkscrew_backtrace_symbols_fd(void* buffer, int fd); + +#ifdef __cplusplus +} +#endif + +#endif /* WINPR_DEBUG_CORKSCREW_H */ diff --git a/winpr/libwinpr/utils/debug.c b/winpr/libwinpr/utils/debug.c index b11d33f92120..d3ba2bc0acf4 100644 --- a/winpr/libwinpr/utils/debug.c +++ b/winpr/libwinpr/utils/debug.c @@ -30,8 +30,8 @@ #include #endif -#if defined(ANDROID) -#include +#if defined(HAVE_CORKSCREW) +#include #endif #if defined(_WIN32) || defined(_WIN64) @@ -76,124 +76,6 @@ static const char* support_msg = "Invalid stacktrace buffer! check if platform is supported!"; -#if defined(ANDROID) -#include -#include -#include - -typedef struct -{ - backtrace_frame_t* buffer; - size_t max; - size_t used; -} t_corkscrew_data; - -typedef struct -{ - void* hdl; - ssize_t (*unwind_backtrace)(backtrace_frame_t* backtrace, size_t ignore_depth, - size_t max_depth); - ssize_t (*unwind_backtrace_thread)(pid_t tid, backtrace_frame_t* backtrace, size_t ignore_depth, - size_t max_depth); - ssize_t (*unwind_backtrace_ptrace)(pid_t tid, const ptrace_context_t* context, - backtrace_frame_t* backtrace, size_t ignore_depth, - size_t max_depth); - void (*get_backtrace_symbols)(const backtrace_frame_t* backtrace, size_t frames, - backtrace_symbol_t* backtrace_symbols); - void (*get_backtrace_symbols_ptrace)(const ptrace_context_t* context, - const backtrace_frame_t* backtrace, size_t frames, - backtrace_symbol_t* backtrace_symbols); - void (*free_backtrace_symbols)(backtrace_symbol_t* backtrace_symbols, size_t frames); - void (*format_backtrace_line)(unsigned frameNumber, const backtrace_frame_t* frame, - const backtrace_symbol_t* symbol, char* buffer, - size_t bufferSize); -} t_corkscrew; - -static pthread_once_t initialized = PTHREAD_ONCE_INIT; -static t_corkscrew* fkt = NULL; - -void load_library(void) -{ - static t_corkscrew lib; - { - lib.hdl = dlopen("libcorkscrew.so", RTLD_LAZY); - - if (!lib.hdl) - { - LOGF("dlopen error %s", dlerror()); - goto fail; - } - - lib.unwind_backtrace = dlsym(lib.hdl, "unwind_backtrace"); - - if (!lib.unwind_backtrace) - { - LOGF("dlsym error %s", dlerror()); - goto fail; - } - - lib.unwind_backtrace_thread = dlsym(lib.hdl, "unwind_backtrace_thread"); - - if (!lib.unwind_backtrace_thread) - { - LOGF("dlsym error %s", dlerror()); - goto fail; - } - - lib.unwind_backtrace_ptrace = dlsym(lib.hdl, "unwind_backtrace_ptrace"); - - if (!lib.unwind_backtrace_ptrace) - { - LOGF("dlsym error %s", dlerror()); - goto fail; - } - - lib.get_backtrace_symbols = dlsym(lib.hdl, "get_backtrace_symbols"); - - if (!lib.get_backtrace_symbols) - { - LOGF("dlsym error %s", dlerror()); - goto fail; - } - - lib.get_backtrace_symbols_ptrace = dlsym(lib.hdl, "get_backtrace_symbols_ptrace"); - - if (!lib.get_backtrace_symbols_ptrace) - { - LOGF("dlsym error %s", dlerror()); - goto fail; - } - - lib.free_backtrace_symbols = dlsym(lib.hdl, "free_backtrace_symbols"); - - if (!lib.free_backtrace_symbols) - { - LOGF("dlsym error %s", dlerror()); - goto fail; - } - - lib.format_backtrace_line = dlsym(lib.hdl, "format_backtrace_line"); - - if (!lib.format_backtrace_line) - { - LOGF("dlsym error %s", dlerror()); - goto fail; - } - - fkt = &lib; - return; - } -fail: -{ - if (lib.hdl) - dlclose(lib.hdl); - - fkt = NULL; -} -} - -#endif - void winpr_backtrace_free(void* buffer) { if (!buffer) @@ -201,10 +83,8 @@ void winpr_backtrace_free(void* buffer) #if defined(HAVE_EXECINFO_H) winpr_execinfo_backtrace_free(buffer); -#elif defined(ANDROID) - t_corkscrew_data* data = (t_corkscrew_data*)buffer; - free(data->buffer); - free(data); +#elif defined(HAVE_CORKSCREW) + winpr_corkscrew_backtrace_free(buffer); #elif defined(_WIN32) || defined(_WIN64) winpr_win_backtrace_free(buffer); #else @@ -216,24 +96,8 @@ void* winpr_backtrace(DWORD size) { #if defined(HAVE_EXECINFO_H) return winpr_execinfo_backtrace(size); -#elif defined(ANDROID) - t_corkscrew_data* data = calloc(1, sizeof(t_corkscrew_data)); - - if (!data) - return NULL; - - data->buffer = calloc(size, sizeof(backtrace_frame_t)); - - if (!data->buffer) - { - free(data); - return NULL; - } - - pthread_once(&initialized, load_library); - data->max = size; - data->used = fkt->unwind_backtrace(data->buffer, 0, size); - return data; +#elif defined(HAVE_CORKSCREW) + return winpr_corkscrew_backtrace(size); #elif (defined(_WIN32) || defined(_WIN64)) && !defined(_UWP) return winpr_win_backtrace(size); #else @@ -255,52 +119,8 @@ char** winpr_backtrace_symbols(void* buffer, size_t* used) #if defined(HAVE_EXECINFO_H) return winpr_execinfo_backtrace_symbols(buffer, used); -#elif defined(ANDROID) - t_corkscrew_data* data = (t_corkscrew_data*)buffer; - - if (!data) - return NULL; - - pthread_once(&initialized, load_library); - - if (!fkt) - { - LOGF(support_msg); - return NULL; - } - else - { - size_t line_len = (data->max > 1024) ? data->max : 1024; - size_t i; - size_t array_size = data->used * sizeof(char*); - size_t lines_size = data->used * line_len; - char** vlines = calloc(1, array_size + lines_size); - backtrace_symbol_t* symbols = calloc(data->used, sizeof(backtrace_symbol_t)); - - if (!vlines || !symbols) - { - free(vlines); - free(symbols); - return NULL; - } - - /* Set the pointers in the allocated buffer's initial array section */ - for (i = 0; i < data->used; i++) - vlines[i] = (char*)vlines + array_size + i * line_len; - - fkt->get_backtrace_symbols(data->buffer, data->used, symbols); - - for (i = 0; i < data->used; i++) - fkt->format_backtrace_line(i, &data->buffer[i], &symbols[i], vlines[i], line_len); - - fkt->free_backtrace_symbols(symbols, data->used); - free(symbols); - - if (used) - *used = data->used; - - return vlines; - } +#elif defined(HAVE_CORKSCREW) + return winpr_corkscrew_backtrace_symbols(buffer, used); #elif (defined(_WIN32) || defined(_WIN64)) && !defined(_UWP) return winpr_win_backtrace_symbols(buffer, used); From 5e1eca6ff5a768be26b71997d23315f513025554 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Fri, 29 Apr 2022 11:28:49 +0200 Subject: [PATCH 157/496] Added unwind.h support (cherry picked from commit b52416da6ba37dfca70147408dfd486cc8f2567b) --- winpr/CMakeLists.txt | 4 + winpr/libwinpr/utils/CMakeLists.txt | 6 ++ winpr/libwinpr/utils/debug.c | 18 +++- winpr/libwinpr/utils/unwind/debug.c | 130 ++++++++++++++++++++++++++++ winpr/libwinpr/utils/unwind/debug.h | 41 +++++++++ 5 files changed, 195 insertions(+), 4 deletions(-) create mode 100644 winpr/libwinpr/utils/unwind/debug.c create mode 100644 winpr/libwinpr/utils/unwind/debug.h diff --git a/winpr/CMakeLists.txt b/winpr/CMakeLists.txt index d8a40da1ae92..52d0f65c2ff4 100644 --- a/winpr/CMakeLists.txt +++ b/winpr/CMakeLists.txt @@ -114,6 +114,10 @@ else() check_include_files(sys/sockio.h HAVE_SYS_SOCKIO_H) check_include_files(sys/strtio.h HAVE_SYS_STRTIO_H) check_include_files(sys/select.h HAVE_SYS_SELECT_H) + check_include_files(unwind.h HAVE_UNWIND_H) + if (HAVE_UNWIND_H) + add_definitions(-DHAVE_UNWIND_H) + endif() else() set(HAVE_FCNTL_H 1) set(HAVE_UNISTD_H 1) diff --git a/winpr/libwinpr/utils/CMakeLists.txt b/winpr/libwinpr/utils/CMakeLists.txt index 032c432cbd37..641a2e63c495 100644 --- a/winpr/libwinpr/utils/CMakeLists.txt +++ b/winpr/libwinpr/utils/CMakeLists.txt @@ -132,6 +132,12 @@ if (HAVE_EXECINFO_H) execinfo/debug.h) endif() +if (HAVE_UNWIND_H) + list(APPEND SRCS + unwind/debug.c + unwind/debug.h) +endif() + winpr_module_add(${SRCS} ${COLLECTIONS_SRCS} ${LODEPNG_SRCS} diff --git a/winpr/libwinpr/utils/debug.c b/winpr/libwinpr/utils/debug.c index d3ba2bc0acf4..3cc0ce53728e 100644 --- a/winpr/libwinpr/utils/debug.c +++ b/winpr/libwinpr/utils/debug.c @@ -30,6 +30,10 @@ #include #endif +#if defined(HAVE_UNWIND_H) +#include +#endif + #if defined(HAVE_CORKSCREW) #include #endif @@ -81,7 +85,9 @@ void winpr_backtrace_free(void* buffer) if (!buffer) return; -#if defined(HAVE_EXECINFO_H) +#if defined(HAVE_UNWIND_H) + winpr_unwind_backtrace_free(buffer); +#elif defined(HAVE_EXECINFO_H) winpr_execinfo_backtrace_free(buffer); #elif defined(HAVE_CORKSCREW) winpr_corkscrew_backtrace_free(buffer); @@ -94,7 +100,9 @@ void winpr_backtrace_free(void* buffer) void* winpr_backtrace(DWORD size) { -#if defined(HAVE_EXECINFO_H) +#if defined(HAVE_UNWIND_H) + return winpr_unwind_backtrace(size); +#elif defined(HAVE_EXECINFO_H) return winpr_execinfo_backtrace(size); #elif defined(HAVE_CORKSCREW) return winpr_corkscrew_backtrace(size); @@ -117,7 +125,9 @@ char** winpr_backtrace_symbols(void* buffer, size_t* used) return NULL; } -#if defined(HAVE_EXECINFO_H) +#if defined(HAVE_UNWIND_H) + return winpr_unwind_backtrace_symbols(buffer, used); +#elif defined(HAVE_EXECINFO_H) return winpr_execinfo_backtrace_symbols(buffer, used); #elif defined(HAVE_CORKSCREW) return winpr_corkscrew_backtrace_symbols(buffer, used); @@ -138,7 +148,7 @@ void winpr_backtrace_symbols_fd(void* buffer, int fd) return; } -#if defined(HAVE_EXECINFO_H) +#if defined(HAVE_EXECINFO_H) && !defined(HAVE_UNWIND_H) winpr_execinfo_backtrace_symbols_fd(buffer, fd); #elif !defined(ANDROID) { diff --git a/winpr/libwinpr/utils/unwind/debug.c b/winpr/libwinpr/utils/unwind/debug.c new file mode 100644 index 000000000000..8173654890d0 --- /dev/null +++ b/winpr/libwinpr/utils/unwind/debug.c @@ -0,0 +1,130 @@ +/** + * WinPR: Windows Portable Runtime + * WinPR Debugging helpers + * + * Copyright 2022 Armin Novak + * Copyright 2022 Thincast Technologies GmbH + * + * 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. + */ + +/* Required to test on linux +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif +*/ + +#include +#include +#include + +#include +#include "debug.h" + +#include + +typedef struct +{ + uintptr_t pc; + void* langSpecificData; +} unwind_info_t; + +typedef struct +{ + size_t pos; + size_t size; + unwind_info_t* info; +} unwind_context_t; + +static _Unwind_Reason_Code unwind_backtrace_callback(struct _Unwind_Context* context, void* arg) +{ + unwind_context_t* ctx = arg; + + assert(ctx); + + if (ctx->pos < ctx->size) + { + unwind_info_t* info = &ctx->info[ctx->pos++]; + info->pc = _Unwind_GetIP(context); + info->langSpecificData = _Unwind_GetLanguageSpecificData(context); + } + + return _URC_NO_REASON; +} + +void* winpr_unwind_backtrace(DWORD size) +{ + _Unwind_Reason_Code rc; + unwind_context_t* ctx = calloc(1, sizeof(unwind_context_t)); + if (!ctx) + goto fail; + ctx->size = size; + ctx->info = calloc(size, sizeof(unwind_info_t)); + if (!ctx->info) + goto fail; + + rc = _Unwind_Backtrace(unwind_backtrace_callback, ctx); + if (rc != _URC_END_OF_STACK) + goto fail; + + return ctx; +fail: + winpr_unwind_backtrace_free(ctx); + return NULL; +} + +void winpr_unwind_backtrace_free(void* buffer) +{ + unwind_context_t* ctx = buffer; + if (!ctx) + return; + free(ctx->info); + free(ctx); +} + +#define UNWIND_MAX_LINE_SIZE 1024 + +char** winpr_unwind_backtrace_symbols(void* buffer, size_t* used) +{ + size_t x; + char** str = NULL; + unwind_context_t* ctx = buffer; + + if (!ctx) + return NULL; + + str = calloc(ctx->pos * (sizeof(char*) + UNWIND_MAX_LINE_SIZE), sizeof(char*)); + if (!str) + return NULL; + + if (used) + *used = ctx->pos; + + for (x = 0; x < ctx->pos; x++) + { + char* msg = str + ctx->pos * sizeof(char*) + x * UNWIND_MAX_LINE_SIZE; + const unwind_info_t* info = &ctx->info[x]; + Dl_info dlinfo = { 0 }; + int rc = dladdr(info->pc, &dlinfo); + + str[x] = msg; + + if (rc == 0) + _snprintf(msg, UNWIND_MAX_LINE_SIZE, "unresolvable, address=%p", info->pc); + else + _snprintf(msg, UNWIND_MAX_LINE_SIZE, "dli_fname=%s [%p], dli_sname=%s [%p]", + dlinfo.dli_fname, dlinfo.dli_fbase, dlinfo.dli_sname, dlinfo.dli_saddr); + } + + return str; +} diff --git a/winpr/libwinpr/utils/unwind/debug.h b/winpr/libwinpr/utils/unwind/debug.h new file mode 100644 index 000000000000..5cd1290a8ee7 --- /dev/null +++ b/winpr/libwinpr/utils/unwind/debug.h @@ -0,0 +1,41 @@ +/** + * WinPR: Windows Portable Runtime + * WinPR Debugging helpers + * + * Copyright 2022 Armin Novak + * Copyright 2022 Thincast Technologies GmbH + * + * 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 WINPR_DEBUG_UNWIND_H +#define WINPR_DEBUG_UNWIND_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include +#include +#include + + void* winpr_unwind_backtrace(DWORD size); + void winpr_unwind_backtrace_free(void* buffer); + char** winpr_unwind_backtrace_symbols(void* buffer, size_t* used); + +#ifdef __cplusplus +} +#endif + +#endif /* WINPR_DEBUG_UNWIND_H */ From 30680b6e7f454570c29968016e63fc2da836c74d Mon Sep 17 00:00:00 2001 From: akallabeth Date: Fri, 29 Apr 2022 13:41:44 +0200 Subject: [PATCH 158/496] default android to unwind (cherry picked from commit 734f90692b302008dfd0e549b06d77be03ac3454) --- winpr/libwinpr/utils/CMakeLists.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/winpr/libwinpr/utils/CMakeLists.txt b/winpr/libwinpr/utils/CMakeLists.txt index 641a2e63c495..33a867981f5f 100644 --- a/winpr/libwinpr/utils/CMakeLists.txt +++ b/winpr/libwinpr/utils/CMakeLists.txt @@ -112,6 +112,10 @@ set(SRCS if (ANDROID) include_directories(${CMAKE_CURRENT_SOURCE_DIR}) + if (NOT HAVE_UNWIND_H) + message("[backtrace] android NDK without unwind.h, falling back to corkscrew") + set(HAVE_CORKSCREW 1) + endif() endif() if (HAVE_CORKSCREW) From 50d045be97efd5a833d59c5e4c4b003ef2a77017 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Fri, 29 Apr 2022 15:04:54 +0200 Subject: [PATCH 159/496] Enable unwind.h and dladdr as default backtrace implementation * config option USE_UNWIND to enable/disable (cherry picked from commit 728d1c5892cbee981f778fa4774a14a094e5e1d5) --- winpr/libwinpr/utils/CMakeLists.txt | 10 +++++++--- winpr/libwinpr/utils/debug.c | 10 +++++----- winpr/libwinpr/utils/unwind/debug.c | 2 -- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/winpr/libwinpr/utils/CMakeLists.txt b/winpr/libwinpr/utils/CMakeLists.txt index 33a867981f5f..b1acf9a9336a 100644 --- a/winpr/libwinpr/utils/CMakeLists.txt +++ b/winpr/libwinpr/utils/CMakeLists.txt @@ -137,9 +137,13 @@ if (HAVE_EXECINFO_H) endif() if (HAVE_UNWIND_H) - list(APPEND SRCS - unwind/debug.c - unwind/debug.h) + option(USE_UNWIND "Use unwind.h to generate backtraces" ON) + if (USE_UNWIND) + add_definitions(-DUSE_UNWIND) + list(APPEND SRCS + unwind/debug.c + unwind/debug.h) + endif() endif() winpr_module_add(${SRCS} diff --git a/winpr/libwinpr/utils/debug.c b/winpr/libwinpr/utils/debug.c index 3cc0ce53728e..74eccbb08b27 100644 --- a/winpr/libwinpr/utils/debug.c +++ b/winpr/libwinpr/utils/debug.c @@ -30,7 +30,7 @@ #include #endif -#if defined(HAVE_UNWIND_H) +#if defined(USE_UNWIND_H) #include #endif @@ -85,7 +85,7 @@ void winpr_backtrace_free(void* buffer) if (!buffer) return; -#if defined(HAVE_UNWIND_H) +#if defined(USE_UNWIND_H) winpr_unwind_backtrace_free(buffer); #elif defined(HAVE_EXECINFO_H) winpr_execinfo_backtrace_free(buffer); @@ -100,7 +100,7 @@ void winpr_backtrace_free(void* buffer) void* winpr_backtrace(DWORD size) { -#if defined(HAVE_UNWIND_H) +#if defined(USE_UNWIND_H) return winpr_unwind_backtrace(size); #elif defined(HAVE_EXECINFO_H) return winpr_execinfo_backtrace(size); @@ -125,7 +125,7 @@ char** winpr_backtrace_symbols(void* buffer, size_t* used) return NULL; } -#if defined(HAVE_UNWIND_H) +#if defined(USE_UNWIND_H) return winpr_unwind_backtrace_symbols(buffer, used); #elif defined(HAVE_EXECINFO_H) return winpr_execinfo_backtrace_symbols(buffer, used); @@ -148,7 +148,7 @@ void winpr_backtrace_symbols_fd(void* buffer, int fd) return; } -#if defined(HAVE_EXECINFO_H) && !defined(HAVE_UNWIND_H) +#if defined(HAVE_EXECINFO_H) && !defined(USE_UNWIND_H) winpr_execinfo_backtrace_symbols_fd(buffer, fd); #elif !defined(ANDROID) { diff --git a/winpr/libwinpr/utils/unwind/debug.c b/winpr/libwinpr/utils/unwind/debug.c index 8173654890d0..4e86f7b1fc49 100644 --- a/winpr/libwinpr/utils/unwind/debug.c +++ b/winpr/libwinpr/utils/unwind/debug.c @@ -18,11 +18,9 @@ * limitations under the License. */ -/* Required to test on linux #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif -*/ #include #include From f117ff13ade9d29645fe86e1d5734f6d9212e360 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Fri, 29 Apr 2022 15:10:54 +0200 Subject: [PATCH 160/496] Updated changelog --- ChangeLog | 1 + 1 file changed, 1 insertion(+) diff --git a/ChangeLog b/ChangeLog index 72cc881f3080..faee92edb022 100644 --- a/ChangeLog +++ b/ChangeLog @@ -4,6 +4,7 @@ Noteworthy changes: Fixed issues: * Fixed #7837: Prevent out of bound reads for FFMPEG +* Backported #7859 and #7861: Unwind support for backtrace generation * Backported #7440: wlfreerdp appid * Backported #7832: RAIL window restore * Backported #7833: Refactored WinPR thread locking From f1bf99f0755a23ac52c73d4067026f3c6a03c4e5 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Tue, 3 May 2022 17:22:11 +0200 Subject: [PATCH 161/496] Only build RFX neon path with -DWITH_NEON=ON (cherry picked from commit d18187c949817b025f76772e065ded7cd5a69a63) --- CMakeLists.txt | 1 - libfreerdp/codec/rfx_neon.c | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index bfdb7a82683f..11bd2568ed8e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -600,7 +600,6 @@ if(ANDROID) if(ANDROID_ABI STREQUAL arm64-v8a) # https://github.com/android/ndk/issues/910 - add_definitions(-D__ARM_NEON) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mfloat-abi=softfp") endif() diff --git a/libfreerdp/codec/rfx_neon.c b/libfreerdp/codec/rfx_neon.c index 8a9bd8bcf1c8..c41ebb404d66 100644 --- a/libfreerdp/codec/rfx_neon.c +++ b/libfreerdp/codec/rfx_neon.c @@ -21,7 +21,7 @@ #include "config.h" #endif -#if defined(__ARM_NEON) +#if defined(WITH_NEON) #include #include @@ -241,4 +241,4 @@ void rfx_init_neon(RFX_CONTEXT* context) } } -#endif // __ARM_NEON +#endif // WITH_NEON From c5672a992ad4915b1d84ad8aa1c04a100809b20c Mon Sep 17 00:00:00 2001 From: akallabeth Date: Tue, 3 May 2022 20:46:15 +0200 Subject: [PATCH 162/496] Unified neon source options (cherry picked from commit bfdbe180297f475fe585a1ec99e5f7ca22ab9bc2) --- libfreerdp/CMakeLists.txt | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/libfreerdp/CMakeLists.txt b/libfreerdp/CMakeLists.txt index 0b55388168e0..a259b68cc304 100644 --- a/libfreerdp/CMakeLists.txt +++ b/libfreerdp/CMakeLists.txt @@ -313,7 +313,7 @@ freerdp_definition_add(-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}) ### IPP Variable debugging if(WITH_IPP) - if(CMAKE_COMPILER_IS_GNUCC) + if(CMAKE_COMPILER_IS_GNUCC OR ${CMAKE_C_COMPILER_ID} STREQUAL "Clang") foreach(INCLDIR ${IPP_INCLUDE_DIRS}) set(OPTIMIZATION "${OPTIMIZATION} -I${INCLDIR}") endforeach(INCLDIR) @@ -335,9 +335,11 @@ if(WITH_SSE2) PROPERTIES COMPILE_FLAGS "${OPTIMIZATION} /arch:SSE2") endif() elseif(WITH_NEON) - if(CMAKE_COMPILER_IS_GNUCC) - set_source_files_properties(${PRIMITIVES_OPT_SRCS} - PROPERTIES COMPILE_FLAGS "${OPTIMIZATION} -mfpu=neon") + if(CMAKE_COMPILER_IS_GNUCC OR ${CMAKE_C_COMPILER_ID} STREQUAL "Clang") + if (NOT MSVC_ARM64 AND NOT ARCH_ARM64) + set_source_files_properties(${PRIMITIVES_OPT_SRCS} + PROPERTIES COMPILE_FLAGS "${OPTIMIZATION} -mfpu=neon") + endif() endif() # TODO: Add MSVC equivalent endif() From 3e6545a2c29df043c07e88459b7422bd608275b8 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Tue, 3 May 2022 08:25:27 +0200 Subject: [PATCH 163/496] Updated ios toolchain file with version from https://github.com/leetal/ios-cmake (cherry picked from commit 0da860ad1fe2eb8d83c29190a3ef66f814ccd5e2) --- cmake/ios.toolchain.cmake | 945 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 945 insertions(+) create mode 100644 cmake/ios.toolchain.cmake diff --git a/cmake/ios.toolchain.cmake b/cmake/ios.toolchain.cmake new file mode 100644 index 000000000000..1ecfd25567ce --- /dev/null +++ b/cmake/ios.toolchain.cmake @@ -0,0 +1,945 @@ +# This file is part of the ios-cmake project. It was retrieved from +# https://github.com/leetal/ios-cmake.git, which is a fork of +# https://github.com/gerstrong/ios-cmake.git, which is a fork of +# https://github.com/cristeab/ios-cmake.git, which is a fork of +# https://code.google.com/p/ios-cmake/. Which in turn is based off of +# the Platform/Darwin.cmake and Platform/UnixPaths.cmake files which +# are included with CMake 2.8.4 +# +# The ios-cmake project is licensed under the new BSD license. +# +# Copyright (c) 2014, Bogdan Cristea and LTE Engineering Software, +# Kitware, Inc., Insight Software Consortium. All rights reserved. +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# 3. Neither the name of the copyright holder nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +# FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +# COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# +# This file is based off of the Platform/Darwin.cmake and +# Platform/UnixPaths.cmake files which are included with CMake 2.8.4 +# It has been altered for iOS development. +# +# Updated by Alex Stewart (alexs.mac@gmail.com) +# +# ***************************************************************************** +# Now maintained by Alexander Widerberg (widerbergaren [at] gmail.com) +# under the BSD-3-Clause license +# https://github.com/leetal/ios-cmake +# ***************************************************************************** +# +# INFORMATION / HELP +# +# The following options control the behaviour of this toolchain: +# +# PLATFORM: (default "OS64") +# OS = Build for iPhoneOS. +# OS64 = Build for arm64 iphoneOS. +# OS64COMBINED = Build for arm64 x86_64 iphoneOS. Combined into FAT STATIC lib (supported on 3.14+ of CMakewith "-G Xcode" argument ONLY) +# SIMULATOR = Build for x86 i386 iphoneOS Simulator. +# SIMULATOR64 = Build for x86_64 iphoneOS Simulator. +# SIMULATORARM64 = Build for arm64 iphoneOS Simulator. +# TVOS = Build for arm64 tvOS. +# TVOSCOMBINED = Build for arm64 x86_64 tvOS. Combined into FAT STATIC lib (supported on 3.14+ of CMake with "-G Xcode" argument ONLY) +# SIMULATOR_TVOS = Build for x86_64 tvOS Simulator. +# WATCHOS = Build for armv7k arm64_32 for watchOS. +# WATCHOSCOMBINED = Build for armv7k arm64_32 x86_64 watchOS. Combined into FAT STATIC lib (supported on 3.14+ of CMake with "-G Xcode" argument ONLY) +# SIMULATOR_WATCHOS = Build for x86_64 for watchOS Simulator. +# MAC = Build for x86_64 macOS. +# MAC_ARM64 = Build for Apple Silicon macOS. +# MAC_CATALYST = Build for x86_64 macOS with Catalyst support (iOS toolchain on macOS). +# Note: The build argument "MACOSX_DEPLOYMENT_TARGET" can be used to control min-version of macOS +# MAC_CATALYST_ARM64 = Build for Apple Silicon macOS with Catalyst support (iOS toolchain on macOS). +# Note: The build argument "MACOSX_DEPLOYMENT_TARGET" can be used to control min-version of macOS +# +# CMAKE_OSX_SYSROOT: Path to the SDK to use. By default this is +# automatically determined from PLATFORM and xcodebuild, but +# can also be manually specified (although this should not be required). +# +# CMAKE_DEVELOPER_ROOT: Path to the Developer directory for the platform +# being compiled for. By default this is automatically determined from +# CMAKE_OSX_SYSROOT, but can also be manually specified (although this should +# not be required). +# +# DEPLOYMENT_TARGET: Minimum SDK version to target. Default 2.0 on watchOS and 9.0 on tvOS+iOS +# +# ENABLE_BITCODE: (1|0) Enables or disables bitcode support. Default 1 (true) +# +# ENABLE_ARC: (1|0) Enables or disables ARC support. Default 1 (true, ARC enabled by default) +# +# ENABLE_VISIBILITY: (1|0) Enables or disables symbol visibility support. Default 0 (false, visibility hidden by default) +# +# ENABLE_STRICT_TRY_COMPILE: (1|0) Enables or disables strict try_compile() on all Check* directives (will run linker +# to actually check if linking is possible). Default 0 (false, will set CMAKE_TRY_COMPILE_TARGET_TYPE to STATIC_LIBRARY) +# +# ARCHS: (armv7 armv7s armv7k arm64 arm64_32 i386 x86_64) If specified, will override the default architectures for the given PLATFORM +# OS = armv7 armv7s arm64 (if applicable) +# OS64 = arm64 (if applicable) +# SIMULATOR = i386 +# SIMULATOR64 = x86_64 +# SIMULATORARM64 = arm64 +# TVOS = arm64 +# SIMULATOR_TVOS = x86_64 (i386 has since long been deprecated) +# WATCHOS = armv7k arm64_32 (if applicable) +# SIMULATOR_WATCHOS = x86_64 (i386 has since long been deprecated) +# MAC = x86_64 +# MAC_ARM64 = arm64 +# MAC_CATALYST = x86_64 +# MAC_CATALYST_ARM64 = arm64 +# +# This toolchain defines the following properties (available via get_property()) for use externally: +# +# PLATFORM: The currently targeted platform. +# XCODE_VERSION: Version number (not including Build version) of Xcode detected. +# SDK_VERSION: Version of SDK being used. +# OSX_ARCHITECTURES: Architectures being compiled for (generated from PLATFORM). +# APPLE_TARGET_TRIPLE: Used by autoconf build systems. NOTE: If "ARCHS" are overridden, this will *NOT* be set! +# +# This toolchain defines the following macros for use externally: +# +# set_xcode_property (TARGET XCODE_PROPERTY XCODE_VALUE XCODE_VARIANT) +# A convenience macro for setting xcode specific properties on targets. +# Available variants are: All, Release, RelWithDebInfo, Debug, MinSizeRel +# example: set_xcode_property (myioslib IPHONEOS_DEPLOYMENT_TARGET "3.1" "all"). +# +# find_host_package (PROGRAM ARGS) +# A macro used to find executable programs on the host system, not within the +# environment. Thanks to the android-cmake project for providing the +# command. +# + +cmake_minimum_required(VERSION 3.8.0) + +# CMake invokes the toolchain file twice during the first build, but only once during subsequent rebuilds. +if(DEFINED ENV{_IOS_TOOLCHAIN_HAS_RUN}) + return() +endif() +set(ENV{_IOS_TOOLCHAIN_HAS_RUN} true) + +############################################################################### +# OPTIONS # +############################################################################### + +option(DROP_32_BIT "Drops the 32-bit targets universally." YES) + +############################################################################### +# END OPTIONS # +############################################################################### + +# List of supported platform values +list(APPEND _supported_platforms + "OS" "OS64" "OS64COMBINED" "SIMULATOR" "SIMULATOR64" "SIMULATORARM64" + "TVOS" "TVOSCOMBINED" "SIMULATOR_TVOS" + "WATCHOS" "WATCHOSCOMBINED" "SIMULATOR_WATCHOS" + "MAC" "MAC_ARM64" + "MAC_CATALYST" "MAC_CATALYST_ARM64") + +# Cache what generator is used +set(USED_CMAKE_GENERATOR "${CMAKE_GENERATOR}") + +# Check if using a CMake version capable of building combined FAT builds (simulator and target slices combined in one static lib) +if(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.14") + set(MODERN_CMAKE YES) +endif() + +# Get the Xcode version being used. +# Problem: CMake runs toolchain files multiple times, but can't read cache variables on some runs. +# Workaround: On first run (in which cache variables are always accessible), set an intermediary environment variable. +# +# NOTE: This pattern is used i many places in this toolchain to speed up checks of all sorts +if(DEFINED XCODE_VERSION_INT) + # Environment variables are always preserved. + set(ENV{_XCODE_VERSION_INT} "${XCODE_VERSION_INT}") +elseif(DEFINED ENV{_XCODE_VERSION_INT}) + set(XCODE_VERSION_INT "$ENV{_XCODE_VERSION_INT}") +elseif(NOT DEFINED XCODE_VERSION_INT) + find_program(XCODEBUILD_EXECUTABLE xcodebuild) + if(NOT XCODEBUILD_EXECUTABLE) + message(FATAL_ERROR "xcodebuild not found. Please install either the standalone commandline tools or Xcode.") + endif() + execute_process(COMMAND ${XCODEBUILD_EXECUTABLE} -version + OUTPUT_VARIABLE XCODE_VERSION_INT + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE) + string(REGEX MATCH "Xcode [0-9\\.]+" XCODE_VERSION_INT "${XCODE_VERSION_INT}") + string(REGEX REPLACE "Xcode ([0-9\\.]+)" "\\1" XCODE_VERSION_INT "${XCODE_VERSION_INT}") + set(XCODE_VERSION_INT "${XCODE_VERSION_INT}" CACHE INTERNAL "") +endif() + +# Assuming that xcode 12.0 is installed you most probably have ios sdk 14.0 or later installed (tested on Big Sur) +# if you don't set a deployment target it will be set the way you only get 64-bit builds +if(NOT DEFINED DEPLOYMENT_TARGET AND XCODE_VERSION_INT VERSION_GREATER 12.0) + # Temporarily fix the arm64 issues in CMake install-combined by excluding arm64 for simulator builds (needed for Apple Silicon...) + set(CMAKE_XCODE_ATTRIBUTE_EXCLUDED_ARCHS[sdk=iphonesimulator*] "arm64") +endif() + +# Check if the platform variable is set +if(DEFINED PLATFORM) + # Environment variables are always preserved. + set(ENV{_PLATFORM} "${PLATFORM}") +elseif(DEFINED ENV{_PLATFORM}) + set(PLATFORM "$ENV{_PLATFORM}") +elseif(NOT DEFINED PLATFORM) + message(FATAL_ERROR "PLATFORM argument not set. Bailing configure since I don't know what target you want to build for!") +endif () + +if(PLATFORM MATCHES ".*COMBINED" AND NOT CMAKE_GENERATOR MATCHES "Xcode") + message(FATAL_ERROR "The combined builds support requires Xcode to be used as generator via '-G Xcode' command-line argument in CMake") +endif() + +# Safeguard that the platform value is set and is one of the supported values +list(FIND _supported_platforms ${PLATFORM} contains_PLATFORM) +if("${contains_PLATFORM}" EQUAL "-1") + string(REPLACE ";" "\n * " _supported_platforms_formatted "${_supported_platforms}") + message(FATAL_ERROR " Invalid PLATFORM specified! Current value: ${PLATFORM}.\n" + " Supported PLATFORM values: \n * ${_supported_platforms_formatted}") +endif() + +# Check if Apple Silicon is supported +if(PLATFORM MATCHES "^(MAC_ARM64)$|^(MAC_CATALYST_ARM64)$" AND ${CMAKE_VERSION} VERSION_LESS "3.19.5") + message(FATAL_ERROR "Apple Silicon builds requires a minimum of CMake 3.19.5") +endif() + +# Touch toolchain variable to suppress "unused variable" warning. +# This happens if CMake is invoked with the same command line the second time. +if(CMAKE_TOOLCHAIN_FILE) +endif() + +# Fix for PThread library not in path +set(CMAKE_THREAD_LIBS_INIT "-lpthread") +set(CMAKE_HAVE_THREADS_LIBRARY 1) +set(CMAKE_USE_WIN32_THREADS_INIT 0) +set(CMAKE_USE_PTHREADS_INIT 1) + +# Specify minimum version of deployment target. +if(NOT DEFINED DEPLOYMENT_TARGET) + if (PLATFORM MATCHES "WATCHOS") + # Unless specified, SDK version 4.0 is used by default as minimum target version (watchOS). + set(DEPLOYMENT_TARGET "4.0") + elseif(PLATFORM STREQUAL "MAC") + # Unless specified, SDK version 10.13 (High sierra) is used by default as minimum target version (macos). + set(DEPLOYMENT_TARGET "10.13") + elseif(PLATFORM STREQUAL "MAC_ARM64") + # Unless specified, SDK version 11.0 (Big Sur) is used by default as minimum target version (macos on arm). + set(DEPLOYMENT_TARGET "11.0") + elseif(PLATFORM STREQUAL "MAC_CATALYST" OR PLATFORM STREQUAL "MAC_CATALYST_ARM64") + # Unless specified, SDK version 13.0 is used by default as minimum target version (mac catalyst minimum requirement). + set(DEPLOYMENT_TARGET "13.0") + else() + # Unless specified, SDK version 11.0 is used by default as minimum target version (iOS, tvOS). + set(DEPLOYMENT_TARGET "11.0") + endif() + message(STATUS "[DEFAULTS] Using the default min-version since DEPLOYMENT_TARGET not provided!") +elseif(DEFINED DEPLOYMENT_TARGET AND PLATFORM MATCHES "^MAC_CATALYST" AND ${DEPLOYMENT_TARGET} VERSION_LESS "13.0") + message(FATAL_ERROR "Mac Catalyst builds requires a minimum deployment target of 13.0!") +endif() + +# Store the DEPLOYMENT_TARGET in the cache +set(DEPLOYMENT_TARGET "${DEPLOYMENT_TARGET}" CACHE INTERNAL "") + +# Handle the case where we are targeting iOS and a version above 10.3.4 (32-bit support dropped officially) +if(PLATFORM STREQUAL "OS" AND DEPLOYMENT_TARGET VERSION_GREATER_EQUAL 10.3.4) + set(PLATFORM "OS64") + message(STATUS "Targeting minimum SDK version ${DEPLOYMENT_TARGET}. Dropping 32-bit support.") +elseif(PLATFORM STREQUAL "SIMULATOR" AND DEPLOYMENT_TARGET VERSION_GREATER_EQUAL 10.3.4) + set(PLATFORM "SIMULATOR64") + message(STATUS "Targeting minimum SDK version ${DEPLOYMENT_TARGET}. Dropping 32-bit support.") +endif() + +set(PLATFORM_INT "${PLATFORM}") + +if(DEFINED ARCHS) + string(REPLACE ";" "-" ARCHS_SPLIT "${ARCHS}") +endif() + +# Determine the platform name and architectures for use in xcodebuild commands +# from the specified PLATFORM_INT name. +if(PLATFORM_INT STREQUAL "OS") + set(SDK_NAME iphoneos) + if(NOT ARCHS) + set(ARCHS armv7 armv7s arm64) + set(APPLE_TARGET_TRIPLE_INT arm-apple-ios$${DEPLOYMENT_TARGET}) + else() + set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-ios${DEPLOYMENT_TARGET}) + endif() +elseif(PLATFORM_INT STREQUAL "OS64") + set(SDK_NAME iphoneos) + if(NOT ARCHS) + if (XCODE_VERSION_INT VERSION_GREATER 10.0) + set(ARCHS arm64) # Add arm64e when Apple have fixed the integration issues with it, libarclite_iphoneos.a is currently missung bitcode markers for example + else() + set(ARCHS arm64) + endif() + set(APPLE_TARGET_TRIPLE_INT aarch64-apple-ios${DEPLOYMENT_TARGET}) + else() + set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-ios${DEPLOYMENT_TARGET}) + endif() +elseif(PLATFORM_INT STREQUAL "OS64COMBINED") + set(SDK_NAME iphoneos) + if(MODERN_CMAKE) + if(NOT ARCHS) + if (XCODE_VERSION_INT VERSION_GREATER 10.0) + set(ARCHS arm64 x86_64) # Add arm64e when Apple have fixed the integration issues with it, libarclite_iphoneos.a is currently missung bitcode markers for example + set(CMAKE_XCODE_ATTRIBUTE_ARCHS[sdk=iphoneos*] "arm64") + set(CMAKE_XCODE_ATTRIBUTE_ARCHS[sdk=iphonesimulator*] "x86_64") + set(CMAKE_XCODE_ATTRIBUTE_VALID_ARCHS[sdk=iphoneos*] "arm64") + set(CMAKE_XCODE_ATTRIBUTE_VALID_ARCHS[sdk=iphonesimulator*] "x86_64") + else() + set(ARCHS arm64 x86_64) + set(CMAKE_XCODE_ATTRIBUTE_ARCHS[sdk=iphoneos*] "arm64") + set(CMAKE_XCODE_ATTRIBUTE_ARCHS[sdk=iphonesimulator*] "x86_64") + set(CMAKE_XCODE_ATTRIBUTE_VALID_ARCHS[sdk=iphoneos*] "arm64") + set(CMAKE_XCODE_ATTRIBUTE_VALID_ARCHS[sdk=iphonesimulator*] "x86_64") + endif() + set(APPLE_TARGET_TRIPLE_INT aarch64-x86_64-apple-ios${DEPLOYMENT_TARGET}) + else() + set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-ios${DEPLOYMENT_TARGET}) + endif() + else() + message(FATAL_ERROR "Please make sure that you are running CMake 3.14+ to make the OS64COMBINED setting work") + endif() +elseif(PLATFORM_INT STREQUAL "SIMULATOR") + set(SDK_NAME iphonesimulator) + if(NOT ARCHS) + set(ARCHS i386) + set(APPLE_TARGET_TRIPLE_INT i386-apple-ios${DEPLOYMENT_TARGET}-simulator) + else() + set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-ios${DEPLOYMENT_TARGET}-simulator) + endif() + message(DEPRECATION "SIMULATOR IS DEPRECATED. Consider using SIMULATOR64 instead.") +elseif(PLATFORM_INT STREQUAL "SIMULATOR64") + set(SDK_NAME iphonesimulator) + if(NOT ARCHS) + set(ARCHS x86_64) + set(APPLE_TARGET_TRIPLE_INT x86_64-apple-ios${DEPLOYMENT_TARGET}-simulator) + else() + set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-ios${DEPLOYMENT_TARGET}-simulator) + endif() +elseif(PLATFORM_INT STREQUAL "SIMULATORARM64") + set(SDK_NAME iphonesimulator) + if(NOT ARCHS) + set(ARCHS arm64) + set(APPLE_TARGET_TRIPLE_INT aarch64-apple-ios${DEPLOYMENT_TARGET}-simulator) + else() + set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-ios${DEPLOYMENT_TARGET}-simulator) + endif() +elseif(PLATFORM_INT STREQUAL "TVOS") + set(SDK_NAME appletvos) + if(NOT ARCHS) + set(ARCHS arm64) + set(APPLE_TARGET_TRIPLE_INT aarch64-apple-tvos${DEPLOYMENT_TARGET}) + else() + set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-tvos${DEPLOYMENT_TARGET}) + endif() +elseif (PLATFORM_INT STREQUAL "TVOSCOMBINED") + set(SDK_NAME appletvos) + if(MODERN_CMAKE) + if(NOT ARCHS) + set(ARCHS arm64 x86_64) + set(APPLE_TARGET_TRIPLE_INT aarch64-x86_64-apple-tvos${DEPLOYMENT_TARGET}) + set(CMAKE_XCODE_ATTRIBUTE_ARCHS[sdk=appletvos*] "arm64") + set(CMAKE_XCODE_ATTRIBUTE_ARCHS[sdk=appletvsimulator*] "x86_64") + set(CMAKE_XCODE_ATTRIBUTE_VALID_ARCHS[sdk=appletvos*] "arm64") + set(CMAKE_XCODE_ATTRIBUTE_VALID_ARCHS[sdk=appletvsimulator*] "x86_64") + else() + set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-tvos${DEPLOYMENT_TARGET}) + endif() + else() + message(FATAL_ERROR "Please make sure that you are running CMake 3.14+ to make the TVOSCOMBINED setting work") + endif() +elseif(PLATFORM_INT STREQUAL "SIMULATOR_TVOS") + set(SDK_NAME appletvsimulator) + if(NOT ARCHS) + set(ARCHS x86_64) + set(APPLE_TARGET_TRIPLE_INT x86_64-apple-tvos${DEPLOYMENT_TARGET}-simulator) + else() + set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-tvos${DEPLOYMENT_TARGET}-simulator) + endif() +elseif(PLATFORM_INT STREQUAL "WATCHOS") + set(SDK_NAME watchos) + if(NOT ARCHS) + if (XCODE_VERSION_INT VERSION_GREATER 10.0) + set(ARCHS armv7k arm64_32) + set(APPLE_TARGET_TRIPLE_INT aarch64_32-apple-watchos${DEPLOYMENT_TARGET}) + else() + set(ARCHS armv7k) + set(APPLE_TARGET_TRIPLE_INT arm-apple-watchos${DEPLOYMENT_TARGET}) + endif() + else() + set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-watchos${DEPLOYMENT_TARGET}) + endif() +elseif(PLATFORM_INT STREQUAL "WATCHOSCOMBINED") + set(SDK_NAME watchos) + if(MODERN_CMAKE) + if(NOT ARCHS) + if (XCODE_VERSION_INT VERSION_GREATER 10.0) + set(ARCHS armv7k arm64_32 i386) + set(APPLE_TARGET_TRIPLE_INT aarch64_32-i386-apple-watchos${DEPLOYMENT_TARGET}) + set(CMAKE_XCODE_ATTRIBUTE_ARCHS[sdk=watchos*] "armv7k arm64_32") + set(CMAKE_XCODE_ATTRIBUTE_ARCHS[sdk=watchsimulator*] "i386") + set(CMAKE_XCODE_ATTRIBUTE_VALID_ARCHS[sdk=watchos*] "armv7k arm64_32") + set(CMAKE_XCODE_ATTRIBUTE_VALID_ARCHS[sdk=watchsimulator*] "i386") + else() + set(ARCHS armv7k i386) + set(APPLE_TARGET_TRIPLE_INT arm-i386-apple-watchos${DEPLOYMENT_TARGET}) + set(CMAKE_XCODE_ATTRIBUTE_ARCHS[sdk=watchos*] "armv7k") + set(CMAKE_XCODE_ATTRIBUTE_ARCHS[sdk=watchsimulator*] "i386") + set(CMAKE_XCODE_ATTRIBUTE_VALID_ARCHS[sdk=watchos*] "armv7k") + set(CMAKE_XCODE_ATTRIBUTE_VALID_ARCHS[sdk=watchsimulator*] "i386") + endif() + else() + set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-watchos${DEPLOYMENT_TARGET}) + endif() + else() + message(FATAL_ERROR "Please make sure that you are running CMake 3.14+ to make the WATCHOSCOMBINED setting work") + endif() +elseif(PLATFORM_INT STREQUAL "SIMULATOR_WATCHOS") + set(SDK_NAME watchsimulator) + if(NOT ARCHS) + set(ARCHS i386) + set(APPLE_TARGET_TRIPLE_INT i386-apple-watchos${DEPLOYMENT_TARGET}-simulator) + else() + set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-watchos${DEPLOYMENT_TARGET}-simulator) + endif() +elseif(PLATFORM_INT STREQUAL "MAC" OR PLATFORM_INT STREQUAL "MAC_CATALYST") + set(SDK_NAME macosx) + if(NOT ARCHS) + set(ARCHS x86_64) + endif() + string(REPLACE ";" "-" ARCHS_SPLIT "${ARCHS}") + if(PLATFORM_INT STREQUAL "MAC") + set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-macosx${DEPLOYMENT_TARGET}) + elseif(PLATFORM_INT STREQUAL "MAC_CATALYST") + set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-ios${DEPLOYMENT_TARGET}-macabi) + endif() +elseif(PLATFORM_INT MATCHES "^(MAC_ARM64)$|^(MAC_CATALYST_ARM64)$") + set(SDK_NAME macosx) + if(NOT ARCHS) + set(ARCHS arm64) + endif() + string(REPLACE ";" "-" ARCHS_SPLIT "${ARCHS}") + if(PLATFORM_INT STREQUAL "MAC_ARM64") + set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-macosx${DEPLOYMENT_TARGET}) + elseif(PLATFORM_INT STREQUAL "MAC_CATALYST_ARM64") + set(APPLE_TARGET_TRIPLE_INT ${ARCHS_SPLIT}-apple-ios${DEPLOYMENT_TARGET}-macabi) + endif() +else() + message(FATAL_ERROR "Invalid PLATFORM: ${PLATFORM_INT}") +endif() + +if(MODERN_CMAKE AND PLATFORM_INT MATCHES ".*COMBINED" AND NOT CMAKE_GENERATOR MATCHES "Xcode") + message(FATAL_ERROR "The COMBINED options only work with Xcode generator, -G Xcode") +endif() + +if(CMAKE_GENERATOR MATCHES "Xcode" AND PLATFORM_INT MATCHES "^MAC_CATALYST") + set(CMAKE_XCODE_ATTRIBUTE_CLANG_CXX_LIBRARY "libc++") + set(CMAKE_XCODE_ATTRIBUTE_SUPPORTED_PLATFORMS "macosx") + set(CMAKE_XCODE_EFFECTIVE_PLATFORMS "-maccatalyst") + if(NOT DEFINED MACOSX_DEPLOYMENT_TARGET) + set(CMAKE_XCODE_ATTRIBUTE_MACOSX_DEPLOYMENT_TARGET "10.15") + else() + set(CMAKE_XCODE_ATTRIBUTE_MACOSX_DEPLOYMENT_TARGET "${MACOSX_DEPLOYMENT_TARGET}") + endif() +elseif(CMAKE_GENERATOR MATCHES "Xcode") + set(CMAKE_XCODE_ATTRIBUTE_IPHONEOS_DEPLOYMENT_TARGET "${DEPLOYMENT_TARGET}") + if(NOT PLATFORM_INT MATCHES ".*COMBINED") + set(CMAKE_XCODE_ATTRIBUTE_ARCHS[sdk=${SDK_NAME}*] "${ARCHS}") + set(CMAKE_XCODE_ATTRIBUTE_VALID_ARCHS[sdk=${SDK_NAME}*] "${ARCHS}") + endif() +endif() + +# If user did not specify the SDK root to use, then query xcodebuild for it. +if(DEFINED CMAKE_OSX_SYSROOT_INT) + # Environment variables are always preserved. + set(ENV{_CMAKE_OSX_SYSROOT_INT} "${CMAKE_OSX_SYSROOT_INT}") +elseif(DEFINED ENV{_CMAKE_OSX_SYSROOT_INT}) + set(CMAKE_OSX_SYSROOT_INT "$ENV{_CMAKE_OSX_SYSROOT_INT}") +elseif(NOT DEFINED CMAKE_OSX_SYSROOT_INT) + execute_process(COMMAND ${XCODEBUILD_EXECUTABLE} -version -sdk ${SDK_NAME} Path + OUTPUT_VARIABLE CMAKE_OSX_SYSROOT_INT + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE) +endif() + +if (NOT DEFINED CMAKE_OSX_SYSROOT_INT AND NOT DEFINED CMAKE_OSX_SYSROOT) + message(SEND_ERROR "Please make sure that Xcode is installed and that the toolchain" + "is pointing to the correct path. Please run:" + "sudo xcode-select -s /Applications/Xcode.app/Contents/Developer" + "and see if that fixes the problem for you.") + message(FATAL_ERROR "Invalid CMAKE_OSX_SYSROOT: ${CMAKE_OSX_SYSROOT} " + "does not exist.") +elseif(DEFINED CMAKE_OSX_SYSROOT_INT) + set(CMAKE_OSX_SYSROOT_INT "${CMAKE_OSX_SYSROOT_INT}" CACHE INTERNAL "") + # Specify the location or name of the platform SDK to be used in CMAKE_OSX_SYSROOT. + set(CMAKE_OSX_SYSROOT "${CMAKE_OSX_SYSROOT_INT}" CACHE INTERNAL "") +endif() + +# Use bitcode or not +if(NOT DEFINED ENABLE_BITCODE AND NOT ARCHS MATCHES "((^|;|, )(i386|x86_64))+") + # Unless specified, enable bitcode support by default + message(STATUS "[DEFAULTS] Enabling bitcode support by default. ENABLE_BITCODE not provided!") + set(ENABLE_BITCODE TRUE) +elseif(NOT DEFINED ENABLE_BITCODE) + message(STATUS "[DEFAULTS] Disabling bitcode support by default on simulators. ENABLE_BITCODE not provided for override!") + set(ENABLE_BITCODE FALSE) +endif() +set(ENABLE_BITCODE_INT ${ENABLE_BITCODE} CACHE BOOL + "Whether or not to enable bitcode" FORCE) +# Use ARC or not +if(NOT DEFINED ENABLE_ARC) + # Unless specified, enable ARC support by default + set(ENABLE_ARC TRUE) + message(STATUS "[DEFAULTS] Enabling ARC support by default. ENABLE_ARC not provided!") +endif() +set(ENABLE_ARC_INT ${ENABLE_ARC} CACHE BOOL "Whether or not to enable ARC" FORCE) +# Use hidden visibility or not +if(NOT DEFINED ENABLE_VISIBILITY) + # Unless specified, disable symbols visibility by default + set(ENABLE_VISIBILITY FALSE) + message(STATUS "[DEFAULTS] Hiding symbols visibility by default. ENABLE_VISIBILITY not provided!") +endif() +set(ENABLE_VISIBILITY_INT ${ENABLE_VISIBILITY} CACHE BOOL "Whether or not to hide symbols from the dynamic linker (-fvisibility=hidden)" FORCE) +# Set strict compiler checks or not +if(NOT DEFINED ENABLE_STRICT_TRY_COMPILE) + # Unless specified, disable strict try_compile() + set(ENABLE_STRICT_TRY_COMPILE FALSE) + message(STATUS "[DEFAULTS] Using NON-strict compiler checks by default. ENABLE_STRICT_TRY_COMPILE not provided!") +endif() +set(ENABLE_STRICT_TRY_COMPILE_INT ${ENABLE_STRICT_TRY_COMPILE} CACHE BOOL + "Whether or not to use strict compiler checks" FORCE) + +# Get the SDK version information. +if(DEFINED SDK_VERSION) + # Environment variables are always preserved. + set(ENV{_SDK_VERSION} "${SDK_VERSION}") +elseif(DEFINED ENV{_SDK_VERSION}) + set(SDK_VERSION "$ENV{_SDK_VERSION}") +elseif(NOT DEFINED SDK_VERSION) + execute_process(COMMAND ${XCODEBUILD_EXECUTABLE} -sdk ${CMAKE_OSX_SYSROOT_INT} -version SDKVersion + OUTPUT_VARIABLE SDK_VERSION + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE) +endif() + +# Find the Developer root for the specific iOS platform being compiled for +# from CMAKE_OSX_SYSROOT. Should be ../../ from SDK specified in +# CMAKE_OSX_SYSROOT. There does not appear to be a direct way to obtain +# this information from xcrun or xcodebuild. +if (NOT DEFINED CMAKE_DEVELOPER_ROOT AND NOT CMAKE_GENERATOR MATCHES "Xcode") + get_filename_component(PLATFORM_SDK_DIR ${CMAKE_OSX_SYSROOT_INT} PATH) + get_filename_component(CMAKE_DEVELOPER_ROOT ${PLATFORM_SDK_DIR} PATH) + if (NOT EXISTS "${CMAKE_DEVELOPER_ROOT}") + message(FATAL_ERROR "Invalid CMAKE_DEVELOPER_ROOT: ${CMAKE_DEVELOPER_ROOT} does not exist.") + endif() +endif() + +# Find the C & C++ compilers for the specified SDK. +if(DEFINED CMAKE_C_COMPILER) + # Environment variables are always preserved. + set(ENV{_CMAKE_C_COMPILER} "${CMAKE_C_COMPILER}") +elseif(DEFINED ENV{_CMAKE_C_COMPILER}) + set(CMAKE_C_COMPILER "$ENV{_CMAKE_C_COMPILER}") + set(CMAKE_ASM_COMPILER ${CMAKE_C_COMPILER}) +elseif(NOT DEFINED CMAKE_C_COMPILER) + execute_process(COMMAND xcrun -sdk ${CMAKE_OSX_SYSROOT_INT} -find clang + OUTPUT_VARIABLE CMAKE_C_COMPILER + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE) + set(CMAKE_ASM_COMPILER ${CMAKE_C_COMPILER}) +endif() +if(DEFINED CMAKE_CXX_COMPILER) + # Environment variables are always preserved. + set(ENV{_CMAKE_CXX_COMPILER} "${CMAKE_CXX_COMPILER}") +elseif(DEFINED ENV{_CMAKE_CXX_COMPILER}) + set(CMAKE_CXX_COMPILER "$ENV{_CMAKE_CXX_COMPILER}") +elseif(NOT DEFINED CMAKE_CXX_COMPILER) + execute_process(COMMAND xcrun -sdk ${CMAKE_OSX_SYSROOT_INT} -find clang++ + OUTPUT_VARIABLE CMAKE_CXX_COMPILER + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE) +endif() +# Find (Apple's) libtool. +if(DEFINED BUILD_LIBTOOL) + # Environment variables are always preserved. + set(ENV{_BUILD_LIBTOOL} "${BUILD_LIBTOOL}") +elseif(DEFINED ENV{_BUILD_LIBTOOL}) + set(BUILD_LIBTOOL "$ENV{_BUILD_LIBTOOL}") +elseif(NOT DEFINED BUILD_LIBTOOL) + execute_process(COMMAND xcrun -sdk ${CMAKE_OSX_SYSROOT_INT} -find libtool + OUTPUT_VARIABLE BUILD_LIBTOOL + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE) +endif() +# Find the toolchain's provided install_name_tool if none is found on the host +if(DEFINED CMAKE_INSTALL_NAME_TOOL) + # Environment variables are always preserved. + set(ENV{_CMAKE_INSTALL_NAME_TOOL} "${CMAKE_INSTALL_NAME_TOOL}") +elseif(DEFINED ENV{_CMAKE_INSTALL_NAME_TOOL}) + set(CMAKE_INSTALL_NAME_TOOL "$ENV{_CMAKE_INSTALL_NAME_TOOL}") +elseif(NOT DEFINED CMAKE_INSTALL_NAME_TOOL) + execute_process(COMMAND xcrun -sdk ${CMAKE_OSX_SYSROOT_INT} -find install_name_tool + OUTPUT_VARIABLE CMAKE_INSTALL_NAME_TOOL_INT + ERROR_QUIET + OUTPUT_STRIP_TRAILING_WHITESPACE) + set(CMAKE_INSTALL_NAME_TOOL ${CMAKE_INSTALL_NAME_TOOL_INT} CACHE INTERNAL "") +endif() + +# Configure libtool to be used instead of ar + ranlib to build static libraries. +# This is required on Xcode 7+, but should also work on previous versions of +# Xcode. +get_property(languages GLOBAL PROPERTY ENABLED_LANGUAGES) +foreach(lang ${languages}) + set(CMAKE_${lang}_CREATE_STATIC_LIBRARY "${BUILD_LIBTOOL} -static -o " CACHE INTERNAL "") +endforeach() + +# CMake 3.14+ support building for iOS, watchOS and tvOS out of the box. +if(MODERN_CMAKE) + if(SDK_NAME MATCHES "iphone") + set(CMAKE_SYSTEM_NAME iOS) + elseif(SDK_NAME MATCHES "macosx") + set(CMAKE_SYSTEM_NAME Darwin) + elseif(SDK_NAME MATCHES "appletv") + set(CMAKE_SYSTEM_NAME tvOS) + elseif(SDK_NAME MATCHES "watch") + set(CMAKE_SYSTEM_NAME watchOS) + endif() + # Provide flags for a combined FAT library build on newer CMake versions + if(PLATFORM_INT MATCHES ".*COMBINED") + set(CMAKE_XCODE_ATTRIBUTE_ONLY_ACTIVE_ARCH "NO") + set(CMAKE_IOS_INSTALL_COMBINED YES) + message(STATUS "Will combine built (static) artifacts into FAT lib...") + endif() +elseif(NOT DEFINED CMAKE_SYSTEM_NAME AND ${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.10") + # Legacy code path prior to CMake 3.14 or fallback if no CMAKE_SYSTEM_NAME specified + set(CMAKE_SYSTEM_NAME iOS) +elseif(NOT DEFINED CMAKE_SYSTEM_NAME) + # Legacy code path prior to CMake 3.14 or fallback if no CMAKE_SYSTEM_NAME specified + set(CMAKE_SYSTEM_NAME Darwin) +endif() +# Standard settings. +set(CMAKE_SYSTEM_VERSION ${SDK_VERSION} CACHE INTERNAL "") +set(UNIX TRUE CACHE BOOL "") +set(APPLE TRUE CACHE BOOL "") +if(PLATFORM STREQUAL "MAC" OR PLATFORM STREQUAL "MAC_ARM64") + set(IOS FALSE CACHE BOOL "") + set(MACOS TRUE CACHE BOOL "") +elseif(PLATFORM STREQUAL "MAC_CATALYST" OR PLATFORM STREQUAL "MAC_CATALYST_ARM64") + set(IOS TRUE CACHE BOOL "") + set(MACOS TRUE CACHE BOOL "") +else() + set(IOS TRUE CACHE BOOL "") +endif() +set(CMAKE_AR ar CACHE FILEPATH "" FORCE) +set(CMAKE_RANLIB ranlib CACHE FILEPATH "" FORCE) +set(CMAKE_STRIP strip CACHE FILEPATH "" FORCE) +# Set the architectures for which to build. +set(CMAKE_OSX_ARCHITECTURES ${ARCHS} CACHE INTERNAL "") +# Change the type of target generated for try_compile() so it'll work when cross-compiling, weak compiler checks +if(NOT ENABLE_STRICT_TRY_COMPILE_INT) + set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) +endif() +# All iOS/Darwin specific settings - some may be redundant. +set(CMAKE_MACOSX_BUNDLE YES) +set(CMAKE_XCODE_ATTRIBUTE_CODE_SIGNING_REQUIRED "NO") +set(CMAKE_SHARED_LIBRARY_PREFIX "lib") +set(CMAKE_SHARED_LIBRARY_SUFFIX ".dylib") +set(CMAKE_SHARED_MODULE_PREFIX "lib") +set(CMAKE_SHARED_MODULE_SUFFIX ".so") +set(CMAKE_C_COMPILER_ABI ELF) +set(CMAKE_CXX_COMPILER_ABI ELF) +set(CMAKE_C_HAS_ISYSROOT 1) +set(CMAKE_CXX_HAS_ISYSROOT 1) +set(CMAKE_MODULE_EXISTS 1) +set(CMAKE_DL_LIBS "") +set(CMAKE_C_OSX_COMPATIBILITY_VERSION_FLAG "-compatibility_version ") +set(CMAKE_C_OSX_CURRENT_VERSION_FLAG "-current_version ") +set(CMAKE_CXX_OSX_COMPATIBILITY_VERSION_FLAG "${CMAKE_C_OSX_COMPATIBILITY_VERSION_FLAG}") +set(CMAKE_CXX_OSX_CURRENT_VERSION_FLAG "${CMAKE_C_OSX_CURRENT_VERSION_FLAG}") + +if(ARCHS MATCHES "((^|;|, )(arm64|arm64e|x86_64))+") + set(CMAKE_C_SIZEOF_DATA_PTR 8) + set(CMAKE_CXX_SIZEOF_DATA_PTR 8) + if(ARCHS MATCHES "((^|;|, )(arm64|arm64e))+") + set(CMAKE_SYSTEM_PROCESSOR "aarch64") + else() + set(CMAKE_SYSTEM_PROCESSOR "x86_64") + endif() +else() + set(CMAKE_C_SIZEOF_DATA_PTR 4) + set(CMAKE_CXX_SIZEOF_DATA_PTR 4) + set(CMAKE_SYSTEM_PROCESSOR "arm") +endif() + +# Note that only Xcode 7+ supports the newer more specific: +# -m${SDK_NAME}-version-min flags, older versions of Xcode use: +# -m(ios/ios-simulator)-version-min instead. +if(${CMAKE_VERSION} VERSION_LESS "3.11") + if(PLATFORM_INT STREQUAL "OS" OR PLATFORM_INT STREQUAL "OS64") + if(XCODE_VERSION_INT VERSION_LESS 7.0) + set(SDK_NAME_VERSION_FLAGS + "-mios-version-min=${DEPLOYMENT_TARGET}") + else() + # Xcode 7.0+ uses flags we can build directly from SDK_NAME. + set(SDK_NAME_VERSION_FLAGS + "-m${SDK_NAME}-version-min=${DEPLOYMENT_TARGET}") + endif() + elseif(PLATFORM_INT STREQUAL "TVOS") + set(SDK_NAME_VERSION_FLAGS + "-mtvos-version-min=${DEPLOYMENT_TARGET}") + elseif(PLATFORM_INT STREQUAL "SIMULATOR_TVOS") + set(SDK_NAME_VERSION_FLAGS + "-mtvos-simulator-version-min=${DEPLOYMENT_TARGET}") + elseif(PLATFORM_INT STREQUAL "WATCHOS") + set(SDK_NAME_VERSION_FLAGS + "-mwatchos-version-min=${DEPLOYMENT_TARGET}") + elseif(PLATFORM_INT STREQUAL "SIMULATOR_WATCHOS") + set(SDK_NAME_VERSION_FLAGS + "-mwatchos-simulator-version-min=${DEPLOYMENT_TARGET}") + elseif(PLATFORM_INT STREQUAL "MAC") + set(SDK_NAME_VERSION_FLAGS + "-mmacosx-version-min=${DEPLOYMENT_TARGET}") + else() + # SIMULATOR or SIMULATOR64 both use -mios-simulator-version-min. + set(SDK_NAME_VERSION_FLAGS + "-mios-simulator-version-min=${DEPLOYMENT_TARGET}") + endif() +elseif(NOT PLATFORM_INT MATCHES "^MAC_CATALYST") + # Newer versions of CMake sets the version min flags correctly, skip this for Mac Catalyst targets + set(CMAKE_OSX_DEPLOYMENT_TARGET ${DEPLOYMENT_TARGET}) +endif() + +if(DEFINED APPLE_TARGET_TRIPLE_INT) + set(APPLE_TARGET_TRIPLE ${APPLE_TARGET_TRIPLE_INT} CACHE INTERNAL "") + set(CMAKE_C_COMPILER_TARGET ${APPLE_TARGET_TRIPLE}) + set(CMAKE_CXX_COMPILER_TARGET ${APPLE_TARGET_TRIPLE}) + set(CMAKE_ASM_COMPILER_TARGET ${APPLE_TARGET_TRIPLE}) +endif() + +if(PLATFORM_INT MATCHES "^MAC_CATALYST") + set(C_TARGET_FLAGS "-isystem ${CMAKE_OSX_SYSROOT_INT}/System/iOSSupport/usr/include -iframework ${CMAKE_OSX_SYSROOT_INT}/System/iOSSupport/System/Library/Frameworks") +endif() + +if(ENABLE_BITCODE_INT) + set(BITCODE "-fembed-bitcode") + set(CMAKE_XCODE_ATTRIBUTE_BITCODE_GENERATION_MODE "bitcode") + set(CMAKE_XCODE_ATTRIBUTE_ENABLE_BITCODE "YES") +else() + set(BITCODE "") + set(CMAKE_XCODE_ATTRIBUTE_ENABLE_BITCODE "NO") +endif() + +if(ENABLE_ARC_INT) + set(FOBJC_ARC "-fobjc-arc") + set(CMAKE_XCODE_ATTRIBUTE_CLANG_ENABLE_OBJC_ARC "YES") +else() + set(FOBJC_ARC "-fno-objc-arc") + set(CMAKE_XCODE_ATTRIBUTE_CLANG_ENABLE_OBJC_ARC "NO") +endif() + +if(NOT ENABLE_VISIBILITY_INT) + foreach(lang ${languages}) + set(CMAKE_${lang}_VISIBILITY_PRESET "hidden" CACHE INTERNAL "") + endforeach() + set(CMAKE_XCODE_ATTRIBUTE_GCC_SYMBOLS_PRIVATE_EXTERN "YES") + set(VISIBILITY "-fvisibility=hidden -fvisibility-inlines-hidden") +else() + foreach(lang ${languages}) + set(CMAKE_${lang}_VISIBILITY_PRESET "default" CACHE INTERNAL "") + endforeach() + set(CMAKE_XCODE_ATTRIBUTE_GCC_SYMBOLS_PRIVATE_EXTERN "NO") + set(VISIBILITY "-fvisibility=default") +endif() + +if(DEFINED APPLE_TARGET_TRIPLE) + set(APPLE_TARGET_TRIPLE_FLAG "-target ${APPLE_TARGET_TRIPLE}") +endif() + +#Check if Xcode generator is used, since that will handle these flags automagically +if(CMAKE_GENERATOR MATCHES "Xcode") + message(STATUS "Not setting any manual command-line buildflags, since Xcode is selected as generator.") +else() + # Hidden visibility is required for C++ on iOS. + set(CMAKE_C_FLAGS "${C_TARGET_FLAGS} ${APPLE_TARGET_TRIPLE_FLAG} ${SDK_NAME_VERSION_FLAGS} ${BITCODE} -fobjc-abi-version=2 ${FOBJC_ARC} ${CMAKE_C_FLAGS}") + set(CMAKE_CXX_FLAGS "${C_TARGET_FLAGS} ${APPLE_TARGET_TRIPLE_FLAG} ${SDK_NAME_VERSION_FLAGS} ${BITCODE} ${VISIBILITY} -fobjc-abi-version=2 ${FOBJC_ARC} ${CMAKE_CXX_FLAGS}") + set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS} -O0 -g ${CMAKE_CXX_FLAGS_DEBUG}") + set(CMAKE_CXX_FLAGS_MINSIZEREL "${CMAKE_CXX_FLAGS} -DNDEBUG -Os -ffast-math ${CMAKE_CXX_FLAGS_MINSIZEREL}") + set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS} -DNDEBUG -O2 -g -ffast-math ${CMAKE_CXX_FLAGS_RELWITHDEBINFO}") + set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS} -DNDEBUG -O3 -ffast-math ${CMAKE_CXX_FLAGS_RELEASE}") + set(CMAKE_C_LINK_FLAGS "${C_TARGET_FLAGS} ${SDK_NAME_VERSION_FLAGS} -Wl,-search_paths_first ${CMAKE_C_LINK_FLAGS}") + set(CMAKE_CXX_LINK_FLAGS "${C_TARGET_FLAGS} ${SDK_NAME_VERSION_FLAGS} -Wl,-search_paths_first ${CMAKE_CXX_LINK_FLAGS}") + set(CMAKE_ASM_FLAGS "${CMAKE_C_FLAGS} -x assembler-with-cpp -arch ${CMAKE_OSX_ARCHITECTURES} ${APPLE_TARGET_TRIPLE_FLAG}") +endif() + +## Print status messages to inform of the current state +message(STATUS "Configuring ${SDK_NAME} build for platform: ${PLATFORM_INT}, architecture(s): ${ARCHS}") +message(STATUS "Using SDK: ${CMAKE_OSX_SYSROOT_INT}") +message(STATUS "Using C compiler: ${CMAKE_C_COMPILER}") +message(STATUS "Using CXX compiler: ${CMAKE_CXX_COMPILER}") +message(STATUS "Using libtool: ${BUILD_LIBTOOL}") +message(STATUS "Using install name tool: ${CMAKE_INSTALL_NAME_TOOL}") +if(DEFINED APPLE_TARGET_TRIPLE) + message(STATUS "Autoconf target triple: ${APPLE_TARGET_TRIPLE}") +endif() +message(STATUS "Using minimum deployment version: ${DEPLOYMENT_TARGET}" + " (SDK version: ${SDK_VERSION})") +if(MODERN_CMAKE) + message(STATUS "Merging integrated CMake 3.14+ iOS,tvOS,watchOS,macOS toolchain(s) with this toolchain!") +endif() +if(CMAKE_GENERATOR MATCHES "Xcode") + message(STATUS "Using Xcode version: ${XCODE_VERSION_INT}") +endif() +message(STATUS "CMake version: ${CMAKE_VERSION}") +if(DEFINED SDK_NAME_VERSION_FLAGS) + message(STATUS "Using version flags: ${SDK_NAME_VERSION_FLAGS}") +endif() +message(STATUS "Using a data_ptr size of: ${CMAKE_CXX_SIZEOF_DATA_PTR}") +if(ENABLE_BITCODE_INT) + message(STATUS "Bitcode: Enabled") +else() + message(STATUS "Bitcode: Disabled") +endif() + +if(ENABLE_ARC_INT) + message(STATUS "ARC: Enabled") +else() + message(STATUS "ARC: Disabled") +endif() + +if(ENABLE_VISIBILITY_INT) + message(STATUS "Hiding symbols: Disabled") +else() + message(STATUS "Hiding symbols: Enabled") +endif() + +# Set global properties +set_property(GLOBAL PROPERTY PLATFORM "${PLATFORM}") +set_property(GLOBAL PROPERTY APPLE_TARGET_TRIPLE "${APPLE_TARGET_TRIPLE_INT}") +set_property(GLOBAL PROPERTY SDK_VERSION "${SDK_VERSION}") +set_property(GLOBAL PROPERTY XCODE_VERSION "${XCODE_VERSION_INT}") +set_property(GLOBAL PROPERTY OSX_ARCHITECTURES "${CMAKE_OSX_ARCHITECTURES}") + +# Export configurable variables for the try_compile() command. +set(CMAKE_TRY_COMPILE_PLATFORM_VARIABLES + PLATFORM + XCODE_VERSION_INT + SDK_VERSION + DEPLOYMENT_TARGET + CMAKE_DEVELOPER_ROOT + CMAKE_OSX_SYSROOT_INT + ENABLE_BITCODE + ENABLE_ARC + CMAKE_ASM_COMPILER + CMAKE_C_COMPILER + CMAKE_C_COMPILER_TARGET + CMAKE_CXX_COMPILER + CMAKE_CXX_COMPILER_TARGET + BUILD_LIBTOOL + CMAKE_INSTALL_NAME_TOOL + CMAKE_C_FLAGS + CMAKE_CXX_FLAGS + CMAKE_CXX_FLAGS_DEBUG + CMAKE_CXX_FLAGS_MINSIZEREL + CMAKE_CXX_FLAGS_RELWITHDEBINFO + CMAKE_CXX_FLAGS_RELEASE + CMAKE_C_LINK_FLAGS + CMAKE_CXX_LINK_FLAGS + CMAKE_ASM_FLAGS + ) + +set(CMAKE_PLATFORM_HAS_INSTALLNAME 1) +set(CMAKE_SHARED_LINKER_FLAGS "-rpath @executable_path/Frameworks -rpath @loader_path/Frameworks") +set(CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS "-dynamiclib -Wl,-headerpad_max_install_names") +set(CMAKE_SHARED_MODULE_CREATE_C_FLAGS "-bundle -Wl,-headerpad_max_install_names") +set(CMAKE_SHARED_MODULE_LOADER_C_FLAG "-Wl,-bundle_loader,") +set(CMAKE_SHARED_MODULE_LOADER_CXX_FLAG "-Wl,-bundle_loader,") +set(CMAKE_FIND_LIBRARY_SUFFIXES ".tbd" ".dylib" ".so" ".a") +set(CMAKE_SHARED_LIBRARY_SONAME_C_FLAG "-install_name") + +# Set the find root to the SDK developer roots. +# Note: CMAKE_FIND_ROOT_PATH is only useful when cross-compiling. Thus, do not set on macOS builds. +if(NOT PLATFORM_INT STREQUAL "MAC" AND NOT PLATFORM_INT STREQUAL "MAC_ARM64") + list(APPEND CMAKE_FIND_ROOT_PATH "${CMAKE_OSX_SYSROOT_INT}" CACHE INTERNAL "") + set(CMAKE_IGNORE_PATH "/System/Library/Frameworks;/usr/local/lib" CACHE INTERNAL "") +endif() + +# Default to searching for frameworks first. +set(CMAKE_FIND_FRAMEWORK FIRST) + +# Set up the default search directories for frameworks. +if(PLATFORM_INT MATCHES "^MAC_CATALYST") + set(CMAKE_FRAMEWORK_PATH + ${CMAKE_DEVELOPER_ROOT}/Library/PrivateFrameworks + ${CMAKE_OSX_SYSROOT_INT}/System/Library/Frameworks + ${CMAKE_OSX_SYSROOT_INT}/System/iOSSupport/System/Library/Frameworks + ${CMAKE_FRAMEWORK_PATH} CACHE INTERNAL "") +else() + set(CMAKE_FRAMEWORK_PATH + ${CMAKE_DEVELOPER_ROOT}/Library/PrivateFrameworks + ${CMAKE_OSX_SYSROOT_INT}/System/Library/Frameworks + ${CMAKE_FRAMEWORK_PATH} CACHE INTERNAL "") +endif() + +# By default, search both the specified iOS SDK and the remainder of the host filesystem. +if(NOT CMAKE_FIND_ROOT_PATH_MODE_PROGRAM) + set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM BOTH CACHE INTERNAL "") +endif() +if(NOT CMAKE_FIND_ROOT_PATH_MODE_LIBRARY) + set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY BOTH CACHE INTERNAL "") +endif() +if(NOT CMAKE_FIND_ROOT_PATH_MODE_INCLUDE) + set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE BOTH CACHE INTERNAL "") +endif() +if(NOT CMAKE_FIND_ROOT_PATH_MODE_PACKAGE) + set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE BOTH CACHE INTERNAL "") +endif() + +# +# Some helper-macros below to simplify and beautify the CMakeFile +# + +# This little macro lets you set any Xcode specific property. +macro(set_xcode_property TARGET XCODE_PROPERTY XCODE_VALUE XCODE_RELVERSION) + set(XCODE_RELVERSION_I "${XCODE_RELVERSION}") + if(XCODE_RELVERSION_I STREQUAL "All") + set_property(TARGET ${TARGET} PROPERTY XCODE_ATTRIBUTE_${XCODE_PROPERTY} "${XCODE_VALUE}") + else() + set_property(TARGET ${TARGET} PROPERTY XCODE_ATTRIBUTE_${XCODE_PROPERTY}[variant=${XCODE_RELVERSION_I}] "${XCODE_VALUE}") + endif() +endmacro(set_xcode_property) + +# This macro lets you find executable programs on the host system. +macro(find_host_package) + set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) + set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY NEVER) + set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE NEVER) + set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE NEVER) + set(_TOOLCHAIN_IOS ${IOS}) + set(IOS FALSE) + find_package(${ARGN}) + set(IOS ${_TOOLCHAIN_IOS}) + set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM BOTH) + set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY BOTH) + set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE BOTH) + set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE BOTH) +endmacro(find_host_package) From 7f73293145e44cbe2907fafe6219804bb91a3fd1 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Tue, 3 May 2022 09:33:23 +0200 Subject: [PATCH 164/496] Update iOS openssl build (cherry picked from commit ad04153945ad7566142fa6af0c29195e71d762ba) --- scripts/OpenSSL-DownloadAndBuild.command | 85 +++++++++++------------- 1 file changed, 37 insertions(+), 48 deletions(-) diff --git a/scripts/OpenSSL-DownloadAndBuild.command b/scripts/OpenSSL-DownloadAndBuild.command index 1aa03a0af0f2..5de1a31dc8b8 100755 --- a/scripts/OpenSSL-DownloadAndBuild.command +++ b/scripts/OpenSSL-DownloadAndBuild.command @@ -1,4 +1,4 @@ -#!/bin/bash +#!/bin/bash -xe # # Copyright 2015 Thincast Technologies GmbH # @@ -9,19 +9,19 @@ ## Settings # openssl version to use -OPENSSLVERSION="1.0.2q" -SHA256SUM="5744cfcbcec2b1b48629f7354203bc1e5e9b5466998bbccc5b5fcde3b18eb684" +OPENSSLVERSION="3.0.2" +SHA256SUM="98e91ccead4d4756ae3c9cde5e09191a8e586d9f4d50838e7ec09d6411dfdb63" # SDK version to use - if not set latest version found is used SDK_VERSION="" # Minimum SDK version the application supports -MIN_SDK_VERSION="10.0" +MIN_SDK_VERSION="15.0" ## Defaults INSTALLDIR="external" # Architectures to build -ARCHS="i386 x86_64 armv7 armv7s arm64" +ARCHS="arm64 x86_64" # Use default SDK version if not set if [ -z ${SDK_VERSION} ]; then @@ -30,9 +30,6 @@ fi CORES=`sysctl hw.ncpu | awk '{print $2}'` MAKEOPTS="-j $CORES" -# disable parallell builds since openssl build -# fails sometimes -MAKEOPTS="" DEVELOPER=`xcode-select -print-path` if [ ! -d "$DEVELOPER" ]; then @@ -44,16 +41,6 @@ if [ ! -d "$DEVELOPER" ]; then exit 1 fi -function run { - "$@" - local status=$? - if [ $status -ne 0 ]; then - echo "error with $@" >&2 - exit $status - fi - return $status -} - # Functions function buildArch(){ ARCH=$1 @@ -61,36 +48,38 @@ function buildArch(){ then PLATFORM="iPhoneSimulator" else - run sed -ie "s!static volatile sig_atomic_t intr_signal;!static volatile intr_signal;!" "crypto/ui/ui_openssl.c" + sed -ie "s!static volatile sig_atomic_t intr_signal;!static volatile intr_signal;!" "crypto/ui/ui_openssl.c" PLATFORM="iPhoneOS" fi - run export CROSS_TOP="${DEVELOPER}/Platforms/${PLATFORM}.platform/Developer" - run export CROSS_SDK="${PLATFORM}${SDK_VERSION}.sdk" - run export BUILD_TOOLS="${DEVELOPER}" - run export CC="${BUILD_TOOLS}/usr/bin/gcc -arch ${ARCH}" + export CROSS_TOP="${DEVELOPER}/Platforms/${PLATFORM}.platform/Developer" + export CROSS_SDK="${PLATFORM}${SDK_VERSION}.sdk" + export BUILD_TOOLS="${DEVELOPER}" + export CC="${BUILD_TOOLS}/usr/bin/gcc -arch ${ARCH}" if [ ! -z $MIN_SDK_VERSION ]; then - run export CC="$CC -miphoneos-version-min=${MIN_SDK_VERSION}" + export CC="$CC -miphoneos-version-min=${MIN_SDK_VERSION}" fi echo "Building openssl-${OPENSSLVERSION} for ${PLATFORM} ${SDK_VERSION} ${ARCH} (min SDK set: ${MIN_SDK_VERSION:-"none"})" LOGFILE="BuildLog.darwin-${ARCH}.txt" echo -n " Please wait ..." if [[ "$OPENSSLVERSION" =~ 1.0.0. ]]; then - run ./Configure BSD-generic32 > "${LOGFILE}" 2>&1 + CONFIG_ARGS=BSD-generic32 elif [ "${ARCH}" == "x86_64" ]; then - run ./Configure darwin64-x86_64-cc > "${LOGFILE}" 2>&1 + CONFIG_ARGS=darwin64-x86_64-cc elif [ "${ARCH}" == "i386" ]; then - run ./Configure iphoneos-cross no-asm > "${LOGFILE}" 2>&1 + CONFIG_ARGS="iphoneos-cross no-asm" else - run ./Configure iphoneos-cross > "${LOGFILE}" 2>&1 + CONFIG_ARGS=iphoneos-cross fi - run make ${MAKEOPTS} >> ${LOGFILE} 2>&1 + ./Configure $CONFIG_ARGS 2>&1 | tee ${LOGFILE} + + make ${MAKEOPTS} 2>&1 | tee ${LOGFILE} echo " Done. Build log saved in ${LOGFILE}" - run cp libcrypto.a ../../lib/libcrypto_${ARCH}.a - run cp libssl.a ../../lib/libssl_${ARCH}.a - run make clean >/dev/null 2>&1 + cp libcrypto.a ../../lib/libcrypto_${ARCH}.a + cp libssl.a ../../lib/libssl_${ARCH}.a + make clean 2>&1 | tee ${LOGFILE} } # main @@ -104,14 +93,14 @@ fi cd $INSTALLDIR if [ ! -d openssl ];then - run mkdir openssl + mkdir openssl fi -run cd openssl +cd openssl CS=`shasum -a 256 "openssl-$OPENSSLVERSION.tar.gz" | cut -d ' ' -f1` if [ ! "$CS" = "$SHA256SUM" ]; then echo "Downloading OpenSSL Version $OPENSSLVERSION ..." - run rm -f "openssl-$OPENSSLVERSION.tar.gz" - run curl -o "openssl-$OPENSSLVERSION.tar.gz" https://www.openssl.org/source/openssl-$OPENSSLVERSION.tar.gz + rm -f "openssl-$OPENSSLVERSION.tar.gz" + curl -o "openssl-$OPENSSLVERSION.tar.gz" https://www.openssl.org/source/openssl-$OPENSSLVERSION.tar.gz CS=`shasum -a 256 "openssl-$OPENSSLVERSION.tar.gz" | cut -d ' ' -f1` if [ ! "$CS" = "$SHA256SUM" ]; then @@ -121,19 +110,19 @@ if [ ! "$CS" = "$SHA256SUM" ]; then fi # remove old build dir -run rm -rf openssltmp -run mkdir openssltmp -run cd openssltmp +rm -rf openssltmp +mkdir openssltmp +cd openssltmp echo "Unpacking OpenSSL ..." -run tar xfz "../openssl-$OPENSSLVERSION.tar.gz" +tar xfz "../openssl-$OPENSSLVERSION.tar.gz" if [ ! $? = 0 ]; then echo "Unpacking failed." exit 1 fi echo -run cd "openssl-$OPENSSLVERSION" +cd "openssl-$OPENSSLVERSION" case `pwd` in *\ * ) @@ -143,22 +132,22 @@ case `pwd` in esac # Cleanup old build artifacts -run rm -rf ../../include -run mkdir -p ../../include +rm -rf ../../include +mkdir -p ../../include -run rm -rf ../../lib -run mkdir -p ../../lib +rm -rf ../../lib +mkdir -p ../../lib for i in ${ARCHS}; do buildArch $i done echo "Copying header files ..." -run cp -r include/ ../../include/ +cp -r include/ ../../include/ echo echo "Combining to unversal binary" -run lipo -create ../../lib/libcrypto_*.a -o ../../lib/libcrypto.a -run lipo -create ../../lib/libssl_*.a -o ../../lib/libssl.a +lipo -create ../../lib/libcrypto_*.a -o ../../lib/libcrypto.a +lipo -create ../../lib/libssl_*.a -o ../../lib/libssl.a echo "Finished. Please verify the contens of the openssl folder in \"$INSTALLDIR\"" From b29427fd87d1501ccf46e989ea4b85c9d8fc0172 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Wed, 4 May 2022 08:45:30 +0200 Subject: [PATCH 165/496] Removed obsolete toolchain file --- cmake/iOSToolchain.cmake | 196 --------------------------------------- 1 file changed, 196 deletions(-) delete mode 100644 cmake/iOSToolchain.cmake diff --git a/cmake/iOSToolchain.cmake b/cmake/iOSToolchain.cmake deleted file mode 100644 index 1824ecbdfa77..000000000000 --- a/cmake/iOSToolchain.cmake +++ /dev/null @@ -1,196 +0,0 @@ -# This file is based off of the Platform/Darwin.cmake and Platform/UnixPaths.cmake -# files which are included with CMake 2.8.4 -# It has been altered for iOS development - -# Options: -# -# IOS_PLATFORM = OS (default) or SIMULATOR -# This decides if SDKS will be selected from the iPhoneOS.platform or iPhoneSimulator.platform folders -# OS - the default, used to build for iPhone and iPad physical devices, which have an arm arch. -# SIMULATOR - used to build for the Simulator platforms, which have an x86 arch. -# -# CMAKE_IOS_DEVELOPER_ROOT = automatic(default) or /path/to/platform/Developer folder -# By default this location is automatcially chosen based on the IOS_PLATFORM value above. -# If set manually, it will override the default location and force the user of a particular Developer Platform -# -# CMAKE_IOS_SDK_ROOT = automatic(default) or /path/to/platform/Developer/SDKs/SDK folder -# By default this location is automatcially chosen based on the CMAKE_IOS_DEVELOPER_ROOT value. -# In this case it will always be the most up-to-date SDK found in the CMAKE_IOS_DEVELOPER_ROOT path. -# If set manually, this will force the use of a specific SDK version - -# Macros: -# -# set_xcode_property (TARGET XCODE_PROPERTY XCODE_VALUE) -# A convenience macro for setting xcode specific properties on targets -# example: set_xcode_property (myioslib IPHONEOS_DEPLOYMENT_TARGET "3.1") -# -# find_host_package (PROGRAM ARGS) -# A macro used to find executable programs on the host system, not within the iOS environment. -# Thanks to the android-cmake project for providing the command - - -# Standard settings -set (CMAKE_SYSTEM_NAME Darwin) -set (CMAKE_SYSTEM_VERSION 1) -set (UNIX True) -set (APPLE True) -set (IOS True) - -# Required as of cmake 2.8.10 -#set (CMAKE_OSX_DEPLOYMENT_TARGET "" CACHE STRING "Force unset of the deployment target for iOS" FORCE) - -# Determine the cmake host system version so we know where to find the iOS SDKs -find_program (CMAKE_UNAME uname /bin /usr/bin /usr/local/bin) -if (CMAKE_UNAME) - exec_program(uname ARGS -r OUTPUT_VARIABLE CMAKE_HOST_SYSTEM_VERSION) - string (REGEX REPLACE "^([0-9]+)\\.([0-9]+).*$" "\\1" DARWIN_MAJOR_VERSION "${CMAKE_HOST_SYSTEM_VERSION}") -endif (CMAKE_UNAME) - -# Force the compilers to gcc for iOS -include (CMakeForceCompiler) -CMAKE_FORCE_C_COMPILER (/usr/bin/clang Apple) -CMAKE_FORCE_CXX_COMPILER (/usr/bin/clang++ Apple) -set(CMAKE_AR ar CACHE FILEPATH "" FORCE) - -# Skip the platform compiler checks for cross compiling -#set (CMAKE_CXX_COMPILER_WORKS TRUE) -#set (CMAKE_C_COMPILER_WORKS TRUE) - -# All iOS/Darwin specific settings - some may be redundant -set (CMAKE_SHARED_LIBRARY_PREFIX "lib") -set (CMAKE_SHARED_LIBRARY_SUFFIX ".dylib") -set (CMAKE_SHARED_MODULE_PREFIX "lib") -set (CMAKE_SHARED_MODULE_SUFFIX ".so") -set (CMAKE_MODULE_EXISTS 1) -set (CMAKE_DL_LIBS "") - -set (CMAKE_C_OSX_COMPATIBILITY_VERSION_FLAG "-compatibility_version ") -set (CMAKE_C_OSX_CURRENT_VERSION_FLAG "-current_version ") -set (CMAKE_CXX_OSX_COMPATIBILITY_VERSION_FLAG "${CMAKE_C_OSX_COMPATIBILITY_VERSION_FLAG}") -set (CMAKE_CXX_OSX_CURRENT_VERSION_FLAG "${CMAKE_C_OSX_CURRENT_VERSION_FLAG}") - -# Hidden visibilty is required for cxx on iOS -set (CMAKE_C_FLAGS_INIT "") -set (CMAKE_CXX_FLAGS_INIT "-fvisibility=hidden -fvisibility-inlines-hidden -isysroot ${CMAKE_OSX_SYSROOT}") - -set (CMAKE_C_LINK_FLAGS "-Wl,-search_paths_first ${CMAKE_C_LINK_FLAGS}") -set (CMAKE_CXX_LINK_FLAGS "-Wl,-search_paths_first ${CMAKE_CXX_LINK_FLAGS}") - -set (CMAKE_PLATFORM_HAS_INSTALLNAME 1) -set (CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS "-dynamiclib -headerpad_max_install_names") -set (CMAKE_SHARED_MODULE_CREATE_C_FLAGS "-bundle -headerpad_max_install_names") -set (CMAKE_SHARED_MODULE_LOADER_C_FLAG "-Wl,-bundle_loader,") -set (CMAKE_SHARED_MODULE_LOADER_CXX_FLAG "-Wl,-bundle_loader,") -set (CMAKE_FIND_LIBRARY_SUFFIXES ".dylib" ".so" ".a") - -# hack: if a new cmake (which uses CMAKE_INSTALL_NAME_TOOL) runs on an old build tree -# (where install_name_tool was hardcoded) and where CMAKE_INSTALL_NAME_TOOL isn't in the cache -# and still cmake didn't fail in CMakeFindBinUtils.cmake (because it isn't rerun) -# hardcode CMAKE_INSTALL_NAME_TOOL here to install_name_tool, so it behaves as it did before, Alex -if (NOT DEFINED CMAKE_INSTALL_NAME_TOOL) - find_program(CMAKE_INSTALL_NAME_TOOL install_name_tool) -endif (NOT DEFINED CMAKE_INSTALL_NAME_TOOL) - -# Setup iOS platform unless specified manually with IOS_PLATFORM -if (NOT DEFINED IOS_PLATFORM) - set (IOS_PLATFORM "OS") -endif (NOT DEFINED IOS_PLATFORM) -set (IOS_PLATFORM ${IOS_PLATFORM} CACHE STRING "Type of iOS Platform") - -# Check the platform selection and setup for developer root -if (${IOS_PLATFORM} STREQUAL "OS") - set (IOS_PLATFORM_LOCATION "iPhoneOS.platform") - - # This causes the installers to properly locate the output libraries - set (CMAKE_XCODE_EFFECTIVE_PLATFORMS "-iphoneos") -elseif (${IOS_PLATFORM} STREQUAL "SIMULATOR") - set (IOS_PLATFORM_LOCATION "iPhoneSimulator.platform") - - # This causes the installers to properly locate the output libraries - set (CMAKE_XCODE_EFFECTIVE_PLATFORMS "-iphonesimulator") -else (${IOS_PLATFORM} STREQUAL "OS") - message (FATAL_ERROR "Unsupported IOS_PLATFORM value selected. Please choose OS or SIMULATOR") -endif (${IOS_PLATFORM} STREQUAL "OS") - -# Setup iOS developer location unless specified manually with CMAKE_IOS_DEVELOPER_ROOT -# Note Xcode 4.3 changed the installation location, choose the most recent one available -set (XCODE_POST_43_ROOT "/Applications/Xcode.app/Contents/Developer/Platforms/${IOS_PLATFORM_LOCATION}/Developer") -set (XCODE_PRE_43_ROOT "/Developer/Platforms/${IOS_PLATFORM_LOCATION}/Developer") -if (NOT DEFINED CMAKE_IOS_DEVELOPER_ROOT) - if (EXISTS ${XCODE_POST_43_ROOT}) - set (CMAKE_IOS_DEVELOPER_ROOT ${XCODE_POST_43_ROOT}) - elseif(EXISTS ${XCODE_PRE_43_ROOT}) - set (CMAKE_IOS_DEVELOPER_ROOT ${XCODE_PRE_43_ROOT}) - endif (EXISTS ${XCODE_POST_43_ROOT}) -endif (NOT DEFINED CMAKE_IOS_DEVELOPER_ROOT) -set (CMAKE_IOS_DEVELOPER_ROOT ${CMAKE_IOS_DEVELOPER_ROOT} CACHE PATH "Location of iOS Platform") - -# Find and use the most recent iOS sdk unless specified manually with CMAKE_IOS_SDK_ROOT -if (NOT DEFINED CMAKE_IOS_SDK_ROOT) - file (GLOB _CMAKE_IOS_SDKS "${CMAKE_IOS_DEVELOPER_ROOT}/SDKs/*") - if (_CMAKE_IOS_SDKS) - list (SORT _CMAKE_IOS_SDKS) - list (REVERSE _CMAKE_IOS_SDKS) - list (GET _CMAKE_IOS_SDKS 0 CMAKE_IOS_SDK_ROOT) - else (_CMAKE_IOS_SDKS) - message (FATAL_ERROR "No iOS SDK's found in default search path ${CMAKE_IOS_DEVELOPER_ROOT}. Manually set CMAKE_IOS_SDK_ROOT or install the iOS SDK.") - endif (_CMAKE_IOS_SDKS) - message (STATUS "Toolchain using default iOS SDK: ${CMAKE_IOS_SDK_ROOT}") -endif (NOT DEFINED CMAKE_IOS_SDK_ROOT) -set (CMAKE_IOS_SDK_ROOT ${CMAKE_IOS_SDK_ROOT} CACHE PATH "Location of the selected iOS SDK") - -# Set the sysroot default to the most recent SDK -set (CMAKE_OSX_SYSROOT ${CMAKE_IOS_SDK_ROOT} CACHE PATH "Sysroot used for iOS support") - -# set the architecture for iOS -# NOTE: Currently both ARCHS_STANDARD_32_BIT and ARCHS_UNIVERSAL_IPHONE_OS set armv7 only, so set both manually -if (${IOS_PLATFORM} STREQUAL "OS") - set (IOS_ARCH armv7 armv7s) - set (CMAKE_SYSTEM_PROCESSOR armv7) -else (${IOS_PLATFORM} STREQUAL "OS") - set (IOS_ARCH i386) - set (CMAKE_SYSTEM_PROCESSOR i386) -endif (${IOS_PLATFORM} STREQUAL "OS") - -set (CMAKE_OSX_ARCHITECTURES ${IOS_ARCH} CACHE string "Build architecture for iOS") - -# Set the find root to the iOS developer roots and to user defined paths -set (CMAKE_FIND_ROOT_PATH ${CMAKE_IOS_DEVELOPER_ROOT} ${CMAKE_IOS_SDK_ROOT} ${CMAKE_PREFIX_PATH} CACHE string "iOS find search path root") - -# default to searching for frameworks first -set (CMAKE_FIND_FRAMEWORK FIRST) - -# set up the default search directories for frameworks -set (CMAKE_SYSTEM_FRAMEWORK_PATH - ${CMAKE_IOS_SDK_ROOT}/System/Library/Frameworks - ${CMAKE_IOS_SDK_ROOT}/System/Library/PrivateFrameworks - ${CMAKE_IOS_SDK_ROOT}/Developer/Library/Frameworks -) - -# only search the iOS sdks, not the remainder of the host filesystem -set (CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ONLY) -set (CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) -set (CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) - - -# This little macro lets you set any XCode specific property -macro (set_xcode_property TARGET XCODE_PROPERTY XCODE_VALUE) - set_property (TARGET ${TARGET} PROPERTY XCODE_ATTRIBUTE_${XCODE_PROPERTY} ${XCODE_VALUE}) -endmacro (set_xcode_property) - - -# This macro lets you find executable programs on the host system -macro (find_host_package) - set (CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) - set (CMAKE_FIND_ROOT_PATH_MODE_LIBRARY NEVER) - set (CMAKE_FIND_ROOT_PATH_MODE_INCLUDE NEVER) - set (IOS FALSE) - - find_package(${ARGN}) - - set (IOS TRUE) - set (CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ONLY) - set (CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) - set (CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) -endmacro (find_host_package) - From bdf19906313418dc8eb97f31a26d6032675cbf00 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Tue, 3 May 2022 10:45:41 +0200 Subject: [PATCH 166/496] Fixed path of iOS toolchain file (cherry picked from commit e53f0d781f74abc2e1a4fd233d22d05a35d71a5f) --- ci/cmake-preloads/config-ios.txt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ci/cmake-preloads/config-ios.txt b/ci/cmake-preloads/config-ios.txt index 886c36a6da9d..08145bb2cb97 100644 --- a/ci/cmake-preloads/config-ios.txt +++ b/ci/cmake-preloads/config-ios.txt @@ -1,7 +1,8 @@ message("PRELOADING iOS cache") -set (CMAKE_TOOLCHAIN_FILE "cmake/iOSToolchain.cmake" CACHE PATH "ToolChain file") +set (CMAKE_TOOLCHAIN_FILE "${CMAKE_SOURCE_DIR}/cmake/ios.toolchain.cmake" CACHE PATH "cmake toolchain file") set (FREERDP_IOS_EXTERNAL_SSL_PATH $ENV{FREERDP_IOS_EXTERNAL_SSL_PATH} CACHE PATH "android ssl") set (CMAKE_BUILD_TYPE "Debug" CACHE STRING "build type") -set (IOS_PLATFORM "SIMULATOR" CACHE STRING "iso platfrorm to build") +set (CMAKE_OSX_ARCHITECTURES "arm64" CACHE STRING "iOS platform to build") +set (CMAKE_OSX_DEPLOYMENT_TARGET "10.0" CACHE STRING "iOS minimum target") set (WITH_SANITIZE_ADDRESS ON CACHE BOOL "build with address sanitizer") set (WITH_CLIENT OFF CACHE BOOL "disable iOS client") From 7e4d328a389a93026406902d25c9a6e813afe204 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Tue, 3 May 2022 11:02:25 +0200 Subject: [PATCH 167/496] Fixed argument mismatch (cherry picked from commit 400fe6f796f5aa23bb7b67d577275ac3f6be788f) --- winpr/libwinpr/path/shell_ios.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/winpr/libwinpr/path/shell_ios.m b/winpr/libwinpr/path/shell_ios.m index 7a6f78bf1b84..b2b9e31d5f3c 100644 --- a/winpr/libwinpr/path/shell_ios.m +++ b/winpr/libwinpr/path/shell_ios.m @@ -26,7 +26,7 @@ #include "shell_ios.h" -NSString *ios_get_directory_for_search_path(NSString *searchPath) +NSString *ios_get_directory_for_search_path(NSSearchPathDirectory searchPath) { return [NSSearchPathForDirectoriesInDomains(searchPath, NSUserDomainMask, YES) lastObject]; } From b4907dba08afb5b35ecf9cc417934949414f2313 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Fri, 29 Apr 2022 13:34:39 +0200 Subject: [PATCH 168/496] Defined and use _write (cherry picked from commit 9330559d24ff15b782c266febc32342dca8698f4) --- winpr/include/winpr/crt.h | 6 ++++++ winpr/libwinpr/utils/debug.c | 4 +++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/winpr/include/winpr/crt.h b/winpr/include/winpr/crt.h index 181ac14b6afe..3f6b5a119533 100644 --- a/winpr/include/winpr/crt.h +++ b/winpr/include/winpr/crt.h @@ -32,6 +32,12 @@ #ifndef _WIN32 +#include + +#ifndef _write +#define _write write +#endif + #ifndef _strtoui64 #define _strtoui64 strtoull #endif diff --git a/winpr/libwinpr/utils/debug.c b/winpr/libwinpr/utils/debug.c index 74eccbb08b27..89d2dd2faa8d 100644 --- a/winpr/libwinpr/utils/debug.c +++ b/winpr/libwinpr/utils/debug.c @@ -24,6 +24,8 @@ #include #include + +#include #include #if defined(HAVE_EXECINFO_H) @@ -160,7 +162,7 @@ void winpr_backtrace_symbols_fd(void* buffer, int fd) return; for (i = 0; i < used; i++) - write(fd, lines[i], (unsigned)strnlen(lines[i], UINT32_MAX)); + _write(fd, lines[i], (unsigned)strnlen(lines[i], UINT32_MAX)); } #else LOGF(support_msg); From 77d49ab038b98814f2fdc78b42a5e0803f328e34 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Wed, 4 May 2022 09:17:15 +0200 Subject: [PATCH 169/496] Removed manual IOS sysroot settings, let the toolchain file take care --- CMakeLists.txt | 9 --------- 1 file changed, 9 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 11bd2568ed8e..2dfa179c5215 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1037,15 +1037,6 @@ add_subdirectory(include) add_subdirectory(libfreerdp) -if (IOS) - set(CMAKE_OSX_DEPLOYMENT_TARGET "10.0") - if (IOS_PLATFORM MATCHES "SIMULATOR") - set(CMAKE_OSX_SYSROOT "iphonesimulator") - else() - set(CMAKE_OSX_SYSROOT "iphoneos") - endif() -endif() - # RdTk include_directories("${CMAKE_SOURCE_DIR}/rdtk/include") include_directories("${CMAKE_BINARY_DIR}/rdtk/include") From 060e5adf1c1b887a1f68d9ab3f497aaf130ae5e9 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Wed, 4 May 2022 09:24:40 +0200 Subject: [PATCH 170/496] Fixed IOS timer detection --- winpr/libwinpr/CMakeLists.txt | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/winpr/libwinpr/CMakeLists.txt b/winpr/libwinpr/CMakeLists.txt index d9673f2d4a2c..2df8d899231a 100644 --- a/winpr/libwinpr/CMakeLists.txt +++ b/winpr/libwinpr/CMakeLists.txt @@ -78,13 +78,15 @@ macro (winpr_definition_add) endmacro() set(CMAKE_REQUIRED_LIBRARIES rt) -check_function_exists(timer_create TIMER_CREATE) -check_function_exists(timer_delete TIMER_DELETE) -check_function_exists(timer_settime TIMER_SETTIME) -check_function_exists(timer_gettime TIMER_GETTIME) -if (TIMER_CREATE AND TIMER_DELETE AND TIMER_SETTIME AND TIMER_GETTIME) - add_definitions(-DWITH_POSIX_TIMER) - winpr_library_add_private(rt) +if (NOT IOS) + check_function_exists(timer_create TIMER_CREATE) + check_function_exists(timer_delete TIMER_DELETE) + check_function_exists(timer_settime TIMER_SETTIME) + check_function_exists(timer_gettime TIMER_GETTIME) + if (TIMER_CREATE AND TIMER_DELETE AND TIMER_SETTIME AND TIMER_GETTIME) + add_definitions(-DWITH_POSIX_TIMER) + winpr_library_add_private(rt) + endif() endif() if (ANDROID) From 1322566d7ffe989fa7751d7bebe1e5479abb3c0c Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Wed, 4 May 2022 09:26:39 +0200 Subject: [PATCH 171/496] Fixed IOS pthread_mutext_timedlock detection --- CMakeLists.txt | 2 +- winpr/CMakeLists.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 2dfa179c5215..007acaf2d078 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -355,7 +355,7 @@ if(NOT IOS) find_package(Threads REQUIRED) endif() -if(NOT WIN32) +if(NOT WIN32 AND NOT IOS) CHECK_SYMBOL_EXISTS(pthread_mutex_timedlock pthread.h HAVE_PTHREAD_MUTEX_TIMEDLOCK_SYMBOL) if (NOT HAVE_PTHREAD_MUTEX_TIMEDLOCK_SYMBOL) CHECK_LIBRARY_EXISTS(pthread pthread_mutex_timedlock "" HAVE_PTHREAD_MUTEX_TIMEDLOCK_LIB) diff --git a/winpr/CMakeLists.txt b/winpr/CMakeLists.txt index 52d0f65c2ff4..045e09fab1ca 100644 --- a/winpr/CMakeLists.txt +++ b/winpr/CMakeLists.txt @@ -131,7 +131,7 @@ else() set(HAVE_TM_GMTOFF 1) endif() - if(NOT WIN32) + if(NOT WIN32 AND NOT IOS) CHECK_SYMBOL_EXISTS(pthread_mutex_timedlock pthread.h HAVE_PTHREAD_MUTEX_TIMEDLOCK_SYMBOL) if (NOT HAVE_PTHREAD_MUTEX_TIMEDLOCK_SYMBOL) CHECK_LIBRARY_EXISTS(pthread pthread_mutex_timedlock "" HAVE_PTHREAD_MUTEX_TIMEDLOCK_LIB) From 3b2cba58e5efa18d59dc3e63c3f1816c1609f032 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Wed, 4 May 2022 15:11:04 +0200 Subject: [PATCH 172/496] Fixed broken USE_UNWIND check (cherry picked from commit 63a221d845c3a27d3e49b3510cab153a44602ef5) --- winpr/libwinpr/utils/debug.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/winpr/libwinpr/utils/debug.c b/winpr/libwinpr/utils/debug.c index 89d2dd2faa8d..460b6740c7eb 100644 --- a/winpr/libwinpr/utils/debug.c +++ b/winpr/libwinpr/utils/debug.c @@ -32,7 +32,7 @@ #include #endif -#if defined(USE_UNWIND_H) +#if defined(USE_UNWIND) #include #endif @@ -87,7 +87,7 @@ void winpr_backtrace_free(void* buffer) if (!buffer) return; -#if defined(USE_UNWIND_H) +#if defined(USE_UNWIND) winpr_unwind_backtrace_free(buffer); #elif defined(HAVE_EXECINFO_H) winpr_execinfo_backtrace_free(buffer); @@ -102,7 +102,7 @@ void winpr_backtrace_free(void* buffer) void* winpr_backtrace(DWORD size) { -#if defined(USE_UNWIND_H) +#if defined(USE_UNWIND) return winpr_unwind_backtrace(size); #elif defined(HAVE_EXECINFO_H) return winpr_execinfo_backtrace(size); @@ -127,7 +127,7 @@ char** winpr_backtrace_symbols(void* buffer, size_t* used) return NULL; } -#if defined(USE_UNWIND_H) +#if defined(USE_UNWIND) return winpr_unwind_backtrace_symbols(buffer, used); #elif defined(HAVE_EXECINFO_H) return winpr_execinfo_backtrace_symbols(buffer, used); @@ -150,7 +150,7 @@ void winpr_backtrace_symbols_fd(void* buffer, int fd) return; } -#if defined(HAVE_EXECINFO_H) && !defined(USE_UNWIND_H) +#if defined(HAVE_EXECINFO_H) && !defined(USE_UNWIND) winpr_execinfo_backtrace_symbols_fd(buffer, fd); #elif !defined(ANDROID) { From b8be481a56021208e2c86704876147699397c9e9 Mon Sep 17 00:00:00 2001 From: 2fly2 Date: Sat, 7 May 2022 09:21:21 +0800 Subject: [PATCH 173/496] fix moving a window shrinks it 14x7 when connect to server 2019 Signed-off-by: 2fly2 (cherry picked from commit e1e2eef4e1e6fd98bd428e21b8ddeb76979fa2cd) --- client/X11/xf_rail.c | 30 +++++++++++++++++++++--------- client/X11/xf_window.h | 5 +++++ 2 files changed, 26 insertions(+), 9 deletions(-) diff --git a/client/X11/xf_rail.c b/client/X11/xf_rail.c index 770234f7dc24..090f599a0462 100644 --- a/client/X11/xf_rail.c +++ b/client/X11/xf_rail.c @@ -136,10 +136,10 @@ void xf_rail_adjust_position(xfContext* xfc, xfAppWindow* appWindow) * Calculate new size/position for the rail window(new values for * windowOffsetX/windowOffsetY/windowWidth/windowHeight) on the server */ - windowMove.left = appWindow->x; - windowMove.top = appWindow->y; - windowMove.right = windowMove.left + appWindow->width; - windowMove.bottom = windowMove.top + appWindow->height; + windowMove.left = appWindow->x - appWindow->resizeMarginLeft; + windowMove.top = appWindow->y - appWindow->resizeMarginTop; + windowMove.right = appWindow->x + appWindow->width + appWindow->resizeMarginRight; + windowMove.bottom = appWindow->y + appWindow->height + appWindow->resizeMarginBottom; xfc->rail->ClientWindowMove(xfc->rail, &windowMove); } } @@ -163,12 +163,12 @@ void xf_rail_end_local_move(xfContext* xfc, xfAppWindow* appWindow) * windowOffsetX/windowOffsetY/windowWidth/windowHeight) on the server * */ - windowMove.left = appWindow->x; - windowMove.top = appWindow->y; + windowMove.left = appWindow->x - appWindow->resizeMarginLeft; + windowMove.top = appWindow->y - appWindow->resizeMarginTop; windowMove.right = - windowMove.left + - appWindow->width; /* In the update to RDP the position is one past the window */ - windowMove.bottom = windowMove.top + appWindow->height; + appWindow->x + + appWindow->width + appWindow->resizeMarginRight; /* In the update to RDP the position is one past the window */ + windowMove.bottom = appWindow->y + appWindow->height + appWindow->resizeMarginBottom; xfc->rail->ClientWindowMove(xfc->rail, &windowMove); /* * Simulate button up at new position to end the local move (per RDP spec) @@ -344,6 +344,18 @@ static BOOL xf_rail_window_common(rdpContext* context, const WINDOW_ORDER_INFO* appWindow->windowWidth = windowState->windowWidth; appWindow->windowHeight = windowState->windowHeight; } + + if (fieldFlags & WINDOW_ORDER_FIELD_RESIZE_MARGIN_X) + { + appWindow->resizeMarginLeft = windowState->resizeMarginLeft; + appWindow->resizeMarginRight = windowState->resizeMarginRight; + } + + if (fieldFlags & WINDOW_ORDER_FIELD_RESIZE_MARGIN_Y) + { + appWindow->resizeMarginTop = windowState->resizeMarginTop; + appWindow->resizeMarginBottom = windowState->resizeMarginBottom; + } if (fieldFlags & WINDOW_ORDER_FIELD_OWNER) { diff --git a/client/X11/xf_window.h b/client/X11/xf_window.h index 9f55ac761cd7..0f85af1d294e 100644 --- a/client/X11/xf_window.h +++ b/client/X11/xf_window.h @@ -126,6 +126,11 @@ struct xf_app_window UINT32 localWindowOffsetCorrX; UINT32 localWindowOffsetCorrY; + + UINT32 resizeMarginLeft; + UINT32 resizeMarginTop; + UINT32 resizeMarginRight; + UINT32 resizeMarginBottom; GC gc; int shmid; From 017dca48483aab7bc046ece5905c47c9d38be42a Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Tue, 22 Feb 2022 11:13:44 +0100 Subject: [PATCH 174/496] Fixed deprecated mac symbol (cherry picked from commit 951a83e295afbb8939cd27de6fb80d95cf3c407a) --- channels/rdpsnd/client/mac/rdpsnd_mac.m | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/channels/rdpsnd/client/mac/rdpsnd_mac.m b/channels/rdpsnd/client/mac/rdpsnd_mac.m index 8a01d9b73b3b..46fb39d091de 100644 --- a/channels/rdpsnd/client/mac/rdpsnd_mac.m +++ b/channels/rdpsnd/client/mac/rdpsnd_mac.m @@ -144,9 +144,15 @@ static BOOL rdpsnd_mac_open(rdpsndDevicePlugin *device, const AUDIO_FORMAT *form OSStatus err; NSError *error; rdpsndMacPlugin *mac = (rdpsndMacPlugin *)device; - AudioObjectPropertyAddress propertyAddress = { kAudioHardwarePropertyDefaultOutputDevice, - kAudioObjectPropertyScopeGlobal, - kAudioObjectPropertyElementMaster }; + AudioObjectPropertyAddress propertyAddress = { + kAudioHardwarePropertyDefaultOutputDevice, + kAudioObjectPropertyScopeGlobal, +#if defined(MAC_OS_VERSION_12_0) + kAudioObjectPropertyElementMain +#else + kAudioObjectPropertyElementMaster +#endif + }; if (mac->isOpen) return TRUE; From 64bfc9e6534358a72877d93f4ef17553ebc16e71 Mon Sep 17 00:00:00 2001 From: Felix Deimel Date: Thu, 12 May 2022 14:24:00 +0200 Subject: [PATCH 175/496] Fixed memory leaks in rdpsnd mac (cherry picked from commit b0772fe2f018c9b0830507788aa6cbe515b0cafd) --- channels/rdpsnd/client/mac/rdpsnd_mac.m | 295 +++++++++++++----------- 1 file changed, 156 insertions(+), 139 deletions(-) diff --git a/channels/rdpsnd/client/mac/rdpsnd_mac.m b/channels/rdpsnd/client/mac/rdpsnd_mac.m index 46fb39d091de..94ef150495c7 100644 --- a/channels/rdpsnd/client/mac/rdpsnd_mac.m +++ b/channels/rdpsnd/client/mac/rdpsnd_mac.m @@ -139,92 +139,99 @@ static void rdpsnd_mac_release(rdpsndMacPlugin *mac) static BOOL rdpsnd_mac_open(rdpsndDevicePlugin *device, const AUDIO_FORMAT *format, UINT32 latency) { - AudioDeviceID outputDeviceID; - UInt32 propertySize; - OSStatus err; - NSError *error; - rdpsndMacPlugin *mac = (rdpsndMacPlugin *)device; - AudioObjectPropertyAddress propertyAddress = { - kAudioHardwarePropertyDefaultOutputDevice, - kAudioObjectPropertyScopeGlobal, + @autoreleasepool + { + AudioDeviceID outputDeviceID; + UInt32 propertySize; + OSStatus err; + NSError *error; + rdpsndMacPlugin *mac = (rdpsndMacPlugin *)device; + AudioObjectPropertyAddress propertyAddress = { + kAudioHardwarePropertyDefaultOutputDevice, + kAudioObjectPropertyScopeGlobal, #if defined(MAC_OS_VERSION_12_0) - kAudioObjectPropertyElementMain + kAudioObjectPropertyElementMain #else - kAudioObjectPropertyElementMaster + kAudioObjectPropertyElementMaster #endif - }; + }; - if (mac->isOpen) - return TRUE; + if (mac->isOpen) + return TRUE; - if (!rdpsnd_mac_set_format(device, format, latency)) - return FALSE; + if (!rdpsnd_mac_set_format(device, format, latency)) + return FALSE; - propertySize = sizeof(outputDeviceID); - err = AudioObjectGetPropertyData(kAudioObjectSystemObject, &propertyAddress, 0, NULL, - &propertySize, &outputDeviceID); - if (err) - { - WLog_ERR(TAG, "AudioHardwareGetProperty: %s", FormatError(err)); - return FALSE; - } + propertySize = sizeof(outputDeviceID); + err = AudioObjectGetPropertyData(kAudioObjectSystemObject, &propertyAddress, 0, NULL, + &propertySize, &outputDeviceID); + if (err) + { + WLog_ERR(TAG, "AudioHardwareGetProperty: %s", FormatError(err)); + return FALSE; + } - mac->engine = [[AVAudioEngine alloc] init]; - if (!mac->engine) - return FALSE; + mac->engine = [[AVAudioEngine alloc] init]; + if (!mac->engine) + return FALSE; - err = AudioUnitSetProperty(mac->engine.outputNode.audioUnit, - kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, - &outputDeviceID, sizeof(outputDeviceID)); - if (err) - { - rdpsnd_mac_release(mac); - WLog_ERR(TAG, "AudioUnitSetProperty: %s", FormatError(err)); - return FALSE; - } + err = AudioUnitSetProperty(mac->engine.outputNode.audioUnit, + kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, + 0, &outputDeviceID, sizeof(outputDeviceID)); + if (err) + { + rdpsnd_mac_release(mac); + WLog_ERR(TAG, "AudioUnitSetProperty: %s", FormatError(err)); + return FALSE; + } - mac->player = [[AVAudioPlayerNode alloc] init]; - if (!mac->player) - { - rdpsnd_mac_release(mac); - WLog_ERR(TAG, "AVAudioPlayerNode::init() failed"); - return FALSE; - } + mac->player = [[AVAudioPlayerNode alloc] init]; + if (!mac->player) + { + rdpsnd_mac_release(mac); + WLog_ERR(TAG, "AVAudioPlayerNode::init() failed"); + return FALSE; + } - [mac->engine attachNode:mac->player]; + [mac->engine attachNode:mac->player]; - [mac->engine connect:mac->player to:mac->engine.mainMixerNode format:nil]; + [mac->engine connect:mac->player to:mac->engine.mainMixerNode format:nil]; - [mac->engine prepare]; + [mac->engine prepare]; - if (![mac->engine startAndReturnError:&error]) - { - device->Close(device); - WLog_ERR(TAG, "Failed to start audio player %s", [error.localizedDescription UTF8String]); - return FALSE; - } + if (![mac->engine startAndReturnError:&error]) + { + device->Close(device); + WLog_ERR(TAG, "Failed to start audio player %s", + [error.localizedDescription UTF8String]); + return FALSE; + } - mac->isOpen = TRUE; - return TRUE; + mac->isOpen = TRUE; + return TRUE; + } } static void rdpsnd_mac_close(rdpsndDevicePlugin *device) { - rdpsndMacPlugin *mac = (rdpsndMacPlugin *)device; - - if (mac->isPlaying) + @autoreleasepool { - [mac->player stop]; - mac->isPlaying = FALSE; - } + rdpsndMacPlugin *mac = (rdpsndMacPlugin *)device; - if (mac->isOpen) - { - [mac->engine stop]; - mac->isOpen = FALSE; - } + if (mac->isPlaying) + { + [mac->player stop]; + mac->isPlaying = FALSE; + } - rdpsnd_mac_release(mac); + if (mac->isOpen) + { + [mac->engine stop]; + mac->isOpen = FALSE; + } + + rdpsnd_mac_release(mac); + } } static void rdpsnd_mac_free(rdpsndDevicePlugin *device) @@ -252,108 +259,118 @@ static BOOL rdpsnd_mac_format_supported(rdpsndDevicePlugin *device, const AUDIO_ static BOOL rdpsnd_mac_set_volume(rdpsndDevicePlugin *device, UINT32 value) { - Float32 fVolume; - UINT16 volumeLeft; - UINT16 volumeRight; - rdpsndMacPlugin *mac = (rdpsndMacPlugin *)device; + @autoreleasepool + { + Float32 fVolume; + UINT16 volumeLeft; + UINT16 volumeRight; + rdpsndMacPlugin *mac = (rdpsndMacPlugin *)device; - if (!mac->player) - return FALSE; + if (!mac->player) + return FALSE; - volumeLeft = (value & 0xFFFF); - volumeRight = ((value >> 16) & 0xFFFF); - fVolume = ((float)volumeLeft) / 65535.0f; + volumeLeft = (value & 0xFFFF); + volumeRight = ((value >> 16) & 0xFFFF); + fVolume = ((float)volumeLeft) / 65535.0f; - mac->player.volume = fVolume; + mac->player.volume = fVolume; - return TRUE; + return TRUE; + } } static void rdpsnd_mac_start(rdpsndDevicePlugin *device) { - rdpsndMacPlugin *mac = (rdpsndMacPlugin *)device; - - if (!mac->isPlaying) + @autoreleasepool { - if (!mac->engine.isRunning) - { - NSError *error; + rdpsndMacPlugin *mac = (rdpsndMacPlugin *)device; - if (![mac->engine startAndReturnError:&error]) + if (!mac->isPlaying) + { + if (!mac->engine.isRunning) { - device->Close(device); - WLog_ERR(TAG, "Failed to start audio player %s", - [error.localizedDescription UTF8String]); - return; + NSError *error; + + if (![mac->engine startAndReturnError:&error]) + { + device->Close(device); + WLog_ERR(TAG, "Failed to start audio player %s", + [error.localizedDescription UTF8String]); + return; + } } - } - [mac->player play]; + [mac->player play]; - mac->isPlaying = TRUE; - mac->diff = 100; /* Initial latency, corrected after first sample is played. */ + mac->isPlaying = TRUE; + mac->diff = 100; /* Initial latency, corrected after first sample is played. */ + } } } static UINT rdpsnd_mac_play(rdpsndDevicePlugin *device, const BYTE *data, size_t size) { - rdpsndMacPlugin *mac = (rdpsndMacPlugin *)device; - AVAudioPCMBuffer *buffer; - AVAudioFormat *format; - float *const *db; - size_t pos, step, x; - AVAudioFrameCount count; - UINT64 start = GetTickCount64(); - - if (!mac->isOpen) - return 0; - - step = 2 * mac->format.nChannels; - - count = size / step; - format = [[AVAudioFormat alloc] initWithCommonFormat:AVAudioPCMFormatFloat32 - sampleRate:mac->format.nSamplesPerSec - channels:mac->format.nChannels - interleaved:NO]; - if (!format) - { - WLog_WARN(TAG, "AVAudioFormat::init() failed"); - return 0; - } - buffer = [[AVAudioPCMBuffer alloc] initWithPCMFormat:format frameCapacity:count]; - if (!buffer) + @autoreleasepool { + rdpsndMacPlugin *mac = (rdpsndMacPlugin *)device; + AVAudioPCMBuffer *buffer; + AVAudioFormat *format; + float *const *db; + size_t pos, step, x; + AVAudioFrameCount count; + UINT64 start = GetTickCount64(); + + if (!mac->isOpen) + return 0; + + step = 2 * mac->format.nChannels; + + count = size / step; + format = [[AVAudioFormat alloc] initWithCommonFormat:AVAudioPCMFormatFloat32 + sampleRate:mac->format.nSamplesPerSec + channels:mac->format.nChannels + interleaved:NO]; + if (!format) + { + WLog_WARN(TAG, "AVAudioFormat::init() failed"); + return 0; + } + buffer = [[AVAudioPCMBuffer alloc] initWithPCMFormat:format frameCapacity:count]; [format release]; - WLog_WARN(TAG, "AVAudioPCMBuffer::init() failed"); - return 0; - } + if (!buffer) + { + WLog_WARN(TAG, "AVAudioPCMBuffer::init() failed"); + return 0; + } - buffer.frameLength = buffer.frameCapacity; - db = buffer.floatChannelData; + buffer.frameLength = buffer.frameCapacity; + db = buffer.floatChannelData; - for (pos = 0; pos < count; pos++) - { - const BYTE *d = &data[pos * step]; - for (x = 0; x < mac->format.nChannels; x++) + for (pos = 0; pos < count; pos++) { - const float val = (int16_t)((uint16_t)d[0] | ((uint16_t)d[1] << 8)) / 32768.0f; - db[x][pos] = val; - d += sizeof(int16_t); + const BYTE *d = &data[pos * step]; + for (x = 0; x < mac->format.nChannels; x++) + { + const float val = (int16_t)((uint16_t)d[0] | ((uint16_t)d[1] << 8)) / 32768.0f; + db[x][pos] = val; + d += sizeof(int16_t); + } } - } - rdpsnd_mac_start(device); + rdpsnd_mac_start(device); - [mac->player scheduleBuffer:buffer - completionHandler:^{ - UINT64 stop = GetTickCount64(); - if (start > stop) - mac->diff = 0; - else - mac->diff = stop - start; - }]; + [mac->player scheduleBuffer:buffer + completionHandler:^{ + UINT64 stop = GetTickCount64(); + if (start > stop) + mac->diff = 0; + else + mac->diff = stop - start; + }]; + [buffer release]; - return mac->diff > UINT_MAX ? UINT_MAX : mac->diff; + return mac->diff > UINT_MAX ? UINT_MAX : mac->diff; + } } #ifdef BUILTIN_CHANNELS From bd71070063aaece1fef314127e8a275059f44b5f Mon Sep 17 00:00:00 2001 From: akallabeth Date: Thu, 12 May 2022 14:55:14 +0200 Subject: [PATCH 176/496] changelog --- ChangeLog | 1 + 1 file changed, 1 insertion(+) diff --git a/ChangeLog b/ChangeLog index faee92edb022..138076ce6b24 100644 --- a/ChangeLog +++ b/ChangeLog @@ -8,6 +8,7 @@ Fixed issues: * Backported #7440: wlfreerdp appid * Backported #7832: RAIL window restore * Backported #7833: Refactored WinPR thread locking +* Backported #7893: Mac rdpsnd memory leak fixes # 2022-04-25 Version 2.7.0 From f1efd1cacd0adef047f8ee57a8b67d06159e452e Mon Sep 17 00:00:00 2001 From: akallabeth Date: Fri, 13 May 2022 09:19:28 +0200 Subject: [PATCH 177/496] Android auto version code (cherry picked from commit 6b7e1679cc1e42aab3ad228d3d2a392899360cdf) --- client/Android/Studio/aFreeRDP/build.gradle | 17 ++++++++++++++--- client/Android/Studio/build.gradle | 15 +-------------- 2 files changed, 15 insertions(+), 17 deletions(-) diff --git a/client/Android/Studio/aFreeRDP/build.gradle b/client/Android/Studio/aFreeRDP/build.gradle index a625e6bb9510..96f7184d8ce4 100644 --- a/client/Android/Studio/aFreeRDP/build.gradle +++ b/client/Android/Studio/aFreeRDP/build.gradle @@ -1,5 +1,16 @@ -apply plugin: 'com.android.application' +plugins { + id 'com.gladed.androidgitversion' version '0.4.4' +} + +androidGitVersion { + abis = ['armeabi':1, 'armeabi-v7a':2, 'arm64-v8a':3, 'mips':5, 'mips64':6, 'x86':8, 'x86_64':9 ] + prefix '' +} + +println 'Version Name: ' + androidGitVersion.name() +println 'Version Code: ' + androidGitVersion.code() +apply plugin: 'com.android.application' android { compileSdkVersion = rootProject.ext.compileApi buildToolsVersion = rootProject.ext.toolsVersion @@ -9,8 +20,8 @@ android { minSdkVersion rootProject.ext.minApi targetSdkVersion rootProject.ext.targetApi vectorDrawables.useSupportLibrary = true - versionCode = rootProject.ext.versionCode - versionName = rootProject.ext.versionName + versionName = androidGitVersion.name() + versionCode = androidGitVersion.code() } signingConfigs { diff --git a/client/Android/Studio/build.gradle b/client/Android/Studio/build.gradle index aa7d1f7bda78..81ae37c3ec37 100644 --- a/client/Android/Studio/build.gradle +++ b/client/Android/Studio/build.gradle @@ -18,26 +18,13 @@ if (!hasProperty('RELEASE_KEY_PASSWORD')) { ext.RELEASE_KEY_PASSWORD='' } -def getVersionName = { -> - def stdout = new ByteArrayOutputStream() - exec { - commandLine 'git', 'describe', '--tags' - standardOutput = stdout - } - return stdout.toString().trim() -} - ext { - versionName = properties.get('VERSION_NAME', getVersionName()) - versionCode = properties.get('VERSION_CODE', 29) compileApi = properties.get('COMPILE_API', 31) targetApi = properties.get('TARGET_API', 31) minApi = properties.get('MIN_API', 23) toolsVersion = properties.get('TOOLS_VERSION', '31.0.0') println '----------------- Project configuration -------------------' - println 'VERSION_NAME: ' + versionName - println 'VERSION_CODE: ' + versionCode println 'RELEASE_STORE_FILE: ' + RELEASE_STORE_FILE println 'RELEASE_KEY_ALIAS: ' + RELEASE_KEY_ALIAS println 'compile API: ' + compileApi @@ -53,7 +40,7 @@ buildscript { google() } dependencies { - classpath 'com.android.tools.build:gradle:7.0.4' + classpath 'com.android.tools.build:gradle:7.1.2' } } From 003d307026eff7d8dfadf803a04bbf377000febc Mon Sep 17 00:00:00 2001 From: akallabeth Date: Fri, 13 May 2022 09:43:14 +0200 Subject: [PATCH 178/496] Made WITH_MEDIACODEC configurable, use newer openssl (cherry picked from commit 0c7e5fdbfe24325007707abe208580a1e388a1c8) --- scripts/android-build-32.conf | 1 + scripts/android-build-64.conf | 1 + scripts/android-build-freerdp.sh | 14 ++++++++++++++ scripts/android-build-release.conf | 1 + scripts/android-build.conf | 5 +++-- 5 files changed, 20 insertions(+), 2 deletions(-) diff --git a/scripts/android-build-32.conf b/scripts/android-build-32.conf index d7be812b41b6..3bc4265643c5 100644 --- a/scripts/android-build-32.conf +++ b/scripts/android-build-32.conf @@ -16,6 +16,7 @@ WITH_FFMPEG=1 BUILD_DEPS=1 DEPS_ONLY=0 NDK_TARGET=21 +WITH_MEDIACODEC=1 JPEG_TAG=master OPENH264_TAG=v1.8.0 # NOTE: NDK r15c or earlier needed in --openh624-ndk for v1.8.0 diff --git a/scripts/android-build-64.conf b/scripts/android-build-64.conf index 9cfe26111795..3d82ea1490d8 100644 --- a/scripts/android-build-64.conf +++ b/scripts/android-build-64.conf @@ -16,6 +16,7 @@ WITH_FFMPEG=1 BUILD_DEPS=1 DEPS_ONLY=0 NDK_TARGET=21 +WITH_MEDIACODEC=1 JPEG_TAG=master OPENH264_TAG=v1.8.0 # NOTE: NDK r15c or earlier needed in --openh624-ndk for v1.8.0 diff --git a/scripts/android-build-freerdp.sh b/scripts/android-build-freerdp.sh index eb5eeba20f50..c39c3991e9d9 100755 --- a/scripts/android-build-freerdp.sh +++ b/scripts/android-build-freerdp.sh @@ -77,6 +77,12 @@ do done common_parse_arguments $REMAINING +if [ -z ${WITH_MEDIACODEC+x} ]; +then + common_run echo "WITH_MEDIACODEC unset, defining WITH_MEDIACODEC=1" + WITH_MEDIACODEC=1 +fi + # clean up top if [ -d $BUILD_SRC ]; then @@ -140,6 +146,14 @@ do else CMAKE_CMD_ARGS="$CMAKE_CMD_ARGS -DWITH_OPENH264=OFF" fi + + if [ $WITH_MEDIACODEC -ne 0 ]; + then + CMAKE_CMD_ARGS="$CMAKE_CMD_ARGS -DWITH_MEDIACODEC=ON" + else + CMAKE_CMD_ARGS="$CMAKE_CMD_ARGS -DWITH_MEDIACODEC=OFF" + fi + if [ $WITH_FFMPEG -ne 0 ]; then if [ $BUILD_DEPS -ne 0 ]; diff --git a/scripts/android-build-release.conf b/scripts/android-build-release.conf index d1834efbe5ec..20d9bbb3e739 100644 --- a/scripts/android-build-release.conf +++ b/scripts/android-build-release.conf @@ -16,6 +16,7 @@ WITH_FFMPEG=1 BUILD_DEPS=1 DEPS_ONLY=0 NDK_TARGET=23 +WITH_MEDIACODEC=1 JPEG_TAG=master OPENH264_TAG=v1.8.0 # NOTE: NDK r15c or earlier needed in --openh624-ndk for v1.8.0 diff --git a/scripts/android-build.conf b/scripts/android-build.conf index 5f470a5e37f6..afdb4e04cfa9 100644 --- a/scripts/android-build.conf +++ b/scripts/android-build.conf @@ -15,11 +15,12 @@ WITH_OPENSSL=1 WITH_FFMPEG=0 BUILD_DEPS=1 DEPS_ONLY=0 -NDK_TARGET=26 +NDK_TARGET=21 +WITH_MEDIACODEC=1 JPEG_TAG=master OPENH264_TAG=v1.8.0 # NOTE: NDK r15c or earlier needed in --openh624-ndk for v1.8.0 -OPENSSL_TAG=OpenSSL_1_1_1m +OPENSSL_TAG=openssl-1.1.1o FFMPEG_TAG=n4.4.1 SRC_DIR=$SCRIPT_PATH/.. From ad6dae15e33d21838d3ac272daf03524cd2f22d5 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Fri, 13 May 2022 09:50:23 +0200 Subject: [PATCH 179/496] Updated openh264 and openssl versions --- scripts/android-build-32.conf | 4 ++-- scripts/android-build-64.conf | 4 ++-- scripts/android-build-release.conf | 4 ++-- scripts/android-build.conf | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/scripts/android-build-32.conf b/scripts/android-build-32.conf index 3bc4265643c5..ff84d6d986bf 100644 --- a/scripts/android-build-32.conf +++ b/scripts/android-build-32.conf @@ -19,8 +19,8 @@ NDK_TARGET=21 WITH_MEDIACODEC=1 JPEG_TAG=master -OPENH264_TAG=v1.8.0 # NOTE: NDK r15c or earlier needed in --openh624-ndk for v1.8.0 -OPENSSL_TAG=OpenSSL_1_1_1m +OPENH264_TAG=v2.2.0 # NOTE: NDK r15c or earlier needed in --openh624-ndk for v1.8.0 +OPENSSL_TAG=OpenSSL_1_1_1o FFMPEG_TAG=n4.4.1 SRC_DIR=$SCRIPT_PATH/.. diff --git a/scripts/android-build-64.conf b/scripts/android-build-64.conf index 3d82ea1490d8..a8b3a8751472 100644 --- a/scripts/android-build-64.conf +++ b/scripts/android-build-64.conf @@ -19,8 +19,8 @@ NDK_TARGET=21 WITH_MEDIACODEC=1 JPEG_TAG=master -OPENH264_TAG=v1.8.0 # NOTE: NDK r15c or earlier needed in --openh624-ndk for v1.8.0 -OPENSSL_TAG=OpenSSL_1_1_1j +OPENH264_TAG=v2.2.0 # NOTE: NDK r15c or earlier needed in --openh624-ndk for v1.8.0 +OPENSSL_TAG=OpenSSL_1_1_1o FFMPEG_TAG=n4.4.1 SRC_DIR=$SCRIPT_PATH/.. diff --git a/scripts/android-build-release.conf b/scripts/android-build-release.conf index 20d9bbb3e739..06a435600eb2 100644 --- a/scripts/android-build-release.conf +++ b/scripts/android-build-release.conf @@ -19,8 +19,8 @@ NDK_TARGET=23 WITH_MEDIACODEC=1 JPEG_TAG=master -OPENH264_TAG=v1.8.0 # NOTE: NDK r15c or earlier needed in --openh624-ndk for v1.8.0 -OPENSSL_TAG=OpenSSL_1_1_1m +OPENH264_TAG=v2.2.0 # NOTE: NDK r15c or earlier needed in --openh624-ndk for v1.8.0 +OPENSSL_TAG=OpenSSL_1_1_1o FFMPEG_TAG=n4.4.1 SRC_DIR=$SCRIPT_PATH/.. diff --git a/scripts/android-build.conf b/scripts/android-build.conf index afdb4e04cfa9..798c26e8a550 100644 --- a/scripts/android-build.conf +++ b/scripts/android-build.conf @@ -19,8 +19,8 @@ NDK_TARGET=21 WITH_MEDIACODEC=1 JPEG_TAG=master -OPENH264_TAG=v1.8.0 # NOTE: NDK r15c or earlier needed in --openh624-ndk for v1.8.0 -OPENSSL_TAG=openssl-1.1.1o +OPENH264_TAG=v2.2.0 # NOTE: NDK r15c or earlier needed in --openh624-ndk for v1.8.0 +OPENSSL_TAG=OpenSSL_1_1_1o FFMPEG_TAG=n4.4.1 SRC_DIR=$SCRIPT_PATH/.. From ec901e10629d18b6e3b716725a253dbf223e87cd Mon Sep 17 00:00:00 2001 From: Felix Deimel Date: Thu, 12 May 2022 15:45:01 +0200 Subject: [PATCH 180/496] Fixed memory leak in audin mac (cherry picked from commit 24c87c5126b617f6c553fad41911ece29f01d119) --- channels/audin/client/mac/audin_mac.m | 54 ++++++++++++++------------- 1 file changed, 28 insertions(+), 26 deletions(-) diff --git a/channels/audin/client/mac/audin_mac.m b/channels/audin/client/mac/audin_mac.m index ecf3c8cc0011..56b7ea96aee2 100644 --- a/channels/audin/client/mac/audin_mac.m +++ b/channels/audin/client/mac/audin_mac.m @@ -423,32 +423,34 @@ UINT freerdp_audin_client_subsystem_entry(PFREERDP_AUDIN_DEVICE_ENTRY_POINTS pEn #if defined(MAC_OS_X_VERSION_10_14) if (@available(macOS 10.14, *)) { - AVAuthorizationStatus status = - [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeAudio]; - switch (status) - { - case AVAuthorizationStatusAuthorized: - mac->isAuthorized = TRUE; - break; - case AVAuthorizationStatusNotDetermined: - [AVCaptureDevice requestAccessForMediaType:AVMediaTypeAudio - completionHandler:^(BOOL granted) { - if (granted == YES) - { - mac->isAuthorized = TRUE; - } - else - WLog_WARN(TAG, "Microphone access denied by user"); - }]; - break; - case AVAuthorizationStatusRestricted: - WLog_WARN(TAG, "Microphone access restricted by policy"); - break; - case AVAuthorizationStatusDenied: - WLog_WARN(TAG, "Microphone access denied by policy"); - break; - default: - break; + @autoreleasepool { + AVAuthorizationStatus status = + [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeAudio]; + switch (status) + { + case AVAuthorizationStatusAuthorized: + mac->isAuthorized = TRUE; + break; + case AVAuthorizationStatusNotDetermined: + [AVCaptureDevice requestAccessForMediaType:AVMediaTypeAudio + completionHandler:^(BOOL granted) { + if (granted == YES) + { + mac->isAuthorized = TRUE; + } + else + WLog_WARN(TAG, "Microphone access denied by user"); + }]; + break; + case AVAuthorizationStatusRestricted: + WLog_WARN(TAG, "Microphone access restricted by policy"); + break; + case AVAuthorizationStatusDenied: + WLog_WARN(TAG, "Microphone access denied by policy"); + break; + default: + break; + } } } #endif From 9437c4b4bef82d182b047e78eac2edc3088e0a56 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Fri, 13 May 2022 09:46:44 +0200 Subject: [PATCH 181/496] changelog --- ChangeLog | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ChangeLog b/ChangeLog index 138076ce6b24..743fab3711e6 100644 --- a/ChangeLog +++ b/ChangeLog @@ -9,6 +9,8 @@ Fixed issues: * Backported #7832: RAIL window restore * Backported #7833: Refactored WinPR thread locking * Backported #7893: Mac rdpsnd memory leak fixes +* Backported #7895: Mac audin memory leak fixes +* Backported #7898: Automatic android versioning # 2022-04-25 Version 2.7.0 From c01c41436fb6af98311310a8c09bdcd88052ebe8 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Fri, 13 May 2022 10:19:54 +0200 Subject: [PATCH 182/496] Use clang to build openh264 (cherry picked from commit c3787a7b8ac4abe3674f281e2432e0334c99b5d8) --- scripts/android-build-openh264.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/android-build-openh264.sh b/scripts/android-build-openh264.sh index 5e9abed2c182..b0cec9902913 100755 --- a/scripts/android-build-openh264.sh +++ b/scripts/android-build-openh264.sh @@ -9,8 +9,8 @@ function build { BASE=$(pwd) common_run cd $BUILD_SRC PATH=$ANDROID_NDK:$PATH - MAKE="make PATH=$PATH ENABLEPIC=Yes OS=android NDKROOT=$ANDROID_NDK TARGET=android-$2 NDKLEVEL=$2 ARCH=$1 -j libraries" - + MAKE="make PATH=$PATH ENABLEPIC=Yes OS=android NDKROOT=$ANDROID_NDK NDK_TOOLCHAIN_VERSION=clang TARGET=android-$2 NDKLEVEL=$2 ARCH=$1 -j libraries" + common_run export QUIET_AR="$CCACHE " common_run export QUIET_ASM="$CCACHE " common_run export QUIET_CC="$CCACHE " From 7f35f29546b5e502b3da371ea851401f02889337 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Fri, 13 May 2022 11:09:00 +0200 Subject: [PATCH 183/496] Fixed compilation warnings --- channels/audin/client/opensles/audin_opensl_es.c | 2 +- client/Android/android_freerdp.c | 2 +- client/common/client.c | 2 +- winpr/libwinpr/sysinfo/cpufeatures/cpu-features.c | 1 + 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/channels/audin/client/opensles/audin_opensl_es.c b/channels/audin/client/opensles/audin_opensl_es.c index 87393ad36397..a3b7c3cedcc8 100644 --- a/channels/audin/client/opensles/audin_opensl_es.c +++ b/channels/audin/client/opensles/audin_opensl_es.c @@ -215,7 +215,7 @@ static UINT audin_opensles_open(IAudinDevice* device, AudinReceive receive, void opensles->user_data = user_data; return CHANNEL_RC_OK; error_out: - audin_opensles_close(opensles); + audin_opensles_close(device); return ERROR_INTERNAL_ERROR; } diff --git a/client/Android/android_freerdp.c b/client/Android/android_freerdp.c index aa98474a9c11..6ac79a633c54 100644 --- a/client/Android/android_freerdp.c +++ b/client/Android/android_freerdp.c @@ -523,7 +523,7 @@ static int android_freerdp_run(freerdp* instance) count += tmp; status = WaitForMultipleObjects(count, handles, FALSE, INFINITE); - if ((status == WAIT_FAILED)) + if (status == WAIT_FAILED) { WLog_ERR(TAG, "WaitForMultipleObjects failed with %" PRIu32 " [%08lX]", status, GetLastError()); diff --git a/client/common/client.c b/client/common/client.c index 12317dc10fdf..6862deb362fe 100644 --- a/client/common/client.c +++ b/client/common/client.c @@ -782,7 +782,7 @@ BOOL client_auto_reconnect_ex(freerdp* instance, BOOL (*window_events)(freerdp* if (freerdp_reconnect(instance)) return TRUE; - switch (freerdp_get_last_error(instance)) + switch (freerdp_get_last_error(instance->context)) { case FREERDP_ERROR_CONNECT_CANCELLED: WLog_WARN(TAG, "Autoreconnect aborted by user"); diff --git a/winpr/libwinpr/sysinfo/cpufeatures/cpu-features.c b/winpr/libwinpr/sysinfo/cpufeatures/cpu-features.c index a5a0bf19a123..d8d59d0c2c6d 100644 --- a/winpr/libwinpr/sysinfo/cpufeatures/cpu-features.c +++ b/winpr/libwinpr/sysinfo/cpufeatures/cpu-features.c @@ -69,6 +69,7 @@ #include #include #include +#include #include #include #include From 51e39d34d34dcbc25b79ca9b1fcdd24adf4e8ea7 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Fri, 13 May 2022 11:48:10 +0200 Subject: [PATCH 184/496] Remove android version from freeRDPCore --- client/Android/Studio/freeRDPCore/build.gradle | 2 -- 1 file changed, 2 deletions(-) diff --git a/client/Android/Studio/freeRDPCore/build.gradle b/client/Android/Studio/freeRDPCore/build.gradle index 713ad3722c96..e2224c21c75f 100644 --- a/client/Android/Studio/freeRDPCore/build.gradle +++ b/client/Android/Studio/freeRDPCore/build.gradle @@ -8,8 +8,6 @@ android { minSdkVersion rootProject.ext.minApi targetSdkVersion rootProject.ext.targetApi vectorDrawables.useSupportLibrary = true - versionCode = rootProject.ext.versionCode - versionName = rootProject.ext.versionName } buildTypes { From 0220ccdf39a137df84e07fe94972a60fc31b9808 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Fri, 13 May 2022 11:48:46 +0200 Subject: [PATCH 185/496] Updated gradle --- .../Android/Studio/gradle/wrapper/gradle-wrapper.properties | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/client/Android/Studio/gradle/wrapper/gradle-wrapper.properties b/client/Android/Studio/gradle/wrapper/gradle-wrapper.properties index 6b5305e2178a..0416d39546d0 100644 --- a/client/Android/Studio/gradle/wrapper/gradle-wrapper.properties +++ b/client/Android/Studio/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Mon Mar 15 09:39:30 CET 2021 +#Fri May 13 11:48:24 CEST 2022 distributionBase=GRADLE_USER_HOME +distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip distributionPath=wrapper/dists -zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-bin.zip +zipStoreBase=GRADLE_USER_HOME From f8a4c6a9fed51cacd7b75ca95e2fcb018f4ac5b8 Mon Sep 17 00:00:00 2001 From: Pascal Nowack Date: Wed, 18 May 2022 10:04:00 +0200 Subject: [PATCH 186/496] rdpsnd/client: Fix handling of WaveConfirm PDUs (#7910) (#7911) Currently, all FreeRDP-based clients don't send any WaveConfirm PDUs for received samples, when using a dynamic channel for audio output redirection. [MS-RDPEA] 2.2.3.8 Wave Confirm PDU mentions, that a WaveConfirm PDU MUST be sent, when a WaveInfo PDU + Wave PDU, or Wave2 PDU is received and when the audio data sample is emitted to completion by the client. The first WaveConfirm PDU is used by the server to determine the network latency and the second WaveConfirm PDU is used by the server to determine the render latency. So, fix the current behaviour, where FreeRDP currently does not send any WaveConfirm PDU, when using the dynamic channel, or only sends one WaveConfirm PDU for the sample. For the first WaveConfirm PDU, use the same timestamp, that was included in the first WaveInfo/Wave2 PDU. For the second WaveConfirm PDU, add the render latency on top of the arrival timestamp. --- channels/rdpsnd/client/rdpsnd_main.c | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/channels/rdpsnd/client/rdpsnd_main.c b/channels/rdpsnd/client/rdpsnd_main.c index ebdf93121fc2..f6240582dcd3 100644 --- a/channels/rdpsnd/client/rdpsnd_main.c +++ b/channels/rdpsnd/client/rdpsnd_main.c @@ -582,6 +582,7 @@ static UINT rdpsnd_treat_wave(rdpsndPlugin* rdpsnd, wStream* s, size_t size) UINT64 end; UINT64 diffMS, ts; UINT latency = 0; + UINT error; if (Stream_GetRemainingLength(s) < size) return ERROR_BAD_LENGTH; @@ -589,6 +590,15 @@ static UINT rdpsnd_treat_wave(rdpsndPlugin* rdpsnd, wStream* s, size_t size) if (rdpsnd->wCurrentFormatNo >= rdpsnd->NumberOfClientFormats) return ERROR_INTERNAL_ERROR; + /* + * Send the first WaveConfirm PDU. The server side uses this to determine the + * network latency. + * See also [MS-RDPEA] 2.2.3.8 Wave Confirm PDU + */ + error = rdpsnd_send_wave_confirm_pdu(rdpsnd, rdpsnd->wTimeStamp, rdpsnd->cBlockNo); + if (error) + return error; + data = Stream_Pointer(s); format = &rdpsnd->ClientFormats[rdpsnd->wCurrentFormatNo]; WLog_Print(rdpsnd->log, WLOG_DEBUG, @@ -621,10 +631,11 @@ static UINT rdpsnd_treat_wave(rdpsndPlugin* rdpsnd, wStream* s, size_t size) diffMS = end - rdpsnd->wArrivalTime + latency; ts = (rdpsnd->wTimeStamp + diffMS) % UINT16_MAX; - /* Don't send wave confirm PDU if on dynamic channel */ - if (rdpsnd->dynamic) - return CHANNEL_RC_OK; - + /* + * Send the second WaveConfirm PDU. With the first WaveConfirm PDU, + * the server side uses this second WaveConfirm PDU to determine the actual + * render latency. + */ return rdpsnd_send_wave_confirm_pdu(rdpsnd, (UINT16)ts, rdpsnd->cBlockNo); } From 715c80622bc42b1832c5e151f5fba9f30658b1fc Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Tue, 24 May 2022 07:22:03 +0200 Subject: [PATCH 187/496] Updated RDPGFX_CAPSET_VERSION106 code to conform to spec (cherry picked from commit 6ea15d36c423ec4ca97ea16d56602917a988cfb2) --- include/freerdp/channels/rdpgfx.h | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/include/freerdp/channels/rdpgfx.h b/include/freerdp/channels/rdpgfx.h index 095022ddfa15..a4e97ffb1c91 100644 --- a/include/freerdp/channels/rdpgfx.h +++ b/include/freerdp/channels/rdpgfx.h @@ -99,9 +99,7 @@ typedef struct _RDPGFX_HEADER RDPGFX_HEADER; #define RDPGFX_CAPVERSION_103 0x000A0301 /** [MS-RDPEGFX] 2.2.3.6 */ #define RDPGFX_CAPVERSION_104 0x000A0400 /** [MS-RDPEGFX] 2.2.3.7 */ #define RDPGFX_CAPVERSION_105 0x000A0502 /** [MS-RDPEGFX] 2.2.3.8 */ -#define RDPGFX_CAPVERSION_106 \ - 0x000A0600 /** [MS-RDPEGFX] 2.2.3.9, [MS-RDPEGFX-errata] 2018-12-10 \ - */ +#define RDPGFX_CAPVERSION_106 0x000A0601 /** [MS-RDPEGFX] 2.2.3.9 */ #define RDPGFX_NUMBER_CAPSETS 9 #define RDPGFX_CAPSET_BASE_SIZE 8 From da274b6e96c8f73bea487f7855c1f4c1798a0243 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Tue, 24 May 2022 07:45:03 +0200 Subject: [PATCH 188/496] Add GFX 10.7 capsets (cherry picked from commit 9190472e36b6994521fd5b670e34464261db0e9a) --- channels/rdpgfx/client/rdpgfx_main.c | 19 +++++++++++++------ include/freerdp/channels/rdpgfx.h | 4 +++- server/shadow/shadow_client.c | 13 ++++++++----- 3 files changed, 24 insertions(+), 12 deletions(-) diff --git a/channels/rdpgfx/client/rdpgfx_main.c b/channels/rdpgfx/client/rdpgfx_main.c index 67b3a7db4d8a..4c13d43298a7 100644 --- a/channels/rdpgfx/client/rdpgfx_main.c +++ b/channels/rdpgfx/client/rdpgfx_main.c @@ -163,11 +163,10 @@ static UINT rdpgfx_send_caps_advertise_pdu(RdpgfxClientContext* context, static BOOL rdpgfx_is_capability_filtered(RDPGFX_PLUGIN* gfx, UINT32 caps) { const UINT32 filter = gfx->capsFilter; - const UINT32 capList[] = { - RDPGFX_CAPVERSION_8, RDPGFX_CAPVERSION_81, RDPGFX_CAPVERSION_10, - RDPGFX_CAPVERSION_101, RDPGFX_CAPVERSION_102, RDPGFX_CAPVERSION_103, - RDPGFX_CAPVERSION_104, RDPGFX_CAPVERSION_105, RDPGFX_CAPVERSION_106 - }; + const UINT32 capList[] = { RDPGFX_CAPVERSION_8, RDPGFX_CAPVERSION_81, RDPGFX_CAPVERSION_10, + RDPGFX_CAPVERSION_101, RDPGFX_CAPVERSION_102, RDPGFX_CAPVERSION_103, + RDPGFX_CAPVERSION_104, RDPGFX_CAPVERSION_105, RDPGFX_CAPVERSION_106, + RDPGFX_CAPVERSION_107 }; UINT32 x; for (x = 0; x < ARRAYSIZE(capList); x++) @@ -190,7 +189,7 @@ static UINT rdpgfx_send_supported_caps(RDPGFX_CHANNEL_CALLBACK* callback) RdpgfxClientContext* context; RDPGFX_CAPSET* capsSet; RDPGFX_CAPSET capsSets[RDPGFX_NUMBER_CAPSETS] = { 0 }; - RDPGFX_CAPS_ADVERTISE_PDU pdu; + RDPGFX_CAPS_ADVERTISE_PDU pdu = { 0 }; if (!callback) return ERROR_BAD_ARGUMENTS; @@ -323,6 +322,14 @@ static UINT rdpgfx_send_supported_caps(RDPGFX_CHANNEL_CALLBACK* callback) capsSet->length = 0x4; capsSet->flags = caps10Flags; } + + if (!rdpgfx_is_capability_filtered(gfx, RDPGFX_CAPVERSION_107)) + { + capsSet = &capsSets[pdu.capsSetCount++]; + capsSet->version = RDPGFX_CAPVERSION_107; + capsSet->length = 0x4; + capsSet->flags = caps10Flags; + } } return IFCALLRESULT(ERROR_BAD_CONFIGURATION, context->CapsAdvertise, context, &pdu); diff --git a/include/freerdp/channels/rdpgfx.h b/include/freerdp/channels/rdpgfx.h index a4e97ffb1c91..d9351349833c 100644 --- a/include/freerdp/channels/rdpgfx.h +++ b/include/freerdp/channels/rdpgfx.h @@ -100,8 +100,9 @@ typedef struct _RDPGFX_HEADER RDPGFX_HEADER; #define RDPGFX_CAPVERSION_104 0x000A0400 /** [MS-RDPEGFX] 2.2.3.7 */ #define RDPGFX_CAPVERSION_105 0x000A0502 /** [MS-RDPEGFX] 2.2.3.8 */ #define RDPGFX_CAPVERSION_106 0x000A0601 /** [MS-RDPEGFX] 2.2.3.9 */ +#define RDPGFX_CAPVERSION_107 0x000A0701 /** [MS-RDPEGFX] 2.2.3.10 */ -#define RDPGFX_NUMBER_CAPSETS 9 +#define RDPGFX_NUMBER_CAPSETS 10 #define RDPGFX_CAPSET_BASE_SIZE 8 struct _RDPGFX_CAPSET @@ -117,6 +118,7 @@ typedef struct _RDPGFX_CAPSET RDPGFX_CAPSET; #define RDPGFX_CAPS_FLAG_AVC420_ENABLED 0x00000010U /* 8.1+ */ #define RDPGFX_CAPS_FLAG_AVC_DISABLED 0x00000020U /* 10.0+ */ #define RDPGFX_CAPS_FLAG_AVC_THINCLIENT 0x00000040U /* 10.3+ */ +#define RDPGFX_CAPS_FLAG_SCALEDMAP_DISABLE 0x00000080U /* 10.7+ */ struct _RDPGFX_CAPSET_VERSION8 { diff --git a/server/shadow/shadow_client.c b/server/shadow/shadow_client.c index e6bc67b6ed39..183c5d4fb7b7 100644 --- a/server/shadow/shadow_client.c +++ b/server/shadow/shadow_client.c @@ -596,11 +596,10 @@ shadow_client_rdpgfx_frame_acknowledge(RdpgfxServerContext* context, static BOOL shadow_are_caps_filtered(const rdpSettings* settings, UINT32 caps) { const UINT32 filter = settings->GfxCapsFilter; - const UINT32 capList[] = { - RDPGFX_CAPVERSION_8, RDPGFX_CAPVERSION_81, RDPGFX_CAPVERSION_10, - RDPGFX_CAPVERSION_101, RDPGFX_CAPVERSION_102, RDPGFX_CAPVERSION_103, - RDPGFX_CAPVERSION_104, RDPGFX_CAPVERSION_105, RDPGFX_CAPVERSION_106 - }; + const UINT32 capList[] = { RDPGFX_CAPVERSION_8, RDPGFX_CAPVERSION_81, RDPGFX_CAPVERSION_10, + RDPGFX_CAPVERSION_101, RDPGFX_CAPVERSION_102, RDPGFX_CAPVERSION_103, + RDPGFX_CAPVERSION_104, RDPGFX_CAPVERSION_105, RDPGFX_CAPVERSION_106, + RDPGFX_CAPVERSION_107 }; UINT32 x; for (x = 0; x < ARRAYSIZE(capList); x++) @@ -682,6 +681,10 @@ static UINT shadow_client_rdpgfx_caps_advertise(RdpgfxServerContext* context, if (!shadow_client_refresh_rect(&client->context, 0, NULL)) return rc; + if (shadow_client_caps_test_version(context, h264, capsAdvertise->capsSets, + capsAdvertise->capsSetCount, RDPGFX_CAPVERSION_107, &rc)) + return rc; + if (shadow_client_caps_test_version(context, h264, capsAdvertise->capsSets, capsAdvertise->capsSetCount, RDPGFX_CAPVERSION_106, &rc)) return rc; From e69ecadba57a9c4f75f08bec708bc8ab9d8b15ee Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Tue, 24 May 2022 09:58:42 +0200 Subject: [PATCH 189/496] Disable scaled output PDU if no scaling support compiled (cherry picked from commit 7e526e87708cf5530901ae2e7b8d49f67f19ae61) --- channels/rdpgfx/client/rdpgfx_main.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/channels/rdpgfx/client/rdpgfx_main.c b/channels/rdpgfx/client/rdpgfx_main.c index 4c13d43298a7..c064f8bb9ab0 100644 --- a/channels/rdpgfx/client/rdpgfx_main.c +++ b/channels/rdpgfx/client/rdpgfx_main.c @@ -329,6 +329,9 @@ static UINT rdpgfx_send_supported_caps(RDPGFX_CHANNEL_CALLBACK* callback) capsSet->version = RDPGFX_CAPVERSION_107; capsSet->length = 0x4; capsSet->flags = caps10Flags; +#if !defined(CAIRO_FOUND) && !defined(SWSCALE_FOUND) + capsSet->flags |= RDPGFX_CAPS_FLAG_SCALEDMAP_DISABLE; +#endif } } From cf1b4b06033c954dc7e2587b3c74f815b6197796 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Tue, 24 May 2022 10:11:34 +0200 Subject: [PATCH 190/496] Changelog --- ChangeLog | 1 + 1 file changed, 1 insertion(+) diff --git a/ChangeLog b/ChangeLog index 743fab3711e6..3aab6e2d2983 100644 --- a/ChangeLog +++ b/ChangeLog @@ -11,6 +11,7 @@ Fixed issues: * Backported #7893: Mac rdpsnd memory leak fixes * Backported #7895: Mac audin memory leak fixes * Backported #7898: Automatic android versioning +* Backported #7916: GFX 10.7 capability support # 2022-04-25 Version 2.7.0 From a2585fd446f716de55206c363e221567d9d1f83e Mon Sep 17 00:00:00 2001 From: akallabeth Date: Wed, 25 May 2022 10:02:58 +0200 Subject: [PATCH 191/496] Fixed missing WINAPI for callback function declarations (cherry picked from commit 3aca661f0e6adcbdace994fc2a554e55b4f58f86) --- channels/urbdrc/client/libusb/libusb_udevice.c | 4 ++-- channels/urbdrc/client/libusb/libusb_udevman.c | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/channels/urbdrc/client/libusb/libusb_udevice.c b/channels/urbdrc/client/libusb/libusb_udevice.c index 1322a4f3902c..505c31d7b558 100644 --- a/channels/urbdrc/client/libusb/libusb_udevice.c +++ b/channels/urbdrc/client/libusb/libusb_udevice.c @@ -237,7 +237,7 @@ static void async_transfer_user_data_free(ASYNC_TRANSFER_USER_DATA* user_data) } } -static void func_iso_callback(struct libusb_transfer* transfer) +static void LIBUSB_CALL func_iso_callback(struct libusb_transfer* transfer) { ASYNC_TRANSFER_USER_DATA* user_data = (ASYNC_TRANSFER_USER_DATA*)transfer->user_data; const UINT32 streamID = stream_id_from_buffer(transfer); @@ -336,7 +336,7 @@ static const LIBUSB_ENDPOINT_DESCEIPTOR* func_get_ep_desc(LIBUSB_CONFIG_DESCRIPT return NULL; } -static void func_bulk_transfer_cb(struct libusb_transfer* transfer) +static void LIBUSB_CALL func_bulk_transfer_cb(struct libusb_transfer* transfer) { ASYNC_TRANSFER_USER_DATA* user_data; uint32_t streamID; diff --git a/channels/urbdrc/client/libusb/libusb_udevman.c b/channels/urbdrc/client/libusb/libusb_udevman.c index edfe74f415d6..95b37f6d3ff1 100644 --- a/channels/urbdrc/client/libusb/libusb_udevman.c +++ b/channels/urbdrc/client/libusb/libusb_udevman.c @@ -865,7 +865,7 @@ static BOOL poll_libusb_events(UDEVMAN* udevman) return rc > 0; } -static DWORD poll_thread(LPVOID lpThreadParameter) +static DWORD WINAPI poll_thread(LPVOID lpThreadParameter) { libusb_hotplug_callback_handle handle; UDEVMAN* udevman = (UDEVMAN*)lpThreadParameter; From dd5bf396b7c180e6b391cafffb406ef6a66513be Mon Sep 17 00:00:00 2001 From: akallabeth Date: Wed, 25 May 2022 10:33:35 +0200 Subject: [PATCH 192/496] Fixed RDPGFX_CAPVERSION_106 according to errata The [MS-RDPEGFX] spec is not really sure which value to use, so we just announce both, the one from the spec and the one from errata. (cherry picked from commit 8df9170b5d2f96e17034b12525420761c504ef4c) --- channels/rdpgfx/client/rdpgfx_main.c | 18 +++++++++++++++--- include/freerdp/channels/rdpgfx.h | 5 +++-- server/shadow/shadow_client.c | 13 ++++++++++--- 3 files changed, 28 insertions(+), 8 deletions(-) diff --git a/channels/rdpgfx/client/rdpgfx_main.c b/channels/rdpgfx/client/rdpgfx_main.c index c064f8bb9ab0..ceb4c18c8db6 100644 --- a/channels/rdpgfx/client/rdpgfx_main.c +++ b/channels/rdpgfx/client/rdpgfx_main.c @@ -163,9 +163,11 @@ static UINT rdpgfx_send_caps_advertise_pdu(RdpgfxClientContext* context, static BOOL rdpgfx_is_capability_filtered(RDPGFX_PLUGIN* gfx, UINT32 caps) { const UINT32 filter = gfx->capsFilter; - const UINT32 capList[] = { RDPGFX_CAPVERSION_8, RDPGFX_CAPVERSION_81, RDPGFX_CAPVERSION_10, - RDPGFX_CAPVERSION_101, RDPGFX_CAPVERSION_102, RDPGFX_CAPVERSION_103, - RDPGFX_CAPVERSION_104, RDPGFX_CAPVERSION_105, RDPGFX_CAPVERSION_106, + const UINT32 capList[] = { RDPGFX_CAPVERSION_8, RDPGFX_CAPVERSION_81, + RDPGFX_CAPVERSION_10, RDPGFX_CAPVERSION_101, + RDPGFX_CAPVERSION_102, RDPGFX_CAPVERSION_103, + RDPGFX_CAPVERSION_104, RDPGFX_CAPVERSION_105, + RDPGFX_CAPVERSION_106, RDPGFX_CAPVERSION_106_ERR, RDPGFX_CAPVERSION_107 }; UINT32 x; @@ -323,6 +325,14 @@ static UINT rdpgfx_send_supported_caps(RDPGFX_CHANNEL_CALLBACK* callback) capsSet->flags = caps10Flags; } + if (!rdpgfx_is_capability_filtered(gfx, RDPGFX_CAPVERSION_106_ERR)) + { + capsSet = &capsSets[pdu.capsSetCount++]; + capsSet->version = RDPGFX_CAPVERSION_106_ERR; + capsSet->length = 0x4; + capsSet->flags = caps10Flags; + } + if (!rdpgfx_is_capability_filtered(gfx, RDPGFX_CAPVERSION_107)) { capsSet = &capsSets[pdu.capsSetCount++]; @@ -905,6 +915,8 @@ static UINT rdpgfx_recv_end_frame_pdu(RDPGFX_CHANNEL_CALLBACK* callback, wStream case RDPGFX_CAPVERSION_104: case RDPGFX_CAPVERSION_105: case RDPGFX_CAPVERSION_106: + case RDPGFX_CAPVERSION_106_ERR: + case RDPGFX_CAPVERSION_107: if (gfx->SendQoeAck) { RDPGFX_QOE_FRAME_ACKNOWLEDGE_PDU qoe; diff --git a/include/freerdp/channels/rdpgfx.h b/include/freerdp/channels/rdpgfx.h index d9351349833c..01ae4e1c9658 100644 --- a/include/freerdp/channels/rdpgfx.h +++ b/include/freerdp/channels/rdpgfx.h @@ -100,9 +100,10 @@ typedef struct _RDPGFX_HEADER RDPGFX_HEADER; #define RDPGFX_CAPVERSION_104 0x000A0400 /** [MS-RDPEGFX] 2.2.3.7 */ #define RDPGFX_CAPVERSION_105 0x000A0502 /** [MS-RDPEGFX] 2.2.3.8 */ #define RDPGFX_CAPVERSION_106 0x000A0601 /** [MS-RDPEGFX] 2.2.3.9 */ -#define RDPGFX_CAPVERSION_107 0x000A0701 /** [MS-RDPEGFX] 2.2.3.10 */ +#define RDPGFX_CAPVERSION_106_ERR 0x000A0600 /** [MS-RDPEGFX]-180912-errata] */ +#define RDPGFX_CAPVERSION_107 0x000A0701 /** [MS-RDPEGFX] 2.2.3.10 */ -#define RDPGFX_NUMBER_CAPSETS 10 +#define RDPGFX_NUMBER_CAPSETS 11 #define RDPGFX_CAPSET_BASE_SIZE 8 struct _RDPGFX_CAPSET diff --git a/server/shadow/shadow_client.c b/server/shadow/shadow_client.c index 183c5d4fb7b7..0a1519ba283a 100644 --- a/server/shadow/shadow_client.c +++ b/server/shadow/shadow_client.c @@ -596,9 +596,11 @@ shadow_client_rdpgfx_frame_acknowledge(RdpgfxServerContext* context, static BOOL shadow_are_caps_filtered(const rdpSettings* settings, UINT32 caps) { const UINT32 filter = settings->GfxCapsFilter; - const UINT32 capList[] = { RDPGFX_CAPVERSION_8, RDPGFX_CAPVERSION_81, RDPGFX_CAPVERSION_10, - RDPGFX_CAPVERSION_101, RDPGFX_CAPVERSION_102, RDPGFX_CAPVERSION_103, - RDPGFX_CAPVERSION_104, RDPGFX_CAPVERSION_105, RDPGFX_CAPVERSION_106, + const UINT32 capList[] = { RDPGFX_CAPVERSION_8, RDPGFX_CAPVERSION_81, + RDPGFX_CAPVERSION_10, RDPGFX_CAPVERSION_101, + RDPGFX_CAPVERSION_102, RDPGFX_CAPVERSION_103, + RDPGFX_CAPVERSION_104, RDPGFX_CAPVERSION_105, + RDPGFX_CAPVERSION_106, RDPGFX_CAPVERSION_106_ERR, RDPGFX_CAPVERSION_107 }; UINT32 x; @@ -689,6 +691,11 @@ static UINT shadow_client_rdpgfx_caps_advertise(RdpgfxServerContext* context, capsAdvertise->capsSetCount, RDPGFX_CAPVERSION_106, &rc)) return rc; + if (shadow_client_caps_test_version(context, h264, capsAdvertise->capsSets, + capsAdvertise->capsSetCount, RDPGFX_CAPVERSION_106_ERR, + &rc)) + return rc; + if (shadow_client_caps_test_version(context, h264, capsAdvertise->capsSets, capsAdvertise->capsSetCount, RDPGFX_CAPVERSION_105, &rc)) return rc; From 430a1ef7bd1f7fb25422972c495bafa9c671386d Mon Sep 17 00:00:00 2001 From: akallabeth Date: Thu, 16 Dec 2021 12:32:01 +0100 Subject: [PATCH 193/496] Removed recursive xf_lock_x11 warning (cherry picked from commit 298d32164ca0dbdc6cde88a459bd66c6c2c7456b) --- client/X11/xf_client.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/client/X11/xf_client.c b/client/X11/xf_client.c index c2704a4b1291..90b05e87d9b9 100644 --- a/client/X11/xf_client.c +++ b/client/X11/xf_client.c @@ -815,8 +815,6 @@ void xf_lock_x11_(xfContext* xfc, const char* fkt) else XLockDisplay(xfc->display); - if (xfc->locked) - WLog_WARN(TAG, "%s:\t[%" PRIu32 "] recursive lock from %s", __FUNCTION__, xfc->locked, fkt); xfc->locked++; WLog_VRB(TAG, "%s:\t[%" PRIu32 "] from %s", __FUNCTION__, xfc->locked, fkt); } From 232333037d3479fd6dce570180d70d53cfdf7d8a Mon Sep 17 00:00:00 2001 From: akallabeth Date: Thu, 2 Jun 2022 13:45:34 +0200 Subject: [PATCH 194/496] Fix return of getlogin() (cherry picked from commit 1e779f92ec5bcfd694239c2efb26614b79b0886d) --- winpr/libwinpr/sspicli/sspicli.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/winpr/libwinpr/sspicli/sspicli.c b/winpr/libwinpr/sspicli/sspicli.c index 1d491b874fbb..75585dd51efd 100644 --- a/winpr/libwinpr/sspicli/sspicli.c +++ b/winpr/libwinpr/sspicli/sspicli.c @@ -230,7 +230,12 @@ BOOL GetUserNameExA(EXTENDED_NAME_FORMAT NameFormat, LPSTR lpNameBuffer, PULONG if (getlogin_r(lpNameBuffer, *nSize) != 0) return FALSE; #else - strncpy(lpNameBuffer, getlogin(), *nSize); + { + const char* name = getlogin(); + if (!name) + return FALSE; + strncpy(lpNameBuffer, name, strnlen(name, *nSize)); + } #endif *nSize = strnlen(lpNameBuffer, *nSize); return TRUE; From 601d01f7b4339db2ac6cbb418a72f78e0a4b4796 Mon Sep 17 00:00:00 2001 From: kubistika Date: Mon, 21 Sep 2020 10:43:23 +0300 Subject: [PATCH 195/496] core: server: add API to get peer accepted channel names (cherry picked from commit 508ba9201f6f058fcf4d83afce28c8a5a3c52b15) --- include/freerdp/channels/wtsvc.h | 1 + libfreerdp/core/server.c | 22 ++++++++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/include/freerdp/channels/wtsvc.h b/include/freerdp/channels/wtsvc.h index fe937872c3bd..31763dcc5b84 100644 --- a/include/freerdp/channels/wtsvc.h +++ b/include/freerdp/channels/wtsvc.h @@ -76,6 +76,7 @@ extern "C" FREERDP_API void* WTSChannelGetHandleByName(freerdp_peer* client, const char* channel_name); FREERDP_API void* WTSChannelGetHandleById(freerdp_peer* client, const UINT16 channel_id); FREERDP_API const char* WTSChannelGetName(freerdp_peer* client, UINT16 channel_id); + FREERDP_API char** WTSGetAcceptedChannelNames(freerdp_peer* client, size_t* count); #ifdef __cplusplus } diff --git a/libfreerdp/core/server.c b/libfreerdp/core/server.c index 484ed8b96944..39cd0e4f2ebd 100644 --- a/libfreerdp/core/server.c +++ b/libfreerdp/core/server.c @@ -670,6 +670,28 @@ const char* WTSChannelGetName(freerdp_peer* client, UINT16 channel_id) return (const char*)channel->Name; } +char** WTSGetAcceptedChannelNames(freerdp_peer* client, size_t* count) +{ + rdpMcs* mcs; + char** names; + UINT32 index; + + if (!client || !client->context || !count) + return NULL; + + mcs = client->context->rdp->mcs; + *count = mcs->channelCount; + + names = (char**)calloc(mcs->channelCount, sizeof(char*)); + if (!names) + return NULL; + + for (index = 0; index < mcs->channelCount; index++) + names[index] = mcs->channels[index].Name; + + return names; +} + BOOL WINAPI FreeRDP_WTSStartRemoteControlSessionW(LPWSTR pTargetServerName, ULONG TargetLogonId, BYTE HotkeyVk, USHORT HotkeyModifiers) { From 2f78a4cf9a5841dc30f6c949f8ac9270be120ab1 Mon Sep 17 00:00:00 2001 From: Richard Dymond Date: Thu, 2 Jun 2022 09:24:15 -0300 Subject: [PATCH 196/496] Update ChangeLog --- ChangeLog | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 3aab6e2d2983..173e474dd8ac 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,7 +1,8 @@ # 20xx-xx-xx Version 2.x.x Noteworthy changes: - +* Backported API to get peer accepted channel names + Fixed issues: * Fixed #7837: Prevent out of bound reads for FFMPEG * Backported #7859 and #7861: Unwind support for backtrace generation From 6ed2f7d1a379f69cca102e8166d20eb5ed38652b Mon Sep 17 00:00:00 2001 From: akallabeth Date: Fri, 22 Apr 2022 16:27:21 +0200 Subject: [PATCH 197/496] Fixed format string for Stream_CheckAndLogRequiredLength __LINE__ requires %d and not %PRIuz (cherry picked from commit 74c1a006e940308b0653427d25a87ea5a24cb573) --- winpr/include/winpr/stream.h | 14 ++++++++ winpr/libwinpr/utils/stream.c | 65 +++++++++++++++++++++++++++++++++++ 2 files changed, 79 insertions(+) diff --git a/winpr/include/winpr/stream.h b/winpr/include/winpr/stream.h index f351eaa15663..ed637f034465 100644 --- a/winpr/include/winpr/stream.h +++ b/winpr/include/winpr/stream.h @@ -27,6 +27,7 @@ #include #include #include +#include #ifdef __cplusplus extern "C" @@ -56,6 +57,19 @@ extern "C" WINPR_API void Stream_StaticInit(wStream* s, BYTE* buffer, size_t size); WINPR_API void Stream_Free(wStream* s, BOOL bFreeBuffer); +#define Stream_CheckAndLogRequiredLength(tag, s, len) \ + Stream_CheckAndLogRequiredLengthEx(tag, WLOG_WARN, s, len, "%s(%s:%d)", __FUNCTION__, \ + __FILE__, __LINE__) + WINPR_API BOOL Stream_CheckAndLogRequiredLengthEx(const char* tag, DWORD level, wStream* s, + UINT64 len, const char* fmt, ...); + WINPR_API BOOL Stream_CheckAndLogRequiredLengthExVa(const char* tag, DWORD level, wStream* s, + UINT64 len, const char* fmt, va_list args); + WINPR_API BOOL Stream_CheckAndLogRequiredLengthWLogEx(wLog* log, DWORD level, wStream* s, + UINT64 len, const char* fmt, ...); + WINPR_API BOOL Stream_CheckAndLogRequiredLengthWLogExVa(wLog* log, DWORD level, wStream* s, + UINT64 len, const char* fmt, + va_list args); + static INLINE void Stream_Seek(wStream* s, size_t _offset) { s->pointer += (_offset); diff --git a/winpr/libwinpr/utils/stream.c b/winpr/libwinpr/utils/stream.c index 1271981b7860..cc119c771762 100644 --- a/winpr/libwinpr/utils/stream.c +++ b/winpr/libwinpr/utils/stream.c @@ -132,3 +132,68 @@ void Stream_Free(wStream* s, BOOL bFreeBuffer) free(s); } } + +BOOL Stream_CheckAndLogRequiredLengthEx(const char* tag, DWORD level, wStream* s, UINT64 len, + const char* fmt, ...) +{ + const size_t actual = Stream_GetRemainingLength(s); + + if (actual < len) + { + va_list args; + + va_start(args, fmt); + Stream_CheckAndLogRequiredLengthExVa(tag, level, s, len, fmt, args); + va_end(args); + + return FALSE; + } + return TRUE; +} + +BOOL Stream_CheckAndLogRequiredLengthExVa(const char* tag, DWORD level, wStream* s, UINT64 len, + const char* fmt, va_list args) +{ + const size_t actual = Stream_GetRemainingLength(s); + + if (actual < len) + return Stream_CheckAndLogRequiredLengthWLogExVa(WLog_Get(tag), level, s, len, fmt, args); + return TRUE; +} + +BOOL Stream_CheckAndLogRequiredLengthWLogEx(wLog* log, DWORD level, wStream* s, UINT64 len, + const char* fmt, ...) +{ + const size_t actual = Stream_GetRemainingLength(s); + + if (actual < len) + { + va_list args; + + va_start(args, fmt); + Stream_CheckAndLogRequiredLengthWLogExVa(log, level, s, len, fmt, args); + va_end(args); + + return FALSE; + } + return TRUE; +} + +BOOL Stream_CheckAndLogRequiredLengthWLogExVa(wLog* log, DWORD level, wStream* s, UINT64 len, + const char* fmt, va_list args) +{ + const size_t actual = Stream_GetRemainingLength(s); + + if (actual < len) + { + char prefix[1024] = { 0 }; + + vsnprintf(prefix, sizeof(prefix), fmt, args); + + WLog_Print(log, level, "[%s] invalid length, got %" PRIuz ", require at least %" PRIu64, + prefix, actual, len); + winpr_log_backtrace_ex(log, level, 20); + return FALSE; + } + return TRUE; +} From 4a8d2d6628a807e92c07ea6b95aaf7b7ac3d0a02 Mon Sep 17 00:00:00 2001 From: Pascal Nowack Date: Sat, 30 Apr 2022 22:16:58 +0200 Subject: [PATCH 198/496] rdpsnd: Enhance server implementation The current server sided channel handling of RDPSND/AUDIO_PLAYBACK_DVC is currently very constrained. So, solve this. This means: - Add the missing Training/Training Confirm PDUs - Stop overriding the average bytes per second values, when submitting the audio formats, as this currently makes the usage of codecs impossible - Add a way to send the server formats manually again, to be able to restart the protocol after a Close PDU was sent - Add a way to send already encoded audio data to let server implementations to take care of the encoding process and to set custom audio timestamps for the Video Optimized Remoting channel - Add public attributes to let server implementations know the initial volume and pitch values - Add public attribute to let server implementations know the quality mode setting (cherry picked from commit 26488911be9ae8e00f77f075e03ddbe4dc70a402) --- ChangeLog | 2 + channels/rdpsnd/server/rdpsnd_main.c | 328 +++++++++++++++++++-------- include/freerdp/server/rdpsnd.h | 39 ++++ 3 files changed, 275 insertions(+), 94 deletions(-) diff --git a/ChangeLog b/ChangeLog index 173e474dd8ac..d8763a822516 100644 --- a/ChangeLog +++ b/ChangeLog @@ -2,6 +2,7 @@ Noteworthy changes: * Backported API to get peer accepted channel names +* Backported Stream_CheckAndLogRequiredLength Fixed issues: * Fixed #7837: Prevent out of bound reads for FFMPEG @@ -13,6 +14,7 @@ Fixed issues: * Backported #7895: Mac audin memory leak fixes * Backported #7898: Automatic android versioning * Backported #7916: GFX 10.7 capability support +* Backported #7949: Server RDPSND API improvements # 2022-04-25 Version 2.7.0 diff --git a/channels/rdpsnd/server/rdpsnd_main.c b/channels/rdpsnd/server/rdpsnd_main.c index 537aef66697f..7600a3aeccbf 100644 --- a/channels/rdpsnd/server/rdpsnd_main.c +++ b/channels/rdpsnd/server/rdpsnd_main.c @@ -28,6 +28,7 @@ #include #include +#include #include #include @@ -37,12 +38,13 @@ #include "rdpsnd_main.h" /** - * Function description + * Send Server Audio Formats and Version PDU (2.2.2.1) * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpsnd_server_send_formats(RdpsndServerContext* context, wStream* s) +static UINT rdpsnd_server_send_formats(RdpsndServerContext* context) { + wStream* s = context->priv->rdpsnd_pdu; size_t pos; UINT16 i; BOOL status = FALSE; @@ -62,9 +64,6 @@ static UINT rdpsnd_server_send_formats(RdpsndServerContext* context, wStream* s) for (i = 0; i < context->num_server_formats; i++) { AUDIO_FORMAT format = context->server_formats[i]; - // TODO: Eliminate this!!! - format.nAvgBytesPerSec = - format.nSamplesPerSec * format.nChannels * format.wBitsPerSample / 8; if (!audio_format_write(s, &format)) goto fail; @@ -82,7 +81,7 @@ static UINT rdpsnd_server_send_formats(RdpsndServerContext* context, wStream* s) } /** - * Function description + * Read Wave Confirm PDU (2.2.3.8) and handle callback * * @return 0 on success, otherwise a Win32 error code */ @@ -92,11 +91,8 @@ static UINT rdpsnd_server_recv_waveconfirm(RdpsndServerContext* context, wStream BYTE confirmBlockNum; UINT error = CHANNEL_RC_OK; - if (Stream_GetRemainingLength(s) < 4) - { - WLog_ERR(TAG, "not enough data in stream!"); + if (!Stream_CheckAndLogRequiredLength(TAG, s, 4)) return ERROR_INVALID_DATA; - } Stream_Read_UINT16(s, timestamp); Stream_Read_UINT8(s, confirmBlockNum); @@ -110,48 +106,68 @@ static UINT rdpsnd_server_recv_waveconfirm(RdpsndServerContext* context, wStream } /** - * Function description + * Read Training Confirm PDU (2.2.3.2) and handle callback * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpsnd_server_recv_quality_mode(RdpsndServerContext* context, wStream* s) +static UINT rdpsnd_server_recv_trainingconfirm(RdpsndServerContext* context, wStream* s) { - UINT16 quality; + UINT16 timestamp; + UINT16 packsize; + UINT error = CHANNEL_RC_OK; + if (!Stream_CheckAndLogRequiredLength(TAG, s, 4)) + return ERROR_INVALID_DATA; + + Stream_Read_UINT16(s, timestamp); + Stream_Read_UINT16(s, packsize); + + IFCALLRET(context->TrainingConfirm, error, context, timestamp, packsize); + if (error) + WLog_ERR(TAG, "context->TrainingConfirm failed with error %" PRIu32 "", error); + + return error; +} + +/** + * Read Quality Mode PDU (2.2.2.3) + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT rdpsnd_server_recv_quality_mode(RdpsndServerContext* context, wStream* s) +{ if (Stream_GetRemainingLength(s) < 4) { WLog_ERR(TAG, "not enough data in stream!"); return ERROR_INVALID_DATA; } - Stream_Read_UINT16(s, quality); - Stream_Seek_UINT16(s); // reserved - WLog_DBG(TAG, "Client requested sound quality: 0x%04" PRIX16 "", quality); + Stream_Read_UINT16(s, context->qualityMode); /* wQualityMode */ + Stream_Seek_UINT16(s); /* Reserved */ + + WLog_DBG(TAG, "Client requested sound quality: 0x%04" PRIX16 "", context->qualityMode); + return CHANNEL_RC_OK; } /** - * Function description + * Read Client Audio Formats and Version PDU (2.2.2.2) * * @return 0 on success, otherwise a Win32 error code */ static UINT rdpsnd_server_recv_formats(RdpsndServerContext* context, wStream* s) { UINT16 i, num_known_format = 0; - UINT32 flags, vol, pitch; UINT16 udpPort; BYTE lastblock; UINT error = CHANNEL_RC_OK; - if (Stream_GetRemainingLength(s) < 20) - { - WLog_ERR(TAG, "not enough data in stream!"); + if (!Stream_CheckAndLogRequiredLength(TAG, s, 20)) return ERROR_INVALID_DATA; - } - Stream_Read_UINT32(s, flags); /* dwFlags */ - Stream_Read_UINT32(s, vol); /* dwVolume */ - Stream_Read_UINT32(s, pitch); /* dwPitch */ + Stream_Read_UINT32(s, context->capsFlags); /* dwFlags */ + Stream_Read_UINT32(s, context->initialVolume); /* dwVolume */ + Stream_Read_UINT32(s, context->initialPitch); /* dwPitch */ Stream_Read_UINT16(s, udpPort); /* wDGramPort */ Stream_Read_UINT16(s, context->num_client_formats); /* wNumberOfFormats */ Stream_Read_UINT8(s, lastblock); /* cLastBlockConfirmed */ @@ -159,11 +175,8 @@ static UINT rdpsnd_server_recv_formats(RdpsndServerContext* context, wStream* s) Stream_Seek_UINT8(s); /* bPad */ /* this check is only a guess as cbSize can influence the size of a format record */ - if (Stream_GetRemainingLength(s) < context->num_client_formats * 18) - { - WLog_ERR(TAG, "not enough data in stream!"); + if (!Stream_CheckAndLogRequiredLength(TAG, s, 18ull * context->num_client_formats)) return ERROR_INVALID_DATA; - } if (!context->num_client_formats) { @@ -181,7 +194,7 @@ static UINT rdpsnd_server_recv_formats(RdpsndServerContext* context, wStream* s) for (i = 0; i < context->num_client_formats; i++) { - if (Stream_GetRemainingLength(s) < 18) + if (!Stream_CheckAndLogRequiredLength(TAG, s, 18)) { WLog_ERR(TAG, "not enough data in stream!"); error = ERROR_INVALID_DATA; @@ -228,15 +241,16 @@ static UINT rdpsnd_server_recv_formats(RdpsndServerContext* context, wStream* s) static DWORD WINAPI rdpsnd_server_thread(LPVOID arg) { - DWORD nCount, status; - HANDLE events[8]; - RdpsndServerContext* context; + DWORD nCount = 0, status; + HANDLE events[2] = { 0 }; + RdpsndServerContext* context = (RdpsndServerContext*)arg; UINT error = CHANNEL_RC_OK; - context = (RdpsndServerContext*)arg; - nCount = 0; + WINPR_ASSERT(context); events[nCount++] = context->priv->channelEvent; events[nCount++] = context->priv->StopEvent; + WINPR_ASSERT(nCount <= ARRAYSIZE(events)); + while (TRUE) { status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE); @@ -371,6 +385,51 @@ static UINT rdpsnd_server_select_format(RdpsndServerContext* context, UINT16 cli return error; } +/** + * Send Training PDU (2.2.3.1) + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT rdpsnd_server_training(RdpsndServerContext* context, UINT16 timestamp, UINT16 packsize, + BYTE* data) +{ + wStream* s = context->priv->rdpsnd_pdu; + size_t end = 0; + ULONG written; + BOOL status; + + if (!Stream_EnsureRemainingCapacity(s, 8)) + return ERROR_INTERNAL_ERROR; + + Stream_Write_UINT8(s, SNDC_TRAINING); + Stream_Write_UINT8(s, 0); + Stream_Seek_UINT16(s); + Stream_Write_UINT16(s, timestamp); + Stream_Write_UINT16(s, packsize); + + if (packsize > 0) + { + if (!Stream_EnsureRemainingCapacity(s, packsize)) + { + Stream_SetPosition(s, 0); + return ERROR_INTERNAL_ERROR; + } + + Stream_Write(s, data, packsize); + } + + end = Stream_GetPosition(s); + Stream_SetPosition(s, 2); + Stream_Write_UINT16(s, end - 4); + + status = WTSVirtualChannelWrite(context->priv->ChannelHandle, (PCHAR)Stream_Buffer(s), end, + &written); + + Stream_SetPosition(s, 0); + + return status ? CHANNEL_RC_OK : ERROR_INTERNAL_ERROR; +} + static BOOL rdpsnd_server_align_wave_pdu(wStream* s, UINT32 alignment) { size_t size; @@ -407,9 +466,6 @@ static UINT rdpsnd_server_send_wave_pdu(RdpsndServerContext* context, UINT16 wTi wStream* s = context->priv->rdpsnd_pdu; UINT error = CHANNEL_RC_OK; - if (context->selected_client_format >= context->num_client_formats) - return ERROR_INTERNAL_ERROR; - format = &context->client_formats[context->selected_client_format]; /* WaveInfo PDU */ Stream_SetPosition(s, 0); @@ -436,7 +492,6 @@ static UINT rdpsnd_server_send_wave_pdu(RdpsndServerContext* context, UINT16 wTi Stream_SetPosition(s, 2); Stream_Write_UINT16(s, end - start + 8); Stream_SetPosition(s, end); - context->block_no = (context->block_no + 1) % 256; if (!WTSVirtualChannelWrite(context->priv->ChannelHandle, (PCHAR)Stream_Buffer(s), start + 4, &written)) @@ -464,6 +519,8 @@ static UINT rdpsnd_server_send_wave_pdu(RdpsndServerContext* context, UINT16 wTi error = ERROR_INTERNAL_ERROR; } + context->block_no = (context->block_no + 1) % 256; + out: Stream_SetPosition(s, 0); context->priv->out_pending_frames = 0; @@ -476,59 +533,80 @@ static UINT rdpsnd_server_send_wave_pdu(RdpsndServerContext* context, UINT16 wTi * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpsnd_server_send_wave2_pdu(RdpsndServerContext* context, UINT16 wTimestamp) +static UINT rdpsnd_server_send_wave2_pdu(RdpsndServerContext* context, UINT16 formatNo, + const BYTE* data, size_t size, BOOL encoded, + UINT16 timestamp, UINT32 audioTimeStamp) { - size_t length; + wStream* s = context->priv->rdpsnd_pdu; size_t end = 0; - const BYTE* src; - AUDIO_FORMAT* format; ULONG written; - wStream* s = context->priv->rdpsnd_pdu; UINT error = CHANNEL_RC_OK; + BOOL status; - if (context->selected_client_format >= context->num_client_formats) - return ERROR_INTERNAL_ERROR; + if (!Stream_EnsureRemainingCapacity(s, 16)) + { + error = ERROR_INTERNAL_ERROR; + goto out; + } - format = &context->client_formats[context->selected_client_format]; - /* WaveInfo PDU */ + /* Wave2 PDU */ Stream_SetPosition(s, 0); - Stream_Write_UINT8(s, SNDC_WAVE2); /* msgType */ - Stream_Write_UINT8(s, 0); /* bPad */ - Stream_Write_UINT16(s, 0); /* BodySize */ - Stream_Write_UINT16(s, wTimestamp); /* wTimeStamp */ - Stream_Write_UINT16(s, context->selected_client_format); /* wFormatNo */ - Stream_Write_UINT8(s, context->block_no); /* cBlockNo */ - Stream_Seek(s, 3); /* bPad */ - Stream_Write_UINT32(s, wTimestamp); /* dwAudioTimeStamp */ - src = context->priv->out_buffer; - length = context->priv->out_pending_frames * context->priv->src_bytes_per_frame; + Stream_Write_UINT8(s, SNDC_WAVE2); /* msgType */ + Stream_Write_UINT8(s, 0); /* bPad */ + Stream_Write_UINT16(s, 0); /* BodySize */ + Stream_Write_UINT16(s, timestamp); /* wTimeStamp */ + Stream_Write_UINT16(s, formatNo); /* wFormatNo */ + Stream_Write_UINT8(s, context->block_no); /* cBlockNo */ + Stream_Write_UINT8(s, 0); /* bPad */ + Stream_Write_UINT8(s, 0); /* bPad */ + Stream_Write_UINT8(s, 0); /* bPad */ + Stream_Write_UINT32(s, audioTimeStamp); /* dwAudioTimeStamp */ + + if (encoded) + { + if (!Stream_EnsureRemainingCapacity(s, size)) + { + error = ERROR_INTERNAL_ERROR; + goto out; + } - if (!freerdp_dsp_encode(context->priv->dsp_context, context->src_format, src, length, s)) - error = ERROR_INTERNAL_ERROR; + Stream_Write(s, data, size); + } else { - BOOL rc; - - /* Set stream size */ - if (!rdpsnd_server_align_wave_pdu(s, format->nBlockAlign)) - return ERROR_INTERNAL_ERROR; + AUDIO_FORMAT* format; - end = Stream_GetPosition(s); - Stream_SetPosition(s, 2); - Stream_Write_UINT16(s, end - 4); - context->block_no = (context->block_no + 1) % 256; - rc = WTSVirtualChannelWrite(context->priv->ChannelHandle, (PCHAR)Stream_Buffer(s), end, - &written); + if (!freerdp_dsp_encode(context->priv->dsp_context, context->src_format, data, size, s)) + { + error = ERROR_INTERNAL_ERROR; + goto out; + } - if (!rc || (end != written)) + format = &context->client_formats[formatNo]; + if (!rdpsnd_server_align_wave_pdu(s, format->nBlockAlign)) { - WLog_ERR(TAG, - "WTSVirtualChannelWrite failed! [stream length=%" PRIdz " - written=%" PRIu32, - end, written); error = ERROR_INTERNAL_ERROR; + goto out; } } + end = Stream_GetPosition(s); + Stream_SetPosition(s, 2); + Stream_Write_UINT16(s, end - 4); + + status = WTSVirtualChannelWrite(context->priv->ChannelHandle, (PCHAR)Stream_Buffer(s), end, + &written); + + if (!status || (end != written)) + { + WLog_ERR(TAG, "WTSVirtualChannelWrite failed! [stream length=%" PRIdz " - written=%" PRIu32, + end, written); + error = ERROR_INTERNAL_ERROR; + } + + context->block_no = (context->block_no + 1) % 256; + +out: Stream_SetPosition(s, 0); context->priv->out_pending_frames = 0; return error; @@ -537,8 +615,18 @@ static UINT rdpsnd_server_send_wave2_pdu(RdpsndServerContext* context, UINT16 wT /* Wrapper function to send WAVE or WAVE2 PDU depending on client connected */ static UINT rdpsnd_server_send_audio_pdu(RdpsndServerContext* context, UINT16 wTimestamp) { + const BYTE* src; + size_t length; + + if (context->selected_client_format >= context->num_client_formats) + return ERROR_INTERNAL_ERROR; + + src = context->priv->out_buffer; + length = context->priv->out_pending_frames * context->priv->src_bytes_per_frame; + if (context->clientVersion >= CHANNEL_VERSION_WIN_8) - return rdpsnd_server_send_wave2_pdu(context, wTimestamp); + return rdpsnd_server_send_wave2_pdu(context, context->selected_client_format, src, length, + FALSE, wTimestamp, wTimestamp); else return rdpsnd_server_send_wave_pdu(context, wTimestamp); } @@ -551,8 +639,6 @@ static UINT rdpsnd_server_send_audio_pdu(RdpsndServerContext* context, UINT16 wT static UINT rdpsnd_server_send_samples(RdpsndServerContext* context, const void* buf, int nframes, UINT16 wTimestamp) { - int cframes; - int cframesize; UINT error = CHANNEL_RC_OK; EnterCriticalSection(&context->priv->lock); @@ -566,12 +652,13 @@ static UINT rdpsnd_server_send_samples(RdpsndServerContext* context, const void* while (nframes > 0) { - cframes = MIN(nframes, context->priv->out_frames - context->priv->out_pending_frames); - cframesize = cframes * context->priv->src_bytes_per_frame; + const size_t cframes = + MIN(nframes, context->priv->out_frames - context->priv->out_pending_frames); + size_t cframesize = cframes * context->priv->src_bytes_per_frame; CopyMemory(context->priv->out_buffer + (context->priv->out_pending_frames * context->priv->src_bytes_per_frame), buf, cframesize); - buf = (BYTE*)buf + cframesize; + buf = (const BYTE*)buf + cframesize; nframes -= cframes; context->priv->out_pending_frames += cframes; @@ -590,6 +677,30 @@ static UINT rdpsnd_server_send_samples(RdpsndServerContext* context, const void* return error; } +/** + * Send encoded audio samples using a Wave2 PDU. + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT rdpsnd_server_send_samples2(RdpsndServerContext* context, UINT16 formatNo, + const void* buf, size_t size, UINT16 timestamp, + UINT32 audioTimeStamp) +{ + UINT error = CHANNEL_RC_OK; + + if (context->clientVersion < CHANNEL_VERSION_WIN_8) + return ERROR_INTERNAL_ERROR; + + EnterCriticalSection(&context->priv->lock); + + error = + rdpsnd_server_send_wave2_pdu(context, formatNo, buf, size, TRUE, timestamp, audioTimeStamp); + + LeaveCriticalSection(&context->priv->lock); + + return error; +} + /** * Function description * @@ -597,21 +708,30 @@ static UINT rdpsnd_server_send_samples(RdpsndServerContext* context, const void* */ static UINT rdpsnd_server_set_volume(RdpsndServerContext* context, int left, int right) { - size_t pos; + size_t len; BOOL status; ULONG written; - wStream* s = context->priv->rdpsnd_pdu; + wStream* s; + + WINPR_ASSERT(context); + WINPR_ASSERT(context->priv); + + s = context->priv->rdpsnd_pdu; + WINPR_ASSERT(s); + + Stream_SetPosition(s, 0); + if (!Stream_EnsureRemainingCapacity(s, 8)) + return ERROR_NOT_ENOUGH_MEMORY; + Stream_Write_UINT8(s, SNDC_SETVOLUME); Stream_Write_UINT8(s, 0); - Stream_Seek_UINT16(s); + Stream_Write_UINT16(s, 4); /* Payload length */ Stream_Write_UINT16(s, left); Stream_Write_UINT16(s, right); - pos = Stream_GetPosition(s); - Stream_SetPosition(s, 2); - Stream_Write_UINT16(s, pos - 4); - Stream_SetPosition(s, pos); + len = Stream_GetPosition(s); + status = WTSVirtualChannelWrite(context->priv->ChannelHandle, (PCHAR)Stream_Buffer(s), - Stream_GetPosition(s), &written); + (ULONG)len, &written); Stream_SetPosition(s, 0); return status ? CHANNEL_RC_OK : ERROR_INTERNAL_ERROR; } @@ -741,7 +861,7 @@ static UINT rdpsnd_server_start(RdpsndServerContext* context) goto out_pdu; } - if ((error = rdpsnd_server_send_formats(context, context->priv->rdpsnd_pdu))) + if ((error = rdpsnd_server_send_formats(context))) { WLog_ERR(TAG, "rdpsnd_server_send_formats failed with error %" PRIu32 "", error); goto out_lock; @@ -790,6 +910,8 @@ static UINT rdpsnd_server_start(RdpsndServerContext* context) static UINT rdpsnd_server_stop(RdpsndServerContext* context) { UINT error = CHANNEL_RC_OK; + if (!context->priv->StopEvent) + return error; if (context->priv->ownThread) { @@ -806,13 +928,24 @@ static UINT rdpsnd_server_stop(RdpsndServerContext* context) CloseHandle(context->priv->Thread); CloseHandle(context->priv->StopEvent); + context->priv->Thread = NULL; + context->priv->StopEvent = NULL; } } DeleteCriticalSection(&context->priv->lock); if (context->priv->rdpsnd_pdu) + { Stream_Free(context->priv->rdpsnd_pdu, TRUE); + context->priv->rdpsnd_pdu = NULL; + } + + if (context->priv->ChannelHandle) + { + WTSVirtualChannelClose(context->priv->ChannelHandle); + context->priv->ChannelHandle = NULL; + } return error; } @@ -834,8 +967,11 @@ RdpsndServerContext* rdpsnd_server_context_new(HANDLE vcm) context->Stop = rdpsnd_server_stop; context->selected_client_format = 0xFFFF; context->Initialize = rdpsnd_server_initialize; + context->SendFormats = rdpsnd_server_send_formats; context->SelectFormat = rdpsnd_server_select_format; + context->Training = rdpsnd_server_training; context->SendSamples = rdpsnd_server_send_samples; + context->SendSamples2 = rdpsnd_server_send_samples2; context->SetVolume = rdpsnd_server_set_volume; context->Close = rdpsnd_server_close; context->priv = priv = (RdpsndServerPrivate*)calloc(1, sizeof(RdpsndServerPrivate)); @@ -884,8 +1020,10 @@ void rdpsnd_server_context_reset(RdpsndServerContext* context) void rdpsnd_server_context_free(RdpsndServerContext* context) { - if (context->priv->ChannelHandle) - WTSVirtualChannelClose(context->priv->ChannelHandle); + if (!context) + return; + + rdpsnd_server_stop(context); free(context->priv->out_buffer); @@ -980,6 +1118,10 @@ UINT rdpsnd_server_handle_messages(RdpsndServerContext* context) ret = rdpsnd_server_recv_waveconfirm(context, s); break; + case SNDC_TRAINING: + ret = rdpsnd_server_recv_trainingconfirm(context, s); + break; + case SNDC_FORMATS: ret = rdpsnd_server_recv_formats(context, s); @@ -990,8 +1132,6 @@ UINT rdpsnd_server_handle_messages(RdpsndServerContext* context) case SNDC_QUALITYMODE: ret = rdpsnd_server_recv_quality_mode(context, s); - Stream_SetPosition(s, - 0); /* in case the Activated callback tries to treat some messages */ if ((ret == CHANNEL_RC_OK) && (context->clientVersion >= CHANNEL_VERSION_WIN_7)) IFCALL(context->Activated, context); diff --git a/include/freerdp/server/rdpsnd.h b/include/freerdp/server/rdpsnd.h index b83a63610f74..3cdf8f687064 100644 --- a/include/freerdp/server/rdpsnd.h +++ b/include/freerdp/server/rdpsnd.h @@ -33,10 +33,18 @@ typedef UINT (*psRdpsndStart)(RdpsndServerContext* context); typedef UINT (*psRdpsndStop)(RdpsndServerContext* context); typedef UINT (*psRdpsndServerInitialize)(RdpsndServerContext* context, BOOL ownThread); +typedef UINT (*psRdpsndServerSendFormats)(RdpsndServerContext* context); typedef UINT (*psRdpsndServerSelectFormat)(RdpsndServerContext* context, UINT16 client_format_index); +typedef UINT (*psRdpsndServerTraining)(RdpsndServerContext* context, UINT16 timestamp, + UINT16 packsize, BYTE* data); +typedef UINT (*psRdpsndServerTrainingConfirm)(RdpsndServerContext* context, UINT16 timestamp, + UINT16 packsize); typedef UINT (*psRdpsndServerSendSamples)(RdpsndServerContext* context, const void* buf, int nframes, UINT16 wTimestamp); +typedef UINT (*psRdpsndServerSendSamples2)(RdpsndServerContext* context, UINT16 formatNo, + const void* buf, size_t size, UINT16 timestamp, + UINT32 audioTimeStamp); typedef UINT (*psRdpsndServerConfirmBlock)(RdpsndServerContext* context, BYTE confirmBlockNum, UINT16 wtimestamp); typedef UINT (*psRdpsndServerSetVolume)(RdpsndServerContext* context, int left, int right); @@ -122,6 +130,37 @@ struct _rdpsnd_server_context /* Server to request to use dynamic virtual channel. */ BOOL use_dynamic_virtual_channel; + + /* dwFlags in CLIENT_AUDIO_VERSION_AND_FORMATS */ + UINT32 capsFlags; + /* dwVolume in CLIENT_AUDIO_VERSION_AND_FORMATS */ + UINT32 initialVolume; + /* dwPitch in CLIENT_AUDIO_VERSION_AND_FORMATS */ + UINT32 initialPitch; + + UINT16 qualityMode; + + /** + * Send server formats and version to the client. Automatically sent, when + * opening the channel. + * Also used to restart the protocol after sending the Close PDU. + */ + psRdpsndServerSendFormats SendFormats; + /** + * Send Training PDU. + */ + psRdpsndServerTraining Training; + + /** + * Send encoded audio samples using a Wave2 PDU. + * When successful, the block_no member is incremented. + */ + psRdpsndServerSendSamples2 SendSamples2; + + /** + * Called when a TrainingConfirm PDU is received from the client. + */ + psRdpsndServerTrainingConfirm TrainingConfirm; }; #ifdef __cplusplus From 48f417127f7c32dde32e94639fa778df5a84df38 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Fri, 3 Jun 2022 08:05:54 +0200 Subject: [PATCH 199/496] Refactored rdpsnd server * Assert all input arguments * Unify stream buffer handling (cherry picked from commit 33ec06083130e45a0b5db012ff2975da8798db00) --- channels/rdpsnd/server/rdpsnd_main.c | 167 +++++++++++++++++++-------- 1 file changed, 117 insertions(+), 50 deletions(-) diff --git a/channels/rdpsnd/server/rdpsnd_main.c b/channels/rdpsnd/server/rdpsnd_main.c index 7600a3aeccbf..bc2fd4eedfc3 100644 --- a/channels/rdpsnd/server/rdpsnd_main.c +++ b/channels/rdpsnd/server/rdpsnd_main.c @@ -37,6 +37,17 @@ #include "rdpsnd_common.h" #include "rdpsnd_main.h" +static wStream* rdpsnd_server_get_buffer(RdpsndServerContext* context) +{ + wStream* s; + WINPR_ASSERT(context); + WINPR_ASSERT(context->priv); + + s = context->priv->rdpsnd_pdu; + Stream_SetPosition(s, 0); + return s; +} + /** * Send Server Audio Formats and Version PDU (2.2.2.1) * @@ -44,11 +55,15 @@ */ static UINT rdpsnd_server_send_formats(RdpsndServerContext* context) { - wStream* s = context->priv->rdpsnd_pdu; + wStream* s = rdpsnd_server_get_buffer(context); size_t pos; UINT16 i; BOOL status = FALSE; ULONG written; + + if (!Stream_EnsureRemainingCapacity(s, 24)) + return ERROR_OUTOFMEMORY; + Stream_Write_UINT8(s, SNDC_FORMATS); Stream_Write_UINT8(s, 0); Stream_Seek_UINT16(s); @@ -63,9 +78,9 @@ static UINT rdpsnd_server_send_formats(RdpsndServerContext* context) for (i = 0; i < context->num_server_formats; i++) { - AUDIO_FORMAT format = context->server_formats[i]; + const AUDIO_FORMAT* format = &context->server_formats[i]; - if (!audio_format_write(s, &format)) + if (!audio_format_write(s, format)) goto fail; } @@ -73,6 +88,8 @@ static UINT rdpsnd_server_send_formats(RdpsndServerContext* context) Stream_SetPosition(s, 2); Stream_Write_UINT16(s, pos - 4); Stream_SetPosition(s, pos); + + WINPR_ASSERT(context->priv); status = WTSVirtualChannelWrite(context->priv->ChannelHandle, (PCHAR)Stream_Buffer(s), Stream_GetPosition(s), &written); Stream_SetPosition(s, 0); @@ -91,6 +108,8 @@ static UINT rdpsnd_server_recv_waveconfirm(RdpsndServerContext* context, wStream BYTE confirmBlockNum; UINT error = CHANNEL_RC_OK; + WINPR_ASSERT(context); + if (!Stream_CheckAndLogRequiredLength(TAG, s, 4)) return ERROR_INVALID_DATA; @@ -116,6 +135,8 @@ static UINT rdpsnd_server_recv_trainingconfirm(RdpsndServerContext* context, wSt UINT16 packsize; UINT error = CHANNEL_RC_OK; + WINPR_ASSERT(context); + if (!Stream_CheckAndLogRequiredLength(TAG, s, 4)) return ERROR_INVALID_DATA; @@ -136,6 +157,8 @@ static UINT rdpsnd_server_recv_trainingconfirm(RdpsndServerContext* context, wSt */ static UINT rdpsnd_server_recv_quality_mode(RdpsndServerContext* context, wStream* s) { + WINPR_ASSERT(context); + if (Stream_GetRemainingLength(s) < 4) { WLog_ERR(TAG, "not enough data in stream!"); @@ -162,6 +185,8 @@ static UINT rdpsnd_server_recv_formats(RdpsndServerContext* context, wStream* s) BYTE lastblock; UINT error = CHANNEL_RC_OK; + WINPR_ASSERT(context); + if (!Stream_CheckAndLogRequiredLength(TAG, s, 20)) return ERROR_INVALID_DATA; @@ -194,6 +219,8 @@ static UINT rdpsnd_server_recv_formats(RdpsndServerContext* context, wStream* s) for (i = 0; i < context->num_client_formats; i++) { + AUDIO_FORMAT* format = &context->client_formats[i]; + if (!Stream_CheckAndLogRequiredLength(TAG, s, 18)) { WLog_ERR(TAG, "not enough data in stream!"); @@ -201,17 +228,17 @@ static UINT rdpsnd_server_recv_formats(RdpsndServerContext* context, wStream* s) goto out_free; } - Stream_Read_UINT16(s, context->client_formats[i].wFormatTag); - Stream_Read_UINT16(s, context->client_formats[i].nChannels); - Stream_Read_UINT32(s, context->client_formats[i].nSamplesPerSec); - Stream_Read_UINT32(s, context->client_formats[i].nAvgBytesPerSec); - Stream_Read_UINT16(s, context->client_formats[i].nBlockAlign); - Stream_Read_UINT16(s, context->client_formats[i].wBitsPerSample); - Stream_Read_UINT16(s, context->client_formats[i].cbSize); + Stream_Read_UINT16(s, format->wFormatTag); + Stream_Read_UINT16(s, format->nChannels); + Stream_Read_UINT32(s, format->nSamplesPerSec); + Stream_Read_UINT32(s, format->nAvgBytesPerSec); + Stream_Read_UINT16(s, format->nBlockAlign); + Stream_Read_UINT16(s, format->wBitsPerSample); + Stream_Read_UINT16(s, format->cbSize); - if (context->client_formats[i].cbSize > 0) + if (format->cbSize > 0) { - if (!Stream_SafeSeek(s, context->client_formats[i].cbSize)) + if (!Stream_SafeSeek(s, format->cbSize)) { WLog_ERR(TAG, "Stream_SafeSeek failed!"); error = ERROR_INTERNAL_ERROR; @@ -219,7 +246,7 @@ static UINT rdpsnd_server_recv_formats(RdpsndServerContext* context, wStream* s) } } - if (context->client_formats[i].wFormatTag != 0) + if (format->wFormatTag != 0) { // lets call this a known format // TODO: actually look through our own list of known formats @@ -245,7 +272,10 @@ static DWORD WINAPI rdpsnd_server_thread(LPVOID arg) HANDLE events[2] = { 0 }; RdpsndServerContext* context = (RdpsndServerContext*)arg; UINT error = CHANNEL_RC_OK; + WINPR_ASSERT(context); + WINPR_ASSERT(context->priv); + events[nCount++] = context->priv->channelEvent; events[nCount++] = context->priv->StopEvent; @@ -295,6 +325,9 @@ static DWORD WINAPI rdpsnd_server_thread(LPVOID arg) */ static UINT rdpsnd_server_initialize(RdpsndServerContext* context, BOOL ownThread) { + WINPR_ASSERT(context); + WINPR_ASSERT(context->priv); + context->priv->ownThread = ownThread; return context->Start(context); } @@ -311,6 +344,9 @@ static UINT rdpsnd_server_select_format(RdpsndServerContext* context, UINT16 cli AUDIO_FORMAT* format; UINT error = CHANNEL_RC_OK; + WINPR_ASSERT(context); + WINPR_ASSERT(context->priv); + if ((client_format_index >= context->num_client_formats) || (!context->src_format)) { WLog_ERR(TAG, "index %d is not correct.", client_format_index); @@ -393,10 +429,10 @@ static UINT rdpsnd_server_select_format(RdpsndServerContext* context, UINT16 cli static UINT rdpsnd_server_training(RdpsndServerContext* context, UINT16 timestamp, UINT16 packsize, BYTE* data) { - wStream* s = context->priv->rdpsnd_pdu; size_t end = 0; ULONG written; BOOL status; + wStream* s = rdpsnd_server_get_buffer(context); if (!Stream_EnsureRemainingCapacity(s, 8)) return ERROR_INTERNAL_ERROR; @@ -463,12 +499,21 @@ static UINT rdpsnd_server_send_wave_pdu(RdpsndServerContext* context, UINT16 wTi const BYTE* src; AUDIO_FORMAT* format; ULONG written; - wStream* s = context->priv->rdpsnd_pdu; UINT error = CHANNEL_RC_OK; + wStream* s = rdpsnd_server_get_buffer(context); + + if (context->selected_client_format > context->num_client_formats) + return ERROR_INTERNAL_ERROR; + + WINPR_ASSERT(context->client_formats); format = &context->client_formats[context->selected_client_format]; /* WaveInfo PDU */ Stream_SetPosition(s, 0); + + if (!Stream_EnsureRemainingCapacity(s, 16)) + return ERROR_OUTOFMEMORY; + Stream_Write_UINT8(s, SNDC_WAVE); /* msgType */ Stream_Write_UINT8(s, 0); /* bPad */ Stream_Write_UINT16(s, 0); /* BodySize */ @@ -537,11 +582,11 @@ static UINT rdpsnd_server_send_wave2_pdu(RdpsndServerContext* context, UINT16 fo const BYTE* data, size_t size, BOOL encoded, UINT16 timestamp, UINT32 audioTimeStamp) { - wStream* s = context->priv->rdpsnd_pdu; size_t end = 0; ULONG written; UINT error = CHANNEL_RC_OK; BOOL status; + wStream* s = rdpsnd_server_get_buffer(context); if (!Stream_EnsureRemainingCapacity(s, 16)) { @@ -550,7 +595,6 @@ static UINT rdpsnd_server_send_wave2_pdu(RdpsndServerContext* context, UINT16 fo } /* Wave2 PDU */ - Stream_SetPosition(s, 0); Stream_Write_UINT8(s, SNDC_WAVE2); /* msgType */ Stream_Write_UINT8(s, 0); /* bPad */ Stream_Write_UINT16(s, 0); /* BodySize */ @@ -618,6 +662,9 @@ static UINT rdpsnd_server_send_audio_pdu(RdpsndServerContext* context, UINT16 wT const BYTE* src; size_t length; + WINPR_ASSERT(context); + WINPR_ASSERT(context->priv); + if (context->selected_client_format >= context->num_client_formats) return ERROR_INTERNAL_ERROR; @@ -640,6 +687,10 @@ static UINT rdpsnd_server_send_samples(RdpsndServerContext* context, const void* UINT16 wTimestamp) { UINT error = CHANNEL_RC_OK; + + WINPR_ASSERT(context); + WINPR_ASSERT(context->priv); + EnterCriticalSection(&context->priv->lock); if (context->selected_client_format >= context->num_client_formats) @@ -688,6 +739,9 @@ static UINT rdpsnd_server_send_samples2(RdpsndServerContext* context, UINT16 for { UINT error = CHANNEL_RC_OK; + WINPR_ASSERT(context); + WINPR_ASSERT(context->priv); + if (context->clientVersion < CHANNEL_VERSION_WIN_8) return ERROR_INTERNAL_ERROR; @@ -711,15 +765,8 @@ static UINT rdpsnd_server_set_volume(RdpsndServerContext* context, int left, int size_t len; BOOL status; ULONG written; - wStream* s; + wStream* s = rdpsnd_server_get_buffer(context); - WINPR_ASSERT(context); - WINPR_ASSERT(context->priv); - - s = context->priv->rdpsnd_pdu; - WINPR_ASSERT(s); - - Stream_SetPosition(s, 0); if (!Stream_EnsureRemainingCapacity(s, 8)) return ERROR_NOT_ENOUGH_MEMORY; @@ -746,8 +793,9 @@ static UINT rdpsnd_server_close(RdpsndServerContext* context) size_t pos; BOOL status; ULONG written; - wStream* s = context->priv->rdpsnd_pdu; UINT error = CHANNEL_RC_OK; + wStream* s = rdpsnd_server_get_buffer(context); + EnterCriticalSection(&context->priv->lock); if (context->priv->out_pending_frames > 0) @@ -769,6 +817,10 @@ static UINT rdpsnd_server_close(RdpsndServerContext* context) return error; context->selected_client_format = 0xFFFF; + + if (!Stream_EnsureRemainingCapacity(s, 4)) + return ERROR_OUTOFMEMORY; + Stream_Write_UINT8(s, SNDC_CLOSE); Stream_Write_UINT8(s, 0); Stream_Seek_UINT16(s); @@ -791,10 +843,14 @@ static UINT rdpsnd_server_start(RdpsndServerContext* context) { void* buffer = NULL; DWORD bytesReturned; - RdpsndServerPrivate* priv = context->priv; + RdpsndServerPrivate* priv; UINT error = ERROR_INTERNAL_ERROR; PULONG pSessionId = NULL; + WINPR_ASSERT(context); + WINPR_ASSERT(context->priv); + + priv = context->priv; priv->SessionId = WTS_CURRENT_SESSION; if (context->use_dynamic_virtual_channel) @@ -910,6 +966,10 @@ static UINT rdpsnd_server_start(RdpsndServerContext* context) static UINT rdpsnd_server_stop(RdpsndServerContext* context) { UINT error = CHANNEL_RC_OK; + + WINPR_ASSERT(context); + WINPR_ASSERT(context->priv); + if (!context->priv->StopEvent) return error; @@ -952,15 +1012,11 @@ static UINT rdpsnd_server_stop(RdpsndServerContext* context) RdpsndServerContext* rdpsnd_server_context_new(HANDLE vcm) { - RdpsndServerContext* context; RdpsndServerPrivate* priv; - context = (RdpsndServerContext*)calloc(1, sizeof(RdpsndServerContext)); + RdpsndServerContext* context = (RdpsndServerContext*)calloc(1, sizeof(RdpsndServerContext)); if (!context) - { - WLog_ERR(TAG, "calloc failed!"); - return NULL; - } + goto fail; context->vcm = vcm; context->Start = rdpsnd_server_start; @@ -979,7 +1035,7 @@ RdpsndServerContext* rdpsnd_server_context_new(HANDLE vcm) if (!priv) { WLog_ERR(TAG, "calloc failed!"); - goto out_free; + goto fail; } priv->dsp_context = freerdp_dsp_context_new(TRUE); @@ -987,7 +1043,7 @@ RdpsndServerContext* rdpsnd_server_context_new(HANDLE vcm) if (!priv->dsp_context) { WLog_ERR(TAG, "freerdp_dsp_context_new failed!"); - goto out_free_priv; + goto fail; } priv->input_stream = Stream_New(NULL, 4); @@ -995,24 +1051,23 @@ RdpsndServerContext* rdpsnd_server_context_new(HANDLE vcm) if (!priv->input_stream) { WLog_ERR(TAG, "Stream_New failed!"); - goto out_free_dsp; + goto fail; } priv->expectedBytes = 4; priv->waitingHeader = TRUE; priv->ownThread = TRUE; return context; -out_free_dsp: - freerdp_dsp_context_free(priv->dsp_context); -out_free_priv: - free(context->priv); -out_free: - free(context); +fail: + rdpsnd_server_context_free(context); return NULL; } void rdpsnd_server_context_reset(RdpsndServerContext* context) { + WINPR_ASSERT(context); + WINPR_ASSERT(context->priv); + context->priv->expectedBytes = 4; context->priv->waitingHeader = TRUE; Stream_SetPosition(context->priv->input_stream, 0); @@ -1023,15 +1078,18 @@ void rdpsnd_server_context_free(RdpsndServerContext* context) if (!context) return; - rdpsnd_server_stop(context); + if (context->priv) + { + rdpsnd_server_stop(context); - free(context->priv->out_buffer); + free(context->priv->out_buffer); - if (context->priv->dsp_context) - freerdp_dsp_context_free(context->priv->dsp_context); + if (context->priv->dsp_context) + freerdp_dsp_context_free(context->priv->dsp_context); - if (context->priv->input_stream) - Stream_Free(context->priv->input_stream, TRUE); + if (context->priv->input_stream) + Stream_Free(context->priv->input_stream, TRUE); + } free(context->server_formats); free(context->client_formats); @@ -1041,6 +1099,9 @@ void rdpsnd_server_context_free(RdpsndServerContext* context) HANDLE rdpsnd_server_get_event_handle(RdpsndServerContext* context) { + WINPR_ASSERT(context); + WINPR_ASSERT(context->priv); + return context->priv->channelEvent; } @@ -1062,8 +1123,14 @@ UINT rdpsnd_server_handle_messages(RdpsndServerContext* context) { DWORD bytesReturned; UINT ret = CHANNEL_RC_OK; - RdpsndServerPrivate* priv = context->priv; - wStream* s = priv->input_stream; + RdpsndServerPrivate* priv; + wStream* s; + + WINPR_ASSERT(context); + WINPR_ASSERT(context->priv); + + priv = context->priv; + s = priv->input_stream; if (!WTSVirtualChannelRead(priv->ChannelHandle, 0, (PCHAR)Stream_Pointer(s), priv->expectedBytes, &bytesReturned)) From 6826d3626aa3d93169225eb46031059998489702 Mon Sep 17 00:00:00 2001 From: Pascal Nowack Date: Tue, 7 Jun 2022 06:31:48 +0200 Subject: [PATCH 200/496] core/server: Add APIs to get notified of DVC creation statuses This allows server implementations to add handling for situations, where the client side does not support them. Particularly useful for the audio output channels (static channel as fallback, when dynamic channel is not supported). --- include/freerdp/channels/wtsvc.h | 8 ++++++++ libfreerdp/core/server.c | 28 +++++++++++++++++++++++++++- libfreerdp/core/server.h | 3 +++ 3 files changed, 38 insertions(+), 1 deletion(-) diff --git a/include/freerdp/channels/wtsvc.h b/include/freerdp/channels/wtsvc.h index 31763dcc5b84..56ada09a3a3c 100644 --- a/include/freerdp/channels/wtsvc.h +++ b/include/freerdp/channels/wtsvc.h @@ -52,6 +52,9 @@ extern "C" DRDYNVC_STATE_FAILED = 3 }; + typedef BOOL (*psDVCCreationStatusCallback)(void* userdata, UINT32 channelId, + INT32 creationStatus); + /** * WTSVirtualChannelManager functions are FreeRDP extensions to the API. */ @@ -62,6 +65,9 @@ extern "C" FREERDP_API HANDLE WTSVirtualChannelManagerGetEventHandle(HANDLE hServer); FREERDP_API BOOL WTSVirtualChannelManagerIsChannelJoined(HANDLE hServer, const char* name); FREERDP_API BYTE WTSVirtualChannelManagerGetDrdynvcState(HANDLE hServer); + FREERDP_API void WTSVirtualChannelManagerSetDVCCreationCallback(HANDLE hServer, + psDVCCreationStatusCallback cb, + void* userdata); /** * Extended FreeRDP WTS functions for channel handling @@ -78,6 +84,8 @@ extern "C" FREERDP_API const char* WTSChannelGetName(freerdp_peer* client, UINT16 channel_id); FREERDP_API char** WTSGetAcceptedChannelNames(freerdp_peer* client, size_t* count); + FREERDP_API UINT32 WTSChannelGetIdByHandle(HANDLE hChannelHandle); + #ifdef __cplusplus } #endif diff --git a/libfreerdp/core/server.c b/libfreerdp/core/server.c index 39cd0e4f2ebd..6635e116add3 100644 --- a/libfreerdp/core/server.c +++ b/libfreerdp/core/server.c @@ -158,6 +158,7 @@ static BOOL wts_read_drdynvc_capabilities_response(rdpPeerChannel* channel, UINT static BOOL wts_read_drdynvc_create_response(rdpPeerChannel* channel, wStream* s, UINT32 length) { UINT32 CreationStatus; + BOOL status = TRUE; if (length < 4) return FALSE; @@ -176,7 +177,12 @@ static BOOL wts_read_drdynvc_create_response(rdpPeerChannel* channel, wStream* s channel->dvc_open_state = DVC_OPEN_STATE_SUCCEEDED; } - return TRUE; + IFCALLRET(channel->vcm->dvc_creation_status, status, channel->vcm->dvc_creation_status_userdata, + channel->channelId, (INT32)CreationStatus); + if (!status) + WLog_ERR(TAG, "vcm->dvc_creation_status failed!"); + + return status; } static BOOL wts_read_drdynvc_data_first(rdpPeerChannel* channel, wStream* s, int cbLen, @@ -578,6 +584,17 @@ BYTE WTSVirtualChannelManagerGetDrdynvcState(HANDLE hServer) return vcm->drdynvc_state; } +void WTSVirtualChannelManagerSetDVCCreationCallback(HANDLE hServer, psDVCCreationStatusCallback cb, + void* userdata) +{ + WTSVirtualChannelManager* vcm = hServer; + + WINPR_ASSERT(vcm); + + vcm->dvc_creation_status = cb; + vcm->dvc_creation_status_userdata = userdata; +} + UINT16 WTSChannelGetId(freerdp_peer* client, const char* channel_name) { rdpMcsChannel* channel; @@ -593,6 +610,15 @@ UINT16 WTSChannelGetId(freerdp_peer* client, const char* channel_name) return channel->ChannelId; } +UINT32 WTSChannelGetIdByHandle(HANDLE hChannelHandle) +{ + rdpPeerChannel* channel = hChannelHandle; + + WINPR_ASSERT(channel); + + return channel->channelId; +} + BOOL WTSChannelSetHandleByName(freerdp_peer* client, const char* channel_name, void* handle) { rdpMcsChannel* channel; diff --git a/libfreerdp/core/server.h b/libfreerdp/core/server.h index 3e2552ee38a2..ea1415c386bb 100644 --- a/libfreerdp/core/server.h +++ b/libfreerdp/core/server.h @@ -86,6 +86,9 @@ struct WTSVirtualChannelManager BYTE drdynvc_state; LONG dvc_channel_id_seq; + psDVCCreationStatusCallback dvc_creation_status; + void* dvc_creation_status_userdata; + wArrayList* dynamicVirtualChannels; }; From fcf746419fd151f547c8a1108191280361b29775 Mon Sep 17 00:00:00 2001 From: Pascal Nowack Date: Tue, 7 Jun 2022 09:29:51 +0200 Subject: [PATCH 201/496] server/rdpsnd: Add API to get notified of channel id --- channels/rdpsnd/server/rdpsnd_main.c | 12 ++++++++++++ include/freerdp/server/rdpsnd.h | 8 ++++++++ 2 files changed, 20 insertions(+) diff --git a/channels/rdpsnd/server/rdpsnd_main.c b/channels/rdpsnd/server/rdpsnd_main.c index bc2fd4eedfc3..363fac7143f3 100644 --- a/channels/rdpsnd/server/rdpsnd_main.c +++ b/channels/rdpsnd/server/rdpsnd_main.c @@ -855,6 +855,9 @@ static UINT rdpsnd_server_start(RdpsndServerContext* context) if (context->use_dynamic_virtual_channel) { + UINT32 channelId; + BOOL status = TRUE; + if (WTSQuerySessionInformationA(context->vcm, WTS_CURRENT_SESSION, WTSSessionId, (LPSTR*)&pSessionId, &bytesReturned)) { @@ -867,6 +870,15 @@ static UINT rdpsnd_server_start(RdpsndServerContext* context) WLog_ERR(TAG, "Open audio dynamic virtual channel (AUDIO_PLAYBACK_DVC) failed!"); return ERROR_INTERNAL_ERROR; } + + channelId = WTSChannelGetIdByHandle(priv->ChannelHandle); + + IFCALLRET(context->ChannelIdAssigned, status, context, channelId); + if (!status) + { + WLog_ERR(TAG, "context->ChannelIdAssigned failed!"); + goto out_close; + } } else { diff --git a/include/freerdp/server/rdpsnd.h b/include/freerdp/server/rdpsnd.h index 3cdf8f687064..a8cb510ce2f1 100644 --- a/include/freerdp/server/rdpsnd.h +++ b/include/freerdp/server/rdpsnd.h @@ -32,6 +32,8 @@ typedef struct _rdpsnd_server_private RdpsndServerPrivate; typedef UINT (*psRdpsndStart)(RdpsndServerContext* context); typedef UINT (*psRdpsndStop)(RdpsndServerContext* context); +typedef BOOL (*psRdpsndChannelIdAssigned)(RdpsndServerContext* context, UINT32 channelId); + typedef UINT (*psRdpsndServerInitialize)(RdpsndServerContext* context, BOOL ownThread); typedef UINT (*psRdpsndServerSendFormats)(RdpsndServerContext* context); typedef UINT (*psRdpsndServerSelectFormat)(RdpsndServerContext* context, @@ -161,6 +163,12 @@ struct _rdpsnd_server_context * Called when a TrainingConfirm PDU is received from the client. */ psRdpsndServerTrainingConfirm TrainingConfirm; + + /** + * Callback, when the channel got its id assigned. + * Only called, when use_dynamic_virtual_channel=TRUE. + */ + psRdpsndChannelIdAssigned ChannelIdAssigned; }; #ifdef __cplusplus From d8ed0ff1b8310d37203dc1651efbaebc17a12b80 Mon Sep 17 00:00:00 2001 From: Pascal Nowack Date: Mon, 6 Jun 2022 14:16:15 +0200 Subject: [PATCH 202/496] server: Add channel handling for telemetry channel --- channels/server/channels.c | 4 + channels/telemetry/CMakeLists.txt | 23 ++ channels/telemetry/ChannelOptions.cmake | 12 + channels/telemetry/server/CMakeLists.txt | 26 ++ channels/telemetry/server/telemetry_main.c | 443 +++++++++++++++++++++ config.h.in | 3 + include/freerdp/channels/telemetry.h | 38 ++ include/freerdp/server/telemetry.h | 108 +++++ 8 files changed, 657 insertions(+) create mode 100644 channels/telemetry/CMakeLists.txt create mode 100644 channels/telemetry/ChannelOptions.cmake create mode 100644 channels/telemetry/server/CMakeLists.txt create mode 100644 channels/telemetry/server/telemetry_main.c create mode 100644 include/freerdp/channels/telemetry.h create mode 100644 include/freerdp/server/telemetry.h diff --git a/channels/server/channels.c b/channels/server/channels.c index 3714c5ec75ee..8d81269c60e6 100644 --- a/channels/server/channels.c +++ b/channels/server/channels.c @@ -50,6 +50,7 @@ #include #include #include +#include #include #include @@ -71,6 +72,7 @@ void freerdp_channels_dummy(void) RemdeskServerContext* remdesk; EncomspServerContext* encomsp; RailServerContext* rail; + TelemetryServerContext* telemetry; RdpgfxServerContext* rdpgfx; DispServerContext* disp; audin = audin_server_context_new(NULL); @@ -93,6 +95,8 @@ void freerdp_channels_dummy(void) encomsp_server_context_free(encomsp); rail = rail_server_context_new(NULL); rail_server_context_free(rail); + telemetry = telemetry_server_context_new(NULL); + telemetry_server_context_free(telemetry); rdpgfx = rdpgfx_server_context_new(NULL); rdpgfx_server_context_free(rdpgfx); disp = disp_server_context_new(NULL); diff --git a/channels/telemetry/CMakeLists.txt b/channels/telemetry/CMakeLists.txt new file mode 100644 index 000000000000..b2d5e30c72e9 --- /dev/null +++ b/channels/telemetry/CMakeLists.txt @@ -0,0 +1,23 @@ +# FreeRDP: A Remote Desktop Protocol Implementation +# FreeRDP cmake build script +# +# Copyright 2022 Armin Novak +# Copyright 2022 Thincast Technologies GmbH +# +# 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. + +define_channel("telemetry") + +if(WITH_SERVER_CHANNELS) + add_channel_server(${MODULE_PREFIX} ${CHANNEL_NAME}) +endif() diff --git a/channels/telemetry/ChannelOptions.cmake b/channels/telemetry/ChannelOptions.cmake new file mode 100644 index 000000000000..1b9e3917cbad --- /dev/null +++ b/channels/telemetry/ChannelOptions.cmake @@ -0,0 +1,12 @@ + +set(OPTION_DEFAULT OFF) +set(OPTION_CLIENT_DEFAULT OFF) +set(OPTION_SERVER_DEFAULT ON) + +define_channel_options(NAME "telemetry" TYPE "dynamic" + DESCRIPTION "Telemetry Virtual Channel Extension" + SPECIFICATIONS "[MS-RDPET]" + DEFAULT ${OPTION_DEFAULT}) + +define_channel_server_options(${OPTION_SERVER_DEFAULT}) + diff --git a/channels/telemetry/server/CMakeLists.txt b/channels/telemetry/server/CMakeLists.txt new file mode 100644 index 000000000000..75be8ac9ec8b --- /dev/null +++ b/channels/telemetry/server/CMakeLists.txt @@ -0,0 +1,26 @@ +# FreeRDP: A Remote Desktop Protocol Implementation +# FreeRDP cmake build script +# +# Copyright 2022 Pascal Nowack +# +# 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. + +define_channel_server("telemetry") + +set(${MODULE_PREFIX}_SRCS + telemetry_main.c) + +add_channel_server_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE "DVCPluginEntry") + +target_link_libraries(${MODULE_NAME} freerdp) +set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Channels/${CHANNEL_NAME}/Server") diff --git a/channels/telemetry/server/telemetry_main.c b/channels/telemetry/server/telemetry_main.c new file mode 100644 index 000000000000..ec276ff8310d --- /dev/null +++ b/channels/telemetry/server/telemetry_main.c @@ -0,0 +1,443 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Advanced Input Virtual Channel Extension + * + * Copyright 2022 Pascal Nowack + * + * 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include + +#define TAG CHANNELS_TAG("telemetry.server") + +typedef enum +{ + TELEMETRY_INITIAL, + TELEMETRY_OPENED, +} eTelemetryChannelState; + +typedef struct +{ + TelemetryServerContext context; + + HANDLE stopEvent; + + HANDLE thread; + void* telemetry_channel; + + DWORD SessionId; + + BOOL isOpened; + BOOL externalThread; + + /* Channel state */ + eTelemetryChannelState state; + + wStream* buffer; +} telemetry_server; + +static UINT telemetry_server_initialize(TelemetryServerContext* context, BOOL externalThread) +{ + UINT error = CHANNEL_RC_OK; + telemetry_server* telemetry = (telemetry_server*)context; + + WINPR_ASSERT(telemetry); + + if (telemetry->isOpened) + { + WLog_WARN(TAG, "Application error: TELEMETRY channel already initialized, " + "calling in this state is not possible!"); + return ERROR_INVALID_STATE; + } + + telemetry->externalThread = externalThread; + + return error; +} + +static UINT telemetry_server_open_channel(telemetry_server* telemetry) +{ + TelemetryServerContext* context = &telemetry->context; + DWORD Error = ERROR_SUCCESS; + HANDLE hEvent; + DWORD BytesReturned = 0; + PULONG pSessionId = NULL; + UINT32 channelId; + BOOL status = TRUE; + + WINPR_ASSERT(telemetry); + + if (WTSQuerySessionInformationA(telemetry->context.vcm, WTS_CURRENT_SESSION, WTSSessionId, + (LPSTR*)&pSessionId, &BytesReturned) == FALSE) + { + WLog_ERR(TAG, "WTSQuerySessionInformationA failed!"); + return ERROR_INTERNAL_ERROR; + } + + telemetry->SessionId = (DWORD)*pSessionId; + WTSFreeMemory(pSessionId); + hEvent = WTSVirtualChannelManagerGetEventHandle(telemetry->context.vcm); + + if (WaitForSingleObject(hEvent, 1000) == WAIT_FAILED) + { + Error = GetLastError(); + WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "!", Error); + return Error; + } + + telemetry->telemetry_channel = WTSVirtualChannelOpenEx( + telemetry->SessionId, TELEMETRY_DVC_CHANNEL_NAME, WTS_CHANNEL_OPTION_DYNAMIC); + if (!telemetry->telemetry_channel) + { + Error = GetLastError(); + WLog_ERR(TAG, "WTSVirtualChannelOpenEx failed with error %" PRIu32 "!", Error); + return Error; + } + + channelId = WTSChannelGetIdByHandle(telemetry->telemetry_channel); + + IFCALLRET(context->ChannelIdAssigned, status, context, channelId); + if (!status) + { + WLog_ERR(TAG, "context->ChannelIdAssigned failed!"); + return ERROR_INTERNAL_ERROR; + } + + return Error; +} + +static UINT telemetry_server_recv_rdp_telemetry_pdu(TelemetryServerContext* context, wStream* s) +{ + TELEMETRY_RDP_TELEMETRY_PDU pdu; + UINT error = CHANNEL_RC_OK; + + if (Stream_GetRemainingLength(s) < 16) + { + WLog_ERR(TAG, "telemetry_server_recv_rdp_telemetry_pdu: Not enough data!"); + return ERROR_NO_DATA; + } + + Stream_Read_UINT32(s, pdu.PromptForCredentialsMillis); + Stream_Read_UINT32(s, pdu.PromptForCredentialsDoneMillis); + Stream_Read_UINT32(s, pdu.GraphicsChannelOpenedMillis); + Stream_Read_UINT32(s, pdu.FirstGraphicsReceivedMillis); + + IFCALLRET(context->RdpTelemetry, error, context, &pdu); + if (error) + WLog_ERR(TAG, "context->RdpTelemetry failed with error %" PRIu32 "", error); + + return error; +} + +static UINT telemetry_process_message(telemetry_server* telemetry) +{ + BOOL rc; + UINT error = ERROR_INTERNAL_ERROR; + ULONG BytesReturned; + BYTE MessageId; + BYTE Length; + wStream* s; + + WINPR_ASSERT(telemetry); + WINPR_ASSERT(telemetry->telemetry_channel); + + s = telemetry->buffer; + WINPR_ASSERT(s); + + Stream_SetPosition(s, 0); + rc = WTSVirtualChannelRead(telemetry->telemetry_channel, 0, NULL, 0, &BytesReturned); + if (!rc) + goto out; + + if (BytesReturned < 1) + { + error = CHANNEL_RC_OK; + goto out; + } + + if (!Stream_EnsureRemainingCapacity(s, BytesReturned)) + { + WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!"); + error = CHANNEL_RC_NO_MEMORY; + goto out; + } + + if (WTSVirtualChannelRead(telemetry->telemetry_channel, 0, (PCHAR)Stream_Buffer(s), + (ULONG)Stream_Capacity(s), &BytesReturned) == FALSE) + { + WLog_ERR(TAG, "WTSVirtualChannelRead failed!"); + goto out; + } + + if (!Stream_CheckAndLogRequiredLength(TAG, s, 2)) + return ERROR_NO_DATA; + + Stream_SetLength(s, BytesReturned); + Stream_Read_UINT8(s, MessageId); + Stream_Read_UINT8(s, Length); + + switch (MessageId) + { + case 0x01: + error = telemetry_server_recv_rdp_telemetry_pdu(&telemetry->context, s); + break; + default: + WLog_ERR(TAG, "telemetry_process_message: unknown MessageId %" PRIu8 "", MessageId); + break; + } + +out: + if (error) + WLog_ERR(TAG, "Response failed with error %" PRIu32 "!", error); + + return error; +} + +static UINT telemetry_server_context_poll_int(TelemetryServerContext* context) +{ + telemetry_server* telemetry = (telemetry_server*)context; + UINT error = ERROR_INTERNAL_ERROR; + + WINPR_ASSERT(telemetry); + + switch (telemetry->state) + { + case TELEMETRY_INITIAL: + error = telemetry_server_open_channel(telemetry); + if (error) + WLog_ERR(TAG, "telemetry_server_open_channel failed with error %" PRIu32 "!", + error); + else + telemetry->state = TELEMETRY_OPENED; + break; + case TELEMETRY_OPENED: + error = telemetry_process_message(telemetry); + break; + } + + return error; +} + +static HANDLE telemetry_server_get_channel_handle(telemetry_server* telemetry) +{ + void* buffer = NULL; + DWORD BytesReturned = 0; + HANDLE ChannelEvent = NULL; + + WINPR_ASSERT(telemetry); + + if (WTSVirtualChannelQuery(telemetry->telemetry_channel, WTSVirtualEventHandle, &buffer, + &BytesReturned) == TRUE) + { + if (BytesReturned == sizeof(HANDLE)) + CopyMemory(&ChannelEvent, buffer, sizeof(HANDLE)); + + WTSFreeMemory(buffer); + } + + return ChannelEvent; +} + +static DWORD WINAPI telemetry_server_thread_func(LPVOID arg) +{ + DWORD nCount; + HANDLE events[2] = { 0 }; + telemetry_server* telemetry = (telemetry_server*)arg; + UINT error = CHANNEL_RC_OK; + DWORD status; + + WINPR_ASSERT(telemetry); + + nCount = 0; + events[nCount++] = telemetry->stopEvent; + + while ((error == CHANNEL_RC_OK) && (WaitForSingleObject(events[0], 0) != WAIT_OBJECT_0)) + { + switch (telemetry->state) + { + case TELEMETRY_INITIAL: + error = telemetry_server_context_poll_int(&telemetry->context); + if (error == CHANNEL_RC_OK) + { + events[1] = telemetry_server_get_channel_handle(telemetry); + nCount = 2; + } + break; + case TELEMETRY_OPENED: + status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE); + switch (status) + { + case WAIT_OBJECT_0: + break; + case WAIT_OBJECT_0 + 1: + case WAIT_TIMEOUT: + error = telemetry_server_context_poll_int(&telemetry->context); + break; + + case WAIT_FAILED: + default: + error = ERROR_INTERNAL_ERROR; + break; + } + break; + } + } + + WTSVirtualChannelClose(telemetry->telemetry_channel); + telemetry->telemetry_channel = NULL; + + if (error && telemetry->context.rdpcontext) + setChannelError(telemetry->context.rdpcontext, error, + "telemetry_server_thread_func reported an error"); + + ExitThread(error); + return error; +} + +static UINT telemetry_server_open(TelemetryServerContext* context) +{ + telemetry_server* telemetry = (telemetry_server*)context; + + WINPR_ASSERT(telemetry); + + if (!telemetry->externalThread && (telemetry->thread == NULL)) + { + telemetry->stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + if (!telemetry->stopEvent) + { + WLog_ERR(TAG, "CreateEvent failed!"); + return ERROR_INTERNAL_ERROR; + } + + telemetry->thread = CreateThread(NULL, 0, telemetry_server_thread_func, telemetry, 0, NULL); + if (!telemetry->thread) + { + WLog_ERR(TAG, "CreateThread failed!"); + CloseHandle(telemetry->stopEvent); + telemetry->stopEvent = NULL; + return ERROR_INTERNAL_ERROR; + } + } + telemetry->isOpened = TRUE; + + return CHANNEL_RC_OK; +} + +static UINT telemetry_server_close(TelemetryServerContext* context) +{ + UINT error = CHANNEL_RC_OK; + telemetry_server* telemetry = (telemetry_server*)context; + + WINPR_ASSERT(telemetry); + + if (!telemetry->externalThread && telemetry->thread) + { + SetEvent(telemetry->stopEvent); + + if (WaitForSingleObject(telemetry->thread, INFINITE) == WAIT_FAILED) + { + error = GetLastError(); + WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "", error); + return error; + } + + CloseHandle(telemetry->thread); + CloseHandle(telemetry->stopEvent); + telemetry->thread = NULL; + telemetry->stopEvent = NULL; + } + if (telemetry->externalThread) + { + if (telemetry->state != TELEMETRY_INITIAL) + { + WTSVirtualChannelClose(telemetry->telemetry_channel); + telemetry->telemetry_channel = NULL; + telemetry->state = TELEMETRY_INITIAL; + } + } + telemetry->isOpened = FALSE; + + return error; +} + +static UINT telemetry_server_context_poll(TelemetryServerContext* context) +{ + telemetry_server* telemetry = (telemetry_server*)context; + + WINPR_ASSERT(telemetry); + + if (!telemetry->externalThread) + return ERROR_INTERNAL_ERROR; + + return telemetry_server_context_poll_int(context); +} + +static BOOL telemetry_server_context_handle(TelemetryServerContext* context, HANDLE* handle) +{ + telemetry_server* telemetry = (telemetry_server*)context; + + WINPR_ASSERT(telemetry); + WINPR_ASSERT(handle); + + if (!telemetry->externalThread) + return FALSE; + if (telemetry->state == TELEMETRY_INITIAL) + return FALSE; + + *handle = telemetry_server_get_channel_handle(telemetry); + + return TRUE; +} + +TelemetryServerContext* telemetry_server_context_new(HANDLE vcm) +{ + telemetry_server* telemetry = (telemetry_server*)calloc(1, sizeof(telemetry_server)); + + if (!telemetry) + return NULL; + + telemetry->context.vcm = vcm; + telemetry->context.Initialize = telemetry_server_initialize; + telemetry->context.Open = telemetry_server_open; + telemetry->context.Close = telemetry_server_close; + telemetry->context.Poll = telemetry_server_context_poll; + telemetry->context.ChannelHandle = telemetry_server_context_handle; + + telemetry->buffer = Stream_New(NULL, 4096); + if (!telemetry->buffer) + goto fail; + + return &telemetry->context; +fail: + telemetry_server_context_free(&telemetry->context); + return NULL; +} + +void telemetry_server_context_free(TelemetryServerContext* context) +{ + telemetry_server* telemetry = (telemetry_server*)context; + + if (telemetry) + { + telemetry_server_close(context); + Stream_Free(telemetry->buffer, TRUE); + } + + free(telemetry); +} diff --git a/config.h.in b/config.h.in index 1f35d682b106..fdff6d90f2d9 100644 --- a/config.h.in +++ b/config.h.in @@ -132,6 +132,9 @@ #cmakedefine CHANNEL_SSHAGENT #cmakedefine CHANNEL_SSHAGENT_CLIENT #cmakedefine CHANNEL_SSHAGENT_SERVER +#cmakedefine CHANNEL_TELEMETRY +#cmakedefine CHANNEL_TELEMETRY_CLIENT +#cmakedefine CHANNEL_TELEMETRY_SERVER #cmakedefine CHANNEL_TSMF #cmakedefine CHANNEL_TSMF_CLIENT #cmakedefine CHANNEL_TSMF_SERVER diff --git a/include/freerdp/channels/telemetry.h b/include/freerdp/channels/telemetry.h new file mode 100644 index 000000000000..a92d97d39b62 --- /dev/null +++ b/include/freerdp/channels/telemetry.h @@ -0,0 +1,38 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Audio Input Redirection Virtual Channel + * + * Copyright 2022 Pascal Nowack + * + * 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_CHANNEL_TELEMETRY_H +#define FREERDP_CHANNEL_TELEMETRY_H + +#include +#include +#include + +#define TELEMETRY_DVC_CHANNEL_NAME "Microsoft::Windows::RDS::Telemetry" + +struct _TELEMETRY_RDP_TELEMETRY_PDU +{ + UINT32 PromptForCredentialsMillis; + UINT32 PromptForCredentialsDoneMillis; + UINT32 GraphicsChannelOpenedMillis; + UINT32 FirstGraphicsReceivedMillis; +}; +typedef struct _TELEMETRY_RDP_TELEMETRY_PDU TELEMETRY_RDP_TELEMETRY_PDU; + +#endif /* FREERDP_CHANNEL_TELEMETRY_H */ diff --git a/include/freerdp/server/telemetry.h b/include/freerdp/server/telemetry.h new file mode 100644 index 000000000000..04f72ad2a6e1 --- /dev/null +++ b/include/freerdp/server/telemetry.h @@ -0,0 +1,108 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Telemetry Virtual Channel Extension + * + * Copyright 2022 Pascal Nowack + * + * 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_CHANNEL_TELEMETRY_SERVER_TELEMETRY_H +#define FREERDP_CHANNEL_TELEMETRY_SERVER_TELEMETRY_H + +#include +#include + +typedef struct _telemetry_server_context TelemetryServerContext; + +typedef UINT (*psTelemetryServerOpen)(TelemetryServerContext* context); +typedef UINT (*psTelemetryServerClose)(TelemetryServerContext* context); + +typedef BOOL (*psTelemetryServerChannelIdAssigned)(TelemetryServerContext* context, + UINT32 channelId); + +typedef UINT (*psTelemetryServerInitialize)(TelemetryServerContext* context, BOOL externalThread); +typedef UINT (*psTelemetryServerPoll)(TelemetryServerContext* context); +typedef BOOL (*psTelemetryServerChannelHandle)(TelemetryServerContext* context, HANDLE* handle); + +typedef UINT (*psTelemetryServerRdpTelemetry)(TelemetryServerContext* context, + const TELEMETRY_RDP_TELEMETRY_PDU* rdpTelemetry); + +struct _telemetry_server_context +{ + HANDLE vcm; + + /* Server self-defined pointer. */ + void* userdata; + + /*** APIs called by the server. ***/ + + /** + * Optional: Set thread handling. + * When externalThread=TRUE, the application is responsible to call + * Poll() periodically to process channel events. + * + * Defaults to externalThread=FALSE + */ + psTelemetryServerInitialize Initialize; + + /** + * Open the telemetry channel. + */ + psTelemetryServerOpen Open; + + /** + * Close the telemetry channel. + */ + psTelemetryServerClose Close; + + /** + * Poll + * When externalThread=TRUE, call Poll() periodically from your main loop. + * If externalThread=FALSE do not call. + */ + psTelemetryServerPoll Poll; + + /** + * Retrieve the channel handle for use in conjunction with Poll(). + * If externalThread=FALSE do not call. + */ + psTelemetryServerChannelHandle ChannelHandle; + + /*** Callbacks registered by the server. ***/ + + /** + * Callback, when the channel got its id assigned + */ + psTelemetryServerChannelIdAssigned ChannelIdAssigned; + /** + * Callback for the RDP Telemetry PDU. + */ + psTelemetryServerRdpTelemetry RdpTelemetry; + + rdpContext* rdpcontext; +}; + +#ifdef __cplusplus +extern "C" +{ +#endif + + FREERDP_API TelemetryServerContext* telemetry_server_context_new(HANDLE vcm); + FREERDP_API void telemetry_server_context_free(TelemetryServerContext* context); + +#ifdef __cplusplus +} +#endif + +#endif /* FREERDP_CHANNEL_TELEMETRY_SERVER_TELEMETRY_H */ From b27efe5a62dc9dfd8585cb68e469cccbd57375f6 Mon Sep 17 00:00:00 2001 From: Pascal Nowack Date: Wed, 8 Jun 2022 13:22:09 +0200 Subject: [PATCH 203/496] audin/server: Do not overwrite values of the server audio formats It just makes the usage of codecs impossible. --- channels/audin/server/audin.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/channels/audin/server/audin.c b/channels/audin/server/audin.c index e5c51bbf221d..ef1ff28ff88a 100644 --- a/channels/audin/server/audin.c +++ b/channels/audin/server/audin.c @@ -162,9 +162,6 @@ static UINT audin_server_send_formats(audin_server* audin, wStream* s) for (i = 0; i < audin->context.num_server_formats; i++) { AUDIO_FORMAT format = audin->context.server_formats[i]; - // TODO: Eliminate this - format.nAvgBytesPerSec = - format.nSamplesPerSec * format.nChannels * format.wBitsPerSample / 8; if (!audio_format_write(s, &format)) { From 3545728e5e23ab0be602e107685e182eac7122b4 Mon Sep 17 00:00:00 2001 From: Pascal Nowack Date: Wed, 8 Jun 2022 13:35:52 +0200 Subject: [PATCH 204/496] channels/server: Add APIs for DVCs to get notified of channel id This allows server implementations to watch these channel ids for their creation statuses. --- channels/ainput/server/ainput_main.c | 14 ++++++++++++++ channels/audin/server/audin.c | 11 +++++++++++ channels/disp/server/disp_main.c | 12 ++++++++++++ channels/echo/server/echo_main.c | 14 ++++++++++++++ channels/rdpei/server/rdpei_main.c | 11 +++++++++++ channels/rdpgfx/server/rdpgfx_main.c | 11 +++++++++++ include/freerdp/server/ainput.h | 7 +++++++ include/freerdp/server/audin.h | 7 +++++++ include/freerdp/server/disp.h | 7 +++++++ include/freerdp/server/echo.h | 7 +++++++ include/freerdp/server/rdpei.h | 5 +++++ include/freerdp/server/rdpgfx.h | 7 +++++++ 12 files changed, 113 insertions(+) diff --git a/channels/ainput/server/ainput_main.c b/channels/ainput/server/ainput_main.c index bc1737ee1846..805928f27002 100644 --- a/channels/ainput/server/ainput_main.c +++ b/channels/ainput/server/ainput_main.c @@ -122,7 +122,21 @@ static UINT ainput_server_open_channel(ainput_server* ainput) WTS_CHANNEL_OPTION_DYNAMIC); if (ainput->ainput_channel) + { + UINT32 channelId; + BOOL status = TRUE; + + channelId = WTSChannelGetIdByHandle(ainput->ainput_channel); + + IFCALLRET(ainput->context.ChannelIdAssigned, status, &ainput->context, channelId); + if (!status) + { + WLog_ERR(TAG, "context->ChannelIdAssigned failed!"); + return ERROR_INTERNAL_ERROR; + } + break; + } Error = GetLastError(); diff --git a/channels/audin/server/audin.c b/channels/audin/server/audin.c index ef1ff28ff88a..8252236f8d8e 100644 --- a/channels/audin/server/audin.c +++ b/channels/audin/server/audin.c @@ -557,6 +557,8 @@ static BOOL audin_server_open(audin_server_context* context) PULONG pSessionId = NULL; DWORD BytesReturned = 0; audin->SessionId = WTS_CURRENT_SESSION; + UINT32 channelId; + BOOL status = TRUE; if (WTSQuerySessionInformationA(context->vcm, WTS_CURRENT_SESSION, WTSSessionId, (LPSTR*)&pSessionId, &BytesReturned)) @@ -574,6 +576,15 @@ static BOOL audin_server_open(audin_server_context* context) return FALSE; } + channelId = WTSChannelGetIdByHandle(audin->audin_channel); + + IFCALLRET(context->ChannelIdAssigned, status, context, channelId); + if (!status) + { + WLog_ERR(TAG, "context->ChannelIdAssigned failed!"); + return ERROR_INTERNAL_ERROR; + } + if (!(audin->stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL))) { WLog_ERR(TAG, "CreateEvent failed!"); diff --git a/channels/disp/server/disp_main.c b/channels/disp/server/disp_main.c index 64e96c301aaa..9caec45e7e41 100644 --- a/channels/disp/server/disp_main.c +++ b/channels/disp/server/disp_main.c @@ -378,6 +378,8 @@ static UINT disp_server_open(DispServerContext* context) void* buffer; buffer = NULL; priv->SessionId = WTS_CURRENT_SESSION; + UINT32 channelId; + BOOL status = TRUE; if (WTSQuerySessionInformationA(context->vcm, WTS_CURRENT_SESSION, WTSSessionId, (LPSTR*)&pSessionId, &BytesReturned) == FALSE) @@ -399,6 +401,16 @@ static UINT disp_server_open(DispServerContext* context) goto out_close; } + channelId = WTSChannelGetIdByHandle(priv->disp_channel); + + IFCALLRET(context->ChannelIdAssigned, status, context, channelId); + if (!status) + { + WLog_ERR(TAG, "context->ChannelIdAssigned failed!"); + rc = ERROR_INTERNAL_ERROR; + goto out_close; + } + /* Query for channel event handle */ if (!WTSVirtualChannelQuery(priv->disp_channel, WTSVirtualEventHandle, &buffer, &BytesReturned) || diff --git a/channels/echo/server/echo_main.c b/channels/echo/server/echo_main.c index 55e2fa237c66..1da2894d3213 100644 --- a/channels/echo/server/echo_main.c +++ b/channels/echo/server/echo_main.c @@ -91,7 +91,21 @@ static UINT echo_server_open_channel(echo_server* echo) WTSVirtualChannelOpenEx(echo->SessionId, "ECHO", WTS_CHANNEL_OPTION_DYNAMIC); if (echo->echo_channel) + { + UINT32 channelId; + BOOL status = TRUE; + + channelId = WTSChannelGetIdByHandle(echo->echo_channel); + + IFCALLRET(echo->context.ChannelIdAssigned, status, &echo->context, channelId); + if (!status) + { + WLog_ERR(TAG, "context->ChannelIdAssigned failed!"); + return ERROR_INTERNAL_ERROR; + } + break; + } Error = GetLastError(); diff --git a/channels/rdpei/server/rdpei_main.c b/channels/rdpei/server/rdpei_main.c index 1e2dfe2427cb..433b2cf10e42 100644 --- a/channels/rdpei/server/rdpei_main.c +++ b/channels/rdpei/server/rdpei_main.c @@ -99,6 +99,8 @@ UINT rdpei_server_init(RdpeiServerContext* context) void* buffer = NULL; DWORD bytesReturned; RdpeiServerPrivate* priv = context->priv; + UINT32 channelId; + BOOL status = TRUE; priv->channelHandle = WTSVirtualChannelOpenEx(WTS_CURRENT_SESSION, RDPEI_DVC_CHANNEL_NAME, WTS_CHANNEL_OPTION_DYNAMIC); @@ -108,6 +110,15 @@ UINT rdpei_server_init(RdpeiServerContext* context) return CHANNEL_RC_INITIALIZATION_ERROR; } + channelId = WTSChannelGetIdByHandle(priv->channelHandle); + + IFCALLRET(context->onChannelIdAssigned, status, context, channelId); + if (!status) + { + WLog_ERR(TAG, "context->onChannelIdAssigned failed!"); + goto out_close; + } + if (!WTSVirtualChannelQuery(priv->channelHandle, WTSVirtualEventHandle, &buffer, &bytesReturned) || (bytesReturned != sizeof(HANDLE))) diff --git a/channels/rdpgfx/server/rdpgfx_main.c b/channels/rdpgfx/server/rdpgfx_main.c index 306cc1c44841..283bb880d6de 100644 --- a/channels/rdpgfx/server/rdpgfx_main.c +++ b/channels/rdpgfx/server/rdpgfx_main.c @@ -1428,6 +1428,8 @@ static BOOL rdpgfx_server_open(RdpgfxServerContext* context) PULONG pSessionId = NULL; DWORD BytesReturned = 0; priv->SessionId = WTS_CURRENT_SESSION; + UINT32 channelId; + BOOL status = TRUE; if (WTSQuerySessionInformationA(context->vcm, WTS_CURRENT_SESSION, WTSSessionId, (LPSTR*)&pSessionId, &BytesReturned) == FALSE) @@ -1447,6 +1449,15 @@ static BOOL rdpgfx_server_open(RdpgfxServerContext* context) return FALSE; } + channelId = WTSChannelGetIdByHandle(priv->rdpgfx_channel); + + IFCALLRET(context->ChannelIdAssigned, status, context, channelId); + if (!status) + { + WLog_ERR(TAG, "context->ChannelIdAssigned failed!"); + goto out_close; + } + /* Query for channel event handle */ if (!WTSVirtualChannelQuery(priv->rdpgfx_channel, WTSVirtualEventHandle, &buffer, &BytesReturned) || diff --git a/include/freerdp/server/ainput.h b/include/freerdp/server/ainput.h index 39acad118e63..588504f76f02 100644 --- a/include/freerdp/server/ainput.h +++ b/include/freerdp/server/ainput.h @@ -33,6 +33,8 @@ typedef enum AINPUT_SERVER_OPEN_RESULT typedef struct _ainput_server_context ainput_server_context; +typedef BOOL (*psAInputChannelIdAssigned)(ainput_server_context* context, UINT32 channelId); + typedef UINT (*psAInputServerInitialize)(ainput_server_context* context, BOOL externalThread); typedef UINT (*psAInputServerPoll)(ainput_server_context* context); typedef BOOL (*psAInputServerChannelHandle)(ainput_server_context* context, HANDLE* handle); @@ -97,6 +99,11 @@ struct _ainput_server_context psAInputServerMouseEvent MouseEvent; rdpContext* rdpcontext; + + /** + * Callback, when the channel got its id assigned. + */ + psAInputChannelIdAssigned ChannelIdAssigned; }; #ifdef __cplusplus diff --git a/include/freerdp/server/audin.h b/include/freerdp/server/audin.h index a8da17d27056..f9c581f2a83c 100644 --- a/include/freerdp/server/audin.h +++ b/include/freerdp/server/audin.h @@ -28,6 +28,8 @@ typedef struct _audin_server_context audin_server_context; +typedef BOOL (*psAudinServerChannelIdAssigned)(audin_server_context* context, UINT32 channelId); + typedef UINT (*psAudinServerSelectFormat)(audin_server_context* context, size_t client_format_index); typedef BOOL (*psAudinServerOpen)(audin_server_context* context); @@ -99,6 +101,11 @@ struct _audin_server_context psAudinServerReceiveSamples ReceiveSamples; rdpContext* rdpcontext; + + /** + * Callback, when the channel got its id assigned. + */ + psAudinServerChannelIdAssigned ChannelIdAssigned; }; #ifdef __cplusplus diff --git a/include/freerdp/server/disp.h b/include/freerdp/server/disp.h index 43aea647a7db..ab7e09b64d39 100644 --- a/include/freerdp/server/disp.h +++ b/include/freerdp/server/disp.h @@ -29,6 +29,8 @@ typedef struct _disp_server_private DispServerPrivate; typedef struct _disp_server_context DispServerContext; +typedef BOOL (*psDispChannelIdAssigned)(DispServerContext* context, UINT32 channelId); + typedef UINT (*psDispMonitorLayout)(DispServerContext* context, const DISPLAY_CONTROL_MONITOR_LAYOUT_PDU* pdu); typedef UINT (*psDispCaps)(DispServerContext* context); @@ -53,6 +55,11 @@ struct _disp_server_context DispServerPrivate* priv; rdpContext* rdpcontext; + + /** + * Callback, when the channel got its id assigned. + */ + psDispChannelIdAssigned ChannelIdAssigned; }; #ifdef __cplusplus diff --git a/include/freerdp/server/echo.h b/include/freerdp/server/echo.h index 0643a5932c99..bbaeb581b8d3 100644 --- a/include/freerdp/server/echo.h +++ b/include/freerdp/server/echo.h @@ -34,6 +34,8 @@ typedef enum ECHO_SERVER_OPEN_RESULT typedef struct _echo_server_context echo_server_context; +typedef BOOL (*psEchoServerChannelIdAssigned)(echo_server_context* context, UINT32 channelId); + typedef UINT (*psEchoServerOpen)(echo_server_context* context); typedef UINT (*psEchoServerClose)(echo_server_context* context); typedef BOOL (*psEchoServerRequest)(echo_server_context* context, const BYTE* buffer, @@ -76,6 +78,11 @@ struct _echo_server_context psEchoServerResponse Response; rdpContext* rdpcontext; + + /** + * Callback, when the channel got its id assigned. + */ + psEchoServerChannelIdAssigned ChannelIdAssigned; }; #ifdef __cplusplus diff --git a/include/freerdp/server/rdpei.h b/include/freerdp/server/rdpei.h index b784e78c2661..01b13937d64f 100644 --- a/include/freerdp/server/rdpei.h +++ b/include/freerdp/server/rdpei.h @@ -47,6 +47,11 @@ struct _rdpei_server_context void* user_data; /* user data, useful for callbacks */ UINT (*onPenEvent)(RdpeiServerContext* context, const RDPINPUT_PEN_EVENT* penEvent); + + /** + * Callback, when the channel got its id assigned. + */ + BOOL (*onChannelIdAssigned)(RdpeiServerContext* context, UINT32 channelId); }; #ifdef __cplusplus diff --git a/include/freerdp/server/rdpgfx.h b/include/freerdp/server/rdpgfx.h index 9e52ca1de7cb..aee9de9379e1 100644 --- a/include/freerdp/server/rdpgfx.h +++ b/include/freerdp/server/rdpgfx.h @@ -29,6 +29,8 @@ typedef struct _rdpgfx_server_private RdpgfxServerPrivate; typedef BOOL (*psRdpgfxServerOpen)(RdpgfxServerContext* context); typedef BOOL (*psRdpgfxServerClose)(RdpgfxServerContext* context); +typedef BOOL (*psRdpgfxServerChannelIdAssigned)(RdpgfxServerContext* context, UINT32 channelId); + typedef UINT (*psRdpgfxResetGraphics)(RdpgfxServerContext* context, const RDPGFX_RESET_GRAPHICS_PDU* resetGraphics); typedef UINT (*psRdpgfxStartFrame)(RdpgfxServerContext* context, @@ -112,6 +114,11 @@ struct _rdpgfx_server_context RdpgfxServerPrivate* priv; rdpContext* rdpcontext; + + /** + * Callback, when the channel got its id assigned. + */ + psRdpgfxServerChannelIdAssigned ChannelIdAssigned; }; #ifdef __cplusplus From 19538c03e860821ebe840b3349441974fc916725 Mon Sep 17 00:00:00 2001 From: Pascal Nowack Date: Wed, 8 Jun 2022 15:57:43 +0200 Subject: [PATCH 205/496] Update changelog --- ChangeLog | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ChangeLog b/ChangeLog index d8763a822516..e3ab08404eb8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -3,6 +3,7 @@ Noteworthy changes: * Backported API to get peer accepted channel names * Backported Stream_CheckAndLogRequiredLength +* Backported server side handling for [MS-RDPET] (#7954) Fixed issues: * Fixed #7837: Prevent out of bound reads for FFMPEG @@ -15,6 +16,7 @@ Fixed issues: * Backported #7898: Automatic android versioning * Backported #7916: GFX 10.7 capability support * Backported #7949: Server RDPSND API improvements +* Backported #7957: Server DVC API improvements # 2022-04-25 Version 2.7.0 From a7664ea88ab447e7220fccf049fafc935fcdf97e Mon Sep 17 00:00:00 2001 From: Richard Dymond Date: Wed, 1 Jun 2022 11:21:11 -0300 Subject: [PATCH 206/496] Add WTSChannelGetOptions --- include/freerdp/channels/wtsvc.h | 1 + libfreerdp/core/server.c | 15 +++++++++++++++ 2 files changed, 16 insertions(+) diff --git a/include/freerdp/channels/wtsvc.h b/include/freerdp/channels/wtsvc.h index 56ada09a3a3c..286c7520505e 100644 --- a/include/freerdp/channels/wtsvc.h +++ b/include/freerdp/channels/wtsvc.h @@ -82,6 +82,7 @@ extern "C" FREERDP_API void* WTSChannelGetHandleByName(freerdp_peer* client, const char* channel_name); FREERDP_API void* WTSChannelGetHandleById(freerdp_peer* client, const UINT16 channel_id); FREERDP_API const char* WTSChannelGetName(freerdp_peer* client, UINT16 channel_id); + FREERDP_API INT64 WTSChannelGetOptions(freerdp_peer* client, UINT16 channel_id); FREERDP_API char** WTSGetAcceptedChannelNames(freerdp_peer* client, size_t* count); FREERDP_API UINT32 WTSChannelGetIdByHandle(HANDLE hChannelHandle); diff --git a/libfreerdp/core/server.c b/libfreerdp/core/server.c index 6635e116add3..8e36972e5965 100644 --- a/libfreerdp/core/server.c +++ b/libfreerdp/core/server.c @@ -696,6 +696,21 @@ const char* WTSChannelGetName(freerdp_peer* client, UINT16 channel_id) return (const char*)channel->Name; } +INT64 WTSChannelGetOptions(freerdp_peer* client, UINT16 channel_id) +{ + rdpMcsChannel* channel; + + if (!client || !client->context || !client->context->rdp) + return -1; + + channel = wts_get_joined_channel_by_id(client->context->rdp->mcs, channel_id); + + if (!channel) + return -1; + + return (INT64)channel->options; +} + char** WTSGetAcceptedChannelNames(freerdp_peer* client, size_t* count) { rdpMcs* mcs; From 16676959f18de458439605fc4758decf2910a6bd Mon Sep 17 00:00:00 2001 From: Richard Dymond Date: Wed, 8 Jun 2022 11:20:06 -0300 Subject: [PATCH 207/496] Update ChangeLog --- ChangeLog | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index e3ab08404eb8..0e61e5a968dd 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,7 @@ # 20xx-xx-xx Version 2.x.x Noteworthy changes: +* Backported API to get peer accepted channel option flags * Backported API to get peer accepted channel names * Backported Stream_CheckAndLogRequiredLength * Backported server side handling for [MS-RDPET] (#7954) @@ -603,4 +604,3 @@ Virtual Channels: * rdpsnd (Sound Redirection) * alsa support * pulse support - From e7851f067fbb894387819462b084ddcebe442564 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Thu, 9 Jun 2022 13:10:39 +0200 Subject: [PATCH 208/496] Invert RDPGFX_CAPVERSION_106_ERR and RDPGFX_CAPVERSION_106 values Define the actual value as RDPGFX_CAPVERSION_106 and the wrongly documented one as RDPGFX_CAPVERSION_106_ERR (cherry picked from commit a42017996a3099ceeeaf49c20c1511316e3de512) --- include/freerdp/channels/rdpgfx.h | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/include/freerdp/channels/rdpgfx.h b/include/freerdp/channels/rdpgfx.h index 01ae4e1c9658..b7511f864732 100644 --- a/include/freerdp/channels/rdpgfx.h +++ b/include/freerdp/channels/rdpgfx.h @@ -99,8 +99,13 @@ typedef struct _RDPGFX_HEADER RDPGFX_HEADER; #define RDPGFX_CAPVERSION_103 0x000A0301 /** [MS-RDPEGFX] 2.2.3.6 */ #define RDPGFX_CAPVERSION_104 0x000A0400 /** [MS-RDPEGFX] 2.2.3.7 */ #define RDPGFX_CAPVERSION_105 0x000A0502 /** [MS-RDPEGFX] 2.2.3.8 */ -#define RDPGFX_CAPVERSION_106 0x000A0601 /** [MS-RDPEGFX] 2.2.3.9 */ -#define RDPGFX_CAPVERSION_106_ERR 0x000A0600 /** [MS-RDPEGFX]-180912-errata] */ +#define RDPGFX_CAPVERSION_106 \ + 0x000A0600 /** [MS-RDPEGFX] 2.2.3.9 (the value in the doc is wrong, see \ + * [MS-RDPEGFX]-180912-errata] \ + * Since this is/was documented for a long time, also define \ + * the incorrect value in case some server actually uses it. \ + */ +#define RDPGFX_CAPVERSION_106_ERR 0x000A0601 #define RDPGFX_CAPVERSION_107 0x000A0701 /** [MS-RDPEGFX] 2.2.3.10 */ #define RDPGFX_NUMBER_CAPSETS 11 From 436f212be3950917e4bb209aa5064e423f0dd882 Mon Sep 17 00:00:00 2001 From: Adrian Perez de Castro Date: Mon, 27 Jun 2022 11:45:44 +0200 Subject: [PATCH 209/496] Fix building with LibreSSL 2.7.0 or newer With LibreSSL 2.7.0 (or newer versions) some more structs have made opaque, which requires a few changes: - BIO_meth_new() and related functions are now defined by LibreSSL, the versions from opensslcompat.{h,c} does not need to be used anymore. - HMAC_CTX is now opaque, HMAC_CTX_new(), EVP_MD_CTX_new, and related functions should be used instead in winpr's hash.c. --- libfreerdp/crypto/opensslcompat.c | 3 ++- libfreerdp/crypto/opensslcompat.h | 3 ++- winpr/libwinpr/crypto/hash.c | 21 ++++++++++++++------- 3 files changed, 18 insertions(+), 9 deletions(-) diff --git a/libfreerdp/crypto/opensslcompat.c b/libfreerdp/crypto/opensslcompat.c index 701902dc29ee..314d6b51f61d 100644 --- a/libfreerdp/crypto/opensslcompat.c +++ b/libfreerdp/crypto/opensslcompat.c @@ -19,7 +19,8 @@ #include "opensslcompat.h" -#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) +#if OPENSSL_VERSION_NUMBER < 0x10100000L || \ + (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x2070000fL) BIO_METHOD* BIO_meth_new(int type, const char* name) { diff --git a/libfreerdp/crypto/opensslcompat.h b/libfreerdp/crypto/opensslcompat.h index 169e8e4c28f8..3ad5b6bd48a9 100644 --- a/libfreerdp/crypto/opensslcompat.h +++ b/libfreerdp/crypto/opensslcompat.h @@ -30,7 +30,8 @@ #include -#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) +#if OPENSSL_VERSION_NUMBER < 0x10100000L || \ + (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x2070000fL) #include #include diff --git a/winpr/libwinpr/crypto/hash.c b/winpr/libwinpr/crypto/hash.c index 8265b2e904b9..5e94039e78cd 100644 --- a/winpr/libwinpr/crypto/hash.c +++ b/winpr/libwinpr/crypto/hash.c @@ -151,7 +151,8 @@ WINPR_HMAC_CTX* winpr_HMAC_New(void) WINPR_HMAC_CTX* ctx = NULL; #if defined(WITH_OPENSSL) HMAC_CTX* hmac = NULL; -#if (OPENSSL_VERSION_NUMBER < 0x10100000L) || defined(LIBRESSL_VERSION_NUMBER) +#if (OPENSSL_VERSION_NUMBER < 0x10100000L) || \ + (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x2070000fL) if (!(hmac = (HMAC_CTX*)calloc(1, sizeof(HMAC_CTX)))) return NULL; @@ -185,7 +186,8 @@ BOOL winpr_HMAC_Init(WINPR_HMAC_CTX* ctx, WINPR_MD_TYPE md, const BYTE* key, siz if (!evp || !hmac) return FALSE; -#if (OPENSSL_VERSION_NUMBER < 0x10000000L) || defined(LIBRESSL_VERSION_NUMBER) +#if (OPENSSL_VERSION_NUMBER < 0x10000000L) || \ + (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x2070000fL) HMAC_Init_ex(hmac, key, keylen, evp, NULL); /* no return value on OpenSSL 0.9.x */ return TRUE; #else @@ -221,7 +223,8 @@ BOOL winpr_HMAC_Update(WINPR_HMAC_CTX* ctx, const BYTE* input, size_t ilen) { #if defined(WITH_OPENSSL) HMAC_CTX* hmac = (HMAC_CTX*)ctx; -#if (OPENSSL_VERSION_NUMBER < 0x10000000L) || defined(LIBRESSL_VERSION_NUMBER) +#if (OPENSSL_VERSION_NUMBER < 0x10000000L) || \ + (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x2070000fL) HMAC_Update(hmac, input, ilen); /* no return value on OpenSSL 0.9.x */ return TRUE; #else @@ -253,7 +256,8 @@ BOOL winpr_HMAC_Final(WINPR_HMAC_CTX* ctx, BYTE* output, size_t olen) #if defined(WITH_OPENSSL) hmac = (HMAC_CTX*)ctx; -#if (OPENSSL_VERSION_NUMBER < 0x10000000L) || defined(LIBRESSL_VERSION_NUMBER) +#if (OPENSSL_VERSION_NUMBER < 0x10000000L) || \ + (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x2070000fL) HMAC_Final(hmac, output, NULL); /* no return value on OpenSSL 0.9.x */ return TRUE; #else @@ -279,7 +283,8 @@ void winpr_HMAC_Free(WINPR_HMAC_CTX* ctx) if (hmac) { -#if (OPENSSL_VERSION_NUMBER < 0x10100000L) || defined(LIBRESSL_VERSION_NUMBER) +#if (OPENSSL_VERSION_NUMBER < 0x10100000L) || \ + (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x2070000fL) HMAC_CTX_cleanup(hmac); free(hmac); #else @@ -332,7 +337,8 @@ WINPR_DIGEST_CTX* winpr_Digest_New(void) WINPR_DIGEST_CTX* ctx = NULL; #if defined(WITH_OPENSSL) EVP_MD_CTX* mdctx; -#if (OPENSSL_VERSION_NUMBER < 0x10100000L) || defined(LIBRESSL_VERSION_NUMBER) +#if (OPENSSL_VERSION_NUMBER < 0x10100000L) || \ + (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x2070000fL) mdctx = EVP_MD_CTX_create(); #else mdctx = EVP_MD_CTX_new(); @@ -464,7 +470,8 @@ void winpr_Digest_Free(WINPR_DIGEST_CTX* ctx) if (mdctx) { -#if (OPENSSL_VERSION_NUMBER < 0x10100000L) || defined(LIBRESSL_VERSION_NUMBER) +#if (OPENSSL_VERSION_NUMBER < 0x10100000L) || \ + (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x2070000fL) EVP_MD_CTX_destroy(mdctx); #else EVP_MD_CTX_free(mdctx); From a2822855845418a2c00c94742be186da44e13a92 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Fri, 2 Apr 2021 09:15:05 +0200 Subject: [PATCH 210/496] Improved RAIL order debug messages (cherry picked from commit 44e7531847dcf3547670e0d9476a2236ad16bcfe) --- channels/rail/client/rail_orders.c | 2 +- channels/rail/rail_common.c | 84 +++++++++++++++++++----------- 2 files changed, 56 insertions(+), 30 deletions(-) diff --git a/channels/rail/client/rail_orders.c b/channels/rail/client/rail_orders.c index c394a5925bc7..f5f3d5286eea 100644 --- a/channels/rail/client/rail_orders.c +++ b/channels/rail/client/rail_orders.c @@ -969,7 +969,7 @@ UINT rail_order_recv(railPlugin* rail, wStream* s) return rail_recv_get_application_id_extended_response_order(rail, s); default: - WLog_ERR(TAG, "Unknown RAIL PDU order reveived."); + WLog_ERR(TAG, "Unknown RAIL PDU order 0x%08" PRIx32 " received.", orderType); return ERROR_INVALID_DATA; } diff --git a/channels/rail/rail_common.c b/channels/rail/rail_common.c index b6d69b799105..561614c466c1 100644 --- a/channels/rail/rail_common.c +++ b/channels/rail/rail_common.c @@ -27,37 +27,63 @@ #define TAG CHANNELS_TAG("rail.common") -static const char* const RAIL_ORDER_TYPE_STRINGS[] = { "", - "Execute", - "Activate", - "System Parameters Update", - "System Command", - "Handshake", - "Notify Event", - "", - "Window Move", - "Local Move/Size", - "Min Max Info", - "Client Status", - "System Menu", - "Language Bar Info", - "Get Application ID Request", - "Get Application ID Response", - "Execute Result", - "", - "", - "", - "", - "", - "" }; - const char* rail_get_order_type_string(UINT16 orderType) { - UINT32 index = ((orderType & 0xF0) >> 3) + (orderType & 0x0F); - if (index >= ARRAYSIZE(RAIL_ORDER_TYPE_STRINGS)) - return "UNKNOWN"; - - return RAIL_ORDER_TYPE_STRINGS[index]; + static char buffer[64] = { 0 }; + switch (orderType) + { + case TS_RAIL_ORDER_EXEC: + return "TS_RAIL_ORDER_EXEC"; + case TS_RAIL_ORDER_ACTIVATE: + return "TS_RAIL_ORDER_ACTIVATE"; + case TS_RAIL_ORDER_SYSPARAM: + return "TS_RAIL_ORDER_SYSPARAM"; + case TS_RAIL_ORDER_SYSCOMMAND: + return "TS_RAIL_ORDER_SYSCOMMAND"; + case TS_RAIL_ORDER_HANDSHAKE: + return "TS_RAIL_ORDER_HANDSHAKE"; + case TS_RAIL_ORDER_NOTIFY_EVENT: + return "TS_RAIL_ORDER_NOTIFY_EVENT"; + case TS_RAIL_ORDER_WINDOWMOVE: + return "TS_RAIL_ORDER_WINDOWMOVE"; + case TS_RAIL_ORDER_LOCALMOVESIZE: + return "TS_RAIL_ORDER_LOCALMOVESIZE"; + case TS_RAIL_ORDER_MINMAXINFO: + return "TS_RAIL_ORDER_MINMAXINFO"; + case TS_RAIL_ORDER_CLIENTSTATUS: + return "TS_RAIL_ORDER_CLIENTSTATUS"; + case TS_RAIL_ORDER_SYSMENU: + return "TS_RAIL_ORDER_SYSMENU"; + case TS_RAIL_ORDER_LANGBARINFO: + return "TS_RAIL_ORDER_LANGBARINFO"; + case TS_RAIL_ORDER_GET_APPID_REQ: + return "TS_RAIL_ORDER_GET_APPID_REQ"; + case TS_RAIL_ORDER_GET_APPID_RESP: + return "TS_RAIL_ORDER_GET_APPID_RESP"; + case TS_RAIL_ORDER_TASKBARINFO: + return "TS_RAIL_ORDER_TASKBARINFO"; + case TS_RAIL_ORDER_LANGUAGEIMEINFO: + return "TS_RAIL_ORDER_LANGUAGEIMEINFO"; + case TS_RAIL_ORDER_COMPARTMENTINFO: + return "TS_RAIL_ORDER_COMPARTMENTINFO"; + case TS_RAIL_ORDER_HANDSHAKE_EX: + return "TS_RAIL_ORDER_HANDSHAKE_EX"; + case TS_RAIL_ORDER_ZORDER_SYNC: + return "TS_RAIL_ORDER_ZORDER_SYNC"; + case TS_RAIL_ORDER_CLOAK: + return "TS_RAIL_ORDER_CLOAK"; + case TS_RAIL_ORDER_POWER_DISPLAY_REQUEST: + return "TS_RAIL_ORDER_POWER_DISPLAY_REQUEST"; + case TS_RAIL_ORDER_SNAP_ARRANGE: + return "TS_RAIL_ORDER_SNAP_ARRANGE"; + case TS_RAIL_ORDER_GET_APPID_RESP_EX: + return "TS_RAIL_ORDER_GET_APPID_RESP_EX"; + case TS_RAIL_ORDER_EXEC_RESULT: + return "TS_RAIL_ORDER_EXEC_RESULT"; + default: + _snprintf(buffer, sizeof(buffer), "UNKNOWN [0x%08" PRIx32 "]", orderType); + return buffer; + } } /** From a92c7071ba474149d0430f2f91b405c0a57e49fe Mon Sep 17 00:00:00 2001 From: akallabeth Date: Wed, 29 Jun 2022 08:58:43 +0200 Subject: [PATCH 211/496] Added rail_get_order_type_string_full for better debug logs (cherry picked from commit 79ba632acb7d4c5ca0d9aaa28106fbed3d46d445) --- channels/rail/client/rail_orders.c | 59 +++++++++++++++++++++--------- channels/rail/rail_common.c | 11 ++++-- channels/rail/rail_common.h | 1 + channels/rail/server/rail_main.c | 10 +++-- 4 files changed, 56 insertions(+), 25 deletions(-) diff --git a/channels/rail/client/rail_orders.c b/channels/rail/client/rail_orders.c index f5f3d5286eea..63be665e3a83 100644 --- a/channels/rail/client/rail_orders.c +++ b/channels/rail/client/rail_orders.c @@ -39,6 +39,7 @@ */ UINT rail_send_pdu(railPlugin* rail, wStream* s, UINT16 orderType) { + char buffer[128] = { 0 }; UINT16 orderLength; if (!rail || !s) @@ -49,7 +50,7 @@ UINT rail_send_pdu(railPlugin* rail, wStream* s, UINT16 orderType) rail_write_pdu_header(s, orderType, orderLength); Stream_SetPosition(s, orderLength); WLog_Print(rail->log, WLOG_DEBUG, "Sending %s PDU, length: %" PRIu16 "", - rail_get_order_type_string(orderType), orderLength); + rail_get_order_type_string_full(orderType, buffer, sizeof(buffer)), orderLength); return rail_send_channel_data(rail, s); } @@ -911,9 +912,10 @@ static UINT rail_recv_get_application_id_extended_response_order(railPlugin* rai */ UINT rail_order_recv(railPlugin* rail, wStream* s) { + char buffer[128] = { 0 }; UINT16 orderType; UINT16 orderLength; - UINT error; + UINT error = CHANNEL_RC_OK; if (!rail || !s) return ERROR_INVALID_PARAMETER; @@ -925,55 +927,76 @@ UINT rail_order_recv(railPlugin* rail, wStream* s) } WLog_Print(rail->log, WLOG_DEBUG, "Received %s PDU, length:%" PRIu16 "", - rail_get_order_type_string(orderType), orderLength); + rail_get_order_type_string_full(orderType, buffer, sizeof(buffer)), orderLength); switch (orderType) { case TS_RAIL_ORDER_HANDSHAKE: - return rail_recv_handshake_order(rail, s); + error = rail_recv_handshake_order(rail, s); + break; case TS_RAIL_ORDER_HANDSHAKE_EX: - return rail_recv_handshake_ex_order(rail, s); + error = rail_recv_handshake_ex_order(rail, s); + break; case TS_RAIL_ORDER_EXEC_RESULT: - return rail_recv_exec_result_order(rail, s); + error = rail_recv_exec_result_order(rail, s); + break; case TS_RAIL_ORDER_SYSPARAM: - return rail_recv_server_sysparam_order(rail, s); + error = rail_recv_server_sysparam_order(rail, s); + break; case TS_RAIL_ORDER_MINMAXINFO: - return rail_recv_server_minmaxinfo_order(rail, s); + error = rail_recv_server_minmaxinfo_order(rail, s); + break; case TS_RAIL_ORDER_LOCALMOVESIZE: - return rail_recv_server_localmovesize_order(rail, s); + error = rail_recv_server_localmovesize_order(rail, s); + break; case TS_RAIL_ORDER_GET_APPID_RESP: - return rail_recv_server_get_appid_resp_order(rail, s); + error = rail_recv_server_get_appid_resp_order(rail, s); + break; case TS_RAIL_ORDER_LANGBARINFO: - return rail_recv_langbar_info_order(rail, s); + error = rail_recv_langbar_info_order(rail, s); + break; case TS_RAIL_ORDER_TASKBARINFO: - return rail_recv_taskbar_info_order(rail, s); + error = rail_recv_taskbar_info_order(rail, s); + break; case TS_RAIL_ORDER_ZORDER_SYNC: - return rail_recv_zorder_sync_order(rail, s); + error = rail_recv_zorder_sync_order(rail, s); + break; case TS_RAIL_ORDER_CLOAK: - return rail_recv_cloak_order(rail, s); + error = rail_recv_cloak_order(rail, s); + break; case TS_RAIL_ORDER_POWER_DISPLAY_REQUEST: - return rail_recv_power_display_request_order(rail, s); + error = rail_recv_power_display_request_order(rail, s); + break; case TS_RAIL_ORDER_GET_APPID_RESP_EX: - return rail_recv_get_application_id_extended_response_order(rail, s); + error = rail_recv_get_application_id_extended_response_order(rail, s); + break; default: - WLog_ERR(TAG, "Unknown RAIL PDU order 0x%08" PRIx32 " received.", orderType); + WLog_ERR(TAG, "Unknown RAIL PDU %s received.", + rail_get_order_type_string_full(orderType, buffer, sizeof(buffer))); return ERROR_INVALID_DATA; } - return CHANNEL_RC_OK; + if (error != CHANNEL_RC_OK) + { + char buffer[128] = { 0 }; + WLog_Print(rail->log, WLOG_ERROR, "Failed to process rail %s PDU, length:%" PRIu16 "", + rail_get_order_type_string_full(orderType, buffer, sizeof(buffer)), orderLength); + } + + return error; } /** diff --git a/channels/rail/rail_common.c b/channels/rail/rail_common.c index 561614c466c1..beda30659c43 100644 --- a/channels/rail/rail_common.c +++ b/channels/rail/rail_common.c @@ -29,7 +29,6 @@ const char* rail_get_order_type_string(UINT16 orderType) { - static char buffer[64] = { 0 }; switch (orderType) { case TS_RAIL_ORDER_EXEC: @@ -81,11 +80,17 @@ const char* rail_get_order_type_string(UINT16 orderType) case TS_RAIL_ORDER_EXEC_RESULT: return "TS_RAIL_ORDER_EXEC_RESULT"; default: - _snprintf(buffer, sizeof(buffer), "UNKNOWN [0x%08" PRIx32 "]", orderType); - return buffer; + return "TS_RAIL_ORDER_UNKNOWN"; } } +const char* rail_get_order_type_string_full(UINT16 orderType, char* buffer, size_t length) +{ + _snprintf(buffer, length, "%s[0x%04" PRIx16 "]", rail_get_order_type_string(orderType), + orderType); + return buffer; +} + /** * Function description * diff --git a/channels/rail/rail_common.h b/channels/rail/rail_common.h index e13412df9257..34b6fa05d15a 100644 --- a/channels/rail/rail_common.h +++ b/channels/rail/rail_common.h @@ -71,5 +71,6 @@ UINT rail_write_sysparam_order(wStream* s, const RAIL_SYSPARAM_ORDER* sysparam, BOOL extendedSpiSupported); BOOL rail_is_extended_spi_supported(UINT32 channelsFlags); const char* rail_get_order_type_string(UINT16 orderType); +const char* rail_get_order_type_string_full(UINT16 orderType, char* buffer, size_t length); #endif /* FREERDP_CHANNEL_RAIL_COMMON_H */ diff --git a/channels/rail/server/rail_main.c b/channels/rail/server/rail_main.c index db389282c47f..4949fb775c0a 100644 --- a/channels/rail/server/rail_main.c +++ b/channels/rail/server/rail_main.c @@ -62,6 +62,7 @@ static UINT rail_send(RailServerContext* context, wStream* s, ULONG length) */ static UINT rail_server_send_pdu(RailServerContext* context, wStream* s, UINT16 orderType) { + char buffer[128] = { 0 }; UINT16 orderLength; if (!context || !s) @@ -71,8 +72,8 @@ static UINT rail_server_send_pdu(RailServerContext* context, wStream* s, UINT16 Stream_SetPosition(s, 0); rail_write_pdu_header(s, orderType, orderLength); Stream_SetPosition(s, orderLength); - WLog_DBG(TAG, "Sending %s PDU, length: %" PRIu16 "", rail_get_order_type_string(orderType), - orderLength); + WLog_DBG(TAG, "Sending %s PDU, length: %" PRIu16 "", + rail_get_order_type_string_full(orderType, buffer, sizeof(buffer)), orderLength); return rail_send(context, s, orderLength); } @@ -1535,6 +1536,7 @@ void rail_server_set_handshake_ex_flags(RailServerContext* context, DWORD flags) UINT rail_server_handle_messages(RailServerContext* context) { + char buffer[128] = { 0 }; UINT status = CHANNEL_RC_OK; DWORD bytesReturned; UINT16 orderType; @@ -1584,8 +1586,8 @@ UINT rail_server_handle_messages(RailServerContext* context) return ERROR_INTERNAL_ERROR; } - WLog_DBG(TAG, "Received %s PDU, length:%" PRIu16 "", rail_get_order_type_string(orderType), - orderLength); + WLog_DBG(TAG, "Received %s PDU, length:%" PRIu16 "", + rail_get_order_type_string_full(orderType, buffer, sizeof(buffer)), orderLength); switch (orderType) { From bbdf949938ac31b8e0c02804f90f0ac99fc16dda Mon Sep 17 00:00:00 2001 From: akallabeth Date: Wed, 29 Jun 2022 09:48:38 +0200 Subject: [PATCH 212/496] Added new rail orders textscaleinfo and caretblinkrate (cherry picked from commit dfadfd3b769dc0c860087c9a0df237cab06317b6) --- channels/rail/client/rail_orders.c | 75 ++++++++++++++++++++++++++++++ channels/rail/rail_common.c | 4 ++ include/freerdp/client/rail.h | 4 ++ include/freerdp/rail.h | 53 +++++++++++---------- 4 files changed, 112 insertions(+), 24 deletions(-) diff --git a/channels/rail/client/rail_orders.c b/channels/rail/client/rail_orders.c index 63be665e3a83..7d6b67d34296 100644 --- a/channels/rail/client/rail_orders.c +++ b/channels/rail/client/rail_orders.c @@ -905,6 +905,73 @@ static UINT rail_recv_get_application_id_extended_response_order(railPlugin* rai return error; } +static UINT rail_read_textscaleinfo_order(wStream* s, UINT32* pTextScaleFactor) +{ + WINPR_ASSERT(pTextScaleFactor); + + if (!Stream_CheckAndLogRequiredLength(TAG, s, 4)) + return ERROR_INVALID_DATA; + + Stream_Read_UINT32(s, *pTextScaleFactor); + return CHANNEL_RC_OK; +} + +static UINT rail_recv_textscaleinfo_order(railPlugin* rail, wStream* s) +{ + RailClientContext* context = rail_get_client_interface(rail); + UINT32 TextScaleFactor = 0; + UINT error; + + if (!context) + return ERROR_INVALID_PARAMETER; + + if ((error = rail_read_textscaleinfo_order(s, &TextScaleFactor))) + return error; + + if (context->custom) + { + IFCALLRET(context->ClientTextScale, error, context, TextScaleFactor); + + if (error) + WLog_ERR(TAG, "context.ClientTextScale failed with error %" PRIu32 "", error); + } + + return error; +} + +static UINT rail_read_caretblinkinfo_order(wStream* s, UINT32* pCaretBlinkRate) +{ + WINPR_ASSERT(pCaretBlinkRate); + + if (!Stream_CheckAndLogRequiredLength(TAG, s, 4)) + return ERROR_INVALID_DATA; + + Stream_Read_UINT32(s, *pCaretBlinkRate); + return CHANNEL_RC_OK; +} + +static UINT rail_recv_caretblinkinfo_order(railPlugin* rail, wStream* s) +{ + RailClientContext* context = rail_get_client_interface(rail); + UINT32 CaretBlinkRate = 0; + UINT error; + + if (!context) + return ERROR_INVALID_PARAMETER; + if ((error = rail_read_caretblinkinfo_order(s, &CaretBlinkRate))) + return error; + + if (context->custom) + { + IFCALLRET(context->ClientCaretBlinkRate, error, context, CaretBlinkRate); + + if (error) + WLog_ERR(TAG, "context.ClientCaretBlinkRate failed with error %" PRIu32 "", error); + } + + return error; +} + /** * Function description * @@ -983,6 +1050,14 @@ UINT rail_order_recv(railPlugin* rail, wStream* s) error = rail_recv_get_application_id_extended_response_order(rail, s); break; + case TS_RAIL_ORDER_TEXTSCALEINFO: + error = rail_recv_textscaleinfo_order(rail, s); + break; + + case TS_RAIL_ORDER_CARETBLINKINFO: + error = rail_recv_caretblinkinfo_order(rail, s); + break; + default: WLog_ERR(TAG, "Unknown RAIL PDU %s received.", rail_get_order_type_string_full(orderType, buffer, sizeof(buffer))); diff --git a/channels/rail/rail_common.c b/channels/rail/rail_common.c index beda30659c43..e77616d1b7f0 100644 --- a/channels/rail/rail_common.c +++ b/channels/rail/rail_common.c @@ -79,6 +79,10 @@ const char* rail_get_order_type_string(UINT16 orderType) return "TS_RAIL_ORDER_GET_APPID_RESP_EX"; case TS_RAIL_ORDER_EXEC_RESULT: return "TS_RAIL_ORDER_EXEC_RESULT"; + case TS_RAIL_ORDER_TEXTSCALEINFO: + return "TS_RAIL_ORDER_TEXTSCALEINFO"; + case TS_RAIL_ORDER_CARETBLINKINFO: + return "TS_RAIL_ORDER_CARETBLINKINFO"; default: return "TS_RAIL_ORDER_UNKNOWN"; } diff --git a/include/freerdp/client/rail.h b/include/freerdp/client/rail.h index 0ce7dc33299e..ef5aefdaec71 100644 --- a/include/freerdp/client/rail.h +++ b/include/freerdp/client/rail.h @@ -86,6 +86,8 @@ typedef UINT (*pcRailServerGetAppidResponseExtended)(RailClientContext* context, const RAIL_GET_APPID_RESP_EX* id); typedef UINT (*pcRailClientCompartmentInfo)(RailClientContext* context, const RAIL_COMPARTMENT_INFO_ORDER* compartmentInfo); +typedef UINT (*pcRailClientTextScale)(RailClientContext* context, UINT32 TextScale); +typedef UINT (*pcRailClientCaretBlinkRate)(RailClientContext* context, UINT32 CaretBlinkRate); struct _rail_client_context { @@ -121,6 +123,8 @@ struct _rail_client_context pcRailServerGetAppidResponseExtended ServerGetAppidResponseExtended; pcRailClientCompartmentInfo ClientCompartmentInfo; pcRailOnOpen OnOpen; + pcRailClientTextScale ClientTextScale; + pcRailClientCaretBlinkRate ClientCaretBlinkRate; }; #endif /* FREERDP_CHANNEL_RAIL_CLIENT_RAIL_H */ diff --git a/include/freerdp/rail.h b/include/freerdp/rail.h index e532082bed05..bf753ac3765f 100644 --- a/include/freerdp/rail.h +++ b/include/freerdp/rail.h @@ -560,30 +560,35 @@ typedef struct _RAIL_GET_APPID_RESP_EX RAIL_GET_APPID_RESP_EX; /* RAIL Constants */ -#define TS_RAIL_ORDER_EXEC 0x0001 -#define TS_RAIL_ORDER_ACTIVATE 0x0002 -#define TS_RAIL_ORDER_SYSPARAM 0x0003 -#define TS_RAIL_ORDER_SYSCOMMAND 0x0004 -#define TS_RAIL_ORDER_HANDSHAKE 0x0005 -#define TS_RAIL_ORDER_NOTIFY_EVENT 0x0006 -#define TS_RAIL_ORDER_WINDOWMOVE 0x0008 -#define TS_RAIL_ORDER_LOCALMOVESIZE 0x0009 -#define TS_RAIL_ORDER_MINMAXINFO 0x000A -#define TS_RAIL_ORDER_CLIENTSTATUS 0x000B -#define TS_RAIL_ORDER_SYSMENU 0x000C -#define TS_RAIL_ORDER_LANGBARINFO 0x000D -#define TS_RAIL_ORDER_GET_APPID_REQ 0x000E -#define TS_RAIL_ORDER_GET_APPID_RESP 0x000F -#define TS_RAIL_ORDER_TASKBARINFO 0x0010 -#define TS_RAIL_ORDER_LANGUAGEIMEINFO 0x0011 -#define TS_RAIL_ORDER_COMPARTMENTINFO 0x0012 -#define TS_RAIL_ORDER_HANDSHAKE_EX 0x0013 -#define TS_RAIL_ORDER_ZORDER_SYNC 0x0014 -#define TS_RAIL_ORDER_CLOAK 0x0015 -#define TS_RAIL_ORDER_POWER_DISPLAY_REQUEST 0x0016 -#define TS_RAIL_ORDER_SNAP_ARRANGE 0x0017 -#define TS_RAIL_ORDER_GET_APPID_RESP_EX 0x0018 -#define TS_RAIL_ORDER_EXEC_RESULT 0x0080 +typedef enum +{ + TS_RAIL_ORDER_EXEC = 0x0001, + TS_RAIL_ORDER_ACTIVATE = 0x0002, + TS_RAIL_ORDER_SYSPARAM = 0x0003, + TS_RAIL_ORDER_SYSCOMMAND = 0x0004, + TS_RAIL_ORDER_HANDSHAKE = 0x0005, + TS_RAIL_ORDER_NOTIFY_EVENT = 0x0006, + TS_RAIL_ORDER_WINDOWMOVE = 0x0008, + TS_RAIL_ORDER_LOCALMOVESIZE = 0x0009, + TS_RAIL_ORDER_MINMAXINFO = 0x000A, + TS_RAIL_ORDER_CLIENTSTATUS = 0x000B, + TS_RAIL_ORDER_SYSMENU = 0x000C, + TS_RAIL_ORDER_LANGBARINFO = 0x000D, + TS_RAIL_ORDER_GET_APPID_REQ = 0x000E, + TS_RAIL_ORDER_GET_APPID_RESP = 0x000F, + TS_RAIL_ORDER_TASKBARINFO = 0x0010, + TS_RAIL_ORDER_LANGUAGEIMEINFO = 0x0011, + TS_RAIL_ORDER_COMPARTMENTINFO = 0x0012, + TS_RAIL_ORDER_HANDSHAKE_EX = 0x0013, + TS_RAIL_ORDER_ZORDER_SYNC = 0x0014, + TS_RAIL_ORDER_CLOAK = 0x0015, + TS_RAIL_ORDER_POWER_DISPLAY_REQUEST = 0x0016, + TS_RAIL_ORDER_SNAP_ARRANGE = 0x0017, + TS_RAIL_ORDER_GET_APPID_RESP_EX = 0x0018, + TS_RAIL_ORDER_TEXTSCALEINFO = 0x0019, + TS_RAIL_ORDER_CARETBLINKINFO = 0x001A, + TS_RAIL_ORDER_EXEC_RESULT = 0x0080 +} ORDER_TYPE; #ifdef __cplusplus extern "C" From 758a00ed79f32bc946f8cc6dab0ac4d2389a3958 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Wed, 29 Jun 2022 10:23:58 +0200 Subject: [PATCH 213/496] Updated flags required by [MS-RDPERP] (cherry picked from commit fc949e43874252d5fbfe27526417c2742c36b25a) --- include/freerdp/rail.h | 43 ++++++++++++++++++++++++----------- winpr/include/winpr/windows.h | 32 ++++++++++++++++++++++---- 2 files changed, 58 insertions(+), 17 deletions(-) diff --git a/include/freerdp/rail.h b/include/freerdp/rail.h index bf753ac3765f..e50eb1c7476e 100644 --- a/include/freerdp/rail.h +++ b/include/freerdp/rail.h @@ -116,6 +116,14 @@ enum SPI_MASK /* Client Notify Event PDU */ #ifndef _WIN32 +#define WM_LBUTTONDOWN 0x00000201 +#define WM_LBUTTONUP 0x00000202 +#define WM_RBUTTONDOWN 0x00000204 +#define WM_RBUTTONUP 0x00000205 +#define WM_CONTEXTMENU 0x0000007b +#define WM_LBUTTONDBLCLK 0x00000203 +#define WM_RBUTTONDBLCLK 0x00000206 + #define NIN_SELECT 0x00000400 #define NIN_KEYSELECT 0x00000401 #define NIN_BALLOONSHOW 0x00000402 @@ -135,15 +143,19 @@ enum SPI_MASK #endif /* Client Information PDU */ -#define TS_RAIL_CLIENTSTATUS_ALLOWLOCALMOVESIZE 0x00000001 -#define TS_RAIL_CLIENTSTATUS_AUTORECONNECT 0x00000002 -#define TS_RAIL_CLIENTSTATUS_ZORDER_SYNC 0x00000004 -#define TS_RAIL_CLIENTSTATUS_WINDOW_RESIZE_MARGIN_SUPPORTED 0x00000010 -#define TS_RAIL_CLIENTSTATUS_HIGH_DPI_ICONS_SUPPORTED 0x00000020 -#define TS_RAIL_CLIENTSTATUS_APPBAR_REMOTING_SUPPORTED 0x00000040 -#define TS_RAIL_CLIENTSTATUS_POWER_DISPLAY_REQUEST_SUPPORTED 0x00000080 -#define TS_RAIL_CLIENTSTATUS_GET_APPID_RESPONSE_EX_SUPPORTED 0x00000100 -#define TS_RAIL_CLIENTSTATUS_BIDIRECTIONAL_CLOAK_SUPPORTED 0x00000200 +typedef enum +{ + TS_RAIL_CLIENTSTATUS_ALLOWLOCALMOVESIZE = 0x00000001, + TS_RAIL_CLIENTSTATUS_AUTORECONNECT = 0x00000002, + TS_RAIL_CLIENTSTATUS_ZORDER_SYNC = 0x00000004, + TS_RAIL_CLIENTSTATUS_WINDOW_RESIZE_MARGIN_SUPPORTED = 0x00000010, + TS_RAIL_CLIENTSTATUS_HIGH_DPI_ICONS_SUPPORTED = 0x00000020, + TS_RAIL_CLIENTSTATUS_APPBAR_REMOTING_SUPPORTED = 0x00000040, + TS_RAIL_CLIENTSTATUS_POWER_DISPLAY_REQUEST_SUPPORTED = 0x00000080, + TS_RAIL_CLIENTSTATUS_GET_APPID_RESPONSE_EX_SUPPORTED = 0x00000100, + TS_RAIL_CLIENTSTATUS_BIDIRECTIONAL_CLOAK_SUPPORTED = 0x00000200, + TS_RAIL_CLIENTSTATUS_SUPPRESS_ICON_ORDERS = 0x00000400 +} CLIENT_INFO_PDU; /* Server Move/Size Start PDU */ #define RAIL_WMSZ_LEFT 0x0001 @@ -182,10 +194,15 @@ enum SPI_MASK #endif /* Extended Handshake Flags */ -#define TS_RAIL_ORDER_HANDSHAKEEX_FLAGS_HIDEF 0x00000001 -#define TS_RAIL_ORDER_HANDSHAKE_EX_FLAGS_EXTENDED_SPI_SUPPORTED 0x00000002 -#define TS_RAIL_ORDER_HANDSHAKE_EX_FLAGS_SNAP_ARRANGE_SUPPORTED 0x00000004 - +typedef enum +{ + TS_RAIL_ORDER_HANDSHAKEEX_FLAGS_HIDEF = 0x00000001, + TS_RAIL_ORDER_HANDSHAKE_EX_FLAGS_EXTENDED_SPI_SUPPORTED = 0x00000002, + TS_RAIL_ORDER_HANDSHAKE_EX_FLAGS_SNAP_ARRANGE_SUPPORTED = 0x00000004, + TS_RAIL_ORDER_HANDSHAKE_EX_FLAGS_TEXT_SCALE_SUPPORTED = 0x00000008, + TS_RAIL_ORDER_HANDSHAKE_EX_FLAGS_CARET_BLINK_SUPPORTED = 0x00000010, + TS_RAIL_ORDER_HANDSHAKE_EX_FLAGS_EXTENDED_SPI_2_SUPPORTED = 0x00000020 +} EXTENDED_HANDSHAKE_FLAGS; /* Language Profile Information Flags */ #define TF_PROFILETYPE_INPUTPROCESSOR 0x00000001 #define TF_PROFILETYPE_KEYBOARDLAYOUT 0x00000002 diff --git a/winpr/include/winpr/windows.h b/winpr/include/winpr/windows.h index b5313f0670c4..5bc6722c2d31 100644 --- a/winpr/include/winpr/windows.h +++ b/winpr/include/winpr/windows.h @@ -37,10 +37,34 @@ /* Client System Parameters Update PDU * defined in winuser.h */ -#define SPI_SETCARETWIDTH 0x00002007 -#define SPI_SETSTICKYKEYS 0x0000003B -#define SPI_SETTOGGLEKEYS 0x00000035 -#define SPI_SETFILTERKEYS 0x00000033 +typedef enum +{ + SPI_SETDRAGFULLWINDOWS = 0x00000025, + SPI_SETKEYBOARDCUES = 0x0000100B, + SPI_SETKEYBOARDPREF = 0x00000045, + SPI_SETWORKAREA = 0x0000002f, + RAIL_SPI_DISPLAYCHANGE = 0x0000F001, + SPI_SETMOUSEBUTTONSWAP = 0x00000021, + RAIL_SPI_TASKBARPOS = 0x0000F000, + SPI_SETHIGHCONTRAST = 0x00000043, + SPI_SETCARETWIDTH = 0x00002007, + SPI_SETSTICKYKEYS = 0x0000003B, + SPI_SETTOGGLEKEYS = 0x00000035, + SPI_SETFILTERKEYS = 0x00000033, + RAIL_SPI_DISPLAY_ANIMATIONS_ENABLED = 0x0000F002, + RAIL_SPI_DISPLAY_ADVANCED_EFFECTS_ENABLED = 0x0000F003, + RAIL_SPI_DISPLAY_AUTO_HIDE_SCROLLBARS = 0x0000F004, + RAIL_SPI_DISPLAY_MESSAGE_DURATION = 0x0000F005, + RAIL_SPI_CLOSED_CAPTION_FONT_COLOR = 0x0000F006, + RAIL_SPI_CLOSED_CAPTION_FONT_OPACITY = 0x0000F007, + RAIL_SPI_CLOSED_CAPTION_FONT_SIZE = 0x0000F008, + RAIL_SPI_CLOSED_CAPTION_FONT_STYLE = 0x0000F009, + RAIL_SPI_CLOSED_CAPTION_FONT_EDGE_EFFECT = 0x0000F00A, + RAIL_SPI_CLOSED_CAPTION_BACKGROUND_COLOR = 0x0000F00B, + RAIL_SPI_CLOSED_CAPTION_BACKGROUND_OPACITY = 0x0000F00C, + RAIL_SPI_CLOSED_CAPTION_REGION_COLOR = 0x0000F00D, + RAIL_SPI_CLOSED_CAPTION_REGION_OPACITY = 0x0000F00E +} SystemParam; /* Server System Parameters Update PDU */ #define SPI_SETSCREENSAVEACTIVE 0x00000011 From b3a4b717171b2526a09b4d69a1b7594c48a3fd8d Mon Sep 17 00:00:00 2001 From: akallabeth Date: Wed, 29 Jun 2022 12:35:31 +0200 Subject: [PATCH 214/496] Added RAIL compartmentinfo server to client message (cherry picked from commit ad6dd99190657f42e44a59bd7a6ad5132f217d83) --- channels/rail/client/rail_orders.c | 58 +++++++++++++++++++++++++++++- include/freerdp/settings.h | 3 ++ libfreerdp/common/settings.c | 23 ++++++++++++ 3 files changed, 83 insertions(+), 1 deletion(-) diff --git a/channels/rail/client/rail_orders.c b/channels/rail/client/rail_orders.c index 7d6b67d34296..4070b0fe29db 100644 --- a/channels/rail/client/rail_orders.c +++ b/channels/rail/client/rail_orders.c @@ -32,6 +32,8 @@ #include "rail_orders.h" +static BOOL rail_is_feature_supported(const rdpContext* context, UINT32 featureMask); + /** * Function description * @@ -389,7 +391,46 @@ static UINT rail_recv_handshake_order(railPlugin* rail, wStream* s) return error; } -static BOOL rail_is_feature_supported(const rdpContext* context, UINT32 featureMask) +static UINT rail_read_compartment_info_order(wStream* s, + RAIL_COMPARTMENT_INFO_ORDER* compartmentInfo) +{ + if (!Stream_CheckAndLogRequiredLength(TAG, s, RAIL_COMPARTMENT_INFO_ORDER_LENGTH)) + return ERROR_INVALID_DATA; + + Stream_Read_UINT32(s, compartmentInfo->ImeState); /* ImeState (4 bytes) */ + Stream_Read_UINT32(s, compartmentInfo->ImeConvMode); /* ImeConvMode (4 bytes) */ + Stream_Read_UINT32(s, compartmentInfo->ImeSentenceMode); /* ImeSentenceMode (4 bytes) */ + Stream_Read_UINT32(s, compartmentInfo->KanaMode); /* KANAMode (4 bytes) */ + return CHANNEL_RC_OK; +} + +static UINT rail_recv_compartmentinfo_order(railPlugin* rail, wStream* s) +{ + RailClientContext* context = rail_get_client_interface(rail); + RAIL_COMPARTMENT_INFO_ORDER pdu = { 0 }; + UINT error; + + if (!context || !s) + return ERROR_INVALID_PARAMETER; + + if (!rail_is_feature_supported(rail->rdpcontext, RAIL_LEVEL_LANGUAGE_IME_SYNC_SUPPORTED)) + return ERROR_BAD_CONFIGURATION; + + if ((error = rail_read_compartment_info_order(s, &pdu))) + return error; + + if (context->custom) + { + IFCALLRET(context->ClientCompartmentInfo, error, context, &pdu); + + if (error) + WLog_ERR(TAG, "context.ClientCompartmentInfo failed with error %" PRIu32 "", error); + } + + return error; +} + +BOOL rail_is_feature_supported(const rdpContext* context, UINT32 featureMask) { UINT32 supported, masked; @@ -401,7 +442,15 @@ static BOOL rail_is_feature_supported(const rdpContext* context, UINT32 featureM masked = (supported & featureMask); if (masked != featureMask) + { + char mask[256] = { 0 }; + char actual[256] = { 0 }; + + WLog_WARN(TAG, "[%s] have %s, require %s", __func__, + freerdp_rail_support_flags_to_string(supported, actual, sizeof(actual)), + freerdp_rail_support_flags_to_string(featureMask, mask, sizeof(mask))); return FALSE; + } return TRUE; } @@ -1002,6 +1051,10 @@ UINT rail_order_recv(railPlugin* rail, wStream* s) error = rail_recv_handshake_order(rail, s); break; + case TS_RAIL_ORDER_COMPARTMENTINFO: + error = rail_recv_compartmentinfo_order(rail, s); + break; + case TS_RAIL_ORDER_HANDSHAKE_EX: error = rail_recv_handshake_ex_order(rail, s); break; @@ -1456,6 +1509,9 @@ UINT rail_send_client_compartment_info_order(railPlugin* rail, if (!rail || !compartmentInfo) return ERROR_INVALID_PARAMETER; + if (!rail_is_feature_supported(rail->rdpcontext, RAIL_LEVEL_LANGUAGE_IME_SYNC_SUPPORTED)) + return ERROR_BAD_CONFIGURATION; + s = rail_pdu_init(RAIL_COMPARTMENT_INFO_ORDER_LENGTH); if (!s) diff --git a/include/freerdp/settings.h b/include/freerdp/settings.h index 3b7a13896c36..7553a1d663ec 100644 --- a/include/freerdp/settings.h +++ b/include/freerdp/settings.h @@ -1705,6 +1705,9 @@ extern "C" FREERDP_API SSIZE_T freerdp_settings_get_type_for_key(size_t key); FREERDP_API const char* freerdp_settings_get_name_for_key(size_t key); + FREERDP_API char* freerdp_rail_support_flags_to_string(UINT32 flags, char* buffer, + size_t length); + #ifdef __cplusplus } #endif diff --git a/libfreerdp/common/settings.c b/libfreerdp/common/settings.c index b639778b0462..f32f32ac2615 100644 --- a/libfreerdp/common/settings.c +++ b/libfreerdp/common/settings.c @@ -925,3 +925,26 @@ BOOL freerdp_settings_set_value_for_name(rdpSettings* settings, const char* name } return FALSE; } + +char* freerdp_rail_support_flags_to_string(UINT32 flags, char* buffer, size_t length) +{ + if (flags & RAIL_LEVEL_SUPPORTED) + winpr_str_append("RAIL_LEVEL_SUPPORTED", buffer, length, "|"); + if (flags & RAIL_LEVEL_DOCKED_LANGBAR_SUPPORTED) + winpr_str_append("RAIL_LEVEL_DOCKED_LANGBAR_SUPPORTED", buffer, length, "|"); + if (flags & RAIL_LEVEL_SHELL_INTEGRATION_SUPPORTED) + winpr_str_append("RAIL_LEVEL_SHELL_INTEGRATION_SUPPORTED", buffer, length, "|"); + if (flags & RAIL_LEVEL_LANGUAGE_IME_SYNC_SUPPORTED) + winpr_str_append("RAIL_LEVEL_LANGUAGE_IME_SYNC_SUPPORTED", buffer, length, "|"); + if (flags & RAIL_LEVEL_SERVER_TO_CLIENT_IME_SYNC_SUPPORTED) + winpr_str_append("RAIL_LEVEL_SERVER_TO_CLIENT_IME_SYNC_SUPPORTED", buffer, length, "|"); + if (flags & RAIL_LEVEL_HIDE_MINIMIZED_APPS_SUPPORTED) + winpr_str_append("RAIL_LEVEL_HIDE_MINIMIZED_APPS_SUPPORTED", buffer, length, "|"); + if (flags & RAIL_LEVEL_WINDOW_CLOAKING_SUPPORTED) + winpr_str_append("RAIL_LEVEL_WINDOW_CLOAKING_SUPPORTED", buffer, length, "|"); + if (flags & RAIL_LEVEL_HANDSHAKE_EX_SUPPORTED) + winpr_str_append("RAIL_LEVEL_HANDSHAKE_EX_SUPPORTED", buffer, length, "|"); + if (flags & RAIL_LEVEL_LANGUAGE_IME_SYNC_SUPPORTED) + winpr_str_append("RAIL_LEVEL_LANGUAGE_IME_SYNC_SUPPORTED", buffer, length, "|"); + return buffer; +} From 75bfec61f912eaddedf71780c4617c4f032b68be Mon Sep 17 00:00:00 2001 From: akallabeth Date: Wed, 29 Jun 2022 13:30:39 +0200 Subject: [PATCH 215/496] Removed duplicate defined symbols stable has wnd.h defining this --- include/freerdp/rail.h | 8 -------- 1 file changed, 8 deletions(-) diff --git a/include/freerdp/rail.h b/include/freerdp/rail.h index e50eb1c7476e..fefffc1d9e03 100644 --- a/include/freerdp/rail.h +++ b/include/freerdp/rail.h @@ -116,14 +116,6 @@ enum SPI_MASK /* Client Notify Event PDU */ #ifndef _WIN32 -#define WM_LBUTTONDOWN 0x00000201 -#define WM_LBUTTONUP 0x00000202 -#define WM_RBUTTONDOWN 0x00000204 -#define WM_RBUTTONUP 0x00000205 -#define WM_CONTEXTMENU 0x0000007b -#define WM_LBUTTONDBLCLK 0x00000203 -#define WM_RBUTTONDBLCLK 0x00000206 - #define NIN_SELECT 0x00000400 #define NIN_KEYSELECT 0x00000401 #define NIN_BALLOONSHOW 0x00000402 From a4c86723a37ac8c03d419bacef409a536412b64c Mon Sep 17 00:00:00 2001 From: akallabeth Date: Fri, 3 Jun 2022 10:25:30 +0200 Subject: [PATCH 216/496] Unifiy string append functions (cherry picked from commit f25261e27129e23737f1d9b18cf7325697f492c5) --- channels/ainput/common/ainput_common.h | 44 +++------ channels/rdpdr/server/rdpdr_main.c | 2 +- .../urbdrc/client/libusb/libusb_udevman.c | 7 +- client/X11/xf_keyboard.c | 11 ++- client/common/cmdline.c | 9 +- libfreerdp/core/gateway/rdg.c | 12 +-- libfreerdp/core/info.c | 23 ++--- libfreerdp/core/nego.c | 23 +++++ libfreerdp/core/nego.h | 1 + winpr/include/winpr/string.h | 3 + winpr/libwinpr/clipboard/synthetic.c | 98 +++++++++++-------- winpr/libwinpr/crt/string.c | 17 ++++ winpr/libwinpr/file/generic.c | 13 +-- winpr/libwinpr/smartcard/smartcard.c | 90 ++++------------- winpr/libwinpr/sspi/NTLM/ntlm.c | 12 +-- 15 files changed, 165 insertions(+), 200 deletions(-) diff --git a/channels/ainput/common/ainput_common.h b/channels/ainput/common/ainput_common.h index bc1be04b9c76..34442f7d9561 100644 --- a/channels/ainput/common/ainput_common.h +++ b/channels/ainput/common/ainput_common.h @@ -21,59 +21,37 @@ #ifndef FREERDP_INT_AINPUT_COMMON_H #define FREERDP_INT_AINPUT_COMMON_H -#include #include #include -static INLINE void ainput_append(char* buffer, size_t size, const char* what, BOOL separator) -{ - size_t have; - size_t toadd; - - assert(buffer || (size == 0)); - assert(what); - - have = strnlen(buffer, size); - toadd = strlen(what); - if (have > 0) - toadd += 1; - - if (size - have < toadd + 1) - return; - - if (have > 0) - strcat(buffer, separator ? "|" : " "); - strcat(buffer, what); -} - static INLINE const char* ainput_flags_to_string(UINT64 flags, char* buffer, size_t size) { char number[32] = { 0 }; if (flags & AINPUT_FLAGS_HAVE_REL) - ainput_append(buffer, size, "AINPUT_FLAGS_HAVE_REL", TRUE); + winpr_str_append("AINPUT_FLAGS_HAVE_REL", buffer, size, "|"); if (flags & AINPUT_FLAGS_WHEEL) - ainput_append(buffer, size, "AINPUT_FLAGS_WHEEL", TRUE); + winpr_str_append("AINPUT_FLAGS_WHEEL", buffer, size, "|"); if (flags & AINPUT_FLAGS_MOVE) - ainput_append(buffer, size, "AINPUT_FLAGS_MOVE", TRUE); + winpr_str_append("AINPUT_FLAGS_MOVE", buffer, size, "|"); if (flags & AINPUT_FLAGS_DOWN) - ainput_append(buffer, size, "AINPUT_FLAGS_DOWN", TRUE); + winpr_str_append("AINPUT_FLAGS_DOWN", buffer, size, "|"); if (flags & AINPUT_FLAGS_REL) - ainput_append(buffer, size, "AINPUT_FLAGS_REL", TRUE); + winpr_str_append("AINPUT_FLAGS_REL", buffer, size, "|"); if (flags & AINPUT_FLAGS_BUTTON1) - ainput_append(buffer, size, "AINPUT_FLAGS_BUTTON1", TRUE); + winpr_str_append("AINPUT_FLAGS_BUTTON1", buffer, size, "|"); if (flags & AINPUT_FLAGS_BUTTON2) - ainput_append(buffer, size, "AINPUT_FLAGS_BUTTON2", TRUE); + winpr_str_append("AINPUT_FLAGS_BUTTON2", buffer, size, "|"); if (flags & AINPUT_FLAGS_BUTTON3) - ainput_append(buffer, size, "AINPUT_FLAGS_BUTTON3", TRUE); + winpr_str_append("AINPUT_FLAGS_BUTTON3", buffer, size, "|"); if (flags & AINPUT_XFLAGS_BUTTON1) - ainput_append(buffer, size, "AINPUT_XFLAGS_BUTTON1", TRUE); + winpr_str_append("AINPUT_XFLAGS_BUTTON1", buffer, size, "|"); if (flags & AINPUT_XFLAGS_BUTTON2) - ainput_append(buffer, size, "AINPUT_XFLAGS_BUTTON2", TRUE); + winpr_str_append("AINPUT_XFLAGS_BUTTON2", buffer, size, "|"); _snprintf(number, sizeof(number), "[0x%08" PRIx64 "]", flags); - ainput_append(buffer, size, number, FALSE); + winpr_str_append(number, buffer, size, " "); return buffer; } diff --git a/channels/rdpdr/server/rdpdr_main.c b/channels/rdpdr/server/rdpdr_main.c index 3e005da0fa95..2dcb2a0c731e 100644 --- a/channels/rdpdr/server/rdpdr_main.c +++ b/channels/rdpdr/server/rdpdr_main.c @@ -1952,7 +1952,7 @@ static UINT rdpdr_server_drive_query_directory_callback1(RdpdrServerContext* con irp->Callback = rdpdr_server_drive_query_directory_callback2; irp->DeviceId = deviceId; irp->FileId = fileId; - strcat(irp->PathName, "\\*.*"); + winpr_str_append("\\*.*", irp->PathName, ARRAYSIZE(irp->PathName), NULL); if (!rdpdr_server_enqueue_irp(context, irp)) { diff --git a/channels/urbdrc/client/libusb/libusb_udevman.c b/channels/urbdrc/client/libusb/libusb_udevman.c index 95b37f6d3ff1..5f1e9e0d2356 100644 --- a/channels/urbdrc/client/libusb/libusb_udevman.c +++ b/channels/urbdrc/client/libusb/libusb_udevman.c @@ -511,12 +511,7 @@ static BOOL filter_by_class(uint8_t bDeviceClass, uint8_t bDeviceSubClass) static BOOL append(char* dst, size_t length, const char* src) { - size_t slen = strlen(src); - size_t dlen = strnlen(dst, length); - if (dlen + slen >= length) - return FALSE; - strcat(dst, src); - return TRUE; + return winpr_str_append(src, dst, length, NULL); } static BOOL device_is_filtered(struct libusb_device* dev, diff --git a/client/X11/xf_keyboard.c b/client/X11/xf_keyboard.c index 26a1fd2e50cc..377e9bdd80f6 100644 --- a/client/X11/xf_keyboard.c +++ b/client/X11/xf_keyboard.c @@ -400,18 +400,19 @@ static int xf_keyboard_execute_action_script(xfContext* xfc, XF_MODIFIER_KEYS* m } if (mod->Shift) - strcat(combination, "Shift+"); + winpr_str_append("Shift", combination, sizeof(combination), "+"); if (mod->Ctrl) - strcat(combination, "Ctrl+"); + winpr_str_append("Ctrl", combination, sizeof(combination), "+"); if (mod->Alt) - strcat(combination, "Alt+"); + winpr_str_append("Alt", combination, sizeof(combination), "+"); if (mod->Super) - strcat(combination, "Super+"); + winpr_str_append("Super", combination, sizeof(combination), "+"); + + winpr_str_append(keyStr, combination, sizeof(combination), NULL); - strcat(combination, keyStr); count = ArrayList_Count(xfc->keyCombinations); for (index = 0; index < count; index++) diff --git a/client/common/cmdline.c b/client/common/cmdline.c index 77fcf81849d9..52f90f503d5a 100644 --- a/client/common/cmdline.c +++ b/client/common/cmdline.c @@ -211,6 +211,7 @@ static BOOL copy_value(const char* value, char** dst) static BOOL append_value(const char* value, char** dst) { size_t x = 0, y; + size_t size; char* tmp; if (!dst || !value) return FALSE; @@ -218,14 +219,16 @@ static BOOL append_value(const char* value, char** dst) if (*dst) x = strlen(*dst); y = strlen(value); - tmp = realloc(*dst, x + y + 2); + + size = x + y + 2; + tmp = realloc(*dst, size); if (!tmp) return FALSE; if (x == 0) tmp[0] = '\0'; else - strcat(tmp, ","); - strcat(tmp, value); + winpr_str_append(",", tmp, size, NULL); + winpr_str_append(value, tmp, size, NULL); *dst = tmp; return TRUE; } diff --git a/libfreerdp/core/gateway/rdg.c b/libfreerdp/core/gateway/rdg.c index 6b998c8d9b78..07f2be42034f 100644 --- a/libfreerdp/core/gateway/rdg.c +++ b/libfreerdp/core/gateway/rdg.c @@ -257,20 +257,18 @@ static const char* flags_to_string(UINT32 flags, const t_flag_mapping* map, size { size_t x = 0; static char buffer[1024] = { 0 }; - char fields[12]; - memset(buffer, 0, sizeof(buffer)); + char fields[12] = { 0 }; for (x = 0; x < elements; x++) { - if (buffer[0] != '\0') - strcat(buffer, "|"); + const t_flag_mapping* cur = &map[x]; - if ((map[x].code & flags) != 0) - strcat(buffer, map[x].name); + if ((cur->code & flags) != 0) + winpr_str_append(cur->name, buffer, sizeof(buffer), "|"); } sprintf_s(fields, ARRAYSIZE(fields), " [%04" PRIx32 "]", flags); - strcat(buffer, fields); + winpr_str_append(fields, buffer, sizeof(buffer), NULL); return buffer; } diff --git a/libfreerdp/core/info.c b/libfreerdp/core/info.c index f31b736d7bbb..1603adcdd2fa 100644 --- a/libfreerdp/core/info.c +++ b/libfreerdp/core/info.c @@ -41,11 +41,13 @@ static const char* const INFO_TYPE_LOGON_STRINGS[4] = { "Logon Info V1", "Logon /* This define limits the length of the strings in the label field. */ #define MAX_LABEL_LENGTH 40 -static struct +struct info_flags_t { UINT32 flag; const char* label; -} const info_flags[] = { +}; + +static const struct info_flags_t info_flags[] = { { INFO_MOUSE, "INFO_MOUSE" }, { INFO_DISABLECTRLALTDEL, "INFO_DISABLECTRLALTDEL" }, { INFO_AUTOLOGON, "INFO_AUTOLOGON" }, @@ -118,12 +120,8 @@ static BOOL rdp_read_info_null_string(UINT32 flags, wStream* s, size_t cbLen, CH static char* rdp_info_package_flags_description(UINT32 flags) { char* result; - size_t maximum_size = 1; /* Reserve space for the terminating '\0' by strcat if all flags set */ + size_t maximum_size = 1 + MAX_LABEL_LENGTH * ARRAYSIZE(info_flags); size_t i; - size_t size; - - for (i = 0; i < ARRAYSIZE(info_flags); i++) - maximum_size += strnlen(info_flags[i].label, MAX_LABEL_LENGTH) + 1; result = calloc(maximum_size, sizeof(char)); @@ -132,18 +130,13 @@ static char* rdp_info_package_flags_description(UINT32 flags) for (i = 0; i < ARRAYSIZE(info_flags); i++) { - if (info_flags[i].flag & flags) + const struct info_flags_t* cur = &info_flags[i]; + if (cur->flag & flags) { - strcat(result, info_flags[i].label); - strcat(result, "|"); + winpr_str_append(cur->label, result, maximum_size, "|"); } } - size = strnlen(result, maximum_size); - - if (size > 0) - result[size - 1] = '\0'; /* remove last "|" */ - return result; } diff --git a/libfreerdp/core/nego.c b/libfreerdp/core/nego.c index ac4e93f7c6ab..48739a78d183 100644 --- a/libfreerdp/core/nego.c +++ b/libfreerdp/core/nego.c @@ -945,6 +945,28 @@ BOOL nego_process_negotiation_request(rdpNego* nego, wStream* s) * @param nego * @param s */ +static const char* nego_rdp_neg_rsp_flags_str(UINT32 flags) +{ + static char buffer[1024] = { 0 }; + + _snprintf(buffer, ARRAYSIZE(buffer), "[0x%02" PRIx32 "] ", flags); + if (flags & EXTENDED_CLIENT_DATA_SUPPORTED) + winpr_str_append("EXTENDED_CLIENT_DATA_SUPPORTED", buffer, sizeof(buffer), "|"); + if (flags & DYNVC_GFX_PROTOCOL_SUPPORTED) + winpr_str_append("DYNVC_GFX_PROTOCOL_SUPPORTED", buffer, sizeof(buffer), "|"); + if (flags & RDP_NEGRSP_RESERVED) + winpr_str_append("RDP_NEGRSP_RESERVED", buffer, sizeof(buffer), "|"); + if (flags & RESTRICTED_ADMIN_MODE_SUPPORTED) + winpr_str_append("RESTRICTED_ADMIN_MODE_SUPPORTED", buffer, sizeof(buffer), "|"); + if (flags & REDIRECTED_AUTHENTICATION_MODE_SUPPORTED) + winpr_str_append("REDIRECTED_AUTHENTICATION_MODE_SUPPORTED", buffer, sizeof(buffer), "|"); + if ((flags & + ~(EXTENDED_CLIENT_DATA_SUPPORTED | DYNVC_GFX_PROTOCOL_SUPPORTED | RDP_NEGRSP_RESERVED | + RESTRICTED_ADMIN_MODE_SUPPORTED | REDIRECTED_AUTHENTICATION_MODE_SUPPORTED))) + winpr_str_append("UNKNOWN", buffer, sizeof(buffer), "|"); + + return buffer; +} BOOL nego_process_negotiation_response(rdpNego* nego, wStream* s) { @@ -959,6 +981,7 @@ BOOL nego_process_negotiation_response(rdpNego* nego, wStream* s) } Stream_Read_UINT8(s, nego->flags); + WLog_DBG(TAG, "RDP_NEG_RSP::flags = { %s }", nego_rdp_neg_rsp_flags_str(nego->flags)); Stream_Read_UINT16(s, length); Stream_Read_UINT32(s, nego->SelectedProtocol); nego->state = NEGO_STATE_FINAL; diff --git a/libfreerdp/core/nego.h b/libfreerdp/core/nego.h index f67e4fa95ce2..ce7a47e346bc 100644 --- a/libfreerdp/core/nego.h +++ b/libfreerdp/core/nego.h @@ -81,6 +81,7 @@ enum RDP_NEG_MSG #define DYNVC_GFX_PROTOCOL_SUPPORTED 0x02 #define RDP_NEGRSP_RESERVED 0x04 #define RESTRICTED_ADMIN_MODE_SUPPORTED 0x08 +#define REDIRECTED_AUTHENTICATION_MODE_SUPPORTED 0x10 #define PRECONNECTION_PDU_V1_SIZE 16 #define PRECONNECTION_PDU_V2_MIN_SIZE (PRECONNECTION_PDU_V1_SIZE + 2) diff --git a/winpr/include/winpr/string.h b/winpr/include/winpr/string.h index 8ce83bc1d97a..69af1a0553f3 100644 --- a/winpr/include/winpr/string.h +++ b/winpr/include/winpr/string.h @@ -31,6 +31,9 @@ extern "C" { #endif + WINPR_API BOOL winpr_str_append(const char* what, char* buffer, size_t size, + const char* separator); + #ifndef _WIN32 #define CSTR_LESS_THAN 1 diff --git a/winpr/libwinpr/clipboard/synthetic.c b/winpr/libwinpr/clipboard/synthetic.c index 63b5153489e4..fcd66dcb6197 100644 --- a/winpr/libwinpr/clipboard/synthetic.c +++ b/winpr/libwinpr/clipboard/synthetic.c @@ -321,91 +321,107 @@ static void* clipboard_synthesize_image_bmp(wClipboard* clipboard, UINT32 format */ static void* clipboard_synthesize_html_format(wClipboard* clipboard, UINT32 formatId, - const void* data, UINT32* pSize) + const void* pData, UINT32* pSize) { - char* pSrcData = NULL; + union + { + const void* cpv; + const char* cpc; + const BYTE* cpb; + WCHAR* pv; + } pSrcData; char* pDstData = NULL; - INT64 SrcSize = (INT64)*pSize; + pSrcData.cpv = NULL; + + WINPR_ASSERT(clipboard); + WINPR_ASSERT(pSize); if (formatId == ClipboardGetFormatId(clipboard, "text/html")) { + const INT64 SrcSize = (INT64)*pSize; + const size_t DstSize = SrcSize + 200; char* body; - BYTE bom[2]; - char num[20]; - WCHAR* wstr; + char num[20] = { 0 }; + + /* Create a copy, we modify the input data */ + pSrcData.pv = calloc(1, SrcSize + 1); + if (!pSrcData.pv) + goto fail; + memcpy(pSrcData.pv, pData, SrcSize); if (SrcSize > 2) { - CopyMemory(bom, data, 2); + if (SrcSize > INT_MAX) + return NULL; - if ((bom[0] == 0xFE) && (bom[1] == 0xFF)) - { - ByteSwapUnicode((WCHAR*)data, SrcSize / 2); - } + /* Check the BOM (Byte Order Mark) */ + if ((pSrcData.cpb[0] == 0xFE) && (pSrcData.cpb[1] == 0xFF)) + ByteSwapUnicode(pSrcData.pv, (int)(SrcSize / 2)); - if ((bom[0] == 0xFF) && (bom[1] == 0xFE)) + /* Check if we have WCHAR, convert to UTF-8 */ + if ((pSrcData.cpb[0] == 0xFF) && (pSrcData.cpb[1] == 0xFE)) { - wstr = (WCHAR*)&((BYTE*)data)[2]; - ConvertFromUnicode(CP_UTF8, 0, wstr, (SrcSize - 2) / 2, &pSrcData, 0, NULL, NULL); + char* utfString = NULL; + ConvertFromUnicode(CP_UTF8, 0, &pSrcData.pv[1], (int)(SrcSize - 2) / 2, &utfString, + 0, NULL, NULL); + free(pSrcData.pv); + pSrcData.cpc = utfString; } } - if (!pSrcData) - { - pSrcData = (char*)calloc(1, SrcSize + 1); - - if (!pSrcData) - return NULL; - - CopyMemory(pSrcData, data, SrcSize); - } - - pDstData = (char*)calloc(1, SrcSize + 200); + pDstData = (char*)calloc(1, DstSize); if (!pDstData) - { - free(pSrcData); - return NULL; - } + goto fail; - sprintf_s(pDstData, SrcSize + 200, + sprintf_s(pDstData, DstSize, "Version:0.9\r\n" "StartHTML:0000000000\r\n" "EndHTML:0000000000\r\n" "StartFragment:0000000000\r\n" "EndFragment:0000000000\r\n"); - body = strstr(pSrcData, ""); + { + if (!winpr_str_append("", pDstData, DstSize, NULL)) + goto fail; + } - strcat(pDstData, ""); + if (!winpr_str_append("", pDstData, DstSize, NULL)) + goto fail; /* StartFragment */ sprintf_s(num, sizeof(num), "%010" PRIuz "", strnlen(pDstData, SrcSize + 200)); CopyMemory(&pDstData[69], num, 10); - strcat(pDstData, pSrcData); + if (!winpr_str_append(pSrcData.cpc, pDstData, DstSize, NULL)) + goto fail; /* EndFragment */ sprintf_s(num, sizeof(num), "%010" PRIuz "", strnlen(pDstData, SrcSize + 200)); CopyMemory(&pDstData[93], num, 10); - strcat(pDstData, ""); + if (!winpr_str_append("", pDstData, DstSize, NULL)) + goto fail; if (!body) - strcat(pDstData, ""); + { + if (!winpr_str_append("", pDstData, DstSize, NULL)) + goto fail; + } /* EndHTML */ - sprintf_s(num, sizeof(num), "%010" PRIuz "", strnlen(pDstData, SrcSize + 200)); + sprintf_s(num, sizeof(num), "%010" PRIuz "", strnlen(pDstData, DstSize)); CopyMemory(&pDstData[43], num, 10); - *pSize = (UINT32)strlen(pDstData) + 1; - free(pSrcData); + *pSize = (UINT32)strnlen(pDstData, DstSize) + 1; } +fail: + free(pSrcData.pv); return pDstData; } diff --git a/winpr/libwinpr/crt/string.c b/winpr/libwinpr/crt/string.c index 37fcb4b25b3c..748210e4c677 100644 --- a/winpr/libwinpr/crt/string.c +++ b/winpr/libwinpr/crt/string.c @@ -33,6 +33,23 @@ #include "../log.h" #define TAG WINPR_TAG("crt") +BOOL winpr_str_append(const char* what, char* buffer, size_t size, const char* separator) +{ + const size_t used = strnlen(buffer, size); + const size_t add = strnlen(what, size); + const size_t sep_len = separator ? strnlen(separator, size) : 0; + const size_t sep = (used > 0) ? sep_len : 0; + + if (used + add + sep >= size) + return FALSE; + + if ((used > 0) && (sep_len > 0)) + strncat(buffer, separator, sep_len); + + strncat(buffer, what, add); + return TRUE; +} + #ifndef _WIN32 char* _strdup(const char* strSource) diff --git a/winpr/libwinpr/file/generic.c b/winpr/libwinpr/file/generic.c index aa53f68fc755..9668bb55d1e2 100644 --- a/winpr/libwinpr/file/generic.c +++ b/winpr/libwinpr/file/generic.c @@ -24,6 +24,7 @@ #endif #include +#include #include #include @@ -541,15 +542,7 @@ DWORD WINAPI GetFileAttributesW(LPCWSTR lpFileName) static char* append(char* buffer, size_t size, const char* append) { - const size_t len = strnlen(buffer, size); - if (len == 0) - _snprintf(buffer, size, "%s", append); - else - { - strcat(buffer, "|"); - strcat(buffer, append); - } - + winpr_str_append(append, buffer, size, "|"); return buffer; } @@ -588,7 +581,7 @@ static const char* flagsToStr(char* buffer, size_t size, DWORD flags) append(buffer, size, "FILE_ATTRIBUTE_VIRTUAL"); _snprintf(strflags, sizeof(strflags), " [0x%08" PRIx32 "]", flags); - strcat(buffer, strflags); + winpr_str_append(strflags, buffer, size, NULL); return buffer; } diff --git a/winpr/libwinpr/smartcard/smartcard.c b/winpr/libwinpr/smartcard/smartcard.c index 22d6b03ed477..30e472ca2c73 100644 --- a/winpr/libwinpr/smartcard/smartcard.c +++ b/winpr/libwinpr/smartcard/smartcard.c @@ -1047,103 +1047,47 @@ WINSCARDAPI const char* WINAPI SCardGetCardStateString(DWORD dwCardState) WINSCARDAPI char* WINAPI SCardGetReaderStateString(DWORD dwReaderState) { - char* szReaderState = malloc(512); + const size_t size = 512; + char* buffer = calloc(size, sizeof(char)); - if (!szReaderState) + if (!buffer) return NULL; - szReaderState[0] = '\0'; - if (dwReaderState & SCARD_STATE_IGNORE) - { - if (szReaderState[0]) - strcat(szReaderState, " | "); - - strcat(szReaderState, "SCARD_STATE_IGNORE"); - } + winpr_str_append("SCARD_STATE_IGNORE", buffer, size, "|"); if (dwReaderState & SCARD_STATE_CHANGED) - { - if (szReaderState[0]) - strcat(szReaderState, " | "); - - strcat(szReaderState, "SCARD_STATE_CHANGED"); - } + winpr_str_append("SCARD_STATE_CHANGED", buffer, size, "|"); if (dwReaderState & SCARD_STATE_UNKNOWN) - { - if (szReaderState[0]) - strcat(szReaderState, " | "); - - strcat(szReaderState, "SCARD_STATE_UNKNOWN"); - } + winpr_str_append("SCARD_STATE_UNKNOWN", buffer, size, "|"); if (dwReaderState & SCARD_STATE_UNAVAILABLE) - { - if (szReaderState[0]) - strcat(szReaderState, " | "); - - strcat(szReaderState, "SCARD_STATE_UNAVAILABLE"); - } + winpr_str_append("SCARD_STATE_UNAVAILABLE", buffer, size, "|"); if (dwReaderState & SCARD_STATE_EMPTY) - { - if (szReaderState[0]) - strcat(szReaderState, " | "); - - strcat(szReaderState, "SCARD_STATE_EMPTY"); - } + winpr_str_append("SCARD_STATE_EMPTY", buffer, size, "|"); if (dwReaderState & SCARD_STATE_PRESENT) - { - if (szReaderState[0]) - strcat(szReaderState, " | "); - - strcat(szReaderState, "SCARD_STATE_PRESENT"); - } + winpr_str_append("SCARD_STATE_PRESENT", buffer, size, "|"); if (dwReaderState & SCARD_STATE_ATRMATCH) - { - if (szReaderState[0]) - strcat(szReaderState, " | "); - - strcat(szReaderState, "SCARD_STATE_ATRMATCH"); - } + winpr_str_append("SCARD_STATE_ATRMATCH", buffer, size, "|"); if (dwReaderState & SCARD_STATE_EXCLUSIVE) - { - if (szReaderState[0]) - strcat(szReaderState, " | "); - - strcat(szReaderState, "SCARD_STATE_EXCLUSIVE"); - } + winpr_str_append("SCARD_STATE_EXCLUSIVE", buffer, size, "|"); if (dwReaderState & SCARD_STATE_INUSE) - { - if (szReaderState[0]) - strcat(szReaderState, " | "); - - strcat(szReaderState, "SCARD_STATE_INUSE"); - } + winpr_str_append("SCARD_STATE_INUSE", buffer, size, "|"); if (dwReaderState & SCARD_STATE_MUTE) - { - if (szReaderState[0]) - strcat(szReaderState, " | "); - - strcat(szReaderState, "SCARD_STATE_MUTE"); - } + winpr_str_append("SCARD_STATE_MUTE", buffer, size, "|"); if (dwReaderState & SCARD_STATE_UNPOWERED) - { - if (szReaderState[0]) - strcat(szReaderState, " | "); - - strcat(szReaderState, "SCARD_STATE_UNPOWERED"); - } + winpr_str_append("SCARD_STATE_UNPOWERED", buffer, size, "|"); - if (!szReaderState[0]) - strcat(szReaderState, "SCARD_STATE_UNAWARE"); + if (!buffer[0]) + winpr_str_append("SCARD_STATE_UNAWARE", buffer, size, "|"); - return szReaderState; + return buffer; } diff --git a/winpr/libwinpr/sspi/NTLM/ntlm.c b/winpr/libwinpr/sspi/NTLM/ntlm.c index 372e6fb9957e..0e12a3429712 100644 --- a/winpr/libwinpr/sspi/NTLM/ntlm.c +++ b/winpr/libwinpr/sspi/NTLM/ntlm.c @@ -1309,15 +1309,15 @@ char* ntlm_negotiate_flags_string(char* buffer, size_t size, UINT32 flags) { if (size - len < 1) break; - strcat(buffer, "|"); - len++; - } + winpr_str_append("|", buffer, size, NULL); + len++; + } if (size - len < flen) break; - strcat(buffer, str); - } - } + winpr_str_append(str, buffer, size, NULL); + } + } return buffer; } From 1eead867dbf37fc5ee39ccfd869962fe79bf0f9b Mon Sep 17 00:00:00 2001 From: Pascal Nowack Date: Tue, 29 Mar 2022 07:01:57 +0200 Subject: [PATCH 217/496] freerdp/constants: Conform osMinorType values to documentation The OSMINORTYPE_NATIVE_WAYLAND value does not officially exist in [MS-RDPBCGR]. Its value also is the one for Windows RT. Fix this situation, by introducing the os minor type OSMINORTYPE_WINDOWS_RT with its correct value and by choosing a different value for OSMINORTYPE_NATIVE_WAYLAND, as that value does not exist officially. --- include/freerdp/constants.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/include/freerdp/constants.h b/include/freerdp/constants.h index d7949efa49d6..d95947cf7792 100644 --- a/include/freerdp/constants.h +++ b/include/freerdp/constants.h @@ -58,6 +58,8 @@ enum RDP_CODEC_ID #define OSMINORTYPE_MACINTOSH 0x0006 #define OSMINORTYPE_NATIVE_XSERVER 0x0007 #define OSMINORTYPE_PSEUDO_XSERVER 0x0008 -#define OSMINORTYPE_NATIVE_WAYLAND 0x0009 +#define OSMINORTYPE_WINDOWS_RT 0x0009 +/* As of 2022-03-29 the following does not exist officially in [MS-RDPBCGR] */ +#define OSMINORTYPE_NATIVE_WAYLAND (0xFFFF - 1) #endif /* FREERDP_CONSTANTS_H */ From 82991117eb8c23e2b0b501e81882ecffa4935836 Mon Sep 17 00:00:00 2001 From: Pascal Nowack Date: Wed, 29 Jun 2022 14:26:34 +0200 Subject: [PATCH 218/496] constants: Add missing OS major type constants --- include/freerdp/constants.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/freerdp/constants.h b/include/freerdp/constants.h index d95947cf7792..44fb1cb54ba1 100644 --- a/include/freerdp/constants.h +++ b/include/freerdp/constants.h @@ -45,6 +45,10 @@ enum RDP_CODEC_ID #define OSMAJORTYPE_OS2 0x0002 #define OSMAJORTYPE_MACINTOSH 0x0003 #define OSMAJORTYPE_UNIX 0x0004 +#define OSMAJORTYPE_IOS 0x0005 +#define OSMAJORTYPE_OSX 0x0006 +#define OSMAJORTYPE_ANDROID 0x0007 +#define OSMAJORTYPE_CHROME_OS 0x0008 /** * OSMinorType From cbdab6cdb4d3591c48e4877198c8238ee3bf59b4 Mon Sep 17 00:00:00 2001 From: Pascal Nowack Date: Thu, 9 Jun 2022 12:50:12 +0200 Subject: [PATCH 219/496] channels/server: Fix channel name in license comments --- channels/telemetry/server/telemetry_main.c | 2 +- include/freerdp/channels/telemetry.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/channels/telemetry/server/telemetry_main.c b/channels/telemetry/server/telemetry_main.c index ec276ff8310d..262f658fe8de 100644 --- a/channels/telemetry/server/telemetry_main.c +++ b/channels/telemetry/server/telemetry_main.c @@ -1,6 +1,6 @@ /** * FreeRDP: A Remote Desktop Protocol Implementation - * Advanced Input Virtual Channel Extension + * Telemetry Virtual Channel Extension * * Copyright 2022 Pascal Nowack * diff --git a/include/freerdp/channels/telemetry.h b/include/freerdp/channels/telemetry.h index a92d97d39b62..85ad1ff29c40 100644 --- a/include/freerdp/channels/telemetry.h +++ b/include/freerdp/channels/telemetry.h @@ -1,6 +1,6 @@ /** * FreeRDP: A Remote Desktop Protocol Implementation - * Audio Input Redirection Virtual Channel + * Telemetry Virtual Channel Extension * * Copyright 2022 Pascal Nowack * From 5ae19bb4c3ed5c2443b0b4d5f78c1875d3cb7093 Mon Sep 17 00:00:00 2001 From: Pascal Nowack Date: Wed, 29 Jun 2022 10:34:54 +0200 Subject: [PATCH 220/496] telemetry/server: Fix copyright in license comment --- channels/telemetry/CMakeLists.txt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/channels/telemetry/CMakeLists.txt b/channels/telemetry/CMakeLists.txt index b2d5e30c72e9..d2b4f24e3c57 100644 --- a/channels/telemetry/CMakeLists.txt +++ b/channels/telemetry/CMakeLists.txt @@ -1,8 +1,7 @@ # FreeRDP: A Remote Desktop Protocol Implementation # FreeRDP cmake build script # -# Copyright 2022 Armin Novak -# Copyright 2022 Thincast Technologies GmbH +# Copyright 2022 Pascal Nowack # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. From 6bd1d524c6c3c9c668cbd7efbf3c40de8db26e80 Mon Sep 17 00:00:00 2001 From: Pascal Nowack Date: Wed, 15 Jun 2022 05:20:17 +0200 Subject: [PATCH 221/496] server: Add channel handling for camera device and enumerator channel --- channels/rdpecam/CMakeLists.txt | 23 + channels/rdpecam/ChannelOptions.cmake | 17 + channels/rdpecam/server/CMakeLists.txt | 28 + .../server/camera_device_enumerator_main.c | 612 +++++++++++ channels/rdpecam/server/camera_device_main.c | 974 ++++++++++++++++++ channels/server/channels.c | 8 + config.h.in | 3 + include/freerdp/channels/camera-device.h | 335 ++++++ .../freerdp/server/camera-device-enumerator.h | 134 +++ include/freerdp/server/camera-device.h | 278 +++++ 10 files changed, 2412 insertions(+) create mode 100644 channels/rdpecam/CMakeLists.txt create mode 100644 channels/rdpecam/ChannelOptions.cmake create mode 100644 channels/rdpecam/server/CMakeLists.txt create mode 100644 channels/rdpecam/server/camera_device_enumerator_main.c create mode 100644 channels/rdpecam/server/camera_device_main.c create mode 100644 include/freerdp/channels/camera-device.h create mode 100644 include/freerdp/server/camera-device-enumerator.h create mode 100644 include/freerdp/server/camera-device.h diff --git a/channels/rdpecam/CMakeLists.txt b/channels/rdpecam/CMakeLists.txt new file mode 100644 index 000000000000..2ea7828d0b43 --- /dev/null +++ b/channels/rdpecam/CMakeLists.txt @@ -0,0 +1,23 @@ +# FreeRDP: A Remote Desktop Protocol Implementation +# FreeRDP cmake build script +# +# Copyright 2022 Pascal Nowack +# +# 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. + +define_channel("camera-device") +define_channel("camera-device-enumerator") + +if(WITH_SERVER_CHANNELS) + add_channel_server(${MODULE_PREFIX} ${CHANNEL_NAME}) +endif() diff --git a/channels/rdpecam/ChannelOptions.cmake b/channels/rdpecam/ChannelOptions.cmake new file mode 100644 index 000000000000..6377499d7872 --- /dev/null +++ b/channels/rdpecam/ChannelOptions.cmake @@ -0,0 +1,17 @@ + +set(OPTION_DEFAULT OFF) +set(OPTION_CLIENT_DEFAULT OFF) +set(OPTION_SERVER_DEFAULT ON) + +define_channel_options(NAME "camera-device" TYPE "dynamic" + DESCRIPTION "Video Capture Virtual Channel Extension" + SPECIFICATIONS "[MS-RDPECAM]" + DEFAULT ${OPTION_DEFAULT}) + +define_channel_options(NAME "camera-device-enumerator" TYPE "dynamic" + DESCRIPTION "Video Capture Virtual Channel Extension" + SPECIFICATIONS "[MS-RDPECAM]" + DEFAULT ${OPTION_DEFAULT}) + +define_channel_server_options(${OPTION_SERVER_DEFAULT}) + diff --git a/channels/rdpecam/server/CMakeLists.txt b/channels/rdpecam/server/CMakeLists.txt new file mode 100644 index 000000000000..e272f9d4039e --- /dev/null +++ b/channels/rdpecam/server/CMakeLists.txt @@ -0,0 +1,28 @@ +# FreeRDP: A Remote Desktop Protocol Implementation +# FreeRDP cmake build script +# +# Copyright 2022 Pascal Nowack +# +# 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. + +define_channel_server("camera-device") +define_channel_server("camera-device-enumerator") + +set(${MODULE_PREFIX}_SRCS + camera_device_enumerator_main.c + camera_device_main.c) + +add_channel_server_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE "DVCPluginEntry") + +target_link_libraries(${MODULE_NAME} freerdp) +set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Channels/${CHANNEL_NAME}/Server") diff --git a/channels/rdpecam/server/camera_device_enumerator_main.c b/channels/rdpecam/server/camera_device_enumerator_main.c new file mode 100644 index 000000000000..810491eba9ac --- /dev/null +++ b/channels/rdpecam/server/camera_device_enumerator_main.c @@ -0,0 +1,612 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Video Capture Virtual Channel Extension + * + * Copyright 2022 Pascal Nowack + * + * 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include + +#define TAG CHANNELS_TAG("cam-dev-enum.server") + +typedef enum +{ + ENUMERATOR_INITIAL, + ENUMERATOR_OPENED, +} eEnumeratorChannelState; + +typedef struct +{ + CamDevEnumServerContext context; + + HANDLE stopEvent; + + HANDLE thread; + void* enumerator_channel; + + DWORD SessionId; + + BOOL isOpened; + BOOL externalThread; + + /* Channel state */ + eEnumeratorChannelState state; + + wStream* buffer; +} enumerator_server; + +static UINT enumerator_server_initialize(CamDevEnumServerContext* context, BOOL externalThread) +{ + UINT error = CHANNEL_RC_OK; + enumerator_server* enumerator = (enumerator_server*)context; + + WINPR_ASSERT(enumerator); + + if (enumerator->isOpened) + { + WLog_WARN(TAG, "Application error: Camera Device Enumerator channel already initialized, " + "calling in this state is not possible!"); + return ERROR_INVALID_STATE; + } + + enumerator->externalThread = externalThread; + + return error; +} + +static UINT enumerator_server_open_channel(enumerator_server* enumerator) +{ + CamDevEnumServerContext* context = &enumerator->context; + DWORD Error = ERROR_SUCCESS; + HANDLE hEvent; + DWORD BytesReturned = 0; + PULONG pSessionId = NULL; + UINT32 channelId; + BOOL status = TRUE; + + WINPR_ASSERT(enumerator); + + if (WTSQuerySessionInformationA(enumerator->context.vcm, WTS_CURRENT_SESSION, WTSSessionId, + (LPSTR*)&pSessionId, &BytesReturned) == FALSE) + { + WLog_ERR(TAG, "WTSQuerySessionInformationA failed!"); + return ERROR_INTERNAL_ERROR; + } + + enumerator->SessionId = (DWORD)*pSessionId; + WTSFreeMemory(pSessionId); + hEvent = WTSVirtualChannelManagerGetEventHandle(enumerator->context.vcm); + + if (WaitForSingleObject(hEvent, 1000) == WAIT_FAILED) + { + Error = GetLastError(); + WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "!", Error); + return Error; + } + + enumerator->enumerator_channel = WTSVirtualChannelOpenEx( + enumerator->SessionId, CAM_DEVICE_ENUMERATOR_DVC_CHANNEL_NAME, WTS_CHANNEL_OPTION_DYNAMIC); + if (!enumerator->enumerator_channel) + { + Error = GetLastError(); + WLog_ERR(TAG, "WTSVirtualChannelOpenEx failed with error %" PRIu32 "!", Error); + return Error; + } + + channelId = WTSChannelGetIdByHandle(enumerator->enumerator_channel); + + IFCALLRET(context->ChannelIdAssigned, status, context, channelId); + if (!status) + { + WLog_ERR(TAG, "context->ChannelIdAssigned failed!"); + return ERROR_INTERNAL_ERROR; + } + + return Error; +} + +static UINT enumerator_server_handle_select_version_request(CamDevEnumServerContext* context, + wStream* s, + const CAM_SHARED_MSG_HEADER* header) +{ + CAM_SELECT_VERSION_REQUEST pdu = {}; + UINT error = CHANNEL_RC_OK; + + WINPR_ASSERT(context); + WINPR_ASSERT(header); + + pdu.Header = *header; + + IFCALLRET(context->SelectVersionRequest, error, context, &pdu); + if (error) + WLog_ERR(TAG, "context->SelectVersionRequest failed with error %" PRIu32 "", error); + + return error; +} + +static UINT enumerator_server_recv_device_added_notification(CamDevEnumServerContext* context, + wStream* s, + const CAM_SHARED_MSG_HEADER* header) +{ + CAM_DEVICE_ADDED_NOTIFICATION pdu; + UINT error = CHANNEL_RC_OK; + size_t remaining_length; + WCHAR* channel_name_start; + char* tmp; + size_t i; + + WINPR_ASSERT(context); + WINPR_ASSERT(header); + + pdu.Header = *header; + + /* + * RequiredLength 4: + * + * Nullterminator DeviceName (2), + * VirtualChannelName (>= 1), + * Nullterminator VirtualChannelName (1) + */ + if (!Stream_CheckAndLogRequiredLength(TAG, s, 4)) + return ERROR_NO_DATA; + + pdu.DeviceName = (WCHAR*)Stream_Pointer(s); + + remaining_length = Stream_GetRemainingLength(s); + channel_name_start = (WCHAR*)Stream_Pointer(s); + + /* Search for null terminator of DeviceName */ + for (i = 0; i < remaining_length; i += sizeof(WCHAR), ++channel_name_start) + { + if (*channel_name_start == L'\0') + break; + } + + if (*channel_name_start != L'\0') + { + WLog_ERR(TAG, "enumerator_server_recv_device_added_notification: Invalid DeviceName!"); + return ERROR_INVALID_DATA; + } + + pdu.VirtualChannelName = (char*)++channel_name_start; + ++i; + + if (i >= remaining_length || *pdu.VirtualChannelName == '\0') + { + WLog_ERR(TAG, + "enumerator_server_recv_device_added_notification: Invalid VirtualChannelName!"); + return ERROR_INVALID_DATA; + } + + tmp = pdu.VirtualChannelName; + for (; i < remaining_length; ++i, ++tmp) + { + if (*tmp == '\0') + break; + } + + if (*tmp != '\0') + { + WLog_ERR(TAG, + "enumerator_server_recv_device_added_notification: Invalid VirtualChannelName!"); + return ERROR_INVALID_DATA; + } + + IFCALLRET(context->DeviceAddedNotification, error, context, &pdu); + if (error) + WLog_ERR(TAG, "context->DeviceAddedNotification failed with error %" PRIu32 "", error); + + return error; +} + +static UINT enumerator_server_recv_device_removed_notification(CamDevEnumServerContext* context, + wStream* s, + const CAM_SHARED_MSG_HEADER* header) +{ + CAM_DEVICE_REMOVED_NOTIFICATION pdu; + UINT error = CHANNEL_RC_OK; + size_t remaining_length; + char* tmp; + size_t i; + + WINPR_ASSERT(context); + WINPR_ASSERT(header); + + pdu.Header = *header; + + if (!Stream_CheckAndLogRequiredLength(TAG, s, 2)) + return ERROR_NO_DATA; + + pdu.VirtualChannelName = (char*)Stream_Pointer(s); + + remaining_length = Stream_GetRemainingLength(s); + tmp = (char*)(Stream_Pointer(s) + 1); + + for (i = 1; i < remaining_length; ++i, ++tmp) + { + if (*tmp == '\0') + break; + } + + if (*tmp != '\0') + { + WLog_ERR(TAG, + "enumerator_server_recv_device_removed_notification: Invalid VirtualChannelName!"); + return ERROR_INVALID_DATA; + } + + IFCALLRET(context->DeviceRemovedNotification, error, context, &pdu); + if (error) + WLog_ERR(TAG, "context->DeviceRemovedNotification failed with error %" PRIu32 "", error); + + return error; +} + +static UINT enumerator_process_message(enumerator_server* enumerator) +{ + BOOL rc; + UINT error = ERROR_INTERNAL_ERROR; + ULONG BytesReturned; + CAM_SHARED_MSG_HEADER header = {}; + wStream* s; + + WINPR_ASSERT(enumerator); + WINPR_ASSERT(enumerator->enumerator_channel); + + s = enumerator->buffer; + WINPR_ASSERT(s); + + Stream_SetPosition(s, 0); + rc = WTSVirtualChannelRead(enumerator->enumerator_channel, 0, NULL, 0, &BytesReturned); + if (!rc) + goto out; + + if (BytesReturned < 1) + { + error = CHANNEL_RC_OK; + goto out; + } + + if (!Stream_EnsureRemainingCapacity(s, BytesReturned)) + { + WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!"); + error = CHANNEL_RC_NO_MEMORY; + goto out; + } + + if (WTSVirtualChannelRead(enumerator->enumerator_channel, 0, (PCHAR)Stream_Buffer(s), + (ULONG)Stream_Capacity(s), &BytesReturned) == FALSE) + { + WLog_ERR(TAG, "WTSVirtualChannelRead failed!"); + goto out; + } + + if (!Stream_CheckAndLogRequiredLength(TAG, s, CAM_HEADER_SIZE)) + return ERROR_NO_DATA; + + Stream_SetLength(s, BytesReturned); + Stream_Read_UINT8(s, header.Version); + Stream_Read_UINT8(s, header.MessageId); + + switch (header.MessageId) + { + case CAM_MSG_ID_SelectVersionRequest: + error = + enumerator_server_handle_select_version_request(&enumerator->context, s, &header); + break; + case CAM_MSG_ID_DeviceAddedNotification: + error = + enumerator_server_recv_device_added_notification(&enumerator->context, s, &header); + break; + case CAM_MSG_ID_DeviceRemovedNotification: + error = enumerator_server_recv_device_removed_notification(&enumerator->context, s, + &header); + break; + default: + WLog_ERR(TAG, "enumerator_process_message: unknown or invalid MessageId %" PRIu8 "", + header.MessageId); + break; + } + +out: + if (error) + WLog_ERR(TAG, "Response failed with error %" PRIu32 "!", error); + + return error; +} + +static UINT enumerator_server_context_poll_int(CamDevEnumServerContext* context) +{ + enumerator_server* enumerator = (enumerator_server*)context; + UINT error = ERROR_INTERNAL_ERROR; + + WINPR_ASSERT(enumerator); + + switch (enumerator->state) + { + case ENUMERATOR_INITIAL: + error = enumerator_server_open_channel(enumerator); + if (error) + WLog_ERR(TAG, "enumerator_server_open_channel failed with error %" PRIu32 "!", + error); + else + enumerator->state = ENUMERATOR_OPENED; + break; + case ENUMERATOR_OPENED: + error = enumerator_process_message(enumerator); + break; + } + + return error; +} + +static HANDLE enumerator_server_get_channel_handle(enumerator_server* enumerator) +{ + void* buffer = NULL; + DWORD BytesReturned = 0; + HANDLE ChannelEvent = NULL; + + WINPR_ASSERT(enumerator); + + if (WTSVirtualChannelQuery(enumerator->enumerator_channel, WTSVirtualEventHandle, &buffer, + &BytesReturned) == TRUE) + { + if (BytesReturned == sizeof(HANDLE)) + CopyMemory(&ChannelEvent, buffer, sizeof(HANDLE)); + + WTSFreeMemory(buffer); + } + + return ChannelEvent; +} + +static DWORD WINAPI enumerator_server_thread_func(LPVOID arg) +{ + DWORD nCount; + HANDLE events[2] = { 0 }; + enumerator_server* enumerator = (enumerator_server*)arg; + UINT error = CHANNEL_RC_OK; + DWORD status; + + WINPR_ASSERT(enumerator); + + nCount = 0; + events[nCount++] = enumerator->stopEvent; + + while ((error == CHANNEL_RC_OK) && (WaitForSingleObject(events[0], 0) != WAIT_OBJECT_0)) + { + switch (enumerator->state) + { + case ENUMERATOR_INITIAL: + error = enumerator_server_context_poll_int(&enumerator->context); + if (error == CHANNEL_RC_OK) + { + events[1] = enumerator_server_get_channel_handle(enumerator); + nCount = 2; + } + break; + case ENUMERATOR_OPENED: + status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE); + switch (status) + { + case WAIT_OBJECT_0: + break; + case WAIT_OBJECT_0 + 1: + case WAIT_TIMEOUT: + error = enumerator_server_context_poll_int(&enumerator->context); + break; + + case WAIT_FAILED: + default: + error = ERROR_INTERNAL_ERROR; + break; + } + break; + } + } + + WTSVirtualChannelClose(enumerator->enumerator_channel); + enumerator->enumerator_channel = NULL; + + if (error && enumerator->context.rdpcontext) + setChannelError(enumerator->context.rdpcontext, error, + "enumerator_server_thread_func reported an error"); + + ExitThread(error); + return error; +} + +static UINT enumerator_server_open(CamDevEnumServerContext* context) +{ + enumerator_server* enumerator = (enumerator_server*)context; + + WINPR_ASSERT(enumerator); + + if (!enumerator->externalThread && (enumerator->thread == NULL)) + { + enumerator->stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + if (!enumerator->stopEvent) + { + WLog_ERR(TAG, "CreateEvent failed!"); + return ERROR_INTERNAL_ERROR; + } + + enumerator->thread = + CreateThread(NULL, 0, enumerator_server_thread_func, enumerator, 0, NULL); + if (!enumerator->thread) + { + WLog_ERR(TAG, "CreateThread failed!"); + CloseHandle(enumerator->stopEvent); + enumerator->stopEvent = NULL; + return ERROR_INTERNAL_ERROR; + } + } + enumerator->isOpened = TRUE; + + return CHANNEL_RC_OK; +} + +static UINT enumerator_server_close(CamDevEnumServerContext* context) +{ + UINT error = CHANNEL_RC_OK; + enumerator_server* enumerator = (enumerator_server*)context; + + WINPR_ASSERT(enumerator); + + if (!enumerator->externalThread && enumerator->thread) + { + SetEvent(enumerator->stopEvent); + + if (WaitForSingleObject(enumerator->thread, INFINITE) == WAIT_FAILED) + { + error = GetLastError(); + WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "", error); + return error; + } + + CloseHandle(enumerator->thread); + CloseHandle(enumerator->stopEvent); + enumerator->thread = NULL; + enumerator->stopEvent = NULL; + } + if (enumerator->externalThread) + { + if (enumerator->state != ENUMERATOR_INITIAL) + { + WTSVirtualChannelClose(enumerator->enumerator_channel); + enumerator->enumerator_channel = NULL; + enumerator->state = ENUMERATOR_INITIAL; + } + } + enumerator->isOpened = FALSE; + + return error; +} + +static UINT enumerator_server_context_poll(CamDevEnumServerContext* context) +{ + enumerator_server* enumerator = (enumerator_server*)context; + + WINPR_ASSERT(enumerator); + + if (!enumerator->externalThread) + return ERROR_INTERNAL_ERROR; + + return enumerator_server_context_poll_int(context); +} + +static BOOL enumerator_server_context_handle(CamDevEnumServerContext* context, HANDLE* handle) +{ + enumerator_server* enumerator = (enumerator_server*)context; + + WINPR_ASSERT(enumerator); + WINPR_ASSERT(handle); + + if (!enumerator->externalThread) + return FALSE; + if (enumerator->state == ENUMERATOR_INITIAL) + return FALSE; + + *handle = enumerator_server_get_channel_handle(enumerator); + + return TRUE; +} + +static UINT enumerator_server_packet_send(CamDevEnumServerContext* context, wStream* s) +{ + enumerator_server* enumerator = (enumerator_server*)context; + UINT error = CHANNEL_RC_OK; + ULONG written; + + if (!WTSVirtualChannelWrite(enumerator->enumerator_channel, (PCHAR)Stream_Buffer(s), + Stream_GetPosition(s), &written)) + { + WLog_ERR(TAG, "WTSVirtualChannelWrite failed!"); + error = ERROR_INTERNAL_ERROR; + goto out; + } + + if (written < Stream_GetPosition(s)) + { + WLog_WARN(TAG, "Unexpected bytes written: %" PRIu32 "/%" PRIuz "", written, + Stream_GetPosition(s)); + } + +out: + Stream_Free(s, TRUE); + return error; +} + +static UINT enumerator_send_select_version_response_pdu( + CamDevEnumServerContext* context, const CAM_SELECT_VERSION_RESPONSE* selectVersionResponse) +{ + wStream* s; + + s = Stream_New(NULL, CAM_HEADER_SIZE); + if (!s) + { + WLog_ERR(TAG, "Stream_New failed!"); + return ERROR_NOT_ENOUGH_MEMORY; + } + + Stream_Write_UINT8(s, selectVersionResponse->Header.Version); + Stream_Write_UINT8(s, selectVersionResponse->Header.MessageId); + + return enumerator_server_packet_send(context, s); +} + +CamDevEnumServerContext* cam_dev_enum_server_context_new(HANDLE vcm) +{ + enumerator_server* enumerator = (enumerator_server*)calloc(1, sizeof(enumerator_server)); + + if (!enumerator) + return NULL; + + enumerator->context.vcm = vcm; + enumerator->context.Initialize = enumerator_server_initialize; + enumerator->context.Open = enumerator_server_open; + enumerator->context.Close = enumerator_server_close; + enumerator->context.Poll = enumerator_server_context_poll; + enumerator->context.ChannelHandle = enumerator_server_context_handle; + + enumerator->context.SelectVersionResponse = enumerator_send_select_version_response_pdu; + + enumerator->buffer = Stream_New(NULL, 4096); + if (!enumerator->buffer) + goto fail; + + return &enumerator->context; +fail: + cam_dev_enum_server_context_free(&enumerator->context); + return NULL; +} + +void cam_dev_enum_server_context_free(CamDevEnumServerContext* context) +{ + enumerator_server* enumerator = (enumerator_server*)context; + + if (enumerator) + { + enumerator_server_close(context); + Stream_Free(enumerator->buffer, TRUE); + } + + free(enumerator); +} diff --git a/channels/rdpecam/server/camera_device_main.c b/channels/rdpecam/server/camera_device_main.c new file mode 100644 index 000000000000..67702d89dd18 --- /dev/null +++ b/channels/rdpecam/server/camera_device_main.c @@ -0,0 +1,974 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Video Capture Virtual Channel Extension + * + * Copyright 2022 Pascal Nowack + * + * 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include + +#define TAG CHANNELS_TAG("camera-device.server") + +typedef enum +{ + CAMERA_DEVICE_INITIAL, + CAMERA_DEVICE_OPENED, +} eCameraDeviceChannelState; + +typedef struct +{ + CameraDeviceServerContext context; + + HANDLE stopEvent; + + HANDLE thread; + void* device_channel; + + DWORD SessionId; + + BOOL isOpened; + BOOL externalThread; + + /* Channel state */ + eCameraDeviceChannelState state; + + wStream* buffer; +} device_server; + +static UINT device_server_initialize(CameraDeviceServerContext* context, BOOL externalThread) +{ + UINT error = CHANNEL_RC_OK; + device_server* device = (device_server*)context; + + WINPR_ASSERT(device); + + if (device->isOpened) + { + WLog_WARN(TAG, "Application error: Camera channel already initialized, " + "calling in this state is not possible!"); + return ERROR_INVALID_STATE; + } + + device->externalThread = externalThread; + + return error; +} + +static UINT device_server_open_channel(device_server* device) +{ + CameraDeviceServerContext* context = &device->context; + DWORD Error = ERROR_SUCCESS; + HANDLE hEvent; + DWORD BytesReturned = 0; + PULONG pSessionId = NULL; + UINT32 channelId; + BOOL status = TRUE; + + WINPR_ASSERT(device); + + if (WTSQuerySessionInformationA(device->context.vcm, WTS_CURRENT_SESSION, WTSSessionId, + (LPSTR*)&pSessionId, &BytesReturned) == FALSE) + { + WLog_ERR(TAG, "WTSQuerySessionInformationA failed!"); + return ERROR_INTERNAL_ERROR; + } + + device->SessionId = (DWORD)*pSessionId; + WTSFreeMemory(pSessionId); + hEvent = WTSVirtualChannelManagerGetEventHandle(device->context.vcm); + + if (WaitForSingleObject(hEvent, 1000) == WAIT_FAILED) + { + Error = GetLastError(); + WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "!", Error); + return Error; + } + + device->device_channel = WTSVirtualChannelOpenEx(device->SessionId, context->virtualChannelName, + WTS_CHANNEL_OPTION_DYNAMIC); + if (!device->device_channel) + { + Error = GetLastError(); + WLog_ERR(TAG, "WTSVirtualChannelOpenEx failed with error %" PRIu32 "!", Error); + return Error; + } + + channelId = WTSChannelGetIdByHandle(device->device_channel); + + IFCALLRET(context->ChannelIdAssigned, status, context, channelId); + if (!status) + { + WLog_ERR(TAG, "context->ChannelIdAssigned failed!"); + return ERROR_INTERNAL_ERROR; + } + + return Error; +} + +static UINT device_server_handle_success_response(CameraDeviceServerContext* context, wStream* s, + const CAM_SHARED_MSG_HEADER* header) +{ + CAM_SUCCESS_RESPONSE pdu = {}; + UINT error = CHANNEL_RC_OK; + + WINPR_ASSERT(context); + WINPR_ASSERT(header); + + pdu.Header = *header; + + IFCALLRET(context->SuccessResponse, error, context, &pdu); + if (error) + WLog_ERR(TAG, "context->SuccessResponse failed with error %" PRIu32 "", error); + + return error; +} + +static UINT device_server_recv_error_response(CameraDeviceServerContext* context, wStream* s, + const CAM_SHARED_MSG_HEADER* header) +{ + CAM_ERROR_RESPONSE pdu = {}; + UINT error = CHANNEL_RC_OK; + + WINPR_ASSERT(context); + WINPR_ASSERT(header); + + pdu.Header = *header; + + if (!Stream_CheckAndLogRequiredLength(TAG, s, 4)) + return ERROR_NO_DATA; + + Stream_Read_UINT32(s, pdu.ErrorCode); + + IFCALLRET(context->ErrorResponse, error, context, &pdu); + if (error) + WLog_ERR(TAG, "context->ErrorResponse failed with error %" PRIu32 "", error); + + return error; +} + +static UINT device_server_recv_stream_list_response(CameraDeviceServerContext* context, wStream* s, + const CAM_SHARED_MSG_HEADER* header) +{ + CAM_STREAM_LIST_RESPONSE pdu = {}; + UINT error = CHANNEL_RC_OK; + BYTE i; + + WINPR_ASSERT(context); + WINPR_ASSERT(header); + + pdu.Header = *header; + + if (!Stream_CheckAndLogRequiredLength(TAG, s, 5)) + return ERROR_NO_DATA; + + pdu.N_Descriptions = MIN(Stream_GetRemainingLength(s) / 5, 255); + + for (i = 0; i < pdu.N_Descriptions; ++i) + { + CAM_STREAM_DESCRIPTION* StreamDescription = &pdu.StreamDescriptions[i]; + + Stream_Read_UINT16(s, StreamDescription->FrameSourceTypes); + Stream_Read_UINT8(s, StreamDescription->StreamCategory); + Stream_Read_UINT8(s, StreamDescription->Selected); + Stream_Read_UINT8(s, StreamDescription->CanBeShared); + } + + IFCALLRET(context->StreamListResponse, error, context, &pdu); + if (error) + WLog_ERR(TAG, "context->StreamListResponse failed with error %" PRIu32 "", error); + + return error; +} + +static UINT device_server_recv_media_type_list_response(CameraDeviceServerContext* context, + wStream* s, + const CAM_SHARED_MSG_HEADER* header) +{ + CAM_MEDIA_TYPE_LIST_RESPONSE pdu = {}; + UINT error = CHANNEL_RC_OK; + BYTE i; + + WINPR_ASSERT(context); + WINPR_ASSERT(header); + + pdu.Header = *header; + + if (!Stream_CheckAndLogRequiredLength(TAG, s, 26)) + return ERROR_NO_DATA; + + pdu.N_Descriptions = Stream_GetRemainingLength(s) / 26; + + pdu.MediaTypeDescriptions = calloc(pdu.N_Descriptions, sizeof(CAM_MEDIA_TYPE_DESCRIPTION)); + if (!pdu.MediaTypeDescriptions) + { + WLog_ERR(TAG, "Failed to allocate %zu CAM_MEDIA_TYPE_DESCRIPTION structs", + pdu.N_Descriptions); + return ERROR_NOT_ENOUGH_MEMORY; + } + + for (i = 0; i < pdu.N_Descriptions; ++i) + { + CAM_MEDIA_TYPE_DESCRIPTION* MediaTypeDescriptions = &pdu.MediaTypeDescriptions[i]; + + Stream_Read_UINT8(s, MediaTypeDescriptions->Format); + Stream_Read_UINT32(s, MediaTypeDescriptions->Width); + Stream_Read_UINT32(s, MediaTypeDescriptions->Height); + Stream_Read_UINT32(s, MediaTypeDescriptions->FrameRateNumerator); + Stream_Read_UINT32(s, MediaTypeDescriptions->FrameRateDenominator); + Stream_Read_UINT32(s, MediaTypeDescriptions->PixelAspectRatioNumerator); + Stream_Read_UINT32(s, MediaTypeDescriptions->PixelAspectRatioDenominator); + Stream_Read_UINT8(s, MediaTypeDescriptions->Flags); + } + + IFCALLRET(context->MediaTypeListResponse, error, context, &pdu); + if (error) + WLog_ERR(TAG, "context->MediaTypeListResponse failed with error %" PRIu32 "", error); + + free(pdu.MediaTypeDescriptions); + + return error; +} + +static UINT device_server_recv_current_media_type_response(CameraDeviceServerContext* context, + wStream* s, + const CAM_SHARED_MSG_HEADER* header) +{ + CAM_CURRENT_MEDIA_TYPE_RESPONSE pdu = {}; + UINT error = CHANNEL_RC_OK; + + WINPR_ASSERT(context); + WINPR_ASSERT(header); + + pdu.Header = *header; + + if (!Stream_CheckAndLogRequiredLength(TAG, s, 26)) + return ERROR_NO_DATA; + + Stream_Read_UINT8(s, pdu.MediaTypeDescription.Format); + Stream_Read_UINT32(s, pdu.MediaTypeDescription.Width); + Stream_Read_UINT32(s, pdu.MediaTypeDescription.Height); + Stream_Read_UINT32(s, pdu.MediaTypeDescription.FrameRateNumerator); + Stream_Read_UINT32(s, pdu.MediaTypeDescription.FrameRateDenominator); + Stream_Read_UINT32(s, pdu.MediaTypeDescription.PixelAspectRatioNumerator); + Stream_Read_UINT32(s, pdu.MediaTypeDescription.PixelAspectRatioDenominator); + Stream_Read_UINT8(s, pdu.MediaTypeDescription.Flags); + + IFCALLRET(context->CurrentMediaTypeResponse, error, context, &pdu); + if (error) + WLog_ERR(TAG, "context->CurrentMediaTypeResponse failed with error %" PRIu32 "", error); + + return error; +} + +static UINT device_server_recv_sample_response(CameraDeviceServerContext* context, wStream* s, + const CAM_SHARED_MSG_HEADER* header) +{ + CAM_SAMPLE_RESPONSE pdu = {}; + UINT error = CHANNEL_RC_OK; + + WINPR_ASSERT(context); + WINPR_ASSERT(header); + + pdu.Header = *header; + + if (!Stream_CheckAndLogRequiredLength(TAG, s, 1)) + return ERROR_NO_DATA; + + Stream_Read_UINT8(s, pdu.StreamIndex); + + pdu.SampleSize = Stream_GetRemainingLength(s); + pdu.Sample = Stream_Pointer(s); + + IFCALLRET(context->SampleResponse, error, context, &pdu); + if (error) + WLog_ERR(TAG, "context->SampleResponse failed with error %" PRIu32 "", error); + + return error; +} + +static UINT device_server_recv_sample_error_response(CameraDeviceServerContext* context, wStream* s, + const CAM_SHARED_MSG_HEADER* header) +{ + CAM_SAMPLE_ERROR_RESPONSE pdu = {}; + UINT error = CHANNEL_RC_OK; + + WINPR_ASSERT(context); + WINPR_ASSERT(header); + + pdu.Header = *header; + + if (!Stream_CheckAndLogRequiredLength(TAG, s, 5)) + return ERROR_NO_DATA; + + Stream_Read_UINT8(s, pdu.StreamIndex); + Stream_Read_UINT32(s, pdu.ErrorCode); + + IFCALLRET(context->SampleErrorResponse, error, context, &pdu); + if (error) + WLog_ERR(TAG, "context->SampleErrorResponse failed with error %" PRIu32 "", error); + + return error; +} + +static UINT device_server_recv_property_list_response(CameraDeviceServerContext* context, + wStream* s, + const CAM_SHARED_MSG_HEADER* header) +{ + CAM_PROPERTY_LIST_RESPONSE pdu = {}; + UINT error = CHANNEL_RC_OK; + + WINPR_ASSERT(context); + WINPR_ASSERT(header); + + pdu.Header = *header; + + pdu.N_Properties = Stream_GetRemainingLength(s) / 19; + + if (pdu.N_Properties > 0) + { + size_t i; + + pdu.Properties = calloc(pdu.N_Properties, sizeof(CAM_PROPERTY_DESCRIPTION)); + if (!pdu.Properties) + { + WLog_ERR(TAG, "Failed to allocate %zu CAM_PROPERTY_DESCRIPTION structs", + pdu.N_Properties); + return ERROR_NOT_ENOUGH_MEMORY; + } + + for (i = 0; i < pdu.N_Properties; ++i) + { + Stream_Read_UINT8(s, pdu.Properties[i].PropertySet); + Stream_Read_UINT8(s, pdu.Properties[i].PropertyId); + Stream_Read_UINT8(s, pdu.Properties[i].Capabilities); + Stream_Read_INT32(s, pdu.Properties[i].MinValue); + Stream_Read_INT32(s, pdu.Properties[i].MaxValue); + Stream_Read_INT32(s, pdu.Properties[i].Step); + Stream_Read_INT32(s, pdu.Properties[i].DefaultValue); + } + } + + IFCALLRET(context->PropertyListResponse, error, context, &pdu); + if (error) + WLog_ERR(TAG, "context->PropertyListResponse failed with error %" PRIu32 "", error); + + free(pdu.Properties); + + return error; +} + +static UINT device_server_recv_property_value_response(CameraDeviceServerContext* context, + wStream* s, + const CAM_SHARED_MSG_HEADER* header) +{ + CAM_PROPERTY_VALUE_RESPONSE pdu = {}; + UINT error = CHANNEL_RC_OK; + + WINPR_ASSERT(context); + WINPR_ASSERT(header); + + pdu.Header = *header; + + if (!Stream_CheckAndLogRequiredLength(TAG, s, 5)) + return ERROR_NO_DATA; + + Stream_Read_UINT8(s, pdu.PropertyValue.Mode); + Stream_Read_INT32(s, pdu.PropertyValue.Value); + + IFCALLRET(context->PropertyValueResponse, error, context, &pdu); + if (error) + WLog_ERR(TAG, "context->PropertyValueResponse failed with error %" PRIu32 "", error); + + return error; +} + +static UINT device_process_message(device_server* device) +{ + BOOL rc; + UINT error = ERROR_INTERNAL_ERROR; + ULONG BytesReturned; + CAM_SHARED_MSG_HEADER header = {}; + wStream* s; + + WINPR_ASSERT(device); + WINPR_ASSERT(device->device_channel); + + s = device->buffer; + WINPR_ASSERT(s); + + Stream_SetPosition(s, 0); + rc = WTSVirtualChannelRead(device->device_channel, 0, NULL, 0, &BytesReturned); + if (!rc) + goto out; + + if (BytesReturned < 1) + { + error = CHANNEL_RC_OK; + goto out; + } + + if (!Stream_EnsureRemainingCapacity(s, BytesReturned)) + { + WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!"); + error = CHANNEL_RC_NO_MEMORY; + goto out; + } + + if (WTSVirtualChannelRead(device->device_channel, 0, (PCHAR)Stream_Buffer(s), + (ULONG)Stream_Capacity(s), &BytesReturned) == FALSE) + { + WLog_ERR(TAG, "WTSVirtualChannelRead failed!"); + goto out; + } + + if (!Stream_CheckAndLogRequiredLength(TAG, s, CAM_HEADER_SIZE)) + return ERROR_NO_DATA; + + Stream_SetLength(s, BytesReturned); + Stream_Read_UINT8(s, header.Version); + Stream_Read_UINT8(s, header.MessageId); + + switch (header.MessageId) + { + case CAM_MSG_ID_SuccessResponse: + error = device_server_handle_success_response(&device->context, s, &header); + break; + case CAM_MSG_ID_ErrorResponse: + error = device_server_recv_error_response(&device->context, s, &header); + break; + case CAM_MSG_ID_StreamListResponse: + error = device_server_recv_stream_list_response(&device->context, s, &header); + break; + case CAM_MSG_ID_MediaTypeListResponse: + error = device_server_recv_media_type_list_response(&device->context, s, &header); + break; + case CAM_MSG_ID_CurrentMediaTypeResponse: + error = device_server_recv_current_media_type_response(&device->context, s, &header); + break; + case CAM_MSG_ID_SampleResponse: + error = device_server_recv_sample_response(&device->context, s, &header); + break; + case CAM_MSG_ID_SampleErrorResponse: + error = device_server_recv_sample_error_response(&device->context, s, &header); + break; + case CAM_MSG_ID_PropertyListResponse: + error = device_server_recv_property_list_response(&device->context, s, &header); + break; + case CAM_MSG_ID_PropertyValueResponse: + error = device_server_recv_property_value_response(&device->context, s, &header); + break; + default: + WLog_ERR(TAG, "device_process_message: unknown or invalid MessageId %" PRIu8 "", + header.MessageId); + break; + } + +out: + if (error) + WLog_ERR(TAG, "Response failed with error %" PRIu32 "!", error); + + return error; +} + +static UINT device_server_context_poll_int(CameraDeviceServerContext* context) +{ + device_server* device = (device_server*)context; + UINT error = ERROR_INTERNAL_ERROR; + + WINPR_ASSERT(device); + + switch (device->state) + { + case CAMERA_DEVICE_INITIAL: + error = device_server_open_channel(device); + if (error) + WLog_ERR(TAG, "device_server_open_channel failed with error %" PRIu32 "!", error); + else + device->state = CAMERA_DEVICE_OPENED; + break; + case CAMERA_DEVICE_OPENED: + error = device_process_message(device); + break; + } + + return error; +} + +static HANDLE device_server_get_channel_handle(device_server* device) +{ + void* buffer = NULL; + DWORD BytesReturned = 0; + HANDLE ChannelEvent = NULL; + + WINPR_ASSERT(device); + + if (WTSVirtualChannelQuery(device->device_channel, WTSVirtualEventHandle, &buffer, + &BytesReturned) == TRUE) + { + if (BytesReturned == sizeof(HANDLE)) + CopyMemory(&ChannelEvent, buffer, sizeof(HANDLE)); + + WTSFreeMemory(buffer); + } + + return ChannelEvent; +} + +static DWORD WINAPI device_server_thread_func(LPVOID arg) +{ + DWORD nCount; + HANDLE events[2] = { 0 }; + device_server* device = (device_server*)arg; + UINT error = CHANNEL_RC_OK; + DWORD status; + + WINPR_ASSERT(device); + + nCount = 0; + events[nCount++] = device->stopEvent; + + while ((error == CHANNEL_RC_OK) && (WaitForSingleObject(events[0], 0) != WAIT_OBJECT_0)) + { + switch (device->state) + { + case CAMERA_DEVICE_INITIAL: + error = device_server_context_poll_int(&device->context); + if (error == CHANNEL_RC_OK) + { + events[1] = device_server_get_channel_handle(device); + nCount = 2; + } + break; + case CAMERA_DEVICE_OPENED: + status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE); + switch (status) + { + case WAIT_OBJECT_0: + break; + case WAIT_OBJECT_0 + 1: + case WAIT_TIMEOUT: + error = device_server_context_poll_int(&device->context); + break; + + case WAIT_FAILED: + default: + error = ERROR_INTERNAL_ERROR; + break; + } + break; + } + } + + WTSVirtualChannelClose(device->device_channel); + device->device_channel = NULL; + + if (error && device->context.rdpcontext) + setChannelError(device->context.rdpcontext, error, + "device_server_thread_func reported an error"); + + ExitThread(error); + return error; +} + +static UINT device_server_open(CameraDeviceServerContext* context) +{ + device_server* device = (device_server*)context; + + WINPR_ASSERT(device); + + if (!device->externalThread && (device->thread == NULL)) + { + device->stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + if (!device->stopEvent) + { + WLog_ERR(TAG, "CreateEvent failed!"); + return ERROR_INTERNAL_ERROR; + } + + device->thread = CreateThread(NULL, 0, device_server_thread_func, device, 0, NULL); + if (!device->thread) + { + WLog_ERR(TAG, "CreateThread failed!"); + CloseHandle(device->stopEvent); + device->stopEvent = NULL; + return ERROR_INTERNAL_ERROR; + } + } + device->isOpened = TRUE; + + return CHANNEL_RC_OK; +} + +static UINT device_server_close(CameraDeviceServerContext* context) +{ + UINT error = CHANNEL_RC_OK; + device_server* device = (device_server*)context; + + WINPR_ASSERT(device); + + if (!device->externalThread && device->thread) + { + SetEvent(device->stopEvent); + + if (WaitForSingleObject(device->thread, INFINITE) == WAIT_FAILED) + { + error = GetLastError(); + WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "", error); + return error; + } + + CloseHandle(device->thread); + CloseHandle(device->stopEvent); + device->thread = NULL; + device->stopEvent = NULL; + } + if (device->externalThread) + { + if (device->state != CAMERA_DEVICE_INITIAL) + { + WTSVirtualChannelClose(device->device_channel); + device->device_channel = NULL; + device->state = CAMERA_DEVICE_INITIAL; + } + } + device->isOpened = FALSE; + + return error; +} + +static UINT device_server_context_poll(CameraDeviceServerContext* context) +{ + device_server* device = (device_server*)context; + + WINPR_ASSERT(device); + + if (!device->externalThread) + return ERROR_INTERNAL_ERROR; + + return device_server_context_poll_int(context); +} + +static BOOL device_server_context_handle(CameraDeviceServerContext* context, HANDLE* handle) +{ + device_server* device = (device_server*)context; + + WINPR_ASSERT(device); + WINPR_ASSERT(handle); + + if (!device->externalThread) + return FALSE; + if (device->state == CAMERA_DEVICE_INITIAL) + return FALSE; + + *handle = device_server_get_channel_handle(device); + + return TRUE; +} + +static wStream* device_server_packet_new(size_t size, BYTE version, BYTE messageId) +{ + wStream* s; + + WINPR_ASSERT(size > 0); + + s = Stream_New(NULL, size); + if (!s) + { + WLog_ERR(TAG, "Stream_New failed!"); + return NULL; + } + + Stream_Write_UINT8(s, version); + Stream_Write_UINT8(s, messageId); + + return s; +} + +static UINT device_server_packet_send(CameraDeviceServerContext* context, wStream* s) +{ + device_server* device = (device_server*)context; + UINT error = CHANNEL_RC_OK; + ULONG written; + + WINPR_ASSERT(context); + WINPR_ASSERT(s); + + if (!WTSVirtualChannelWrite(device->device_channel, (PCHAR)Stream_Buffer(s), + Stream_GetPosition(s), &written)) + { + WLog_ERR(TAG, "WTSVirtualChannelWrite failed!"); + error = ERROR_INTERNAL_ERROR; + goto out; + } + + if (written < Stream_GetPosition(s)) + { + WLog_WARN(TAG, "Unexpected bytes written: %" PRIu32 "/%" PRIuz "", written, + Stream_GetPosition(s)); + } + +out: + Stream_Free(s, TRUE); + return error; +} + +static UINT device_server_write_and_send_header(CameraDeviceServerContext* context, BYTE messageId) +{ + wStream* s; + + WINPR_ASSERT(context); + + s = device_server_packet_new(CAM_HEADER_SIZE, context->protocolVersion, messageId); + if (!s) + return ERROR_NOT_ENOUGH_MEMORY; + + return device_server_packet_send(context, s); +} + +static UINT +device_send_activate_device_request_pdu(CameraDeviceServerContext* context, + const CAM_ACTIVATE_DEVICE_REQUEST* activateDeviceRequest) +{ + WINPR_ASSERT(context); + + return device_server_write_and_send_header(context, CAM_MSG_ID_ActivateDeviceRequest); +} + +static UINT device_send_deactivate_device_request_pdu( + CameraDeviceServerContext* context, + const CAM_DEACTIVATE_DEVICE_REQUEST* deactivateDeviceRequest) +{ + WINPR_ASSERT(context); + + return device_server_write_and_send_header(context, CAM_MSG_ID_DeactivateDeviceRequest); +} + +static UINT device_send_stream_list_request_pdu(CameraDeviceServerContext* context, + const CAM_STREAM_LIST_REQUEST* streamListRequest) +{ + WINPR_ASSERT(context); + + return device_server_write_and_send_header(context, CAM_MSG_ID_StreamListRequest); +} + +static UINT +device_send_media_type_list_request_pdu(CameraDeviceServerContext* context, + const CAM_MEDIA_TYPE_LIST_REQUEST* mediaTypeListRequest) +{ + wStream* s; + + WINPR_ASSERT(context); + WINPR_ASSERT(mediaTypeListRequest); + + s = device_server_packet_new(CAM_HEADER_SIZE + 1, context->protocolVersion, + CAM_MSG_ID_MediaTypeListRequest); + if (!s) + return ERROR_NOT_ENOUGH_MEMORY; + + Stream_Write_UINT8(s, mediaTypeListRequest->StreamIndex); + + return device_server_packet_send(context, s); +} + +static UINT device_send_current_media_type_request_pdu( + CameraDeviceServerContext* context, + const CAM_CURRENT_MEDIA_TYPE_REQUEST* currentMediaTypeRequest) +{ + wStream* s; + + WINPR_ASSERT(context); + WINPR_ASSERT(currentMediaTypeRequest); + + s = device_server_packet_new(CAM_HEADER_SIZE + 1, context->protocolVersion, + CAM_MSG_ID_CurrentMediaTypeRequest); + if (!s) + return ERROR_NOT_ENOUGH_MEMORY; + + Stream_Write_UINT8(s, currentMediaTypeRequest->StreamIndex); + + return device_server_packet_send(context, s); +} + +static UINT +device_send_start_streams_request_pdu(CameraDeviceServerContext* context, + const CAM_START_STREAMS_REQUEST* startStreamsRequest) +{ + wStream* s; + size_t i; + + WINPR_ASSERT(context); + WINPR_ASSERT(startStreamsRequest); + + s = device_server_packet_new(CAM_HEADER_SIZE + startStreamsRequest->N_Infos * 27, + context->protocolVersion, CAM_MSG_ID_StartStreamsRequest); + if (!s) + return ERROR_NOT_ENOUGH_MEMORY; + + for (i = 0; i < startStreamsRequest->N_Infos; ++i) + { + const CAM_START_STREAM_INFO* info = &startStreamsRequest->StartStreamsInfo[i]; + const CAM_MEDIA_TYPE_DESCRIPTION* description = &info->MediaTypeDescription; + + Stream_Write_UINT8(s, info->StreamIndex); + + Stream_Write_UINT8(s, description->Format); + Stream_Write_UINT32(s, description->Width); + Stream_Write_UINT32(s, description->Height); + Stream_Write_UINT32(s, description->FrameRateNumerator); + Stream_Write_UINT32(s, description->FrameRateDenominator); + Stream_Write_UINT32(s, description->PixelAspectRatioNumerator); + Stream_Write_UINT32(s, description->PixelAspectRatioDenominator); + Stream_Write_UINT8(s, description->Flags); + } + + return device_server_packet_send(context, s); +} + +static UINT device_send_stop_streams_request_pdu(CameraDeviceServerContext* context, + const CAM_STOP_STREAMS_REQUEST* stopStreamsRequest) +{ + WINPR_ASSERT(context); + + return device_server_write_and_send_header(context, CAM_MSG_ID_StopStreamsRequest); +} + +static UINT device_send_sample_request_pdu(CameraDeviceServerContext* context, + const CAM_SAMPLE_REQUEST* sampleRequest) +{ + wStream* s; + + WINPR_ASSERT(context); + WINPR_ASSERT(sampleRequest); + + s = device_server_packet_new(CAM_HEADER_SIZE + 1, context->protocolVersion, + CAM_MSG_ID_SampleRequest); + if (!s) + return ERROR_NOT_ENOUGH_MEMORY; + + Stream_Write_UINT8(s, sampleRequest->StreamIndex); + + return device_server_packet_send(context, s); +} + +static UINT +device_send_property_list_request_pdu(CameraDeviceServerContext* context, + const CAM_PROPERTY_LIST_REQUEST* propertyListRequest) +{ + WINPR_ASSERT(context); + + return device_server_write_and_send_header(context, CAM_MSG_ID_PropertyListRequest); +} + +static UINT +device_send_property_value_request_pdu(CameraDeviceServerContext* context, + const CAM_PROPERTY_VALUE_REQUEST* propertyValueRequest) +{ + wStream* s; + + WINPR_ASSERT(context); + WINPR_ASSERT(propertyValueRequest); + + s = device_server_packet_new(CAM_HEADER_SIZE + 2, context->protocolVersion, + CAM_MSG_ID_PropertyValueRequest); + if (!s) + return ERROR_NOT_ENOUGH_MEMORY; + + Stream_Write_UINT8(s, propertyValueRequest->PropertySet); + Stream_Write_UINT8(s, propertyValueRequest->PropertyId); + + return device_server_packet_send(context, s); +} + +static UINT device_send_set_property_value_request_pdu( + CameraDeviceServerContext* context, + const CAM_SET_PROPERTY_VALUE_REQUEST* setPropertyValueRequest) +{ + wStream* s; + + WINPR_ASSERT(context); + WINPR_ASSERT(setPropertyValueRequest); + + s = device_server_packet_new(CAM_HEADER_SIZE + 2 + 5, context->protocolVersion, + CAM_MSG_ID_SetPropertyValueRequest); + if (!s) + return ERROR_NOT_ENOUGH_MEMORY; + + Stream_Write_UINT8(s, setPropertyValueRequest->PropertySet); + Stream_Write_UINT8(s, setPropertyValueRequest->PropertyId); + + Stream_Write_UINT8(s, setPropertyValueRequest->PropertyValue.Mode); + Stream_Write_INT32(s, setPropertyValueRequest->PropertyValue.Value); + + return device_server_packet_send(context, s); +} + +CameraDeviceServerContext* camera_device_server_context_new(HANDLE vcm) +{ + device_server* device = (device_server*)calloc(1, sizeof(device_server)); + + if (!device) + return NULL; + + device->context.vcm = vcm; + device->context.Initialize = device_server_initialize; + device->context.Open = device_server_open; + device->context.Close = device_server_close; + device->context.Poll = device_server_context_poll; + device->context.ChannelHandle = device_server_context_handle; + + device->context.ActivateDeviceRequest = device_send_activate_device_request_pdu; + device->context.DeactivateDeviceRequest = device_send_deactivate_device_request_pdu; + + device->context.StreamListRequest = device_send_stream_list_request_pdu; + device->context.MediaTypeListRequest = device_send_media_type_list_request_pdu; + device->context.CurrentMediaTypeRequest = device_send_current_media_type_request_pdu; + + device->context.StartStreamsRequest = device_send_start_streams_request_pdu; + device->context.StopStreamsRequest = device_send_stop_streams_request_pdu; + device->context.SampleRequest = device_send_sample_request_pdu; + + device->context.PropertyListRequest = device_send_property_list_request_pdu; + device->context.PropertyValueRequest = device_send_property_value_request_pdu; + device->context.SetPropertyValueRequest = device_send_set_property_value_request_pdu; + + device->buffer = Stream_New(NULL, 4096); + if (!device->buffer) + goto fail; + + return &device->context; +fail: + camera_device_server_context_free(&device->context); + return NULL; +} + +void camera_device_server_context_free(CameraDeviceServerContext* context) +{ + device_server* device = (device_server*)context; + + if (device) + { + device_server_close(context); + Stream_Free(device->buffer, TRUE); + } + + free(context->virtualChannelName); + + free(device); +} diff --git a/channels/server/channels.c b/channels/server/channels.c index 8d81269c60e6..ac7444467069 100644 --- a/channels/server/channels.c +++ b/channels/server/channels.c @@ -53,6 +53,8 @@ #include #include #include +#include +#include #if defined(CHANNEL_AINPUT_SERVER) #include @@ -75,6 +77,8 @@ void freerdp_channels_dummy(void) TelemetryServerContext* telemetry; RdpgfxServerContext* rdpgfx; DispServerContext* disp; + CamDevEnumServerContext* camera_enumerator; + CameraDeviceServerContext* camera_device; audin = audin_server_context_new(NULL); audin_server_context_free(audin); rdpsnd = rdpsnd_server_context_new(NULL); @@ -101,6 +105,10 @@ void freerdp_channels_dummy(void) rdpgfx_server_context_free(rdpgfx); disp = disp_server_context_new(NULL); disp_server_context_free(disp); + camera_enumerator = cam_dev_enum_server_context_new(NULL); + cam_dev_enum_server_context_free(camera_enumerator); + camera_device = camera_device_server_context_new(NULL); + camera_device_server_context_free(camera_device); #if defined(CHANNEL_AINPUT_SERVER) { ainput_server_context* ainput = ainput_server_context_new(NULL); diff --git a/config.h.in b/config.h.in index fdff6d90f2d9..315d4d24442a 100644 --- a/config.h.in +++ b/config.h.in @@ -81,6 +81,9 @@ #cmakedefine CHANNEL_AUDIN #cmakedefine CHANNEL_AUDIN_CLIENT #cmakedefine CHANNEL_AUDIN_SERVER +#cmakedefine CHANNEL_CAMERA +#cmakedefine CHANNEL_CAMERA_CLIENT +#cmakedefine CHANNEL_CAMERA_SERVER #cmakedefine CHANNEL_CLIPRDR #cmakedefine CHANNEL_CLIPRDR_CLIENT #cmakedefine CHANNEL_CLIPRDR_SERVER diff --git a/include/freerdp/channels/camera-device.h b/include/freerdp/channels/camera-device.h new file mode 100644 index 000000000000..adb97be20475 --- /dev/null +++ b/include/freerdp/channels/camera-device.h @@ -0,0 +1,335 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Video Capture Virtual Channel Extension + * + * Copyright 2022 Pascal Nowack + * + * 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_CHANNEL_CAMERA_DEVICE_H +#define FREERDP_CHANNEL_CAMERA_DEVICE_H + +#include +#include +#include + +#define CAM_DEVICE_ENUMERATOR_DVC_CHANNEL_NAME "RDCamera_Device_Enumerator" + +typedef enum +{ + CAM_MSG_ID_SuccessResponse = 0x01, + CAM_MSG_ID_ErrorResponse = 0x02, + CAM_MSG_ID_SelectVersionRequest = 0x03, + CAM_MSG_ID_SelectVersionResponse = 0x04, + CAM_MSG_ID_DeviceAddedNotification = 0x05, + CAM_MSG_ID_DeviceRemovedNotification = 0x06, + CAM_MSG_ID_ActivateDeviceRequest = 0x07, + CAM_MSG_ID_DeactivateDeviceRequest = 0x08, + CAM_MSG_ID_StreamListRequest = 0x09, + CAM_MSG_ID_StreamListResponse = 0x0A, + CAM_MSG_ID_MediaTypeListRequest = 0x0B, + CAM_MSG_ID_MediaTypeListResponse = 0x0C, + CAM_MSG_ID_CurrentMediaTypeRequest = 0x0D, + CAM_MSG_ID_CurrentMediaTypeResponse = 0x0E, + CAM_MSG_ID_StartStreamsRequest = 0x0F, + CAM_MSG_ID_StopStreamsRequest = 0x10, + CAM_MSG_ID_SampleRequest = 0x11, + CAM_MSG_ID_SampleResponse = 0x12, + CAM_MSG_ID_SampleErrorResponse = 0x13, + CAM_MSG_ID_PropertyListRequest = 0x14, + CAM_MSG_ID_PropertyListResponse = 0x15, + CAM_MSG_ID_PropertyValueRequest = 0x16, + CAM_MSG_ID_PropertyValueResponse = 0x17, + CAM_MSG_ID_SetPropertyValueRequest = 0x18, +} CAM_MSG_ID; + +#define CAM_HEADER_SIZE 2 + +typedef struct +{ + BYTE Version; + CAM_MSG_ID MessageId; +} CAM_SHARED_MSG_HEADER; + +/* Messages Exchanged on the Device Enumeration Channel (2.2.2) */ + +typedef struct +{ + CAM_SHARED_MSG_HEADER Header; +} CAM_SELECT_VERSION_REQUEST; + +typedef struct +{ + CAM_SHARED_MSG_HEADER Header; +} CAM_SELECT_VERSION_RESPONSE; + +typedef struct +{ + CAM_SHARED_MSG_HEADER Header; + WCHAR* DeviceName; + char* VirtualChannelName; +} CAM_DEVICE_ADDED_NOTIFICATION; + +typedef struct +{ + CAM_SHARED_MSG_HEADER Header; + char* VirtualChannelName; +} CAM_DEVICE_REMOVED_NOTIFICATION; + +/* Messages Exchanged on Device Channels (2.2.3) */ + +typedef struct +{ + CAM_SHARED_MSG_HEADER Header; +} CAM_SUCCESS_RESPONSE; + +typedef enum +{ + CAM_ERROR_CODE_UnexpectedError = 0x00000001, + CAM_ERROR_CODE_InvalidMessage = 0x00000002, + CAM_ERROR_CODE_NotInitialized = 0x00000003, + CAM_ERROR_CODE_InvalidRequest = 0x00000004, + CAM_ERROR_CODE_InvalidStreamNumber = 0x00000005, + CAM_ERROR_CODE_InvalidMediaType = 0x00000006, + CAM_ERROR_CODE_OutOfMemory = 0x00000007, + CAM_ERROR_CODE_ItemNotFound = 0x00000008, + CAM_ERROR_CODE_SetNotFound = 0x00000009, + CAM_ERROR_CODE_OperationNotSupported = 0x0000000A, +} CAM_ERROR_CODE; + +typedef struct +{ + CAM_SHARED_MSG_HEADER Header; + CAM_ERROR_CODE ErrorCode; +} CAM_ERROR_RESPONSE; + +typedef struct +{ + CAM_SHARED_MSG_HEADER Header; +} CAM_ACTIVATE_DEVICE_REQUEST; + +typedef struct +{ + CAM_SHARED_MSG_HEADER Header; +} CAM_DEACTIVATE_DEVICE_REQUEST; + +typedef struct +{ + CAM_SHARED_MSG_HEADER Header; +} CAM_STREAM_LIST_REQUEST; + +typedef enum +{ + CAM_STREAM_FRAME_SOURCE_TYPE_Color = 0x0001, + CAM_STREAM_FRAME_SOURCE_TYPE_Infrared = 0x0002, + CAM_STREAM_FRAME_SOURCE_TYPE_Custom = 0x0008, +} CAM_STREAM_FRAME_SOURCE_TYPES; + +typedef enum +{ + CAM_STREAM_CATEGORY_Capture = 0x01, +} CAM_STREAM_CATEGORY; + +typedef struct +{ + CAM_STREAM_FRAME_SOURCE_TYPES FrameSourceTypes; + CAM_STREAM_CATEGORY StreamCategory; + BYTE Selected; + BYTE CanBeShared; +} CAM_STREAM_DESCRIPTION; + +typedef struct +{ + CAM_SHARED_MSG_HEADER Header; + BYTE N_Descriptions; + CAM_STREAM_DESCRIPTION StreamDescriptions[255]; +} CAM_STREAM_LIST_RESPONSE; + +typedef struct +{ + CAM_SHARED_MSG_HEADER Header; + BYTE StreamIndex; +} CAM_MEDIA_TYPE_LIST_REQUEST; + +typedef enum +{ + CAM_MEDIA_FORMAT_H264 = 0x01, + CAM_MEDIA_FORMAT_MJPG = 0x02, + CAM_MEDIA_FORMAT_YUY2 = 0x03, + CAM_MEDIA_FORMAT_NV12 = 0x04, + CAM_MEDIA_FORMAT_I420 = 0x05, + CAM_MEDIA_FORMAT_RGB24 = 0x06, + CAM_MEDIA_FORMAT_RGB32 = 0x07, +} CAM_MEDIA_FORMAT; + +typedef enum +{ + CAM_MEDIA_TYPE_DESCRIPTION_FLAG_DecodingRequired = 0x01, + CAM_MEDIA_TYPE_DESCRIPTION_FLAG_BottomUpImage = 0x02, +} CAM_MEDIA_TYPE_DESCRIPTION_FLAGS; + +typedef struct +{ + CAM_MEDIA_FORMAT Format; + UINT32 Width; + UINT32 Height; + UINT32 FrameRateNumerator; + UINT32 FrameRateDenominator; + UINT32 PixelAspectRatioNumerator; + UINT32 PixelAspectRatioDenominator; + CAM_MEDIA_TYPE_DESCRIPTION_FLAGS Flags; +} CAM_MEDIA_TYPE_DESCRIPTION; + +typedef struct +{ + CAM_SHARED_MSG_HEADER Header; + size_t N_Descriptions; + CAM_MEDIA_TYPE_DESCRIPTION* MediaTypeDescriptions; +} CAM_MEDIA_TYPE_LIST_RESPONSE; + +typedef struct +{ + CAM_SHARED_MSG_HEADER Header; + BYTE StreamIndex; +} CAM_CURRENT_MEDIA_TYPE_REQUEST; + +typedef struct +{ + CAM_SHARED_MSG_HEADER Header; + CAM_MEDIA_TYPE_DESCRIPTION MediaTypeDescription; +} CAM_CURRENT_MEDIA_TYPE_RESPONSE; + +typedef struct +{ + BYTE StreamIndex; + CAM_MEDIA_TYPE_DESCRIPTION MediaTypeDescription; +} CAM_START_STREAM_INFO; + +typedef struct +{ + CAM_SHARED_MSG_HEADER Header; + BYTE N_Infos; + CAM_START_STREAM_INFO StartStreamsInfo[255]; +} CAM_START_STREAMS_REQUEST; + +typedef struct +{ + CAM_SHARED_MSG_HEADER Header; +} CAM_STOP_STREAMS_REQUEST; + +typedef struct +{ + CAM_SHARED_MSG_HEADER Header; + BYTE StreamIndex; +} CAM_SAMPLE_REQUEST; + +typedef struct +{ + CAM_SHARED_MSG_HEADER Header; + BYTE StreamIndex; + size_t SampleSize; + BYTE* Sample; +} CAM_SAMPLE_RESPONSE; + +typedef struct +{ + CAM_SHARED_MSG_HEADER Header; + BYTE StreamIndex; + CAM_ERROR_CODE ErrorCode; +} CAM_SAMPLE_ERROR_RESPONSE; + +typedef struct +{ + CAM_SHARED_MSG_HEADER Header; +} CAM_PROPERTY_LIST_REQUEST; + +typedef enum +{ + CAM_PROPERTY_SET_CameraControl = 0x01, + CAM_PROPERTY_SET_VideoProcAmp = 0x02, +} CAM_PROPERTY_SET; + +/* CameraControl properties */ +#define CAM_PROPERTY_ID_CAMERA_CONTROL_Exposure 0x01 +#define CAM_PROPERTY_ID_CAMERA_CONTROL_Focus 0x02 +#define CAM_PROPERTY_ID_CAMERA_CONTROL_Pan 0x03 +#define CAM_PROPERTY_ID_CAMERA_CONTROL_Roll 0x04 +#define CAM_PROPERTY_ID_CAMERA_CONTROL_Tilt 0x05 +#define CAM_PROPERTY_ID_CAMERA_CONTROL_Zoom 0x06 + +/* VideoProcAmp properties */ +#define CAM_PROPERTY_ID_VIDEO_PROC_AMP_BacklightCompensation 0x01 +#define CAM_PROPERTY_ID_VIDEO_PROC_AMP_Brightness 0x02 +#define CAM_PROPERTY_ID_VIDEO_PROC_AMP_Contrast 0x03 +#define CAM_PROPERTY_ID_VIDEO_PROC_AMP_Hue 0x04 +#define CAM_PROPERTY_ID_VIDEO_PROC_AMP_WhiteBalance 0x05 + +typedef enum +{ + CAM_PROPERTY_CAPABILITY_Manual = 0x01, + CAM_PROPERTY_CAPABILITY_Auto = 0x02, +} CAM_PROPERTY_CAPABILITIES; + +typedef struct +{ + CAM_PROPERTY_SET PropertySet; + BYTE PropertyId; + CAM_PROPERTY_CAPABILITIES Capabilities; + INT32 MinValue; + INT32 MaxValue; + INT32 Step; + INT32 DefaultValue; +} CAM_PROPERTY_DESCRIPTION; + +typedef struct +{ + CAM_SHARED_MSG_HEADER Header; + size_t N_Properties; + CAM_PROPERTY_DESCRIPTION* Properties; +} CAM_PROPERTY_LIST_RESPONSE; + +typedef struct +{ + CAM_SHARED_MSG_HEADER Header; + CAM_PROPERTY_SET PropertySet; + BYTE PropertyId; +} CAM_PROPERTY_VALUE_REQUEST; + +typedef enum +{ + CAM_PROPERTY_MODE_Manual = 0x01, + CAM_PROPERTY_MODE_Auto = 0x02, +} CAM_PROPERTY_MODE; + +typedef struct +{ + CAM_PROPERTY_MODE Mode; + INT32 Value; +} CAM_PROPERTY_VALUE; + +typedef struct +{ + CAM_SHARED_MSG_HEADER Header; + CAM_PROPERTY_VALUE PropertyValue; +} CAM_PROPERTY_VALUE_RESPONSE; + +typedef struct +{ + CAM_SHARED_MSG_HEADER Header; + CAM_PROPERTY_SET PropertySet; + BYTE PropertyId; + CAM_PROPERTY_VALUE PropertyValue; +} CAM_SET_PROPERTY_VALUE_REQUEST; + +#endif /* FREERDP_CHANNEL_CAMERA_DEVICE_H */ diff --git a/include/freerdp/server/camera-device-enumerator.h b/include/freerdp/server/camera-device-enumerator.h new file mode 100644 index 000000000000..230b4e49c8b4 --- /dev/null +++ b/include/freerdp/server/camera-device-enumerator.h @@ -0,0 +1,134 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Video Capture Virtual Channel Extension + * + * Copyright 2022 Pascal Nowack + * + * 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_CHANNEL_CAM_DEV_ENUM_SERVER_CAM_DEV_ENUM_H +#define FREERDP_CHANNEL_CAM_DEV_ENUM_SERVER_CAM_DEV_ENUM_H + +#include +#include + +typedef struct _cam_dev_enum_server_context CamDevEnumServerContext; + +typedef UINT (*psCamDevEnumServerServerOpen)(CamDevEnumServerContext* context); +typedef UINT (*psCamDevEnumServerServerClose)(CamDevEnumServerContext* context); + +typedef BOOL (*psCamDevEnumServerServerChannelIdAssigned)(CamDevEnumServerContext* context, + UINT32 channelId); + +typedef UINT (*psCamDevEnumServerServerInitialize)(CamDevEnumServerContext* context, + BOOL externalThread); +typedef UINT (*psCamDevEnumServerServerPoll)(CamDevEnumServerContext* context); +typedef BOOL (*psCamDevEnumServerServerChannelHandle)(CamDevEnumServerContext* context, + HANDLE* handle); + +typedef UINT (*psCamDevEnumServerServerSelectVersionRequest)( + CamDevEnumServerContext* context, const CAM_SELECT_VERSION_REQUEST* selectVersionRequest); +typedef UINT (*psCamDevEnumServerServerSelectVersionResponse)( + CamDevEnumServerContext* context, const CAM_SELECT_VERSION_RESPONSE* selectVersionResponse); + +typedef UINT (*psCamDevEnumServerServerDeviceAddedNotification)( + CamDevEnumServerContext* context, const CAM_DEVICE_ADDED_NOTIFICATION* deviceAddedNotification); +typedef UINT (*psCamDevEnumServerServerDeviceRemovedNotification)( + CamDevEnumServerContext* context, + const CAM_DEVICE_REMOVED_NOTIFICATION* deviceRemovedNotification); + +struct _cam_dev_enum_server_context +{ + HANDLE vcm; + + /* Server self-defined pointer. */ + void* userdata; + + /*** APIs called by the server. ***/ + + /** + * Optional: Set thread handling. + * When externalThread=TRUE, the application is responsible to call + * Poll() periodically to process channel events. + * + * Defaults to externalThread=FALSE + */ + psCamDevEnumServerServerInitialize Initialize; + + /** + * Open the camera device enumerator channel. + */ + psCamDevEnumServerServerOpen Open; + + /** + * Close the camera device enumerator channel. + */ + psCamDevEnumServerServerClose Close; + + /** + * Poll + * When externalThread=TRUE, call Poll() periodically from your main loop. + * If externalThread=FALSE do not call. + */ + psCamDevEnumServerServerPoll Poll; + + /** + * Retrieve the channel handle for use in conjunction with Poll(). + * If externalThread=FALSE do not call. + */ + psCamDevEnumServerServerChannelHandle ChannelHandle; + + /* + * Send a Select Version Response PDU. + */ + psCamDevEnumServerServerSelectVersionResponse SelectVersionResponse; + + /*** Callbacks registered by the server. ***/ + + /** + * Callback, when the channel got its id assigned. + */ + psCamDevEnumServerServerChannelIdAssigned ChannelIdAssigned; + + /** + * Callback for the Select Version Request PDU. + */ + psCamDevEnumServerServerSelectVersionRequest SelectVersionRequest; + + /** + * Callback for the Device Added Notification PDU. + */ + psCamDevEnumServerServerDeviceAddedNotification DeviceAddedNotification; + + /** + * Callback for the Device Removed Notification PDU. + */ + psCamDevEnumServerServerDeviceRemovedNotification DeviceRemovedNotification; + + rdpContext* rdpcontext; +}; + +#ifdef __cplusplus +extern "C" +{ +#endif + + FREERDP_API CamDevEnumServerContext* cam_dev_enum_server_context_new(HANDLE vcm); + FREERDP_API void cam_dev_enum_server_context_free(CamDevEnumServerContext* context); + +#ifdef __cplusplus +} +#endif + +#endif /* FREERDP_CHANNEL_CAM_DEV_ENUM_SERVER_CAM_DEV_ENUM_H */ diff --git a/include/freerdp/server/camera-device.h b/include/freerdp/server/camera-device.h new file mode 100644 index 000000000000..966a9dbbdf42 --- /dev/null +++ b/include/freerdp/server/camera-device.h @@ -0,0 +1,278 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Video Capture Virtual Channel Extension + * + * Copyright 2022 Pascal Nowack + * + * 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_CHANNEL_CAMERA_DEVICE_SERVER_CAMERA_DEVICE_H +#define FREERDP_CHANNEL_CAMERA_DEVICE_SERVER_CAMERA_DEVICE_H + +#include +#include + +typedef struct _camera_device_server_context CameraDeviceServerContext; + +typedef UINT (*psCameraDeviceServerOpen)(CameraDeviceServerContext* context); +typedef UINT (*psCameraDeviceServerClose)(CameraDeviceServerContext* context); + +typedef BOOL (*psCameraDeviceServerChannelIdAssigned)(CameraDeviceServerContext* context, + UINT32 channelId); + +typedef UINT (*psCameraDeviceServerInitialize)(CameraDeviceServerContext* context, + BOOL externalThread); +typedef UINT (*psCameraDeviceServerPoll)(CameraDeviceServerContext* context); +typedef BOOL (*psCameraDeviceServerChannelHandle)(CameraDeviceServerContext* context, + HANDLE* handle); + +typedef UINT (*psCameraDeviceServerSuccessResponse)(CameraDeviceServerContext* context, + const CAM_SUCCESS_RESPONSE* successResponse); +typedef UINT (*psCameraDeviceServerErrorResponse)(CameraDeviceServerContext* context, + const CAM_ERROR_RESPONSE* errorResponse); + +typedef UINT (*psCameraDeviceServerActivateDeviceRequest)( + CameraDeviceServerContext* context, const CAM_ACTIVATE_DEVICE_REQUEST* activateDeviceRequest); +typedef UINT (*psCameraDeviceServerDeactivateDeviceRequest)( + CameraDeviceServerContext* context, + const CAM_DEACTIVATE_DEVICE_REQUEST* deactivateDeviceRequest); + +typedef UINT (*psCameraDeviceServerStreamListRequest)( + CameraDeviceServerContext* context, const CAM_STREAM_LIST_REQUEST* streamListRequest); +typedef UINT (*psCameraDeviceServerStreamListResponse)( + CameraDeviceServerContext* context, const CAM_STREAM_LIST_RESPONSE* streamListResponse); + +typedef UINT (*psCameraDeviceServerMediaTypeListRequest)( + CameraDeviceServerContext* context, const CAM_MEDIA_TYPE_LIST_REQUEST* mediaTypeListRequest); +typedef UINT (*psCameraDeviceServerMediaTypeListResponse)( + CameraDeviceServerContext* context, const CAM_MEDIA_TYPE_LIST_RESPONSE* mediaTypeListResponse); + +typedef UINT (*psCameraDeviceServerCurrentMediaTypeRequest)( + CameraDeviceServerContext* context, + const CAM_CURRENT_MEDIA_TYPE_REQUEST* currentMediaTypeRequest); +typedef UINT (*psCameraDeviceServerCurrentMediaTypeResponse)( + CameraDeviceServerContext* context, + const CAM_CURRENT_MEDIA_TYPE_RESPONSE* currentMediaTypeResponse); + +typedef UINT (*psCameraDeviceServerStartStreamsRequest)( + CameraDeviceServerContext* context, const CAM_START_STREAMS_REQUEST* startStreamsRequest); +typedef UINT (*psCameraDeviceServerStopStreamsRequest)( + CameraDeviceServerContext* context, const CAM_STOP_STREAMS_REQUEST* stopStreamsRequest); + +typedef UINT (*psCameraDeviceServerSampleRequest)(CameraDeviceServerContext* context, + const CAM_SAMPLE_REQUEST* sampleRequest); +typedef UINT (*psCameraDeviceServerSampleResponse)(CameraDeviceServerContext* context, + const CAM_SAMPLE_RESPONSE* sampleResponse); +typedef UINT (*psCameraDeviceServerSampleErrorResponse)( + CameraDeviceServerContext* context, const CAM_SAMPLE_ERROR_RESPONSE* sampleErrorResponse); + +typedef UINT (*psCameraDeviceServerPropertyListRequest)( + CameraDeviceServerContext* context, const CAM_PROPERTY_LIST_REQUEST* propertyListRequest); +typedef UINT (*psCameraDeviceServerPropertyListResponse)( + CameraDeviceServerContext* context, const CAM_PROPERTY_LIST_RESPONSE* propertyListResponse); + +typedef UINT (*psCameraDeviceServerPropertyValueRequest)( + CameraDeviceServerContext* context, const CAM_PROPERTY_VALUE_REQUEST* propertyValueRequest); +typedef UINT (*psCameraDeviceServerPropertyValueResponse)( + CameraDeviceServerContext* context, const CAM_PROPERTY_VALUE_RESPONSE* propertyValueResponse); + +typedef UINT (*psCameraDeviceServerSetPropertyValueRequest)( + CameraDeviceServerContext* context, + const CAM_SET_PROPERTY_VALUE_REQUEST* setPropertyValueRequest); + +struct _camera_device_server_context +{ + HANDLE vcm; + + /* Server self-defined pointer. */ + void* userdata; + + /** + * Name of the virtual channel. Pointer owned by the CameraDeviceServerContext, + * meaning camera_device_server_context_free() takes care of freeing the pointer. + * + * Server implementations should sanitize the virtual channel name for invalid + * names, like names for other known channels + * ("ECHO", "AUDIO_PLAYBACK_DVC", etc.) + */ + char* virtualChannelName; + + /** + * Protocol version to be used. Every sent server to client PDU has the + * version value in the Header set to the following value. + */ + BYTE protocolVersion; + + /*** APIs called by the server. ***/ + + /** + * Optional: Set thread handling. + * When externalThread=TRUE, the application is responsible to call + * Poll() periodically to process channel events. + * + * Defaults to externalThread=FALSE + */ + psCameraDeviceServerInitialize Initialize; + + /** + * Open the camera device channel. + */ + psCameraDeviceServerOpen Open; + + /** + * Close the camera device channel. + */ + psCameraDeviceServerClose Close; + + /** + * Poll + * When externalThread=TRUE, call Poll() periodically from your main loop. + * If externalThread=FALSE do not call. + */ + psCameraDeviceServerPoll Poll; + + /** + * Retrieve the channel handle for use in conjunction with Poll(). + * If externalThread=FALSE do not call. + */ + psCameraDeviceServerChannelHandle ChannelHandle; + + /** + * For the following server to client PDUs, + * the message header does not have to be set. + */ + + /** + * Send a Activate Device Request PDU. + */ + psCameraDeviceServerActivateDeviceRequest ActivateDeviceRequest; + + /** + * Send a Deactivate Device Request PDU. + */ + psCameraDeviceServerDeactivateDeviceRequest DeactivateDeviceRequest; + + /** + * Send a Stream List Request PDU. + */ + psCameraDeviceServerStreamListRequest StreamListRequest; + + /** + * Send a Media Type List Request PDU. + */ + psCameraDeviceServerMediaTypeListRequest MediaTypeListRequest; + + /** + * Send a Current Media Type Request PDU. + */ + psCameraDeviceServerCurrentMediaTypeRequest CurrentMediaTypeRequest; + + /** + * Send a Start Streams Request PDU. + */ + psCameraDeviceServerStartStreamsRequest StartStreamsRequest; + + /** + * Send a Stop Streams Request PDU. + */ + psCameraDeviceServerStopStreamsRequest StopStreamsRequest; + + /** + * Send a Sample Request PDU. + */ + psCameraDeviceServerSampleRequest SampleRequest; + + /** + * Send a Property List Request PDU. + */ + psCameraDeviceServerPropertyListRequest PropertyListRequest; + + /** + * Send a Property Value Request PDU. + */ + psCameraDeviceServerPropertyValueRequest PropertyValueRequest; + + /** + * Send a Set Property Value Request PDU. + */ + psCameraDeviceServerSetPropertyValueRequest SetPropertyValueRequest; + + /*** Callbacks registered by the server. ***/ + + /** + * Callback, when the channel got its id assigned. + */ + psCameraDeviceServerChannelIdAssigned ChannelIdAssigned; + + /** + * Callback for the Success Response PDU. + */ + psCameraDeviceServerSuccessResponse SuccessResponse; + + /** + * Callback for the Error Response PDU. + */ + psCameraDeviceServerErrorResponse ErrorResponse; + + /** + * Callback for the Stream List Response PDU. + */ + psCameraDeviceServerStreamListResponse StreamListResponse; + + /** + * Callback for the Media Type List Response PDU. + */ + psCameraDeviceServerMediaTypeListResponse MediaTypeListResponse; + + /** + * Callback for the Current Media Type Response PDU. + */ + psCameraDeviceServerCurrentMediaTypeResponse CurrentMediaTypeResponse; + + /** + * Callback for the Sample Response PDU. + */ + psCameraDeviceServerSampleResponse SampleResponse; + + /** + * Callback for the Sample Error Response PDU. + */ + psCameraDeviceServerSampleErrorResponse SampleErrorResponse; + + /** + * Callback for the Property List Response PDU. + */ + psCameraDeviceServerPropertyListResponse PropertyListResponse; + + /** + * Callback for the Property Value Response PDU. + */ + psCameraDeviceServerPropertyValueResponse PropertyValueResponse; + + rdpContext* rdpcontext; +}; + +#ifdef __cplusplus +extern "C" +{ +#endif + + FREERDP_API CameraDeviceServerContext* camera_device_server_context_new(HANDLE vcm); + FREERDP_API void camera_device_server_context_free(CameraDeviceServerContext* context); + +#ifdef __cplusplus +} +#endif + +#endif /* FREERDP_CHANNEL_CAMERA_DEVICE_SERVER_CAMERA_DEVICE_H */ From f5710c30d82063872916cbbf2263fa2fd7dc2312 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Thu, 30 Jun 2022 10:48:36 +0200 Subject: [PATCH 222/496] Used C style struct init --- channels/rdpecam/server/camera_device_main.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/channels/rdpecam/server/camera_device_main.c b/channels/rdpecam/server/camera_device_main.c index 67702d89dd18..7c152112d100 100644 --- a/channels/rdpecam/server/camera_device_main.c +++ b/channels/rdpecam/server/camera_device_main.c @@ -125,7 +125,7 @@ static UINT device_server_open_channel(device_server* device) static UINT device_server_handle_success_response(CameraDeviceServerContext* context, wStream* s, const CAM_SHARED_MSG_HEADER* header) { - CAM_SUCCESS_RESPONSE pdu = {}; + CAM_SUCCESS_RESPONSE pdu = { 0 }; UINT error = CHANNEL_RC_OK; WINPR_ASSERT(context); @@ -143,7 +143,7 @@ static UINT device_server_handle_success_response(CameraDeviceServerContext* con static UINT device_server_recv_error_response(CameraDeviceServerContext* context, wStream* s, const CAM_SHARED_MSG_HEADER* header) { - CAM_ERROR_RESPONSE pdu = {}; + CAM_ERROR_RESPONSE pdu = { 0 }; UINT error = CHANNEL_RC_OK; WINPR_ASSERT(context); @@ -166,7 +166,7 @@ static UINT device_server_recv_error_response(CameraDeviceServerContext* context static UINT device_server_recv_stream_list_response(CameraDeviceServerContext* context, wStream* s, const CAM_SHARED_MSG_HEADER* header) { - CAM_STREAM_LIST_RESPONSE pdu = {}; + CAM_STREAM_LIST_RESPONSE pdu = { 0 }; UINT error = CHANNEL_RC_OK; BYTE i; @@ -201,7 +201,7 @@ static UINT device_server_recv_media_type_list_response(CameraDeviceServerContex wStream* s, const CAM_SHARED_MSG_HEADER* header) { - CAM_MEDIA_TYPE_LIST_RESPONSE pdu = {}; + CAM_MEDIA_TYPE_LIST_RESPONSE pdu = { 0 }; UINT error = CHANNEL_RC_OK; BYTE i; @@ -250,7 +250,7 @@ static UINT device_server_recv_current_media_type_response(CameraDeviceServerCon wStream* s, const CAM_SHARED_MSG_HEADER* header) { - CAM_CURRENT_MEDIA_TYPE_RESPONSE pdu = {}; + CAM_CURRENT_MEDIA_TYPE_RESPONSE pdu = { 0 }; UINT error = CHANNEL_RC_OK; WINPR_ASSERT(context); @@ -280,7 +280,7 @@ static UINT device_server_recv_current_media_type_response(CameraDeviceServerCon static UINT device_server_recv_sample_response(CameraDeviceServerContext* context, wStream* s, const CAM_SHARED_MSG_HEADER* header) { - CAM_SAMPLE_RESPONSE pdu = {}; + CAM_SAMPLE_RESPONSE pdu = { 0 }; UINT error = CHANNEL_RC_OK; WINPR_ASSERT(context); @@ -306,7 +306,7 @@ static UINT device_server_recv_sample_response(CameraDeviceServerContext* contex static UINT device_server_recv_sample_error_response(CameraDeviceServerContext* context, wStream* s, const CAM_SHARED_MSG_HEADER* header) { - CAM_SAMPLE_ERROR_RESPONSE pdu = {}; + CAM_SAMPLE_ERROR_RESPONSE pdu = { 0 }; UINT error = CHANNEL_RC_OK; WINPR_ASSERT(context); @@ -331,7 +331,7 @@ static UINT device_server_recv_property_list_response(CameraDeviceServerContext* wStream* s, const CAM_SHARED_MSG_HEADER* header) { - CAM_PROPERTY_LIST_RESPONSE pdu = {}; + CAM_PROPERTY_LIST_RESPONSE pdu = { 0 }; UINT error = CHANNEL_RC_OK; WINPR_ASSERT(context); @@ -378,7 +378,7 @@ static UINT device_server_recv_property_value_response(CameraDeviceServerContext wStream* s, const CAM_SHARED_MSG_HEADER* header) { - CAM_PROPERTY_VALUE_RESPONSE pdu = {}; + CAM_PROPERTY_VALUE_RESPONSE pdu = { 0 }; UINT error = CHANNEL_RC_OK; WINPR_ASSERT(context); @@ -404,7 +404,7 @@ static UINT device_process_message(device_server* device) BOOL rc; UINT error = ERROR_INTERNAL_ERROR; ULONG BytesReturned; - CAM_SHARED_MSG_HEADER header = {}; + CAM_SHARED_MSG_HEADER header = { 0 }; wStream* s; WINPR_ASSERT(device); From 2f5f79ca74bf20dca24c30552d7f208d2c06abcd Mon Sep 17 00:00:00 2001 From: akallabeth Date: Thu, 30 Jun 2022 11:11:14 +0200 Subject: [PATCH 223/496] Fixed reserved symbol use in struct name --- include/freerdp/server/camera-device.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/freerdp/server/camera-device.h b/include/freerdp/server/camera-device.h index 966a9dbbdf42..96e375ddfc03 100644 --- a/include/freerdp/server/camera-device.h +++ b/include/freerdp/server/camera-device.h @@ -23,7 +23,7 @@ #include #include -typedef struct _camera_device_server_context CameraDeviceServerContext; +typedef struct camera_device_server_context CameraDeviceServerContext; typedef UINT (*psCameraDeviceServerOpen)(CameraDeviceServerContext* context); typedef UINT (*psCameraDeviceServerClose)(CameraDeviceServerContext* context); @@ -91,7 +91,7 @@ typedef UINT (*psCameraDeviceServerSetPropertyValueRequest)( CameraDeviceServerContext* context, const CAM_SET_PROPERTY_VALUE_REQUEST* setPropertyValueRequest); -struct _camera_device_server_context +typedef struct camera_device_server_context { HANDLE vcm; From a59abddb12476fbd4ad08aa651d5bdbf063a02b5 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Thu, 30 Jun 2022 11:11:29 +0200 Subject: [PATCH 224/496] Fix rdpecam server channel naming --- channels/rdpecam/CMakeLists.txt | 3 +-- channels/rdpecam/ChannelOptions.cmake | 9 ++------- channels/rdpecam/server/CMakeLists.txt | 3 +-- 3 files changed, 4 insertions(+), 11 deletions(-) diff --git a/channels/rdpecam/CMakeLists.txt b/channels/rdpecam/CMakeLists.txt index 2ea7828d0b43..63ed41069553 100644 --- a/channels/rdpecam/CMakeLists.txt +++ b/channels/rdpecam/CMakeLists.txt @@ -15,8 +15,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -define_channel("camera-device") -define_channel("camera-device-enumerator") +define_channel("rdpecam") if(WITH_SERVER_CHANNELS) add_channel_server(${MODULE_PREFIX} ${CHANNEL_NAME}) diff --git a/channels/rdpecam/ChannelOptions.cmake b/channels/rdpecam/ChannelOptions.cmake index 6377499d7872..7528d115c80e 100644 --- a/channels/rdpecam/ChannelOptions.cmake +++ b/channels/rdpecam/ChannelOptions.cmake @@ -1,14 +1,9 @@ -set(OPTION_DEFAULT OFF) +set(OPTION_DEFAULT ON) set(OPTION_CLIENT_DEFAULT OFF) set(OPTION_SERVER_DEFAULT ON) -define_channel_options(NAME "camera-device" TYPE "dynamic" - DESCRIPTION "Video Capture Virtual Channel Extension" - SPECIFICATIONS "[MS-RDPECAM]" - DEFAULT ${OPTION_DEFAULT}) - -define_channel_options(NAME "camera-device-enumerator" TYPE "dynamic" +define_channel_options(NAME "rdpecam" TYPE "dynamic" DESCRIPTION "Video Capture Virtual Channel Extension" SPECIFICATIONS "[MS-RDPECAM]" DEFAULT ${OPTION_DEFAULT}) diff --git a/channels/rdpecam/server/CMakeLists.txt b/channels/rdpecam/server/CMakeLists.txt index e272f9d4039e..2a65ba7fee46 100644 --- a/channels/rdpecam/server/CMakeLists.txt +++ b/channels/rdpecam/server/CMakeLists.txt @@ -15,8 +15,7 @@ # See the License for the specific language governing permissions and # limitations under the License. -define_channel_server("camera-device") -define_channel_server("camera-device-enumerator") +define_channel_server("rdpecam") set(${MODULE_PREFIX}_SRCS camera_device_enumerator_main.c From 94b951382f8582169990360af25672b61b0c5c1a Mon Sep 17 00:00:00 2001 From: akallabeth Date: Thu, 30 Jun 2022 11:22:47 +0200 Subject: [PATCH 225/496] Renamed server channel to rdpei --- .../rdpecam/server/camera_device_enumerator_main.c | 4 ++-- channels/rdpecam/server/camera_device_main.c | 4 ++-- channels/server/channels.c | 13 +++++++++++-- config.h.in | 6 +++--- ...era-device-enumerator.h => rdpecam-enumerator.h} | 0 .../freerdp/server/{camera-device.h => rdpecam.h} | 2 +- 6 files changed, 19 insertions(+), 10 deletions(-) rename include/freerdp/server/{camera-device-enumerator.h => rdpecam-enumerator.h} (100%) rename include/freerdp/server/{camera-device.h => rdpecam.h} (99%) diff --git a/channels/rdpecam/server/camera_device_enumerator_main.c b/channels/rdpecam/server/camera_device_enumerator_main.c index 810491eba9ac..aef06e46b520 100644 --- a/channels/rdpecam/server/camera_device_enumerator_main.c +++ b/channels/rdpecam/server/camera_device_enumerator_main.c @@ -22,9 +22,9 @@ #endif #include -#include +#include -#define TAG CHANNELS_TAG("cam-dev-enum.server") +#define TAG CHANNELS_TAG("rdpecam-enumerator.server") typedef enum { diff --git a/channels/rdpecam/server/camera_device_main.c b/channels/rdpecam/server/camera_device_main.c index 7c152112d100..df504f80920c 100644 --- a/channels/rdpecam/server/camera_device_main.c +++ b/channels/rdpecam/server/camera_device_main.c @@ -22,9 +22,9 @@ #endif #include -#include +#include -#define TAG CHANNELS_TAG("camera-device.server") +#define TAG CHANNELS_TAG("rdpecam.server") typedef enum { diff --git a/channels/server/channels.c b/channels/server/channels.c index ac7444467069..2223ef82c48d 100644 --- a/channels/server/channels.c +++ b/channels/server/channels.c @@ -53,8 +53,11 @@ #include #include #include -#include -#include + +#if defined(CHANNEL_RDPECAM_SERVER) +#include +#include +#endif #if defined(CHANNEL_AINPUT_SERVER) #include @@ -77,8 +80,10 @@ void freerdp_channels_dummy(void) TelemetryServerContext* telemetry; RdpgfxServerContext* rdpgfx; DispServerContext* disp; +#if defined (CHANNEL_RDPECAM_SERVER) CamDevEnumServerContext* camera_enumerator; CameraDeviceServerContext* camera_device; +#endif audin = audin_server_context_new(NULL); audin_server_context_free(audin); rdpsnd = rdpsnd_server_context_new(NULL); @@ -105,10 +110,14 @@ void freerdp_channels_dummy(void) rdpgfx_server_context_free(rdpgfx); disp = disp_server_context_new(NULL); disp_server_context_free(disp); + +#if defined (CHANNEL_RDPECAM_SERVER) camera_enumerator = cam_dev_enum_server_context_new(NULL); cam_dev_enum_server_context_free(camera_enumerator); camera_device = camera_device_server_context_new(NULL); camera_device_server_context_free(camera_device); +#endif + #if defined(CHANNEL_AINPUT_SERVER) { ainput_server_context* ainput = ainput_server_context_new(NULL); diff --git a/config.h.in b/config.h.in index 315d4d24442a..801b085e4b5b 100644 --- a/config.h.in +++ b/config.h.in @@ -81,9 +81,6 @@ #cmakedefine CHANNEL_AUDIN #cmakedefine CHANNEL_AUDIN_CLIENT #cmakedefine CHANNEL_AUDIN_SERVER -#cmakedefine CHANNEL_CAMERA -#cmakedefine CHANNEL_CAMERA_CLIENT -#cmakedefine CHANNEL_CAMERA_SERVER #cmakedefine CHANNEL_CLIPRDR #cmakedefine CHANNEL_CLIPRDR_CLIENT #cmakedefine CHANNEL_CLIPRDR_SERVER @@ -114,6 +111,9 @@ #cmakedefine CHANNEL_RDPDR #cmakedefine CHANNEL_RDPDR_CLIENT #cmakedefine CHANNEL_RDPDR_SERVER +#cmakedefine CHANNEL_RDPECAM +#cmakedefine CHANNEL_RDPECAM_CLIENT +#cmakedefine CHANNEL_RDPECAM_SERVER #cmakedefine CHANNEL_RDPEI #cmakedefine CHANNEL_RDPEI_CLIENT #cmakedefine CHANNEL_RDPEI_SERVER diff --git a/include/freerdp/server/camera-device-enumerator.h b/include/freerdp/server/rdpecam-enumerator.h similarity index 100% rename from include/freerdp/server/camera-device-enumerator.h rename to include/freerdp/server/rdpecam-enumerator.h diff --git a/include/freerdp/server/camera-device.h b/include/freerdp/server/rdpecam.h similarity index 99% rename from include/freerdp/server/camera-device.h rename to include/freerdp/server/rdpecam.h index 96e375ddfc03..67140ea97b7a 100644 --- a/include/freerdp/server/camera-device.h +++ b/include/freerdp/server/rdpecam.h @@ -91,7 +91,7 @@ typedef UINT (*psCameraDeviceServerSetPropertyValueRequest)( CameraDeviceServerContext* context, const CAM_SET_PROPERTY_VALUE_REQUEST* setPropertyValueRequest); -typedef struct camera_device_server_context +struct camera_device_server_context { HANDLE vcm; From 2045b8645813928b90db48fd5bfb0cf2eda041b9 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Thu, 30 Jun 2022 11:36:33 +0200 Subject: [PATCH 226/496] Use C style struct init --- channels/rdpecam/server/camera_device_enumerator_main.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/channels/rdpecam/server/camera_device_enumerator_main.c b/channels/rdpecam/server/camera_device_enumerator_main.c index aef06e46b520..ae125f7e6355 100644 --- a/channels/rdpecam/server/camera_device_enumerator_main.c +++ b/channels/rdpecam/server/camera_device_enumerator_main.c @@ -126,7 +126,7 @@ static UINT enumerator_server_handle_select_version_request(CamDevEnumServerCont wStream* s, const CAM_SHARED_MSG_HEADER* header) { - CAM_SELECT_VERSION_REQUEST pdu = {}; + CAM_SELECT_VERSION_REQUEST pdu = { 0 }; UINT error = CHANNEL_RC_OK; WINPR_ASSERT(context); @@ -264,7 +264,7 @@ static UINT enumerator_process_message(enumerator_server* enumerator) BOOL rc; UINT error = ERROR_INTERNAL_ERROR; ULONG BytesReturned; - CAM_SHARED_MSG_HEADER header = {}; + CAM_SHARED_MSG_HEADER header = { 0 }; wStream* s; WINPR_ASSERT(enumerator); From 34f9d4246a5c9d53c48c534ef56a1d02037da28e Mon Sep 17 00:00:00 2001 From: akallabeth Date: Thu, 30 Jun 2022 11:59:37 +0200 Subject: [PATCH 227/496] Merged camera-device.h with existing rdpecam.h --- .../rdpecam/server/camera_device_enumerator_main.c | 2 +- .../channels/{camera-device.h => rdpecam.h} | 14 ++++++++------ include/freerdp/server/rdpecam-enumerator.h | 2 +- include/freerdp/server/rdpecam.h | 2 +- 4 files changed, 11 insertions(+), 9 deletions(-) rename include/freerdp/channels/{camera-device.h => rdpecam.h} (95%) diff --git a/channels/rdpecam/server/camera_device_enumerator_main.c b/channels/rdpecam/server/camera_device_enumerator_main.c index ae125f7e6355..7657a30502d7 100644 --- a/channels/rdpecam/server/camera_device_enumerator_main.c +++ b/channels/rdpecam/server/camera_device_enumerator_main.c @@ -102,7 +102,7 @@ static UINT enumerator_server_open_channel(enumerator_server* enumerator) } enumerator->enumerator_channel = WTSVirtualChannelOpenEx( - enumerator->SessionId, CAM_DEVICE_ENUMERATOR_DVC_CHANNEL_NAME, WTS_CHANNEL_OPTION_DYNAMIC); + enumerator->SessionId, RDPECAM_CONTROL_DVC_CHANNEL_NAME, WTS_CHANNEL_OPTION_DYNAMIC); if (!enumerator->enumerator_channel) { Error = GetLastError(); diff --git a/include/freerdp/channels/camera-device.h b/include/freerdp/channels/rdpecam.h similarity index 95% rename from include/freerdp/channels/camera-device.h rename to include/freerdp/channels/rdpecam.h index adb97be20475..ee06bcd202bb 100644 --- a/include/freerdp/channels/camera-device.h +++ b/include/freerdp/channels/rdpecam.h @@ -1,8 +1,9 @@ /** * FreeRDP: A Remote Desktop Protocol Implementation - * Video Capture Virtual Channel Extension + * Video Optimized Remoting Virtual Channel Extension * - * Copyright 2022 Pascal Nowack + * Copyright 2021 Armin Novak + * Copyright 2021 Thincast Technologies GmbH * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,14 +18,15 @@ * limitations under the License. */ -#ifndef FREERDP_CHANNEL_CAMERA_DEVICE_H -#define FREERDP_CHANNEL_CAMERA_DEVICE_H +#ifndef FREERDP_CHANNEL_RDPECAM_H +#define FREERDP_CHANNEL_RDPECAM_H #include #include #include -#define CAM_DEVICE_ENUMERATOR_DVC_CHANNEL_NAME "RDCamera_Device_Enumerator" +#define RDPECAM_DVC_CHANNEL_NAME "rdpecam" +#define RDPECAM_CONTROL_DVC_CHANNEL_NAME "RDCamera_Device_Enumerator" typedef enum { @@ -332,4 +334,4 @@ typedef struct CAM_PROPERTY_VALUE PropertyValue; } CAM_SET_PROPERTY_VALUE_REQUEST; -#endif /* FREERDP_CHANNEL_CAMERA_DEVICE_H */ +#endif /* FREERDP_CHANNEL_RDPECAM_H */ diff --git a/include/freerdp/server/rdpecam-enumerator.h b/include/freerdp/server/rdpecam-enumerator.h index 230b4e49c8b4..3f1b77069bce 100644 --- a/include/freerdp/server/rdpecam-enumerator.h +++ b/include/freerdp/server/rdpecam-enumerator.h @@ -20,7 +20,7 @@ #ifndef FREERDP_CHANNEL_CAM_DEV_ENUM_SERVER_CAM_DEV_ENUM_H #define FREERDP_CHANNEL_CAM_DEV_ENUM_SERVER_CAM_DEV_ENUM_H -#include +#include #include typedef struct _cam_dev_enum_server_context CamDevEnumServerContext; diff --git a/include/freerdp/server/rdpecam.h b/include/freerdp/server/rdpecam.h index 67140ea97b7a..a28ff87405d0 100644 --- a/include/freerdp/server/rdpecam.h +++ b/include/freerdp/server/rdpecam.h @@ -20,7 +20,7 @@ #ifndef FREERDP_CHANNEL_CAMERA_DEVICE_SERVER_CAMERA_DEVICE_H #define FREERDP_CHANNEL_CAMERA_DEVICE_SERVER_CAMERA_DEVICE_H -#include +#include #include typedef struct camera_device_server_context CameraDeviceServerContext; From 50a97799d134ba2835aa4ca20822d1f0f313928e Mon Sep 17 00:00:00 2001 From: akallabeth Date: Thu, 30 Jun 2022 12:11:15 +0200 Subject: [PATCH 228/496] Reordered stream advance and length check, always add header byte length --- channels/rdpecam/server/camera_device_main.c | 25 +++++++++----------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/channels/rdpecam/server/camera_device_main.c b/channels/rdpecam/server/camera_device_main.c index df504f80920c..c675beb5551d 100644 --- a/channels/rdpecam/server/camera_device_main.c +++ b/channels/rdpecam/server/camera_device_main.c @@ -438,10 +438,10 @@ static UINT device_process_message(device_server* device) goto out; } + Stream_Seek(s, BytesReturned); if (!Stream_CheckAndLogRequiredLength(TAG, s, CAM_HEADER_SIZE)) return ERROR_NO_DATA; - Stream_SetLength(s, BytesReturned); Stream_Read_UINT8(s, header.Version); Stream_Read_UINT8(s, header.MessageId); @@ -688,7 +688,8 @@ static wStream* device_server_packet_new(size_t size, BYTE version, BYTE message WINPR_ASSERT(size > 0); - s = Stream_New(NULL, size); + /* Allocate what we need plus header bytes */ + s = Stream_New(NULL, size + CAM_HEADER_SIZE); if (!s) { WLog_ERR(TAG, "Stream_New failed!"); @@ -735,7 +736,7 @@ static UINT device_server_write_and_send_header(CameraDeviceServerContext* conte WINPR_ASSERT(context); - s = device_server_packet_new(CAM_HEADER_SIZE, context->protocolVersion, messageId); + s = device_server_packet_new(0, context->protocolVersion, messageId); if (!s) return ERROR_NOT_ENOUGH_MEMORY; @@ -777,8 +778,7 @@ device_send_media_type_list_request_pdu(CameraDeviceServerContext* context, WINPR_ASSERT(context); WINPR_ASSERT(mediaTypeListRequest); - s = device_server_packet_new(CAM_HEADER_SIZE + 1, context->protocolVersion, - CAM_MSG_ID_MediaTypeListRequest); + s = device_server_packet_new(1, context->protocolVersion, CAM_MSG_ID_MediaTypeListRequest); if (!s) return ERROR_NOT_ENOUGH_MEMORY; @@ -796,8 +796,7 @@ static UINT device_send_current_media_type_request_pdu( WINPR_ASSERT(context); WINPR_ASSERT(currentMediaTypeRequest); - s = device_server_packet_new(CAM_HEADER_SIZE + 1, context->protocolVersion, - CAM_MSG_ID_CurrentMediaTypeRequest); + s = device_server_packet_new(1, context->protocolVersion, CAM_MSG_ID_CurrentMediaTypeRequest); if (!s) return ERROR_NOT_ENOUGH_MEMORY; @@ -816,8 +815,8 @@ device_send_start_streams_request_pdu(CameraDeviceServerContext* context, WINPR_ASSERT(context); WINPR_ASSERT(startStreamsRequest); - s = device_server_packet_new(CAM_HEADER_SIZE + startStreamsRequest->N_Infos * 27, - context->protocolVersion, CAM_MSG_ID_StartStreamsRequest); + s = device_server_packet_new(startStreamsRequest->N_Infos * 27ul, context->protocolVersion, + CAM_MSG_ID_StartStreamsRequest); if (!s) return ERROR_NOT_ENOUGH_MEMORY; @@ -857,8 +856,7 @@ static UINT device_send_sample_request_pdu(CameraDeviceServerContext* context, WINPR_ASSERT(context); WINPR_ASSERT(sampleRequest); - s = device_server_packet_new(CAM_HEADER_SIZE + 1, context->protocolVersion, - CAM_MSG_ID_SampleRequest); + s = device_server_packet_new(1, context->protocolVersion, CAM_MSG_ID_SampleRequest); if (!s) return ERROR_NOT_ENOUGH_MEMORY; @@ -885,8 +883,7 @@ device_send_property_value_request_pdu(CameraDeviceServerContext* context, WINPR_ASSERT(context); WINPR_ASSERT(propertyValueRequest); - s = device_server_packet_new(CAM_HEADER_SIZE + 2, context->protocolVersion, - CAM_MSG_ID_PropertyValueRequest); + s = device_server_packet_new(2, context->protocolVersion, CAM_MSG_ID_PropertyValueRequest); if (!s) return ERROR_NOT_ENOUGH_MEMORY; @@ -905,7 +902,7 @@ static UINT device_send_set_property_value_request_pdu( WINPR_ASSERT(context); WINPR_ASSERT(setPropertyValueRequest); - s = device_server_packet_new(CAM_HEADER_SIZE + 2 + 5, context->protocolVersion, + s = device_server_packet_new(2 + 5, context->protocolVersion, CAM_MSG_ID_SetPropertyValueRequest); if (!s) return ERROR_NOT_ENOUGH_MEMORY; From 2755f915fa33940148cbb4167f785892ba40dafa Mon Sep 17 00:00:00 2001 From: akallabeth Date: Thu, 30 Jun 2022 12:19:06 +0200 Subject: [PATCH 229/496] Fixed stream advance before length checks --- channels/telemetry/server/telemetry_main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/channels/telemetry/server/telemetry_main.c b/channels/telemetry/server/telemetry_main.c index 262f658fe8de..3f8b3d12dd95 100644 --- a/channels/telemetry/server/telemetry_main.c +++ b/channels/telemetry/server/telemetry_main.c @@ -185,10 +185,10 @@ static UINT telemetry_process_message(telemetry_server* telemetry) goto out; } + Stream_Seek(s, BytesReturned); if (!Stream_CheckAndLogRequiredLength(TAG, s, 2)) return ERROR_NO_DATA; - Stream_SetLength(s, BytesReturned); Stream_Read_UINT8(s, MessageId); Stream_Read_UINT8(s, Length); From ab159cc23658c381c9b7c8ed331ddc80f8eb8a04 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Thu, 30 Jun 2022 13:07:42 +0200 Subject: [PATCH 230/496] Fixed copyright headers and stream length --- channels/rdpecam/server/camera_device_enumerator_main.c | 2 +- channels/rdpecam/server/camera_device_main.c | 2 +- channels/telemetry/server/telemetry_main.c | 2 +- include/freerdp/channels/rdpecam.h | 5 ++--- 4 files changed, 5 insertions(+), 6 deletions(-) diff --git a/channels/rdpecam/server/camera_device_enumerator_main.c b/channels/rdpecam/server/camera_device_enumerator_main.c index 7657a30502d7..a17eeee93e49 100644 --- a/channels/rdpecam/server/camera_device_enumerator_main.c +++ b/channels/rdpecam/server/camera_device_enumerator_main.c @@ -298,10 +298,10 @@ static UINT enumerator_process_message(enumerator_server* enumerator) goto out; } + Stream_SetLength(s, BytesReturned); if (!Stream_CheckAndLogRequiredLength(TAG, s, CAM_HEADER_SIZE)) return ERROR_NO_DATA; - Stream_SetLength(s, BytesReturned); Stream_Read_UINT8(s, header.Version); Stream_Read_UINT8(s, header.MessageId); diff --git a/channels/rdpecam/server/camera_device_main.c b/channels/rdpecam/server/camera_device_main.c index c675beb5551d..00bea941e2e9 100644 --- a/channels/rdpecam/server/camera_device_main.c +++ b/channels/rdpecam/server/camera_device_main.c @@ -438,7 +438,7 @@ static UINT device_process_message(device_server* device) goto out; } - Stream_Seek(s, BytesReturned); + Stream_SetLength(s, BytesReturned); if (!Stream_CheckAndLogRequiredLength(TAG, s, CAM_HEADER_SIZE)) return ERROR_NO_DATA; diff --git a/channels/telemetry/server/telemetry_main.c b/channels/telemetry/server/telemetry_main.c index 3f8b3d12dd95..717360311897 100644 --- a/channels/telemetry/server/telemetry_main.c +++ b/channels/telemetry/server/telemetry_main.c @@ -185,7 +185,7 @@ static UINT telemetry_process_message(telemetry_server* telemetry) goto out; } - Stream_Seek(s, BytesReturned); + Stream_SetLength(s, BytesReturned); if (!Stream_CheckAndLogRequiredLength(TAG, s, 2)) return ERROR_NO_DATA; diff --git a/include/freerdp/channels/rdpecam.h b/include/freerdp/channels/rdpecam.h index ee06bcd202bb..2d5ae40088d1 100644 --- a/include/freerdp/channels/rdpecam.h +++ b/include/freerdp/channels/rdpecam.h @@ -1,9 +1,8 @@ /** * FreeRDP: A Remote Desktop Protocol Implementation - * Video Optimized Remoting Virtual Channel Extension + * Video Capture Virtual Channel Extension * - * Copyright 2021 Armin Novak - * Copyright 2021 Thincast Technologies GmbH + * Copyright 2022 Pascal Nowack * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. From 5696d0b613980a6b44e196c9be64ed4d79fdd659 Mon Sep 17 00:00:00 2001 From: Pascal Nowack Date: Thu, 30 Jun 2022 13:54:31 +0200 Subject: [PATCH 231/496] Update changelog --- ChangeLog | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ChangeLog b/ChangeLog index 0e61e5a968dd..fcb4dae4068c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -5,6 +5,7 @@ Noteworthy changes: * Backported API to get peer accepted channel names * Backported Stream_CheckAndLogRequiredLength * Backported server side handling for [MS-RDPET] (#7954) +* Backported server side handling for [MS-RDPECAM] (#8010) Fixed issues: * Fixed #7837: Prevent out of bound reads for FFMPEG @@ -18,6 +19,8 @@ Fixed issues: * Backported #7916: GFX 10.7 capability support * Backported #7949: Server RDPSND API improvements * Backported #7957: Server DVC API improvements +* Backported #7760: Fixed osMinorType values +* Backported #8013: Add missing osMajorType values # 2022-04-25 Version 2.7.0 From dd3bdc0dcdebd54c22a205f4652b5a3a2171a29d Mon Sep 17 00:00:00 2001 From: akallabeth Date: Fri, 1 Jul 2022 11:06:40 +0200 Subject: [PATCH 232/496] Fixed broken format string in rdg.c (cherry picked from commit f55a420a0001cd567f574789406f178a9f69860e) --- libfreerdp/core/gateway/rdg.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libfreerdp/core/gateway/rdg.c b/libfreerdp/core/gateway/rdg.c index 07f2be42034f..ffcd3d4382ab 100644 --- a/libfreerdp/core/gateway/rdg.c +++ b/libfreerdp/core/gateway/rdg.c @@ -312,7 +312,8 @@ static BOOL rdg_read_http_unicode_string(wStream* s, const WCHAR** string, UINT1 /* Read length of the string */ if (rem < 4) { - WLog_ERR(TAG, "[%s]: Could not read stream length, only have % " PRIuz " bytes", rem); + WLog_ERR(TAG, "[%s]: Could not read stream length, only have % " PRIuz " bytes", + __FUNCTION__, rem); return FALSE; } Stream_Read_UINT16(s, strLenBytes); @@ -325,7 +326,7 @@ static BOOL rdg_read_http_unicode_string(wStream* s, const WCHAR** string, UINT1 { WLog_ERR(TAG, "[%s]: Could not read stream data, only have % " PRIuz " bytes, expected %" PRIu16, - rem - 4, strLenBytes); + __FUNCTION__, rem - 4, strLenBytes); return FALSE; } From 40571e5df320cde019986151a8c8d242680c6ae0 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Sat, 2 Jul 2022 16:07:58 +0200 Subject: [PATCH 233/496] Added debug logs --- channels/ainput/server/ainput_main.c | 49 ++++++++++++++++++++++------ 1 file changed, 39 insertions(+), 10 deletions(-) diff --git a/channels/ainput/server/ainput_main.c b/channels/ainput/server/ainput_main.c index 805928f27002..943d0faf1628 100644 --- a/channels/ainput/server/ainput_main.c +++ b/channels/ainput/server/ainput_main.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include @@ -121,6 +122,14 @@ static UINT ainput_server_open_channel(ainput_server* ainput) ainput->ainput_channel = WTSVirtualChannelOpenEx(ainput->SessionId, AINPUT_DVC_CHANNEL_NAME, WTS_CHANNEL_OPTION_DYNAMIC); + Error = GetLastError(); + + if (Error == ERROR_NOT_FOUND) + { + WLog_DBG(TAG, "Channel %s not found", AINPUT_DVC_CHANNEL_NAME); + break; + } + if (ainput->ainput_channel) { UINT32 channelId; @@ -138,13 +147,11 @@ static UINT ainput_server_open_channel(ainput_server* ainput) break; } - Error = GetLastError(); - - if (Error == ERROR_NOT_FOUND) - break; - if (GetTickCount() - StartTick > 5000) + { + WLog_WARN(TAG, "Timeout opening channel %s", AINPUT_DVC_CHANNEL_NAME); break; + } } return ainput->ainput_channel ? CHANNEL_RC_OK : ERROR_INTERNAL_ERROR; @@ -162,7 +169,10 @@ static UINT ainput_server_send_version(ainput_server* ainput) Stream_SetPosition(s, 0); if (!Stream_EnsureCapacity(s, 10)) + { + WLog_WARN(TAG, "[%s] out of memory", AINPUT_DVC_CHANNEL_NAME); return ERROR_OUTOFMEMORY; + } Stream_Write_UINT16(s, MSG_AINPUT_VERSION); Stream_Write_UINT32(s, AINPUT_VERSION_MAJOR); /* Version (4 bytes) */ @@ -189,7 +199,7 @@ static UINT ainput_server_recv_mouse_event(ainput_server* ainput, wStream* s) WINPR_ASSERT(ainput); WINPR_ASSERT(s); - if (Stream_GetRemainingLength(s) < 24) + if (!Stream_CheckAndLogRequiredLength(TAG, s, 24)) return ERROR_NO_DATA; Stream_Read_UINT64(s, time); @@ -251,9 +261,11 @@ static DWORD WINAPI ainput_server_thread_func(LPVOID arg) case WAIT_OBJECT_0 + 1: case WAIT_OBJECT_0: error = ainput_server_context_poll_int(&ainput->context); + break; case WAIT_FAILED: default: + WLog_WARN(TAG, "[%s] Wait for open failed", AINPUT_DVC_CHANNEL_NAME); error = ERROR_INTERNAL_ERROR; break; } @@ -266,9 +278,10 @@ static DWORD WINAPI ainput_server_thread_func(LPVOID arg) case WAIT_OBJECT_0 + 1: case WAIT_OBJECT_0: error = ainput_server_context_poll_int(&ainput->context); - + break; case WAIT_FAILED: default: + WLog_WARN(TAG, "[%s] Wait for version failed", AINPUT_DVC_CHANNEL_NAME); error = ERROR_INTERNAL_ERROR; break; } @@ -422,7 +435,7 @@ static UINT ainput_process_message(ainput_server* ainput) { BOOL rc; UINT error = ERROR_INTERNAL_ERROR; - ULONG BytesReturned; + ULONG BytesReturned, ActualBytesReturned; UINT16 MessageId; wStream* s; @@ -451,13 +464,20 @@ static UINT ainput_process_message(ainput_server* ainput) } if (WTSVirtualChannelRead(ainput->ainput_channel, 0, (PCHAR)Stream_Buffer(s), - (ULONG)Stream_Capacity(s), &BytesReturned) == FALSE) + (ULONG)Stream_Capacity(s), &ActualBytesReturned) == FALSE) { WLog_ERR(TAG, "WTSVirtualChannelRead failed!"); goto out; } - Stream_SetLength(s, BytesReturned); + if (BytesReturned != ActualBytesReturned) + { + WLog_ERR(TAG, "WTSVirtualChannelRead size mismatch %" PRId32 ", expected %" PRId32, + ActualBytesReturned, BytesReturned); + goto out; + } + + Stream_SetLength(s, ActualBytesReturned); Stream_Read_UINT16(s, MessageId); switch (MessageId) @@ -485,9 +505,15 @@ BOOL ainput_server_context_handle(ainput_server_context* context, HANDLE* handle WINPR_ASSERT(handle); if (!ainput->externalThread) + { + WLog_WARN(TAG, "[%s] externalThread fail!", AINPUT_DVC_CHANNEL_NAME); return FALSE; + } if (ainput->state == AINPUT_INITIAL) + { + WLog_WARN(TAG, "[%s] state fail!", AINPUT_DVC_CHANNEL_NAME); return FALSE; + } *handle = ainput_server_get_channel_handle(ainput); return TRUE; } @@ -553,6 +579,9 @@ UINT ainput_server_context_poll(ainput_server_context* context) WINPR_ASSERT(ainput); if (!ainput->externalThread) + { + WLog_WARN(TAG, "[%s] externalThread fail!", AINPUT_DVC_CHANNEL_NAME); return ERROR_INTERNAL_ERROR; + } return ainput_server_context_poll_int(context); } From 600ec7a309cd89cee2e28eb73d20334aa7ef8d87 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Fri, 21 Jan 2022 16:03:27 +0100 Subject: [PATCH 234/496] Added missing include for ainput server channel (cherry picked from commit ae49581673e55680251c0050787fbffca38d95ca) --- include/freerdp/server/ainput.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/freerdp/server/ainput.h b/include/freerdp/server/ainput.h index 588504f76f02..200de567a99d 100644 --- a/include/freerdp/server/ainput.h +++ b/include/freerdp/server/ainput.h @@ -22,6 +22,7 @@ #define FREERDP_CHANNEL_AINPUT_SERVER_H #include +#include typedef enum AINPUT_SERVER_OPEN_RESULT { From cbafee032f622adad70d443c6b8704bb9a3bd3a6 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Mon, 4 Jul 2022 09:53:41 +0200 Subject: [PATCH 235/496] Fixed xf_Pointer_GetCursorForCurrentScale check (cherry picked from commit a993db8e591ec9c731d9bae9cd615b1e709e90e6) --- client/X11/xf_graphics.c | 33 +++++++++++++++++---------------- 1 file changed, 17 insertions(+), 16 deletions(-) diff --git a/client/X11/xf_graphics.c b/client/X11/xf_graphics.c index 11c6d59b1923..22ae8cd6a630 100644 --- a/client/X11/xf_graphics.c +++ b/client/X11/xf_graphics.c @@ -306,23 +306,25 @@ static BOOL _xf_Pointer_GetCursorForCurrentScale(rdpContext* context, const rdpP ci.yhot = pointer->yPos * yscale; size = ci.height * ci.width * GetBytesPerPixel(CursorFormat) * 1ULL; - if (xscale != 1 || yscale != 1) + if (!(ci.pixels = (XcursorPixel*)_aligned_malloc(size, 16))) { - if (!(ci.pixels = (XcursorPixel*)_aligned_malloc(size, 16))) - { - xf_unlock_x11(xfc); - return FALSE; + xf_unlock_x11(xfc); + return FALSE; } - if (!freerdp_image_scale((BYTE*)ci.pixels, CursorFormat, 0, 0, 0, ci.width, ci.height, - (BYTE*)xpointer->cursorPixels, CursorFormat, 0, 0, 0, - pointer->width, pointer->height)) - { - _aligned_free(ci.pixels); - xf_unlock_x11(xfc); - return FALSE; - } - } + const double xs = fabs(fabs(xscale) - 1.0); + const double ys = fabs(fabs(yscale) - 1.0); + if ((xs > DBL_EPSILON) || (ys > DBL_EPSILON)) + { + if (!freerdp_image_scale((BYTE*)ci.pixels, CursorFormat, 0, 0, 0, ci.width, + ci.height, (BYTE*)xpointer->cursorPixels, CursorFormat, 0, + 0, 0, pointer->width, pointer->height)) + { + _aligned_free(ci.pixels); + xf_unlock_x11(xfc); + return FALSE; + } + } else { ci.pixels = xpointer->cursorPixels; @@ -333,8 +335,7 @@ static BOOL _xf_Pointer_GetCursorForCurrentScale(rdpContext* context, const rdpP xpointer->cursorHeights[cursorIndex] = ci.height; xpointer->cursors[cursorIndex] = XcursorImageLoadCursor(xfc->display, &ci); xpointer->nCursors += 1; - if (xscale != 1 || yscale != 1) - _aligned_free(ci.pixels); + _aligned_free(ci.pixels); xf_unlock_x11(xfc); } From ecb04b781a9deb959e040b632e746bc29e37fca5 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Mon, 4 Jul 2022 08:52:17 +0200 Subject: [PATCH 236/496] Update scaled pointer on FocusIn (cherry picked from commit 5f0d4fb9f7ba5f3cc502bb5a9a427bb23bdda618) --- client/X11/xf_event.c | 63 ++++++++++++++++++++-------------------- client/X11/xf_graphics.c | 25 +++++++++++----- client/X11/xf_graphics.h | 2 ++ 3 files changed, 52 insertions(+), 38 deletions(-) diff --git a/client/X11/xf_event.c b/client/X11/xf_event.c index 747e818b6172..f026dbb63f0c 100644 --- a/client/X11/xf_event.c +++ b/client/X11/xf_event.c @@ -35,6 +35,7 @@ #include "xf_disp.h" #include "xf_input.h" #include "xf_gfx.h" +#include "xf_graphics.h" #include "xf_event.h" #include "xf_input.h" @@ -539,6 +540,7 @@ static BOOL xf_event_FocusIn(xfContext* xfc, const XFocusInEvent* event, BOOL ap /* Release all keys, should already be done at FocusOut but might be missed * if the WM decided to use an alternate event order */ xf_keyboard_release_all_keypress(xfc); + xf_pointer_update_scale(xfc); if (app) { @@ -712,43 +714,42 @@ static BOOL xf_event_ConfigureNotify(xfContext* xfc, const XConfigureEvent* even /* ask the server to resize using the display channel */ xf_disp_handle_configureNotify(xfc, alignedWidth, alignedHeight); } - - return TRUE; } - - appWindow = xf_AppWindowFromX11Window(xfc, event->window); - - if (appWindow) + else { - /* - * ConfigureNotify coordinates are expressed relative to the window parent. - * Translate these to root window coordinates. - */ - XTranslateCoordinates(xfc->display, appWindow->handle, RootWindowOfScreen(xfc->screen), 0, - 0, &appWindow->x, &appWindow->y, &childWindow); - appWindow->width = event->width; - appWindow->height = event->height; - - /* - * Additional checks for not in a local move and not ignoring configure to send - * position update to server, also should the window not be focused then do not - * send to server yet (i.e. resizing using window decoration). - * The server will be updated when the window gets refocused. - */ - if (appWindow->decorations) - { - /* moving resizing using window decoration */ - xf_rail_adjust_position(xfc, appWindow); - } - else + appWindow = xf_AppWindowFromX11Window(xfc, event->window); + + if (appWindow) { - if ((!event->send_event || appWindow->local_move.state == LMS_NOT_ACTIVE) && - !appWindow->rail_ignore_configure && xfc->focused) + /* + * ConfigureNotify coordinates are expressed relative to the window parent. + * Translate these to root window coordinates. + */ + XTranslateCoordinates(xfc->display, appWindow->handle, RootWindowOfScreen(xfc->screen), + 0, 0, &appWindow->x, &appWindow->y, &childWindow); + appWindow->width = event->width; + appWindow->height = event->height; + + /* + * Additional checks for not in a local move and not ignoring configure to send + * position update to server, also should the window not be focused then do not + * send to server yet (i.e. resizing using window decoration). + * The server will be updated when the window gets refocused. + */ + if (appWindow->decorations) + { + /* moving resizing using window decoration */ xf_rail_adjust_position(xfc, appWindow); + } + else + { + if ((!event->send_event || appWindow->local_move.state == LMS_NOT_ACTIVE) && + !appWindow->rail_ignore_configure && xfc->focused) + xf_rail_adjust_position(xfc, appWindow); + } } } - - return TRUE; + return xf_pointer_update_scale(xfc); } static BOOL xf_event_MapNotify(xfContext* xfc, const XMapEvent* event, BOOL app) diff --git a/client/X11/xf_graphics.c b/client/X11/xf_graphics.c index 22ae8cd6a630..10c1be9ef59e 100644 --- a/client/X11/xf_graphics.c +++ b/client/X11/xf_graphics.c @@ -42,6 +42,8 @@ #include #define TAG CLIENT_TAG("x11") +static BOOL xf_Pointer_Set(rdpContext* context, const rdpPointer* pointer); + BOOL xf_decode_color(xfContext* xfc, const UINT32 srcColor, XColor* color) { rdpGdi* gdi; @@ -227,14 +229,14 @@ static BOOL xf_Bitmap_SetSurface(rdpContext* context, rdpBitmap* bitmap, BOOL pr return TRUE; } -static BOOL _xf_Pointer_GetCursorForCurrentScale(rdpContext* context, const rdpPointer* pointer, - Cursor* cursor) +static BOOL xf_Pointer_GetCursorForCurrentScale(rdpContext* context, const rdpPointer* pointer, + Cursor* cursor) { #ifdef WITH_XCURSOR UINT32 CursorFormat; xfContext* xfc = (xfContext*)context; xfPointer* xpointer = (xfPointer*)pointer; - XcursorImage ci; + XcursorImage ci = { 0 }; rdpSettings* settings; UINT32 xTargetSize; UINT32 yTargetSize; @@ -297,7 +299,6 @@ static BOOL _xf_Pointer_GetCursorForCurrentScale(rdpContext* context, const rdpP } } - ZeroMemory(&ci, sizeof(ci)); ci.version = XCURSOR_IMAGE_VERSION; ci.size = sizeof(ci); ci.width = xTargetSize; @@ -373,6 +374,18 @@ static Window xf_Pointer_get_window(xfContext* xfc) } } +BOOL xf_pointer_update_scale(xfContext* xfc) +{ + xfPointer* pointer; + WINPR_ASSERT(xfc); + + pointer = xfc->pointer; + if (!pointer) + return TRUE; + + return xf_Pointer_Set(&xfc->common.context, &xfc->pointer->pointer); +} + static BOOL xf_Pointer_New(rdpContext* context, rdpPointer* pointer) { #ifdef WITH_XCURSOR @@ -406,8 +419,6 @@ static BOOL xf_Pointer_New(rdpContext* context, rdpPointer* pointer) return FALSE; } - if (!_xf_Pointer_GetCursorForCurrentScale(context, pointer, &(xpointer->cursor))) - return FALSE; #endif return TRUE; } @@ -448,7 +459,7 @@ static BOOL xf_Pointer_Set(rdpContext* context, const rdpPointer* pointer) if (handle) { - if (!_xf_Pointer_GetCursorForCurrentScale(context, pointer, &(xfc->pointer->cursor))) + if (!xf_Pointer_GetCursorForCurrentScale(context, pointer, &(xfc->pointer->cursor))) return FALSE; xf_lock_x11(xfc); XDefineCursor(xfc->display, handle, xfc->pointer->cursor); diff --git a/client/X11/xf_graphics.h b/client/X11/xf_graphics.h index 303e116c19cb..96e1d982f881 100644 --- a/client/X11/xf_graphics.h +++ b/client/X11/xf_graphics.h @@ -29,4 +29,6 @@ BOOL xf_register_graphics(rdpGraphics* graphics); BOOL xf_decode_color(xfContext* xfc, const UINT32 srcColor, XColor* color); UINT32 xf_get_local_color_format(xfContext* xfc, BOOL aligned); +BOOL xf_pointer_update_scale(xfContext* xfc); + #endif /* FREERDP_CLIENT_X11_GRAPHICS_H */ From e535601d270b876c00f516e572446488c2c79044 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Mon, 4 Jul 2022 12:13:20 +0200 Subject: [PATCH 237/496] Updated pointer debug log messages (cherry picked from commit 73251193c2b13fd132ee5e6f2fd343bc33ed42fb) --- client/X11/xf_event.c | 3 ++ client/X11/xf_graphics.c | 75 ++++++++++++++++++++++++++++------------ 2 files changed, 55 insertions(+), 23 deletions(-) diff --git a/client/X11/xf_event.c b/client/X11/xf_event.c index f026dbb63f0c..bdcdcb5da0f6 100644 --- a/client/X11/xf_event.c +++ b/client/X11/xf_event.c @@ -672,6 +672,9 @@ static BOOL xf_event_ConfigureNotify(xfContext* xfc, const XConfigureEvent* even rdpSettings* settings; settings = xfc->context.settings; + WLog_DBG(TAG, "%s: x=%" PRId32 ", y=%" PRId32 ", w=%" PRId32 ", h=%" PRId32, __func__, event->x, + event->y, event->width, event->height); + if (!app) { if (!xfc->window) diff --git a/client/X11/xf_graphics.c b/client/X11/xf_graphics.c index 10c1be9ef59e..86b2def82aa0 100644 --- a/client/X11/xf_graphics.c +++ b/client/X11/xf_graphics.c @@ -30,6 +30,9 @@ #include #endif +#include +#include + #include #include @@ -258,6 +261,9 @@ static BOOL xf_Pointer_GetCursorForCurrentScale(rdpContext* context, const rdpPo xTargetSize = pointer->width * xscale; yTargetSize = pointer->height * yscale; + WLog_DBG(TAG, "%s: scaled: %" PRIu32 "x%" PRIu32 ", desktop: %" PRIu32 "x%" PRIu32, __func__, + xfc->scaledWidth, xfc->savedHeight, settings->DesktopWidth, settings->DesktopHeight); + for (int i = 0; i < xpointer->nCursors; i++) { if (xpointer->cursorWidths[i] == xTargetSize && xpointer->cursorHeights[i] == yTargetSize) @@ -311,21 +317,26 @@ static BOOL xf_Pointer_GetCursorForCurrentScale(rdpContext* context, const rdpPo { xf_unlock_x11(xfc); return FALSE; - } + } - const double xs = fabs(fabs(xscale) - 1.0); - const double ys = fabs(fabs(yscale) - 1.0); - if ((xs > DBL_EPSILON) || (ys > DBL_EPSILON)) - { - if (!freerdp_image_scale((BYTE*)ci.pixels, CursorFormat, 0, 0, 0, ci.width, - ci.height, (BYTE*)xpointer->cursorPixels, CursorFormat, 0, - 0, 0, pointer->width, pointer->height)) - { - _aligned_free(ci.pixels); - xf_unlock_x11(xfc); - return FALSE; - } - } + const double xs = fabs(fabs(xscale) - 1.0); + const double ys = fabs(fabs(yscale) - 1.0); + WLog_DBG(TAG, + "%s: cursorIndex %" PRId32 " scaling pointer %" PRIu32 "x%" PRIu32 " --> %" PRIu32 + "x%" PRIu32 " [%lfx%lf]", + __func__, cursorIndex, pointer->width, pointer->height, ci.width, ci.height, + xscale, yscale); + if ((xs > DBL_EPSILON) || (ys > DBL_EPSILON)) + { + if (!freerdp_image_scale((BYTE*)ci.pixels, CursorFormat, 0, 0, 0, ci.width, ci.height, + (BYTE*)xpointer->cursorPixels, CursorFormat, 0, 0, 0, + pointer->width, pointer->height)) + { + _aligned_free(ci.pixels); + xf_unlock_x11(xfc); + return FALSE; + } + } else { ci.pixels = xpointer->cursorPixels; @@ -340,6 +351,10 @@ static BOOL xf_Pointer_GetCursorForCurrentScale(rdpContext* context, const rdpPo xf_unlock_x11(xfc); } + else + { + WLog_DBG(TAG, "%s: using cached cursor %" PRId32, __func__, cursorIndex); + } cursor[0] = xpointer->cursors[cursorIndex]; #endif @@ -383,11 +398,12 @@ BOOL xf_pointer_update_scale(xfContext* xfc) if (!pointer) return TRUE; - return xf_Pointer_Set(&xfc->common.context, &xfc->pointer->pointer); + return xf_Pointer_Set(&xfc->context, &xfc->pointer->pointer); } static BOOL xf_Pointer_New(rdpContext* context, rdpPointer* pointer) { + BOOL rc = FALSE; #ifdef WITH_XCURSOR UINT32 CursorFormat; size_t size; @@ -395,7 +411,7 @@ static BOOL xf_Pointer_New(rdpContext* context, rdpPointer* pointer) xfPointer* xpointer = (xfPointer*)pointer; if (!context || !pointer || !context->gdi) - return FALSE; + goto fail; if (!xfc->invert) CursorFormat = (!xfc->big_endian) ? PIXEL_FORMAT_RGBA32 : PIXEL_FORMAT_ABGR32; @@ -408,7 +424,7 @@ static BOOL xf_Pointer_New(rdpContext* context, rdpPointer* pointer) size = pointer->height * pointer->width * GetBytesPerPixel(CursorFormat) * 1ULL; if (!(xpointer->cursorPixels = (XcursorPixel*)_aligned_malloc(size, 16))) - return FALSE; + goto fail; if (!freerdp_image_copy_from_pointer_data( (BYTE*)xpointer->cursorPixels, CursorFormat, 0, 0, 0, pointer->width, pointer->height, @@ -418,13 +434,18 @@ static BOOL xf_Pointer_New(rdpContext* context, rdpPointer* pointer) _aligned_free(xpointer->cursorPixels); return FALSE; } + rc = TRUE; #endif - return TRUE; +fail: + WLog_DBG(TAG, "%s: %ld", __func__, rc ? pointer : -1); + return rc; } static void xf_Pointer_Free(rdpContext* context, rdpPointer* pointer) { + WLog_DBG(TAG, "%s: %p", __func__, pointer); + #ifdef WITH_XCURSOR xfContext* xfc = (xfContext*)context; xfPointer* xpointer = (xfPointer*)pointer; @@ -450,6 +471,8 @@ static void xf_Pointer_Free(rdpContext* context, rdpPointer* pointer) static BOOL xf_Pointer_Set(rdpContext* context, const rdpPointer* pointer) { + WLog_DBG(TAG, "%s: %p", __func__, pointer); + #ifdef WITH_XCURSOR xfContext* xfc = (xfContext*)context; Window handle = xf_Pointer_get_window(xfc); @@ -465,12 +488,17 @@ static BOOL xf_Pointer_Set(rdpContext* context, const rdpPointer* pointer) XDefineCursor(xfc->display, handle, xfc->pointer->cursor); xf_unlock_x11(xfc); } + else + { + WLog_WARN(TAG, "%s: handle=%ld", __func__, handle); + } #endif return TRUE; } static BOOL xf_Pointer_SetNull(rdpContext* context) { + WLog_DBG(TAG, "%s", __func__); #ifdef WITH_XCURSOR xfContext* xfc = (xfContext*)context; static Cursor nullcursor = None; @@ -527,10 +555,11 @@ static BOOL xf_Pointer_SetPosition(rdpContext* context, UINT32 x, UINT32 y) if (!handle) { - WLog_WARN(TAG, "xf_Pointer_SetPosition: focus %d, handle%lu", xfc->focused, handle); + WLog_WARN(TAG, "%s: focus %d, handle%lu", __func__, xfc->focused, handle); return TRUE; } + WLog_DBG(TAG, "%s: %" PRIu32 "x%" PRIu32, __func__, x, y); if (xfc->remote_app && !xfc->focused) return TRUE; @@ -541,7 +570,7 @@ static BOOL xf_Pointer_SetPosition(rdpContext* context, UINT32 x, UINT32 y) rc = XGetWindowAttributes(xfc->display, handle, ¤t); if (rc == 0) { - WLog_WARN(TAG, "xf_Pointer_SetPosition: XGetWindowAttributes==%d", rc); + WLog_WARN(TAG, "%s: XGetWindowAttributes==%d", __func__, rc); goto out; } @@ -550,17 +579,17 @@ static BOOL xf_Pointer_SetPosition(rdpContext* context, UINT32 x, UINT32 y) rc = XChangeWindowAttributes(xfc->display, handle, CWEventMask, &tmp); if (rc == 0) { - WLog_WARN(TAG, "xf_Pointer_SetPosition: XChangeWindowAttributes==%d", rc); + WLog_WARN(TAG, "%s: XChangeWindowAttributes==%d", __func__, rc); goto out; } rc = XWarpPointer(xfc->display, None, handle, 0, 0, 0, 0, x, y); if (rc == 0) - WLog_WARN(TAG, "xf_Pointer_SetPosition: XWarpPointer==%d", rc); + WLog_WARN(TAG, "%s: XWarpPointer==%d", __func__, rc); tmp.event_mask = current.your_event_mask; rc = XChangeWindowAttributes(xfc->display, handle, CWEventMask, &tmp); if (rc == 0) - WLog_WARN(TAG, "xf_Pointer_SetPosition: 2.try XChangeWindowAttributes==%d", rc); + WLog_WARN(TAG, "%s: 2.try XChangeWindowAttributes==%d", __func__, rc); ret = TRUE; out: xf_unlock_x11(xfc); From a8a8c101bf3ffb5774a29528eff7af274d968db7 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Tue, 5 Jul 2022 13:31:34 +0200 Subject: [PATCH 238/496] Removed ALAW/ULAW from alsa/oss/pulse backends The codec does not work reliably with some hardware. (cherry picked from commit 7b02aba636c3962f6669621fdfc014b7082f69aa) --- channels/rdpsnd/client/alsa/rdpsnd_alsa.c | 4 ---- channels/rdpsnd/client/oss/rdpsnd_oss.c | 4 ---- channels/rdpsnd/client/pulse/rdpsnd_pulse.c | 10 +--------- 3 files changed, 1 insertion(+), 17 deletions(-) diff --git a/channels/rdpsnd/client/alsa/rdpsnd_alsa.c b/channels/rdpsnd/client/alsa/rdpsnd_alsa.c index 95e7a79769fa..a903596aef95 100644 --- a/channels/rdpsnd/client/alsa/rdpsnd_alsa.c +++ b/channels/rdpsnd/client/alsa/rdpsnd_alsa.c @@ -213,10 +213,6 @@ static BOOL rdpsnd_alsa_set_format(rdpsndDevicePlugin* device, const AUDIO_FORMA break; - case WAVE_FORMAT_ALAW: - case WAVE_FORMAT_MULAW: - break; - default: return FALSE; } diff --git a/channels/rdpsnd/client/oss/rdpsnd_oss.c b/channels/rdpsnd/client/oss/rdpsnd_oss.c index 7a7937dad4e9..f8e15d2cb226 100644 --- a/channels/rdpsnd/client/oss/rdpsnd_oss.c +++ b/channels/rdpsnd/client/oss/rdpsnd_oss.c @@ -117,10 +117,6 @@ static BOOL rdpsnd_oss_format_supported(rdpsndDevicePlugin* device, const AUDIO_ break; - case WAVE_FORMAT_MULAW: - case WAVE_FORMAT_ALAW: - break; - default: return FALSE; } diff --git a/channels/rdpsnd/client/pulse/rdpsnd_pulse.c b/channels/rdpsnd/client/pulse/rdpsnd_pulse.c index 7f3a6daf7897..7a95470800f5 100644 --- a/channels/rdpsnd/client/pulse/rdpsnd_pulse.c +++ b/channels/rdpsnd/client/pulse/rdpsnd_pulse.c @@ -427,15 +427,7 @@ BOOL rdpsnd_pulse_format_supported(rdpsndDevicePlugin* device, const AUDIO_FORMA break; - case WAVE_FORMAT_ALAW: - case WAVE_FORMAT_MULAW: - if (format->cbSize == 0 && (format->nSamplesPerSec <= PA_RATE_MAX) && - (format->wBitsPerSample == 8) && - (format->nChannels >= 1 && format->nChannels <= PA_CHANNELS_MAX)) - { - return TRUE; - } - + default: break; } From e231a848fe04ea5d7fcb913072c15b398f545c7e Mon Sep 17 00:00:00 2001 From: akallabeth Date: Tue, 5 Jul 2022 14:22:15 +0200 Subject: [PATCH 239/496] Updated changelog --- ChangeLog | 1 + 1 file changed, 1 insertion(+) diff --git a/ChangeLog b/ChangeLog index fcb4dae4068c..ce80465f82aa 100644 --- a/ChangeLog +++ b/ChangeLog @@ -6,6 +6,7 @@ Noteworthy changes: * Backported Stream_CheckAndLogRequiredLength * Backported server side handling for [MS-RDPET] (#7954) * Backported server side handling for [MS-RDPECAM] (#8010) +* Backported #8041: Remove ALAW/ULAW codecs from linux backends (unreliable) Fixed issues: * Fixed #7837: Prevent out of bound reads for FFMPEG From 9a21f79ae151fb6d8296a2f15f89df8f1a741fd4 Mon Sep 17 00:00:00 2001 From: Pascal Nowack Date: Tue, 5 Jul 2022 11:38:52 +0200 Subject: [PATCH 240/496] freerdp/peer: Add APIs to get OS major and minor type strings --- include/freerdp/peer.h | 3 ++ libfreerdp/core/peer.c | 88 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 91 insertions(+) diff --git a/include/freerdp/peer.h b/include/freerdp/peer.h index a6404444d359..4176f2572c53 100644 --- a/include/freerdp/peer.h +++ b/include/freerdp/peer.h @@ -143,6 +143,9 @@ extern "C" FREERDP_API BOOL freerdp_peer_context_new(freerdp_peer* client); FREERDP_API void freerdp_peer_context_free(freerdp_peer* client); + FREERDP_API const char* freerdp_peer_os_major_type_string(freerdp_peer* client); + FREERDP_API const char* freerdp_peer_os_minor_type_string(freerdp_peer* client); + FREERDP_API freerdp_peer* freerdp_peer_new(int sockfd); FREERDP_API void freerdp_peer_free(freerdp_peer* client); diff --git a/libfreerdp/core/peer.c b/libfreerdp/core/peer.c index ce8628f2353c..aff32c254cbc 100644 --- a/libfreerdp/core/peer.c +++ b/libfreerdp/core/peer.c @@ -866,6 +866,94 @@ void freerdp_peer_context_free(freerdp_peer* client) } } +static const char* os_major_type_to_string(UINT16 osMajorType) +{ + switch (osMajorType) + { + case OSMAJORTYPE_UNSPECIFIED: + return "Unspecified platform"; + case OSMAJORTYPE_WINDOWS: + return "Windows platform"; + case OSMAJORTYPE_OS2: + return "OS/2 platform"; + case OSMAJORTYPE_MACINTOSH: + return "Macintosh platform"; + case OSMAJORTYPE_UNIX: + return "UNIX platform"; + case OSMAJORTYPE_IOS: + return "iOS platform"; + case OSMAJORTYPE_OSX: + return "OS X platform"; + case OSMAJORTYPE_ANDROID: + return "Android platform"; + case OSMAJORTYPE_CHROME_OS: + return "Chrome OS platform"; + } + + return "Unknown platform"; +} + +const char* freerdp_peer_os_major_type_string(freerdp_peer* client) +{ + rdpContext* context; + UINT16 osMajorType; + + WINPR_ASSERT(client); + + context = client->context; + WINPR_ASSERT(context); + WINPR_ASSERT(context->settings); + + osMajorType = freerdp_settings_get_uint32(context->settings, FreeRDP_OsMajorType); + + return os_major_type_to_string(osMajorType); +} + +static const char* os_minor_type_to_string(UINT16 osMinorType) +{ + switch (osMinorType) + { + case OSMINORTYPE_UNSPECIFIED: + return "Unspecified version"; + case OSMINORTYPE_WINDOWS_31X: + return "Windows 3.1x"; + case OSMINORTYPE_WINDOWS_95: + return "Windows 95"; + case OSMINORTYPE_WINDOWS_NT: + return "Windows NT"; + case OSMINORTYPE_OS2_V21: + return "OS/2 2.1"; + case OSMINORTYPE_POWER_PC: + return "PowerPC"; + case OSMINORTYPE_MACINTOSH: + return "Macintosh"; + case OSMINORTYPE_NATIVE_XSERVER: + return "Native X Server"; + case OSMINORTYPE_PSEUDO_XSERVER: + return "Pseudo X Server"; + case OSMINORTYPE_WINDOWS_RT: + return "Windows RT"; + } + + return "Unknown version"; +} + +const char* freerdp_peer_os_minor_type_string(freerdp_peer* client) +{ + rdpContext* context; + UINT16 osMinorType; + + WINPR_ASSERT(client); + + context = client->context; + WINPR_ASSERT(context); + WINPR_ASSERT(context->settings); + + osMinorType = freerdp_settings_get_uint32(context->settings, FreeRDP_OsMinorType); + + return os_minor_type_to_string(osMinorType); +} + freerdp_peer* freerdp_peer_new(int sockfd) { UINT32 option_value; From 5f9c519f033d3d9afd5acab0bad9ed9591f5a3ca Mon Sep 17 00:00:00 2001 From: Pascal Nowack Date: Wed, 6 Jul 2022 12:00:16 +0200 Subject: [PATCH 241/496] winpr/clipboard: Allow overriding ValidFileNameComponent call When using the wClipboard API, the connected peer might not be on the Windows platform, where further filename restriction exists. As a result, it is currently not possible to use the wClipboard API, when intending to allow filenames, containing characters like ':'. So, add a callback to the wClipboardDelegate, which is set to the ValidFileNameComponent call by default. This callback can be overridden by the API user, when it is known, that there is no need to impose very strict filename restrictions. --- winpr/include/winpr/clipboard.h | 2 ++ winpr/libwinpr/clipboard/posix.c | 59 +++++++++++++++++++------------- 2 files changed, 38 insertions(+), 23 deletions(-) diff --git a/winpr/include/winpr/clipboard.h b/winpr/include/winpr/clipboard.h index bbf2f5f9573b..95fb913e2aa8 100644 --- a/winpr/include/winpr/clipboard.h +++ b/winpr/include/winpr/clipboard.h @@ -64,6 +64,8 @@ struct _wClipboardDelegate (wClipboardDelegate*, const wClipboardFileRangeRequest*, const BYTE* data, UINT32 size); UINT(*ClipboardFileRangeFailure) (wClipboardDelegate*, const wClipboardFileRangeRequest*, UINT errorCode); + + BOOL (*IsFileNameComponentValid)(LPCWSTR lpFileName); }; #ifdef __cplusplus diff --git a/winpr/libwinpr/clipboard/posix.c b/winpr/libwinpr/clipboard/posix.c index 3fe1d70f48de..867fddf974eb 100644 --- a/winpr/libwinpr/clipboard/posix.c +++ b/winpr/libwinpr/clipboard/posix.c @@ -182,10 +182,13 @@ static char* decode_percent_encoded_string(const char* str, size_t len) * Note that the function converts a single file name component, * it does not take care of component separators. */ -static WCHAR* convert_local_name_component_to_remote(const char* local_name) +static WCHAR* convert_local_name_component_to_remote(wClipboard* clipboard, const char* local_name) { + wClipboardDelegate* delegate = ClipboardGetDelegate(clipboard); WCHAR* remote_name = NULL; + WINPR_ASSERT(delegate); + /* * Note that local file names are not actually guaranteed to be * encoded in UTF-8. Filesystems and users can use whatever they @@ -203,8 +206,12 @@ static WCHAR* convert_local_name_component_to_remote(const char* local_name) * Some file names are not valid on Windows. Check for these now * so that we won't get ourselves into a trouble later as such names * are known to crash some Windows shells when pasted via clipboard. + * + * The IsFileNameComponentValid callback can be overridden by the API + * user, if it is known, that the connected peer is not on the + * Windows platform. */ - if (!ValidFileNameComponent(remote_name)) + if (!delegate->IsFileNameComponentValid(remote_name)) { WLog_ERR(TAG, "invalid file name component: %s", local_name); goto error; @@ -252,10 +259,12 @@ static WCHAR* concat_remote_name(const WCHAR* dir, const WCHAR* file) return buffer; } -static BOOL add_file_to_list(const char* local_name, const WCHAR* remote_name, wArrayList* files); +static BOOL add_file_to_list(wClipboard* clipboard, const char* local_name, + const WCHAR* remote_name, wArrayList* files); -static BOOL add_directory_entry_to_list(const char* local_dir_name, const WCHAR* remote_dir_name, - const struct dirent* entry, wArrayList* files) +static BOOL add_directory_entry_to_list(wClipboard* clipboard, const char* local_dir_name, + const WCHAR* remote_dir_name, const struct dirent* entry, + wArrayList* files) { BOOL result = FALSE; char* local_name = NULL; @@ -266,7 +275,7 @@ static BOOL add_directory_entry_to_list(const char* local_dir_name, const WCHAR* if ((strcmp(entry->d_name, ".") == 0) || (strcmp(entry->d_name, "..") == 0)) return TRUE; - remote_base_name = convert_local_name_component_to_remote(entry->d_name); + remote_base_name = convert_local_name_component_to_remote(clipboard, entry->d_name); if (!remote_base_name) return FALSE; @@ -275,7 +284,7 @@ static BOOL add_directory_entry_to_list(const char* local_dir_name, const WCHAR* remote_name = concat_remote_name(remote_dir_name, remote_base_name); if (local_name && remote_name) - result = add_file_to_list(local_name, remote_name, files); + result = add_file_to_list(clipboard, local_name, remote_name, files); free(remote_base_name); free(remote_name); @@ -283,8 +292,9 @@ static BOOL add_directory_entry_to_list(const char* local_dir_name, const WCHAR* return result; } -static BOOL do_add_directory_contents_to_list(const char* local_name, const WCHAR* remote_name, - DIR* dirp, wArrayList* files) +static BOOL do_add_directory_contents_to_list(wClipboard* clipboard, const char* local_name, + const WCHAR* remote_name, DIR* dirp, + wArrayList* files) { /* * For some reason POSIX does not require readdir() to be thread-safe. @@ -316,15 +326,15 @@ static BOOL do_add_directory_contents_to_list(const char* local_name, const WCHA return FALSE; } - if (!add_directory_entry_to_list(local_name, remote_name, entry, files)) + if (!add_directory_entry_to_list(clipboard, local_name, remote_name, entry, files)) return FALSE; } return TRUE; } -static BOOL add_directory_contents_to_list(const char* local_name, const WCHAR* remote_name, - wArrayList* files) +static BOOL add_directory_contents_to_list(wClipboard* clipboard, const char* local_name, + const WCHAR* remote_name, wArrayList* files) { BOOL result = FALSE; DIR* dirp = NULL; @@ -338,7 +348,7 @@ static BOOL add_directory_contents_to_list(const char* local_name, const WCHAR* goto out; } - result = do_add_directory_contents_to_list(local_name, remote_name, dirp, files); + result = do_add_directory_contents_to_list(clipboard, local_name, remote_name, dirp, files); if (closedir(dirp)) { @@ -350,7 +360,8 @@ static BOOL add_directory_contents_to_list(const char* local_name, const WCHAR* return result; } -static BOOL add_file_to_list(const char* local_name, const WCHAR* remote_name, wArrayList* files) +static BOOL add_file_to_list(wClipboard* clipboard, const char* local_name, + const WCHAR* remote_name, wArrayList* files) { struct posix_file* file = NULL; WLog_VRB(TAG, "adding file: %s", local_name); @@ -371,7 +382,7 @@ static BOOL add_file_to_list(const char* local_name, const WCHAR* remote_name, w * This is effectively a recursive call, but we do not track * recursion depth, thus filesystem loops can cause a crash. */ - if (!add_directory_contents_to_list(local_name, remote_name, files)) + if (!add_directory_contents_to_list(clipboard, local_name, remote_name, files)) return FALSE; } @@ -392,7 +403,7 @@ static const char* get_basename(const char* name) return last_name; } -static BOOL process_file_name(const char* local_name, wArrayList* files) +static BOOL process_file_name(wClipboard* clipboard, const char* local_name, wArrayList* files) { BOOL result = FALSE; const char* base_name = NULL; @@ -403,17 +414,17 @@ static BOOL process_file_name(const char* local_name, wArrayList* files) * to have names relative to that selection. */ base_name = get_basename(local_name); - remote_name = convert_local_name_component_to_remote(base_name); + remote_name = convert_local_name_component_to_remote(clipboard, base_name); if (!remote_name) return FALSE; - result = add_file_to_list(local_name, remote_name, files); + result = add_file_to_list(clipboard, local_name, remote_name, files); free(remote_name); return result; } -static BOOL process_uri(const char* uri, size_t uri_len, wArrayList* files) +static BOOL process_uri(wClipboard* clipboard, const char* uri, size_t uri_len, wArrayList* files) { const char prefix[] = "file://"; BOOL result = FALSE; @@ -432,13 +443,14 @@ static BOOL process_uri(const char* uri, size_t uri_len, wArrayList* files) if (!name) goto out; - result = process_file_name(name, files); + result = process_file_name(clipboard, name, files); out: free(name); return result; } -static BOOL process_uri_list(const char* data, size_t length, wArrayList* files) +static BOOL process_uri_list(wClipboard* clipboard, const char* data, size_t length, + wArrayList* files) { const char* cur = data; const char* lim = data + length; @@ -485,7 +497,7 @@ static BOOL process_uri_list(const char* data, size_t length, wArrayList* files) if (comment) continue; - if (!process_uri(start, stop - start, files)) + if (!process_uri(clipboard, start, stop - start, files)) return FALSE; } @@ -561,7 +573,7 @@ static void* convert_uri_list_to_filedescriptors(wClipboard* clipboard, UINT32 f if (formatId != ClipboardGetFormatId(clipboard, "text/uri-list")) return NULL; - if (!process_uri_list((const char*)data, *pSize, clipboard->localFiles)) + if (!process_uri_list(clipboard, (const char*)data, *pSize, clipboard->localFiles)) return NULL; descriptors = convert_local_file_list_to_filedescriptors(clipboard->localFiles); @@ -946,6 +958,7 @@ static void setup_delegate(wClipboardDelegate* delegate) delegate->ClientRequestFileRange = posix_file_request_range; delegate->ClipboardFileRangeSuccess = dummy_file_range_success; delegate->ClipboardFileRangeFailure = dummy_file_range_failure; + delegate->IsFileNameComponentValid = ValidFileNameComponent; } BOOL ClipboardInitPosixFileSubsystem(wClipboard* clipboard) From 28d968a4d6137043bcdfad5e0f2ee6402a246516 Mon Sep 17 00:00:00 2001 From: Pascal Nowack Date: Wed, 6 Jul 2022 13:46:39 +0200 Subject: [PATCH 242/496] client/X11: Relieve CLIPRDR filename restriction when possible Microsoft Windows imposes strict filename restrictions on its platform. As RDP is developed by Microsoft and the RDS in MS Windows is typically used as remote desktop server for the RDP protocol, these filename restrictions are also enforced in WinPR, when copy-pasting files over the clipboard. However, in some connections no peer on MS Windows is involved and in these situations, these filename restrictions are just an annoyance. With a recent API addition in WinPR, it is now possible to override the callback, where the filename is checked, whether it is valid. So, use this new API to relieve the filename restriction, when the connected remote desktop server is not on MS Windows. --- client/X11/xf_client.c | 4 +++- client/X11/xf_cliprdr.c | 29 ++++++++++++++++++++++++++++- client/X11/xf_cliprdr.h | 2 +- libfreerdp/core/capabilities.c | 31 +++++++++++-------------------- 4 files changed, 43 insertions(+), 23 deletions(-) diff --git a/client/X11/xf_client.c b/client/X11/xf_client.c index 90b05e87d9b9..bd3eb0d5663e 100644 --- a/client/X11/xf_client.c +++ b/client/X11/xf_client.c @@ -1254,6 +1254,7 @@ static BOOL xf_post_connect(freerdp* instance) context = instance->context; settings = instance->settings; update = context->update; + BOOL serverIsWindowsPlatform; if (!gdi_init(instance, xf_get_local_color_format(xfc, TRUE))) return FALSE; @@ -1323,7 +1324,8 @@ static BOOL xf_post_connect(freerdp* instance) update->SetKeyboardIndicators = xf_keyboard_set_indicators; update->SetKeyboardImeStatus = xf_keyboard_set_ime_status; - if (!(xfc->clipboard = xf_clipboard_new(xfc))) + serverIsWindowsPlatform = (settings->OsMajorType == OSMAJORTYPE_WINDOWS); + if (!(xfc->clipboard = xf_clipboard_new(xfc, !serverIsWindowsPlatform))) return FALSE; if (!(xfc->xfDisp = xf_disp_new(xfc))) diff --git a/client/X11/xf_cliprdr.c b/client/X11/xf_cliprdr.c index 85a17363c7af..37ed538e63c9 100644 --- a/client/X11/xf_cliprdr.c +++ b/client/X11/xf_cliprdr.c @@ -1756,7 +1756,27 @@ static UINT xf_cliprdr_clipboard_file_range_failure(wClipboardDelegate* delegate return clipboard->context->ClientFileContentsResponse(clipboard->context, &response); } -xfClipboard* xf_clipboard_new(xfContext* xfc) +static BOOL xf_cliprdr_clipboard_is_valid_unix_filename(LPCWSTR filename) +{ + LPCWSTR c; + + if (!filename) + return FALSE; + + if (filename[0] == L'\0') + return FALSE; + + /* Reserved characters */ + for (c = filename; *c; ++c) + { + if (*c == L'/') + return FALSE; + } + + return TRUE; +} + +xfClipboard* xf_clipboard_new(xfContext* xfc, BOOL relieveFilenameRestriction) { int i, n = 0; rdpChannels* channels; @@ -1885,6 +1905,13 @@ xfClipboard* xf_clipboard_new(xfContext* xfc) clipboard->delegate->ClipboardFileSizeFailure = xf_cliprdr_clipboard_file_size_failure; clipboard->delegate->ClipboardFileRangeSuccess = xf_cliprdr_clipboard_file_range_success; clipboard->delegate->ClipboardFileRangeFailure = xf_cliprdr_clipboard_file_range_failure; + + if (relieveFilenameRestriction) + { + WLog_DBG(TAG, "Relieving CLIPRDR filename restriction"); + clipboard->delegate->IsFileNameComponentValid = xf_cliprdr_clipboard_is_valid_unix_filename; + } + return clipboard; error: diff --git a/client/X11/xf_cliprdr.h b/client/X11/xf_cliprdr.h index f2262f79eca6..7f571c477884 100644 --- a/client/X11/xf_cliprdr.h +++ b/client/X11/xf_cliprdr.h @@ -25,7 +25,7 @@ #include -xfClipboard* xf_clipboard_new(xfContext* xfc); +xfClipboard* xf_clipboard_new(xfContext* xfc, BOOL relieveFilenameRestriction); void xf_clipboard_free(xfClipboard* clipboard); void xf_cliprdr_init(xfContext* xfc, CliprdrClientContext* cliprdr); diff --git a/libfreerdp/core/capabilities.c b/libfreerdp/core/capabilities.c index 30edcbb1c0a6..433f4cefc0ea 100644 --- a/libfreerdp/core/capabilities.c +++ b/libfreerdp/core/capabilities.c @@ -162,26 +162,17 @@ static BOOL rdp_read_general_capability_set(wStream* s, rdpSettings* settings) if (Stream_GetRemainingLength(s) < 20) return FALSE; - if (settings->ServerMode) - { - Stream_Read_UINT16(s, settings->OsMajorType); /* osMajorType (2 bytes) */ - Stream_Read_UINT16(s, settings->OsMinorType); /* osMinorType (2 bytes) */ - } - else - { - Stream_Seek_UINT16(s); /* osMajorType (2 bytes) */ - Stream_Seek_UINT16(s); /* osMinorType (2 bytes) */ - } - - Stream_Seek_UINT16(s); /* protocolVersion (2 bytes) */ - Stream_Seek_UINT16(s); /* pad2OctetsA (2 bytes) */ - Stream_Seek_UINT16(s); /* generalCompressionTypes (2 bytes) */ - Stream_Read_UINT16(s, extraFlags); /* extraFlags (2 bytes) */ - Stream_Seek_UINT16(s); /* updateCapabilityFlag (2 bytes) */ - Stream_Seek_UINT16(s); /* remoteUnshareFlag (2 bytes) */ - Stream_Seek_UINT16(s); /* generalCompressionLevel (2 bytes) */ - Stream_Read_UINT8(s, refreshRectSupport); /* refreshRectSupport (1 byte) */ - Stream_Read_UINT8(s, suppressOutputSupport); /* suppressOutputSupport (1 byte) */ + Stream_Read_UINT16(s, settings->OsMajorType); /* osMajorType (2 bytes) */ + Stream_Read_UINT16(s, settings->OsMinorType); /* osMinorType (2 bytes) */ + Stream_Seek_UINT16(s); /* protocolVersion (2 bytes) */ + Stream_Seek_UINT16(s); /* pad2OctetsA (2 bytes) */ + Stream_Seek_UINT16(s); /* generalCompressionTypes (2 bytes) */ + Stream_Read_UINT16(s, extraFlags); /* extraFlags (2 bytes) */ + Stream_Seek_UINT16(s); /* updateCapabilityFlag (2 bytes) */ + Stream_Seek_UINT16(s); /* remoteUnshareFlag (2 bytes) */ + Stream_Seek_UINT16(s); /* generalCompressionLevel (2 bytes) */ + Stream_Read_UINT8(s, refreshRectSupport); /* refreshRectSupport (1 byte) */ + Stream_Read_UINT8(s, suppressOutputSupport); /* suppressOutputSupport (1 byte) */ settings->NoBitmapCompressionHeader = (extraFlags & NO_BITMAP_COMPRESSION_HDR) ? TRUE : FALSE; settings->LongCredentialsSupported = (extraFlags & LONG_CREDENTIALS_SUPPORTED) ? TRUE : FALSE; From ea3c4174c7386ad5ae9f2a3e6c1f71c2a5c3b649 Mon Sep 17 00:00:00 2001 From: Pascal Nowack Date: Thu, 7 Jul 2022 14:53:01 +0200 Subject: [PATCH 243/496] Update changelog --- ChangeLog | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index ce80465f82aa..654a9f33a58f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -4,9 +4,10 @@ Noteworthy changes: * Backported API to get peer accepted channel option flags * Backported API to get peer accepted channel names * Backported Stream_CheckAndLogRequiredLength -* Backported server side handling for [MS-RDPET] (#7954) -* Backported server side handling for [MS-RDPECAM] (#8010) +* Backported #7954: Add server side handling for [MS-RDPET] +* Backported #8010: Add server side handling for [MS-RDPECAM] * Backported #8041: Remove ALAW/ULAW codecs from linux backends (unreliable) +* Backported #8051: Relieve CLIPRDR filename restriction when connecting to non-MS Windows servers Fixed issues: * Fixed #7837: Prevent out of bound reads for FFMPEG From 88c09ff697cd68a5c1642f6da698d4d0016405d0 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Thu, 7 Jul 2022 16:17:19 +0200 Subject: [PATCH 244/496] Fixed xf_Pointer_GetCursorForCurrentScale double free --- client/X11/xf_graphics.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/X11/xf_graphics.c b/client/X11/xf_graphics.c index 86b2def82aa0..705056941c81 100644 --- a/client/X11/xf_graphics.c +++ b/client/X11/xf_graphics.c @@ -339,7 +339,7 @@ static BOOL xf_Pointer_GetCursorForCurrentScale(rdpContext* context, const rdpPo } else { - ci.pixels = xpointer->cursorPixels; + memcpy(ci.pixels, xpointer->cursorPixels, size); } cursorIndex = xpointer->nCursors; From f344d1d4815550ee4648d7ae7e083ac53a530a07 Mon Sep 17 00:00:00 2001 From: Pascal Nowack Date: Fri, 15 Jul 2022 08:52:02 +0200 Subject: [PATCH 245/496] [stable-2.0] codec/progressive: Fix wrong usage of subband diffing flag (#8077) * codec/progressive: Fix wrong usage of subband diffing flag (#8076) Currently, all Calista Progressive encoded streams contain tile artifacts, when the RFX_SUBBAND_DIFFING is used, but not the RFX_DWT_REDUCE_EXTRAPOLATE flag. The reason is the wrong usage of the context and tile flags. The RFX_SUBBAND_DIFFING flag should have no actual impact on the decoder itself. Especially, it does not affect the band sizes within a 64x64 tile. The RFX_DWT_REDUCE_EXTRAPOLATE flag, on the other hand, MUST have an effect on the band sizes. However, FreeRDP currently uses the RFX_SUBBAND_DIFFING flag when decoding a component to determine whether the Reduce-Extrapolate method is used, resulting in tile artifacts, when that method was actually not used. The current behaviour did not result in tile artifacts with the MS Windows RDS, as that server always sets both flags. So, fix this issue by using the correct flag, when decoding a tile. * Update changelog --- ChangeLog | 1 + libfreerdp/codec/progressive.c | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 654a9f33a58f..6e0ac0761094 100644 --- a/ChangeLog +++ b/ChangeLog @@ -23,6 +23,7 @@ Fixed issues: * Backported #7957: Server DVC API improvements * Backported #7760: Fixed osMinorType values * Backported #8013: Add missing osMajorType values +* Backported #8076: Fix wrong usage of subband diffing flag (tile artifact fix) # 2022-04-25 Version 2.7.0 diff --git a/libfreerdp/codec/progressive.c b/libfreerdp/codec/progressive.c index a9e39d2c824e..e95db2d0adf3 100644 --- a/libfreerdp/codec/progressive.c +++ b/libfreerdp/codec/progressive.c @@ -896,7 +896,7 @@ static INLINE int progressive_rfx_decode_component(PROGRESSIVE_CONTEXT* progress return status; CopyMemory(sign, buffer, 4096 * 2); - if (!subbandDiff) + if (!extrapolate) { rfx_differential_decode(buffer + 4032, 64); progressive_rfx_decode_block(prims, &buffer[0], 1024, shift->HL1); /* HL1 */ From 26a83e6ccde272c1bbc2b2591325dc7a493811bc Mon Sep 17 00:00:00 2001 From: akallabeth Date: Thu, 28 Jul 2022 13:45:57 +0200 Subject: [PATCH 246/496] Moved clipboard utils to core library, fixes #6760 (#7752) * Moved clipboard utils to core library, fixes #6760 (cherry picked from commit 4fb686d40f51a6a8315924ddfd1bd5d0c26b891c) * Fixed compilation warnings in cliprdr_utils (cherry picked from commit 8b7a086411d2563e7a44b71402d4467b7fe95630) * Fixed backport API mismatch * Added C++ guards to header (cherry picked from commit 7626a2ce6a33c0cc976a69c0b8365d961fabe090) --- channels/cliprdr/client/cliprdr_format.c | 195 ------------------- include/freerdp/channels/cliprdr.h | 12 +- include/freerdp/utils/cliprdr_utils.h | 48 +++++ libfreerdp/utils/CMakeLists.txt | 1 + libfreerdp/utils/cliprdr_utils.c | 235 +++++++++++++++++++++++ 5 files changed, 285 insertions(+), 206 deletions(-) create mode 100644 include/freerdp/utils/cliprdr_utils.h create mode 100644 libfreerdp/utils/cliprdr_utils.c diff --git a/channels/cliprdr/client/cliprdr_format.c b/channels/cliprdr/client/cliprdr_format.c index 4c31a1b0810f..0b6111b963f8 100644 --- a/channels/cliprdr/client/cliprdr_format.c +++ b/channels/cliprdr/client/cliprdr_format.c @@ -173,198 +173,3 @@ UINT cliprdr_process_format_data_response(cliprdrPlugin* cliprdr, wStream* s, UI return error; } - -static UINT64 filetime_to_uint64(FILETIME value) -{ - UINT64 converted = 0; - converted |= (UINT32)value.dwHighDateTime; - converted <<= 32; - converted |= (UINT32)value.dwLowDateTime; - return converted; -} - -static FILETIME uint64_to_filetime(UINT64 value) -{ - FILETIME converted; - converted.dwLowDateTime = (UINT32)(value >> 0); - converted.dwHighDateTime = (UINT32)(value >> 32); - return converted; -} - -#define CLIPRDR_FILEDESCRIPTOR_SIZE (4 + 32 + 4 + 16 + 8 + 8 + 520) - -/** - * Parse a packed file list. - * - * The resulting array must be freed with the `free()` function. - * - * @param [in] format_data packed `CLIPRDR_FILELIST` to parse. - * @param [in] format_data_length length of `format_data` in bytes. - * @param [out] file_descriptor_array parsed array of `FILEDESCRIPTOR` structs. - * @param [out] file_descriptor_count number of elements in `file_descriptor_array`. - * - * @returns 0 on success, otherwise a Win32 error code. - */ -UINT cliprdr_parse_file_list(const BYTE* format_data, UINT32 format_data_length, - FILEDESCRIPTORW** file_descriptor_array, UINT32* file_descriptor_count) -{ - UINT result = NO_ERROR; - UINT32 i; - UINT32 count = 0; - wStream* s = NULL; - - if (!format_data || !file_descriptor_array || !file_descriptor_count) - return ERROR_BAD_ARGUMENTS; - - s = Stream_New((BYTE*)format_data, format_data_length); - if (!s) - return ERROR_NOT_ENOUGH_MEMORY; - - if (Stream_GetRemainingLength(s) < 4) - { - WLog_ERR(TAG, "invalid packed file list"); - - result = ERROR_INCORRECT_SIZE; - goto out; - } - - Stream_Read_UINT32(s, count); /* cItems (4 bytes) */ - - if (Stream_GetRemainingLength(s) / CLIPRDR_FILEDESCRIPTOR_SIZE < count) - { - WLog_ERR(TAG, "packed file list is too short: expected %" PRIuz ", have %" PRIuz, - ((size_t)count) * CLIPRDR_FILEDESCRIPTOR_SIZE, Stream_GetRemainingLength(s)); - - result = ERROR_INCORRECT_SIZE; - goto out; - } - - *file_descriptor_count = count; - *file_descriptor_array = calloc(count, sizeof(FILEDESCRIPTORW)); - if (!*file_descriptor_array) - { - result = ERROR_NOT_ENOUGH_MEMORY; - goto out; - } - - for (i = 0; i < count; i++) - { - int c; - UINT64 lastWriteTime; - FILEDESCRIPTORW* file = &((*file_descriptor_array)[i]); - - Stream_Read_UINT32(s, file->dwFlags); /* flags (4 bytes) */ - Stream_Seek(s, 32); /* reserved1 (32 bytes) */ - Stream_Read_UINT32(s, file->dwFileAttributes); /* fileAttributes (4 bytes) */ - Stream_Seek(s, 16); /* reserved2 (16 bytes) */ - Stream_Read_UINT64(s, lastWriteTime); /* lastWriteTime (8 bytes) */ - file->ftLastWriteTime = uint64_to_filetime(lastWriteTime); - Stream_Read_UINT32(s, file->nFileSizeHigh); /* fileSizeHigh (4 bytes) */ - Stream_Read_UINT32(s, file->nFileSizeLow); /* fileSizeLow (4 bytes) */ - for (c = 0; c < 260; c++) /* cFileName (520 bytes) */ - Stream_Read_UINT16(s, file->cFileName[c]); - } - - if (Stream_GetRemainingLength(s) > 0) - WLog_WARN(TAG, "packed file list has %" PRIuz " excess bytes", - Stream_GetRemainingLength(s)); -out: - Stream_Free(s, FALSE); - - return result; -} - -#define CLIPRDR_MAX_FILE_SIZE (2U * 1024 * 1024 * 1024) - -/** - * Serialize a packed file list. - * - * The resulting format data must be freed with the `free()` function. - * - * @param [in] file_descriptor_array array of `FILEDESCRIPTOR` structs to serialize. - * @param [in] file_descriptor_count number of elements in `file_descriptor_array`. - * @param [out] format_data serialized CLIPRDR_FILELIST. - * @param [out] format_data_length length of `format_data` in bytes. - * - * @returns 0 on success, otherwise a Win32 error code. - */ -UINT cliprdr_serialize_file_list(const FILEDESCRIPTORW* file_descriptor_array, - UINT32 file_descriptor_count, BYTE** format_data, - UINT32* format_data_length) -{ - return cliprdr_serialize_file_list_ex(CB_STREAM_FILECLIP_ENABLED, file_descriptor_array, - file_descriptor_count, format_data, format_data_length); -} - -UINT cliprdr_serialize_file_list_ex(UINT32 flags, const FILEDESCRIPTORW* file_descriptor_array, - UINT32 file_descriptor_count, BYTE** format_data, - UINT32* format_data_length) -{ - UINT result = NO_ERROR; - UINT32 i; - wStream* s = NULL; - - if (!file_descriptor_array || !format_data || !format_data_length) - return ERROR_BAD_ARGUMENTS; - - if ((flags & CB_STREAM_FILECLIP_ENABLED) == 0) - { - WLog_WARN(TAG, "No file clipboard support annouonced!"); - return ERROR_BAD_ARGUMENTS; - } - - s = Stream_New(NULL, 4 + file_descriptor_count * CLIPRDR_FILEDESCRIPTOR_SIZE); - if (!s) - return ERROR_NOT_ENOUGH_MEMORY; - - Stream_Write_UINT32(s, file_descriptor_count); /* cItems (4 bytes) */ - - for (i = 0; i < file_descriptor_count; i++) - { - int c; - UINT64 lastWriteTime; - const FILEDESCRIPTORW* file = &file_descriptor_array[i]; - - /* - * There is a known issue with Windows server getting stuck in - * an infinite loop when downloading files that are larger than - * 2 gigabytes. Do not allow clients to send such file lists. - * - * https://support.microsoft.com/en-us/help/2258090 - */ - if ((flags & CB_HUGE_FILE_SUPPORT_ENABLED) == 0) - { - if ((file->nFileSizeHigh > 0) || (file->nFileSizeLow >= CLIPRDR_MAX_FILE_SIZE)) - { - WLog_ERR(TAG, "cliprdr does not support files over 2 GB"); - result = ERROR_FILE_TOO_LARGE; - goto error; - } - } - - Stream_Write_UINT32(s, file->dwFlags); /* flags (4 bytes) */ - Stream_Zero(s, 32); /* reserved1 (32 bytes) */ - Stream_Write_UINT32(s, file->dwFileAttributes); /* fileAttributes (4 bytes) */ - Stream_Zero(s, 16); /* reserved2 (16 bytes) */ - lastWriteTime = filetime_to_uint64(file->ftLastWriteTime); - Stream_Write_UINT64(s, lastWriteTime); /* lastWriteTime (8 bytes) */ - Stream_Write_UINT32(s, file->nFileSizeHigh); /* fileSizeHigh (4 bytes) */ - Stream_Write_UINT32(s, file->nFileSizeLow); /* fileSizeLow (4 bytes) */ - for (c = 0; c < 260; c++) /* cFileName (520 bytes) */ - Stream_Write_UINT16(s, file->cFileName[c]); - } - - Stream_SealLength(s); - - Stream_GetBuffer(s, *format_data); - Stream_GetLength(s, *format_data_length); - - Stream_Free(s, FALSE); - - return result; - -error: - Stream_Free(s, TRUE); - - return result; -} diff --git a/include/freerdp/channels/cliprdr.h b/include/freerdp/channels/cliprdr.h index 86fc65890ba3..fbf23f6e5c9e 100644 --- a/include/freerdp/channels/cliprdr.h +++ b/include/freerdp/channels/cliprdr.h @@ -22,6 +22,7 @@ #include #include +#include #include @@ -93,17 +94,6 @@ extern "C" { #endif - FREERDP_API UINT cliprdr_parse_file_list(const BYTE* format_data, UINT32 format_data_length, - FILEDESCRIPTORW** file_descriptor_array, - UINT32* file_descriptor_count); - FREERDP_API UINT cliprdr_serialize_file_list(const FILEDESCRIPTORW* file_descriptor_array, - UINT32 file_descriptor_count, BYTE** format_data, - UINT32* format_data_length); - FREERDP_API UINT cliprdr_serialize_file_list_ex(UINT32 flags, - const FILEDESCRIPTORW* file_descriptor_array, - UINT32 file_descriptor_count, - BYTE** format_data, UINT32* format_data_length); - #ifdef __cplusplus } #endif diff --git a/include/freerdp/utils/cliprdr_utils.h b/include/freerdp/utils/cliprdr_utils.h new file mode 100644 index 000000000000..59ecf848fedf --- /dev/null +++ b/include/freerdp/utils/cliprdr_utils.h @@ -0,0 +1,48 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * RDPDR utility functions + * + * Copyright 2022 Armin Novak + * Copyright 2022 Thincast Technologies GmbH + * + * 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_UTILS_CLIPRDR_H +#define FREERDP_UTILS_CLIPRDR_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + + FREERDP_API UINT cliprdr_parse_file_list(const BYTE* format_data, UINT32 format_data_length, + FILEDESCRIPTORW** file_descriptor_array, + UINT32* file_descriptor_count); + FREERDP_API UINT cliprdr_serialize_file_list(const FILEDESCRIPTORW* file_descriptor_array, + UINT32 file_descriptor_count, BYTE** format_data, + UINT32* format_data_length); + FREERDP_API UINT cliprdr_serialize_file_list_ex(UINT32 flags, + const FILEDESCRIPTORW* file_descriptor_array, + UINT32 file_descriptor_count, + BYTE** format_data, UINT32* format_data_length); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libfreerdp/utils/CMakeLists.txt b/libfreerdp/utils/CMakeLists.txt index e3a8981d85a3..d09ca8b4f242 100644 --- a/libfreerdp/utils/CMakeLists.txt +++ b/libfreerdp/utils/CMakeLists.txt @@ -20,6 +20,7 @@ set(MODULE_PREFIX "FREERDP_UTILS") set(${MODULE_PREFIX}_SRCS passphrase.c + cliprdr_utils.c pcap.c profiler.c ringbuffer.c diff --git a/libfreerdp/utils/cliprdr_utils.c b/libfreerdp/utils/cliprdr_utils.c new file mode 100644 index 000000000000..7fb99d63a1b6 --- /dev/null +++ b/libfreerdp/utils/cliprdr_utils.c @@ -0,0 +1,235 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * Clipboard Virtual Channel Extension + * + * Copyright 2013 Marc-Andre Moreau + * Copyright 2022 Armin Novak +#include +#include + +#include +#define TAG FREERDP_TAG("utils." CLIPRDR_SVC_CHANNEL_NAME) + +#define CLIPRDR_FILEDESCRIPTOR_SIZE (4 + 32 + 4 + 16 + 8 + 8 + 520) +#define CLIPRDR_MAX_FILE_SIZE (2U * 1024 * 1024 * 1024) + +static UINT64 filetime_to_uint64(FILETIME value) +{ + UINT64 converted = 0; + converted |= (UINT32)value.dwHighDateTime; + converted <<= 32; + converted |= (UINT32)value.dwLowDateTime; + return converted; +} + +static FILETIME uint64_to_filetime(UINT64 value) +{ + FILETIME converted; + converted.dwLowDateTime = (UINT32)(value >> 0); + converted.dwHighDateTime = (UINT32)(value >> 32); + return converted; +} + +/** + * Parse a packed file list. + * + * The resulting array must be freed with the `free()` function. + * + * @param [in] format_data packed `CLIPRDR_FILELIST` to parse. + * @param [in] format_data_length length of `format_data` in bytes. + * @param [out] file_descriptor_array parsed array of `FILEDESCRIPTOR` structs. + * @param [out] file_descriptor_count number of elements in `file_descriptor_array`. + * + * @returns 0 on success, otherwise a Win32 error code. + */ +UINT cliprdr_parse_file_list(const BYTE* format_data, UINT32 format_data_length, + FILEDESCRIPTORW** file_descriptor_array, UINT32* file_descriptor_count) +{ + UINT result = NO_ERROR; + UINT32 i; + UINT32 count = 0; + wStream sbuffer; + wStream* s = &sbuffer; + + if (!format_data || !file_descriptor_array || !file_descriptor_count) + return ERROR_BAD_ARGUMENTS; + + Stream_StaticInit(&sbuffer, format_data, format_data_length); + if (!s) + return ERROR_NOT_ENOUGH_MEMORY; + + if (Stream_GetRemainingLength(s) < 4) + { + WLog_ERR(TAG, "invalid packed file list"); + + result = ERROR_INCORRECT_SIZE; + goto out; + } + + Stream_Read_UINT32(s, count); /* cItems (4 bytes) */ + + if (Stream_GetRemainingLength(s) / CLIPRDR_FILEDESCRIPTOR_SIZE < count) + { + WLog_ERR(TAG, "packed file list is too short: expected %" PRIuz ", have %" PRIuz, + ((size_t)count) * CLIPRDR_FILEDESCRIPTOR_SIZE, Stream_GetRemainingLength(s)); + + result = ERROR_INCORRECT_SIZE; + goto out; + } + + *file_descriptor_count = count; + *file_descriptor_array = calloc(count, sizeof(FILEDESCRIPTORW)); + if (!*file_descriptor_array) + { + result = ERROR_NOT_ENOUGH_MEMORY; + goto out; + } + + for (i = 0; i < count; i++) + { + UINT64 tmp; + FILEDESCRIPTORW* file = &((*file_descriptor_array)[i]); + + Stream_Read_UINT32(s, file->dwFlags); /* flags (4 bytes) */ + Stream_Read_UINT32(s, file->clsid.Data1); + Stream_Read_UINT16(s, file->clsid.Data2); + Stream_Read_UINT16(s, file->clsid.Data3); + Stream_Read(s, &file->clsid.Data4, sizeof(file->clsid.Data4)); + Stream_Read_INT32(s, file->sizel.cx); + Stream_Read_INT32(s, file->sizel.cy); + Stream_Read_INT32(s, file->pointl.x); + Stream_Read_INT32(s, file->pointl.y); + Stream_Read_UINT32(s, file->dwFileAttributes); /* fileAttributes (4 bytes) */ + Stream_Read_UINT64(s, tmp); /* ftCreationTime (8 bytes) */ + file->ftCreationTime = uint64_to_filetime(tmp); + Stream_Read_UINT64(s, tmp); /* ftLastAccessTime (8 bytes) */ + file->ftLastAccessTime = uint64_to_filetime(tmp); + Stream_Read_UINT64(s, tmp); /* lastWriteTime (8 bytes) */ + file->ftLastWriteTime = uint64_to_filetime(tmp); + Stream_Read_UINT32(s, file->nFileSizeHigh); /* fileSizeHigh (4 bytes) */ + Stream_Read_UINT32(s, file->nFileSizeLow); /* fileSizeLow (4 bytes) */ + Stream_Read_UTF16_String(s, file->cFileName, + ARRAYSIZE(file->cFileName)); /* cFileName (520 bytes) */ + } + + if (Stream_GetRemainingLength(s) > 0) + WLog_WARN(TAG, "packed file list has %" PRIuz " excess bytes", + Stream_GetRemainingLength(s)); +out: + + return result; +} + +/** + * Serialize a packed file list. + * + * The resulting format data must be freed with the `free()` function. + * + * @param [in] file_descriptor_array array of `FILEDESCRIPTOR` structs to serialize. + * @param [in] file_descriptor_count number of elements in `file_descriptor_array`. + * @param [out] format_data serialized CLIPRDR_FILELIST. + * @param [out] format_data_length length of `format_data` in bytes. + * + * @returns 0 on success, otherwise a Win32 error code. + */ +UINT cliprdr_serialize_file_list(const FILEDESCRIPTORW* file_descriptor_array, + UINT32 file_descriptor_count, BYTE** format_data, + UINT32* format_data_length) +{ + return cliprdr_serialize_file_list_ex(CB_STREAM_FILECLIP_ENABLED, file_descriptor_array, + file_descriptor_count, format_data, format_data_length); +} + +UINT cliprdr_serialize_file_list_ex(UINT32 flags, const FILEDESCRIPTORW* file_descriptor_array, + UINT32 file_descriptor_count, BYTE** format_data, + UINT32* format_data_length) +{ + UINT result = NO_ERROR; + UINT32 i; + size_t len; + wStream* s = NULL; + + if (!file_descriptor_array || !format_data || !format_data_length) + return ERROR_BAD_ARGUMENTS; + + if ((flags & CB_STREAM_FILECLIP_ENABLED) == 0) + { + WLog_WARN(TAG, "No file clipboard support annouonced!"); + return ERROR_BAD_ARGUMENTS; + } + + s = Stream_New(NULL, 4 + file_descriptor_count * CLIPRDR_FILEDESCRIPTOR_SIZE); + if (!s) + return ERROR_NOT_ENOUGH_MEMORY; + + Stream_Write_UINT32(s, file_descriptor_count); /* cItems (4 bytes) */ + + for (i = 0; i < file_descriptor_count; i++) + { + int c; + UINT64 lastWriteTime; + const FILEDESCRIPTORW* file = &file_descriptor_array[i]; + + /* + * There is a known issue with Windows server getting stuck in + * an infinite loop when downloading files that are larger than + * 2 gigabytes. Do not allow clients to send such file lists. + * + * https://support.microsoft.com/en-us/help/2258090 + */ + if ((flags & CB_HUGE_FILE_SUPPORT_ENABLED) == 0) + { + if ((file->nFileSizeHigh > 0) || (file->nFileSizeLow >= CLIPRDR_MAX_FILE_SIZE)) + { + WLog_ERR(TAG, "cliprdr does not support files over 2 GB"); + result = ERROR_FILE_TOO_LARGE; + goto error; + } + } + + Stream_Write_UINT32(s, file->dwFlags); /* flags (4 bytes) */ + Stream_Zero(s, 32); /* reserved1 (32 bytes) */ + Stream_Write_UINT32(s, file->dwFileAttributes); /* fileAttributes (4 bytes) */ + Stream_Zero(s, 16); /* reserved2 (16 bytes) */ + lastWriteTime = filetime_to_uint64(file->ftLastWriteTime); + Stream_Write_UINT64(s, lastWriteTime); /* lastWriteTime (8 bytes) */ + Stream_Write_UINT32(s, file->nFileSizeHigh); /* fileSizeHigh (4 bytes) */ + Stream_Write_UINT32(s, file->nFileSizeLow); /* fileSizeLow (4 bytes) */ + for (c = 0; c < 260; c++) /* cFileName (520 bytes) */ + Stream_Write_UINT16(s, file->cFileName[c]); + } + + Stream_SealLength(s); + + Stream_GetBuffer(s, *format_data); + Stream_GetLength(s, len); + if (len > UINT32_MAX) + goto error; + + *format_data_length = (UINT32)len; + + Stream_Free(s, FALSE); + + return result; + +error: + Stream_Free(s, TRUE); + + return result; +} From 7a2215fd40a95fd9d506c704967386511340b85c Mon Sep 17 00:00:00 2001 From: Siva Gudivada <98360053+sivagudivadaz@users.noreply.github.com> Date: Thu, 28 Jul 2022 05:12:12 -0700 Subject: [PATCH 247/496] Backport TLS1.2 enforcement and version control from master to stable2.0 (#8094) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add a new command line arg to enforce tls1.2 * Add better explanation of FreeRDP_EnforceTLSv1_2 (cherry picked from commit ce2e3ab0c7b8d94fbfedfcfbe248b98e1d2917d2) * Regenerated settings helpers * backport prev cherry-pick * Cleanup tls_prepare * TLS version control * added settings for minimal and maximal TLS versions supported * refactorisation of the force TLSv1.2 setting * cleanup from prev cherry-pick * updated change log Co-authored-by: akallabeth Co-authored-by: David Véron --- ChangeLog | 2 + client/common/cmdline.c | 6 + client/common/cmdline.h | 3 + include/freerdp/settings.h | 6 +- libfreerdp/common/settings_getters.c | 14 ++ libfreerdp/common/settings_str.c | 219 ++++++++++++++++++ libfreerdp/core/settings.c | 3 + .../core/test/settings_property_lists.h | 2 + libfreerdp/crypto/tls.c | 37 ++- 9 files changed, 281 insertions(+), 11 deletions(-) diff --git a/ChangeLog b/ChangeLog index 6e0ac0761094..fe91fab6b462 100644 --- a/ChangeLog +++ b/ChangeLog @@ -8,6 +8,8 @@ Noteworthy changes: * Backported #8010: Add server side handling for [MS-RDPECAM] * Backported #8041: Remove ALAW/ULAW codecs from linux backends (unreliable) * Backported #8051: Relieve CLIPRDR filename restriction when connecting to non-MS Windows servers +* Backported #8048: TLS version control +* Backported #7987: Add a new command line arg to enforce tls1.2 Fixed issues: * Fixed #7837: Prevent out of bound reads for FFMPEG diff --git a/client/common/cmdline.c b/client/common/cmdline.c index 52f90f503d5a..d2d949b71e9a 100644 --- a/client/common/cmdline.c +++ b/client/common/cmdline.c @@ -2918,6 +2918,12 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, settings->TlsSecLevel = (UINT32)val; } + CommandLineSwitchCase(arg, "enforce-tlsv1_2") + { + if (!(freerdp_settings_set_uint16(settings, FreeRDP_TLSMinVersion, TLS1_2_VERSION) && + freerdp_settings_set_uint16(settings, FreeRDP_TLSMaxVersion, TLS1_2_VERSION))) + return COMMAND_LINE_ERROR_UNEXPECTED_VALUE; + } CommandLineSwitchCase(arg, "cert") { int rc = 0; diff --git a/client/common/cmdline.h b/client/common/cmdline.h index 9a60e3df922b..92a86f96fa26 100644 --- a/client/common/cmdline.h +++ b/client/common/cmdline.h @@ -353,6 +353,9 @@ static const COMMAND_LINE_ARGUMENT_A args[] = { "Allowed TLS ciphers" }, { "tls-seclevel", COMMAND_LINE_VALUE_REQUIRED, "", "1", NULL, -1, NULL, "TLS security level - defaults to 1" }, + { "enforce-tlsv1_2", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueFalse, NULL, -1, NULL, + "Force use of TLS1.2 for connection. Some servers have a buggy TLS version negotiation and " + "might fail without this" }, { "toggle-fullscreen", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueTrue, NULL, -1, NULL, "Alt+Ctrl+Enter to toggle fullscreen" }, { "tune", COMMAND_LINE_VALUE_REQUIRED, ",", "", NULL, -1, NULL, diff --git a/include/freerdp/settings.h b/include/freerdp/settings.h index 7553a1d663ec..46d853622281 100644 --- a/include/freerdp/settings.h +++ b/include/freerdp/settings.h @@ -656,6 +656,8 @@ typedef struct _RDPDR_PARALLEL RDPDR_PARALLEL; #define FreeRDP_NtlmSamFile (1103) #define FreeRDP_FIPSMode (1104) #define FreeRDP_TlsSecLevel (1105) +#define FreeRDP_TLSMinVersion (1106) +#define FreeRDP_TLSMaxVersion (1107) #define FreeRDP_MstscCookieMode (1152) #define FreeRDP_CookieMaxLength (1153) #define FreeRDP_PreconnectionId (1154) @@ -1108,7 +1110,9 @@ struct rdp_settings ALIGN64 char* NtlmSamFile; /* 1103 */ ALIGN64 BOOL FIPSMode; /* 1104 */ ALIGN64 UINT32 TlsSecLevel; /* 1105 */ - UINT64 padding1152[1152 - 1106]; /* 1106 */ + ALIGN64 UINT16 TLSMinVersion; /* 1106 */ + ALIGN64 UINT16 TLSMaxVersion; /* 1107 */ + UINT64 padding1152[1152 - 1108]; /* 1108 */ /* Connection Cookie */ ALIGN64 BOOL MstscCookieMode; /* 1152 */ diff --git a/libfreerdp/common/settings_getters.c b/libfreerdp/common/settings_getters.c index a3ce8e9611e5..9224524d9f22 100644 --- a/libfreerdp/common/settings_getters.c +++ b/libfreerdp/common/settings_getters.c @@ -1193,6 +1193,12 @@ UINT16 freerdp_settings_get_uint16(const rdpSettings* settings, size_t id) case FreeRDP_ProxyPort: return settings->ProxyPort; + case FreeRDP_TLSMaxVersion: + return settings->TLSMaxVersion; + + case FreeRDP_TLSMinVersion: + return settings->TLSMinVersion; + default: WLog_ERR(TAG, "[%s] Invalid key index %" PRIuz, __FUNCTION__, id); return FALSE; @@ -1214,6 +1220,14 @@ BOOL freerdp_settings_set_uint16(rdpSettings* settings, size_t id, UINT16 val) settings->ProxyPort = val; break; + case FreeRDP_TLSMaxVersion: + settings->TLSMaxVersion = val; + break; + + case FreeRDP_TLSMinVersion: + settings->TLSMinVersion = val; + break; + default: WLog_ERR(TAG, "[%s] Invalid key index %" PRIuz, __FUNCTION__, id); return FALSE; diff --git a/libfreerdp/common/settings_str.c b/libfreerdp/common/settings_str.c index 9a545f25d2d0..9a0bf5378d0e 100644 --- a/libfreerdp/common/settings_str.c +++ b/libfreerdp/common/settings_str.c @@ -180,6 +180,8 @@ static const struct settings_str_entry settings_map[] = { { FreeRDP_Workarea, 0, "FreeRDP_Workarea" }, { FreeRDP_DesktopOrientation, 1, "FreeRDP_DesktopOrientation" }, { FreeRDP_ProxyPort, 1, "FreeRDP_ProxyPort" }, + { FreeRDP_TLSMaxVersion, 1, "FreeRDP_TLSMaxVersion" }, + { FreeRDP_TLSMinVersion, 1, "FreeRDP_TLSMinVersion" }, { FreeRDP_AcceptedCertLength, 3, "FreeRDP_AcceptedCertLength" }, { FreeRDP_AuthenticationLevel, 3, "FreeRDP_AuthenticationLevel" }, { FreeRDP_AutoReconnectMaxRetries, 3, "FreeRDP_AutoReconnectMaxRetries" }, @@ -393,6 +395,10 @@ static const struct settings_str_entry settings_map[] = { BOOL freerdp_settings_clone_keys(rdpSettings* dst, const rdpSettings* src) { size_t x; + + WINPR_ASSERT(dst); + WINPR_ASSERT(src); + for (x = 0; x < ARRAYSIZE(settings_map); x++) { const struct settings_str_entry* cur = &settings_map[x]; @@ -466,9 +472,214 @@ BOOL freerdp_settings_clone_keys(rdpSettings* dst, const rdpSettings* src) return TRUE; } +BOOL freerdp_settings_print_diff(wLog* log, DWORD level, const rdpSettings* settings, + const rdpSettings* other) +{ + BOOL rc = FALSE; + size_t x; + + WINPR_ASSERT(log); + WINPR_ASSERT(settings); + WINPR_ASSERT(other); + + for (x = 0; x < ARRAYSIZE(settings_map); x++) + { + const struct settings_str_entry* cur = &settings_map[x]; + switch (cur->type) + { + case 0: /* bool */ + { + BOOL sval = freerdp_settings_get_bool(settings, cur->id); + BOOL cval = freerdp_settings_get_bool(other, cur->id); + if (sval != cval) + { + rc = TRUE; + WLog_Print(log, level, "%s [BOOL]: %s -> %s", cur->str, sval ? "TRUE" : "FALSE", + cval ? "TRUE" : "FALSE"); + } + } + break; + case 1: /* UINT16 */ + { + UINT16 sval = freerdp_settings_get_uint16(settings, cur->id); + UINT16 cval = freerdp_settings_get_uint16(other, cur->id); + if (sval != cval) + { + rc = TRUE; + WLog_Print(log, level, "%s [UINT16]: %" PRIu16 " -> %" PRIu16, cur->str, sval, + cval); + } + } + break; + case 2: /* INT16 */ + { + INT16 sval = freerdp_settings_get_int16(settings, cur->id); + INT16 cval = freerdp_settings_get_int16(other, cur->id); + if (sval != cval) + { + rc = TRUE; + WLog_Print(log, level, "%s [INT16]: %" PRId16 " -> %" PRId16, cur->str, sval, + cval); + } + } + break; + case 3: /* UINT32 */ + { + UINT32 sval = freerdp_settings_get_uint32(settings, cur->id); + UINT32 cval = freerdp_settings_get_uint32(other, cur->id); + if (sval != cval) + { + rc = TRUE; + WLog_Print(log, level, "%s [UINT32]: %" PRIu32 " -> %" PRIu32, cur->str, sval, + cval); + } + } + break; + case 4: /* INT32 */ + { + INT32 sval = freerdp_settings_get_int32(settings, cur->id); + INT32 cval = freerdp_settings_get_int32(other, cur->id); + if (sval != cval) + { + rc = TRUE; + WLog_Print(log, level, "%s [INT32]: %" PRId32 " -> %" PRId32, cur->str, sval, + cval); + } + } + break; + case 5: /* UINT64 */ + { + UINT64 sval = freerdp_settings_get_uint64(settings, cur->id); + UINT64 cval = freerdp_settings_get_uint64(other, cur->id); + if (sval != cval) + { + rc = TRUE; + WLog_Print(log, level, "%s [UINT64]: %" PRIu64 " -> %" PRIu64, cur->str, sval, + cval); + } + } + break; + case 6: /* INT64 */ + { + INT64 sval = freerdp_settings_get_int64(settings, cur->id); + INT64 cval = freerdp_settings_get_int64(other, cur->id); + if (sval != cval) + { + rc = TRUE; + WLog_Print(log, level, "%s [INT64]: %" PRId64 " -> %" PRId64, cur->str, sval, + cval); + } + } + break; + case 7: /* strings */ + { + const char* sval = freerdp_settings_get_string(settings, cur->id); + const char* cval = freerdp_settings_get_string(other, cur->id); + if (sval != cval) + { + if (!sval || !cval || (strcmp(sval, cval) != 0)) + { + rc = TRUE; + WLog_Print(log, level, "%s [STRING]: '%s' -> '%s'", cur->str, sval, cval); + } + } + } + break; + case 8: /* pointer */ + { + const void* sval = freerdp_settings_get_pointer(settings, cur->id); + const void* cval = freerdp_settings_get_pointer(other, cur->id); + if (sval != cval) + { + if ((sval && !cval) || (!sval && cval)) + { + rc = TRUE; + WLog_Print(log, level, "%s [POINTER]: '%p' -> '%p'", cur->str, sval, cval); + } + } + } + break; + } + } + return rc; +} + +void freerdp_settings_dump(wLog* log, DWORD level, const rdpSettings* settings) +{ + size_t x; + + WINPR_ASSERT(log); + WINPR_ASSERT(settings); + + for (x = 0; x < ARRAYSIZE(settings_map); x++) + { + const struct settings_str_entry* cur = &settings_map[x]; + switch (cur->type) + { + case 0: /* bool */ + { + BOOL sval = freerdp_settings_get_bool(settings, cur->id); + WLog_Print(log, level, "%s [BOOL]: %s", cur->str, sval ? "TRUE" : "FALSE"); + } + break; + case 1: /* UINT16 */ + { + UINT16 sval = freerdp_settings_get_uint16(settings, cur->id); + WLog_Print(log, level, "%s [UINT16]: %" PRIu16, cur->str, sval); + } + break; + case 2: /* INT16 */ + { + INT16 sval = freerdp_settings_get_int16(settings, cur->id); + WLog_Print(log, level, "%s [INT16]: %" PRId16, cur->str, sval); + } + break; + case 3: /* UINT32 */ + { + UINT32 sval = freerdp_settings_get_uint32(settings, cur->id); + WLog_Print(log, level, "%s [UINT32]: %" PRIu32, cur->str, sval); + } + break; + case 4: /* INT32 */ + { + INT32 sval = freerdp_settings_get_int32(settings, cur->id); + WLog_Print(log, level, "%s [INT32]: %" PRId32, cur->str, sval); + } + break; + case 5: /* UINT64 */ + { + UINT64 sval = freerdp_settings_get_uint64(settings, cur->id); + WLog_Print(log, level, "%s [UINT64]: %" PRIu64, cur->str, sval); + } + break; + case 6: /* INT64 */ + { + INT64 sval = freerdp_settings_get_int64(settings, cur->id); + WLog_Print(log, level, "%s [INT64]: %" PRId64, cur->str, sval); + } + break; + case 7: /* strings */ + { + const char* sval = freerdp_settings_get_string(settings, cur->id); + WLog_Print(log, level, "%s [STRING]: '%s'", cur->str, sval); + } + break; + case 8: /* pointer */ + { + const void* sval = freerdp_settings_get_pointer(settings, cur->id); + WLog_Print(log, level, "%s [POINTER]: '%p'", cur->str, sval); + } + break; + } + } +} + void freerdp_settings_free_keys(rdpSettings* dst, BOOL cleanup) { size_t x; + + WINPR_ASSERT(dst); + for (x = 0; x < ARRAYSIZE(settings_map); x++) { const struct settings_str_entry* cur = &settings_map[x]; @@ -487,6 +698,9 @@ void freerdp_settings_free_keys(rdpSettings* dst, BOOL cleanup) SSIZE_T freerdp_settings_get_key_for_name(const char* value) { size_t x; + + WINPR_ASSERT(value); + for (x = 0; x < ARRAYSIZE(settings_map); x++) { const struct settings_str_entry* cur = &settings_map[x]; @@ -499,6 +713,9 @@ SSIZE_T freerdp_settings_get_key_for_name(const char* value) SSIZE_T freerdp_settings_get_type_for_name(const char* value) { size_t x; + + WINPR_ASSERT(value); + for (x = 0; x < ARRAYSIZE(settings_map); x++) { const struct settings_str_entry* cur = &settings_map[x]; @@ -511,6 +728,7 @@ SSIZE_T freerdp_settings_get_type_for_name(const char* value) SSIZE_T freerdp_settings_get_type_for_key(size_t key) { size_t x; + for (x = 0; x < ARRAYSIZE(settings_map); x++) { const struct settings_str_entry* cur = &settings_map[x]; @@ -523,6 +741,7 @@ SSIZE_T freerdp_settings_get_type_for_key(size_t key) const char* freerdp_settings_get_name_for_key(size_t key) { size_t x; + for (x = 0; x < ARRAYSIZE(settings_map); x++) { const struct settings_str_entry* cur = &settings_map[x]; diff --git a/libfreerdp/core/settings.c b/libfreerdp/core/settings.c index 6a7b9900c48c..76b0e790b40b 100644 --- a/libfreerdp/core/settings.c +++ b/libfreerdp/core/settings.c @@ -599,6 +599,9 @@ rdpSettings* freerdp_settings_new(DWORD flags) settings->TlsSecLevel = 1; settings->OrderSupport = calloc(1, 32); + freerdp_settings_set_uint16(settings, FreeRDP_TLSMinVersion, TLS1_VERSION); + freerdp_settings_set_uint16(settings, FreeRDP_TLSMaxVersion, 0); + if (!settings->OrderSupport) goto out_fail; diff --git a/libfreerdp/core/test/settings_property_lists.h b/libfreerdp/core/test/settings_property_lists.h index db8e5ed8e290..dcf1e49296ff 100644 --- a/libfreerdp/core/test/settings_property_lists.h +++ b/libfreerdp/core/test/settings_property_lists.h @@ -173,6 +173,8 @@ static const size_t bool_list_indices[] = { static const size_t uint16_list_indices[] = { FreeRDP_DesktopOrientation, FreeRDP_ProxyPort, + FreeRDP_TLSMaxVersion, + FreeRDP_TLSMinVersion, }; #define have_uint32_list_indices diff --git a/libfreerdp/crypto/tls.c b/libfreerdp/crypto/tls.c index 1990302b7637..99b079212db7 100644 --- a/libfreerdp/crypto/tls.c +++ b/libfreerdp/crypto/tls.c @@ -77,6 +77,7 @@ struct _BIO_RDP_TLS }; typedef struct _BIO_RDP_TLS BIO_RDP_TLS; +static BOOL tls_prep(rdpTls* tls, BIO* underlying, int options, BOOL clientMode); static int tls_verify_certificate(rdpTls* tls, CryptoCert cert, const char* hostname, UINT16 port); static void tls_print_certificate_name_mismatch_error(const char* hostname, UINT16 port, const char* common_name, char** alt_names, @@ -667,8 +668,18 @@ static BOOL tls_prepare(rdpTls* tls, BIO* underlying, SSL_METHOD* method, int op SSL_CTX_set_options(tls->ctx, options); SSL_CTX_set_read_ahead(tls->ctx, 1); #if OPENSSL_VERSION_NUMBER >= 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) - SSL_CTX_set_min_proto_version(tls->ctx, TLS1_VERSION); /* min version */ - SSL_CTX_set_max_proto_version(tls->ctx, 0); /* highest supported version by library */ + UINT16 version = freerdp_settings_get_uint16(settings, FreeRDP_TLSMinVersion); + if (!SSL_CTX_set_min_proto_version(tls->ctx, version)) + { + WLog_ERR(TAG, "SSL_CTX_set_min_proto_version %s failed", version); + return FALSE; + } + version = freerdp_settings_get_uint16(settings, FreeRDP_TLSMaxVersion); + if (!SSL_CTX_set_max_proto_version(tls->ctx, version)) + { + WLog_ERR(TAG, "SSL_CTX_set_max_proto_version %s failed", version); + return FALSE; + } #endif #if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER) SSL_CTX_set_security_level(tls->ctx, settings->TlsSecLevel); @@ -855,6 +866,18 @@ int tls_connect(rdpTls* tls, BIO* underlying) * support empty fragments. This needs to be disabled. */ options |= SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS; + + if (!tls_prep(tls, underlying, options, TRUE)) + return 0; + +#if !defined(OPENSSL_NO_TLSEXT) && !defined(LIBRESSL_VERSION_NUMBER) + SSL_set_tlsext_host_name(tls->ssl, tls->hostname); +#endif + return tls_do_handshake(tls, TRUE); +} + +BOOL tls_prep(rdpTls* tls, BIO* underlying, int options, BOOL clientMode) +{ #if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER) /** * disable SSLv2 and SSLv3 @@ -862,16 +885,10 @@ int tls_connect(rdpTls* tls, BIO* underlying) options |= SSL_OP_NO_SSLv2; options |= SSL_OP_NO_SSLv3; - if (!tls_prepare(tls, underlying, SSLv23_client_method(), options, TRUE)) + return tls_prepare(tls, underlying, SSLv23_client_method(), options, clientMode); #else - if (!tls_prepare(tls, underlying, TLS_client_method(), options, TRUE)) + return tls_prepare(tls, underlying, TLS_client_method(), options, clientMode); #endif - return 0; - -#if !defined(OPENSSL_NO_TLSEXT) && !defined(LIBRESSL_VERSION_NUMBER) - SSL_set_tlsext_host_name(tls->ssl, tls->hostname); -#endif - return tls_do_handshake(tls, TRUE); } #if defined(MICROSOFT_IOS_SNI_BUG) && !defined(OPENSSL_NO_TLSEXT) && \ From e3fc97feb512053189e276b2ca79762990bb8c4c Mon Sep 17 00:00:00 2001 From: Bernhard Miklautz Date: Thu, 28 Jul 2022 15:12:43 +0200 Subject: [PATCH 248/496] Release 2.8.0 (#8096) --- CMakeLists.txt | 2 +- ChangeLog | 8 +++++++- client/Android/android_freerdp.c | 2 +- winpr/CMakeLists.txt | 2 +- 4 files changed, 10 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 007acaf2d078..b1ad102b41ee 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -85,7 +85,7 @@ if ($ENV{BUILD_NUMBER}) endif() set(WITH_LIBRARY_VERSIONING "ON") -set(RAW_VERSION_STRING "2.7.0") +set(RAW_VERSION_STRING "2.8.0") if(EXISTS "${CMAKE_SOURCE_DIR}/.source_tag") file(READ ${CMAKE_SOURCE_DIR}/.source_tag RAW_VERSION_STRING) elseif(USE_VERSION_FROM_GIT_TAG) diff --git a/ChangeLog b/ChangeLog index fe91fab6b462..c2e7a3f741d2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,7 @@ -# 20xx-xx-xx Version 2.x.x +# 2022-07-28 Version 2.8.0 Noteworthy changes: + * Backported API to get peer accepted channel option flags * Backported API to get peer accepted channel names * Backported Stream_CheckAndLogRequiredLength @@ -12,6 +13,7 @@ Noteworthy changes: * Backported #7987: Add a new command line arg to enforce tls1.2 Fixed issues: + * Fixed #7837: Prevent out of bound reads for FFMPEG * Backported #7859 and #7861: Unwind support for backtrace generation * Backported #7440: wlfreerdp appid @@ -27,6 +29,10 @@ Fixed issues: * Backported #8013: Add missing osMajorType values * Backported #8076: Fix wrong usage of subband diffing flag (tile artifact fix) +For a complete and detailed change log since the last release run: +git log 2.7.0..2.8.0 + + # 2022-04-25 Version 2.7.0 Noteworthy changes: diff --git a/client/Android/android_freerdp.c b/client/Android/android_freerdp.c index 6ac79a633c54..6811381152e7 100644 --- a/client/Android/android_freerdp.c +++ b/client/Android/android_freerdp.c @@ -57,7 +57,7 @@ #define TAG CLIENT_TAG("android") /* Defines the JNI version supported by this library. */ -#define FREERDP_JNI_VERSION "2.7.0" +#define FREERDP_JNI_VERSION "2.8.0" static void android_OnChannelConnectedEventHandler(void* context, ChannelConnectedEventArgs* e) { diff --git a/winpr/CMakeLists.txt b/winpr/CMakeLists.txt index 045e09fab1ca..cf500edfe816 100644 --- a/winpr/CMakeLists.txt +++ b/winpr/CMakeLists.txt @@ -57,7 +57,7 @@ if (NOT WIN32) endif() # Soname versioning -set(RAW_VERSION_STRING "2.7.0") +set(RAW_VERSION_STRING "2.8.0") if(EXISTS "${CMAKE_SOURCE_DIR}/.source_tag") file(READ ${CMAKE_SOURCE_DIR}/.source_tag RAW_VERSION_STRING) elseif(USE_VERSION_FROM_GIT_TAG) From 6eb3a26a7c9bb37223767c663869d8573295c0e3 Mon Sep 17 00:00:00 2001 From: David Fort Date: Fri, 5 Aug 2022 08:32:40 +0200 Subject: [PATCH 249/496] Backport: fix test create process (#8112) * winpr: fix unitary test when CreateProcess is CreateProcessW As the second argument of CreateProcessW is modified to split with spaces and so this can not be a const arg. * winpr: removed a C++ style comment --- winpr/include/winpr/crt.h | 20 +++++++++---------- winpr/include/winpr/string.h | 2 +- winpr/libwinpr/crt/alignment.c | 2 +- .../thread/test/TestThreadCreateProcess.c | 14 ++++++------- 4 files changed, 19 insertions(+), 19 deletions(-) diff --git a/winpr/include/winpr/crt.h b/winpr/include/winpr/crt.h index 3f6b5a119533..40fde55a9ffd 100644 --- a/winpr/include/winpr/crt.h +++ b/winpr/include/winpr/crt.h @@ -40,39 +40,39 @@ #ifndef _strtoui64 #define _strtoui64 strtoull -#endif +#endif /* _strtoui64 */ #ifndef _strtoi64 #define _strtoi64 strtoll -#endif +#endif /* _strtoi64 */ #ifndef _rotl static INLINE UINT32 _rotl(UINT32 value, int shift) { return (value << shift) | (value >> (32 - shift)); } -#endif +#endif /* _rotl */ #ifndef _rotl64 static INLINE UINT64 _rotl64(UINT64 value, int shift) { return (value << shift) | (value >> (64 - shift)); } -#endif +#endif /* _rotl64 */ #ifndef _rotr static INLINE UINT32 _rotr(UINT32 value, int shift) { return (value >> shift) | (value << (32 - shift)); } -#endif +#endif /* _rotr */ #ifndef _rotr64 static INLINE UINT64 _rotr64(UINT64 value, int shift) { return (value >> shift) | (value << (64 - shift)); } -#endif +#endif /* _rotr64 */ #if (__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 2)) @@ -95,7 +95,7 @@ static INLINE UINT64 _byteswap_uint64(UINT64 _val) ((_val) >> 56)); } -#endif +#endif /* (__GNUC__ > 4) || ... */ #if (__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 8)) @@ -108,7 +108,7 @@ static INLINE UINT16 _byteswap_ushort(UINT16 _val) return (((_val) >> 8) | ((_val) << 8)); } -#endif +#endif /* (__GNUC__ > 4) || ... */ #define CopyMemory(Destination, Source, Length) memcpy((Destination), (Source), (Length)) #define MoveMemory(Destination, Source, Length) memmove((Destination), (Source), (Length)) @@ -131,7 +131,7 @@ extern "C" #ifndef _ERRNO_T_DEFINED #define _ERRNO_T_DEFINED typedef int errno_t; -#endif +#endif /* _ERRNO_T_DEFINED */ #ifdef __cplusplus extern "C" @@ -166,6 +166,6 @@ extern "C" } #endif -#endif +#endif /* _WIN32 */ #endif /* WINPR_CRT_H */ diff --git a/winpr/include/winpr/string.h b/winpr/include/winpr/string.h index 69af1a0553f3..d7a849c8bed1 100644 --- a/winpr/include/winpr/string.h +++ b/winpr/include/winpr/string.h @@ -78,7 +78,7 @@ extern "C" #define _wcschr wcschr #define _wcsrchr wcsrchr -#endif +#endif /* _WIN32 */ #if !defined(_WIN32) || defined(_UWP) diff --git a/winpr/libwinpr/crt/alignment.c b/winpr/libwinpr/crt/alignment.c index af76023d7689..88c3f7d4043c 100644 --- a/winpr/libwinpr/crt/alignment.c +++ b/winpr/libwinpr/crt/alignment.c @@ -242,4 +242,4 @@ void _aligned_free(void* memblock) free(pMem->base_addr); } -#endif +#endif /* _WIN32 */ diff --git a/winpr/libwinpr/thread/test/TestThreadCreateProcess.c b/winpr/libwinpr/thread/test/TestThreadCreateProcess.c index 61659fe70844..7d662e207796 100644 --- a/winpr/libwinpr/thread/test/TestThreadCreateProcess.c +++ b/winpr/libwinpr/thread/test/TestThreadCreateProcess.c @@ -15,7 +15,13 @@ int TestThreadCreateProcess(int argc, char* argv[]) BOOL status; DWORD exitCode; LPCTSTR lpApplicationName; - LPTSTR lpCommandLine; + +#ifdef _WIN32 + TCHAR lpCommandLine[200] = _T("cmd /C set"); +#else + TCHAR lpCommandLine[200] = _T("printenv"); +#endif + LPSECURITY_ATTRIBUTES lpProcessAttributes; LPSECURITY_ATTRIBUTES lpThreadAttributes; BOOL bInheritHandles; @@ -36,12 +42,6 @@ int TestThreadCreateProcess(int argc, char* argv[]) lpApplicationName = NULL; -#ifdef _WIN32 - lpCommandLine = _T("cmd /C set"); -#else - lpCommandLine = _T("printenv"); -#endif - lpProcessAttributes = NULL; lpThreadAttributes = NULL; bInheritHandles = FALSE; From 96955d346fa90470b0b2d8b72872b7425ccdc47c Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Mon, 12 Sep 2022 09:10:56 +0200 Subject: [PATCH 250/496] Fix #8186: AVCodec split version defines in two files... --- CMakeLists.txt | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b1ad102b41ee..cd3c749f8e4a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -861,18 +861,23 @@ if (WITH_DSP_FFMPEG) # Deactivate FFmpeg backend for sound, if the version is too old. # See libfreerdp/codec/dsp_ffmpeg.h file(STRINGS "${AVCODEC_INCLUDE_DIR}/libavcodec/version.h" AV_VERSION_FILE REGEX "LIBAVCODEC_VERSION_M[A-Z]+[\t ]*[0-9]+") + if (EXISTS "${AVCODEC_INCLUDE_DIR}/libavcodec/version_major.h") + file(STRINGS "${AVCODEC_INCLUDE_DIR}/libavcodec/version_major.h" AV_VERSION_FILE2 REGEX "LIBAVCODEC_VERSION_M[A-Z]+[\t ]*[0-9]+") + list(APPEND AV_VERSION_FILE ${AV_VERSION_FILE2}) + endif() + FOREACH(item ${AV_VERSION_FILE}) STRING(REGEX MATCH "LIBAVCODEC_VERSION_M[A-Z]+[\t ]*[0-9]+" litem ${item}) - IF(litem) - string(REGEX REPLACE "[ \t]+" ";" VSPLIT_LINE ${litem}) - list(LENGTH VSPLIT_LINE VSPLIT_LINE_LEN) - if (NOT "${VSPLIT_LINE_LEN}" EQUAL "2") - message(ERROR "invalid entry in libavcodec version header ${item}") - endif(NOT "${VSPLIT_LINE_LEN}" EQUAL "2") - list(GET VSPLIT_LINE 0 VNAME) - list(GET VSPLIT_LINE 1 VVALUE) - set(${VNAME} ${VVALUE}) - ENDIF(litem) + IF(litem) + string(REGEX REPLACE "[ \t]+" ";" VSPLIT_LINE ${litem}) + list(LENGTH VSPLIT_LINE VSPLIT_LINE_LEN) + if (NOT "${VSPLIT_LINE_LEN}" EQUAL "2") + message(ERROR "invalid entry in libavcodec version header ${item}") + endif(NOT "${VSPLIT_LINE_LEN}" EQUAL "2") + list(GET VSPLIT_LINE 0 VNAME) + list(GET VSPLIT_LINE 1 VVALUE) + set(${VNAME} ${VVALUE}) + ENDIF(litem) ENDFOREACH(item ${AV_VERSION_FILE}) set(AVCODEC_VERSION "${LIBAVCODEC_VERSION_MAJOR}.${LIBAVCODEC_VERSION_MINOR}.${LIBAVCODEC_VERSION_MICRO}") From 246ac55d9c5791edbe6d52fe37d395d4f9fdd1fc Mon Sep 17 00:00:00 2001 From: Pascal Nowack Date: Wed, 14 Sep 2022 05:08:11 +0200 Subject: [PATCH 251/496] Update changelog --- ChangeLog | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/ChangeLog b/ChangeLog index c2e7a3f741d2..4264e66ad174 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,9 @@ +# 20xx-xx-xx Version 2.x.x + +Fixed issues: + +* Backported #8190: Fix build break with newer FFMPEG versions + # 2022-07-28 Version 2.8.0 Noteworthy changes: From 388abfa24e815d4a1afaae569fa84e62ddf91a15 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Wed, 21 Sep 2022 15:28:42 +0200 Subject: [PATCH 252/496] Updated flatpak manifest * Use current dependencies * Bundle OpenSSL 1.1.1 for windows XP/vista/xp compatibility * Build currently checked out FreeRDP instead of origin/master (cherry picked from commit 541e8f88f6b79e0a47b4faf8b9b5cf3f8a296757) --- packaging/flatpak/com.freerdp.FreeRDP.json | 140 ++++++++++++++------- 1 file changed, 95 insertions(+), 45 deletions(-) diff --git a/packaging/flatpak/com.freerdp.FreeRDP.json b/packaging/flatpak/com.freerdp.FreeRDP.json index 815b914aadd5..6004b7ba11b4 100644 --- a/packaging/flatpak/com.freerdp.FreeRDP.json +++ b/packaging/flatpak/com.freerdp.FreeRDP.json @@ -1,29 +1,45 @@ { "app-id": "com.freerdp.FreeRDP", "runtime": "org.freedesktop.Platform", - "runtime-version": "19.08", + "runtime-version": "22.08", "sdk": "org.freedesktop.Sdk", "build-options" : { - "cflags": "-O2 -g", - "cxxflags": "-O2 -g" + "cflags": "-O3", + "cxxflags": "-O3" }, "command": "freerdp.sh", "cleanup": [ + "*.la", + "/include", + "/lib/cmake", + "/lib/pkgconfig" ], "finish-args": [ /* X11 + XShm access */ "--share=ipc", "--socket=x11", - "--socket=fallback-x11", /* Needs to talk to the network */ "--share=network", /* Play sounds redirected from guests */ "--socket=pulseaudio", + "--socket=cups", /* Wayland access */ "--socket=wayland", /* Allow rw access to download folder */ "--filesystem=xdg-download" ], + "add-build-extensions": { + "org.freedesktop.Platform.ffmpeg-full": { + "directory": "lib/ffmpeg", + "version": "22.08", + "add-ld-path": "." + }, + "org.freedesktop.Platform.openh264": { + "directory": "lib/openh264", + "version": "2.3.0", + "add-ld-path": "." + } + }, "modules": [ { /** @@ -33,10 +49,14 @@ "sources": [ { "type": "archive", - "url": "https://xorg.freedesktop.org/releases/individual/app/xprop-1.2.3.tar.bz2", - "sha256": "d22afb28c86d85fff10a50156a7d0fa930c80ae865d70b26d805fd28a17a521b" + "url": "https://xorg.freedesktop.org/releases/individual/app/xprop-1.2.5.tar.bz2", + "sha256": "9b92ed0316bf2486121d8bac88bd1878f16b43bd335f18009b1f941f1eca93a1" } - ] + ], + "cleanup": [ + "/share/doc", + "/share/man" + ] }, { "name": "libusb", @@ -45,10 +65,13 @@ { "type": "git", "url": "https://github.com/libusb/libusb.git", - "tag": "v1.0.22", - "commit": "0034b2afdcdb1614e78edaa2a9e22d5936aeae5d" + "tag": "v1.0.26" } - ] + ], + "cleanup": [ + "/share/doc", + "/share/man" + ] }, { "name": "pcsc", @@ -63,16 +86,73 @@ { "type": "git", "url": "https://github.com/LudovicRousseau/PCSC.git", - "tag": "pcsc-1.8.24", - "commit": "73d95ada3221c060cbd7b6aa2375453f9d0e359b" + "tag": "1.9.9" } + ], + "cleanup": [ + "/share/doc", + "/share/man" + ] + }, + { + "name": "openssl111", + "buildsystem": "simple", + "build-commands": [ + "./config --prefix=/app", + "make -j $FLATPAK_BUILDER_N_JOBS", + "make install" + ], + "cleanup": [ + "/share/doc", + "/share/man", + "/bin" + ], + "sources": [ + { + "type": "archive", + "url": "https://www.openssl.org/source/openssl-1.1.1q.tar.gz", + "sha256": "d7939ce614029cdff0b6c20f0e2e5703158a489a72b2507b8bd51bf8c8fd10ca" + } + ] + }, + { + "name": "freerdp", + "buildsystem": "cmake-ninja", + "cleanup": [ + ], + "config-opts": [ + "-DCMAKE_VERBOSE_MAKEFILE=ON", + "-DCMAKE_BUILD_TYPE:STRING=Release", + "-DCMAKE_INSTALL_LIBDIR:PATH=lib", + "-DCHANNEL_TSMF:BOOL=OFF", + "-DCHANNEL_URBDRC:BOOL=ON", + "-DBUILD_TESTING:BOOL=OFF", + "-DWITH_MANPAGES:BOOL=OFF", + "-DWITH_GSSAPI:BOOL=OFF", + "-DWITH_PCSC:BOOL=ON", + "-DWITH_SWSCALE:BOOL=ON", + "-DWITH_SERVER:BOOL=ON", + "-DWITH_SAMPLE:BOOL=ON", + "-DWITH_CUPS:BOOL=ON", + "-DWITH_FFMPEG:BOOL=ON", + "-DWITH_DSP_FFMPEG:BOOL=ON", + "-DWITH_OSS:BOOL=OFF", + "-DWITH_PULSE:BOOL=ON" + ], + "sources": [ + { + "type": "dir", + "path": "../.." + } ] }, - { + { "name": "wrapper", "buildsystem": "simple", "build-commands": [ - "install -D freerdp.sh /app/bin/freerdp.sh" + "install -D freerdp.sh /app/bin/freerdp.sh", + "mkdir -p /app/lib/ffmpeg", + "mkdir -p /app/lib/openh264" ], "sources": [ { @@ -80,36 +160,6 @@ "path": "freerdp.sh" } ] - }, - { - "name": "freerdp", - "buildsystem": "cmake-ninja", - "cleanup": [ - ], - "config-opts": [ - "-DCMAKE_BUILD_TYPE:STRING=Release", - "-DCMAKE_INSTALL_LIBDIR:PATH=lib", - "-DCHANNEL_TSMF:BOOL=ON", - "-DCHANNEL_URBDRC:BOOL=ON", - "-DBUILD_TESTING:BOOL=OFF", - "-DWITH_MANPAGES:BOOL=OFF", - "-DWITH_GSSAPI:BOOL=OFF", - "-DWITH_PCSC:BOOL=ON", - "-DWITH_SERVER:BOOL=ON", - "-DWITH_SAMPLE:BOOL=ON", - "-DWITH_CUPS:BOOL=ON", - "-DWITH_FFMPEG:BOOL=ON", - "-DWITH_DSP_FFMPEG:BOOL=ON", - "-DWITH_OSS:BOOL=OFF", - "-DWITH_PULSE:BOOL=ON" - ], - "sources": [ - { - "type": "git", - "url": "https://github.com/FreeRDP/FreeRDP.git", - "branch": "master" - } - ] - } + } ] } From 82f292a1c7d94df1e5740eba79a8093665503197 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Wed, 21 Sep 2022 15:29:50 +0200 Subject: [PATCH 253/496] Add flatpak bundle build script * Builds the flatpak manifest (uses a temporary directory for intermediate files) * Bundles the flatpak and writes it to the current directory (cherry picked from commit 4a5d0df9540aa8fcd058b136b752618f5be5daec) --- packaging/flatpak/build-bundle.sh | 32 +++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100755 packaging/flatpak/build-bundle.sh diff --git a/packaging/flatpak/build-bundle.sh b/packaging/flatpak/build-bundle.sh new file mode 100755 index 000000000000..3afb9c33d7bf --- /dev/null +++ b/packaging/flatpak/build-bundle.sh @@ -0,0 +1,32 @@ +#!/bin/bash -xe +SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd ) + +MANIFEST=com.freerdp.FreeRDP + +BUILD_BASE=$(mktemp -d) +if [ $# -gt 0 ]; +then + BUILD_BASE=$1 +fi + +echo "Using $BUILD_BASE as temporary build directory" +REPO=$BUILD_BASE/repo +BUILD=$BUILD_BASE/build +STATE=$BUILD_BASE/state + +BUILDER=$(which flatpak-builder) +if [ ! -x "$BUILDER" ]; +then + echo "command 'flatpak-builder' could not be found, please install and add to PATH" + exit 1 +fi + +FLATPAK=$(which flatpak) +if [ ! -x "$FLATPAK" ]; +then + echo "command 'flatpak' could not be found, please install and add to PATH" + exit 1 +fi + +flatpak-builder -v --repo=$REPO --state-dir=$STATE $BUILD $SCRIPT_DIR/$MANIFEST.json --force-clean +flatpak build-bundle -v $REPO $MANIFEST.flatpak $MANIFEST --runtime-repo=https://flathub.org/repo/flathub.flatpakrepo From 9584e53133498b84a7577643fba94e8325e296da Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Thu, 22 Sep 2022 09:18:49 +0200 Subject: [PATCH 254/496] Install required flathub remote and sdk automatically (cherry picked from commit f013ebc49ab06d704ef6033eb3610519955c9123) --- packaging/flatpak/build-bundle.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packaging/flatpak/build-bundle.sh b/packaging/flatpak/build-bundle.sh index 3afb9c33d7bf..ed4b5a8aa45e 100755 --- a/packaging/flatpak/build-bundle.sh +++ b/packaging/flatpak/build-bundle.sh @@ -28,5 +28,6 @@ then exit 1 fi -flatpak-builder -v --repo=$REPO --state-dir=$STATE $BUILD $SCRIPT_DIR/$MANIFEST.json --force-clean +flatpak remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo --user +flatpak-builder -v --repo=$REPO --state-dir=$STATE $BUILD $SCRIPT_DIR/$MANIFEST.json --force-clean --user --install-deps-from=flathub flatpak build-bundle -v $REPO $MANIFEST.flatpak $MANIFEST --runtime-repo=https://flathub.org/repo/flathub.flatpakrepo From ee79164b86a8613fc7a9c326e27fd941f7a6c7dd Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Thu, 22 Sep 2022 09:38:10 +0200 Subject: [PATCH 255/496] Enable PKCS11 (cherry picked from commit f1569c5a7f67ebcd32f486b212b825d0b45d9c15) --- packaging/flatpak/com.freerdp.FreeRDP.json | 1 + 1 file changed, 1 insertion(+) diff --git a/packaging/flatpak/com.freerdp.FreeRDP.json b/packaging/flatpak/com.freerdp.FreeRDP.json index 6004b7ba11b4..38c5f17e0cb8 100644 --- a/packaging/flatpak/com.freerdp.FreeRDP.json +++ b/packaging/flatpak/com.freerdp.FreeRDP.json @@ -130,6 +130,7 @@ "-DWITH_MANPAGES:BOOL=OFF", "-DWITH_GSSAPI:BOOL=OFF", "-DWITH_PCSC:BOOL=ON", + "-DWITH_PKCS11:BOOL=ON", "-DWITH_SWSCALE:BOOL=ON", "-DWITH_SERVER:BOOL=ON", "-DWITH_SAMPLE:BOOL=ON", From 63dfaa4e5ed7c96e41e68303dd5e65ac6cbcfdde Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Thu, 15 Sep 2022 12:03:07 +0200 Subject: [PATCH 256/496] Disable execinfo support if only header detected Some implementations (e.g. Android with API < 33) provide the execinfo.h header file, but do not define the backtrace functions expected. Disable the support for execinfo backtrace in such a case (cherry picked from commit 09275bf4c7fe2c4d522f02285bf97cadd7a683c8) --- CMakeLists.txt | 13 ++++++++++++- winpr/CMakeLists.txt | 13 ++++++++++++- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index cd3c749f8e4a..d876914b2e5d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -532,7 +532,6 @@ add_definitions(-DWINPR_EXPORTS -DFREERDP_EXPORTS) if(NOT IOS) check_include_files(fcntl.h HAVE_FCNTL_H) check_include_files(unistd.h HAVE_UNISTD_H) - check_include_files(execinfo.h HAVE_EXECINFO_H) check_include_files(inttypes.h HAVE_INTTYPES_H) check_include_files(sys/modem.h HAVE_SYS_MODEM_H) check_include_files(sys/filio.h HAVE_SYS_FILIO_H) @@ -540,6 +539,18 @@ if(NOT IOS) check_include_files(sys/strtio.h HAVE_SYS_STRTIO_H) check_include_files(sys/select.h HAVE_SYS_SELECT_H) check_include_files(syslog.h HAVE_SYSLOG_H) + check_include_files(execinfo.h HAVE_EXECINFO_HEADER) + if (HAVE_EXECINFO_HEADER) + check_symbol_exists(backtrace execinfo.h HAVE_EXECINFO_BACKTRACE) + check_symbol_exists(backtrace_symbols execinfo.h HAVE_EXECINFO_BACKTRACE_SYMBOLS) + check_symbol_exists(backtrace_symbols_fd execinfo.h HAVE_EXECINFO_BACKTRACE_SYMBOLS_FD) + + # Some implementations (e.g. Android NDK API < 33) provide execinfo.h but do not define + # the backtrace functions. Disable detection for these cases + if (HAVE_EXECINFO_BACKTRACE AND HAVE_EXECINFO_BACKTRACE_SYMBOLS AND HAVE_EXECINFO_BACKTRACE_SYMBOLS_FD) + set(HAVE_EXECINFO_H ON) + endif() + endif() else() set(HAVE_FCNTL_H 1) set(HAVE_UNISTD_H 1) diff --git a/winpr/CMakeLists.txt b/winpr/CMakeLists.txt index cf500edfe816..050068e15c5b 100644 --- a/winpr/CMakeLists.txt +++ b/winpr/CMakeLists.txt @@ -86,6 +86,18 @@ if(NOT IOS) check_include_files(stdbool.h WINPR_HAVE_STDBOOL_H) check_include_files(stdint.h WINPR_HAVE_STDINT_H) check_include_files(inttypes.h WINPR_HAVE_INTTYPES_H) + check_include_files(execinfo.h HAVE_EXECINFO_HEADER) + if (HAVE_EXECINFO_HEADER) + check_symbol_exists(backtrace execinfo.h HAVE_EXECINFO_BACKTRACE) + check_symbol_exists(backtrace_symbols execinfo.h HAVE_EXECINFO_BACKTRACE_SYMBOLS) + check_symbol_exists(backtrace_symbols_fd execinfo.h HAVE_EXECINFO_BACKTRACE_SYMBOLS_FD) + + # Some implementations (e.g. Android NDK API < 33) provide execinfo.h but do not define + # the backtrace functions. Disable detection for these cases + if (HAVE_EXECINFO_BACKTRACE AND HAVE_EXECINFO_BACKTRACE_SYMBOLS AND HAVE_EXECINFO_BACKTRACE_SYMBOLS_FD) + set(HAVE_EXECINFO_H ON) + endif() + endif() else(NOT IOS) set(WINPR_HAVE_STDBOOL_H 1) set(WINPR_HAVE_STDINT_H 1) @@ -107,7 +119,6 @@ else() if(NOT IOS) check_include_files(fcntl.h HAVE_FCNTL_H) check_include_files(unistd.h HAVE_UNISTD_H) - check_include_files(execinfo.h HAVE_EXECINFO_H) check_include_files(inttypes.h HAVE_INTTYPES_H) check_include_files(sys/modem.h HAVE_SYS_MODEM_H) check_include_files(sys/filio.h HAVE_SYS_FILIO_H) From 5418392be610644bedcd2d291eb177b87739d095 Mon Sep 17 00:00:00 2001 From: Mike Gabriel Date: Tue, 8 Mar 2022 08:37:46 +0100 Subject: [PATCH 257/496] winpr/{libwinpr/thread/thread.c,include/winpr/thread.h}: Keep DumpThreadHandles as a symbol even if WITH_DEBUG_THREADS is OFF. (cherry picked from commit 8ab9809e8bb534930189b0d74fc8688048d57999) --- winpr/include/winpr/thread.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/winpr/include/winpr/thread.h b/winpr/include/winpr/thread.h index c7961e90da9e..1771526491d0 100644 --- a/winpr/include/winpr/thread.h +++ b/winpr/include/winpr/thread.h @@ -248,10 +248,7 @@ extern "C" /* CommandLineToArgvA is not present in the original Windows API, WinPR always exports it */ WINPR_API LPSTR* CommandLineToArgvA(LPCSTR lpCmdLine, int* pNumArgs); - -#if defined(WITH_DEBUG_THREADS) WINPR_API VOID DumpThreadHandles(void); -#endif #ifdef __cplusplus } From 09315478edf6139dd71daf4bae1fd30f68ecdcbc Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Wed, 21 Sep 2022 16:51:40 +0200 Subject: [PATCH 258/496] Updated changelog --- ChangeLog | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ChangeLog b/ChangeLog index 4264e66ad174..f835a1b074a0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -3,6 +3,9 @@ Fixed issues: * Backported #8190: Fix build break with newer FFMPEG versions +* Backported #8234: Updated flatpak with build script +* Backported #8210: Better execinfo support check for android +* Backported #7708: Header now defines DumpThreadHandles # 2022-07-28 Version 2.8.0 From 60aac2abf0740dd36b62712fba91498fd6e055fe Mon Sep 17 00:00:00 2001 From: akallabeth Date: Thu, 6 Oct 2022 09:12:40 +0200 Subject: [PATCH 259/496] Fix length checks in parallel driver The length requested was not checked against the length read from the port. (cherry picked from commit 094cc5a4596c299595b732effd59ee149181fd61) --- channels/parallel/client/parallel_main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/channels/parallel/client/parallel_main.c b/channels/parallel/client/parallel_main.c index af3e82703a60..993605a65e23 100644 --- a/channels/parallel/client/parallel_main.c +++ b/channels/parallel/client/parallel_main.c @@ -159,7 +159,7 @@ static UINT parallel_process_irp_read(PARALLEL_DEVICE* parallel, IRP* irp) return ERROR_INVALID_DATA; Stream_Read_UINT32(irp->input, Length); Stream_Read_UINT64(irp->input, Offset); - buffer = (BYTE*)malloc(Length); + buffer = (BYTE*)calloc(Length, sizeof(BYTE)); if (!buffer) { @@ -178,6 +178,7 @@ static UINT parallel_process_irp_read(PARALLEL_DEVICE* parallel, IRP* irp) } else { + Length = status; } Stream_Write_UINT32(irp->output, Length); From be793c3bb776c1bbda9156b427408d5a5eb00f70 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Thu, 6 Oct 2022 09:15:40 +0200 Subject: [PATCH 260/496] Fixed missing length check in video channel Data received in video redirection channel was not checked for proper length. (cherry picked from commit eeffd1050e9284d1464b58e049b2b4d88726632b) --- channels/video/client/video_main.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/channels/video/client/video_main.c b/channels/video/client/video_main.c index a21e7cdf2b86..a8031fc86852 100644 --- a/channels/video/client/video_main.c +++ b/channels/video/client/video_main.c @@ -930,6 +930,8 @@ static UINT video_data_on_data_received(IWTSVirtualChannelCallback* pChannelCall Stream_Read_UINT16(s, data.PacketsInSample); Stream_Read_UINT32(s, data.SampleNumber); Stream_Read_UINT32(s, data.cbSample); + if (!Stream_CheckAndLogRequiredLength(TAG, s, data.cbSample)) + return ERROR_INVALID_DATA; data.pSample = Stream_Pointer(s); /* From b263ce67a37368de69cec73a81220d343616201f Mon Sep 17 00:00:00 2001 From: akallabeth Date: Thu, 6 Oct 2022 09:49:38 +0200 Subject: [PATCH 261/496] Fixed tsmf ffmpeg context extra data size checks tsmf_ffmpeg_init_stream did not abort if the video format ExtraDataSize was not sufficiently large to satisfy expectations. (cherry picked from commit 5beef2c5e66f8d71afb3243acea0fbc143d9b84b) --- channels/tsmf/client/ffmpeg/tsmf_ffmpeg.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/channels/tsmf/client/ffmpeg/tsmf_ffmpeg.c b/channels/tsmf/client/ffmpeg/tsmf_ffmpeg.c index cf0aa9ba172a..5aff235b5726 100644 --- a/channels/tsmf/client/ffmpeg/tsmf_ffmpeg.c +++ b/channels/tsmf/client/ffmpeg/tsmf_ffmpeg.c @@ -195,9 +195,12 @@ static BOOL tsmf_ffmpeg_init_stream(ITSMFDecoder* decoder, const TS_AM_MEDIA_TYP if (media_type->SubType == TSMF_SUB_TYPE_AVC1 && media_type->FormatType == TSMF_FORMAT_TYPE_MPEG2VIDEOINFO) { + size_t required = 6; /* The extradata format that FFmpeg uses is following CodecPrivate in Matroska. See http://haali.su/mkv/codecs.pdf */ p = mdecoder->codec_context->extradata; + if (mdecoder->codec_context->extradata_size < required) + return FALSE; *p++ = 1; /* Reserved? */ *p++ = media_type->ExtraData[8]; /* Profile */ *p++ = 0; /* Profile */ @@ -206,17 +209,28 @@ static BOOL tsmf_ffmpeg_init_stream(ITSMFDecoder* decoder, const TS_AM_MEDIA_TYP *p++ = 0xe0 | 0x01; /* Reserved | #sps */ s = media_type->ExtraData + 20; size = ((UINT32)(*s)) * 256 + ((UINT32)(*(s + 1))); + required += size + 2; + if (mdecoder->codec_context->extradata_size < required) + return FALSE; memcpy(p, s, size + 2); s += size + 2; p += size + 2; + required++; + if (mdecoder->codec_context->extradata_size < required) + return FALSE; *p++ = 1; /* #pps */ size = ((UINT32)(*s)) * 256 + ((UINT32)(*(s + 1))); + required += size + 2; + if (mdecoder->codec_context->extradata_size < required) + return FALSE; memcpy(p, s, size + 2); } else { memcpy(mdecoder->codec_context->extradata, media_type->ExtraData, media_type->ExtraDataSize); + if (mdecoder->codec_context->extradata_size < media_type->ExtraDataSize + 8) + return FALSE; memset(mdecoder->codec_context->extradata + media_type->ExtraDataSize, 0, 8); } } From 779a35bf62611661175be4ef6e04fca74fc79bbe Mon Sep 17 00:00:00 2001 From: akallabeth Date: Thu, 6 Oct 2022 09:54:00 +0200 Subject: [PATCH 262/496] Fixed missing input data length check tsmf_ifman_exchange_capability_request did not check if the input data stream actually contained the amount of bytes requested to copy. (cherry picked from commit 4182bfbf382ca92752595f3036744d50a3ea02fd) --- channels/tsmf/client/tsmf_ifman.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/channels/tsmf/client/tsmf_ifman.c b/channels/tsmf/client/tsmf_ifman.c index a71a03fda8a2..cfee41c8bda9 100644 --- a/channels/tsmf/client/tsmf_ifman.c +++ b/channels/tsmf/client/tsmf_ifman.c @@ -69,16 +69,20 @@ UINT tsmf_ifman_rim_exchange_capability_request(TSMF_IFMAN* ifman) */ UINT tsmf_ifman_exchange_capability_request(TSMF_IFMAN* ifman) { - UINT32 i; - UINT32 v; - UINT32 pos; - UINT32 CapabilityType; - UINT32 cbCapabilityLength; - UINT32 numHostCapabilities; - + UINT32 i = 0; + UINT32 v = 0; + UINT32 pos = 0; + UINT32 CapabilityType = 0; + UINT32 cbCapabilityLength = 0; + UINT32 numHostCapabilities = 0; + + WINPR_ASSERT(ifman); if (!Stream_EnsureRemainingCapacity(ifman->output, ifman->input_size + 4)) return ERROR_OUTOFMEMORY; + if (Stream_GetRemainingLength(ifman->input) < ifman->input_size) + return ERROR_INVALID_DATA; + pos = Stream_GetPosition(ifman->output); Stream_Copy(ifman->input, ifman->output, ifman->input_size); Stream_SetPosition(ifman->output, pos); From 6f660e73aa5b05bd8250b9b9a62781c13f8ff8c5 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Thu, 6 Oct 2022 09:56:17 +0200 Subject: [PATCH 263/496] Fixed TSMF tsmf_ffmpeg_set_format length checks ExtraDataSize of format was not checked for expected minimum length (cherry picked from commit b7c0b43a37bc15f9bead4467a45a48368f3aae41) --- channels/tsmf/client/ffmpeg/tsmf_ffmpeg.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/channels/tsmf/client/ffmpeg/tsmf_ffmpeg.c b/channels/tsmf/client/ffmpeg/tsmf_ffmpeg.c index 5aff235b5726..c14877b43ac1 100644 --- a/channels/tsmf/client/ffmpeg/tsmf_ffmpeg.c +++ b/channels/tsmf/client/ffmpeg/tsmf_ffmpeg.c @@ -259,6 +259,9 @@ static BOOL tsmf_ffmpeg_set_format(ITSMFDecoder* decoder, TS_AM_MEDIA_TYPE* medi { TSMFFFmpegDecoder* mdecoder = (TSMFFFmpegDecoder*)decoder; + WINPR_ASSERT(mdecoder); + WINPR_ASSERT(media_type); + switch (media_type->MajorType) { case TSMF_MAJOR_TYPE_VIDEO: @@ -311,6 +314,9 @@ static BOOL tsmf_ffmpeg_set_format(ITSMFDecoder* decoder, TS_AM_MEDIA_TYPE* medi http://msdn.microsoft.com/en-us/library/dd757806.aspx */ if (media_type->ExtraData) { + if (media_type->ExtraDataSize < 12) + return FALSE; + media_type->ExtraData += 12; media_type->ExtraDataSize -= 12; } From 55db5824348366c028aa98e9118486a94d1add34 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Thu, 6 Oct 2022 10:00:40 +0200 Subject: [PATCH 264/496] Fixed TSMF tsmf_read_format_type length checks ExtraDataSize of format was not checked for expected minimum length (cherry picked from commit dc88cfc7257d741c6b0d007f569e851b81a8ff0b) --- channels/tsmf/client/tsmf_codec.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/channels/tsmf/client/tsmf_codec.c b/channels/tsmf/client/tsmf_codec.c index 66723962d0fd..a212affea3ba 100644 --- a/channels/tsmf/client/tsmf_codec.c +++ b/channels/tsmf/client/tsmf_codec.c @@ -386,7 +386,12 @@ static BOOL tsmf_read_format_type(TS_AM_MEDIA_TYPE* mediatype, wStream* s, UINT3 if (cbFormat > 176) { - mediatype->ExtraDataSize = cbFormat - 176; + const size_t nsize = cbFormat - 176; + if (mediatype->ExtraDataSize < nsize) + return FALSE; + if (!Stream_CheckAndLogRequiredLength(TAG, s, nsize)) + return FALSE; + mediatype->ExtraDataSize = nsize; mediatype->ExtraData = Stream_Pointer(s); } break; From 5a6271cf5c19443198555ee6b5575b162c30242a Mon Sep 17 00:00:00 2001 From: akallabeth Date: Thu, 6 Oct 2022 10:28:41 +0200 Subject: [PATCH 265/496] Fixed TSMF tsmf_gstreamer_set_format length checks ExtraDataSize of format was not checked for expected minimum length (cherry picked from commit 136d92bb466aa2420e8eea20420cb50da7334548) --- channels/tsmf/client/gstreamer/tsmf_gstreamer.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/channels/tsmf/client/gstreamer/tsmf_gstreamer.c b/channels/tsmf/client/gstreamer/tsmf_gstreamer.c index 61ea6a82c58c..51cbc869f0c2 100644 --- a/channels/tsmf/client/gstreamer/tsmf_gstreamer.c +++ b/channels/tsmf/client/gstreamer/tsmf_gstreamer.c @@ -420,6 +420,8 @@ static BOOL tsmf_gstreamer_set_format(ITSMFDecoder* decoder, TS_AM_MEDIA_TYPE* m http://msdn.microsoft.com/en-us/library/dd757806.aspx */ if (media_type->ExtraData) { + if (media_type->ExtraDataSize < 12) + return FALSE; media_type->ExtraData += 12; media_type->ExtraDataSize -= 12; } From 114fdfc4b9f24f3307f007aa15c93d0800a40d84 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Mon, 12 Sep 2022 11:55:26 +0200 Subject: [PATCH 266/496] Fix #8176: Check fullscreen state and not setting Timer based dynamic resolution updates are disabled in fullscreen state. Check current value and not (permanent) setting (cherry picked from commit a47dcd37052c38865afbaa1d0c1cf02f8730a60b) --- client/X11/xf_disp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/X11/xf_disp.c b/client/X11/xf_disp.c index 316e1829b5be..20eee75aebbf 100644 --- a/client/X11/xf_disp.c +++ b/client/X11/xf_disp.c @@ -93,7 +93,7 @@ static BOOL xf_update_last_sent(xfDispContext* xfDisp) static BOOL xf_disp_sendResize(xfDispContext* xfDisp) { - DISPLAY_CONTROL_MONITOR_LAYOUT layout; + DISPLAY_CONTROL_MONITOR_LAYOUT layout = { 0 }; xfContext* xfc; rdpSettings* settings; @@ -242,7 +242,7 @@ static void xf_disp_OnTimer(void* context, TimerEventArgs* e) if (!xf_disp_check_context(context, &xfc, &xfDisp, &settings)) return; - if (!xfDisp->activated || settings->Fullscreen) + if (!xfDisp->activated || xfc->fullscreen) return; xf_disp_sendResize(xfDisp); From f1807e6a1c4ae209de9fd56f0451884f88afbdca Mon Sep 17 00:00:00 2001 From: James Fu Date: Wed, 21 Sep 2022 18:01:58 +0800 Subject: [PATCH 267/496] Send resize on window state change (cherry picked from commit abbd1cd3802d3d7b7193f8b21fafe1950947bdf1) --- client/X11/xf_disp.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/client/X11/xf_disp.c b/client/X11/xf_disp.c index 20eee75aebbf..32ddb626c3aa 100644 --- a/client/X11/xf_disp.c +++ b/client/X11/xf_disp.c @@ -248,6 +248,23 @@ static void xf_disp_OnTimer(void* context, TimerEventArgs* e) xf_disp_sendResize(xfDisp); } +static void xf_disp_OnWindowStateChange(void* context, const WindowStateChangeEventArgs* e) +{ + xfContext* xfc; + xfDispContext* xfDisp; + rdpSettings* settings; + + WINPR_UNUSED(e); + + if (!xf_disp_check_context(context, &xfc, &xfDisp, &settings)) + return; + + if (!xfDisp->activated || !xfc->fullscreen) + return; + + xf_disp_sendResize(xfDisp); +} + xfDispContext* xf_disp_new(xfContext* xfc) { xfDispContext* ret; @@ -274,6 +291,7 @@ xfDispContext* xf_disp_new(xfContext* xfc) PubSub_SubscribeActivated(xfc->context.pubSub, xf_disp_OnActivated); PubSub_SubscribeGraphicsReset(xfc->context.pubSub, xf_disp_OnGraphicsReset); PubSub_SubscribeTimer(xfc->context.pubSub, xf_disp_OnTimer); + PubSub_SubscribeWindowStateChange(xfc->context.pubSub, xf_disp_OnWindowStateChange); return ret; } @@ -287,6 +305,7 @@ void xf_disp_free(xfDispContext* disp) PubSub_UnsubscribeActivated(disp->xfc->context.pubSub, xf_disp_OnActivated); PubSub_UnsubscribeGraphicsReset(disp->xfc->context.pubSub, xf_disp_OnGraphicsReset); PubSub_UnsubscribeTimer(disp->xfc->context.pubSub, xf_disp_OnTimer); + PubSub_UnsubscribeWindowStateChange(disp->xfc->context.pubSub, xf_disp_OnWindowStateChange); } free(disp); From 74a54407e972af7f508836f167332d0c9ab1be8f Mon Sep 17 00:00:00 2001 From: akallabeth Date: Fri, 7 Oct 2022 09:59:41 +0200 Subject: [PATCH 268/496] changelog --- ChangeLog | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ChangeLog b/ChangeLog index f835a1b074a0..49f4da3b077e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -6,6 +6,8 @@ Fixed issues: * Backported #8234: Updated flatpak with build script * Backported #8210: Better execinfo support check for android * Backported #7708: Header now defines DumpThreadHandles +* Backported #8176: Check fullscreen state and not setting +* Backported #8236: Send resize on window state change # 2022-07-28 Version 2.8.0 From 2d4b0858d94d288c1b99364ffea4cd99851f6143 Mon Sep 17 00:00:00 2001 From: Felix Deimel Date: Mon, 31 Jan 2022 15:16:38 +0100 Subject: [PATCH 269/496] Fixes https://github.com/FreeRDP/FreeRDP/issues/7408 (cherry picked from commit a8e80695030dd04aaba64032f04c977506010b19) --- channels/audin/client/mac/audin_mac.m | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/channels/audin/client/mac/audin_mac.m b/channels/audin/client/mac/audin_mac.m index 56b7ea96aee2..b81e551d53c6 100644 --- a/channels/audin/client/mac/audin_mac.m +++ b/channels/audin/client/mac/audin_mac.m @@ -154,12 +154,16 @@ static UINT audin_mac_set_format(IAudinDevice *device, const AUDIO_FORMAT *forma if (format->wBitsPerSample == 0) mac->audioFormat.mBitsPerChannel = 16; - mac->audioFormat.mBytesPerFrame = 0; - mac->audioFormat.mBytesPerPacket = 0; mac->audioFormat.mChannelsPerFrame = mac->format.nChannels; + mac->audioFormat.mFramesPerPacket = 1; + + mac->audioFormat.mBytesPerFrame = + mac->audioFormat.mChannelsPerFrame * (mac->audioFormat.mBitsPerChannel / 8); + mac->audioFormat.mBytesPerPacket = + mac->audioFormat.mBytesPerFrame * mac->audioFormat.mFramesPerPacket; + mac->audioFormat.mFormatFlags = audin_mac_get_flags_for_format(format); mac->audioFormat.mFormatID = audin_mac_get_format(format); - mac->audioFormat.mFramesPerPacket = 1; mac->audioFormat.mReserved = 0; mac->audioFormat.mSampleRate = mac->format.nSamplesPerSec; return CHANNEL_RC_OK; From b2447efd447011ffe68ad3d1837631d449fb958f Mon Sep 17 00:00:00 2001 From: akallabeth Date: Fri, 7 Oct 2022 11:35:34 +0200 Subject: [PATCH 270/496] Changelog --- ChangeLog | 1 + 1 file changed, 1 insertion(+) diff --git a/ChangeLog b/ChangeLog index 49f4da3b077e..1388ba434abb 100644 --- a/ChangeLog +++ b/ChangeLog @@ -8,6 +8,7 @@ Fixed issues: * Backported #7708: Header now defines DumpThreadHandles * Backported #8176: Check fullscreen state and not setting * Backported #8236: Send resize on window state change +* Backported #7611: Audin macOS monterey fix # 2022-07-28 Version 2.8.0 From acd44ef2921d143c7c5d95c1752a5b11a3eca034 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Tue, 5 Jul 2022 12:58:31 +0200 Subject: [PATCH 271/496] Removed ALAW/ULAW from supported backend formats pulse/alsa/oss do not reliably work with ALAW/ULAW codecs with all hardware available. Since these formats are poor quality anyway, deactivate them for audin channel. (cherry picked from commit c3e8720c87bed96ba91d29fb22fe0e0e0f09db2f) --- channels/audin/client/alsa/audin_alsa.c | 4 ---- channels/audin/client/oss/audin_oss.c | 4 ---- channels/audin/client/pulse/audin_pulse.c | 11 ----------- 3 files changed, 19 deletions(-) diff --git a/channels/audin/client/alsa/audin_alsa.c b/channels/audin/client/alsa/audin_alsa.c index 60e9fd8d4f34..53d4e9bc03c2 100644 --- a/channels/audin/client/alsa/audin_alsa.c +++ b/channels/audin/client/alsa/audin_alsa.c @@ -242,10 +242,6 @@ static BOOL audin_alsa_format_supported(IAudinDevice* device, const AUDIO_FORMAT break; - case WAVE_FORMAT_ALAW: - case WAVE_FORMAT_MULAW: - return TRUE; - default: return FALSE; } diff --git a/channels/audin/client/oss/audin_oss.c b/channels/audin/client/oss/audin_oss.c index 97eb3496ed83..305686c75c04 100644 --- a/channels/audin/client/oss/audin_oss.c +++ b/channels/audin/client/oss/audin_oss.c @@ -113,10 +113,6 @@ static BOOL audin_oss_format_supported(IAudinDevice* device, const AUDIO_FORMAT* break; - case WAVE_FORMAT_ALAW: - case WAVE_FORMAT_MULAW: - return TRUE; - default: return FALSE; } diff --git a/channels/audin/client/pulse/audin_pulse.c b/channels/audin/client/pulse/audin_pulse.c index 8a5c3beb6dcb..fb8fdb711213 100644 --- a/channels/audin/client/pulse/audin_pulse.c +++ b/channels/audin/client/pulse/audin_pulse.c @@ -236,17 +236,6 @@ static BOOL audin_pulse_format_supported(IAudinDevice* device, const AUDIO_FORMA break; - case WAVE_FORMAT_ALAW: /* A-LAW */ - case WAVE_FORMAT_MULAW: /* U-LAW */ - if (format->cbSize == 0 && (format->nSamplesPerSec <= PA_RATE_MAX) && - (format->wBitsPerSample == 8) && - (format->nChannels >= 1 && format->nChannels <= PA_CHANNELS_MAX)) - { - return TRUE; - } - - break; - default: return FALSE; } From 266e5816c0cea8e2b15cd40068650b030fae1134 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Mon, 10 Oct 2022 09:49:28 +0200 Subject: [PATCH 272/496] Android build script updatee * Remove JPEG build support (deprecated) * Add sha256 check to tar/git checkout * Update default dependency versions (cherry picked from commit 7f13922370428149b6c86dfa34ecce1e287f538b) --- scripts/android-build-32.conf | 9 +++--- scripts/android-build-64.conf | 9 +++--- scripts/android-build-common.sh | 44 ++++++++++++++++++++++++------ scripts/android-build-ffmpeg.sh | 3 +- scripts/android-build-freerdp.sh | 39 ++++++++------------------ scripts/android-build-jpeg.sh | 40 --------------------------- scripts/android-build-openh264.sh | 7 +++-- scripts/android-build-openssl.sh | 8 +++--- scripts/android-build-release.conf | 9 +++--- scripts/android-build.conf | 9 +++--- 10 files changed, 78 insertions(+), 99 deletions(-) delete mode 100755 scripts/android-build-jpeg.sh diff --git a/scripts/android-build-32.conf b/scripts/android-build-32.conf index ff84d6d986bf..d9e425017d00 100644 --- a/scripts/android-build-32.conf +++ b/scripts/android-build-32.conf @@ -9,7 +9,6 @@ # If you require support for older NDK API levels, # create seperate configurations for each NDK API level # and architecture you want to support. -WITH_JPEG=0 WITH_OPENH264=0 WITH_OPENSSL=1 WITH_FFMPEG=1 @@ -18,10 +17,12 @@ DEPS_ONLY=0 NDK_TARGET=21 WITH_MEDIACODEC=1 -JPEG_TAG=master -OPENH264_TAG=v2.2.0 # NOTE: NDK r15c or earlier needed in --openh624-ndk for v1.8.0 -OPENSSL_TAG=OpenSSL_1_1_1o +OPENH264_TAG=v2.3.1 +OPENH264_HASH=453afa66dacb560bc5fd0468aabee90c483741571bca820a39a1c07f0362dc32 +OPENSSL_TAG=openssl-1.1.1q +OPENSSL_HASH=d7939ce614029cdff0b6c20f0e2e5703158a489a72b2507b8bd51bf8c8fd10ca FFMPEG_TAG=n4.4.1 +FFMPEG_HASH=82b43cc67296bcd01a59ae6b327cdb50121d3a9e35f41a30de1edd71bb4a6666 SRC_DIR=$SCRIPT_PATH/.. BUILD_DST=$SCRIPT_PATH/../client/Android/Studio/freeRDPCore/src/main/jniLibs diff --git a/scripts/android-build-64.conf b/scripts/android-build-64.conf index a8b3a8751472..fa0a80bb94a6 100644 --- a/scripts/android-build-64.conf +++ b/scripts/android-build-64.conf @@ -9,7 +9,6 @@ # If you require support for older NDK API levels, # create seperate configurations for each NDK API level # and architecture you want to support. -WITH_JPEG=0 WITH_OPENH264=1 WITH_OPENSSL=1 WITH_FFMPEG=1 @@ -18,10 +17,12 @@ DEPS_ONLY=0 NDK_TARGET=21 WITH_MEDIACODEC=1 -JPEG_TAG=master -OPENH264_TAG=v2.2.0 # NOTE: NDK r15c or earlier needed in --openh624-ndk for v1.8.0 -OPENSSL_TAG=OpenSSL_1_1_1o +OPENH264_TAG=v2.3.1 +OPENH264_HASH=453afa66dacb560bc5fd0468aabee90c483741571bca820a39a1c07f0362dc32 +OPENSSL_TAG=openssl-1.1.1q +OPENSSL_HASH=d7939ce614029cdff0b6c20f0e2e5703158a489a72b2507b8bd51bf8c8fd10ca FFMPEG_TAG=n4.4.1 +FFMPEG_HASH=82b43cc67296bcd01a59ae6b327cdb50121d3a9e35f41a30de1edd71bb4a6666 SRC_DIR=$SCRIPT_PATH/.. BUILD_DST=$SCRIPT_PATH/../client/Android/Studio/freeRDPCore/src/main/jniLibs diff --git a/scripts/android-build-common.sh b/scripts/android-build-common.sh index 05ef16af4ea7..b3675e374cad 100644 --- a/scripts/android-build-common.sh +++ b/scripts/android-build-common.sh @@ -1,8 +1,20 @@ -#!/bin/bash +#!/bin/bash -x SCRIPT_PATH=$(dirname "${BASH_SOURCE[0]}") SCRIPT_PATH=$(realpath "$SCRIPT_PATH") +FIND_ARGS="-type f -print -quit" +case "$(uname -s)" in + + Darwin) + FIND_ARGS="-perm +111 $FIND_ARGS" + ;; + + *) + FIND_ARGS="-executable $FIND_ARGS" + ;; +esac + if [ -z $BUILD_ARCH ]; then BUILD_ARCH="armeabi-v7a x86 x86_64 arm64-v8a" fi @@ -12,7 +24,7 @@ if [ -z $NDK_TARGET ]; then fi if [ -z $CMAKE_PROGRAM ]; then - CMAKE_PROGRAM=$(find $ANDROID_SDK/cmake -name cmake -type f -executable -print -quit) + CMAKE_PROGRAM=$(find $ANDROID_SDK/cmake -name cmake $FIND_ARGS) fi if [ -z $CCACHE ]; then @@ -61,6 +73,8 @@ function common_help { echo " SCM_URL=$SCM_URL" echo " --tag The SCM branch or tag to check out" echo " SCM_TAG=$SCM_TAG" + echo " --hash The SCM commit or hash to check out" + echo " SCM_HASH=$SCM_HASH" echo " --clean Clean the destination before build" echo " --help Display this help" exit 0 @@ -99,7 +113,7 @@ function common_parse_arguments { --sdk) ANDROID_SDK="$2" - CMAKE_PROGRAM=$(find $ANDROID_SDK/cmake -name cmake -type f -executable -print -quit) + CMAKE_PROGRAM=$(find $ANDROID_SDK/cmake -name cmake $FIND_ARGS) shift ;; @@ -128,6 +142,11 @@ function common_parse_arguments { shift ;; + --hash) + SCM_HASH="$2" + shift + ;; + --clean) CLEAN_BUILD_DIR=1 shift @@ -181,6 +200,12 @@ function common_check_requirements { exit 1 fi + if [[ -z $SCM_HASH ]]; + then + echo "SCM HASH not defined! Define SCM_HASH" + exit 1 + fi + if [[ -z $NDK_TARGET ]]; then echo "Android platform NDK_TARGET not defined" @@ -196,7 +221,7 @@ function common_check_requirements { fi if [ -z $CMAKE_PROGRAM ]; then - CMAKE_PROGRAM=$(find $ANDROID_SDK/cmake -name cmake -type f -executable -print -quit) + CMAKE_PROGRAM=$(find $ANDROID_SDK/cmake -name cmake $FIND_ARGS) fi for CMD in make git $CMAKE_PROGRAM $NDK_BUILD @@ -218,7 +243,7 @@ function common_check_requirements { } function common_update { - if [ $# -ne 3 ]; + if [ $# -ne 4 ]; then echo "Invalid arguments to update function $@" exit 1 @@ -226,19 +251,22 @@ function common_update { SCM_URL=$1 SCM_TAG=$2 BUILD_SRC=$3 + SCM_HASH=$4 echo "Preparing checkout..." BASE=$(pwd) CACHE=$SCRIPT_PATH/../cache common_run mkdir -p $CACHE TARFILE="$CACHE/$SCM_TAG.tar.gz" - - + if [[ ! -f "$TARFILE" ]]; then - common_run wget -O "$TARFILE" "$SCM_URL/archive/$SCM_TAG.tar.gz" + common_run wget -O "$TARFILE" "$SCM_URL/$SCM_TAG.tar.gz" fi + echo "$SCM_HASH $TARFILE" > $TARFILE.sha256sum + common_run sha256sum -c $TARFILE.sha256sum + if [[ -d $BUILD_SRC ]]; then common_run rm -rf $BUILD_SRC diff --git a/scripts/android-build-ffmpeg.sh b/scripts/android-build-ffmpeg.sh index 066b18ccaf9a..4233ca0c552e 100755 --- a/scripts/android-build-ffmpeg.sh +++ b/scripts/android-build-ffmpeg.sh @@ -2,6 +2,7 @@ SCM_URL=https://github.com/FFmpeg/FFmpeg SCM_TAG=n4.4.1 +SCM_HASH=82b43cc67296bcd01a59ae6b327cdb50121d3a9e35f41a30de1edd71bb4a6666 OLD_PATH=$PATH @@ -135,7 +136,7 @@ function build { # Run the main program. common_parse_arguments $@ common_check_requirements -common_update $SCM_URL $SCM_TAG $BUILD_SRC +common_update $SCM_URL $SCM_TAG $BUILD_SRC $SCM_HASH HOST_PKG_CONFIG_PATH=`command -v pkg-config` if [ -z ${HOST_PKG_CONFIG_PATH} ]; then diff --git a/scripts/android-build-freerdp.sh b/scripts/android-build-freerdp.sh index c39c3991e9d9..6257cc9310f6 100755 --- a/scripts/android-build-freerdp.sh +++ b/scripts/android-build-freerdp.sh @@ -1,11 +1,12 @@ #!/bin/bash -JPEG_TAG=master -OPENH264_TAG=master -OPENSSL_TAG=master +OPENH264_TAG=v2.3.1 +OPENH264_HASH=453afa66dacb560bc5fd0468aabee90c483741571bca820a39a1c07f0362dc32 +OPENSSL_TAG=openssl-1.1.1q +OPENSSL_HASH=d7939ce614029cdff0b6c20f0e2e5703158a489a72b2507b8bd51bf8c8fd10ca FFMPEG_TAG=n4.4.1 +FFMPEG_HASH=82b43cc67296bcd01a59ae6b327cdb50121d3a9e35f41a30de1edd71bb4a6666 -WITH_JPEG=0 WITH_OPENH264=0 WITH_OPENSSL=0 WITH_FFMPEG=0 @@ -32,10 +33,6 @@ do SRC_DIR="$2" shift ;; - --jpeg) - WITH_JPEG=1 - shift - ;; --openh264) WITH_OPENH264=1 shift @@ -108,21 +105,6 @@ BASE=$(pwd) for ARCH in $BUILD_ARCH do # build dependencies. - if [ $WITH_JPEG -ne 0 ]; - then - if [ $BUILD_DEPS -ne 0 ]; - then - common_run bash $SCRIPT_PATH/android-build-jpeg.sh \ - --src $BUILD_SRC/jpeg --dst $BUILD_DST \ - --ndk $ANDROID_NDK \ - --arch $ARCH \ - --target $NDK_TARGET \ - --tag $JPEG_TAG - fi - CMAKE_CMD_ARGS="$CMAKE_CMD_ARGS -DWITH_JPEG=ON" - else - CMAKE_CMD_ARGS="$CMAKE_CMD_ARGS -DWITH_JPEG=OFF" - fi if [ $WITH_OPENH264 -ne 0 ]; then if [ -z "$ANDROID_NDK_OPENH264" ] @@ -140,7 +122,8 @@ do --ndk "$ANDROID_NDK_OPENH264" \ --arch $ARCH \ --target $NDK_TARGET \ - --tag $OPENH264_TAG + --tag $OPENH264_TAG \ + --hash $OPENH264_HASH fi CMAKE_CMD_ARGS="$CMAKE_CMD_ARGS -DWITH_OPENH264=ON" else @@ -164,7 +147,8 @@ do --ndk "$ANDROID_NDK" \ --arch $ARCH \ --target $NDK_TARGET \ - --tag $FFMPEG_TAG + --tag $FFMPEG_TAG \ + --hash $FFMPEG_HASH fi CMAKE_CMD_ARGS="$CMAKE_CMD_ARGS -DWITH_FFMPEG=ON -DWITH_SWSCALE=ON -DWITH_DSP_FFMPEG=ON" else @@ -179,8 +163,9 @@ do --sdk "$ANDROID_SDK" \ --ndk $ANDROID_NDK \ --arch $ARCH \ - --target $NDK_TARGET \ - --tag $OPENSSL_TAG + --target $NDK_TARGET \ + --tag $OPENSSL_TAG \ + --hash $OPENSSL_HASH fi fi diff --git a/scripts/android-build-jpeg.sh b/scripts/android-build-jpeg.sh deleted file mode 100755 index dafcf893ac4a..000000000000 --- a/scripts/android-build-jpeg.sh +++ /dev/null @@ -1,40 +0,0 @@ -#!/bin/bash -SCM_URL=https://github.com/akallabeth/jpeg8d -SCM_TAG=master - -source $(dirname "${BASH_SOURCE[0]}")/android-build-common.sh - -function usage { - echo $0 [arguments] - echo "\tThe script checks out the OpenH264 git repository" - echo "\tto a local source directory, builds and installs" - echo "\tthe library for all architectures defined to" - echo "\tthe destination directory." - echo "" - echo "\t[-s|--source-dir ]" - echo "\t[-d|--destination-dir ]" - echo "\t[-a|--arch ]" - echo "\t[-t|--tag ]" - echo "\t[--scm-url ]" - echo "\t[--ndk ]" - echo "\t[--sdk ]" - exit 1 -} - -function build { - echo "Building architectures $BUILD_ARCH..." - BASE=$(pwd) - common_run cd $BUILD_SRC - common_run $NDK_BUILD V=1 APP_ABI="${BUILD_ARCH}" NDK_TOOLCHAIN_VERSION=4.9 -j clean - common_run $NDK_BUILD V=1 APP_ABI="${BUILD_ARCH}" NDK_TOOLCHAIN_VERSION=4.9 -j - common_run cd $BASE -} - -# Run the main program. -common_parse_arguments $@ -common_check_requirements -common_update $SCM_URL $SCM_TAG $BUILD_SRC - -build - -common_copy $BUILD_SRC $BUILD_DST diff --git a/scripts/android-build-openh264.sh b/scripts/android-build-openh264.sh index b0cec9902913..44d39f660adc 100755 --- a/scripts/android-build-openh264.sh +++ b/scripts/android-build-openh264.sh @@ -1,6 +1,7 @@ #!/bin/bash -SCM_URL=https://github.com/cisco/openh264 -SCM_TAG=master +SCM_URL=https://github.com/cisco/openh264/archive +SCM_TAG=v2.3.1 +SCM_HASH=453afa66dacb560bc5fd0468aabee90c483741571bca820a39a1c07f0362dc32 source $(dirname "${BASH_SOURCE[0]}")/android-build-common.sh @@ -26,7 +27,7 @@ function build { # Run the main program. common_parse_arguments $@ common_check_requirements -common_update $SCM_URL $SCM_TAG $BUILD_SRC +common_update $SCM_URL $SCM_TAG $BUILD_SRC $SCM_HASH for ARCH in $BUILD_ARCH diff --git a/scripts/android-build-openssl.sh b/scripts/android-build-openssl.sh index 834e53a21f27..d5c815741f47 100755 --- a/scripts/android-build-openssl.sh +++ b/scripts/android-build-openssl.sh @@ -1,7 +1,8 @@ #!/bin/bash -SCM_URL=https://github.com/openssl/openssl -SCM_TAG=master +SCM_URL=https://www.openssl.org/source +SCM_TAG=OpenSSL_1_1_1q +SCM_HASH=d7939ce614029cdff0b6c20f0e2e5703158a489a72b2507b8bd51bf8c8fd10ca COMPILER=4.9 @@ -43,7 +44,7 @@ function build { # Run the main program. common_parse_arguments $@ common_check_requirements -common_update $SCM_URL $SCM_TAG $BUILD_SRC +common_update $SCM_URL $SCM_TAG $BUILD_SRC $SCM_HASH ORG_PATH=$PATH for ARCH in $BUILD_ARCH @@ -74,4 +75,3 @@ then common_run mkdir -p $BUILD_DST/$ARCH/include fi common_run cp -L -R $BUILD_SRC/include/openssl $BUILD_DST/$ARCH/include/ - diff --git a/scripts/android-build-release.conf b/scripts/android-build-release.conf index 06a435600eb2..90059e49cccc 100644 --- a/scripts/android-build-release.conf +++ b/scripts/android-build-release.conf @@ -9,7 +9,6 @@ # If you require support for older NDK API levels, # create seperate configurations for each NDK API level # and architecture you want to support. -WITH_JPEG=0 WITH_OPENH264=0 WITH_OPENSSL=1 WITH_FFMPEG=1 @@ -18,10 +17,12 @@ DEPS_ONLY=0 NDK_TARGET=23 WITH_MEDIACODEC=1 -JPEG_TAG=master -OPENH264_TAG=v2.2.0 # NOTE: NDK r15c or earlier needed in --openh624-ndk for v1.8.0 -OPENSSL_TAG=OpenSSL_1_1_1o +OPENH264_TAG=v2.3.1 +OPENH264_HASH=453afa66dacb560bc5fd0468aabee90c483741571bca820a39a1c07f0362dc32 +OPENSSL_TAG=openssl-1.1.1q +OPENSSL_HASH=d7939ce614029cdff0b6c20f0e2e5703158a489a72b2507b8bd51bf8c8fd10ca FFMPEG_TAG=n4.4.1 +FFMPEG_HASH=82b43cc67296bcd01a59ae6b327cdb50121d3a9e35f41a30de1edd71bb4a6666 SRC_DIR=$SCRIPT_PATH/.. BUILD_DST=$SCRIPT_PATH/../client/Android/Studio/freeRDPCore/src/main/jniLibs diff --git a/scripts/android-build.conf b/scripts/android-build.conf index 798c26e8a550..4bafc1e289ea 100644 --- a/scripts/android-build.conf +++ b/scripts/android-build.conf @@ -9,7 +9,6 @@ # If you require support for older NDK API levels, # create seperate configurations for each NDK API level # and architecture you want to support. -WITH_JPEG=0 WITH_OPENH264=0 WITH_OPENSSL=1 WITH_FFMPEG=0 @@ -18,10 +17,12 @@ DEPS_ONLY=0 NDK_TARGET=21 WITH_MEDIACODEC=1 -JPEG_TAG=master -OPENH264_TAG=v2.2.0 # NOTE: NDK r15c or earlier needed in --openh624-ndk for v1.8.0 -OPENSSL_TAG=OpenSSL_1_1_1o +OPENH264_TAG=v2.3.1 +OPENH264_HASH=453afa66dacb560bc5fd0468aabee90c483741571bca820a39a1c07f0362dc32 +OPENSSL_TAG=openssl-1.1.1q +OPENSSL_HASH=d7939ce614029cdff0b6c20f0e2e5703158a489a72b2507b8bd51bf8c8fd10ca FFMPEG_TAG=n4.4.1 +FFMPEG_HASH=82b43cc67296bcd01a59ae6b327cdb50121d3a9e35f41a30de1edd71bb4a6666 SRC_DIR=$SCRIPT_PATH/.. BUILD_DST=$SCRIPT_PATH/../client/Android/Studio/freeRDPCore/src/main/jniLibs From 36247e3a4805660220960ec001703f8c62873c6f Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Mon, 10 Oct 2022 09:17:14 +0200 Subject: [PATCH 273/496] Updated version to 2.8.1 --- CMakeLists.txt | 2 +- ChangeLog | 10 ++++++++-- client/Android/android_freerdp.c | 2 +- winpr/CMakeLists.txt | 2 +- 4 files changed, 11 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d876914b2e5d..aa1131d3d49d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -85,7 +85,7 @@ if ($ENV{BUILD_NUMBER}) endif() set(WITH_LIBRARY_VERSIONING "ON") -set(RAW_VERSION_STRING "2.8.0") +set(RAW_VERSION_STRING "2.8.1") if(EXISTS "${CMAKE_SOURCE_DIR}/.source_tag") file(READ ${CMAKE_SOURCE_DIR}/.source_tag RAW_VERSION_STRING) elseif(USE_VERSION_FROM_GIT_TAG) diff --git a/ChangeLog b/ChangeLog index 1388ba434abb..b878eacc8329 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,7 +1,12 @@ -# 20xx-xx-xx Version 2.x.x +# 2022-10-12 Version 2.8.1 -Fixed issues: +Notewhorth changes: +* Fixed CVE-2022-39282 +* Fixed CVE-2022-39283 +* Added missing commit for backported #8041: Remove ALAW/ULAW codecs from linux backends (unreliable) +* Added hash checks for android build script dependencies +Fixed issues: * Backported #8190: Fix build break with newer FFMPEG versions * Backported #8234: Updated flatpak with build script * Backported #8210: Better execinfo support check for android @@ -9,6 +14,7 @@ Fixed issues: * Backported #8176: Check fullscreen state and not setting * Backported #8236: Send resize on window state change * Backported #7611: Audin macOS monterey fix +* Backported #8291: Android build script update # 2022-07-28 Version 2.8.0 diff --git a/client/Android/android_freerdp.c b/client/Android/android_freerdp.c index 6811381152e7..019a7193e6b8 100644 --- a/client/Android/android_freerdp.c +++ b/client/Android/android_freerdp.c @@ -57,7 +57,7 @@ #define TAG CLIENT_TAG("android") /* Defines the JNI version supported by this library. */ -#define FREERDP_JNI_VERSION "2.8.0" +#define FREERDP_JNI_VERSION "2.8.1" static void android_OnChannelConnectedEventHandler(void* context, ChannelConnectedEventArgs* e) { diff --git a/winpr/CMakeLists.txt b/winpr/CMakeLists.txt index 050068e15c5b..c9fbc5c994e2 100644 --- a/winpr/CMakeLists.txt +++ b/winpr/CMakeLists.txt @@ -57,7 +57,7 @@ if (NOT WIN32) endif() # Soname versioning -set(RAW_VERSION_STRING "2.8.0") +set(RAW_VERSION_STRING "2.8.1") if(EXISTS "${CMAKE_SOURCE_DIR}/.source_tag") file(READ ${CMAKE_SOURCE_DIR}/.source_tag RAW_VERSION_STRING) elseif(USE_VERSION_FROM_GIT_TAG) From af053892ae26783207ab40415e4dfae417948749 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Tue, 18 Oct 2022 13:52:50 +0200 Subject: [PATCH 274/496] Updated TestCryptoHash Do multiple updates to hashes to better test implementation (cherry picked from commit cfca31d3849c4c112952bf3f888b3310d8f72016) --- winpr/libwinpr/crypto/test/TestCryptoHash.c | 26 +++++++++++++++------ 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/winpr/libwinpr/crypto/test/TestCryptoHash.c b/winpr/libwinpr/crypto/test/TestCryptoHash.c index 8b911866bb7a..761d72d77522 100644 --- a/winpr/libwinpr/crypto/test/TestCryptoHash.c +++ b/winpr/libwinpr/crypto/test/TestCryptoHash.c @@ -11,7 +11,7 @@ static const BYTE TEST_MD5_HASH[] = static BOOL test_crypto_hash_md5(void) { BOOL result = FALSE; - BYTE hash[WINPR_MD5_DIGEST_LENGTH]; + BYTE hash[WINPR_MD5_DIGEST_LENGTH] = { 0 }; WINPR_DIGEST_CTX* ctx; if (!(ctx = winpr_Digest_New())) @@ -64,7 +64,7 @@ static const BYTE TEST_MD4_HASH[] = static BOOL test_crypto_hash_md4(void) { BOOL result = FALSE; - BYTE hash[WINPR_MD4_DIGEST_LENGTH]; + BYTE hash[WINPR_MD4_DIGEST_LENGTH] = { 0 }; WINPR_DIGEST_CTX* ctx; if (!(ctx = winpr_Digest_New())) @@ -117,7 +117,7 @@ static const BYTE TEST_SHA1_HASH[] = static BOOL test_crypto_hash_sha1(void) { BOOL result = FALSE; - BYTE hash[WINPR_SHA1_DIGEST_LENGTH]; + BYTE hash[WINPR_SHA1_DIGEST_LENGTH] = { 0 }; WINPR_DIGEST_CTX* ctx; if (!(ctx = winpr_Digest_New())) @@ -168,11 +168,11 @@ static const char TEST_HMAC_MD5_DATA[] = "Hi There"; static const BYTE TEST_HMAC_MD5_KEY[] = "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b"; static const BYTE TEST_HMAC_MD5_HASH[] = - "\x92\x94\x72\x7a\x36\x38\xbb\x1c\x13\xf4\x8e\xf8\x15\x8b\xfc\x9d"; + "\xb5\x79\x91\xa2\x20\x3d\x49\x2d\x73\xfb\x71\x43\xdf\xc5\x08\x28"; static BOOL test_crypto_hash_hmac_md5(void) { - BYTE hash[WINPR_MD5_DIGEST_LENGTH]; + BYTE hash[WINPR_MD5_DIGEST_LENGTH] = { 0 }; WINPR_HMAC_CTX* ctx; BOOL result = FALSE; @@ -193,6 +193,12 @@ static BOOL test_crypto_hash_hmac_md5(void) fprintf(stderr, "%s: winpr_HMAC_Update failed\n", __FUNCTION__); goto out; } + if (!winpr_HMAC_Update(ctx, (const BYTE*)TEST_HMAC_MD5_DATA, + strnlen(TEST_HMAC_MD5_DATA, sizeof(TEST_HMAC_MD5_DATA)))) + { + fprintf(stderr, "%s: winpr_HMAC_Update failed\n", __FUNCTION__); + goto out; + } if (!winpr_HMAC_Final(ctx, hash, sizeof(hash))) { fprintf(stderr, "%s: winpr_HMAC_Final failed\n", __FUNCTION__); @@ -225,11 +231,11 @@ static const char TEST_HMAC_SHA1_DATA[] = "Hi There"; static const BYTE TEST_HMAC_SHA1_KEY[] = "\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b\x0b"; static const BYTE TEST_HMAC_SHA1_HASH[] = - "\xb6\x17\x31\x86\x55\x05\x72\x64\xe2\x8b\xc0\xb6\xfb\x37\x8c\x8e\xf1\x46\xbe\x00"; + "\xab\x23\x08\x2d\xca\x0c\x75\xea\xca\x60\x09\xc0\xb8\x8c\x2d\xf4\xf4\xbf\x88\xee"; static BOOL test_crypto_hash_hmac_sha1(void) { - BYTE hash[WINPR_SHA1_DIGEST_LENGTH]; + BYTE hash[WINPR_SHA1_DIGEST_LENGTH] = { 0 }; WINPR_HMAC_CTX* ctx; BOOL result = FALSE; @@ -250,6 +256,12 @@ static BOOL test_crypto_hash_hmac_sha1(void) fprintf(stderr, "%s: winpr_HMAC_Update failed\n", __FUNCTION__); goto out; } + if (!winpr_HMAC_Update(ctx, (const BYTE*)TEST_HMAC_SHA1_DATA, + strnlen(TEST_HMAC_SHA1_DATA, sizeof(TEST_HMAC_SHA1_DATA)))) + { + fprintf(stderr, "%s: winpr_HMAC_Update failed\n", __FUNCTION__); + goto out; + } if (!winpr_HMAC_Final(ctx, hash, sizeof(hash))) { fprintf(stderr, "%s: winpr_HMAC_Final failed\n", __FUNCTION__); From 4b2260c54626a9d1ad3fd227bfeb77b22faae73c Mon Sep 17 00:00:00 2001 From: akallabeth Date: Tue, 18 Oct 2022 13:51:09 +0200 Subject: [PATCH 275/496] Added replacement MD4 implementation (cherry picked from commit 095f1dca62035d05493e213300f787b80414c7a8) --- config.h.in | 2 + winpr/CMakeLists.txt | 1 + winpr/libwinpr/crypto/CMakeLists.txt | 12 +- winpr/libwinpr/crypto/hash.c | 126 ++++++++++--- winpr/libwinpr/crypto/md4.c | 266 +++++++++++++++++++++++++++ winpr/libwinpr/crypto/md4.h | 46 +++++ 6 files changed, 422 insertions(+), 31 deletions(-) create mode 100644 winpr/libwinpr/crypto/md4.c create mode 100644 winpr/libwinpr/crypto/md4.h diff --git a/config.h.in b/config.h.in index 801b085e4b5b..964124a4ee45 100644 --- a/config.h.in +++ b/config.h.in @@ -183,4 +183,6 @@ /* Proxy */ #cmakedefine WITH_PROXY_MODULES +#cmakedefine WITH_INTERNAL_MD4 + #endif /* FREERDP_CONFIG_H */ diff --git a/winpr/CMakeLists.txt b/winpr/CMakeLists.txt index c9fbc5c994e2..00cd50203f5b 100644 --- a/winpr/CMakeLists.txt +++ b/winpr/CMakeLists.txt @@ -82,6 +82,7 @@ else() set(WINPR_VERSION_FULL "${WINPR_VERSION}") endif() +option(WITH_INTERNAL_MD4 "Use compiled in md4 hash functions instead of OpenSSL/MBedTLS" OFF) if(NOT IOS) check_include_files(stdbool.h WINPR_HAVE_STDBOOL_H) check_include_files(stdint.h WINPR_HAVE_STDINT_H) diff --git a/winpr/libwinpr/crypto/CMakeLists.txt b/winpr/libwinpr/crypto/CMakeLists.txt index d215744c7196..a836321203a6 100644 --- a/winpr/libwinpr/crypto/CMakeLists.txt +++ b/winpr/libwinpr/crypto/CMakeLists.txt @@ -15,13 +15,21 @@ # See the License for the specific language governing permissions and # limitations under the License. -winpr_module_add( +set(SRCS hash.c rand.c cipher.c cert.c crypto.c - crypto.h) + crypto.h +) +if (WITH_INTERNAL_MD4) + list(APPEND SRCS md4.c md4.h) +endif() + +winpr_module_add( + ${SRCS} +) if(OPENSSL_FOUND) winpr_include_directory_add(${OPENSSL_INCLUDE_DIR}) diff --git a/winpr/libwinpr/crypto/hash.c b/winpr/libwinpr/crypto/hash.c index 5e94039e78cd..6435e5367cc0 100644 --- a/winpr/libwinpr/crypto/hash.c +++ b/winpr/libwinpr/crypto/hash.c @@ -21,7 +21,7 @@ #endif #include - +#include #include #ifdef WITH_OPENSSL @@ -39,6 +39,10 @@ #include #endif +#if defined(WITH_INTERNAL_MD4) +#include "md4.h" +#endif + /** * HMAC */ @@ -332,34 +336,56 @@ BOOL winpr_HMAC(WINPR_MD_TYPE md, const BYTE* key, size_t keylen, const BYTE* in * Generic Digest API */ -WINPR_DIGEST_CTX* winpr_Digest_New(void) +struct _winpr_digest_ctx_private_st { - WINPR_DIGEST_CTX* ctx = NULL; + WINPR_MD_TYPE md; + +#if defined(WITH_INTERNAL_MD4) + WINPR_MD4_CTX md4; +#endif #if defined(WITH_OPENSSL) EVP_MD_CTX* mdctx; +#endif +#if defined(WITH_MBEDTLS) + mbedtls_md_context_t* mdctx; +#endif +}; + +WINPR_DIGEST_CTX* winpr_Digest_New(void) +{ + WINPR_DIGEST_CTX* ctx = calloc(1, sizeof(WINPR_DIGEST_CTX)); + if (!ctx) + return NULL; + +#if defined(WITH_OPENSSL) #if (OPENSSL_VERSION_NUMBER < 0x10100000L) || \ (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x2070000fL) - mdctx = EVP_MD_CTX_create(); + ctx->mdctx = EVP_MD_CTX_create(); #else - mdctx = EVP_MD_CTX_new(); + ctx->mdctx = EVP_MD_CTX_new(); #endif - ctx = (WINPR_DIGEST_CTX*)mdctx; + if (!ctx->mdctx) + goto fail; + #elif defined(WITH_MBEDTLS) - mbedtls_md_context_t* mdctx; - mdctx = (mbedtls_md_context_t*)calloc(1, sizeof(mbedtls_md_context_t)); + ctx->mdctx = (mbedtls_md_context_t*)calloc(1, sizeof(mbedtls_md_context_t)); - if (mdctx) - mbedtls_md_init(mdctx); + if (!ctx->mdctx) + goto fail; - ctx = (WINPR_DIGEST_CTX*)mdctx; + mbedtls_md_init(ctx->mdctx); #endif return ctx; + +fail: + winpr_Digest_Free(ctx); } #if defined(WITH_OPENSSL) static BOOL winpr_Digest_Init_Internal(WINPR_DIGEST_CTX* ctx, const EVP_MD* evp) { - EVP_MD_CTX* mdctx = (EVP_MD_CTX*)ctx; + WINPR_ASSERT(ctx); + EVP_MD_CTX* mdctx = ctx->mdctx; if (!mdctx || !evp) return FALSE; @@ -373,7 +399,8 @@ static BOOL winpr_Digest_Init_Internal(WINPR_DIGEST_CTX* ctx, const EVP_MD* evp) #elif defined(WITH_MBEDTLS) static BOOL winpr_Digest_Init_Internal(WINPR_DIGEST_CTX* ctx, WINPR_MD_TYPE md) { - mbedtls_md_context_t* mdctx = (mbedtls_md_context_t*)ctx; + WINPR_ASSERT(ctx); + mbedtls_md_context_t* mdctx = ctx->mdctx; mbedtls_md_type_t md_type = winpr_mbedtls_get_md_type(md); const mbedtls_md_info_t* md_info = mbedtls_md_info_from_type(md_type); @@ -397,15 +424,16 @@ static BOOL winpr_Digest_Init_Internal(WINPR_DIGEST_CTX* ctx, WINPR_MD_TYPE md) BOOL winpr_Digest_Init_Allow_FIPS(WINPR_DIGEST_CTX* ctx, WINPR_MD_TYPE md) { + WINPR_ASSERT(ctx); + #if defined(WITH_OPENSSL) - EVP_MD_CTX* mdctx = (EVP_MD_CTX*)ctx; const EVP_MD* evp = winpr_openssl_get_evp_md(md); /* Only MD5 is supported for FIPS allow override */ if (md != WINPR_MD_MD5) return FALSE; - EVP_MD_CTX_set_flags(mdctx, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW); + EVP_MD_CTX_set_flags(ctx->mdctx, EVP_MD_CTX_FLAG_NON_FIPS_ALLOW); return winpr_Digest_Init_Internal(ctx, evp); #elif defined(WITH_MBEDTLS) @@ -419,6 +447,20 @@ BOOL winpr_Digest_Init_Allow_FIPS(WINPR_DIGEST_CTX* ctx, WINPR_MD_TYPE md) BOOL winpr_Digest_Init(WINPR_DIGEST_CTX* ctx, WINPR_MD_TYPE md) { + WINPR_ASSERT(ctx); + + ctx->md = md; + switch (md) + { +#if defined(WITH_INTERNAL_MD4) + case WINPR_MD_MD4: + winpr_MD4_Init(&ctx->md4); + return TRUE; +#endif + default: + break; + } + #if defined(WITH_OPENSSL) const EVP_MD* evp = winpr_openssl_get_evp_md(md); return winpr_Digest_Init_Internal(ctx, evp); @@ -429,14 +471,27 @@ BOOL winpr_Digest_Init(WINPR_DIGEST_CTX* ctx, WINPR_MD_TYPE md) BOOL winpr_Digest_Update(WINPR_DIGEST_CTX* ctx, const BYTE* input, size_t ilen) { + WINPR_ASSERT(ctx); + + switch (ctx->md) + { +#if defined(WITH_INTERNAL_MD4) + case WINPR_MD_MD4: + winpr_MD4_Update(&ctx->md4, input, ilen); + return TRUE; +#endif + default: + break; + } + #if defined(WITH_OPENSSL) - EVP_MD_CTX* mdctx = (EVP_MD_CTX*)ctx; + EVP_MD_CTX* mdctx = ctx->mdctx; if (EVP_DigestUpdate(mdctx, input, ilen) != 1) return FALSE; #elif defined(WITH_MBEDTLS) - mbedtls_md_context_t* mdctx = (mbedtls_md_context_t*)ctx; + mbedtls_md_context_t* mdctx = ctx->mdctx; if (mbedtls_md_update(mdctx, input, ilen) != 0) return FALSE; @@ -447,14 +502,30 @@ BOOL winpr_Digest_Update(WINPR_DIGEST_CTX* ctx, const BYTE* input, size_t ilen) BOOL winpr_Digest_Final(WINPR_DIGEST_CTX* ctx, BYTE* output, size_t olen) { + WINPR_ASSERT(ctx); + + switch (ctx->md) + { +#if defined(WITH_INTERNAL_MD4) + case WINPR_MD_MD4: + if (olen < WINPR_MD4_DIGEST_LENGTH) + return FALSE; + winpr_MD4_Final(output, &ctx->md4); + return TRUE; +#endif + + default: + break; + } + #if defined(WITH_OPENSSL) - EVP_MD_CTX* mdctx = (EVP_MD_CTX*)ctx; + EVP_MD_CTX* mdctx = ctx->mdctx; if (EVP_DigestFinal_ex(mdctx, output, NULL) == 1) return TRUE; #elif defined(WITH_MBEDTLS) - mbedtls_md_context_t* mdctx = (mbedtls_md_context_t*)ctx; + mbedtls_md_context_t* mdctx = ctx->mdctx; if (mbedtls_md_finish(mdctx, output) == 0) return TRUE; @@ -466,28 +537,25 @@ BOOL winpr_Digest_Final(WINPR_DIGEST_CTX* ctx, BYTE* output, size_t olen) void winpr_Digest_Free(WINPR_DIGEST_CTX* ctx) { #if defined(WITH_OPENSSL) - EVP_MD_CTX* mdctx = (EVP_MD_CTX*)ctx; - - if (mdctx) + if (ctx->mdctx) { #if (OPENSSL_VERSION_NUMBER < 0x10100000L) || \ (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x2070000fL) - EVP_MD_CTX_destroy(mdctx); + EVP_MD_CTX_destroy(ctx->mdctx); #else - EVP_MD_CTX_free(mdctx); + EVP_MD_CTX_free(ctx->mdctx); #endif } #elif defined(WITH_MBEDTLS) - mbedtls_md_context_t* mdctx = (mbedtls_md_context_t*)ctx; - - if (mdctx) + if (ctx->mdctx) { - mbedtls_md_free(mdctx); - free(mdctx); + mbedtls_md_free(ctx->mdctx); + free(ctx->mdctx); } #endif + free(ctx); } BOOL winpr_Digest_Allow_FIPS(WINPR_MD_TYPE md, const BYTE* input, size_t ilen, BYTE* output, diff --git a/winpr/libwinpr/crypto/md4.c b/winpr/libwinpr/crypto/md4.c new file mode 100644 index 000000000000..c33aea334b38 --- /dev/null +++ b/winpr/libwinpr/crypto/md4.c @@ -0,0 +1,266 @@ +/* + * This is an OpenSSL-compatible implementation of the RSA Data Security, Inc. + * MD4 Message-Digest Algorithm (RFC 1320). + * + * Homepage: + * http://openwall.info/wiki/people/solar/software/public-domain-source-code/md4 + * + * Author: + * Alexander Peslyak, better known as Solar Designer + * + * This software was written by Alexander Peslyak in 2001. No copyright is + * claimed, and the software is hereby placed in the public domain. + * In case this attempt to disclaim copyright and place the software in the + * public domain is deemed null and void, then the software is + * Copyright (c) 2001 Alexander Peslyak and it is hereby released to the + * general public under the following terms: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + * There's ABSOLUTELY NO WARRANTY, express or implied. + * + * (This is a heavily cut-down "BSD license".) + * + * This differs from Colin Plumb's older public domain implementation in that + * no exactly 32-bit integer data type is required (any 32-bit or wider + * unsigned integer data type will do), there's no compile-time endianness + * configuration, and the function prototypes match OpenSSL's. No code from + * Colin Plumb's implementation has been reused; this comment merely compares + * the properties of the two independent implementations. + * + * The primary goals of this implementation are portability and ease of use. + * It is meant to be fast, but not as fast as possible. Some known + * optimizations are not included to reduce source code size and avoid + * compile-time configuration. + */ + +#include + +#include "md4.h" + +/* + * The basic MD4 functions. + * + * F and G are optimized compared to their RFC 1320 definitions, with the + * optimization for F borrowed from Colin Plumb's MD5 implementation. + */ +#define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z)))) +#define G(x, y, z) (((x) & ((y) | (z))) | ((y) & (z))) +#define H(x, y, z) ((x) ^ (y) ^ (z)) + +/* + * The MD4 transformation for all three rounds. + */ +#define STEP(f, a, b, c, d, x, s) \ + (a) += f((b), (c), (d)) + (x); \ + (a) = (((a) << (s)) | (((a)&0xffffffff) >> (32 - (s)))); + +/* + * SET reads 4 input bytes in little-endian byte order and stores them in a + * properly aligned word in host byte order. + * + * The check for little-endian architectures that tolerate unaligned memory + * accesses is just an optimization. Nothing will break if it fails to detect + * a suitable architecture. + * + * Unfortunately, this optimization may be a C strict aliasing rules violation + * if the caller's data buffer has effective type that cannot be aliased by + * winpr_MD4_u32plus. In practice, this problem may occur if these MD4 routines are + * inlined into a calling function, or with future and dangerously advanced + * link-time optimizations. For the time being, keeping these MD4 routines in + * their own translation unit avoids the problem. + */ +#if defined(__i386__) || defined(__x86_64__) || defined(__vax__) +#define SET(n) (*(winpr_MD4_u32plus*)&ptr[(n)*4]) +#define GET(n) SET(n) +#else +#define SET(n) \ + (ctx->block[(n)] = (winpr_MD4_u32plus)ptr[(n)*4] | ((winpr_MD4_u32plus)ptr[(n)*4 + 1] << 8) | \ + ((winpr_MD4_u32plus)ptr[(n)*4 + 2] << 16) | \ + ((winpr_MD4_u32plus)ptr[(n)*4 + 3] << 24)) +#define GET(n) (ctx->block[(n)]) +#endif + +/* + * This processes one or more 64-byte data blocks, but does NOT update the bit + * counters. There are no alignment requirements. + */ +static const void* body(WINPR_MD4_CTX* ctx, const void* data, unsigned long size) +{ + const unsigned char* ptr; + winpr_MD4_u32plus a, b, c, d; + winpr_MD4_u32plus saved_a, saved_b, saved_c, saved_d; + const winpr_MD4_u32plus ac1 = 0x5a827999, ac2 = 0x6ed9eba1; + + ptr = (const unsigned char*)data; + + a = ctx->a; + b = ctx->b; + c = ctx->c; + d = ctx->d; + + do + { + saved_a = a; + saved_b = b; + saved_c = c; + saved_d = d; + + /* Round 1 */ + STEP(F, a, b, c, d, SET(0), 3) + STEP(F, d, a, b, c, SET(1), 7) + STEP(F, c, d, a, b, SET(2), 11) + STEP(F, b, c, d, a, SET(3), 19) + STEP(F, a, b, c, d, SET(4), 3) + STEP(F, d, a, b, c, SET(5), 7) + STEP(F, c, d, a, b, SET(6), 11) + STEP(F, b, c, d, a, SET(7), 19) + STEP(F, a, b, c, d, SET(8), 3) + STEP(F, d, a, b, c, SET(9), 7) + STEP(F, c, d, a, b, SET(10), 11) + STEP(F, b, c, d, a, SET(11), 19) + STEP(F, a, b, c, d, SET(12), 3) + STEP(F, d, a, b, c, SET(13), 7) + STEP(F, c, d, a, b, SET(14), 11) + STEP(F, b, c, d, a, SET(15), 19) + + /* Round 2 */ + STEP(G, a, b, c, d, GET(0) + ac1, 3) + STEP(G, d, a, b, c, GET(4) + ac1, 5) + STEP(G, c, d, a, b, GET(8) + ac1, 9) + STEP(G, b, c, d, a, GET(12) + ac1, 13) + STEP(G, a, b, c, d, GET(1) + ac1, 3) + STEP(G, d, a, b, c, GET(5) + ac1, 5) + STEP(G, c, d, a, b, GET(9) + ac1, 9) + STEP(G, b, c, d, a, GET(13) + ac1, 13) + STEP(G, a, b, c, d, GET(2) + ac1, 3) + STEP(G, d, a, b, c, GET(6) + ac1, 5) + STEP(G, c, d, a, b, GET(10) + ac1, 9) + STEP(G, b, c, d, a, GET(14) + ac1, 13) + STEP(G, a, b, c, d, GET(3) + ac1, 3) + STEP(G, d, a, b, c, GET(7) + ac1, 5) + STEP(G, c, d, a, b, GET(11) + ac1, 9) + STEP(G, b, c, d, a, GET(15) + ac1, 13) + + /* Round 3 */ + STEP(H, a, b, c, d, GET(0) + ac2, 3) + STEP(H, d, a, b, c, GET(8) + ac2, 9) + STEP(H, c, d, a, b, GET(4) + ac2, 11) + STEP(H, b, c, d, a, GET(12) + ac2, 15) + STEP(H, a, b, c, d, GET(2) + ac2, 3) + STEP(H, d, a, b, c, GET(10) + ac2, 9) + STEP(H, c, d, a, b, GET(6) + ac2, 11) + STEP(H, b, c, d, a, GET(14) + ac2, 15) + STEP(H, a, b, c, d, GET(1) + ac2, 3) + STEP(H, d, a, b, c, GET(9) + ac2, 9) + STEP(H, c, d, a, b, GET(5) + ac2, 11) + STEP(H, b, c, d, a, GET(13) + ac2, 15) + STEP(H, a, b, c, d, GET(3) + ac2, 3) + STEP(H, d, a, b, c, GET(11) + ac2, 9) + STEP(H, c, d, a, b, GET(7) + ac2, 11) + STEP(H, b, c, d, a, GET(15) + ac2, 15) + + a += saved_a; + b += saved_b; + c += saved_c; + d += saved_d; + + ptr += 64; + } while (size -= 64); + + ctx->a = a; + ctx->b = b; + ctx->c = c; + ctx->d = d; + + return ptr; +} + +void winpr_MD4_Init(WINPR_MD4_CTX* ctx) +{ + ctx->a = 0x67452301; + ctx->b = 0xefcdab89; + ctx->c = 0x98badcfe; + ctx->d = 0x10325476; + + ctx->lo = 0; + ctx->hi = 0; +} + +void winpr_MD4_Update(WINPR_MD4_CTX* ctx, const void* data, unsigned long size) +{ + winpr_MD4_u32plus saved_lo; + unsigned long used, available; + + saved_lo = ctx->lo; + if ((ctx->lo = (saved_lo + size) & 0x1fffffff) < saved_lo) + ctx->hi++; + ctx->hi += size >> 29; + + used = saved_lo & 0x3f; + + if (used) + { + available = 64 - used; + + if (size < available) + { + memcpy(&ctx->buffer[used], data, size); + return; + } + + memcpy(&ctx->buffer[used], data, available); + data = (const unsigned char*)data + available; + size -= available; + body(ctx, ctx->buffer, 64); + } + + if (size >= 64) + { + data = body(ctx, data, size & ~(unsigned long)0x3f); + size &= 0x3f; + } + + memcpy(ctx->buffer, data, size); +} + +#define OUT(dst, src) \ + (dst)[0] = (unsigned char)(src); \ + (dst)[1] = (unsigned char)((src) >> 8); \ + (dst)[2] = (unsigned char)((src) >> 16); \ + (dst)[3] = (unsigned char)((src) >> 24); + +void winpr_MD4_Final(unsigned char* result, WINPR_MD4_CTX* ctx) +{ + unsigned long used, available; + + used = ctx->lo & 0x3f; + + ctx->buffer[used++] = 0x80; + + available = 64 - used; + + if (available < 8) + { + memset(&ctx->buffer[used], 0, available); + body(ctx, ctx->buffer, 64); + used = 0; + available = 64; + } + + memset(&ctx->buffer[used], 0, available - 8); + + ctx->lo <<= 3; + OUT(&ctx->buffer[56], ctx->lo) + OUT(&ctx->buffer[60], ctx->hi) + + body(ctx, ctx->buffer, 64); + + OUT(&result[0], ctx->a) + OUT(&result[4], ctx->b) + OUT(&result[8], ctx->c) + OUT(&result[12], ctx->d) + + memset(ctx, 0, sizeof(*ctx)); +} diff --git a/winpr/libwinpr/crypto/md4.h b/winpr/libwinpr/crypto/md4.h new file mode 100644 index 000000000000..1ea008eccbef --- /dev/null +++ b/winpr/libwinpr/crypto/md4.h @@ -0,0 +1,46 @@ +/* + * This is an OpenSSL-compatible implementation of the RSA Data Security, Inc. + * MD4 Message-Digest Algorithm (RFC 1320). + * + * Homepage: + * http://openwall.info/wiki/people/solar/software/public-domain-source-code/md4 + * + * Author: + * Alexander Peslyak, better known as Solar Designer + * + * This software was written by Alexander Peslyak in 2001. No copyright is + * claimed, and the software is hereby placed in the public domain. + * In case this attempt to disclaim copyright and place the software in the + * public domain is deemed null and void, then the software is + * Copyright (c) 2001 Alexander Peslyak and it is hereby released to the + * general public under the following terms: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + * There's ABSOLUTELY NO WARRANTY, express or implied. + * + * See md4.c for more information. + */ + +#if !defined(WINPR_MD4_H) +#define WINPR_MD4_H + +#include + +/* Any 32-bit or wider unsigned integer data type will do */ +typedef UINT32 winpr_MD4_u32plus; + +typedef struct +{ + winpr_MD4_u32plus lo, hi; + winpr_MD4_u32plus a, b, c, d; + unsigned char buffer[64]; + winpr_MD4_u32plus block[16]; +} WINPR_MD4_CTX; + +extern void winpr_MD4_Init(WINPR_MD4_CTX* ctx); +extern void winpr_MD4_Update(WINPR_MD4_CTX* ctx, const void* data, unsigned long size); +extern void winpr_MD4_Final(unsigned char* result, WINPR_MD4_CTX* ctx); + +#endif From 276690a1878c4ce7b63661835a3f6da26384a31c Mon Sep 17 00:00:00 2001 From: akallabeth Date: Tue, 18 Oct 2022 13:52:00 +0200 Subject: [PATCH 276/496] Added replacement MD5 implementation (cherry picked from commit e6bb4fa29ae4e3dbc18fac478b1b526c0ddbd1fd) --- config.h.in | 1 + winpr/CMakeLists.txt | 1 + winpr/libwinpr/crypto/CMakeLists.txt | 4 + winpr/libwinpr/crypto/hash.c | 24 +++ winpr/libwinpr/crypto/md5.c | 287 +++++++++++++++++++++++++++ winpr/libwinpr/crypto/md5.h | 48 +++++ 6 files changed, 365 insertions(+) create mode 100644 winpr/libwinpr/crypto/md5.c create mode 100644 winpr/libwinpr/crypto/md5.h diff --git a/config.h.in b/config.h.in index 964124a4ee45..650d5adcba31 100644 --- a/config.h.in +++ b/config.h.in @@ -184,5 +184,6 @@ #cmakedefine WITH_PROXY_MODULES #cmakedefine WITH_INTERNAL_MD4 +#cmakedefine WITH_INTERNAL_MD5 #endif /* FREERDP_CONFIG_H */ diff --git a/winpr/CMakeLists.txt b/winpr/CMakeLists.txt index 00cd50203f5b..f168f997dd61 100644 --- a/winpr/CMakeLists.txt +++ b/winpr/CMakeLists.txt @@ -83,6 +83,7 @@ else() endif() option(WITH_INTERNAL_MD4 "Use compiled in md4 hash functions instead of OpenSSL/MBedTLS" OFF) +option(WITH_INTERNAL_MD5 "Use compiled in md5 hash functions instead of OpenSSL/MBedTLS" OFF) if(NOT IOS) check_include_files(stdbool.h WINPR_HAVE_STDBOOL_H) check_include_files(stdint.h WINPR_HAVE_STDINT_H) diff --git a/winpr/libwinpr/crypto/CMakeLists.txt b/winpr/libwinpr/crypto/CMakeLists.txt index a836321203a6..0d686042c675 100644 --- a/winpr/libwinpr/crypto/CMakeLists.txt +++ b/winpr/libwinpr/crypto/CMakeLists.txt @@ -27,6 +27,10 @@ if (WITH_INTERNAL_MD4) list(APPEND SRCS md4.c md4.h) endif() +if (WITH_INTERNAL_MD5) + list(APPEND SRCS md5.c md5.h) +endif() + winpr_module_add( ${SRCS} ) diff --git a/winpr/libwinpr/crypto/hash.c b/winpr/libwinpr/crypto/hash.c index 6435e5367cc0..fed40e91e708 100644 --- a/winpr/libwinpr/crypto/hash.c +++ b/winpr/libwinpr/crypto/hash.c @@ -43,6 +43,10 @@ #include "md4.h" #endif +#if defined(WITH_INTERNAL_MD5) +#include "md5.h" +#endif + /** * HMAC */ @@ -343,6 +347,9 @@ struct _winpr_digest_ctx_private_st #if defined(WITH_INTERNAL_MD4) WINPR_MD4_CTX md4; #endif +#if defined(WITH_INTERNAL_MD5) + WINPR_MD5_CTX md5; +#endif #if defined(WITH_OPENSSL) EVP_MD_CTX* mdctx; #endif @@ -456,6 +463,11 @@ BOOL winpr_Digest_Init(WINPR_DIGEST_CTX* ctx, WINPR_MD_TYPE md) case WINPR_MD_MD4: winpr_MD4_Init(&ctx->md4); return TRUE; +#endif +#if defined(WITH_INTERNAL_MD5) + case WINPR_MD_MD5: + winpr_MD5_Init(&ctx->md5); + return TRUE; #endif default: break; @@ -479,6 +491,11 @@ BOOL winpr_Digest_Update(WINPR_DIGEST_CTX* ctx, const BYTE* input, size_t ilen) case WINPR_MD_MD4: winpr_MD4_Update(&ctx->md4, input, ilen); return TRUE; +#endif +#if defined(WITH_INTERNAL_MD5) + case WINPR_MD_MD5: + winpr_MD5_Update(&ctx->md5, input, ilen); + return TRUE; #endif default: break; @@ -513,6 +530,13 @@ BOOL winpr_Digest_Final(WINPR_DIGEST_CTX* ctx, BYTE* output, size_t olen) winpr_MD4_Final(output, &ctx->md4); return TRUE; #endif +#if defined(WITH_INTERNAL_MD5) + case WINPR_MD_MD5: + if (olen < WINPR_MD5_DIGEST_LENGTH) + return FALSE; + winpr_MD5_Final(output, &ctx->md5); + return TRUE; +#endif default: break; diff --git a/winpr/libwinpr/crypto/md5.c b/winpr/libwinpr/crypto/md5.c new file mode 100644 index 000000000000..96e8282a32c0 --- /dev/null +++ b/winpr/libwinpr/crypto/md5.c @@ -0,0 +1,287 @@ +/* + * This is an OpenSSL-compatible implementation of the RSA Data Security, Inc. + * MD5 Message-Digest Algorithm (RFC 1321). + * + * Homepage: + * http://openwall.info/wiki/people/solar/software/public-domain-source-code/md5 + * + * Author: + * Alexander Peslyak, better known as Solar Designer + * + * This software was written by Alexander Peslyak in 2001. No copyright is + * claimed, and the software is hereby placed in the public domain. + * In case this attempt to disclaim copyright and place the software in the + * public domain is deemed null and void, then the software is + * Copyright (c) 2001 Alexander Peslyak and it is hereby released to the + * general public under the following terms: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + * There's ABSOLUTELY NO WARRANTY, express or implied. + * + * (This is a heavily cut-down "BSD license".) + * + * This differs from Colin Plumb's older public domain implementation in that + * no exactly 32-bit integer data type is required (any 32-bit or wider + * unsigned integer data type will do), there's no compile-time endianness + * configuration, and the function prototypes match OpenSSL's. No code from + * Colin Plumb's implementation has been reused; this comment merely compares + * the properties of the two independent implementations. + * + * The primary goals of this implementation are portability and ease of use. + * It is meant to be fast, but not as fast as possible. Some known + * optimizations are not included to reduce source code size and avoid + * compile-time configuration. + */ + +#include + +#include "md5.h" + +/* + * The basic MD5 functions. + * + * F and G are optimized compared to their RFC 1321 definitions for + * architectures that lack an AND-NOT instruction, just like in Colin Plumb's + * implementation. + */ +#define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z)))) +#define G(x, y, z) ((y) ^ ((z) & ((x) ^ (y)))) +#define H(x, y, z) (((x) ^ (y)) ^ (z)) +#define H2(x, y, z) ((x) ^ ((y) ^ (z))) +#define I(x, y, z) ((y) ^ ((x) | ~(z))) + +/* + * The MD5 transformation for all four rounds. + */ +#define STEP(f, a, b, c, d, x, t, s) \ + (a) += f((b), (c), (d)) + (x) + (t); \ + (a) = (((a) << (s)) | (((a)&0xffffffff) >> (32 - (s)))); \ + (a) += (b); + +/* + * SET reads 4 input bytes in little-endian byte order and stores them in a + * properly aligned word in host byte order. + * + * The check for little-endian architectures that tolerate unaligned memory + * accesses is just an optimization. Nothing will break if it fails to detect + * a suitable architecture. + * + * Unfortunately, this optimization may be a C strict aliasing rules violation + * if the caller's data buffer has effective type that cannot be aliased by + * MD5_u32plus. In practice, this problem may occur if these MD5 routines are + * inlined into a calling function, or with future and dangerously advanced + * link-time optimizations. For the time being, keeping these MD5 routines in + * their own translation unit avoids the problem. + */ +#if defined(__i386__) || defined(__x86_64__) || defined(__vax__) +#define SET(n) (*(winpr_MD5_u32plus*)&ptr[(n)*4]) +#define GET(n) SET(n) +#else +#define SET(n) \ + (ctx->block[(n)] = (winpr_MD5_u32plus)ptr[(n)*4] | ((winpr_MD5_u32plus)ptr[(n)*4 + 1] << 8) | \ + ((winpr_MD5_u32plus)ptr[(n)*4 + 2] << 16) | \ + ((winpr_MD5_u32plus)ptr[(n)*4 + 3] << 24)) +#define GET(n) (ctx->block[(n)]) +#endif + +/* + * This processes one or more 64-byte data blocks, but does NOT update the bit + * counters. There are no alignment requirements. + */ +static const void* body(WINPR_MD5_CTX* ctx, const void* data, unsigned long size) +{ + const unsigned char* ptr; + winpr_MD5_u32plus a, b, c, d; + winpr_MD5_u32plus saved_a, saved_b, saved_c, saved_d; + + ptr = (const unsigned char*)data; + + a = ctx->a; + b = ctx->b; + c = ctx->c; + d = ctx->d; + + do + { + saved_a = a; + saved_b = b; + saved_c = c; + saved_d = d; + + /* Round 1 */ + STEP(F, a, b, c, d, SET(0), 0xd76aa478, 7) + STEP(F, d, a, b, c, SET(1), 0xe8c7b756, 12) + STEP(F, c, d, a, b, SET(2), 0x242070db, 17) + STEP(F, b, c, d, a, SET(3), 0xc1bdceee, 22) + STEP(F, a, b, c, d, SET(4), 0xf57c0faf, 7) + STEP(F, d, a, b, c, SET(5), 0x4787c62a, 12) + STEP(F, c, d, a, b, SET(6), 0xa8304613, 17) + STEP(F, b, c, d, a, SET(7), 0xfd469501, 22) + STEP(F, a, b, c, d, SET(8), 0x698098d8, 7) + STEP(F, d, a, b, c, SET(9), 0x8b44f7af, 12) + STEP(F, c, d, a, b, SET(10), 0xffff5bb1, 17) + STEP(F, b, c, d, a, SET(11), 0x895cd7be, 22) + STEP(F, a, b, c, d, SET(12), 0x6b901122, 7) + STEP(F, d, a, b, c, SET(13), 0xfd987193, 12) + STEP(F, c, d, a, b, SET(14), 0xa679438e, 17) + STEP(F, b, c, d, a, SET(15), 0x49b40821, 22) + + /* Round 2 */ + STEP(G, a, b, c, d, GET(1), 0xf61e2562, 5) + STEP(G, d, a, b, c, GET(6), 0xc040b340, 9) + STEP(G, c, d, a, b, GET(11), 0x265e5a51, 14) + STEP(G, b, c, d, a, GET(0), 0xe9b6c7aa, 20) + STEP(G, a, b, c, d, GET(5), 0xd62f105d, 5) + STEP(G, d, a, b, c, GET(10), 0x02441453, 9) + STEP(G, c, d, a, b, GET(15), 0xd8a1e681, 14) + STEP(G, b, c, d, a, GET(4), 0xe7d3fbc8, 20) + STEP(G, a, b, c, d, GET(9), 0x21e1cde6, 5) + STEP(G, d, a, b, c, GET(14), 0xc33707d6, 9) + STEP(G, c, d, a, b, GET(3), 0xf4d50d87, 14) + STEP(G, b, c, d, a, GET(8), 0x455a14ed, 20) + STEP(G, a, b, c, d, GET(13), 0xa9e3e905, 5) + STEP(G, d, a, b, c, GET(2), 0xfcefa3f8, 9) + STEP(G, c, d, a, b, GET(7), 0x676f02d9, 14) + STEP(G, b, c, d, a, GET(12), 0x8d2a4c8a, 20) + + /* Round 3 */ + STEP(H, a, b, c, d, GET(5), 0xfffa3942, 4) + STEP(H2, d, a, b, c, GET(8), 0x8771f681, 11) + STEP(H, c, d, a, b, GET(11), 0x6d9d6122, 16) + STEP(H2, b, c, d, a, GET(14), 0xfde5380c, 23) + STEP(H, a, b, c, d, GET(1), 0xa4beea44, 4) + STEP(H2, d, a, b, c, GET(4), 0x4bdecfa9, 11) + STEP(H, c, d, a, b, GET(7), 0xf6bb4b60, 16) + STEP(H2, b, c, d, a, GET(10), 0xbebfbc70, 23) + STEP(H, a, b, c, d, GET(13), 0x289b7ec6, 4) + STEP(H2, d, a, b, c, GET(0), 0xeaa127fa, 11) + STEP(H, c, d, a, b, GET(3), 0xd4ef3085, 16) + STEP(H2, b, c, d, a, GET(6), 0x04881d05, 23) + STEP(H, a, b, c, d, GET(9), 0xd9d4d039, 4) + STEP(H2, d, a, b, c, GET(12), 0xe6db99e5, 11) + STEP(H, c, d, a, b, GET(15), 0x1fa27cf8, 16) + STEP(H2, b, c, d, a, GET(2), 0xc4ac5665, 23) + + /* Round 4 */ + STEP(I, a, b, c, d, GET(0), 0xf4292244, 6) + STEP(I, d, a, b, c, GET(7), 0x432aff97, 10) + STEP(I, c, d, a, b, GET(14), 0xab9423a7, 15) + STEP(I, b, c, d, a, GET(5), 0xfc93a039, 21) + STEP(I, a, b, c, d, GET(12), 0x655b59c3, 6) + STEP(I, d, a, b, c, GET(3), 0x8f0ccc92, 10) + STEP(I, c, d, a, b, GET(10), 0xffeff47d, 15) + STEP(I, b, c, d, a, GET(1), 0x85845dd1, 21) + STEP(I, a, b, c, d, GET(8), 0x6fa87e4f, 6) + STEP(I, d, a, b, c, GET(15), 0xfe2ce6e0, 10) + STEP(I, c, d, a, b, GET(6), 0xa3014314, 15) + STEP(I, b, c, d, a, GET(13), 0x4e0811a1, 21) + STEP(I, a, b, c, d, GET(4), 0xf7537e82, 6) + STEP(I, d, a, b, c, GET(11), 0xbd3af235, 10) + STEP(I, c, d, a, b, GET(2), 0x2ad7d2bb, 15) + STEP(I, b, c, d, a, GET(9), 0xeb86d391, 21) + + a += saved_a; + b += saved_b; + c += saved_c; + d += saved_d; + + ptr += 64; + } while (size -= 64); + + ctx->a = a; + ctx->b = b; + ctx->c = c; + ctx->d = d; + + return ptr; +} + +void winpr_MD5_Init(WINPR_MD5_CTX* ctx) +{ + ctx->a = 0x67452301; + ctx->b = 0xefcdab89; + ctx->c = 0x98badcfe; + ctx->d = 0x10325476; + + ctx->lo = 0; + ctx->hi = 0; +} + +void winpr_MD5_Update(WINPR_MD5_CTX* ctx, const void* data, unsigned long size) +{ + winpr_MD5_u32plus saved_lo; + unsigned long used, available; + + saved_lo = ctx->lo; + if ((ctx->lo = (saved_lo + size) & 0x1fffffff) < saved_lo) + ctx->hi++; + ctx->hi += size >> 29; + + used = saved_lo & 0x3f; + + if (used) + { + available = 64 - used; + + if (size < available) + { + memcpy(&ctx->buffer[used], data, size); + return; + } + + memcpy(&ctx->buffer[used], data, available); + data = (const unsigned char*)data + available; + size -= available; + body(ctx, ctx->buffer, 64); + } + + if (size >= 64) + { + data = body(ctx, data, size & ~(unsigned long)0x3f); + size &= 0x3f; + } + + memcpy(ctx->buffer, data, size); +} + +#define OUT(dst, src) \ + (dst)[0] = (unsigned char)(src); \ + (dst)[1] = (unsigned char)((src) >> 8); \ + (dst)[2] = (unsigned char)((src) >> 16); \ + (dst)[3] = (unsigned char)((src) >> 24); + +void winpr_MD5_Final(unsigned char* result, WINPR_MD5_CTX* ctx) +{ + unsigned long used, available; + + used = ctx->lo & 0x3f; + + ctx->buffer[used++] = 0x80; + + available = 64 - used; + + if (available < 8) + { + memset(&ctx->buffer[used], 0, available); + body(ctx, ctx->buffer, 64); + used = 0; + available = 64; + } + + memset(&ctx->buffer[used], 0, available - 8); + + ctx->lo <<= 3; + OUT(&ctx->buffer[56], ctx->lo) + OUT(&ctx->buffer[60], ctx->hi) + + body(ctx, ctx->buffer, 64); + + OUT(&result[0], ctx->a) + OUT(&result[4], ctx->b) + OUT(&result[8], ctx->c) + OUT(&result[12], ctx->d) + + memset(ctx, 0, sizeof(*ctx)); +} diff --git a/winpr/libwinpr/crypto/md5.h b/winpr/libwinpr/crypto/md5.h new file mode 100644 index 000000000000..2056b9a806fc --- /dev/null +++ b/winpr/libwinpr/crypto/md5.h @@ -0,0 +1,48 @@ + + +/* + * This is an OpenSSL-compatible implementation of the RSA Data Security, Inc. + * MD5 Message-Digest Algorithm (RFC 1321). + * + * Homepage: + * http://openwall.info/wiki/people/solar/software/public-domain-source-code/md5 + * + * Author: + * Alexander Peslyak, better known as Solar Designer + * + * This software was written by Alexander Peslyak in 2001. No copyright is + * claimed, and the software is hereby placed in the public domain. + * In case this attempt to disclaim copyright and place the software in the + * public domain is deemed null and void, then the software is + * Copyright (c) 2001 Alexander Peslyak and it is hereby released to the + * general public under the following terms: + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted. + * + * There's ABSOLUTELY NO WARRANTY, express or implied. + * + * See md5.c for more information. + */ + +#if !defined(WINPR_MD5_H) +#define WINPR_MD5_H + +#include + +/* Any 32-bit or wider unsigned integer data type will do */ +typedef UINT32 winpr_MD5_u32plus; + +typedef struct +{ + winpr_MD5_u32plus lo, hi; + winpr_MD5_u32plus a, b, c, d; + unsigned char buffer[64]; + winpr_MD5_u32plus block[16]; +} WINPR_MD5_CTX; + +extern void winpr_MD5_Init(WINPR_MD5_CTX* ctx); +extern void winpr_MD5_Update(WINPR_MD5_CTX* ctx, const void* data, unsigned long size); +extern void winpr_MD5_Final(unsigned char* result, WINPR_MD5_CTX* ctx); + +#endif From bda64c56ae72042edca763c205e2d26f4cf917c7 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Tue, 18 Oct 2022 14:11:15 +0200 Subject: [PATCH 277/496] Added replacement HMAC-MD5 implementation (cherry picked from commit cd7dcf71bf086d4a37bf69181dc009dd4c818074) --- winpr/libwinpr/crypto/CMakeLists.txt | 1 + winpr/libwinpr/crypto/hash.c | 112 +++++++++++++++++++-------- winpr/libwinpr/crypto/hmac_md5.c | 54 +++++++++++++ winpr/libwinpr/crypto/hmac_md5.h | 19 +++++ 4 files changed, 154 insertions(+), 32 deletions(-) create mode 100644 winpr/libwinpr/crypto/hmac_md5.c create mode 100644 winpr/libwinpr/crypto/hmac_md5.h diff --git a/winpr/libwinpr/crypto/CMakeLists.txt b/winpr/libwinpr/crypto/CMakeLists.txt index 0d686042c675..92077ec872d7 100644 --- a/winpr/libwinpr/crypto/CMakeLists.txt +++ b/winpr/libwinpr/crypto/CMakeLists.txt @@ -29,6 +29,7 @@ endif() if (WITH_INTERNAL_MD5) list(APPEND SRCS md5.c md5.h) + list(APPEND SRCS hmac_md5.c hmac_md5.h) endif() winpr_module_add( diff --git a/winpr/libwinpr/crypto/hash.c b/winpr/libwinpr/crypto/hash.c index fed40e91e708..eb20cdfee2ea 100644 --- a/winpr/libwinpr/crypto/hash.c +++ b/winpr/libwinpr/crypto/hash.c @@ -45,6 +45,7 @@ #if defined(WITH_INTERNAL_MD5) #include "md5.h" +#include "hmac_md5.h" #endif /** @@ -154,41 +155,67 @@ const char* winpr_md_type_to_string(WINPR_MD_TYPE md) return NULL; } +struct _winpr_hmac_ctx_private_st +{ + WINPR_MD_TYPE md; + +#if defined(WITH_INTERNAL_MD5) + WINPR_HMAC_MD5_CTX hmac_md5; +#endif +#if defined(WITH_OPENSSL) + HMAC_CTX* hmac; +#endif +#if defined(WITH_MBEDTLS) + mbedtls_md_context_t hmac; +#endif +}; + WINPR_HMAC_CTX* winpr_HMAC_New(void) { - WINPR_HMAC_CTX* ctx = NULL; + WINPR_HMAC_CTX* ctx = calloc(1, sizeof(WINPR_HMAC_CTX)); + if (!ctx) + return NULL; #if defined(WITH_OPENSSL) - HMAC_CTX* hmac = NULL; #if (OPENSSL_VERSION_NUMBER < 0x10100000L) || \ (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x2070000fL) - if (!(hmac = (HMAC_CTX*)calloc(1, sizeof(HMAC_CTX)))) - return NULL; + if (!(ctx->hmac = (HMAC_CTX*)calloc(1, sizeof(HMAC_CTX)))) + goto fail; HMAC_CTX_init(hmac); #else - if (!(hmac = HMAC_CTX_new())) - return NULL; + if (!(ctx->hmac = HMAC_CTX_new())) + goto fail; #endif - ctx = (WINPR_HMAC_CTX*)hmac; #elif defined(WITH_MBEDTLS) - mbedtls_md_context_t* hmac; - - if (!(hmac = (mbedtls_md_context_t*)calloc(1, sizeof(mbedtls_md_context_t)))) - return NULL; - - mbedtls_md_init(hmac); - ctx = (WINPR_HMAC_CTX*)hmac; + mbedtls_md_init(&ctx->hmac); #endif return ctx; + +fail: + winpr_HMAC_Free(ctx); } BOOL winpr_HMAC_Init(WINPR_HMAC_CTX* ctx, WINPR_MD_TYPE md, const BYTE* key, size_t keylen) { + WINPR_ASSERT(ctx); + + ctx->md = md; + switch (ctx->md) + { +#if defined(WITH_INTERNAL_MD5) + case WINPR_MD_MD5: + hmac_md5_init(&ctx->hmac_md5, key, keylen); + return TRUE; +#endif + default: + break; + } + #if defined(WITH_OPENSSL) - HMAC_CTX* hmac = (HMAC_CTX*)ctx; + HMAC_CTX* hmac = ctx->hmac; const EVP_MD* evp = winpr_openssl_get_evp_md(md); if (!evp || !hmac) @@ -205,7 +232,7 @@ BOOL winpr_HMAC_Init(WINPR_HMAC_CTX* ctx, WINPR_MD_TYPE md, const BYTE* key, siz #endif #elif defined(WITH_MBEDTLS) - mbedtls_md_context_t* hmac = (mbedtls_md_context_t*)ctx; + mbedtls_md_context_t* hmac = &ctx->hmac; mbedtls_md_type_t md_type = winpr_mbedtls_get_md_type(md); const mbedtls_md_info_t* md_info = mbedtls_md_info_from_type(md_type); @@ -229,8 +256,21 @@ BOOL winpr_HMAC_Init(WINPR_HMAC_CTX* ctx, WINPR_MD_TYPE md, const BYTE* key, siz BOOL winpr_HMAC_Update(WINPR_HMAC_CTX* ctx, const BYTE* input, size_t ilen) { + WINPR_ASSERT(ctx); + + switch (ctx->md) + { +#if defined(WITH_INTERNAL_MD5) + case WINPR_MD_MD5: + hmac_md5_update(&ctx->hmac_md5, input, ilen); + return TRUE; +#endif + default: + break; + } + #if defined(WITH_OPENSSL) - HMAC_CTX* hmac = (HMAC_CTX*)ctx; + HMAC_CTX* hmac = ctx->hmac; #if (OPENSSL_VERSION_NUMBER < 0x10000000L) || \ (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x2070000fL) HMAC_Update(hmac, input, ilen); /* no return value on OpenSSL 0.9.x */ @@ -242,7 +282,7 @@ BOOL winpr_HMAC_Update(WINPR_HMAC_CTX* ctx, const BYTE* input, size_t ilen) #endif #elif defined(WITH_MBEDTLS) - mbedtls_md_context_t* mdctx = (mbedtls_md_context_t*)ctx; + mbedtls_md_context_t* mdctx = &ctx->hmac; if (mbedtls_md_hmac_update(mdctx, input, ilen) == 0) return TRUE; @@ -253,17 +293,23 @@ BOOL winpr_HMAC_Update(WINPR_HMAC_CTX* ctx, const BYTE* input, size_t ilen) BOOL winpr_HMAC_Final(WINPR_HMAC_CTX* ctx, BYTE* output, size_t olen) { -#if defined(WITH_OPENSSL) - HMAC_CTX* hmac; -#elif defined(WITH_MBEDTLS) - mbedtls_md_context_t* mdctx; -#endif + WINPR_ASSERT(ctx); - if (!ctx) - return FALSE; + switch (ctx->md) + { +#if defined(WITH_INTERNAL_MD5) + case WINPR_MD_MD5: + if (olen < WINPR_MD5_DIGEST_LENGTH) + return FALSE; + hmac_md5_finalize(&ctx->hmac_md5, output); + return TRUE; +#endif + default: + break; + } #if defined(WITH_OPENSSL) - hmac = (HMAC_CTX*)ctx; + HMAC_CTX* hmac = ctx->hmac; #if (OPENSSL_VERSION_NUMBER < 0x10000000L) || \ (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x2070000fL) HMAC_Final(hmac, output, NULL); /* no return value on OpenSSL 0.9.x */ @@ -275,7 +321,7 @@ BOOL winpr_HMAC_Final(WINPR_HMAC_CTX* ctx, BYTE* output, size_t olen) #endif #elif defined(WITH_MBEDTLS) - mdctx = (mbedtls_md_context_t*)ctx; + mbedtls_md_context_t* mdctx = &ctx->hmac; if (mbedtls_md_hmac_finish(mdctx, output) == 0) return TRUE; @@ -286,8 +332,11 @@ BOOL winpr_HMAC_Final(WINPR_HMAC_CTX* ctx, BYTE* output, size_t olen) void winpr_HMAC_Free(WINPR_HMAC_CTX* ctx) { + if (!ctx) + return; + #if defined(WITH_OPENSSL) - HMAC_CTX* hmac = (HMAC_CTX*)ctx; + HMAC_CTX* hmac = ctx->hmac; if (hmac) { @@ -301,15 +350,14 @@ void winpr_HMAC_Free(WINPR_HMAC_CTX* ctx) } #elif defined(WITH_MBEDTLS) - mbedtls_md_context_t* hmac = (mbedtls_md_context_t*)ctx; + mbedtls_md_context_t* hmac = &ctx->hmac; if (hmac) - { mbedtls_md_free(hmac); - free(hmac); - } #endif + + free(ctx); } BOOL winpr_HMAC(WINPR_MD_TYPE md, const BYTE* key, size_t keylen, const BYTE* input, size_t ilen, diff --git a/winpr/libwinpr/crypto/hmac_md5.c b/winpr/libwinpr/crypto/hmac_md5.c new file mode 100644 index 000000000000..4bc9b9305c41 --- /dev/null +++ b/winpr/libwinpr/crypto/hmac_md5.c @@ -0,0 +1,54 @@ +#include +#include "hmac_md5.h" +#include "md5.h" + +void hmac_md5_init(WINPR_HMAC_MD5_CTX* ctx, unsigned char* key, size_t key_len) +{ + const WINPR_HMAC_MD5_CTX empty = { 0 }; + unsigned char k_ipad[KEY_IOPAD_SIZE] = { 0 }; + unsigned char k_opad[KEY_IOPAD_SIZE] = { 0 }; + + assert(ctx); + *ctx = empty; + + if (key_len <= KEY_IOPAD_SIZE) + { + memcpy(k_ipad, key, key_len); + memcpy(k_opad, key, key_len); + } + else + { + WINPR_MD5_CTX lctx = { 0 }; + + winpr_MD5_Init(&lctx); + winpr_MD5_Update(&lctx, key, key_len); + winpr_MD5_Final(k_ipad, &lctx); + memcpy(k_opad, k_ipad, KEY_IOPAD_SIZE); + } + for (size_t i = 0; i < KEY_IOPAD_SIZE; i++) + { + k_ipad[i] ^= 0x36; + k_opad[i] ^= 0x5c; + } + + winpr_MD5_Init(&ctx->icontext); + winpr_MD5_Update(&ctx->icontext, k_ipad, KEY_IOPAD_SIZE); + + winpr_MD5_Init(&ctx->ocontext); + winpr_MD5_Update(&ctx->ocontext, k_opad, KEY_IOPAD_SIZE); +} + +void hmac_md5_update(WINPR_HMAC_MD5_CTX* ctx, unsigned char* text, size_t text_len) +{ + assert(ctx); + winpr_MD5_Update(&ctx->icontext, text, text_len); +} + +void hmac_md5_finalize(WINPR_HMAC_MD5_CTX* ctx, unsigned char* hmac) +{ + assert(ctx); + winpr_MD5_Final(hmac, &ctx->icontext); + + winpr_MD5_Update(&ctx->ocontext, hmac, 16); + winpr_MD5_Final(hmac, &ctx->ocontext); +} diff --git a/winpr/libwinpr/crypto/hmac_md5.h b/winpr/libwinpr/crypto/hmac_md5.h new file mode 100644 index 000000000000..a1ea6a045ce1 --- /dev/null +++ b/winpr/libwinpr/crypto/hmac_md5.h @@ -0,0 +1,19 @@ +#ifndef WINPR_HMAC_MD5 +#define WINPR_HMAC_MD5 + +#include + +#include "md5.h" + +#define KEY_IOPAD_SIZE 64 +typedef struct +{ + WINPR_MD5_CTX icontext; + WINPR_MD5_CTX ocontext; +} WINPR_HMAC_MD5_CTX; + +void hmac_md5_init(WINPR_HMAC_MD5_CTX* ctx, unsigned char* key, size_t key_len); +void hmac_md5_update(WINPR_HMAC_MD5_CTX* ctx, unsigned char* text, size_t text_len); +void hmac_md5_finalize(WINPR_HMAC_MD5_CTX* ctx, unsigned char* hmac); + +#endif From a4f2d1a4aaef576575fb5fc364a015d8d2fabd3f Mon Sep 17 00:00:00 2001 From: akallabeth Date: Tue, 18 Oct 2022 13:31:46 +0200 Subject: [PATCH 278/496] Updated changelog --- ChangeLog | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/ChangeLog b/ChangeLog index b878eacc8329..528e90e24d77 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,18 @@ +# 20xx-xx-xx Version 2.8.x + +Notewhorth changes: +* Backported #8324: Internal replacements for md4, md5 and hmac-md5 + For the time being the RDP protocol requires these outdated hash + algorithms. So any distribution that wants to ship a working + FreeRDP should check the options WITH_INTERNAL_MD4 (and depending + on OpenSSL deprecation status WITH_INTERNAL_MD5) + +Fixed issues: + +For a complete and detailed change log since the last release run: +git log 2.8.1..2.8.x + + # 2022-10-12 Version 2.8.1 Notewhorth changes: From 711176ccacb4fe9643ffc77931baab91c855a2e5 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Wed, 19 Oct 2022 08:38:57 +0200 Subject: [PATCH 279/496] Improve OpenSSL provider loading * Added log messages for failure to load a provider * Add code to clean up loaded providers on shutdown (cherry picked from commit 4db4b4cb829239acb33e87b3e5f1b66a5acd6240) --- winpr/libwinpr/utils/ssl.c | 29 ++++++++++++++++++++++++++--- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/winpr/libwinpr/utils/ssl.c b/winpr/libwinpr/utils/ssl.c index 301f9401cece..1924909d0cb8 100644 --- a/winpr/libwinpr/utils/ssl.c +++ b/winpr/libwinpr/utils/ssl.c @@ -42,6 +42,12 @@ static BOOL g_winpr_openssl_initialized_by_winpr = FALSE; +#if defined(OPENSSL_VERSION_MAJOR) && (OPENSSL_VERSION_MAJOR >= 3) +static OSSL_PROVIDER* s_winpr_openssl_provider_fips = NULL; +static OSSL_PROVIDER* s_winpr_openssl_provider_legacy = NULL; +static OSSL_PROVIDER* s_winpr_openssl_provider_default = NULL; +#endif + /** * Note from OpenSSL 1.1.0 "CHANGES": * OpenSSL now uses a new threading API. It is no longer necessary to @@ -249,7 +255,11 @@ static BOOL winpr_enable_fips(DWORD flags) WLog_DBG(TAG, "Ensuring openssl fips mode is enabled"); #if defined(OPENSSL_VERSION_MAJOR) && (OPENSSL_VERSION_MAJOR >= 3) - OSSL_PROVIDER_load(NULL, "fips"); + s_winpr_openssl_provider_fips = OSSL_PROVIDER_load(NULL, "fips"); + if (s_winpr_openssl_provider_fips == NULL) + { + WLog_WARN(TAG, "OpenSSL FIPS provider failled to load"); + } if (!EVP_default_properties_is_fips_enabled(NULL)) #else if (FIPS_mode() != 1) @@ -313,8 +323,16 @@ static BOOL CALLBACK _winpr_openssl_initialize(PINIT_ONCE once, PVOID param, PVO #if defined(OPENSSL_VERSION_MAJOR) && (OPENSSL_VERSION_MAJOR >= 3) /* The legacy provider is needed for MD4. */ - OSSL_PROVIDER_load(NULL, "legacy"); - OSSL_PROVIDER_load(NULL, "default"); + s_winpr_openssl_provider_legacy = OSSL_PROVIDER_load(NULL, "legacy"); + if (s_winpr_openssl_provider_legacy == NULL) + { + WLog_WARN(TAG, "OpenSSL LEGACY provider failed to load, no md4 support available!"); + } + s_winpr_openssl_provider_default = OSSL_PROVIDER_load(NULL, "default"); + if (s_winpr_openssl_provider_default == NULL) + { + WLog_WARN(TAG, "OpenSSL DEFAULT provider failed to load"); + } #endif g_winpr_openssl_initialized_by_winpr = TRUE; @@ -368,6 +386,11 @@ BOOL winpr_CleanupSSL(DWORD flags) #endif } +#endif +#if defined(OPENSSL_VERSION_MAJOR) && (OPENSSL_VERSION_MAJOR >= 3) + OSSL_PROVIDER_unload(s_winpr_openssl_provider_fips); + OSSL_PROVIDER_unload(s_winpr_openssl_provider_legacy); + OSSL_PROVIDER_unload(s_winpr_openssl_provider_default); #endif return TRUE; } From 525a7c8d160317caae6228962c85055f5e045d18 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Wed, 19 Oct 2022 09:47:52 +0200 Subject: [PATCH 280/496] Added missing include (cherry picked from commit d48cd82ccd4658c251727fc829ec23333eb28f82) --- winpr/include/winpr/ssl.h | 1 + winpr/include/winpr/wlog.h | 1 + 2 files changed, 2 insertions(+) diff --git a/winpr/include/winpr/ssl.h b/winpr/include/winpr/ssl.h index 942a062ed8bc..ff50097a00ec 100644 --- a/winpr/include/winpr/ssl.h +++ b/winpr/include/winpr/ssl.h @@ -22,6 +22,7 @@ #define WINPR_SSL_H #include +#include #define WINPR_SSL_INIT_DEFAULT 0x00 #define WINPR_SSL_INIT_ALREADY_INITIALIZED 0x01 diff --git a/winpr/include/winpr/wlog.h b/winpr/include/winpr/wlog.h index 292eac3d64e6..1eedffa8252a 100644 --- a/winpr/include/winpr/wlog.h +++ b/winpr/include/winpr/wlog.h @@ -30,6 +30,7 @@ extern "C" #include #include +#include #include #include From 73c9755743a884f8093068e49bb376c95278a216 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Thu, 20 Oct 2022 15:21:03 +0200 Subject: [PATCH 281/496] Added missing return in winpr_Digest_New (cherry picked from commit 0ea1957da5d574e2be0ad157aac397110377edf8) --- winpr/libwinpr/crypto/hash.c | 1 + 1 file changed, 1 insertion(+) diff --git a/winpr/libwinpr/crypto/hash.c b/winpr/libwinpr/crypto/hash.c index eb20cdfee2ea..3f273efe4882 100644 --- a/winpr/libwinpr/crypto/hash.c +++ b/winpr/libwinpr/crypto/hash.c @@ -434,6 +434,7 @@ WINPR_DIGEST_CTX* winpr_Digest_New(void) fail: winpr_Digest_Free(ctx); + return NULL; } #if defined(WITH_OPENSSL) From fd092b6d701f07d87d705e59475a7f2fe3790e88 Mon Sep 17 00:00:00 2001 From: fifthdegree Date: Sun, 23 Oct 2022 15:03:38 -0400 Subject: [PATCH 282/496] Check for NULL pointer in winpr_Digest_Free (cherry picked from commit a806da90edb10228966fcf244908832e9f103554) --- winpr/libwinpr/crypto/hash.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/winpr/libwinpr/crypto/hash.c b/winpr/libwinpr/crypto/hash.c index 3f273efe4882..79b0848e1838 100644 --- a/winpr/libwinpr/crypto/hash.c +++ b/winpr/libwinpr/crypto/hash.c @@ -609,6 +609,8 @@ BOOL winpr_Digest_Final(WINPR_DIGEST_CTX* ctx, BYTE* output, size_t olen) void winpr_Digest_Free(WINPR_DIGEST_CTX* ctx) { + if (!ctx) + return; #if defined(WITH_OPENSSL) if (ctx->mdctx) { From 7cfd97f5316c3c34b4ee4f4f96fafb12abb38ba8 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Mon, 12 Sep 2022 09:40:34 +0200 Subject: [PATCH 283/496] Added support for audin version 2 (cherry picked from commit 6f62d30bfd23a386dc9597afbed1b100ae4ac0d3) --- channels/audin/client/audin_main.c | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) diff --git a/channels/audin/client/audin_main.c b/channels/audin/client/audin_main.c index 81a6e8fcd9f8..23561b153a83 100644 --- a/channels/audin/client/audin_main.c +++ b/channels/audin/client/audin_main.c @@ -43,13 +43,18 @@ #include "audin_main.h" -#define MSG_SNDIN_VERSION 0x01 -#define MSG_SNDIN_FORMATS 0x02 -#define MSG_SNDIN_OPEN 0x03 -#define MSG_SNDIN_OPEN_REPLY 0x04 -#define MSG_SNDIN_DATA_INCOMING 0x05 -#define MSG_SNDIN_DATA 0x06 -#define MSG_SNDIN_FORMATCHANGE 0x07 +#define SNDIN_VERSION 0x02 + +enum +{ + MSG_SNDIN_VERSION = 0x01, + MSG_SNDIN_FORMATS = 0x02, + MSG_SNDIN_OPEN = 0x03, + MSG_SNDIN_OPEN_REPLY = 0x04, + MSG_SNDIN_DATA_INCOMING = 0x05, + MSG_SNDIN_DATA = 0x06, + MSG_SNDIN_FORMATCHANGE = 0x07 +} MSG_SNDIN_CMD; typedef struct _AUDIN_LISTENER_CALLBACK AUDIN_LISTENER_CALLBACK; struct _AUDIN_LISTENER_CALLBACK @@ -105,6 +110,7 @@ struct _AUDIN_PLUGIN IWTSListener* listener; BOOL initialized; + UINT32 version; }; static BOOL audin_process_addin_args(AUDIN_PLUGIN* audin, ADDIN_ARGV* args); @@ -138,7 +144,7 @@ static UINT audin_channel_write_and_free(AUDIN_CHANNEL_CALLBACK* callback, wStre static UINT audin_process_version(AUDIN_PLUGIN* audin, AUDIN_CHANNEL_CALLBACK* callback, wStream* s) { wStream* out; - const UINT32 ClientVersion = 0x01; + const UINT32 ClientVersion = SNDIN_VERSION; UINT32 ServerVersion; if (Stream_GetRemainingLength(s) < 4) @@ -149,7 +155,7 @@ static UINT audin_process_version(AUDIN_PLUGIN* audin, AUDIN_CHANNEL_CALLBACK* c ServerVersion, ClientVersion); /* Do not answer server packet, we do not support the channel version. */ - if (ServerVersion != ClientVersion) + if (ServerVersion > ClientVersion) { WLog_Print(audin->log, WLOG_WARN, "Incompatible channel version server=%" PRIu32 @@ -157,6 +163,7 @@ static UINT audin_process_version(AUDIN_PLUGIN* audin, AUDIN_CHANNEL_CALLBACK* c ServerVersion, ClientVersion); return CHANNEL_RC_OK; } + audin->version = ServerVersion; out = Stream_New(NULL, 5); From 3adcd2d471cfc7c8f5da5eb9051249bdf7b8bd2b Mon Sep 17 00:00:00 2001 From: akallabeth Date: Mon, 24 Oct 2022 08:37:05 +0200 Subject: [PATCH 284/496] Updated changelog --- ChangeLog | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ChangeLog b/ChangeLog index 528e90e24d77..9e60dc62b487 100644 --- a/ChangeLog +++ b/ChangeLog @@ -8,6 +8,9 @@ Notewhorth changes: on OpenSSL deprecation status WITH_INTERNAL_MD5) Fixed issues: +* Backported #8341: Null checks in winpr_Digest_Free +* Backported #8335: Missing NULL return in winpr_Digest_New +* Backported #8192: Support for audin version 2 microphone channel For a complete and detailed change log since the last release run: git log 2.8.1..2.8.x From b14fe5af7b7371c9fe12019b18382026ce81b861 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Thu, 27 Oct 2022 09:39:33 +0200 Subject: [PATCH 285/496] Fixed compile error for old openssl (cherry picked from commit f3082b3798ea77548d830de8dfd384da9274799d) --- winpr/libwinpr/crypto/hash.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/winpr/libwinpr/crypto/hash.c b/winpr/libwinpr/crypto/hash.c index 79b0848e1838..9e564a16df01 100644 --- a/winpr/libwinpr/crypto/hash.c +++ b/winpr/libwinpr/crypto/hash.c @@ -182,7 +182,7 @@ WINPR_HMAC_CTX* winpr_HMAC_New(void) if (!(ctx->hmac = (HMAC_CTX*)calloc(1, sizeof(HMAC_CTX)))) goto fail; - HMAC_CTX_init(hmac); + HMAC_CTX_init(ctx->hmac); #else if (!(ctx->hmac = HMAC_CTX_new())) @@ -196,6 +196,7 @@ WINPR_HMAC_CTX* winpr_HMAC_New(void) fail: winpr_HMAC_Free(ctx); + return NULL; } BOOL winpr_HMAC_Init(WINPR_HMAC_CTX* ctx, WINPR_MD_TYPE md, const BYTE* key, size_t keylen) From d859574f8c0e921672c698af166de2125cd3885c Mon Sep 17 00:00:00 2001 From: akallabeth Date: Fri, 3 Sep 2021 09:12:23 +0200 Subject: [PATCH 286/496] Expose CONNECTION_STATE via public API * Expose type CONNECTION_STATE * Add getter freerdp_get_state * Add helper freerdp_state_string (cherry picked from commit 32b3f54bb33f0fd5a9a1f1417fb8efaff3e01426) --- include/freerdp/freerdp.h | 22 ++++++++ libfreerdp/core/activation.c | 4 +- libfreerdp/core/connection.c | 98 +++++++++++++++++++++--------------- libfreerdp/core/connection.h | 28 +++-------- libfreerdp/core/fastpath.c | 2 +- libfreerdp/core/freerdp.c | 11 ++++ libfreerdp/core/peer.c | 32 ++++++------ libfreerdp/core/rdp.c | 25 ++++----- libfreerdp/core/rdp.h | 2 +- 9 files changed, 128 insertions(+), 96 deletions(-) diff --git a/include/freerdp/freerdp.h b/include/freerdp/freerdp.h index b5b38c0271ed..77ceb54f51f1 100644 --- a/include/freerdp/freerdp.h +++ b/include/freerdp/freerdp.h @@ -70,6 +70,25 @@ extern "C" #define VERIFY_CERT_FLAG_MISMATCH 0x80 #define VERIFY_CERT_FLAG_MATCH_LEGACY_SHA1 0x100 + typedef enum + { + CONNECTION_STATE_INITIAL, + CONNECTION_STATE_NEGO, + CONNECTION_STATE_NLA, + CONNECTION_STATE_MCS_CONNECT, + CONNECTION_STATE_MCS_ERECT_DOMAIN, + CONNECTION_STATE_MCS_ATTACH_USER, + CONNECTION_STATE_MCS_CHANNEL_JOIN, + CONNECTION_STATE_RDP_SECURITY_COMMENCEMENT, + CONNECTION_STATE_SECURE_SETTINGS_EXCHANGE, + CONNECTION_STATE_CONNECT_TIME_AUTO_DETECT, + CONNECTION_STATE_LICENSING, + CONNECTION_STATE_MULTITRANSPORT_BOOTSTRAPPING, + CONNECTION_STATE_CAPABILITIES_EXCHANGE, + CONNECTION_STATE_FINALIZATION, + CONNECTION_STATE_ACTIVE + } CONNECTION_STATE; + /* Message types used by gateway messaging callback */ #define GATEWAY_MESSAGE_CONSENT 1 #define GATEWAY_MESSAGE_SERVICE 2 @@ -527,6 +546,9 @@ extern "C" FREERDP_API const char* freerdp_nego_get_routing_token(rdpContext* context, DWORD* length); + FREERDP_API CONNECTION_STATE freerdp_get_state(rdpContext* context); + FREERDP_API const char* freerdp_state_string(CONNECTION_STATE state); + #ifdef __cplusplus } #endif diff --git a/libfreerdp/core/activation.c b/libfreerdp/core/activation.c index 3c9606ea6a3f..c6e335bcf1aa 100644 --- a/libfreerdp/core/activation.c +++ b/libfreerdp/core/activation.c @@ -350,7 +350,7 @@ BOOL rdp_recv_deactivate_all(rdpRdp* rdp, wStream* s) UINT16 lengthSourceDescriptor; UINT32 timeout; - if (rdp->state == CONNECTION_STATE_ACTIVE) + if (rdp_get_state(rdp) == CONNECTION_STATE_ACTIVE) rdp->deactivation_reactivation = TRUE; else rdp->deactivation_reactivation = FALSE; @@ -390,7 +390,7 @@ BOOL rdp_recv_deactivate_all(rdpRdp* rdp, wStream* s) if (freerdp_shall_disconnect(rdp->instance)) return TRUE; - if (rdp->state == CONNECTION_STATE_ACTIVE) + if (rdp_get_state(rdp) == CONNECTION_STATE_ACTIVE) return TRUE; Sleep(100); diff --git a/libfreerdp/core/connection.c b/libfreerdp/core/connection.c index a1a01e9b738e..815418e9e2d0 100644 --- a/libfreerdp/core/connection.c +++ b/libfreerdp/core/connection.c @@ -188,6 +188,7 @@ static int rdp_client_connect_finalize(rdpRdp* rdp); static BOOL rdp_send_server_control_granted_pdu(rdpRdp* rdp); +static BOOL rdp_set_state(rdpRdp* rdp, CONNECTION_STATE state); static BOOL rdp_client_reset_codecs(rdpContext* context) { @@ -358,7 +359,7 @@ BOOL rdp_client_connect(rdpRdp* rdp) rdp->transport->ReceiveExtra = rdp; transport_set_blocking_mode(rdp->transport, FALSE); - if (rdp->state != CONNECTION_STATE_NLA) + if (rdp_get_state(rdp) != CONNECTION_STATE_NLA) { if (!mcs_client_begin(rdp->mcs)) return FALSE; @@ -372,7 +373,7 @@ BOOL rdp_client_connect(rdpRdp* rdp) return FALSE; } - if (rdp->state == CONNECTION_STATE_ACTIVE) + if (rdp_get_state(rdp) == CONNECTION_STATE_ACTIVE) return TRUE; Sleep(100); @@ -1137,68 +1138,69 @@ int rdp_client_transition_to_state(rdpRdp* rdp, int state) { int status = 0; + WLog_DBG(TAG, "%s %s --> %s", __FUNCTION__, rdp_get_state_string(rdp), rdp_state_string(state)); switch (state) { case CONNECTION_STATE_INITIAL: - rdp->state = CONNECTION_STATE_INITIAL; + rdp_set_state(rdp, CONNECTION_STATE_INITIAL); break; case CONNECTION_STATE_NEGO: - rdp->state = CONNECTION_STATE_NEGO; + rdp_set_state(rdp, CONNECTION_STATE_NEGO); break; case CONNECTION_STATE_NLA: - rdp->state = CONNECTION_STATE_NLA; + rdp_set_state(rdp, CONNECTION_STATE_NLA); break; case CONNECTION_STATE_MCS_CONNECT: - rdp->state = CONNECTION_STATE_MCS_CONNECT; + rdp_set_state(rdp, CONNECTION_STATE_MCS_CONNECT); break; case CONNECTION_STATE_MCS_ERECT_DOMAIN: - rdp->state = CONNECTION_STATE_MCS_ERECT_DOMAIN; + rdp_set_state(rdp, CONNECTION_STATE_MCS_ERECT_DOMAIN); break; case CONNECTION_STATE_MCS_ATTACH_USER: - rdp->state = CONNECTION_STATE_MCS_ATTACH_USER; + rdp_set_state(rdp, CONNECTION_STATE_MCS_ATTACH_USER); break; case CONNECTION_STATE_MCS_CHANNEL_JOIN: - rdp->state = CONNECTION_STATE_MCS_CHANNEL_JOIN; + rdp_set_state(rdp, CONNECTION_STATE_MCS_CHANNEL_JOIN); break; case CONNECTION_STATE_RDP_SECURITY_COMMENCEMENT: - rdp->state = CONNECTION_STATE_RDP_SECURITY_COMMENCEMENT; + rdp_set_state(rdp, CONNECTION_STATE_RDP_SECURITY_COMMENCEMENT); break; case CONNECTION_STATE_SECURE_SETTINGS_EXCHANGE: - rdp->state = CONNECTION_STATE_SECURE_SETTINGS_EXCHANGE; + rdp_set_state(rdp, CONNECTION_STATE_SECURE_SETTINGS_EXCHANGE); break; case CONNECTION_STATE_CONNECT_TIME_AUTO_DETECT: - rdp->state = CONNECTION_STATE_CONNECT_TIME_AUTO_DETECT; + rdp_set_state(rdp, CONNECTION_STATE_CONNECT_TIME_AUTO_DETECT); break; case CONNECTION_STATE_LICENSING: - rdp->state = CONNECTION_STATE_LICENSING; + rdp_set_state(rdp, CONNECTION_STATE_LICENSING); break; case CONNECTION_STATE_MULTITRANSPORT_BOOTSTRAPPING: - rdp->state = CONNECTION_STATE_MULTITRANSPORT_BOOTSTRAPPING; + rdp_set_state(rdp, CONNECTION_STATE_MULTITRANSPORT_BOOTSTRAPPING); break; case CONNECTION_STATE_CAPABILITIES_EXCHANGE: - rdp->state = CONNECTION_STATE_CAPABILITIES_EXCHANGE; + rdp_set_state(rdp, CONNECTION_STATE_CAPABILITIES_EXCHANGE); break; case CONNECTION_STATE_FINALIZATION: - rdp->state = CONNECTION_STATE_FINALIZATION; + rdp_set_state(rdp, CONNECTION_STATE_FINALIZATION); update_reset_state(rdp->update); rdp->finalize_sc_pdus = 0; break; case CONNECTION_STATE_ACTIVE: - rdp->state = CONNECTION_STATE_ACTIVE; + rdp_set_state(rdp, CONNECTION_STATE_ACTIVE); { ActivatedEventArgs activatedEvent; rdpContext* context = rdp->context; @@ -1218,8 +1220,8 @@ int rdp_client_transition_to_state(rdpRdp* rdp, int state) ConnectionStateChangeEventArgs stateEvent; rdpContext* context = rdp->context; EventArgsInit(&stateEvent, "libfreerdp"); - stateEvent.state = rdp->state; - stateEvent.active = rdp->state == CONNECTION_STATE_ACTIVE; + stateEvent.state = rdp_get_state(rdp); + stateEvent.active = rdp_get_state(rdp) == CONNECTION_STATE_ACTIVE; PubSub_OnConnectionStateChange(context->pubSub, context, &stateEvent); } @@ -1406,7 +1408,7 @@ BOOL rdp_server_accept_confirm_active(rdpRdp* rdp, wStream* s, UINT16 pduLength) { freerdp_peer* peer = rdp->context->peer; - if (rdp->state != CONNECTION_STATE_CAPABILITIES_EXCHANGE) + if (rdp_get_state(rdp) != CONNECTION_STATE_CAPABILITIES_EXCHANGE) return FALSE; if (!rdp_recv_confirm_active(rdp, s, pduLength)) @@ -1455,74 +1457,76 @@ int rdp_server_transition_to_state(rdpRdp* rdp, int state) { int status = 0; freerdp_peer* client = NULL; + const int cstate = rdp_get_state(rdp); - if (rdp->state >= CONNECTION_STATE_RDP_SECURITY_COMMENCEMENT) + if (cstate >= CONNECTION_STATE_RDP_SECURITY_COMMENCEMENT) client = rdp->context->peer; - if (rdp->state < CONNECTION_STATE_ACTIVE) + if (cstate < CONNECTION_STATE_ACTIVE) { if (client) client->activated = FALSE; } + WLog_DBG(TAG, "%s %s --> %s", __FUNCTION__, rdp_get_state_string(rdp), rdp_state_string(state)); switch (state) { case CONNECTION_STATE_INITIAL: - rdp->state = CONNECTION_STATE_INITIAL; + rdp_set_state(rdp, CONNECTION_STATE_INITIAL); break; case CONNECTION_STATE_NEGO: - rdp->state = CONNECTION_STATE_NEGO; + rdp_set_state(rdp, CONNECTION_STATE_NEGO); break; case CONNECTION_STATE_MCS_CONNECT: - rdp->state = CONNECTION_STATE_MCS_CONNECT; + rdp_set_state(rdp, CONNECTION_STATE_MCS_CONNECT); break; case CONNECTION_STATE_MCS_ERECT_DOMAIN: - rdp->state = CONNECTION_STATE_MCS_ERECT_DOMAIN; + rdp_set_state(rdp, CONNECTION_STATE_MCS_ERECT_DOMAIN); break; case CONNECTION_STATE_MCS_ATTACH_USER: - rdp->state = CONNECTION_STATE_MCS_ATTACH_USER; + rdp_set_state(rdp, CONNECTION_STATE_MCS_ATTACH_USER); break; case CONNECTION_STATE_MCS_CHANNEL_JOIN: - rdp->state = CONNECTION_STATE_MCS_CHANNEL_JOIN; + rdp_set_state(rdp, CONNECTION_STATE_MCS_CHANNEL_JOIN); break; case CONNECTION_STATE_RDP_SECURITY_COMMENCEMENT: - rdp->state = CONNECTION_STATE_RDP_SECURITY_COMMENCEMENT; + rdp_set_state(rdp, CONNECTION_STATE_RDP_SECURITY_COMMENCEMENT); break; case CONNECTION_STATE_SECURE_SETTINGS_EXCHANGE: - rdp->state = CONNECTION_STATE_SECURE_SETTINGS_EXCHANGE; + rdp_set_state(rdp, CONNECTION_STATE_SECURE_SETTINGS_EXCHANGE); break; case CONNECTION_STATE_CONNECT_TIME_AUTO_DETECT: - rdp->state = CONNECTION_STATE_CONNECT_TIME_AUTO_DETECT; + rdp_set_state(rdp, CONNECTION_STATE_CONNECT_TIME_AUTO_DETECT); break; case CONNECTION_STATE_LICENSING: - rdp->state = CONNECTION_STATE_LICENSING; + rdp_set_state(rdp, CONNECTION_STATE_LICENSING); break; case CONNECTION_STATE_MULTITRANSPORT_BOOTSTRAPPING: - rdp->state = CONNECTION_STATE_MULTITRANSPORT_BOOTSTRAPPING; + rdp_set_state(rdp, CONNECTION_STATE_MULTITRANSPORT_BOOTSTRAPPING); break; case CONNECTION_STATE_CAPABILITIES_EXCHANGE: - rdp->state = CONNECTION_STATE_CAPABILITIES_EXCHANGE; + rdp_set_state(rdp, CONNECTION_STATE_CAPABILITIES_EXCHANGE); rdp->AwaitCapabilities = FALSE; break; case CONNECTION_STATE_FINALIZATION: - rdp->state = CONNECTION_STATE_FINALIZATION; + rdp_set_state(rdp, CONNECTION_STATE_FINALIZATION); rdp->finalize_sc_pdus = 0; break; case CONNECTION_STATE_ACTIVE: - rdp->state = CONNECTION_STATE_ACTIVE; + rdp_set_state(rdp, CONNECTION_STATE_ACTIVE); update_reset_state(rdp->update); if (client) @@ -1539,7 +1543,7 @@ int rdp_server_transition_to_state(rdpRdp* rdp, int state) return -1; } - if (rdp->state >= CONNECTION_STATE_ACTIVE) + if (rdp_get_state(rdp) >= CONNECTION_STATE_ACTIVE) { IFCALLRET(client->Activate, client->activated, client); @@ -1573,7 +1577,7 @@ const char* rdp_client_connection_state_string(int state) } } -const char* rdp_server_connection_state_string(int state) +const char* rdp_state_string(CONNECTION_STATE state) { switch (state) { @@ -1612,9 +1616,21 @@ const char* rdp_server_connection_state_string(int state) } } -int rdp_client_get_state(rdpRdp* rdp) +CONNECTION_STATE rdp_get_state(rdpRdp* rdp) { - if (!rdp) - return -1; + WINPR_ASSERT(rdp); return rdp->state; } + +BOOL rdp_set_state(rdpRdp* rdp, CONNECTION_STATE state) +{ + WINPR_ASSERT(rdp); + rdp->state = state; + return TRUE; +} + +const char* rdp_get_state_string(rdpRdp* rdp) +{ + int state = rdp_get_state(rdp); + return rdp_state_string(state); +} diff --git a/libfreerdp/core/connection.h b/libfreerdp/core/connection.h index 8458c60c7b4c..946f745bd79e 100644 --- a/libfreerdp/core/connection.h +++ b/libfreerdp/core/connection.h @@ -30,25 +30,6 @@ #include #include -enum CONNECTION_STATE -{ - CONNECTION_STATE_INITIAL, - CONNECTION_STATE_NEGO, - CONNECTION_STATE_NLA, - CONNECTION_STATE_MCS_CONNECT, - CONNECTION_STATE_MCS_ERECT_DOMAIN, - CONNECTION_STATE_MCS_ATTACH_USER, - CONNECTION_STATE_MCS_CHANNEL_JOIN, - CONNECTION_STATE_RDP_SECURITY_COMMENCEMENT, - CONNECTION_STATE_SECURE_SETTINGS_EXCHANGE, - CONNECTION_STATE_CONNECT_TIME_AUTO_DETECT, - CONNECTION_STATE_LICENSING, - CONNECTION_STATE_MULTITRANSPORT_BOOTSTRAPPING, - CONNECTION_STATE_CAPABILITIES_EXCHANGE, - CONNECTION_STATE_FINALIZATION, - CONNECTION_STATE_ACTIVE -}; - enum CLIENT_CONNECTION_STATE { CLIENT_STATE_INITIAL, @@ -66,8 +47,9 @@ FREERDP_LOCAL BOOL rdp_client_connect_auto_detect(rdpRdp* rdp, wStream* s); FREERDP_LOCAL int rdp_client_connect_license(rdpRdp* rdp, wStream* s); FREERDP_LOCAL int rdp_client_connect_demand_active(rdpRdp* rdp, wStream* s); FREERDP_LOCAL int rdp_client_transition_to_state(rdpRdp* rdp, int state); -FREERDP_LOCAL const char* rdp_client_connection_state_string(int state); -FREERDP_LOCAL int rdp_client_get_state(rdpRdp* rdp); + +FREERDP_LOCAL CONNECTION_STATE rdp_get_state(rdpRdp* rdp); +FREERDP_LOCAL const char* rdp_state_string(CONNECTION_STATE state); FREERDP_LOCAL BOOL rdp_server_accept_nego(rdpRdp* rdp, wStream* s); FREERDP_LOCAL BOOL rdp_server_accept_mcs_connect_initial(rdpRdp* rdp, wStream* s); @@ -78,6 +60,8 @@ FREERDP_LOCAL BOOL rdp_server_accept_confirm_active(rdpRdp* rdp, wStream* s, UIN FREERDP_LOCAL BOOL rdp_server_establish_keys(rdpRdp* rdp, wStream* s); FREERDP_LOCAL BOOL rdp_server_reactivate(rdpRdp* rdp); FREERDP_LOCAL int rdp_server_transition_to_state(rdpRdp* rdp, int state); -FREERDP_LOCAL const char* rdp_server_connection_state_string(int state); +FREERDP_LOCAL const char* rdp_get_state_string(rdpRdp* rdp); + +FREERDP_LOCAL const char* rdp_client_connection_state_string(int state); #endif /* FREERDP_LIB_CORE_CONNECTION_H */ diff --git a/libfreerdp/core/fastpath.c b/libfreerdp/core/fastpath.c index 7a67638fefd0..0b3549ace4de 100644 --- a/libfreerdp/core/fastpath.c +++ b/libfreerdp/core/fastpath.c @@ -948,7 +948,7 @@ BOOL fastpath_send_multiple_input_pdu(rdpFastPath* fastpath, wStream* s, size_t goto fail; rdp = fastpath->rdp; - state = rdp_client_get_state(rdp); + state = rdp_get_state(rdp); if (state != CONNECTION_STATE_ACTIVE) { WLog_WARN(TAG, "[%s] called before activation [%s]", __FUNCTION__, diff --git a/libfreerdp/core/freerdp.c b/libfreerdp/core/freerdp.c index 7d9eba4287e2..b31d7d84f946 100644 --- a/libfreerdp/core/freerdp.c +++ b/libfreerdp/core/freerdp.c @@ -1135,3 +1135,14 @@ const char* freerdp_nego_get_routing_token(rdpContext* context, DWORD* length) return (const char*)nego_get_routing_token(context->rdp->nego, length); } + +CONNECTION_STATE freerdp_get_state(rdpContext* context) +{ + WINPR_ASSERT(context); + return rdp_get_state(context->rdp); +} + +const char* freerdp_state_string(CONNECTION_STATE state) +{ + return rdp_state_string(state); +} diff --git a/libfreerdp/core/peer.c b/libfreerdp/core/peer.c index aff32c254cbc..dec2ea6baabe 100644 --- a/libfreerdp/core/peer.c +++ b/libfreerdp/core/peer.c @@ -203,7 +203,6 @@ static BOOL freerdp_peer_initialize(freerdp_peer* client) settings->ServerMode = TRUE; settings->FrameAcknowledge = 0; settings->LocalConnection = client->local; - rdp->state = CONNECTION_STATE_INITIAL; if (settings->RdpKeyFile) { @@ -475,13 +474,13 @@ static int peer_recv_callback(rdpTransport* transport, wStream* s, void* extra) freerdp_peer* client = (freerdp_peer*)extra; rdpRdp* rdp = client->context->rdp; - switch (rdp->state) + switch (rdp_get_state(rdp)) { case CONNECTION_STATE_INITIAL: if (!rdp_server_accept_nego(rdp, s)) { WLog_ERR(TAG, "%s: %s - rdp_server_accept_nego() fail", __FUNCTION__, - rdp_server_connection_state_string(rdp->state)); + rdp_state_string(rdp_get_state(rdp))); return -1; } @@ -510,7 +509,7 @@ static int peer_recv_callback(rdpTransport* transport, wStream* s, void* extra) WLog_ERR(TAG, "%s: %s - " "rdp_server_accept_mcs_connect_initial() fail", - __FUNCTION__, rdp_server_connection_state_string(rdp->state)); + __FUNCTION__, rdp_state_string(rdp_get_state(rdp))); return -1; } @@ -522,7 +521,7 @@ static int peer_recv_callback(rdpTransport* transport, wStream* s, void* extra) WLog_ERR(TAG, "%s: %s - " "rdp_server_accept_mcs_erect_domain_request() fail", - __FUNCTION__, rdp_server_connection_state_string(rdp->state)); + __FUNCTION__, rdp_state_string(rdp_get_state(rdp))); return -1; } @@ -534,7 +533,7 @@ static int peer_recv_callback(rdpTransport* transport, wStream* s, void* extra) WLog_ERR(TAG, "%s: %s - " "rdp_server_accept_mcs_attach_user_request() fail", - __FUNCTION__, rdp_server_connection_state_string(rdp->state)); + __FUNCTION__, rdp_state_string(rdp_get_state(rdp))); return -1; } @@ -546,7 +545,7 @@ static int peer_recv_callback(rdpTransport* transport, wStream* s, void* extra) WLog_ERR(TAG, "%s: %s - " "rdp_server_accept_mcs_channel_join_request() fail", - __FUNCTION__, rdp_server_connection_state_string(rdp->state)); + __FUNCTION__, rdp_state_string(rdp_get_state(rdp))); return -1; } @@ -560,7 +559,7 @@ static int peer_recv_callback(rdpTransport* transport, wStream* s, void* extra) WLog_ERR(TAG, "%s: %s - " "rdp_server_establish_keys() fail", - __FUNCTION__, rdp_server_connection_state_string(rdp->state)); + __FUNCTION__, rdp_state_string(rdp_get_state(rdp))); return -1; } } @@ -578,7 +577,7 @@ static int peer_recv_callback(rdpTransport* transport, wStream* s, void* extra) WLog_ERR(TAG, "%s: %s - " "rdp_recv_client_info() fail", - __FUNCTION__, rdp_server_connection_state_string(rdp->state)); + __FUNCTION__, rdp_state_string(rdp_get_state(rdp))); return -1; } @@ -606,7 +605,7 @@ static int peer_recv_callback(rdpTransport* transport, wStream* s, void* extra) WLog_ERR(TAG, "%s: %s - callback internal " "error, aborting", - __FUNCTION__, rdp_server_connection_state_string(rdp->state)); + __FUNCTION__, rdp_state_string(rdp_get_state(rdp))); return -1; case LICENSE_CB_ABORT: @@ -641,7 +640,7 @@ static int peer_recv_callback(rdpTransport* transport, wStream* s, void* extra) WLog_ERR(TAG, "%s: %s - " "rdp_send_demand_active() fail", - __FUNCTION__, rdp_server_connection_state_string(rdp->state)); + __FUNCTION__, rdp_state_string(rdp_get_state(rdp))); return -1; } @@ -654,7 +653,7 @@ static int peer_recv_callback(rdpTransport* transport, wStream* s, void* extra) WLog_ERR(TAG, "%s: %s - " "peer_recv_pdu() fail", - __FUNCTION__, rdp_server_connection_state_string(rdp->state)); + __FUNCTION__, rdp_state_string(rdp_get_state(rdp))); return -1; } } @@ -670,7 +669,7 @@ static int peer_recv_callback(rdpTransport* transport, wStream* s, void* extra) WLog_ERR(TAG, "%s: %s - " "peer_recv_pdu() fail", - __FUNCTION__, rdp_server_connection_state_string(rdp->state)); + __FUNCTION__, rdp_state_string(rdp_get_state(rdp))); return -1; } } @@ -681,7 +680,7 @@ static int peer_recv_callback(rdpTransport* transport, wStream* s, void* extra) if (peer_recv_pdu(client, s) < 0) { WLog_ERR(TAG, "%s: %s - peer_recv_pdu() fail", __FUNCTION__, - rdp_server_connection_state_string(rdp->state)); + rdp_state_string(rdp_get_state(rdp))); return -1; } @@ -691,15 +690,14 @@ static int peer_recv_callback(rdpTransport* transport, wStream* s, void* extra) if (peer_recv_pdu(client, s) < 0) { WLog_ERR(TAG, "%s: %s - peer_recv_pdu() fail", __FUNCTION__, - rdp_server_connection_state_string(rdp->state)); + rdp_state_string(rdp_get_state(rdp))); return -1; } break; default: - WLog_ERR(TAG, "%s state %d", rdp_server_connection_state_string(rdp->state), - rdp->state); + WLog_ERR(TAG, "%s state %d", rdp_state_string(rdp_get_state(rdp)), rdp_get_state(rdp)); return -1; } diff --git a/libfreerdp/core/rdp.c b/libfreerdp/core/rdp.c index 610d81e25b4c..4de256129966 100644 --- a/libfreerdp/core/rdp.c +++ b/libfreerdp/core/rdp.c @@ -1502,13 +1502,14 @@ int rdp_recv_callback(rdpTransport* transport, wStream* s, void* extra) * enters the active state, an auto-detect PDU can be received * on the MCS message channel. */ - if ((rdp->state > CONNECTION_STATE_MCS_CHANNEL_JOIN) && (rdp->state < CONNECTION_STATE_ACTIVE)) + if ((rdp_get_state(rdp) > CONNECTION_STATE_MCS_CHANNEL_JOIN) && + (rdp_get_state(rdp) < CONNECTION_STATE_ACTIVE)) { if (rdp_client_connect_auto_detect(rdp, s)) return 0; } - switch (rdp->state) + switch (rdp_get_state(rdp)) { case CONNECTION_STATE_NLA: if (nla_get_state(rdp->nla) < NLA_STATE_AUTH_INFO) @@ -1516,7 +1517,7 @@ int rdp_recv_callback(rdpTransport* transport, wStream* s, void* extra) if (nla_recv_pdu(rdp->nla, s) < 1) { WLog_ERR(TAG, "%s: %s - nla_recv_pdu() fail", __FUNCTION__, - rdp_server_connection_state_string(rdp->state)); + rdp_state_string(rdp_get_state(rdp))); return -1; } } @@ -1527,7 +1528,7 @@ int rdp_recv_callback(rdpTransport* transport, wStream* s, void* extra) if (nego_get_state(rdp->nego) != NEGO_STATE_FINAL) { WLog_ERR(TAG, "%s: %s - nego_recv() fail", __FUNCTION__, - rdp_server_connection_state_string(rdp->state)); + rdp_state_string(rdp_get_state(rdp))); return -1; } @@ -1567,7 +1568,7 @@ int rdp_recv_callback(rdpTransport* transport, wStream* s, void* extra) if (!mcs_client_begin(rdp->mcs)) { WLog_ERR(TAG, "%s: %s - mcs_client_begin() fail", __FUNCTION__, - rdp_server_connection_state_string(rdp->state)); + rdp_state_string(rdp_get_state(rdp))); return -1; } } @@ -1618,7 +1619,7 @@ int rdp_recv_callback(rdpTransport* transport, wStream* s, void* extra) WLog_ERR(TAG, "%s: %s - " "rdp_client_connect_mcs_channel_join_confirm() fail", - __FUNCTION__, rdp_server_connection_state_string(rdp->state)); + __FUNCTION__, rdp_state_string(rdp_get_state(rdp))); status = -1; } @@ -1629,7 +1630,7 @@ int rdp_recv_callback(rdpTransport* transport, wStream* s, void* extra) if (status < 0) WLog_DBG(TAG, "%s: %s - rdp_client_connect_license() - %i", __FUNCTION__, - rdp_server_connection_state_string(rdp->state), status); + rdp_state_string(rdp_get_state(rdp)), status); break; @@ -1640,7 +1641,7 @@ int rdp_recv_callback(rdpTransport* transport, wStream* s, void* extra) WLog_DBG(TAG, "%s: %s - " "rdp_client_connect_demand_active() - %i", - __FUNCTION__, rdp_server_connection_state_string(rdp->state), status); + __FUNCTION__, rdp_state_string(rdp_get_state(rdp)), status); break; @@ -1655,7 +1656,7 @@ int rdp_recv_callback(rdpTransport* transport, wStream* s, void* extra) if (status < 0) WLog_DBG(TAG, "%s: %s - rdp_recv_pdu() - %i", __FUNCTION__, - rdp_server_connection_state_string(rdp->state), status); + rdp_state_string(rdp_get_state(rdp)), status); break; @@ -1664,13 +1665,13 @@ int rdp_recv_callback(rdpTransport* transport, wStream* s, void* extra) if (status < 0) WLog_DBG(TAG, "%s: %s - rdp_recv_pdu() - %i", __FUNCTION__, - rdp_server_connection_state_string(rdp->state), status); + rdp_state_string(rdp_get_state(rdp)), status); break; default: - WLog_ERR(TAG, "%s: %s state %d", __FUNCTION__, - rdp_server_connection_state_string(rdp->state), rdp->state); + WLog_ERR(TAG, "%s: %s state %d", __FUNCTION__, rdp_state_string(rdp_get_state(rdp)), + rdp_get_state(rdp)); status = -1; break; } diff --git a/libfreerdp/core/rdp.h b/libfreerdp/core/rdp.h index d36a932e35fb..8212482a0588 100644 --- a/libfreerdp/core/rdp.h +++ b/libfreerdp/core/rdp.h @@ -132,7 +132,7 @@ struct rdp_rdp { - int state; + CONNECTION_STATE state; freerdp* instance; rdpContext* context; rdpNla* nla; From af69f8c25de29e0f85a865ad40ad893a4d4ff567 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Fri, 10 Sep 2021 10:39:07 +0200 Subject: [PATCH 287/496] Added proxy input state sync (#7282) The proxy server component might receive input related events before the proxy client has established the connection to the target machine. With this change, the current keyboard state is cached and sent to the target when it is ready. All input events received before the target is ready are discarded. (cherry picked from commit 4d23bc9372fc1d101ed6ff3841ab4567fd384d5f) --- server/proxy/pf_context.h | 3 +++ server/proxy/pf_input.c | 31 ++++++++++++++++++++++++++++++- 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/server/proxy/pf_context.h b/server/proxy/pf_context.h index 7c49fa722f19..2a5b7a9ee5b3 100644 --- a/server/proxy/pf_context.h +++ b/server/proxy/pf_context.h @@ -94,6 +94,9 @@ struct p_client_context UINT64 frames_count; wHashTable* vc_ids; /* channel_name -> channel_id map */ + + BOOL input_state_sync_pending; + UINT32 input_state; }; typedef struct p_client_context pClientContext; diff --git a/server/proxy/pf_input.c b/server/proxy/pf_input.c index 2a9baaa9162d..9703ac0dae76 100644 --- a/server/proxy/pf_input.c +++ b/server/proxy/pf_input.c @@ -23,11 +23,28 @@ #include "pf_context.h" #include "pf_modules.h" +static BOOL pf_server_check_and_sync_input_state(pClientContext* pc) +{ + if (freerdp_get_state(&pc->context) < CONNECTION_STATE_ACTIVE) + return FALSE; + if (pc->input_state_sync_pending) + { + BOOL rc = freerdp_input_send_synchronize_event(pc->context.input, pc->input_state); + if (rc) + pc->input_state_sync_pending = FALSE; + } + return TRUE; +} + static BOOL pf_server_synchronize_event(rdpInput* input, UINT32 flags) { pServerContext* ps = (pServerContext*)input->context; pClientContext* pc = ps->pdata->pc; - return freerdp_input_send_synchronize_event(pc->context.input, flags); + + pc->input_state = flags; + pc->input_state_sync_pending = TRUE; + pf_server_check_and_sync_input_state(pc); + return TRUE; } static BOOL pf_server_keyboard_event(rdpInput* input, UINT16 flags, UINT16 code) @@ -37,6 +54,9 @@ static BOOL pf_server_keyboard_event(rdpInput* input, UINT16 flags, UINT16 code) proxyConfig* config = ps->pdata->config; proxyKeyboardEventInfo event; + if (!pf_server_check_and_sync_input_state(pc)) + return TRUE; + if (!config->Keyboard) return TRUE; @@ -55,6 +75,9 @@ static BOOL pf_server_unicode_keyboard_event(rdpInput* input, UINT16 flags, UINT pClientContext* pc = ps->pdata->pc; proxyConfig* config = ps->pdata->config; + if (!pf_server_check_and_sync_input_state(pc)) + return TRUE; + if (!config->Keyboard) return TRUE; @@ -68,6 +91,9 @@ static BOOL pf_server_mouse_event(rdpInput* input, UINT16 flags, UINT16 x, UINT1 proxyConfig* config = ps->pdata->config; proxyMouseEventInfo event; + if (!pf_server_check_and_sync_input_state(pc)) + return TRUE; + if (!config->Mouse) return TRUE; @@ -87,6 +113,9 @@ static BOOL pf_server_extended_mouse_event(rdpInput* input, UINT16 flags, UINT16 pClientContext* pc = ps->pdata->pc; proxyConfig* config = ps->pdata->config; + if (!pf_server_check_and_sync_input_state(pc)) + return TRUE; + if (!config->Mouse) return TRUE; From 41185a28a09491a2dc08fd2a9fc476b13e6c4949 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Mon, 7 Nov 2022 09:08:51 +0100 Subject: [PATCH 288/496] updated changelog --- ChangeLog | 1 + 1 file changed, 1 insertion(+) diff --git a/ChangeLog b/ChangeLog index 9e60dc62b487..a8ff43913c38 100644 --- a/ChangeLog +++ b/ChangeLog @@ -11,6 +11,7 @@ Fixed issues: * Backported #8341: Null checks in winpr_Digest_Free * Backported #8335: Missing NULL return in winpr_Digest_New * Backported #8192: Support for audin version 2 microphone channel +* Backported #7282: Discard input events before activation (Fixes #8374) For a complete and detailed change log since the last release run: git log 2.8.1..2.8.x From 80adde17ddc4b596ed1dae0922a0c54ab3d4b8ea Mon Sep 17 00:00:00 2001 From: akallabeth Date: Thu, 13 Oct 2022 08:27:41 +0200 Subject: [PATCH 289/496] Fixed division by zero in urbdrc (cherry picked from commit 731f8419d04b481d7160de1f34062d630ed48765) --- channels/urbdrc/client/libusb/libusb_udevice.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/channels/urbdrc/client/libusb/libusb_udevice.c b/channels/urbdrc/client/libusb/libusb_udevice.c index 505c31d7b558..ef87f195f380 100644 --- a/channels/urbdrc/client/libusb/libusb_udevice.c +++ b/channels/urbdrc/client/libusb/libusb_udevice.c @@ -1221,12 +1221,18 @@ static int libusb_udev_isoch_transfer(IUDEVICE* idev, URBDRC_CHANNEL_CALLBACK* c if (!Buffer) Stream_Seek(user_data->data, (NumberOfPackets * 12)); - iso_packet_size = BufferSize / NumberOfPackets; - iso_transfer = libusb_alloc_transfer(NumberOfPackets); + if (NumberOfPackets > 0) + { + iso_packet_size = BufferSize / NumberOfPackets; + iso_transfer = libusb_alloc_transfer((int)NumberOfPackets); + } if (iso_transfer == NULL) { - WLog_Print(urbdrc->log, WLOG_ERROR, "Error: libusb_alloc_transfer."); + WLog_Print(urbdrc->log, WLOG_ERROR, + "Error: libusb_alloc_transfer [NumberOfPackets=%" PRIu32 ", BufferSize=%" PRIu32 + " ]", + NumberOfPackets, BufferSize); async_transfer_user_data_free(user_data); return -1; } From 68c6a8c1878b5294aecb04d5e27531a720b3793f Mon Sep 17 00:00:00 2001 From: akallabeth Date: Thu, 13 Oct 2022 08:36:26 +0200 Subject: [PATCH 290/496] Ensure urb_create_iocompletion uses size_t for calculation (cherry picked from commit de7e0f062ee53d00b4a966a43855a716e3478150) --- channels/urbdrc/client/data_transfer.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/channels/urbdrc/client/data_transfer.c b/channels/urbdrc/client/data_transfer.c index 698796126922..d8725c02cf35 100644 --- a/channels/urbdrc/client/data_transfer.c +++ b/channels/urbdrc/client/data_transfer.c @@ -97,7 +97,13 @@ static wStream* urb_create_iocompletion(UINT32 InterfaceField, UINT32 MessageId, UINT32 OutputBufferSize) { const UINT32 InterfaceId = (STREAM_ID_PROXY << 30) | (InterfaceField & 0x3FFFFFFF); - wStream* out = Stream_New(NULL, OutputBufferSize + 28); + +#if UINT32_MAX >= SIZE_MAX + if (OutputBufferSize > UINT32_MAX - 28ull) + return NULL; +#endif + + wStream* out = Stream_New(NULL, OutputBufferSize + 28ull); if (!out) return NULL; From 11555828d2cf289b350baba5ad1f462f10b80b76 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Thu, 13 Oct 2022 08:47:51 +0200 Subject: [PATCH 291/496] Fixed missing input buffer length check in urbdrc (cherry picked from commit 497df00f741dd4fc89292aaef2db7368aee45d0d) --- channels/urbdrc/client/data_transfer.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/channels/urbdrc/client/data_transfer.c b/channels/urbdrc/client/data_transfer.c index d8725c02cf35..aabeef84752d 100644 --- a/channels/urbdrc/client/data_transfer.c +++ b/channels/urbdrc/client/data_transfer.c @@ -247,6 +247,10 @@ static UINT urbdrc_process_io_control(IUDEVICE* pdev, URBDRC_CHANNEL_CALLBACK* c Stream_Read_UINT32(s, OutputBufferSize); Stream_Read_UINT32(s, RequestId); + + if (OutputBufferSize > UINT32_MAX - 4) + return ERROR_INVALID_DATA; + InterfaceId = ((STREAM_ID_PROXY << 30) | pdev->get_ReqCompletion(pdev)); out = urb_create_iocompletion(InterfaceId, MessageId, RequestId, OutputBufferSize + 4); @@ -726,6 +730,15 @@ static UINT urb_bulk_or_interrupt_transfer(IUDEVICE* pdev, URBDRC_CHANNEL_CALLBA Stream_Read_UINT32(s, TransferFlags); /** TransferFlags */ Stream_Read_UINT32(s, OutputBufferSize); EndpointAddress = (PipeHandle & 0x000000ff); + + if (transferDir == USBD_TRANSFER_DIRECTION_OUT) + { + if (!Stream_CheckAndLogRequiredLength(TAG, s, OutputBufferSize)) + { + return ERROR_INVALID_DATA; + } + } + /** process TS_URB_BULK_OR_INTERRUPT_TRANSFER */ return pdev->bulk_or_interrupt_transfer( pdev, callback, MessageId, RequestId, EndpointAddress, TransferFlags, noAck, @@ -810,6 +823,13 @@ static UINT urb_isoch_transfer(IUDEVICE* pdev, URBDRC_CHANNEL_CALLBACK* callback packetDescriptorData = Stream_Pointer(s); Stream_Seek(s, NumberOfPackets * 12); Stream_Read_UINT32(s, OutputBufferSize); + + if (transferDir == USBD_TRANSFER_DIRECTION_OUT) + { + if (!Stream_CheckAndLogRequiredLength(TAG, s, OutputBufferSize)) + return ERROR_INVALID_DATA; + } + return pdev->isoch_transfer( pdev, callback, MessageId, RequestId, EndpointAddress, TransferFlags, StartFrame, ErrorCount, noAck, packetDescriptorData, NumberOfPackets, OutputBufferSize, From ff82ae84342f68afc37f289a164d65ee3daefe97 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Thu, 13 Oct 2022 09:00:48 +0200 Subject: [PATCH 292/496] Added missing length check in urb_control_transfer (cherry picked from commit ce838e2477cb8173ea5e98f35ad55ff41ea5117d) --- channels/urbdrc/client/data_transfer.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/channels/urbdrc/client/data_transfer.c b/channels/urbdrc/client/data_transfer.c index aabeef84752d..ed6ccf32d5a5 100644 --- a/channels/urbdrc/client/data_transfer.c +++ b/channels/urbdrc/client/data_transfer.c @@ -683,7 +683,11 @@ static UINT urb_control_transfer(IUDEVICE* pdev, URBDRC_CHANNEL_CALLBACK* callba buffer = Stream_Pointer(out); if (transferDir == USBD_TRANSFER_DIRECTION_OUT) + { + if (!Stream_CheckAndLogRequiredLength(TAG, s, OutputBufferSize)) + return ERROR_INVALID_DATA; Stream_Copy(s, out, OutputBufferSize); + } /** process TS_URB_CONTROL_TRANSFER */ if (!pdev->control_transfer(pdev, RequestId, EndpointAddress, TransferFlags, bmRequestType, From e865c24efc40ebc52e75979c94cdd4ee2c1495b0 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Thu, 13 Oct 2022 09:09:28 +0200 Subject: [PATCH 293/496] Added missing length checks in zgfx_decompress_segment (cherry picked from commit 64716b335858109d14f27b51acc4c4d71a92a816) --- libfreerdp/codec/zgfx.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/libfreerdp/codec/zgfx.c b/libfreerdp/codec/zgfx.c index 20fbd3545711..e260aa6e28ad 100644 --- a/libfreerdp/codec/zgfx.c +++ b/libfreerdp/codec/zgfx.c @@ -230,19 +230,19 @@ static BOOL zgfx_decompress_segment(ZGFX_CONTEXT* zgfx, wStream* stream, size_t BYTE* pbSegment; size_t cbSegment; - if (!zgfx || !stream) + if (!zgfx || !stream || (segmentSize < 2)) return FALSE; cbSegment = segmentSize - 1; - if ((Stream_GetRemainingLength(stream) < segmentSize) || (segmentSize < 1) || - (segmentSize > UINT32_MAX)) + if ((Stream_GetRemainingLength(stream) < segmentSize) || (segmentSize > UINT32_MAX)) return FALSE; Stream_Read_UINT8(stream, flags); /* header (1 byte) */ zgfx->OutputCount = 0; pbSegment = Stream_Pointer(stream); - Stream_Seek(stream, cbSegment); + if (!Stream_SafeSeek(stream, cbSegment)) + return FALSE; if (!(flags & PACKET_COMPRESSED)) { @@ -346,6 +346,9 @@ static BOOL zgfx_decompress_segment(ZGFX_CONTEXT* zgfx, wStream* stream, size_t if (count > sizeof(zgfx->OutputBuffer) - zgfx->OutputCount) return FALSE; + if (count > zgfx->cBitsRemaining / 8) + return FALSE; + CopyMemory(&(zgfx->OutputBuffer[zgfx->OutputCount]), zgfx->pbInputCurrent, count); zgfx_history_buffer_ring_write(zgfx, zgfx->pbInputCurrent, count); From 6655841cf2a00b764f855040aecb8803cfc5eaba Mon Sep 17 00:00:00 2001 From: akallabeth Date: Mon, 24 Oct 2022 08:45:05 +0200 Subject: [PATCH 294/496] Fixed missing stream length check in drive_file_query_directory (cherry picked from commit 4e4bb79795d6ac85473fb7a83e53ccf63d204b93) --- channels/drive/client/drive_main.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/channels/drive/client/drive_main.c b/channels/drive/client/drive_main.c index 1b5422522587..35dc704e099c 100644 --- a/channels/drive/client/drive_main.c +++ b/channels/drive/client/drive_main.c @@ -629,6 +629,9 @@ static UINT drive_process_irp_query_directory(DRIVE_DEVICE* drive, IRP* irp) Stream_Read_UINT32(irp->input, PathLength); Stream_Seek(irp->input, 23); /* Padding */ path = (WCHAR*)Stream_Pointer(irp->input); + if (!Stream_CheckAndLogRequiredLength(TAG, irp->input, PathLength)) + return ERROR_INVALID_DATA; + file = drive_get_file_by_id(drive, irp->FileId); if (file == NULL) From 5101fbbba36d05a7c6a0ca72db7491036c8ccad7 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Mon, 24 Oct 2022 10:42:56 +0200 Subject: [PATCH 295/496] Added function _wcsncmp * Compare WCHAR strings up to n characters (cherry picked from commit 8178ed26a459356ece17414c6e871a7e0735a4ec) --- winpr/include/winpr/string.h | 2 ++ winpr/libwinpr/crt/string.c | 15 ++++++++++++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/winpr/include/winpr/string.h b/winpr/include/winpr/string.h index d7a849c8bed1..19d0c776d53f 100644 --- a/winpr/include/winpr/string.h +++ b/winpr/include/winpr/string.h @@ -60,6 +60,7 @@ extern "C" WINPR_API int _strnicmp(const char* string1, const char* string2, size_t count); WINPR_API int _wcscmp(const WCHAR* string1, const WCHAR* string2); + WINPR_API int _wcsncmp(const WCHAR* string1, const WCHAR* string2, size_t count); WINPR_API size_t _wcslen(const WCHAR* str); WINPR_API size_t _wcsnlen(const WCHAR* str, size_t maxNumberOfElements); @@ -73,6 +74,7 @@ extern "C" #else #define _wcscmp wcscmp +#define _wcsncmp wcsncmp #define _wcslen wcslen #define _wcsnlen wcsnlen #define _wcschr wcschr diff --git a/winpr/libwinpr/crt/string.c b/winpr/libwinpr/crt/string.c index 748210e4c677..b3df4c6a0ccb 100644 --- a/winpr/libwinpr/crt/string.c +++ b/winpr/libwinpr/crt/string.c @@ -107,7 +107,20 @@ int _wcscmp(const WCHAR* string1, const WCHAR* string2) Data_Read_UINT16(string1, value1); Data_Read_UINT16(string2, value2); - return value1 - value2; + return (int)value1 - value2; +} + +int _wcsncmp(const WCHAR* string1, const WCHAR* string2, size_t count) +{ + for (size_t x = 0; x < count; x++) + { + const WCHAR a = string1[x]; + const WCHAR b = string2[x]; + + if (a != b) + return (int)a - b; + } + return 0; } /* _wcslen -> wcslen */ From 3ac3a2ce9e965b334a446bc225ae85acb493e06e Mon Sep 17 00:00:00 2001 From: akallabeth Date: Thu, 10 Nov 2022 14:21:22 +0100 Subject: [PATCH 296/496] [winpr, crt] Fix wcs*cmp and wcs*len checks (cherry picked from commit b60fac1a0470fe83e8d0b448f0fd7e9e6d6a0f96) --- winpr/libwinpr/crt/string.c | 30 +++++++++++++++++++----------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/winpr/libwinpr/crt/string.c b/winpr/libwinpr/crt/string.c index b3df4c6a0ccb..623baa6c7949 100644 --- a/winpr/libwinpr/crt/string.c +++ b/winpr/libwinpr/crt/string.c @@ -26,6 +26,7 @@ #include #include +#include #include /* String Manipulation (CRT): http://msdn.microsoft.com/en-us/library/f0151s4x.aspx */ @@ -97,21 +98,28 @@ int _strnicmp(const char* string1, const char* string2, size_t count) int _wcscmp(const WCHAR* string1, const WCHAR* string2) { - WCHAR value1, value2; + WINPR_ASSERT(string1); + WINPR_ASSERT(string2); - while (*string1 && (*string1 == *string2)) + while (TRUE) { - string1++; - string2++; + const WCHAR w1 = *string1++; + const WCHAR w2 = *string2++; + + if (w1 != w2) + return (int)w1 - w2; + else if ((w1 == '\0') || (w2 == '\0')) + return (int)w1 - w2; } - Data_Read_UINT16(string1, value1); - Data_Read_UINT16(string2, value2); - return (int)value1 - value2; + return 0; } int _wcsncmp(const WCHAR* string1, const WCHAR* string2, size_t count) { + WINPR_ASSERT(string1); + WINPR_ASSERT(string2); + for (size_t x = 0; x < count; x++) { const WCHAR a = string1[x]; @@ -119,6 +127,8 @@ int _wcsncmp(const WCHAR* string1, const WCHAR* string2, size_t count) if (a != b) return (int)a - b; + else if ((a == '\0') || (b == '\0')) + return (int)a - b; } return 0; } @@ -129,8 +139,7 @@ size_t _wcslen(const WCHAR* str) { const WCHAR* p = (const WCHAR*)str; - if (!p) - return 0; + WINPR_ASSERT(p); while (*p) p++; @@ -144,8 +153,7 @@ size_t _wcsnlen(const WCHAR* str, size_t max) { size_t x; - if (!str) - return 0; + WINPR_ASSERT(str); for (x = 0; x < max; x++) { From 0a62aba0caba88775ceb24211feb8eb319c034c1 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Thu, 10 Nov 2022 15:54:28 +0100 Subject: [PATCH 297/496] [winpr, crt] Added wcsstr implementation (cherry picked from commit 6c034ba6117a4efc9266e845fe9a9a92ed4ee61d) --- winpr/include/winpr/string.h | 3 +++ winpr/libwinpr/crt/string.c | 20 ++++++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/winpr/include/winpr/string.h b/winpr/include/winpr/string.h index 19d0c776d53f..bb98dffdc9ea 100644 --- a/winpr/include/winpr/string.h +++ b/winpr/include/winpr/string.h @@ -65,6 +65,8 @@ extern "C" WINPR_API size_t _wcslen(const WCHAR* str); WINPR_API size_t _wcsnlen(const WCHAR* str, size_t maxNumberOfElements); + WINPR_API WCHAR* _wcsstr(const WCHAR* str, const WCHAR* strSearch); + WINPR_API WCHAR* _wcschr(const WCHAR* str, WCHAR c); WINPR_API WCHAR* _wcsrchr(const WCHAR* str, WCHAR c); @@ -77,6 +79,7 @@ extern "C" #define _wcsncmp wcsncmp #define _wcslen wcslen #define _wcsnlen wcsnlen +#define _wcsstr wcsstr #define _wcschr wcschr #define _wcsrchr wcsrchr diff --git a/winpr/libwinpr/crt/string.c b/winpr/libwinpr/crt/string.c index 623baa6c7949..6596b42f525c 100644 --- a/winpr/libwinpr/crt/string.c +++ b/winpr/libwinpr/crt/string.c @@ -164,6 +164,26 @@ size_t _wcsnlen(const WCHAR* str, size_t max) return x; } +/* _wcsstr -> wcsstr */ + +WCHAR* _wcsstr(const WCHAR* str, const WCHAR* strSearch) +{ + WINPR_ASSERT(str); + WINPR_ASSERT(strSearch); + + if (strSearch[0] == '\0') + return str; + + const size_t searchLen = _wcslen(strSearch); + while (*str) + { + if (_wcsncmp(str, strSearch, searchLen) == 0) + return str; + str++; + } + return NULL; +} + /* _wcschr -> wcschr */ WCHAR* _wcschr(const WCHAR* str, WCHAR c) From 027424c2c6c0991cb9c22f9511478229c9b17e5d Mon Sep 17 00:00:00 2001 From: akallabeth Date: Mon, 24 Oct 2022 10:41:55 +0200 Subject: [PATCH 298/496] Fixed path validation in drive channel Check that canonical path is a subpath of the shared directory (cherry picked from commit 844c94e6d0438fa7bd8ff8d5513c3f69c3018b85) --- channels/drive/client/drive_file.c | 106 ++++++++++++++++++----------- channels/drive/client/drive_file.h | 8 +-- channels/drive/client/drive_main.c | 8 +-- 3 files changed, 73 insertions(+), 49 deletions(-) diff --git a/channels/drive/client/drive_file.c b/channels/drive/client/drive_file.c index 3054385933ca..1ea4ab9dabf0 100644 --- a/channels/drive/client/drive_file.c +++ b/channels/drive/client/drive_file.c @@ -61,10 +61,14 @@ } while (0) #endif -static void drive_file_fix_path(WCHAR* path) +static BOOL drive_file_fix_path(WCHAR* path, size_t length) { size_t i; - size_t length = _wcslen(path); + + if ((length == 0) || (length > UINT32_MAX)) + return FALSE; + + WINPR_ASSERT(path); for (i = 0; i < length; i++) { @@ -75,58 +79,82 @@ static void drive_file_fix_path(WCHAR* path) #ifdef WIN32 if ((length == 3) && (path[1] == L':') && (path[2] == L'/')) - return; + return FALSE; #else if ((length == 1) && (path[0] == L'/')) - return; + return FALSE; #endif if ((length > 0) && (path[length - 1] == L'/')) path[length - 1] = L'\0'; + + return TRUE; } static WCHAR* drive_file_combine_fullpath(const WCHAR* base_path, const WCHAR* path, - size_t PathLength) + size_t PathWCharLength) { - WCHAR* fullpath; - size_t base_path_length; + BOOL ok = FALSE; + WCHAR* fullpath = NULL; + size_t length; - if (!base_path || (!path && (PathLength > 0))) - return NULL; + if (!base_path || (!path && (PathWCharLength > 0))) + goto fail; - base_path_length = _wcslen(base_path) * 2; - fullpath = (WCHAR*)calloc(1, base_path_length + PathLength + sizeof(WCHAR)); + const size_t base_path_length = _wcsnlen(base_path, MAX_PATH); + length = base_path_length + PathWCharLength + 1; + fullpath = (WCHAR*)calloc(length, sizeof(WCHAR)); if (!fullpath) + goto fail; + + CopyMemory(fullpath, base_path, base_path_length * sizeof(WCHAR)); + if (path) + CopyMemory(&fullpath[base_path_length], path, PathWCharLength * sizeof(WCHAR)); + + if (!drive_file_fix_path(fullpath, length)) + goto fail; + + /* Ensure the path does not contain sequences like '..' */ + const WCHAR dotdot[] = { '.', '.', '\0' }; + if (_wcsstr(&fullpath[base_path_length], dotdot)) { - WLog_ERR(TAG, "malloc failed!"); - return NULL; + char abuffer[MAX_PATH] = { 0 }; + ConvertFromUnicode(CP_UTF8, 0, &fullpath[base_path_length], -1, (char**)&abuffer, + ARRAYSIZE(abuffer) - 1, NULL, NULL); + + WLog_WARN(TAG, "[rdpdr] received invalid file path '%s' from server, aborting!", + &abuffer[base_path_length]); + goto fail; } - CopyMemory(fullpath, base_path, base_path_length); - if (path) - CopyMemory((char*)fullpath + base_path_length, path, PathLength); - drive_file_fix_path(fullpath); + ok = TRUE; +fail: + if (!ok) + { + free(fullpath); + fullpath = NULL; + } return fullpath; } static BOOL drive_file_remove_dir(const WCHAR* path) { - WIN32_FIND_DATAW findFileData; + WIN32_FIND_DATAW findFileData = { 0 }; BOOL ret = TRUE; - HANDLE dir; - WCHAR* fullpath; - WCHAR* path_slash; - size_t base_path_length; + HANDLE dir = INVALID_HANDLE_VALUE; + WCHAR* fullpath = NULL; + WCHAR* path_slash = NULL; + size_t base_path_length = 0; if (!path) return FALSE; - base_path_length = _wcslen(path) * 2; - path_slash = (WCHAR*)calloc(1, base_path_length + sizeof(WCHAR) * 3); + base_path_length = _wcslen(path); + path_slash = (WCHAR*)calloc(base_path_length + 3, sizeof(WCHAR)); if (!path_slash) { @@ -134,12 +162,11 @@ static BOOL drive_file_remove_dir(const WCHAR* path) return FALSE; } - CopyMemory(path_slash, path, base_path_length); - path_slash[base_path_length / 2] = L'/'; - path_slash[base_path_length / 2 + 1] = L'*'; + CopyMemory(path_slash, path, base_path_length * sizeof(WCHAR)); + path_slash[base_path_length] = L'/'; + path_slash[base_path_length + 1] = L'*'; DEBUG_WSTR("Search in %s", path_slash); dir = FindFirstFileW(path_slash, &findFileData); - path_slash[base_path_length / 2 + 1] = 0; if (dir == INVALID_HANDLE_VALUE) { @@ -149,7 +176,7 @@ static BOOL drive_file_remove_dir(const WCHAR* path) do { - size_t len = _wcslen(findFileData.cFileName); + const size_t len = _wcsnlen(findFileData.cFileName, ARRAYSIZE(findFileData.cFileName)); if ((len == 1 && findFileData.cFileName[0] == L'.') || (len == 2 && findFileData.cFileName[0] == L'.' && findFileData.cFileName[1] == L'.')) @@ -157,7 +184,7 @@ static BOOL drive_file_remove_dir(const WCHAR* path) continue; } - fullpath = drive_file_combine_fullpath(path_slash, findFileData.cFileName, len * 2); + fullpath = drive_file_combine_fullpath(path_slash, findFileData.cFileName, len); DEBUG_WSTR("Delete %s", fullpath); if (findFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) @@ -333,13 +360,13 @@ static BOOL drive_file_init(DRIVE_FILE* file) return file->file_handle != INVALID_HANDLE_VALUE; } -DRIVE_FILE* drive_file_new(const WCHAR* base_path, const WCHAR* path, UINT32 PathLength, UINT32 id, - UINT32 DesiredAccess, UINT32 CreateDisposition, UINT32 CreateOptions, - UINT32 FileAttributes, UINT32 SharedAccess) +DRIVE_FILE* drive_file_new(const WCHAR* base_path, const WCHAR* path, UINT32 PathWCharLength, + UINT32 id, UINT32 DesiredAccess, UINT32 CreateDisposition, + UINT32 CreateOptions, UINT32 FileAttributes, UINT32 SharedAccess) { DRIVE_FILE* file; - if (!base_path || (!path && (PathLength > 0))) + if (!base_path || (!path && (PathWCharLength > 0))) return NULL; file = (DRIVE_FILE*)calloc(1, sizeof(DRIVE_FILE)); @@ -359,7 +386,7 @@ DRIVE_FILE* drive_file_new(const WCHAR* base_path, const WCHAR* path, UINT32 Pat file->CreateDisposition = CreateDisposition; file->CreateOptions = CreateOptions; file->SharedAccess = SharedAccess; - drive_file_set_fullpath(file, drive_file_combine_fullpath(base_path, path, PathLength)); + drive_file_set_fullpath(file, drive_file_combine_fullpath(base_path, path, PathWCharLength)); if (!drive_file_init(file)) { @@ -714,13 +741,10 @@ BOOL drive_file_set_information(DRIVE_FILE* file, UINT32 FsInformationClass, UIN return FALSE; fullpath = drive_file_combine_fullpath(file->basepath, (WCHAR*)Stream_Pointer(input), - FileNameLength); + FileNameLength / sizeof(WCHAR)); if (!fullpath) - { - WLog_ERR(TAG, "drive_file_combine_fullpath failed!"); return FALSE; - } #ifdef _WIN32 @@ -759,7 +783,7 @@ BOOL drive_file_set_information(DRIVE_FILE* file, UINT32 FsInformationClass, UIN } BOOL drive_file_query_directory(DRIVE_FILE* file, UINT32 FsInformationClass, BYTE InitialQuery, - const WCHAR* path, UINT32 PathLength, wStream* output) + const WCHAR* path, UINT32 PathWCharLength, wStream* output) { size_t length; WCHAR* ent_path; @@ -773,7 +797,7 @@ BOOL drive_file_query_directory(DRIVE_FILE* file, UINT32 FsInformationClass, BYT if (file->find_handle != INVALID_HANDLE_VALUE) FindClose(file->find_handle); - ent_path = drive_file_combine_fullpath(file->basepath, path, PathLength); + ent_path = drive_file_combine_fullpath(file->basepath, path, PathWCharLength); /* open new search handle and retrieve the first entry */ file->find_handle = FindFirstFileW(ent_path, &file->find_data); free(ent_path); diff --git a/channels/drive/client/drive_file.h b/channels/drive/client/drive_file.h index ed789d6f09be..6d3bd7045cd2 100644 --- a/channels/drive/client/drive_file.h +++ b/channels/drive/client/drive_file.h @@ -51,9 +51,9 @@ struct _DRIVE_FILE UINT32 CreateOptions; }; -DRIVE_FILE* drive_file_new(const WCHAR* base_path, const WCHAR* path, UINT32 PathLength, UINT32 id, - UINT32 DesiredAccess, UINT32 CreateDisposition, UINT32 CreateOptions, - UINT32 FileAttributes, UINT32 SharedAccess); +DRIVE_FILE* drive_file_new(const WCHAR* base_path, const WCHAR* path, UINT32 PathWCharLength, + UINT32 id, UINT32 DesiredAccess, UINT32 CreateDisposition, + UINT32 CreateOptions, UINT32 FileAttributes, UINT32 SharedAccess); BOOL drive_file_free(DRIVE_FILE* file); BOOL drive_file_open(DRIVE_FILE* file); @@ -64,6 +64,6 @@ BOOL drive_file_query_information(DRIVE_FILE* file, UINT32 FsInformationClass, w BOOL drive_file_set_information(DRIVE_FILE* file, UINT32 FsInformationClass, UINT32 Length, wStream* input); BOOL drive_file_query_directory(DRIVE_FILE* file, UINT32 FsInformationClass, BYTE InitialQuery, - const WCHAR* path, UINT32 PathLength, wStream* output); + const WCHAR* path, UINT32 PathWCharLength, wStream* output); #endif /* FREERDP_CHANNEL_DRIVE_FILE_H */ diff --git a/channels/drive/client/drive_main.c b/channels/drive/client/drive_main.c index 35dc704e099c..b6cf2ad32bc8 100644 --- a/channels/drive/client/drive_main.c +++ b/channels/drive/client/drive_main.c @@ -184,8 +184,8 @@ static UINT drive_process_irp_create(DRIVE_DEVICE* drive, IRP* irp) path = (const WCHAR*)Stream_Pointer(irp->input); FileId = irp->devman->id_sequence++; - file = drive_file_new(drive->path, path, PathLength, FileId, DesiredAccess, CreateDisposition, - CreateOptions, FileAttributes, SharedAccess); + file = drive_file_new(drive->path, path, PathLength / sizeof(WCHAR), FileId, DesiredAccess, + CreateDisposition, CreateOptions, FileAttributes, SharedAccess); if (!file) { @@ -639,8 +639,8 @@ static UINT drive_process_irp_query_directory(DRIVE_DEVICE* drive, IRP* irp) irp->IoStatus = STATUS_UNSUCCESSFUL; Stream_Write_UINT32(irp->output, 0); /* Length */ } - else if (!drive_file_query_directory(file, FsInformationClass, InitialQuery, path, PathLength, - irp->output)) + else if (!drive_file_query_directory(file, FsInformationClass, InitialQuery, path, + PathLength / sizeof(WCHAR), irp->output)) { irp->IoStatus = drive_map_windows_err(GetLastError()); } From 330e09ae12e14d6e37ec72e4d296faa29e08fc0c Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Wed, 16 Nov 2022 10:49:13 +0100 Subject: [PATCH 299/496] [capabilities] properly set RemoteFxOnly The check was inverted, setting the flag properly now (cherry picked from commit 73a722ec8e887d2f61bc8f80a9696701a07f84ae) --- libfreerdp/core/capabilities.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libfreerdp/core/capabilities.c b/libfreerdp/core/capabilities.c index 433f4cefc0ea..786e30c5ddf8 100644 --- a/libfreerdp/core/capabilities.c +++ b/libfreerdp/core/capabilities.c @@ -2780,7 +2780,7 @@ static BOOL rdp_read_bitmap_codecs_capability_set(wStream* s, rdpSettings* setti Stream_Read_UINT32(&sub, captureFlags); /* captureFlags (4 bytes) */ Stream_Read_UINT32(&sub, rfxCapsLength); /* capsLength (4 bytes) */ settings->RemoteFxCaptureFlags = captureFlags; - settings->RemoteFxOnly = (captureFlags & CARDP_CAPS_CAPTURE_NON_CAC) ? TRUE : FALSE; + settings->RemoteFxOnly = (captureFlags & CARDP_CAPS_CAPTURE_NON_CAC) ? FALSE : TRUE; if (rfxCapsLength) { From 30a056835f2c272c5cb43ce3004ab3ca78d8762b Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Wed, 16 Nov 2022 11:58:02 +0100 Subject: [PATCH 300/496] [client,x11] Fixed #8397: Clamp scaled cursor sizes If a cursor is scaled, ensure the result size is at least 1x1 pixel wide. (cherry picked from commit 0ebc468d12a8d71cf68df92787e8b8fcf9208ba8) --- client/X11/xf_graphics.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/X11/xf_graphics.c b/client/X11/xf_graphics.c index 705056941c81..82b0b95b37ac 100644 --- a/client/X11/xf_graphics.c +++ b/client/X11/xf_graphics.c @@ -258,8 +258,8 @@ static BOOL xf_Pointer_GetCursorForCurrentScale(rdpContext* context, const rdpPo xscale = (settings->SmartSizing ? xfc->scaledWidth / (double)settings->DesktopWidth : 1); yscale = (settings->SmartSizing ? xfc->scaledHeight / (double)settings->DesktopHeight : 1); - xTargetSize = pointer->width * xscale; - yTargetSize = pointer->height * yscale; + xTargetSize = MAX(1, pointer->width * xscale); + yTargetSize = MAX(1, pointer->height * yscale); WLog_DBG(TAG, "%s: scaled: %" PRIu32 "x%" PRIu32 ", desktop: %" PRIu32 "x%" PRIu32, __func__, xfc->scaledWidth, xfc->savedHeight, settings->DesktopWidth, settings->DesktopHeight); From 4001a6d0cd2c31fbbeb30872d435423f8494b3a1 Mon Sep 17 00:00:00 2001 From: Joan Torres Date: Tue, 27 Sep 2022 17:09:53 +0200 Subject: [PATCH 301/496] Add support to send a ServerRedirection PDU. (cherry picked from commit e35b0321213f9882ce0474dfa2a75dc1636ea115) --- include/freerdp/peer.h | 9 ++ libfreerdp/core/peer.c | 240 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 249 insertions(+) diff --git a/include/freerdp/peer.h b/include/freerdp/peer.h index 4176f2572c53..90bbb461fe23 100644 --- a/include/freerdp/peer.h +++ b/include/freerdp/peer.h @@ -48,6 +48,13 @@ typedef BOOL (*psPeerCapabilities)(freerdp_peer* peer); typedef BOOL (*psPeerPostConnect)(freerdp_peer* peer); typedef BOOL (*psPeerActivate)(freerdp_peer* peer); typedef BOOL (*psPeerLogon)(freerdp_peer* peer, SEC_WINNT_AUTH_IDENTITY* identity, BOOL automatic); +typedef BOOL (*psPeerSendServerRedirection)(freerdp_peer* peer, UINT32 sessionId, + const char* targetNetAddress, const char* routingToken, + const char* userName, const char* domain, + const char* password, const char* targetFQDN, + const char* targetNetBiosName, DWORD tsvUrlLength, + const BYTE* tsvUrl, UINT32 targetNetAddressesCount, + const char** targetNetAddresses); typedef BOOL (*psPeerAdjustMonitorsLayout)(freerdp_peer* peer); typedef BOOL (*psPeerClientCapabilities)(freerdp_peer* peer); @@ -133,6 +140,8 @@ struct rdp_freerdp_peer psPeerClientCapabilities ClientCapabilities; psPeerComputeNtlmHash ComputeNtlmHash; psPeerLicenseCallback LicenseCallback; + + psPeerSendServerRedirection SendServerRedirection; }; #ifdef __cplusplus diff --git a/libfreerdp/core/peer.c b/libfreerdp/core/peer.c index dec2ea6baabe..41730efecbd9 100644 --- a/libfreerdp/core/peer.c +++ b/libfreerdp/core/peer.c @@ -743,6 +743,245 @@ static BOOL freerdp_peer_send_channel_data(freerdp_peer* client, UINT16 channelI return rdp_send_channel_data(client->context->rdp, channelId, data, size); } +static BOOL freerdp_peer_send_server_redirection_pdu( + freerdp_peer* peer, UINT32 sessionId, const char* targetNetAddress, const char* routingToken, + const char* userName, const char* domain, const char* password, const char* targetFQDN, + const char* targetNetBiosName, DWORD tsvUrlLength, const BYTE* tsvUrl, + UINT32 targetNetAddressesCount, const char** targetNetAddresses) +{ + wStream* s = rdp_send_stream_pdu_init(peer->context->rdp); + UINT16 length; + UINT32 redirFlags; + + UINT32 targetNetAddressLength; + UINT32 loadBalanceInfoLength; + UINT32 userNameLength; + UINT32 domainLength; + UINT32 passwordLength; + UINT32 targetFQDNLength; + UINT32 targetNetBiosNameLength; + UINT32 targetNetAddressesLength; + UINT32* targetNetAddressesWLength; + + LPWSTR targetNetAddressW = NULL; + LPWSTR userNameW = NULL; + LPWSTR domainW = NULL; + LPWSTR passwordW = NULL; + LPWSTR targetFQDNW = NULL; + LPWSTR targetNetBiosNameW = NULL; + LPWSTR* targetNetAddressesW = NULL; + + length = 12; /* Flags (2) + length (2) + sessionId (4) + redirection flags (4) */ + redirFlags = 0; + + if (targetNetAddress) + { + redirFlags |= LB_TARGET_NET_ADDRESS; + + ConvertToUnicode(CP_UTF8, 0, (LPCSTR)targetNetAddress, -1, &targetNetAddressW, 0); + targetNetAddressLength = (strlen(targetNetAddress) + 1) * sizeof(WCHAR); + + length += 4 + targetNetAddressLength; + } + + if (routingToken) + { + redirFlags |= LB_LOAD_BALANCE_INFO; + loadBalanceInfoLength = + 13 + strlen(routingToken) + 2; /* Add routing token prefix and suffix */ + length += 4 + loadBalanceInfoLength; + } + + if (userName) + { + redirFlags |= LB_USERNAME; + + ConvertToUnicode(CP_UTF8, 0, (LPCSTR)userName, -1, &userNameW, 0); + userNameLength = (strlen(userName) + 1) * sizeof(WCHAR); + + length += 4 + userNameLength; + } + + if (domain) + { + redirFlags |= LB_DOMAIN; + + ConvertToUnicode(CP_UTF8, 0, (LPCSTR)domain, -1, &domainW, 0); + domainLength = (strlen(domain) + 1) * sizeof(WCHAR); + + length += 4 + domainLength; + } + + if (password) + { + redirFlags |= LB_PASSWORD; + + ConvertToUnicode(CP_UTF8, 0, (LPCSTR)password, -1, &passwordW, 0); + passwordLength = (strlen(password) + 1) * sizeof(WCHAR); + + length += 4 + passwordLength; + } + + if (targetFQDN) + { + redirFlags |= LB_TARGET_FQDN; + + ConvertToUnicode(CP_UTF8, 0, (LPCSTR)targetFQDN, -1, &targetFQDNW, 0); + targetFQDNLength = (strlen(targetFQDN) + 1) * sizeof(WCHAR); + + length += 4 + targetFQDNLength; + } + + if (targetNetBiosName) + { + redirFlags |= LB_TARGET_NETBIOS_NAME; + + ConvertToUnicode(CP_UTF8, 0, (LPCSTR)targetNetBiosName, -1, &targetNetBiosNameW, 0); + targetNetBiosNameLength = (strlen(targetNetBiosName) + 1) * sizeof(WCHAR); + + length += 4 + targetNetBiosNameLength; + } + + if (tsvUrl) + { + redirFlags |= LB_CLIENT_TSV_URL; + length += 4 + tsvUrlLength; + } + + if (targetNetAddresses) + { + UINT32 i; + + redirFlags |= LB_TARGET_NET_ADDRESSES; + + targetNetAddressesLength = 0; + targetNetAddressesW = calloc(targetNetAddressesCount, sizeof(LPWSTR)); + targetNetAddressesWLength = calloc(targetNetAddressesCount, sizeof(UINT32)); + for (i = 0; i < targetNetAddressesCount; i++) + { + ConvertToUnicode(CP_UTF8, 0, (LPCSTR)targetNetAddresses[i], -1, &targetNetAddressesW[i], + 0); + targetNetAddressesWLength[i] = (strlen(targetNetAddresses[i]) + 1) * sizeof(WCHAR); + targetNetAddressesLength += 4 + targetNetAddressesWLength[i]; + } + + length += 4 + 4 + targetNetAddressesLength; + } + + Stream_Write_UINT16(s, 0); + Stream_Write_UINT16(s, SEC_REDIRECTION_PKT); + Stream_Write_UINT16(s, length); + + if (!Stream_EnsureRemainingCapacity(s, length)) + { + WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!"); + goto fail; + } + + if (sessionId) + Stream_Write_UINT32(s, sessionId); + else + Stream_Write_UINT32(s, 0); + + Stream_Write_UINT32(s, redirFlags); + + if (redirFlags & LB_TARGET_NET_ADDRESS) + { + Stream_Write_UINT32(s, targetNetAddressLength); + Stream_Write(s, targetNetAddressW, targetNetAddressLength); + free(targetNetAddressW); + } + + if (redirFlags & LB_LOAD_BALANCE_INFO) + { + Stream_Write_UINT32(s, loadBalanceInfoLength); + Stream_Write(s, "Cookie: msts=", 13); + Stream_Write(s, routingToken, strlen(routingToken)); + Stream_Write_UINT8(s, 0x0d); + Stream_Write_UINT8(s, 0x0a); + } + + if (redirFlags & LB_USERNAME) + { + Stream_Write_UINT32(s, userNameLength); + Stream_Write(s, userNameW, userNameLength); + free(userNameW); + } + + if (redirFlags & LB_DOMAIN) + { + Stream_Write_UINT32(s, domainLength); + Stream_Write(s, domainW, domainLength); + free(domainW); + } + + if (redirFlags & LB_PASSWORD) + { + Stream_Write_UINT32(s, passwordLength); + Stream_Write(s, passwordW, passwordLength); + free(passwordW); + } + + if (redirFlags & LB_TARGET_FQDN) + { + Stream_Write_UINT32(s, targetFQDNLength); + Stream_Write(s, targetFQDNW, targetFQDNLength); + free(targetFQDNW); + } + + if (redirFlags & LB_TARGET_NETBIOS_NAME) + { + Stream_Write_UINT32(s, targetNetBiosNameLength); + Stream_Write(s, targetNetBiosNameW, targetNetBiosNameLength); + free(targetNetBiosNameW); + } + + if (redirFlags & LB_CLIENT_TSV_URL) + { + Stream_Write_UINT32(s, tsvUrlLength); + Stream_Write(s, tsvUrl, tsvUrlLength); + } + + if (redirFlags & LB_TARGET_NET_ADDRESSES) + { + UINT32 i; + Stream_Write_UINT32(s, targetNetAddressesLength); + Stream_Write_UINT32(s, targetNetAddressesCount); + for (i = 0; i < targetNetAddressesCount; i++) + { + Stream_Write_UINT32(s, targetNetAddressesWLength[i]); + Stream_Write(s, targetNetAddressesW[i], targetNetAddressesWLength[i]); + free(targetNetAddressesW[i]); + } + free(targetNetAddressesW); + free(targetNetAddressesWLength); + } + + Stream_Write_UINT8(s, 0); + rdp_send_pdu(peer->context->rdp, s, PDU_TYPE_SERVER_REDIRECTION, 0); + + return TRUE; + +fail: + free(targetNetAddressW); + free(userNameW); + free(domainW); + free(passwordW); + free(targetFQDNW); + free(targetNetBiosNameW); + free(targetNetAddressesWLength); + + if (targetNetAddressesCount > 0) + { + UINT32 i; + for (i = 0; i < targetNetAddressesCount; i++) + free(targetNetAddressesW[i]); + free(targetNetAddressesW); + } + + return FALSE; +} + static BOOL freerdp_peer_is_write_blocked(freerdp_peer* peer) { rdpTransport* transport = peer->context->rdp->transport; @@ -978,6 +1217,7 @@ freerdp_peer* freerdp_peer_new(int sockfd) client->Close = freerdp_peer_close; client->Disconnect = freerdp_peer_disconnect; client->SendChannelData = freerdp_peer_send_channel_data; + client->SendServerRedirection = freerdp_peer_send_server_redirection_pdu; client->IsWriteBlocked = freerdp_peer_is_write_blocked; client->DrainOutputBuffer = freerdp_peer_drain_output_buffer; client->HasMoreToRead = freerdp_peer_has_more_to_read; From cce52d2cc183fb0968aaad59ca53d0a9dc394ca1 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Wed, 16 Nov 2022 11:19:41 +0100 Subject: [PATCH 302/496] Updated version to 2.9.0 --- CMakeLists.txt | 2 +- client/Android/android_freerdp.c | 2 +- winpr/CMakeLists.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index aa1131d3d49d..811cd39b8265 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -85,7 +85,7 @@ if ($ENV{BUILD_NUMBER}) endif() set(WITH_LIBRARY_VERSIONING "ON") -set(RAW_VERSION_STRING "2.8.1") +set(RAW_VERSION_STRING "2.9.0") if(EXISTS "${CMAKE_SOURCE_DIR}/.source_tag") file(READ ${CMAKE_SOURCE_DIR}/.source_tag RAW_VERSION_STRING) elseif(USE_VERSION_FROM_GIT_TAG) diff --git a/client/Android/android_freerdp.c b/client/Android/android_freerdp.c index 019a7193e6b8..b79a563b53ad 100644 --- a/client/Android/android_freerdp.c +++ b/client/Android/android_freerdp.c @@ -57,7 +57,7 @@ #define TAG CLIENT_TAG("android") /* Defines the JNI version supported by this library. */ -#define FREERDP_JNI_VERSION "2.8.1" +#define FREERDP_JNI_VERSION "2.9.0" static void android_OnChannelConnectedEventHandler(void* context, ChannelConnectedEventArgs* e) { diff --git a/winpr/CMakeLists.txt b/winpr/CMakeLists.txt index f168f997dd61..05eefe4c1464 100644 --- a/winpr/CMakeLists.txt +++ b/winpr/CMakeLists.txt @@ -57,7 +57,7 @@ if (NOT WIN32) endif() # Soname versioning -set(RAW_VERSION_STRING "2.8.1") +set(RAW_VERSION_STRING "2.9.0") if(EXISTS "${CMAKE_SOURCE_DIR}/.source_tag") file(READ ${CMAKE_SOURCE_DIR}/.source_tag RAW_VERSION_STRING) elseif(USE_VERSION_FROM_GIT_TAG) From fa8e1b1c765a4466030ac52240f052c0b440a4d1 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Wed, 16 Nov 2022 11:25:17 +0100 Subject: [PATCH 303/496] changelog --- ChangeLog | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index a8ff43913c38..68c40382cdd8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,13 @@ -# 20xx-xx-xx Version 2.8.x +# 2022-11-16 Version 2.9.0 Notewhorth changes: +* Backported #8252: Support sending server redirection PDU +* Backported #8406: Ensure X11 client cursor is never smaller 1x1 +* Backported #8403: Fixed multiple client side input validation issues + (CVE-2022-39316, CVE-2022-39317, CVE-2022-39318, CVE-2022-39319, + CVE-2022-39320, CVE-2022-41877, CVE-2022-39347) +* Backported #7282: Proxy server now discards input events sent before + activation was received * Backported #8324: Internal replacements for md4, md5 and hmac-md5 For the time being the RDP protocol requires these outdated hash algorithms. So any distribution that wants to ship a working @@ -14,7 +21,7 @@ Fixed issues: * Backported #7282: Discard input events before activation (Fixes #8374) For a complete and detailed change log since the last release run: -git log 2.8.1..2.8.x +git log 2.8.1..2.9.0 # 2022-10-12 Version 2.8.1 From 8f5fa9aeec576bd7ec21c14c633c97f5c77696ca Mon Sep 17 00:00:00 2001 From: Steve Pronovost Date: Sat, 16 Oct 2021 09:22:58 -0700 Subject: [PATCH 304/496] Fix connection negotiation with mstsc/msrdc mstsc/msrdc includes an optional correlation info (RDP_NEG_CORRELATION_INFO) during connection negotiation. This confuses FreeRDP which interpret this as a cookie and eventually fails the negotiation, preventing a successful connection to these RDP client. This commit addresses 3 things. 1) When processing connection token or cookie, skip if the remaining bytes are neither. 2) After processing the RDP_NEG_REQ info, skip the optional correlation info (RDP_NEG_CORRELATION_INFO) if one is present. 3) Allow local connection without server certificate when the client inherently trust the server. (cherry picked from commit 592f8d95be8aa9cb2a8f75d83f22eb498716136f) --- libfreerdp/core/nego.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/libfreerdp/core/nego.c b/libfreerdp/core/nego.c index 48739a78d183..5c3c54a1140a 100644 --- a/libfreerdp/core/nego.c +++ b/libfreerdp/core/nego.c @@ -710,6 +710,11 @@ static BOOL nego_read_request_token_or_cookie(rdpNego* nego, wStream* s) if (memcmp(Stream_Pointer(s), "Cookie: mstshash=", 17) != 0) { + if (memcmp(Stream_Pointer(s), "Cookie: msts=", 13) != 0) + { + /* remaining bytes are neither a token nor a cookie */ + return TRUE; + } isToken = TRUE; } else @@ -805,6 +810,14 @@ BOOL nego_read_request(rdpNego* nego, wStream* s) return FALSE; } + /* Skip over optional RDP_NEG_CORRELATION_INFO + * see MS-RDPBCGR 2.2.1.1.2 RDP Correlation Info (RDP_NEG_CORRELATION_INFO) + */ + if (Stream_GetRemainingLength(s) >= 36) + { + Stream_Seek(s, 36); + } + return tpkt_ensure_stream_consumed(s, length); } @@ -1139,8 +1152,8 @@ BOOL nego_send_negotiation_response(rdpNego* nego) settings->UseRdpSecurityLayer = FALSE; settings->EncryptionLevel = ENCRYPTION_LEVEL_NONE; } - - if (!settings->RdpServerRsaKey && !settings->RdpKeyFile && !settings->RdpKeyContent) + else if (!settings->RdpServerRsaKey && !settings->RdpKeyFile && + !settings->RdpKeyContent) { WLog_ERR(TAG, "Missing server certificate"); return FALSE; From 6d9f7d7616abdea5629f59d0dea53b1a2d7f71ba Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Mon, 21 Nov 2022 15:18:51 +0100 Subject: [PATCH 305/496] [channels,printer] Fixed reference counting --- channels/printer/client/cups/printer_cups.c | 2 +- channels/printer/client/win/printer_win.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/channels/printer/client/cups/printer_cups.c b/channels/printer/client/cups/printer_cups.c index baa46e5d2e17..ed0eb90e948d 100644 --- a/channels/printer/client/cups/printer_cups.c +++ b/channels/printer/client/cups/printer_cups.c @@ -403,8 +403,8 @@ FREERDP_API rdpPrinterDriver* freerdp_printer_client_subsystem_entry(void) uniq_cups_driver->driver.ReleaseRef = printer_cups_release_ref_driver; uniq_cups_driver->id_sequence = 1; - uniq_cups_driver->driver.AddRef(&uniq_cups_driver->driver); } + uniq_cups_driver->driver.AddRef(&uniq_cups_driver->driver); return &uniq_cups_driver->driver; } diff --git a/channels/printer/client/win/printer_win.c b/channels/printer/client/win/printer_win.c index 86b5e66d9240..81c7055529cc 100644 --- a/channels/printer/client/win/printer_win.c +++ b/channels/printer/client/win/printer_win.c @@ -452,8 +452,8 @@ FREERDP_API rdpPrinterDriver* freerdp_printer_client_subsystem_entry(void) win_driver->driver.ReleaseRef = printer_win_release_ref_driver; win_driver->id_sequence = 1; - win_driver->driver.AddRef(&win_driver->driver); } + win_driver->driver.AddRef(&win_driver->driver); return &win_driver->driver; } From e57d1e0fc207c29acd35868c8a547d06b14789c8 Mon Sep 17 00:00:00 2001 From: akarl10 Date: Mon, 21 Nov 2022 11:06:57 +0100 Subject: [PATCH 306/496] [ntlm]: use rfc5929 binding hash algorithm rfc5929 mandates some specific hashes for the binding algorithm (cherry picked from commit 3a10bcd36a062437af9db40b45260def71144b01) --- include/freerdp/crypto/crypto.h | 2 ++ libfreerdp/crypto/crypto.c | 51 +++++++++++++++++++++++++++++++++ libfreerdp/crypto/tls.c | 20 ++++++++++++- 3 files changed, 72 insertions(+), 1 deletion(-) diff --git a/include/freerdp/crypto/crypto.h b/include/freerdp/crypto/crypto.h index 3138362cf1b4..bbc6a2cd29e5 100644 --- a/include/freerdp/crypto/crypto.h +++ b/include/freerdp/crypto/crypto.h @@ -22,6 +22,7 @@ /* OpenSSL includes windows.h */ #include +#include #include #include @@ -54,6 +55,7 @@ extern "C" typedef struct crypto_cert_struct* CryptoCert; FREERDP_API CryptoCert crypto_cert_read(BYTE* data, UINT32 length); + FREERDP_API WINPR_MD_TYPE crypto_cert_get_signature_alg(X509* xcert); FREERDP_API BYTE* crypto_cert_hash(X509* xcert, const char* hash, UINT32* length); FREERDP_API char* crypto_cert_fingerprint_by_hash(X509* xcert, const char* hash); FREERDP_API char* crypto_cert_fingerprint(X509* xcert); diff --git a/libfreerdp/crypto/crypto.c b/libfreerdp/crypto/crypto.c index 82df956c2669..00dca582f853 100644 --- a/libfreerdp/crypto/crypto.c +++ b/libfreerdp/crypto/crypto.c @@ -21,7 +21,10 @@ #include "config.h" #endif +#include + #include +#include #include #include @@ -943,3 +946,51 @@ void crypto_cert_print_info(X509* xcert) free(issuer); free(subject); } + +WINPR_MD_TYPE crypto_cert_get_signature_alg(X509* xcert) +{ + WINPR_ASSERT(xcert); + + const int nid = X509_get_signature_nid(xcert); + + int hash_nid = 0; + if (OBJ_find_sigid_algs(nid, &hash_nid, NULL) != 1) + return WINPR_MD_NONE; + + switch (hash_nid) + { + case NID_md2: + return WINPR_MD_MD2; + case NID_md4: + return WINPR_MD_MD4; + case NID_md5: + return WINPR_MD_MD5; + case NID_sha1: + return WINPR_MD_SHA1; + case NID_sha224: + return WINPR_MD_SHA224; + case NID_sha256: + return WINPR_MD_SHA256; + case NID_sha384: + return WINPR_MD_SHA384; + case NID_sha512: + return WINPR_MD_SHA512; + case NID_ripemd160: + return WINPR_MD_RIPEMD160; + case NID_sha3_224: + return WINPR_MD_SHA3_224; + case NID_sha3_256: + return WINPR_MD_SHA3_256; + case NID_sha3_384: + return WINPR_MD_SHA3_384; + case NID_sha3_512: + return WINPR_MD_SHA3_512; + case NID_shake128: + return WINPR_MD_SHAKE128; + case NID_shake256: + return WINPR_MD_SHAKE256; + case NID_undef: + default: + return WINPR_MD_NONE; + } +} diff --git a/libfreerdp/crypto/tls.c b/libfreerdp/crypto/tls.c index 99b079212db7..29a17e2dcc33 100644 --- a/libfreerdp/crypto/tls.c +++ b/libfreerdp/crypto/tls.c @@ -617,7 +617,25 @@ static SecPkgContext_Bindings* tls_get_channel_bindings(X509* cert) SEC_CHANNEL_BINDINGS* ChannelBindings; SecPkgContext_Bindings* ContextBindings; const size_t PrefixLength = strnlen(TLS_SERVER_END_POINT, ARRAYSIZE(TLS_SERVER_END_POINT)); - BYTE* CertificateHash = crypto_cert_hash(cert, "sha256", &CertificateHashLength); + + /* See https://www.rfc-editor.org/rfc/rfc5929 for details about hashes */ + WINPR_MD_TYPE alg = crypto_cert_get_signature_alg(cert); + const char* hash; + switch (alg) + { + + case WINPR_MD_MD5: + case WINPR_MD_SHA1: + hash = winpr_md_type_to_string(WINPR_MD_SHA256); + break; + default: + hash = winpr_md_type_to_string(alg); + break; + } + if (!hash) + return NULL; + + BYTE* CertificateHash = crypto_cert_hash(cert, hash, &CertificateHashLength); if (!CertificateHash) return NULL; From 1731f3074bbfa3e0a306ca94595feca22156e10a Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Mon, 21 Nov 2022 13:03:32 +0100 Subject: [PATCH 307/496] [winpr,crypto] Split headers Split windows API emulation from custom functions Including both might yield issues with OpenSSL headers (cherry picked from commit d03f230426a8860657ca9fc1ca111fd165e33579) --- libfreerdp/core/settings.c | 1 + winpr/include/winpr/crypto.h | 599 ---------------- winpr/include/winpr/schannel.h | 1 + winpr/include/winpr/wincrypt.h | 637 ++++++++++++++++++ winpr/libwinpr/crypto/cert.c | 1 + winpr/libwinpr/crypto/crypto.c | 1 + .../TestCryptoCertEnumCertificatesInStore.c | 1 + .../crypto/test/TestCryptoProtectMemory.c | 1 + winpr/libwinpr/sspi/Schannel/schannel.c | 1 + 9 files changed, 644 insertions(+), 599 deletions(-) create mode 100644 winpr/include/winpr/wincrypt.h diff --git a/libfreerdp/core/settings.c b/libfreerdp/core/settings.c index 76b0e790b40b..d0d80fff89e5 100644 --- a/libfreerdp/core/settings.c +++ b/libfreerdp/core/settings.c @@ -35,6 +35,7 @@ #include #include #include +#include #include #include diff --git a/winpr/include/winpr/crypto.h b/winpr/include/winpr/crypto.h index c550719ced7c..c5aee30b3f32 100644 --- a/winpr/include/winpr/crypto.h +++ b/winpr/include/winpr/crypto.h @@ -25,605 +25,6 @@ #include -#ifdef _WIN32 - -#include - -#endif - -#ifndef ALG_TYPE_RESERVED7 -#define ALG_TYPE_RESERVED7 (7 << 9) -#endif - -#if (NTDDI_VERSION <= 0x05010200) -#define ALG_SID_SHA_256 12 -#define ALG_SID_SHA_384 13 -#define ALG_SID_SHA_512 14 -#define CALG_SHA_256 (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_SHA_256) -#define CALG_SHA_384 (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_SHA_384) -#define CALG_SHA_512 (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_SHA_512) -#endif - -#ifndef _WIN32 - -/* ncrypt.h */ - -typedef ULONG_PTR NCRYPT_HANDLE; -typedef ULONG_PTR NCRYPT_PROV_HANDLE; -typedef ULONG_PTR NCRYPT_KEY_HANDLE; -typedef ULONG_PTR NCRYPT_HASH_HANDLE; -typedef ULONG_PTR NCRYPT_SECRET_HANDLE; - -/* wincrypt.h */ - -#define GET_ALG_CLASS(x) (x & (7 << 13)) -#define GET_ALG_TYPE(x) (x & (15 << 9)) -#define GET_ALG_SID(x) (x & (511)) - -#define ALG_CLASS_ANY (0) -#define ALG_CLASS_SIGNATURE (1 << 13) -#define ALG_CLASS_MSG_ENCRYPT (2 << 13) -#define ALG_CLASS_DATA_ENCRYPT (3 << 13) -#define ALG_CLASS_HASH (4 << 13) -#define ALG_CLASS_KEY_EXCHANGE (5 << 13) -#define ALG_CLASS_ALL (7 << 13) - -#define ALG_TYPE_ANY (0) -#define ALG_TYPE_DSS (1 << 9) -#define ALG_TYPE_RSA (2 << 9) -#define ALG_TYPE_BLOCK (3 << 9) -#define ALG_TYPE_STREAM (4 << 9) -#define ALG_TYPE_DH (5 << 9) -#define ALG_TYPE_SECURECHANNEL (6 << 9) - -#define ALG_SID_ANY (0) - -#define ALG_SID_RSA_ANY 0 -#define ALG_SID_RSA_PKCS 1 -#define ALG_SID_RSA_MSATWORK 2 -#define ALG_SID_RSA_ENTRUST 3 -#define ALG_SID_RSA_PGP 4 - -#define ALG_SID_DSS_ANY 0 -#define ALG_SID_DSS_PKCS 1 -#define ALG_SID_DSS_DMS 2 - -#define ALG_SID_DES 1 -#define ALG_SID_3DES 3 -#define ALG_SID_DESX 4 -#define ALG_SID_IDEA 5 -#define ALG_SID_CAST 6 -#define ALG_SID_SAFERSK64 7 -#define ALG_SID_SAFERSK128 8 -#define ALG_SID_3DES_112 9 -#define ALG_SID_CYLINK_MEK 12 -#define ALG_SID_RC5 13 - -#define ALG_SID_AES_128 14 -#define ALG_SID_AES_192 15 -#define ALG_SID_AES_256 16 -#define ALG_SID_AES 17 - -#define ALG_SID_SKIPJACK 10 -#define ALG_SID_TEK 11 - -#define CRYPT_MODE_CBCI 6 -#define CRYPT_MODE_CFBP 7 -#define CRYPT_MODE_OFBP 8 -#define CRYPT_MODE_CBCOFM 9 -#define CRYPT_MODE_CBCOFMI 10 - -#define ALG_SID_RC2 2 - -#define ALG_SID_RC4 1 -#define ALG_SID_SEAL 2 - -#define ALG_SID_DH_SANDF 1 -#define ALG_SID_DH_EPHEM 2 -#define ALG_SID_AGREED_KEY_ANY 3 -#define ALG_SID_KEA 4 - -#define ALG_SID_ECDH 5 - -#define ALG_SID_MD2 1 -#define ALG_SID_MD4 2 -#define ALG_SID_MD5 3 -#define ALG_SID_SHA 4 -#define ALG_SID_SHA1 4 -#define ALG_SID_MAC 5 -#define ALG_SID_RIPEMD 6 -#define ALG_SID_RIPEMD160 7 -#define ALG_SID_SSL3SHAMD5 8 -#define ALG_SID_HMAC 9 -#define ALG_SID_TLS1PRF 10 - -#define ALG_SID_HASH_REPLACE_OWF 11 - -#define ALG_SID_SHA_256 12 -#define ALG_SID_SHA_384 13 -#define ALG_SID_SHA_512 14 - -#define ALG_SID_SSL3_MASTER 1 -#define ALG_SID_SCHANNEL_MASTER_HASH 2 -#define ALG_SID_SCHANNEL_MAC_KEY 3 -#define ALG_SID_PCT1_MASTER 4 -#define ALG_SID_SSL2_MASTER 5 -#define ALG_SID_TLS1_MASTER 6 -#define ALG_SID_SCHANNEL_ENC_KEY 7 - -#define ALG_SID_ECMQV 1 - -#define CALG_MD2 (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_MD2) -#define CALG_MD4 (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_MD4) -#define CALG_MD5 (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_MD5) -#define CALG_SHA (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_SHA) -#define CALG_SHA1 (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_SHA1) -#define CALG_MAC (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_MAC) -#define CALG_RSA_SIGN (ALG_CLASS_SIGNATURE | ALG_TYPE_RSA | ALG_SID_RSA_ANY) -#define CALG_DSS_SIGN (ALG_CLASS_SIGNATURE | ALG_TYPE_DSS | ALG_SID_DSS_ANY) - -#define CALG_NO_SIGN (ALG_CLASS_SIGNATURE | ALG_TYPE_ANY | ALG_SID_ANY) - -#define CALG_RSA_KEYX (ALG_CLASS_KEY_EXCHANGE | ALG_TYPE_RSA | ALG_SID_RSA_ANY) -#define CALG_DES (ALG_CLASS_DATA_ENCRYPT | ALG_TYPE_BLOCK | ALG_SID_DES) -#define CALG_3DES_112 (ALG_CLASS_DATA_ENCRYPT | ALG_TYPE_BLOCK | ALG_SID_3DES_112) -#define CALG_3DES (ALG_CLASS_DATA_ENCRYPT | ALG_TYPE_BLOCK | ALG_SID_3DES) -#define CALG_DESX (ALG_CLASS_DATA_ENCRYPT | ALG_TYPE_BLOCK | ALG_SID_DESX) -#define CALG_RC2 (ALG_CLASS_DATA_ENCRYPT | ALG_TYPE_BLOCK | ALG_SID_RC2) -#define CALG_RC4 (ALG_CLASS_DATA_ENCRYPT | ALG_TYPE_STREAM | ALG_SID_RC4) -#define CALG_SEAL (ALG_CLASS_DATA_ENCRYPT | ALG_TYPE_STREAM | ALG_SID_SEAL) -#define CALG_DH_SF (ALG_CLASS_KEY_EXCHANGE | ALG_TYPE_DH | ALG_SID_DH_SANDF) -#define CALG_DH_EPHEM (ALG_CLASS_KEY_EXCHANGE | ALG_TYPE_DH | ALG_SID_DH_EPHEM) -#define CALG_AGREEDKEY_ANY (ALG_CLASS_KEY_EXCHANGE | ALG_TYPE_DH | ALG_SID_AGREED_KEY_ANY) -#define CALG_KEA_KEYX (ALG_CLASS_KEY_EXCHANGE | ALG_TYPE_DH | ALG_SID_KEA) -#define CALG_HUGHES_MD5 (ALG_CLASS_KEY_EXCHANGE | ALG_TYPE_ANY | ALG_SID_MD5) -#define CALG_SKIPJACK (ALG_CLASS_DATA_ENCRYPT | ALG_TYPE_BLOCK | ALG_SID_SKIPJACK) -#define CALG_TEK (ALG_CLASS_DATA_ENCRYPT | ALG_TYPE_BLOCK | ALG_SID_TEK) -#define CALG_CYLINK_MEK (ALG_CLASS_DATA_ENCRYPT | ALG_TYPE_BLOCK | ALG_SID_CYLINK_MEK) -#define CALG_SSL3_SHAMD5 (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_SSL3SHAMD5) -#define CALG_SSL3_MASTER (ALG_CLASS_MSG_ENCRYPT | ALG_TYPE_SECURECHANNEL | ALG_SID_SSL3_MASTER) -#define CALG_SCHANNEL_MASTER_HASH \ - (ALG_CLASS_MSG_ENCRYPT | ALG_TYPE_SECURECHANNEL | ALG_SID_SCHANNEL_MASTER_HASH) -#define CALG_SCHANNEL_MAC_KEY \ - (ALG_CLASS_MSG_ENCRYPT | ALG_TYPE_SECURECHANNEL | ALG_SID_SCHANNEL_MAC_KEY) -#define CALG_SCHANNEL_ENC_KEY \ - (ALG_CLASS_MSG_ENCRYPT | ALG_TYPE_SECURECHANNEL | ALG_SID_SCHANNEL_ENC_KEY) -#define CALG_PCT1_MASTER (ALG_CLASS_MSG_ENCRYPT | ALG_TYPE_SECURECHANNEL | ALG_SID_PCT1_MASTER) -#define CALG_SSL2_MASTER (ALG_CLASS_MSG_ENCRYPT | ALG_TYPE_SECURECHANNEL | ALG_SID_SSL2_MASTER) -#define CALG_TLS1_MASTER (ALG_CLASS_MSG_ENCRYPT | ALG_TYPE_SECURECHANNEL | ALG_SID_TLS1_MASTER) -#define CALG_RC5 (ALG_CLASS_DATA_ENCRYPT | ALG_TYPE_BLOCK | ALG_SID_RC5) -#define CALG_HMAC (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_HMAC) -#define CALG_TLS1PRF (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_TLS1PRF) - -#define CALG_HASH_REPLACE_OWF (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_HASH_REPLACE_OWF) -#define CALG_AES_128 (ALG_CLASS_DATA_ENCRYPT | ALG_TYPE_BLOCK | ALG_SID_AES_128) -#define CALG_AES_192 (ALG_CLASS_DATA_ENCRYPT | ALG_TYPE_BLOCK | ALG_SID_AES_192) -#define CALG_AES_256 (ALG_CLASS_DATA_ENCRYPT | ALG_TYPE_BLOCK | ALG_SID_AES_256) -#define CALG_AES (ALG_CLASS_DATA_ENCRYPT | ALG_TYPE_BLOCK | ALG_SID_AES) - -#define CALG_SHA_256 (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_SHA_256) -#define CALG_SHA_384 (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_SHA_384) -#define CALG_SHA_512 (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_SHA_512) - -#define CALG_ECDH (ALG_CLASS_KEY_EXCHANGE | ALG_TYPE_DH | ALG_SID_ECDH) -#define CALG_ECMQV (ALG_CLASS_KEY_EXCHANGE | ALG_TYPE_ANY | ALG_SID_ECMQV) - -typedef struct _CRYPTOAPI_BLOB -{ - DWORD cbData; - BYTE* pbData; -} CRYPT_INTEGER_BLOB, *PCRYPT_INTEGER_BLOB, CRYPT_UINT_BLOB, *PCRYPT_UINT_BLOB, CRYPT_OBJID_BLOB, - *PCRYPT_OBJID_BLOB, CERT_NAME_BLOB, *PCERT_NAME_BLOB, CERT_RDN_VALUE_BLOB, - *PCERT_RDN_VALUE_BLOB, CERT_BLOB, *PCERT_BLOB, CRL_BLOB, *PCRL_BLOB, DATA_BLOB, *PDATA_BLOB, - CRYPT_DATA_BLOB, *PCRYPT_DATA_BLOB, CRYPT_HASH_BLOB, *PCRYPT_HASH_BLOB, CRYPT_DIGEST_BLOB, - *PCRYPT_DIGEST_BLOB, CRYPT_DER_BLOB, *PCRYPT_DER_BLOB, CRYPT_ATTR_BLOB, *PCRYPT_ATTR_BLOB; - -typedef struct _CRYPT_ALGORITHM_IDENTIFIER -{ - LPSTR pszObjId; - CRYPT_OBJID_BLOB Parameters; -} CRYPT_ALGORITHM_IDENTIFIER, *PCRYPT_ALGORITHM_IDENTIFIER; - -typedef struct _CRYPT_BIT_BLOB -{ - DWORD cbData; - BYTE* pbData; - DWORD cUnusedBits; -} CRYPT_BIT_BLOB, *PCRYPT_BIT_BLOB; - -typedef struct _CERT_PUBLIC_KEY_INFO -{ - CRYPT_ALGORITHM_IDENTIFIER Algorithm; - CRYPT_BIT_BLOB PublicKey; -} CERT_PUBLIC_KEY_INFO, *PCERT_PUBLIC_KEY_INFO; - -typedef struct _CERT_EXTENSION -{ - LPSTR pszObjId; - BOOL fCritical; - CRYPT_OBJID_BLOB Value; -} CERT_EXTENSION, *PCERT_EXTENSION; -typedef const CERT_EXTENSION* PCCERT_EXTENSION; - -typedef struct _CERT_INFO -{ - DWORD dwVersion; - CRYPT_INTEGER_BLOB SerialNumber; - CRYPT_ALGORITHM_IDENTIFIER SignatureAlgorithm; - CERT_NAME_BLOB Issuer; - FILETIME NotBefore; - FILETIME NotAfter; - CERT_NAME_BLOB Subject; - CERT_PUBLIC_KEY_INFO SubjectPublicKeyInfo; - CRYPT_BIT_BLOB IssuerUniqueId; - CRYPT_BIT_BLOB SubjectUniqueId; - DWORD cExtension; - PCERT_EXTENSION rgExtension; -} CERT_INFO, *PCERT_INFO; - -typedef void* HCERTSTORE; -typedef ULONG_PTR HCRYPTPROV; -typedef ULONG_PTR HCRYPTPROV_LEGACY; - -typedef struct _CERT_CONTEXT -{ - DWORD dwCertEncodingType; - BYTE* pbCertEncoded; - DWORD cbCertEncoded; - PCERT_INFO pCertInfo; - HCERTSTORE hCertStore; -} CERT_CONTEXT, *PCERT_CONTEXT; -typedef const CERT_CONTEXT* PCCERT_CONTEXT; - -#define CERT_ENCODING_TYPE_MASK 0x0000FFFF -#define CMSG_ENCODING_TYPE_MASK 0xFFFF0000 -#define GET_CERT_ENCODING_TYPE(x) (x & CERT_ENCODING_TYPE_MASK) -#define GET_CMSG_ENCODING_TYPE(x) (x & CMSG_ENCODING_TYPE_MASK) - -#define CRYPT_ASN_ENCODING 0x00000001 -#define CRYPT_NDR_ENCODING 0x00000002 -#define X509_ASN_ENCODING 0x00000001 -#define X509_NDR_ENCODING 0x00000002 -#define PKCS_7_ASN_ENCODING 0x00010000 -#define PKCS_7_NDR_ENCODING 0x00020000 - -#define CERT_COMPARE_MASK 0xFFFF -#define CERT_COMPARE_SHIFT 16 -#define CERT_COMPARE_ANY 0 -#define CERT_COMPARE_SHA1_HASH 1 -#define CERT_COMPARE_NAME 2 -#define CERT_COMPARE_ATTR 3 -#define CERT_COMPARE_MD5_HASH 4 -#define CERT_COMPARE_PROPERTY 5 -#define CERT_COMPARE_PUBLIC_KEY 6 -#define CERT_COMPARE_HASH CERT_COMPARE_SHA1_HASH -#define CERT_COMPARE_NAME_STR_A 7 -#define CERT_COMPARE_NAME_STR_W 8 -#define CERT_COMPARE_KEY_SPEC 9 -#define CERT_COMPARE_ENHKEY_USAGE 10 -#define CERT_COMPARE_CTL_USAGE CERT_COMPARE_ENHKEY_USAGE -#define CERT_COMPARE_SUBJECT_CERT 11 -#define CERT_COMPARE_ISSUER_OF 12 -#define CERT_COMPARE_EXISTING 13 -#define CERT_COMPARE_SIGNATURE_HASH 14 -#define CERT_COMPARE_KEY_IDENTIFIER 15 -#define CERT_COMPARE_CERT_ID 16 -#define CERT_COMPARE_CROSS_CERT_DIST_POINTS 17 -#define CERT_COMPARE_PUBKEY_MD5_HASH 18 -#define CERT_COMPARE_SUBJECT_INFO_ACCESS 19 -#define CERT_COMPARE_HASH_STR 20 -#define CERT_COMPARE_HAS_PRIVATE_KEY 21 - -#define CERT_FIND_ANY (CERT_COMPARE_ANY << CERT_COMPARE_SHIFT) -#define CERT_FIND_SHA1_HASH (CERT_COMPARE_SHA1_HASH << CERT_COMPARE_SHIFT) -#define CERT_FIND_MD5_HASH (CERT_COMPARE_MD5_HASH << CERT_COMPARE_SHIFT) -#define CERT_FIND_SIGNATURE_HASH (CERT_COMPARE_SIGNATURE_HASH << CERT_COMPARE_SHIFT) -#define CERT_FIND_KEY_IDENTIFIER (CERT_COMPARE_KEY_IDENTIFIER << CERT_COMPARE_SHIFT) -#define CERT_FIND_HASH CERT_FIND_SHA1_HASH -#define CERT_FIND_PROPERTY (CERT_COMPARE_PROPERTY << CERT_COMPARE_SHIFT) -#define CERT_FIND_PUBLIC_KEY (CERT_COMPARE_PUBLIC_KEY << CERT_COMPARE_SHIFT) -#define CERT_FIND_SUBJECT_NAME (CERT_COMPARE_NAME << CERT_COMPARE_SHIFT | CERT_INFO_SUBJECT_FLAG) -#define CERT_FIND_SUBJECT_ATTR (CERT_COMPARE_ATTR << CERT_COMPARE_SHIFT | CERT_INFO_SUBJECT_FLAG) -#define CERT_FIND_ISSUER_NAME (CERT_COMPARE_NAME << CERT_COMPARE_SHIFT | CERT_INFO_ISSUER_FLAG) -#define CERT_FIND_ISSUER_ATTR (CERT_COMPARE_ATTR << CERT_COMPARE_SHIFT | CERT_INFO_ISSUER_FLAG) -#define CERT_FIND_SUBJECT_STR_A \ - (CERT_COMPARE_NAME_STR_A << CERT_COMPARE_SHIFT | CERT_INFO_SUBJECT_FLAG) -#define CERT_FIND_SUBJECT_STR_W \ - (CERT_COMPARE_NAME_STR_W << CERT_COMPARE_SHIFT | CERT_INFO_SUBJECT_FLAG) -#define CERT_FIND_SUBJECT_STR CERT_FIND_SUBJECT_STR_W -#define CERT_FIND_ISSUER_STR_A \ - (CERT_COMPARE_NAME_STR_A << CERT_COMPARE_SHIFT | CERT_INFO_ISSUER_FLAG) -#define CERT_FIND_ISSUER_STR_W \ - (CERT_COMPARE_NAME_STR_W << CERT_COMPARE_SHIFT | CERT_INFO_ISSUER_FLAG) -#define CERT_FIND_ISSUER_STR CERT_FIND_ISSUER_STR_W -#define CERT_FIND_KEY_SPEC (CERT_COMPARE_KEY_SPEC << CERT_COMPARE_SHIFT) -#define CERT_FIND_ENHKEY_USAGE (CERT_COMPARE_ENHKEY_USAGE << CERT_COMPARE_SHIFT) -#define CERT_FIND_CTL_USAGE CERT_FIND_ENHKEY_USAGE -#define CERT_FIND_SUBJECT_CERT (CERT_COMPARE_SUBJECT_CERT << CERT_COMPARE_SHIFT) -#define CERT_FIND_ISSUER_OF (CERT_COMPARE_ISSUER_OF << CERT_COMPARE_SHIFT) -#define CERT_FIND_EXISTING (CERT_COMPARE_EXISTING << CERT_COMPARE_SHIFT) -#define CERT_FIND_CERT_ID (CERT_COMPARE_CERT_ID << CERT_COMPARE_SHIFT) -#define CERT_FIND_CROSS_CERT_DIST_POINTS (CERT_COMPARE_CROSS_CERT_DIST_POINTS << CERT_COMPARE_SHIFT) -#define CERT_FIND_PUBKEY_MD5_HASH (CERT_COMPARE_PUBKEY_MD5_HASH << CERT_COMPARE_SHIFT) -#define CERT_FIND_SUBJECT_INFO_ACCESS (CERT_COMPARE_SUBJECT_INFO_ACCESS << CERT_COMPARE_SHIFT) -#define CERT_FIND_HASH_STR (CERT_COMPARE_HASH_STR << CERT_COMPARE_SHIFT) -#define CERT_FIND_HAS_PRIVATE_KEY (CERT_COMPARE_HAS_PRIVATE_KEY << CERT_COMPARE_SHIFT) - -#define CERT_FIND_OPTIONAL_ENHKEY_USAGE_FLAG 0x1 -#define CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG 0x2 -#define CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG 0x4 -#define CERT_FIND_NO_ENHKEY_USAGE_FLAG 0x8 -#define CERT_FIND_OR_ENHKEY_USAGE_FLAG 0x10 -#define CERT_FIND_VALID_ENHKEY_USAGE_FLAG 0x20 -#define CERT_FIND_OPTIONAL_CTL_USAGE_FLAG CERT_FIND_OPTIONAL_ENHKEY_USAGE_FLAG -#define CERT_FIND_EXT_ONLY_CTL_USAGE_FLAG CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG -#define CERT_FIND_PROP_ONLY_CTL_USAGE_FLAG CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG -#define CERT_FIND_NO_CTL_USAGE_FLAG CERT_FIND_NO_ENHKEY_USAGE_FLAG -#define CERT_FIND_OR_CTL_USAGE_FLAG CERT_FIND_OR_ENHKEY_USAGE_FLAG -#define CERT_FIND_VALID_CTL_USAGE_FLAG CERT_FIND_VALID_ENHKEY_USAGE_FLAG - -#define CERT_NAME_EMAIL_TYPE 1 -#define CERT_NAME_RDN_TYPE 2 -#define CERT_NAME_ATTR_TYPE 3 -#define CERT_NAME_SIMPLE_DISPLAY_TYPE 4 -#define CERT_NAME_FRIENDLY_DISPLAY_TYPE 5 -#define CERT_NAME_DNS_TYPE 6 -#define CERT_NAME_URL_TYPE 7 -#define CERT_NAME_UPN_TYPE 8 - -#define CERT_NAME_ISSUER_FLAG 0x1 -#define CERT_NAME_DISABLE_IE4_UTF8_FLAG 0x00010000 - -#define CERT_NAME_SEARCH_ALL_NAMES_FLAG 0x2 - -#define CERT_STORE_PROV_MSG ((LPCSTR)1) -#define CERT_STORE_PROV_MEMORY ((LPCSTR)2) -#define CERT_STORE_PROV_FILE ((LPCSTR)3) -#define CERT_STORE_PROV_REG ((LPCSTR)4) -#define CERT_STORE_PROV_PKCS7 ((LPCSTR)5) -#define CERT_STORE_PROV_SERIALIZED ((LPCSTR)6) -#define CERT_STORE_PROV_FILENAME_A ((LPCSTR)7) -#define CERT_STORE_PROV_FILENAME_W ((LPCSTR)8) -#define CERT_STORE_PROV_FILENAME CERT_STORE_PROV_FILENAME_W -#define CERT_STORE_PROV_SYSTEM_A ((LPCSTR)9) -#define CERT_STORE_PROV_SYSTEM_W ((LPCSTR)10) -#define CERT_STORE_PROV_SYSTEM CERT_STORE_PROV_SYSTEM_W -#define CERT_STORE_PROV_COLLECTION ((LPCSTR)11) -#define CERT_STORE_PROV_SYSTEM_REGISTRY_A ((LPCSTR)12) -#define CERT_STORE_PROV_SYSTEM_REGISTRY_W ((LPCSTR)13) -#define CERT_STORE_PROV_SYSTEM_REGISTRY CERT_STORE_PROV_SYSTEM_REGISTRY_W -#define CERT_STORE_PROV_PHYSICAL_W ((LPCSTR)14) -#define CERT_STORE_PROV_PHYSICAL CERT_STORE_PROV_PHYSICAL_W -#define CERT_STORE_PROV_SMART_CARD_W ((LPCSTR)15) -#define CERT_STORE_PROV_SMART_CARD CERT_STORE_PROV_SMART_CARD_W -#define CERT_STORE_PROV_LDAP_W ((LPCSTR)16) -#define CERT_STORE_PROV_LDAP CERT_STORE_PROV_LDAP_W -#define CERT_STORE_PROV_PKCS12 ((LPCSTR)17) -#define sz_CERT_STORE_PROV_MEMORY "Memory" -#define sz_CERT_STORE_PROV_FILENAME_W "File" -#define sz_CERT_STORE_PROV_FILENAME sz_CERT_STORE_PROV_FILENAME_W -#define sz_CERT_STORE_PROV_SYSTEM_W "System" -#define sz_CERT_STORE_PROV_SYSTEM sz_CERT_STORE_PROV_SYSTEM_W -#define sz_CERT_STORE_PROV_PKCS7 "PKCS7" -#define sz_CERT_STORE_PROV_PKCS12 "PKCS12" -#define sz_CERT_STORE_PROV_SERIALIZED "Serialized" -#define sz_CERT_STORE_PROV_COLLECTION "Collection" -#define sz_CERT_STORE_PROV_SYSTEM_REGISTRY_W "SystemRegistry" -#define sz_CERT_STORE_PROV_SYSTEM_REGISTRY sz_CERT_STORE_PROV_SYSTEM_REGISTRY_W -#define sz_CERT_STORE_PROV_PHYSICAL_W "Physical" -#define sz_CERT_STORE_PROV_PHYSICAL sz_CERT_STORE_PROV_PHYSICAL_W -#define sz_CERT_STORE_PROV_SMART_CARD_W "SmartCard" -#define sz_CERT_STORE_PROV_SMART_CARD sz_CERT_STORE_PROV_SMART_CARD_W -#define sz_CERT_STORE_PROV_LDAP_W "Ldap" -#define sz_CERT_STORE_PROV_LDAP sz_CERT_STORE_PROV_LDAP_W - -#define CERT_STORE_SIGNATURE_FLAG 0x00000001 -#define CERT_STORE_TIME_VALIDITY_FLAG 0x00000002 -#define CERT_STORE_REVOCATION_FLAG 0x00000004 -#define CERT_STORE_NO_CRL_FLAG 0x00010000 -#define CERT_STORE_NO_ISSUER_FLAG 0x00020000 -#define CERT_STORE_BASE_CRL_FLAG 0x00000100 -#define CERT_STORE_DELTA_CRL_FLAG 0x00000200 - -#define CERT_STORE_NO_CRYPT_RELEASE_FLAG 0x00000001 -#define CERT_STORE_SET_LOCALIZED_NAME_FLAG 0x00000002 -#define CERT_STORE_DEFER_CLOSE_UNTIL_LAST_FREE_FLAG 0x00000004 -#define CERT_STORE_DELETE_FLAG 0x00000010 -#define CERT_STORE_UNSAFE_PHYSICAL_FLAG 0x00000020 -#define CERT_STORE_SHARE_STORE_FLAG 0x00000040 -#define CERT_STORE_SHARE_CONTEXT_FLAG 0x00000080 -#define CERT_STORE_MANIFOLD_FLAG 0x00000100 -#define CERT_STORE_ENUM_ARCHIVED_FLAG 0x00000200 -#define CERT_STORE_UPDATE_KEYID_FLAG 0x00000400 -#define CERT_STORE_BACKUP_RESTORE_FLAG 0x00000800 -#define CERT_STORE_READONLY_FLAG 0x00008000 -#define CERT_STORE_OPEN_EXISTING_FLAG 0x00004000 -#define CERT_STORE_CREATE_NEW_FLAG 0x00002000 -#define CERT_STORE_MAXIMUM_ALLOWED_FLAG 0x00001000 - -#define CERT_SYSTEM_STORE_MASK 0xFFFF0000 -#define CERT_SYSTEM_STORE_RELOCATE_FLAG 0x80000000 -#define CERT_SYSTEM_STORE_UNPROTECTED_FLAG 0x40000000 -#define CERT_SYSTEM_STORE_DEFER_READ_FLAG 0x20000000 -#define CERT_SYSTEM_STORE_LOCATION_MASK 0x00FF0000 -#define CERT_SYSTEM_STORE_LOCATION_SHIFT 16 -#define CERT_SYSTEM_STORE_CURRENT_USER_ID 1 -#define CERT_SYSTEM_STORE_LOCAL_MACHINE_ID 2 -#define CERT_SYSTEM_STORE_CURRENT_SERVICE_ID 4 -#define CERT_SYSTEM_STORE_SERVICES_ID 5 -#define CERT_SYSTEM_STORE_USERS_ID 6 -#define CERT_SYSTEM_STORE_CURRENT_USER_GROUP_POLICY_ID 7 -#define CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY_ID 8 -#define CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE_ID 9 - -#define CERT_SYSTEM_STORE_CURRENT_USER \ - (CERT_SYSTEM_STORE_CURRENT_USER_ID << CERT_SYSTEM_STORE_LOCATION_SHIFT) -#define CERT_SYSTEM_STORE_LOCAL_MACHINE \ - (CERT_SYSTEM_STORE_LOCAL_MACHINE_ID << CERT_SYSTEM_STORE_LOCATION_SHIFT) -#define CERT_SYSTEM_STORE_CURRENT_SERVICE \ - (CERT_SYSTEM_STORE_CURRENT_SERVICE_ID << CERT_SYSTEM_STORE_LOCATION_SHIFT) -#define CERT_SYSTEM_STORE_SERVICES \ - (CERT_SYSTEM_STORE_SERVICES_ID << CERT_SYSTEM_STORE_LOCATION_SHIFT) -#define CERT_SYSTEM_STORE_USERS (CERT_SYSTEM_STORE_USERS_ID << CERT_SYSTEM_STORE_LOCATION_SHIFT) -#define CERT_SYSTEM_STORE_CURRENT_USER_GROUP_POLICY \ - (CERT_SYSTEM_STORE_CURRENT_USER_GROUP_POLICY_ID << CERT_SYSTEM_STORE_LOCATION_SHIFT) -#define CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY \ - (CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY_ID << CERT_SYSTEM_STORE_LOCATION_SHIFT) -#define CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE \ - (CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE_ID << CERT_SYSTEM_STORE_LOCATION_SHIFT) - -WINPR_API HCERTSTORE CertOpenStore(LPCSTR lpszStoreProvider, DWORD dwMsgAndCertEncodingType, - HCRYPTPROV_LEGACY hCryptProv, DWORD dwFlags, const void* pvPara); - -WINPR_API HCERTSTORE CertOpenSystemStoreW(HCRYPTPROV_LEGACY hProv, LPCWSTR szSubsystemProtocol); -WINPR_API HCERTSTORE CertOpenSystemStoreA(HCRYPTPROV_LEGACY hProv, LPCSTR szSubsystemProtocol); - -WINPR_API BOOL CertCloseStore(HCERTSTORE hCertStore, DWORD dwFlags); - -#ifdef UNICODE -#define CertOpenSystemStore CertOpenSystemStoreW -#else -#define CertOpenSystemStore CertOpenSystemStoreA -#endif - -#ifdef __cplusplus -extern "C" -{ -#endif - - WINPR_API PCCERT_CONTEXT CertFindCertificateInStore(HCERTSTORE hCertStore, - DWORD dwCertEncodingType, DWORD dwFindFlags, - DWORD dwFindType, const void* pvFindPara, - PCCERT_CONTEXT pPrevCertContext); - - WINPR_API PCCERT_CONTEXT CertEnumCertificatesInStore(HCERTSTORE hCertStore, - PCCERT_CONTEXT pPrevCertContext); - - WINPR_API DWORD CertGetNameStringW(PCCERT_CONTEXT pCertContext, DWORD dwType, DWORD dwFlags, - void* pvTypePara, LPWSTR pszNameString, DWORD cchNameString); - WINPR_API DWORD CertGetNameStringA(PCCERT_CONTEXT pCertContext, DWORD dwType, DWORD dwFlags, - void* pvTypePara, LPSTR pszNameString, DWORD cchNameString); - -#ifdef __cplusplus -} -#endif - -#ifdef UNICODE -#define CertGetNameString CertGetNameStringW -#else -#define CertGetNameString CertGetNameStringA -#endif - -/** - * Data Protection API (DPAPI) - */ - -#define CRYPTPROTECTMEMORY_BLOCK_SIZE 16 - -#define CRYPTPROTECTMEMORY_SAME_PROCESS 0x00000000 -#define CRYPTPROTECTMEMORY_CROSS_PROCESS 0x00000001 -#define CRYPTPROTECTMEMORY_SAME_LOGON 0x00000002 - -#define CRYPTPROTECT_PROMPT_ON_UNPROTECT 0x00000001 -#define CRYPTPROTECT_PROMPT_ON_PROTECT 0x00000002 -#define CRYPTPROTECT_PROMPT_RESERVED 0x00000004 -#define CRYPTPROTECT_PROMPT_STRONG 0x00000008 -#define CRYPTPROTECT_PROMPT_REQUIRE_STRONG 0x00000010 - -#define CRYPTPROTECT_UI_FORBIDDEN 0x1 -#define CRYPTPROTECT_LOCAL_MACHINE 0x4 -#define CRYPTPROTECT_CRED_SYNC 0x8 -#define CRYPTPROTECT_AUDIT 0x10 -#define CRYPTPROTECT_NO_RECOVERY 0x20 -#define CRYPTPROTECT_VERIFY_PROTECTION 0x40 -#define CRYPTPROTECT_CRED_REGENERATE 0x80 - -#define CRYPTPROTECT_FIRST_RESERVED_FLAGVAL 0x0FFFFFFF -#define CRYPTPROTECT_LAST_RESERVED_FLAGVAL 0xFFFFFFFF - -typedef struct _CRYPTPROTECT_PROMPTSTRUCT -{ - DWORD cbSize; - DWORD dwPromptFlags; - HWND hwndApp; - LPCWSTR szPrompt; -} CRYPTPROTECT_PROMPTSTRUCT, *PCRYPTPROTECT_PROMPTSTRUCT; - -#define CRYPTPROTECT_DEFAULT_PROVIDER \ - { \ - 0xdf9d8cd0, 0x1501, 0x11d1, \ - { \ - 0x8c, 0x7a, 0x00, 0xc0, 0x4f, 0xc2, 0x97, 0xeb \ - } \ - } - -#ifdef __cplusplus -extern "C" -{ -#endif - - WINPR_API BOOL CryptProtectMemory(LPVOID pData, DWORD cbData, DWORD dwFlags); - WINPR_API BOOL CryptUnprotectMemory(LPVOID pData, DWORD cbData, DWORD dwFlags); - - WINPR_API BOOL CryptProtectData(DATA_BLOB* pDataIn, LPCWSTR szDataDescr, - DATA_BLOB* pOptionalEntropy, PVOID pvReserved, - CRYPTPROTECT_PROMPTSTRUCT* pPromptStruct, DWORD dwFlags, - DATA_BLOB* pDataOut); - WINPR_API BOOL CryptUnprotectData(DATA_BLOB* pDataIn, LPWSTR* ppszDataDescr, - DATA_BLOB* pOptionalEntropy, PVOID pvReserved, - CRYPTPROTECT_PROMPTSTRUCT* pPromptStruct, DWORD dwFlags, - DATA_BLOB* pDataOut); - -#ifdef __cplusplus -} -#endif - -#define CRYPT_STRING_BASE64HEADER 0x00000000 -#define CRYPT_STRING_BASE64 0x00000001 -#define CRYPT_STRING_BINARY 0x00000002 -#define CRYPT_STRING_BASE64REQUESTHEADER 0x00000003 -#define CRYPT_STRING_HEX 0x00000004 -#define CRYPT_STRING_HEXASCII 0x00000005 -#define CRYPT_STRING_BASE64_ANY 0x00000006 -#define CRYPT_STRING_ANY 0x00000007 -#define CRYPT_STRING_HEX_ANY 0x00000008 -#define CRYPT_STRING_BASE64X509CRLHEADER 0x00000009 -#define CRYPT_STRING_HEXADDR 0x0000000A -#define CRYPT_STRING_HEXASCIIADDR 0x0000000B -#define CRYPT_STRING_HEXRAW 0x0000000C - -#define CRYPT_STRING_HASHDATA 0x10000000 -#define CRYPT_STRING_STRICT 0x20000000 -#define CRYPT_STRING_NOCRLF 0x40000000 -#define CRYPT_STRING_NOCR 0x80000000 - -WINPR_API BOOL CryptStringToBinaryW(LPCWSTR pszString, DWORD cchString, DWORD dwFlags, - BYTE* pbBinary, DWORD* pcbBinary, DWORD* pdwSkip, - DWORD* pdwFlags); -WINPR_API BOOL CryptStringToBinaryA(LPCSTR pszString, DWORD cchString, DWORD dwFlags, - BYTE* pbBinary, DWORD* pcbBinary, DWORD* pdwSkip, - DWORD* pdwFlags); - -WINPR_API BOOL CryptBinaryToStringW(CONST BYTE* pbBinary, DWORD cbBinary, DWORD dwFlags, - LPWSTR pszString, DWORD* pcchString); -WINPR_API BOOL CryptBinaryToStringA(CONST BYTE* pbBinary, DWORD cbBinary, DWORD dwFlags, - LPSTR pszString, DWORD* pcchString); - -#ifdef UNICODE -#define CryptStringToBinary CryptStringToBinaryW -#define CryptBinaryToString CryptBinaryToStringW -#else -#define CryptStringToBinary CryptStringToBinaryA -#define CryptBinaryToString CryptBinaryToStringA -#endif - -#endif - -#ifndef ALG_SID_ECSDA -#define ALG_SID_ECDSA 3 -#define CALG_ECDSA (ALG_CLASS_SIGNATURE | ALG_TYPE_DSS | ALG_SID_ECDSA) -#endif - /** * Custom Crypto API Abstraction Layer */ diff --git a/winpr/include/winpr/schannel.h b/winpr/include/winpr/schannel.h index d9e2d6525c8d..f6bd190b51b3 100644 --- a/winpr/include/winpr/schannel.h +++ b/winpr/include/winpr/schannel.h @@ -22,6 +22,7 @@ #include #include +#include #if defined(_WIN32) && !defined(_UWP) diff --git a/winpr/include/winpr/wincrypt.h b/winpr/include/winpr/wincrypt.h new file mode 100644 index 000000000000..10a1274ba218 --- /dev/null +++ b/winpr/include/winpr/wincrypt.h @@ -0,0 +1,637 @@ +/** + * WinPR: Windows Portable Runtime + * Cryptography API (CryptoAPI) + * + * Copyright 2012 Marc-Andre Moreau + * + * 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 WINPR_WINCRYPT_H +#define WINPR_WINCRYPT_H + +#include +#include + +#include + +#ifdef _WIN32 + +#include + +#endif + +#ifndef ALG_TYPE_RESERVED7 +#define ALG_TYPE_RESERVED7 (7 << 9) +#endif + +#if !defined(NTDDI_VERSION) || (NTDDI_VERSION <= 0x05010200) +#define ALG_SID_SHA_256 12 +#define ALG_SID_SHA_384 13 +#define ALG_SID_SHA_512 14 +#define CALG_SHA_256 (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_SHA_256) +#define CALG_SHA_384 (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_SHA_384) +#define CALG_SHA_512 (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_SHA_512) +#endif + +#ifndef _WIN32 + +/* ncrypt.h */ + +typedef ULONG_PTR NCRYPT_HANDLE; +typedef ULONG_PTR NCRYPT_PROV_HANDLE; +typedef ULONG_PTR NCRYPT_KEY_HANDLE; +typedef ULONG_PTR NCRYPT_HASH_HANDLE; +typedef ULONG_PTR NCRYPT_SECRET_HANDLE; + +/* wincrypt.h */ + +#define GET_ALG_CLASS(x) (x & (7 << 13)) +#define GET_ALG_TYPE(x) (x & (15 << 9)) +#define GET_ALG_SID(x) (x & (511)) + +#define ALG_CLASS_ANY (0) +#define ALG_CLASS_SIGNATURE (1 << 13) +#define ALG_CLASS_MSG_ENCRYPT (2 << 13) +#define ALG_CLASS_DATA_ENCRYPT (3 << 13) +#define ALG_CLASS_HASH (4 << 13) +#define ALG_CLASS_KEY_EXCHANGE (5 << 13) +#define ALG_CLASS_ALL (7 << 13) + +#define ALG_TYPE_ANY (0) +#define ALG_TYPE_DSS (1 << 9) +#define ALG_TYPE_RSA (2 << 9) +#define ALG_TYPE_BLOCK (3 << 9) +#define ALG_TYPE_STREAM (4 << 9) +#define ALG_TYPE_DH (5 << 9) +#define ALG_TYPE_SECURECHANNEL (6 << 9) + +#define ALG_SID_ANY (0) + +#define ALG_SID_RSA_ANY 0 +#define ALG_SID_RSA_PKCS 1 +#define ALG_SID_RSA_MSATWORK 2 +#define ALG_SID_RSA_ENTRUST 3 +#define ALG_SID_RSA_PGP 4 + +#define ALG_SID_DSS_ANY 0 +#define ALG_SID_DSS_PKCS 1 +#define ALG_SID_DSS_DMS 2 + +#define ALG_SID_DES 1 +#define ALG_SID_3DES 3 +#define ALG_SID_DESX 4 +#define ALG_SID_IDEA 5 +#define ALG_SID_CAST 6 +#define ALG_SID_SAFERSK64 7 +#define ALG_SID_SAFERSK128 8 +#define ALG_SID_3DES_112 9 +#define ALG_SID_CYLINK_MEK 12 +#define ALG_SID_RC5 13 + +#define ALG_SID_AES_128 14 +#define ALG_SID_AES_192 15 +#define ALG_SID_AES_256 16 +#define ALG_SID_AES 17 + +#define ALG_SID_SKIPJACK 10 +#define ALG_SID_TEK 11 + +#define CRYPT_MODE_CBCI 6 +#define CRYPT_MODE_CFBP 7 +#define CRYPT_MODE_OFBP 8 +#define CRYPT_MODE_CBCOFM 9 +#define CRYPT_MODE_CBCOFMI 10 + +#define ALG_SID_RC2 2 + +#define ALG_SID_RC4 1 +#define ALG_SID_SEAL 2 + +#define ALG_SID_DH_SANDF 1 +#define ALG_SID_DH_EPHEM 2 +#define ALG_SID_AGREED_KEY_ANY 3 +#define ALG_SID_KEA 4 + +#define ALG_SID_ECDH 5 + +#define ALG_SID_MD2 1 +#define ALG_SID_MD4 2 +#define ALG_SID_MD5 3 +#define ALG_SID_SHA 4 +#define ALG_SID_SHA1 4 +#define ALG_SID_MAC 5 +#define ALG_SID_RIPEMD 6 +#define ALG_SID_RIPEMD160 7 +#define ALG_SID_SSL3SHAMD5 8 +#define ALG_SID_HMAC 9 +#define ALG_SID_TLS1PRF 10 + +#define ALG_SID_HASH_REPLACE_OWF 11 + +#define ALG_SID_SHA_256 12 +#define ALG_SID_SHA_384 13 +#define ALG_SID_SHA_512 14 + +#define ALG_SID_SSL3_MASTER 1 +#define ALG_SID_SCHANNEL_MASTER_HASH 2 +#define ALG_SID_SCHANNEL_MAC_KEY 3 +#define ALG_SID_PCT1_MASTER 4 +#define ALG_SID_SSL2_MASTER 5 +#define ALG_SID_TLS1_MASTER 6 +#define ALG_SID_SCHANNEL_ENC_KEY 7 + +#define ALG_SID_ECMQV 1 + +#define CALG_MD2 (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_MD2) +#define CALG_MD4 (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_MD4) +#define CALG_MD5 (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_MD5) +#define CALG_SHA (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_SHA) +#define CALG_SHA1 (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_SHA1) +#define CALG_MAC (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_MAC) +#define CALG_RSA_SIGN (ALG_CLASS_SIGNATURE | ALG_TYPE_RSA | ALG_SID_RSA_ANY) +#define CALG_DSS_SIGN (ALG_CLASS_SIGNATURE | ALG_TYPE_DSS | ALG_SID_DSS_ANY) + +#define CALG_NO_SIGN (ALG_CLASS_SIGNATURE | ALG_TYPE_ANY | ALG_SID_ANY) + +#define CALG_RSA_KEYX (ALG_CLASS_KEY_EXCHANGE | ALG_TYPE_RSA | ALG_SID_RSA_ANY) +#define CALG_DES (ALG_CLASS_DATA_ENCRYPT | ALG_TYPE_BLOCK | ALG_SID_DES) +#define CALG_3DES_112 (ALG_CLASS_DATA_ENCRYPT | ALG_TYPE_BLOCK | ALG_SID_3DES_112) +#define CALG_3DES (ALG_CLASS_DATA_ENCRYPT | ALG_TYPE_BLOCK | ALG_SID_3DES) +#define CALG_DESX (ALG_CLASS_DATA_ENCRYPT | ALG_TYPE_BLOCK | ALG_SID_DESX) +#define CALG_RC2 (ALG_CLASS_DATA_ENCRYPT | ALG_TYPE_BLOCK | ALG_SID_RC2) +#define CALG_RC4 (ALG_CLASS_DATA_ENCRYPT | ALG_TYPE_STREAM | ALG_SID_RC4) +#define CALG_SEAL (ALG_CLASS_DATA_ENCRYPT | ALG_TYPE_STREAM | ALG_SID_SEAL) +#define CALG_DH_SF (ALG_CLASS_KEY_EXCHANGE | ALG_TYPE_DH | ALG_SID_DH_SANDF) +#define CALG_DH_EPHEM (ALG_CLASS_KEY_EXCHANGE | ALG_TYPE_DH | ALG_SID_DH_EPHEM) +#define CALG_AGREEDKEY_ANY (ALG_CLASS_KEY_EXCHANGE | ALG_TYPE_DH | ALG_SID_AGREED_KEY_ANY) +#define CALG_KEA_KEYX (ALG_CLASS_KEY_EXCHANGE | ALG_TYPE_DH | ALG_SID_KEA) +#define CALG_HUGHES_MD5 (ALG_CLASS_KEY_EXCHANGE | ALG_TYPE_ANY | ALG_SID_MD5) +#define CALG_SKIPJACK (ALG_CLASS_DATA_ENCRYPT | ALG_TYPE_BLOCK | ALG_SID_SKIPJACK) +#define CALG_TEK (ALG_CLASS_DATA_ENCRYPT | ALG_TYPE_BLOCK | ALG_SID_TEK) +#define CALG_CYLINK_MEK (ALG_CLASS_DATA_ENCRYPT | ALG_TYPE_BLOCK | ALG_SID_CYLINK_MEK) +#define CALG_SSL3_SHAMD5 (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_SSL3SHAMD5) +#define CALG_SSL3_MASTER (ALG_CLASS_MSG_ENCRYPT | ALG_TYPE_SECURECHANNEL | ALG_SID_SSL3_MASTER) +#define CALG_SCHANNEL_MASTER_HASH \ + (ALG_CLASS_MSG_ENCRYPT | ALG_TYPE_SECURECHANNEL | ALG_SID_SCHANNEL_MASTER_HASH) +#define CALG_SCHANNEL_MAC_KEY \ + (ALG_CLASS_MSG_ENCRYPT | ALG_TYPE_SECURECHANNEL | ALG_SID_SCHANNEL_MAC_KEY) +#define CALG_SCHANNEL_ENC_KEY \ + (ALG_CLASS_MSG_ENCRYPT | ALG_TYPE_SECURECHANNEL | ALG_SID_SCHANNEL_ENC_KEY) +#define CALG_PCT1_MASTER (ALG_CLASS_MSG_ENCRYPT | ALG_TYPE_SECURECHANNEL | ALG_SID_PCT1_MASTER) +#define CALG_SSL2_MASTER (ALG_CLASS_MSG_ENCRYPT | ALG_TYPE_SECURECHANNEL | ALG_SID_SSL2_MASTER) +#define CALG_TLS1_MASTER (ALG_CLASS_MSG_ENCRYPT | ALG_TYPE_SECURECHANNEL | ALG_SID_TLS1_MASTER) +#define CALG_RC5 (ALG_CLASS_DATA_ENCRYPT | ALG_TYPE_BLOCK | ALG_SID_RC5) +#define CALG_HMAC (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_HMAC) +#define CALG_TLS1PRF (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_TLS1PRF) + +#define CALG_HASH_REPLACE_OWF (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_HASH_REPLACE_OWF) +#define CALG_AES_128 (ALG_CLASS_DATA_ENCRYPT | ALG_TYPE_BLOCK | ALG_SID_AES_128) +#define CALG_AES_192 (ALG_CLASS_DATA_ENCRYPT | ALG_TYPE_BLOCK | ALG_SID_AES_192) +#define CALG_AES_256 (ALG_CLASS_DATA_ENCRYPT | ALG_TYPE_BLOCK | ALG_SID_AES_256) +#define CALG_AES (ALG_CLASS_DATA_ENCRYPT | ALG_TYPE_BLOCK | ALG_SID_AES) + +#define CALG_SHA_256 (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_SHA_256) +#define CALG_SHA_384 (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_SHA_384) +#define CALG_SHA_512 (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_SHA_512) + +#define CALG_ECDH (ALG_CLASS_KEY_EXCHANGE | ALG_TYPE_DH | ALG_SID_ECDH) +#define CALG_ECMQV (ALG_CLASS_KEY_EXCHANGE | ALG_TYPE_ANY | ALG_SID_ECMQV) + +typedef struct +{ + DWORD cbData; + BYTE* pbData; +} CRYPT_INTEGER_BLOB, *PCRYPT_INTEGER_BLOB, CRYPT_UINT_BLOB, *PCRYPT_UINT_BLOB, CRYPT_OBJID_BLOB, + *PCRYPT_OBJID_BLOB, CERT_NAME_BLOB, *PCERT_NAME_BLOB, CERT_RDN_VALUE_BLOB, + *PCERT_RDN_VALUE_BLOB, CERT_BLOB, *PCERT_BLOB, CRL_BLOB, *PCRL_BLOB, DATA_BLOB, *PDATA_BLOB, + CRYPT_DATA_BLOB, *PCRYPT_DATA_BLOB, CRYPT_HASH_BLOB, *PCRYPT_HASH_BLOB, CRYPT_DIGEST_BLOB, + *PCRYPT_DIGEST_BLOB, CRYPT_DER_BLOB, *PCRYPT_DER_BLOB, CRYPT_ATTR_BLOB, *PCRYPT_ATTR_BLOB; + +typedef struct +{ + LPSTR pszObjId; + CRYPT_OBJID_BLOB Parameters; +} CRYPT_ALGORITHM_IDENTIFIER, *PCRYPT_ALGORITHM_IDENTIFIER; + +typedef struct +{ + DWORD cbData; + BYTE* pbData; + DWORD cUnusedBits; +} CRYPT_BIT_BLOB, *PCRYPT_BIT_BLOB; + +typedef struct +{ + CRYPT_ALGORITHM_IDENTIFIER Algorithm; + CRYPT_BIT_BLOB PublicKey; +} CERT_PUBLIC_KEY_INFO, *PCERT_PUBLIC_KEY_INFO; + +typedef struct +{ + LPSTR pszObjId; + BOOL fCritical; + CRYPT_OBJID_BLOB Value; +} CERT_EXTENSION, *PCERT_EXTENSION; +typedef const CERT_EXTENSION* PCCERT_EXTENSION; + +typedef struct +{ + DWORD dwVersion; + CRYPT_INTEGER_BLOB SerialNumber; + CRYPT_ALGORITHM_IDENTIFIER SignatureAlgorithm; + CERT_NAME_BLOB Issuer; + FILETIME NotBefore; + FILETIME NotAfter; + CERT_NAME_BLOB Subject; + CERT_PUBLIC_KEY_INFO SubjectPublicKeyInfo; + CRYPT_BIT_BLOB IssuerUniqueId; + CRYPT_BIT_BLOB SubjectUniqueId; + DWORD cExtension; + PCERT_EXTENSION rgExtension; +} CERT_INFO, *PCERT_INFO; + +typedef void* HCERTSTORE; +typedef ULONG_PTR HCRYPTPROV; +typedef ULONG_PTR HCRYPTPROV_LEGACY; + +typedef struct +{ + DWORD dwCertEncodingType; + BYTE* pbCertEncoded; + DWORD cbCertEncoded; + PCERT_INFO pCertInfo; + HCERTSTORE hCertStore; +} CERT_CONTEXT, *PCERT_CONTEXT; +typedef const CERT_CONTEXT* PCCERT_CONTEXT; + +#if !defined(AT_KEYEXCHANGE) +#define AT_KEYEXCHANGE (1) +#endif +#if !defined(AT_SIGNATURE) +#define AT_SIGNATURE (2) +#endif +#if !defined(AT_AUTHENTICATE) +#define AT_AUTHENTICATE (3) +#endif + +#define CERT_ENCODING_TYPE_MASK 0x0000FFFF +#define CMSG_ENCODING_TYPE_MASK 0xFFFF0000 +#define GET_CERT_ENCODING_TYPE(x) (x & CERT_ENCODING_TYPE_MASK) +#define GET_CMSG_ENCODING_TYPE(x) (x & CMSG_ENCODING_TYPE_MASK) + +#define CRYPT_ASN_ENCODING 0x00000001 +#define CRYPT_NDR_ENCODING 0x00000002 +#define X509_ASN_ENCODING 0x00000001 +#define X509_NDR_ENCODING 0x00000002 +#define PKCS_7_ASN_ENCODING 0x00010000 +#define PKCS_7_NDR_ENCODING 0x00020000 + +#define CERT_COMPARE_MASK 0xFFFF +#define CERT_COMPARE_SHIFT 16 +#define CERT_COMPARE_ANY 0 +#define CERT_COMPARE_SHA1_HASH 1 +#define CERT_COMPARE_NAME 2 +#define CERT_COMPARE_ATTR 3 +#define CERT_COMPARE_MD5_HASH 4 +#define CERT_COMPARE_PROPERTY 5 +#define CERT_COMPARE_PUBLIC_KEY 6 +#define CERT_COMPARE_HASH CERT_COMPARE_SHA1_HASH +#define CERT_COMPARE_NAME_STR_A 7 +#define CERT_COMPARE_NAME_STR_W 8 +#define CERT_COMPARE_KEY_SPEC 9 +#define CERT_COMPARE_ENHKEY_USAGE 10 +#define CERT_COMPARE_CTL_USAGE CERT_COMPARE_ENHKEY_USAGE +#define CERT_COMPARE_SUBJECT_CERT 11 +#define CERT_COMPARE_ISSUER_OF 12 +#define CERT_COMPARE_EXISTING 13 +#define CERT_COMPARE_SIGNATURE_HASH 14 +#define CERT_COMPARE_KEY_IDENTIFIER 15 +#define CERT_COMPARE_CERT_ID 16 +#define CERT_COMPARE_CROSS_CERT_DIST_POINTS 17 +#define CERT_COMPARE_PUBKEY_MD5_HASH 18 +#define CERT_COMPARE_SUBJECT_INFO_ACCESS 19 +#define CERT_COMPARE_HASH_STR 20 +#define CERT_COMPARE_HAS_PRIVATE_KEY 21 + +#define CERT_FIND_ANY (CERT_COMPARE_ANY << CERT_COMPARE_SHIFT) +#define CERT_FIND_SHA1_HASH (CERT_COMPARE_SHA1_HASH << CERT_COMPARE_SHIFT) +#define CERT_FIND_MD5_HASH (CERT_COMPARE_MD5_HASH << CERT_COMPARE_SHIFT) +#define CERT_FIND_SIGNATURE_HASH (CERT_COMPARE_SIGNATURE_HASH << CERT_COMPARE_SHIFT) +#define CERT_FIND_KEY_IDENTIFIER (CERT_COMPARE_KEY_IDENTIFIER << CERT_COMPARE_SHIFT) +#define CERT_FIND_HASH CERT_FIND_SHA1_HASH +#define CERT_FIND_PROPERTY (CERT_COMPARE_PROPERTY << CERT_COMPARE_SHIFT) +#define CERT_FIND_PUBLIC_KEY (CERT_COMPARE_PUBLIC_KEY << CERT_COMPARE_SHIFT) +#define CERT_FIND_SUBJECT_NAME (CERT_COMPARE_NAME << CERT_COMPARE_SHIFT | CERT_INFO_SUBJECT_FLAG) +#define CERT_FIND_SUBJECT_ATTR (CERT_COMPARE_ATTR << CERT_COMPARE_SHIFT | CERT_INFO_SUBJECT_FLAG) +#define CERT_FIND_ISSUER_NAME (CERT_COMPARE_NAME << CERT_COMPARE_SHIFT | CERT_INFO_ISSUER_FLAG) +#define CERT_FIND_ISSUER_ATTR (CERT_COMPARE_ATTR << CERT_COMPARE_SHIFT | CERT_INFO_ISSUER_FLAG) +#define CERT_FIND_SUBJECT_STR_A \ + (CERT_COMPARE_NAME_STR_A << CERT_COMPARE_SHIFT | CERT_INFO_SUBJECT_FLAG) +#define CERT_FIND_SUBJECT_STR_W \ + (CERT_COMPARE_NAME_STR_W << CERT_COMPARE_SHIFT | CERT_INFO_SUBJECT_FLAG) +#define CERT_FIND_SUBJECT_STR CERT_FIND_SUBJECT_STR_W +#define CERT_FIND_ISSUER_STR_A \ + (CERT_COMPARE_NAME_STR_A << CERT_COMPARE_SHIFT | CERT_INFO_ISSUER_FLAG) +#define CERT_FIND_ISSUER_STR_W \ + (CERT_COMPARE_NAME_STR_W << CERT_COMPARE_SHIFT | CERT_INFO_ISSUER_FLAG) +#define CERT_FIND_ISSUER_STR CERT_FIND_ISSUER_STR_W +#define CERT_FIND_KEY_SPEC (CERT_COMPARE_KEY_SPEC << CERT_COMPARE_SHIFT) +#define CERT_FIND_ENHKEY_USAGE (CERT_COMPARE_ENHKEY_USAGE << CERT_COMPARE_SHIFT) +#define CERT_FIND_CTL_USAGE CERT_FIND_ENHKEY_USAGE +#define CERT_FIND_SUBJECT_CERT (CERT_COMPARE_SUBJECT_CERT << CERT_COMPARE_SHIFT) +#define CERT_FIND_ISSUER_OF (CERT_COMPARE_ISSUER_OF << CERT_COMPARE_SHIFT) +#define CERT_FIND_EXISTING (CERT_COMPARE_EXISTING << CERT_COMPARE_SHIFT) +#define CERT_FIND_CERT_ID (CERT_COMPARE_CERT_ID << CERT_COMPARE_SHIFT) +#define CERT_FIND_CROSS_CERT_DIST_POINTS (CERT_COMPARE_CROSS_CERT_DIST_POINTS << CERT_COMPARE_SHIFT) +#define CERT_FIND_PUBKEY_MD5_HASH (CERT_COMPARE_PUBKEY_MD5_HASH << CERT_COMPARE_SHIFT) +#define CERT_FIND_SUBJECT_INFO_ACCESS (CERT_COMPARE_SUBJECT_INFO_ACCESS << CERT_COMPARE_SHIFT) +#define CERT_FIND_HASH_STR (CERT_COMPARE_HASH_STR << CERT_COMPARE_SHIFT) +#define CERT_FIND_HAS_PRIVATE_KEY (CERT_COMPARE_HAS_PRIVATE_KEY << CERT_COMPARE_SHIFT) + +#define CERT_FIND_OPTIONAL_ENHKEY_USAGE_FLAG 0x1 +#define CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG 0x2 +#define CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG 0x4 +#define CERT_FIND_NO_ENHKEY_USAGE_FLAG 0x8 +#define CERT_FIND_OR_ENHKEY_USAGE_FLAG 0x10 +#define CERT_FIND_VALID_ENHKEY_USAGE_FLAG 0x20 +#define CERT_FIND_OPTIONAL_CTL_USAGE_FLAG CERT_FIND_OPTIONAL_ENHKEY_USAGE_FLAG +#define CERT_FIND_EXT_ONLY_CTL_USAGE_FLAG CERT_FIND_EXT_ONLY_ENHKEY_USAGE_FLAG +#define CERT_FIND_PROP_ONLY_CTL_USAGE_FLAG CERT_FIND_PROP_ONLY_ENHKEY_USAGE_FLAG +#define CERT_FIND_NO_CTL_USAGE_FLAG CERT_FIND_NO_ENHKEY_USAGE_FLAG +#define CERT_FIND_OR_CTL_USAGE_FLAG CERT_FIND_OR_ENHKEY_USAGE_FLAG +#define CERT_FIND_VALID_CTL_USAGE_FLAG CERT_FIND_VALID_ENHKEY_USAGE_FLAG + +#define CERT_NAME_EMAIL_TYPE 1 +#define CERT_NAME_RDN_TYPE 2 +#define CERT_NAME_ATTR_TYPE 3 +#define CERT_NAME_SIMPLE_DISPLAY_TYPE 4 +#define CERT_NAME_FRIENDLY_DISPLAY_TYPE 5 +#define CERT_NAME_DNS_TYPE 6 +#define CERT_NAME_URL_TYPE 7 +#define CERT_NAME_UPN_TYPE 8 + +#define CERT_NAME_ISSUER_FLAG 0x1 +#define CERT_NAME_DISABLE_IE4_UTF8_FLAG 0x00010000 + +#define CERT_NAME_SEARCH_ALL_NAMES_FLAG 0x2 + +#define CERT_STORE_PROV_MSG ((LPCSTR)1) +#define CERT_STORE_PROV_MEMORY ((LPCSTR)2) +#define CERT_STORE_PROV_FILE ((LPCSTR)3) +#define CERT_STORE_PROV_REG ((LPCSTR)4) +#define CERT_STORE_PROV_PKCS7 ((LPCSTR)5) +#define CERT_STORE_PROV_SERIALIZED ((LPCSTR)6) +#define CERT_STORE_PROV_FILENAME_A ((LPCSTR)7) +#define CERT_STORE_PROV_FILENAME_W ((LPCSTR)8) +#define CERT_STORE_PROV_FILENAME CERT_STORE_PROV_FILENAME_W +#define CERT_STORE_PROV_SYSTEM_A ((LPCSTR)9) +#define CERT_STORE_PROV_SYSTEM_W ((LPCSTR)10) +#define CERT_STORE_PROV_SYSTEM CERT_STORE_PROV_SYSTEM_W +#define CERT_STORE_PROV_COLLECTION ((LPCSTR)11) +#define CERT_STORE_PROV_SYSTEM_REGISTRY_A ((LPCSTR)12) +#define CERT_STORE_PROV_SYSTEM_REGISTRY_W ((LPCSTR)13) +#define CERT_STORE_PROV_SYSTEM_REGISTRY CERT_STORE_PROV_SYSTEM_REGISTRY_W +#define CERT_STORE_PROV_PHYSICAL_W ((LPCSTR)14) +#define CERT_STORE_PROV_PHYSICAL CERT_STORE_PROV_PHYSICAL_W +#define CERT_STORE_PROV_SMART_CARD_W ((LPCSTR)15) +#define CERT_STORE_PROV_SMART_CARD CERT_STORE_PROV_SMART_CARD_W +#define CERT_STORE_PROV_LDAP_W ((LPCSTR)16) +#define CERT_STORE_PROV_LDAP CERT_STORE_PROV_LDAP_W +#define CERT_STORE_PROV_PKCS12 ((LPCSTR)17) +#define sz_CERT_STORE_PROV_MEMORY "Memory" +#define sz_CERT_STORE_PROV_FILENAME_W "File" +#define sz_CERT_STORE_PROV_FILENAME sz_CERT_STORE_PROV_FILENAME_W +#define sz_CERT_STORE_PROV_SYSTEM_W "System" +#define sz_CERT_STORE_PROV_SYSTEM sz_CERT_STORE_PROV_SYSTEM_W +#define sz_CERT_STORE_PROV_PKCS7 "PKCS7" +#define sz_CERT_STORE_PROV_PKCS12 "PKCS12" +#define sz_CERT_STORE_PROV_SERIALIZED "Serialized" +#define sz_CERT_STORE_PROV_COLLECTION "Collection" +#define sz_CERT_STORE_PROV_SYSTEM_REGISTRY_W "SystemRegistry" +#define sz_CERT_STORE_PROV_SYSTEM_REGISTRY sz_CERT_STORE_PROV_SYSTEM_REGISTRY_W +#define sz_CERT_STORE_PROV_PHYSICAL_W "Physical" +#define sz_CERT_STORE_PROV_PHYSICAL sz_CERT_STORE_PROV_PHYSICAL_W +#define sz_CERT_STORE_PROV_SMART_CARD_W "SmartCard" +#define sz_CERT_STORE_PROV_SMART_CARD sz_CERT_STORE_PROV_SMART_CARD_W +#define sz_CERT_STORE_PROV_LDAP_W "Ldap" +#define sz_CERT_STORE_PROV_LDAP sz_CERT_STORE_PROV_LDAP_W + +#define CERT_STORE_SIGNATURE_FLAG 0x00000001 +#define CERT_STORE_TIME_VALIDITY_FLAG 0x00000002 +#define CERT_STORE_REVOCATION_FLAG 0x00000004 +#define CERT_STORE_NO_CRL_FLAG 0x00010000 +#define CERT_STORE_NO_ISSUER_FLAG 0x00020000 +#define CERT_STORE_BASE_CRL_FLAG 0x00000100 +#define CERT_STORE_DELTA_CRL_FLAG 0x00000200 + +#define CERT_STORE_NO_CRYPT_RELEASE_FLAG 0x00000001 +#define CERT_STORE_SET_LOCALIZED_NAME_FLAG 0x00000002 +#define CERT_STORE_DEFER_CLOSE_UNTIL_LAST_FREE_FLAG 0x00000004 +#define CERT_STORE_DELETE_FLAG 0x00000010 +#define CERT_STORE_UNSAFE_PHYSICAL_FLAG 0x00000020 +#define CERT_STORE_SHARE_STORE_FLAG 0x00000040 +#define CERT_STORE_SHARE_CONTEXT_FLAG 0x00000080 +#define CERT_STORE_MANIFOLD_FLAG 0x00000100 +#define CERT_STORE_ENUM_ARCHIVED_FLAG 0x00000200 +#define CERT_STORE_UPDATE_KEYID_FLAG 0x00000400 +#define CERT_STORE_BACKUP_RESTORE_FLAG 0x00000800 +#define CERT_STORE_READONLY_FLAG 0x00008000 +#define CERT_STORE_OPEN_EXISTING_FLAG 0x00004000 +#define CERT_STORE_CREATE_NEW_FLAG 0x00002000 +#define CERT_STORE_MAXIMUM_ALLOWED_FLAG 0x00001000 + +#define CERT_SYSTEM_STORE_MASK 0xFFFF0000 +#define CERT_SYSTEM_STORE_RELOCATE_FLAG 0x80000000 +#define CERT_SYSTEM_STORE_UNPROTECTED_FLAG 0x40000000 +#define CERT_SYSTEM_STORE_DEFER_READ_FLAG 0x20000000 +#define CERT_SYSTEM_STORE_LOCATION_MASK 0x00FF0000 +#define CERT_SYSTEM_STORE_LOCATION_SHIFT 16 +#define CERT_SYSTEM_STORE_CURRENT_USER_ID 1 +#define CERT_SYSTEM_STORE_LOCAL_MACHINE_ID 2 +#define CERT_SYSTEM_STORE_CURRENT_SERVICE_ID 4 +#define CERT_SYSTEM_STORE_SERVICES_ID 5 +#define CERT_SYSTEM_STORE_USERS_ID 6 +#define CERT_SYSTEM_STORE_CURRENT_USER_GROUP_POLICY_ID 7 +#define CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY_ID 8 +#define CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE_ID 9 + +#define CERT_SYSTEM_STORE_CURRENT_USER \ + (CERT_SYSTEM_STORE_CURRENT_USER_ID << CERT_SYSTEM_STORE_LOCATION_SHIFT) +#define CERT_SYSTEM_STORE_LOCAL_MACHINE \ + (CERT_SYSTEM_STORE_LOCAL_MACHINE_ID << CERT_SYSTEM_STORE_LOCATION_SHIFT) +#define CERT_SYSTEM_STORE_CURRENT_SERVICE \ + (CERT_SYSTEM_STORE_CURRENT_SERVICE_ID << CERT_SYSTEM_STORE_LOCATION_SHIFT) +#define CERT_SYSTEM_STORE_SERVICES \ + (CERT_SYSTEM_STORE_SERVICES_ID << CERT_SYSTEM_STORE_LOCATION_SHIFT) +#define CERT_SYSTEM_STORE_USERS (CERT_SYSTEM_STORE_USERS_ID << CERT_SYSTEM_STORE_LOCATION_SHIFT) +#define CERT_SYSTEM_STORE_CURRENT_USER_GROUP_POLICY \ + (CERT_SYSTEM_STORE_CURRENT_USER_GROUP_POLICY_ID << CERT_SYSTEM_STORE_LOCATION_SHIFT) +#define CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY \ + (CERT_SYSTEM_STORE_LOCAL_MACHINE_GROUP_POLICY_ID << CERT_SYSTEM_STORE_LOCATION_SHIFT) +#define CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE \ + (CERT_SYSTEM_STORE_LOCAL_MACHINE_ENTERPRISE_ID << CERT_SYSTEM_STORE_LOCATION_SHIFT) + +WINPR_API HCERTSTORE CertOpenStore(LPCSTR lpszStoreProvider, DWORD dwMsgAndCertEncodingType, + HCRYPTPROV_LEGACY hCryptProv, DWORD dwFlags, const void* pvPara); + +WINPR_API HCERTSTORE CertOpenSystemStoreW(HCRYPTPROV_LEGACY hProv, LPCWSTR szSubsystemProtocol); +WINPR_API HCERTSTORE CertOpenSystemStoreA(HCRYPTPROV_LEGACY hProv, LPCSTR szSubsystemProtocol); + +WINPR_API BOOL CertCloseStore(HCERTSTORE hCertStore, DWORD dwFlags); + +#ifdef UNICODE +#define CertOpenSystemStore CertOpenSystemStoreW +#else +#define CertOpenSystemStore CertOpenSystemStoreA +#endif + +#ifdef __cplusplus +extern "C" +{ +#endif + + WINPR_API PCCERT_CONTEXT CertFindCertificateInStore(HCERTSTORE hCertStore, + DWORD dwCertEncodingType, DWORD dwFindFlags, + DWORD dwFindType, const void* pvFindPara, + PCCERT_CONTEXT pPrevCertContext); + + WINPR_API PCCERT_CONTEXT CertEnumCertificatesInStore(HCERTSTORE hCertStore, + PCCERT_CONTEXT pPrevCertContext); + + WINPR_API DWORD CertGetNameStringW(PCCERT_CONTEXT pCertContext, DWORD dwType, DWORD dwFlags, + void* pvTypePara, LPWSTR pszNameString, DWORD cchNameString); + WINPR_API DWORD CertGetNameStringA(PCCERT_CONTEXT pCertContext, DWORD dwType, DWORD dwFlags, + void* pvTypePara, LPSTR pszNameString, DWORD cchNameString); + +#ifdef __cplusplus +} +#endif + +#ifdef UNICODE +#define CertGetNameString CertGetNameStringW +#else +#define CertGetNameString CertGetNameStringA +#endif + +/** + * Data Protection API (DPAPI) + */ + +#define CRYPTPROTECTMEMORY_BLOCK_SIZE 16 + +#define CRYPTPROTECTMEMORY_SAME_PROCESS 0x00000000 +#define CRYPTPROTECTMEMORY_CROSS_PROCESS 0x00000001 +#define CRYPTPROTECTMEMORY_SAME_LOGON 0x00000002 + +#define CRYPTPROTECT_PROMPT_ON_UNPROTECT 0x00000001 +#define CRYPTPROTECT_PROMPT_ON_PROTECT 0x00000002 +#define CRYPTPROTECT_PROMPT_RESERVED 0x00000004 +#define CRYPTPROTECT_PROMPT_STRONG 0x00000008 +#define CRYPTPROTECT_PROMPT_REQUIRE_STRONG 0x00000010 + +#define CRYPTPROTECT_UI_FORBIDDEN 0x1 +#define CRYPTPROTECT_LOCAL_MACHINE 0x4 +#define CRYPTPROTECT_CRED_SYNC 0x8 +#define CRYPTPROTECT_AUDIT 0x10 +#define CRYPTPROTECT_NO_RECOVERY 0x20 +#define CRYPTPROTECT_VERIFY_PROTECTION 0x40 +#define CRYPTPROTECT_CRED_REGENERATE 0x80 + +#define CRYPTPROTECT_FIRST_RESERVED_FLAGVAL 0x0FFFFFFF +#define CRYPTPROTECT_LAST_RESERVED_FLAGVAL 0xFFFFFFFF + +typedef struct +{ + DWORD cbSize; + DWORD dwPromptFlags; + HWND hwndApp; + LPCWSTR szPrompt; +} CRYPTPROTECT_PROMPTSTRUCT, *PCRYPTPROTECT_PROMPTSTRUCT; + +#define CRYPTPROTECT_DEFAULT_PROVIDER \ + { \ + 0xdf9d8cd0, 0x1501, 0x11d1, \ + { \ + 0x8c, 0x7a, 0x00, 0xc0, 0x4f, 0xc2, 0x97, 0xeb \ + } \ + } + +#ifdef __cplusplus +extern "C" +{ +#endif + + WINPR_API BOOL CryptProtectMemory(LPVOID pData, DWORD cbData, DWORD dwFlags); + WINPR_API BOOL CryptUnprotectMemory(LPVOID pData, DWORD cbData, DWORD dwFlags); + + WINPR_API BOOL CryptProtectData(DATA_BLOB* pDataIn, LPCWSTR szDataDescr, + DATA_BLOB* pOptionalEntropy, PVOID pvReserved, + CRYPTPROTECT_PROMPTSTRUCT* pPromptStruct, DWORD dwFlags, + DATA_BLOB* pDataOut); + WINPR_API BOOL CryptUnprotectData(DATA_BLOB* pDataIn, LPWSTR* ppszDataDescr, + DATA_BLOB* pOptionalEntropy, PVOID pvReserved, + CRYPTPROTECT_PROMPTSTRUCT* pPromptStruct, DWORD dwFlags, + DATA_BLOB* pDataOut); + +#ifdef __cplusplus +} +#endif + +#define CRYPT_STRING_BASE64HEADER 0x00000000 +#define CRYPT_STRING_BASE64 0x00000001 +#define CRYPT_STRING_BINARY 0x00000002 +#define CRYPT_STRING_BASE64REQUESTHEADER 0x00000003 +#define CRYPT_STRING_HEX 0x00000004 +#define CRYPT_STRING_HEXASCII 0x00000005 +#define CRYPT_STRING_BASE64_ANY 0x00000006 +#define CRYPT_STRING_ANY 0x00000007 +#define CRYPT_STRING_HEX_ANY 0x00000008 +#define CRYPT_STRING_BASE64X509CRLHEADER 0x00000009 +#define CRYPT_STRING_HEXADDR 0x0000000A +#define CRYPT_STRING_HEXASCIIADDR 0x0000000B +#define CRYPT_STRING_HEXRAW 0x0000000C + +#define CRYPT_STRING_HASHDATA 0x10000000 +#define CRYPT_STRING_STRICT 0x20000000 +#define CRYPT_STRING_NOCRLF 0x40000000 +#define CRYPT_STRING_NOCR 0x80000000 + +WINPR_API BOOL CryptStringToBinaryW(LPCWSTR pszString, DWORD cchString, DWORD dwFlags, + BYTE* pbBinary, DWORD* pcbBinary, DWORD* pdwSkip, + DWORD* pdwFlags); +WINPR_API BOOL CryptStringToBinaryA(LPCSTR pszString, DWORD cchString, DWORD dwFlags, + BYTE* pbBinary, DWORD* pcbBinary, DWORD* pdwSkip, + DWORD* pdwFlags); + +WINPR_API BOOL CryptBinaryToStringW(CONST BYTE* pbBinary, DWORD cbBinary, DWORD dwFlags, + LPWSTR pszString, DWORD* pcchString); +WINPR_API BOOL CryptBinaryToStringA(CONST BYTE* pbBinary, DWORD cbBinary, DWORD dwFlags, + LPSTR pszString, DWORD* pcchString); + +#ifdef UNICODE +#define CryptStringToBinary CryptStringToBinaryW +#define CryptBinaryToString CryptBinaryToStringW +#else +#define CryptStringToBinary CryptStringToBinaryA +#define CryptBinaryToString CryptBinaryToStringA +#endif + +#endif + +#ifndef ALG_SID_ECSDA +#define ALG_SID_ECDSA 3 +#define CALG_ECDSA (ALG_CLASS_SIGNATURE | ALG_TYPE_DSS | ALG_SID_ECDSA) +#endif + +#endif /* WINPR_WINCRYPT_H */ diff --git a/winpr/libwinpr/crypto/cert.c b/winpr/libwinpr/crypto/cert.c index c769f563d743..cecd51692560 100644 --- a/winpr/libwinpr/crypto/cert.c +++ b/winpr/libwinpr/crypto/cert.c @@ -151,6 +151,7 @@ */ #include +#include #ifndef _WIN32 diff --git a/winpr/libwinpr/crypto/crypto.c b/winpr/libwinpr/crypto/crypto.c index 94990f1867a3..d8352c8119b2 100644 --- a/winpr/libwinpr/crypto/crypto.c +++ b/winpr/libwinpr/crypto/crypto.c @@ -22,6 +22,7 @@ #endif #include +#include /** * CryptAcquireCertificatePrivateKey diff --git a/winpr/libwinpr/crypto/test/TestCryptoCertEnumCertificatesInStore.c b/winpr/libwinpr/crypto/test/TestCryptoCertEnumCertificatesInStore.c index 868e9544e221..1e2636e5385b 100644 --- a/winpr/libwinpr/crypto/test/TestCryptoCertEnumCertificatesInStore.c +++ b/winpr/libwinpr/crypto/test/TestCryptoCertEnumCertificatesInStore.c @@ -3,6 +3,7 @@ #include #include #include +#include #ifdef _WIN32 //#define WITH_CRYPTUI 1 diff --git a/winpr/libwinpr/crypto/test/TestCryptoProtectMemory.c b/winpr/libwinpr/crypto/test/TestCryptoProtectMemory.c index f0993ef51120..6e4c5fcae49b 100644 --- a/winpr/libwinpr/crypto/test/TestCryptoProtectMemory.c +++ b/winpr/libwinpr/crypto/test/TestCryptoProtectMemory.c @@ -2,6 +2,7 @@ #include #include #include +#include #include #include diff --git a/winpr/libwinpr/sspi/Schannel/schannel.c b/winpr/libwinpr/sspi/Schannel/schannel.c index 5dec1021457c..f0bf4b6b87b2 100644 --- a/winpr/libwinpr/sspi/Schannel/schannel.c +++ b/winpr/libwinpr/sspi/Schannel/schannel.c @@ -23,6 +23,7 @@ #include #include +#include #include "schannel.h" From 68fd24cc959d8b2b89ea2e8375abac2075aeb2b6 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Mon, 21 Nov 2022 14:41:47 +0100 Subject: [PATCH 308/496] [winpr,crypto] Split crypto header renamed * Renamed custom winpr crypto function header * Added compatiblity header (cherry picked from commit 23f63668f535f8ac6c9054c64d6696c9aa2476aa) --- include/freerdp/crypto/crypto.h | 2 +- libfreerdp/core/settings.c | 1 - libfreerdp/crypto/crypto.c | 1 - winpr/include/winpr/crypto.h | 229 +--------------- winpr/include/winpr/custom-crypto.h | 251 ++++++++++++++++++ winpr/include/winpr/schannel.h | 1 - winpr/libwinpr/crypto/crypto.c | 1 - .../TestCryptoCertEnumCertificatesInStore.c | 1 - .../crypto/test/TestCryptoProtectMemory.c | 1 - winpr/libwinpr/sspi/Schannel/schannel.c | 1 - 10 files changed, 254 insertions(+), 235 deletions(-) create mode 100644 winpr/include/winpr/custom-crypto.h diff --git a/include/freerdp/crypto/crypto.h b/include/freerdp/crypto/crypto.h index bbc6a2cd29e5..c029ce7e91a4 100644 --- a/include/freerdp/crypto/crypto.h +++ b/include/freerdp/crypto/crypto.h @@ -22,7 +22,7 @@ /* OpenSSL includes windows.h */ #include -#include +#include #include #include diff --git a/libfreerdp/core/settings.c b/libfreerdp/core/settings.c index d0d80fff89e5..76b0e790b40b 100644 --- a/libfreerdp/core/settings.c +++ b/libfreerdp/core/settings.c @@ -35,7 +35,6 @@ #include #include #include -#include #include #include diff --git a/libfreerdp/crypto/crypto.c b/libfreerdp/crypto/crypto.c index 00dca582f853..b4602f582475 100644 --- a/libfreerdp/crypto/crypto.c +++ b/libfreerdp/crypto/crypto.c @@ -25,7 +25,6 @@ #include #include -#include #include #include diff --git a/winpr/include/winpr/crypto.h b/winpr/include/winpr/crypto.h index c5aee30b3f32..df38fedb708a 100644 --- a/winpr/include/winpr/crypto.h +++ b/winpr/include/winpr/crypto.h @@ -20,232 +20,7 @@ #ifndef WINPR_CRYPTO_H #define WINPR_CRYPTO_H -#include -#include - -#include - -/** - * Custom Crypto API Abstraction Layer - */ - -#define WINPR_MD4_DIGEST_LENGTH 16 -#define WINPR_MD5_DIGEST_LENGTH 16 -#define WINPR_SHA1_DIGEST_LENGTH 20 -#define WINPR_SHA224_DIGEST_LENGTH 28 -#define WINPR_SHA256_DIGEST_LENGTH 32 -#define WINPR_SHA384_DIGEST_LENGTH 48 -#define WINPR_SHA512_DIGEST_LENGTH 64 -#define WINPR_RIPEMD160_DIGEST_LENGTH 20 -#define WINPR_SHA3_224_DIGEST_LENGTH 28 -#define WINPR_SHA3_256_DIGEST_LENGTH 32 -#define WINPR_SHA3_384_DIGEST_LENGTH 48 -#define WINPR_SHA3_512_DIGEST_LENGTH 64 -#define WINPR_SHAKE128_DIGEST_LENGTH 16 -#define WINPR_SHAKE256_DIGEST_LENGTH 32 - -/** - * HMAC - */ -typedef enum -{ - WINPR_MD_NONE = 0, - WINPR_MD_MD2 = 1, - WINPR_MD_MD4 = 2, - WINPR_MD_MD5 = 3, - WINPR_MD_SHA1 = 4, - WINPR_MD_SHA224 = 5, - WINPR_MD_SHA256 = 6, - WINPR_MD_SHA384 = 7, - WINPR_MD_SHA512 = 8, - WINPR_MD_RIPEMD160 = 9, - WINPR_MD_SHA3_224 = 10, - WINPR_MD_SHA3_256 = 11, - WINPR_MD_SHA3_384 = 12, - WINPR_MD_SHA3_512 = 13, - WINPR_MD_SHAKE128 = 14, - WINPR_MD_SHAKE256 = 15 -} WINPR_MD_TYPE; - -typedef struct _winpr_hmac_ctx_private_st WINPR_HMAC_CTX; - -#ifdef __cplusplus -extern "C" -{ -#endif - - WINPR_API WINPR_MD_TYPE winpr_md_type_from_string(const char* name); - WINPR_API const char* winpr_md_type_to_string(WINPR_MD_TYPE md); - - WINPR_API WINPR_HMAC_CTX* winpr_HMAC_New(void); - WINPR_API BOOL winpr_HMAC_Init(WINPR_HMAC_CTX* ctx, WINPR_MD_TYPE md, const BYTE* key, - size_t keylen); - WINPR_API BOOL winpr_HMAC_Update(WINPR_HMAC_CTX* ctx, const BYTE* input, size_t ilen); - WINPR_API BOOL winpr_HMAC_Final(WINPR_HMAC_CTX* ctx, BYTE* output, size_t ilen); - WINPR_API void winpr_HMAC_Free(WINPR_HMAC_CTX* ctx); - WINPR_API BOOL winpr_HMAC(WINPR_MD_TYPE md, const BYTE* key, size_t keylen, const BYTE* input, - size_t ilen, BYTE* output, size_t olen); - -#ifdef __cplusplus -} -#endif - -/** - * Generic Digest API - */ - -typedef struct _winpr_digest_ctx_private_st WINPR_DIGEST_CTX; - -#ifdef __cplusplus -extern "C" -{ -#endif - - WINPR_API WINPR_DIGEST_CTX* winpr_Digest_New(void); - WINPR_API BOOL winpr_Digest_Init_Allow_FIPS(WINPR_DIGEST_CTX* ctx, WINPR_MD_TYPE md); - WINPR_API BOOL winpr_Digest_Init(WINPR_DIGEST_CTX* ctx, WINPR_MD_TYPE md); - WINPR_API BOOL winpr_Digest_Update(WINPR_DIGEST_CTX* ctx, const BYTE* input, size_t ilen); - WINPR_API BOOL winpr_Digest_Final(WINPR_DIGEST_CTX* ctx, BYTE* output, size_t ilen); - WINPR_API void winpr_Digest_Free(WINPR_DIGEST_CTX* ctx); - WINPR_API BOOL winpr_Digest_Allow_FIPS(WINPR_MD_TYPE md, const BYTE* input, size_t ilen, - BYTE* output, size_t olen); - WINPR_API BOOL winpr_Digest(WINPR_MD_TYPE md, const BYTE* input, size_t ilen, BYTE* output, - size_t olen); - -#ifdef __cplusplus -} -#endif - -/** - * Random Number Generation - */ - -#ifdef __cplusplus -extern "C" -{ -#endif - - WINPR_API int winpr_RAND(BYTE* output, size_t len); - WINPR_API int winpr_RAND_pseudo(BYTE* output, size_t len); - -#ifdef __cplusplus -} -#endif - -/** - * RC4 - */ - -typedef struct _winpr_rc4_ctx_private_st WINPR_RC4_CTX; - -#ifdef __cplusplus -extern "C" -{ -#endif - - WINPR_API WINPR_RC4_CTX* winpr_RC4_New_Allow_FIPS(const BYTE* key, size_t keylen); - WINPR_API WINPR_RC4_CTX* winpr_RC4_New(const BYTE* key, size_t keylen); - WINPR_API BOOL winpr_RC4_Update(WINPR_RC4_CTX* ctx, size_t length, const BYTE* input, - BYTE* output); - WINPR_API void winpr_RC4_Free(WINPR_RC4_CTX* ctx); - -#ifdef __cplusplus -} -#endif - -/** - * Generic Cipher API - */ - -#define WINPR_AES_BLOCK_SIZE 16 - -/* cipher operation types */ -#define WINPR_ENCRYPT 0 -#define WINPR_DECRYPT 1 - -/* cipher types */ -#define WINPR_CIPHER_NONE 0 -#define WINPR_CIPHER_NULL 1 -#define WINPR_CIPHER_AES_128_ECB 2 -#define WINPR_CIPHER_AES_192_ECB 3 -#define WINPR_CIPHER_AES_256_ECB 4 -#define WINPR_CIPHER_AES_128_CBC 5 -#define WINPR_CIPHER_AES_192_CBC 6 -#define WINPR_CIPHER_AES_256_CBC 7 -#define WINPR_CIPHER_AES_128_CFB128 8 -#define WINPR_CIPHER_AES_192_CFB128 9 -#define WINPR_CIPHER_AES_256_CFB128 10 -#define WINPR_CIPHER_AES_128_CTR 11 -#define WINPR_CIPHER_AES_192_CTR 12 -#define WINPR_CIPHER_AES_256_CTR 13 -#define WINPR_CIPHER_AES_128_GCM 14 -#define WINPR_CIPHER_AES_192_GCM 15 -#define WINPR_CIPHER_AES_256_GCM 16 -#define WINPR_CIPHER_CAMELLIA_128_ECB 17 -#define WINPR_CIPHER_CAMELLIA_192_ECB 18 -#define WINPR_CIPHER_CAMELLIA_256_ECB 19 -#define WINPR_CIPHER_CAMELLIA_128_CBC 20 -#define WINPR_CIPHER_CAMELLIA_192_CBC 21 -#define WINPR_CIPHER_CAMELLIA_256_CBC 22 -#define WINPR_CIPHER_CAMELLIA_128_CFB128 23 -#define WINPR_CIPHER_CAMELLIA_192_CFB128 24 -#define WINPR_CIPHER_CAMELLIA_256_CFB128 25 -#define WINPR_CIPHER_CAMELLIA_128_CTR 26 -#define WINPR_CIPHER_CAMELLIA_192_CTR 27 -#define WINPR_CIPHER_CAMELLIA_256_CTR 28 -#define WINPR_CIPHER_CAMELLIA_128_GCM 29 -#define WINPR_CIPHER_CAMELLIA_192_GCM 30 -#define WINPR_CIPHER_CAMELLIA_256_GCM 31 -#define WINPR_CIPHER_DES_ECB 32 -#define WINPR_CIPHER_DES_CBC 33 -#define WINPR_CIPHER_DES_EDE_ECB 34 -#define WINPR_CIPHER_DES_EDE_CBC 35 -#define WINPR_CIPHER_DES_EDE3_ECB 36 -#define WINPR_CIPHER_DES_EDE3_CBC 37 -#define WINPR_CIPHER_BLOWFISH_ECB 38 -#define WINPR_CIPHER_BLOWFISH_CBC 39 -#define WINPR_CIPHER_BLOWFISH_CFB64 40 -#define WINPR_CIPHER_BLOWFISH_CTR 41 -#define WINPR_CIPHER_ARC4_128 42 -#define WINPR_CIPHER_AES_128_CCM 43 -#define WINPR_CIPHER_AES_192_CCM 44 -#define WINPR_CIPHER_AES_256_CCM 45 -#define WINPR_CIPHER_CAMELLIA_128_CCM 46 -#define WINPR_CIPHER_CAMELLIA_192_CCM 47 -#define WINPR_CIPHER_CAMELLIA_256_CCM 48 - -typedef struct _winpr_cipher_ctx_private_st WINPR_CIPHER_CTX; - -#ifdef __cplusplus -extern "C" -{ -#endif - - WINPR_API WINPR_CIPHER_CTX* winpr_Cipher_New(int cipher, int op, const BYTE* key, - const BYTE* iv); - WINPR_API BOOL winpr_Cipher_Update(WINPR_CIPHER_CTX* ctx, const BYTE* input, size_t ilen, - BYTE* output, size_t* olen); - WINPR_API BOOL winpr_Cipher_Final(WINPR_CIPHER_CTX* ctx, BYTE* output, size_t* olen); - WINPR_API void winpr_Cipher_Free(WINPR_CIPHER_CTX* ctx); - -#ifdef __cplusplus -} -#endif - -/** - * Key Generation - */ - -#ifdef __cplusplus -extern "C" -{ -#endif - - WINPR_API int winpr_Cipher_BytesToKey(int cipher, int md, const BYTE* salt, const BYTE* data, - int datal, int count, BYTE* key, BYTE* iv); - -#ifdef __cplusplus -} -#endif +#include +#include #endif /* WINPR_CRYPTO_H */ diff --git a/winpr/include/winpr/custom-crypto.h b/winpr/include/winpr/custom-crypto.h new file mode 100644 index 000000000000..1b195ea2b39a --- /dev/null +++ b/winpr/include/winpr/custom-crypto.h @@ -0,0 +1,251 @@ +/** + * WinPR: Windows Portable Runtime + * Cryptography API (CryptoAPI) + * + * Copyright 2012 Marc-Andre Moreau + * + * 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 WINPR_CUSTOM_CRYPTO_H +#define WINPR_CUSTOM_CRYPTO_H + +#include +#include + +#include + +/** + * Custom Crypto API Abstraction Layer + */ + +#define WINPR_MD4_DIGEST_LENGTH 16 +#define WINPR_MD5_DIGEST_LENGTH 16 +#define WINPR_SHA1_DIGEST_LENGTH 20 +#define WINPR_SHA224_DIGEST_LENGTH 28 +#define WINPR_SHA256_DIGEST_LENGTH 32 +#define WINPR_SHA384_DIGEST_LENGTH 48 +#define WINPR_SHA512_DIGEST_LENGTH 64 +#define WINPR_RIPEMD160_DIGEST_LENGTH 20 +#define WINPR_SHA3_224_DIGEST_LENGTH 28 +#define WINPR_SHA3_256_DIGEST_LENGTH 32 +#define WINPR_SHA3_384_DIGEST_LENGTH 48 +#define WINPR_SHA3_512_DIGEST_LENGTH 64 +#define WINPR_SHAKE128_DIGEST_LENGTH 16 +#define WINPR_SHAKE256_DIGEST_LENGTH 32 + +/** + * HMAC + */ +typedef enum +{ + WINPR_MD_NONE = 0, + WINPR_MD_MD2 = 1, + WINPR_MD_MD4 = 2, + WINPR_MD_MD5 = 3, + WINPR_MD_SHA1 = 4, + WINPR_MD_SHA224 = 5, + WINPR_MD_SHA256 = 6, + WINPR_MD_SHA384 = 7, + WINPR_MD_SHA512 = 8, + WINPR_MD_RIPEMD160 = 9, + WINPR_MD_SHA3_224 = 10, + WINPR_MD_SHA3_256 = 11, + WINPR_MD_SHA3_384 = 12, + WINPR_MD_SHA3_512 = 13, + WINPR_MD_SHAKE128 = 14, + WINPR_MD_SHAKE256 = 15 +} WINPR_MD_TYPE; + +typedef struct _winpr_hmac_ctx_private_st WINPR_HMAC_CTX; + +#ifdef __cplusplus +extern "C" +{ +#endif + + WINPR_API WINPR_MD_TYPE winpr_md_type_from_string(const char* name); + WINPR_API const char* winpr_md_type_to_string(WINPR_MD_TYPE md); + + WINPR_API WINPR_HMAC_CTX* winpr_HMAC_New(void); + WINPR_API BOOL winpr_HMAC_Init(WINPR_HMAC_CTX* ctx, WINPR_MD_TYPE md, const BYTE* key, + size_t keylen); + WINPR_API BOOL winpr_HMAC_Update(WINPR_HMAC_CTX* ctx, const BYTE* input, size_t ilen); + WINPR_API BOOL winpr_HMAC_Final(WINPR_HMAC_CTX* ctx, BYTE* output, size_t ilen); + WINPR_API void winpr_HMAC_Free(WINPR_HMAC_CTX* ctx); + WINPR_API BOOL winpr_HMAC(WINPR_MD_TYPE md, const BYTE* key, size_t keylen, const BYTE* input, + size_t ilen, BYTE* output, size_t olen); + +#ifdef __cplusplus +} +#endif + +/** + * Generic Digest API + */ + +typedef struct _winpr_digest_ctx_private_st WINPR_DIGEST_CTX; + +#ifdef __cplusplus +extern "C" +{ +#endif + + WINPR_API WINPR_DIGEST_CTX* winpr_Digest_New(void); + WINPR_API BOOL winpr_Digest_Init_Allow_FIPS(WINPR_DIGEST_CTX* ctx, WINPR_MD_TYPE md); + WINPR_API BOOL winpr_Digest_Init(WINPR_DIGEST_CTX* ctx, WINPR_MD_TYPE md); + WINPR_API BOOL winpr_Digest_Update(WINPR_DIGEST_CTX* ctx, const BYTE* input, size_t ilen); + WINPR_API BOOL winpr_Digest_Final(WINPR_DIGEST_CTX* ctx, BYTE* output, size_t ilen); + WINPR_API void winpr_Digest_Free(WINPR_DIGEST_CTX* ctx); + WINPR_API BOOL winpr_Digest_Allow_FIPS(WINPR_MD_TYPE md, const BYTE* input, size_t ilen, + BYTE* output, size_t olen); + WINPR_API BOOL winpr_Digest(WINPR_MD_TYPE md, const BYTE* input, size_t ilen, BYTE* output, + size_t olen); + +#ifdef __cplusplus +} +#endif + +/** + * Random Number Generation + */ + +#ifdef __cplusplus +extern "C" +{ +#endif + + WINPR_API int winpr_RAND(BYTE* output, size_t len); + WINPR_API int winpr_RAND_pseudo(BYTE* output, size_t len); + +#ifdef __cplusplus +} +#endif + +/** + * RC4 + */ + +typedef struct _winpr_rc4_ctx_private_st WINPR_RC4_CTX; + +#ifdef __cplusplus +extern "C" +{ +#endif + + WINPR_API WINPR_RC4_CTX* winpr_RC4_New_Allow_FIPS(const BYTE* key, size_t keylen); + WINPR_API WINPR_RC4_CTX* winpr_RC4_New(const BYTE* key, size_t keylen); + WINPR_API BOOL winpr_RC4_Update(WINPR_RC4_CTX* ctx, size_t length, const BYTE* input, + BYTE* output); + WINPR_API void winpr_RC4_Free(WINPR_RC4_CTX* ctx); + +#ifdef __cplusplus +} +#endif + +/** + * Generic Cipher API + */ + +#define WINPR_AES_BLOCK_SIZE 16 + +/* cipher operation types */ +#define WINPR_ENCRYPT 0 +#define WINPR_DECRYPT 1 + +/* cipher types */ +#define WINPR_CIPHER_NONE 0 +#define WINPR_CIPHER_NULL 1 +#define WINPR_CIPHER_AES_128_ECB 2 +#define WINPR_CIPHER_AES_192_ECB 3 +#define WINPR_CIPHER_AES_256_ECB 4 +#define WINPR_CIPHER_AES_128_CBC 5 +#define WINPR_CIPHER_AES_192_CBC 6 +#define WINPR_CIPHER_AES_256_CBC 7 +#define WINPR_CIPHER_AES_128_CFB128 8 +#define WINPR_CIPHER_AES_192_CFB128 9 +#define WINPR_CIPHER_AES_256_CFB128 10 +#define WINPR_CIPHER_AES_128_CTR 11 +#define WINPR_CIPHER_AES_192_CTR 12 +#define WINPR_CIPHER_AES_256_CTR 13 +#define WINPR_CIPHER_AES_128_GCM 14 +#define WINPR_CIPHER_AES_192_GCM 15 +#define WINPR_CIPHER_AES_256_GCM 16 +#define WINPR_CIPHER_CAMELLIA_128_ECB 17 +#define WINPR_CIPHER_CAMELLIA_192_ECB 18 +#define WINPR_CIPHER_CAMELLIA_256_ECB 19 +#define WINPR_CIPHER_CAMELLIA_128_CBC 20 +#define WINPR_CIPHER_CAMELLIA_192_CBC 21 +#define WINPR_CIPHER_CAMELLIA_256_CBC 22 +#define WINPR_CIPHER_CAMELLIA_128_CFB128 23 +#define WINPR_CIPHER_CAMELLIA_192_CFB128 24 +#define WINPR_CIPHER_CAMELLIA_256_CFB128 25 +#define WINPR_CIPHER_CAMELLIA_128_CTR 26 +#define WINPR_CIPHER_CAMELLIA_192_CTR 27 +#define WINPR_CIPHER_CAMELLIA_256_CTR 28 +#define WINPR_CIPHER_CAMELLIA_128_GCM 29 +#define WINPR_CIPHER_CAMELLIA_192_GCM 30 +#define WINPR_CIPHER_CAMELLIA_256_GCM 31 +#define WINPR_CIPHER_DES_ECB 32 +#define WINPR_CIPHER_DES_CBC 33 +#define WINPR_CIPHER_DES_EDE_ECB 34 +#define WINPR_CIPHER_DES_EDE_CBC 35 +#define WINPR_CIPHER_DES_EDE3_ECB 36 +#define WINPR_CIPHER_DES_EDE3_CBC 37 +#define WINPR_CIPHER_BLOWFISH_ECB 38 +#define WINPR_CIPHER_BLOWFISH_CBC 39 +#define WINPR_CIPHER_BLOWFISH_CFB64 40 +#define WINPR_CIPHER_BLOWFISH_CTR 41 +#define WINPR_CIPHER_ARC4_128 42 +#define WINPR_CIPHER_AES_128_CCM 43 +#define WINPR_CIPHER_AES_192_CCM 44 +#define WINPR_CIPHER_AES_256_CCM 45 +#define WINPR_CIPHER_CAMELLIA_128_CCM 46 +#define WINPR_CIPHER_CAMELLIA_192_CCM 47 +#define WINPR_CIPHER_CAMELLIA_256_CCM 48 + +typedef struct _winpr_cipher_ctx_private_st WINPR_CIPHER_CTX; + +#ifdef __cplusplus +extern "C" +{ +#endif + + WINPR_API WINPR_CIPHER_CTX* winpr_Cipher_New(int cipher, int op, const BYTE* key, + const BYTE* iv); + WINPR_API BOOL winpr_Cipher_Update(WINPR_CIPHER_CTX* ctx, const BYTE* input, size_t ilen, + BYTE* output, size_t* olen); + WINPR_API BOOL winpr_Cipher_Final(WINPR_CIPHER_CTX* ctx, BYTE* output, size_t* olen); + WINPR_API void winpr_Cipher_Free(WINPR_CIPHER_CTX* ctx); + +#ifdef __cplusplus +} +#endif + +/** + * Key Generation + */ + +#ifdef __cplusplus +extern "C" +{ +#endif + + WINPR_API int winpr_Cipher_BytesToKey(int cipher, int md, const BYTE* salt, const BYTE* data, + int datal, int count, BYTE* key, BYTE* iv); + +#ifdef __cplusplus +} +#endif + +#endif /* WINPR_CUSTOM_CRYPTO_H */ diff --git a/winpr/include/winpr/schannel.h b/winpr/include/winpr/schannel.h index f6bd190b51b3..d9e2d6525c8d 100644 --- a/winpr/include/winpr/schannel.h +++ b/winpr/include/winpr/schannel.h @@ -22,7 +22,6 @@ #include #include -#include #if defined(_WIN32) && !defined(_UWP) diff --git a/winpr/libwinpr/crypto/crypto.c b/winpr/libwinpr/crypto/crypto.c index d8352c8119b2..94990f1867a3 100644 --- a/winpr/libwinpr/crypto/crypto.c +++ b/winpr/libwinpr/crypto/crypto.c @@ -22,7 +22,6 @@ #endif #include -#include /** * CryptAcquireCertificatePrivateKey diff --git a/winpr/libwinpr/crypto/test/TestCryptoCertEnumCertificatesInStore.c b/winpr/libwinpr/crypto/test/TestCryptoCertEnumCertificatesInStore.c index 1e2636e5385b..868e9544e221 100644 --- a/winpr/libwinpr/crypto/test/TestCryptoCertEnumCertificatesInStore.c +++ b/winpr/libwinpr/crypto/test/TestCryptoCertEnumCertificatesInStore.c @@ -3,7 +3,6 @@ #include #include #include -#include #ifdef _WIN32 //#define WITH_CRYPTUI 1 diff --git a/winpr/libwinpr/crypto/test/TestCryptoProtectMemory.c b/winpr/libwinpr/crypto/test/TestCryptoProtectMemory.c index 6e4c5fcae49b..f0993ef51120 100644 --- a/winpr/libwinpr/crypto/test/TestCryptoProtectMemory.c +++ b/winpr/libwinpr/crypto/test/TestCryptoProtectMemory.c @@ -2,7 +2,6 @@ #include #include #include -#include #include #include diff --git a/winpr/libwinpr/sspi/Schannel/schannel.c b/winpr/libwinpr/sspi/Schannel/schannel.c index f0bf4b6b87b2..5dec1021457c 100644 --- a/winpr/libwinpr/sspi/Schannel/schannel.c +++ b/winpr/libwinpr/sspi/Schannel/schannel.c @@ -23,7 +23,6 @@ #include #include -#include #include "schannel.h" From b933372ec4a458e74a136457d8f62e8dfc508e7e Mon Sep 17 00:00:00 2001 From: akallabeth Date: Tue, 22 Nov 2022 11:55:26 +0100 Subject: [PATCH 309/496] [crypto] Added sha3 define guards sha3 is only supported with OpenSSL 1.1.1a or later (cherry picked from commit deaf2b6666d7351e7da2389abc9827433fa68dec) --- libfreerdp/crypto/crypto.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libfreerdp/crypto/crypto.c b/libfreerdp/crypto/crypto.c index b4602f582475..943b4df9dcc0 100644 --- a/libfreerdp/crypto/crypto.c +++ b/libfreerdp/crypto/crypto.c @@ -976,6 +976,7 @@ WINPR_MD_TYPE crypto_cert_get_signature_alg(X509* xcert) return WINPR_MD_SHA512; case NID_ripemd160: return WINPR_MD_RIPEMD160; +#if (OPENSSL_VERSION_NUMBER >= 0x1010101fL) || defined(LIBRESSL_VERSION_NUMBER) case NID_sha3_224: return WINPR_MD_SHA3_224; case NID_sha3_256: @@ -984,6 +985,7 @@ WINPR_MD_TYPE crypto_cert_get_signature_alg(X509* xcert) return WINPR_MD_SHA3_384; case NID_sha3_512: return WINPR_MD_SHA3_512; +#endif case NID_shake128: return WINPR_MD_SHAKE128; case NID_shake256: From f4a05d5d7e3d3b33613e9b58ff928b7378dec163 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Fri, 25 Nov 2022 10:05:32 +0100 Subject: [PATCH 310/496] [core,rdp] Add a check for broken RDP security RDP security is rarely used nowadays, but there have been reports about situations where the encryption key is missing. Add this check to properly terminate the connection in case of such an unexpected event. (cherry picked from commit c8956513d64e470752e9e0034c26f5e625967fd7) --- libfreerdp/core/security.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/libfreerdp/core/security.c b/libfreerdp/core/security.c index 7caf5a842e18..89ced48eee14 100644 --- a/libfreerdp/core/security.c +++ b/libfreerdp/core/security.c @@ -719,6 +719,12 @@ BOOL security_encrypt(BYTE* data, size_t length, rdpRdp* rdp) { BOOL rc = FALSE; EnterCriticalSection(&rdp->critical); + if (!rdp->rc4_encrypt_key) + { + WLog_ERR(TAG, "[%s] rdp->rc4_encrypt_key=%p", __FUNCTION__, rdp->rc4_encrypt_key); + goto fail; + } + if (rdp->encrypt_use_count >= 4096) { if (!security_key_update(rdp->encrypt_key, rdp->encrypt_update_key, rdp->rc4_key_len, rdp)) @@ -748,8 +754,11 @@ BOOL security_decrypt(BYTE* data, size_t length, rdpRdp* rdp) { BOOL rc = FALSE; EnterCriticalSection(&rdp->critical); - if (rdp->rc4_decrypt_key == NULL) + if (!rdp->rc4_decrypt_key) + { + WLog_ERR(TAG, "[%s] rdp->rc4_decrypt_key=%p", __FUNCTION__, rdp->rc4_decrypt_key); goto fail; + } if (rdp->decrypt_use_count >= 4096) { From 48702e449aa8ded919ce781dab757ab11144d721 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Fri, 25 Nov 2022 10:12:25 +0100 Subject: [PATCH 311/496] [core,rdp] Refactor rdp security encryption Unify rc4 encryption key handling, use common free and reset functions (cherry picked from commit 1304af47480295707ce93ab8c445eccd4cf7b6bd) --- libfreerdp/core/connection.c | 27 +++++++++---------- libfreerdp/core/rdp.c | 51 +++++++++++++++++++++++++++--------- libfreerdp/core/rdp.h | 6 +++++ libfreerdp/core/security.c | 14 ++-------- 4 files changed, 58 insertions(+), 40 deletions(-) diff --git a/libfreerdp/core/connection.c b/libfreerdp/core/connection.c index 815418e9e2d0..3d8d70634788 100644 --- a/libfreerdp/core/connection.c +++ b/libfreerdp/core/connection.c @@ -717,10 +717,9 @@ static BOOL rdp_client_establish_keys(rdpRdp* rdp) goto end; } - rdp->rc4_decrypt_key = winpr_RC4_New(rdp->decrypt_key, rdp->rc4_key_len); - rdp->rc4_encrypt_key = winpr_RC4_New(rdp->encrypt_key, rdp->rc4_key_len); - - if (!rdp->rc4_decrypt_key || !rdp->rc4_encrypt_key) + if (!rdp_reset_rc4_encrypt_keys(rdp)) + goto end; + if (!rdp_reset_rc4_decrypt_keys(rdp)) goto end; ret = TRUE; @@ -731,12 +730,11 @@ static BOOL rdp_client_establish_keys(rdpRdp* rdp) { winpr_Cipher_Free(rdp->fips_decrypt); winpr_Cipher_Free(rdp->fips_encrypt); - winpr_RC4_Free(rdp->rc4_decrypt_key); - winpr_RC4_Free(rdp->rc4_encrypt_key); rdp->fips_decrypt = NULL; rdp->fips_encrypt = NULL; - rdp->rc4_decrypt_key = NULL; - rdp->rc4_encrypt_key = NULL; + + rdp_free_rc4_decrypt_keys(rdp); + rdp_free_rc4_encrypt_keys(rdp); } return ret; @@ -852,10 +850,10 @@ BOOL rdp_server_establish_keys(rdpRdp* rdp, wStream* s) goto end; } - rdp->rc4_decrypt_key = winpr_RC4_New(rdp->decrypt_key, rdp->rc4_key_len); - rdp->rc4_encrypt_key = winpr_RC4_New(rdp->encrypt_key, rdp->rc4_key_len); + if (!rdp_reset_rc4_encrypt_keys(rdp)) + goto end; - if (!rdp->rc4_decrypt_key || !rdp->rc4_encrypt_key) + if (!rdp_reset_rc4_decrypt_keys(rdp)) goto end; ret = tpkt_ensure_stream_consumed(s, length); @@ -866,12 +864,11 @@ BOOL rdp_server_establish_keys(rdpRdp* rdp, wStream* s) { winpr_Cipher_Free(rdp->fips_encrypt); winpr_Cipher_Free(rdp->fips_decrypt); - winpr_RC4_Free(rdp->rc4_encrypt_key); - winpr_RC4_Free(rdp->rc4_decrypt_key); rdp->fips_encrypt = NULL; rdp->fips_decrypt = NULL; - rdp->rc4_encrypt_key = NULL; - rdp->rc4_decrypt_key = NULL; + + rdp_free_rc4_encrypt_keys(rdp); + rdp_free_rc4_decrypt_keys(rdp); } return ret; diff --git a/libfreerdp/core/rdp.c b/libfreerdp/core/rdp.c index 4de256129966..cd93d713ab6f 100644 --- a/libfreerdp/core/rdp.c +++ b/libfreerdp/core/rdp.c @@ -1874,17 +1874,8 @@ void rdp_reset(rdpRdp* rdp) settings = rdp->settings; bulk_reset(rdp->bulk); - if (rdp->rc4_decrypt_key) - { - winpr_RC4_Free(rdp->rc4_decrypt_key); - rdp->rc4_decrypt_key = NULL; - } - - if (rdp->rc4_encrypt_key) - { - winpr_RC4_Free(rdp->rc4_encrypt_key); - rdp->rc4_encrypt_key = NULL; - } + rdp_free_rc4_decrypt_keys(rdp); + rdp_free_rc4_encrypt_keys(rdp); if (rdp->fips_encrypt) { @@ -1943,8 +1934,8 @@ void rdp_free(rdpRdp* rdp) if (rdp) { DeleteCriticalSection(&rdp->critical); - winpr_RC4_Free(rdp->rc4_decrypt_key); - winpr_RC4_Free(rdp->rc4_encrypt_key); + rdp_free_rc4_decrypt_keys(rdp); + rdp_free_rc4_encrypt_keys(rdp); winpr_Cipher_Free(rdp->fips_encrypt); winpr_Cipher_Free(rdp->fips_decrypt); freerdp_settings_free(rdp->settings); @@ -1964,3 +1955,37 @@ void rdp_free(rdpRdp* rdp) free(rdp); } } + +BOOL rdp_reset_rc4_encrypt_keys(rdpRdp* rdp) +{ + WINPR_ASSERT(rdp); + rdp_free_rc4_encrypt_keys(rdp); + rdp->rc4_encrypt_key = winpr_RC4_New(rdp->encrypt_key, rdp->rc4_key_len); + + rdp->encrypt_use_count = 0; + return rdp->rc4_encrypt_key != NULL; +} + +void rdp_free_rc4_encrypt_keys(rdpRdp* rdp) +{ + WINPR_ASSERT(rdp); + winpr_RC4_Free(rdp->rc4_encrypt_key); + rdp->rc4_encrypt_key = NULL; +} + +void rdp_free_rc4_decrypt_keys(rdpRdp* rdp) +{ + WINPR_ASSERT(rdp); + winpr_RC4_Free(rdp->rc4_decrypt_key); + rdp->rc4_decrypt_key = NULL; +} + +BOOL rdp_reset_rc4_decrypt_keys(rdpRdp* rdp) +{ + WINPR_ASSERT(rdp); + rdp_free_rc4_decrypt_keys(rdp); + rdp->rc4_decrypt_key = winpr_RC4_New(rdp->decrypt_key, rdp->rc4_key_len); + + rdp->decrypt_use_count = 0; + return rdp->rc4_decrypt_key != NULL; +} diff --git a/libfreerdp/core/rdp.h b/libfreerdp/core/rdp.h index 8212482a0588..3953329963dc 100644 --- a/libfreerdp/core/rdp.h +++ b/libfreerdp/core/rdp.h @@ -242,4 +242,10 @@ BOOL rdp_decrypt(rdpRdp* rdp, wStream* s, UINT16* pLength, UINT16 securityFlags) BOOL rdp_set_error_info(rdpRdp* rdp, UINT32 errorInfo); BOOL rdp_send_error_info(rdpRdp* rdp); +void rdp_free_rc4_encrypt_keys(rdpRdp* rdp); +BOOL rdp_reset_rc4_encrypt_keys(rdpRdp* rdp); + +void rdp_free_rc4_decrypt_keys(rdpRdp* rdp); +BOOL rdp_reset_rc4_decrypt_keys(rdpRdp* rdp); + #endif /* FREERDP_LIB_CORE_RDP_H */ diff --git a/libfreerdp/core/security.c b/libfreerdp/core/security.c index 89ced48eee14..17811c747e69 100644 --- a/libfreerdp/core/security.c +++ b/libfreerdp/core/security.c @@ -730,13 +730,8 @@ BOOL security_encrypt(BYTE* data, size_t length, rdpRdp* rdp) if (!security_key_update(rdp->encrypt_key, rdp->encrypt_update_key, rdp->rc4_key_len, rdp)) goto fail; - winpr_RC4_Free(rdp->rc4_encrypt_key); - rdp->rc4_encrypt_key = winpr_RC4_New(rdp->encrypt_key, rdp->rc4_key_len); - - if (!rdp->rc4_encrypt_key) + if (!rdp_reset_rc4_encrypt_keys(rdp)) goto fail; - - rdp->encrypt_use_count = 0; } if (!winpr_RC4_Update(rdp->rc4_encrypt_key, length, data, data)) @@ -765,13 +760,8 @@ BOOL security_decrypt(BYTE* data, size_t length, rdpRdp* rdp) if (!security_key_update(rdp->decrypt_key, rdp->decrypt_update_key, rdp->rc4_key_len, rdp)) goto fail; - winpr_RC4_Free(rdp->rc4_decrypt_key); - rdp->rc4_decrypt_key = winpr_RC4_New(rdp->decrypt_key, rdp->rc4_key_len); - - if (!rdp->rc4_decrypt_key) + if (!rdp_reset_rc4_decrypt_keys(rdp)) goto fail; - - rdp->decrypt_use_count = 0; } if (!winpr_RC4_Update(rdp->rc4_decrypt_key, length, data, data)) From e540cb5f6a238b0f328a994318dafab4cb60e96a Mon Sep 17 00:00:00 2001 From: akallabeth Date: Tue, 22 Nov 2022 08:51:12 +0100 Subject: [PATCH 312/496] [uwac] Add support for building against pixman --- config.h.in | 3 +++ uwac/CMakeLists.txt | 8 ++++++++ uwac/libuwac/CMakeLists.txt | 8 ++++++-- 3 files changed, 17 insertions(+), 2 deletions(-) diff --git a/config.h.in b/config.h.in index 650d5adcba31..9644ab909899 100644 --- a/config.h.in +++ b/config.h.in @@ -186,4 +186,7 @@ #cmakedefine WITH_INTERNAL_MD4 #cmakedefine WITH_INTERNAL_MD5 +/* Uwac */ +#cmakedefine HAVE_PIXMAN_REGION + #endif /* FREERDP_CONFIG_H */ diff --git a/uwac/CMakeLists.txt b/uwac/CMakeLists.txt index 8ebd4952fedb..eaee928d621c 100644 --- a/uwac/CMakeLists.txt +++ b/uwac/CMakeLists.txt @@ -23,6 +23,14 @@ set(UWAC_VERSION "${UWAC_VERSION_MAJOR}.${UWAC_VERSION_MINOR}.${UWAC_VERSION_REV set(UWAC_VERSION_FULL "${UWAC_VERSION}") set(UWAC_API_VERSION "${UWAC_VERSION_MAJOR}") +option(HAVE_PIXMAN_REGION "Use PIXMAN or FreeRDP for region calculations" OFF) + +if (HAVE_PIXMAN_REGION) + include(FindPkgConfig) + pkg_check_modules(pixman REQUIRED pixman-1) + include_directories(${pixman_INCLUDE_DIRS}) +endif() + add_subdirectory(include) add_subdirectory(libuwac) diff --git a/uwac/libuwac/CMakeLists.txt b/uwac/libuwac/CMakeLists.txt index cfadba8ae150..f66a8c4aacd9 100644 --- a/uwac/libuwac/CMakeLists.txt +++ b/uwac/libuwac/CMakeLists.txt @@ -70,13 +70,17 @@ set(${MODULE_PREFIX}_SRCS add_library(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS}) - set_target_properties(${MODULE_NAME} PROPERTIES OUTPUT_NAME ${MODULE_NAME}${UWAC_API_VERSION}) if (WITH_LIBRARY_VERSIONING) set_target_properties(${MODULE_NAME} PROPERTIES VERSION ${UWAC_VERSION} SOVERSION ${UWAC_API_VERSION}) endif() -target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS} ${PRIVATE_KEYWORD} ${WAYLAND_LIBS} ${XKBCOMMON_LIBS} ${EPOLLSHIM_LIBS} freerdp) +target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS} ${PRIVATE_KEYWORD} ${WAYLAND_LIBS} ${XKBCOMMON_LIBS} ${EPOLLSHIM_LIBS}) +if (HAVE_PIXMAN_REGION) + target_link_libraries(${MODULE_NAME} PRIVATE ${pixman_LINK_LIBRARIES}) +else() + target_link_libraries(${MODULE_NAME} PRIVATE freerdp) +endif() install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR} EXPORT uwac) From d49ce39624c7c305e4d9b2f8b45c1c432e58d191 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Tue, 22 Nov 2022 09:01:19 +0100 Subject: [PATCH 313/496] [uwac] Fixed types and format strings Do not rely on FreeRDP types, use inttypes.h and stdint.h supplied ones. --- uwac/libuwac/uwac-input.c | 5 +++-- uwac/libuwac/uwac-priv.h | 4 ++-- uwac/libuwac/uwac-window.c | 8 ++++---- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/uwac/libuwac/uwac-input.c b/uwac/libuwac/uwac-input.c index 1e02001672f4..52d9d3e22019 100644 --- a/uwac/libuwac/uwac-input.c +++ b/uwac/libuwac/uwac-input.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -71,8 +72,8 @@ static struct wl_buffer* create_pointer_buffer(UwacSeat* seat, const void* src, wl_shm_pool_destroy(pool); if (munmap(data, size) < 0) - fprintf(stderr, "%s: munmap(%p, %" PRIuz ") failed with [%d] %s\n", __FUNCTION__, data, - size, errno, strerror(errno)); + fprintf(stderr, "%s: munmap(%p, %z) failed with [%d] %s\n", __FUNCTION__, data, size, errno, + strerror(errno)); error_mmap: close(fd); diff --git a/uwac/libuwac/uwac-priv.h b/uwac/libuwac/uwac-priv.h index cbc570409eae..1bda15ff0285 100644 --- a/uwac/libuwac/uwac-priv.h +++ b/uwac/libuwac/uwac-priv.h @@ -237,8 +237,8 @@ struct uwac_window struct wl_region* opaque_region; struct wl_region* input_region; - SSIZE_T drawingBufferIdx; - SSIZE_T pendingBufferIdx; + ssize_t drawingBufferIdx; + ssize_t pendingBufferIdx; struct wl_surface* surface; struct wl_shell_surface* shell_surface; struct xdg_surface* xdg_surface; diff --git a/uwac/libuwac/uwac-window.c b/uwac/libuwac/uwac-window.c index 4600ad7fe37d..d503755740e3 100644 --- a/uwac/libuwac/uwac-window.c +++ b/uwac/libuwac/uwac-window.c @@ -370,9 +370,9 @@ int UwacWindowShmAllocBuffers(UwacWindow* w, int nbuffers, int allocSize, uint32 return ret; } -static UwacBuffer* UwacWindowFindFreeBuffer(UwacWindow* w, SSIZE_T* index) +static UwacBuffer* UwacWindowFindFreeBuffer(UwacWindow* w, ssize_t* index) { - SSIZE_T i; + ssize_t i; int ret; if (index) @@ -637,7 +637,7 @@ static const struct wl_callback_listener frame_listener = { frame_done_cb }; #ifdef HAVE_PIXMAN_REGION static void damage_surface(UwacWindow* window, UwacBuffer* buffer) { - UINT32 nrects, i; + uint32_t nrects, i; const pixman_box32_t* box = pixman_region32_rectangles(&buffer->damage, &nrects); for (i = 0; i < nrects; i++, box++) @@ -689,7 +689,7 @@ static void frame_done_cb(void* data, struct wl_callback* callback, uint32_t tim UwacReturnCode UwacWindowAddDamage(UwacWindow* window, uint32_t x, uint32_t y, uint32_t width, uint32_t height) { - UwacBuffer* buf = window->drawingBuffer; + UwacBuffer* buf = &window->buffers[window->drawingBufferIdx]; if (!pixman_region32_union_rect(&buf->damage, &buf->damage, x, y, width, height)) return UWAC_ERROR_INTERNAL; From f5c2485df22bdc61b654a5390e45c781b296c569 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Tue, 22 Nov 2022 09:14:06 +0100 Subject: [PATCH 314/496] [codec] fixed region16_union_rect * If source and destination are equal, free the buffer on destination to avoid compiler warnings. * Remove assert that is not required (cherry picked from commit 646ecd32cce8bded005b77719b031276f5574ac7) --- libfreerdp/codec/region.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/libfreerdp/codec/region.c b/libfreerdp/codec/region.c index 1009b852a903..dc4377fcbdc6 100644 --- a/libfreerdp/codec/region.c +++ b/libfreerdp/codec/region.c @@ -496,7 +496,6 @@ BOOL region16_union_rect(REGION16* dst, const REGION16* src, const RECTANGLE_16* UINT32 usedRects, srcNbRects; UINT16 topInterBand; assert(src); - assert(src->data); assert(dst); srcExtents = region16_extents(src); dstExtents = region16_extents_noconst(dst); @@ -658,8 +657,8 @@ BOOL region16_union_rect(REGION16* dst, const REGION16* src, const RECTANGLE_16* dstRect++; } - if ((src == dst) && (src->data->size > 0) && (src->data != &empty_region)) - free(src->data); + if ((src == dst) && (dst->data != &empty_region)) + free(dst->data); dstExtents->top = MIN(rect->top, srcExtents->top); dstExtents->left = MIN(rect->left, srcExtents->left); @@ -673,10 +672,7 @@ BOOL region16_union_rect(REGION16* dst, const REGION16* src, const RECTANGLE_16* dst->data = newItems; if (!dst->data) - { - free(newItems); return FALSE; - } dst->data->nbRects = usedRects; return region16_simplify_bands(dst); From 2466ddad844788c9c1973e92cc3e33729db6c6b7 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Wed, 7 Dec 2022 09:59:59 +0100 Subject: [PATCH 315/496] [channel,urbdrc] fix type of usb hotplug callback The libusb_hotplug_callback_fn uses LIBUSB_CALL call type (cherry picked from commit c9b806ba47b3f16793e5dc6300736d6a9c5adaf4) --- channels/urbdrc/client/libusb/libusb_udevman.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/channels/urbdrc/client/libusb/libusb_udevman.c b/channels/urbdrc/client/libusb/libusb_udevman.c index 5f1e9e0d2356..224ec304fbc9 100644 --- a/channels/urbdrc/client/libusb/libusb_udevman.c +++ b/channels/urbdrc/client/libusb/libusb_udevman.c @@ -581,8 +581,8 @@ static BOOL device_is_filtered(struct libusb_device* dev, return filtered; } -static int hotplug_callback(struct libusb_context* ctx, struct libusb_device* dev, - libusb_hotplug_event event, void* user_data) +static int LIBUSB_CALL hotplug_callback(struct libusb_context* ctx, struct libusb_device* dev, + libusb_hotplug_event event, void* user_data) { VID_PID_PAIR pair; struct libusb_device_descriptor desc; From 16935a7e9fdd25a22424843dacedba351f68eca6 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Mon, 12 Dec 2022 10:14:21 +0100 Subject: [PATCH 316/496] [client,x11] Fixed #8099: Detect key autorepeat When a key is pressed in autorepeat mode, skip the KeyRelease events in between. (cherry picked from commit c06317c0d173ee185361a779476cb277e67f524b) --- client/X11/xf_event.c | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/client/X11/xf_event.c b/client/X11/xf_event.c index bdcdcb5da0f6..eb50ef1e87da 100644 --- a/client/X11/xf_event.c +++ b/client/X11/xf_event.c @@ -521,6 +521,29 @@ static BOOL xf_event_KeyRelease(xfContext* xfc, const XKeyEvent* event, BOOL app return TRUE; } +/* Release a key, but ignore the event in case of autorepeat. + */ +static BOOL xf_event_KeyReleaseOrIgnore(xfContext* xfc, const XKeyEvent* event, BOOL app) +{ + WINPR_ASSERT(xfc); + WINPR_ASSERT(event); + + if ((event->type == KeyRelease) && XEventsQueued(xfc->display, QueuedAfterReading)) + { + XEvent nev = { 0 }; + XPeekEvent(xfc->display, &nev); + + if ((nev.type == KeyPress) && (nev.xkey.time == event->time) && + (nev.xkey.keycode == event->keycode)) + { + /* Key wasn’t actually released */ + return TRUE; + } + } + + return xf_event_KeyRelease(xfc, event, app); +} + static BOOL xf_event_FocusIn(xfContext* xfc, const XFocusInEvent* event, BOOL app) { if (event->mode == NotifyGrab) @@ -1086,7 +1109,7 @@ BOOL xf_event_process(freerdp* instance, const XEvent* event) break; case KeyRelease: - status = xf_event_KeyRelease(xfc, &event->xkey, xfc->remote_app); + status = xf_event_KeyReleaseOrIgnore(xfc, &event->xkey, xfc->remote_app); break; case FocusIn: From d931e63cd81065e92b45f055d9b47799d1bf7fb1 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Wed, 14 Dec 2022 09:44:57 +0100 Subject: [PATCH 317/496] [core,info] enforce extended info limits the cbClientAddress field limits defined in [MS-RDPBCGR] 2.2.1.11.1.1.1 Extended Info Packet (TS_EXTENDED_INFO_PACKET) are now properly enforced. (cherry picked from commit 268520f9f7b22bff249be772c55f973ad60fc267) --- libfreerdp/core/info.c | 39 +++++++++++++++++++++++++++++++++++---- 1 file changed, 35 insertions(+), 4 deletions(-) diff --git a/libfreerdp/core/info.c b/libfreerdp/core/info.c index 1603adcdd2fa..2a7d73d07ba0 100644 --- a/libfreerdp/core/info.c +++ b/libfreerdp/core/info.c @@ -272,6 +272,27 @@ static void rdp_write_client_auto_reconnect_cookie(rdpRdp* rdp, wStream* s) Stream_Write(s, autoReconnectCookie->securityVerifier, 16); /* SecurityVerifier (16 bytes) */ } +/* + * Get the cbClientAddress size limit + * see [MS-RDPBCGR] 2.2.1.11.1.1.1 Extended Info Packet (TS_EXTENDED_INFO_PACKET) + */ + +static size_t rdp_get_client_address_max_size(const rdpRdp* rdp) +{ + UINT32 version; + rdpSettings* settings; + + WINPR_ASSERT(rdp); + + settings = rdp->settings; + WINPR_ASSERT(settings); + + version = freerdp_settings_get_uint32(settings, FreeRDP_RdpVersion); + if (version < RDP_VERSION_10_0) + return 64; + return 80; +} + /** * Read Extended Info Packet (TS_EXTENDED_INFO_PACKET).\n * @msdn{cc240476} @@ -300,7 +321,7 @@ static BOOL rdp_read_extended_info_packet(rdpRdp* rdp, wStream* s) * is mandatory, connections via Microsoft's TS Gateway set cbClientAddress to 0. */ - if ((cbClientAddress % 2) || cbClientAddress > 80) + if ((cbClientAddress % 2) || (cbClientAddress > rdp_get_client_address_max_size(rdp))) { WLog_ERR(TAG, "protocol error: invalid cbClientAddress value: %" PRIu16 "", cbClientAddress); @@ -399,7 +420,8 @@ static BOOL rdp_write_extended_info_packet(rdpRdp* rdp, wStream* s) int rc; UINT16 clientAddressFamily; WCHAR* clientAddress = NULL; - UINT16 cbClientAddress; + size_t cbClientAddress; + const size_t cbClientAddressMax = rdp_get_client_address_max_size(rdp); WCHAR* clientDir = NULL; UINT16 cbClientDir; UINT16 cbAutoReconnectCookie; @@ -412,6 +434,16 @@ static BOOL rdp_write_extended_info_packet(rdpRdp* rdp, wStream* s) if ((rc < 0) || (rc > (UINT16_MAX / 2))) goto fail; cbClientAddress = (UINT16)rc * 2; + if (cbClientAddress > cbClientAddressMax) + { + WLog_WARN(TAG, + "[%s] the client address %s [%" PRIuz "] exceeds the limit of %" PRIuz + ", truncating.", + __FUNCTION__, settings->ClientAddress, cbClientAddress, cbClientAddressMax); + + clientAddress[(cbClientAddressMax / sizeof(WCHAR)) - 1] = '\0'; + cbClientAddress = cbClientAddressMax; + } rc = ConvertToUnicode(CP_UTF8, 0, settings->ClientDir, -1, &clientDir, 0); if ((rc < 0) || (rc > (UINT16_MAX / 2))) @@ -423,11 +455,10 @@ static BOOL rdp_write_extended_info_packet(rdpRdp* rdp, wStream* s) cbAutoReconnectCookie = (UINT16)settings->ServerAutoReconnectCookie->cbLen; Stream_Write_UINT16(s, clientAddressFamily); /* clientAddressFamily (2 bytes) */ - Stream_Write_UINT16(s, cbClientAddress + 2); /* cbClientAddress (2 bytes) */ + Stream_Write_UINT16(s, cbClientAddress); /* cbClientAddress (2 bytes) */ Stream_Write(s, clientAddress, cbClientAddress); /* clientAddress */ - Stream_Write_UINT16(s, 0); Stream_Write_UINT16(s, cbClientDir + 2); /* cbClientDir (2 bytes) */ Stream_Write(s, clientDir, cbClientDir); /* clientDir */ From 568c5a2bd3457a7b55178a9621dd099c5e66bca1 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Wed, 14 Dec 2022 09:59:43 +0100 Subject: [PATCH 318/496] [core,info] enforce cbClientDir limits the cbClientDir field limits defined in [MS-RDPBCGR] 2.2.1.11.1.1.1 Extended Info Packet (TS_EXTENDED_INFO_PACKET) are now properly enforced. (cherry picked from commit 66de09c2b1042d6cc56a28b55d88968dea6dfe8e) --- libfreerdp/core/info.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/libfreerdp/core/info.c b/libfreerdp/core/info.c index 2a7d73d07ba0..ca448c813cca 100644 --- a/libfreerdp/core/info.c +++ b/libfreerdp/core/info.c @@ -423,7 +423,8 @@ static BOOL rdp_write_extended_info_packet(rdpRdp* rdp, wStream* s) size_t cbClientAddress; const size_t cbClientAddressMax = rdp_get_client_address_max_size(rdp); WCHAR* clientDir = NULL; - UINT16 cbClientDir; + size_t cbClientDir; + const size_t cbClientDirMax = 512; UINT16 cbAutoReconnectCookie; rdpSettings* settings; if (!rdp || !rdp->settings || !s) @@ -449,6 +450,15 @@ static BOOL rdp_write_extended_info_packet(rdpRdp* rdp, wStream* s) if ((rc < 0) || (rc > (UINT16_MAX / 2))) goto fail; cbClientDir = (UINT16)rc * 2; + if (cbClientDir > cbClientDirMax) + { + WLog_WARN( + TAG, "[%s] the client dir %s [%" PRIuz "] exceeds the limit of %" PRIuz ", truncating.", + __FUNCTION__, settings->ClientDir, cbClientDir, cbClientDirMax); + + clientDir[(cbClientDirMax / sizeof(WCHAR)) - 1] = '\0'; + cbClientDir = cbClientDirMax; + } if (settings->ServerAutoReconnectCookie->cbLen > UINT16_MAX) goto fail; @@ -459,11 +469,10 @@ static BOOL rdp_write_extended_info_packet(rdpRdp* rdp, wStream* s) Stream_Write(s, clientAddress, cbClientAddress); /* clientAddress */ - Stream_Write_UINT16(s, cbClientDir + 2); /* cbClientDir (2 bytes) */ + Stream_Write_UINT16(s, cbClientDir); /* cbClientDir (2 bytes) */ Stream_Write(s, clientDir, cbClientDir); /* clientDir */ - Stream_Write_UINT16(s, 0); if (!rdp_write_client_time_zone(s, settings)) /* clientTimeZone (172 bytes) */ goto fail; From cdedc49a4771944917e5784454661dba66f0173f Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Wed, 14 Dec 2022 10:43:07 +0100 Subject: [PATCH 319/496] [core,info] ensure stream length ensure the stream is large enough for all info packets (cherry picked from commit daaec60daefdf8be7b7905a7199ee28e907fe824) --- libfreerdp/core/info.c | 29 +++++++++++++++++++++--- libfreerdp/core/timezone.c | 46 +++++++++++++++++++++++++++++--------- 2 files changed, 62 insertions(+), 13 deletions(-) diff --git a/libfreerdp/core/info.c b/libfreerdp/core/info.c index ca448c813cca..f16b5424a8c9 100644 --- a/libfreerdp/core/info.c +++ b/libfreerdp/core/info.c @@ -251,13 +251,23 @@ static BOOL rdp_read_client_auto_reconnect_cookie(rdpRdp* rdp, wStream* s) * @param settings settings */ -static void rdp_write_client_auto_reconnect_cookie(rdpRdp* rdp, wStream* s) +static BOOL rdp_write_client_auto_reconnect_cookie(rdpRdp* rdp, wStream* s) { BYTE* p; ARC_CS_PRIVATE_PACKET* autoReconnectCookie; - rdpSettings* settings = rdp->settings; + rdpSettings* settings; + + WINPR_ASSERT(rdp); + + settings = rdp->settings; + WINPR_ASSERT(settings); + autoReconnectCookie = settings->ClientAutoReconnectCookie; + WINPR_ASSERT(autoReconnectCookie); + p = autoReconnectCookie->securityVerifier; + WINPR_ASSERT(p); + WLog_DBG(TAG, "ClientAutoReconnectCookie: Version: %" PRIu32 " LogonId: %" PRIu32 " ArcRandomBits: " "%02" PRIX8 "%02" PRIX8 "%02" PRIX8 "%02" PRIX8 "%02" PRIX8 "%02" PRIX8 "%02" PRIX8 @@ -266,10 +276,13 @@ static void rdp_write_client_auto_reconnect_cookie(rdpRdp* rdp, wStream* s) "%02" PRIX8 "", autoReconnectCookie->version, autoReconnectCookie->logonId, p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]); + if (!Stream_EnsureRemainingCapacity(s, 12ull + 16ull)) + return FALSE; Stream_Write_UINT32(s, autoReconnectCookie->cbLen); /* cbLen (4 bytes) */ Stream_Write_UINT32(s, autoReconnectCookie->version); /* version (4 bytes) */ Stream_Write_UINT32(s, autoReconnectCookie->logonId); /* LogonId (4 bytes) */ Stream_Write(s, autoReconnectCookie->securityVerifier, 16); /* SecurityVerifier (16 bytes) */ + return TRUE; } /* @@ -464,6 +477,9 @@ static BOOL rdp_write_extended_info_packet(rdpRdp* rdp, wStream* s) goto fail; cbAutoReconnectCookie = (UINT16)settings->ServerAutoReconnectCookie->cbLen; + if (!Stream_EnsureRemainingCapacity(s, 4ull + cbClientAddress + 2ull + cbClientDir)) + goto fail; + Stream_Write_UINT16(s, clientAddressFamily); /* clientAddressFamily (2 bytes) */ Stream_Write_UINT16(s, cbClientAddress); /* cbClientAddress (2 bytes) */ @@ -476,6 +492,9 @@ static BOOL rdp_write_extended_info_packet(rdpRdp* rdp, wStream* s) if (!rdp_write_client_time_zone(s, settings)) /* clientTimeZone (172 bytes) */ goto fail; + if (!Stream_EnsureRemainingCapacity(s, 10ull)) + goto fail; + 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 (4 bytes) */ @@ -485,7 +504,11 @@ static BOOL rdp_write_extended_info_packet(rdpRdp* rdp, wStream* s) { if (!rdp_compute_client_auto_reconnect_cookie(rdp)) goto fail; - rdp_write_client_auto_reconnect_cookie(rdp, s); /* autoReconnectCookie */ + if (!rdp_write_client_auto_reconnect_cookie(rdp, s)) /* autoReconnectCookie */ + goto fail; + + if (!Stream_EnsureRemainingCapacity(s, 4ull)) + goto fail; Stream_Write_UINT16(s, 0); /* reserved1 (2 bytes) */ Stream_Write_UINT16(s, 0); /* reserved2 (2 bytes) */ } diff --git a/libfreerdp/core/timezone.c b/libfreerdp/core/timezone.c index 9de268719492..f6894d0c0904 100644 --- a/libfreerdp/core/timezone.c +++ b/libfreerdp/core/timezone.c @@ -22,12 +22,13 @@ #endif #include +#include #include #include "timezone.h" -static void rdp_read_system_time(wStream* s, SYSTEMTIME* system_time); -static void rdp_write_system_time(wStream* s, SYSTEMTIME* system_time); +static BOOL rdp_read_system_time(wStream* s, SYSTEMTIME* system_time); +static BOOL rdp_write_system_time(wStream* s, const SYSTEMTIME* system_time); /** * Read SYSTEM_TIME structure (TS_SYSTEMTIME).\n @@ -36,8 +37,13 @@ static void rdp_write_system_time(wStream* s, SYSTEMTIME* system_time); * @param system_time system time structure */ -void rdp_read_system_time(wStream* s, SYSTEMTIME* system_time) +BOOL rdp_read_system_time(wStream* s, SYSTEMTIME* system_time) { + WINPR_ASSERT(system_time); + + if (Stream_GetRemainingLength(s) < 16ull) + return FALSE; + Stream_Read_UINT16(s, system_time->wYear); /* wYear, must be set to 0 */ Stream_Read_UINT16(s, system_time->wMonth); /* wMonth */ Stream_Read_UINT16(s, system_time->wDayOfWeek); /* wDayOfWeek */ @@ -46,6 +52,7 @@ void rdp_read_system_time(wStream* s, SYSTEMTIME* system_time) Stream_Read_UINT16(s, system_time->wMinute); /* wMinute */ Stream_Read_UINT16(s, system_time->wSecond); /* wSecond */ Stream_Read_UINT16(s, system_time->wMilliseconds); /* wMilliseconds */ + return TRUE; } /** @@ -55,8 +62,12 @@ void rdp_read_system_time(wStream* s, SYSTEMTIME* system_time) * @param system_time system time structure */ -void rdp_write_system_time(wStream* s, SYSTEMTIME* system_time) +BOOL rdp_write_system_time(wStream* s, const SYSTEMTIME* system_time) { + WINPR_ASSERT(system_time); + if (!Stream_EnsureRemainingCapacity(s, 16ull)) + return FALSE; + Stream_Write_UINT16(s, system_time->wYear); /* wYear, must be set to 0 */ Stream_Write_UINT16(s, system_time->wMonth); /* wMonth */ Stream_Write_UINT16(s, system_time->wDayOfWeek); /* wDayOfWeek */ @@ -70,6 +81,7 @@ void rdp_write_system_time(wStream* s, SYSTEMTIME* system_time) system_time->wYear, system_time->wMonth, system_time->wDayOfWeek, system_time->wDay, system_time->wHour, system_time->wMinute, system_time->wSecond, system_time->wMilliseconds); + return TRUE; } /** @@ -81,7 +93,7 @@ void rdp_write_system_time(wStream* s, SYSTEMTIME* system_time) BOOL rdp_read_client_time_zone(wStream* s, rdpSettings* settings) { - LPTIME_ZONE_INFORMATION tz; + LPTIME_ZONE_INFORMATION tz = { 0 }; if (!s || !settings) return FALSE; @@ -97,11 +109,13 @@ BOOL rdp_read_client_time_zone(wStream* s, rdpSettings* settings) Stream_Read_UINT32(s, tz->Bias); /* Bias */ /* standardName (64 bytes) */ Stream_Read(s, tz->StandardName, sizeof(tz->StandardName)); - rdp_read_system_time(s, &tz->StandardDate); /* StandardDate */ + if (!rdp_read_system_time(s, &tz->StandardDate)) /* StandardDate */ + return FALSE; Stream_Read_UINT32(s, tz->StandardBias); /* StandardBias */ /* daylightName (64 bytes) */ Stream_Read(s, tz->DaylightName, sizeof(tz->DaylightName)); - rdp_read_system_time(s, &tz->DaylightDate); /* DaylightDate */ + if (!rdp_read_system_time(s, &tz->DaylightDate)) /* DaylightDate */ + return FALSE; Stream_Read_UINT32(s, tz->DaylightBias); /* DaylightBias */ return TRUE; } @@ -115,19 +129,26 @@ BOOL rdp_read_client_time_zone(wStream* s, rdpSettings* settings) BOOL rdp_write_client_time_zone(wStream* s, rdpSettings* settings) { - LPTIME_ZONE_INFORMATION tz; + LPTIME_ZONE_INFORMATION tz = { 0 }; + + WINPR_ASSERT(settings); tz = settings->ClientTimeZone; if (!tz) return FALSE; GetTimeZoneInformation(tz); + if (!Stream_EnsureRemainingCapacity(s, 4ull + sizeof(tz->StandardName))) + return FALSE; + /* Bias */ Stream_Write_UINT32(s, tz->Bias); /* standardName (64 bytes) */ Stream_Write(s, tz->StandardName, sizeof(tz->StandardName)); /* StandardDate */ - rdp_write_system_time(s, &tz->StandardDate); + if (!rdp_write_system_time(s, &tz->StandardDate)) + return FALSE; + #ifdef WITH_DEBUG_TIMEZONE WLog_DBG(TIMEZONE_TAG, "bias=%" PRId32 "", tz->Bias); WLog_DBG(TIMEZONE_TAG, "StandardName:"); @@ -139,14 +160,19 @@ BOOL rdp_write_client_time_zone(wStream* s, rdpSettings* settings) #endif /* Note that StandardBias is ignored if no valid standardDate is provided. */ /* StandardBias */ + if (!Stream_EnsureRemainingCapacity(s, 4ull + sizeof(tz->DaylightName))) + return FALSE; Stream_Write_UINT32(s, tz->StandardBias); DEBUG_TIMEZONE("StandardBias=%" PRId32 "", tz->StandardBias); /* daylightName (64 bytes) */ Stream_Write(s, tz->DaylightName, sizeof(tz->DaylightName)); /* DaylightDate */ - rdp_write_system_time(s, &tz->DaylightDate); + if (!rdp_write_system_time(s, &tz->DaylightDate)) + return FALSE; /* Note that DaylightBias is ignored if no valid daylightDate is provided. */ /* DaylightBias */ + if (!Stream_EnsureRemainingCapacity(s, 4ull)) + return FALSE; Stream_Write_UINT32(s, tz->DaylightBias); DEBUG_TIMEZONE("DaylightBias=%" PRId32 "", tz->DaylightBias); return TRUE; From 124232482404027123536489d6b5730169086a26 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Wed, 14 Dec 2022 11:31:10 +0100 Subject: [PATCH 320/496] [core,info] improve rdp_read_info_null_string * Removed comments with invalid assumptions * Added arguments to rdp_read_info_null_string to indicate if the string is expected to be '\0' terminated and what is actually read for error logs (cherry picked from commit 4fd3eb1469fffd3e4fce1fff7cba4d1bb146934b) --- libfreerdp/core/info.c | 55 ++++++++++++++++++------------------------ 1 file changed, 24 insertions(+), 31 deletions(-) diff --git a/libfreerdp/core/info.c b/libfreerdp/core/info.c index f16b5424a8c9..9aaa6cff6b74 100644 --- a/libfreerdp/core/info.c +++ b/libfreerdp/core/info.c @@ -69,8 +69,8 @@ static const struct info_flags_t info_flags[] = { { INFO_HIDEF_RAIL_SUPPORTED, "INFO_HIDEF_RAIL_SUPPORTED" }, }; -static BOOL rdp_read_info_null_string(UINT32 flags, wStream* s, size_t cbLen, CHAR** dst, - size_t max) +static BOOL rdp_read_info_null_string(const char* what, UINT32 flags, wStream* s, size_t cbLen, + CHAR** dst, size_t max, BOOL isNullTerminated) { CHAR* ret = NULL; @@ -78,23 +78,24 @@ static BOOL rdp_read_info_null_string(UINT32 flags, wStream* s, size_t cbLen, CH const size_t nullSize = unicode ? sizeof(WCHAR) : sizeof(CHAR); if (Stream_GetRemainingLength(s) < (size_t)(cbLen)) + { + WLog_ERR(TAG, "protocol error: no data to read for %s [expected %" PRIuz "]", what, cbLen); return FALSE; + } if (cbLen > 0) { - WCHAR domain[512 / sizeof(WCHAR) + sizeof(WCHAR)] = { 0 }; - /* cbDomain is the size in bytes of the character data in the Domain field. - * This size excludes (!) the length of the mandatory null terminator. - * Maximum value including the mandatory null terminator: 512 - */ - if ((cbLen % 2) || (cbLen > (max - nullSize))) + const WCHAR* domain = Stream_Pointer(s); + + if (isNullTerminated && (max > 0)) + max -= nullSize; + + if ((cbLen > max) || (unicode && ((cbLen % 2) != 0))) { - WLog_ERR(TAG, "protocol error: invalid value: %" PRIuz "", cbLen); + WLog_ERR(TAG, "protocol error: %s has invalid value: %" PRIuz "", what, cbLen); return FALSE; } - Stream_Read(s, domain, cbLen); - if (unicode) { if (ConvertFromUnicode(CP_UTF8, 0, domain, cbLen, &ret, 0, NULL, NULL) < 1) @@ -110,6 +111,13 @@ static BOOL rdp_read_info_null_string(UINT32 flags, wStream* s, size_t cbLen, CH return FALSE; memcpy(ret, domain, cbLen); } + + if (!Stream_SafeSeek(s, cbLen)) + { + WLog_ERR(TAG, "protocol error: no data to read for %s [expected %" PRIuz "]", what, + cbLen); + return FALSE; + } } free(*dst); @@ -327,27 +335,11 @@ static BOOL rdp_read_extended_info_packet(rdpRdp* rdp, wStream* s) Stream_Read_UINT16(s, clientAddressFamily); /* clientAddressFamily (2 bytes) */ Stream_Read_UINT16(s, cbClientAddress); /* cbClientAddress (2 bytes) */ - /* cbClientAddress is the size in bytes of the character data in the clientAddress field. - * This size includes the length of the mandatory null terminator. - * The maximum allowed value is 80 bytes - * Note: Although according to [MS-RDPBCGR 2.2.1.11.1.1.1] the null terminator - * is mandatory, connections via Microsoft's TS Gateway set cbClientAddress to 0. - */ - - if ((cbClientAddress % 2) || (cbClientAddress > rdp_get_client_address_max_size(rdp))) - { - WLog_ERR(TAG, "protocol error: invalid cbClientAddress value: %" PRIu16 "", - cbClientAddress); - return FALSE; - } - settings->IPv6Enabled = (clientAddressFamily == ADDRESS_FAMILY_INET6 ? TRUE : FALSE); - if (Stream_GetRemainingLength(s) < cbClientAddress) - return FALSE; - - if (!rdp_read_info_null_string(INFO_UNICODE, s, cbClientAddress, &settings->ClientAddress, - (settings->RdpVersion < RDP_VERSION_10_0) ? 64 : 80)) + if (!rdp_read_info_null_string("cbClientAddress", INFO_UNICODE, s, cbClientAddress, + &settings->ClientAddress, rdp_get_client_address_max_size(rdp), + TRUE)) return FALSE; if (Stream_GetRemainingLength(s) < 2) @@ -363,7 +355,8 @@ static BOOL rdp_read_extended_info_packet(rdpRdp* rdp, wStream* s) * sets cbClientDir to 0. */ - if (!rdp_read_info_null_string(INFO_UNICODE, s, cbClientDir, &settings->ClientDir, 512)) + if (!rdp_read_info_null_string("cbClientDir", INFO_UNICODE, s, cbClientDir, + &settings->ClientDir, 512, TRUE)) return FALSE; /** From c7513f37c72b6b2683a9cf8f5b7107d4cb266dc8 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Thu, 15 Dec 2022 15:55:49 +0100 Subject: [PATCH 321/496] [build] add channel path to RPATH some parts of freerdp link in channel libraries. if they are build with -DBUILTIN_CHANNELS=OFF the libraries are not found in the proper RPATH locations. --- CMakeLists.txt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 811cd39b8265..febd8133c035 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -990,7 +990,11 @@ if (APPLE) else (APPLE) set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) if (NOT FREEBSD) - set(CMAKE_INSTALL_RPATH "\$ORIGIN/../${CMAKE_INSTALL_LIBDIR}:\$ORIGIN/..") + if (NOT BUILTIN_CHANNELS) + set(CMAKE_INSTALL_RPATH "\$ORIGIN/../${CMAKE_INSTALL_LIBDIR}:\$ORIGIN/..:\$ORIGIN/../${FREERDP_PLUGIN_PATH}") + else() + set(CMAKE_INSTALL_RPATH "\$ORIGIN/../${CMAKE_INSTALL_LIBDIR}:\$ORIGIN/..") + endif() endif() endif(APPLE) From 5cfd76641963d06e803e16da9278a168ff1e51ce Mon Sep 17 00:00:00 2001 From: Hans-Peter Jansen Date: Fri, 16 Dec 2022 17:22:07 +0100 Subject: [PATCH 322/496] [build] add missing link targets for BUILTIN_CHANNELS --- channels/rdp2tcp/client/CMakeLists.txt | 2 +- channels/rdpsnd/client/proxy/CMakeLists.txt | 3 +++ channels/video/client/CMakeLists.txt | 6 ++++-- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/channels/rdp2tcp/client/CMakeLists.txt b/channels/rdp2tcp/client/CMakeLists.txt index 2e510200efdf..6c9e2fcd3685 100644 --- a/channels/rdp2tcp/client/CMakeLists.txt +++ b/channels/rdp2tcp/client/CMakeLists.txt @@ -22,6 +22,6 @@ set(${MODULE_PREFIX}_SRCS add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} TRUE "VirtualChannelEntryEx") -target_link_libraries(${MODULE_NAME} freerdp) +target_link_libraries(${MODULE_NAME} winpr freerdp) set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Channels/${CHANNEL_NAME}/Client") diff --git a/channels/rdpsnd/client/proxy/CMakeLists.txt b/channels/rdpsnd/client/proxy/CMakeLists.txt index 2d40750911b4..874d46a652a2 100644 --- a/channels/rdpsnd/client/proxy/CMakeLists.txt +++ b/channels/rdpsnd/client/proxy/CMakeLists.txt @@ -25,6 +25,9 @@ include_directories(..) add_channel_client_subsystem_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} "" TRUE "") +if (NOT BUILTIN_CHANNELS) + list(APPEND ${MODULE_PREFIX}_LIBS freerdp-client) +endif() list(APPEND ${MODULE_PREFIX}_LIBS freerdp) list(APPEND ${MODULE_PREFIX}_LIBS winpr) diff --git a/channels/video/client/CMakeLists.txt b/channels/video/client/CMakeLists.txt index cbbe483db95d..476b31677fb5 100644 --- a/channels/video/client/CMakeLists.txt +++ b/channels/video/client/CMakeLists.txt @@ -25,8 +25,10 @@ include_directories(..) add_channel_client_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} TRUE "DVCPluginEntry") - - +if (NOT BUILTIN_CHANNELS) + set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} freerdp-client) + set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} rdpgfx-client) +endif() set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} winpr) target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS}) From c6be8e7c971e4c1ef920ced3ecff4ba1d6fe2b58 Mon Sep 17 00:00:00 2001 From: Hans-Peter Jansen Date: Fri, 16 Dec 2022 17:26:30 +0100 Subject: [PATCH 323/496] [build] add cmake definition `WITH_PLUGIN_RPATH_ONLY` If we compile with `BUILTIN_CHANNELS`, we need to set up a run path to `FREERDP_PLUGIN_PATH`, even if we avoid using RPATHs in general. Supplying `-DWITH_PLUGIN_RPATH_ONLY=ON` will do this for you. --- CMakeLists.txt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index febd8133c035..9cf675f200ed 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -991,7 +991,12 @@ else (APPLE) set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) if (NOT FREEBSD) if (NOT BUILTIN_CHANNELS) - set(CMAKE_INSTALL_RPATH "\$ORIGIN/../${CMAKE_INSTALL_LIBDIR}:\$ORIGIN/..:\$ORIGIN/../${FREERDP_PLUGIN_PATH}") + if (NOT DEFINED WITH_PLUGIN_RPATH_ONLY) + set(CMAKE_INSTALL_RPATH "\$ORIGIN/../${CMAKE_INSTALL_LIBDIR}:\$ORIGIN/..:\$ORIGIN/../${FREERDP_PLUGIN_PATH}") + else() + # we need to supply this run path, even if not using RPATH in general + set(CMAKE_INSTALL_RPATH "\$ORIGIN/../${FREERDP_PLUGIN_PATH}") + endif() else() set(CMAKE_INSTALL_RPATH "\$ORIGIN/../${CMAKE_INSTALL_LIBDIR}:\$ORIGIN/..") endif() From 8083f1dcc29d85cdb35502fd7e258ecf2eb413e2 Mon Sep 17 00:00:00 2001 From: David VERON Date: Thu, 22 Dec 2022 10:34:22 +0100 Subject: [PATCH 324/496] revert changes so that the osmajortype/osminortype is not overwritten --- libfreerdp/core/capabilities.c | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/libfreerdp/core/capabilities.c b/libfreerdp/core/capabilities.c index 786e30c5ddf8..c7fbd7e99840 100644 --- a/libfreerdp/core/capabilities.c +++ b/libfreerdp/core/capabilities.c @@ -162,17 +162,26 @@ static BOOL rdp_read_general_capability_set(wStream* s, rdpSettings* settings) if (Stream_GetRemainingLength(s) < 20) return FALSE; - Stream_Read_UINT16(s, settings->OsMajorType); /* osMajorType (2 bytes) */ - Stream_Read_UINT16(s, settings->OsMinorType); /* osMinorType (2 bytes) */ - Stream_Seek_UINT16(s); /* protocolVersion (2 bytes) */ - Stream_Seek_UINT16(s); /* pad2OctetsA (2 bytes) */ - Stream_Seek_UINT16(s); /* generalCompressionTypes (2 bytes) */ - Stream_Read_UINT16(s, extraFlags); /* extraFlags (2 bytes) */ - Stream_Seek_UINT16(s); /* updateCapabilityFlag (2 bytes) */ - Stream_Seek_UINT16(s); /* remoteUnshareFlag (2 bytes) */ - Stream_Seek_UINT16(s); /* generalCompressionLevel (2 bytes) */ - Stream_Read_UINT8(s, refreshRectSupport); /* refreshRectSupport (1 byte) */ - Stream_Read_UINT8(s, suppressOutputSupport); /* suppressOutputSupport (1 byte) */ + if (settings->ServerMode) + { + Stream_Read_UINT16(s, settings->OsMajorType); /* osMajorType (2 bytes) */ + Stream_Read_UINT16(s, settings->OsMinorType); /* osMinorType (2 bytes) */ + } + else + { + Stream_Seek_UINT16(s); /* osMajorType (2 bytes) */ + Stream_Seek_UINT16(s); /* osMinorType (2 bytes) */ + } + + Stream_Seek_UINT16(s); /* protocolVersion (2 bytes) */ + Stream_Seek_UINT16(s); /* pad2OctetsA (2 bytes) */ + Stream_Seek_UINT16(s); /* generalCompressionTypes (2 bytes) */ + Stream_Read_UINT16(s, extraFlags); /* extraFlags (2 bytes) */ + Stream_Seek_UINT16(s); /* updateCapabilityFlag (2 bytes) */ + Stream_Seek_UINT16(s); /* remoteUnshareFlag (2 bytes) */ + Stream_Seek_UINT16(s); /* generalCompressionLevel (2 bytes) */ + Stream_Read_UINT8(s, refreshRectSupport); /* refreshRectSupport (1 byte) */ + Stream_Read_UINT8(s, suppressOutputSupport); /* suppressOutputSupport (1 byte) */ settings->NoBitmapCompressionHeader = (extraFlags & NO_BITMAP_COMPRESSION_HDR) ? TRUE : FALSE; settings->LongCredentialsSupported = (extraFlags & LONG_CREDENTIALS_SUPPORTED) ? TRUE : FALSE; From 559dcf214a2a1203e43d57d2b7b048c5612b4f05 Mon Sep 17 00:00:00 2001 From: Pascal Nowack Date: Fri, 30 Dec 2022 13:38:09 +0100 Subject: [PATCH 325/496] core/server: Ignore data PDUs for DVCs that were not opened successfully When a FreeRDP-based server tried to open a DVC, but the client answered the DVC create request with a negative CreationStatus in the DVC create response PDU, the server can then assume that no actual PDUs can be received for that channel. However, as long as the channel handle exists, FreeRDP happily forwards any potential PDU for that handle disregarding the CreationStatus. This is problematic, since the channel handling usually runs in its own thread and as a result, the channel may not be destructed yet, when receiving such stray PDU. The PDU may be processed, even though it is not expected to be. A situation, where this becomes problematic is the AUDIO_PLAYBACK_DVC channel. It may be the case, that the client answered the DVC create request with a negative result, the server may try to close the handle and open the static channel (RDPSND) instead, but before the server can close the channel handle, the client actually sends PDUs regarding the format negotiation. In this case, the server may unintentionally already set things up, which was not desired (the DVC is about to be closed anyway). While this specific situation is hypothetical, since it would depend on a malicious client, it is still possible to happen, especially since the server implementation does not invoke the format negotiation, but FreeRDP does it automatically, as soon as the DVC create request is sent. Fix this issue by discarding any data PDUs (DYNVC_DATA_FIRST and DYNVC_DATA) of channels, that were not opened successfully. --- libfreerdp/core/server.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/libfreerdp/core/server.c b/libfreerdp/core/server.c index 8e36972e5965..a786cbd8e4e1 100644 --- a/libfreerdp/core/server.c +++ b/libfreerdp/core/server.c @@ -291,9 +291,27 @@ static BOOL wts_read_drdynvc_pdu(rdpPeerChannel* channel) return wts_read_drdynvc_create_response(dvc, channel->receiveData, length); case DATA_FIRST_PDU: + if (dvc->dvc_open_state != DVC_OPEN_STATE_SUCCEEDED) + { + WLog_ERR(TAG, + "ChannelId %" PRIu32 " did not open successfully. " + "Ignoring DYNVC_DATA_FIRST PDU", + ChannelId); + return TRUE; + } + return wts_read_drdynvc_data_first(dvc, channel->receiveData, Sp, length); case DATA_PDU: + if (dvc->dvc_open_state != DVC_OPEN_STATE_SUCCEEDED) + { + WLog_ERR(TAG, + "ChannelId %" PRIu32 " did not open successfully. " + "Ignoring DYNVC_DATA PDU", + ChannelId); + return TRUE; + } + return wts_read_drdynvc_data(dvc, channel->receiveData, length); case CLOSE_REQUEST_PDU: From 2ec1b3bef6cb4b37529948a0d46e58881e9e05a1 Mon Sep 17 00:00:00 2001 From: Pascal Nowack Date: Sat, 31 Dec 2022 11:51:03 +0100 Subject: [PATCH 326/496] Update changelog --- ChangeLog | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ChangeLog b/ChangeLog index 68c40382cdd8..41ce3be12dd3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +# 20xx-xx-xx Version 2.x.x + +Fixed issues: +* Backported #8581: Ignore data PDUs for DVCs that were not opened successfully + # 2022-11-16 Version 2.9.0 Notewhorth changes: From bf5c1901a43bf928ff97b92b92d6c203e62b9e7c Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Wed, 11 Jan 2023 19:56:26 +0100 Subject: [PATCH 327/496] [uwac] do not use iso C functions --- uwac/libuwac/uwac-clipboard.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/uwac/libuwac/uwac-clipboard.c b/uwac/libuwac/uwac-clipboard.c index 1d5c8fbf0002..6811bfb95abd 100644 --- a/uwac/libuwac/uwac-clipboard.c +++ b/uwac/libuwac/uwac-clipboard.c @@ -54,7 +54,7 @@ static void data_offer_offer(void* data, struct wl_data_offer* data_offer, else { event->seat = seat; - sprintf_s(event->mime, sizeof(event->mime), "%s", offered_mime_type); + snprintf(event->mime, sizeof(event->mime), "%s", offered_mime_type); } } } From a23a24fe068c37d20c254fe393d4fe5d4c6ab31d Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Wed, 11 Jan 2023 20:31:20 +0100 Subject: [PATCH 328/496] [winpr,ntlm] fix NTOWFvxxxA functions MultiByte string encoding lenght might differ from WCHAR encoding length. Pass on proper lengths. --- winpr/libwinpr/utils/ntlm.c | 51 ++++++++++++++++++++----------------- 1 file changed, 27 insertions(+), 24 deletions(-) diff --git a/winpr/libwinpr/utils/ntlm.c b/winpr/libwinpr/utils/ntlm.c index 3af38b642ebe..42eaf552e77b 100644 --- a/winpr/libwinpr/utils/ntlm.c +++ b/winpr/libwinpr/utils/ntlm.c @@ -48,16 +48,15 @@ BOOL NTOWFv1A(LPSTR Password, UINT32 PasswordLength, BYTE* NtHash) { LPWSTR PasswordW = NULL; BOOL result = FALSE; + int PasswordLengthW = 0; if (!NtHash) return FALSE; - if (!(PasswordW = (LPWSTR)calloc(PasswordLength, 2))) - return FALSE; - - MultiByteToWideChar(CP_ACP, 0, Password, PasswordLength, PasswordW, PasswordLength); - - if (!NTOWFv1W(PasswordW, PasswordLength * 2, NtHash)) + PasswordLengthW = ConvertToUnicode(CP_ACP, 0, Password, PasswordLength, &PasswordW, 0); + if (PasswordLengthW < 0) + goto out_fail; + if (!NTOWFv1W(PasswordW, PasswordLengthW * sizeof(WCHAR), NtHash)) goto out_fail; result = TRUE; @@ -94,23 +93,26 @@ BOOL NTOWFv2A(LPSTR Password, UINT32 PasswordLength, LPSTR User, UINT32 UserLeng LPWSTR DomainW = NULL; LPWSTR PasswordW = NULL; BOOL result = FALSE; + int UserLengthW = 0; + int DomainLengthW = 0; + int PasswordLengthW = 0; if (!NtHash) return FALSE; - UserW = (LPWSTR)calloc(UserLength, 2); - DomainW = (LPWSTR)calloc(DomainLength, 2); - PasswordW = (LPWSTR)calloc(PasswordLength, 2); + UserLengthW = ConvertToUnicode(CP_ACP, 0, User, UserLength, &UserW, 0); + DomainLengthW = ConvertToUnicode(CP_ACP, 0, Domain, DomainLength, &DomainW, 0); + PasswordLengthW = ConvertToUnicode(CP_ACP, 0, Password, PasswordLength, &PasswordW, 0); - if (!UserW || !DomainW || !PasswordW) + if (UserLengthW < 0) + goto out_fail; + if (DomainLengthW < 0) + goto out_fail; + if (PasswordLengthW < 0) goto out_fail; - MultiByteToWideChar(CP_ACP, 0, User, UserLength, UserW, UserLength); - MultiByteToWideChar(CP_ACP, 0, Domain, DomainLength, DomainW, DomainLength); - MultiByteToWideChar(CP_ACP, 0, Password, PasswordLength, PasswordW, PasswordLength); - - if (!NTOWFv2W(PasswordW, PasswordLength * 2, UserW, UserLength * 2, DomainW, DomainLength * 2, - NtHash)) + if (!NTOWFv2W(PasswordW, PasswordLengthW * sizeof(WCHAR), UserW, UserLengthW * sizeof(WCHAR), + DomainW, DomainLengthW * sizeof(WCHAR), NtHash)) goto out_fail; result = TRUE; @@ -160,20 +162,21 @@ BOOL NTOWFv2FromHashA(BYTE* NtHashV1, LPSTR User, UINT32 UserLength, LPSTR Domai LPWSTR UserW = NULL; LPWSTR DomainW = NULL; BOOL result = FALSE; + int UserLengthW = 0; + int DomainLengthW = 0; if (!NtHash) return FALSE; - UserW = (LPWSTR)calloc(UserLength, 2); - DomainW = (LPWSTR)calloc(DomainLength, 2); - - if (!UserW || !DomainW) + UserLengthW = ConvertToUnicode(CP_ACP, 0, User, UserLength, &UserW, 0); + DomainLengthW = ConvertToUnicode(CP_ACP, 0, Domain, DomainLength, &DomainW, 0); + if (UserLengthW < 0) + goto out_fail; + if (DomainLengthW < 0) goto out_fail; - MultiByteToWideChar(CP_ACP, 0, User, UserLength, UserW, UserLength); - MultiByteToWideChar(CP_ACP, 0, Domain, DomainLength, DomainW, DomainLength); - - if (!NTOWFv2FromHashW(NtHashV1, UserW, UserLength * 2, DomainW, DomainLength * 2, NtHash)) + if (!NTOWFv2FromHashW(NtHashV1, UserW, UserLength * sizeof(WCHAR), DomainW, + DomainLength * sizeof(WCHAR), NtHash)) goto out_fail; result = TRUE; From 2e88032b806e3b80ad18e5d1a7077d26fc11c4fb Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Wed, 11 Jan 2023 21:07:59 +0100 Subject: [PATCH 329/496] [winpr,sam] fix inalid NULL arguments (cherry picked from commit efa2adc58790cfed5a355f6942f3ad04323f699a) --- winpr/libwinpr/utils/sam.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/winpr/libwinpr/utils/sam.c b/winpr/libwinpr/utils/sam.c index 7270bf69d587..78ac5640008c 100644 --- a/winpr/libwinpr/utils/sam.c +++ b/winpr/libwinpr/utils/sam.c @@ -59,9 +59,11 @@ static WINPR_SAM_ENTRY* SamEntryFromDataA(LPCSTR User, DWORD UserLength, LPCSTR WINPR_SAM_ENTRY* entry = calloc(1, sizeof(WINPR_SAM_ENTRY)); if (!entry) return NULL; - entry->User = _strdup(User); + if (User && (UserLength > 0)) + entry->User = _strdup(User); entry->UserLength = UserLength; - entry->Domain = _strdup(Domain); + if (Domain && (DomainLength > 0)) + entry->Domain = _strdup(Domain); entry->DomainLength = DomainLength; return entry; } From aba265398dc23e8ddaa378f371ecb48de204fca4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Wed, 16 Nov 2022 16:56:36 +0100 Subject: [PATCH 330/496] uwac/input: Set the right serial when setting cursor The serial in wl_pointer.set_cursor must exactly match the one from wl_pointer.enter, it should not use whatever serial for any input class is the newest. (cherry picked from commit b2cf6f5c2c8acbe3a4acdf052c3aec3b776e352e) --- uwac/libuwac/uwac-input.c | 3 ++- uwac/libuwac/uwac-priv.h | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/uwac/libuwac/uwac-input.c b/uwac/libuwac/uwac-input.c index 52d9d3e22019..661f9bfa2eff 100644 --- a/uwac/libuwac/uwac-input.c +++ b/uwac/libuwac/uwac-input.c @@ -732,6 +732,7 @@ static void pointer_handle_enter(void* data, struct wl_pointer* pointer, uint32_ } input->display->serial = serial; + input->display->pointer_focus_serial = serial; window = wl_surface_get_user_data(surface); if (window) window->pointer_enter_serial = serial; @@ -1162,5 +1163,5 @@ UwacReturnCode UwacSeatSetMouseCursor(UwacSeat* seat, const void* data, size_t l { seat->pointer_type = 1; } - return set_cursor_image(seat, seat->display->serial); + return set_cursor_image(seat, seat->display->pointer_focus_serial); } diff --git a/uwac/libuwac/uwac-priv.h b/uwac/libuwac/uwac-priv.h index 1bda15ff0285..69556bfc6174 100644 --- a/uwac/libuwac/uwac-priv.h +++ b/uwac/libuwac/uwac-priv.h @@ -121,6 +121,7 @@ struct uwac_display bool running; UwacTask dispatch_fd_task; uint32_t serial; + uint32_t pointer_focus_serial; struct wl_list windows; From 020fdf491d1f3d78e3fd214d41c6d2d64fc7392c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Wed, 16 Nov 2022 17:01:02 +0100 Subject: [PATCH 331/496] uwac/input: Don't pass hotspot as offset when attaching cursor buffer Passing a non-zero offset to cursor buffer and then calling wl_pointer.set_cursor doesn't make much sense, as any offset will immediately be reset. The protocol specifies the cursor set by wl_pointer.set_cursor to be > The parameters hotspot_x and hotspot_y define the position of > the pointer surface relative to the pointer location. Its > top-left corner is always at (x, y) - (hotspot_x, hotspot_y), > where (x, y) are the coordinates of the pointer location, in > surface-local coordinates. This leaves no room available for any previously set offsets to be kept in response to wl_pointer.set_cursor. (cherry picked from commit 5b09cd57a7ecd2bd588a3edd784081796c96e324) --- uwac/libuwac/uwac-input.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/uwac/libuwac/uwac-input.c b/uwac/libuwac/uwac-input.c index 661f9bfa2eff..6854092fa490 100644 --- a/uwac/libuwac/uwac-input.c +++ b/uwac/libuwac/uwac-input.c @@ -137,7 +137,7 @@ static UwacReturnCode set_cursor_image(UwacSeat* seat, uint32_t serial) if (surface && buffer_add_listener_success > -1) { - wl_surface_attach(surface, buffer, -x, -y); + wl_surface_attach(surface, buffer, 0, 0); wl_surface_damage(surface, 0, 0, image->width, image->height); wl_surface_commit(surface); } From 0128dfaa89cc1c57529b11fc31486f287e8ed837 Mon Sep 17 00:00:00 2001 From: Khem Raj Date: Tue, 17 Jan 2023 19:31:17 -0800 Subject: [PATCH 332/496] Fix incompatible function pointer types clang 16+ is flagging the function pointer prototype mismatches, therefore fix it. Fixes Issue #8487 Signed-off-by: Khem Raj --- client/X11/xf_disp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/X11/xf_disp.c b/client/X11/xf_disp.c index 32ddb626c3aa..ef0cb93ff398 100644 --- a/client/X11/xf_disp.c +++ b/client/X11/xf_disp.c @@ -248,7 +248,7 @@ static void xf_disp_OnTimer(void* context, TimerEventArgs* e) xf_disp_sendResize(xfDisp); } -static void xf_disp_OnWindowStateChange(void* context, const WindowStateChangeEventArgs* e) +static void xf_disp_OnWindowStateChange(void* context, WindowStateChangeEventArgs* e) { xfContext* xfc; xfDispContext* xfDisp; From 01d0f7c640cacda2b9050c11a7c0d44905ef0d70 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Wed, 8 Feb 2023 07:48:49 +0100 Subject: [PATCH 333/496] [build,android] only use CMake from SDK * only use CMake from android SDK * abort if CMake or ndk-build are not detected * update default OpenSSL (cherry picked from commit de5899500623eedd8c08f5c954d85e3d378e68d9) --- scripts/android-build-common.sh | 28 ++++-- scripts/android-build-freerdp.sh | 157 ++++++++++++++++--------------- 2 files changed, 97 insertions(+), 88 deletions(-) diff --git a/scripts/android-build-common.sh b/scripts/android-build-common.sh index b3675e374cad..2e58331a9ab9 100644 --- a/scripts/android-build-common.sh +++ b/scripts/android-build-common.sh @@ -8,11 +8,11 @@ case "$(uname -s)" in Darwin) FIND_ARGS="-perm +111 $FIND_ARGS" - ;; + ;; *) FIND_ARGS="-executable $FIND_ARGS" - ;; + ;; esac if [ -z $BUILD_ARCH ]; then @@ -96,10 +96,10 @@ function common_parse_arguments { do key="$1" case $key in - --conf) - source "$2" || exit 1 - shift - ;; + --conf) + source "$2" || exit 1 + shift + ;; --target) NDK_TARGET="$2" @@ -217,12 +217,20 @@ function common_check_requirements { else echo "ndk-build not found in NDK directory $ANDROID_NDK" echo "assuming ndk-build is in path..." - NDK_BUILD=ndk-build + NDK_BUILD=$(which ndk-build) + if [ -z $NDK_BUILD ]; then + echo "ndk-build not found in $ANDROID_NDK and not in PATH" + exit 1 + fi fi - if [ -z $CMAKE_PROGRAM ]; then - CMAKE_PROGRAM=$(find $ANDROID_SDK/cmake -name cmake $FIND_ARGS) - fi + if [ -z $CMAKE_PROGRAM ]; then + CMAKE_PROGRAM=$(find $ANDROID_SDK/cmake -name cmake $FIND_ARGS) + if [ -z $CMAKE_PROGRAM ]; then + echo "CMake not found in $ANDROID_SDK, install CMake from the android SDK!" + exit 1 + fi + fi for CMD in make git $CMAKE_PROGRAM $NDK_BUILD do diff --git a/scripts/android-build-freerdp.sh b/scripts/android-build-freerdp.sh index 6257cc9310f6..0caab58f3c46 100755 --- a/scripts/android-build-freerdp.sh +++ b/scripts/android-build-freerdp.sh @@ -2,8 +2,8 @@ OPENH264_TAG=v2.3.1 OPENH264_HASH=453afa66dacb560bc5fd0468aabee90c483741571bca820a39a1c07f0362dc32 -OPENSSL_TAG=openssl-1.1.1q -OPENSSL_HASH=d7939ce614029cdff0b6c20f0e2e5703158a489a72b2507b8bd51bf8c8fd10ca +OPENSSL_TAG=openssl-1.1.1s +OPENSSL_HASH=c5ac01e760ee6ff0dab61d6b2bbd30146724d063eb322180c6f18a6f74e4b6aa FFMPEG_TAG=n4.4.1 FFMPEG_HASH=82b43cc67296bcd01a59ae6b327cdb50121d3a9e35f41a30de1edd71bb4a6666 @@ -76,8 +76,8 @@ common_parse_arguments $REMAINING if [ -z ${WITH_MEDIACODEC+x} ]; then - common_run echo "WITH_MEDIACODEC unset, defining WITH_MEDIACODEC=1" - WITH_MEDIACODEC=1 + common_run echo "WITH_MEDIACODEC unset, defining WITH_MEDIACODEC=1" + WITH_MEDIACODEC=1 fi # clean up top @@ -99,91 +99,92 @@ CMAKE_CMD_ARGS="-DANDROID_NDK=$ANDROID_NDK \ -DCMAKE_TOOLCHAIN_FILE=$ANDROID_NDK/build/cmake/android.toolchain.cmake \ -DCMAKE_BUILD_TYPE=$CMAKE_BUILD_TYPE \ -DFREERDP_EXTERNAL_PATH=$BUILD_DST \ + -DWITH_CLIENT_SDL=OFF \ -DCMAKE_MAKE_PROGRAM=make" BASE=$(pwd) for ARCH in $BUILD_ARCH do - # build dependencies. - if [ $WITH_OPENH264 -ne 0 ]; - then - if [ -z "$ANDROID_NDK_OPENH264" ] - then - echo - echo "Warning: Missing openh264-ndk, using $ANDROID_NDK" >&2 - echo - ANDROID_NDK_OPENH264=$ANDROID_NDK - fi - if [ $BUILD_DEPS -ne 0 ]; - then - common_run bash $SCRIPT_PATH/android-build-openh264.sh \ - --src $BUILD_SRC/openh264 --dst $BUILD_DST \ - --sdk "$ANDROID_SDK" \ - --ndk "$ANDROID_NDK_OPENH264" \ - --arch $ARCH \ - --target $NDK_TARGET \ - --tag $OPENH264_TAG \ + # build dependencies. + if [ $WITH_OPENH264 -ne 0 ]; + then + if [ -z "$ANDROID_NDK_OPENH264" ] + then + echo + echo "Warning: Missing openh264-ndk, using $ANDROID_NDK" >&2 + echo + ANDROID_NDK_OPENH264=$ANDROID_NDK + fi + if [ $BUILD_DEPS -ne 0 ]; + then + common_run bash $SCRIPT_PATH/android-build-openh264.sh \ + --src $BUILD_SRC/openh264 --dst $BUILD_DST \ + --sdk "$ANDROID_SDK" \ + --ndk "$ANDROID_NDK_OPENH264" \ + --arch $ARCH \ + --target $NDK_TARGET \ + --tag $OPENH264_TAG \ --hash $OPENH264_HASH - fi - CMAKE_CMD_ARGS="$CMAKE_CMD_ARGS -DWITH_OPENH264=ON" - else - CMAKE_CMD_ARGS="$CMAKE_CMD_ARGS -DWITH_OPENH264=OFF" - fi - - if [ $WITH_MEDIACODEC -ne 0 ]; - then - CMAKE_CMD_ARGS="$CMAKE_CMD_ARGS -DWITH_MEDIACODEC=ON" - else - CMAKE_CMD_ARGS="$CMAKE_CMD_ARGS -DWITH_MEDIACODEC=OFF" - fi + fi + CMAKE_CMD_ARGS="$CMAKE_CMD_ARGS -DWITH_OPENH264=ON" + else + CMAKE_CMD_ARGS="$CMAKE_CMD_ARGS -DWITH_OPENH264=OFF" + fi + + if [ $WITH_MEDIACODEC -ne 0 ]; + then + CMAKE_CMD_ARGS="$CMAKE_CMD_ARGS -DWITH_MEDIACODEC=ON" + else + CMAKE_CMD_ARGS="$CMAKE_CMD_ARGS -DWITH_MEDIACODEC=OFF" + fi if [ $WITH_FFMPEG -ne 0 ]; - then + then if [ $BUILD_DEPS -ne 0 ]; - then - common_run bash $SCRIPT_PATH/android-build-ffmpeg.sh \ - --src $BUILD_SRC/ffmpeg --dst $BUILD_DST \ - --sdk "$ANDROID_SDK" \ - --ndk "$ANDROID_NDK" \ - --arch $ARCH \ - --target $NDK_TARGET \ - --tag $FFMPEG_TAG \ - --hash $FFMPEG_HASH - fi - CMAKE_CMD_ARGS="$CMAKE_CMD_ARGS -DWITH_FFMPEG=ON -DWITH_SWSCALE=ON -DWITH_DSP_FFMPEG=ON" + then + common_run bash $SCRIPT_PATH/android-build-ffmpeg.sh \ + --src $BUILD_SRC/ffmpeg --dst $BUILD_DST \ + --sdk "$ANDROID_SDK" \ + --ndk "$ANDROID_NDK" \ + --arch $ARCH \ + --target $NDK_TARGET \ + --tag $FFMPEG_TAG \ + --hash $FFMPEG_HASH + fi + CMAKE_CMD_ARGS="$CMAKE_CMD_ARGS -DWITH_FFMPEG=ON -DWITH_SWCALE=ON" else - CMAKE_CMD_ARGS="$CMAKE_CMD_ARGS -DWITH_FFMPEG=OFF -DWITH_SWSCALE=OFF -DWITH_DSP_FFMPEG=OFF" - fi - if [ $WITH_OPENSSL -ne 0 ]; - then - if [ $BUILD_DEPS -ne 0 ]; - then - common_run bash $SCRIPT_PATH/android-build-openssl.sh \ - --src $BUILD_SRC/openssl --dst $BUILD_DST \ - --sdk "$ANDROID_SDK" \ - --ndk $ANDROID_NDK \ - --arch $ARCH \ + CMAKE_CMD_ARGS="$CMAKE_CMD_ARGS -DWITH_FFMPEG=OFF" + fi + if [ $WITH_OPENSSL -ne 0 ]; + then + if [ $BUILD_DEPS -ne 0 ]; + then + common_run bash $SCRIPT_PATH/android-build-openssl.sh \ + --src $BUILD_SRC/openssl --dst $BUILD_DST \ + --sdk "$ANDROID_SDK" \ + --ndk $ANDROID_NDK \ + --arch $ARCH \ --target $NDK_TARGET \ - --tag $OPENSSL_TAG \ - --hash $OPENSSL_HASH - fi - fi - - # Build and install the library. - if [ $DEPS_ONLY -eq 0 ]; - then - common_run cd $BASE - common_run mkdir -p $BUILD_SRC/freerdp-build/$ARCH - common_run cd $BUILD_SRC/freerdp-build/$ARCH - common_run export ANDROID_NDK=$ANDROID_NDK - common_run $CMAKE_PROGRAM $CMAKE_CMD_ARGS \ - -DANDROID_ABI=$ARCH \ - -DCMAKE_INSTALL_PREFIX=$BUILD_DST/$ARCH \ - -DCMAKE_INSTALL_LIBDIR=. \ - $SRC_DIR - echo $(pwd) - common_run cmake --build . --target install - fi + --tag $OPENSSL_TAG \ + --hash $OPENSSL_HASH + fi + fi + + # Build and install the library. + if [ $DEPS_ONLY -eq 0 ]; + then + common_run cd $BASE + common_run mkdir -p $BUILD_SRC/freerdp-build/$ARCH + common_run cd $BUILD_SRC/freerdp-build/$ARCH + common_run export ANDROID_NDK=$ANDROID_NDK + common_run $CMAKE_PROGRAM $CMAKE_CMD_ARGS \ + -DANDROID_ABI=$ARCH \ + -DCMAKE_INSTALL_PREFIX=$BUILD_DST/$ARCH \ + -DCMAKE_INSTALL_LIBDIR=. \ + $SRC_DIR + echo $(pwd) + common_run $CMAKE_PROGRAM --build . --target install + fi done echo "Successfully build library for architectures $BUILD_ARCH" From b363ba5a637c155ceb5ff2b4f9a50c6c7c7f8bc4 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Thu, 29 Jul 2021 12:33:22 +0200 Subject: [PATCH 334/496] Backported utils_str_* (cherry picked from commit 50e9d3adf90fe73c0c95818ad835794e3cc207bb) --- libfreerdp/core/CMakeLists.txt | 2 ++ libfreerdp/core/utils.c | 22 ++++++++++++++++++++++ libfreerdp/core/utils.h | 3 +++ 3 files changed, 27 insertions(+) diff --git a/libfreerdp/core/CMakeLists.txt b/libfreerdp/core/CMakeLists.txt index a979d7ad2dd1..22757fda02a8 100644 --- a/libfreerdp/core/CMakeLists.txt +++ b/libfreerdp/core/CMakeLists.txt @@ -50,6 +50,8 @@ set(${MODULE_PREFIX}_GATEWAY_SRCS ${${MODULE_PREFIX}_GATEWAY_DIR}/ncacn_http.h) set(${MODULE_PREFIX}_SRCS + utils.c + utils.h bulk.c bulk.h activation.c diff --git a/libfreerdp/core/utils.c b/libfreerdp/core/utils.c index 72432a2b9fff..139c1a4336d8 100644 --- a/libfreerdp/core/utils.c +++ b/libfreerdp/core/utils.c @@ -31,6 +31,19 @@ #include "utils.h" +BOOL utils_str_copy(const char* value, char** dst) +{ + WINPR_ASSERT(dst); + + free(*dst); + *dst = NULL; + if (!value) + return TRUE; + + (*dst) = _strdup(value); + return (*dst) != NULL; +} + BOOL utils_abort_connect(rdpContext* context) { WINPR_ASSERT(context); @@ -43,3 +56,12 @@ BOOL utils_reset_abort(rdpContext* context) WINPR_ASSERT(context); return ResetEvent(context->abortEvent); } + +BOOL utils_str_is_empty(const char* str) +{ + if (!str) + return TRUE; + if (strlen(str) == 0) + return TRUE; + return FALSE; +} diff --git a/libfreerdp/core/utils.h b/libfreerdp/core/utils.h index c7985be6650d..432951812f5e 100644 --- a/libfreerdp/core/utils.h +++ b/libfreerdp/core/utils.h @@ -27,4 +27,7 @@ BOOL utils_reset_abort(rdpContext* context); BOOL utils_abort_connect(rdpContext* context); +BOOL utils_str_is_empty(const char* str); +BOOL utils_str_copy(const char* value, char** dst); + #endif /* FREERDP_LIB_CORE_UTILS_H */ From b6fe146e3d6e93c89c73f3f2c13a8fc4a5ad1b77 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Wed, 15 Dec 2021 09:30:18 +0100 Subject: [PATCH 335/496] Cleaned up redirection code (cherry picked from commit b545094664097dee3c873706a2b4447c4122d94a) --- include/freerdp/settings.h | 2 ++ libfreerdp/common/settings.c | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/include/freerdp/settings.h b/include/freerdp/settings.h index 46d853622281..0e9fd150f083 100644 --- a/include/freerdp/settings.h +++ b/include/freerdp/settings.h @@ -1635,6 +1635,8 @@ extern "C" FREERDP_API void freerdp_dynamic_channel_collection_free(rdpSettings* settings); FREERDP_API void freerdp_target_net_addresses_free(rdpSettings* settings); + FREERDP_API BOOL freerdp_target_net_addresses_copy(rdpSettings* settings, char** addresses, + UINT32 count); FREERDP_API void freerdp_performance_flags_make(rdpSettings* settings); FREERDP_API void freerdp_performance_flags_split(rdpSettings* settings); diff --git a/libfreerdp/common/settings.c b/libfreerdp/common/settings.c index f32f32ac2615..2be4fcd0d5e3 100644 --- a/libfreerdp/common/settings.c +++ b/libfreerdp/common/settings.c @@ -948,3 +948,35 @@ char* freerdp_rail_support_flags_to_string(UINT32 flags, char* buffer, size_t le winpr_str_append("RAIL_LEVEL_LANGUAGE_IME_SYNC_SUPPORTED", buffer, length, "|"); return buffer; } + +BOOL freerdp_target_net_addresses_copy(rdpSettings* settings, char** addresses, UINT32 count) +{ + UINT32 i; + + WINPR_ASSERT(settings); + WINPR_ASSERT(addresses); + + freerdp_target_net_addresses_free(settings); + + settings->TargetNetAddressCount = count; + settings->TargetNetAddresses = (char**)calloc(settings->TargetNetAddressCount, sizeof(char*)); + + if (!settings->TargetNetAddresses) + { + freerdp_target_net_addresses_free(settings); + return FALSE; + } + + for (i = 0; i < settings->TargetNetAddressCount; i++) + { + settings->TargetNetAddresses[i] = _strdup(addresses[i]); + + if (!settings->TargetNetAddresses[i]) + { + freerdp_target_net_addresses_free(settings); + return FALSE; + } + } + + return TRUE; +} From 93bce775b95b486c7f8d5056b8771152750e86ef Mon Sep 17 00:00:00 2001 From: akallabeth Date: Fri, 3 Jun 2022 09:59:47 +0200 Subject: [PATCH 336/496] Added utility module for string functions (cherry picked from commit 44582f821b6c8a473380c1c67c605dc41f435bd3) --- include/freerdp/utils/string.h | 39 ++++++++++++++++++++++ libfreerdp/utils/CMakeLists.txt | 1 + libfreerdp/utils/string.c | 59 +++++++++++++++++++++++++++++++++ 3 files changed, 99 insertions(+) create mode 100644 include/freerdp/utils/string.h create mode 100644 libfreerdp/utils/string.c diff --git a/include/freerdp/utils/string.h b/include/freerdp/utils/string.h new file mode 100644 index 000000000000..805930fb222e --- /dev/null +++ b/include/freerdp/utils/string.h @@ -0,0 +1,39 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * + * String Utils - Helper functions converting something to string + * + * Copyright 2022 Armin Novak + * Copyright 2022 Thincast Technologies GmbH + * + * 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_UTILS_STRING_H +#define FREERDP_UTILS_STRING_H + +#include +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + + FREERDP_API char* rdp_redirection_flags_to_string(UINT32 flags, char* buffer, size_t size); + +#ifdef __cplusplus +} +#endif + +#endif /* FREERDP_UTILS_STRING_H */ diff --git a/libfreerdp/utils/CMakeLists.txt b/libfreerdp/utils/CMakeLists.txt index d09ca8b4f242..2ec561d33fd0 100644 --- a/libfreerdp/utils/CMakeLists.txt +++ b/libfreerdp/utils/CMakeLists.txt @@ -25,6 +25,7 @@ set(${MODULE_PREFIX}_SRCS profiler.c ringbuffer.c signal.c + string.c stopwatch.c) freerdp_module_add(${${MODULE_PREFIX}_SRCS}) diff --git a/libfreerdp/utils/string.c b/libfreerdp/utils/string.c new file mode 100644 index 000000000000..195148416d88 --- /dev/null +++ b/libfreerdp/utils/string.c @@ -0,0 +1,59 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * + * String Utils - Helper functions converting something to string + * + * Copyright 2022 Armin Novak + * Copyright 2022 Thincast Technologies GmbH + * + * 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. + */ + +#include +#include + +char* rdp_redirection_flags_to_string(UINT32 flags, char* buffer, size_t size) +{ + size_t x; + struct map_t + { + UINT32 flag; + const char* name; + }; + const struct map_t map[] = { + { LB_TARGET_NET_ADDRESS, "LB_TARGET_NET_ADDRESS" }, + { LB_LOAD_BALANCE_INFO, "LB_LOAD_BALANCE_INFO" }, + { LB_USERNAME, "LB_USERNAME" }, + { LB_DOMAIN, "LB_DOMAIN" }, + { LB_PASSWORD, "LB_PASSWORD" }, + { LB_DONTSTOREUSERNAME, "LB_DONTSTOREUSERNAME" }, + { LB_SMARTCARD_LOGON, "LB_SMARTCARD_LOGON" }, + { LB_NOREDIRECT, "LB_NOREDIRECT" }, + { LB_TARGET_FQDN, "LB_TARGET_FQDN" }, + { LB_TARGET_NETBIOS_NAME, "LB_TARGET_NETBIOS_NAME" }, + { LB_TARGET_NET_ADDRESSES, "LB_TARGET_NET_ADDRESSES" }, + { LB_CLIENT_TSV_URL, "LB_CLIENT_TSV_URL" }, + { LB_SERVER_TSV_CAPABLE, "LB_SERVER_TSV_CAPABLE" }, + }; + + for (x = 0; x < ARRAYSIZE(map); x++) + { + const struct map_t* cur = &map[x]; + if (flags & cur->flag) + { + if (!winpr_str_append(cur->name, buffer, size, "|")) + return NULL; + } + } + return buffer; +} From 07354702dc6b5ef56230e8c7a24c808f9d26d9b4 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Mon, 16 Jan 2023 08:33:46 +0100 Subject: [PATCH 337/496] [core,settings] add missing redirection options * RedirectionGuid * TargetCertificate (cherry picked from commit a9482caff13ad253d30060959be14b1a5c0c85bf) --- include/freerdp/settings.h | 13 +- libfreerdp/common/settings_getters.c | 28 +++ libfreerdp/common/settings_str.c | 221 +----------------- .../core/test/settings_property_lists.h | 4 + 4 files changed, 48 insertions(+), 218 deletions(-) diff --git a/include/freerdp/settings.h b/include/freerdp/settings.h index 0e9fd150f083..4268efd8c153 100644 --- a/include/freerdp/settings.h +++ b/include/freerdp/settings.h @@ -251,6 +251,9 @@ typedef enum #define LB_TARGET_NET_ADDRESSES 0x00000800 #define LB_CLIENT_TSV_URL 0x00001000 #define LB_SERVER_TSV_CAPABLE 0x00002000 +#define LB_PASSWORD_IS_PK_ENCRYPTED 0x00004000 +#define LB_REDIRECTION_GUID 0x00008000 +#define LB_TARGET_CERTIFICATE 0x00010000 #define LB_PASSWORD_MAX_LENGTH 512 @@ -681,6 +684,10 @@ typedef struct _RDPDR_PARALLEL RDPDR_PARALLEL; #define FreeRDP_RedirectionAcceptedCert (1231) #define FreeRDP_RedirectionAcceptedCertLength (1232) #define FreeRDP_RedirectionPreferType (1233) +#define FreeRDP_RedirectionGuid (1234) +#define FreeRDP_RedirectionGuidLength (1235) +#define FreeRDP_RedirectionTargetCertificate (1236) +#define FreeRDP_RedirectionTargetCertificateLength (1237) #define FreeRDP_Password51 (1280) #define FreeRDP_Password51Length (1281) #define FreeRDP_SmartcardLogon (1282) @@ -1141,7 +1148,11 @@ struct rdp_settings ALIGN64 char* RedirectionAcceptedCert; /* 1231 */ ALIGN64 UINT32 RedirectionAcceptedCertLength; /* 1232 */ ALIGN64 UINT32 RedirectionPreferType; /* 1233 */ - UINT64 padding1280[1280 - 1234]; /* 1234 */ + ALIGN64 BYTE* RedirectionGuid; /* 1234 */ + ALIGN64 UINT32 RedirectionGuidLength; /* 1235 */ + ALIGN64 BYTE* RedirectionTargetCertificate; /* 1236 */ + ALIGN64 UINT32 RedirectionTargetCertificateLength; /* 1237 */ + UINT64 padding1280[1280 - 1238]; /* 1238 */ /** * Security diff --git a/libfreerdp/common/settings_getters.c b/libfreerdp/common/settings_getters.c index 9224524d9f22..76f66460f790 100644 --- a/libfreerdp/common/settings_getters.c +++ b/libfreerdp/common/settings_getters.c @@ -1509,12 +1509,18 @@ UINT32 freerdp_settings_get_uint32(const rdpSettings* settings, size_t id) case FreeRDP_RedirectionFlags: return settings->RedirectionFlags; + case FreeRDP_RedirectionGuidLength: + return settings->RedirectionGuidLength; + case FreeRDP_RedirectionPasswordLength: return settings->RedirectionPasswordLength; case FreeRDP_RedirectionPreferType: return settings->RedirectionPreferType; + case FreeRDP_RedirectionTargetCertificateLength: + return settings->RedirectionTargetCertificateLength; + case FreeRDP_RedirectionTsvUrlLength: return settings->RedirectionTsvUrlLength; @@ -1938,6 +1944,10 @@ BOOL freerdp_settings_set_uint32(rdpSettings* settings, size_t id, UINT32 val) settings->RedirectionFlags = val; break; + case FreeRDP_RedirectionGuidLength: + settings->RedirectionGuidLength = val; + break; + case FreeRDP_RedirectionPasswordLength: settings->RedirectionPasswordLength = val; break; @@ -1946,6 +1956,10 @@ BOOL freerdp_settings_set_uint32(rdpSettings* settings, size_t id, UINT32 val) settings->RedirectionPreferType = val; break; + case FreeRDP_RedirectionTargetCertificateLength: + settings->RedirectionTargetCertificateLength = val; + break; + case FreeRDP_RedirectionTsvUrlLength: settings->RedirectionTsvUrlLength = val; break; @@ -2868,9 +2882,15 @@ const void* freerdp_settings_get_pointer(const rdpSettings* settings, size_t id) case FreeRDP_ReceivedCapabilities: return settings->ReceivedCapabilities; + case FreeRDP_RedirectionGuid: + return settings->RedirectionGuid; + case FreeRDP_RedirectionPassword: return settings->RedirectionPassword; + case FreeRDP_RedirectionTargetCertificate: + return settings->RedirectionTargetCertificate; + case FreeRDP_RedirectionTsvUrl: return settings->RedirectionTsvUrl; @@ -2976,10 +2996,18 @@ BOOL freerdp_settings_set_pointer(rdpSettings* settings, size_t id, const void* settings->ReceivedCapabilities = (void*)val; break; + case FreeRDP_RedirectionGuid: + settings->RedirectionGuid = (void*)val; + break; + case FreeRDP_RedirectionPassword: settings->RedirectionPassword = (void*)val; break; + case FreeRDP_RedirectionTargetCertificate: + settings->RedirectionTargetCertificate = (void*)val; + break; + case FreeRDP_RedirectionTsvUrl: settings->RedirectionTsvUrl = (void*)val; break; diff --git a/libfreerdp/common/settings_str.c b/libfreerdp/common/settings_str.c index 9a0bf5378d0e..d4e20ae821ba 100644 --- a/libfreerdp/common/settings_str.c +++ b/libfreerdp/common/settings_str.c @@ -262,8 +262,10 @@ static const struct settings_str_entry settings_map[] = { { FreeRDP_RedirectedSessionId, 3, "FreeRDP_RedirectedSessionId" }, { FreeRDP_RedirectionAcceptedCertLength, 3, "FreeRDP_RedirectionAcceptedCertLength" }, { FreeRDP_RedirectionFlags, 3, "FreeRDP_RedirectionFlags" }, + { FreeRDP_RedirectionGuidLength, 3, "FreeRDP_RedirectionGuidLength" }, { FreeRDP_RedirectionPasswordLength, 3, "FreeRDP_RedirectionPasswordLength" }, { FreeRDP_RedirectionPreferType, 3, "FreeRDP_RedirectionPreferType" }, + { FreeRDP_RedirectionTargetCertificateLength, 3, "FreeRDP_RedirectionTargetCertificateLength" }, { FreeRDP_RedirectionTsvUrlLength, 3, "FreeRDP_RedirectionTsvUrlLength" }, { FreeRDP_RemoteAppNumIconCacheEntries, 3, "FreeRDP_RemoteAppNumIconCacheEntries" }, { FreeRDP_RemoteAppNumIconCaches, 3, "FreeRDP_RemoteAppNumIconCaches" }, @@ -381,7 +383,9 @@ static const struct settings_str_entry settings_map[] = { { FreeRDP_RdpServerCertificate, 8, "FreeRDP_RdpServerCertificate" }, { FreeRDP_RdpServerRsaKey, 8, "FreeRDP_RdpServerRsaKey" }, { FreeRDP_ReceivedCapabilities, 8, "FreeRDP_ReceivedCapabilities" }, + { FreeRDP_RedirectionGuid, 8, "FreeRDP_RedirectionGuid" }, { FreeRDP_RedirectionPassword, 8, "FreeRDP_RedirectionPassword" }, + { FreeRDP_RedirectionTargetCertificate, 8, "FreeRDP_RedirectionTargetCertificate" }, { FreeRDP_RedirectionTsvUrl, 8, "FreeRDP_RedirectionTsvUrl" }, { FreeRDP_ServerAutoReconnectCookie, 8, "FreeRDP_ServerAutoReconnectCookie" }, { FreeRDP_ServerCertificate, 8, "FreeRDP_ServerCertificate" }, @@ -395,10 +399,6 @@ static const struct settings_str_entry settings_map[] = { BOOL freerdp_settings_clone_keys(rdpSettings* dst, const rdpSettings* src) { size_t x; - - WINPR_ASSERT(dst); - WINPR_ASSERT(src); - for (x = 0; x < ARRAYSIZE(settings_map); x++) { const struct settings_str_entry* cur = &settings_map[x]; @@ -472,214 +472,9 @@ BOOL freerdp_settings_clone_keys(rdpSettings* dst, const rdpSettings* src) return TRUE; } -BOOL freerdp_settings_print_diff(wLog* log, DWORD level, const rdpSettings* settings, - const rdpSettings* other) -{ - BOOL rc = FALSE; - size_t x; - - WINPR_ASSERT(log); - WINPR_ASSERT(settings); - WINPR_ASSERT(other); - - for (x = 0; x < ARRAYSIZE(settings_map); x++) - { - const struct settings_str_entry* cur = &settings_map[x]; - switch (cur->type) - { - case 0: /* bool */ - { - BOOL sval = freerdp_settings_get_bool(settings, cur->id); - BOOL cval = freerdp_settings_get_bool(other, cur->id); - if (sval != cval) - { - rc = TRUE; - WLog_Print(log, level, "%s [BOOL]: %s -> %s", cur->str, sval ? "TRUE" : "FALSE", - cval ? "TRUE" : "FALSE"); - } - } - break; - case 1: /* UINT16 */ - { - UINT16 sval = freerdp_settings_get_uint16(settings, cur->id); - UINT16 cval = freerdp_settings_get_uint16(other, cur->id); - if (sval != cval) - { - rc = TRUE; - WLog_Print(log, level, "%s [UINT16]: %" PRIu16 " -> %" PRIu16, cur->str, sval, - cval); - } - } - break; - case 2: /* INT16 */ - { - INT16 sval = freerdp_settings_get_int16(settings, cur->id); - INT16 cval = freerdp_settings_get_int16(other, cur->id); - if (sval != cval) - { - rc = TRUE; - WLog_Print(log, level, "%s [INT16]: %" PRId16 " -> %" PRId16, cur->str, sval, - cval); - } - } - break; - case 3: /* UINT32 */ - { - UINT32 sval = freerdp_settings_get_uint32(settings, cur->id); - UINT32 cval = freerdp_settings_get_uint32(other, cur->id); - if (sval != cval) - { - rc = TRUE; - WLog_Print(log, level, "%s [UINT32]: %" PRIu32 " -> %" PRIu32, cur->str, sval, - cval); - } - } - break; - case 4: /* INT32 */ - { - INT32 sval = freerdp_settings_get_int32(settings, cur->id); - INT32 cval = freerdp_settings_get_int32(other, cur->id); - if (sval != cval) - { - rc = TRUE; - WLog_Print(log, level, "%s [INT32]: %" PRId32 " -> %" PRId32, cur->str, sval, - cval); - } - } - break; - case 5: /* UINT64 */ - { - UINT64 sval = freerdp_settings_get_uint64(settings, cur->id); - UINT64 cval = freerdp_settings_get_uint64(other, cur->id); - if (sval != cval) - { - rc = TRUE; - WLog_Print(log, level, "%s [UINT64]: %" PRIu64 " -> %" PRIu64, cur->str, sval, - cval); - } - } - break; - case 6: /* INT64 */ - { - INT64 sval = freerdp_settings_get_int64(settings, cur->id); - INT64 cval = freerdp_settings_get_int64(other, cur->id); - if (sval != cval) - { - rc = TRUE; - WLog_Print(log, level, "%s [INT64]: %" PRId64 " -> %" PRId64, cur->str, sval, - cval); - } - } - break; - case 7: /* strings */ - { - const char* sval = freerdp_settings_get_string(settings, cur->id); - const char* cval = freerdp_settings_get_string(other, cur->id); - if (sval != cval) - { - if (!sval || !cval || (strcmp(sval, cval) != 0)) - { - rc = TRUE; - WLog_Print(log, level, "%s [STRING]: '%s' -> '%s'", cur->str, sval, cval); - } - } - } - break; - case 8: /* pointer */ - { - const void* sval = freerdp_settings_get_pointer(settings, cur->id); - const void* cval = freerdp_settings_get_pointer(other, cur->id); - if (sval != cval) - { - if ((sval && !cval) || (!sval && cval)) - { - rc = TRUE; - WLog_Print(log, level, "%s [POINTER]: '%p' -> '%p'", cur->str, sval, cval); - } - } - } - break; - } - } - return rc; -} - -void freerdp_settings_dump(wLog* log, DWORD level, const rdpSettings* settings) -{ - size_t x; - - WINPR_ASSERT(log); - WINPR_ASSERT(settings); - - for (x = 0; x < ARRAYSIZE(settings_map); x++) - { - const struct settings_str_entry* cur = &settings_map[x]; - switch (cur->type) - { - case 0: /* bool */ - { - BOOL sval = freerdp_settings_get_bool(settings, cur->id); - WLog_Print(log, level, "%s [BOOL]: %s", cur->str, sval ? "TRUE" : "FALSE"); - } - break; - case 1: /* UINT16 */ - { - UINT16 sval = freerdp_settings_get_uint16(settings, cur->id); - WLog_Print(log, level, "%s [UINT16]: %" PRIu16, cur->str, sval); - } - break; - case 2: /* INT16 */ - { - INT16 sval = freerdp_settings_get_int16(settings, cur->id); - WLog_Print(log, level, "%s [INT16]: %" PRId16, cur->str, sval); - } - break; - case 3: /* UINT32 */ - { - UINT32 sval = freerdp_settings_get_uint32(settings, cur->id); - WLog_Print(log, level, "%s [UINT32]: %" PRIu32, cur->str, sval); - } - break; - case 4: /* INT32 */ - { - INT32 sval = freerdp_settings_get_int32(settings, cur->id); - WLog_Print(log, level, "%s [INT32]: %" PRId32, cur->str, sval); - } - break; - case 5: /* UINT64 */ - { - UINT64 sval = freerdp_settings_get_uint64(settings, cur->id); - WLog_Print(log, level, "%s [UINT64]: %" PRIu64, cur->str, sval); - } - break; - case 6: /* INT64 */ - { - INT64 sval = freerdp_settings_get_int64(settings, cur->id); - WLog_Print(log, level, "%s [INT64]: %" PRId64, cur->str, sval); - } - break; - case 7: /* strings */ - { - const char* sval = freerdp_settings_get_string(settings, cur->id); - WLog_Print(log, level, "%s [STRING]: '%s'", cur->str, sval); - } - break; - case 8: /* pointer */ - { - const void* sval = freerdp_settings_get_pointer(settings, cur->id); - WLog_Print(log, level, "%s [POINTER]: '%p'", cur->str, sval); - } - break; - } - } -} - void freerdp_settings_free_keys(rdpSettings* dst, BOOL cleanup) { size_t x; - - WINPR_ASSERT(dst); - for (x = 0; x < ARRAYSIZE(settings_map); x++) { const struct settings_str_entry* cur = &settings_map[x]; @@ -698,9 +493,6 @@ void freerdp_settings_free_keys(rdpSettings* dst, BOOL cleanup) SSIZE_T freerdp_settings_get_key_for_name(const char* value) { size_t x; - - WINPR_ASSERT(value); - for (x = 0; x < ARRAYSIZE(settings_map); x++) { const struct settings_str_entry* cur = &settings_map[x]; @@ -713,9 +505,6 @@ SSIZE_T freerdp_settings_get_key_for_name(const char* value) SSIZE_T freerdp_settings_get_type_for_name(const char* value) { size_t x; - - WINPR_ASSERT(value); - for (x = 0; x < ARRAYSIZE(settings_map); x++) { const struct settings_str_entry* cur = &settings_map[x]; @@ -728,7 +517,6 @@ SSIZE_T freerdp_settings_get_type_for_name(const char* value) SSIZE_T freerdp_settings_get_type_for_key(size_t key) { size_t x; - for (x = 0; x < ARRAYSIZE(settings_map); x++) { const struct settings_str_entry* cur = &settings_map[x]; @@ -741,7 +529,6 @@ SSIZE_T freerdp_settings_get_type_for_key(size_t key) const char* freerdp_settings_get_name_for_key(size_t key) { size_t x; - for (x = 0; x < ARRAYSIZE(settings_map); x++) { const struct settings_str_entry* cur = &settings_map[x]; diff --git a/libfreerdp/core/test/settings_property_lists.h b/libfreerdp/core/test/settings_property_lists.h index dcf1e49296ff..69f7bce4ba15 100644 --- a/libfreerdp/core/test/settings_property_lists.h +++ b/libfreerdp/core/test/settings_property_lists.h @@ -259,8 +259,10 @@ static const size_t uint32_list_indices[] = { FreeRDP_RedirectedSessionId, FreeRDP_RedirectionAcceptedCertLength, FreeRDP_RedirectionFlags, + FreeRDP_RedirectionGuidLength, FreeRDP_RedirectionPasswordLength, FreeRDP_RedirectionPreferType, + FreeRDP_RedirectionTargetCertificateLength, FreeRDP_RedirectionTsvUrlLength, FreeRDP_RemoteAppNumIconCacheEntries, FreeRDP_RemoteAppNumIconCaches, @@ -394,7 +396,9 @@ static const size_t pointer_list_indices[] = { FreeRDP_RdpServerCertificate, FreeRDP_RdpServerRsaKey, FreeRDP_ReceivedCapabilities, + FreeRDP_RedirectionGuid, FreeRDP_RedirectionPassword, + FreeRDP_RedirectionTargetCertificate, FreeRDP_RedirectionTsvUrl, FreeRDP_ServerAutoReconnectCookie, FreeRDP_ServerCertificate, From daa1402138279f56e6c2f170a7c411f8337d8580 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Mon, 16 Jan 2023 08:35:19 +0100 Subject: [PATCH 338/496] [core] fix client side redirection handling * Read previously ignored fields RedirectionGuid and TargetCertificate * Check password requirements according to LB_PASSWORD_IS_PK_ENCRYPTED (cherry picked from commit 968dfd7bc1c5f2e2bfadb0af658c68556b2dbf39) --- libfreerdp/core/redirection.c | 452 +++++++++++++++++++--------------- libfreerdp/utils/string.c | 3 + 2 files changed, 258 insertions(+), 197 deletions(-) diff --git a/libfreerdp/core/redirection.c b/libfreerdp/core/redirection.c index 9f94583b86c8..7e348611237b 100644 --- a/libfreerdp/core/redirection.c +++ b/libfreerdp/core/redirection.c @@ -23,10 +23,11 @@ #include #include +#include #include "connection.h" - #include "redirection.h" +#include "utils.h" #define TAG FREERDP_TAG("core.redirection") @@ -47,50 +48,110 @@ struct rdp_redirection char* TargetNetAddress; UINT32 TargetNetAddressesCount; char** TargetNetAddresses; + UINT32 RedirectionGuidLength; + BYTE* RedirectionGuid; + UINT32 TargetCertificateLength; + BYTE* TargetCertificate; }; -static void rdp_print_redirection_flags(UINT32 flags) +static void redirection_free_array(char*** what, UINT32* count) { - WLog_DBG(TAG, "redirectionFlags = {"); - - if (flags & LB_TARGET_NET_ADDRESS) - WLog_DBG(TAG, "\tLB_TARGET_NET_ADDRESS"); - - if (flags & LB_LOAD_BALANCE_INFO) - WLog_DBG(TAG, "\tLB_LOAD_BALANCE_INFO"); + WINPR_ASSERT(what); + WINPR_ASSERT(count); - if (flags & LB_USERNAME) - WLog_DBG(TAG, "\tLB_USERNAME"); + if (*what) + { + for (UINT32 x = 0; x < *count; x++) + free((*what)[x]); + free(*what); + } - if (flags & LB_DOMAIN) - WLog_DBG(TAG, "\tLB_DOMAIN"); + *what = NULL; + *count = 0; +} - if (flags & LB_PASSWORD) - WLog_DBG(TAG, "\tLB_PASSWORD"); +static void redirection_free_string(char** str) +{ + WINPR_ASSERT(str); + free(*str); + *str = NULL; +} - if (flags & LB_DONTSTOREUSERNAME) - WLog_DBG(TAG, "\tLB_DONTSTOREUSERNAME"); +static void redirection_free_data(BYTE** str, UINT32* length) +{ + WINPR_ASSERT(str); + WINPR_ASSERT(length); + free(*str); + *length = 0; + *str = NULL; +} - if (flags & LB_SMARTCARD_LOGON) - WLog_DBG(TAG, "\tLB_SMARTCARD_LOGON"); +static BOOL redirection_copy_data(char** dst, UINT32* plen, const char* str, UINT32 len) +{ + redirection_free_data(dst, plen); - if (flags & LB_NOREDIRECT) - WLog_DBG(TAG, "\tLB_NOREDIRECT"); + if (!str || (len == 0)) + return TRUE; - if (flags & LB_TARGET_FQDN) - WLog_DBG(TAG, "\tLB_TARGET_FQDN"); + *dst = malloc(len); + if (!*dst) + return FALSE; + memcpy(*dst, str, len); + *plen = len; + return *dst != NULL; +} - if (flags & LB_TARGET_NETBIOS_NAME) - WLog_DBG(TAG, "\tLB_TARGET_NETBIOS_NAME"); +static BOOL freerdp_settings_set_pointer_len(rdpSettings* settings, size_t id, const BYTE* data, + size_t length) +{ + BYTE** pdata = NULL; + UINT32* plen = NULL; + switch (id) + { + case FreeRDP_TargetNetAddress: + pdata = &settings->TargetNetAddress; + plen = &settings->TargetNetAddressCount; + break; + case FreeRDP_LoadBalanceInfo: + pdata = &settings->LoadBalanceInfo; + plen = &settings->LoadBalanceInfoLength; + break; + case FreeRDP_RedirectionPassword: + pdata = &settings->RedirectionPassword; + plen = &settings->RedirectionPasswordLength; + break; + case FreeRDP_RedirectionTsvUrl: + pdata = &settings->RedirectionTsvUrl; + plen = &settings->RedirectionTsvUrlLength; + break; + case FreeRDP_RedirectionGuid: + pdata = &settings->RedirectionGuid; + plen = &settings->RedirectionGuidLength; + break; + case FreeRDP_RedirectionTargetCertificate: + pdata = &settings->RedirectionTargetCertificate; + plen = &settings->RedirectionTargetCertificateLength; + break; + default: + return FALSE; + } - if (flags & LB_TARGET_NET_ADDRESSES) - WLog_DBG(TAG, "\tLB_TARGET_NET_ADDRESSES"); + return redirection_copy_data(pdata, plen, data, length); +} - if (flags & LB_CLIENT_TSV_URL) - WLog_DBG(TAG, "\tLB_CLIENT_TSV_URL"); +static void rdp_print_redirection_flags(UINT32 flags) +{ + WLog_DBG(TAG, "redirectionFlags = {"); - if (flags & LB_SERVER_TSV_CAPABLE) - WLog_DBG(TAG, "\tLB_SERVER_TSV_CAPABLE"); + for (UINT32 x = 0; x < 32; x++) + { + const UINT32 mask = 1 << x; + if ((flags & mask) != 0) + { + char buffer[64] = { 0 }; + WLog_DBG(TAG, "\t%s", rdp_redirection_flags_to_string(mask, buffer, sizeof(buffer))); + } + } WLog_DBG(TAG, "}"); } @@ -98,13 +159,10 @@ static void rdp_print_redirection_flags(UINT32 flags) static BOOL rdp_redirection_read_unicode_string(wStream* s, char** str, size_t maxLength) { UINT32 length; - WCHAR* wstr = NULL; + const WCHAR* wstr = NULL; - if (Stream_GetRemainingLength(s) < 4) - { - WLog_ERR(TAG, "rdp_redirection_read_string failure: cannot read length"); + if (!Stream_CheckAndLogRequiredLength(TAG, s, 4)) return FALSE; - } Stream_Read_UINT32(s, length); @@ -116,7 +174,7 @@ static BOOL rdp_redirection_read_unicode_string(wStream* s, char** str, size_t m return FALSE; } - if (Stream_GetRemainingLength(s) < length) + if (!Stream_CheckAndLogRequiredLength(TAG, s, length)) { WLog_ERR(TAG, "rdp_redirection_read_string failure: insufficient stream length (%" PRIu32 @@ -125,7 +183,7 @@ static BOOL rdp_redirection_read_unicode_string(wStream* s, char** str, size_t m return FALSE; } - wstr = (WCHAR*)Stream_Pointer(s); + wstr = (const WCHAR*)Stream_Pointer(s); if (wstr[length / 2 - 1]) { @@ -133,10 +191,15 @@ static BOOL rdp_redirection_read_unicode_string(wStream* s, char** str, size_t m return FALSE; } - if (ConvertFromUnicode(CP_UTF8, 0, wstr, -1, str, 0, NULL, NULL) < 1) + redirection_free_string(str); { - WLog_ERR(TAG, "rdp_redirection_read_string failure: string conversion failed"); - return FALSE; + const int res = + ConvertFromUnicode(CP_UTF8, 0, wstr, length / sizeof(WCHAR), str, 0, NULL, NULL); + if ((res < 0) || !(*str)) + { + WLog_ERR(TAG, "rdp_redirection_read_string failure: string conversion failed"); + return FALSE; + } } Stream_Seek(s, length); @@ -145,23 +208,34 @@ static BOOL rdp_redirection_read_unicode_string(wStream* s, char** str, size_t m int rdp_redirection_apply_settings(rdpRdp* rdp) { - rdpSettings* settings = rdp->settings; - rdpRedirection* redirection = rdp->redirection; + rdpSettings* settings; + rdpRedirection* redirection; + + WINPR_ASSERT(rdp); + + settings = rdp->settings; + WINPR_ASSERT(settings); + + redirection = rdp->redirection; + WINPR_ASSERT(redirection); + settings->RedirectionFlags = redirection->flags; settings->RedirectedSessionId = redirection->sessionID; + if (settings->RedirectionFlags & LB_TARGET_NET_ADDRESS) + { + if (!freerdp_settings_set_string(settings, FreeRDP_TargetNetAddress, + redirection->TargetNetAddress)) + return -1; + } + if (settings->RedirectionFlags & LB_LOAD_BALANCE_INFO) { /* LoadBalanceInfo may not contain a null terminator */ - free(settings->LoadBalanceInfo); - settings->LoadBalanceInfoLength = redirection->LoadBalanceInfoLength; - settings->LoadBalanceInfo = (BYTE*)malloc(settings->LoadBalanceInfoLength); - - if (!settings->LoadBalanceInfo) + if (!freerdp_settings_set_pointer_len(settings, FreeRDP_LoadBalanceInfo, + redirection->LoadBalanceInfo, + redirection->LoadBalanceInfoLength)) return -1; - - CopyMemory(settings->LoadBalanceInfo, redirection->LoadBalanceInfo, - settings->LoadBalanceInfoLength); } else { @@ -169,128 +243,138 @@ int rdp_redirection_apply_settings(rdpRdp* rdp) * Free previous LoadBalanceInfo, if any, otherwise it may end up * being reused for the redirected session, which is not what we want. */ - free(settings->LoadBalanceInfo); - settings->LoadBalanceInfo = NULL; - settings->LoadBalanceInfoLength = 0; + if (!freerdp_settings_set_pointer_len(settings, FreeRDP_LoadBalanceInfo, NULL, 0)) + return -1; } - if (settings->RedirectionFlags & LB_TARGET_FQDN) + if (settings->RedirectionFlags & LB_USERNAME) { - free(settings->RedirectionTargetFQDN); - settings->RedirectionTargetFQDN = _strdup(redirection->TargetFQDN); - - if (!settings->RedirectionTargetFQDN) + if (!freerdp_settings_set_string(settings, FreeRDP_RedirectionUsername, + redirection->Username)) return -1; } - if (settings->RedirectionFlags & LB_TARGET_NET_ADDRESS) + if (settings->RedirectionFlags & LB_DOMAIN) { - free(settings->TargetNetAddress); - settings->TargetNetAddress = _strdup(redirection->TargetNetAddress); - - if (!settings->TargetNetAddress) + if (!freerdp_settings_set_string(settings, FreeRDP_RedirectionDomain, redirection->Domain)) return -1; } - if (settings->RedirectionFlags & LB_TARGET_NETBIOS_NAME) + if (settings->RedirectionFlags & LB_PASSWORD) { - free(settings->RedirectionTargetNetBiosName); - settings->RedirectionTargetNetBiosName = _strdup(redirection->TargetNetBiosName); - - if (!settings->RedirectionTargetNetBiosName) + /* Password may be a cookie without a null terminator */ + if (!freerdp_settings_set_pointer_len(settings, FreeRDP_RedirectionPassword, + redirection->Password, redirection->PasswordLength)) return -1; } - if (settings->RedirectionFlags & LB_USERNAME) + if (settings->RedirectionFlags & LB_DONTSTOREUSERNAME) { - free(settings->RedirectionUsername); - settings->RedirectionUsername = _strdup(redirection->Username); + // TODO + } - if (!settings->RedirectionUsername) - return -1; + if (settings->RedirectionFlags & LB_SMARTCARD_LOGON) + { + // TODO } - if (settings->RedirectionFlags & LB_DOMAIN) + if (settings->RedirectionFlags & LB_NOREDIRECT) { - free(settings->RedirectionDomain); - settings->RedirectionDomain = _strdup(redirection->Domain); + // TODO + } - if (!settings->RedirectionDomain) + if (settings->RedirectionFlags & LB_TARGET_FQDN) + { + if (!freerdp_settings_set_string(settings, FreeRDP_RedirectionTargetFQDN, + redirection->TargetFQDN)) return -1; } - if (settings->RedirectionFlags & LB_PASSWORD) + if (settings->RedirectionFlags & LB_TARGET_NETBIOS_NAME) { - /* Password may be a cookie without a null terminator */ - free(settings->RedirectionPassword); - settings->RedirectionPasswordLength = redirection->PasswordLength; - /* For security reasons we'll allocate an additional zero WCHAR at the - * end of the buffer that is not included in RedirectionPasswordLength - */ - settings->RedirectionPassword = - (BYTE*)calloc(1, settings->RedirectionPasswordLength + sizeof(WCHAR)); - - if (!settings->RedirectionPassword) + if (!freerdp_settings_set_string(settings, FreeRDP_RedirectionTargetNetBiosName, + redirection->TargetNetBiosName)) return -1; + } - CopyMemory(settings->RedirectionPassword, redirection->Password, - settings->RedirectionPasswordLength); + if (settings->RedirectionFlags & LB_TARGET_NET_ADDRESSES) + { + if (!freerdp_target_net_addresses_copy(settings, redirection->TargetNetAddresses, + redirection->TargetNetAddressesCount)) + return -1; } if (settings->RedirectionFlags & LB_CLIENT_TSV_URL) { /* TsvUrl may not contain a null terminator */ - free(settings->RedirectionTsvUrl); - settings->RedirectionTsvUrlLength = redirection->TsvUrlLength; - settings->RedirectionTsvUrl = (BYTE*)malloc(settings->RedirectionTsvUrlLength); - - if (!settings->RedirectionTsvUrl) + if (!freerdp_settings_set_pointer_len(settings, FreeRDP_RedirectionTsvUrl, + redirection->TsvUrl, redirection->TsvUrlLength)) return -1; + } - CopyMemory(settings->RedirectionTsvUrl, redirection->TsvUrl, - settings->RedirectionTsvUrlLength); + if (settings->RedirectionFlags & LB_SERVER_TSV_CAPABLE) + { + // TODO } - if (settings->RedirectionFlags & LB_TARGET_NET_ADDRESSES) + if (settings->RedirectionFlags & LB_PASSWORD_IS_PK_ENCRYPTED) { - UINT32 i; - freerdp_target_net_addresses_free(settings); - settings->TargetNetAddressCount = redirection->TargetNetAddressesCount; - settings->TargetNetAddresses = - (char**)calloc(settings->TargetNetAddressCount, sizeof(char*)); + // TODO + } - if (!settings->TargetNetAddresses) - { - settings->TargetNetAddressCount = 0; + if (settings->RedirectionFlags & LB_REDIRECTION_GUID) + { + if (!freerdp_settings_set_pointer_len(settings, FreeRDP_RedirectionGuid, + redirection->RedirectionGuid, + redirection->RedirectionGuidLength)) return -1; - } + } - for (i = 0; i < settings->TargetNetAddressCount; i++) - { - settings->TargetNetAddresses[i] = _strdup(redirection->TargetNetAddresses[i]); + if (settings->RedirectionFlags & LB_TARGET_CERTIFICATE) + { + if (!freerdp_settings_set_pointer_len(settings, FreeRDP_RedirectionTargetCertificate, + redirection->TargetCertificate, + redirection->TargetCertificateLength)) + return -1; + } - if (!settings->TargetNetAddresses[i]) - { - UINT32 j; + return 0; +} - for (j = 0; j < i; j++) - free(settings->TargetNetAddresses[j]); +static BOOL rdp_redirection_read_data(UINT32 flag, wStream* s, UINT32* pLength, BYTE** pData) +{ + char buffer[64] = { 0 }; - return -1; - } - } - } + WINPR_ASSERT(pLength); + WINPR_ASSERT(pData); - return 0; + if (!Stream_CheckAndLogRequiredLength(TAG, s, 4)) + return FALSE; + + Stream_Read_UINT32(s, *pLength); + + if (!Stream_CheckAndLogRequiredLength(TAG, s, *pLength)) + return FALSE; + + redirection_free_data(pData, pLength); + *pData = (BYTE*)malloc(*pLength); + + if (!*pData) + return FALSE; + + Stream_Read(s, *pData, *pLength); + WLog_DBG(TAG, "%s:", rdp_redirection_flags_to_string(flag, buffer, sizeof(buffer))); + winpr_HexDump(TAG, WLOG_DEBUG, *pData, *pLength); + return TRUE; } -static BOOL rdp_recv_server_redirection_pdu(rdpRdp* rdp, wStream* s) +static int rdp_recv_server_redirection_pdu(rdpRdp* rdp, wStream* s) { UINT16 flags; UINT16 length; rdpRedirection* redirection = rdp->redirection; - if (Stream_GetRemainingLength(s) < 12) + if (!Stream_CheckAndLogRequiredLength(TAG, s, 12)) return -1; Stream_Read_UINT16(s, flags); /* flags (2 bytes) */ @@ -329,23 +413,9 @@ static BOOL rdp_recv_server_redirection_pdu(rdpRdp* rdp, wStream* s) * 0010 34 30 32 36 34 33 32 2e 31 35 36 32 39 2e 30 30 4026432.15629.00 * 0020 30 30 0d 0a 00.. */ - if (Stream_GetRemainingLength(s) < 4) - return -1; - - Stream_Read_UINT32(s, redirection->LoadBalanceInfoLength); - - if (Stream_GetRemainingLength(s) < redirection->LoadBalanceInfoLength) + if (!rdp_redirection_read_data(LB_LOAD_BALANCE_INFO, s, &redirection->LoadBalanceInfoLength, + &redirection->LoadBalanceInfo)) return -1; - - redirection->LoadBalanceInfo = (BYTE*)malloc(redirection->LoadBalanceInfoLength); - - if (!redirection->LoadBalanceInfo) - return -1; - - Stream_Read(s, redirection->LoadBalanceInfo, redirection->LoadBalanceInfoLength); - WLog_DBG(TAG, "loadBalanceInfo:"); - winpr_HexDump(TAG, WLOG_DEBUG, redirection->LoadBalanceInfo, - redirection->LoadBalanceInfoLength); } if (redirection->flags & LB_USERNAME) @@ -359,7 +429,7 @@ static BOOL rdp_recv_server_redirection_pdu(rdpRdp* rdp, wStream* s) if (redirection->flags & LB_DOMAIN) { if (!rdp_redirection_read_unicode_string(s, &(redirection->Domain), 52)) - return FALSE; + return -1; WLog_DBG(TAG, "Domain: %s", redirection->Domain); } @@ -387,32 +457,24 @@ static BOOL rdp_recv_server_redirection_pdu(rdpRdp* rdp, wStream* s) * Notwithstanding the above, we'll allocated an additional zero WCHAR at the * end of the buffer which won't get counted in PasswordLength. */ - if (Stream_GetRemainingLength(s) < 4) + if (!rdp_redirection_read_data(LB_PASSWORD, s, &redirection->PasswordLength, + &redirection->Password)) return -1; - Stream_Read_UINT32(s, redirection->PasswordLength); - /* [MS-RDPBCGR] specifies 512 bytes as the upper limit for the password length * including the null terminatior(s). This should also be enough for the unknown * password cookie format (see previous comment). */ + if ((redirection->flags & LB_PASSWORD_IS_PK_ENCRYPTED) == 0) + { + const size_t charLen = redirection->PasswordLength / sizeof(WCHAR); + if (redirection->PasswordLength > LB_PASSWORD_MAX_LENGTH) + return -1; - if (Stream_GetRemainingLength(s) < redirection->PasswordLength) - return -1; - - if (redirection->PasswordLength > LB_PASSWORD_MAX_LENGTH) - return -1; - - redirection->Password = (BYTE*)calloc(1, redirection->PasswordLength + sizeof(WCHAR)); - - if (!redirection->Password) - return -1; - - Stream_Read(s, redirection->Password, redirection->PasswordLength); - WLog_DBG(TAG, "PasswordCookie:"); -#if defined(WITH_DEBUG_REDIR) - winpr_HexDump(TAG, WLOG_DEBUG, redirection->Password, redirection->PasswordLength); -#endif + /* Ensure the text password is '\0' terminated */ + if (_wcsnlen((const WCHAR*)redirection->Password, charLen) == charLen) + return -1; + } } if (redirection->flags & LB_TARGET_FQDN) @@ -433,31 +495,33 @@ static BOOL rdp_recv_server_redirection_pdu(rdpRdp* rdp, wStream* s) if (redirection->flags & LB_CLIENT_TSV_URL) { - if (Stream_GetRemainingLength(s) < 4) + if (!rdp_redirection_read_data(LB_CLIENT_TSV_URL, s, &redirection->TsvUrlLength, + &redirection->TsvUrl)) return -1; + } - Stream_Read_UINT32(s, redirection->TsvUrlLength); - - if (Stream_GetRemainingLength(s) < redirection->TsvUrlLength) + if (redirection->flags & LB_REDIRECTION_GUID) + { + if (!rdp_redirection_read_data(LB_REDIRECTION_GUID, s, &redirection->RedirectionGuidLength, + &redirection->RedirectionGuid)) return -1; + } - redirection->TsvUrl = (BYTE*)malloc(redirection->TsvUrlLength); - - if (!redirection->TsvUrl) + if (redirection->flags & LB_TARGET_CERTIFICATE) + { + if (!rdp_redirection_read_data(LB_TARGET_CERTIFICATE, s, + &redirection->TargetCertificateLength, + &redirection->TargetCertificate)) return -1; - - Stream_Read(s, redirection->TsvUrl, redirection->TsvUrlLength); - WLog_DBG(TAG, "TsvUrl:"); - winpr_HexDump(TAG, WLOG_DEBUG, redirection->TsvUrl, redirection->TsvUrlLength); } if (redirection->flags & LB_TARGET_NET_ADDRESSES) { - int i; + size_t i; UINT32 count; UINT32 targetNetAddressesLength; - if (Stream_GetRemainingLength(s) < 8) + if (!Stream_CheckAndLogRequiredLength(TAG, s, 8)) return -1; Stream_Read_UINT32(s, targetNetAddressesLength); @@ -466,16 +530,17 @@ static BOOL rdp_recv_server_redirection_pdu(rdpRdp* rdp, wStream* s) redirection->TargetNetAddresses = (char**)calloc(count, sizeof(char*)); if (!redirection->TargetNetAddresses) - return FALSE; + return -1; WLog_DBG(TAG, "TargetNetAddressesCount: %" PRIu32 "", redirection->TargetNetAddressesCount); - for (i = 0; i < (int)count; i++) + for (i = 0; i < count; i++) { if (!rdp_redirection_read_unicode_string(s, &(redirection->TargetNetAddresses[i]), 80)) - return FALSE; + return -1; - WLog_DBG(TAG, "TargetNetAddresses[%d]: %s", i, redirection->TargetNetAddresses[i]); + WLog_DBG(TAG, "TargetNetAddresses[%" PRIuz "]: %s", i, + redirection->TargetNetAddresses[i]); } } @@ -512,7 +577,7 @@ int rdp_recv_enhanced_security_redirection_packet(rdpRdp* rdp, wStream* s) return status; } -rdpRedirection* redirection_new() +rdpRedirection* redirection_new(void) { rdpRedirection* redirection; redirection = (rdpRedirection*)calloc(1, sizeof(rdpRedirection)); @@ -528,26 +593,19 @@ void redirection_free(rdpRedirection* redirection) { if (redirection) { - free(redirection->TsvUrl); - free(redirection->Username); - free(redirection->Domain); - free(redirection->TargetFQDN); - free(redirection->TargetNetBiosName); - free(redirection->TargetNetAddress); - free(redirection->LoadBalanceInfo); - free(redirection->Password); - - if (redirection->TargetNetAddresses) - { - int i; - - for (i = 0; i < (int)redirection->TargetNetAddressesCount; i++) - { - free(redirection->TargetNetAddresses[i]); - } - - free(redirection->TargetNetAddresses); - } + redirection_free_data(&redirection->TsvUrl, &redirection->TsvUrlLength); + redirection_free_string(&redirection->Username); + redirection_free_string(&redirection->Domain); + redirection_free_string(&redirection->TargetFQDN); + redirection_free_string(&redirection->TargetNetBiosName); + redirection_free_string(&redirection->TargetNetAddress); + redirection_free_data(&redirection->LoadBalanceInfo, &redirection->LoadBalanceInfoLength); + redirection_free_data(&redirection->Password, &redirection->PasswordLength); + redirection_free_data(&redirection->RedirectionGuid, &redirection->RedirectionGuidLength); + redirection_free_data(&redirection->TargetCertificate, + &redirection->TargetCertificateLength); + redirection_free_array(&redirection->TargetNetAddresses, + &redirection->TargetNetAddressesCount); free(redirection); } diff --git a/libfreerdp/utils/string.c b/libfreerdp/utils/string.c index 195148416d88..3ddb4b7fbbb7 100644 --- a/libfreerdp/utils/string.c +++ b/libfreerdp/utils/string.c @@ -44,6 +44,9 @@ char* rdp_redirection_flags_to_string(UINT32 flags, char* buffer, size_t size) { LB_TARGET_NET_ADDRESSES, "LB_TARGET_NET_ADDRESSES" }, { LB_CLIENT_TSV_URL, "LB_CLIENT_TSV_URL" }, { LB_SERVER_TSV_CAPABLE, "LB_SERVER_TSV_CAPABLE" }, + { LB_PASSWORD_IS_PK_ENCRYPTED, "LB_PASSWORD_IS_PK_ENCRYPTED" }, + { LB_REDIRECTION_GUID, "LB_REDIRECTION_GUID" }, + { LB_TARGET_CERTIFICATE, "LB_TARGET_CERTIFICATE" }, }; for (x = 0; x < ARRAYSIZE(map); x++) From d2bacdf96f0a3f76693a391d73c637de50e7bcc4 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Mon, 16 Jan 2023 13:45:20 +0100 Subject: [PATCH 339/496] [core,nla] refactor buffer use Use helper functions to ensure buffers are properly freed up only once --- libfreerdp/core/nla.c | 78 +++++++++++++++++++++++++++---------------- 1 file changed, 49 insertions(+), 29 deletions(-) diff --git a/libfreerdp/core/nla.c b/libfreerdp/core/nla.c index 2e99b7e9864d..33f366ec1f92 100644 --- a/libfreerdp/core/nla.c +++ b/libfreerdp/core/nla.c @@ -424,8 +424,10 @@ static int nla_client_init(rdpNla* nla) nla->haveContext = FALSE; nla->haveInputBuffer = FALSE; nla->havePubKeyAuth = FALSE; - ZeroMemory(&nla->inputBuffer, sizeof(SecBuffer)); - ZeroMemory(&nla->outputBuffer, sizeof(SecBuffer)); + + sspi_SecBufferFree(&nla->inputBuffer); + sspi_SecBufferFree(&nla->outputBuffer); + ZeroMemory(&nla->ContextSizes, sizeof(SecPkgContext_Sizes)); /* * from tspkg.dll: 0x00000132 @@ -438,6 +440,26 @@ static int nla_client_init(rdpNla* nla) return 1; } +static BOOL nla_alloc_buffer(SecBuffer* buffer, size_t size) +{ + sspi_SecBufferFree(buffer); + buffer->BufferType = SECBUFFER_TOKEN; + return sspi_SecBufferAlloc(buffer, size) != 0; +} + +static BOOL nla_transfer_buffer(SecBuffer* dst, SecBuffer* src) +{ + WINPR_ASSERT(dst); + WINPR_ASSERT(src); + sspi_SecBufferFree(dst); + dst->cbBuffer = src->cbBuffer; + src->cbBuffer = 0; + + dst->pvBuffer = src->pvBuffer; + src->pvBuffer = NULL; + return TRUE; +} + int nla_client_begin(rdpNla* nla) { if (nla_client_init(nla) < 1) @@ -449,11 +471,8 @@ int nla_client_begin(rdpNla* nla) nla->outputBufferDesc.ulVersion = SECBUFFER_VERSION; nla->outputBufferDesc.cBuffers = 1; nla->outputBufferDesc.pBuffers = &nla->outputBuffer; - nla->outputBuffer.BufferType = SECBUFFER_TOKEN; - nla->outputBuffer.cbBuffer = nla->cbMaxToken; - nla->outputBuffer.pvBuffer = malloc(nla->outputBuffer.cbBuffer); - if (!nla->outputBuffer.pvBuffer) + if (!nla_alloc_buffer(&nla->outputBuffer, nla->cbMaxToken)) return -1; nla->status = nla->table->InitializeSecurityContext( @@ -518,8 +537,8 @@ int nla_client_begin(rdpNla* nla) if (nla->outputBuffer.cbBuffer < 1) return -1; - nla->negoToken.pvBuffer = nla->outputBuffer.pvBuffer; - nla->negoToken.cbBuffer = nla->outputBuffer.cbBuffer; + if (!nla_transfer_buffer(&nla->negoToken, &nla->outputBuffer)) + return -1; if (!nla_send(nla, "Client: Sending Authentication Token")) { @@ -542,16 +561,15 @@ static int nla_client_recv(rdpNla* nla) nla->inputBufferDesc.cBuffers = 1; nla->inputBufferDesc.pBuffers = &nla->inputBuffer; nla->inputBuffer.BufferType = SECBUFFER_TOKEN; - nla->inputBuffer.pvBuffer = nla->negoToken.pvBuffer; - nla->inputBuffer.cbBuffer = nla->negoToken.cbBuffer; + + if (!nla_transfer_buffer(&nla->inputBuffer, &nla->negoToken)) + return -1; + nla->outputBufferDesc.ulVersion = SECBUFFER_VERSION; nla->outputBufferDesc.cBuffers = 1; nla->outputBufferDesc.pBuffers = &nla->outputBuffer; - nla->outputBuffer.BufferType = SECBUFFER_TOKEN; - nla->outputBuffer.cbBuffer = nla->cbMaxToken; - nla->outputBuffer.pvBuffer = malloc(nla->outputBuffer.cbBuffer); - if (!nla->outputBuffer.pvBuffer) + if (!nla_alloc_buffer(&nla->outputBuffer, nla->cbMaxToken)) return -1; nla->status = nla->table->InitializeSecurityContext( @@ -560,8 +578,8 @@ static int nla_client_recv(rdpNla* nla) &nla->pfContextAttr, &nla->expiration); WLog_VRB(TAG, "InitializeSecurityContext %s [0x%08" PRIX32 "]", GetSecurityStatusString(nla->status), nla->status); - free(nla->inputBuffer.pvBuffer); - nla->inputBuffer.pvBuffer = NULL; + + sspi_SecBufferFree(&nla->inputBuffer); if ((nla->status == SEC_I_COMPLETE_AND_CONTINUE) || (nla->status == SEC_I_COMPLETE_NEEDED)) { @@ -607,8 +625,8 @@ static int nla_client_recv(rdpNla* nla) return -1; } - nla->negoToken.pvBuffer = nla->outputBuffer.pvBuffer; - nla->negoToken.cbBuffer = nla->outputBuffer.cbBuffer; + if (!nla_transfer_buffer(&nla->negoToken, &nla->outputBuffer)) + return -1; if (!nla_send(nla, "Client: Sending Authentication Token")) { @@ -799,8 +817,10 @@ static int nla_server_init(rdpNla* nla) nla->haveContext = FALSE; nla->haveInputBuffer = FALSE; nla->havePubKeyAuth = FALSE; - ZeroMemory(&nla->inputBuffer, sizeof(SecBuffer)); - ZeroMemory(&nla->outputBuffer, sizeof(SecBuffer)); + + sspi_SecBufferFree(&nla->inputBuffer); + sspi_SecBufferFree(&nla->outputBuffer); + ZeroMemory(&nla->inputBufferDesc, sizeof(SecBufferDesc)); ZeroMemory(&nla->outputBufferDesc, sizeof(SecBufferDesc)); ZeroMemory(&nla->ContextSizes, sizeof(SecPkgContext_Sizes)); @@ -843,10 +863,10 @@ static int nla_server_authenticate(rdpNla* nla) if (nla_recv(nla, "Receiving Authentication Token") < 0) return -1; - nla->inputBuffer.pvBuffer = nla->negoToken.pvBuffer; - nla->inputBuffer.cbBuffer = nla->negoToken.cbBuffer; + if (!nla_transfer_buffer(&nla->inputBuffer, &nla->negoToken)) + return -1; - if (nla->negoToken.cbBuffer < 1) + if (nla->inputBuffer.cbBuffer < 1) { WLog_ERR(TAG, "CredSSP: invalid negoToken!"); return -1; @@ -855,11 +875,8 @@ static int nla_server_authenticate(rdpNla* nla) nla->outputBufferDesc.ulVersion = SECBUFFER_VERSION; nla->outputBufferDesc.cBuffers = 1; nla->outputBufferDesc.pBuffers = &nla->outputBuffer; - nla->outputBuffer.BufferType = SECBUFFER_TOKEN; - nla->outputBuffer.cbBuffer = nla->cbMaxToken; - nla->outputBuffer.pvBuffer = malloc(nla->outputBuffer.cbBuffer); - if (!nla->outputBuffer.pvBuffer) + if (!nla_alloc_buffer(&nla->outputBuffer, nla->cbMaxToken)) return -1; nla->status = nla->table->AcceptSecurityContext( @@ -868,8 +885,9 @@ static int nla_server_authenticate(rdpNla* nla) &nla->pfContextAttr, &nla->expiration); WLog_VRB(TAG, "AcceptSecurityContext status %s [0x%08" PRIX32 "]", GetSecurityStatusString(nla->status), nla->status); - nla->negoToken.pvBuffer = nla->outputBuffer.pvBuffer; - nla->negoToken.cbBuffer = nla->outputBuffer.cbBuffer; + + if (!nla_transfer_buffer(&nla->negoToken, &nla->outputBuffer)) + return -1; if ((nla->status == SEC_I_COMPLETE_AND_CONTINUE) || (nla->status == SEC_I_COMPLETE_NEEDED)) { @@ -2261,6 +2279,8 @@ void nla_buffer_free(rdpNla* nla) sspi_SecBufferFree(&nla->negoToken); sspi_SecBufferFree(&nla->pubKeyAuth); sspi_SecBufferFree(&nla->authInfo); + sspi_SecBufferFree(&nla->inputBuffer); + sspi_SecBufferFree(&nla->outputBuffer); } LPTSTR nla_make_spn(const char* ServiceClass, const char* hostname) From 8c0dcb7248fadf367afc5763f1c5cdc1877ba1d8 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Mon, 16 Jan 2023 14:24:06 +0100 Subject: [PATCH 340/496] [core,redirect] refactor settings update --- libfreerdp/core/redirection.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/libfreerdp/core/redirection.c b/libfreerdp/core/redirection.c index 7e348611237b..9d03f3c06d94 100644 --- a/libfreerdp/core/redirection.c +++ b/libfreerdp/core/redirection.c @@ -219,6 +219,12 @@ int rdp_redirection_apply_settings(rdpRdp* rdp) redirection = rdp->redirection; WINPR_ASSERT(redirection); + { + char buffer[2048] = { 0 }; + WLog_DBG(TAG, "RedirectionFlags=%s", + rdp_redirection_flags_to_string(redirection->flags, buffer, sizeof(buffer))); + } + settings->RedirectionFlags = redirection->flags; settings->RedirectedSessionId = redirection->sessionID; From 3bd7890d01291c342e14b36260cb8ec906231c1d Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Tue, 17 Jan 2023 16:37:19 +0100 Subject: [PATCH 341/496] [core,redirection] fix string read, cleanup logs (cherry picked from commit 7eb332fe983f560b76832c64ae7578db338d3947) --- libfreerdp/core/redirection.c | 43 ++++++++++++++++------------------- 1 file changed, 20 insertions(+), 23 deletions(-) diff --git a/libfreerdp/core/redirection.c b/libfreerdp/core/redirection.c index 9d03f3c06d94..59c6dbceed3d 100644 --- a/libfreerdp/core/redirection.c +++ b/libfreerdp/core/redirection.c @@ -36,14 +36,14 @@ struct rdp_redirection UINT32 flags; UINT32 sessionID; BYTE* TsvUrl; - DWORD TsvUrlLength; + UINT32 TsvUrlLength; char* Username; char* Domain; BYTE* Password; - DWORD PasswordLength; + UINT32 PasswordLength; char* TargetFQDN; BYTE* LoadBalanceInfo; - DWORD LoadBalanceInfoLength; + UINT32 LoadBalanceInfoLength; char* TargetNetBiosName; char* TargetNetAddress; UINT32 TargetNetAddressesCount; @@ -80,9 +80,9 @@ static void redirection_free_string(char** str) static void redirection_free_data(BYTE** str, UINT32* length) { WINPR_ASSERT(str); - WINPR_ASSERT(length); free(*str); - *length = 0; + if (length) + *length = 0; *str = NULL; } @@ -158,7 +158,7 @@ static void rdp_print_redirection_flags(UINT32 flags) static BOOL rdp_redirection_read_unicode_string(wStream* s, char** str, size_t maxLength) { - UINT32 length; + UINT32 length = 0; const WCHAR* wstr = NULL; if (!Stream_CheckAndLogRequiredLength(TAG, s, 4)) @@ -168,18 +168,15 @@ static BOOL rdp_redirection_read_unicode_string(wStream* s, char** str, size_t m if ((length % 2) || length < 2 || length > maxLength) { - WLog_ERR(TAG, - "rdp_redirection_read_string failure: invalid unicode string length: %" PRIu32 "", + WLog_ERR(TAG, "[%s] failure: invalid unicode string length: %" PRIu32 "", __FUNCTION__, length); return FALSE; } if (!Stream_CheckAndLogRequiredLength(TAG, s, length)) { - WLog_ERR(TAG, - "rdp_redirection_read_string failure: insufficient stream length (%" PRIu32 - " bytes required)", - length); + WLog_ERR(TAG, "[%s] failure: insufficient stream length (%" PRIu32 " bytes required)", + __FUNCTION__, length); return FALSE; } @@ -187,7 +184,7 @@ static BOOL rdp_redirection_read_unicode_string(wStream* s, char** str, size_t m if (wstr[length / 2 - 1]) { - WLog_ERR(TAG, "rdp_redirection_read_string failure: unterminated unicode string"); + WLog_ERR(TAG, "[%s] failure: unterminated unicode string", __FUNCTION__); return FALSE; } @@ -197,7 +194,7 @@ static BOOL rdp_redirection_read_unicode_string(wStream* s, char** str, size_t m ConvertFromUnicode(CP_UTF8, 0, wstr, length / sizeof(WCHAR), str, 0, NULL, NULL); if ((res < 0) || !(*str)) { - WLog_ERR(TAG, "rdp_redirection_read_string failure: string conversion failed"); + WLog_ERR(TAG, "[%s] failure: string conversion failed", __FUNCTION__); return FALSE; } } @@ -208,8 +205,8 @@ static BOOL rdp_redirection_read_unicode_string(wStream* s, char** str, size_t m int rdp_redirection_apply_settings(rdpRdp* rdp) { - rdpSettings* settings; - rdpRedirection* redirection; + rdpSettings* settings = NULL; + rdpRedirection* redirection = NULL; WINPR_ASSERT(rdp); @@ -362,7 +359,7 @@ static BOOL rdp_redirection_read_data(UINT32 flag, wStream* s, UINT32* pLength, if (!Stream_CheckAndLogRequiredLength(TAG, s, *pLength)) return FALSE; - redirection_free_data(pData, pLength); + redirection_free_data(pData, NULL); *pData = (BYTE*)malloc(*pLength); if (!*pData) @@ -376,8 +373,8 @@ static BOOL rdp_redirection_read_data(UINT32 flag, wStream* s, UINT32* pLength, static int rdp_recv_server_redirection_pdu(rdpRdp* rdp, wStream* s) { - UINT16 flags; - UINT16 length; + UINT16 flags = 0; + UINT16 length = 0; rdpRedirection* redirection = rdp->redirection; if (!Stream_CheckAndLogRequiredLength(TAG, s, 12)) @@ -523,9 +520,9 @@ static int rdp_recv_server_redirection_pdu(rdpRdp* rdp, wStream* s) if (redirection->flags & LB_TARGET_NET_ADDRESSES) { - size_t i; - UINT32 count; - UINT32 targetNetAddressesLength; + size_t i = 0; + UINT32 count = 0; + UINT32 targetNetAddressesLength = 0; if (!Stream_CheckAndLogRequiredLength(TAG, s, 8)) return -1; @@ -538,7 +535,7 @@ static int rdp_recv_server_redirection_pdu(rdpRdp* rdp, wStream* s) if (!redirection->TargetNetAddresses) return -1; - WLog_DBG(TAG, "TargetNetAddressesCount: %" PRIu32 "", redirection->TargetNetAddressesCount); + WLog_DBG(TAG, "TargetNetAddressesCount: %" PRIu32 "", count); for (i = 0; i < count; i++) { From 3a559ccb92f076ce08450832a4881fb30da808a9 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Thu, 16 Feb 2023 09:55:33 +0100 Subject: [PATCH 342/496] [release] updated version to 2.10.0 --- CMakeLists.txt | 2 +- client/Android/android_freerdp.c | 2 +- winpr/CMakeLists.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9cf675f200ed..cdca0a064aa1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -85,7 +85,7 @@ if ($ENV{BUILD_NUMBER}) endif() set(WITH_LIBRARY_VERSIONING "ON") -set(RAW_VERSION_STRING "2.9.0") +set(RAW_VERSION_STRING "2.10.0") if(EXISTS "${CMAKE_SOURCE_DIR}/.source_tag") file(READ ${CMAKE_SOURCE_DIR}/.source_tag RAW_VERSION_STRING) elseif(USE_VERSION_FROM_GIT_TAG) diff --git a/client/Android/android_freerdp.c b/client/Android/android_freerdp.c index b79a563b53ad..5a506278574e 100644 --- a/client/Android/android_freerdp.c +++ b/client/Android/android_freerdp.c @@ -57,7 +57,7 @@ #define TAG CLIENT_TAG("android") /* Defines the JNI version supported by this library. */ -#define FREERDP_JNI_VERSION "2.9.0" +#define FREERDP_JNI_VERSION "2.10.0" static void android_OnChannelConnectedEventHandler(void* context, ChannelConnectedEventArgs* e) { diff --git a/winpr/CMakeLists.txt b/winpr/CMakeLists.txt index 05eefe4c1464..7b3ef1a6c56c 100644 --- a/winpr/CMakeLists.txt +++ b/winpr/CMakeLists.txt @@ -57,7 +57,7 @@ if (NOT WIN32) endif() # Soname versioning -set(RAW_VERSION_STRING "2.9.0") +set(RAW_VERSION_STRING "2.10.0") if(EXISTS "${CMAKE_SOURCE_DIR}/.source_tag") file(READ ${CMAKE_SOURCE_DIR}/.source_tag RAW_VERSION_STRING) elseif(USE_VERSION_FROM_GIT_TAG) From 7471ae383e7b7a613f275e19f7b54958a193c891 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Thu, 16 Feb 2023 09:54:29 +0100 Subject: [PATCH 343/496] [release] updated changelog --- ChangeLog | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 41ce3be12dd3..17707a3512ec 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,7 +1,25 @@ -# 20xx-xx-xx Version 2.x.x +# 2023-02-16 Version 2.10.0 + +Notewhorth changes: +* Fix android build scripts, use CMake from SDK +* Fix connection negotiation with mstsc/msrdc #8426 +* [ntlm]: use rfc5929 binding hash algorithm #8430 +* [channels,printer] Fixed reference counting #8433 +* Fix uwac pixman #8439 +* Fix Rdp security #8457 +* [client,x11] Detect key autorepeat #8522 +* [build] add channel path to RPATH #8551 +* Fix build with BUILTIN_CHANNELS=OFF #8560 +* revert changes so that the osmajortype/osminortype is not overwritten #8571 +* [uwac] do not use iso C functions #8604 +* [winpr,sam] fix inalid NULL arguments #8605 +* Fix incompatible function pointer types #8625 Fixed issues: * Backported #8581: Ignore data PDUs for DVCs that were not opened successfully +* Backported #8498: [channel,urbdrc] fix type of usb hotplug callback +* Backported #8537: Extended info enforce limits +* Backported #8611: [core] add missing redirection fields # 2022-11-16 Version 2.9.0 From 498ddbf23e520fbff6c96a3c4bd4c6b2534529c4 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Mon, 20 Feb 2023 16:23:39 +0100 Subject: [PATCH 344/496] Fix #8702: Disable sha3 and shake hashes for libressl (cherry picked from commit bd093454fe126163634c00b7484ab7fee6ffe670) --- libfreerdp/crypto/crypto.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libfreerdp/crypto/crypto.c b/libfreerdp/crypto/crypto.c index 943b4df9dcc0..68590d0fa7db 100644 --- a/libfreerdp/crypto/crypto.c +++ b/libfreerdp/crypto/crypto.c @@ -976,7 +976,7 @@ WINPR_MD_TYPE crypto_cert_get_signature_alg(X509* xcert) return WINPR_MD_SHA512; case NID_ripemd160: return WINPR_MD_RIPEMD160; -#if (OPENSSL_VERSION_NUMBER >= 0x1010101fL) || defined(LIBRESSL_VERSION_NUMBER) +#if (OPENSSL_VERSION_NUMBER >= 0x1010101fL) && !defined(LIBRESSL_VERSION_NUMBER) case NID_sha3_224: return WINPR_MD_SHA3_224; case NID_sha3_256: @@ -985,11 +985,11 @@ WINPR_MD_TYPE crypto_cert_get_signature_alg(X509* xcert) return WINPR_MD_SHA3_384; case NID_sha3_512: return WINPR_MD_SHA3_512; -#endif case NID_shake128: return WINPR_MD_SHAKE128; case NID_shake256: return WINPR_MD_SHAKE256; +#endif case NID_undef: default: return WINPR_MD_NONE; From 7f55c97d60453738323e0ecafe6d357019528227 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Tue, 14 Feb 2023 07:48:54 +0100 Subject: [PATCH 345/496] Fixed #8686: Update h264 to use new FFMPEG API --- channels/tsmf/client/ffmpeg/tsmf_ffmpeg.c | 2 ++ libfreerdp/codec/h264_ffmpeg.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/channels/tsmf/client/ffmpeg/tsmf_ffmpeg.c b/channels/tsmf/client/ffmpeg/tsmf_ffmpeg.c index c14877b43ac1..215337464386 100644 --- a/channels/tsmf/client/ffmpeg/tsmf_ffmpeg.c +++ b/channels/tsmf/client/ffmpeg/tsmf_ffmpeg.c @@ -235,8 +235,10 @@ static BOOL tsmf_ffmpeg_init_stream(ITSMFDecoder* decoder, const TS_AM_MEDIA_TYP } } +#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(59, 18, 100) if (mdecoder->codec->capabilities & AV_CODEC_CAP_TRUNCATED) mdecoder->codec_context->flags |= AV_CODEC_FLAG_TRUNCATED; +#endif return TRUE; } diff --git a/libfreerdp/codec/h264_ffmpeg.c b/libfreerdp/codec/h264_ffmpeg.c index 4e3ba8f9282f..9c445b8253ae 100644 --- a/libfreerdp/codec/h264_ffmpeg.c +++ b/libfreerdp/codec/h264_ffmpeg.c @@ -529,10 +529,12 @@ static BOOL libavcodec_init(H264_CONTEXT* h264) goto EXCEPTION; } +#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(59, 18, 100) if (sys->codecDecoder->capabilities & AV_CODEC_CAP_TRUNCATED) { sys->codecDecoderContext->flags |= AV_CODEC_FLAG_TRUNCATED; } +#endif #ifdef WITH_VAAPI From 59aa1d30713989d4ddb2a4f2fcaf3f0563593d84 Mon Sep 17 00:00:00 2001 From: Pascal Nowack Date: Fri, 10 Mar 2023 16:59:43 +0100 Subject: [PATCH 346/496] Update Changelog --- ChangeLog | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/ChangeLog b/ChangeLog index 17707a3512ec..91a9e1fe8795 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,11 @@ +# 20XX-YY-ZZ Version 2.UU.V + +Fixed issues: +* Backported #8690: Update h264 to use new FFMPEG API + # 2023-02-16 Version 2.10.0 -Notewhorth changes: +Noteworthy changes: * Fix android build scripts, use CMake from SDK * Fix connection negotiation with mstsc/msrdc #8426 * [ntlm]: use rfc5929 binding hash algorithm #8430 @@ -23,7 +28,7 @@ Fixed issues: # 2022-11-16 Version 2.9.0 -Notewhorth changes: +Noteworthy changes: * Backported #8252: Support sending server redirection PDU * Backported #8406: Ensure X11 client cursor is never smaller 1x1 * Backported #8403: Fixed multiple client side input validation issues @@ -49,7 +54,7 @@ git log 2.8.1..2.9.0 # 2022-10-12 Version 2.8.1 -Notewhorth changes: +Noteworthy changes: * Fixed CVE-2022-39282 * Fixed CVE-2022-39283 * Added missing commit for backported #8041: Remove ALAW/ULAW codecs from linux backends (unreliable) From 192cf43b0a21d375fa65e530a0c89f01ea34dc49 Mon Sep 17 00:00:00 2001 From: Pascal Nowack Date: Fri, 10 Mar 2023 19:09:22 +0100 Subject: [PATCH 347/496] ci: Build linux builds with WITH_GSSAPI=OFF --- ci/cmake-preloads/config-linux-all.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci/cmake-preloads/config-linux-all.txt b/ci/cmake-preloads/config-linux-all.txt index 4ba743e7247a..03fa536892d9 100644 --- a/ci/cmake-preloads/config-linux-all.txt +++ b/ci/cmake-preloads/config-linux-all.txt @@ -8,7 +8,7 @@ set (WITH_CHANNELS ON CACHE BOOL "channels") set (BUILTIN_CHANNELS ON CACHE BOOL "static channels") set (WITH_CUPS ON CACHE BOOL "cups") set (WITH_WAYLAND ON CACHE BOOL "wayland") -set (WITH_GSSAPI ON CACHE BOOL "Kerberos support") +set (WITH_GSSAPI OFF CACHE BOOL "Kerberos support") set (WITH_PCSC ON CACHE BOOL "PCSC") set (WITH_JPEG ON CACHE BOOL "jpeg") set (WITH_GSTREAMER_0_10 ON CACHE BOOL "gstreamer") From 1fe10abdddf892cb61cca634dbda9c565258f5a0 Mon Sep 17 00:00:00 2001 From: Jeremy Cross Date: Mon, 20 Sep 2021 13:12:04 -0700 Subject: [PATCH 348/496] early bail from update_read_window_state_order when handling WINDOW_ORDER_FIELD_WND_RECTS breaks subsequent protocol parsing (cherry picked from commit 6547db2f17aea56dc638649cef8ebb913a2f9e2a) --- libfreerdp/core/window.c | 42 +++++++++++++++++++--------------------- 1 file changed, 20 insertions(+), 22 deletions(-) diff --git a/libfreerdp/core/window.c b/libfreerdp/core/window.c index 51411c8c26f6..cb0acb9a8bf7 100644 --- a/libfreerdp/core/window.c +++ b/libfreerdp/core/window.c @@ -359,33 +359,31 @@ static BOOL update_read_window_state_order(wStream* s, WINDOW_ORDER_INFO* orderI Stream_Read_UINT16(s, windowState->numWindowRects); /* numWindowRects (2 bytes) */ - if (windowState->numWindowRects == 0) + if (windowState->numWindowRects > 0) { - return TRUE; - } + size = sizeof(RECTANGLE_16) * windowState->numWindowRects; + newRect = (RECTANGLE_16*)realloc(windowState->windowRects, size); - size = sizeof(RECTANGLE_16) * windowState->numWindowRects; - newRect = (RECTANGLE_16*)realloc(windowState->windowRects, size); - - if (!newRect) - { - free(windowState->windowRects); - windowState->windowRects = NULL; - return FALSE; - } + if (!newRect) + { + free(windowState->windowRects); + windowState->windowRects = NULL; + return FALSE; + } - windowState->windowRects = newRect; + windowState->windowRects = newRect; - if (Stream_GetRemainingLength(s) < 8 * windowState->numWindowRects) - return FALSE; + if (Stream_GetRemainingLength(s) < 8 * windowState->numWindowRects) + return FALSE; - /* windowRects */ - for (i = 0; i < windowState->numWindowRects; i++) - { - Stream_Read_UINT16(s, windowState->windowRects[i].left); /* left (2 bytes) */ - Stream_Read_UINT16(s, windowState->windowRects[i].top); /* top (2 bytes) */ - Stream_Read_UINT16(s, windowState->windowRects[i].right); /* right (2 bytes) */ - Stream_Read_UINT16(s, windowState->windowRects[i].bottom); /* bottom (2 bytes) */ + /* windowRects */ + for (i = 0; i < windowState->numWindowRects; i++) + { + Stream_Read_UINT16(s, windowState->windowRects[i].left); /* left (2 bytes) */ + Stream_Read_UINT16(s, windowState->windowRects[i].top); /* top (2 bytes) */ + Stream_Read_UINT16(s, windowState->windowRects[i].right); /* right (2 bytes) */ + Stream_Read_UINT16(s, windowState->windowRects[i].bottom); /* bottom (2 bytes) */ + } } } From a50e158f4615810746092d18e8cb1161d8b5df8c Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Tue, 14 Mar 2023 17:47:31 +0100 Subject: [PATCH 349/496] changelog --- ChangeLog | 1 + 1 file changed, 1 insertion(+) diff --git a/ChangeLog b/ChangeLog index 91a9e1fe8795..b759ed6cae9e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -2,6 +2,7 @@ Fixed issues: * Backported #8690: Update h264 to use new FFMPEG API +* Backported #7306: early bail from update_read_window_state_order breaks protocol # 2023-02-16 Version 2.10.0 From 60a965a9d8f4c450b94eaf027ea1e683ace7db40 Mon Sep 17 00:00:00 2001 From: Neal Gompa Date: Thu, 16 Mar 2023 09:00:03 -0400 Subject: [PATCH 350/496] packaging/rpm: Enable FFmpeg support on Fedora 36+ and RHEL 9+ Since Fedora Linux 36, an FFmpeg implementation is provided in the base distribution as "ffmpeg-free". This implementation is sufficient for building FreeRDP with FFmpeg support. This implementation is also available in Fedora Extra Packages for Enterprise Linux (EPEL) for Red Hat Enterprise Linux 9 and derivatives. Thus, enable FFmpeg support when building for those distributions. (cherry picked from commit d044a1e073ae0345fb43f5a36b7c2189d20ffb6a) --- packaging/rpm/freerdp-nightly.spec | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packaging/rpm/freerdp-nightly.spec b/packaging/rpm/freerdp-nightly.spec index f17bfac4cffb..b213f624c2c1 100644 --- a/packaging/rpm/freerdp-nightly.spec +++ b/packaging/rpm/freerdp-nightly.spec @@ -86,6 +86,10 @@ BuildRequires: libjpeg-turbo-devel BuildRequires: libwayland-client-devel %endif +%if 0%{?fedora} >= 36 || 0%{?rhel} >= 9 +BuildRequires: ffmpeg-free-devel +%endif + BuildRoot: %{_tmppath}/%{name}-%{version}-build %description @@ -116,7 +120,7 @@ cp %{_topdir}/SOURCES/source_version freerdp-nightly-%{version}/.source_version -DWITH_CUPS=ON \ -DWITH_PCSC=ON \ -DWITH_JPEG=ON \ -%if %{defined suse_version} +%if 0%{?fedora} >= 36 || 0%{?rhel} >= 9 || 0%{?suse_version} -DWITH_FFMPEG=ON \ -DWITH_DSP_FFMPEG=ON \ %endif From 7b7ad8bc6d35b4ce01519a97070ff1baeb3a3083 Mon Sep 17 00:00:00 2001 From: Pascal Nowack Date: Wed, 19 Apr 2023 18:49:24 +0200 Subject: [PATCH 351/496] rdpecam/server: Remove wrong assertion Some PDUs, like the Activate Device Request only contain the header. As a result, the size of the rest of the PDU is 0. The assertion for the PDU size in device_server_packet_new only considers the size of the body of the PDU. When that value is 0, the assertion is hit and the server implementation crashes. To fix this issue, simply remove this assertion. Since the allocation size is always at least the header size, there won't ever be an attempt to create a stream with a size of 0. --- channels/rdpecam/server/camera_device_main.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/channels/rdpecam/server/camera_device_main.c b/channels/rdpecam/server/camera_device_main.c index 00bea941e2e9..941a288d3da9 100644 --- a/channels/rdpecam/server/camera_device_main.c +++ b/channels/rdpecam/server/camera_device_main.c @@ -686,8 +686,6 @@ static wStream* device_server_packet_new(size_t size, BYTE version, BYTE message { wStream* s; - WINPR_ASSERT(size > 0); - /* Allocate what we need plus header bytes */ s = Stream_New(NULL, size + CAM_HEADER_SIZE); if (!s) From 41037e3abc89a1464939be78b4d46182bce90498 Mon Sep 17 00:00:00 2001 From: Pascal Nowack Date: Thu, 20 Apr 2023 07:38:40 +0200 Subject: [PATCH 352/496] Update changelog --- ChangeLog | 1 + 1 file changed, 1 insertion(+) diff --git a/ChangeLog b/ChangeLog index b759ed6cae9e..81bd9be462e4 100644 --- a/ChangeLog +++ b/ChangeLog @@ -3,6 +3,7 @@ Fixed issues: * Backported #8690: Update h264 to use new FFMPEG API * Backported #7306: early bail from update_read_window_state_order breaks protocol +* Backported #8903: rdpecam/server: Remove wrong assertion # 2023-02-16 Version 2.10.0 From 856ecaa463e963ecfebc9734423d69139e7b3916 Mon Sep 17 00:00:00 2001 From: houchengqiu Date: Mon, 22 May 2023 16:03:54 +0800 Subject: [PATCH 353/496] [libfreerdp] add bound check in gdi_SolidFill In Windows remote run vulnerabillities exe program, to create Micorosoft::Windows::RDS::Graphics channel, case Remmina crash. So, add bound check, limit the size of the requested rect, no larger than the surface data buffer. (cherry picked from commit 6a63441e4ee8e2bf333361f5d24156a183b14ecd) --- libfreerdp/gdi/gfx.c | 68 ++++++++++++++++++++++++++++---------------- 1 file changed, 43 insertions(+), 25 deletions(-) diff --git a/libfreerdp/gdi/gfx.c b/libfreerdp/gdi/gfx.c index a3b7505c51ba..764f9076f1a0 100644 --- a/libfreerdp/gdi/gfx.c +++ b/libfreerdp/gdi/gfx.c @@ -1079,6 +1079,28 @@ static UINT gdi_DeleteSurface(RdpgfxClientContext* context, return rc; } +static BOOL intersect_rect(const RECTANGLE_16* rect, const gdiGfxSurface* surface, + RECTANGLE_16* prect) +{ + WINPR_ASSERT(rect); + WINPR_ASSERT(surface); + WINPR_ASSERT(prect); + + if (rect->left > rect->right) + return FALSE; + if (rect->left > surface->width) + return FALSE; + if (rect->top > rect->bottom) + return FALSE; + if (rect->top > surface->height) + return FALSE; + prect->left = rect->left; + prect->top = rect->top; + prect->right = MIN(rect->right, surface->width); + prect->bottom = MIN(rect->bottom, surface->height); + return TRUE; +} + /** * Function description * @@ -1087,40 +1109,36 @@ static UINT gdi_DeleteSurface(RdpgfxClientContext* context, static UINT gdi_SolidFill(RdpgfxClientContext* context, const RDPGFX_SOLID_FILL_PDU* solidFill) { UINT status = ERROR_INTERNAL_ERROR; - UINT16 index; - UINT32 color; - BYTE a, r, g, b; - UINT32 nWidth, nHeight; - RECTANGLE_16* rect; - gdiGfxSurface* surface; - RECTANGLE_16 invalidRect; + BYTE a = 0; + RECTANGLE_16 invalidRect = { 0 }; rdpGdi* gdi = (rdpGdi*)context->custom; + EnterCriticalSection(&context->mux); - surface = (gdiGfxSurface*)context->GetSurfaceData(context, solidFill->surfaceId); + + WINPR_ASSERT(context->GetSurfaceData); + gdiGfxSurface* surface = (gdiGfxSurface*)context->GetSurfaceData(context, solidFill->surfaceId); if (!surface) goto fail; - b = solidFill->fillPixel.B; - g = solidFill->fillPixel.G; - r = solidFill->fillPixel.R; - /* a = solidFill->fillPixel.XA; - * Ignore alpha channel, this is a solid fill. */ + const BYTE b = solidFill->fillPixel.B; + const BYTE g = solidFill->fillPixel.G; + const BYTE r = solidFill->fillPixel.R; a = 0xFF; - color = FreeRDPGetColor(surface->format, r, g, b, a); + const UINT32 color = FreeRDPGetColor(surface->format, r, g, b, a); - for (index = 0; index < solidFill->fillRectCount; index++) + for (UINT16 index = 0; index < solidFill->fillRectCount; index++) { - rect = &(solidFill->fillRects[index]); - nWidth = rect->right - rect->left; - nHeight = rect->bottom - rect->top; - invalidRect.left = rect->left; - invalidRect.top = rect->top; - invalidRect.right = rect->right; - invalidRect.bottom = rect->bottom; - - if (!freerdp_image_fill(surface->data, surface->format, surface->scanline, rect->left, - rect->top, nWidth, nHeight, color)) + const RECTANGLE_16* rect = &(solidFill->fillRects[index]); + + if (!intersect_rect(rect, surface, &invalidRect)) + goto fail; + + const UINT32 nWidth = invalidRect.right - invalidRect.left; + const UINT32 nHeight = invalidRect.bottom - invalidRect.top; + + if (!freerdp_image_fill(surface->data, surface->format, surface->scanline, invalidRect.left, + invalidRect.top, nWidth, nHeight, color)) goto fail; region16_union_rect(&(surface->invalidRegion), &(surface->invalidRegion), &invalidRect); From 797e56b4dea08c2f3f4eafe6f0287325d5a92ed8 Mon Sep 17 00:00:00 2001 From: houchengqiu Date: Mon, 22 May 2023 16:12:08 +0800 Subject: [PATCH 354/496] [libfreerdp] add null pointer check in planar_decompress() In Windows remote run vulnerabillities exe program, to create rdpgrfx channel, may case Remmina crash. So, add null pointer check to pSrcData. (cherry picked from commit abdff1dc464f1f7c22ea1ae89a11ad6cf4dff067) --- libfreerdp/codec/planar.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/libfreerdp/codec/planar.c b/libfreerdp/codec/planar.c index 12b9f6daf15c..e49832e1a3db 100644 --- a/libfreerdp/codec/planar.c +++ b/libfreerdp/codec/planar.c @@ -612,11 +612,20 @@ BOOL planar_decompress(BITMAP_PLANAR_CONTEXT* planar, const BYTE* pSrcData, UINT const UINT32 h = MIN(nSrcHeight, nDstHeight); const primitives_t* prims = primitives_get(); + WINPR_ASSERT(planar); + WINPR_ASSERT(prims); + if (nDstStep <= 0) nDstStep = nDstWidth * GetBytesPerPixel(DstFormat); srcp = pSrcData; + if (!pSrcData) + { + WLog_ERR(TAG, "Invalid argument pSrcData=NULL"); + return FALSE; + } + if (!pDstData) { WLog_ERR(TAG, "Invalid argument pDstData=NULL"); From 3cab601f6d34ca1b841561d37a00ec796699b871 Mon Sep 17 00:00:00 2001 From: houchengqiu Date: Mon, 22 May 2023 16:28:42 +0800 Subject: [PATCH 355/496] [libfreerdp] add bound check in gdi_surface_bits() In Windows remote run vulnerabillities exe program, to create rdpgrfx channel, may case Remmina crash. So, add bound check, check that the paste area is valid, and determine if the picture is in the paste area. (cherry picked from commit 6d999672ccc5d94ca97d34bf62a5b8461ec19da5) --- libfreerdp/gdi/gdi.c | 68 +++++++++++++++++++++++++++++++------------- 1 file changed, 49 insertions(+), 19 deletions(-) diff --git a/libfreerdp/gdi/gdi.c b/libfreerdp/gdi/gdi.c index 5ca905b01efd..7a51326eae5c 100644 --- a/libfreerdp/gdi/gdi.c +++ b/libfreerdp/gdi/gdi.c @@ -997,16 +997,46 @@ static BOOL gdi_surface_frame_marker(rdpContext* context, return TRUE; } +static BOOL intersect_rect(const rdpGdi* gdi, const SURFACE_BITS_COMMAND* cmd, RECTANGLE_16* prect) +{ + const UINT32 w = (const UINT32)gdi->width; + const UINT32 h = (const UINT32)gdi->height; + + if (cmd->destLeft > w) + return FALSE; + if (cmd->destRight > w) + return FALSE; + if (cmd->destLeft > cmd->destRight) + return FALSE; + if (cmd->destRight > UINT16_MAX) + return FALSE; + + if (cmd->destTop > h) + return FALSE; + if (cmd->destBottom > h) + return FALSE; + if (cmd->destTop > cmd->destBottom) + return FALSE; + if (cmd->destBottom > UINT16_MAX) + return FALSE; + + prect->left = (const UINT16)cmd->destLeft; + prect->top = (const UINT16)cmd->destTop; + prect->right = MIN((UINT16)cmd->destRight, prect->left + cmd->bmp.width); + prect->bottom = MIN((UINT16)cmd->destBottom, prect->top + cmd->bmp.height); + return TRUE; +} + static BOOL gdi_surface_bits(rdpContext* context, const SURFACE_BITS_COMMAND* cmd) { BOOL result = FALSE; DWORD format; - rdpGdi* gdi; + rdpGdi* gdi = NULL; size_t size; REGION16 region; - RECTANGLE_16 cmdRect; - UINT32 i, nbRects; - const RECTANGLE_16* rects; + RECTANGLE_16 cmdRect = { 0 }; + UINT32 nbRects; + const RECTANGLE_16* rects = NULL; if (!context || !cmd) return FALSE; @@ -1020,16 +1050,15 @@ static BOOL gdi_surface_bits(rdpContext* context, const SURFACE_BITS_COMMAND* cm cmd->destLeft, cmd->destTop, cmd->destRight, cmd->destBottom, cmd->bmp.bpp, cmd->bmp.flags, cmd->bmp.codecID, cmd->bmp.width, cmd->bmp.height, cmd->bmp.bitmapDataLength); region16_init(®ion); - cmdRect.left = cmd->destLeft; - cmdRect.top = cmd->destTop; - cmdRect.right = cmdRect.left + cmd->bmp.width; - cmdRect.bottom = cmdRect.top + cmd->bmp.height; + + if (!intersect_rect(gdi, cmd, &cmdRect)) + goto out; switch (cmd->bmp.codecID) { case RDP_CODEC_ID_REMOTEFX: if (!rfx_process_message(context->codecs->rfx, cmd->bmp.bitmapData, - cmd->bmp.bitmapDataLength, cmd->destLeft, cmd->destTop, + cmd->bmp.bitmapDataLength, cmdRect.left, cmdRect.top, gdi->primary_buffer, gdi->dstFormat, gdi->stride, gdi->height, ®ion)) { @@ -1042,11 +1071,11 @@ static BOOL gdi_surface_bits(rdpContext* context, const SURFACE_BITS_COMMAND* cm case RDP_CODEC_ID_NSCODEC: format = gdi->dstFormat; - if (!nsc_process_message(context->codecs->nsc, cmd->bmp.bpp, cmd->bmp.width, - cmd->bmp.height, cmd->bmp.bitmapData, - cmd->bmp.bitmapDataLength, gdi->primary_buffer, format, - gdi->stride, cmd->destLeft, cmd->destTop, cmd->bmp.width, - cmd->bmp.height, FREERDP_FLIP_VERTICAL)) + if (!nsc_process_message( + context->codecs->nsc, cmd->bmp.bpp, cmd->bmp.width, cmd->bmp.height, + cmd->bmp.bitmapData, cmd->bmp.bitmapDataLength, gdi->primary_buffer, format, + gdi->stride, cmdRect.left, cmdRect.top, cmdRect.right - cmdRect.left, + cmdRect.bottom - cmdRect.top, FREERDP_FLIP_VERTICAL)) { WLog_ERR(TAG, "Failed to process NSCodec message"); goto out; @@ -1064,10 +1093,11 @@ static BOOL gdi_surface_bits(rdpContext* context, const SURFACE_BITS_COMMAND* cm cmd->bmp.bitmapDataLength, size); goto out; } - if (!freerdp_image_copy(gdi->primary_buffer, gdi->dstFormat, gdi->stride, cmd->destLeft, - cmd->destTop, cmd->bmp.width, cmd->bmp.height, - cmd->bmp.bitmapData, format, 0, 0, 0, &gdi->palette, - FREERDP_FLIP_VERTICAL)) + + if (!freerdp_image_copy(gdi->primary_buffer, gdi->dstFormat, gdi->stride, cmdRect.left, + cmdRect.top, cmdRect.right - cmdRect.left, + cmdRect.bottom - cmdRect.top, cmd->bmp.bitmapData, format, 0, 0, + 0, &gdi->palette, FREERDP_FLIP_VERTICAL)) { WLog_ERR(TAG, "Failed to process nocodec message"); goto out; @@ -1084,7 +1114,7 @@ static BOOL gdi_surface_bits(rdpContext* context, const SURFACE_BITS_COMMAND* cm if (!(rects = region16_rects(®ion, &nbRects))) goto out; - for (i = 0; i < nbRects; i++) + for (UINT32 i = 0; i < nbRects; i++) { UINT32 left = rects[i].left; UINT32 top = rects[i].top; From aed7c03c8a42c9e8f43eeda4c6ef5a652c9b8bf3 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Mon, 22 May 2023 12:03:44 +0200 Subject: [PATCH 356/496] changelog --- ChangeLog | 1 + 1 file changed, 1 insertion(+) diff --git a/ChangeLog b/ChangeLog index 81bd9be462e4..50b291962079 100644 --- a/ChangeLog +++ b/ChangeLog @@ -4,6 +4,7 @@ Fixed issues: * Backported #8690: Update h264 to use new FFMPEG API * Backported #7306: early bail from update_read_window_state_order breaks protocol * Backported #8903: rdpecam/server: Remove wrong assertion +* Backported #8994: bounds checks for gdi/gfx rectangles # 2023-02-16 Version 2.10.0 From c617d27115038f47eeb113586e59f7980a9a87e0 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Fri, 2 Jun 2023 11:44:38 +0200 Subject: [PATCH 357/496] [channels,rdpdr] enforce client state checks Keep track of client channel state and abort on invalid messages for a certain state --- channels/rdpdr/client/rdpdr_capabilities.c | 3 + channels/rdpdr/client/rdpdr_main.c | 150 +++++++++++++++++++-- channels/rdpdr/client/rdpdr_main.h | 15 +++ 3 files changed, 156 insertions(+), 12 deletions(-) diff --git a/channels/rdpdr/client/rdpdr_capabilities.c b/channels/rdpdr/client/rdpdr_capabilities.c index 97c876b0e3b9..1d0cbecb1144 100644 --- a/channels/rdpdr/client/rdpdr_capabilities.c +++ b/channels/rdpdr/client/rdpdr_capabilities.c @@ -206,6 +206,9 @@ UINT rdpdr_process_capability_request(rdpdrPlugin* rdpdr, wStream* s) if (!rdpdr || !s) return CHANNEL_RC_NULL_DATA; + WINPR_ASSERT(rdpdr->state == RDPDR_CHANNEL_STATE_SERVER_CAPS); + rdpdr_state_advance(rdpdr, RDPDR_CHANNEL_STATE_CLIENT_CAPS); + if (Stream_GetRemainingLength(s) < 4) return ERROR_INVALID_DATA; diff --git a/channels/rdpdr/client/rdpdr_main.c b/channels/rdpdr/client/rdpdr_main.c index 681ebced990e..c782a762dd1e 100644 --- a/channels/rdpdr/client/rdpdr_main.c +++ b/channels/rdpdr/client/rdpdr_main.c @@ -79,12 +79,50 @@ struct _DEVICE_DRIVE_EXT BOOL automount; }; +static const char* rdpdr_state_str(enum RDPDR_CHANNEL_STATE state) +{ + switch (state) + { + case RDPDR_CHANNEL_STATE_INITIAL: + return "RDPDR_CHANNEL_STATE_INITIAL"; + case RDPDR_CHANNEL_STATE_ANNOUNCE: + return "RDPDR_CHANNEL_STATE_ANNOUNCE"; + case RDPDR_CHANNEL_STATE_ANNOUNCE_REPLY: + return "RDPDR_CHANNEL_STATE_ANNOUNCE_REPLY"; + case RDPDR_CHANNEL_STATE_NAME_REQUEST: + return "RDPDR_CHANNEL_STATE_NAME_REQUEST"; + case RDPDR_CHANNEL_STATE_SERVER_CAPS: + return "RDPDR_CHANNEL_STATE_SERVER_CAPS"; + case RDPDR_CHANNEL_STATE_CLIENT_CAPS: + return "RDPDR_CHANNEL_STATE_CLIENT_CAPS"; + case RDPDR_CHANNEL_STATE_CLIENTID_CONFIRM: + return "RDPDR_CHANNEL_STATE_CLIENTID_CONFIRM"; + case RDPDR_CHANNEL_STATE_READY: + return "RDPDR_CHANNEL_STATE_READY"; + case RDPDR_CHANNEL_STATE_USER_LOGGEDON: + return "RDPDR_CHANNEL_STATE_USER_LOGGEDON"; + default: + return "RDPDR_CHANNEL_STATE_UNKNOWN"; + } +} + +BOOL rdpdr_state_advance(rdpdrPlugin* rdpdr, enum RDPDR_CHANNEL_STATE next) +{ + WINPR_ASSERT(rdpdr); + + if (next != rdpdr->state) + WLog_Print(rdpdr->log, WLOG_DEBUG, "[RDPDR] transition from %s to %s", + rdpdr_state_str(rdpdr->state), rdpdr_state_str(next)); + rdpdr->state = next; + return TRUE; +} + /** * Function description * * @return 0 on success, otherwise a Win32 error code */ -static UINT rdpdr_send_device_list_announce_request(rdpdrPlugin* rdpdr, BOOL userLoggedOn); +static UINT rdpdr_try_send_device_list_announce_request(rdpdrPlugin* rdpdr); /** * Function description @@ -212,7 +250,7 @@ LRESULT CALLBACK hotplug_proc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) devman_load_device_service(rdpdr->devman, (const RDPDR_DEVICE*)&drive, rdpdr->rdpcontext); - rdpdr_send_device_list_announce_request(rdpdr, TRUE); + rdpdr_try_send_device_list_announce_request(rdpdr); } } @@ -543,7 +581,7 @@ static void drive_hotplug_fsevent_callback(ConstFSEventStreamRef streamRef, WLog_ERR(TAG, "handle_hotplug failed with error %" PRIu32 "!", error); } else - rdpdr_send_device_list_announce_request(rdpdr, TRUE); + rdpdr_try_send_device_list_announce_request(rdpdr); return; } @@ -661,7 +699,7 @@ static void handle_mountpoint(hotplug_dev* dev_array, size_t* size, const char* #ifdef __sun #include -static UINT handle_platform_mounts_sun(hotplug_dev* dev_array, size_t* size) +static UINT handle_platform_mounts_sun(wLog* log, hotplug_dev* dev_array, size_t* size) { FILE* f; struct mnttab ent; @@ -682,7 +720,7 @@ static UINT handle_platform_mounts_sun(hotplug_dev* dev_array, size_t* size) #if defined(__FreeBSD__) || defined(__OpenBSD__) #include -static UINT handle_platform_mounts_bsd(hotplug_dev* dev_array, size_t* size) +static UINT handle_platform_mounts_bsd(wLog* log, hotplug_dev* dev_array, size_t* size) { int mntsize; size_t idx; @@ -706,7 +744,7 @@ static UINT handle_platform_mounts_bsd(hotplug_dev* dev_array, size_t* size) #if defined(__LINUX__) || defined(__linux__) #include -static UINT handle_platform_mounts_linux(hotplug_dev* dev_array, size_t* size) +static UINT handle_platform_mounts_linux(wLog* log, hotplug_dev* dev_array, size_t* size) { FILE* f; struct mntent* ent; @@ -725,14 +763,14 @@ static UINT handle_platform_mounts_linux(hotplug_dev* dev_array, size_t* size) } #endif -static UINT handle_platform_mounts(hotplug_dev* dev_array, size_t* size) +static UINT handle_platform_mounts(wLog* log, hotplug_dev* dev_array, size_t* size) { #ifdef __sun - return handle_platform_mounts_sun(dev_array, size); + return handle_platform_mounts_sun(log, dev_array, size); #elif defined(__FreeBSD__) || defined(__OpenBSD__) - return handle_platform_mounts_bsd(dev_array, size); + return handle_platform_mounts_bsd(log, dev_array, size); #elif defined(__LINUX__) || defined(__linux__) - return handle_platform_mounts_linux(dev_array, size); + return handle_platform_mounts_linux(log, dev_array, size); #endif return ERROR_CALL_NOT_IMPLEMENTED; } @@ -790,7 +828,7 @@ static UINT handle_hotplug(rdpdrPlugin* rdpdr) UINT32 ids[1]; UINT error = ERROR_SUCCESS; - error = handle_platform_mounts(dev_array, &size); + error = handle_platform_mounts(rdpdr->log, dev_array, &size); /* delete removed devices */ count = ListDictionary_GetKeys(rdpdr->devman->devices, &keys); @@ -938,7 +976,7 @@ static DWORD WINAPI drive_hotplug_thread_func(LPVOID arg) goto out; } else - rdpdr_send_device_list_announce_request(rdpdr, TRUE); + rdpdr_try_send_device_list_announce_request(rdpdr); } FD_ZERO(&rfds); @@ -1087,6 +1125,11 @@ static UINT rdpdr_process_server_announce_request(rdpdrPlugin* rdpdr, wStream* s static UINT rdpdr_send_client_announce_reply(rdpdrPlugin* rdpdr) { wStream* s; + + WINPR_ASSERT(rdpdr); + WINPR_ASSERT(rdpdr->state == RDPDR_CHANNEL_STATE_ANNOUNCE); + rdpdr_state_advance(rdpdr, RDPDR_CHANNEL_STATE_ANNOUNCE_REPLY); + s = Stream_New(NULL, 12); if (!s) @@ -1114,6 +1157,10 @@ static UINT rdpdr_send_client_name_request(rdpdrPlugin* rdpdr) WCHAR* computerNameW = NULL; size_t computerNameLenW; + WINPR_ASSERT(rdpdr); + WINPR_ASSERT(rdpdr->state == RDPDR_CHANNEL_STATE_ANNOUNCE_REPLY); + rdpdr_state_advance(rdpdr, RDPDR_CHANNEL_STATE_NAME_REQUEST); + if (!rdpdr->computerName[0]) { DWORD size = sizeof(rdpdr->computerName) - 1; @@ -1184,6 +1231,18 @@ static UINT rdpdr_send_device_list_announce_request(rdpdrPlugin* rdpdr, BOOL use DEVICE* device; int keyCount; ULONG_PTR* pKeys = NULL; + + if (userLoggedOn) + { + WINPR_ASSERT(rdpdr->state >= RDPDR_CHANNEL_STATE_READY); + rdpdr_state_advance(rdpdr, RDPDR_CHANNEL_STATE_USER_LOGGEDON); + } + else + { + WINPR_ASSERT(rdpdr->state >= RDPDR_CHANNEL_STATE_CLIENTID_CONFIRM); + rdpdr_state_advance(rdpdr, RDPDR_CHANNEL_STATE_READY); + } + s = Stream_New(NULL, 256); if (!s) @@ -1258,6 +1317,19 @@ static UINT rdpdr_send_device_list_announce_request(rdpdrPlugin* rdpdr, BOOL use return rdpdr_send(rdpdr, s); } +UINT rdpdr_try_send_device_list_announce_request(rdpdrPlugin* rdpdr) +{ + WINPR_ASSERT(rdpdr); + if (rdpdr->state != RDPDR_CHANNEL_STATE_USER_LOGGEDON) + { + WLog_Print(rdpdr->log, WLOG_DEBUG, + "hotplug event received, but channel [RDPDR] is not ready (state %s), ignoring.", + rdpdr_state_str(rdpdr->state)); + return CHANNEL_RC_OK; + } + return rdpdr_send_device_list_announce_request(rdpdr, TRUE); +} + static UINT dummy_irp_response(rdpdrPlugin* rdpdr, wStream* s) { @@ -1380,6 +1452,57 @@ static UINT rdpdr_process_init(rdpdrPlugin* rdpdr) return CHANNEL_RC_OK; } +static BOOL rdpdr_state_check(rdpdrPlugin* rdpdr, UINT16 packetid, + enum RDPDR_CHANNEL_STATE expected, enum RDPDR_CHANNEL_STATE next) +{ + WINPR_ASSERT(rdpdr); + + const char* strstate = rdpdr_state_str(rdpdr->state); + if (rdpdr->state != expected) + { + WLog_Print(rdpdr->log, WLOG_ERROR, + "channel [RDPDR] received %s, expected state %s but have state %s, aborting.", + rdpdr_packetid_string(packetid), rdpdr_state_str(expected), strstate); + + rdpdr_state_advance(rdpdr, RDPDR_CHANNEL_STATE_INITIAL); + return FALSE; + } + return rdpdr_state_advance(rdpdr, next); +} + +static BOOL rdpdr_check_channel_state(rdpdrPlugin* rdpdr, UINT16 packetid) +{ + WINPR_ASSERT(rdpdr); + + switch (packetid) + { + case PAKID_CORE_SERVER_ANNOUNCE: + /* windows servers sometimes send this message. + * it seems related to session login (e.g. first initialization for RDP/TLS style login, + * then reinitialize the channel after login successful + */ + rdpdr_state_advance(rdpdr, RDPDR_CHANNEL_STATE_INITIAL); + return rdpdr_state_check(rdpdr, packetid, RDPDR_CHANNEL_STATE_INITIAL, + RDPDR_CHANNEL_STATE_ANNOUNCE); + case PAKID_CORE_SERVER_CAPABILITY: + return rdpdr_state_check(rdpdr, packetid, RDPDR_CHANNEL_STATE_NAME_REQUEST, + RDPDR_CHANNEL_STATE_SERVER_CAPS); + case PAKID_CORE_CLIENTID_CONFIRM: + return rdpdr_state_check(rdpdr, packetid, RDPDR_CHANNEL_STATE_CLIENT_CAPS, + RDPDR_CHANNEL_STATE_CLIENTID_CONFIRM); + case PAKID_CORE_USER_LOGGEDON: + return rdpdr_state_check(rdpdr, packetid, RDPDR_CHANNEL_STATE_READY, + RDPDR_CHANNEL_STATE_USER_LOGGEDON); + default: + { + enum RDPDR_CHANNEL_STATE state = RDPDR_CHANNEL_STATE_READY; + if (rdpdr->state == RDPDR_CHANNEL_STATE_USER_LOGGEDON) + state = RDPDR_CHANNEL_STATE_USER_LOGGEDON; + return rdpdr_state_check(rdpdr, packetid, state, state); + } + } +} + /** * Function description * @@ -1403,6 +1526,9 @@ static UINT rdpdr_process_receive(rdpdrPlugin* rdpdr, wStream* s) if (component == RDPDR_CTYP_CORE) { + if (!rdpdr_check_channel_state(rdpdr, packetId)) + return CHANNEL_RC_OK; + switch (packetId) { case PAKID_CORE_SERVER_ANNOUNCE: diff --git a/channels/rdpdr/client/rdpdr_main.h b/channels/rdpdr/client/rdpdr_main.h index 4c372da63dad..b27f1c29d148 100644 --- a/channels/rdpdr/client/rdpdr_main.h +++ b/channels/rdpdr/client/rdpdr_main.h @@ -46,11 +46,25 @@ typedef struct rdpdr_plugin rdpdrPlugin; +enum RDPDR_CHANNEL_STATE +{ + RDPDR_CHANNEL_STATE_INITIAL = 0, + RDPDR_CHANNEL_STATE_ANNOUNCE, + RDPDR_CHANNEL_STATE_ANNOUNCE_REPLY, + RDPDR_CHANNEL_STATE_NAME_REQUEST, + RDPDR_CHANNEL_STATE_SERVER_CAPS, + RDPDR_CHANNEL_STATE_CLIENT_CAPS, + RDPDR_CHANNEL_STATE_CLIENTID_CONFIRM, + RDPDR_CHANNEL_STATE_READY, + RDPDR_CHANNEL_STATE_USER_LOGGEDON +}; + struct rdpdr_plugin { CHANNEL_DEF channelDef; CHANNEL_ENTRY_POINTS_FREERDP_EX channelEntryPoints; + enum RDPDR_CHANNEL_STATE state; HANDLE thread; wStream* data_in; void* InitHandle; @@ -80,6 +94,7 @@ struct rdpdr_plugin rdpContext* rdpcontext; }; +BOOL rdpdr_state_advance(rdpdrPlugin* rdpdr, enum RDPDR_CHANNEL_STATE next); UINT rdpdr_send(rdpdrPlugin* rdpdr, wStream* s); #endif /* FREERDP_CHANNEL_RDPDR_CLIENT_MAIN_H */ From ad7cedc64d93d3f431c18bfc34d3197a86f425f0 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Thu, 22 Dec 2022 00:32:17 +0100 Subject: [PATCH 358/496] [channel,rdpdr] use wLog* for client logging --- channels/rdpdr/client/devman.c | 6 +- channels/rdpdr/client/irp.c | 10 +- channels/rdpdr/client/irp.h | 3 +- channels/rdpdr/client/rdpdr_capabilities.c | 26 +-- channels/rdpdr/client/rdpdr_main.c | 211 ++++++++++++--------- channels/rdpdr/client/rdpdr_main.h | 7 +- 6 files changed, 149 insertions(+), 114 deletions(-) diff --git a/channels/rdpdr/client/devman.c b/channels/rdpdr/client/devman.c index af3cdd6b268d..841e928fec62 100644 --- a/channels/rdpdr/client/devman.c +++ b/channels/rdpdr/client/devman.c @@ -41,6 +41,8 @@ #include "devman.h" +#define TAG CHANNELS_TAG("rdpdr.client") + static void devman_device_free(void* obj) { DEVICE* device = (DEVICE*)obj; @@ -62,7 +64,7 @@ DEVMAN* devman_new(rdpdrPlugin* rdpdr) if (!devman) { - WLog_INFO(TAG, "calloc failed!"); + WLog_Print(rdpdr->log, WLOG_INFO, "calloc failed!"); return NULL; } @@ -72,7 +74,7 @@ DEVMAN* devman_new(rdpdrPlugin* rdpdr) if (!devman->devices) { - WLog_INFO(TAG, "ListDictionary_New failed!"); + WLog_Print(rdpdr->log, WLOG_INFO, "ListDictionary_New failed!"); free(devman); return NULL; } diff --git a/channels/rdpdr/client/irp.c b/channels/rdpdr/client/irp.c index b818b67ac35b..b1278103cbb4 100644 --- a/channels/rdpdr/client/irp.c +++ b/channels/rdpdr/client/irp.c @@ -76,13 +76,13 @@ static UINT irp_complete(IRP* irp) return irp_free(irp); } -IRP* irp_new(DEVMAN* devman, wStream* s, UINT* error) +IRP* irp_new(DEVMAN* devman, wStream* s, wLog* log, UINT* error) { IRP* irp; DEVICE* device; UINT32 DeviceId; - if (Stream_GetRemainingLength(s) < 20) + if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 20)) { if (error) *error = ERROR_INVALID_DATA; @@ -94,7 +94,7 @@ IRP* irp_new(DEVMAN* devman, wStream* s, UINT* error) if (!device) { - WLog_WARN(TAG, "devman_get_device_by_id failed!"); + WLog_Print(log, WLOG_WARN, "devman_get_device_by_id failed!"); if (error) *error = CHANNEL_RC_OK; @@ -105,7 +105,7 @@ IRP* irp_new(DEVMAN* devman, wStream* s, UINT* error) if (!irp) { - WLog_ERR(TAG, "_aligned_malloc failed!"); + WLog_Print(log, WLOG_ERROR, "_aligned_malloc failed!"); if (error) *error = CHANNEL_RC_NO_MEMORY; return NULL; @@ -125,7 +125,7 @@ IRP* irp_new(DEVMAN* devman, wStream* s, UINT* error) irp->output = Stream_New(NULL, 256); if (!irp->output) { - WLog_ERR(TAG, "Stream_New failed!"); + WLog_Print(log, WLOG_ERROR, "Stream_New failed!"); _aligned_free(irp); if (error) *error = CHANNEL_RC_NO_MEMORY; diff --git a/channels/rdpdr/client/irp.h b/channels/rdpdr/client/irp.h index 17d75acde6ee..46a67be2bc24 100644 --- a/channels/rdpdr/client/irp.h +++ b/channels/rdpdr/client/irp.h @@ -21,8 +21,9 @@ #ifndef FREERDP_CHANNEL_RDPDR_CLIENT_IRP_H #define FREERDP_CHANNEL_RDPDR_CLIENT_IRP_H +#include #include "rdpdr_main.h" -IRP* irp_new(DEVMAN* devman, wStream* s, UINT* error); +IRP* irp_new(DEVMAN* devman, wStream* s, wLog* log, UINT* error); #endif /* FREERDP_CHANNEL_RDPDR_CLIENT_IRP_H */ diff --git a/channels/rdpdr/client/rdpdr_capabilities.c b/channels/rdpdr/client/rdpdr_capabilities.c index 1d0cbecb1144..7669766e10ee 100644 --- a/channels/rdpdr/client/rdpdr_capabilities.c +++ b/channels/rdpdr/client/rdpdr_capabilities.c @@ -69,7 +69,7 @@ static UINT rdpdr_process_general_capset(rdpdrPlugin* rdpdr, wStream* s) UINT16 capabilityLength; WINPR_UNUSED(rdpdr); - if (Stream_GetRemainingLength(s) < 2) + if (!Stream_CheckAndLogRequiredLengthWLog(rdpdr->log, s, 2)) return ERROR_INVALID_DATA; Stream_Read_UINT16(s, capabilityLength); @@ -77,7 +77,7 @@ static UINT rdpdr_process_general_capset(rdpdrPlugin* rdpdr, wStream* s) if (capabilityLength < 4) return ERROR_INVALID_DATA; - if (Stream_GetRemainingLength(s) < capabilityLength - 4U) + if (!Stream_CheckAndLogRequiredLengthWLog(rdpdr->log, s, capabilityLength - 4U)) return ERROR_INVALID_DATA; Stream_Seek(s, capabilityLength - 4U); @@ -97,7 +97,7 @@ static UINT rdpdr_process_printer_capset(rdpdrPlugin* rdpdr, wStream* s) UINT16 capabilityLength; WINPR_UNUSED(rdpdr); - if (Stream_GetRemainingLength(s) < 2) + if (!Stream_CheckAndLogRequiredLengthWLog(rdpdr->log, s, 2)) return ERROR_INVALID_DATA; Stream_Read_UINT16(s, capabilityLength); @@ -105,7 +105,7 @@ static UINT rdpdr_process_printer_capset(rdpdrPlugin* rdpdr, wStream* s) if (capabilityLength < 4) return ERROR_INVALID_DATA; - if (Stream_GetRemainingLength(s) < capabilityLength - 4U) + if (!Stream_CheckAndLogRequiredLengthWLog(rdpdr->log, s, capabilityLength - 4U)) return ERROR_INVALID_DATA; Stream_Seek(s, capabilityLength - 4U); @@ -125,7 +125,7 @@ static UINT rdpdr_process_port_capset(rdpdrPlugin* rdpdr, wStream* s) UINT16 capabilityLength; WINPR_UNUSED(rdpdr); - if (Stream_GetRemainingLength(s) < 2) + if (!Stream_CheckAndLogRequiredLengthWLog(rdpdr->log, s, 2)) return ERROR_INVALID_DATA; Stream_Read_UINT16(s, capabilityLength); @@ -133,7 +133,7 @@ static UINT rdpdr_process_port_capset(rdpdrPlugin* rdpdr, wStream* s) if (capabilityLength < 4U) return ERROR_INVALID_DATA; - if (Stream_GetRemainingLength(s) < capabilityLength - 4U) + if (!Stream_CheckAndLogRequiredLengthWLog(rdpdr->log, s, capabilityLength - 4U)) return ERROR_INVALID_DATA; Stream_Seek(s, capabilityLength - 4U); @@ -153,7 +153,7 @@ static UINT rdpdr_process_drive_capset(rdpdrPlugin* rdpdr, wStream* s) UINT16 capabilityLength; WINPR_UNUSED(rdpdr); - if (Stream_GetRemainingLength(s) < 2) + if (!Stream_CheckAndLogRequiredLengthWLog(rdpdr->log, s, 2)) return ERROR_INVALID_DATA; Stream_Read_UINT16(s, capabilityLength); @@ -161,7 +161,7 @@ static UINT rdpdr_process_drive_capset(rdpdrPlugin* rdpdr, wStream* s) if (capabilityLength < 4) return ERROR_INVALID_DATA; - if (Stream_GetRemainingLength(s) < capabilityLength - 4U) + if (!Stream_CheckAndLogRequiredLengthWLog(rdpdr->log, s, capabilityLength - 4U)) return ERROR_INVALID_DATA; Stream_Seek(s, capabilityLength - 4U); @@ -181,7 +181,7 @@ static UINT rdpdr_process_smartcard_capset(rdpdrPlugin* rdpdr, wStream* s) UINT16 capabilityLength; WINPR_UNUSED(rdpdr); - if (Stream_GetRemainingLength(s) < 2) + if (!Stream_CheckAndLogRequiredLengthWLog(rdpdr->log, s, 2)) return ERROR_INVALID_DATA; Stream_Read_UINT16(s, capabilityLength); @@ -189,7 +189,7 @@ static UINT rdpdr_process_smartcard_capset(rdpdrPlugin* rdpdr, wStream* s) if (capabilityLength < 4) return ERROR_INVALID_DATA; - if (Stream_GetRemainingLength(s) < capabilityLength - 4U) + if (!Stream_CheckAndLogRequiredLengthWLog(rdpdr->log, s, capabilityLength - 4U)) return ERROR_INVALID_DATA; Stream_Seek(s, capabilityLength - 4U); @@ -209,7 +209,7 @@ UINT rdpdr_process_capability_request(rdpdrPlugin* rdpdr, wStream* s) WINPR_ASSERT(rdpdr->state == RDPDR_CHANNEL_STATE_SERVER_CAPS); rdpdr_state_advance(rdpdr, RDPDR_CHANNEL_STATE_CLIENT_CAPS); - if (Stream_GetRemainingLength(s) < 4) + if (!Stream_CheckAndLogRequiredLengthWLog(rdpdr->log, s, 4)) return ERROR_INVALID_DATA; Stream_Read_UINT16(s, numCapabilities); @@ -217,7 +217,7 @@ UINT rdpdr_process_capability_request(rdpdrPlugin* rdpdr, wStream* s) for (i = 0; i < numCapabilities; i++) { - if (Stream_GetRemainingLength(s) < sizeof(UINT16)) + if (!Stream_CheckAndLogRequiredLengthWLog(rdpdr->log, s, sizeof(UINT16))) return ERROR_INVALID_DATA; Stream_Read_UINT16(s, capabilityType); @@ -267,7 +267,7 @@ UINT rdpdr_send_capability_response(rdpdrPlugin* rdpdr) if (!s) { - WLog_ERR(TAG, "Stream_New failed!"); + WLog_Print(rdpdr->log, WLOG_ERROR, "Stream_New failed!"); return CHANNEL_RC_NO_MEMORY; } diff --git a/channels/rdpdr/client/rdpdr_main.c b/channels/rdpdr/client/rdpdr_main.c index c782a762dd1e..adaaf1df196c 100644 --- a/channels/rdpdr/client/rdpdr_main.c +++ b/channels/rdpdr/client/rdpdr_main.c @@ -137,7 +137,7 @@ static UINT rdpdr_send_device_list_remove_request(rdpdrPlugin* rdpdr, UINT32 cou if (!s) { - WLog_ERR(TAG, "Stream_New failed!"); + WLog_Print(rdpdr->log, WLOG_ERROR, "Stream_New failed!"); return CHANNEL_RC_NO_MEMORY; } @@ -299,8 +299,8 @@ LRESULT CALLBACK hotplug_proc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) rdpdr, 1, ids))) { // dont end on error, just report ? - WLog_ERR( - TAG, + WLog_Print( + rdpdr->log, WLOG_ERROR, "rdpdr_send_device_list_remove_request failed " "with error %" PRIu32 "!", error); @@ -396,7 +396,7 @@ static UINT drive_hotplug_thread_terminate(rdpdrPlugin* rdpdr) if (rdpdr->hotplug_wnd && !PostMessage(rdpdr->hotplug_wnd, WM_QUIT, 0, 0)) { error = GetLastError(); - WLog_ERR(TAG, "PostMessage failed with error %" PRIu32 "", error); + WLog_Print(rdpdr->log, WLOG_ERROR, "PostMessage failed with error %" PRIu32 "", error); } return error; @@ -513,9 +513,9 @@ static UINT handle_hotplug(rdpdrPlugin* rdpdr) if ((error = rdpdr_send_device_list_remove_request(rdpdr, 1, ids))) { - WLog_ERR(TAG, - "rdpdr_send_device_list_remove_request failed with error %" PRIu32 "!", - error); + WLog_Print(rdpdr->log, WLOG_ERROR, + "rdpdr_send_device_list_remove_request failed with error %" PRIu32 "!", + error); goto cleanup; } } @@ -544,7 +544,7 @@ static UINT handle_hotplug(rdpdrPlugin* rdpdr) if ((error = devman_load_device_service(rdpdr->devman, (RDPDR_DEVICE*)&drive, rdpdr->rdpcontext))) { - WLog_ERR(TAG, "devman_load_device_service failed!"); + WLog_Print(rdpdr->log, WLOG_ERROR, "devman_load_device_service failed!"); error = CHANNEL_RC_NO_MEMORY; goto cleanup; } @@ -578,7 +578,8 @@ static void drive_hotplug_fsevent_callback(ConstFSEventStreamRef streamRef, { if ((error = handle_hotplug(rdpdr))) { - WLog_ERR(TAG, "handle_hotplug failed with error %" PRIu32 "!", error); + WLog_Print(rdpdr->log, WLOG_ERROR, "handle_hotplug failed with error %" PRIu32 "!", + error); } else rdpdr_try_send_device_list_announce_request(rdpdr); @@ -594,7 +595,7 @@ void first_hotplug(rdpdrPlugin* rdpdr) if ((error = handle_hotplug(rdpdr))) { - WLog_ERR(TAG, "handle_hotplug failed with error %" PRIu32 "!", error); + WLog_Print(rdpdr->log, WLOG_ERROR, "handle_hotplug failed with error %" PRIu32 "!", error); } } @@ -706,7 +707,7 @@ static UINT handle_platform_mounts_sun(wLog* log, hotplug_dev* dev_array, size_t f = fopen("/etc/mnttab", "r"); if (f == NULL) { - WLog_ERR(TAG, "fopen failed!"); + WLog_Print(log, WLOG_ERROR, "fopen failed!"); return ERROR_OPEN_FAILED; } while (getmntent(f, &ent) == 0) @@ -730,7 +731,7 @@ static UINT handle_platform_mounts_bsd(wLog* log, hotplug_dev* dev_array, size_t if (!mntsize) { /* TODO: handle 'errno' */ - WLog_ERR(TAG, "getmntinfo failed!"); + WLog_Print(log, WLOG_ERROR, "getmntinfo failed!"); return ERROR_OPEN_FAILED; } for (idx = 0; idx < (size_t)mntsize; idx++) @@ -751,7 +752,7 @@ static UINT handle_platform_mounts_linux(wLog* log, hotplug_dev* dev_array, size f = fopen("/proc/mounts", "r"); if (f == NULL) { - WLog_ERR(TAG, "fopen failed!"); + WLog_Print(log, WLOG_ERROR, "fopen failed!"); return ERROR_OPEN_FAILED; } while ((ent = getmntent(f)) != NULL) @@ -872,9 +873,9 @@ static UINT handle_hotplug(rdpdrPlugin* rdpdr) if ((error = rdpdr_send_device_list_remove_request(rdpdr, 1, ids))) { - WLog_ERR(TAG, - "rdpdr_send_device_list_remove_request failed with error %" PRIu32 "!", - error); + WLog_Print(rdpdr->log, WLOG_ERROR, + "rdpdr_send_device_list_remove_request failed with error %" PRIu32 "!", + error); goto cleanup; } } @@ -896,7 +897,7 @@ static UINT handle_hotplug(rdpdrPlugin* rdpdr) if (!drive.Name) { - WLog_ERR(TAG, "_strdup failed!"); + WLog_Print(rdpdr->log, WLOG_ERROR, "_strdup failed!"); error = CHANNEL_RC_NO_MEMORY; goto cleanup; } @@ -904,7 +905,7 @@ static UINT handle_hotplug(rdpdrPlugin* rdpdr) if ((error = devman_load_device_service(rdpdr->devman, (const RDPDR_DEVICE*)&drive, rdpdr->rdpcontext))) { - WLog_ERR(TAG, "devman_load_device_service failed!"); + WLog_Print(rdpdr->log, WLOG_ERROR, "devman_load_device_service failed!"); goto cleanup; } } @@ -925,7 +926,7 @@ static void first_hotplug(rdpdrPlugin* rdpdr) if ((error = handle_hotplug(rdpdr))) { - WLog_ERR(TAG, "handle_hotplug failed with error %" PRIu32 "!", error); + WLog_Print(rdpdr->log, WLOG_ERROR, "handle_hotplug failed with error %" PRIu32 "!", error); } } @@ -943,7 +944,7 @@ static DWORD WINAPI drive_hotplug_thread_func(LPVOID arg) if (mfd < 0) { - WLog_ERR(TAG, "ERROR: Unable to open /proc/mounts."); + WLog_Print(rdpdr->log, WLOG_ERROR, "ERROR: Unable to open /proc/mounts."); error = ERROR_INTERNAL_ERROR; goto out; } @@ -960,7 +961,8 @@ static DWORD WINAPI drive_hotplug_thread_func(LPVOID arg) if (status == WAIT_FAILED) { error = GetLastError(); - WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "!", error); + WLog_Print(rdpdr->log, WLOG_ERROR, "WaitForSingleObject failed with error %" PRIu32 "!", + error); goto out; } @@ -972,7 +974,8 @@ static DWORD WINAPI drive_hotplug_thread_func(LPVOID arg) /* file /proc/mounts changed, handle this */ if ((error = handle_hotplug(rdpdr))) { - WLog_ERR(TAG, "handle_hotplug failed with error %" PRIu32 "!", error); + WLog_Print(rdpdr->log, WLOG_ERROR, "handle_hotplug failed with error %" PRIu32 "!", + error); goto out; } else @@ -1016,7 +1019,8 @@ static UINT drive_hotplug_thread_terminate(rdpdrPlugin* rdpdr) if (WaitForSingleObject(rdpdr->hotplugThread, INFINITE) == WAIT_FAILED) { error = GetLastError(); - WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "!", error); + WLog_Print(rdpdr->log, WLOG_ERROR, "WaitForSingleObject failed with error %" PRIu32 "!", + error); return error; } @@ -1045,7 +1049,7 @@ static UINT rdpdr_process_connect(rdpdrPlugin* rdpdr) if (!rdpdr->devman) { - WLog_ERR(TAG, "devman_new failed!"); + WLog_Print(rdpdr->log, WLOG_ERROR, "devman_new failed!"); return CHANNEL_RC_NO_MEMORY; } @@ -1074,7 +1078,7 @@ static UINT rdpdr_process_connect(rdpdrPlugin* rdpdr) if (!(rdpdr->stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL))) { - WLog_ERR(TAG, "CreateEvent failed!"); + WLog_Print(rdpdr->log, WLOG_ERROR, "CreateEvent failed!"); return ERROR_INTERNAL_ERROR; } @@ -1083,7 +1087,7 @@ static UINT rdpdr_process_connect(rdpdrPlugin* rdpdr) if (!(rdpdr->hotplugThread = CreateThread(NULL, 0, drive_hotplug_thread_func, rdpdr, 0, NULL))) { - WLog_ERR(TAG, "CreateThread failed!"); + WLog_Print(rdpdr->log, WLOG_ERROR, "CreateThread failed!"); #ifndef _WIN32 CloseHandle(rdpdr->stopEvent); rdpdr->stopEvent = NULL; @@ -1097,7 +1101,8 @@ static UINT rdpdr_process_connect(rdpdrPlugin* rdpdr) if ((error = devman_load_device_service(rdpdr->devman, device, rdpdr->rdpcontext))) { - WLog_ERR(TAG, "devman_load_device_service failed with error %" PRIu32 "!", error); + WLog_Print(rdpdr->log, WLOG_ERROR, + "devman_load_device_service failed with error %" PRIu32 "!", error); return error; } } @@ -1134,7 +1139,7 @@ static UINT rdpdr_send_client_announce_reply(rdpdrPlugin* rdpdr) if (!s) { - WLog_ERR(TAG, "Stream_New failed!"); + WLog_Print(rdpdr->log, WLOG_ERROR, "Stream_New failed!"); return CHANNEL_RC_NO_MEMORY; } @@ -1173,7 +1178,7 @@ static UINT rdpdr_send_client_name_request(rdpdrPlugin* rdpdr) if (!s) { free(computerNameW); - WLog_ERR(TAG, "Stream_New failed!"); + WLog_Print(rdpdr->log, WLOG_ERROR, "Stream_New failed!"); return CHANNEL_RC_NO_MEMORY; } @@ -1194,7 +1199,10 @@ static UINT rdpdr_process_server_clientid_confirm(rdpdrPlugin* rdpdr, wStream* s UINT16 versionMinor; UINT32 clientID; - if (Stream_GetRemainingLength(s) < 8) + WINPR_ASSERT(rdpdr); + WINPR_ASSERT(s); + + if (!Stream_CheckAndLogRequiredLengthWLog(rdpdr->log, s, 8)) return ERROR_INVALID_DATA; Stream_Read_UINT16(s, versionMajor); @@ -1247,7 +1255,7 @@ static UINT rdpdr_send_device_list_announce_request(rdpdrPlugin* rdpdr, BOOL use if (!s) { - WLog_ERR(TAG, "Stream_New failed!"); + WLog_Print(rdpdr->log, WLOG_ERROR, "Stream_New failed!"); return CHANNEL_RC_NO_MEMORY; } @@ -1279,7 +1287,7 @@ static UINT rdpdr_send_device_list_announce_request(rdpdrPlugin* rdpdr, BOOL use { free(pKeys); Stream_Free(s, TRUE); - WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!"); + WLog_Print(rdpdr->log, WLOG_ERROR, "Stream_EnsureRemainingCapacity failed!"); return ERROR_INVALID_DATA; } @@ -1303,8 +1311,9 @@ static UINT rdpdr_send_device_list_announce_request(rdpdrPlugin* rdpdr, BOOL use Stream_Write(s, Stream_Buffer(device->data), data_len); count++; - WLog_INFO(TAG, "registered device #%" PRIu32 ": %s (type=%" PRIu32 " id=%" PRIu32 ")", - count, device->name, device->type, device->id); + WLog_Print(rdpdr->log, WLOG_INFO, + "registered device #%" PRIu32 ": %s (type=%" PRIu32 " id=%" PRIu32 ")", + count, device->name, device->type, device->id); } } @@ -1340,7 +1349,7 @@ static UINT dummy_irp_response(rdpdrPlugin* rdpdr, wStream* s) wStream* output = Stream_New(NULL, 256); // RDPDR_DEVICE_IO_RESPONSE_LENGTH if (!output) { - WLog_ERR(TAG, "Stream_New failed!"); + WLog_Print(rdpdr->log, WLOG_ERROR, "Stream_New failed!"); return CHANNEL_RC_NO_MEMORY; } @@ -1373,11 +1382,11 @@ static UINT rdpdr_process_irp(rdpdrPlugin* rdpdr, wStream* s) { IRP* irp; UINT error = CHANNEL_RC_OK; - irp = irp_new(rdpdr->devman, s, &error); + irp = irp_new(rdpdr->devman, s, rdpdr->log, &error); if (!irp) { - WLog_ERR(TAG, "irp_new failed with %" PRIu32 "!", error); + WLog_Print(rdpdr->log, WLOG_ERROR, "irp_new failed with %" PRIu32 "!", error); if (error == CHANNEL_RC_OK) { @@ -1389,8 +1398,11 @@ static UINT rdpdr_process_irp(rdpdrPlugin* rdpdr, wStream* s) IFCALLRET(irp->device->IRPRequest, error, irp->device, irp); - if (error) - WLog_ERR(TAG, "device->IRPRequest failed with error %" PRIu32 "", error); + if (error != CHANNEL_RC_OK) + { + WLog_Print(rdpdr->log, WLOG_ERROR, "device->IRPRequest failed with error %" PRIu32 "", + error); + } return error; } @@ -1442,7 +1454,7 @@ static UINT rdpdr_process_init(rdpdrPlugin* rdpdr) if (error != CHANNEL_RC_OK) { - WLog_ERR(TAG, "Init failed!"); + WLog_Print(rdpdr->log, WLOG_ERROR, "Init failed!"); free(pKeys); return error; } @@ -1461,8 +1473,9 @@ static BOOL rdpdr_state_check(rdpdrPlugin* rdpdr, UINT16 packetid, if (rdpdr->state != expected) { WLog_Print(rdpdr->log, WLOG_ERROR, - "channel [RDPDR] received %s, expected state %s but have state %s, aborting.", - rdpdr_packetid_string(packetid), rdpdr_state_str(expected), strstate); + "channel [RDPDR] received %" PRIu16 + ", expected state %s but have state %s, aborting.", + packetid, rdpdr_state_str(expected), strstate); rdpdr_state_advance(rdpdr, RDPDR_CHANNEL_STATE_INITIAL); return FALSE; @@ -1537,19 +1550,20 @@ static UINT rdpdr_process_receive(rdpdrPlugin* rdpdr, wStream* s) } else if ((error = rdpdr_send_client_announce_reply(rdpdr))) { - WLog_ERR(TAG, - "rdpdr_send_client_announce_reply failed with error %" PRIu32 "", - error); + WLog_Print(rdpdr->log, WLOG_ERROR, + "rdpdr_send_client_announce_reply failed with error %" PRIu32 "", + error); } else if ((error = rdpdr_send_client_name_request(rdpdr))) { - WLog_ERR(TAG, - "rdpdr_send_client_name_request failed with error %" PRIu32 "", - error); + WLog_Print(rdpdr->log, WLOG_ERROR, + "rdpdr_send_client_name_request failed with error %" PRIu32 "", + error); } else if ((error = rdpdr_process_init(rdpdr))) { - WLog_ERR(TAG, "rdpdr_process_init failed with error %" PRIu32 "", error); + WLog_Print(rdpdr->log, WLOG_ERROR, + "rdpdr_process_init failed with error %" PRIu32 "", error); } break; @@ -1560,9 +1574,9 @@ static UINT rdpdr_process_receive(rdpdrPlugin* rdpdr, wStream* s) } else if ((error = rdpdr_send_capability_response(rdpdr))) { - WLog_ERR(TAG, - "rdpdr_send_capability_response failed with error %" PRIu32 "", - error); + WLog_Print(rdpdr->log, WLOG_ERROR, + "rdpdr_send_capability_response failed with error %" PRIu32 "", + error); } break; @@ -1573,8 +1587,8 @@ static UINT rdpdr_process_receive(rdpdrPlugin* rdpdr, wStream* s) } else if ((error = rdpdr_send_device_list_announce_request(rdpdr, FALSE))) { - WLog_ERR( - TAG, + WLog_Print( + rdpdr->log, WLOG_ERROR, "rdpdr_send_device_list_announce_request failed with error %" PRIu32 "", error); } @@ -1584,8 +1598,8 @@ static UINT rdpdr_process_receive(rdpdrPlugin* rdpdr, wStream* s) case PAKID_CORE_USER_LOGGEDON: if ((error = rdpdr_send_device_list_announce_request(rdpdr, TRUE))) { - WLog_ERR( - TAG, + WLog_Print( + rdpdr->log, WLOG_ERROR, "rdpdr_send_device_list_announce_request failed with error %" PRIu32 "", error); } @@ -1607,7 +1621,8 @@ static UINT rdpdr_process_receive(rdpdrPlugin* rdpdr, wStream* s) case PAKID_CORE_DEVICE_IOREQUEST: if ((error = rdpdr_process_irp(rdpdr, s))) { - WLog_ERR(TAG, "rdpdr_process_irp failed with error %" PRIu32 "", error); + WLog_Print(rdpdr->log, WLOG_ERROR, + "rdpdr_process_irp failed with error %" PRIu32 "", error); return error; } else @@ -1616,7 +1631,8 @@ static UINT rdpdr_process_receive(rdpdrPlugin* rdpdr, wStream* s) break; default: - WLog_ERR(TAG, "RDPDR_CTYP_CORE unknown PacketId: 0x%04" PRIX16 "", packetId); + WLog_Print(rdpdr->log, WLOG_ERROR, + "RDPDR_CTYP_CORE unknown PacketId: 0x%04" PRIX16 "", packetId); error = ERROR_INVALID_DATA; break; } @@ -1627,9 +1643,10 @@ static UINT rdpdr_process_receive(rdpdrPlugin* rdpdr, wStream* s) if (error != CHANNEL_RC_OK) { - WLog_ERR(TAG, - "Unknown message: Component: 0x%04" PRIX16 " PacketId: 0x%04" PRIX16 "", - component, packetId); + WLog_Print(rdpdr->log, WLOG_ERROR, + "Unknown message: Component: [0x%04" PRIX16 "] PacketId: [0x%04" PRIX16 + "]", + component, packetId); } } } @@ -1669,8 +1686,8 @@ UINT rdpdr_send(rdpdrPlugin* rdpdr, wStream* s) if (status != CHANNEL_RC_OK) { Stream_Free(s, TRUE); - WLog_ERR(TAG, "pVirtualChannelWriteEx failed with %s [%08" PRIX32 "]", - WTSErrorToString(status), status); + WLog_Print(rdpdr->log, WLOG_ERROR, "pVirtualChannelWriteEx failed with %s [%08" PRIX32 "]", + WTSErrorToString(status), status); } return status; @@ -1707,7 +1724,7 @@ static UINT rdpdr_virtual_channel_event_data_received(rdpdrPlugin* rdpdr, void* if (!rdpdr->data_in) { - WLog_ERR(TAG, "Stream_New failed!"); + WLog_Print(rdpdr->log, WLOG_ERROR, "Stream_New failed!"); return CHANNEL_RC_NO_MEMORY; } } @@ -1716,7 +1733,7 @@ static UINT rdpdr_virtual_channel_event_data_received(rdpdrPlugin* rdpdr, void* if (!Stream_EnsureRemainingCapacity(data_in, dataLength)) { - WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!"); + WLog_Print(rdpdr->log, WLOG_ERROR, "Stream_EnsureRemainingCapacity failed!"); return ERROR_INVALID_DATA; } @@ -1726,7 +1743,8 @@ static UINT rdpdr_virtual_channel_event_data_received(rdpdrPlugin* rdpdr, void* { if (Stream_Capacity(data_in) != Stream_GetPosition(data_in)) { - WLog_ERR(TAG, "rdpdr_virtual_channel_event_data_received: read error"); + WLog_Print(rdpdr->log, WLOG_ERROR, + "rdpdr_virtual_channel_event_data_received: read error"); return ERROR_INTERNAL_ERROR; } @@ -1736,7 +1754,7 @@ static UINT rdpdr_virtual_channel_event_data_received(rdpdrPlugin* rdpdr, void* if (!MessageQueue_Post(rdpdr->queue, NULL, 0, (void*)data_in, NULL)) { - WLog_ERR(TAG, "MessageQueue_Post failed!"); + WLog_Print(rdpdr->log, WLOG_ERROR, "MessageQueue_Post failed!"); return ERROR_INTERNAL_ERROR; } } @@ -1757,14 +1775,15 @@ static VOID VCAPITYPE rdpdr_virtual_channel_open_event_ex(LPVOID lpUserParam, DW case CHANNEL_EVENT_DATA_RECEIVED: if (!rdpdr || !pData || (rdpdr->OpenHandle != openHandle)) { - WLog_ERR(TAG, "error no match"); + WLog_Print(rdpdr->log, WLOG_ERROR, "error no match"); return; } if ((error = rdpdr_virtual_channel_event_data_received(rdpdr, pData, dataLength, totalLength, dataFlags))) - WLog_ERR(TAG, - "rdpdr_virtual_channel_event_data_received failed with error %" PRIu32 "!", - error); + WLog_Print(rdpdr->log, WLOG_ERROR, + "rdpdr_virtual_channel_event_data_received failed with error %" PRIu32 + "!", + error); break; @@ -1802,7 +1821,8 @@ static DWORD WINAPI rdpdr_virtual_channel_client_thread(LPVOID arg) if ((error = rdpdr_process_connect(rdpdr))) { - WLog_ERR(TAG, "rdpdr_process_connect failed with error %" PRIu32 "!", error); + WLog_Print(rdpdr->log, WLOG_ERROR, "rdpdr_process_connect failed with error %" PRIu32 "!", + error); if (rdpdr->rdpcontext) setChannelError(rdpdr->rdpcontext, error, @@ -1828,7 +1848,8 @@ static DWORD WINAPI rdpdr_virtual_channel_client_thread(LPVOID arg) if ((error = rdpdr_process_receive(rdpdr, data))) { - WLog_ERR(TAG, "rdpdr_process_receive failed with error %" PRIu32 "!", error); + WLog_Print(rdpdr->log, WLOG_ERROR, + "rdpdr_process_receive failed with error %" PRIu32 "!", error); if (rdpdr->rdpcontext) setChannelError(rdpdr->rdpcontext, error, @@ -1866,8 +1887,8 @@ static UINT rdpdr_virtual_channel_event_connected(rdpdrPlugin* rdpdr, LPVOID pDa if (status != CHANNEL_RC_OK) { - WLog_ERR(TAG, "pVirtualChannelOpenEx failed with %s [%08" PRIX32 "]", - WTSErrorToString(status), status); + WLog_Print(rdpdr->log, WLOG_ERROR, "pVirtualChannelOpenEx failed with %s [%08" PRIX32 "]", + WTSErrorToString(status), status); return status; } @@ -1875,7 +1896,7 @@ static UINT rdpdr_virtual_channel_event_connected(rdpdrPlugin* rdpdr, LPVOID pDa if (!rdpdr->queue) { - WLog_ERR(TAG, "MessageQueue_New failed!"); + WLog_Print(rdpdr->log, WLOG_ERROR, "MessageQueue_New failed!"); return CHANNEL_RC_NO_MEMORY; } @@ -1884,7 +1905,7 @@ static UINT rdpdr_virtual_channel_event_connected(rdpdrPlugin* rdpdr, LPVOID pDa if (!(rdpdr->thread = CreateThread(NULL, 0, rdpdr_virtual_channel_client_thread, (void*)rdpdr, 0, NULL))) { - WLog_ERR(TAG, "CreateThread failed!"); + WLog_Print(rdpdr->log, WLOG_ERROR, "CreateThread failed!"); return ERROR_INTERNAL_ERROR; } @@ -1907,7 +1928,8 @@ static UINT rdpdr_virtual_channel_event_disconnected(rdpdrPlugin* rdpdr) (WaitForSingleObject(rdpdr->thread, INFINITE) == WAIT_FAILED)) { error = GetLastError(); - WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "!", error); + WLog_Print(rdpdr->log, WLOG_ERROR, "WaitForSingleObject failed with error %" PRIu32 "!", + error); return error; } @@ -1918,7 +1940,8 @@ static UINT rdpdr_virtual_channel_event_disconnected(rdpdrPlugin* rdpdr) if ((error = drive_hotplug_thread_terminate(rdpdr))) { - WLog_ERR(TAG, "drive_hotplug_thread_terminate failed with error %" PRIu32 "!", error); + WLog_Print(rdpdr->log, WLOG_ERROR, + "drive_hotplug_thread_terminate failed with error %" PRIu32 "!", error); return error; } @@ -1926,8 +1949,8 @@ static UINT rdpdr_virtual_channel_event_disconnected(rdpdrPlugin* rdpdr) if (CHANNEL_RC_OK != error) { - WLog_ERR(TAG, "pVirtualChannelCloseEx failed with %s [%08" PRIX32 "]", - WTSErrorToString(error), error); + WLog_Print(rdpdr->log, WLOG_ERROR, "pVirtualChannelCloseEx failed with %s [%08" PRIX32 "]", + WTSErrorToString(error), error); } rdpdr->OpenHandle = 0; @@ -1961,7 +1984,7 @@ static VOID VCAPITYPE rdpdr_virtual_channel_init_event_ex(LPVOID lpUserParam, LP if (!rdpdr || (rdpdr->InitHandle != pInitHandle)) { - WLog_ERR(TAG, "error no match"); + WLog_Print(rdpdr->log, WLOG_ERROR, "error no match"); return; } @@ -1972,17 +1995,18 @@ static VOID VCAPITYPE rdpdr_virtual_channel_init_event_ex(LPVOID lpUserParam, LP case CHANNEL_EVENT_CONNECTED: if ((error = rdpdr_virtual_channel_event_connected(rdpdr, pData, dataLength))) - WLog_ERR(TAG, - "rdpdr_virtual_channel_event_connected failed with error %" PRIu32 "!", - error); + WLog_Print(rdpdr->log, WLOG_ERROR, + "rdpdr_virtual_channel_event_connected failed with error %" PRIu32 "!", + error); break; case CHANNEL_EVENT_DISCONNECTED: if ((error = rdpdr_virtual_channel_event_disconnected(rdpdr))) - WLog_ERR(TAG, - "rdpdr_virtual_channel_event_disconnected failed with error %" PRIu32 "!", - error); + WLog_Print(rdpdr->log, WLOG_ERROR, + "rdpdr_virtual_channel_event_disconnected failed with error %" PRIu32 + "!", + error); break; @@ -1993,7 +2017,7 @@ static VOID VCAPITYPE rdpdr_virtual_channel_init_event_ex(LPVOID lpUserParam, LP case CHANNEL_EVENT_ATTACHED: case CHANNEL_EVENT_DETACHED: default: - WLog_ERR(TAG, "unknown event %" PRIu32 "!", event); + WLog_Print(rdpdr->log, WLOG_ERROR, "unknown event %" PRIu32 "!", event); break; } @@ -2003,6 +2027,7 @@ static VOID VCAPITYPE rdpdr_virtual_channel_init_event_ex(LPVOID lpUserParam, LP } /* rdpdr is always built-in */ +#define TAG CHANNELS_TAG("rdpdr.client") #define VirtualChannelEntryEx rdpdr_VirtualChannelEntryEx BOOL VCAPITYPE VirtualChannelEntryEx(PCHANNEL_ENTRY_POINTS pEntryPoints, PVOID pInitHandle) @@ -2014,9 +2039,11 @@ BOOL VCAPITYPE VirtualChannelEntryEx(PCHANNEL_ENTRY_POINTS pEntryPoints, PVOID p if (!rdpdr) { - WLog_ERR(TAG, "calloc failed!"); + WLog_Print(rdpdr->log, WLOG_ERROR, "calloc failed!"); return FALSE; } + rdpdr->log = WLog_Get(TAG); + WINPR_ASSERT(rdpdr->log); rdpdr->channelDef.options = CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_ENCRYPT_RDP | CHANNEL_OPTION_COMPRESS_RDP; @@ -2038,8 +2065,8 @@ BOOL VCAPITYPE VirtualChannelEntryEx(PCHANNEL_ENTRY_POINTS pEntryPoints, PVOID p if (CHANNEL_RC_OK != rc) { - WLog_ERR(TAG, "pVirtualChannelInitEx failed with %s [%08" PRIX32 "]", WTSErrorToString(rc), - rc); + WLog_Print(rdpdr->log, WLOG_ERROR, "pVirtualChannelInitEx failed with %s [%08" PRIX32 "]", + WTSErrorToString(rc), rc); free(rdpdr); return FALSE; } diff --git a/channels/rdpdr/client/rdpdr_main.h b/channels/rdpdr/client/rdpdr_main.h index b27f1c29d148..37ffb5f290de 100644 --- a/channels/rdpdr/client/rdpdr_main.h +++ b/channels/rdpdr/client/rdpdr_main.h @@ -42,7 +42,11 @@ #include #endif -#define TAG CHANNELS_TAG("rdpdr.client") +#if !defined(Stream_CheckAndLogRequiredLengthWLog) +#define Stream_CheckAndLogRequiredLengthWLog(log, s, len) \ + Stream_CheckAndLogRequiredLengthWLogEx(log, WLOG_WARN, s, len, "%s(%s:%d)", __FUNCTION__, \ + __FILE__, __LINE__) +#endif typedef struct rdpdr_plugin rdpdrPlugin; @@ -92,6 +96,7 @@ struct rdpdr_plugin HANDLE stopEvent; #endif rdpContext* rdpcontext; + wLog* log; }; BOOL rdpdr_state_advance(rdpdrPlugin* rdpdr, enum RDPDR_CHANNEL_STATE next); From c3a523823dadf389fddb549afcf8c3e22442b8b7 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Fri, 2 Jun 2023 14:24:43 +0200 Subject: [PATCH 359/496] changelog --- ChangeLog | 1 + 1 file changed, 1 insertion(+) diff --git a/ChangeLog b/ChangeLog index 50b291962079..8f9ccef0a767 100644 --- a/ChangeLog +++ b/ChangeLog @@ -5,6 +5,7 @@ Fixed issues: * Backported #7306: early bail from update_read_window_state_order breaks protocol * Backported #8903: rdpecam/server: Remove wrong assertion * Backported #8994: bounds checks for gdi/gfx rectangles +* Backported #9023: enforce rdpdr client side state checks # 2023-02-16 Version 2.10.0 From 37e9f98048f0d7d14ec63ffc702441365f0032f3 Mon Sep 17 00:00:00 2001 From: bolt Date: Mon, 29 Jun 2020 21:05:12 +0200 Subject: [PATCH 360/496] Add support for -grab-mouse, to prevent the client from moving the user's pointer (cherry picked from commit 03ced3d8f0fc323009bd9dd81eba510edff4ce71) --- client/common/cmdline.c | 4 ++++ client/common/cmdline.h | 1 + include/freerdp/settings.h | 4 +++- libfreerdp/cache/pointer.c | 3 +++ libfreerdp/common/settings_getters.c | 7 +++++++ libfreerdp/common/settings_str.c | 1 + libfreerdp/core/test/settings_property_lists.h | 1 + 7 files changed, 20 insertions(+), 1 deletion(-) diff --git a/client/common/cmdline.c b/client/common/cmdline.c index d2d949b71e9a..19ece39016d2 100644 --- a/client/common/cmdline.c +++ b/client/common/cmdline.c @@ -2996,6 +2996,10 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, { settings->GrabKeyboard = enable; } + CommandLineSwitchCase(arg, "grab-mouse") + { + settings->GrabMouse = enable; + } CommandLineSwitchCase(arg, "unmap-buttons") { settings->UnmapButtons = enable; diff --git a/client/common/cmdline.h b/client/common/cmdline.h index 92a86f96fa26..6ecc8c57ae43 100644 --- a/client/common/cmdline.h +++ b/client/common/cmdline.h @@ -184,6 +184,7 @@ static const COMMAND_LINE_ARGUMENT_A args[] = { { "gp", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, "Gateway password" }, { "grab-keyboard", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueTrue, NULL, -1, NULL, "Grab keyboard" }, + { "grab-mouse", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueTrue, NULL, -1, NULL, "Grab mouse" }, { "gt", COMMAND_LINE_VALUE_REQUIRED, "[rpc|http[,no-websockets]|auto[,no-websockets]]", NULL, NULL, -1, NULL, "Gateway transport type" }, { "gu", COMMAND_LINE_VALUE_REQUIRED, "[[\\]|[@]]", NULL, NULL, -1, diff --git a/include/freerdp/settings.h b/include/freerdp/settings.h index 4268efd8c153..76f1951993eb 100644 --- a/include/freerdp/settings.h +++ b/include/freerdp/settings.h @@ -730,6 +730,7 @@ typedef struct _RDPDR_PARALLEL RDPDR_PARALLEL; #define FreeRDP_PercentScreenUseWidth (1556) #define FreeRDP_PercentScreenUseHeight (1557) #define FreeRDP_DynamicResolutionUpdate (1558) +#define FreeRDP_GrabMouse (1559) #define FreeRDP_SoftwareGdi (1601) #define FreeRDP_LocalConnection (1602) #define FreeRDP_AuthenticationOnly (1603) @@ -1216,7 +1217,8 @@ struct rdp_settings ALIGN64 BOOL PercentScreenUseWidth; /* 1556 */ ALIGN64 BOOL PercentScreenUseHeight; /* 1557 */ ALIGN64 BOOL DynamicResolutionUpdate; /* 1558 */ - UINT64 padding1601[1601 - 1559]; /* 1559 */ + ALIGN64 BOOL GrabMouse; /* 1559 */ + UINT64 padding1601[1601 - 1560]; /* 1560 */ /* Miscellaneous */ ALIGN64 BOOL SoftwareGdi; /* 1601 */ diff --git a/libfreerdp/cache/pointer.c b/libfreerdp/cache/pointer.c index 010df17031e8..42acf65da58b 100644 --- a/libfreerdp/cache/pointer.c +++ b/libfreerdp/cache/pointer.c @@ -68,6 +68,9 @@ static BOOL update_pointer_position(rdpContext* context, !pointer_position) return FALSE; + if (!context->settings->GrabMouse) + return TRUE; + pointer = context->graphics->Pointer_Prototype; return IFCALLRESULT(TRUE, pointer->SetPosition, context, pointer_position->xPos, pointer_position->yPos); diff --git a/libfreerdp/common/settings_getters.c b/libfreerdp/common/settings_getters.c index 76f66460f790..8df8957c66b1 100644 --- a/libfreerdp/common/settings_getters.c +++ b/libfreerdp/common/settings_getters.c @@ -231,6 +231,9 @@ BOOL freerdp_settings_get_bool(const rdpSettings* settings, size_t id) case FreeRDP_GrabKeyboard: return settings->GrabKeyboard; + case FreeRDP_GrabMouse: + return settings->GrabMouse; + case FreeRDP_HasExtendedMouseEvent: return settings->HasExtendedMouseEvent; @@ -809,6 +812,10 @@ BOOL freerdp_settings_set_bool(rdpSettings* settings, size_t id, BOOL val) settings->GrabKeyboard = val; break; + case FreeRDP_GrabMouse: + settings->GrabMouse = val; + break; + case FreeRDP_HasExtendedMouseEvent: settings->HasExtendedMouseEvent = val; break; diff --git a/libfreerdp/common/settings_str.c b/libfreerdp/common/settings_str.c index d4e20ae821ba..6fa11c05b79a 100644 --- a/libfreerdp/common/settings_str.c +++ b/libfreerdp/common/settings_str.c @@ -87,6 +87,7 @@ static const struct settings_str_entry settings_map[] = { { FreeRDP_GfxSmallCache, 0, "FreeRDP_GfxSmallCache" }, { FreeRDP_GfxThinClient, 0, "FreeRDP_GfxThinClient" }, { FreeRDP_GrabKeyboard, 0, "FreeRDP_GrabKeyboard" }, + { FreeRDP_GrabMouse, 0, "FreeRDP_GrabMouse" }, { FreeRDP_HasExtendedMouseEvent, 0, "FreeRDP_HasExtendedMouseEvent" }, { FreeRDP_HasHorizontalWheel, 0, "FreeRDP_HasHorizontalWheel" }, { FreeRDP_HasMonitorAttributes, 0, "FreeRDP_HasMonitorAttributes" }, diff --git a/libfreerdp/core/test/settings_property_lists.h b/libfreerdp/core/test/settings_property_lists.h index 69f7bce4ba15..a85c2ffa6755 100644 --- a/libfreerdp/core/test/settings_property_lists.h +++ b/libfreerdp/core/test/settings_property_lists.h @@ -76,6 +76,7 @@ static const size_t bool_list_indices[] = { FreeRDP_GfxSmallCache, FreeRDP_GfxThinClient, FreeRDP_GrabKeyboard, + FreeRDP_GrabMouse, FreeRDP_HasExtendedMouseEvent, FreeRDP_HasHorizontalWheel, FreeRDP_HasMonitorAttributes, From 187123b0178cd5f08483d852e97db04938695667 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Mon, 26 Jun 2023 15:59:21 +0200 Subject: [PATCH 361/496] [client,x11] restrict pointer move to active window (cherry picked from commit a8cbe439f4999e4946bca14396569d640a69e692) --- client/X11/xf_graphics.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/X11/xf_graphics.c b/client/X11/xf_graphics.c index 82b0b95b37ac..5e51d5e85bc6 100644 --- a/client/X11/xf_graphics.c +++ b/client/X11/xf_graphics.c @@ -560,7 +560,7 @@ static BOOL xf_Pointer_SetPosition(rdpContext* context, UINT32 x, UINT32 y) } WLog_DBG(TAG, "%s: %" PRIu32 "x%" PRIu32, __func__, x, y); - if (xfc->remote_app && !xfc->focused) + if (!xfc->focused) return TRUE; xf_adjust_coordinates_to_screen(xfc, &x, &y); @@ -583,7 +583,7 @@ static BOOL xf_Pointer_SetPosition(rdpContext* context, UINT32 x, UINT32 y) goto out; } - rc = XWarpPointer(xfc->display, None, handle, 0, 0, 0, 0, x, y); + rc = XWarpPointer(xfc->display, handle, handle, 0, 0, 0, 0, x, y); if (rc == 0) WLog_WARN(TAG, "%s: XWarpPointer==%d", __func__, rc); tmp.event_mask = current.your_event_mask; From 357d0c832163a01f282c67a587434a402eaef9d2 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Mon, 26 Jun 2023 16:06:27 +0200 Subject: [PATCH 362/496] changelog --- ChangeLog | 1 + 1 file changed, 1 insertion(+) diff --git a/ChangeLog b/ChangeLog index 8f9ccef0a767..93e9514a6ec7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -6,6 +6,7 @@ Fixed issues: * Backported #8903: rdpecam/server: Remove wrong assertion * Backported #8994: bounds checks for gdi/gfx rectangles * Backported #9023: enforce rdpdr client side state checks +* Backported #6331: deactivate mouse grabbing by default # 2023-02-16 Version 2.10.0 From 6784527e49bf7a5ed1a635a374621299791e624f Mon Sep 17 00:00:00 2001 From: linsui <36977733+linsui@users.noreply.github.com> Date: Sat, 8 Jul 2023 10:42:11 +0000 Subject: [PATCH 363/496] fix ffmpeg source tarball url --- scripts/android-build-ffmpeg.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/android-build-ffmpeg.sh b/scripts/android-build-ffmpeg.sh index 4233ca0c552e..206e728c1023 100755 --- a/scripts/android-build-ffmpeg.sh +++ b/scripts/android-build-ffmpeg.sh @@ -1,6 +1,6 @@ #!/bin/bash -SCM_URL=https://github.com/FFmpeg/FFmpeg +SCM_URL=https://github.com/FFmpeg/FFmpeg/archive SCM_TAG=n4.4.1 SCM_HASH=82b43cc67296bcd01a59ae6b327cdb50121d3a9e35f41a30de1edd71bb4a6666 From c20a322935ef57b31ab74c940d27aae9b9071d2b Mon Sep 17 00:00:00 2001 From: Pascal Nowack Date: Wed, 19 Jul 2023 17:07:34 +0200 Subject: [PATCH 364/496] channels/cliprdr: Fix writing incorrect PDU type for unlock PDUs --- channels/cliprdr/cliprdr_common.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/channels/cliprdr/cliprdr_common.c b/channels/cliprdr/cliprdr_common.c index 69157adaaca2..8472fdeb197b 100644 --- a/channels/cliprdr/cliprdr_common.c +++ b/channels/cliprdr/cliprdr_common.c @@ -138,7 +138,7 @@ cliprdr_packet_unlock_clipdata_new(const CLIPRDR_UNLOCK_CLIPBOARD_DATA* unlockCl if (!unlockClipboardData) return NULL; - s = cliprdr_packet_new(CB_LOCK_CLIPDATA, 0, 4); + s = cliprdr_packet_new(CB_UNLOCK_CLIPDATA, 0, 4); if (!s) return NULL; From 2a72946d18d813daffa574b26c686c3df479a447 Mon Sep 17 00:00:00 2001 From: Pascal Nowack Date: Fri, 21 Jul 2023 11:26:24 +0200 Subject: [PATCH 365/496] Update changelog --- ChangeLog | 1 + 1 file changed, 1 insertion(+) diff --git a/ChangeLog b/ChangeLog index 93e9514a6ec7..b41bee0e12d6 100644 --- a/ChangeLog +++ b/ChangeLog @@ -7,6 +7,7 @@ Fixed issues: * Backported #8994: bounds checks for gdi/gfx rectangles * Backported #9023: enforce rdpdr client side state checks * Backported #6331: deactivate mouse grabbing by default +* Cherry-pick out of #9172: channels/cliprdr: Fix writing incorrect PDU type for unlock PDUs # 2023-02-16 Version 2.10.0 From 7ece410ce5b5660b9191e1ccb6835158afa11822 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Fri, 4 Aug 2023 13:55:40 +0200 Subject: [PATCH 366/496] [codec,rfx] fix possible out of bound read Allows malicious servers to crash FreeRDP based clients reported by @pwn2carr (cherry picked from commit a51952882f2eb3bbce6b69a7a4f9a54bf1dbb672) --- libfreerdp/codec/rfx.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/libfreerdp/codec/rfx.c b/libfreerdp/codec/rfx.c index b41c15794daa..6cd267203a73 100644 --- a/libfreerdp/codec/rfx.c +++ b/libfreerdp/codec/rfx.c @@ -1109,8 +1109,18 @@ BOOL rfx_process_message(RFX_CONTEXT* context, const BYTE* data, UINT32 length, } } - Stream_StaticInit(&subStream, Stream_Pointer(s), blockLen - (6 + extraBlockLen)); - Stream_Seek(s, blockLen - (6 + extraBlockLen)); + const size_t blockLenNoHeader = blockLen - 6; + if (blockLenNoHeader < extraBlockLen) + { + WLog_Print(context->priv->log, WLOG_ERROR, + "blockLen too small(%" PRIu32 "), must be >= 6 + %" PRIu16, blockLen, + extraBlockLen); + return FALSE; + } + + const size_t subStreamLen = blockLenNoHeader - extraBlockLen; + Stream_StaticInit(&subStream, Stream_Pointer(s), subStreamLen); + Stream_Seek(s, subStreamLen); switch (blockType) { From 82ac0164f330c08ddd9a6ef6f3dbf846c4b79def Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Sat, 5 Aug 2023 10:53:29 +0200 Subject: [PATCH 367/496] [codec,nsc] fix missing plane length check reported by @pwn2carr (cherry picked from commit 89cd622426b3fcac64b9203e69f9f407cc19760e) --- libfreerdp/codec/nsc.c | 71 +++++++++++++++++++++--------------------- 1 file changed, 36 insertions(+), 35 deletions(-) diff --git a/libfreerdp/codec/nsc.c b/libfreerdp/codec/nsc.c index dc3a978ed243..66aa275f1434 100644 --- a/libfreerdp/codec/nsc.c +++ b/libfreerdp/codec/nsc.c @@ -29,6 +29,8 @@ #include #include +#include +#include #include #include @@ -38,6 +40,12 @@ #include "nsc_sse2.h" +#if !defined(Stream_CheckAndLogRequiredLengthWLog) +#define Stream_CheckAndLogRequiredLengthWLog(log, s, len) \ + Stream_CheckAndLogRequiredLengthWLogEx(log, WLOG_WARN, s, len, "%s(%s:%d)", __FUNCTION__, \ + __FILE__, __LINE__) +#endif + #ifndef NSC_INIT_SIMD #define NSC_INIT_SIMD(_nsc_context) \ do \ @@ -175,20 +183,16 @@ static BOOL nsc_rle_decode(BYTE* in, BYTE* out, UINT32 outSize, UINT32 originalS static BOOL nsc_rle_decompress_data(NSC_CONTEXT* context) { - UINT16 i; - BYTE* rle; - UINT32 planeSize; - UINT32 originalSize; - if (!context) return FALSE; - rle = context->Planes; + BYTE* rle = context->Planes; + WINPR_ASSERT(rle); - for (i = 0; i < 4; i++) + for (size_t i = 0; i < 4; i++) { - originalSize = context->OrgByteCount[i]; - planeSize = context->PlaneByteCount[i]; + const UINT32 originalSize = context->OrgByteCount[i]; + const UINT32 planeSize = context->PlaneByteCount[i]; if (planeSize == 0) { @@ -219,64 +223,63 @@ static BOOL nsc_rle_decompress_data(NSC_CONTEXT* context) static BOOL nsc_stream_initialize(NSC_CONTEXT* context, wStream* s) { - int i; - - if (Stream_GetRemainingLength(s) < 20) + WINPR_ASSERT(context); + WINPR_ASSERT(context->priv); + if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 20)) return FALSE; - for (i = 0; i < 4; i++) + size_t total = 0; + for (size_t i = 0; i < 4; i++) + { Stream_Read_UINT32(s, context->PlaneByteCount[i]); + total += context->PlaneByteCount[i]; + } Stream_Read_UINT8(s, context->ColorLossLevel); /* ColorLossLevel (1 byte) */ Stream_Read_UINT8(s, context->ChromaSubsamplingLevel); /* ChromaSubsamplingLevel (1 byte) */ Stream_Seek(s, 2); /* Reserved (2 bytes) */ context->Planes = Stream_Pointer(s); - return TRUE; + return Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, total); } static BOOL nsc_context_initialize(NSC_CONTEXT* context, wStream* s) { - int i; - UINT32 length; - UINT32 tempWidth; - UINT32 tempHeight; - if (!nsc_stream_initialize(context, s)) return FALSE; - length = context->width * context->height * 4; + const size_t blength = context->width * context->height * 4; if (!context->BitmapData) { - context->BitmapData = calloc(1, length + 16); + context->BitmapData = calloc(1, blength + 16); if (!context->BitmapData) return FALSE; - context->BitmapDataLength = length; + context->BitmapDataLength = blength; } - else if (length > context->BitmapDataLength) + else if (blength > context->BitmapDataLength) { void* tmp; - tmp = realloc(context->BitmapData, length + 16); + tmp = realloc(context->BitmapData, blength + 16); if (!tmp) return FALSE; context->BitmapData = tmp; - context->BitmapDataLength = length; + context->BitmapDataLength = blength; } - tempWidth = ROUND_UP_TO(context->width, 8); - tempHeight = ROUND_UP_TO(context->height, 2); + const UINT32 tempWidth = ROUND_UP_TO(context->width, 8); + const UINT32 tempHeight = ROUND_UP_TO(context->height, 2); /* The maximum length a decoded plane can reach in all cases */ - length = tempWidth * tempHeight; + const size_t plength = tempWidth * tempHeight; - if (length > context->priv->PlaneBuffersLength) + if (plength > context->priv->PlaneBuffersLength) { - for (i = 0; i < 4; i++) + for (size_t i = 0; i < 4; i++) { - void* tmp = (BYTE*)realloc(context->priv->PlaneBuffers[i], length); + void* tmp = (BYTE*)realloc(context->priv->PlaneBuffers[i], plength); if (!tmp) return FALSE; @@ -284,13 +287,11 @@ static BOOL nsc_context_initialize(NSC_CONTEXT* context, wStream* s) context->priv->PlaneBuffers[i] = tmp; } - context->priv->PlaneBuffersLength = length; + context->priv->PlaneBuffersLength = plength; } - for (i = 0; i < 4; i++) - { + for (size_t i = 0; i < 4; i++) context->OrgByteCount[i] = context->width * context->height; - } if (context->ChromaSubsamplingLevel) { From 99e243cdbc31f66b5c917452c8fed3276e8bdcd5 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Sat, 5 Aug 2023 09:29:19 +0200 Subject: [PATCH 368/496] [codec,rfx] free content of currentMessage on fail (cherry picked from commit e17ee48065d1ebcf863e8d0421cd656c4ef04d41) --- libfreerdp/codec/rfx.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/libfreerdp/codec/rfx.c b/libfreerdp/codec/rfx.c index 6cd267203a73..13d48c24f329 100644 --- a/libfreerdp/codec/rfx.c +++ b/libfreerdp/codec/rfx.c @@ -1241,6 +1241,11 @@ BOOL rfx_process_message(RFX_CONTEXT* context, const BYTE* data, UINT32 length, region16_uninit(&clippingRects); return TRUE; } + else + { + rfx_message_free(context, message); + context->currentMessage.freeArray = TRUE; + } WLog_ERR(TAG, "%s failed", __FUNCTION__); return FALSE; From efa0567c027239b901ccdc590b9e229e0111c68b Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Sat, 5 Aug 2023 08:57:28 +0200 Subject: [PATCH 369/496] [coded,rfx] check indices are within range reported by @pwn2carr (cherry picked from commit 61e17f4707cee66ecaa7519073bae74ecf0a9af4) --- libfreerdp/codec/rfx.c | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/libfreerdp/codec/rfx.c b/libfreerdp/codec/rfx.c index 13d48c24f329..d7f0d8c65d25 100644 --- a/libfreerdp/codec/rfx.c +++ b/libfreerdp/codec/rfx.c @@ -936,6 +936,30 @@ static BOOL rfx_process_message_tileset(RFX_CONTEXT* context, RFX_MESSAGE* messa Stream_Read_UINT8(&sub, tile->quantIdxY); /* quantIdxY (1 byte) */ Stream_Read_UINT8(&sub, tile->quantIdxCb); /* quantIdxCb (1 byte) */ Stream_Read_UINT8(&sub, tile->quantIdxCr); /* quantIdxCr (1 byte) */ + if (tile->quantIdxY >= context->numQuant) + { + WLog_Print(context->priv->log, WLOG_ERROR, + "quantIdxY %" PRIu8 " >= numQuant %" PRIu8, tile->quantIdxY, + context->numQuant); + rc = FALSE; + break; + } + if (tile->quantIdxCb >= context->numQuant) + { + WLog_Print(context->priv->log, WLOG_ERROR, + "quantIdxCb %" PRIu8 " >= numQuant %" PRIu8, tile->quantIdxCb, + context->numQuant); + rc = FALSE; + break; + } + if (tile->quantIdxCr >= context->numQuant) + { + WLog_Print(context->priv->log, WLOG_ERROR, + "quantIdxCr %" PRIu8 " >= numQuant %" PRIu8, tile->quantIdxCr, + context->numQuant); + rc = FALSE; + break; + Stream_Read_UINT16(&sub, tile->xIdx); /* xIdx (2 bytes) */ Stream_Read_UINT16(&sub, tile->yIdx); /* yIdx (2 bytes) */ Stream_Read_UINT16(&sub, tile->YLen); /* YLen (2 bytes) */ From ed264b9c24bd81bafacee9d464fee809914506b5 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Fri, 4 Aug 2023 16:42:05 +0200 Subject: [PATCH 370/496] [codec,color] fix freerdp_image_fill in case width or height == 0 out of bounds write might happen. reported by @pwn2carr (cherry picked from commit 1f88e98cb6aabfa072e836294a8a91a2d0bdb2fa) --- libfreerdp/codec/color.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/libfreerdp/codec/color.c b/libfreerdp/codec/color.c index edbfcd4ed677..7b65b1d628e6 100644 --- a/libfreerdp/codec/color.c +++ b/libfreerdp/codec/color.c @@ -728,18 +728,19 @@ BOOL freerdp_image_copy(BYTE* pDstData, DWORD DstFormat, UINT32 nDstStep, UINT32 BOOL freerdp_image_fill(BYTE* pDstData, DWORD DstFormat, UINT32 nDstStep, UINT32 nXDst, UINT32 nYDst, UINT32 nWidth, UINT32 nHeight, UINT32 color) { - UINT32 x, y; + if ((nWidth == 0) || (nHeight == 0)) + return TRUE; const UINT32 bpp = GetBytesPerPixel(DstFormat); BYTE* pFirstDstLine = &pDstData[nYDst * nDstStep]; BYTE* pFirstDstLineXOffset = &pFirstDstLine[nXDst * bpp]; - for (x = 0; x < nWidth; x++) + for (UINT32 x = 0; x < nWidth; x++) { BYTE* pDst = &pFirstDstLine[(x + nXDst) * bpp]; WriteColor(pDst, DstFormat, color); } - for (y = 1; y < nHeight; y++) + for (UINT32 y = 1; y < nHeight; y++) { BYTE* pDstLine = &pDstData[(y + nYDst) * nDstStep + nXDst * bpp]; memcpy(pDstLine, pFirstDstLineXOffset, nWidth * bpp * 1ULL); From d8a1ac342ae375644c70579c33b5cf38fb43b083 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Tue, 22 Aug 2023 09:41:28 +0200 Subject: [PATCH 371/496] [warnings] fix integer multiplications Ensure the integer width for size arguments is 64bit in a multiplication. Leading 64bit constant 1ull expands width, a trailing one is ignored. (cherry picked from commit b3f0ab2814e39e0f779343c53699e7dc6c1b1c22) --- channels/rdpsnd/server/rdpsnd_main.c | 2 +- client/X11/xf_gdi.c | 2 +- client/X11/xf_gfx.c | 4 ++-- client/X11/xf_graphics.c | 4 ++-- client/X11/xf_rail.c | 4 ++-- libfreerdp/codec/clear.c | 4 ++-- libfreerdp/codec/color.c | 6 +++--- libfreerdp/codec/h264.c | 6 +++--- libfreerdp/codec/progressive.c | 2 +- libfreerdp/gdi/bitmap.c | 2 +- libfreerdp/gdi/gdi.c | 2 +- libfreerdp/gdi/gfx.c | 4 ++-- libfreerdp/gdi/graphics.c | 2 +- libfreerdp/gdi/shape.c | 2 +- libfreerdp/gdi/video.c | 2 +- libfreerdp/primitives/prim_copy.c | 4 ++-- libfreerdp/primitives/primitives.c | 2 +- uwac/libuwac/uwac-window.c | 8 ++++---- winpr/libwinpr/utils/lodepng/lodepng.c | 14 +++++++------- 19 files changed, 38 insertions(+), 38 deletions(-) diff --git a/channels/rdpsnd/server/rdpsnd_main.c b/channels/rdpsnd/server/rdpsnd_main.c index 363fac7143f3..a26c3cff51b4 100644 --- a/channels/rdpsnd/server/rdpsnd_main.c +++ b/channels/rdpsnd/server/rdpsnd_main.c @@ -523,7 +523,7 @@ static UINT rdpsnd_server_send_wave_pdu(RdpsndServerContext* context, UINT16 wTi Stream_Seek(s, 3); /* bPad */ start = Stream_GetPosition(s); src = context->priv->out_buffer; - length = context->priv->out_pending_frames * context->priv->src_bytes_per_frame * 1ULL; + length = 1ull * context->priv->out_pending_frames * context->priv->src_bytes_per_frame; if (!freerdp_dsp_encode(context->priv->dsp_context, context->src_format, src, length, s)) return ERROR_INTERNAL_ERROR; diff --git a/client/X11/xf_gdi.c b/client/X11/xf_gdi.c index 4f52853bfeef..aecd389cc2e5 100644 --- a/client/X11/xf_gdi.c +++ b/client/X11/xf_gdi.c @@ -1066,7 +1066,7 @@ static BOOL xf_gdi_surface_bits(rdpContext* context, const SURFACE_BITS_COMMAND* case RDP_CODEC_ID_NONE: pSrcData = cmd->bmp.bitmapData; format = gdi_get_pixel_format(cmd->bmp.bpp); - size = cmd->bmp.width * cmd->bmp.height * GetBytesPerPixel(format) * 1ULL; + size = 1ull * cmd->bmp.width * cmd->bmp.height * GetBytesPerPixel(format); if (size > cmd->bmp.bitmapDataLength) { WLog_ERR(TAG, "Short nocodec message: got %" PRIu32 " bytes, require %" PRIuz, diff --git a/client/X11/xf_gfx.c b/client/X11/xf_gfx.c index 97d3ad3cca6e..3863d6698cf8 100644 --- a/client/X11/xf_gfx.c +++ b/client/X11/xf_gfx.c @@ -288,7 +288,7 @@ static UINT xf_CreateSurface(RdpgfxClientContext* context, surface->gdi.scanline = surface->gdi.width * GetBytesPerPixel(surface->gdi.format); surface->gdi.scanline = x11_pad_scanline(surface->gdi.scanline, xfc->scanline_pad); - size = surface->gdi.scanline * surface->gdi.height * 1ULL; + size = 1ull * surface->gdi.scanline * surface->gdi.height; surface->gdi.data = (BYTE*)_aligned_malloc(size, 16); if (!surface->gdi.data) @@ -312,7 +312,7 @@ static UINT xf_CreateSurface(RdpgfxClientContext* context, UINT32 bytes = GetBytesPerPixel(gdi->dstFormat); surface->stageScanline = width * bytes; surface->stageScanline = x11_pad_scanline(surface->stageScanline, xfc->scanline_pad); - size = surface->stageScanline * surface->gdi.height * 1ULL; + size = 1ull * surface->stageScanline * surface->gdi.height; surface->stage = (BYTE*)_aligned_malloc(size, 16); if (!surface->stage) diff --git a/client/X11/xf_graphics.c b/client/X11/xf_graphics.c index 5e51d5e85bc6..5aa1fd48b5a3 100644 --- a/client/X11/xf_graphics.c +++ b/client/X11/xf_graphics.c @@ -311,7 +311,7 @@ static BOOL xf_Pointer_GetCursorForCurrentScale(rdpContext* context, const rdpPo ci.height = yTargetSize; ci.xhot = pointer->xPos * xscale; ci.yhot = pointer->yPos * yscale; - size = ci.height * ci.width * GetBytesPerPixel(CursorFormat) * 1ULL; + size = 1ull * ci.height * ci.width * GetBytesPerPixel(CursorFormat); if (!(ci.pixels = (XcursorPixel*)_aligned_malloc(size, 16))) { @@ -421,7 +421,7 @@ static BOOL xf_Pointer_New(rdpContext* context, rdpPointer* pointer) xpointer->nCursors = 0; xpointer->mCursors = 0; - size = pointer->height * pointer->width * GetBytesPerPixel(CursorFormat) * 1ULL; + size = 1ull * pointer->height * pointer->width * GetBytesPerPixel(CursorFormat); if (!(xpointer->cursorPixels = (XcursorPixel*)_aligned_malloc(size, 16))) goto fail; diff --git a/client/X11/xf_rail.c b/client/X11/xf_rail.c index 090f599a0462..6995bdd3e4af 100644 --- a/client/X11/xf_rail.c +++ b/client/X11/xf_rail.c @@ -544,7 +544,7 @@ static xfRailIconCache* RailIconCache_New(rdpSettings* settings) cache->numCaches = settings->RemoteAppNumIconCaches; cache->numCacheEntries = settings->RemoteAppNumIconCacheEntries; - cache->entries = calloc(cache->numCaches * cache->numCacheEntries * 1ULL, sizeof(xfRailIcon)); + cache->entries = calloc(1ull * cache->numCaches * cache->numCacheEntries, sizeof(xfRailIcon)); if (!cache->entries) { @@ -614,7 +614,7 @@ static BOOL convert_rail_icon(const ICON_INFO* iconInfo, xfRailIcon* railIcon) long* pixels; int i; int nelements; - argbPixels = calloc(iconInfo->width * iconInfo->height * 1ULL, 4); + argbPixels = calloc(1ull * iconInfo->width * iconInfo->height, 4); if (!argbPixels) goto error; diff --git a/libfreerdp/codec/clear.c b/libfreerdp/codec/clear.c index fadd98e6738a..ecf7f1ca161b 100644 --- a/libfreerdp/codec/clear.c +++ b/libfreerdp/codec/clear.c @@ -566,7 +566,7 @@ static BOOL resize_vbar_entry(CLEAR_CONTEXT* clear, CLEAR_VBAR_ENTRY* vBarEntry) const UINT32 diffSize = (vBarEntry->count - vBarEntry->size) * bpp; BYTE* tmp; vBarEntry->size = vBarEntry->count; - tmp = (BYTE*)realloc(vBarEntry->pixels, vBarEntry->count * bpp * 1ULL); + tmp = (BYTE*)realloc(vBarEntry->pixels, 1ull * vBarEntry->count * bpp); if (!tmp) { @@ -980,7 +980,7 @@ static BOOL clear_decompress_glyph_data(CLEAR_CONTEXT* clear, wStream* s, UINT32 if (glyphEntry->count > glyphEntry->size) { BYTE* tmp; - tmp = realloc(glyphEntry->pixels, glyphEntry->count * bpp * 1ULL); + tmp = realloc(glyphEntry->pixels, 1ull * glyphEntry->count * bpp); if (!tmp) { diff --git a/libfreerdp/codec/color.c b/libfreerdp/codec/color.c index 7b65b1d628e6..00919983c343 100644 --- a/libfreerdp/codec/color.c +++ b/libfreerdp/codec/color.c @@ -56,7 +56,7 @@ BYTE* freerdp_glyph_convert(UINT32 width, UINT32 height, const BYTE* data) * means of accessing individual pixels in blitting operations */ scanline = (width + 7) / 8; - dstData = (BYTE*)_aligned_malloc(width * height * 1ULL, 16); + dstData = (BYTE*)_aligned_malloc(1ull * width * height, 16); if (!dstData) return NULL; @@ -545,7 +545,7 @@ BOOL freerdp_image_copy_from_pointer_data(BYTE* pDstData, UINT32 DstFormat, UINT for (y = nYDst; y < nHeight; y++) { BYTE* pDstLine = &pDstData[y * nDstStep + nXDst * dstBytesPerPixel]; - memset(pDstLine, 0, dstBytesPerPixel * (nWidth - nXDst) * 1ULL); + memset(pDstLine, 0, 1ull * dstBytesPerPixel * (nWidth - nXDst)); } switch (xorBpp) @@ -743,7 +743,7 @@ BOOL freerdp_image_fill(BYTE* pDstData, DWORD DstFormat, UINT32 nDstStep, UINT32 for (UINT32 y = 1; y < nHeight; y++) { BYTE* pDstLine = &pDstData[(y + nYDst) * nDstStep + nXDst * bpp]; - memcpy(pDstLine, pFirstDstLineXOffset, nWidth * bpp * 1ULL); + memcpy(pDstLine, pFirstDstLineXOffset, 1ull * nWidth * bpp); } return TRUE; diff --git a/libfreerdp/codec/h264.c b/libfreerdp/codec/h264.c index 36b5a7cba8d7..3f1ddb34090f 100644 --- a/libfreerdp/codec/h264.c +++ b/libfreerdp/codec/h264.c @@ -63,9 +63,9 @@ BOOL avc420_ensure_buffer(H264_CONTEXT* h264, UINT32 stride, UINT32 width, UINT3 _aligned_free(h264->pYUVData[0]); _aligned_free(h264->pYUVData[1]); _aligned_free(h264->pYUVData[2]); - h264->pYUVData[0] = _aligned_malloc(h264->iStride[0] * height * 1ULL, 16); - h264->pYUVData[1] = _aligned_malloc(h264->iStride[1] * height * 1ULL, 16); - h264->pYUVData[2] = _aligned_malloc(h264->iStride[2] * height * 1ULL, 16); + h264->pYUVData[0] = _aligned_malloc(1ull * h264->iStride[0] * height, 16); + h264->pYUVData[1] = _aligned_malloc(1ull * h264->iStride[1] * height, 16); + h264->pYUVData[2] = _aligned_malloc(1ull * h264->iStride[2] * height, 16); if (!h264->pYUVData[0] || !h264->pYUVData[1] || !h264->pYUVData[2]) return FALSE; diff --git a/libfreerdp/codec/progressive.c b/libfreerdp/codec/progressive.c index e95db2d0adf3..d8017be78275 100644 --- a/libfreerdp/codec/progressive.c +++ b/libfreerdp/codec/progressive.c @@ -415,7 +415,7 @@ static INLINE BOOL progressive_tile_allocate(RFX_PROGRESSIVE_TILE* tile) tile->stride = 4 * tile->width; { - size_t dataLen = tile->stride * tile->height * 1ULL; + size_t dataLen = 1ull * tile->stride * tile->height; tile->data = (BYTE*)_aligned_malloc(dataLen, 16); } diff --git a/libfreerdp/gdi/bitmap.c b/libfreerdp/gdi/bitmap.c index 8fde46556b53..cac815881615 100644 --- a/libfreerdp/gdi/bitmap.c +++ b/libfreerdp/gdi/bitmap.c @@ -148,7 +148,7 @@ HGDI_BITMAP gdi_CreateCompatibleBitmap(HGDI_DC hdc, UINT32 nWidth, UINT32 nHeigh hBitmap->width = nWidth; hBitmap->height = nHeight; hBitmap->data = - _aligned_malloc(nWidth * nHeight * GetBytesPerPixel(hBitmap->format) * 1ULL, 16); + _aligned_malloc(1ull * nWidth * nHeight * GetBytesPerPixel(hBitmap->format), 16); hBitmap->free = _aligned_free; if (!hBitmap->data) diff --git a/libfreerdp/gdi/gdi.c b/libfreerdp/gdi/gdi.c index 7a51326eae5c..37a010431405 100644 --- a/libfreerdp/gdi/gdi.c +++ b/libfreerdp/gdi/gdi.c @@ -1086,7 +1086,7 @@ static BOOL gdi_surface_bits(rdpContext* context, const SURFACE_BITS_COMMAND* cm case RDP_CODEC_ID_NONE: format = gdi_get_pixel_format(cmd->bmp.bpp); - size = cmd->bmp.width * cmd->bmp.height * GetBytesPerPixel(format) * 1ULL; + size = 1ull * cmd->bmp.width * cmd->bmp.height * GetBytesPerPixel(format); if (size > cmd->bmp.bitmapDataLength) { WLog_ERR(TAG, "Short nocodec message: got %" PRIu32 " bytes, require %" PRIuz, diff --git a/libfreerdp/gdi/gfx.c b/libfreerdp/gdi/gfx.c index 764f9076f1a0..3970715e0187 100644 --- a/libfreerdp/gdi/gfx.c +++ b/libfreerdp/gdi/gfx.c @@ -726,7 +726,7 @@ static UINT gdi_SurfaceCommand_Alpha(rdpGdi* gdi, RdpgfxClientContext* context, { UINT32 x, y; - if (Stream_GetRemainingLength(&s) < cmd->height * cmd->width * 1ULL) + if (Stream_GetRemainingLength(&s) < 1ull * cmd->height * cmd->width) return ERROR_INVALID_DATA; for (y = cmd->top; y < cmd->top + cmd->height; y++) @@ -1025,7 +1025,7 @@ static UINT gdi_CreateSurface(RdpgfxClientContext* context, } surface->scanline = gfx_align_scanline(surface->width * 4UL, 16); - surface->data = (BYTE*)_aligned_malloc(surface->scanline * surface->height * 1ULL, 16); + surface->data = (BYTE*)_aligned_malloc(1ull * surface->scanline * surface->height, 16); if (!surface->data) { diff --git a/libfreerdp/gdi/graphics.c b/libfreerdp/gdi/graphics.c index c8b5fc9132a3..479eac9b83f3 100644 --- a/libfreerdp/gdi/graphics.c +++ b/libfreerdp/gdi/graphics.c @@ -52,7 +52,7 @@ HGDI_BITMAP gdi_create_bitmap(rdpGdi* gdi, UINT32 nWidth, UINT32 nHeight, UINT32 return NULL; nDstStep = nWidth * GetBytesPerPixel(gdi->dstFormat); - pDstData = _aligned_malloc(nHeight * nDstStep * 1ULL, 16); + pDstData = _aligned_malloc(1ull * nHeight * nDstStep, 16); if (!pDstData) return NULL; diff --git a/libfreerdp/gdi/shape.c b/libfreerdp/gdi/shape.c index 6c45e0c92b0b..51a8a36dd251 100644 --- a/libfreerdp/gdi/shape.c +++ b/libfreerdp/gdi/shape.c @@ -158,7 +158,7 @@ BOOL gdi_FillRect(HGDI_DC hdc, const HGDI_RECT rect, HGDI_BRUSH hbr) for (y = 1; y < nHeight; y++) { BYTE* dstp = gdi_get_bitmap_pointer(hdc, nXDest, nYDest + y); - memcpy(dstp, srcp, nWidth * formatSize * 1ULL); + memcpy(dstp, srcp, 1ull * nWidth * formatSize); } break; diff --git a/libfreerdp/gdi/video.c b/libfreerdp/gdi/video.c index 0e12c52e7a6f..8c74f0ae3674 100644 --- a/libfreerdp/gdi/video.c +++ b/libfreerdp/gdi/video.c @@ -66,7 +66,7 @@ static VideoSurface* gdiVideoCreateSurface(VideoClientContext* video, BYTE* data ret->base.w = width; ret->base.h = height; ret->scanline = width * bpp; - ret->image = _aligned_malloc(ret->scanline * height * 1ULL, 16); + ret->image = _aligned_malloc(1ull * ret->scanline * height, 16); if (!ret->image) { diff --git a/libfreerdp/primitives/prim_copy.c b/libfreerdp/primitives/prim_copy.c index ae841d0c478f..30c9cb15ed90 100644 --- a/libfreerdp/primitives/prim_copy.c +++ b/libfreerdp/primitives/prim_copy.c @@ -60,14 +60,14 @@ static BOOL memory_regions_overlap_2d(const BYTE* p1, int p1Step, int p1Size, co if (p1m <= p2m) { - ULONG_PTR p1mEnd = p1m + (height - 1) * p1Step * 1ULL + width * p1Size * 1ULL; + ULONG_PTR p1mEnd = p1m + 1ull * (height - 1) * p1Step + 1ull * width * p1Size; if (p1mEnd > p2m) return TRUE; } else { - ULONG_PTR p2mEnd = p2m + (height - 1) * p2Step * 1ULL + width * p2Size * 1ULL; + ULONG_PTR p2mEnd = p2m + 1ull * (height - 1) * p2Step + 1ull * width * p2Size; if (p2mEnd > p1m) return TRUE; diff --git a/libfreerdp/primitives/primitives.c b/libfreerdp/primitives/primitives.c index 0a4303d9f051..6820a5822336 100644 --- a/libfreerdp/primitives/primitives.c +++ b/libfreerdp/primitives/primitives.c @@ -157,7 +157,7 @@ static primitives_YUV_benchmark* primitives_YUV_benchmark_init(primitives_YUV_be if (!buf) goto fail; - winpr_RAND(buf, roi->width * roi->height * 1ULL); + winpr_RAND(buf, 1ull * roi->width * roi->height); ret->steps[i] = roi->width; } diff --git a/uwac/libuwac/uwac-window.c b/uwac/libuwac/uwac-window.c index d503755740e3..c1e2b798378a 100644 --- a/uwac/libuwac/uwac-window.c +++ b/uwac/libuwac/uwac-window.c @@ -320,14 +320,14 @@ int UwacWindowShmAllocBuffers(UwacWindow* w, int nbuffers, int allocSize, uint32 w->buffers = newBuffers; memset(w->buffers + w->nbuffers, 0, sizeof(UwacBuffer) * nbuffers); - fd = uwac_create_anonymous_file(allocSize * nbuffers * 1ULL); + fd = uwac_create_anonymous_file(1ull * allocSize * nbuffers); if (fd < 0) { return UWAC_ERROR_INTERNAL; } - data = mmap(NULL, allocSize * nbuffers * 1ULL, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + data = mmap(NULL, 1ull * allocSize * nbuffers, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); if (data == MAP_FAILED) { @@ -339,7 +339,7 @@ int UwacWindowShmAllocBuffers(UwacWindow* w, int nbuffers, int allocSize, uint32 if (!pool) { - munmap(data, allocSize * nbuffers * 1ULL); + munmap(data, 1ull * allocSize * nbuffers); ret = UWAC_ERROR_NOMEMORY; goto error_mmap; } @@ -764,7 +764,7 @@ UwacReturnCode UwacWindowSubmitBuffer(UwacWindow* window, bool copyContentForNex if (copyContentForNextFrame) memcpy(nextDrawingBuffer->data, pendingBuffer->data, - window->stride * window->height * 1ULL); + 1ull * window->stride * window->height); UwacSubmitBufferPtr(window, pendingBuffer); return UWAC_SUCCESS; diff --git a/winpr/libwinpr/utils/lodepng/lodepng.c b/winpr/libwinpr/utils/lodepng/lodepng.c index 2dd526a2cdc9..b5c23073eeb2 100644 --- a/winpr/libwinpr/utils/lodepng/lodepng.c +++ b/winpr/libwinpr/utils/lodepng/lodepng.c @@ -3815,7 +3815,7 @@ unsigned lodepng_convert(unsigned char* out, const unsigned char* in, LodePNGCol { size_t i; ColorTree tree; - size_t numpixels = w * h * 1ULL; + size_t numpixels = 1ull * w * h; if (lodepng_color_mode_equal(mode_out, mode_in)) { @@ -3918,7 +3918,7 @@ unsigned get_color_profile(LodePNGColorProfile* profile, const unsigned char* in unsigned error = 0; size_t i; ColorTree tree; - size_t numpixels = w * h * 1ULL; + size_t numpixels = 1ull * w * h; unsigned colored_done = lodepng_is_greyscale_type(mode) ? 1 : 0; unsigned alpha_done = lodepng_can_have_alpha(mode) ? 0 : 1; @@ -4539,7 +4539,7 @@ static unsigned postProcessScanlines(unsigned char* out, unsigned char* in, unsi if (bpp < 8 && w * bpp != ((w * bpp + 7) / 8) * 8) { CERROR_TRY_RETURN(unfilter(in, in, w, h, bpp)); - removePaddingBits(out, in, w * bpp * 1ULL, ((w * bpp + 7ULL) / 8ULL) * 8ULL, h); + removePaddingBits(out, in, 1ull * w * bpp, ((w * bpp + 7ULL) / 8ULL) * 8ULL, h); } /*we can immediatly filter into the out buffer, no other steps needed*/ else @@ -4565,7 +4565,7 @@ static unsigned postProcessScanlines(unsigned char* out, unsigned char* in, unsi bits between the different reduced images: each reduced image still starts nicely at a byte*/ removePaddingBits(&in[passstart[i]], &in[padded_passstart[i]], - passw[i] * bpp * 1ULL, ((passw[i] * bpp + 7ULL) / 8ULL) * 8ULL, + 1ull * passw[i] * bpp, ((passw[i] * bpp + 7ULL) / 8ULL) * 8ULL, passh[i]); } } @@ -6056,7 +6056,7 @@ static unsigned preProcessScanlines(unsigned char** out, size_t* outsize, const error = 83; /*alloc fail*/ if (!error) { - addPaddingBits(padded, in, ((w * bpp + 7ULL) / 8ULL) * 8ULL, w * bpp * 1ULL, h); + addPaddingBits(padded, in, ((w * bpp + 7ULL) / 8ULL) * 8ULL, 1ull * w * bpp, h); error = filter(*out, padded, w, h, &info_png->color, settings); } free(padded); @@ -6100,8 +6100,8 @@ static unsigned preProcessScanlines(unsigned char** out, size_t* outsize, const if (!padded) ERROR_BREAK(83); /*alloc fail*/ addPaddingBits(padded, &adam7[passstart[i]], - ((passw[i] * bpp + 7ULL) / 8ULL) * 8ULL, passw[i] * bpp * 1ULL, - passh[i] * 1ULL); + ((passw[i] * bpp + 7ULL) / 8ULL) * 8ULL, 1ull * passw[i] * bpp, + 1ull * passh[i]); error = filter(&(*out)[filter_passstart[i]], padded, passw[i], passh[i], &info_png->color, settings); free(padded); From 2596f664da354bee6782dd94635305b5c4c34f88 Mon Sep 17 00:00:00 2001 From: Bernhard Miklautz Date: Wed, 14 Dec 2022 23:34:54 +0100 Subject: [PATCH 372/496] fix [client/Mac]: ninja build Problem that caused the ninja build to fail: * `ninja: error: build.ninja:14841: bad $-escape (literal $ must be written as $$)` - because of the way CONFIGURATION was passed * missing build dependency betwenn client/Mac and client/Mac/cli (cherry picked from commit 67b96a60760a4513d218c3f2b92395fdadccae57) --- client/Mac/CMakeLists.txt | 42 ++++++++++++++++++++++++++--------- client/Mac/cli/CMakeLists.txt | 25 +++++++++++++++------ 2 files changed, 49 insertions(+), 18 deletions(-) diff --git a/client/Mac/CMakeLists.txt b/client/Mac/CMakeLists.txt index b3eb59187785..41b1db424f82 100644 --- a/client/Mac/CMakeLists.txt +++ b/client/Mac/CMakeLists.txt @@ -110,6 +110,16 @@ endforeach() set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Client/Mac") +if(CMAKE_GENERATOR MATCHES "Ninja") + if (NOT ${CONFIGURATION} STREQUAL "") + set(safe_configuration "$CONFIGURATION") + else() + set(safe_configuration "") + endif() +else() + set(safe_configuration "$(CONFIGURATION)") +endif() + if (${BUILD_SHARED_LIBS}) # Add a post-build event to copy the dependent libraries in the framework bundle # Call install_name_tool to reassign the library install name @@ -118,15 +128,15 @@ if (${BUILD_SHARED_LIBS}) add_custom_command(TARGET ${MODULE_NAME} POST_BUILD COMMAND "${CMAKE_COMMAND}" -E copy "$" - "${CMAKE_CURRENT_BINARY_DIR}/$(CONFIGURATION)/${MODULE_OUTPUT_NAME}.framework/Contents/$" + "${CMAKE_CURRENT_BINARY_DIR}/${safe_configuration}/${MODULE_OUTPUT_NAME}.framework/Contents/$" COMMENT "Copying ${LIB} to output directory" COMMAND install_name_tool -change "$" "@executable_path/../Frameworks/${MODULE_OUTPUT_NAME}.framework/Contents/$" - "${CMAKE_CURRENT_BINARY_DIR}/$(CONFIGURATION)/${MODULE_OUTPUT_NAME}.framework/${MODULE_OUTPUT_NAME}" + "${CMAKE_CURRENT_BINARY_DIR}/${safe_configuration}/${MODULE_OUTPUT_NAME}.framework/${MODULE_OUTPUT_NAME}" COMMENT Setting install name for ${LIB} COMMAND "${CMAKE_COMMAND}" -E echo install_name_tool -change "$" "@executable_path/../Frameworks/${MODULE_OUTPUT_NAME}.framework/Contents/$" - "${CMAKE_CURRENT_BINARY_DIR}/$(CONFIGURATION)/${MODULE_OUTPUT_NAME}.framework/${MODULE_OUTPUT_NAME}") + "${CMAKE_CURRENT_BINARY_DIR}/${safe_configuration}/${MODULE_OUTPUT_NAME}.framework/${MODULE_OUTPUT_NAME}") endforeach() # Call install_name_tool to reassign the library install names in dependent libraries @@ -136,7 +146,7 @@ if (${BUILD_SHARED_LIBS}) add_custom_command(TARGET ${MODULE_NAME} POST_BUILD COMMAND install_name_tool -change "$" "@executable_path/../Frameworks/${MODULE_OUTPUT_NAME}.framework/Contents/$" - "${CMAKE_CURRENT_BINARY_DIR}/$(CONFIGURATION)/${MODULE_OUTPUT_NAME}.framework/Contents/$" + "${CMAKE_CURRENT_BINARY_DIR}/${safe_configuration}/${MODULE_OUTPUT_NAME}.framework/Contents/$" COMMENT Setting install name for ${LIB} in module ${DEST}) endforeach() endforeach() @@ -144,7 +154,7 @@ if (${BUILD_SHARED_LIBS}) endif() # Add post-build NIB file generation in unix makefiles. XCode handles this implicitly. -# if("${CMAKE_GENERATOR}" MATCHES "Unix Makefiles") +# if(NOT "${CMAKE_GENERATOR}" MATCHES "Xcode") message(STATUS "Adding post-build NIB file generation event for ${MODULE_NAME}") # Make sure we can find the 'ibtool' program. If we can NOT find it we @@ -157,7 +167,7 @@ endif() # Make sure the 'Resources' Directory is correctly created before we build add_custom_command(TARGET ${MODULE_NAME} PRE_BUILD - COMMAND mkdir -p ${CMAKE_CURRENT_BINARY_DIR}/$(CONFIGURATION)/${MODULE_OUTPUT_NAME}.framework/Versions/${MACOSX_BUNDLE_SHORT_VERSION_STRING}/Resources) + COMMAND mkdir -p ${CMAKE_CURRENT_BINARY_DIR}/${safe_configuration}/${MODULE_OUTPUT_NAME}.framework/Versions/${MACOSX_BUNDLE_SHORT_VERSION_STRING}/Resources) # Compile the .xib files using the 'ibtool' program with the destination being the app package foreach(xib ${${MODULE_PREFIX}_XIBS}) @@ -165,23 +175,33 @@ endif() add_custom_command (TARGET ${MODULE_NAME} POST_BUILD COMMAND ${IBTOOL} --errors --warnings --notices --output-format human-readable-text - --compile ${CMAKE_CURRENT_BINARY_DIR}/$(CONFIGURATION)/${MODULE_OUTPUT_NAME}.framework/Versions/${MACOSX_BUNDLE_SHORT_VERSION_STRING}/Resources/${XIB_WE}.nib ${CMAKE_CURRENT_SOURCE_DIR}/${xib} + --compile ${CMAKE_CURRENT_BINARY_DIR}/${safe_configuration}/${MODULE_OUTPUT_NAME}.framework/Versions/${MACOSX_BUNDLE_SHORT_VERSION_STRING}/Resources/${XIB_WE}.nib ${CMAKE_CURRENT_SOURCE_DIR}/${xib} COMMENT "Compiling ${xib}") endforeach() # endif() +set(MAC_LIB_FRAMEWORK_HEADERS "") # Copy the public header files into the framework foreach(HEADER ${${MODULE_PREFIX}_HEADERS}) - # message("adding post-build dependency: ${LIB}") + #message("adding post-build dependency: ${MODULE_NAME} ${HEADER}") + if( POLICY CMP0058 ) + set(NinjaByproducts BYPRODUCTS ${CMAKE_CURRENT_BINARY_DIR}/${CONFIGURATION}/${MODULE_OUTPUT_NAME}.framework/Headers/${HEADER}) + endif() add_custom_command(TARGET ${MODULE_NAME} POST_BUILD - COMMAND ditto ${CMAKE_CURRENT_SOURCE_DIR}/${HEADER} ${CMAKE_CURRENT_BINARY_DIR}/$(CONFIGURATION)/${MODULE_OUTPUT_NAME}.framework/Headers/ + COMMAND ditto ${CMAKE_CURRENT_SOURCE_DIR}/${HEADER} ${CMAKE_CURRENT_BINARY_DIR}/${safe_configuration}/${MODULE_OUTPUT_NAME}.framework/Headers/ + ${NinjaByproducts} COMMENT Copying public header files to ${MODULE_NAME}) + list(APPEND MAC_LIB_FRAMEWORK_HEADERS ${CMAKE_CURRENT_BINARY_DIR}/${CONFIGURATION}/${MODULE_OUTPUT_NAME}.framework/Headers/${HEADER}) endforeach() +add_custom_target( + prepare-framework-headers + DEPENDS ${MAC_LIB_FRAMEWORK_HEADERS} +) # Copy the FreeRDP header files into the framework add_custom_command(TARGET ${MODULE_NAME} POST_BUILD - COMMAND ditto ${CMAKE_SOURCE_DIR}/include/freerdp ${CMAKE_CURRENT_BINARY_DIR}/$(CONFIGURATION)/${MODULE_OUTPUT_NAME}.framework/Headers/freerdp - COMMAND ditto ${CMAKE_SOURCE_DIR}/winpr/include/winpr ${CMAKE_CURRENT_BINARY_DIR}/$(CONFIGURATION)/${MODULE_OUTPUT_NAME}.framework/Headers/winpr + COMMAND ditto ${CMAKE_SOURCE_DIR}/include/freerdp ${CMAKE_CURRENT_BINARY_DIR}/${safe_configuration}/${MODULE_OUTPUT_NAME}.framework/Headers/freerdp + COMMAND ditto ${CMAKE_SOURCE_DIR}/winpr/include/winpr ${CMAKE_CURRENT_BINARY_DIR}/${CONFIGURATION}/${MODULE_OUTPUT_NAME}.framework/Headers/winpr COMMENT Copying FreeRDP header files to ${MODULE_NAME}) add_subdirectory(cli) diff --git a/client/Mac/cli/CMakeLists.txt b/client/Mac/cli/CMakeLists.txt index b481ab5f7563..e2822d027828 100644 --- a/client/Mac/cli/CMakeLists.txt +++ b/client/Mac/cli/CMakeLists.txt @@ -55,6 +55,7 @@ add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_RESOURCES}) set_target_properties(${MODULE_NAME} PROPERTIES OUTPUT_NAME "${MODULE_OUTPUT_NAME}") +add_dependencies(${MODULE_NAME} prepare-framework-headers) # This is necessary for the xib file part below configure_file(${CMAKE_CURRENT_SOURCE_DIR}/Info.plist ${CMAKE_CURRENT_BINARY_DIR}/Info.plist) @@ -66,9 +67,19 @@ set_target_properties(${MODULE_NAME} PROPERTIES RESOURCE "${${MODULE_PREFIX}_RES set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -F../") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -F../") +if(CMAKE_GENERATOR MATCHES "Ninja") + if (NOT ${CONFIGURATION} STREQUAL "") + set(safe_configuration "$CONFIGURATION") + else() + set(safe_configuration "") + endif() +else() + set(safe_configuration "$(CONFIGURATION)") +endif() + # Tell XCode where to look for the MacFreeRDP framework set_target_properties(${MODULE_NAME} PROPERTIES XCODE_ATTRIBUTE_FRAMEWORK_SEARCH_PATHS - "${XCODE_ATTRIBUTE_FRAMEWORK_SEARCH_PATHS} ${CMAKE_CURRENT_BINARY_DIR}/../$(CONFIGURATION)") + "${XCODE_ATTRIBUTE_FRAMEWORK_SEARCH_PATHS} ${CMAKE_CURRENT_BINARY_DIR}/../${safe_configuration}") # Set the info plist to the custom instance set_target_properties(${MODULE_NAME} PROPERTIES MACOSX_BUNDLE_INFO_PLIST ${CMAKE_CURRENT_BINARY_DIR}/Info.plist) @@ -80,15 +91,15 @@ set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Client/Mac") # Embed the FreeRDP framework into the app bundle add_custom_command(TARGET ${MODULE_NAME} POST_BUILD - COMMAND mkdir ARGS -p ${CMAKE_CURRENT_BINARY_DIR}/$(CONFIGURATION)/${MODULE_OUTPUT_NAME}.app/Contents/Frameworks - COMMAND ditto ${CMAKE_CURRENT_BINARY_DIR}/../$(CONFIGURATION)/MacFreeRDP.framework ${CMAKE_CURRENT_BINARY_DIR}/$(CONFIGURATION)/${MODULE_OUTPUT_NAME}.app/Contents/Frameworks/MacFreeRDP.framework + COMMAND mkdir ARGS -p ${CMAKE_CURRENT_BINARY_DIR}/${safe_configuration}/${MODULE_OUTPUT_NAME}.app/Contents/Frameworks + COMMAND ditto ${CMAKE_CURRENT_BINARY_DIR}/../${safe_configuration}/MacFreeRDP.framework ${CMAKE_CURRENT_BINARY_DIR}/${safe_configuration}/${MODULE_OUTPUT_NAME}.app/Contents/Frameworks/MacFreeRDP.framework COMMAND install_name_tool -change "@executable_path/../Frameworks/MacFreeRDP.framework/Versions/${MAC_OS_X_BUNDLE_BUNDLE_VERSION}/MacFreeRDP" "@executable_path/../Frameworks/MacFreeRDP.framework/Versions/Current/MacFreeRDP" - "${CMAKE_CURRENT_BINARY_DIR}/$(CONFIGURATION)/${MODULE_OUTPUT_NAME}.app/Contents/MacOS/${MODULE_NAME}" + "${CMAKE_CURRENT_BINARY_DIR}/${safe_configuration}/${MODULE_OUTPUT_NAME}.app/Contents/MacOS/${MODULE_NAME}" COMMENT Setting install name for MacFreeRDP) # Add post-build NIB file generation in unix makefiles. XCode handles this implicitly. -if("${CMAKE_GENERATOR}" MATCHES "Unix Makefiles") +if(NOT "${CMAKE_GENERATOR}" MATCHES "Xcode") message(STATUS "Adding post-build NIB file generation event for ${MODULE_NAME}") # Make sure we can find the 'ibtool' program. If we can NOT find it we skip generation of this project @@ -99,7 +110,7 @@ if("${CMAKE_GENERATOR}" MATCHES "Unix Makefiles") endif() # Make sure the 'Resources' Directory is correctly created before we build - add_custom_command(TARGET ${MODULE_NAME} PRE_BUILD COMMAND mkdir -p ${CMAKE_CURRENT_BINARY_DIR}/\${CONFIGURATION}/${MODULE_OUTPUT_NAME}.app/Contents/Resources) + add_custom_command(TARGET ${MODULE_NAME} PRE_BUILD COMMAND mkdir -p ${CMAKE_CURRENT_BINARY_DIR}/${safe_configuration}/${MODULE_OUTPUT_NAME}.app/Contents/Resources) # Compile the .xib files using the 'ibtool' program with the destination being the app package foreach(xib ${${MODULE_PREFIX}_XIBS}) @@ -107,7 +118,7 @@ if("${CMAKE_GENERATOR}" MATCHES "Unix Makefiles") add_custom_command (TARGET ${MODULE_NAME} POST_BUILD COMMAND ${IBTOOL} --errors --warnings --notices --output-format human-readable-text - --compile ${CMAKE_CURRENT_BINARY_DIR}/\${CONFIGURATION}/${MODULE_OUTPUT_NAME}.app/Contents/Resources/${XIB_WE}.nib ${CMAKE_CURRENT_SOURCE_DIR}/${xib} + --compile ${CMAKE_CURRENT_BINARY_DIR}/${safe_configuration}/${MODULE_OUTPUT_NAME}.app/Contents/Resources/${XIB_WE}.nib ${CMAKE_CURRENT_SOURCE_DIR}/${xib} COMMENT "Compiling ${xib}") endforeach() From ed231252f9b661b199097e04e35af955bb603477 Mon Sep 17 00:00:00 2001 From: Bernhard Miklautz Date: Wed, 14 Dec 2022 23:34:54 +0100 Subject: [PATCH 373/496] fix [client/Mac]: ninja build Problem that caused the ninja build to fail: * `ninja: error: build.ninja:14841: bad $-escape (literal $ must be written as $$)` - because of the way CONFIGURATION was passed * missing build dependency betwenn client/Mac and client/Mac/cli (cherry picked from commit 67b96a60760a4513d218c3f2b92395fdadccae57) --- winpr/include/winpr/wtypes.h.in | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/winpr/include/winpr/wtypes.h.in b/winpr/include/winpr/wtypes.h.in index d2648908b670..c868095b53b6 100644 --- a/winpr/include/winpr/wtypes.h.in +++ b/winpr/include/winpr/wtypes.h.in @@ -161,8 +161,9 @@ typedef void* PVOID, *LPVOID, *PVOID64, *LPVOID64; #ifndef __APPLE__ typedef __int32 BOOL; #else /* __APPLE__ */ +#include /* ensure compatibility with objc libraries */ -#if (TARGET_OS_IPHONE && __LP64__) || TARGET_OS_WATCH +#if (defined(TARGET_OS_IPHONE) && (TARGET_OS_IPHONE != 0) && defined(__LP64__)) || (defined(TARGET_OS_WATCH) && (TARGET_OS_WATCH != 0)) typedef bool BOOL; #else typedef signed char BOOL; From 636b7fc5f636e803077a2a39bd3149d385195470 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Wed, 9 Jun 2021 11:40:46 +0200 Subject: [PATCH 374/496] Renamed planar ALIGN macro to avoid name collission on osx (cherry picked from commit ea8858c705a389021a26c5cca74b90777d1e55be) --- libfreerdp/codec/planar.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/libfreerdp/codec/planar.c b/libfreerdp/codec/planar.c index e49832e1a3db..b4815a632309 100644 --- a/libfreerdp/codec/planar.c +++ b/libfreerdp/codec/planar.c @@ -33,7 +33,8 @@ #define TAG FREERDP_TAG("codec") -#define ALIGN(val, align) ((val) % (align) == 0) ? (val) : ((val) + (align) - (val) % (align)) +#define PLANAR_ALIGN(val, align) \ + ((val) % (align) == 0) ? (val) : ((val) + (align) - (val) % (align)) static INLINE UINT32 planar_invert_format(BITMAP_PLANAR_CONTEXT* planar, BOOL alpha, UINT32 DstFormat) @@ -1493,8 +1494,8 @@ BOOL freerdp_bitmap_planar_context_reset(BITMAP_PLANAR_CONTEXT* context, UINT32 return FALSE; context->bgr = FALSE; - context->maxWidth = ALIGN(width, 4); - context->maxHeight = ALIGN(height, 4); + context->maxWidth = PLANAR_ALIGN(width, 4); + context->maxHeight = PLANAR_ALIGN(height, 4); context->maxPlaneSize = context->maxWidth * context->maxHeight; context->nTempStep = context->maxWidth * 4; free(context->planesBuffer); From ad6ce58ddd2d7ceaf18bfa3d7372b6b55699bc70 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Tue, 22 Aug 2023 11:00:37 +0200 Subject: [PATCH 375/496] [cmake] backport options use CMake options for commonly used settings --- CMakeLists.txt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index cdca0a064aa1..db3dc7c9bb35 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -34,9 +34,9 @@ if(NOT DEFINED FREERDP_VENDOR) set(FREERDP_VENDOR 1) endif() -set(CMAKE_COLOR_MAKEFILE ON) - -set(CMAKE_POSITION_INDEPENDENT_CODE ON) +option(CMAKE_COLOR_MAKEFILE "colorful CMake makefile" ON) +option(CMAKE_VERBOSE_MAKEFILE "verbose CMake makefile" ON) +option(CMAKE_POSITION_INDEPENDENT_CODE "build with position independent code (-fPIC or -fPIE)" ON) # Include our extra modules set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/) @@ -225,7 +225,7 @@ endif() if(MSVC) include(MSVCRuntime) if(NOT DEFINED MSVC_RUNTIME) - set(MSVC_RUNTIME "dynamic") + set(MSVC_RUNTIME "dynamic" CACHE STRING "MSVC runtime type [dynamic|static]") endif() if(MSVC_RUNTIME STREQUAL "static") if(BUILD_SHARED_LIBS) From 9ed6d6baede27d5006e0e4c9bec8e506f695cb6a Mon Sep 17 00:00:00 2001 From: akallabeth Date: Tue, 22 Aug 2023 11:37:57 +0200 Subject: [PATCH 376/496] [codec,rfx] fix missing brace from broken backport --- libfreerdp/codec/rfx.c | 43 ++++++++++++++++++++---------------------- 1 file changed, 20 insertions(+), 23 deletions(-) diff --git a/libfreerdp/codec/rfx.c b/libfreerdp/codec/rfx.c index d7f0d8c65d25..ccbc5afe44fa 100644 --- a/libfreerdp/codec/rfx.c +++ b/libfreerdp/codec/rfx.c @@ -937,29 +937,26 @@ static BOOL rfx_process_message_tileset(RFX_CONTEXT* context, RFX_MESSAGE* messa Stream_Read_UINT8(&sub, tile->quantIdxCb); /* quantIdxCb (1 byte) */ Stream_Read_UINT8(&sub, tile->quantIdxCr); /* quantIdxCr (1 byte) */ if (tile->quantIdxY >= context->numQuant) - { - WLog_Print(context->priv->log, WLOG_ERROR, - "quantIdxY %" PRIu8 " >= numQuant %" PRIu8, tile->quantIdxY, - context->numQuant); - rc = FALSE; - break; - } - if (tile->quantIdxCb >= context->numQuant) - { - WLog_Print(context->priv->log, WLOG_ERROR, - "quantIdxCb %" PRIu8 " >= numQuant %" PRIu8, tile->quantIdxCb, - context->numQuant); - rc = FALSE; - break; - } - if (tile->quantIdxCr >= context->numQuant) - { - WLog_Print(context->priv->log, WLOG_ERROR, - "quantIdxCr %" PRIu8 " >= numQuant %" PRIu8, tile->quantIdxCr, - context->numQuant); - rc = FALSE; - break; - + { + WLog_Print(context->priv->log, WLOG_ERROR, "quantIdxY %" PRIu8 " >= numQuant %" PRIu8, + tile->quantIdxY, context->numQuant); + rc = FALSE; + break; + } + else if (tile->quantIdxCb >= context->numQuant) + { + WLog_Print(context->priv->log, WLOG_ERROR, "quantIdxCb %" PRIu8 " >= numQuant %" PRIu8, + tile->quantIdxCb, context->numQuant); + rc = FALSE; + break; + } + else if (tile->quantIdxCr >= context->numQuant) + { + WLog_Print(context->priv->log, WLOG_ERROR, "quantIdxCr %" PRIu8 " >= numQuant %" PRIu8, + tile->quantIdxCr, context->numQuant); + rc = FALSE; + break; + } Stream_Read_UINT16(&sub, tile->xIdx); /* xIdx (2 bytes) */ Stream_Read_UINT16(&sub, tile->yIdx); /* yIdx (2 bytes) */ Stream_Read_UINT16(&sub, tile->YLen); /* YLen (2 bytes) */ From 7debd1093df24ca68a35456eda7452b5dca0d04b Mon Sep 17 00:00:00 2001 From: akallabeth Date: Tue, 22 Aug 2023 12:12:45 +0200 Subject: [PATCH 377/496] [cmake] update FindOpenSSL also check OPENSSL_VERSION_STR if OPENSSL_VERSION_NUMBER fails to parse --- cmake/FindOpenSSL.cmake | 69 ++++++++++++++++++++++++++++------------- 1 file changed, 47 insertions(+), 22 deletions(-) diff --git a/cmake/FindOpenSSL.cmake b/cmake/FindOpenSSL.cmake index d42a50cde7b7..f630d1a16ec5 100644 --- a/cmake/FindOpenSSL.cmake +++ b/cmake/FindOpenSSL.cmake @@ -55,7 +55,7 @@ FIND_PATH(OPENSSL_INCLUDE_DIR NAMES openssl/ssl.h PATH_SUFFIXES - "include" + "include" HINTS ${_OPENSSL_INCLUDEDIR} ${_OPENSSL_ROOT_HINTS_AND_PATHS} @@ -172,8 +172,8 @@ ELSEIF(WIN32 AND NOT CYGWIN) ) set( OPENSSL_DEBUG_LIBRARIES ${SSL_EAY_DEBUG} ${LIB_EAY_DEBUG} ) - set( OPENSSL_RELEASE_LIBRARIES ${SSL_EAY_RELEASE} ${LIB_EAY_RELEASE} ) - set( OPENSSL_LIBRARIES ${OPENSSL_RELEASE_LIBRARIES} ) + set( OPENSSL_RELEASE_LIBRARIES ${SSL_EAY_RELEASE} ${LIB_EAY_RELEASE} ) + set( OPENSSL_LIBRARIES ${OPENSSL_RELEASE_LIBRARIES} ) MARK_AS_ADVANCED(SSL_EAY_DEBUG SSL_EAY_RELEASE) MARK_AS_ADVANCED(LIB_EAY_DEBUG LIB_EAY_RELEASE) @@ -313,25 +313,50 @@ if (OPENSSL_INCLUDE_DIR) string(REGEX REPLACE "^.*OPENSSL_VERSION_NUMBER[\t ]+0x([0-9a-fA-F])([0-9a-fA-F][0-9a-fA-F])([0-9a-fA-F][0-9a-fA-F])([0-9a-fA-F][0-9a-fA-F])([0-9a-fA-F]).*$" "\\1;\\2;\\3;\\4;\\5" OPENSSL_VERSION_LIST "${openssl_version_str}") - list(GET OPENSSL_VERSION_LIST 0 OPENSSL_VERSION_MAJOR) - list(GET OPENSSL_VERSION_LIST 1 OPENSSL_VERSION_MINOR) - from_hex("${OPENSSL_VERSION_MINOR}" OPENSSL_VERSION_MINOR) - list(GET OPENSSL_VERSION_LIST 2 OPENSSL_VERSION_FIX) - from_hex("${OPENSSL_VERSION_FIX}" OPENSSL_VERSION_FIX) - list(GET OPENSSL_VERSION_LIST 3 OPENSSL_VERSION_PATCH) - - if (NOT OPENSSL_VERSION_PATCH STREQUAL "00") - from_hex("${OPENSSL_VERSION_PATCH}" _tmp) - # 96 is the ASCII code of 'a' minus 1 - math(EXPR OPENSSL_VERSION_PATCH_ASCII "${_tmp} + 96") - unset(_tmp) - # Once anyone knows how OpenSSL would call the patch versions beyond 'z' - # this should be updated to handle that, too. This has not happened yet - # so it is simply ignored here for now. - string(ASCII "${OPENSSL_VERSION_PATCH_ASCII}" OPENSSL_VERSION_PATCH_STRING) - endif (NOT OPENSSL_VERSION_PATCH STREQUAL "00") - - set(OPENSSL_VERSION "${OPENSSL_VERSION_MAJOR}.${OPENSSL_VERSION_MINOR}.${OPENSSL_VERSION_FIX}${OPENSSL_VERSION_PATCH_STRING}") + if (OPENSSL_VERSION_LIST) + list(GET OPENSSL_VERSION_LIST 0 OPENSSL_VERSION_MAJOR) + list(GET OPENSSL_VERSION_LIST 1 OPENSSL_VERSION_MINOR) + from_hex("${OPENSSL_VERSION_MINOR}" OPENSSL_VERSION_MINOR) + list(GET OPENSSL_VERSION_LIST 2 OPENSSL_VERSION_FIX) + from_hex("${OPENSSL_VERSION_FIX}" OPENSSL_VERSION_FIX) + list(GET OPENSSL_VERSION_LIST 3 OPENSSL_VERSION_PATCH) + + if (NOT OPENSSL_VERSION_PATCH STREQUAL "00") + from_hex("${OPENSSL_VERSION_PATCH}" _tmp) + # 96 is the ASCII code of 'a' minus 1 + math(EXPR OPENSSL_VERSION_PATCH_ASCII "${_tmp} + 96") + unset(_tmp) + # Once anyone knows how OpenSSL would call the patch versions beyond 'z' + # this should be updated to handle that, too. This has not happened yet + # so it is simply ignored here for now. + string(ASCII "${OPENSSL_VERSION_PATCH_ASCII}" OPENSSL_VERSION_PATCH_STRING) + endif (NOT OPENSSL_VERSION_PATCH STREQUAL "00") + + set(OPENSSL_VERSION "${OPENSSL_VERSION_MAJOR}.${OPENSSL_VERSION_MINOR}.${OPENSSL_VERSION_FIX}${OPENSSL_VERSION_PATCH_STRING}") + endif() + + if (NOT OPENSSL_VERSION_LIST) + file(STRINGS "${OPENSSL_INCLUDE_DIR}/openssl/opensslv.h" openssl_version_str_str + REGEX "^#[\t ]*define[\t ]+OPENSSL_VERSION_STR[\t ]\"([0-9a-fA-F]+)\\.([0-9a-fA-F]+)\\.([0-9a-fA-F]+).*\".*$") + string(REGEX REPLACE "^.*OPENSSL_VERSION_STR[\t ]+\"([0-9a-fA-F]+)\\.([0-9a-fA-F]+)\\.([0-9a-fA-F]+).*\".*$" + "\\1.\\2.\\3" OPENSSL_VERSION "${openssl_version_str_str}") + endif() + + if (NOT OPENSSL_VERSION_LIST) + file(STRINGS "${OPENSSL_INCLUDE_DIR}/openssl/opensslv.h" openssl_version_major_str + REGEX "^#[\t ]*define[\t ]+OPENSSL_VERSION_MAJOR[\t ]+([0-9a-fA-F]+).*$") + string(REGEX REPLACE "^#[\t ]*define[\t ]+OPENSSL_VERSION_MAJOR[\t ]+([0-9a-fA-F]+).*$" + "\\1" OPENSSL_VERSION_MAJOR "${openssl_version_major_str}") + file(STRINGS "${OPENSSL_INCLUDE_DIR}/openssl/opensslv.h" openssl_version_minor_str + REGEX "^#[\t ]*define[\t ]+OPENSSL_VERSION_MINOR[\t ]+([0-9a-fA-F]+).*$") + string(REGEX REPLACE "^#[\t ]*define[\t ]+OPENSSL_VERSION_MINOR[\t ]+([0-9a-fA-F]+).*$" + "\\1" OPENSSL_VERSION_MINOR "${openssl_version_minor_str}") + file(STRINGS "${OPENSSL_INCLUDE_DIR}/openssl/opensslv.h" openssl_version_patch_str + REGEX "^#[\t ]*define[\t ]+OPENSSL_VERSION_PATCH[\t ]+([0-9a-fA-F]+).*$") + string(REGEX REPLACE "^#[\t ]*define[\t ]+OPENSSL_VERSION_PATCH[\t ]+([0-9a-fA-F]+).*$" + "\\1" OPENSSL_VERSION_PATCH "${openssl_version_patch_str}") + set(OPENSSL_VERSION "${OPENSSL_VERSION_MAJOR}.${OPENSSL_VERSION_MINOR}.${OPENSSL_VERSION_PATCH}") + endif() endif (_OPENSSL_VERSION) endif (OPENSSL_INCLUDE_DIR) From 0e58eb0714c0d27046ec94c6ff77a374cd65f90f Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Thu, 27 Jul 2023 18:07:10 +0200 Subject: [PATCH 378/496] [ci] add code quality preload files (cherry picked from commit 8ad6fcbb5a1407ab746e2883cadca6f324e61526) --- ci/cmake-preloads/config-qa-static.cmake | 4 ++++ ci/cmake-preloads/config-qa.cmake | 17 +++++++++++++++++ 2 files changed, 21 insertions(+) create mode 100644 ci/cmake-preloads/config-qa-static.cmake create mode 100644 ci/cmake-preloads/config-qa.cmake diff --git a/ci/cmake-preloads/config-qa-static.cmake b/ci/cmake-preloads/config-qa-static.cmake new file mode 100644 index 000000000000..f8d831475b61 --- /dev/null +++ b/ci/cmake-preloads/config-qa-static.cmake @@ -0,0 +1,4 @@ +set (WITH_SERVER ON CACHE BOOL "qa default") +set (WITH_SAMPLE ON CACHE BOOL "qa default") +set (WITH_VERBOSE_WINPR_ASSERT OFF CACHE BOOL "qa default") +set (BUILD_SHARED_LIBS OFF CACHE BOOL "qa default") diff --git a/ci/cmake-preloads/config-qa.cmake b/ci/cmake-preloads/config-qa.cmake new file mode 100644 index 000000000000..02c137239a59 --- /dev/null +++ b/ci/cmake-preloads/config-qa.cmake @@ -0,0 +1,17 @@ +set (BUILD_TESTING ON CACHE BOOL "qa default") +set (WITH_SAMPLE ON CACHE BOOL "qa default") +set (WITH_SERVER ON CACHE BOOL "qa default") +set (WITH_SHADOW ON CACHE BOOL "qa default") +set (WITH_PROXY ON CACHE BOOL "qa default") +set (WITH_PULSE ON CACHE BOOL "qa default") +set (WITH_CUPS ON CACHE BOOL "qa default") +set (WITH_PCSC ON CACHE BOOL "qa default") +set (WITH_SOXR ON CACHE BOOL "qa default") +set (WITH_SWSCALE ON CACHE BOOL "qa default") +set (WITH_DSP_FFMPEG OFF CACHE BOOL "qa default") +set (WITH_FFMPEG OFF CACHE BOOL "qa default") +set (WITH_SANITIZE_ADDRESS ON CACHE BOOL "qa default") +set (CMAKE_C_FLAGS "-Weverything" CACHE STRING "qa default") +set (CMAKE_CXX_FLAGS "-Weverything" CACHE STRING "qa default") +set (CMAKE_C_COMPILER "/usr/bin/clang-10" CACHE STRING "qa default") +set (CMAKE_CXX_COMPILER "/usr/bin/clang++-10" CACHE STRING "qa default") From a7f022cc43f334654a3c902537bdf6c0eb38c991 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Tue, 22 Aug 2023 14:12:32 +0200 Subject: [PATCH 379/496] [winpr,credui] disable tests on windows --- winpr/libwinpr/credui/CMakeLists.txt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/winpr/libwinpr/credui/CMakeLists.txt b/winpr/libwinpr/credui/CMakeLists.txt index b01be1d97ef7..886fe12ebece 100644 --- a/winpr/libwinpr/credui/CMakeLists.txt +++ b/winpr/libwinpr/credui/CMakeLists.txt @@ -19,8 +19,8 @@ winpr_module_add(credui.c) if(WIN32) winpr_library_add_public(credui) -endif() - -if(BUILD_TESTING) - add_subdirectory(test) +else() + if(BUILD_TESTING) + add_subdirectory(test) + endif() endif() From bdb3909a7713fb0b3d94c9676fe44d19de80eb4b Mon Sep 17 00:00:00 2001 From: akallabeth Date: Tue, 22 Aug 2023 10:06:15 +0200 Subject: [PATCH 380/496] [codec,nsc] ensure integer width ensure multiplication result is 64bit (cherry picked from commit adb1630d623f76b314631e338559afe4d62b24fa) --- libfreerdp/codec/nsc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libfreerdp/codec/nsc.c b/libfreerdp/codec/nsc.c index 66aa275f1434..cd65f072f000 100644 --- a/libfreerdp/codec/nsc.c +++ b/libfreerdp/codec/nsc.c @@ -247,7 +247,7 @@ static BOOL nsc_context_initialize(NSC_CONTEXT* context, wStream* s) if (!nsc_stream_initialize(context, s)) return FALSE; - const size_t blength = context->width * context->height * 4; + const size_t blength = context->width * context->height * 4ull; if (!context->BitmapData) { @@ -273,7 +273,7 @@ static BOOL nsc_context_initialize(NSC_CONTEXT* context, wStream* s) const UINT32 tempWidth = ROUND_UP_TO(context->width, 8); const UINT32 tempHeight = ROUND_UP_TO(context->height, 2); /* The maximum length a decoded plane can reach in all cases */ - const size_t plength = tempWidth * tempHeight; + const size_t plength = 1ull * tempWidth * tempHeight; if (plength > context->priv->PlaneBuffersLength) { From 23c3daeca1598393f8c93f563f7847a4d67919f1 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Tue, 22 Aug 2023 15:05:20 +0200 Subject: [PATCH 381/496] [codec,progressive] fix missing destination checks (cherry picked from commit ef7e0d60c207dae478952d795e74751d1516629d) --- libfreerdp/codec/progressive.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/libfreerdp/codec/progressive.c b/libfreerdp/codec/progressive.c index d8017be78275..a05a3341c644 100644 --- a/libfreerdp/codec/progressive.c +++ b/libfreerdp/codec/progressive.c @@ -2422,11 +2422,17 @@ INT32 progressive_decompress_ex(PROGRESSIVE_CONTEXT* progressive, const BYTE* pS for (j = 0; j < nbUpdateRects; j++) { const RECTANGLE_16* rect = &updateRects[j]; - const UINT32 nXSrc = rect->left - (nXDst + tile->x); - const UINT32 nYSrc = rect->top - (nYDst + tile->y); + if (rect->left < updateRect.left) + goto fail; + const UINT32 nXSrc = rect->left - updateRect.left; + const UINT32 nYSrc = rect->top - updateRect.top; const UINT32 width = rect->right - rect->left; const UINT32 height = rect->bottom - rect->top; + if (rect->left + width > surface->width) + goto fail; + if (rect->top + height > surface->height) + goto fail; if (!freerdp_image_copy(pDstData, DstFormat, nDstStep, rect->left, rect->top, width, height, tile->data, progressive->format, tile->stride, nXSrc, nYSrc, NULL, FREERDP_FLIP_NONE)) From bacb8c016ef72aa767760b6b01d15500aee9d59a Mon Sep 17 00:00:00 2001 From: akallabeth Date: Tue, 22 Aug 2023 14:44:57 +0200 Subject: [PATCH 382/496] [codec,clear] fix missing bounds checks (cherry picked from commit 680619fc48f40d458c9614b47bfde61226a324aa) --- libfreerdp/codec/clear.c | 59 +++++++++++++++++++--------------------- 1 file changed, 28 insertions(+), 31 deletions(-) diff --git a/libfreerdp/codec/clear.c b/libfreerdp/codec/clear.c index ecf7f1ca161b..101260770ba7 100644 --- a/libfreerdp/codec/clear.c +++ b/libfreerdp/codec/clear.c @@ -591,13 +591,9 @@ static BOOL resize_vbar_entry(CLEAR_CONTEXT* clear, CLEAR_VBAR_ENTRY* vBarEntry) static BOOL clear_decompress_bands_data(CLEAR_CONTEXT* clear, wStream* s, UINT32 bandsByteCount, UINT32 nWidth, UINT32 nHeight, BYTE* pDstData, UINT32 DstFormat, UINT32 nDstStep, UINT32 nXDst, - UINT32 nYDst) + UINT32 nYDst, UINT32 nDstWidth, UINT32 nDstHeight) { - UINT32 i, y; - UINT32 count; - UINT32 suboffset; - UINT32 nXDstRel; - UINT32 nYDstRel; + UINT32 suboffset = 0; if (Stream_GetRemainingLength(s) < bandsByteCount) { @@ -605,22 +601,20 @@ static BOOL clear_decompress_bands_data(CLEAR_CONTEXT* clear, wStream* s, UINT32 return FALSE; } - suboffset = 0; - while (suboffset < bandsByteCount) { - BYTE r, g, b; + BYTE cr, cg, cb; UINT16 xStart; UINT16 xEnd; UINT16 yStart; UINT16 yEnd; UINT32 colorBkg; UINT16 vBarHeader; - UINT16 vBarYOn; + UINT16 vBarYOn = 0; UINT16 vBarYOff; UINT32 vBarCount; UINT32 vBarPixelCount; - UINT32 vBarShortPixelCount; + UINT32 vBarShortPixelCount = 0; if (Stream_GetRemainingLength(s) < 11) { @@ -632,11 +626,11 @@ static BOOL clear_decompress_bands_data(CLEAR_CONTEXT* clear, wStream* s, UINT32 Stream_Read_UINT16(s, xEnd); Stream_Read_UINT16(s, yStart); Stream_Read_UINT16(s, yEnd); - Stream_Read_UINT8(s, b); - Stream_Read_UINT8(s, g); - Stream_Read_UINT8(s, r); + Stream_Read_UINT8(s, cb); + Stream_Read_UINT8(s, cg); + Stream_Read_UINT8(s, cr); suboffset += 11; - colorBkg = FreeRDPGetColor(clear->format, r, g, b, 0xFF); + colorBkg = FreeRDPGetColor(clear->format, cr, cg, cb, 0xFF); if (xEnd < xStart) { @@ -652,13 +646,13 @@ static BOOL clear_decompress_bands_data(CLEAR_CONTEXT* clear, wStream* s, UINT32 vBarCount = (xEnd - xStart) + 1; - for (i = 0; i < vBarCount; i++) + for (UINT32 i = 0; i < vBarCount; i++) { UINT32 vBarHeight; CLEAR_VBAR_ENTRY* vBarEntry = NULL; - CLEAR_VBAR_ENTRY* vBarShortEntry; + CLEAR_VBAR_ENTRY* vBarShortEntry = NULL; BOOL vBarUpdate = FALSE; - const BYTE* pSrcPixel; + const BYTE* cpSrcPixel; if (Stream_GetRemainingLength(s) < 2) { @@ -740,11 +734,11 @@ static BOOL clear_decompress_bands_data(CLEAR_CONTEXT* clear, wStream* s, UINT32 if (!resize_vbar_entry(clear, vBarShortEntry)) return FALSE; - for (y = 0; y < vBarShortPixelCount; y++) + for (UINT32 y = 0; y < vBarShortPixelCount; y++) { - BYTE r, g, b; + BYTE r = 0, g = 0, b = 0; BYTE* dstBuffer = &vBarShortEntry->pixels[y * GetBytesPerPixel(clear->format)]; - UINT32 color; + UINT32 color = 0; Stream_Read_UINT8(s, b); Stream_Read_UINT8(s, g); Stream_Read_UINT8(s, r); @@ -804,8 +798,8 @@ static BOOL clear_decompress_bands_data(CLEAR_CONTEXT* clear, wStream* s, UINT32 dstBuffer = vBarEntry->pixels; /* if (y < vBarYOn), use colorBkg */ - y = 0; - count = vBarYOn; + UINT32 y = 0; + UINT32 count = vBarYOn; if ((y + count) > vBarPixelCount) count = (vBarPixelCount > y) ? (vBarPixelCount - y) : 0; @@ -868,28 +862,31 @@ static BOOL clear_decompress_bands_data(CLEAR_CONTEXT* clear, wStream* s, UINT32 return FALSE; } - nXDstRel = nXDst + xStart; - nYDstRel = nYDst + yStart; - pSrcPixel = vBarEntry->pixels; + const UINT32 nXDstRel = nXDst + xStart; + const UINT32 nYDstRel = nYDst + yStart; + cpSrcPixel = vBarEntry->pixels; if (i < nWidth) { - count = vBarEntry->count; + UINT32 count = vBarEntry->count; if (count > nHeight) count = nHeight; - for (y = 0; y < count; y++) + if (nXDstRel + i > nDstWidth) + return FALSE; + + for (UINT32 y = 0; y < count; y++) { BYTE* pDstPixel8 = &pDstData[((nYDstRel + y) * nDstStep) + ((nXDstRel + i) * GetBytesPerPixel(DstFormat))]; - UINT32 color = ReadColor(pSrcPixel, clear->format); + UINT32 color = ReadColor(cpSrcPixel, clear->format); color = FreeRDPConvertColor(color, clear->format, DstFormat, NULL); if (!WriteColor(pDstPixel8, DstFormat, color)) return FALSE; - pSrcPixel += GetBytesPerPixel(clear->format); + cpSrcPixel += GetBytesPerPixel(clear->format); } } } @@ -1117,7 +1114,7 @@ INT32 clear_decompress(CLEAR_CONTEXT* clear, const BYTE* pSrcData, UINT32 SrcSiz if (bandsByteCount > 0) { if (!clear_decompress_bands_data(clear, s, bandsByteCount, nWidth, nHeight, pDstData, - DstFormat, nDstStep, nXDst, nYDst)) + DstFormat, nDstStep, nXDst, nYDst, nDstWidth, nDstHeight)) { WLog_ERR(TAG, "clear_decompress_bands_data failed!"); goto fail; From 9a1ee1bae5a9561f5031a7b69129f10458b62d4a Mon Sep 17 00:00:00 2001 From: akallabeth Date: Tue, 22 Aug 2023 10:48:57 +0200 Subject: [PATCH 383/496] [codec,nsc] fix input length validation (cherry picked from commit e6bb37bea1a645610cc7e030e11fa3ec9e758dc9) --- libfreerdp/codec/nsc.c | 32 ++++++++++++++++++++++++++++---- libfreerdp/codec/nsc_types.h | 1 + 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/libfreerdp/codec/nsc.c b/libfreerdp/codec/nsc.c index cd65f072f000..645ca7512716 100644 --- a/libfreerdp/codec/nsc.c +++ b/libfreerdp/codec/nsc.c @@ -119,12 +119,17 @@ static BOOL nsc_decode(NSC_CONTEXT* context) return TRUE; } -static BOOL nsc_rle_decode(BYTE* in, BYTE* out, UINT32 outSize, UINT32 originalSize) +static BOOL nsc_rle_decode(const BYTE* in, size_t inSize, BYTE* out, UINT32 outSize, + UINT32 originalSize) { UINT32 left = originalSize; while (left > 4) { + if (inSize < 1) + return FALSE; + inSize--; + const BYTE value = *in++; UINT32 len = 0; @@ -137,17 +142,26 @@ static BOOL nsc_rle_decode(BYTE* in, BYTE* out, UINT32 outSize, UINT32 originalS *out++ = value; left--; } + else if (inSize < 1) + return FALSE; else if (value == *in) { + inSize--; in++; - if (*in < 0xFF) + if (inSize < 1) + return FALSE; + else if (*in < 0xFF) { + inSize--; len = (UINT32)*in++; len += 2; } else { + if (inSize < 5) + return FALSE; + inSize -= 5; in++; len = ((UINT32)(*in++)); len |= ((UINT32)(*in++)) << 8U; @@ -177,6 +191,8 @@ static BOOL nsc_rle_decode(BYTE* in, BYTE* out, UINT32 outSize, UINT32 originalS if ((outSize < 4) || (left < 4)) return FALSE; + if (inSize < 4) + return FALSE; memcpy(out, in, 4); return TRUE; } @@ -186,7 +202,8 @@ static BOOL nsc_rle_decompress_data(NSC_CONTEXT* context) if (!context) return FALSE; - BYTE* rle = context->Planes; + const BYTE* rle = context->Planes; + size_t rleSize = context->PlanesSize; WINPR_ASSERT(rle); for (size_t i = 0; i < 4; i++) @@ -194,6 +211,9 @@ static BOOL nsc_rle_decompress_data(NSC_CONTEXT* context) const UINT32 originalSize = context->OrgByteCount[i]; const UINT32 planeSize = context->PlaneByteCount[i]; + if (rleSize < planeSize) + return FALSE; + if (planeSize == 0) { if (context->priv->PlaneBuffersLength < originalSize) @@ -203,7 +223,7 @@ static BOOL nsc_rle_decompress_data(NSC_CONTEXT* context) } else if (planeSize < originalSize) { - if (!nsc_rle_decode(rle, context->priv->PlaneBuffers[i], + if (!nsc_rle_decode(rle, rleSize, context->priv->PlaneBuffers[i], context->priv->PlaneBuffersLength, originalSize)) return FALSE; } @@ -212,6 +232,9 @@ static BOOL nsc_rle_decompress_data(NSC_CONTEXT* context) if (context->priv->PlaneBuffersLength < originalSize) return FALSE; + if (rleSize < originalSize) + return FALSE; + CopyMemory(context->priv->PlaneBuffers[i], rle, originalSize); } @@ -239,6 +262,7 @@ static BOOL nsc_stream_initialize(NSC_CONTEXT* context, wStream* s) Stream_Read_UINT8(s, context->ChromaSubsamplingLevel); /* ChromaSubsamplingLevel (1 byte) */ Stream_Seek(s, 2); /* Reserved (2 bytes) */ context->Planes = Stream_Pointer(s); + context->PlanesSize = total; return Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, total); } diff --git a/libfreerdp/codec/nsc_types.h b/libfreerdp/codec/nsc_types.h index 14c1a946bcd1..5a6506baea5a 100644 --- a/libfreerdp/codec/nsc_types.h +++ b/libfreerdp/codec/nsc_types.h @@ -61,6 +61,7 @@ struct _NSC_CONTEXT UINT32 BitmapDataLength; BYTE* Planes; + size_t PlanesSize; UINT32 PlaneByteCount[4]; UINT32 ColorLossLevel; UINT32 ChromaSubsamplingLevel; From c23cbdc4a5756bd723223c7139654de7439fdcc0 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Mon, 21 Aug 2023 14:30:11 +0200 Subject: [PATCH 384/496] [codec,zgfx] fix cBitsRemaining calculation fixed out of bound read reported by @pwn2carr (cherry picked from commit c39c82277a73332e9c1b64db98a34559f424fe20) --- libfreerdp/codec/zgfx.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/libfreerdp/codec/zgfx.c b/libfreerdp/codec/zgfx.c index e260aa6e28ad..841b50860711 100644 --- a/libfreerdp/codec/zgfx.c +++ b/libfreerdp/codec/zgfx.c @@ -259,7 +259,11 @@ static BOOL zgfx_decompress_segment(ZGFX_CONTEXT* zgfx, wStream* stream, size_t zgfx->pbInputCurrent = pbSegment; zgfx->pbInputEnd = &pbSegment[cbSegment - 1]; /* NumberOfBitsToDecode = ((NumberOfBytesToDecode - 1) * 8) - ValueOfLastByte */ - zgfx->cBitsRemaining = 8 * (cbSegment - 1) - *zgfx->pbInputEnd; + const UINT32 bits = 8u * (cbSegment - 1u); + if (bits < *zgfx->pbInputEnd) + return FALSE; + + zgfx->cBitsRemaining = bits - *zgfx->pbInputEnd; zgfx->cBitsCurrent = 0; zgfx->BitsCurrent = 0; From 889348a86e49bc8f1351ed6496d847b32db5f86e Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Sat, 5 Aug 2023 11:31:08 +0200 Subject: [PATCH 385/496] [core,orders] fix checks for multi opaque rect (cherry picked from commit 567847066278ec112abb99707902818b282059ad) --- libfreerdp/core/orders.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/libfreerdp/core/orders.c b/libfreerdp/core/orders.c index 34ccbb7b01ce..013dc8e8c9c5 100644 --- a/libfreerdp/core/orders.c +++ b/libfreerdp/core/orders.c @@ -27,6 +27,7 @@ #include #include +#include #include #include @@ -1390,7 +1391,7 @@ static BOOL update_read_multi_dstblt_order(wStream* s, const ORDER_INFO* orderIn return update_read_delta_rects(s, multi_dstblt->rectangles, &multi_dstblt->numRectangles); } - return TRUE; + return multi_dstblt->numRectangles == 0; } static BOOL update_read_multi_patblt_order(wStream* s, const ORDER_INFO* orderInfo, MULTI_PATBLT_ORDER* multi_patblt) @@ -1420,12 +1421,18 @@ static BOOL update_read_multi_patblt_order(wStream* s, const ORDER_INFO* orderIn if (!update_read_delta_rects(s, multi_patblt->rectangles, &multi_patblt->numRectangles)) return FALSE; } + else if (multi_patblt->numRectangles != 0) + return FALSE; return TRUE; } static BOOL update_read_multi_scrblt_order(wStream* s, const ORDER_INFO* orderInfo, MULTI_SCRBLT_ORDER* multi_scrblt) { + WINPR_ASSERT(orderInfo); + WINPR_ASSERT(multi_scrblt); + + multi_scrblt->numRectangles = 0; if (!read_order_field_coord(orderInfo, s, 1, &multi_scrblt->nLeftRect, FALSE) || !read_order_field_coord(orderInfo, s, 2, &multi_scrblt->nTopRect, FALSE) || !read_order_field_coord(orderInfo, s, 3, &multi_scrblt->nWidth, FALSE) || @@ -1445,7 +1452,7 @@ static BOOL update_read_multi_scrblt_order(wStream* s, const ORDER_INFO* orderIn return update_read_delta_rects(s, multi_scrblt->rectangles, &multi_scrblt->numRectangles); } - return TRUE; + return multi_scrblt->numRectangles == 0; } static BOOL update_read_multi_opaque_rect_order(wStream* s, const ORDER_INFO* orderInfo, MULTI_OPAQUE_RECT_ORDER* multi_opaque_rect) @@ -1497,7 +1504,7 @@ static BOOL update_read_multi_opaque_rect_order(wStream* s, const ORDER_INFO* or &multi_opaque_rect->numRectangles); } - return TRUE; + return multi_opaque_rect->numRectangles == 0; } static BOOL update_read_multi_draw_nine_grid_order(wStream* s, const ORDER_INFO* orderInfo, MULTI_DRAW_NINE_GRID_ORDER* multi_draw_nine_grid) @@ -1520,7 +1527,7 @@ static BOOL update_read_multi_draw_nine_grid_order(wStream* s, const ORDER_INFO* &multi_draw_nine_grid->nDeltaEntries); } - return TRUE; + return multi_draw_nine_grid->nDeltaEntries == 0; } static BOOL update_read_line_to_order(wStream* s, const ORDER_INFO* orderInfo, LINE_TO_ORDER* line_to) From c659973bb4cd65c065f2fe1a807dbc6805c684c6 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Mon, 28 Aug 2023 09:06:42 +0200 Subject: [PATCH 386/496] [codec,ncrush] fix index checks properly verify all offsets while decoding data. (cherry picked from commit 880285c332a1d98334fd8fa4b06c10fba0fb6959) --- libfreerdp/codec/ncrush.c | 137 ++++++++++++++++++++++++++++++-------- 1 file changed, 108 insertions(+), 29 deletions(-) diff --git a/libfreerdp/codec/ncrush.c b/libfreerdp/codec/ncrush.c index 3d6a216d32f4..c1d622a9c0bd 100644 --- a/libfreerdp/codec/ncrush.c +++ b/libfreerdp/codec/ncrush.c @@ -1994,15 +1994,9 @@ int ncrush_decompress(NCRUSH_CONTEXT* ncrush, BYTE* pSrcData, UINT32 SrcSize, BY UINT32* pDstSize, UINT32 flags) { UINT32 index; - UINT32 bits; - INT32 nbits; - const BYTE* SrcPtr; - const BYTE* SrcEnd; - UINT16 Mask; BYTE Literal; UINT32 IndexLEC; UINT32 BitLength; - UINT32 MaskedBits; UINT32 CopyOffset; UINT32 CopyLength; UINT32 OldCopyOffset; @@ -2010,9 +2004,6 @@ int ncrush_decompress(NCRUSH_CONTEXT* ncrush, BYTE* pSrcData, UINT32 SrcSize, BY UINT32 LengthOfMatch; UINT32 CopyOffsetIndex; UINT32 OffsetCacheIndex; - BYTE* HistoryPtr; - BYTE* HistoryBuffer; - BYTE* HistoryBufferEnd; UINT32 CopyOffsetBits; UINT32 CopyOffsetBase; UINT32 LengthOfMatchBits; @@ -2021,8 +2012,8 @@ int ncrush_decompress(NCRUSH_CONTEXT* ncrush, BYTE* pSrcData, UINT32 SrcSize, BY if (ncrush->HistoryEndOffset != 65535) return -1001; - HistoryBuffer = ncrush->HistoryBuffer; - HistoryBufferEnd = &HistoryBuffer[ncrush->HistoryEndOffset]; + BYTE* HistoryBuffer = ncrush->HistoryBuffer; + const BYTE* HistoryBufferEnd = &HistoryBuffer[ncrush->HistoryEndOffset]; if (flags & PACKET_AT_FRONT) { @@ -2041,7 +2032,7 @@ int ncrush_decompress(NCRUSH_CONTEXT* ncrush, BYTE* pSrcData, UINT32 SrcSize, BY ZeroMemory(&(ncrush->OffsetCache), sizeof(ncrush->OffsetCache)); } - HistoryPtr = ncrush->HistoryPtr; + BYTE* HistoryPtr = ncrush->HistoryPtr; if (!(flags & PACKET_COMPRESSED)) { @@ -2050,17 +2041,19 @@ int ncrush_decompress(NCRUSH_CONTEXT* ncrush, BYTE* pSrcData, UINT32 SrcSize, BY return 1; } - SrcEnd = &pSrcData[SrcSize]; - nbits = 32; - bits = get_dword(pSrcData); - SrcPtr = pSrcData + 4; + const BYTE* SrcEnd = &pSrcData[SrcSize]; + const BYTE* SrcPtr = pSrcData + 4; + INT32 nbits = 32; + UINT32 bits = get_dword(pSrcData); while (1) { while (1) { - Mask = get_word(&HuffTableMask[29]); - MaskedBits = bits & Mask; + const UINT16 Mask = get_word(&HuffTableMask[29]); + const UINT32 MaskedBits = bits & Mask; + if (MaskedBits >= ARRAYSIZE(HuffTableLEC)) + return -1; IndexLEC = HuffTableLEC[MaskedBits] & 0xFFF; BitLength = HuffTableLEC[MaskedBits] >> 12; bits >>= BitLength; @@ -2096,8 +2089,10 @@ int ncrush_decompress(NCRUSH_CONTEXT* ncrush, BYTE* pSrcData, UINT32 SrcSize, BY return -1004; CopyOffset = ncrush->OffsetCache[OffsetCacheIndex]; - Mask = get_word(&HuffTableMask[21]); - MaskedBits = bits & Mask; + const UINT16 Mask = get_word(&HuffTableMask[21]); + const UINT32 MaskedBits = bits & Mask; + if (MaskedBits > ARRAYSIZE(HuffTableLOM)) + return -1; LengthOfMatch = HuffTableLOM[MaskedBits] & 0xFFF; BitLength = HuffTableLOM[MaskedBits] >> 12; bits >>= BitLength; @@ -2106,13 +2101,23 @@ int ncrush_decompress(NCRUSH_CONTEXT* ncrush, BYTE* pSrcData, UINT32 SrcSize, BY if (!NCrushFetchBits(&SrcPtr, &SrcEnd, &nbits, &bits)) return -1; + if (LengthOfMatch >= ARRAYSIZE(LOMBitsLUT)) + return -1; + LengthOfMatchBits = LOMBitsLUT[LengthOfMatch]; + + if (LengthOfMatch >= ARRAYSIZE(LOMBaseLUT)) + return -1; LengthOfMatchBase = LOMBaseLUT[LengthOfMatch]; if (LengthOfMatchBits) { - Mask = get_word(&HuffTableMask[(2 * LengthOfMatchBits) + 3]); - MaskedBits = bits & Mask; + const size_t idx = (2ull * LengthOfMatchBits) + 3ull; + if (idx >= ARRAYSIZE(HuffTableMask)) + return -1; + + const UINT16 Mask = get_word(&HuffTableMask[idx]); + const UINT32 MaskedBits = bits & Mask; bits >>= LengthOfMatchBits; nbits -= LengthOfMatchBits; LengthOfMatchBase += MaskedBits; @@ -2127,15 +2132,28 @@ int ncrush_decompress(NCRUSH_CONTEXT* ncrush, BYTE* pSrcData, UINT32 SrcSize, BY } else { + if (CopyOffsetIndex >= ARRAYSIZE(CopyOffsetBitsLUT)) + return -1; + CopyOffsetBits = CopyOffsetBitsLUT[CopyOffsetIndex]; + + if (CopyOffsetIndex >= ARRAYSIZE(CopyOffsetBaseLUT)) + return -1; CopyOffsetBase = CopyOffsetBaseLUT[CopyOffsetIndex]; CopyOffset = CopyOffsetBase - 1; if (CopyOffsetBits) { - Mask = get_word(&HuffTableMask[(2 * CopyOffsetBits) + 3]); - MaskedBits = bits & Mask; - CopyOffset = CopyOffsetBase + MaskedBits - 1; + const size_t idx = (2ull * CopyOffsetBits) + 3ull; + if (idx >= ARRAYSIZE(HuffTableMask)) + return -1; + + const UINT16 Mask = get_word(&HuffTableMask[idx]); + const UINT32 MaskedBits = bits & Mask; + const UINT32 tmp = CopyOffsetBase + MaskedBits; + if (tmp < 1) + return -1; + CopyOffset = tmp - 1; bits >>= CopyOffsetBits; nbits -= CopyOffsetBits; @@ -2143,8 +2161,11 @@ int ncrush_decompress(NCRUSH_CONTEXT* ncrush, BYTE* pSrcData, UINT32 SrcSize, BY return -1; } - Mask = get_word(&HuffTableMask[21]); - MaskedBits = bits & Mask; + const UINT16 Mask = get_word(&HuffTableMask[21]); + const UINT32 MaskedBits = bits & Mask; + if (MaskedBits >= ARRAYSIZE(HuffTableLOM)) + return -1; + LengthOfMatch = HuffTableLOM[MaskedBits] & 0xFFF; BitLength = HuffTableLOM[MaskedBits] >> 12; bits >>= BitLength; @@ -2153,13 +2174,23 @@ int ncrush_decompress(NCRUSH_CONTEXT* ncrush, BYTE* pSrcData, UINT32 SrcSize, BY if (!NCrushFetchBits(&SrcPtr, &SrcEnd, &nbits, &bits)) return -1; + if (LengthOfMatch >= ARRAYSIZE(LOMBitsLUT)) + return -1; + LengthOfMatchBits = LOMBitsLUT[LengthOfMatch]; + + if (LengthOfMatch >= ARRAYSIZE(LOMBaseLUT)) + return -1; LengthOfMatchBase = LOMBaseLUT[LengthOfMatch]; if (LengthOfMatchBits) { - Mask = get_word(&HuffTableMask[(2 * LengthOfMatchBits) + 3]); - MaskedBits = bits & Mask; + const size_t idx = (2ull * LengthOfMatchBits) + 3ull; + if (idx >= ARRAYSIZE(HuffTableMask)) + return -1; + + const UINT16 Mask = get_word(&HuffTableMask[idx]); + const UINT32 MaskedBits = bits & Mask; bits >>= LengthOfMatchBits; nbits -= LengthOfMatchBits; LengthOfMatchBase += MaskedBits; @@ -2583,7 +2614,12 @@ int ncrush_compress(NCRUSH_CONTEXT* ncrush, BYTE* pSrcData, UINT32 SrcSize, BYTE } IndexLEC = Literal; + if (IndexLEC >= ARRAYSIZE(HuffLengthLEC)) + return -1; BitLength = HuffLengthLEC[IndexLEC]; + + if (IndexLEC * 2ull >= ARRAYSIZE(HuffCodeLEC)) + return -1; CodeLEC = get_word(&HuffCodeLEC[IndexLEC * 2]); if (BitLength > 15) @@ -2666,9 +2702,18 @@ int ncrush_compress(NCRUSH_CONTEXT* ncrush, BYTE* pSrcData, UINT32 SrcSize, BYTE bits = CopyOffset; CopyOffsetIndex = ncrush->HuffTableCopyOffset[bits + 2]; + + if (CopyOffsetIndex >= ARRAYSIZE(CopyOffsetBitsLUT)) + return -1; + CopyOffsetBits = CopyOffsetBitsLUT[CopyOffsetIndex]; IndexLEC = 257 + CopyOffsetIndex; + if (IndexLEC >= ARRAYSIZE(HuffLengthLEC)) + return -1; BitLength = HuffLengthLEC[IndexLEC]; + + if (IndexLEC * 2ull >= ARRAYSIZE(HuffCodeLEC)) + return -1; CodeLEC = get_word(&HuffCodeLEC[IndexLEC * 2]); if (BitLength > 15) @@ -2687,13 +2732,23 @@ int ncrush_compress(NCRUSH_CONTEXT* ncrush, BYTE* pSrcData, UINT32 SrcSize, BYTE else IndexCO = ncrush->HuffTableLOM[MatchLength]; + if (IndexCO >= ARRAYSIZE(HuffLengthLOM)) + return -1; BitLength = HuffLengthLOM[IndexCO]; + + if (IndexCO >= ARRAYSIZE(LOMBitsLUT)) + return -1; IndexLOM = LOMBitsLUT[IndexCO]; + + if (IndexCO >= ARRAYSIZE(HuffCodeLOM)) + return -1; NCrushWriteBits(&DstPtr, &accumulator, &offset, HuffCodeLOM[IndexCO], BitLength); Mask = ((1 << IndexLOM) - 1); MaskedBits = (MatchLength - 2) & Mask; NCrushWriteBits(&DstPtr, &accumulator, &offset, MaskedBits, IndexLOM); + if (IndexCO >= ARRAYSIZE(LOMBaseLUT)) + return -1; if ((MaskedBits + LOMBaseLUT[IndexCO]) != MatchLength) return -1010; } @@ -2701,7 +2756,11 @@ int ncrush_compress(NCRUSH_CONTEXT* ncrush, BYTE* pSrcData, UINT32 SrcSize, BYTE { /* CopyOffset in OffsetCache */ IndexLEC = 289 + OffsetCacheIndex; + if (IndexLEC >= ARRAYSIZE(HuffLengthLEC)) + return -1; BitLength = HuffLengthLEC[IndexLEC]; + if (IndexLEC * 2ull >= ARRAYSIZE(HuffCodeLEC)) + return -1; CodeLEC = get_word(&HuffCodeLEC[IndexLEC * 2]); if (BitLength >= 15) @@ -2714,13 +2773,24 @@ int ncrush_compress(NCRUSH_CONTEXT* ncrush, BYTE* pSrcData, UINT32 SrcSize, BYTE else IndexCO = ncrush->HuffTableLOM[MatchLength]; + if (IndexCO >= ARRAYSIZE(HuffLengthLOM)) + return -1; + BitLength = HuffLengthLOM[IndexCO]; + + if (IndexCO >= ARRAYSIZE(LOMBitsLUT)) + return -1; IndexLOM = LOMBitsLUT[IndexCO]; + + if (IndexCO >= ARRAYSIZE(HuffCodeLOM)) + return -1; NCrushWriteBits(&DstPtr, &accumulator, &offset, HuffCodeLOM[IndexCO], BitLength); Mask = ((1 << IndexLOM) - 1); MaskedBits = (MatchLength - 2) & Mask; NCrushWriteBits(&DstPtr, &accumulator, &offset, MaskedBits, IndexLOM); + if (IndexCO >= ARRAYSIZE(LOMBaseLUT)) + return -1; if ((MaskedBits + LOMBaseLUT[IndexCO]) != MatchLength) return -1012; } @@ -2745,6 +2815,10 @@ int ncrush_compress(NCRUSH_CONTEXT* ncrush, BYTE* pSrcData, UINT32 SrcSize, BYTE Literal = *SrcPtr++; HistoryPtr++; IndexLEC = Literal; + if (IndexLEC >= ARRAYSIZE(HuffLengthLEC)) + return -1; + if (IndexLEC * 2ull >= ARRAYSIZE(HuffCodeLEC)) + return -1; BitLength = HuffLengthLEC[IndexLEC]; CodeLEC = get_word(&HuffCodeLEC[IndexLEC * 2]); @@ -2817,6 +2891,11 @@ static int ncrush_generate_tables(NCRUSH_CONTEXT* context) else i = context->HuffTableLOM[k]; + if (i >= ARRAYSIZE(LOMBitsLUT)) + return -1; + if (i >= ARRAYSIZE(LOMBaseLUT)) + return -1; + if (((((1 << LOMBitsLUT[i]) - 1) & (k - 2)) + LOMBaseLUT[i]) != k) return -1; } From 7073e7e96467cd1c6816f41cbc2b6fac71b783f9 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Tue, 2 Mar 2021 09:34:39 +0100 Subject: [PATCH 387/496] Proper pointer event handling for wayland (cherry picked from commit 8732ff68abbaa0c65928d7c3236bd496da334c9b) --- client/Wayland/wlf_input.c | 128 +++++++++++++++++++++++++++++++++---- client/Wayland/wlf_input.h | 3 + client/Wayland/wlfreerdp.c | 64 ++++++++++++++----- client/Wayland/wlfreerdp.h | 1 + 4 files changed, 168 insertions(+), 28 deletions(-) diff --git a/client/Wayland/wlf_input.c b/client/Wayland/wlf_input.c index 22041eaa2588..735245b3bd8c 100644 --- a/client/Wayland/wlf_input.c +++ b/client/Wayland/wlf_input.c @@ -134,26 +134,44 @@ BOOL wlf_handle_pointer_buttons(freerdp* instance, const UwacPointerButtonEvent* } BOOL wlf_handle_pointer_axis(freerdp* instance, const UwacPointerAxisEvent* ev) +{ + wlfContext* context; + if (!instance || !instance->context || !ev) + return FALSE; + + context = (wlfContext*)instance->context; + ArrayList_Add(context->events, ev); + return TRUE; +} + +BOOL wlf_handle_pointer_axis_discrete(freerdp* instance, const UwacPointerAxisEvent* ev) +{ + wlfContext* context; + if (!instance || !instance->context || !ev) + return FALSE; + + context = (wlfContext*)instance->context; + ArrayList_Add(context->events, ev); + return TRUE; +} + +static BOOL wlf_handle_wheel(freerdp* instance, uint32_t x, uint32_t y, uint32_t axis, + int32_t value) { rdpInput* input; UINT16 flags = 0; int32_t direction; - uint32_t x, y; - uint32_t i; + uint32_t avalue = abs(value); - if (!instance || !ev || !instance->input) - return FALSE; - - x = ev->x; - y = ev->y; + input = instance->input; if (!wlf_scale_coordinates(instance->context, &x, &y, TRUE)) return FALSE; input = instance->input; - direction = ev->value; - switch (ev->axis) + direction = value; + switch (axis) { case WL_POINTER_AXIS_VERTICAL_SCROLL: flags |= PTR_FLAGS_WHEEL; @@ -176,16 +194,102 @@ BOOL wlf_handle_pointer_axis(freerdp* instance, const UwacPointerAxisEvent* ev) * positive: 0 ... 0xFF -> slow ... fast * negative: 0 ... 0xFF -> fast ... slow */ - for (i = 0; i < abs(direction); i++) + + while (avalue > 0) { - uint32_t cflags = flags | 0x78; + const uint32_t cval = avalue > 0xFF ? 0xFF : avalue; + uint32_t cflags = flags | cval; /* Convert negative values to 9bit twos complement */ if (flags & PTR_FLAGS_WHEEL_NEGATIVE) - cflags = (flags & 0xFF00) | (0x100 - (cflags & 0xFF)); + cflags = (flags & 0xFF00) | (0x100 - cval); if (!freerdp_input_send_mouse_event(input, cflags, (UINT16)x, (UINT16)y)) return FALSE; + + avalue -= cval; } + return TRUE; +} +BOOL wlf_handle_pointer_frame(freerdp* instance, const UwacPointerFrameEvent* ev) +{ + BOOL success = TRUE; + BOOL handle = FALSE; + size_t x; + wlfContext* context; + enum wl_pointer_axis_source source; + + if (!instance || !ev || !instance->input || !instance->context) + return FALSE; + + context = (wlfContext*)instance->context; + + for (x = 0; x < ArrayList_Count(context->events); x++) + { + UwacEvent* ev = ArrayList_GetItem(context->events, x); + if (!ev) + continue; + if (ev->type == UWAC_EVENT_POINTER_SOURCE) + { + handle = TRUE; + source = ev->mouse_source.axis_source; + } + } + + /* We need source events to determine how to interpret the data */ + if (handle) + { + for (x = 0; x < ArrayList_Count(context->events); x++) + { + UwacEvent* ev = ArrayList_GetItem(context->events, x); + if (!ev) + continue; + + switch (source) + { + /* If we have a mouse wheel, just use discrete data */ + case WL_POINTER_AXIS_SOURCE_WHEEL: +#if defined(WL_POINTER_AXIS_SOURCE_WHEEL_TILT_SINCE_VERSION) + case WL_POINTER_AXIS_SOURCE_WHEEL_TILT: +#endif + if (ev->type == UWAC_EVENT_POINTER_AXIS_DISCRETE) + { + /* Get the number of steps, multiply by default step width of 120 */ + int32_t val = ev->mouse_axis.value * 0x78; + /* No wheel event received, success! */ + if (!wlf_handle_wheel(instance, ev->mouse_axis.x, ev->mouse_axis.y, + ev->mouse_axis.axis, val)) + success = FALSE; + } + break; + /* If we have a touch pad we get actual data, scale */ + case WL_POINTER_AXIS_SOURCE_FINGER: + case WL_POINTER_AXIS_SOURCE_CONTINUOUS: + if (ev->type == UWAC_EVENT_POINTER_AXIS) + { + double dval = wl_fixed_to_double(ev->mouse_axis.value); + int32_t val = dval * 0x78 / 10.0; + if (!wlf_handle_wheel(instance, ev->mouse_axis.x, ev->mouse_axis.y, + ev->mouse_axis.axis, val)) + success = FALSE; + } + break; + default: + break; + } + } + } + ArrayList_Clear(context->events); + return success; +} + +BOOL wlf_handle_pointer_source(freerdp* instance, const UwacPointerSourceEvent* ev) +{ + wlfContext* context; + if (!instance || !instance->context || !ev) + return FALSE; + + context = (wlfContext*)instance->context; + ArrayList_Add(context->events, ev); return TRUE; } diff --git a/client/Wayland/wlf_input.h b/client/Wayland/wlf_input.h index 2382dd8b84b9..ff41300c5ec0 100644 --- a/client/Wayland/wlf_input.h +++ b/client/Wayland/wlf_input.h @@ -30,6 +30,9 @@ BOOL wlf_handle_pointer_enter(freerdp* instance, const UwacPointerEnterLeaveEven BOOL wlf_handle_pointer_motion(freerdp* instance, const UwacPointerMotionEvent* ev); BOOL wlf_handle_pointer_buttons(freerdp* instance, const UwacPointerButtonEvent* ev); BOOL wlf_handle_pointer_axis(freerdp* instance, const UwacPointerAxisEvent* ev); +BOOL wlf_handle_pointer_axis_discrete(freerdp* instance, const UwacPointerAxisEvent* ev); +BOOL wlf_handle_pointer_frame(freerdp* instance, const UwacPointerFrameEvent* ev); +BOOL wlf_handle_pointer_source(freerdp* instance, const UwacPointerSourceEvent* ev); BOOL wlf_handle_touch_up(freerdp* instance, const UwacTouchUp* ev); BOOL wlf_handle_touch_down(freerdp* instance, const UwacTouchDown* ev); BOOL wlf_handle_touch_motion(freerdp* instance, const UwacTouchMotion* ev); diff --git a/client/Wayland/wlfreerdp.c b/client/Wayland/wlfreerdp.c index c7a9fca59b6e..65e29bc51109 100644 --- a/client/Wayland/wlfreerdp.c +++ b/client/Wayland/wlfreerdp.c @@ -362,12 +362,22 @@ static BOOL handle_uwac_events(freerdp* instance, UwacDisplay* display) break; case UWAC_EVENT_POINTER_AXIS: + if (!wlf_handle_pointer_axis(instance, &event.mouse_axis)) + return FALSE; break; case UWAC_EVENT_POINTER_AXIS_DISCRETE: - if (!wlf_handle_pointer_axis(instance, &event.mouse_axis)) + if (!wlf_handle_pointer_axis_discrete(instance, &event.mouse_axis)) return FALSE; + break; + case UWAC_EVENT_POINTER_FRAME: + if (!wlf_handle_pointer_frame(instance, &event.mouse_frame)) + return FALSE; + break; + case UWAC_EVENT_POINTER_SOURCE: + if (!wlf_handle_pointer_source(instance, &event.mouse_source)) + return FALSE; break; case UWAC_EVENT_KEY: @@ -561,8 +571,37 @@ static int wlf_logon_error_info(freerdp* instance, UINT32 data, UINT32 type) return 1; } +static void wlf_client_free(freerdp* instance, rdpContext* context) +{ + wlfContext* wlf = (wlfContext*)instance->context; + + if (!context) + return; + + if (wlf->display) + UwacCloseDisplay(&wlf->display); + + if (wlf->displayHandle) + CloseHandle(wlf->displayHandle); + ArrayList_Free(wlf->events); + DeleteCriticalSection(&wlf->critical); +} + +static void* uwac_event_clone(const void* val) +{ + UwacEvent* copy; + UwacEvent* ev = (UwacEvent*)val; + + copy = calloc(1, sizeof(UwacEvent)); + if (!copy) + return NULL; + *copy = *ev; + return copy; +} + static BOOL wlf_client_new(freerdp* instance, rdpContext* context) { + wObject* obj; UwacReturnCode status; wlfContext* wfl = (wlfContext*)context; @@ -590,24 +629,17 @@ static BOOL wlf_client_new(freerdp* instance, rdpContext* context) if (!wfl->displayHandle) return FALSE; - InitializeCriticalSection(&wfl->critical); - - return TRUE; -} - -static void wlf_client_free(freerdp* instance, rdpContext* context) -{ - wlfContext* wlf = (wlfContext*)instance->context; + wfl->events = ArrayList_New(FALSE); + if (!wfl->events) + return FALSE; - if (!context) - return; + obj = ArrayList_Object(wfl->events); + obj->fnObjectNew = uwac_event_clone; + obj->fnObjectFree = free; - if (wlf->display) - UwacCloseDisplay(&wlf->display); + InitializeCriticalSection(&wfl->critical); - if (wlf->displayHandle) - CloseHandle(wlf->displayHandle); - DeleteCriticalSection(&wlf->critical); + return TRUE; } static int wfl_client_start(rdpContext* context) diff --git a/client/Wayland/wlfreerdp.h b/client/Wayland/wlfreerdp.h index d84f91cbba2a..6af13bbbc055 100644 --- a/client/Wayland/wlfreerdp.h +++ b/client/Wayland/wlfreerdp.h @@ -53,6 +53,7 @@ struct wlf_context wlfDispContext* disp; wLog* log; CRITICAL_SECTION critical; + wArrayList* events; }; BOOL wlf_scale_coordinates(rdpContext* context, UINT32* px, UINT32* py, BOOL fromLocalToRDP); From bb9a52a7e5eb125413a0b7a22fca4dc5ea2b97ae Mon Sep 17 00:00:00 2001 From: akallabeth Date: Tue, 2 Mar 2021 09:30:58 +0100 Subject: [PATCH 388/496] Increased UWAC version (cherry picked from commit 98987c697be4210b0a1c1791cff9173bae6906c9) --- uwac/CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/uwac/CMakeLists.txt b/uwac/CMakeLists.txt index eaee928d621c..c97cd4f4c104 100644 --- a/uwac/CMakeLists.txt +++ b/uwac/CMakeLists.txt @@ -17,8 +17,8 @@ # Soname versioning set(UWAC_VERSION_MAJOR "0") -set(UWAC_VERSION_MINOR "1") -set(UWAC_VERSION_REVISION "1") +set(UWAC_VERSION_MINOR "2") +set(UWAC_VERSION_REVISION "0") set(UWAC_VERSION "${UWAC_VERSION_MAJOR}.${UWAC_VERSION_MINOR}.${UWAC_VERSION_REVISION}") set(UWAC_VERSION_FULL "${UWAC_VERSION}") set(UWAC_API_VERSION "${UWAC_VERSION_MAJOR}") From ca28de4be3698c5ac150063ab853bf52a288c5de Mon Sep 17 00:00:00 2001 From: akallabeth Date: Tue, 2 Mar 2021 09:30:01 +0100 Subject: [PATCH 389/496] Added pointer source events (cherry picked from commit f22939750ef96f95adb405e8dad3108ca8a38b53) --- uwac/include/uwac/uwac.h | 23 ++++++++++++++++++++++- uwac/libuwac/uwac-input.c | 15 ++++++++++++++- 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/uwac/include/uwac/uwac.h b/uwac/include/uwac/uwac.h index c3ad12cf149d..a86b48b26b0a 100644 --- a/uwac/include/uwac/uwac.h +++ b/uwac/include/uwac/uwac.h @@ -107,7 +107,9 @@ enum UWAC_EVENT_CLIPBOARD_OFFER, UWAC_EVENT_OUTPUT_GEOMETRY, UWAC_EVENT_KEYBOARD_MODIFIERS, - UWAC_EVENT_POINTER_AXIS_DISCRETE + UWAC_EVENT_POINTER_AXIS_DISCRETE, + UWAC_EVENT_POINTER_FRAME, + UWAC_EVENT_POINTER_SOURCE }; /** @brief window states */ @@ -195,6 +197,23 @@ struct uwac_pointer_axis_event }; typedef struct uwac_pointer_axis_event UwacPointerAxisEvent; +struct uwac_pointer_frame_event +{ + int type; + UwacWindow* window; + UwacSeat* seat; +}; +typedef struct uwac_pointer_frame_event UwacPointerFrameEvent; + +struct uwac_pointer_source_event +{ + int type; + UwacWindow* window; + UwacSeat* seat; + enum wl_pointer_axis_source axis_source; +}; +typedef struct uwac_pointer_source_event UwacPointerSourceEvent; + struct uwac_touch_frame_event { int type; @@ -286,6 +305,8 @@ union uwac_event { UwacPointerMotionEvent mouse_motion; UwacPointerButtonEvent mouse_button; UwacPointerAxisEvent mouse_axis; + UwacPointerFrameEvent mouse_frame; + UwacPointerSourceEvent mouse_source; UwacKeyboardEnterLeaveEvent keyboard_enter_leave; UwacKeyboardModifiersEvent keyboard_modifiers; UwacClipboardEvent clipboard; diff --git a/uwac/libuwac/uwac-input.c b/uwac/libuwac/uwac-input.c index 6854092fa490..42cc6519da05 100644 --- a/uwac/libuwac/uwac-input.c +++ b/uwac/libuwac/uwac-input.c @@ -851,7 +851,20 @@ static void pointer_frame(void* data, struct wl_pointer* wl_pointer) static void pointer_axis_source(void* data, struct wl_pointer* wl_pointer, uint32_t axis_source) { - /*UwacSeat *seat = data;*/ + UwacPointerSourceEvent* event; + UwacSeat* seat = data; + UwacWindow* window = seat->pointer_focus; + + if (!window) + return; + + event = (UwacPointerSourceEvent*)UwacDisplayNewEvent(seat->display, UWAC_EVENT_POINTER_SOURCE); + if (!event) + return; + + event->seat = seat; + event->window = window; + event->axis_source = axis_source; } static void pointer_axis_stop(void* data, struct wl_pointer* wl_pointer, uint32_t time, From 55f02d3f9ad3efd8de2d8d184082c78fe2ed08d6 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Tue, 2 Mar 2021 08:49:50 +0100 Subject: [PATCH 390/496] Added pointer frame events (cherry picked from commit 784db04f1d7462c97d4c1f95e44b08661d134b66) --- uwac/libuwac/uwac-input.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/uwac/libuwac/uwac-input.c b/uwac/libuwac/uwac-input.c index 42cc6519da05..0d448c3c58e3 100644 --- a/uwac/libuwac/uwac-input.c +++ b/uwac/libuwac/uwac-input.c @@ -846,7 +846,19 @@ static void pointer_handle_axis(void* data, struct wl_pointer* pointer, uint32_t static void pointer_frame(void* data, struct wl_pointer* wl_pointer) { - /*UwacSeat *seat = data;*/ + UwacPointerFrameEvent* event; + UwacSeat* seat = data; + UwacWindow* window = seat->pointer_focus; + + if (!window) + return; + + event = (UwacPointerFrameEvent*)UwacDisplayNewEvent(seat->display, UWAC_EVENT_POINTER_FRAME); + if (!event) + return; + + event->seat = seat; + event->window = window; } static void pointer_axis_source(void* data, struct wl_pointer* wl_pointer, uint32_t axis_source) From 4efd7dcec53070b954cfc8b50e0beeb5d68aca97 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Mon, 28 Aug 2023 13:39:08 +0200 Subject: [PATCH 391/496] Updated changelog --- ChangeLog | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index b41bee0e12d6..7fbf6fd33346 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,13 @@ -# 20XX-YY-ZZ Version 2.UU.V +# 2023-08-28 Version 2.11.0 + +Noteworthy changes: +* Various input validation fixes +* Added various CMake options #9317 +* LibreSSL build fixes #8709 Fixed issues: +* Backported #9099: Mouse grabbing support +* Backported #6851: wayland scrolling fix * Backported #8690: Update h264 to use new FFMPEG API * Backported #7306: early bail from update_read_window_state_order breaks protocol * Backported #8903: rdpecam/server: Remove wrong assertion From 1dae018ac0938d30a959cb01cf5c3b67750eba2f Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Mon, 28 Aug 2023 13:41:11 +0200 Subject: [PATCH 392/496] [release] update version --- CMakeLists.txt | 2 +- client/Android/android_freerdp.c | 2 +- winpr/CMakeLists.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index db3dc7c9bb35..063a5401d5c5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -85,7 +85,7 @@ if ($ENV{BUILD_NUMBER}) endif() set(WITH_LIBRARY_VERSIONING "ON") -set(RAW_VERSION_STRING "2.10.0") +set(RAW_VERSION_STRING "2.11.0") if(EXISTS "${CMAKE_SOURCE_DIR}/.source_tag") file(READ ${CMAKE_SOURCE_DIR}/.source_tag RAW_VERSION_STRING) elseif(USE_VERSION_FROM_GIT_TAG) diff --git a/client/Android/android_freerdp.c b/client/Android/android_freerdp.c index 5a506278574e..438f4d5661ed 100644 --- a/client/Android/android_freerdp.c +++ b/client/Android/android_freerdp.c @@ -57,7 +57,7 @@ #define TAG CLIENT_TAG("android") /* Defines the JNI version supported by this library. */ -#define FREERDP_JNI_VERSION "2.10.0" +#define FREERDP_JNI_VERSION "2.11.0" static void android_OnChannelConnectedEventHandler(void* context, ChannelConnectedEventArgs* e) { diff --git a/winpr/CMakeLists.txt b/winpr/CMakeLists.txt index 7b3ef1a6c56c..f1736e474491 100644 --- a/winpr/CMakeLists.txt +++ b/winpr/CMakeLists.txt @@ -57,7 +57,7 @@ if (NOT WIN32) endif() # Soname versioning -set(RAW_VERSION_STRING "2.10.0") +set(RAW_VERSION_STRING "2.11.0") if(EXISTS "${CMAKE_SOURCE_DIR}/.source_tag") file(READ ${CMAKE_SOURCE_DIR}/.source_tag RAW_VERSION_STRING) elseif(USE_VERSION_FROM_GIT_TAG) From e3ef8a02ddf079bcf6dfa58888db69a709ce50c9 Mon Sep 17 00:00:00 2001 From: Joan Torres Date: Mon, 31 Jul 2023 19:07:08 +0200 Subject: [PATCH 393/496] [codec] encode messages considering endianness The byte order of the pixels is affected by endianness, use bitwise operations to access those bytes so the endiannes won't affect the final result. (cherry picked from commit 6ba4aad9ab0d3a039f982494dc40c7fc56a35376) --- libfreerdp/codec/nsc_encode.c | 76 ++++++++++++++++++++++------------- libfreerdp/codec/rfx_encode.c | 74 +++++++++++++++++++++------------- 2 files changed, 92 insertions(+), 58 deletions(-) diff --git a/libfreerdp/codec/nsc_encode.c b/libfreerdp/codec/nsc_encode.c index fd9626a6d2ca..477318cc191c 100644 --- a/libfreerdp/codec/nsc_encode.c +++ b/libfreerdp/codec/nsc_encode.c @@ -119,6 +119,8 @@ static BOOL nsc_encode_argb_to_aycocg(NSC_CONTEXT* context, const BYTE* data, UI UINT16 rw; BYTE ccl; const BYTE* src; + const UINT32* src_32; + const UINT16* src_16; BYTE* yplane = NULL; BYTE* coplane = NULL; BYTE* cgplane = NULL; @@ -140,69 +142,85 @@ static BOOL nsc_encode_argb_to_aycocg(NSC_CONTEXT* context, const BYTE* data, UI coplane = context->priv->PlaneBuffers[1] + y * rw; cgplane = context->priv->PlaneBuffers[2] + y * rw; aplane = context->priv->PlaneBuffers[3] + y * context->width; + src_32 = (UINT32*)src; + src_16 = (UINT16*)src; for (x = 0; x < context->width; x++) { switch (context->format) { case PIXEL_FORMAT_BGRX32: - b_val = *src++; - g_val = *src++; - r_val = *src++; - src++; + b_val = (INT16)(*src_32 & 0xFF); + g_val = (INT16)((*src_32 >> 8) & 0xFF); + r_val = (INT16)((*src_32 >> 16) & 0xFF); a_val = 0xFF; + src_32++; break; case PIXEL_FORMAT_BGRA32: - b_val = *src++; - g_val = *src++; - r_val = *src++; - a_val = *src++; + b_val = (INT16)(*src_32 & 0xFF); + g_val = (INT16)((*src_32 >> 8) & 0xFF); + r_val = (INT16)((*src_32 >> 16) & 0xFF); + a_val = (INT16)((*src_32 >> 24) & 0xFF); + src_32++; break; case PIXEL_FORMAT_RGBX32: - r_val = *src++; - g_val = *src++; - b_val = *src++; - src++; + r_val = (INT16)(*src_32 & 0xFF); + g_val = (INT16)((*src_32 >> 8) & 0xFF); + b_val = (INT16)((*src_32 >> 16) & 0xFF); a_val = 0xFF; + src_32++; break; case PIXEL_FORMAT_RGBA32: - r_val = *src++; - g_val = *src++; - b_val = *src++; - a_val = *src++; + r_val = (INT16)(*src_32 & 0xFF); + g_val = (INT16)((*src_32 >> 8) & 0xFF); + b_val = (INT16)((*src_32 >> 16) & 0xFF); + a_val = (INT16)((*src_32 >> 24) & 0xFF); + src_32++; break; case PIXEL_FORMAT_BGR24: +#ifdef __LITTLE_ENDIAN__ b_val = *src++; g_val = *src++; r_val = *src++; +#else + r_val = *src++; + g_val = *src++; + b_val = *src++; +#endif a_val = 0xFF; break; case PIXEL_FORMAT_RGB24: +#ifdef __LITTLE_ENDIAN__ r_val = *src++; g_val = *src++; b_val = *src++; +#else + b_val = *src++; + g_val = *src++; + r_val = *src++; +#endif a_val = 0xFF; break; case PIXEL_FORMAT_BGR16: - b_val = (INT16)(((*(src + 1)) & 0xF8) | ((*(src + 1)) >> 5)); - g_val = (INT16)((((*(src + 1)) & 0x07) << 5) | (((*src) & 0xE0) >> 3)); - r_val = (INT16)((((*src) & 0x1F) << 3) | (((*src) >> 2) & 0x07)); + b_val = (INT16)((*src_16) & 0x1F); + g_val = (INT16)((*src_16 >> 5) & 0x3F); + r_val = (INT16)((*src_16 >> 11) & 0x1F); a_val = 0xFF; - src += 2; + src_16++; break; case PIXEL_FORMAT_RGB16: - r_val = (INT16)(((*(src + 1)) & 0xF8) | ((*(src + 1)) >> 5)); - g_val = (INT16)((((*(src + 1)) & 0x07) << 5) | (((*src) & 0xE0) >> 3)); - b_val = (INT16)((((*src) & 0x1F) << 3) | (((*src) >> 2) & 0x07)); + r_val = (INT16)((*src_16) & 0x1F); + g_val = (INT16)((*src_16 >> 5) & 0x3F); + b_val = (INT16)((*src_16 >> 11) & 0x1F); a_val = 0xFF; - src += 2; + src_16++; break; case PIXEL_FORMAT_A4: @@ -210,17 +228,17 @@ static BOOL nsc_encode_argb_to_aycocg(NSC_CONTEXT* context, const BYTE* data, UI int shift; BYTE idx; shift = (7 - (x % 8)); - idx = ((*src) >> shift) & 1; - idx |= (((*(src + 1)) >> shift) & 1) << 1; - idx |= (((*(src + 2)) >> shift) & 1) << 2; - idx |= (((*(src + 3)) >> shift) & 1) << 3; + idx = (BYTE)(((*src_32 & 0xFF) >> shift) & 1); + idx |= (BYTE)(((((*src_32 >> 8) & 0xFF) >> shift) & 1) << 1); + idx |= (BYTE)(((((*src_32 >> 16) & 0xFF) >> shift) & 1) << 2); + idx |= (BYTE)(((((*src_32 >> 24) & 0xFF) >> shift) & 1) << 3); idx *= 3; r_val = (INT16)context->palette[idx]; g_val = (INT16)context->palette[idx + 1]; b_val = (INT16)context->palette[idx + 2]; if (shift == 0) - src += 4; + src_32++; } a_val = 0xFF; diff --git a/libfreerdp/codec/rfx_encode.c b/libfreerdp/codec/rfx_encode.c index b4f393605205..355f74340242 100644 --- a/libfreerdp/codec/rfx_encode.c +++ b/libfreerdp/codec/rfx_encode.c @@ -49,6 +49,8 @@ static void rfx_encode_format_rgb(const BYTE* rgb_data, int width, int height, i int x_exceed; int y_exceed; const BYTE* src; + const UINT32* src_32; + const UINT16* src_16; INT16 r, g, b; INT16 *r_last, *g_last, *b_last; x_exceed = 64 - width; @@ -57,6 +59,8 @@ static void rfx_encode_format_rgb(const BYTE* rgb_data, int width, int height, i for (y = 0; y < height; y++) { src = rgb_data + y * rowstride; + src_32 = (UINT32*)src; + src_16 = (UINT16*)src; switch (pixel_format) { @@ -64,10 +68,10 @@ static void rfx_encode_format_rgb(const BYTE* rgb_data, int width, int height, i case PIXEL_FORMAT_BGRA32: for (x = 0; x < width; x++) { - *b_buf++ = (INT16)(*src++); - *g_buf++ = (INT16)(*src++); - *r_buf++ = (INT16)(*src++); - src++; + *b_buf++ = (INT16)(*src_32 & 0xFF); + *g_buf++ = (INT16)((*src_32 >> 8) & 0xFF); + *r_buf++ = (INT16)((*src_32 >> 16) & 0xFF); + src_32++; } break; @@ -76,10 +80,10 @@ static void rfx_encode_format_rgb(const BYTE* rgb_data, int width, int height, i case PIXEL_FORMAT_ABGR32: for (x = 0; x < width; x++) { - src++; - *b_buf++ = (INT16)(*src++); - *g_buf++ = (INT16)(*src++); - *r_buf++ = (INT16)(*src++); + *b_buf++ = (INT16)((*src_32 >> 8) & 0xFF); + *g_buf++ = (INT16)((*src_32 >> 16) & 0xFF); + *r_buf++ = (INT16)((*src_32 >> 24) & 0xFF); + src_32++; } break; @@ -88,10 +92,10 @@ static void rfx_encode_format_rgb(const BYTE* rgb_data, int width, int height, i case PIXEL_FORMAT_RGBA32: for (x = 0; x < width; x++) { - *r_buf++ = (INT16)(*src++); - *g_buf++ = (INT16)(*src++); - *b_buf++ = (INT16)(*src++); - src++; + *r_buf++ = (INT16)(*src_32 & 0xFF); + *g_buf++ = (INT16)((*src_32 >> 8) & 0xFF); + *b_buf++ = (INT16)((*src_32 >> 16) & 0xFF); + src_32++; } break; @@ -100,10 +104,10 @@ static void rfx_encode_format_rgb(const BYTE* rgb_data, int width, int height, i case PIXEL_FORMAT_ARGB32: for (x = 0; x < width; x++) { - src++; - *r_buf++ = (INT16)(*src++); - *g_buf++ = (INT16)(*src++); - *b_buf++ = (INT16)(*src++); + *r_buf++ = (INT16)((*src_32 >> 8) & 0xFF); + *g_buf++ = (INT16)((*src_32 >> 16) & 0xFF); + *b_buf++ = (INT16)((*src_32 >> 24) & 0xFF); + src_32++; } break; @@ -111,9 +115,15 @@ static void rfx_encode_format_rgb(const BYTE* rgb_data, int width, int height, i case PIXEL_FORMAT_BGR24: for (x = 0; x < width; x++) { +#ifdef __LITTLE_ENDIAN__ *b_buf++ = (INT16)(*src++); *g_buf++ = (INT16)(*src++); *r_buf++ = (INT16)(*src++); +#else + *r_buf++ = (INT16)(*src++); + *g_buf++ = (INT16)(*src++); + *b_buf++ = (INT16)(*src++); +#endif } break; @@ -121,9 +131,15 @@ static void rfx_encode_format_rgb(const BYTE* rgb_data, int width, int height, i case PIXEL_FORMAT_RGB24: for (x = 0; x < width; x++) { +#ifdef __LITTLE_ENDIAN__ *r_buf++ = (INT16)(*src++); *g_buf++ = (INT16)(*src++); *b_buf++ = (INT16)(*src++); +#else + *b_buf++ = (INT16)(*src++); + *g_buf++ = (INT16)(*src++); + *r_buf++ = (INT16)(*src++); +#endif } break; @@ -131,10 +147,10 @@ static void rfx_encode_format_rgb(const BYTE* rgb_data, int width, int height, i case PIXEL_FORMAT_BGR16: for (x = 0; x < width; x++) { - *b_buf++ = (INT16)(((*(src + 1)) & 0xF8) | ((*(src + 1)) >> 5)); - *g_buf++ = (INT16)((((*(src + 1)) & 0x07) << 5) | (((*src) & 0xE0) >> 3)); - *r_buf++ = (INT16)((((*src) & 0x1F) << 3) | (((*src) >> 2) & 0x07)); - src += 2; + *b_buf++ = (INT16)((*src_16) & 0x1F); + *g_buf++ = (INT16)((*src_16 >> 5) & 0x3F); + *r_buf++ = (INT16)((*src_16 >> 11) & 0x1F); + src_16++; } break; @@ -142,10 +158,10 @@ static void rfx_encode_format_rgb(const BYTE* rgb_data, int width, int height, i case PIXEL_FORMAT_RGB16: for (x = 0; x < width; x++) { - *r_buf++ = (INT16)(((*(src + 1)) & 0xF8) | ((*(src + 1)) >> 5)); - *g_buf++ = (INT16)((((*(src + 1)) & 0x07) << 5) | (((*src) & 0xE0) >> 3)); - *b_buf++ = (INT16)((((*src) & 0x1F) << 3) | (((*src) >> 2) & 0x07)); - src += 2; + *r_buf++ = (INT16)((*src_16 & 0x1F)); + *g_buf++ = (INT16)((*src_16 >> 5) & 0x3F); + *b_buf++ = (INT16)((*src_16 >> 11) & 0x1F); + src_16++; } break; @@ -159,17 +175,17 @@ static void rfx_encode_format_rgb(const BYTE* rgb_data, int width, int height, i int shift; BYTE idx; shift = (7 - (x % 8)); - idx = ((*src) >> shift) & 1; - idx |= (((*(src + 1)) >> shift) & 1) << 1; - idx |= (((*(src + 2)) >> shift) & 1) << 2; - idx |= (((*(src + 3)) >> shift) & 1) << 3; + idx = (BYTE)(((*src_32 & 0xFF) >> shift) & 1); + idx |= (BYTE)(((((*src_32 >> 8) & 0xFF) >> shift) & 1) << 1); + idx |= (BYTE)(((((*src_32 >> 16) & 0xFF) >> shift) & 1) << 2); + idx |= (BYTE)(((((*src_32 >> 24) & 0xFF) >> shift) & 1) << 3); idx *= 3; *r_buf++ = (INT16)palette[idx]; *g_buf++ = (INT16)palette[idx + 1]; *b_buf++ = (INT16)palette[idx + 2]; if (shift == 0) - src += 4; + src_32++; } break; From 16047bd16f159ee4aea581854170e83c36862793 Mon Sep 17 00:00:00 2001 From: Joan Torres Date: Mon, 31 Jul 2023 19:01:31 +0200 Subject: [PATCH 394/496] [libfreerdp] fix endianness issues There were some fields sent without considering endianness, making the clients fail when parsing those fields. Use Data_Write_XXX functions so the endiannes won't affect the byte order and the clients will read properly the fields. (cherry picked from commit 8d6c27ba10955985b3880f65a793a8bf142681a7) --- libfreerdp/codec/xcrush.c | 14 +++++++------- libfreerdp/core/server.c | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/libfreerdp/codec/xcrush.c b/libfreerdp/codec/xcrush.c index 350801df338e..56bf649f5560 100644 --- a/libfreerdp/codec/xcrush.c +++ b/libfreerdp/codec/xcrush.c @@ -674,7 +674,7 @@ static int xcrush_generate_output(XCRUSH_CONTEXT* xcrush, BYTE* OutputBuffer, UI if (&OutputBuffer[2] >= &OutputBuffer[OutputSize]) return -6001; /* error */ - *((UINT16*)OutputBuffer) = MatchCount; + Data_Write_UINT16(OutputBuffer, MatchCount); MatchDetails = (RDP61_MATCH_DETAILS*)&OutputBuffer[2]; Literals = (BYTE*)&MatchDetails[MatchCount]; @@ -683,12 +683,12 @@ static int xcrush_generate_output(XCRUSH_CONTEXT* xcrush, BYTE* OutputBuffer, UI for (MatchIndex = 0; MatchIndex < MatchCount; MatchIndex++) { - MatchDetails[MatchIndex].MatchLength = - (UINT16)(xcrush->OptimizedMatches[MatchIndex].MatchLength); - MatchDetails[MatchIndex].MatchOutputOffset = - (UINT16)(xcrush->OptimizedMatches[MatchIndex].MatchOffset - HistoryOffset); - MatchDetails[MatchIndex].MatchHistoryOffset = - xcrush->OptimizedMatches[MatchIndex].ChunkOffset; + Data_Write_UINT16(&MatchDetails[MatchIndex].MatchLength, + xcrush->OptimizedMatches[MatchIndex].MatchLength); + Data_Write_UINT16(&MatchDetails[MatchIndex].MatchOutputOffset, + xcrush->OptimizedMatches[MatchIndex].MatchOffset - HistoryOffset); + Data_Write_UINT32(&MatchDetails[MatchIndex].MatchHistoryOffset, + xcrush->OptimizedMatches[MatchIndex].ChunkOffset); } CurrentOffset = HistoryOffset; diff --git a/libfreerdp/core/server.c b/libfreerdp/core/server.c index a786cbd8e4e1..b8298a22a84d 100644 --- a/libfreerdp/core/server.c +++ b/libfreerdp/core/server.c @@ -493,7 +493,7 @@ BOOL WTSVirtualChannelManagerCheckFileDescriptor(HANDLE hServer) { ULONG written; vcm->drdynvc_channel = channel; - dynvc_caps = 0x00010050; /* DYNVC_CAPS_VERSION1 (4 bytes) */ + Data_Write_UINT32(&dynvc_caps, 0x00010050); /* DYNVC_CAPS_VERSION1 (4 bytes) */ if (!WTSVirtualChannelWrite(channel, (PCHAR)&dynvc_caps, sizeof(dynvc_caps), &written)) return FALSE; From 1384b3c33b9bd7599633cc54bf20cf20ec6be83c Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Mon, 28 Aug 2023 14:19:18 +0200 Subject: [PATCH 395/496] Updated changelog --- ChangeLog | 1 + 1 file changed, 1 insertion(+) diff --git a/ChangeLog b/ChangeLog index 7fbf6fd33346..80cfe216ae6b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -6,6 +6,7 @@ Noteworthy changes: * LibreSSL build fixes #8709 Fixed issues: +* Backported #9233: Big endian support * Backported #9099: Mouse grabbing support * Backported #6851: wayland scrolling fix * Backported #8690: Update h264 to use new FFMPEG API From 23db2f4e6ba71f1c10c543f24de595d7340adb46 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Mon, 4 Sep 2023 09:43:32 +0200 Subject: [PATCH 396/496] [core,orders] fix reading order number field the field for delta rectangles/points/... are only transmitted if they changed from the previous order of the same type. So keep the original value and update only if a new one is read. (cherry picked from commit 5b7cf4acc6b4138c513287a2eaa2c7fb9dfbf5c8) --- libfreerdp/core/orders.c | 97 +++++++++++++++++++++++++++++++++++----- 1 file changed, 85 insertions(+), 12 deletions(-) diff --git a/libfreerdp/core/orders.c b/libfreerdp/core/orders.c index 013dc8e8c9c5..0f19914d7d93 100644 --- a/libfreerdp/core/orders.c +++ b/libfreerdp/core/orders.c @@ -1374,12 +1374,13 @@ static BOOL update_read_draw_nine_grid_order(wStream* s, const ORDER_INFO* order static BOOL update_read_multi_dstblt_order(wStream* s, const ORDER_INFO* orderInfo, MULTI_DSTBLT_ORDER* multi_dstblt) { + UINT32 numRectangles = multi_dstblt->numRectangles; if (!read_order_field_coord(orderInfo, s, 1, &multi_dstblt->nLeftRect, FALSE) || !read_order_field_coord(orderInfo, s, 2, &multi_dstblt->nTopRect, FALSE) || !read_order_field_coord(orderInfo, s, 3, &multi_dstblt->nWidth, FALSE) || !read_order_field_coord(orderInfo, s, 4, &multi_dstblt->nHeight, FALSE) || !read_order_field_byte(orderInfo, s, 5, &multi_dstblt->bRop, TRUE) || - !read_order_field_byte(orderInfo, s, 6, &multi_dstblt->numRectangles, TRUE)) + !read_order_field_byte(orderInfo, s, 6, &numRectangles, TRUE)) return FALSE; if ((orderInfo->fieldFlags & ORDER_FIELD_07) != 0) @@ -1387,12 +1388,21 @@ static BOOL update_read_multi_dstblt_order(wStream* s, const ORDER_INFO* orderIn if (Stream_GetRemainingLength(s) < 2) return FALSE; + multi_dstblt->numRectangles = numRectangles; Stream_Read_UINT16(s, multi_dstblt->cbData); return update_read_delta_rects(s, multi_dstblt->rectangles, &multi_dstblt->numRectangles); } - - return multi_dstblt->numRectangles == 0; + if (numRectangles > multi_dstblt->numRectangles) + { + const char* orderName = __func__; + WLog_ERR(TAG, "%s numRectangles %" PRIu32 " > %" PRIu32, orderName, numRectangles, + multi_dstblt->numRectangles); + return FALSE; + } + multi_dstblt->numRectangles = numRectangles; + return TRUE; } + static BOOL update_read_multi_patblt_order(wStream* s, const ORDER_INFO* orderInfo, MULTI_PATBLT_ORDER* multi_patblt) { @@ -1408,7 +1418,8 @@ static BOOL update_read_multi_patblt_order(wStream* s, const ORDER_INFO* orderIn if (!update_read_brush(s, &multi_patblt->brush, orderInfo->fieldFlags >> 7)) return FALSE; - if (!read_order_field_byte(orderInfo, s, 13, &multi_patblt->numRectangles, TRUE)) + UINT32 numRectangles = multi_patblt->numRectangles; + if (!read_order_field_byte(orderInfo, s, 13, &numRectangles, TRUE)) return FALSE; if ((orderInfo->fieldFlags & ORDER_FIELD_14) != 0) @@ -1416,13 +1427,21 @@ static BOOL update_read_multi_patblt_order(wStream* s, const ORDER_INFO* orderIn if (Stream_GetRemainingLength(s) < 2) return FALSE; + multi_patblt->numRectangles = numRectangles; Stream_Read_UINT16(s, multi_patblt->cbData); if (!update_read_delta_rects(s, multi_patblt->rectangles, &multi_patblt->numRectangles)) return FALSE; } - else if (multi_patblt->numRectangles != 0) + + if (numRectangles > multi_patblt->numRectangles) + { + const char* orderName = __func__; + WLog_ERR(TAG, "%s numRectangles %" PRIu32 " > %" PRIu32, orderName, numRectangles, + multi_patblt->numRectangles); return FALSE; + } + multi_patblt->numRectangles = numRectangles; return TRUE; } @@ -1432,7 +1451,7 @@ static BOOL update_read_multi_scrblt_order(wStream* s, const ORDER_INFO* orderIn WINPR_ASSERT(orderInfo); WINPR_ASSERT(multi_scrblt); - multi_scrblt->numRectangles = 0; + UINT32 numRectangles = multi_scrblt->numRectangles; if (!read_order_field_coord(orderInfo, s, 1, &multi_scrblt->nLeftRect, FALSE) || !read_order_field_coord(orderInfo, s, 2, &multi_scrblt->nTopRect, FALSE) || !read_order_field_coord(orderInfo, s, 3, &multi_scrblt->nWidth, FALSE) || @@ -1440,7 +1459,7 @@ static BOOL update_read_multi_scrblt_order(wStream* s, const ORDER_INFO* orderIn !read_order_field_byte(orderInfo, s, 5, &multi_scrblt->bRop, TRUE) || !read_order_field_coord(orderInfo, s, 6, &multi_scrblt->nXSrc, FALSE) || !read_order_field_coord(orderInfo, s, 7, &multi_scrblt->nYSrc, FALSE) || - !read_order_field_byte(orderInfo, s, 8, &multi_scrblt->numRectangles, TRUE)) + !read_order_field_byte(orderInfo, s, 8, &numRectangles, TRUE)) return FALSE; if ((orderInfo->fieldFlags & ORDER_FIELD_09) != 0) @@ -1448,11 +1467,21 @@ static BOOL update_read_multi_scrblt_order(wStream* s, const ORDER_INFO* orderIn if (Stream_GetRemainingLength(s) < 2) return FALSE; + multi_scrblt->numRectangles = numRectangles; Stream_Read_UINT16(s, multi_scrblt->cbData); return update_read_delta_rects(s, multi_scrblt->rectangles, &multi_scrblt->numRectangles); } - return multi_scrblt->numRectangles == 0; + if (numRectangles > multi_scrblt->numRectangles) + { + const char* orderName = __func__; + WLog_ERR(TAG, "%s numRectangles %" PRIu32 " > %" PRIu32, orderName, numRectangles, + multi_scrblt->numRectangles); + return FALSE; + } + multi_scrblt->numRectangles = numRectangles; + + return TRUE; } static BOOL update_read_multi_opaque_rect_order(wStream* s, const ORDER_INFO* orderInfo, MULTI_OPAQUE_RECT_ORDER* multi_opaque_rect) @@ -1491,7 +1520,8 @@ static BOOL update_read_multi_opaque_rect_order(wStream* s, const ORDER_INFO* or multi_opaque_rect->color = (multi_opaque_rect->color & 0x0000FFFF) | ((UINT32)byte << 16); } - if (!read_order_field_byte(orderInfo, s, 8, &multi_opaque_rect->numRectangles, TRUE)) + UINT32 numRectangles = multi_opaque_rect->numRectangles; + if (!read_order_field_byte(orderInfo, s, 8, &numRectangles, TRUE)) return FALSE; if ((orderInfo->fieldFlags & ORDER_FIELD_09) != 0) @@ -1499,22 +1529,32 @@ static BOOL update_read_multi_opaque_rect_order(wStream* s, const ORDER_INFO* or if (Stream_GetRemainingLength(s) < 2) return FALSE; + multi_opaque_rect->numRectangles = numRectangles; Stream_Read_UINT16(s, multi_opaque_rect->cbData); return update_read_delta_rects(s, multi_opaque_rect->rectangles, &multi_opaque_rect->numRectangles); } + if (numRectangles > multi_opaque_rect->numRectangles) + { + const char* orderName = __func__; + WLog_ERR(TAG, "%s numRectangles %" PRIu32 " > %" PRIu32, orderName, numRectangles, + multi_opaque_rect->numRectangles); + return FALSE; + } + multi_opaque_rect->numRectangles = numRectangles; - return multi_opaque_rect->numRectangles == 0; + return TRUE; } static BOOL update_read_multi_draw_nine_grid_order(wStream* s, const ORDER_INFO* orderInfo, MULTI_DRAW_NINE_GRID_ORDER* multi_draw_nine_grid) { + UINT32 nDeltaEntries = multi_draw_nine_grid->nDeltaEntries; if (!read_order_field_coord(orderInfo, s, 1, &multi_draw_nine_grid->srcLeft, FALSE) || !read_order_field_coord(orderInfo, s, 2, &multi_draw_nine_grid->srcTop, FALSE) || !read_order_field_coord(orderInfo, s, 3, &multi_draw_nine_grid->srcRight, FALSE) || !read_order_field_coord(orderInfo, s, 4, &multi_draw_nine_grid->srcBottom, FALSE) || !read_order_field_uint16(orderInfo, s, 5, &multi_draw_nine_grid->bitmapId, TRUE) || - !read_order_field_byte(orderInfo, s, 6, &multi_draw_nine_grid->nDeltaEntries, TRUE)) + !read_order_field_byte(orderInfo, s, 6, &nDeltaEntries, TRUE)) return FALSE; if ((orderInfo->fieldFlags & ORDER_FIELD_07) != 0) @@ -1522,12 +1562,22 @@ static BOOL update_read_multi_draw_nine_grid_order(wStream* s, const ORDER_INFO* if (Stream_GetRemainingLength(s) < 2) return FALSE; + multi_draw_nine_grid->nDeltaEntries = nDeltaEntries; Stream_Read_UINT16(s, multi_draw_nine_grid->cbData); return update_read_delta_rects(s, multi_draw_nine_grid->rectangles, &multi_draw_nine_grid->nDeltaEntries); } - return multi_draw_nine_grid->nDeltaEntries == 0; + if (nDeltaEntries > multi_draw_nine_grid->nDeltaEntries) + { + const char* orderName = __func__; + WLog_ERR(TAG, "%s nDeltaEntries %" PRIu32 " > %" PRIu32, orderName, nDeltaEntries, + multi_draw_nine_grid->nDeltaEntries); + return FALSE; + } + multi_draw_nine_grid->nDeltaEntries = nDeltaEntries; + + return TRUE; } static BOOL update_read_line_to_order(wStream* s, const ORDER_INFO* orderInfo, LINE_TO_ORDER* line_to) @@ -1617,6 +1667,14 @@ static BOOL update_read_polyline_order(wStream* s, const ORDER_INFO* orderInfo, return update_read_delta_points(s, polyline->points, polyline->numDeltaEntries, polyline->xStart, polyline->yStart); } + if (new_num > polyline->numDeltaEntries) + { + const char* orderName = __func__; + WLog_ERR(TAG, "%s numDeltaEntries %" PRIu32 " > %" PRIu32, orderName, new_num, + polyline->numDeltaEntries); + return FALSE; + } + polyline->numDeltaEntries = new_num; return TRUE; } @@ -1949,6 +2007,13 @@ static BOOL update_read_polygon_sc_order(wStream* s, const ORDER_INFO* orderInfo return update_read_delta_points(s, polygon_sc->points, polygon_sc->numPoints, polygon_sc->xStart, polygon_sc->yStart); } + if (num > polygon_sc->numPoints) + { + const char* orderName = __func__; + WLog_ERR(TAG, "%s numPoints %" PRIu32 " > %" PRIu32, orderName, num, polygon_sc->numPoints); + return FALSE; + } + polygon_sc->numPoints = num; return TRUE; } @@ -1994,6 +2059,14 @@ static BOOL update_read_polygon_cb_order(wStream* s, const ORDER_INFO* orderInfo return FALSE; } + if (num > polygon_cb->numPoints) + { + const char* orderName = __func__; + WLog_ERR(TAG, "%s numPoints %" PRIu32 " > %" PRIu32, orderName, num, polygon_cb->numPoints); + return FALSE; + } + polygon_cb->numPoints = num; + polygon_cb->backMode = (polygon_cb->bRop2 & 0x80) ? BACKMODE_TRANSPARENT : BACKMODE_OPAQUE; polygon_cb->bRop2 = (polygon_cb->bRop2 & 0x1F); return TRUE; From 270e77216586bc4f757aaf5a85df22f757009f38 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Mon, 4 Sep 2023 11:46:21 +0200 Subject: [PATCH 397/496] [release] update changelog --- ChangeLog | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/ChangeLog b/ChangeLog index 80cfe216ae6b..6c828d352e4a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +# 2023-09-04 Version 2.11.1 + +Notworthy changes: +* Backported #9356: Fix issues with order updates + +For a complete and detailed change log since the last release run: +git log 2.11.1..2.11.0 + # 2023-08-28 Version 2.11.0 Noteworthy changes: From 9d3d40bf3e429c0cd6609f686c0e73ed0eff0a07 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Mon, 4 Sep 2023 11:44:54 +0200 Subject: [PATCH 398/496] [release] update version to 2.11.1 --- CMakeLists.txt | 2 +- client/Android/android_freerdp.c | 2 +- winpr/CMakeLists.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 063a5401d5c5..18d4631d94ce 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -85,7 +85,7 @@ if ($ENV{BUILD_NUMBER}) endif() set(WITH_LIBRARY_VERSIONING "ON") -set(RAW_VERSION_STRING "2.11.0") +set(RAW_VERSION_STRING "2.11.1") if(EXISTS "${CMAKE_SOURCE_DIR}/.source_tag") file(READ ${CMAKE_SOURCE_DIR}/.source_tag RAW_VERSION_STRING) elseif(USE_VERSION_FROM_GIT_TAG) diff --git a/client/Android/android_freerdp.c b/client/Android/android_freerdp.c index 438f4d5661ed..0d3ee7d7df3f 100644 --- a/client/Android/android_freerdp.c +++ b/client/Android/android_freerdp.c @@ -57,7 +57,7 @@ #define TAG CLIENT_TAG("android") /* Defines the JNI version supported by this library. */ -#define FREERDP_JNI_VERSION "2.11.0" +#define FREERDP_JNI_VERSION "2.11.1" static void android_OnChannelConnectedEventHandler(void* context, ChannelConnectedEventArgs* e) { diff --git a/winpr/CMakeLists.txt b/winpr/CMakeLists.txt index f1736e474491..7c64824c884a 100644 --- a/winpr/CMakeLists.txt +++ b/winpr/CMakeLists.txt @@ -57,7 +57,7 @@ if (NOT WIN32) endif() # Soname versioning -set(RAW_VERSION_STRING "2.11.0") +set(RAW_VERSION_STRING "2.11.1") if(EXISTS "${CMAKE_SOURCE_DIR}/.source_tag") file(READ ${CMAKE_SOURCE_DIR}/.source_tag RAW_VERSION_STRING) elseif(USE_VERSION_FROM_GIT_TAG) From e93433fb21231dba2b989b38e058706c3e46d9e2 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Mon, 4 Sep 2023 13:32:51 +0200 Subject: [PATCH 399/496] [crypto] backport certificate alg detection use the more robust code from FreeRDP 3.0 to detect the hash algorightm of a certificate --- libfreerdp/crypto/crypto.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/libfreerdp/crypto/crypto.c b/libfreerdp/crypto/crypto.c index 68590d0fa7db..f08a4b842736 100644 --- a/libfreerdp/crypto/crypto.c +++ b/libfreerdp/crypto/crypto.c @@ -950,10 +950,12 @@ WINPR_MD_TYPE crypto_cert_get_signature_alg(X509* xcert) { WINPR_ASSERT(xcert); - const int nid = X509_get_signature_nid(xcert); + EVP_PKEY* evp = X509_get0_pubkey(xcert); + WINPR_ASSERT(evp); int hash_nid = 0; - if (OBJ_find_sigid_algs(nid, &hash_nid, NULL) != 1) + const int res = EVP_PKEY_get_default_digest_nid(evp, &hash_nid); + if (res <= 0) return WINPR_MD_NONE; switch (hash_nid) From 0472543b019d01280ed6ac7806d79f304bc95eaf Mon Sep 17 00:00:00 2001 From: akallabeth Date: Mon, 11 Sep 2023 17:29:38 +0200 Subject: [PATCH 400/496] [winpr,collections] implement duplication for wArrayList --- winpr/libwinpr/utils/collections/ArrayList.c | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/winpr/libwinpr/utils/collections/ArrayList.c b/winpr/libwinpr/utils/collections/ArrayList.c index f8fc3df065d0..cb7e39a35e7c 100644 --- a/winpr/libwinpr/utils/collections/ArrayList.c +++ b/winpr/libwinpr/utils/collections/ArrayList.c @@ -233,6 +233,18 @@ BOOL ArrayList_Contains(wArrayList* arrayList, void* obj) * Adds an object to the end of the ArrayList. */ +static int insert(wArrayList* arrayList, size_t index, void* obj) +{ + if (arrayList->object.fnObjectNew) + { + obj = arrayList->object.fnObjectNew(obj); + arrayList->array[index] = obj; + } + else + arrayList->array[index] = obj; + return index + 1; +} + int ArrayList_Add(wArrayList* arrayList, void* obj) { int index = -1; @@ -253,8 +265,7 @@ int ArrayList_Add(wArrayList* arrayList, void* obj) arrayList->capacity = newCapacity; } - arrayList->array[arrayList->size++] = obj; - index = arrayList->size; + index = arrayList->size = insert(arrayList, arrayList->size, obj); out: if (arrayList->synchronized) @@ -282,7 +293,7 @@ BOOL ArrayList_Insert(wArrayList* arrayList, int index, void* obj) } else { - arrayList->array[index] = obj; + insert(arrayList, index, obj); } } From b84069f753b44d64b6c774931b5768e6a3e4936d Mon Sep 17 00:00:00 2001 From: akallabeth Date: Wed, 20 Sep 2023 09:33:14 +0200 Subject: [PATCH 401/496] changelog --- ChangeLog | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/ChangeLog b/ChangeLog index 6c828d352e4a..9405152bd186 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +# 2023-09-20 Version 2.11.2 + +Notworthy changes: +* Backported #9378: backported wArrayList (optional) copy on insert +* Backported #9360: backported certificate algorithm detection + +For a complete and detailed change log since the last release run: +git log 2.11.2..2.11.1 + # 2023-09-04 Version 2.11.1 Notworthy changes: From a38c1be9eee39a9bc22b511fffe96e63fdf8ebe7 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Wed, 20 Sep 2023 09:34:04 +0200 Subject: [PATCH 402/496] update to 2.11.2 --- CMakeLists.txt | 2 +- client/Android/android_freerdp.c | 2 +- winpr/CMakeLists.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 18d4631d94ce..45affd55ce6f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -85,7 +85,7 @@ if ($ENV{BUILD_NUMBER}) endif() set(WITH_LIBRARY_VERSIONING "ON") -set(RAW_VERSION_STRING "2.11.1") +set(RAW_VERSION_STRING "2.11.2") if(EXISTS "${CMAKE_SOURCE_DIR}/.source_tag") file(READ ${CMAKE_SOURCE_DIR}/.source_tag RAW_VERSION_STRING) elseif(USE_VERSION_FROM_GIT_TAG) diff --git a/client/Android/android_freerdp.c b/client/Android/android_freerdp.c index 0d3ee7d7df3f..142caaeb7f18 100644 --- a/client/Android/android_freerdp.c +++ b/client/Android/android_freerdp.c @@ -57,7 +57,7 @@ #define TAG CLIENT_TAG("android") /* Defines the JNI version supported by this library. */ -#define FREERDP_JNI_VERSION "2.11.1" +#define FREERDP_JNI_VERSION "2.11.2" static void android_OnChannelConnectedEventHandler(void* context, ChannelConnectedEventArgs* e) { diff --git a/winpr/CMakeLists.txt b/winpr/CMakeLists.txt index 7c64824c884a..34dd6dfb98b6 100644 --- a/winpr/CMakeLists.txt +++ b/winpr/CMakeLists.txt @@ -57,7 +57,7 @@ if (NOT WIN32) endif() # Soname versioning -set(RAW_VERSION_STRING "2.11.1") +set(RAW_VERSION_STRING "2.11.2") if(EXISTS "${CMAKE_SOURCE_DIR}/.source_tag") file(READ ${CMAKE_SOURCE_DIR}/.source_tag RAW_VERSION_STRING) elseif(USE_VERSION_FROM_GIT_TAG) From b27b20b2a27217be44fbc5d734299dc45572a207 Mon Sep 17 00:00:00 2001 From: Koichiro Iwao Date: Sun, 24 Sep 2023 01:47:36 +0900 Subject: [PATCH 403/496] [client,cmdline] Advertise Image RFX GUID when rfx-mode:image (cherry picked from commit c1772999741a6609b47e57ee42553acd02c4b1f1) --- client/common/cmdline.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/client/common/cmdline.c b/client/common/cmdline.c index 19ece39016d2..df5e8e820f63 100644 --- a/client/common/cmdline.c +++ b/client/common/cmdline.c @@ -2728,7 +2728,10 @@ int freerdp_client_settings_parse_command_line_arguments(rdpSettings* settings, if (strcmp(arg->Value, "video") == 0) settings->RemoteFxCodecMode = 0x00; else if (strcmp(arg->Value, "image") == 0) + { + settings->RemoteFxImageCodec = TRUE; settings->RemoteFxCodecMode = 0x02; + } } CommandLineSwitchCase(arg, "frame-ack") { From b389d02d31063f601e395482ea21718c539210c4 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Tue, 17 Oct 2023 12:27:52 +0200 Subject: [PATCH 404/496] Fix #9469: Disable WITH_MEDIAFOUNDATION by default the h264 decoder does have issues, deactivate by default until resolved. --- ChangeLog | 5 +++++ cmake/ConfigOptions.cmake | 24 ++++++++++++------------ 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/ChangeLog b/ChangeLog index 9405152bd186..bdb82968fc84 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +# 20xx-xx-xx Version 2.xx.xx + +Notworthy changes: +* Disabled windows MEDIA FOUNDATION h264 decoder due to reported issues (#9469) + # 2023-09-20 Version 2.11.2 Notworthy changes: diff --git a/cmake/ConfigOptions.cmake b/cmake/ConfigOptions.cmake index 1a6a359b7e9e..f16a42ca116b 100644 --- a/cmake/ConfigOptions.cmake +++ b/cmake/ConfigOptions.cmake @@ -47,12 +47,12 @@ if(NOT WIN32) CMAKE_DEPENDENT_OPTION(WITH_SANITIZE_ADDRESS "Compile with gcc/clang address sanitizer." OFF "NOT WITH_VALGRIND_MEMCHECK; NOT WITH_SANITIZE_MEMORY; NOT WITH_SANITIZE_THREAD" OFF) CMAKE_DEPENDENT_OPTION(WITH_SANITIZE_MEMORY "Compile with gcc/clang memory sanitizer." OFF - "NOT WITH_VALGRIND_MEMCHECK; NOT WITH_SANITIZE_ADDRESS; NOT WITH_SANITIZE_THREAD" OFF) + "NOT WITH_VALGRIND_MEMCHECK; NOT WITH_SANITIZE_ADDRESS; NOT WITH_SANITIZE_THREAD" OFF) CMAKE_DEPENDENT_OPTION(WITH_SANITIZE_THREAD "Compile with gcc/clang thread sanitizer." OFF "NOT WITH_VALGRIND_MEMCHECK; NOT WITH_SANITIZE_ADDRESS; NOT WITH_SANITIZE_MEMORY" OFF) else() if(NOT UWP) - option(WITH_MEDIA_FOUNDATION "Enable H264 media foundation decoder." ON) + option(WITH_MEDIA_FOUNDATION "Enable H264 media foundation decoder." OFF) endif() endif() @@ -98,7 +98,7 @@ option(WITH_SERVER_INTERFACE "Build servers as a library with an interface" ON) option(WITH_DEBUG_ALL "Print all debug messages." OFF) if(WITH_DEBUG_ALL) - message(WARNING "WITH_DEBUG_ALL=ON, the build will be slow and might leak sensitive information, do not use with release builds!") + message(WARNING "WITH_DEBUG_ALL=ON, the build will be slow and might leak sensitive information, do not use with release builds!") set(DEFAULT_DEBUG_OPTION "ON") else() set(DEFAULT_DEBUG_OPTION "OFF") @@ -106,7 +106,7 @@ endif() option(WITH_DEBUG_CERTIFICATE "Print certificate related debug messages." ${DEFAULT_DEBUG_OPTION}) if(WITH_DEBUG_CERTIFICATE) - message(WARNING "WITH_DEBUG_CERTIFICATE=ON, the build might leak sensitive information, do not use with release builds!") + message(WARNING "WITH_DEBUG_CERTIFICATE=ON, the build might leak sensitive information, do not use with release builds!") endif() option(WITH_DEBUG_CAPABILITIES "Print capability negotiation debug messages." ${DEFAULT_DEBUG_OPTION}) option(WITH_DEBUG_CHANNELS "Print channel manager debug messages." ${DEFAULT_DEBUG_OPTION}) @@ -116,23 +116,23 @@ option(WITH_DEBUG_DVC "Print dynamic virtual channel debug messages." ${DEFAULT_ CMAKE_DEPENDENT_OPTION(WITH_DEBUG_TSMF "Print TSMF virtual channel debug messages." ${DEFAULT_DEBUG_OPTION} "CHANNEL_TSMF" OFF) option(WITH_DEBUG_KBD "Print keyboard related debug messages." OFF) if(WITH_DEBUG_KBD) - message(WARNING "WITH_DEBUG_KBD=ON, the build might leak sensitive information, do not use with release builds!") + message(WARNING "WITH_DEBUG_KBD=ON, the build might leak sensitive information, do not use with release builds!") endif() option(WITH_DEBUG_LICENSE "Print license debug messages." OFF) if(WITH_DEBUG_LICENSE) - message(WARNING "WITH_DEBUG_LICENSE=ON, the build might leak sensitive information, do not use with release builds!") + message(WARNING "WITH_DEBUG_LICENSE=ON, the build might leak sensitive information, do not use with release builds!") endif() option(WITH_DEBUG_NEGO "Print negotiation related debug messages." OFF) if(WITH_DEBUG_NEGO) - message(WARNING "WITH_DEBUG_NEGO=ON, the build might leak sensitive information, do not use with release builds!") + message(WARNING "WITH_DEBUG_NEGO=ON, the build might leak sensitive information, do not use with release builds!") endif() option(WITH_DEBUG_NLA "Print authentication related debug messages." OFF) if(WITH_DEBUG_NLA) - message(WARNING "WITH_DEBUG_NLA=ON, the build might leak sensitive information, do not use with release builds!") + message(WARNING "WITH_DEBUG_NLA=ON, the build might leak sensitive information, do not use with release builds!") endif() option(WITH_DEBUG_NTLM "Print NTLM debug messages" OFF) if(WITH_DEBUG_NTLM) - message(WARNING "WITH_DEBUG_NTLM=ON, the build might leak sensitive information, do not use with release builds!") + message(WARNING "WITH_DEBUG_NTLM=ON, the build might leak sensitive information, do not use with release builds!") endif() option(WITH_DEBUG_TSG "Print Terminal Server Gateway debug messages" ${DEFAULT_DEBUG_OPTION}) option(WITH_DEBUG_RAIL "Print RemoteApp debug messages" ${DEFAULT_DEBUG_OPTION}) @@ -163,13 +163,13 @@ option(WITH_GSSAPI "Compile support for kerberos authentication. (EXPERIMENTAL)" option(WITH_DSP_EXPERIMENTAL "Enable experimental sound encoder/decoder formats" OFF) if (WITH_FFMPEG) - option(WITH_DSP_FFMPEG "Use FFMPEG for audio encoding/decoding" OFF) - option(WITH_VAAPI "Use FFMPEG VAAPI (EXPERIMENTAL)" OFF) + option(WITH_DSP_FFMPEG "Use FFMPEG for audio encoding/decoding" OFF) + option(WITH_VAAPI "Use FFMPEG VAAPI (EXPERIMENTAL)" OFF) endif(WITH_FFMPEG) option(USE_VERSION_FROM_GIT_TAG "Extract FreeRDP version from git tag." OFF) -option(WITH_CAIRO "Use CAIRO image library for screen resizing" OFF) +option(WITH_CAIRO "Use CAIRO image library for screen resizing" OFF) option(WITH_SWSCALE "Use SWScale image library for screen resizing" OFF) option(DEFINE_NO_DEPRECATED "Compile without legacy functions and symbols" OFF) From fc17d472c9bf376f7943cdf70bc05fc266cfe4d4 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Sun, 29 Oct 2023 19:16:38 +0100 Subject: [PATCH 405/496] [channels,rdpdr] fix user loggedon handling PAKID_CORE_USER_LOGGEDON might happen in quite a lot of combinations not obvious from the spec at first glance. Relax state checks so that all valid combinations are allowed. (cherry picked from commit 6de3c383a2eb7e1fe6fa0241935e23237ea52a3e) --- channels/rdpdr/client/rdpdr_main.c | 124 ++++++++++++++++++++++------- channels/rdpdr/client/rdpdr_main.h | 1 + 2 files changed, 97 insertions(+), 28 deletions(-) diff --git a/channels/rdpdr/client/rdpdr_main.c b/channels/rdpdr/client/rdpdr_main.c index adaaf1df196c..588a81d16497 100644 --- a/channels/rdpdr/client/rdpdr_main.c +++ b/channels/rdpdr/client/rdpdr_main.c @@ -79,6 +79,41 @@ struct _DEVICE_DRIVE_EXT BOOL automount; }; +static const char* rdpdr_packetid_string(UINT16 packetid) +{ + switch (packetid) + { + case PAKID_CORE_SERVER_ANNOUNCE: + return "PAKID_CORE_SERVER_ANNOUNCE"; + case PAKID_CORE_CLIENTID_CONFIRM: + return "PAKID_CORE_CLIENTID_CONFIRM"; + case PAKID_CORE_CLIENT_NAME: + return "PAKID_CORE_CLIENT_NAME"; + case PAKID_CORE_DEVICELIST_ANNOUNCE: + return "PAKID_CORE_DEVICELIST_ANNOUNCE"; + case PAKID_CORE_DEVICE_REPLY: + return "PAKID_CORE_DEVICE_REPLY"; + case PAKID_CORE_DEVICE_IOREQUEST: + return "PAKID_CORE_DEVICE_IOREQUEST"; + case PAKID_CORE_DEVICE_IOCOMPLETION: + return "PAKID_CORE_DEVICE_IOCOMPLETION"; + case PAKID_CORE_SERVER_CAPABILITY: + return "PAKID_CORE_SERVER_CAPABILITY"; + case PAKID_CORE_CLIENT_CAPABILITY: + return "PAKID_CORE_CLIENT_CAPABILITY"; + case PAKID_CORE_DEVICELIST_REMOVE: + return "PAKID_CORE_DEVICELIST_REMOVE"; + case PAKID_CORE_USER_LOGGEDON: + return "PAKID_CORE_USER_LOGGEDON"; + case PAKID_PRN_CACHE_DATA: + return "PAKID_PRN_CACHE_DATA"; + case PAKID_PRN_USING_XPS: + return "PAKID_PRN_USING_XPS"; + default: + return "UNKNOWN"; + } +} + static const char* rdpdr_state_str(enum RDPDR_CHANNEL_STATE state) { switch (state) @@ -1241,15 +1276,7 @@ static UINT rdpdr_send_device_list_announce_request(rdpdrPlugin* rdpdr, BOOL use ULONG_PTR* pKeys = NULL; if (userLoggedOn) - { - WINPR_ASSERT(rdpdr->state >= RDPDR_CHANNEL_STATE_READY); - rdpdr_state_advance(rdpdr, RDPDR_CHANNEL_STATE_USER_LOGGEDON); - } - else - { - WINPR_ASSERT(rdpdr->state >= RDPDR_CHANNEL_STATE_CLIENTID_CONFIRM); - rdpdr_state_advance(rdpdr, RDPDR_CHANNEL_STATE_READY); - } + rdpdr->userLoggedOn = TRUE; s = Stream_New(NULL, 256); @@ -1444,6 +1471,8 @@ static UINT rdpdr_process_init(rdpdrPlugin* rdpdr) DEVICE* device; ULONG_PTR* pKeys = NULL; UINT error = CHANNEL_RC_OK; + + rdpdr->userLoggedOn = FALSE; /* reset possible received state */ pKeys = NULL; keyCount = ListDictionary_GetKeys(rdpdr->devman->devices, &pKeys); @@ -1464,18 +1493,50 @@ static UINT rdpdr_process_init(rdpdrPlugin* rdpdr) return CHANNEL_RC_OK; } -static BOOL rdpdr_state_check(rdpdrPlugin* rdpdr, UINT16 packetid, - enum RDPDR_CHANNEL_STATE expected, enum RDPDR_CHANNEL_STATE next) +static BOOL state_match(enum RDPDR_CHANNEL_STATE state, size_t count, va_list ap) +{ + for (size_t x = 0; x < count; x++) + { + enum RDPDR_CHANNEL_STATE cur = va_arg(ap, enum RDPDR_CHANNEL_STATE); + if (state == cur) + return TRUE; + } + return FALSE; +} + +static const char* state_str(size_t count, va_list ap, char* buffer, size_t size) +{ + for (size_t x = 0; x < count; x++) + { + enum RDPDR_CHANNEL_STATE cur = va_arg(ap, enum RDPDR_CHANNEL_STATE); + const char* curstr = rdpdr_state_str(cur); + winpr_str_append(curstr, buffer, size, "|"); + } + return buffer; +} + +static BOOL rdpdr_state_check(rdpdrPlugin* rdpdr, UINT16 packetid, enum RDPDR_CHANNEL_STATE next, + size_t count, ...) { + va_list ap; WINPR_ASSERT(rdpdr); - const char* strstate = rdpdr_state_str(rdpdr->state); - if (rdpdr->state != expected) + va_start(ap, count); + BOOL rc = state_match(rdpdr->state, count, ap); + va_end(ap); + + if (!rc) { + const char* strstate = rdpdr_state_str(rdpdr->state); + char buffer[256] = { 0 }; + + va_start(ap, count); + state_str(count, ap, buffer, sizeof(buffer)); + va_end(ap); + WLog_Print(rdpdr->log, WLOG_ERROR, - "channel [RDPDR] received %" PRIu16 - ", expected state %s but have state %s, aborting.", - packetid, rdpdr_state_str(expected), strstate); + "channel [RDPDR] received %s, expected states [%s] but have state %s, aborting.", + rdpdr_packetid_string(packetid), buffer, strstate); rdpdr_state_advance(rdpdr, RDPDR_CHANNEL_STATE_INITIAL); return FALSE; @@ -1495,23 +1556,23 @@ static BOOL rdpdr_check_channel_state(rdpdrPlugin* rdpdr, UINT16 packetid) * then reinitialize the channel after login successful */ rdpdr_state_advance(rdpdr, RDPDR_CHANNEL_STATE_INITIAL); - return rdpdr_state_check(rdpdr, packetid, RDPDR_CHANNEL_STATE_INITIAL, - RDPDR_CHANNEL_STATE_ANNOUNCE); + return rdpdr_state_check(rdpdr, packetid, RDPDR_CHANNEL_STATE_ANNOUNCE, 1, + RDPDR_CHANNEL_STATE_INITIAL); case PAKID_CORE_SERVER_CAPABILITY: - return rdpdr_state_check(rdpdr, packetid, RDPDR_CHANNEL_STATE_NAME_REQUEST, - RDPDR_CHANNEL_STATE_SERVER_CAPS); + return rdpdr_state_check(rdpdr, packetid, RDPDR_CHANNEL_STATE_SERVER_CAPS, 1, + RDPDR_CHANNEL_STATE_NAME_REQUEST); case PAKID_CORE_CLIENTID_CONFIRM: - return rdpdr_state_check(rdpdr, packetid, RDPDR_CHANNEL_STATE_CLIENT_CAPS, - RDPDR_CHANNEL_STATE_CLIENTID_CONFIRM); + return rdpdr_state_check(rdpdr, packetid, RDPDR_CHANNEL_STATE_CLIENTID_CONFIRM, 1, + RDPDR_CHANNEL_STATE_CLIENT_CAPS); case PAKID_CORE_USER_LOGGEDON: - return rdpdr_state_check(rdpdr, packetid, RDPDR_CHANNEL_STATE_READY, - RDPDR_CHANNEL_STATE_USER_LOGGEDON); + return rdpdr_state_check( + rdpdr, packetid, RDPDR_CHANNEL_STATE_USER_LOGGEDON, 4, + RDPDR_CHANNEL_STATE_NAME_REQUEST, RDPDR_CHANNEL_STATE_CLIENT_CAPS, + RDPDR_CHANNEL_STATE_CLIENTID_CONFIRM, RDPDR_CHANNEL_STATE_READY); default: { enum RDPDR_CHANNEL_STATE state = RDPDR_CHANNEL_STATE_READY; - if (rdpdr->state == RDPDR_CHANNEL_STATE_USER_LOGGEDON) - state = RDPDR_CHANNEL_STATE_USER_LOGGEDON; - return rdpdr_state_check(rdpdr, packetid, state, state); + return rdpdr_state_check(rdpdr, packetid, state, 1, state); } } } @@ -1592,7 +1653,10 @@ static UINT rdpdr_process_receive(rdpdrPlugin* rdpdr, wStream* s) "rdpdr_send_device_list_announce_request failed with error %" PRIu32 "", error); } - + else if (!rdpdr_state_advance(rdpdr, RDPDR_CHANNEL_STATE_READY)) + { + error = ERROR_INTERNAL_ERROR; + } break; case PAKID_CORE_USER_LOGGEDON: @@ -1603,6 +1667,10 @@ static UINT rdpdr_process_receive(rdpdrPlugin* rdpdr, wStream* s) "rdpdr_send_device_list_announce_request failed with error %" PRIu32 "", error); } + else if (!rdpdr_state_advance(rdpdr, RDPDR_CHANNEL_STATE_READY)) + { + error = ERROR_INTERNAL_ERROR; + } break; diff --git a/channels/rdpdr/client/rdpdr_main.h b/channels/rdpdr/client/rdpdr_main.h index 37ffb5f290de..8e386914352c 100644 --- a/channels/rdpdr/client/rdpdr_main.h +++ b/channels/rdpdr/client/rdpdr_main.h @@ -83,6 +83,7 @@ struct rdpdr_plugin char computerName[256]; UINT32 sequenceId; + BOOL userLoggedOn; /* hotplug support */ HANDLE hotplugThread; From 2e238da61c188ce4b516325ce363c46d765a0665 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Thu, 28 Apr 2022 17:49:42 +0200 Subject: [PATCH 406/496] Some rdpsnd debug improvements (cherry picked from commit 5521a73e9097949f61ff39e70c8a365e76d7312e) --- channels/rdpsnd/client/pulse/rdpsnd_pulse.c | 137 +++++++++++++++----- channels/rdpsnd/client/rdpsnd_main.c | 8 +- 2 files changed, 109 insertions(+), 36 deletions(-) diff --git a/channels/rdpsnd/client/pulse/rdpsnd_pulse.c b/channels/rdpsnd/client/pulse/rdpsnd_pulse.c index 7a95470800f5..2de2bba8eaa5 100644 --- a/channels/rdpsnd/client/pulse/rdpsnd_pulse.c +++ b/channels/rdpsnd/client/pulse/rdpsnd_pulse.c @@ -28,6 +28,7 @@ #include #include +#include #include #include @@ -53,6 +54,35 @@ struct rdpsnd_pulse_plugin UINT32 volume; }; +static BOOL rdpsnd_check_pulse(rdpsndPulsePlugin* pulse, BOOL haveStream) +{ + BOOL rc = TRUE; + WINPR_ASSERT(pulse); + + if (!pulse->context) + { + WLog_WARN(TAG, "pulse->context=%p", pulse->context); + rc = FALSE; + } + + if (haveStream) + { + if (!pulse->stream) + { + WLog_WARN(TAG, "pulse->stream=%p", pulse->stream); + rc = FALSE; + } + } + + if (!pulse->mainloop) + { + WLog_WARN(TAG, "pulse->mainloop=%p", pulse->mainloop); + rc = FALSE; + } + + return rc; +} + static BOOL rdpsnd_pulse_format_supported(rdpsndDevicePlugin* device, const AUDIO_FORMAT* format); static void rdpsnd_pulse_get_sink_info(pa_context* c, const pa_sink_info* i, int eol, @@ -65,7 +95,8 @@ static void rdpsnd_pulse_get_sink_info(pa_context* c, const pa_sink_info* i, int ; rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*)userdata; - if (!pulse || !c || !i) + WINPR_ASSERT(c); + if (!rdpsnd_check_pulse(pulse, FALSE) || !i) return; for (x = 0; x < i->volume.channels; x++) @@ -97,6 +128,10 @@ static void rdpsnd_pulse_context_state_callback(pa_context* context, void* userd { pa_context_state_t state; rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*)userdata; + + WINPR_ASSERT(context); + WINPR_ASSERT(pulse); + state = pa_context_get_state(context); switch (state) @@ -121,7 +156,7 @@ static BOOL rdpsnd_pulse_connect(rdpsndDevicePlugin* device) pa_context_state_t state; rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*)device; - if (!pulse->context) + if (!rdpsnd_check_pulse(pulse, FALSE)) return FALSE; if (pa_context_connect(pulse->context, NULL, 0, NULL)) @@ -173,11 +208,18 @@ static BOOL rdpsnd_pulse_connect(rdpsndDevicePlugin* device) static void rdpsnd_pulse_stream_success_callback(pa_stream* stream, int success, void* userdata) { rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*)userdata; + + if (!rdpsnd_check_pulse(pulse, TRUE)) + return; + pa_threaded_mainloop_signal(pulse->mainloop, 0); } static void rdpsnd_pulse_wait_for_operation(rdpsndPulsePlugin* pulse, pa_operation* operation) { + if (!rdpsnd_check_pulse(pulse, TRUE)) + return; + if (!operation) return; @@ -193,6 +235,11 @@ static void rdpsnd_pulse_stream_state_callback(pa_stream* stream, void* userdata { pa_stream_state_t state; rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*)userdata; + + WINPR_ASSERT(stream); + if (!rdpsnd_check_pulse(pulse, TRUE)) + return; + state = pa_stream_get_state(stream); switch (state) @@ -214,6 +261,11 @@ static void rdpsnd_pulse_stream_state_callback(pa_stream* stream, void* userdata static void rdpsnd_pulse_stream_request_callback(pa_stream* stream, size_t length, void* userdata) { rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*)userdata; + + WINPR_ASSERT(stream); + if (!rdpsnd_check_pulse(pulse, TRUE)) + return; + pa_threaded_mainloop_signal(pulse->mainloop, 0); } @@ -221,15 +273,20 @@ static void rdpsnd_pulse_close(rdpsndDevicePlugin* device) { rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*)device; - if (!pulse->context || !pulse->stream) + WINPR_ASSERT(pulse); + + if (!rdpsnd_check_pulse(pulse, FALSE)) return; pa_threaded_mainloop_lock(pulse->mainloop); - rdpsnd_pulse_wait_for_operation( - pulse, pa_stream_drain(pulse->stream, rdpsnd_pulse_stream_success_callback, pulse)); - pa_stream_disconnect(pulse->stream); - pa_stream_unref(pulse->stream); - pulse->stream = NULL; + if (pulse->stream) + { + rdpsnd_pulse_wait_for_operation( + pulse, pa_stream_drain(pulse->stream, rdpsnd_pulse_stream_success_callback, pulse)); + pa_stream_disconnect(pulse->stream); + pa_stream_unref(pulse->stream); + pulse->stream = NULL; + } pa_threaded_mainloop_unlock(pulse->mainloop); } @@ -237,7 +294,9 @@ static BOOL rdpsnd_pulse_set_format_spec(rdpsndPulsePlugin* pulse, const AUDIO_F { pa_sample_spec sample_spec = { 0 }; - if (!pulse->context) + WINPR_ASSERT(format); + + if (!rdpsnd_check_pulse(pulse, FALSE)) return FALSE; if (!rdpsnd_pulse_format_supported(&pulse->device, format)) @@ -287,10 +346,12 @@ static BOOL rdpsnd_pulse_open(rdpsndDevicePlugin* device, const AUDIO_FORMAT* fo pa_stream_state_t state; pa_stream_flags_t flags; pa_buffer_attr buffer_attr = { 0 }; - char ss[PA_SAMPLE_SPEC_SNPRINT_MAX]; + char ss[PA_SAMPLE_SPEC_SNPRINT_MAX] = { 0 }; rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*)device; - if (!pulse->context || pulse->stream) + WINPR_ASSERT(format); + + if (!rdpsnd_check_pulse(pulse, FALSE)) return TRUE; if (!rdpsnd_pulse_set_format_spec(pulse, format)) @@ -369,9 +430,7 @@ static void rdpsnd_pulse_free(rdpsndDevicePlugin* device) rdpsnd_pulse_close(device); if (pulse->mainloop) - { pa_threaded_mainloop_stop(pulse->mainloop); - } if (pulse->context) { @@ -394,6 +453,7 @@ static BOOL rdpsnd_pulse_default_format(rdpsndDevicePlugin* device, const AUDIO_ AUDIO_FORMAT* defaultFormat) { rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*)device; + if (!pulse || !defaultFormat) return FALSE; @@ -415,6 +475,9 @@ static BOOL rdpsnd_pulse_default_format(rdpsndDevicePlugin* device, const AUDIO_ BOOL rdpsnd_pulse_format_supported(rdpsndDevicePlugin* device, const AUDIO_FORMAT* format) { + WINPR_ASSERT(device); + WINPR_ASSERT(format); + switch (format->wFormatTag) { case WAVE_FORMAT_PCM: @@ -439,10 +502,7 @@ static UINT32 rdpsnd_pulse_get_volume(rdpsndDevicePlugin* device) pa_operation* o; rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*)device; - if (!pulse) - return 0; - - if (!pulse->context || !pulse->mainloop) + if (!rdpsnd_check_pulse(pulse, FALSE)) return 0; pa_threaded_mainloop_lock(pulse->mainloop); @@ -452,26 +512,40 @@ static UINT32 rdpsnd_pulse_get_volume(rdpsndDevicePlugin* device) return pulse->volume; } +static void rdpsnd_set_volume_success_cb(pa_context* c, int success, void* userdata) +{ + rdpsndPulsePlugin* pulse = userdata; + + if (!rdpsnd_check_pulse(pulse, TRUE)) + return; + WINPR_ASSERT(c); + + WLog_INFO(TAG, "%s: %d", __FUNCTION__, success); +} + static BOOL rdpsnd_pulse_set_volume(rdpsndDevicePlugin* device, UINT32 value) { - pa_cvolume cv; + pa_cvolume cv = { 0 }; pa_volume_t left; pa_volume_t right; pa_operation* operation; rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*)device; - if (!pulse->context || !pulse->stream) + if (!rdpsnd_check_pulse(pulse, TRUE)) + { + WLog_WARN(TAG, "%s called before pulse backend was initialized"); return FALSE; + } left = (pa_volume_t)(value & 0xFFFF); right = (pa_volume_t)((value >> 16) & 0xFFFF); pa_cvolume_init(&cv); cv.channels = 2; - cv.values[0] = PA_VOLUME_MUTED + (left * (PA_VOLUME_NORM - PA_VOLUME_MUTED)) / 0xFFFF; - cv.values[1] = PA_VOLUME_MUTED + (right * (PA_VOLUME_NORM - PA_VOLUME_MUTED)) / 0xFFFF; + cv.values[0] = PA_VOLUME_MUTED + (left * (PA_VOLUME_NORM - PA_VOLUME_MUTED)) / PA_VOLUME_NORM; + cv.values[1] = PA_VOLUME_MUTED + (right * (PA_VOLUME_NORM - PA_VOLUME_MUTED)) / PA_VOLUME_NORM; pa_threaded_mainloop_lock(pulse->mainloop); operation = pa_context_set_sink_input_volume(pulse->context, pa_stream_get_index(pulse->stream), - &cv, NULL, NULL); + &cv, rdpsnd_set_volume_success_cb, pulse); if (operation) pa_operation_unref(operation); @@ -488,7 +562,7 @@ static UINT rdpsnd_pulse_play(rdpsndDevicePlugin* device, const BYTE* data, size int negative; rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*)device; - if (!pulse->stream || !data) + if (!rdpsnd_check_pulse(pulse, TRUE) || !data) return 0; pa_threaded_mainloop_lock(pulse->mainloop); @@ -522,11 +596,6 @@ static UINT rdpsnd_pulse_play(rdpsndDevicePlugin* device, const BYTE* data, size return latency / 1000; } -/** - * Function description - * - * @return 0 on success, otherwise a Win32 error code - */ static UINT rdpsnd_pulse_parse_addin_args(rdpsndDevicePlugin* device, ADDIN_ARGV* args) { int status; @@ -538,6 +607,10 @@ static UINT rdpsnd_pulse_parse_addin_args(rdpsndDevicePlugin* device, ADDIN_ARGV { NULL, 0, NULL, NULL, NULL, -1, NULL, NULL } }; flags = COMMAND_LINE_SIGIL_NONE | COMMAND_LINE_SEPARATOR_COLON | COMMAND_LINE_IGN_UNKNOWN_KEYWORD; + + WINPR_ASSERT(pulse); + WINPR_ASSERT(args); + status = CommandLineParseArgumentsA(args->argc, args->argv, rdpsnd_pulse_args, flags, pulse, NULL, NULL); @@ -570,16 +643,14 @@ static UINT rdpsnd_pulse_parse_addin_args(rdpsndDevicePlugin* device, ADDIN_ARGV #define freerdp_rdpsnd_client_subsystem_entry FREERDP_API freerdp_rdpsnd_client_subsystem_entry #endif -/** - * Function description - * - * @return 0 on success, otherwise a Win32 error code - */ UINT freerdp_rdpsnd_client_subsystem_entry(PFREERDP_RDPSND_DEVICE_ENTRY_POINTS pEntryPoints) { ADDIN_ARGV* args; rdpsndPulsePlugin* pulse; UINT ret; + + WINPR_ASSERT(pEntryPoints); + pulse = (rdpsndPulsePlugin*)calloc(1, sizeof(rdpsndPulsePlugin)); if (!pulse) diff --git a/channels/rdpsnd/client/rdpsnd_main.c b/channels/rdpsnd/client/rdpsnd_main.c index f6240582dcd3..d1fbba498ae5 100644 --- a/channels/rdpsnd/client/rdpsnd_main.c +++ b/channels/rdpsnd/client/rdpsnd_main.c @@ -126,6 +126,8 @@ struct rdpsnd_plugin HANDLE thread; wMessageQueue* queue; BOOL initialized; + + UINT16 wVersion; }; static const char* rdpsnd_is_dyn_str(BOOL dynamic) @@ -268,9 +270,9 @@ static UINT rdpsnd_send_client_audio_formats(rdpsndPlugin* rdpsnd) static UINT rdpsnd_recv_server_audio_formats_pdu(rdpsndPlugin* rdpsnd, wStream* s) { UINT16 index; - UINT16 wVersion; UINT16 wNumberOfFormats; UINT ret = ERROR_BAD_LENGTH; + audio_formats_free(rdpsnd->ServerFormats, rdpsnd->NumberOfServerFormats); rdpsnd->NumberOfServerFormats = 0; rdpsnd->ServerFormats = NULL; @@ -285,7 +287,7 @@ static UINT rdpsnd_recv_server_audio_formats_pdu(rdpsndPlugin* rdpsnd, wStream* Stream_Seek_UINT16(s); /* wDGramPort */ Stream_Read_UINT16(s, wNumberOfFormats); Stream_Read_UINT8(s, rdpsnd->cBlockNo); /* cLastBlockConfirmed */ - Stream_Read_UINT16(s, wVersion); /* wVersion */ + Stream_Read_UINT16(s, rdpsnd->wVersion); /* wVersion */ Stream_Seek_UINT8(s); /* bPad */ rdpsnd->NumberOfServerFormats = wNumberOfFormats; @@ -312,7 +314,7 @@ static UINT rdpsnd_recv_server_audio_formats_pdu(rdpsndPlugin* rdpsnd, wStream* if (ret == CHANNEL_RC_OK) { - if (wVersion >= CHANNEL_VERSION_WIN_7) + if (rdpsnd->wVersion >= CHANNEL_VERSION_WIN_7) ret = rdpsnd_send_quality_mode_pdu(rdpsnd); } From 9118037ae3eb34879f4c260151c28cc9ef0162fe Mon Sep 17 00:00:00 2001 From: akallabeth Date: Thu, 28 Apr 2022 18:38:15 +0200 Subject: [PATCH 407/496] Remember received sound volume and apply on open. (cherry picked from commit 1819c24808a0a6d69ef93220411a1d69a271a1aa) --- channels/rdpsnd/client/rdpsnd_main.c | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/channels/rdpsnd/client/rdpsnd_main.c b/channels/rdpsnd/client/rdpsnd_main.c index d1fbba498ae5..3de4cbc66bb0 100644 --- a/channels/rdpsnd/client/rdpsnd_main.c +++ b/channels/rdpsnd/client/rdpsnd_main.c @@ -128,6 +128,8 @@ struct rdpsnd_plugin BOOL initialized; UINT16 wVersion; + UINT32 volume; + BOOL applyVolume; }; static const char* rdpsnd_is_dyn_str(BOOL dynamic) @@ -375,6 +377,20 @@ static UINT rdpsnd_recv_training_pdu(rdpsndPlugin* rdpsnd, wStream* s) return rdpsnd_send_training_confirm_pdu(rdpsnd, wTimeStamp, wPackSize); } +static BOOL rdpsnd_apply_volume(rdpsndPlugin* rdpsnd) +{ + WINPR_ASSERT(rdpsnd); + + if (rdpsnd->isOpen && rdpsnd->applyVolume && rdpsnd->device) + { + BOOL rc = IFCALLRESULT(TRUE, rdpsnd->device->SetVolume, rdpsnd->device, rdpsnd->volume); + if (!rc) + return FALSE; + rdpsnd->applyVolume = FALSE; + } + return TRUE; +} + static BOOL rdpsnd_ensure_device_is_open(rdpsndPlugin* rdpsnd, UINT32 wFormatNo, const AUDIO_FORMAT* format) { @@ -423,7 +439,7 @@ static BOOL rdpsnd_ensure_device_is_open(rdpsndPlugin* rdpsnd, UINT32 wFormatNo, rdpsnd->totalPlaySize = 0; } - return TRUE; + return rdpsnd_apply_volume(rdpsnd); } /** @@ -712,7 +728,7 @@ static void rdpsnd_recv_close_pdu(rdpsndPlugin* rdpsnd) */ static UINT rdpsnd_recv_volume_pdu(rdpsndPlugin* rdpsnd, wStream* s) { - BOOL rc = FALSE; + BOOL rc = TRUE; UINT32 dwVolume; if (Stream_GetRemainingLength(s) < 4) @@ -721,8 +737,10 @@ static UINT rdpsnd_recv_volume_pdu(rdpsndPlugin* rdpsnd, wStream* s) Stream_Read_UINT32(s, dwVolume); WLog_Print(rdpsnd->log, WLOG_DEBUG, "%s Volume: 0x%08" PRIX32 "", rdpsnd_is_dyn_str(rdpsnd->dynamic), dwVolume); - if (rdpsnd->device) - rc = IFCALLRESULT(FALSE, rdpsnd->device->SetVolume, rdpsnd->device, dwVolume); + + rdpsnd->volume = dwVolume; + rdpsnd->applyVolume = TRUE; + rc = rdpsnd_apply_volume(rdpsnd); if (!rc) { From dbebfc7b05cd425ba91f40741a28c09a9a48ff67 Mon Sep 17 00:00:00 2001 From: "Igor V. Kovalenko" Date: Wed, 1 Nov 2023 20:27:43 +0300 Subject: [PATCH 408/496] rdpsnd_pulse: Eliminate synchronous write loop Since complete sound frame is already available, just write it out to pulseaudio stream using more efficient pa_stream_begin_write API. This removes a few milliseconds of pure wait time from each play call and makes audio playback a bit smoother. --- channels/rdpsnd/client/pulse/rdpsnd_pulse.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/channels/rdpsnd/client/pulse/rdpsnd_pulse.c b/channels/rdpsnd/client/pulse/rdpsnd_pulse.c index 2de2bba8eaa5..8f8714cdff67 100644 --- a/channels/rdpsnd/client/pulse/rdpsnd_pulse.c +++ b/channels/rdpsnd/client/pulse/rdpsnd_pulse.c @@ -381,7 +381,7 @@ static BOOL rdpsnd_pulse_open(rdpsndDevicePlugin* device, const AUDIO_FORMAT* fo if (pulse->latency > 0) { - buffer_attr.maxlength = pa_usec_to_bytes(pulse->latency * 2 * 1000, &pulse->sample_spec); + buffer_attr.maxlength = (UINT32)-1; buffer_attr.tlength = pa_usec_to_bytes(pulse->latency * 1000, &pulse->sample_spec); buffer_attr.prebuf = (UINT32)-1; buffer_attr.minreq = (UINT32)-1; @@ -557,6 +557,7 @@ static BOOL rdpsnd_pulse_set_volume(rdpsndDevicePlugin* device, UINT32 value) static UINT rdpsnd_pulse_play(rdpsndDevicePlugin* device, const BYTE* data, size_t size) { size_t length; + void* pa_data; int status; pa_usec_t latency; int negative; @@ -569,16 +570,16 @@ static UINT rdpsnd_pulse_play(rdpsndDevicePlugin* device, const BYTE* data, size while (size > 0) { - while ((length = pa_stream_writable_size(pulse->stream)) == 0) - pa_threaded_mainloop_wait(pulse->mainloop); + length = size; - if (length == (size_t)-1) + status = pa_stream_begin_write(pulse->stream, &pa_data, &length); + + if (status < 0) break; - if (length > size) - length = size; + memcpy(pa_data, data, length); - status = pa_stream_write(pulse->stream, data, length, NULL, 0LL, PA_SEEK_RELATIVE); + status = pa_stream_write(pulse->stream, pa_data, length, NULL, 0LL, PA_SEEK_RELATIVE); if (status < 0) { From dcca5ad3667d7ba48279d6bff7c6425f7866a48c Mon Sep 17 00:00:00 2001 From: "Igor V. Kovalenko" Date: Wed, 1 Nov 2023 20:27:43 +0300 Subject: [PATCH 409/496] rdpsnd_pulse: Allow reconnecting to pulseaudio server Detect if pulseaudio context has lost connection to server and initiate reconnection during play call. --- channels/rdpsnd/client/pulse/rdpsnd_pulse.c | 146 +++++++++++++++----- 1 file changed, 112 insertions(+), 34 deletions(-) diff --git a/channels/rdpsnd/client/pulse/rdpsnd_pulse.c b/channels/rdpsnd/client/pulse/rdpsnd_pulse.c index 8f8714cdff67..fc87e7460aaf 100644 --- a/channels/rdpsnd/client/pulse/rdpsnd_pulse.c +++ b/channels/rdpsnd/client/pulse/rdpsnd_pulse.c @@ -23,6 +23,8 @@ #include "config.h" #endif +#include + #include #include #include @@ -52,6 +54,8 @@ struct rdpsnd_pulse_plugin pa_stream* stream; UINT32 latency; UINT32 volume; + time_t reconnect_delay_seconds; + time_t reconnect_time; }; static BOOL rdpsnd_check_pulse(rdpsndPulsePlugin* pulse, BOOL haveStream) @@ -141,6 +145,14 @@ static void rdpsnd_pulse_context_state_callback(pa_context* context, void* userd break; case PA_CONTEXT_FAILED: + // Destroy context now, create new one for next connection attempt + pa_context_unref(pulse->context); + pulse->context = NULL; + if (pulse->reconnect_delay_seconds >= 0) + pulse->reconnect_time = time(NULL) + pulse->reconnect_delay_seconds; + pa_threaded_mainloop_signal(pulse->mainloop, 0); + break; + case PA_CONTEXT_TERMINATED: pa_threaded_mainloop_signal(pulse->mainloop, 0); break; @@ -152,6 +164,7 @@ static void rdpsnd_pulse_context_state_callback(pa_context* context, void* userd static BOOL rdpsnd_pulse_connect(rdpsndDevicePlugin* device) { + BOOL rc; pa_operation* o; pa_context_state_t state; rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*)device; @@ -159,14 +172,9 @@ static BOOL rdpsnd_pulse_connect(rdpsndDevicePlugin* device) if (!rdpsnd_check_pulse(pulse, FALSE)) return FALSE; - if (pa_context_connect(pulse->context, NULL, 0, NULL)) - { - return FALSE; - } - pa_threaded_mainloop_lock(pulse->mainloop); - if (pa_threaded_mainloop_start(pulse->mainloop) < 0) + if (pa_context_connect(pulse->context, NULL, 0, NULL) < 0) { pa_threaded_mainloop_unlock(pulse->mainloop); return FALSE; @@ -192,17 +200,18 @@ static BOOL rdpsnd_pulse_connect(rdpsndDevicePlugin* device) if (o) pa_operation_unref(o); - pa_threaded_mainloop_unlock(pulse->mainloop); - if (state == PA_CONTEXT_READY) { - return TRUE; + rc = TRUE; } else { pa_context_disconnect(pulse->context); - return FALSE; + rc = FALSE; } + + pa_threaded_mainloop_unlock(pulse->mainloop); + return rc; } static void rdpsnd_pulse_stream_success_callback(pa_stream* stream, int success, void* userdata) @@ -250,6 +259,8 @@ static void rdpsnd_pulse_stream_state_callback(pa_stream* stream, void* userdata case PA_STREAM_FAILED: case PA_STREAM_TERMINATED: + // Stream object is about to be destroyed, clean up our pointer + pulse->stream = NULL; pa_threaded_mainloop_signal(pulse->mainloop, 0); break; @@ -340,32 +351,52 @@ static BOOL rdpsnd_pulse_set_format_spec(rdpsndPulsePlugin* pulse, const AUDIO_F return TRUE; } -static BOOL rdpsnd_pulse_open(rdpsndDevicePlugin* device, const AUDIO_FORMAT* format, - UINT32 latency) +static BOOL rdpsnd_pulse_context_connect(rdpsndDevicePlugin* device) { - pa_stream_state_t state; - pa_stream_flags_t flags; - pa_buffer_attr buffer_attr = { 0 }; - char ss[PA_SAMPLE_SPEC_SNPRINT_MAX] = { 0 }; rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*)device; - WINPR_ASSERT(format); + pulse->context = pa_context_new(pa_threaded_mainloop_get_api(pulse->mainloop), "freerdp"); - if (!rdpsnd_check_pulse(pulse, FALSE)) - return TRUE; + if (!pulse->context) + return FALSE; - if (!rdpsnd_pulse_set_format_spec(pulse, format)) + pa_context_set_state_callback(pulse->context, rdpsnd_pulse_context_state_callback, pulse); + + if (!rdpsnd_pulse_connect((rdpsndDevicePlugin*)pulse)) return FALSE; - pulse->latency = latency; + return TRUE; +} + +static BOOL rdpsnd_pulse_open_stream(rdpsndDevicePlugin* device) +{ + pa_stream_state_t state; + pa_stream_flags_t flags; + pa_buffer_attr buffer_attr = { 0 }; + char ss[PA_SAMPLE_SPEC_SNPRINT_MAX] = { 0 }; + rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*)device; if (pa_sample_spec_valid(&pulse->sample_spec) == 0) { pa_sample_spec_snprint(ss, sizeof(ss), &pulse->sample_spec); - return TRUE; + return FALSE; } pa_threaded_mainloop_lock(pulse->mainloop); + if (!pulse->context) + { + pa_threaded_mainloop_unlock(pulse->mainloop); + if (pulse->reconnect_delay_seconds >= 0 && time(NULL) - pulse->reconnect_time >= 0) + rdpsnd_pulse_context_connect(device); + pa_threaded_mainloop_lock(pulse->mainloop); + } + + if (!rdpsnd_check_pulse(pulse, FALSE)) + { + pa_threaded_mainloop_unlock(pulse->mainloop); + return FALSE; + } + pulse->stream = pa_stream_new(pulse->context, "freerdp", &pulse->sample_spec, NULL); if (!pulse->stream) @@ -392,8 +423,11 @@ static BOOL rdpsnd_pulse_open(rdpsndDevicePlugin* device, const AUDIO_FORMAT* fo if (pa_stream_connect_playback(pulse->stream, pulse->device_name, pulse->latency > 0 ? &buffer_attr : NULL, flags, NULL, NULL) < 0) { + WLog_ERR(TAG, "error connecting playback stream"); + pa_stream_unref(pulse->stream); + pulse->stream = NULL; pa_threaded_mainloop_unlock(pulse->mainloop); - return TRUE; + return FALSE; } for (;;) @@ -420,6 +454,24 @@ static BOOL rdpsnd_pulse_open(rdpsndDevicePlugin* device, const AUDIO_FORMAT* fo return FALSE; } +static BOOL rdpsnd_pulse_open(rdpsndDevicePlugin* device, const AUDIO_FORMAT* format, + UINT32 latency) +{ + rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*)device; + + WINPR_ASSERT(format); + + if (!rdpsnd_check_pulse(pulse, FALSE)) + return TRUE; + + if (!rdpsnd_pulse_set_format_spec(pulse, format)) + return FALSE; + + pulse->latency = latency; + + return rdpsnd_pulse_open_stream(device); +} + static void rdpsnd_pulse_free(rdpsndDevicePlugin* device) { rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*)device; @@ -507,7 +559,8 @@ static UINT32 rdpsnd_pulse_get_volume(rdpsndDevicePlugin* device) pa_threaded_mainloop_lock(pulse->mainloop); o = pa_context_get_sink_info_by_index(pulse->context, 0, rdpsnd_pulse_get_sink_info, pulse); - pa_operation_unref(o); + if (o) + pa_operation_unref(o); pa_threaded_mainloop_unlock(pulse->mainloop); return pulse->volume; } @@ -563,11 +616,20 @@ static UINT rdpsnd_pulse_play(rdpsndDevicePlugin* device, const BYTE* data, size int negative; rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*)device; - if (!rdpsnd_check_pulse(pulse, TRUE) || !data) + if (!data) return 0; pa_threaded_mainloop_lock(pulse->mainloop); + if (!rdpsnd_check_pulse(pulse, TRUE)) + { + pa_threaded_mainloop_unlock(pulse->mainloop); + // Discard this playback request and just attempt to reconnect the stream + WLog_DBG(TAG, "reconnecting playback stream"); + rdpsnd_pulse_open_stream(device); + return 0; + } + while (size > 0) { length = size; @@ -603,9 +665,12 @@ static UINT rdpsnd_pulse_parse_addin_args(rdpsndDevicePlugin* device, ADDIN_ARGV DWORD flags; COMMAND_LINE_ARGUMENT_A* arg; rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*)device; - COMMAND_LINE_ARGUMENT_A rdpsnd_pulse_args[] = { { "dev", COMMAND_LINE_VALUE_REQUIRED, - "", NULL, NULL, -1, NULL, "device" }, - { NULL, 0, NULL, NULL, NULL, -1, NULL, NULL } }; + COMMAND_LINE_ARGUMENT_A rdpsnd_pulse_args[] = { + { "dev", COMMAND_LINE_VALUE_REQUIRED, "", NULL, NULL, -1, NULL, "device" }, + { "reconnect_delay_seconds", COMMAND_LINE_VALUE_REQUIRED, "", NULL, + NULL, -1, NULL, "reconnect_delay_seconds" }, + { NULL, 0, NULL, NULL, NULL, -1, NULL, NULL } + }; flags = COMMAND_LINE_SIGIL_NONE | COMMAND_LINE_SEPARATOR_COLON | COMMAND_LINE_IGN_UNKNOWN_KEYWORD; @@ -632,6 +697,15 @@ static UINT rdpsnd_pulse_parse_addin_args(rdpsndDevicePlugin* device, ADDIN_ARGV if (!pulse->device_name) return ERROR_OUTOFMEMORY; } + CommandLineSwitchCase(arg, "reconnect_delay_seconds") + { + unsigned long val = strtoul(arg->Value, NULL, 0); + + if ((errno != 0) || (val > INT32_MAX)) + return ERROR_INVALID_DATA; + + pulse->reconnect_delay_seconds = val; + } CommandLineSwitchEnd(arg) } while ((arg = CommandLineFindNextArgumentA(arg)) != NULL); @@ -677,6 +751,8 @@ UINT freerdp_rdpsnd_client_subsystem_entry(PFREERDP_RDPSND_DEVICE_ENTRY_POINTS p goto error; } } + pulse->reconnect_delay_seconds = 5; + pulse->reconnect_time = time(NULL); ret = CHANNEL_RC_NO_MEMORY; pulse->mainloop = pa_threaded_mainloop_new(); @@ -684,15 +760,17 @@ UINT freerdp_rdpsnd_client_subsystem_entry(PFREERDP_RDPSND_DEVICE_ENTRY_POINTS p if (!pulse->mainloop) goto error; - pulse->context = pa_context_new(pa_threaded_mainloop_get_api(pulse->mainloop), "freerdp"); + pa_threaded_mainloop_lock(pulse->mainloop); - if (!pulse->context) - goto error; + if (pa_threaded_mainloop_start(pulse->mainloop) < 0) + { + pa_threaded_mainloop_unlock(pulse->mainloop); + return FALSE; + } - pa_context_set_state_callback(pulse->context, rdpsnd_pulse_context_state_callback, pulse); - ret = ERROR_INVALID_OPERATION; + pa_threaded_mainloop_unlock(pulse->mainloop); - if (!rdpsnd_pulse_connect((rdpsndDevicePlugin*)pulse)) + if (!rdpsnd_pulse_context_connect((rdpsndDevicePlugin*)pulse)) goto error; pEntryPoints->pRegisterRdpsndDevice(pEntryPoints->rdpsnd, (rdpsndDevicePlugin*)pulse); From 0774ea7d4cf948a7a57b58baaf5ffcaf53b2ee84 Mon Sep 17 00:00:00 2001 From: "Igor V. Kovalenko" Date: Thu, 2 Nov 2023 20:37:26 +0300 Subject: [PATCH 410/496] rdpsnd_pulse: Use C99 constants --- channels/rdpsnd/client/pulse/rdpsnd_pulse.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/channels/rdpsnd/client/pulse/rdpsnd_pulse.c b/channels/rdpsnd/client/pulse/rdpsnd_pulse.c index fc87e7460aaf..67e2b2b10c56 100644 --- a/channels/rdpsnd/client/pulse/rdpsnd_pulse.c +++ b/channels/rdpsnd/client/pulse/rdpsnd_pulse.c @@ -412,11 +412,11 @@ static BOOL rdpsnd_pulse_open_stream(rdpsndDevicePlugin* device) if (pulse->latency > 0) { - buffer_attr.maxlength = (UINT32)-1; + buffer_attr.maxlength = UINT32_MAX; buffer_attr.tlength = pa_usec_to_bytes(pulse->latency * 1000, &pulse->sample_spec); - buffer_attr.prebuf = (UINT32)-1; - buffer_attr.minreq = (UINT32)-1; - buffer_attr.fragsize = (UINT32)-1; + buffer_attr.prebuf = UINT32_MAX; + buffer_attr.minreq = UINT32_MAX; + buffer_attr.fragsize = UINT32_MAX; flags |= PA_STREAM_ADJUST_LATENCY; } From 82a5e898cdd5750941d5fc79c2344c1df44fec12 Mon Sep 17 00:00:00 2001 From: Konrad Bucheli Date: Fri, 30 Jun 2023 16:39:43 +0200 Subject: [PATCH 411/496] the default Swiss keyboard layout is German, French is a variant (cherry picked from commit d4e2129cd4f042b39537aa25b5e9c56973244fec) --- libfreerdp/locale/xkb_layout_ids.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libfreerdp/locale/xkb_layout_ids.c b/libfreerdp/locale/xkb_layout_ids.c index 223f7d10cae1..91922194891c 100644 --- a/libfreerdp/locale/xkb_layout_ids.c +++ b/libfreerdp/locale/xkb_layout_ids.c @@ -806,7 +806,7 @@ static const XKB_LAYOUT xkbLayouts[] = { { "sk", KBD_SLOVAK, sk_variants }, /* Slovakia */ { "es", KBD_SPANISH, es_variants }, /* Spain */ { "se", KBD_SWEDISH, se_variants }, /* Sweden */ - { "ch", KBD_SWISS_FRENCH, ch_variants }, /* Switzerland */ + { "ch", KBD_SWISS_GERMAN, ch_variants }, /* Switzerland */ { "sy", KBD_SYRIAC, sy_variants }, /* Syria */ { "tj", 0, tj_variants }, /* Tajikistan */ { "lk", 0, lk_variants }, /* Sri Lanka */ From b3c81c19779a999c3381df5a4aa339c71feeb391 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Fri, 3 Nov 2023 08:58:59 +0100 Subject: [PATCH 412/496] [channel,rdpdr] use server general caps * read server CAP_GENERAL_TYPE * check if messages are allowed according to caps (cherry picked from commit 31405b305a9cd7f9d9783995d7c347f858079360) --- channels/rdpdr/client/rdpdr_capabilities.c | 58 +++++++++--- channels/rdpdr/client/rdpdr_main.c | 103 +++++++++++++++++++-- channels/rdpdr/client/rdpdr_main.h | 26 +++++- 3 files changed, 160 insertions(+), 27 deletions(-) diff --git a/channels/rdpdr/client/rdpdr_capabilities.c b/channels/rdpdr/client/rdpdr_capabilities.c index 7669766e10ee..2e5f63856f0d 100644 --- a/channels/rdpdr/client/rdpdr_capabilities.c +++ b/channels/rdpdr/client/rdpdr_capabilities.c @@ -35,6 +35,8 @@ #include "rdpdr_main.h" #include "rdpdr_capabilities.h" +#define RDPDR_CAPABILITY_HEADER_LENGTH 8 + /* Output device redirection capability set header */ static void rdpdr_write_capset_header(wStream* s, UINT16 capabilityType, UINT16 capabilityLength, UINT32 version) @@ -48,19 +50,26 @@ static void rdpdr_write_capset_header(wStream* s, UINT16 capabilityType, UINT16 static void rdpdr_write_general_capset(rdpdrPlugin* rdpdr, wStream* s) { WINPR_UNUSED(rdpdr); - rdpdr_write_capset_header(s, CAP_GENERAL_TYPE, 44, GENERAL_CAPABILITY_VERSION_02); - Stream_Write_UINT32(s, 0); /* osType, ignored on receipt */ - Stream_Write_UINT32(s, 0); /* osVersion, unused and must be set to zero */ - Stream_Write_UINT16(s, 1); /* protocolMajorVersion, must be set to 1 */ - Stream_Write_UINT16(s, RDPDR_MINOR_RDP_VERSION_5_2); /* protocolMinorVersion */ - Stream_Write_UINT32(s, 0x0000FFFF); /* ioCode1 */ - Stream_Write_UINT32(s, 0); /* ioCode2, must be set to zero, reserved for future use */ - Stream_Write_UINT32(s, RDPDR_DEVICE_REMOVE_PDUS | RDPDR_CLIENT_DISPLAY_NAME_PDU | - RDPDR_USER_LOGGEDON_PDU); /* extendedPDU */ - Stream_Write_UINT32(s, ENABLE_ASYNCIO); /* extraFlags1 */ - Stream_Write_UINT32(s, 0); /* extraFlags2, must be set to zero, reserved for future use */ + + const UINT32 ioCode1 = rdpdr->clientIOCode1 & rdpdr->serverIOCode1; + const UINT32 ioCode2 = rdpdr->clientIOCode2 & rdpdr->serverIOCode2; + + rdpdr_write_capset_header(s, CAP_GENERAL_TYPE, RDPDR_CAPABILITY_HEADER_LENGTH + 36, + GENERAL_CAPABILITY_VERSION_02); + Stream_Write_UINT32(s, rdpdr->clientOsType); /* osType, ignored on receipt */ + Stream_Write_UINT32(s, rdpdr->clientOsVersion); /* osVersion, unused and must be set to zero */ + Stream_Write_UINT16(s, rdpdr->clientVersionMajor); /* protocolMajorVersion, must be set to 1 */ + Stream_Write_UINT16(s, rdpdr->clientVersionMinor); /* protocolMinorVersion */ + Stream_Write_UINT32(s, ioCode1); /* ioCode1 */ + Stream_Write_UINT32(s, ioCode2); /* ioCode2, must be set to zero, reserved for future use */ + Stream_Write_UINT32(s, rdpdr->clientExtendedPDU); /* extendedPDU */ + Stream_Write_UINT32(s, rdpdr->clientExtraFlags1); /* extraFlags1 */ Stream_Write_UINT32( - s, 0); /* SpecialTypeDeviceCap, number of special devices to be redirected before logon */ + s, + rdpdr->clientExtraFlags2); /* extraFlags2, must be set to zero, reserved for future use */ + Stream_Write_UINT32( + s, rdpdr->clientSpecialTypeDeviceCap); /* SpecialTypeDeviceCap, number of special devices to + be redirected before logon */ } /* Process device direction general capability set */ @@ -74,13 +83,32 @@ static UINT rdpdr_process_general_capset(rdpdrPlugin* rdpdr, wStream* s) Stream_Read_UINT16(s, capabilityLength); - if (capabilityLength < 4) + if (capabilityLength != 36) + { + WLog_Print(rdpdr->log, WLOG_ERROR, + "CAP_GENERAL_TYPE::CapabilityLength expected 36, got %" PRIu32, + capabilityLength); return ERROR_INVALID_DATA; + } - if (!Stream_CheckAndLogRequiredLengthWLog(rdpdr->log, s, capabilityLength - 4U)) + if (!Stream_CheckAndLogRequiredLengthWLog(rdpdr->log, s, capabilityLength)) return ERROR_INVALID_DATA; - Stream_Seek(s, capabilityLength - 4U); + Stream_Read_UINT32(s, rdpdr->serverOsType); /* osType, ignored on receipt */ + Stream_Read_UINT32(s, rdpdr->serverOsVersion); /* osVersion, unused and must be set to zero */ + Stream_Read_UINT16(s, rdpdr->serverVersionMajor); /* protocolMajorVersion, must be set to 1 */ + Stream_Read_UINT16(s, rdpdr->serverVersionMinor); /* protocolMinorVersion */ + Stream_Read_UINT32(s, rdpdr->serverIOCode1); /* ioCode1 */ + Stream_Read_UINT32( + s, rdpdr->serverIOCode2); /* ioCode2, must be set to zero, reserved for future use */ + Stream_Read_UINT32(s, rdpdr->serverExtendedPDU); /* extendedPDU */ + Stream_Read_UINT32(s, rdpdr->serverExtraFlags1); /* extraFlags1 */ + Stream_Read_UINT32( + s, + rdpdr->serverExtraFlags2); /* extraFlags2, must be set to zero, reserved for future use */ + Stream_Read_UINT32( + s, rdpdr->serverSpecialTypeDeviceCap); /* SpecialTypeDeviceCap, number of special devices to + be redirected before logon */ return CHANNEL_RC_OK; } diff --git a/channels/rdpdr/client/rdpdr_main.c b/channels/rdpdr/client/rdpdr_main.c index 588a81d16497..2b02e686d84e 100644 --- a/channels/rdpdr/client/rdpdr_main.c +++ b/channels/rdpdr/client/rdpdr_main.c @@ -141,6 +141,63 @@ static const char* rdpdr_state_str(enum RDPDR_CHANNEL_STATE state) } } +static const char* rdpdr_device_type_string(UINT32 type) +{ + switch (type) + { + case RDPDR_DTYP_SERIAL: + return "serial"; + case RDPDR_DTYP_PRINT: + return "printer"; + case RDPDR_DTYP_FILESYSTEM: + return "drive"; + case RDPDR_DTYP_SMARTCARD: + return "smartcard"; + case RDPDR_DTYP_PARALLEL: + return "parallel"; + default: + return "UNKNOWN"; + } +} + +static const char* support_str(BOOL val) +{ + if (val) + return "supported"; + return "not found"; +} + +static const char* rdpdr_caps_pdu_str(UINT32 flag) +{ + switch (flag) + { + case RDPDR_DEVICE_REMOVE_PDUS: + return "RDPDR_USER_LOGGEDON_PDU"; + case RDPDR_CLIENT_DISPLAY_NAME_PDU: + return "RDPDR_CLIENT_DISPLAY_NAME_PDU"; + case RDPDR_USER_LOGGEDON_PDU: + return "RDPDR_USER_LOGGEDON_PDU"; + default: + return "RDPDR_UNKNONW"; + } +} + +static BOOL rdpdr_check_extended_pdu_flag(rdpdrPlugin* rdpdr, UINT32 flag) +{ + WINPR_ASSERT(rdpdr); + + const BOOL client = (rdpdr->clientExtendedPDU & flag) != 0; + const BOOL server = (rdpdr->serverExtendedPDU & flag) != 0; + + if (!client || !server) + { + WLog_Print(rdpdr->log, WLOG_WARN, "Checking ExtendedPDU::%s, client %s, server %s", + rdpdr_caps_pdu_str(flag), support_str(client), support_str(server)); + return FALSE; + } + return TRUE; +} + BOOL rdpdr_state_advance(rdpdrPlugin* rdpdr, enum RDPDR_CHANNEL_STATE next) { WINPR_ASSERT(rdpdr); @@ -168,6 +225,16 @@ static UINT rdpdr_send_device_list_remove_request(rdpdrPlugin* rdpdr, UINT32 cou { UINT32 i; wStream* s; + + WINPR_ASSERT(rdpdr); + WINPR_ASSERT(ids || (count == 0)); + + if (count == 0) + return CHANNEL_RC_OK; + + if (!rdpdr_check_extended_pdu_flag(rdpdr, RDPDR_DEVICE_REMOVE_PDUS)) + return CHANNEL_RC_OK; + s = Stream_New(NULL, count * sizeof(UINT32) + 8); if (!s) @@ -1150,8 +1217,8 @@ static UINT rdpdr_process_server_announce_request(rdpdrPlugin* rdpdr, wStream* s if (Stream_GetRemainingLength(s) < 8) return ERROR_INVALID_DATA; - Stream_Read_UINT16(s, rdpdr->versionMajor); - Stream_Read_UINT16(s, rdpdr->versionMinor); + Stream_Read_UINT16(s, rdpdr->serverVersionMajor); + Stream_Read_UINT16(s, rdpdr->serverVersionMinor); Stream_Read_UINT32(s, rdpdr->clientID); rdpdr->sequenceId++; return CHANNEL_RC_OK; @@ -1180,8 +1247,8 @@ static UINT rdpdr_send_client_announce_reply(rdpdrPlugin* rdpdr) Stream_Write_UINT16(s, RDPDR_CTYP_CORE); /* Component (2 bytes) */ Stream_Write_UINT16(s, PAKID_CORE_CLIENTID_CONFIRM); /* PacketId (2 bytes) */ - Stream_Write_UINT16(s, rdpdr->versionMajor); - Stream_Write_UINT16(s, rdpdr->versionMinor); + Stream_Write_UINT16(s, rdpdr->clientVersionMajor); + Stream_Write_UINT16(s, rdpdr->clientVersionMinor); Stream_Write_UINT32(s, (UINT32)rdpdr->clientID); return rdpdr_send(rdpdr, s); } @@ -1244,10 +1311,10 @@ static UINT rdpdr_process_server_clientid_confirm(rdpdrPlugin* rdpdr, wStream* s Stream_Read_UINT16(s, versionMinor); Stream_Read_UINT32(s, clientID); - if (versionMajor != rdpdr->versionMajor || versionMinor != rdpdr->versionMinor) + if (versionMajor != rdpdr->clientVersionMajor || versionMinor != rdpdr->clientVersionMinor) { - rdpdr->versionMajor = versionMajor; - rdpdr->versionMinor = versionMinor; + rdpdr->clientVersionMajor = versionMajor; + rdpdr->clientVersionMinor = versionMinor; } if (clientID != rdpdr->clientID) @@ -1305,7 +1372,7 @@ static UINT rdpdr_send_device_list_announce_request(rdpdrPlugin* rdpdr, BOOL use * 3. other devices are sent only after user_loggedon */ - if ((rdpdr->versionMinor == 0x0005) || (device->type == RDPDR_DTYP_SMARTCARD) || + if ((rdpdr->clientVersionMinor == 0x0005) || (device->type == RDPDR_DTYP_SMARTCARD) || userLoggedOn) { data_len = (device->data == NULL ? 0 : Stream_GetPosition(device->data)); @@ -1565,6 +1632,9 @@ static BOOL rdpdr_check_channel_state(rdpdrPlugin* rdpdr, UINT16 packetid) return rdpdr_state_check(rdpdr, packetid, RDPDR_CHANNEL_STATE_CLIENTID_CONFIRM, 1, RDPDR_CHANNEL_STATE_CLIENT_CAPS); case PAKID_CORE_USER_LOGGEDON: + if (!rdpdr_check_extended_pdu_flag(rdpdr, RDPDR_USER_LOGGEDON_PDU)) + return FALSE; + return rdpdr_state_check( rdpdr, packetid, RDPDR_CHANNEL_STATE_USER_LOGGEDON, 4, RDPDR_CHANNEL_STATE_NAME_REQUEST, RDPDR_CHANNEL_STATE_CLIENT_CAPS, @@ -2103,6 +2173,10 @@ BOOL VCAPITYPE VirtualChannelEntryEx(PCHANNEL_ENTRY_POINTS pEntryPoints, PVOID p UINT rc; rdpdrPlugin* rdpdr; CHANNEL_ENTRY_POINTS_FREERDP_EX* pEntryPointsEx; + + WINPR_ASSERT(pEntryPoints); + WINPR_ASSERT(pInitHandle); + rdpdr = (rdpdrPlugin*)calloc(1, sizeof(rdpdrPlugin)); if (!rdpdr) @@ -2111,7 +2185,18 @@ BOOL VCAPITYPE VirtualChannelEntryEx(PCHANNEL_ENTRY_POINTS pEntryPoints, PVOID p return FALSE; } rdpdr->log = WLog_Get(TAG); - WINPR_ASSERT(rdpdr->log); + + rdpdr->clientExtendedPDU = + RDPDR_DEVICE_REMOVE_PDUS | RDPDR_CLIENT_DISPLAY_NAME_PDU | RDPDR_USER_LOGGEDON_PDU; + rdpdr->clientIOCode1 = + RDPDR_IRP_MJ_CREATE | RDPDR_IRP_MJ_CLEANUP | RDPDR_IRP_MJ_CLOSE | RDPDR_IRP_MJ_READ | + RDPDR_IRP_MJ_WRITE | RDPDR_IRP_MJ_FLUSH_BUFFERS | RDPDR_IRP_MJ_SHUTDOWN | + RDPDR_IRP_MJ_DEVICE_CONTROL | RDPDR_IRP_MJ_QUERY_VOLUME_INFORMATION | + RDPDR_IRP_MJ_SET_VOLUME_INFORMATION | RDPDR_IRP_MJ_QUERY_INFORMATION | + RDPDR_IRP_MJ_SET_INFORMATION | RDPDR_IRP_MJ_DIRECTORY_CONTROL | RDPDR_IRP_MJ_LOCK_CONTROL | + RDPDR_IRP_MJ_QUERY_SECURITY | RDPDR_IRP_MJ_SET_SECURITY; + + rdpdr->clientExtraFlags1 = ENABLE_ASYNCIO; rdpdr->channelDef.options = CHANNEL_OPTION_INITIALIZED | CHANNEL_OPTION_ENCRYPT_RDP | CHANNEL_OPTION_COMPRESS_RDP; diff --git a/channels/rdpdr/client/rdpdr_main.h b/channels/rdpdr/client/rdpdr_main.h index 8e386914352c..37766f1d67ed 100644 --- a/channels/rdpdr/client/rdpdr_main.h +++ b/channels/rdpdr/client/rdpdr_main.h @@ -77,9 +77,29 @@ struct rdpdr_plugin DEVMAN* devman; - UINT16 versionMajor; - UINT16 versionMinor; - UINT16 clientID; + UINT32 serverOsType; + UINT32 serverOsVersion; + UINT16 serverVersionMajor; + UINT16 serverVersionMinor; + UINT32 serverExtendedPDU; + UINT32 serverIOCode1; + UINT32 serverIOCode2; + UINT32 serverExtraFlags1; + UINT32 serverExtraFlags2; + UINT32 serverSpecialTypeDeviceCap; + + UINT32 clientOsType; + UINT32 clientOsVersion; + UINT16 clientVersionMajor; + UINT16 clientVersionMinor; + UINT32 clientExtendedPDU; + UINT32 clientIOCode1; + UINT32 clientIOCode2; + UINT32 clientExtraFlags1; + UINT32 clientExtraFlags2; + UINT32 clientSpecialTypeDeviceCap; + + UINT32 clientID; char computerName[256]; UINT32 sequenceId; From 88438ff4a53562361290734bf029d6dc0c8bf526 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Fri, 3 Nov 2023 14:52:33 +0100 Subject: [PATCH 413/496] [channel,rdpdr] relax state checks ClientID confirm message might be sent async to userloggedon. So allow these messages to arrive in any order (cherry picked from commit cd5a0914a399c3c44309421a165c5fd2be7fa432) --- channels/rdpdr/client/rdpdr_main.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/channels/rdpdr/client/rdpdr_main.c b/channels/rdpdr/client/rdpdr_main.c index 2b02e686d84e..06d653d8f56a 100644 --- a/channels/rdpdr/client/rdpdr_main.c +++ b/channels/rdpdr/client/rdpdr_main.c @@ -1629,8 +1629,9 @@ static BOOL rdpdr_check_channel_state(rdpdrPlugin* rdpdr, UINT16 packetid) return rdpdr_state_check(rdpdr, packetid, RDPDR_CHANNEL_STATE_SERVER_CAPS, 1, RDPDR_CHANNEL_STATE_NAME_REQUEST); case PAKID_CORE_CLIENTID_CONFIRM: - return rdpdr_state_check(rdpdr, packetid, RDPDR_CHANNEL_STATE_CLIENTID_CONFIRM, 1, - RDPDR_CHANNEL_STATE_CLIENT_CAPS); + return rdpdr_state_check(rdpdr, packetid, RDPDR_CHANNEL_STATE_CLIENTID_CONFIRM, 3, + RDPDR_CHANNEL_STATE_CLIENT_CAPS, RDPDR_CHANNEL_STATE_READY, + RDPDR_CHANNEL_STATE_USER_LOGGEDON); case PAKID_CORE_USER_LOGGEDON: if (!rdpdr_check_extended_pdu_flag(rdpdr, RDPDR_USER_LOGGEDON_PDU)) return FALSE; From 39b7d5a2d914d7a668be5c7f6c7c1bcfb4c81706 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Mon, 20 Nov 2023 11:02:21 +0100 Subject: [PATCH 414/496] [codec,aac] add NaN filter ffmpeg format conversion from int16 to float sometimes produces values that are NaN or Infinity. Replace these values as these input values break the AAC encoder (cherry picked from commit 9c6aa41d99d2fe40e632a65f12868df4fb4331fe) --- libfreerdp/codec/dsp_ffmpeg.c | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/libfreerdp/codec/dsp_ffmpeg.c b/libfreerdp/codec/dsp_ffmpeg.c index 086c797a2953..ef6791400d38 100644 --- a/libfreerdp/codec/dsp_ffmpeg.c +++ b/libfreerdp/codec/dsp_ffmpeg.c @@ -418,9 +418,29 @@ static BOOL ffmpeg_resample_frame(AVAudioResampleContext* context, AVFrame* in, static BOOL ffmpeg_encode_frame(AVCodecContext* context, AVFrame* in, AVPacket* packet, wStream* out) { - int ret; + if (in->format == AV_SAMPLE_FMT_FLTP) + { + uint8_t** pp = in->extended_data; + for (int y = 0; y < in->channels; y++) + { + float* data = pp[y]; + for (int x = 0; x < in->nb_samples; x++) + { + const float val1 = data[x]; + if (isnan(val1)) + data[x] = 0.0f; + else if (isinf(val1)) + { + if (val1 < 0.0f) + data[x] = -1.0f; + else + data[x] = 1.0f; + } + } + } + } /* send the packet with the compressed data to the encoder */ - ret = avcodec_send_frame(context, in); + int ret = avcodec_send_frame(context, in); if (ret < 0) { From 7307190f615c43204e127ec0c52b254478f6e320 Mon Sep 17 00:00:00 2001 From: Alessandro Bono Date: Tue, 21 Nov 2023 11:26:01 +0100 Subject: [PATCH 415/496] crypto: Don't rely on OpenSSL 1.1.x symbols Commit e93433fb21231dba2b989b38e058706c3e46d9e2 backports some code from FreeRDP 3.0. However, such code relies on a symbol not present in OpenSSL 1.0.x, effectively bumbing the minimum required version: ``` libfreerdp/crypto/crypto.c:953:18: warning: implicit declaration of function 'X509_get0_pubkey'; did you mean 'X509_get_pubkey'? [-Wimplicit-function-declaration] ``` Drop X509_get0_pubkey() usage in favor of X509_get_pubkey(). Free the returned public key. --- libfreerdp/crypto/crypto.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libfreerdp/crypto/crypto.c b/libfreerdp/crypto/crypto.c index f08a4b842736..69255c94530f 100644 --- a/libfreerdp/crypto/crypto.c +++ b/libfreerdp/crypto/crypto.c @@ -950,11 +950,12 @@ WINPR_MD_TYPE crypto_cert_get_signature_alg(X509* xcert) { WINPR_ASSERT(xcert); - EVP_PKEY* evp = X509_get0_pubkey(xcert); + EVP_PKEY* evp = X509_get_pubkey(xcert); WINPR_ASSERT(evp); int hash_nid = 0; const int res = EVP_PKEY_get_default_digest_nid(evp, &hash_nid); + EVP_PKEY_free(evp); if (res <= 0) return WINPR_MD_NONE; From 5d58c2ceb39030bb0880de4da12563c927164f24 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Fri, 24 Nov 2023 14:07:02 +0100 Subject: [PATCH 416/496] [rdpdr] fix broken backport --- channels/rdpdr/client/rdpdr_capabilities.c | 94 ++++++++-------------- channels/rdpdr/client/rdpdr_main.c | 13 ++- channels/rdpdr/server/rdpdr_main.h | 7 -- include/freerdp/channels/rdpdr.h | 8 ++ 4 files changed, 51 insertions(+), 71 deletions(-) diff --git a/channels/rdpdr/client/rdpdr_capabilities.c b/channels/rdpdr/client/rdpdr_capabilities.c index 2e5f63856f0d..0e6baf8306ae 100644 --- a/channels/rdpdr/client/rdpdr_capabilities.c +++ b/channels/rdpdr/client/rdpdr_capabilities.c @@ -73,16 +73,10 @@ static void rdpdr_write_general_capset(rdpdrPlugin* rdpdr, wStream* s) } /* Process device direction general capability set */ -static UINT rdpdr_process_general_capset(rdpdrPlugin* rdpdr, wStream* s) +static UINT rdpdr_process_general_capset(rdpdrPlugin* rdpdr, wStream* s, UINT16 capabilityLength) { - UINT16 capabilityLength; WINPR_UNUSED(rdpdr); - if (!Stream_CheckAndLogRequiredLengthWLog(rdpdr->log, s, 2)) - return ERROR_INVALID_DATA; - - Stream_Read_UINT16(s, capabilityLength); - if (capabilityLength != 36) { WLog_Print(rdpdr->log, WLOG_ERROR, @@ -120,23 +114,14 @@ static void rdpdr_write_printer_capset(rdpdrPlugin* rdpdr, wStream* s) } /* Process printer direction capability set */ -static UINT rdpdr_process_printer_capset(rdpdrPlugin* rdpdr, wStream* s) +static UINT rdpdr_process_printer_capset(rdpdrPlugin* rdpdr, wStream* s, UINT16 capabilityLength) { - UINT16 capabilityLength; WINPR_UNUSED(rdpdr); - if (!Stream_CheckAndLogRequiredLengthWLog(rdpdr->log, s, 2)) - return ERROR_INVALID_DATA; - - Stream_Read_UINT16(s, capabilityLength); - - if (capabilityLength < 4) - return ERROR_INVALID_DATA; - - if (!Stream_CheckAndLogRequiredLengthWLog(rdpdr->log, s, capabilityLength - 4U)) + if (!Stream_CheckAndLogRequiredLengthWLog(rdpdr->log, s, capabilityLength)) return ERROR_INVALID_DATA; - Stream_Seek(s, capabilityLength - 4U); + Stream_Seek(s, capabilityLength); return CHANNEL_RC_OK; } @@ -148,23 +133,14 @@ static void rdpdr_write_port_capset(rdpdrPlugin* rdpdr, wStream* s) } /* Process port redirection capability set */ -static UINT rdpdr_process_port_capset(rdpdrPlugin* rdpdr, wStream* s) +static UINT rdpdr_process_port_capset(rdpdrPlugin* rdpdr, wStream* s, UINT16 capabilityLength) { - UINT16 capabilityLength; WINPR_UNUSED(rdpdr); - if (!Stream_CheckAndLogRequiredLengthWLog(rdpdr->log, s, 2)) - return ERROR_INVALID_DATA; - - Stream_Read_UINT16(s, capabilityLength); - - if (capabilityLength < 4U) - return ERROR_INVALID_DATA; - - if (!Stream_CheckAndLogRequiredLengthWLog(rdpdr->log, s, capabilityLength - 4U)) + if (!Stream_CheckAndLogRequiredLengthWLog(rdpdr->log, s, capabilityLength)) return ERROR_INVALID_DATA; - Stream_Seek(s, capabilityLength - 4U); + Stream_Seek(s, capabilityLength); return CHANNEL_RC_OK; } @@ -176,23 +152,14 @@ static void rdpdr_write_drive_capset(rdpdrPlugin* rdpdr, wStream* s) } /* Process drive redirection capability set */ -static UINT rdpdr_process_drive_capset(rdpdrPlugin* rdpdr, wStream* s) +static UINT rdpdr_process_drive_capset(rdpdrPlugin* rdpdr, wStream* s, UINT16 capabilityLength) { - UINT16 capabilityLength; WINPR_UNUSED(rdpdr); - if (!Stream_CheckAndLogRequiredLengthWLog(rdpdr->log, s, 2)) - return ERROR_INVALID_DATA; - - Stream_Read_UINT16(s, capabilityLength); - - if (capabilityLength < 4) - return ERROR_INVALID_DATA; - - if (!Stream_CheckAndLogRequiredLengthWLog(rdpdr->log, s, capabilityLength - 4U)) + if (!Stream_CheckAndLogRequiredLengthWLog(rdpdr->log, s, capabilityLength)) return ERROR_INVALID_DATA; - Stream_Seek(s, capabilityLength - 4U); + Stream_Seek(s, capabilityLength); return CHANNEL_RC_OK; } @@ -204,23 +171,14 @@ static void rdpdr_write_smartcard_capset(rdpdrPlugin* rdpdr, wStream* s) } /* Process smartcard redirection capability set */ -static UINT rdpdr_process_smartcard_capset(rdpdrPlugin* rdpdr, wStream* s) +static UINT rdpdr_process_smartcard_capset(rdpdrPlugin* rdpdr, wStream* s, UINT16 capabilityLength) { - UINT16 capabilityLength; WINPR_UNUSED(rdpdr); - if (!Stream_CheckAndLogRequiredLengthWLog(rdpdr->log, s, 2)) - return ERROR_INVALID_DATA; - - Stream_Read_UINT16(s, capabilityLength); - - if (capabilityLength < 4) - return ERROR_INVALID_DATA; - - if (!Stream_CheckAndLogRequiredLengthWLog(rdpdr->log, s, capabilityLength - 4U)) + if (!Stream_CheckAndLogRequiredLengthWLog(rdpdr->log, s, capabilityLength)) return ERROR_INVALID_DATA; - Stream_Seek(s, capabilityLength - 4U); + Stream_Seek(s, capabilityLength); return CHANNEL_RC_OK; } @@ -229,7 +187,6 @@ UINT rdpdr_process_capability_request(rdpdrPlugin* rdpdr, wStream* s) UINT status = CHANNEL_RC_OK; UINT16 i; UINT16 numCapabilities; - UINT16 capabilityType; if (!rdpdr || !s) return CHANNEL_RC_NULL_DATA; @@ -245,31 +202,44 @@ UINT rdpdr_process_capability_request(rdpdrPlugin* rdpdr, wStream* s) for (i = 0; i < numCapabilities; i++) { - if (!Stream_CheckAndLogRequiredLengthWLog(rdpdr->log, s, sizeof(UINT16))) + UINT16 capabilityType; + UINT16 capabilityLength; + UINT32 version = 0; + + if (!Stream_CheckAndLogRequiredLengthWLog(rdpdr->log, s, + 2 * sizeof(UINT16) + sizeof(UINT32))) return ERROR_INVALID_DATA; Stream_Read_UINT16(s, capabilityType); + Stream_Read_UINT16(s, capabilityLength); + Stream_Read_UINT32(s, version); + + if (capabilityLength < 8) + { + return ERROR_INVALID_DATA; + } + capabilityLength -= 8; switch (capabilityType) { case CAP_GENERAL_TYPE: - status = rdpdr_process_general_capset(rdpdr, s); + status = rdpdr_process_general_capset(rdpdr, s, capabilityLength); break; case CAP_PRINTER_TYPE: - status = rdpdr_process_printer_capset(rdpdr, s); + status = rdpdr_process_printer_capset(rdpdr, s, capabilityLength); break; case CAP_PORT_TYPE: - status = rdpdr_process_port_capset(rdpdr, s); + status = rdpdr_process_port_capset(rdpdr, s, capabilityLength); break; case CAP_DRIVE_TYPE: - status = rdpdr_process_drive_capset(rdpdr, s); + status = rdpdr_process_drive_capset(rdpdr, s, capabilityLength); break; case CAP_SMARTCARD_TYPE: - status = rdpdr_process_smartcard_capset(rdpdr, s); + status = rdpdr_process_smartcard_capset(rdpdr, s, capabilityLength); break; default: diff --git a/channels/rdpdr/client/rdpdr_main.c b/channels/rdpdr/client/rdpdr_main.c index 06d653d8f56a..ab68639550c2 100644 --- a/channels/rdpdr/client/rdpdr_main.c +++ b/channels/rdpdr/client/rdpdr_main.c @@ -1221,6 +1221,15 @@ static UINT rdpdr_process_server_announce_request(rdpdrPlugin* rdpdr, wStream* s Stream_Read_UINT16(s, rdpdr->serverVersionMinor); Stream_Read_UINT32(s, rdpdr->clientID); rdpdr->sequenceId++; + + rdpdr->clientVersionMajor = MIN(RDPDR_VERSION_MAJOR, rdpdr->serverVersionMajor); + rdpdr->clientVersionMinor = MIN(RDPDR_VERSION_MINOR_RDP10X, rdpdr->serverVersionMinor); + WLog_Print(rdpdr->log, WLOG_DEBUG, + "[rdpdr] server announces version %" PRIu32 ".%" PRIu32 ", client uses %" PRIu32 + ".%" PRIu32, + rdpdr->serverVersionMajor, rdpdr->serverVersionMinor, rdpdr->clientVersionMajor, + rdpdr->clientVersionMinor); + return CHANNEL_RC_OK; } @@ -1372,8 +1381,8 @@ static UINT rdpdr_send_device_list_announce_request(rdpdrPlugin* rdpdr, BOOL use * 3. other devices are sent only after user_loggedon */ - if ((rdpdr->clientVersionMinor == 0x0005) || (device->type == RDPDR_DTYP_SMARTCARD) || - userLoggedOn) + if ((rdpdr->clientVersionMinor == RDPDR_VERSION_MINOR_RDP51) || + (device->type == RDPDR_DTYP_SMARTCARD) || userLoggedOn) { data_len = (device->data == NULL ? 0 : Stream_GetPosition(device->data)); diff --git a/channels/rdpdr/server/rdpdr_main.h b/channels/rdpdr/server/rdpdr_main.h index f3f54cc0735e..c1ec5344551f 100644 --- a/channels/rdpdr/server/rdpdr_main.h +++ b/channels/rdpdr/server/rdpdr_main.h @@ -57,13 +57,6 @@ struct _RDPDR_HEADER }; typedef struct _RDPDR_HEADER RDPDR_HEADER; -#define RDPDR_VERSION_MAJOR 0x0001 - -#define RDPDR_VERSION_MINOR_RDP50 0x0002 -#define RDPDR_VERSION_MINOR_RDP51 0x0005 -#define RDPDR_VERSION_MINOR_RDP52 0x000A -#define RDPDR_VERSION_MINOR_RDP6X 0x000C - #define RDPDR_CAPABILITY_HEADER_LENGTH 8 struct _RDPDR_CAPABILITY_HEADER diff --git a/include/freerdp/channels/rdpdr.h b/include/freerdp/channels/rdpdr.h index b61a4c7e1891..6cd283b8e620 100644 --- a/include/freerdp/channels/rdpdr.h +++ b/include/freerdp/channels/rdpdr.h @@ -41,6 +41,14 @@ #define RDPDR_DEVICE_IO_CONTROL_REQ_HDR_LENGTH 32 #define RDPDR_DEVICE_IO_CONTROL_RSP_HDR_LENGTH 4 +#define RDPDR_VERSION_MAJOR 0x0001 + +#define RDPDR_VERSION_MINOR_RDP50 0x0002 +#define RDPDR_VERSION_MINOR_RDP51 0x0005 +#define RDPDR_VERSION_MINOR_RDP52 0x000A +#define RDPDR_VERSION_MINOR_RDP6X 0x000C +#define RDPDR_VERSION_MINOR_RDP10X 0x000D + /* RDPDR_HEADER.Component */ enum RDPDR_CTYP { From 453f4cfd040efd66d91469a84eecf6d39e48b734 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Mon, 4 Dec 2023 09:50:53 +0100 Subject: [PATCH 417/496] fixed clang-format --- .clang-format | 1 - 1 file changed, 1 deletion(-) diff --git a/.clang-format b/.clang-format index 33a6584b85b6..6791025b7eb6 100644 --- a/.clang-format +++ b/.clang-format @@ -104,7 +104,6 @@ ForEachMacros: ... Language: ObjC PointerBindsToType: false -ObjCSpaceAfterProperty: true SortIncludes: false ObjCBlockIndentWidth: 4 ObjCSpaceAfterProperty: false From 67df862a17cd8066b0fff9fc7bdb90820fef86ce Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Wed, 6 Dec 2023 14:17:33 +0100 Subject: [PATCH 418/496] [channels,rdpdr] fix #9610 windows RDP server randomly sends PAKID_CORE_SERVER_CAPABILITY to reinitialize the rdpdr channel. Allow this message in all following states. (cherry picked from commit 303c477c066ad65549a51f86bf56d0d30ef12c14) --- channels/rdpdr/client/rdpdr_main.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/channels/rdpdr/client/rdpdr_main.c b/channels/rdpdr/client/rdpdr_main.c index ab68639550c2..a9ac6eca72ca 100644 --- a/channels/rdpdr/client/rdpdr_main.c +++ b/channels/rdpdr/client/rdpdr_main.c @@ -1635,8 +1635,11 @@ static BOOL rdpdr_check_channel_state(rdpdrPlugin* rdpdr, UINT16 packetid) return rdpdr_state_check(rdpdr, packetid, RDPDR_CHANNEL_STATE_ANNOUNCE, 1, RDPDR_CHANNEL_STATE_INITIAL); case PAKID_CORE_SERVER_CAPABILITY: - return rdpdr_state_check(rdpdr, packetid, RDPDR_CHANNEL_STATE_SERVER_CAPS, 1, - RDPDR_CHANNEL_STATE_NAME_REQUEST); + return rdpdr_state_check(rdpdr, packetid, RDPDR_CHANNEL_STATE_SERVER_CAPS, 6, + RDPDR_CHANNEL_STATE_NAME_REQUEST, + RDPDR_CHANNEL_STATE_SERVER_CAPS, RDPDR_CHANNEL_STATE_READY, + RDPDR_CHANNEL_STATE_CLIENT_CAPS, PAKID_CORE_CLIENTID_CONFIRM, + PAKID_CORE_USER_LOGGEDON); case PAKID_CORE_CLIENTID_CONFIRM: return rdpdr_state_check(rdpdr, packetid, RDPDR_CHANNEL_STATE_CLIENTID_CONFIRM, 3, RDPDR_CHANNEL_STATE_CLIENT_CAPS, RDPDR_CHANNEL_STATE_READY, From b837bc15442e0f95e71250106ffbb5a2c566d1ff Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Mon, 11 Dec 2023 11:28:20 +0100 Subject: [PATCH 419/496] [winpr,crt] fix ICU string convert use ucnv_convert to make conversion endian safe (cherry picked from commit d47058011e7c5e628e47be0d968d0bb2ded63f99) --- winpr/libwinpr/crt/CMakeLists.txt | 2 +- winpr/libwinpr/crt/unicode.c | 39 +++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/winpr/libwinpr/crt/CMakeLists.txt b/winpr/libwinpr/crt/CMakeLists.txt index c1645b91352a..5ee4bbd1e3c0 100644 --- a/winpr/libwinpr/crt/CMakeLists.txt +++ b/winpr/libwinpr/crt/CMakeLists.txt @@ -29,7 +29,7 @@ if (NOT WITH_ICU) endif(NOT WITH_ICU) if (WITH_ICU) - find_package(ICU REQUIRED i18n uc io) + find_package(ICU REQUIRED i18n uc io data) winpr_include_directory_add(${ICU_INCLUDE_DIRS}) winpr_library_add_private(${ICU_LIBRARIES}) endif (WITH_ICU) diff --git a/winpr/libwinpr/crt/unicode.c b/winpr/libwinpr/crt/unicode.c index a491979710e1..f189ff2a0826 100644 --- a/winpr/libwinpr/crt/unicode.c +++ b/winpr/libwinpr/crt/unicode.c @@ -40,6 +40,8 @@ #include "../log.h" #define TAG WINPR_TAG("unicode") +#define UCNV_CONVERT 1 + /** * Notes on cross-platform Unicode portability: * @@ -201,6 +203,26 @@ int MultiByteToWideChar(UINT CodePage, DWORD dwFlags, LPCSTR lpMultiByteStr, int targetCapacity = cchWideChar; error = U_ZERO_ERROR; +#if defined(UCNV_CONVERT) + if (cchWideChar == 0) + { + targetLength = + ucnv_convert("UTF-16LE", "UTF-8", NULL, 0, lpMultiByteStr, cbMultiByte, &error); + if (targetLength > 0) + targetLength /= sizeof(WCHAR); + cchWideChar = targetLength; + } + else + { + targetLength = + ucnv_convert("UTF-16LE", "UTF-8", targetStart, targetCapacity * sizeof(WCHAR), + lpMultiByteStr, cbMultiByte, &error); + if (targetLength > 0) + targetLength /= sizeof(WCHAR); + cchWideChar = U_SUCCESS(error) ? targetLength : 0; + } + +#else if (cchWideChar == 0) { u_strFromUTF8(NULL, 0, &targetLength, lpMultiByteStr, cbMultiByte, &error); @@ -212,6 +234,7 @@ int MultiByteToWideChar(UINT CodePage, DWORD dwFlags, LPCSTR lpMultiByteStr, int &error); cchWideChar = U_SUCCESS(error) ? targetLength : 0; } +#endif } #else @@ -327,6 +350,21 @@ int WideCharToMultiByte(UINT CodePage, DWORD dwFlags, LPCWSTR lpWideCharStr, int targetCapacity = cbMultiByte; error = U_ZERO_ERROR; +#if defined(UCNV_CONVERT) + if (cbMultiByte == 0) + { + targetLength = ucnv_convert("UTF-8", "UTF-16LE", NULL, 0, lpWideCharStr, + cchWideChar * sizeof(WCHAR), &error); + cbMultiByte = targetLength; + } + else + { + targetLength = ucnv_convert("UTF-8", "UTF-16LE", targetStarrt, targetCapacity, + lpWideCharStr, cchWideChar * sizeof(WCHAR), &error); + cbMultiByte = U_SUCCESS(error) ? targetLength : 0; + } + +#else if (cbMultiByte == 0) { u_strToUTF8(NULL, 0, &targetLength, lpWideCharStr, cchWideChar, &error); @@ -338,6 +376,7 @@ int WideCharToMultiByte(UINT CodePage, DWORD dwFlags, LPCWSTR lpWideCharStr, int &error); cbMultiByte = U_SUCCESS(error) ? targetLength : 0; } +#endif } #else From b2fa4d6743b9da1281c8f2bcc72a9a5223c231fb Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Thu, 14 Dec 2023 13:37:59 +0100 Subject: [PATCH 420/496] changelog --- ChangeLog | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index bdb82968fc84..2859c5b8246b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,7 +1,12 @@ -# 20xx-xx-xx Version 2.xx.xx +# 2023-12-14 Version 2.11.3 Notworthy changes: * Disabled windows MEDIA FOUNDATION h264 decoder due to reported issues (#9469) +* Fix issues with drive redirection (#9530,9554, #9586, #9617) +* Use endian safe ICU string converter (#9631) +* Improve AAC support (#9577) +* Fix swiss german keyboard layout (#9560) +* Enable rfx-mode:image (#9428) # 2023-09-20 Version 2.11.2 @@ -10,7 +15,7 @@ Notworthy changes: * Backported #9360: backported certificate algorithm detection For a complete and detailed change log since the last release run: -git log 2.11.2..2.11.1 +git log 2.11.3...2.11.2 # 2023-09-04 Version 2.11.1 From b71674f58e22f278d4a75a6fbca89aab2e269fcd Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Thu, 14 Dec 2023 13:42:59 +0100 Subject: [PATCH 421/496] update release version to 2.11.3 --- CMakeLists.txt | 2 +- client/Android/android_freerdp.c | 2 +- winpr/CMakeLists.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 45affd55ce6f..f8980eb51afe 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -85,7 +85,7 @@ if ($ENV{BUILD_NUMBER}) endif() set(WITH_LIBRARY_VERSIONING "ON") -set(RAW_VERSION_STRING "2.11.2") +set(RAW_VERSION_STRING "2.11.3") if(EXISTS "${CMAKE_SOURCE_DIR}/.source_tag") file(READ ${CMAKE_SOURCE_DIR}/.source_tag RAW_VERSION_STRING) elseif(USE_VERSION_FROM_GIT_TAG) diff --git a/client/Android/android_freerdp.c b/client/Android/android_freerdp.c index 142caaeb7f18..cc3ffc9489ca 100644 --- a/client/Android/android_freerdp.c +++ b/client/Android/android_freerdp.c @@ -57,7 +57,7 @@ #define TAG CLIENT_TAG("android") /* Defines the JNI version supported by this library. */ -#define FREERDP_JNI_VERSION "2.11.2" +#define FREERDP_JNI_VERSION "2.11.3" static void android_OnChannelConnectedEventHandler(void* context, ChannelConnectedEventArgs* e) { diff --git a/winpr/CMakeLists.txt b/winpr/CMakeLists.txt index 34dd6dfb98b6..b83d57d0c1d7 100644 --- a/winpr/CMakeLists.txt +++ b/winpr/CMakeLists.txt @@ -57,7 +57,7 @@ if (NOT WIN32) endif() # Soname versioning -set(RAW_VERSION_STRING "2.11.2") +set(RAW_VERSION_STRING "2.11.3") if(EXISTS "${CMAKE_SOURCE_DIR}/.source_tag") file(READ ${CMAKE_SOURCE_DIR}/.source_tag RAW_VERSION_STRING) elseif(USE_VERSION_FROM_GIT_TAG) From f286f34096850715e1887f2b102dc783abe9724f Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Thu, 14 Dec 2023 13:44:07 +0100 Subject: [PATCH 422/496] next development version 2.11.4-dev --- CMakeLists.txt | 2 +- client/Android/android_freerdp.c | 2 +- winpr/CMakeLists.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f8980eb51afe..da641f994fb7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -85,7 +85,7 @@ if ($ENV{BUILD_NUMBER}) endif() set(WITH_LIBRARY_VERSIONING "ON") -set(RAW_VERSION_STRING "2.11.3") +set(RAW_VERSION_STRING "2.11.4-dev") if(EXISTS "${CMAKE_SOURCE_DIR}/.source_tag") file(READ ${CMAKE_SOURCE_DIR}/.source_tag RAW_VERSION_STRING) elseif(USE_VERSION_FROM_GIT_TAG) diff --git a/client/Android/android_freerdp.c b/client/Android/android_freerdp.c index cc3ffc9489ca..62807c75ab92 100644 --- a/client/Android/android_freerdp.c +++ b/client/Android/android_freerdp.c @@ -57,7 +57,7 @@ #define TAG CLIENT_TAG("android") /* Defines the JNI version supported by this library. */ -#define FREERDP_JNI_VERSION "2.11.3" +#define FREERDP_JNI_VERSION "2.11.4-dev" static void android_OnChannelConnectedEventHandler(void* context, ChannelConnectedEventArgs* e) { diff --git a/winpr/CMakeLists.txt b/winpr/CMakeLists.txt index b83d57d0c1d7..badc87202802 100644 --- a/winpr/CMakeLists.txt +++ b/winpr/CMakeLists.txt @@ -57,7 +57,7 @@ if (NOT WIN32) endif() # Soname versioning -set(RAW_VERSION_STRING "2.11.3") +set(RAW_VERSION_STRING "2.11.4-dev") if(EXISTS "${CMAKE_SOURCE_DIR}/.source_tag") file(READ ${CMAKE_SOURCE_DIR}/.source_tag RAW_VERSION_STRING) elseif(USE_VERSION_FROM_GIT_TAG) From 52663d581cb148b2746df43c0c872a3ce5b959dd Mon Sep 17 00:00:00 2001 From: Pascal Nowack Date: Thu, 14 Dec 2023 17:03:22 +0100 Subject: [PATCH 423/496] winpr: Fix typo, that led to a compilation error Closes: https://github.com/FreeRDP/FreeRDP/issues/9651 --- winpr/libwinpr/crt/unicode.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/winpr/libwinpr/crt/unicode.c b/winpr/libwinpr/crt/unicode.c index f189ff2a0826..dc3533a8a7b5 100644 --- a/winpr/libwinpr/crt/unicode.c +++ b/winpr/libwinpr/crt/unicode.c @@ -359,7 +359,7 @@ int WideCharToMultiByte(UINT CodePage, DWORD dwFlags, LPCWSTR lpWideCharStr, int } else { - targetLength = ucnv_convert("UTF-8", "UTF-16LE", targetStarrt, targetCapacity, + targetLength = ucnv_convert("UTF-8", "UTF-16LE", targetStart, targetCapacity, lpWideCharStr, cchWideChar * sizeof(WCHAR), &error); cbMultiByte = U_SUCCESS(error) ? targetLength : 0; } From 60016d94556ae7bdb3f884ba4b924beae917d745 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Thu, 14 Dec 2023 18:12:36 +0100 Subject: [PATCH 424/496] update changelog --- ChangeLog | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 2859c5b8246b..31ce0580ef62 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,13 @@ # 2023-12-14 Version 2.11.3 +Notworthy changes: +* fix a typo in unicode commit (#9652) + +For a complete and detailed change log since the last release run: +git log 2.11.4...2.11.3 + +# 2023-12-14 Version 2.11.3 + Notworthy changes: * Disabled windows MEDIA FOUNDATION h264 decoder due to reported issues (#9469) * Fix issues with drive redirection (#9530,9554, #9586, #9617) @@ -8,6 +16,9 @@ Notworthy changes: * Fix swiss german keyboard layout (#9560) * Enable rfx-mode:image (#9428) +For a complete and detailed change log since the last release run: +git log 2.11.3...2.11.2 + # 2023-09-20 Version 2.11.2 Notworthy changes: @@ -15,7 +26,7 @@ Notworthy changes: * Backported #9360: backported certificate algorithm detection For a complete and detailed change log since the last release run: -git log 2.11.3...2.11.2 +git log 2.11.2...2.11.1 # 2023-09-04 Version 2.11.1 From 9c4cf02f61e69d33fdf9158fec99e6bd943c541b Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Thu, 14 Dec 2023 18:13:50 +0100 Subject: [PATCH 425/496] release-2.11.4 --- CMakeLists.txt | 2 +- client/Android/android_freerdp.c | 2 +- winpr/CMakeLists.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index da641f994fb7..4bd9a4499f76 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -85,7 +85,7 @@ if ($ENV{BUILD_NUMBER}) endif() set(WITH_LIBRARY_VERSIONING "ON") -set(RAW_VERSION_STRING "2.11.4-dev") +set(RAW_VERSION_STRING "2.11.4") if(EXISTS "${CMAKE_SOURCE_DIR}/.source_tag") file(READ ${CMAKE_SOURCE_DIR}/.source_tag RAW_VERSION_STRING) elseif(USE_VERSION_FROM_GIT_TAG) diff --git a/client/Android/android_freerdp.c b/client/Android/android_freerdp.c index 62807c75ab92..74acba3d35c5 100644 --- a/client/Android/android_freerdp.c +++ b/client/Android/android_freerdp.c @@ -57,7 +57,7 @@ #define TAG CLIENT_TAG("android") /* Defines the JNI version supported by this library. */ -#define FREERDP_JNI_VERSION "2.11.4-dev" +#define FREERDP_JNI_VERSION "2.11.4" static void android_OnChannelConnectedEventHandler(void* context, ChannelConnectedEventArgs* e) { diff --git a/winpr/CMakeLists.txt b/winpr/CMakeLists.txt index badc87202802..ffdb91e724cd 100644 --- a/winpr/CMakeLists.txt +++ b/winpr/CMakeLists.txt @@ -57,7 +57,7 @@ if (NOT WIN32) endif() # Soname versioning -set(RAW_VERSION_STRING "2.11.4-dev") +set(RAW_VERSION_STRING "2.11.4") if(EXISTS "${CMAKE_SOURCE_DIR}/.source_tag") file(READ ${CMAKE_SOURCE_DIR}/.source_tag RAW_VERSION_STRING) elseif(USE_VERSION_FROM_GIT_TAG) From 17635aab95fc39880f5774125b7f0516e7c07433 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Thu, 14 Dec 2023 18:14:28 +0100 Subject: [PATCH 426/496] start 2.11.5-dev cycle --- CMakeLists.txt | 2 +- client/Android/android_freerdp.c | 2 +- winpr/CMakeLists.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 4bd9a4499f76..b6941ef45492 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -85,7 +85,7 @@ if ($ENV{BUILD_NUMBER}) endif() set(WITH_LIBRARY_VERSIONING "ON") -set(RAW_VERSION_STRING "2.11.4") +set(RAW_VERSION_STRING "2.11.5-dev") if(EXISTS "${CMAKE_SOURCE_DIR}/.source_tag") file(READ ${CMAKE_SOURCE_DIR}/.source_tag RAW_VERSION_STRING) elseif(USE_VERSION_FROM_GIT_TAG) diff --git a/client/Android/android_freerdp.c b/client/Android/android_freerdp.c index 74acba3d35c5..5672c18fb722 100644 --- a/client/Android/android_freerdp.c +++ b/client/Android/android_freerdp.c @@ -57,7 +57,7 @@ #define TAG CLIENT_TAG("android") /* Defines the JNI version supported by this library. */ -#define FREERDP_JNI_VERSION "2.11.4" +#define FREERDP_JNI_VERSION "2.11.5-dev" static void android_OnChannelConnectedEventHandler(void* context, ChannelConnectedEventArgs* e) { diff --git a/winpr/CMakeLists.txt b/winpr/CMakeLists.txt index ffdb91e724cd..717e0d1baf84 100644 --- a/winpr/CMakeLists.txt +++ b/winpr/CMakeLists.txt @@ -57,7 +57,7 @@ if (NOT WIN32) endif() # Soname versioning -set(RAW_VERSION_STRING "2.11.4") +set(RAW_VERSION_STRING "2.11.5-dev") if(EXISTS "${CMAKE_SOURCE_DIR}/.source_tag") file(READ ${CMAKE_SOURCE_DIR}/.source_tag RAW_VERSION_STRING) elseif(USE_VERSION_FROM_GIT_TAG) From d3f62748c6662ce03ab9bc3b1dfb55794e47252c Mon Sep 17 00:00:00 2001 From: akallabeth Date: Tue, 9 Jan 2024 09:28:00 +0100 Subject: [PATCH 427/496] [deprecation] use new openssl API --- winpr/libwinpr/crypto/cipher.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/winpr/libwinpr/crypto/cipher.c b/winpr/libwinpr/crypto/cipher.c index 41725ab18d83..0fffc6de51d8 100644 --- a/winpr/libwinpr/crypto/cipher.c +++ b/winpr/libwinpr/crypto/cipher.c @@ -66,7 +66,11 @@ static WINPR_RC4_CTX* winpr_RC4_New_Internal(const BYTE* key, size_t keylen, BOO if (!evp) return NULL; +#if (OPENSSL_VERSION_NUMBER >= 0x30000000L) + EVP_CIPHER_CTX_reset((EVP_CIPHER_CTX*)ctx); +#else EVP_CIPHER_CTX_init((EVP_CIPHER_CTX*)ctx); +#endif if (EVP_EncryptInit_ex((EVP_CIPHER_CTX*)ctx, evp, NULL, NULL, NULL) != 1) { EVP_CIPHER_CTX_free ((EVP_CIPHER_CTX*)ctx); From 1d929ae9861ee8cdea83cc95b77176bd1e22a8d7 Mon Sep 17 00:00:00 2001 From: "Alexey R. Gavrilov" Date: Mon, 25 Dec 2023 15:14:32 +0300 Subject: [PATCH 428/496] [codec,progressive] prevent write at NULL When RFX_CONTEXT_PRIV::UseThreads is set to 0, progressive_process_tiles() function will not attempt to write at memory address 0. --- libfreerdp/codec/progressive.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/libfreerdp/codec/progressive.c b/libfreerdp/codec/progressive.c index a05a3341c644..8894b35c8845 100644 --- a/libfreerdp/codec/progressive.c +++ b/libfreerdp/codec/progressive.c @@ -1796,13 +1796,13 @@ static INLINE int progressive_process_tiles(PROGRESSIVE_CONTEXT* progressive, wS for (index = 0; index < region->numTiles; index++) { RFX_PROGRESSIVE_TILE* tile = region->tiles[index]; - params[index].progressive = progressive; - params[index].region = region; - params[index].context = context; - params[index].tile = tile; if (progressive->rfx_context->priv->UseThreads) { + params[index].progressive = progressive; + params[index].region = region; + params[index].context = context; + params[index].tile = tile; if (!(work_objects[index] = CreateThreadpoolWork( progressive_process_tiles_tile_work_callback, (void*)¶ms[index], &progressive->rfx_context->priv->ThreadPoolEnv))) @@ -1817,7 +1817,10 @@ static INLINE int progressive_process_tiles(PROGRESSIVE_CONTEXT* progressive, wS } else { - progressive_process_tiles_tile_work_callback(0, ¶ms[index], 0); + PROGRESSIVE_TILE_PROCESS_WORK_PARAM param = { + .progressive = progressive, .region = region, .context = context, .tile = tile + }; + progressive_process_tiles_tile_work_callback(0, ¶m, 0); } if (status < 0) From 8b0281fb1415151f959e6215bf68ee4b8802f5ed Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Wed, 22 Nov 2023 09:59:53 +0100 Subject: [PATCH 429/496] [channels,rdpsnd] fix missing include --- channels/rdpsnd/client/pulse/rdpsnd_pulse.c | 1 + 1 file changed, 1 insertion(+) diff --git a/channels/rdpsnd/client/pulse/rdpsnd_pulse.c b/channels/rdpsnd/client/pulse/rdpsnd_pulse.c index 67e2b2b10c56..2fd4d7d9e7ef 100644 --- a/channels/rdpsnd/client/pulse/rdpsnd_pulse.c +++ b/channels/rdpsnd/client/pulse/rdpsnd_pulse.c @@ -28,6 +28,7 @@ #include #include #include +#include #include #include From aeac3040cc99eeaff1e1171a822114c857b9dca9 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Sat, 13 Jan 2024 21:01:55 +0100 Subject: [PATCH 430/496] [codec,planar] check resolution for overflow If the codec resolution is too large return an error as the internal buffers would otherwise overflow. (cherry picked from commit 44edab1deae4f8c901c00a00683f888cef36d853) --- libfreerdp/codec/planar.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/libfreerdp/codec/planar.c b/libfreerdp/codec/planar.c index b4815a632309..0a5ec581c6cc 100644 --- a/libfreerdp/codec/planar.c +++ b/libfreerdp/codec/planar.c @@ -1496,7 +1496,13 @@ BOOL freerdp_bitmap_planar_context_reset(BITMAP_PLANAR_CONTEXT* context, UINT32 context->bgr = FALSE; context->maxWidth = PLANAR_ALIGN(width, 4); context->maxHeight = PLANAR_ALIGN(height, 4); - context->maxPlaneSize = context->maxWidth * context->maxHeight; + const UINT64 tmp = (UINT64)context->maxWidth * context->maxHeight; + if (tmp > UINT32_MAX) + return FALSE; + context->maxPlaneSize = tmp; + + if (context->maxWidth > UINT32_MAX / 4) + return FALSE; context->nTempStep = context->maxWidth * 4; free(context->planesBuffer); free(context->pTempData); From 627709512610d67b2e36e8758e20d4e3086f1840 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Fri, 19 Jan 2024 09:01:28 +0100 Subject: [PATCH 431/496] changelog --- ChangeLog | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/ChangeLog b/ChangeLog index 31ce0580ef62..545d99b14209 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,4 +1,14 @@ -# 2023-12-14 Version 2.11.3 +# 2024-01-19 Version 2.11.5 + +Noteworthy changes: +* Fix integer overflow in progressive decoder +* Update OpenSSL API usage for compatiblility with newer versions (#9747) +* Prevent NULL dereference for single thread decoder (#9712) + +For a complete and detailed change log since the last release run: +git log 2.11.5...2.11.4 + +# 2023-12-14 Version 2.11.4 Notworthy changes: * fix a typo in unicode commit (#9652) From f1121b0812f992918b56998df8141ea0ca785def Mon Sep 17 00:00:00 2001 From: akallabeth Date: Fri, 19 Jan 2024 09:02:36 +0100 Subject: [PATCH 432/496] release 2.11.5 --- CMakeLists.txt | 2 +- client/Android/android_freerdp.c | 2 +- winpr/CMakeLists.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index b6941ef45492..e2eba2f974b6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -85,7 +85,7 @@ if ($ENV{BUILD_NUMBER}) endif() set(WITH_LIBRARY_VERSIONING "ON") -set(RAW_VERSION_STRING "2.11.5-dev") +set(RAW_VERSION_STRING "2.11.5") if(EXISTS "${CMAKE_SOURCE_DIR}/.source_tag") file(READ ${CMAKE_SOURCE_DIR}/.source_tag RAW_VERSION_STRING) elseif(USE_VERSION_FROM_GIT_TAG) diff --git a/client/Android/android_freerdp.c b/client/Android/android_freerdp.c index 5672c18fb722..5e793601d4bf 100644 --- a/client/Android/android_freerdp.c +++ b/client/Android/android_freerdp.c @@ -57,7 +57,7 @@ #define TAG CLIENT_TAG("android") /* Defines the JNI version supported by this library. */ -#define FREERDP_JNI_VERSION "2.11.5-dev" +#define FREERDP_JNI_VERSION "2.11.5" static void android_OnChannelConnectedEventHandler(void* context, ChannelConnectedEventArgs* e) { diff --git a/winpr/CMakeLists.txt b/winpr/CMakeLists.txt index 717e0d1baf84..b3322410a3b7 100644 --- a/winpr/CMakeLists.txt +++ b/winpr/CMakeLists.txt @@ -57,7 +57,7 @@ if (NOT WIN32) endif() # Soname versioning -set(RAW_VERSION_STRING "2.11.5-dev") +set(RAW_VERSION_STRING "2.11.5") if(EXISTS "${CMAKE_SOURCE_DIR}/.source_tag") file(READ ${CMAKE_SOURCE_DIR}/.source_tag RAW_VERSION_STRING) elseif(USE_VERSION_FROM_GIT_TAG) From e87df53edc1f3cf427888b1ba6f7a5ca05dd7f45 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Fri, 19 Jan 2024 09:03:26 +0100 Subject: [PATCH 433/496] start 2.11.6-dev cycle --- CMakeLists.txt | 2 +- client/Android/android_freerdp.c | 2 +- winpr/CMakeLists.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e2eba2f974b6..da084c26a139 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -85,7 +85,7 @@ if ($ENV{BUILD_NUMBER}) endif() set(WITH_LIBRARY_VERSIONING "ON") -set(RAW_VERSION_STRING "2.11.5") +set(RAW_VERSION_STRING "2.11.6-dev") if(EXISTS "${CMAKE_SOURCE_DIR}/.source_tag") file(READ ${CMAKE_SOURCE_DIR}/.source_tag RAW_VERSION_STRING) elseif(USE_VERSION_FROM_GIT_TAG) diff --git a/client/Android/android_freerdp.c b/client/Android/android_freerdp.c index 5e793601d4bf..2c4aae2fcaae 100644 --- a/client/Android/android_freerdp.c +++ b/client/Android/android_freerdp.c @@ -57,7 +57,7 @@ #define TAG CLIENT_TAG("android") /* Defines the JNI version supported by this library. */ -#define FREERDP_JNI_VERSION "2.11.5" +#define FREERDP_JNI_VERSION "2.11.6-dev" static void android_OnChannelConnectedEventHandler(void* context, ChannelConnectedEventArgs* e) { diff --git a/winpr/CMakeLists.txt b/winpr/CMakeLists.txt index b3322410a3b7..a2c0f3117653 100644 --- a/winpr/CMakeLists.txt +++ b/winpr/CMakeLists.txt @@ -57,7 +57,7 @@ if (NOT WIN32) endif() # Soname versioning -set(RAW_VERSION_STRING "2.11.5") +set(RAW_VERSION_STRING "2.11.6-dev") if(EXISTS "${CMAKE_SOURCE_DIR}/.source_tag") file(READ ${CMAKE_SOURCE_DIR}/.source_tag RAW_VERSION_STRING) elseif(USE_VERSION_FROM_GIT_TAG) From b70c8e989d2807cea47bbf89e57700b5a10b2ca7 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Tue, 16 Apr 2024 08:45:03 +0200 Subject: [PATCH 434/496] [codec,ncrush] fix missing input length check (cherry picked from commit dbe5d521001789511bbf1db97c9bc565d168e03b) --- libfreerdp/codec/ncrush.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/libfreerdp/codec/ncrush.c b/libfreerdp/codec/ncrush.c index c1d622a9c0bd..199f1ed7c488 100644 --- a/libfreerdp/codec/ncrush.c +++ b/libfreerdp/codec/ncrush.c @@ -2041,6 +2041,12 @@ int ncrush_decompress(NCRUSH_CONTEXT* ncrush, BYTE* pSrcData, UINT32 SrcSize, BY return 1; } + if (SrcSize < 4) + { + WLog_ERR(TAG, "Input size short: SrcSize %" PRIu32 " < 4", SrcSize); + return -1; + } + const BYTE* SrcEnd = &pSrcData[SrcSize]; const BYTE* SrcPtr = pSrcData + 4; From 9bc624c721ecde8251cfabd1edf069bc713ccc97 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Tue, 16 Apr 2024 08:42:52 +0200 Subject: [PATCH 435/496] [codec,planar] fix missing input length checks (cherry picked from commit 52d75f6f4078143951e8a4976bc5af30a5556cb6) --- libfreerdp/codec/planar.c | 53 +++++++++++++++++++++++++++++++-------- 1 file changed, 43 insertions(+), 10 deletions(-) diff --git a/libfreerdp/codec/planar.c b/libfreerdp/codec/planar.c index 0a5ec581c6cc..fe27011e1a08 100644 --- a/libfreerdp/codec/planar.c +++ b/libfreerdp/codec/planar.c @@ -689,6 +689,13 @@ BOOL planar_decompress(BITMAP_PLANAR_CONTEXT* planar, const BYTE* pSrcData, UINT rawHeights[3] = nSrcHeight; } + const size_t diff = srcp - pSrcData; + if (SrcSize < diff) + { + WLog_ERR(TAG, "Size mismatch %" PRIu32 " < %" PRIuz, SrcSize, diff); + return FALSE; + } + if (!rle) /* RAW */ { UINT32 base = planeSize * 3; @@ -697,8 +704,12 @@ BOOL planar_decompress(BITMAP_PLANAR_CONTEXT* planar, const BYTE* pSrcData, UINT if (alpha) { - if ((SrcSize - (srcp - pSrcData)) < (planeSize + base)) + if ((SrcSize - diff) < (planeSize + base)) + { + WLog_ERR(TAG, "Alpha plane size mismatch %" PRIuz " < %" PRIu32, SrcSize - diff, + (planeSize + base)); return FALSE; + } planes[3] = srcp; /* AlphaPlane */ planes[0] = planes[3] + rawSizes[3]; /* LumaOrRedPlane */ @@ -710,8 +721,11 @@ BOOL planar_decompress(BITMAP_PLANAR_CONTEXT* planar, const BYTE* pSrcData, UINT } else { - if ((SrcSize - (srcp - pSrcData)) < base) + if ((SrcSize - diff) < base) + { + WLog_ERR(TAG, "plane size mismatch %" PRIu32 " < %" PRIu32, SrcSize - diff, base); return FALSE; + } planes[0] = srcp; /* LumaOrRedPlane */ planes[1] = planes[0] + rawSizes[0]; /* OrangeChromaOrGreenPlane */ @@ -726,8 +740,8 @@ BOOL planar_decompress(BITMAP_PLANAR_CONTEXT* planar, const BYTE* pSrcData, UINT if (alpha) { planes[3] = srcp; - rleSizes[3] = planar_skip_plane_rle(planes[3], SrcSize - (planes[3] - pSrcData), - rawWidths[3], rawHeights[3]); /* AlphaPlane */ + rleSizes[3] = planar_skip_plane_rle(planes[3], SrcSize - diff, rawWidths[3], + rawHeights[3]); /* AlphaPlane */ if (rleSizes[3] < 0) return FALSE; @@ -737,22 +751,41 @@ BOOL planar_decompress(BITMAP_PLANAR_CONTEXT* planar, const BYTE* pSrcData, UINT else planes[0] = srcp; - rleSizes[0] = planar_skip_plane_rle(planes[0], SrcSize - (planes[0] - pSrcData), - rawWidths[0], rawHeights[0]); /* RedPlane */ + const size_t diff0 = (planes[0] - pSrcData); + if (SrcSize < diff0) + { + WLog_ERR(TAG, "Size mismatch %" PRIu32 " < %" PRIuz, SrcSize, diff0); + return FALSE; + } + rleSizes[0] = planar_skip_plane_rle(planes[0], SrcSize - diff0, rawWidths[0], + rawHeights[0]); /* RedPlane */ if (rleSizes[0] < 0) return FALSE; planes[1] = planes[0] + rleSizes[0]; - rleSizes[1] = planar_skip_plane_rle(planes[1], SrcSize - (planes[1] - pSrcData), - rawWidths[1], rawHeights[1]); /* GreenPlane */ + + const size_t diff1 = (planes[1] - pSrcData); + if (SrcSize < diff1) + { + WLog_ERR(TAG, "Size mismatch %" PRIu32 " < %" PRIuz, SrcSize, diff1); + return FALSE; + } + rleSizes[1] = planar_skip_plane_rle(planes[1], SrcSize - diff1, rawWidths[1], + rawHeights[1]); /* GreenPlane */ if (rleSizes[1] < 1) return FALSE; planes[2] = planes[1] + rleSizes[1]; - rleSizes[2] = planar_skip_plane_rle(planes[2], SrcSize - (planes[2] - pSrcData), - rawWidths[2], rawHeights[2]); /* BluePlane */ + const size_t diff2 = (planes[2] - pSrcData); + if (SrcSize < diff2) + { + WLog_ERR(TAG, "Size mismatch %" PRIu32 " < %" PRIuz, SrcSize, diff); + return FALSE; + } + rleSizes[2] = planar_skip_plane_rle(planes[2], SrcSize - diff2, rawWidths[2], + rawHeights[2]); /* BluePlane */ if (rleSizes[2] < 1) return FALSE; From d88ad1acd142769650a6159906ac90f46a766265 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Tue, 16 Apr 2024 08:35:05 +0200 Subject: [PATCH 436/496] [codec,clear] fix integer overflow reorder check to prevent possible integer overflow (cherry picked from commit 3a2a241b8fcfee853e35cc54bec00375096fedd9) --- libfreerdp/codec/clear.c | 2 +- libfreerdp/codec/zgfx.c | 14 +++++++++----- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/libfreerdp/codec/clear.c b/libfreerdp/codec/clear.c index 101260770ba7..b8899746ecaf 100644 --- a/libfreerdp/codec/clear.c +++ b/libfreerdp/codec/clear.c @@ -410,7 +410,7 @@ static BOOL clear_decompress_residual_data(CLEAR_CONTEXT* clear, wStream* s, } } - if ((pixelIndex + runLengthFactor) > pixelCount) + if ((pixelIndex >= pixelCount) || (runLengthFactor > (pixelCount - pixelIndex))) { WLog_ERR(TAG, "pixelIndex %" PRIu32 " + runLengthFactor %" PRIu32 " > pixelCount %" PRIu32 diff --git a/libfreerdp/codec/zgfx.c b/libfreerdp/codec/zgfx.c index 841b50860711..b7b96ade0c58 100644 --- a/libfreerdp/codec/zgfx.c +++ b/libfreerdp/codec/zgfx.c @@ -230,7 +230,10 @@ static BOOL zgfx_decompress_segment(ZGFX_CONTEXT* zgfx, wStream* stream, size_t BYTE* pbSegment; size_t cbSegment; - if (!zgfx || !stream || (segmentSize < 2)) + WINPR_ASSERT(zgfx); + WINPR_ASSERT(stream); + + if (segmentSize < 2) return FALSE; cbSegment = segmentSize - 1; @@ -349,8 +352,9 @@ static BOOL zgfx_decompress_segment(ZGFX_CONTEXT* zgfx, wStream* stream, size_t if (count > sizeof(zgfx->OutputBuffer) - zgfx->OutputCount) return FALSE; - - if (count > zgfx->cBitsRemaining / 8) + else if (count > zgfx->cBitsRemaining / 8) + return FALSE; + else if (zgfx->pbInputCurrent + count > zgfx->pbInputEnd) return FALSE; CopyMemory(&(zgfx->OutputBuffer[zgfx->OutputCount]), zgfx->pbInputCurrent, @@ -388,8 +392,8 @@ int zgfx_decompress(ZGFX_CONTEXT* zgfx, const BYTE* pSrcData, UINT32 SrcSize, BY BYTE descriptor; wStream* stream = Stream_New((BYTE*)pSrcData, SrcSize); - if (!stream) - return -1; + WINPR_ASSERT(zgfx); + WINPR_ASSERT(stream); if (Stream_GetRemainingLength(stream) < 1) goto fail; From 5893b5f277db38b0040c572b078de838b84cfc07 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Tue, 16 Apr 2024 08:26:37 +0200 Subject: [PATCH 437/496] [codec,nsc] fix missing check in nsc_rle_decode abort if there are more bytes to be read then there are left. (cherry picked from commit fb4f2d6e4db563077afcae4d270ba78ff905f6cf) --- libfreerdp/codec/nsc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libfreerdp/codec/nsc.c b/libfreerdp/codec/nsc.c index 645ca7512716..d10fc6bca085 100644 --- a/libfreerdp/codec/nsc.c +++ b/libfreerdp/codec/nsc.c @@ -169,7 +169,7 @@ static BOOL nsc_rle_decode(const BYTE* in, size_t inSize, BYTE* out, UINT32 outS len |= ((UINT32)(*in++)) << 24U; } - if (outSize < len) + if ((outSize < len) || (left < len)) return FALSE; outSize -= len; From 18cef378eae2b63a1a750da242f00da12b5b3881 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Wed, 17 Apr 2024 11:23:52 +0200 Subject: [PATCH 438/496] [codec,interleaved] backport from 3.5.0 --- libfreerdp/codec/include/bitmap.c | 119 ++++---- libfreerdp/codec/interleaved.c | 448 +++++++++++++++++++++++------- 2 files changed, 413 insertions(+), 154 deletions(-) diff --git a/libfreerdp/codec/include/bitmap.c b/libfreerdp/codec/include/bitmap.c index 38bcaa859f88..af8338711e38 100644 --- a/libfreerdp/codec/include/bitmap.c +++ b/libfreerdp/codec/include/bitmap.c @@ -31,7 +31,10 @@ static INLINE BYTE* WRITEFGBGIMAGE(BYTE* pbDest, const BYTE* pbDestEnd, UINT32 r BYTE mask = 0x01; if (cBits > 8) + { + WLog_ERR(TAG, "cBits %d > 8", cBits); return NULL; + } if (!ENSURE_CAPACITY(pbDest, pbDestEnd, cBits)) return NULL; @@ -46,7 +49,6 @@ static INLINE BYTE* WRITEFGBGIMAGE(BYTE* pbDest, const BYTE* pbDestEnd, UINT32 r data = xorPixel; DESTWRITEPIXEL(pbDest, data); - DESTNEXTPIXEL(pbDest); mask = mask << 1; }); return pbDest; @@ -62,7 +64,10 @@ static INLINE BYTE* WRITEFIRSTLINEFGBGIMAGE(BYTE* pbDest, const BYTE* pbDestEnd, BYTE mask = 0x01; if (cBits > 8) + { + WLog_ERR(TAG, "cBits %d > 8", cBits); return NULL; + } if (!ENSURE_CAPACITY(pbDest, pbDestEnd, cBits)) return NULL; @@ -76,7 +81,6 @@ static INLINE BYTE* WRITEFIRSTLINEFGBGIMAGE(BYTE* pbDest, const BYTE* pbDestEnd, data = BLACK_PIXEL; DESTWRITEPIXEL(pbDest, data); - DESTNEXTPIXEL(pbDest); mask = mask << 1; }); return pbDest; @@ -88,6 +92,9 @@ static INLINE BYTE* WRITEFIRSTLINEFGBGIMAGE(BYTE* pbDest, const BYTE* pbDestEnd, static INLINE BOOL RLEDECOMPRESS(const BYTE* pbSrcBuffer, UINT32 cbSrcBuffer, BYTE* pbDestBuffer, UINT32 rowDelta, UINT32 width, UINT32 height) { +#if defined(WITH_DEBUG_CODECS) + char sbuffer[128] = { 0 }; +#endif const BYTE* pbSrc = pbSrcBuffer; const BYTE* pbEnd; const BYTE* pbDestEnd; @@ -100,14 +107,22 @@ static INLINE BOOL RLEDECOMPRESS(const BYTE* pbSrcBuffer, UINT32 cbSrcBuffer, BY PIXEL pixelA, pixelB; UINT32 runLength; UINT32 code; - UINT32 advance; + UINT32 advance = 0; RLEEXTRA if ((rowDelta == 0) || (rowDelta < width)) + { + WLog_ERR(TAG, "Invalid arguments: rowDelta=%" PRIu32 " == 0 || < width=%" PRIu32, rowDelta, + width); return FALSE; + } if (!pbSrcBuffer || !pbDestBuffer) + { + WLog_ERR(TAG, "Invalid arguments: pbSrcBuffer=%p, pbDestBuffer=%p", pbSrcBuffer, + pbDestBuffer); return FALSE; + } pbEnd = pbSrcBuffer + cbSrcBuffer; pbDestEnd = pbDestBuffer + rowDelta * height; @@ -130,10 +145,17 @@ static INLINE BOOL RLEDECOMPRESS(const BYTE* pbSrcBuffer, UINT32 cbSrcBuffer, BY */ code = ExtractCodeId(*pbSrc); +#if defined(WITH_DEBUG_CODECS) + WLog_VRB(TAG, "pbSrc=%p code=%s, rem=%" PRIuz, pbSrc, + rle_code_str_buffer(code, sbuffer, sizeof(sbuffer)), pbEnd - pbSrc); +#endif + /* Handle Background Run Orders. */ - if (code == REGULAR_BG_RUN || code == MEGA_MEGA_BG_RUN) + if ((code == REGULAR_BG_RUN) || (code == MEGA_MEGA_BG_RUN)) { - runLength = ExtractRunLength(code, pbSrc, &advance); + runLength = ExtractRunLength(code, pbSrc, pbEnd, &advance); + if (advance == 0) + return FALSE; pbSrc = pbSrc + advance; if (fFirstLine) @@ -144,17 +166,13 @@ static INLINE BOOL RLEDECOMPRESS(const BYTE* pbSrcBuffer, UINT32 cbSrcBuffer, BY return FALSE; DESTWRITEPIXEL(pbDest, fgPel); - DESTNEXTPIXEL(pbDest); runLength = runLength - 1; } if (!ENSURE_CAPACITY(pbDest, pbDestEnd, runLength)) return FALSE; - UNROLL(runLength, { - DESTWRITEPIXEL(pbDest, BLACK_PIXEL); - DESTNEXTPIXEL(pbDest); - }); + UNROLL(runLength, { DESTWRITEPIXEL(pbDest, BLACK_PIXEL); }); } else { @@ -166,7 +184,6 @@ static INLINE BOOL RLEDECOMPRESS(const BYTE* pbSrcBuffer, UINT32 cbSrcBuffer, BY return FALSE; DESTWRITEPIXEL(pbDest, temp ^ fgPel); - DESTNEXTPIXEL(pbDest); runLength--; } @@ -176,7 +193,6 @@ static INLINE BOOL RLEDECOMPRESS(const BYTE* pbSrcBuffer, UINT32 cbSrcBuffer, BY UNROLL(runLength, { DESTREADPIXEL(temp, pbDest - rowDelta); DESTWRITEPIXEL(pbDest, temp); - DESTNEXTPIXEL(pbDest); }); } @@ -196,15 +212,16 @@ static INLINE BOOL RLEDECOMPRESS(const BYTE* pbSrcBuffer, UINT32 cbSrcBuffer, BY case MEGA_MEGA_FG_RUN: case LITE_SET_FG_FG_RUN: case MEGA_MEGA_SET_FG_RUN: - runLength = ExtractRunLength(code, pbSrc, &advance); + runLength = ExtractRunLength(code, pbSrc, pbEnd, &advance); + if (advance == 0) + return FALSE; pbSrc = pbSrc + advance; if (code == LITE_SET_FG_FG_RUN || code == MEGA_MEGA_SET_FG_RUN) { - if (pbSrc >= pbEnd) + if (!buffer_within_range(pbSrc, PIXEL_SIZE, pbEnd)) return FALSE; SRCREADPIXEL(fgPel, pbSrc); - SRCNEXTPIXEL(pbSrc); } if (!ENSURE_CAPACITY(pbDest, pbDestEnd, runLength)) @@ -212,17 +229,13 @@ static INLINE BOOL RLEDECOMPRESS(const BYTE* pbSrcBuffer, UINT32 cbSrcBuffer, BY if (fFirstLine) { - UNROLL(runLength, { - DESTWRITEPIXEL(pbDest, fgPel); - DESTNEXTPIXEL(pbDest); - }); + UNROLL(runLength, { DESTWRITEPIXEL(pbDest, fgPel); }); } else { UNROLL(runLength, { DESTREADPIXEL(temp, pbDest - rowDelta); DESTWRITEPIXEL(pbDest, temp ^ fgPel); - DESTNEXTPIXEL(pbDest); }); } @@ -231,45 +244,41 @@ static INLINE BOOL RLEDECOMPRESS(const BYTE* pbSrcBuffer, UINT32 cbSrcBuffer, BY /* Handle Dithered Run Orders. */ case LITE_DITHERED_RUN: case MEGA_MEGA_DITHERED_RUN: - runLength = ExtractRunLength(code, pbSrc, &advance); + runLength = ExtractRunLength(code, pbSrc, pbEnd, &advance); + if (advance == 0) + return FALSE; pbSrc = pbSrc + advance; - if (pbSrc >= pbEnd) + if (!buffer_within_range(pbSrc, PIXEL_SIZE, pbEnd)) return FALSE; SRCREADPIXEL(pixelA, pbSrc); - SRCNEXTPIXEL(pbSrc); - if (pbSrc >= pbEnd) + if (!buffer_within_range(pbSrc, PIXEL_SIZE, pbEnd)) return FALSE; SRCREADPIXEL(pixelB, pbSrc); - SRCNEXTPIXEL(pbSrc); if (!ENSURE_CAPACITY(pbDest, pbDestEnd, runLength * 2)) return FALSE; UNROLL(runLength, { DESTWRITEPIXEL(pbDest, pixelA); - DESTNEXTPIXEL(pbDest); DESTWRITEPIXEL(pbDest, pixelB); - DESTNEXTPIXEL(pbDest); }); break; /* Handle Color Run Orders. */ case REGULAR_COLOR_RUN: case MEGA_MEGA_COLOR_RUN: - runLength = ExtractRunLength(code, pbSrc, &advance); + runLength = ExtractRunLength(code, pbSrc, pbEnd, &advance); + if (advance == 0) + return FALSE; pbSrc = pbSrc + advance; - if (pbSrc >= pbEnd) + if (!buffer_within_range(pbSrc, PIXEL_SIZE, pbEnd)) return FALSE; SRCREADPIXEL(pixelA, pbSrc); - SRCNEXTPIXEL(pbSrc); if (!ENSURE_CAPACITY(pbDest, pbDestEnd, runLength)) return FALSE; - UNROLL(runLength, { - DESTWRITEPIXEL(pbDest, pixelA); - DESTNEXTPIXEL(pbDest); - }); + UNROLL(runLength, { DESTWRITEPIXEL(pbDest, pixelA); }); break; /* Handle Foreground/Background Image Orders. */ @@ -277,17 +286,20 @@ static INLINE BOOL RLEDECOMPRESS(const BYTE* pbSrcBuffer, UINT32 cbSrcBuffer, BY case MEGA_MEGA_FGBG_IMAGE: case LITE_SET_FG_FGBG_IMAGE: case MEGA_MEGA_SET_FGBG_IMAGE: - runLength = ExtractRunLength(code, pbSrc, &advance); + runLength = ExtractRunLength(code, pbSrc, pbEnd, &advance); + if (advance == 0) + return FALSE; pbSrc = pbSrc + advance; - if (pbSrc >= pbEnd) - return FALSE; if (code == LITE_SET_FG_FGBG_IMAGE || code == MEGA_MEGA_SET_FGBG_IMAGE) { + if (!buffer_within_range(pbSrc, PIXEL_SIZE, pbEnd)) + return FALSE; SRCREADPIXEL(fgPel, pbSrc); - SRCNEXTPIXEL(pbSrc); } + if (!buffer_within_range(pbSrc, runLength / 8, pbEnd)) + return FALSE; if (fFirstLine) { while (runLength > 8) @@ -306,8 +318,8 @@ static INLINE BOOL RLEDECOMPRESS(const BYTE* pbSrcBuffer, UINT32 cbSrcBuffer, BY { while (runLength > 8) { - bitmask = *pbSrc; - pbSrc = pbSrc + 1; + bitmask = *pbSrc++; + pbDest = WRITEFGBGIMAGE(pbDest, pbDestEnd, rowDelta, bitmask, fgPel, 8); if (!pbDest) @@ -319,8 +331,9 @@ static INLINE BOOL RLEDECOMPRESS(const BYTE* pbSrcBuffer, UINT32 cbSrcBuffer, BY if (runLength > 0) { - bitmask = *pbSrc; - pbSrc = pbSrc + 1; + if (!buffer_within_range(pbSrc, 1, pbEnd)) + return FALSE; + bitmask = *pbSrc++; if (fFirstLine) { @@ -342,23 +355,25 @@ static INLINE BOOL RLEDECOMPRESS(const BYTE* pbSrcBuffer, UINT32 cbSrcBuffer, BY /* Handle Color Image Orders. */ case REGULAR_COLOR_IMAGE: case MEGA_MEGA_COLOR_IMAGE: - runLength = ExtractRunLength(code, pbSrc, &advance); + runLength = ExtractRunLength(code, pbSrc, pbEnd, &advance); + if (advance == 0) + return FALSE; pbSrc = pbSrc + advance; if (!ENSURE_CAPACITY(pbDest, pbDestEnd, runLength)) return FALSE; + if (!ENSURE_CAPACITY(pbSrc, pbEnd, runLength)) + return FALSE; UNROLL(runLength, { - if (pbSrc >= pbEnd) - return FALSE; SRCREADPIXEL(temp, pbSrc); - SRCNEXTPIXEL(pbSrc); DESTWRITEPIXEL(pbDest, temp); - DESTNEXTPIXEL(pbDest); }); break; /* Handle Special Order 1. */ case SPECIAL_FGBG_1: + if (!buffer_within_range(pbSrc, 1, pbEnd)) + return FALSE; pbSrc = pbSrc + 1; if (fFirstLine) @@ -379,6 +394,8 @@ static INLINE BOOL RLEDECOMPRESS(const BYTE* pbSrcBuffer, UINT32 cbSrcBuffer, BY /* Handle Special Order 2. */ case SPECIAL_FGBG_2: + if (!buffer_within_range(pbSrc, 1, pbEnd)) + return FALSE; pbSrc = pbSrc + 1; if (fFirstLine) @@ -399,27 +416,31 @@ static INLINE BOOL RLEDECOMPRESS(const BYTE* pbSrcBuffer, UINT32 cbSrcBuffer, BY /* Handle White Order. */ case SPECIAL_WHITE: + if (!buffer_within_range(pbSrc, 1, pbEnd)) + return FALSE; pbSrc = pbSrc + 1; if (!ENSURE_CAPACITY(pbDest, pbDestEnd, 1)) return FALSE; DESTWRITEPIXEL(pbDest, WHITE_PIXEL); - DESTNEXTPIXEL(pbDest); break; /* Handle Black Order. */ case SPECIAL_BLACK: + if (!buffer_within_range(pbSrc, 1, pbEnd)) + return FALSE; pbSrc = pbSrc + 1; if (!ENSURE_CAPACITY(pbDest, pbDestEnd, 1)) return FALSE; DESTWRITEPIXEL(pbDest, BLACK_PIXEL); - DESTNEXTPIXEL(pbDest); break; default: + WLog_ERR(TAG, "invalid code 0x%08" PRIx32 ", pbSrcBuffer=%p, pbSrc=%p, pbEnd=%p", + code, pbSrcBuffer, pbSrc, pbEnd); return FALSE; } } diff --git a/libfreerdp/codec/interleaved.c b/libfreerdp/codec/interleaved.c index b76fe1ca3c1b..abfdc51f9988 100644 --- a/libfreerdp/codec/interleaved.c +++ b/libfreerdp/codec/interleaved.c @@ -21,6 +21,7 @@ * limitations under the License. */ +#include #ifdef HAVE_CONFIG_H #include "config.h" #endif @@ -30,15 +31,16 @@ #define TAG FREERDP_TAG("codec") -#define UNROLL_BODY(_exp, _count) \ - do \ - { \ - size_t x; \ - for (x = 0; x < (_count); x++) \ - { \ - do \ - _exp while (FALSE); \ - } \ +#define UNROLL_BODY(_exp, _count) \ + do \ + { \ + for (size_t x = 0; x < (_count); x++) \ + { \ + do \ + { \ + _exp \ + } while (FALSE); \ + } \ } while (FALSE) #define UNROLL_MULTIPLE(_condition, _exp, _count) \ @@ -97,6 +99,80 @@ static const BYTE g_MaskSpecialFgBg2 = 0x05; static const BYTE g_MaskRegularRunLength = 0x1F; static const BYTE g_MaskLiteRunLength = 0x0F; +static const char* rle_code_str(UINT32 code) +{ + switch (code) + { + case REGULAR_BG_RUN: + return "REGULAR_BG_RUN"; + case MEGA_MEGA_BG_RUN: + return "MEGA_MEGA_BG_RUN"; + case REGULAR_FG_RUN: + return "REGULAR_FG_RUN"; + case MEGA_MEGA_FG_RUN: + return "MEGA_MEGA_FG_RUN"; + case LITE_SET_FG_FG_RUN: + return "LITE_SET_FG_FG_RUN"; + case MEGA_MEGA_SET_FG_RUN: + return "MEGA_MEGA_SET_FG_RUN"; + case LITE_DITHERED_RUN: + return "LITE_DITHERED_RUN"; + case MEGA_MEGA_DITHERED_RUN: + return "MEGA_MEGA_DITHERED_RUN"; + case REGULAR_COLOR_RUN: + return "REGULAR_COLOR_RUN"; + case MEGA_MEGA_COLOR_RUN: + return "MEGA_MEGA_COLOR_RUN"; + case REGULAR_FGBG_IMAGE: + return "REGULAR_FGBG_IMAGE"; + case MEGA_MEGA_FGBG_IMAGE: + return "MEGA_MEGA_FGBG_IMAGE"; + case LITE_SET_FG_FGBG_IMAGE: + return "LITE_SET_FG_FGBG_IMAGE"; + case MEGA_MEGA_SET_FGBG_IMAGE: + return "MEGA_MEGA_SET_FGBG_IMAGE"; + case REGULAR_COLOR_IMAGE: + return "REGULAR_COLOR_IMAGE"; + case MEGA_MEGA_COLOR_IMAGE: + return "MEGA_MEGA_COLOR_IMAGE"; + case SPECIAL_FGBG_1: + return "SPECIAL_FGBG_1"; + case SPECIAL_FGBG_2: + return "SPECIAL_FGBG_2"; + case SPECIAL_WHITE: + return "SPECIAL_WHITE"; + case SPECIAL_BLACK: + return "SPECIAL_BLACK"; + default: + return "UNKNOWN"; + } +} + +static const char* rle_code_str_buffer(UINT32 code, char* buffer, size_t size) +{ + const char* str = rle_code_str(code); + _snprintf(buffer, size, "%s [0x%08" PRIx32 "]", str, code); + return buffer; +} + +#define buffer_within_range(pbSrc, size, pbEnd) \ + buffer_within_range_((pbSrc), (size), (pbEnd), __func__, __FILE__, __LINE__) +static INLINE BOOL buffer_within_range_(const void* pbSrc, size_t size, const void* pbEnd, + const char* fkt, const char* file, size_t line) +{ + WINPR_UNUSED(file); + WINPR_ASSERT(pbSrc); + WINPR_ASSERT(pbEnd); + + if ((const char*)pbSrc + size > (const char*)pbEnd) + { + WLog_ERR(TAG, "[%s:%" PRIuz "] pbSrc=%p + %" PRIuz " > pbEnd=%p", fkt, line, pbSrc, size, + pbEnd); + return FALSE; + } + return TRUE; +} + /** * Reads the supplied order header and extracts the compression * order code ID. @@ -127,71 +203,155 @@ static INLINE UINT32 ExtractCodeId(BYTE bOrderHdr) /** * Extract the run length of a compression order. */ -static INLINE UINT32 ExtractRunLength(UINT32 code, const BYTE* pbOrderHdr, UINT32* advance) +static UINT ExtractRunLengthRegularFgBg(const BYTE* pbOrderHdr, const BYTE* pbEnd, UINT32* advance) { - UINT32 runLength; - UINT32 ladvance; - ladvance = 1; - runLength = 0; + UINT runLength = 0; - switch (code) + WINPR_ASSERT(pbOrderHdr); + WINPR_ASSERT(pbEnd); + WINPR_ASSERT(advance); + + runLength = (*pbOrderHdr) & g_MaskRegularRunLength; + if (runLength == 0) { - case REGULAR_FGBG_IMAGE: - runLength = (*pbOrderHdr) & g_MaskRegularRunLength; + if (!buffer_within_range(pbOrderHdr, 1, pbEnd)) + { + *advance = 0; + return 0; + } + runLength = *(pbOrderHdr + 1) + 1; + (*advance)++; + } + else + runLength = runLength * 8; - if (runLength == 0) - { - runLength = (*(pbOrderHdr + 1)) + 1; - ladvance += 1; - } - else - { - runLength = runLength * 8; - } + return runLength; +} - break; +static UINT ExtractRunLengthLiteFgBg(const BYTE* pbOrderHdr, const BYTE* pbEnd, UINT32* advance) +{ + UINT runLength = 0; - case LITE_SET_FG_FGBG_IMAGE: - runLength = (*pbOrderHdr) & g_MaskLiteRunLength; + WINPR_ASSERT(pbOrderHdr); + WINPR_ASSERT(pbEnd); + WINPR_ASSERT(advance); - if (runLength == 0) - { - runLength = (*(pbOrderHdr + 1)) + 1; - ladvance += 1; - } - else - { - runLength = runLength * 8; - } + runLength = *pbOrderHdr & g_MaskLiteRunLength; + if (runLength == 0) + { + if (!buffer_within_range(pbOrderHdr, 2, pbEnd)) + { + *advance = 0; + return 0; + } + runLength = *(pbOrderHdr + 1) + 1; + (*advance)++; + } + else + runLength = runLength * 8; + + return runLength; +} + +static UINT ExtractRunLengthRegular(const BYTE* pbOrderHdr, const BYTE* pbEnd, UINT32* advance) +{ + UINT runLength = 0; + + WINPR_ASSERT(pbOrderHdr); + WINPR_ASSERT(pbEnd); + WINPR_ASSERT(advance); + + runLength = *pbOrderHdr & g_MaskRegularRunLength; + if (runLength == 0) + { + if (!buffer_within_range(pbOrderHdr, 1, pbEnd)) + { + *advance = 0; + return 0; + } + runLength = *(pbOrderHdr + 1) + 32; + (*advance)++; + } + + return runLength; +} + +static UINT ExtractRunLengthMegaMega(const BYTE* pbOrderHdr, const BYTE* pbEnd, UINT32* advance) +{ + UINT runLength = 0; + + WINPR_ASSERT(pbOrderHdr); + WINPR_ASSERT(pbEnd); + WINPR_ASSERT(advance); + + if (!buffer_within_range(pbOrderHdr, 2, pbEnd)) + { + *advance = 0; + return 0; + } + + runLength = ((UINT16)pbOrderHdr[1]) | (((UINT16)pbOrderHdr[2]) << 8); + (*advance) += 2; + + return runLength; +} + +static UINT ExtractRunLengthLite(const BYTE* pbOrderHdr, const BYTE* pbEnd, UINT32* advance) +{ + UINT runLength = 0; + + WINPR_ASSERT(pbOrderHdr); + WINPR_ASSERT(pbEnd); + WINPR_ASSERT(advance); + + runLength = *pbOrderHdr & g_MaskLiteRunLength; + if (runLength == 0) + { + if (!buffer_within_range(pbOrderHdr, 1, pbEnd)) + { + *advance = 0; + return 0; + } + runLength = *(pbOrderHdr + 1) + 16; + (*advance)++; + } + return runLength; +} + +static INLINE UINT32 ExtractRunLength(UINT32 code, const BYTE* pbOrderHdr, const BYTE* pbEnd, + UINT32* advance) +{ + UINT32 runLength = 0; + UINT32 ladvance = 1; + + WINPR_ASSERT(pbOrderHdr); + WINPR_ASSERT(pbEnd); + WINPR_ASSERT(advance); + + *advance = 0; + if (!buffer_within_range(pbOrderHdr, 0, pbEnd)) + return 0; + + switch (code) + { + case REGULAR_FGBG_IMAGE: + runLength = ExtractRunLengthRegularFgBg(pbOrderHdr, pbEnd, &ladvance); + break; + case LITE_SET_FG_FGBG_IMAGE: + runLength = ExtractRunLengthLiteFgBg(pbOrderHdr, pbEnd, &ladvance); break; case REGULAR_BG_RUN: case REGULAR_FG_RUN: case REGULAR_COLOR_RUN: case REGULAR_COLOR_IMAGE: - runLength = (*pbOrderHdr) & g_MaskRegularRunLength; - - if (runLength == 0) - { - /* An extended (MEGA) run. */ - runLength = (*(pbOrderHdr + 1)) + 32; - ladvance += 1; - } - + runLength = ExtractRunLengthRegular(pbOrderHdr, pbEnd, &ladvance); break; case LITE_SET_FG_FG_RUN: case LITE_DITHERED_RUN: - runLength = (*pbOrderHdr) & g_MaskLiteRunLength; - - if (runLength == 0) - { - /* An extended (MEGA) run. */ - runLength = (*(pbOrderHdr + 1)) + 16; - ladvance += 1; - } - + runLength = ExtractRunLengthLite(pbOrderHdr, pbEnd, &ladvance); break; case MEGA_MEGA_BG_RUN: @@ -202,8 +362,12 @@ static INLINE UINT32 ExtractRunLength(UINT32 code, const BYTE* pbOrderHdr, UINT3 case MEGA_MEGA_FGBG_IMAGE: case MEGA_MEGA_SET_FGBG_IMAGE: case MEGA_MEGA_COLOR_IMAGE: - runLength = ((UINT16)pbOrderHdr[1]) | ((UINT16)(pbOrderHdr[2] << 8)); - ladvance += 2; + runLength = ExtractRunLengthMegaMega(pbOrderHdr, pbEnd, &ladvance); + break; + + default: + runLength = 0; + ladvance = 0; break; } @@ -211,20 +375,32 @@ static INLINE UINT32 ExtractRunLength(UINT32 code, const BYTE* pbOrderHdr, UINT3 return runLength; } -static INLINE BOOL ensure_capacity(const BYTE* start, const BYTE* end, size_t size, size_t base) +#define ensure_capacity(start, end, size, base) \ + ensure_capacity_((start), (end), (size), (base), __func__, __FILE__, __LINE__) +static INLINE BOOL ensure_capacity_(const BYTE* start, const BYTE* end, size_t size, size_t base, + const char* fkt, const char* file, size_t line) { const size_t available = (uintptr_t)end - (uintptr_t)start; const BOOL rc = available >= size * base; - return rc && (start <= end); + const BOOL res = rc && (start <= end); + + if (!res) + WLog_ERR(TAG, + "[%s:%" PRIuz "] failed: start=%p <= end=%p, available=%" PRIuz " >= size=%" PRIuz + " * base=%" PRIuz, + fkt, line, start, end, available, size, base); + return res; } static INLINE void write_pixel_8(BYTE* _buf, BYTE _pix) { + WINPR_ASSERT(_buf); *_buf = _pix; } static INLINE void write_pixel_24(BYTE* _buf, UINT32 _pix) { + WINPR_ASSERT(_buf); (_buf)[0] = (BYTE)(_pix); (_buf)[1] = (BYTE)((_pix) >> 8); (_buf)[2] = (BYTE)((_pix) >> 16); @@ -232,6 +408,7 @@ static INLINE void write_pixel_24(BYTE* _buf, UINT32 _pix) static INLINE void write_pixel_16(BYTE* _buf, UINT16 _pix) { + WINPR_ASSERT(_buf); _buf[0] = _pix & 0xFF; _buf[1] = (_pix >> 8) & 0xFF; } @@ -239,19 +416,30 @@ static INLINE void write_pixel_16(BYTE* _buf, UINT16 _pix) #undef DESTWRITEPIXEL #undef DESTREADPIXEL #undef SRCREADPIXEL -#undef DESTNEXTPIXEL -#undef SRCNEXTPIXEL #undef WRITEFGBGIMAGE #undef WRITEFIRSTLINEFGBGIMAGE #undef RLEDECOMPRESS #undef RLEEXTRA #undef WHITE_PIXEL +#undef PIXEL_SIZE +#undef PIXEL +#define PIXEL_SIZE 1 +#define PIXEL BYTE #define WHITE_PIXEL 0xFF -#define DESTWRITEPIXEL(_buf, _pix) write_pixel_8(_buf, _pix) +#define DESTWRITEPIXEL(_buf, _pix) \ + do \ + { \ + write_pixel_8(_buf, _pix); \ + _buf += 1; \ + } while (0) #define DESTREADPIXEL(_pix, _buf) _pix = (_buf)[0] -#define SRCREADPIXEL(_pix, _buf) _pix = (_buf)[0] -#define DESTNEXTPIXEL(_buf) _buf += 1 -#define SRCNEXTPIXEL(_buf) _buf += 1 +#define SRCREADPIXEL(_pix, _buf) \ + do \ + { \ + _pix = (_buf)[0]; \ + _buf += 1; \ + } while (0) + #define WRITEFGBGIMAGE WriteFgBgImage8to8 #define WRITEFIRSTLINEFGBGIMAGE WriteFirstLineFgBgImage8to8 #define RLEDECOMPRESS RleDecompress8to8 @@ -263,19 +451,29 @@ static INLINE void write_pixel_16(BYTE* _buf, UINT16 _pix) #undef DESTWRITEPIXEL #undef DESTREADPIXEL #undef SRCREADPIXEL -#undef DESTNEXTPIXEL -#undef SRCNEXTPIXEL #undef WRITEFGBGIMAGE #undef WRITEFIRSTLINEFGBGIMAGE #undef RLEDECOMPRESS #undef RLEEXTRA #undef WHITE_PIXEL +#undef PIXEL_SIZE +#undef PIXEL +#define PIXEL_SIZE 2 +#define PIXEL UINT16 #define WHITE_PIXEL 0xFFFF -#define DESTWRITEPIXEL(_buf, _pix) write_pixel_16(_buf, _pix) +#define DESTWRITEPIXEL(_buf, _pix) \ + do \ + { \ + write_pixel_16(_buf, _pix); \ + _buf += 2; \ + } while (0) #define DESTREADPIXEL(_pix, _buf) _pix = ((UINT16*)(_buf))[0] -#define SRCREADPIXEL(_pix, _buf) _pix = (_buf)[0] | ((_buf)[1] << 8) -#define DESTNEXTPIXEL(_buf) _buf += 2 -#define SRCNEXTPIXEL(_buf) _buf += 2 +#define SRCREADPIXEL(_pix, _buf) \ + do \ + { \ + _pix = (_buf)[0] | ((_buf)[1] << 8); \ + _buf += 2; \ + } while (0) #define WRITEFGBGIMAGE WriteFgBgImage16to16 #define WRITEFIRSTLINEFGBGIMAGE WriteFirstLineFgBgImage16to16 #define RLEDECOMPRESS RleDecompress16to16 @@ -287,19 +485,30 @@ static INLINE void write_pixel_16(BYTE* _buf, UINT16 _pix) #undef DESTWRITEPIXEL #undef DESTREADPIXEL #undef SRCREADPIXEL -#undef DESTNEXTPIXEL -#undef SRCNEXTPIXEL #undef WRITEFGBGIMAGE #undef WRITEFIRSTLINEFGBGIMAGE #undef RLEDECOMPRESS #undef RLEEXTRA #undef WHITE_PIXEL -#define WHITE_PIXEL 0xFFFFFF -#define DESTWRITEPIXEL(_buf, _pix) write_pixel_24(_buf, _pix) +#undef PIXEL_SIZE +#undef PIXEL +#define PIXEL_SIZE 3 +#define PIXEL UINT32 +#define WHITE_PIXEL 0xffffff +#define DESTWRITEPIXEL(_buf, _pix) \ + do \ + { \ + write_pixel_24(_buf, _pix); \ + _buf += 3; \ + } while (0) #define DESTREADPIXEL(_pix, _buf) _pix = (_buf)[0] | ((_buf)[1] << 8) | ((_buf)[2] << 16) -#define SRCREADPIXEL(_pix, _buf) _pix = (_buf)[0] | ((_buf)[1] << 8) | ((_buf)[2] << 16) -#define DESTNEXTPIXEL(_buf) _buf += 3 -#define SRCNEXTPIXEL(_buf) _buf += 3 +#define SRCREADPIXEL(_pix, _buf) \ + do \ + { \ + _pix = (_buf)[0] | ((_buf)[1] << 8) | ((_buf)[2] << 16); \ + _buf += 3; \ + } while (0) + #define WRITEFGBGIMAGE WriteFgBgImage24to24 #define WRITEFIRSTLINEFGBGIMAGE WriteFirstLineFgBgImage24to24 #define RLEDECOMPRESS RleDecompress24to24 @@ -308,18 +517,32 @@ static INLINE void write_pixel_16(BYTE* _buf, UINT16 _pix) #define ENSURE_CAPACITY(_start, _end, _size) ensure_capacity(_start, _end, _size, 3) #include "include/bitmap.c" +struct S_BITMAP_INTERLEAVED_CONTEXT +{ + BOOL Compressor; + + UINT32 TempSize; + BYTE* TempBuffer; + + wStream* bts; +}; + BOOL interleaved_decompress(BITMAP_INTERLEAVED_CONTEXT* interleaved, const BYTE* pSrcData, UINT32 SrcSize, UINT32 nSrcWidth, UINT32 nSrcHeight, UINT32 bpp, BYTE* pDstData, UINT32 DstFormat, UINT32 nDstStep, UINT32 nXDst, UINT32 nYDst, UINT32 nDstWidth, UINT32 nDstHeight, const gdiPalette* palette) { - UINT32 scanline; - UINT32 SrcFormat; - UINT32 BufferSize; + UINT32 scanline = 0; + UINT32 SrcFormat = 0; + UINT32 BufferSize = 0; if (!interleaved || !pSrcData || !pDstData) + { + WLog_ERR(TAG, "invalid arguments: interleaved=%p, pSrcData=%p, pDstData=%p", interleaved, + pSrcData, pDstData); return FALSE; + } switch (bpp) { @@ -352,19 +575,26 @@ BOOL interleaved_decompress(BITMAP_INTERLEAVED_CONTEXT* interleaved, const BYTE* if (BufferSize > interleaved->TempSize) { - interleaved->TempBuffer = _aligned_realloc(interleaved->TempBuffer, BufferSize, 16); + interleaved->TempBuffer = + _aligned_recalloc(interleaved->TempBuffer, BufferSize, sizeof(BYTE), 16); interleaved->TempSize = BufferSize; } if (!interleaved->TempBuffer) + { + WLog_ERR(TAG, "interleaved->TempBuffer=%p", interleaved->TempBuffer); return FALSE; + } switch (bpp) { case 24: if (!RleDecompress24to24(pSrcData, SrcSize, interleaved->TempBuffer, scanline, nSrcWidth, nSrcHeight)) + { + WLog_ERR(TAG, "RleDecompress24to24 failed"); return FALSE; + } break; @@ -372,24 +602,36 @@ BOOL interleaved_decompress(BITMAP_INTERLEAVED_CONTEXT* interleaved, const BYTE* case 15: if (!RleDecompress16to16(pSrcData, SrcSize, interleaved->TempBuffer, scanline, nSrcWidth, nSrcHeight)) + { + WLog_ERR(TAG, "RleDecompress16to16 failed"); return FALSE; + } break; case 8: if (!RleDecompress8to8(pSrcData, SrcSize, interleaved->TempBuffer, scanline, nSrcWidth, nSrcHeight)) + { + WLog_ERR(TAG, "RleDecompress8to8 failed"); return FALSE; + } break; default: + WLog_ERR(TAG, "Invalid color depth %" PRIu32 "", bpp); return FALSE; } - return freerdp_image_copy(pDstData, DstFormat, nDstStep, nXDst, nYDst, nDstWidth, nDstHeight, - interleaved->TempBuffer, SrcFormat, scanline, 0, 0, palette, - FREERDP_FLIP_VERTICAL); + if (!freerdp_image_copy(pDstData, DstFormat, nDstStep, nXDst, nYDst, nDstWidth, nDstHeight, + interleaved->TempBuffer, SrcFormat, scanline, 0, 0, palette, + FREERDP_FLIP_VERTICAL)) + { + WLog_ERR(TAG, "freerdp_image_copy failed"); + return FALSE; + } + return TRUE; } BOOL interleaved_compress(BITMAP_INTERLEAVED_CONTEXT* interleaved, BYTE* pDstData, UINT32* pDstSize, @@ -397,10 +639,10 @@ BOOL interleaved_compress(BITMAP_INTERLEAVED_CONTEXT* interleaved, BYTE* pDstDat UINT32 nSrcStep, UINT32 nXSrc, UINT32 nYSrc, const gdiPalette* palette, UINT32 bpp) { - BOOL status; - wStream* s; + BOOL status = 0; + wStream* s = NULL; UINT32 DstFormat = 0; - const size_t maxSize = 64 * 64 * 4; + const UINT32 maxSize = 64 * 64 * 4; if (!interleaved || !pDstData || !pSrcData) return FALSE; @@ -442,7 +684,7 @@ BOOL interleaved_compress(BITMAP_INTERLEAVED_CONTEXT* interleaved, BYTE* pDstDat } if (!freerdp_image_copy(interleaved->TempBuffer, DstFormat, 0, 0, 0, nWidth, nHeight, pSrcData, - SrcFormat, nSrcStep, nXSrc, nYSrc, palette, FREERDP_FLIP_NONE)) + SrcFormat, nSrcStep, nXSrc, nYSrc, palette, 0)) return FALSE; s = Stream_New(pDstData, *pDstSize); @@ -474,33 +716,29 @@ BOOL bitmap_interleaved_context_reset(BITMAP_INTERLEAVED_CONTEXT* interleaved) BITMAP_INTERLEAVED_CONTEXT* bitmap_interleaved_context_new(BOOL Compressor) { - BITMAP_INTERLEAVED_CONTEXT* interleaved; - interleaved = (BITMAP_INTERLEAVED_CONTEXT*)calloc(1, sizeof(BITMAP_INTERLEAVED_CONTEXT)); + BITMAP_INTERLEAVED_CONTEXT* interleaved = NULL; + interleaved = (BITMAP_INTERLEAVED_CONTEXT*)_aligned_recalloc( + NULL, 1, sizeof(BITMAP_INTERLEAVED_CONTEXT), 32); if (interleaved) { interleaved->TempSize = 64 * 64 * 4; - interleaved->TempBuffer = _aligned_malloc(interleaved->TempSize, 16); + interleaved->TempBuffer = _aligned_malloc(interleaved->TempSize * sizeof(BYTE), 16); if (!interleaved->TempBuffer) - { - free(interleaved); - WLog_ERR(TAG, "_aligned_malloc failed!"); - return NULL; - } + goto fail; interleaved->bts = Stream_New(NULL, interleaved->TempSize); if (!interleaved->bts) - { - _aligned_free(interleaved->TempBuffer); - free(interleaved); - WLog_ERR(TAG, "Stream_New failed!"); - return NULL; - } + goto fail; } return interleaved; + +fail: + bitmap_interleaved_context_free(interleaved); + return NULL; } void bitmap_interleaved_context_free(BITMAP_INTERLEAVED_CONTEXT* interleaved) @@ -510,5 +748,5 @@ void bitmap_interleaved_context_free(BITMAP_INTERLEAVED_CONTEXT* interleaved) _aligned_free(interleaved->TempBuffer); Stream_Free(interleaved->bts, TRUE); - free(interleaved); + _aligned_free(interleaved); } From 3a5cf5af9cf2aea4f34a3dc85334a66c7d275f3d Mon Sep 17 00:00:00 2001 From: akallabeth Date: Wed, 24 Jan 2024 15:08:33 +0100 Subject: [PATCH 439/496] [clang] unify tool detection (cherry picked from commit fc47a019dfe71beee7ee33c7d6618cc8bbe502d1) --- ci/cmake-preloads/config-qa-static.cmake | 11 ++++++ ci/cmake-preloads/config-qa.cmake | 20 +++++++--- cmake/ClangDetectTool.cmake | 48 ++++++++++++++++++++++++ cmake/ClangFormat.cmake | 35 +---------------- 4 files changed, 75 insertions(+), 39 deletions(-) create mode 100644 cmake/ClangDetectTool.cmake diff --git a/ci/cmake-preloads/config-qa-static.cmake b/ci/cmake-preloads/config-qa-static.cmake index f8d831475b61..c08c1b51de35 100644 --- a/ci/cmake-preloads/config-qa-static.cmake +++ b/ci/cmake-preloads/config-qa-static.cmake @@ -1,4 +1,15 @@ +message("PRELOADING cache") +set (CMAKE_VERBOSE_MAKEFILE ON CACHE BOOL "preload") set (WITH_SERVER ON CACHE BOOL "qa default") set (WITH_SAMPLE ON CACHE BOOL "qa default") set (WITH_VERBOSE_WINPR_ASSERT OFF CACHE BOOL "qa default") set (BUILD_SHARED_LIBS OFF CACHE BOOL "qa default") + +set (BUILD_WITH_CLANG_TIDY OFF CACHE BOOL "qa default") + +include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/ClangDetectTool.cmake) +clang_detect_tool(CLANG_EXE clang REQUIRED) +clang_detect_tool(CLANG_XX_EXE clang++ REQUIRED) + +set (CMAKE_C_COMPILER "${CLANG_EXE}" CACHE STRING "qa default") +set (CMAKE_CXX_COMPILER "${CLANG_XX_EXE}" CACHE STRING "qa default") diff --git a/ci/cmake-preloads/config-qa.cmake b/ci/cmake-preloads/config-qa.cmake index 02c137239a59..4b3953bec5b0 100644 --- a/ci/cmake-preloads/config-qa.cmake +++ b/ci/cmake-preloads/config-qa.cmake @@ -1,4 +1,5 @@ set (BUILD_TESTING ON CACHE BOOL "qa default") +set (CMAKE_VERBOSE_MAKEFILE ON CACHE BOOL "preload") set (WITH_SAMPLE ON CACHE BOOL "qa default") set (WITH_SERVER ON CACHE BOOL "qa default") set (WITH_SHADOW ON CACHE BOOL "qa default") @@ -8,10 +9,17 @@ set (WITH_CUPS ON CACHE BOOL "qa default") set (WITH_PCSC ON CACHE BOOL "qa default") set (WITH_SOXR ON CACHE BOOL "qa default") set (WITH_SWSCALE ON CACHE BOOL "qa default") -set (WITH_DSP_FFMPEG OFF CACHE BOOL "qa default") -set (WITH_FFMPEG OFF CACHE BOOL "qa default") +set (WITH_DSP_FFMPEG ON CACHE BOOL "qa default") +set (WITH_FFMPEG ON CACHE BOOL "qa default") set (WITH_SANITIZE_ADDRESS ON CACHE BOOL "qa default") -set (CMAKE_C_FLAGS "-Weverything" CACHE STRING "qa default") -set (CMAKE_CXX_FLAGS "-Weverything" CACHE STRING "qa default") -set (CMAKE_C_COMPILER "/usr/bin/clang-10" CACHE STRING "qa default") -set (CMAKE_CXX_COMPILER "/usr/bin/clang++-10" CACHE STRING "qa default") +set (CMAKE_C_FLAGS "-Weverything -Wno-exit-time-destructors -Wno-cast-align -Wno-documentation -Wno-documentation-unknown-command -Wno-padded -Wno-covered-switch-default -Wno-declaration-after-statement" CACHE STRING "qa default") +set (CMAKE_CXX_FLAGS "-Weverything -Wno-exit-time-destructors -Wno-cast-align -Wno-documentation -Wno-documentation-unknown-command -Wno-padded -Wno-c++98-compat -Wno-c++98-compat-pedantic -Wno-covered-switch-default -Wno-declaration-after-statement" CACHE STRING "qa default") + +set (BUILD_WITH_CLANG_TIDY ON CACHE BOOL "qa default") + +include(${CMAKE_CURRENT_SOURCE_DIR}/cmake/ClangDetectTool.cmake) +clang_detect_tool(CLANG_EXE clang REQUIRED) +clang_detect_tool(CLANG_XX_EXE clang++ REQUIRED) + +set (CMAKE_C_COMPILER "${CLANG_EXE}" CACHE STRING "qa default") +set (CMAKE_CXX_COMPILER "${CLANG_XX_EXE}" CACHE STRING "qa default") diff --git a/cmake/ClangDetectTool.cmake b/cmake/ClangDetectTool.cmake new file mode 100644 index 000000000000..a1ecd56d3f2a --- /dev/null +++ b/cmake/ClangDetectTool.cmake @@ -0,0 +1,48 @@ +function (clang_detect_tool VAR NAME OPTS) + set(NAMES "") + foreach(CNT RANGE 12 22) + list(APPEND NAMES "${NAME}-${CNT}") + endforeach() + list(REVERSE NAMES) + list(APPEND NAMES ${NAME}) + + find_program(${VAR} + NAMES ${NAMES} + ${OPTS} + ) + if (NOT ${VAR}) + message(WARNING "clang tool ${NAME} (${VAR}) not detected, skipping") + unset(${VAR}) + return() + endif() + + execute_process( + COMMAND ${${VAR}} "--version" + OUTPUT_VARIABLE _CLANG_TOOL_VERSION + RESULT_VARIABLE _CLANG_TOOL_VERSION_FAILED + ) + + if (_CLANG_TOOL_VERSION_FAILED) + message(WARNING "A problem was encounterd with ${${VAR}}") + message(WARNING "${_CLANG_TOOL_VERSION_FAILED}") + unset(${VAR}) + return() + endif() + + string(REGEX MATCH "([7-9]|[1-9][0-9])\\.[0-9]\\.[0-9]" CLANG_TOOL_VERSION + "${_CLANG_TOOL_VERSION}") + + if (NOT CLANG_TOOL_VERSION) + message(WARNING "problem parsing ${NAME} version for ${${VAR}}") + unset(${VAR}) + return() + endif() + + set(_CLANG_TOOL_MINIMUM_VERSION "12.0.0") + if (${CLANG_TOOL_VERSION} VERSION_LESS ${_CLANG_TOOL_MINIMUM_VERSION}) + message(WARNING "clang-format version ${CLANG_TOOL_VERSION} not supported") + message(WARNING "Minimum version required: ${_CLANG_TOOL_MINIMUM_VERSION}") + unset(${VAR}) + return() + endif() +endfunction() diff --git a/cmake/ClangFormat.cmake b/cmake/ClangFormat.cmake index 8985ef358e8c..b815822fafa0 100644 --- a/cmake/ClangFormat.cmake +++ b/cmake/ClangFormat.cmake @@ -1,43 +1,12 @@ # get all project files file(GLOB_RECURSE ALL_SOURCE_FILES *.cpp *.c *.h *.m *.java) -# minimum version required -set(_CLANG_FORMAT_MINIMUM_VERSION 7.0.0) -find_program(CLANG_FORMAT - NAMES - clang-format-8 - clang-format-7 - clang-format - ) +include(ClangDetectTool) +clang_detect_tool(CLANG_FORMAT clang-format "") if (NOT CLANG_FORMAT) message(WARNING "clang-format not found in path! code format target not available.") else() - execute_process( - COMMAND ${CLANG_FORMAT} "--version" - OUTPUT_VARIABLE _CLANG_FORMAT_VERSION - RESULT_VARIABLE _CLANG_FORMAT_VERSION_FAILED - ) - - if (_CLANG_FORMAT_VERSION_FAILED) - message(WARNING "A problem was encounterd with ${CLANG_FORMAT}") - return() - endif() - - string(REGEX MATCH "([7-9]|[1-9][0-9])\\.[0-9]\\.[0-9]" CLANG_FORMAT_VERSION - "${_CLANG_FORMAT_VERSION}") - - if (NOT CLANG_FORMAT_VERSION) - message(WARNING "problem parsing clang-fromat version for ${CLANG_FORMAT}") - return() - endif() - - if (${CLANG_FORMAT_VERSION} VERSION_LESS ${_CLANG_FORMAT_MINIMUM_VERSION}) - message(WARNING "clang-format version ${CLANG_FORMAT_VERSION} not supported") - message(WARNING "Minimum version required: ${_CLANG_FORMAT_MINIMUM_VERSION}") - return() - endif() - add_custom_target( clangformat COMMAND ${CLANG_FORMAT} From 35414fe1f46b91cf3d6405838b26ff6c8aa64778 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Wed, 17 Apr 2024 11:31:20 +0200 Subject: [PATCH 440/496] changelog --- ChangeLog | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/ChangeLog b/ChangeLog index 545d99b14209..94fdf10ae04e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,19 @@ +# 2024-04-17 Version 2.11.6 + +CVE: + CVE-2024-32041 [Low[ OutOfBound Read in zgfx_decompress_segment + CVE-2024-32039 [Moderate] Integer overflow & OutOfBound Write in clear_decompress_residual_data + CVE-2024-32040 [Low] integer underflow in nsc_rle_decode + CVE-2024-32458 [Low] OutOfBound Read in planar_skip_plane_rle + CVE-2024-32459 [Low] OutOfBound Read in ncrush_decompress + CVE-2024-32460 [Low] OutOfBound Read in interleaved_decompress + +Noteworthy changes: +* Backported #10077 + +For a complete and detailed change log since the last release run: +git log 2.11.6...2.11.5 + # 2024-01-19 Version 2.11.5 Noteworthy changes: From dee7e7e7c609c5192273cf8c20540c729ddcb3b0 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Wed, 17 Apr 2024 11:32:19 +0200 Subject: [PATCH 441/496] release-2.11.6 --- CMakeLists.txt | 2 +- client/Android/android_freerdp.c | 2 +- winpr/CMakeLists.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index da084c26a139..f29d4426d5a7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -85,7 +85,7 @@ if ($ENV{BUILD_NUMBER}) endif() set(WITH_LIBRARY_VERSIONING "ON") -set(RAW_VERSION_STRING "2.11.6-dev") +set(RAW_VERSION_STRING "2.11.6") if(EXISTS "${CMAKE_SOURCE_DIR}/.source_tag") file(READ ${CMAKE_SOURCE_DIR}/.source_tag RAW_VERSION_STRING) elseif(USE_VERSION_FROM_GIT_TAG) diff --git a/client/Android/android_freerdp.c b/client/Android/android_freerdp.c index 2c4aae2fcaae..830f2bb14a14 100644 --- a/client/Android/android_freerdp.c +++ b/client/Android/android_freerdp.c @@ -57,7 +57,7 @@ #define TAG CLIENT_TAG("android") /* Defines the JNI version supported by this library. */ -#define FREERDP_JNI_VERSION "2.11.6-dev" +#define FREERDP_JNI_VERSION "2.11.6" static void android_OnChannelConnectedEventHandler(void* context, ChannelConnectedEventArgs* e) { diff --git a/winpr/CMakeLists.txt b/winpr/CMakeLists.txt index a2c0f3117653..9b2e5420abf0 100644 --- a/winpr/CMakeLists.txt +++ b/winpr/CMakeLists.txt @@ -57,7 +57,7 @@ if (NOT WIN32) endif() # Soname versioning -set(RAW_VERSION_STRING "2.11.6-dev") +set(RAW_VERSION_STRING "2.11.6") if(EXISTS "${CMAKE_SOURCE_DIR}/.source_tag") file(READ ${CMAKE_SOURCE_DIR}/.source_tag RAW_VERSION_STRING) elseif(USE_VERSION_FROM_GIT_TAG) From 202474a6836b8cc566712e346ba9220ffce86e69 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Wed, 17 Apr 2024 11:32:51 +0200 Subject: [PATCH 442/496] start-2.11.7-dev-cycle --- CMakeLists.txt | 2 +- client/Android/android_freerdp.c | 2 +- winpr/CMakeLists.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f29d4426d5a7..bbc92360020f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -85,7 +85,7 @@ if ($ENV{BUILD_NUMBER}) endif() set(WITH_LIBRARY_VERSIONING "ON") -set(RAW_VERSION_STRING "2.11.6") +set(RAW_VERSION_STRING "2.11.7-dev") if(EXISTS "${CMAKE_SOURCE_DIR}/.source_tag") file(READ ${CMAKE_SOURCE_DIR}/.source_tag RAW_VERSION_STRING) elseif(USE_VERSION_FROM_GIT_TAG) diff --git a/client/Android/android_freerdp.c b/client/Android/android_freerdp.c index 830f2bb14a14..bee850d08963 100644 --- a/client/Android/android_freerdp.c +++ b/client/Android/android_freerdp.c @@ -57,7 +57,7 @@ #define TAG CLIENT_TAG("android") /* Defines the JNI version supported by this library. */ -#define FREERDP_JNI_VERSION "2.11.6" +#define FREERDP_JNI_VERSION "2.11.7-dev" static void android_OnChannelConnectedEventHandler(void* context, ChannelConnectedEventArgs* e) { diff --git a/winpr/CMakeLists.txt b/winpr/CMakeLists.txt index 9b2e5420abf0..fd13126356ac 100644 --- a/winpr/CMakeLists.txt +++ b/winpr/CMakeLists.txt @@ -57,7 +57,7 @@ if (NOT WIN32) endif() # Soname versioning -set(RAW_VERSION_STRING "2.11.6") +set(RAW_VERSION_STRING "2.11.7-dev") if(EXISTS "${CMAKE_SOURCE_DIR}/.source_tag") file(READ ${CMAKE_SOURCE_DIR}/.source_tag RAW_VERSION_STRING) elseif(USE_VERSION_FROM_GIT_TAG) From cb90fac0749f5d36fd2d899d8ac6ac159d23d85e Mon Sep 17 00:00:00 2001 From: akallabeth Date: Fri, 19 Apr 2024 10:29:24 +0200 Subject: [PATCH 443/496] [codec,interleaved] fix bounds checks (cherry picked from commit a1c373314ecee2f665be8dedac11438175c10853) --- libfreerdp/codec/interleaved.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libfreerdp/codec/interleaved.c b/libfreerdp/codec/interleaved.c index abfdc51f9988..d4d291699e12 100644 --- a/libfreerdp/codec/interleaved.c +++ b/libfreerdp/codec/interleaved.c @@ -264,7 +264,7 @@ static UINT ExtractRunLengthRegular(const BYTE* pbOrderHdr, const BYTE* pbEnd, U runLength = *pbOrderHdr & g_MaskRegularRunLength; if (runLength == 0) { - if (!buffer_within_range(pbOrderHdr, 1, pbEnd)) + if (!buffer_within_range(pbOrderHdr, 2, pbEnd)) { *advance = 0; return 0; @@ -307,7 +307,7 @@ static UINT ExtractRunLengthLite(const BYTE* pbOrderHdr, const BYTE* pbEnd, UINT runLength = *pbOrderHdr & g_MaskLiteRunLength; if (runLength == 0) { - if (!buffer_within_range(pbOrderHdr, 1, pbEnd)) + if (!buffer_within_range(pbOrderHdr, 2, pbEnd)) { *advance = 0; return 0; From f64acf9b76f5625db2a1b6dfdb7e7e96227e9cea Mon Sep 17 00:00:00 2001 From: akallabeth Date: Sat, 20 Apr 2024 15:05:36 +0200 Subject: [PATCH 444/496] [codec,nsc] check for valid ColorLossLevel (cherry picked from commit 0b4db5570762952f823dea8743de73ea97453a95) --- libfreerdp/codec/nsc.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/libfreerdp/codec/nsc.c b/libfreerdp/codec/nsc.c index d10fc6bca085..5dd2646ea9e3 100644 --- a/libfreerdp/codec/nsc.c +++ b/libfreerdp/codec/nsc.c @@ -95,8 +95,8 @@ static BOOL nsc_decode(NSC_CONTEXT* context) for (x = 0; x < context->width; x++) { INT16 y_val = (INT16)*yplane; - INT16 co_val = (INT16)(INT8)(*coplane << shift); - INT16 cg_val = (INT16)(INT8)(*cgplane << shift); + INT16 co_val = (INT16)(INT8)(((INT16)*coplane) << shift); + INT16 cg_val = (INT16)(INT8)(((INT16)*cgplane) << shift); INT16 r_val = y_val + co_val - cg_val; INT16 g_val = y_val + cg_val; INT16 b_val = y_val - co_val - cg_val; @@ -259,6 +259,13 @@ static BOOL nsc_stream_initialize(NSC_CONTEXT* context, wStream* s) } Stream_Read_UINT8(s, context->ColorLossLevel); /* ColorLossLevel (1 byte) */ + if ((context->ColorLossLevel < 1) || (context->ColorLossLevel > 7)) + { + WLog_Print(context->priv->log, WLOG_ERROR, + "ColorLossLevel=%" PRIu8 " out of range, must be [1,7] inclusive", + context->ColorLossLevel); + return FALSE; + } Stream_Read_UINT8(s, context->ChromaSubsamplingLevel); /* ChromaSubsamplingLevel (1 byte) */ Stream_Seek(s, 2); /* Reserved (2 bytes) */ context->Planes = Stream_Pointer(s); From 2b9f30a2fa4b13559a367f7cbe158e1bafe0f482 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Sat, 20 Apr 2024 17:59:49 +0200 Subject: [PATCH 445/496] [codec,interleaved] fix offset error (cherry picked from commit 1a755d898ddc028cc818d0dd9d49d5acff4c44bf) --- libfreerdp/codec/interleaved.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libfreerdp/codec/interleaved.c b/libfreerdp/codec/interleaved.c index d4d291699e12..e419876e6628 100644 --- a/libfreerdp/codec/interleaved.c +++ b/libfreerdp/codec/interleaved.c @@ -214,7 +214,7 @@ static UINT ExtractRunLengthRegularFgBg(const BYTE* pbOrderHdr, const BYTE* pbEn runLength = (*pbOrderHdr) & g_MaskRegularRunLength; if (runLength == 0) { - if (!buffer_within_range(pbOrderHdr, 1, pbEnd)) + if (!buffer_within_range(pbOrderHdr, 2, pbEnd)) { *advance = 0; return 0; @@ -284,7 +284,7 @@ static UINT ExtractRunLengthMegaMega(const BYTE* pbOrderHdr, const BYTE* pbEnd, WINPR_ASSERT(pbEnd); WINPR_ASSERT(advance); - if (!buffer_within_range(pbOrderHdr, 2, pbEnd)) + if (!buffer_within_range(pbOrderHdr, 3, pbEnd)) { *advance = 0; return 0; From a9ff85fc1edc9a3fd91f6cc728c076e4ce94d291 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Sat, 20 Apr 2024 17:16:35 +0200 Subject: [PATCH 446/496] [codec,clear] vBarShortEntry count check (cherry picked from commit 0ca4973a67eda1219e1457e9c721a75f64bd935c) --- libfreerdp/codec/clear.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/libfreerdp/codec/clear.c b/libfreerdp/codec/clear.c index b8899746ecaf..f3411073cef5 100644 --- a/libfreerdp/codec/clear.c +++ b/libfreerdp/codec/clear.c @@ -821,8 +821,15 @@ static BOOL clear_decompress_bands_data(CLEAR_CONTEXT* clear, wStream* s, UINT32 count = (vBarPixelCount > y) ? (vBarPixelCount - y) : 0; if (count > 0) - pSrcPixel = - &vBarShortEntry->pixels[(y - vBarYOn) * GetBytesPerPixel(clear->format)]; + { + const size_t offset = (y - vBarYOn) * GetBytesPerPixel(clear->format); + pSrcPixel = &vBarShortEntry->pixels[offset]; + if (offset + count > vBarShortEntry->count) + { + WLog_ERR(TAG, "offset + count > vBarShortEntry->count"); + return FALSE; + } + } for (x = 0; x < count; x++) { From 0381b3bef6e09b17576445186d26a07ec3772b1a Mon Sep 17 00:00:00 2001 From: akallabeth Date: Sat, 20 Apr 2024 19:59:48 +0200 Subject: [PATCH 447/496] [codec,zgfx] allocate in segment steps do not trust the uncompressedSize of a ZGFX_SEGMENTED_MULTIPART and allocate the output buffer in steps after decoding a segment. (cherry picked from commit 5e5d27cf310e4c10b854be7667bfb7a5d774eb47) --- libfreerdp/codec/zgfx.c | 77 +++++++++++++++++++++++++---------------- 1 file changed, 47 insertions(+), 30 deletions(-) diff --git a/libfreerdp/codec/zgfx.c b/libfreerdp/codec/zgfx.c index b7b96ade0c58..c63229480499 100644 --- a/libfreerdp/codec/zgfx.c +++ b/libfreerdp/codec/zgfx.c @@ -385,15 +385,45 @@ static BYTE* aligned_zgfx_malloc(size_t size) return malloc(size + 64); } +static BOOL zgfx_append(ZGFX_CONTEXT* zgfx, BYTE** ppConcatenated, size_t uncompressedSize, + size_t* pUsed) +{ + WINPR_ASSERT(zgfx); + WINPR_ASSERT(ppConcatenated); + WINPR_ASSERT(pUsed); + + const size_t used = *pUsed; + if (zgfx->OutputCount > UINT32_MAX - used) + return FALSE; + + if (used + zgfx->OutputCount > uncompressedSize) + return FALSE; + + BYTE* tmp = realloc(*ppConcatenated, used + zgfx->OutputCount + 64ull); + if (!tmp) + return FALSE; + *ppConcatenated = tmp; + CopyMemory(&tmp[used], zgfx->OutputBuffer, zgfx->OutputCount); + *pUsed = used + zgfx->OutputCount; + return TRUE; +} + int zgfx_decompress(ZGFX_CONTEXT* zgfx, const BYTE* pSrcData, UINT32 SrcSize, BYTE** ppDstData, UINT32* pDstSize, UINT32 flags) { int status = -1; - BYTE descriptor; + BYTE descriptor = 0; + size_t used = 0; + BYTE* pConcatenated = NULL; wStream* stream = Stream_New((BYTE*)pSrcData, SrcSize); WINPR_ASSERT(zgfx); WINPR_ASSERT(stream); + WINPR_ASSERT(ppDstData); + WINPR_ASSERT(pDstSize); + + *ppDstData = NULL; + *pDstSize = 0; if (Stream_GetRemainingLength(stream) < 1) goto fail; @@ -405,16 +435,15 @@ int zgfx_decompress(ZGFX_CONTEXT* zgfx, const BYTE* pSrcData, UINT32 SrcSize, BY if (!zgfx_decompress_segment(zgfx, stream, Stream_GetRemainingLength(stream))) goto fail; - *ppDstData = NULL; - if (zgfx->OutputCount > 0) - *ppDstData = aligned_zgfx_malloc(zgfx->OutputCount); - - if (!*ppDstData) - goto fail; - - *pDstSize = zgfx->OutputCount; - CopyMemory(*ppDstData, zgfx->OutputBuffer, zgfx->OutputCount); + { + if (!zgfx_append(zgfx, &pConcatenated, zgfx->OutputCount, &used)) + goto fail; + if (used != zgfx->OutputCount) + goto fail; + *ppDstData = pConcatenated; + *pDstSize = zgfx->OutputCount; + } } else if (descriptor == ZGFX_SEGMENTED_MULTIPART) { @@ -422,8 +451,6 @@ int zgfx_decompress(ZGFX_CONTEXT* zgfx, const BYTE* pSrcData, UINT32 SrcSize, BY UINT16 segmentNumber; UINT16 segmentCount; UINT32 uncompressedSize; - BYTE* pConcatenated; - size_t used = 0; if (Stream_GetRemainingLength(stream) < 6) goto fail; @@ -431,17 +458,6 @@ int zgfx_decompress(ZGFX_CONTEXT* zgfx, const BYTE* pSrcData, UINT32 SrcSize, BY Stream_Read_UINT16(stream, segmentCount); /* segmentCount (2 bytes) */ Stream_Read_UINT32(stream, uncompressedSize); /* uncompressedSize (4 bytes) */ - if (Stream_GetRemainingLength(stream) < segmentCount * sizeof(UINT32)) - goto fail; - - pConcatenated = aligned_zgfx_malloc(uncompressedSize); - - if (!pConcatenated) - goto fail; - - *ppDstData = pConcatenated; - *pDstSize = uncompressedSize; - for (segmentNumber = 0; segmentNumber < segmentCount; segmentNumber++) { if (Stream_GetRemainingLength(stream) < sizeof(UINT32)) @@ -452,16 +468,15 @@ int zgfx_decompress(ZGFX_CONTEXT* zgfx, const BYTE* pSrcData, UINT32 SrcSize, BY if (!zgfx_decompress_segment(zgfx, stream, segmentSize)) goto fail; - if (zgfx->OutputCount > UINT32_MAX - used) + if (!zgfx_append(zgfx, &pConcatenated, uncompressedSize, &used)) goto fail; + } - if (used + zgfx->OutputCount > uncompressedSize) - goto fail; + if (used != uncompressedSize) + goto fail; - CopyMemory(pConcatenated, zgfx->OutputBuffer, zgfx->OutputCount); - pConcatenated += zgfx->OutputCount; - used += zgfx->OutputCount; - } + *ppDstData = pConcatenated; + *pDstSize = uncompressedSize; } else { @@ -470,6 +485,8 @@ int zgfx_decompress(ZGFX_CONTEXT* zgfx, const BYTE* pSrcData, UINT32 SrcSize, BY status = 1; fail: + if (status < 0) + free(pConcatenated); Stream_Free(stream, FALSE); return status; } From 29ba9766f7cb263a9d07e624da3e2f07e7343a26 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Sat, 20 Apr 2024 17:40:33 +0200 Subject: [PATCH 448/496] [codec,clear] use size_t types for sizes (cherry picked from commit 9314b5492b501dbe6edb5430ee8d7c29ff772f68) --- libfreerdp/codec/clear.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libfreerdp/codec/clear.c b/libfreerdp/codec/clear.c index f3411073cef5..e38fa0dcfbef 100644 --- a/libfreerdp/codec/clear.c +++ b/libfreerdp/codec/clear.c @@ -512,12 +512,12 @@ static BOOL clear_decompress_subcodecs_data(CLEAR_CONTEXT* clear, wStream* s, { case 0: /* Uncompressed */ { - UINT32 nSrcStep = width * GetBytesPerPixel(PIXEL_FORMAT_BGR24); - UINT32 nSrcSize = nSrcStep * height; + const UINT32 nSrcStep = width * GetBytesPerPixel(PIXEL_FORMAT_BGR24); + const size_t nSrcSize = 1ull * nSrcStep * height; if (bitmapDataByteCount != nSrcSize) { - WLog_ERR(TAG, "bitmapDataByteCount %" PRIu32 " != nSrcSize %" PRIu32 "", + WLog_ERR(TAG, "bitmapDataByteCount %" PRIu32 " != nSrcSize %" PRIuz "", bitmapDataByteCount, nSrcSize); return FALSE; } @@ -822,7 +822,7 @@ static BOOL clear_decompress_bands_data(CLEAR_CONTEXT* clear, wStream* s, UINT32 if (count > 0) { - const size_t offset = (y - vBarYOn) * GetBytesPerPixel(clear->format); + const size_t offset = (1ull * y - vBarYOn) * GetBytesPerPixel(clear->format); pSrcPixel = &vBarShortEntry->pixels[offset]; if (offset + count > vBarShortEntry->count) { From 8b9ad6cf80a2233de22b3b5100d642d876ef9a6e Mon Sep 17 00:00:00 2001 From: akallabeth Date: Sun, 21 Apr 2024 10:18:43 +0200 Subject: [PATCH 449/496] [codec,color] fix out of bound read (cherry picked from commit 6430945ce003a5e24d454d8566f54aae1b6b617b) --- libfreerdp/codec/color.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libfreerdp/codec/color.c b/libfreerdp/codec/color.c index 00919983c343..f8467c295eb7 100644 --- a/libfreerdp/codec/color.c +++ b/libfreerdp/codec/color.c @@ -613,6 +613,9 @@ BOOL freerdp_image_copy(BYTE* pDstData, DWORD DstFormat, UINT32 nDstStep, UINT32 if (!pDstData || !pSrcData) return FALSE; + if ((nWidth == 0) || (nHeight == 0)) + return TRUE; + if (nDstStep == 0) nDstStep = nWidth * GetBytesPerPixel(DstFormat); From 9b341d10a8445637e80311b287962fb8e0e4feb8 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Mon, 22 Apr 2024 09:57:37 +0200 Subject: [PATCH 450/496] [core,orders] shift unsigned value The delta value read is signed, but the operations are done on an unsigned. (cherry picked from commit 5b4e39fd7eacf106367ba6424a3198ce5f856b3d) --- libfreerdp/core/orders.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/libfreerdp/core/orders.c b/libfreerdp/core/orders.c index 0f19914d7d93..d8bf58d92b9e 100644 --- a/libfreerdp/core/orders.c +++ b/libfreerdp/core/orders.c @@ -797,6 +797,7 @@ static INLINE BOOL update_write_4byte_unsigned(wStream* s, UINT32 value) static INLINE BOOL update_read_delta(wStream* s, INT32* value) { BYTE byte; + UINT32 uvalue = 0; if (Stream_GetRemainingLength(s) < 1) { @@ -807,9 +808,9 @@ static INLINE BOOL update_read_delta(wStream* s, INT32* value) Stream_Read_UINT8(s, byte); if (byte & 0x40) - *value = (byte | ~0x3F); + uvalue = (byte | ~0x3F); else - *value = (byte & 0x3F); + uvalue = (byte & 0x3F); if (byte & 0x80) { @@ -820,8 +821,9 @@ static INLINE BOOL update_read_delta(wStream* s, INT32* value) } Stream_Read_UINT8(s, byte); - *value = (*value << 8) | byte; + uvalue = (uvalue << 8) | byte; } + *value = (INT32)uvalue; return TRUE; } From 550355dc528bf5b7f0e6dbf97d74a194d2a81d5f Mon Sep 17 00:00:00 2001 From: akallabeth Date: Mon, 22 Apr 2024 11:09:50 +0200 Subject: [PATCH 451/496] changelog --- ChangeLog | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/ChangeLog b/ChangeLog index 94fdf10ae04e..a2209be5f71b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +# 2024-04-22 Version 2.11.7 + +Noteworthy changes: +* Backported oss-fuzz fixes + +For a complete and detailed change log since the last release run: +git log 2.11.7...2.11.6 + # 2024-04-17 Version 2.11.6 CVE: From 7f6cc93c21d7f0faad6daacca06f494f29ce882c Mon Sep 17 00:00:00 2001 From: akallabeth Date: Mon, 22 Apr 2024 11:10:57 +0200 Subject: [PATCH 452/496] release-2.11.7 --- CMakeLists.txt | 2 +- client/Android/android_freerdp.c | 2 +- winpr/CMakeLists.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index bbc92360020f..67f34372a282 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -85,7 +85,7 @@ if ($ENV{BUILD_NUMBER}) endif() set(WITH_LIBRARY_VERSIONING "ON") -set(RAW_VERSION_STRING "2.11.7-dev") +set(RAW_VERSION_STRING "2.11.7") if(EXISTS "${CMAKE_SOURCE_DIR}/.source_tag") file(READ ${CMAKE_SOURCE_DIR}/.source_tag RAW_VERSION_STRING) elseif(USE_VERSION_FROM_GIT_TAG) diff --git a/client/Android/android_freerdp.c b/client/Android/android_freerdp.c index bee850d08963..656b527268c5 100644 --- a/client/Android/android_freerdp.c +++ b/client/Android/android_freerdp.c @@ -57,7 +57,7 @@ #define TAG CLIENT_TAG("android") /* Defines the JNI version supported by this library. */ -#define FREERDP_JNI_VERSION "2.11.7-dev" +#define FREERDP_JNI_VERSION "2.11.7" static void android_OnChannelConnectedEventHandler(void* context, ChannelConnectedEventArgs* e) { diff --git a/winpr/CMakeLists.txt b/winpr/CMakeLists.txt index fd13126356ac..748582b0ef73 100644 --- a/winpr/CMakeLists.txt +++ b/winpr/CMakeLists.txt @@ -57,7 +57,7 @@ if (NOT WIN32) endif() # Soname versioning -set(RAW_VERSION_STRING "2.11.7-dev") +set(RAW_VERSION_STRING "2.11.7") if(EXISTS "${CMAKE_SOURCE_DIR}/.source_tag") file(READ ${CMAKE_SOURCE_DIR}/.source_tag RAW_VERSION_STRING) elseif(USE_VERSION_FROM_GIT_TAG) From a383740a2f85fa93f390181e5ea4bd1458b34051 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Mon, 22 Apr 2024 11:11:27 +0200 Subject: [PATCH 453/496] next-dev-2.11.8-dev --- CMakeLists.txt | 2 +- client/Android/android_freerdp.c | 2 +- winpr/CMakeLists.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 67f34372a282..3d4a5e515bb8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -85,7 +85,7 @@ if ($ENV{BUILD_NUMBER}) endif() set(WITH_LIBRARY_VERSIONING "ON") -set(RAW_VERSION_STRING "2.11.7") +set(RAW_VERSION_STRING "2.11.8-dev") if(EXISTS "${CMAKE_SOURCE_DIR}/.source_tag") file(READ ${CMAKE_SOURCE_DIR}/.source_tag RAW_VERSION_STRING) elseif(USE_VERSION_FROM_GIT_TAG) diff --git a/client/Android/android_freerdp.c b/client/Android/android_freerdp.c index 656b527268c5..e30a0f43bad7 100644 --- a/client/Android/android_freerdp.c +++ b/client/Android/android_freerdp.c @@ -57,7 +57,7 @@ #define TAG CLIENT_TAG("android") /* Defines the JNI version supported by this library. */ -#define FREERDP_JNI_VERSION "2.11.7" +#define FREERDP_JNI_VERSION "2.11.8-dev" static void android_OnChannelConnectedEventHandler(void* context, ChannelConnectedEventArgs* e) { diff --git a/winpr/CMakeLists.txt b/winpr/CMakeLists.txt index 748582b0ef73..77ff2330227a 100644 --- a/winpr/CMakeLists.txt +++ b/winpr/CMakeLists.txt @@ -57,7 +57,7 @@ if (NOT WIN32) endif() # Soname versioning -set(RAW_VERSION_STRING "2.11.7") +set(RAW_VERSION_STRING "2.11.8-dev") if(EXISTS "${CMAKE_SOURCE_DIR}/.source_tag") file(READ ${CMAKE_SOURCE_DIR}/.source_tag RAW_VERSION_STRING) elseif(USE_VERSION_FROM_GIT_TAG) From 4f411197dc9d2076f00748b1178a60b2423030bf Mon Sep 17 00:00:00 2001 From: Alessandro Bono Date: Wed, 8 May 2024 16:06:17 +0200 Subject: [PATCH 454/496] info: Fix incompatible pointer type MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This fixes the following: ``` libfreerdp/core/info.c: In function ‘rdp_read_info_null_string’: libfreerdp/core/info.c:88:39: error: initialization of ‘const WCHAR *’ {aka ‘const short unsigned int *’} from incompatible pointer type ‘BYTE *’ {aka ‘unsigned char *’} [-Wincompatible-pointer-types] 88 | const WCHAR* domain = Stream_Pointer(s); ``` --- libfreerdp/core/info.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libfreerdp/core/info.c b/libfreerdp/core/info.c index 9aaa6cff6b74..c9b2fc6017d3 100644 --- a/libfreerdp/core/info.c +++ b/libfreerdp/core/info.c @@ -85,7 +85,7 @@ static BOOL rdp_read_info_null_string(const char* what, UINT32 flags, wStream* s if (cbLen > 0) { - const WCHAR* domain = Stream_Pointer(s); + const WCHAR* domain = (WCHAR*)Stream_Pointer(s); if (isNullTerminated && (max > 0)) max -= nullSize; From f3ed1f1ac367eb21f93c9fba5047447fdccdb5cc Mon Sep 17 00:00:00 2001 From: Alessandro Bono Date: Wed, 8 May 2024 16:06:26 +0200 Subject: [PATCH 455/496] redirection: Fix incompatible pointer type MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This fixes the following: ``` libfreerdp/core/redirection.c: In function ‘redirection_copy_data’: libfreerdp/core/redirection.c:91:31: error: passing argument 1 of ‘redirection_free_data’ from incompatible pointer type [-Wincompatible-pointer-types] 91 | redirection_free_data(dst, plen); | ^~~ | | | char ** libfreerdp/core/redirection.c:80:42: note: expected ‘BYTE **’ {aka ‘unsigned char **’} but argument is of type ‘char **’ 80 | static void redirection_free_data(BYTE** str, UINT32* length) | ~~~~~~~^~~ ``` --- libfreerdp/core/redirection.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libfreerdp/core/redirection.c b/libfreerdp/core/redirection.c index 59c6dbceed3d..63bc8cc854ca 100644 --- a/libfreerdp/core/redirection.c +++ b/libfreerdp/core/redirection.c @@ -86,7 +86,7 @@ static void redirection_free_data(BYTE** str, UINT32* length) *str = NULL; } -static BOOL redirection_copy_data(char** dst, UINT32* plen, const char* str, UINT32 len) +static BOOL redirection_copy_data(BYTE** dst, UINT32* plen, const BYTE* str, UINT32 len) { redirection_free_data(dst, plen); From 7894a7dfc5f811cb5dacc57a09236c11744b1ec8 Mon Sep 17 00:00:00 2001 From: Alessandro Bono Date: Wed, 8 May 2024 16:06:30 +0200 Subject: [PATCH 456/496] redirection: Fix incompatible pointer type MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This fixes the following: ``` libfreerdp/core/redirection.c: In function ‘freerdp_settings_set_pointer_len’: libfreerdp/core/redirection.c:112:31: error: assignment to ‘BYTE **’ {aka ‘unsigned char **’} from incompatible pointer type ‘char **’ [-Wincompatible-pointer-types] 112 | pdata = &settings->TargetNetAddress; | ^ ``` --- libfreerdp/core/redirection.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libfreerdp/core/redirection.c b/libfreerdp/core/redirection.c index 63bc8cc854ca..4872d4b8fb17 100644 --- a/libfreerdp/core/redirection.c +++ b/libfreerdp/core/redirection.c @@ -109,7 +109,7 @@ static BOOL freerdp_settings_set_pointer_len(rdpSettings* settings, size_t id, c switch (id) { case FreeRDP_TargetNetAddress: - pdata = &settings->TargetNetAddress; + pdata = (BYTE**)&settings->TargetNetAddress; plen = &settings->TargetNetAddressCount; break; case FreeRDP_LoadBalanceInfo: From d2b6771c748e54e659d5f1243a92e499c3beaa36 Mon Sep 17 00:00:00 2001 From: Mike Gilbert Date: Wed, 22 May 2024 17:04:43 -0400 Subject: [PATCH 457/496] X11: fix pointer/integer type mismatch Fixed on master in 2da280b8a1748052b70b3f5a1ef0d8e932c33adc. --- client/X11/xf_graphics.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/X11/xf_graphics.c b/client/X11/xf_graphics.c index 5aa1fd48b5a3..fe81e0ed91cb 100644 --- a/client/X11/xf_graphics.c +++ b/client/X11/xf_graphics.c @@ -438,7 +438,7 @@ static BOOL xf_Pointer_New(rdpContext* context, rdpPointer* pointer) #endif fail: - WLog_DBG(TAG, "%s: %ld", __func__, rc ? pointer : -1); + WLog_DBG(TAG, "%s: %p", __func__, rc ? pointer : NULL); return rc; } From 67818bddb31900cdf3acb26cb0b673cc90b71cc9 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Thu, 23 May 2024 09:30:33 +0200 Subject: [PATCH 458/496] [client,wayland] fix const correctness --- client/Wayland/wlfreerdp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/Wayland/wlfreerdp.c b/client/Wayland/wlfreerdp.c index 65e29bc51109..5988aed6b03f 100644 --- a/client/Wayland/wlfreerdp.c +++ b/client/Wayland/wlfreerdp.c @@ -587,7 +587,7 @@ static void wlf_client_free(freerdp* instance, rdpContext* context) DeleteCriticalSection(&wlf->critical); } -static void* uwac_event_clone(const void* val) +static void* uwac_event_clone(void* val) { UwacEvent* copy; UwacEvent* ev = (UwacEvent*)val; From 5b2b53b15c9af46b85c4ef0007e7fb59d7608289 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Thu, 8 Aug 2024 11:03:24 +0200 Subject: [PATCH 459/496] [warnings] fix -Wincompatible-pointer-types --- channels/ainput/server/ainput_main.c | 8 ++++---- libfreerdp/codec/dsp_ffmpeg.c | 2 +- winpr/libwinpr/crt/unicode.c | 8 ++++---- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/channels/ainput/server/ainput_main.c b/channels/ainput/server/ainput_main.c index 943d0faf1628..fc61f9b00101 100644 --- a/channels/ainput/server/ainput_main.c +++ b/channels/ainput/server/ainput_main.c @@ -222,7 +222,7 @@ static HANDLE ainput_server_get_channel_handle(ainput_server* ainput) WINPR_ASSERT(ainput); - if (WTSVirtualChannelQuery(ainput->ainput_channel, WTSVirtualEventHandle, &buffer, + if (WTSVirtualChannelQuery(ainput->ainput_channel, WTSVirtualEventHandle, (void**)&buffer, &BytesReturned) == TRUE) { if (BytesReturned == sizeof(HANDLE)) @@ -416,7 +416,7 @@ ainput_server_context* ainput_server_context_new(HANDLE vcm) goto fail; return &ainput->context; fail: - ainput_server_context_free(ainput); + ainput_server_context_free(&ainput->context); return NULL; } @@ -539,8 +539,8 @@ UINT ainput_server_context_poll_int(ainput_server_context* context) BYTE* buffer = NULL; DWORD BytesReturned = 0; - if (WTSVirtualChannelQuery(ainput->ainput_channel, WTSVirtualChannelReady, &buffer, - &BytesReturned) != TRUE) + if (WTSVirtualChannelQuery(ainput->ainput_channel, WTSVirtualChannelReady, + (void**)&buffer, &BytesReturned) != TRUE) { WLog_ERR(TAG, "WTSVirtualChannelReady failed,"); } diff --git a/libfreerdp/codec/dsp_ffmpeg.c b/libfreerdp/codec/dsp_ffmpeg.c index ef6791400d38..80df188339ee 100644 --- a/libfreerdp/codec/dsp_ffmpeg.c +++ b/libfreerdp/codec/dsp_ffmpeg.c @@ -423,7 +423,7 @@ static BOOL ffmpeg_encode_frame(AVCodecContext* context, AVFrame* in, AVPacket* uint8_t** pp = in->extended_data; for (int y = 0; y < in->channels; y++) { - float* data = pp[y]; + float* data = (float*)pp[y]; for (int x = 0; x < in->nb_samples; x++) { const float val1 = data[x]; diff --git a/winpr/libwinpr/crt/unicode.c b/winpr/libwinpr/crt/unicode.c index dc3533a8a7b5..acbec014e67c 100644 --- a/winpr/libwinpr/crt/unicode.c +++ b/winpr/libwinpr/crt/unicode.c @@ -215,8 +215,8 @@ int MultiByteToWideChar(UINT CodePage, DWORD dwFlags, LPCSTR lpMultiByteStr, int else { targetLength = - ucnv_convert("UTF-16LE", "UTF-8", targetStart, targetCapacity * sizeof(WCHAR), - lpMultiByteStr, cbMultiByte, &error); + ucnv_convert("UTF-16LE", "UTF-8", (char*)targetStart, + targetCapacity * sizeof(WCHAR), lpMultiByteStr, cbMultiByte, &error); if (targetLength > 0) targetLength /= sizeof(WCHAR); cchWideChar = U_SUCCESS(error) ? targetLength : 0; @@ -353,14 +353,14 @@ int WideCharToMultiByte(UINT CodePage, DWORD dwFlags, LPCWSTR lpWideCharStr, int #if defined(UCNV_CONVERT) if (cbMultiByte == 0) { - targetLength = ucnv_convert("UTF-8", "UTF-16LE", NULL, 0, lpWideCharStr, + targetLength = ucnv_convert("UTF-8", "UTF-16LE", NULL, 0, (char*)lpWideCharStr, cchWideChar * sizeof(WCHAR), &error); cbMultiByte = targetLength; } else { targetLength = ucnv_convert("UTF-8", "UTF-16LE", targetStart, targetCapacity, - lpWideCharStr, cchWideChar * sizeof(WCHAR), &error); + (char*)lpWideCharStr, cchWideChar * sizeof(WCHAR), &error); cbMultiByte = U_SUCCESS(error) ? targetLength : 0; } From be23ed4ba990bd39391a651444fbb9130722c93b Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Thu, 8 Aug 2024 11:06:54 +0200 Subject: [PATCH 460/496] [server,proxy] deactivate capture module the module does not work (and did not for a long time) --- server/proxy/modules/capture/CMakeLists.txt | 28 +++++++++++---------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/server/proxy/modules/capture/CMakeLists.txt b/server/proxy/modules/capture/CMakeLists.txt index 80ba3b77e1c6..4004aaa96437 100644 --- a/server/proxy/modules/capture/CMakeLists.txt +++ b/server/proxy/modules/capture/CMakeLists.txt @@ -17,17 +17,19 @@ # limitations under the License. # -set(PLUGIN_NAME "proxy-capture-plugin") +# deactivated: does not work -add_library(${PLUGIN_NAME} MODULE - cap_main.c - cap_config.c - cap_config.h - cap_protocol.c - cap_protocol.h -) - -set_target_properties(${PLUGIN_NAME} PROPERTIES PREFIX "") -set_target_properties(${PLUGIN_NAME} PROPERTIES NO_SONAME 1) -set_target_properties(${PLUGIN_NAME} PROPERTIES -LIBRARY_OUTPUT_DIRECTORY "${FREERDP_PROXY_PLUGINDIR}") +#set(PLUGIN_NAME "proxy-capture-plugin") +# +#add_library(${PLUGIN_NAME} MODULE +# cap_main.c +# cap_config.c +# cap_config.h +# cap_protocol.c +# cap_protocol.h +#) +# +#set_target_properties(${PLUGIN_NAME} PROPERTIES PREFIX "") +#set_target_properties(${PLUGIN_NAME} PROPERTIES NO_SONAME 1) +#set_target_properties(${PLUGIN_NAME} PROPERTIES +#LIBRARY_OUTPUT_DIRECTORY "${FREERDP_PROXY_PLUGINDIR}") From 052c525e0999c352bf6012968145ecb013e05f5b Mon Sep 17 00:00:00 2001 From: akallabeth Date: Fri, 25 Oct 2024 08:40:44 +0200 Subject: [PATCH 461/496] [core] eliminate rdpRdp::instance Use rdpRdp::context for access instead --- include/freerdp/freerdp.h | 1 + libfreerdp/core/activation.c | 2 +- libfreerdp/core/capabilities.c | 4 ++-- libfreerdp/core/connection.c | 2 +- libfreerdp/core/freerdp.c | 11 +++++++++-- libfreerdp/core/heartbeat.c | 4 +++- libfreerdp/core/info.c | 9 +++++++-- libfreerdp/core/peer.c | 2 +- libfreerdp/core/rdp.c | 14 +++++++------- libfreerdp/core/rdp.h | 1 - 10 files changed, 32 insertions(+), 18 deletions(-) diff --git a/include/freerdp/freerdp.h b/include/freerdp/freerdp.h index 77ceb54f51f1..235cd04b7c0a 100644 --- a/include/freerdp/freerdp.h +++ b/include/freerdp/freerdp.h @@ -455,6 +455,7 @@ extern "C" FREERDP_API BOOL freerdp_connect(freerdp* instance); FREERDP_API BOOL freerdp_abort_connect(freerdp* instance); FREERDP_API BOOL freerdp_shall_disconnect(freerdp* instance); + FREERDP_API BOOL freerdp_shall_disconnect_context(rdpContext* context); FREERDP_API BOOL freerdp_disconnect(freerdp* instance); FREERDP_API BOOL freerdp_disconnect_before_reconnect(freerdp* instance); diff --git a/libfreerdp/core/activation.c b/libfreerdp/core/activation.c index c6e335bcf1aa..1110b76ba1bc 100644 --- a/libfreerdp/core/activation.c +++ b/libfreerdp/core/activation.c @@ -387,7 +387,7 @@ BOOL rdp_recv_deactivate_all(rdpRdp* rdp, wStream* s) if (rdp_check_fds(rdp) < 0) return FALSE; - if (freerdp_shall_disconnect(rdp->instance)) + if (freerdp_shall_disconnect_context(rdp->context)) return TRUE; if (rdp_get_state(rdp) == CONNECTION_STATE_ACTIVE) diff --git a/libfreerdp/core/capabilities.c b/libfreerdp/core/capabilities.c index c7fbd7e99840..5fcc6c39462a 100644 --- a/libfreerdp/core/capabilities.c +++ b/libfreerdp/core/capabilities.c @@ -3846,7 +3846,7 @@ BOOL rdp_recv_get_active_header(rdpRdp* rdp, wStream* s, UINT16* pChannelId, UIN if (!rdp_read_header(rdp, s, length, pChannelId)) return FALSE; - if (freerdp_shall_disconnect(rdp->instance)) + if (freerdp_shall_disconnect_context(rdp->context)) return TRUE; if (rdp->settings->UseRdpSecurityLayer) @@ -3891,7 +3891,7 @@ BOOL rdp_recv_demand_active(rdpRdp* rdp, wStream* s) if (!rdp_recv_get_active_header(rdp, s, &channelId, &length)) return FALSE; - if (freerdp_shall_disconnect(rdp->instance)) + if (freerdp_shall_disconnect_context(rdp->context)) return TRUE; if (!rdp_read_share_control_header(s, NULL, NULL, &pduType, &pduSource)) diff --git a/libfreerdp/core/connection.c b/libfreerdp/core/connection.c index 3d8d70634788..9b67a86a6713 100644 --- a/libfreerdp/core/connection.c +++ b/libfreerdp/core/connection.c @@ -1063,7 +1063,7 @@ int rdp_client_connect_demand_active(rdpRdp* rdp, wStream* s) return rc; } - if (freerdp_shall_disconnect(rdp->instance)) + if (freerdp_shall_disconnect_context(rdp->context)) return 0; if (!rdp_send_confirm_active(rdp)) diff --git a/libfreerdp/core/freerdp.c b/libfreerdp/core/freerdp.c index b31d7d84f946..2668f3bc03cf 100644 --- a/libfreerdp/core/freerdp.c +++ b/libfreerdp/core/freerdp.c @@ -558,10 +558,17 @@ BOOL freerdp_reconnect(freerdp* instance) BOOL freerdp_shall_disconnect(freerdp* instance) { - if (!instance || !instance->context) + if (!instance) + return FALSE; + return freerdp_shall_disconnect_context(instance->context); +} + +BOOL freerdp_shall_disconnect_context(rdpContext* context) +{ + if (!context) return FALSE; - if (WaitForSingleObject(instance->context->abortEvent, 0) != WAIT_OBJECT_0) + if (WaitForSingleObject(context->abortEvent, 0) != WAIT_OBJECT_0) return FALSE; return TRUE; diff --git a/libfreerdp/core/heartbeat.c b/libfreerdp/core/heartbeat.c index 8418ba3cb695..b019d33c4685 100644 --- a/libfreerdp/core/heartbeat.c +++ b/libfreerdp/core/heartbeat.c @@ -45,7 +45,9 @@ int rdp_recv_heartbeat_packet(rdpRdp* rdp, wStream* s) "received Heartbeat PDU -> period=%" PRIu8 ", count1=%" PRIu8 ", count2=%" PRIu8 "", period, count1, count2); - rc = IFCALLRESULT(TRUE, rdp->heartbeat->ServerHeartbeat, rdp->instance, period, count1, count2); + WINPR_ASSERT(rdp->context->instance); + rc = IFCALLRESULT(TRUE, rdp->heartbeat->ServerHeartbeat, rdp->context->instance, period, count1, + count2); if (!rc) { WLog_ERR(HEARTBEAT_TAG, "heartbeat->ServerHeartbeat callback failed!"); diff --git a/libfreerdp/core/info.c b/libfreerdp/core/info.c index c9b2fc6017d3..534f09989f59 100644 --- a/libfreerdp/core/info.c +++ b/libfreerdp/core/info.c @@ -1177,8 +1177,13 @@ static BOOL rdp_recv_logon_error_info(rdpRdp* rdp, wStream* s, logon_info_ex* in Stream_Read_UINT32(s, errorNotificationData); /* errorNotificationData (4 bytes) */ WLog_DBG(TAG, "LogonErrorInfo: Data: 0x%08" PRIX32 " Type: 0x%08" PRIX32 "", errorNotificationData, errorNotificationType); - IFCALL(rdp->instance->LogonErrorInfo, rdp->instance, errorNotificationData, - errorNotificationType); + + WINPR_ASSERT(rdp); + WINPR_ASSERT(rdp->context); + freerdp* instance = rdp->context->instance; + + WINPR_ASSERT(instance); + IFCALL(instance->LogonErrorInfo, instance, errorNotificationData, errorNotificationType); info->ErrorNotificationType = errorNotificationType; info->ErrorNotificationData = errorNotificationData; return TRUE; diff --git a/libfreerdp/core/peer.c b/libfreerdp/core/peer.c index 41730efecbd9..f629705d5016 100644 --- a/libfreerdp/core/peer.c +++ b/libfreerdp/core/peer.c @@ -359,7 +359,7 @@ static int peer_recv_tpkt_pdu(freerdp_peer* client, wStream* s) } rdp->inPackets++; - if (freerdp_shall_disconnect(rdp->instance)) + if (freerdp_shall_disconnect_context(rdp->context)) return 0; if (rdp->settings->UseRdpSecurityLayer) diff --git a/libfreerdp/core/rdp.c b/libfreerdp/core/rdp.c index cd93d713ab6f..33e7a54668fa 100644 --- a/libfreerdp/core/rdp.c +++ b/libfreerdp/core/rdp.c @@ -415,7 +415,7 @@ BOOL rdp_read_header(rdpRdp* rdp, wStream* s, UINT16* length, UINT16* channelId) { if (code == X224_TPDU_DISCONNECT_REQUEST) { - utils_abort_connect(rdp->instance->context); + utils_abort_connect(rdp->context); return TRUE; } @@ -450,10 +450,10 @@ BOOL rdp_read_header(rdpRdp* rdp, wStream* s, UINT16* length, UINT16* channelId) if (!mcs_recv_disconnect_provider_ultimatum(rdp->mcs, s, &reason)) return FALSE; - if (!rdp->instance) + if (!rdp->context) return FALSE; - context = rdp->instance->context; + context = rdp->context; context->disconnectUltimatum = reason; if (rdp->errorInfo == ERRINFO_SUCCESS) @@ -784,7 +784,7 @@ static BOOL rdp_recv_server_set_keyboard_indicators_pdu(rdpRdp* rdp, wStream* s) { UINT16 unitId; UINT16 ledFlags; - rdpContext* context = rdp->instance->context; + rdpContext* context = rdp->context; if (Stream_GetRemainingLength(s) < 4) return FALSE; @@ -1319,7 +1319,7 @@ static int rdp_recv_tpkt_pdu(rdpRdp* rdp, wStream* s) return -1; } - if (freerdp_shall_disconnect(rdp->instance)) + if (freerdp_shall_disconnect_context(rdp->context)) return 0; if (rdp->autodetect->bandwidthMeasureStarted) @@ -1435,7 +1435,8 @@ static int rdp_recv_tpkt_pdu(rdpRdp* rdp, wStream* s) { rdp->inPackets++; - if (!freerdp_channel_process(rdp->instance, s, channelId, length)) + WINPR_ASSERT(rdp->context); + if (!freerdp_channel_process(rdp->context->instance, s, channelId, length)) return -1; } @@ -1770,7 +1771,6 @@ rdpRdp* rdp_new(rdpContext* context) InitializeCriticalSection(&rdp->critical); rdp->context = context; - rdp->instance = context->instance; flags = 0; if (context->ServerMode) diff --git a/libfreerdp/core/rdp.h b/libfreerdp/core/rdp.h index 3953329963dc..7163adc75a84 100644 --- a/libfreerdp/core/rdp.h +++ b/libfreerdp/core/rdp.h @@ -133,7 +133,6 @@ struct rdp_rdp { CONNECTION_STATE state; - freerdp* instance; rdpContext* context; rdpNla* nla; rdpMcs* mcs; From a9deecc99b3c5080d0f068d7d36e699505d6285d Mon Sep 17 00:00:00 2001 From: Bernhard Miklautz Date: Sun, 27 Oct 2024 19:19:58 +0100 Subject: [PATCH 462/496] fix [core]: 'invalid hHandle' errors peer_recv_tpkt_pdu calls freerdp_shall_disconnect_context which calls WaitForSingleObject. Server side the abortEvent is NULL and therefore every call triggered the following message: ``` [ERROR:com.winpr.sync.wait] [wait.c|WaitForSingleObjectEx|174] - invalid hHandle. ``` --- libfreerdp/core/freerdp.c | 2 +- libfreerdp/core/utils.c | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/libfreerdp/core/freerdp.c b/libfreerdp/core/freerdp.c index 2668f3bc03cf..e2179f4df149 100644 --- a/libfreerdp/core/freerdp.c +++ b/libfreerdp/core/freerdp.c @@ -565,7 +565,7 @@ BOOL freerdp_shall_disconnect(freerdp* instance) BOOL freerdp_shall_disconnect_context(rdpContext* context) { - if (!context) + if (!context || !context->abortEvent) return FALSE; if (WaitForSingleObject(context->abortEvent, 0) != WAIT_OBJECT_0) diff --git a/libfreerdp/core/utils.c b/libfreerdp/core/utils.c index 139c1a4336d8..15cd655981cf 100644 --- a/libfreerdp/core/utils.c +++ b/libfreerdp/core/utils.c @@ -47,8 +47,9 @@ BOOL utils_str_copy(const char* value, char** dst) BOOL utils_abort_connect(rdpContext* context) { WINPR_ASSERT(context); - - return SetEvent(context->abortEvent); + if (context->abortEvent) + return SetEvent(context->abortEvent); + return FALSE; } BOOL utils_reset_abort(rdpContext* context) From 68c7c21b9e63e25221fb90d7e648398963e023a8 Mon Sep 17 00:00:00 2001 From: Malte Starostik Date: Sun, 7 Feb 2021 23:57:05 +0100 Subject: [PATCH 463/496] X11 client: ignore grab related LeaveNotify events This fixes click and drag or more generally any press-hold-release combinations for the primary mouse button. Without this, click and drag, drag and drop and in, some remote applications that presumably rely on the full press-release sequence, even button presses don't always work. (cherry picked from commit 06219e4ecb7a03223df0e02050ebd3c557561678) --- client/X11/xf_event.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/client/X11/xf_event.c b/client/X11/xf_event.c index eb50ef1e87da..0d6d4a429cbc 100644 --- a/client/X11/xf_event.c +++ b/client/X11/xf_event.c @@ -672,6 +672,8 @@ static BOOL xf_event_EnterNotify(xfContext* xfc, const XEnterWindowEvent* event, static BOOL xf_event_LeaveNotify(xfContext* xfc, const XLeaveWindowEvent* event, BOOL app) { + if (event->mode == NotifyGrab || event->mode == NotifyUngrab) + return TRUE; if (!app) { xfc->mouse_active = FALSE; From 562ae3588e297a80fe151e3c186f39514be2206d Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Thu, 28 Nov 2024 12:43:57 +0100 Subject: [PATCH 464/496] [winpr,pubsub] add NULL parameter checks --- winpr/libwinpr/utils/collections/PubSub.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/winpr/libwinpr/utils/collections/PubSub.c b/winpr/libwinpr/utils/collections/PubSub.c index 466dde6897e7..d1eb1134d4a4 100644 --- a/winpr/libwinpr/utils/collections/PubSub.c +++ b/winpr/libwinpr/utils/collections/PubSub.c @@ -22,6 +22,7 @@ #endif #include +#include #include @@ -36,6 +37,9 @@ wEventType* PubSub_GetEventTypes(wPubSub* pubSub, int* count) { + if (!pubSub) + return NULL; + if (count) *count = pubSub->count; @@ -48,11 +52,15 @@ wEventType* PubSub_GetEventTypes(wPubSub* pubSub, int* count) void PubSub_Lock(wPubSub* pubSub) { + WINPR_ASSERT(pubSub); + EnterCriticalSection(&pubSub->lock); } void PubSub_Unlock(wPubSub* pubSub) { + WINPR_ASSERT(pubSub); + LeaveCriticalSection(&pubSub->lock); } @@ -61,6 +69,9 @@ wEventType* PubSub_FindEventType(wPubSub* pubSub, const char* EventName) int index; wEventType* event = NULL; + if (!pubSub) + return event; + for (index = 0; index < pubSub->count; index++) { if (strcmp(pubSub->events[index].EventName, EventName) == 0) @@ -75,6 +86,8 @@ wEventType* PubSub_FindEventType(wPubSub* pubSub, const char* EventName) void PubSub_AddEventTypes(wPubSub* pubSub, wEventType* events, int count) { + WINPR_ASSERT(pubSub); + if (pubSub->synchronized) PubSub_Lock(pubSub); @@ -103,6 +116,9 @@ int PubSub_Subscribe(wPubSub* pubSub, const char* EventName, pEventHandler Event wEventType* event; int status = -1; + if (!pubSub) + return status; + if (pubSub->synchronized) PubSub_Lock(pubSub); @@ -130,6 +146,9 @@ int PubSub_Unsubscribe(wPubSub* pubSub, const char* EventName, pEventHandler Eve wEventType* event; int status = -1; + if (!pubSub) + return status; + if (pubSub->synchronized) PubSub_Lock(pubSub); @@ -164,6 +183,9 @@ int PubSub_OnEvent(wPubSub* pubSub, const char* EventName, void* context, wEvent wEventType* event; int status = -1; + if (!pubSub) + return status; + if (pubSub->synchronized) PubSub_Lock(pubSub); From 4fa53e67280716e536c164d234cb37b6d3eae334 Mon Sep 17 00:00:00 2001 From: Eric_Lee Date: Wed, 20 Aug 2025 16:28:14 +0800 Subject: [PATCH 465/496] fix: correct server port assignment logic --- server/proxy/pf_server.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/proxy/pf_server.c b/server/proxy/pf_server.c index bfeeb61363ca..2ef54184a55c 100644 --- a/server/proxy/pf_server.c +++ b/server/proxy/pf_server.c @@ -118,7 +118,7 @@ static BOOL pf_server_get_target_info(rdpContext* context, rdpSettings* settings return FALSE; } - settings->ServerPort = config->TargetPort > 0 ? 3389 : settings->ServerPort; + settings->ServerPort = config->TargetPort > 0 ? config->TargetPort : 3389; return TRUE; } From fadece9061d6310a9a07924eb26b407b21920d10 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Mon, 9 Feb 2026 13:18:51 +0100 Subject: [PATCH 466/496] [channels,rdpgfx] check available stream length --- channels/rdpgfx/client/rdpgfx_main.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/channels/rdpgfx/client/rdpgfx_main.c b/channels/rdpgfx/client/rdpgfx_main.c index ceb4c18c8db6..52e0e2a9e553 100644 --- a/channels/rdpgfx/client/rdpgfx_main.c +++ b/channels/rdpgfx/client/rdpgfx_main.c @@ -1065,7 +1065,9 @@ static UINT rdpgfx_recv_wire_to_surface_2_pdu(RDPGFX_CHANNEL_CALLBACK* callback, Stream_Read_UINT8(s, pdu.pixelFormat); /* pixelFormat (1 byte) */ Stream_Read_UINT32(s, pdu.bitmapDataLength); /* bitmapDataLength (4 bytes) */ pdu.bitmapData = Stream_Pointer(s); - Stream_Seek(s, pdu.bitmapDataLength); + if (!Stream_SafeSeek(s, pdu.bitmapDataLength)) + return ERROR_INVALID_DATA; + DEBUG_RDPGFX(gfx->log, "RecvWireToSurface2Pdu: surfaceId: %" PRIu16 " codecId: %s (0x%04" PRIX16 ") " "codecContextId: %" PRIu32 " pixelFormat: 0x%02" PRIX8 From a4a495a946087d316f814039da67821766dbc4f4 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Mon, 23 Feb 2026 09:11:46 +0100 Subject: [PATCH 467/496] [winpr,stream] backport parts of #12319 and follow ups --- .../libwinpr/utils/collections/MessageQueue.c | 81 +++++++++++----- winpr/libwinpr/utils/collections/Queue.c | 96 +++++++++++++------ winpr/libwinpr/utils/stream.c | 59 ++++++------ 3 files changed, 154 insertions(+), 82 deletions(-) diff --git a/winpr/libwinpr/utils/collections/MessageQueue.c b/winpr/libwinpr/utils/collections/MessageQueue.c index d787f8ff3645..9d1d5d3c1d51 100644 --- a/winpr/libwinpr/utils/collections/MessageQueue.c +++ b/winpr/libwinpr/utils/collections/MessageQueue.c @@ -67,38 +67,77 @@ BOOL MessageQueue_Wait(wMessageQueue* queue) return status; } -BOOL MessageQueue_Dispatch(wMessageQueue* queue, wMessage* message) +static BOOL MessageQueue_EnsureCapacity(wMessageQueue* queue, size_t count) { - BOOL ret = FALSE; - if (!queue || !message) - return FALSE; + const size_t increment = 128; + WINPR_ASSERT(queue); - EnterCriticalSection(&queue->lock); + const size_t required = queue->size + count; + // check for overflow + if ((required < queue->size) || (required < count) || + (required > (SIZE_MAX - increment) / sizeof(wMessage))) + return FALSE; - if (queue->size == queue->capacity) + if (required > queue->capacity) { - int old_capacity; - int new_capacity; - wMessage* new_arr; + const size_t old_capacity = queue->capacity; + const size_t new_capacity = required + increment; - old_capacity = queue->capacity; - new_capacity = queue->capacity * 2; - - new_arr = (wMessage*)realloc(queue->array, sizeof(wMessage) * new_capacity); + wMessage* new_arr = (wMessage*)realloc(queue->array, sizeof(wMessage) * new_capacity); if (!new_arr) - goto out; + return FALSE; queue->array = new_arr; queue->capacity = new_capacity; ZeroMemory(&(queue->array[old_capacity]), (new_capacity - old_capacity) * sizeof(wMessage)); - /* rearrange wrapped entries */ + /* rearrange wrapped entries: + * fill up the newly available space and move tail + * back by the amount of elements that have been moved to the newly + * allocated space. + */ if (queue->tail <= queue->head) { - CopyMemory(&(queue->array[old_capacity]), queue->array, queue->tail * sizeof(wMessage)); - queue->tail += old_capacity; + size_t tocopy = queue->tail; + size_t slots = new_capacity - old_capacity; + const size_t batch = (tocopy < slots) ? tocopy : slots; + CopyMemory(&(queue->array[old_capacity]), queue->array, batch * sizeof(wMessage)); + + /* Tail is decremented. if the whole thing is appended + * just move the existing tail by old_capacity */ + if (tocopy < slots) + { + ZeroMemory(queue->array, batch * sizeof(wMessage)); + queue->tail += old_capacity; + } + else + { + const size_t remain = queue->tail - batch; + const size_t movesize = remain * sizeof(wMessage); + memmove_s(queue->array, queue->tail * sizeof(wMessage), &queue->array[batch], + movesize); + + const size_t zerooffset = remain; + const size_t zerosize = (queue->tail - remain) * sizeof(wMessage); + ZeroMemory(&queue->array[zerooffset], zerosize); + queue->tail -= batch; + } } } + return TRUE; +} + +BOOL MessageQueue_Dispatch(wMessageQueue* queue, wMessage* message) +{ + BOOL ret = FALSE; + if (!queue || !message) + return FALSE; + + EnterCriticalSection(&queue->lock); + + if (!MessageQueue_EnsureCapacity(queue, 1)) + goto out; + CopyMemory(&(queue->array[queue->tail]), message, sizeof(wMessage)); message = &(queue->array[queue->tail]); @@ -200,14 +239,12 @@ wMessageQueue* MessageQueue_New(const wObject* callback) if (!queue) return NULL; - queue->capacity = 32; - queue->array = (wMessage*)calloc(queue->capacity, sizeof(wMessage)); - if (!queue->array) - goto error_array; - if (!InitializeCriticalSectionAndSpinCount(&queue->lock, 4000)) goto error_spinlock; + if (!MessageQueue_EnsureCapacity(queue, 32)) + goto error_event; + queue->event = CreateEvent(NULL, TRUE, FALSE, NULL); if (!queue->event) goto error_event; diff --git a/winpr/libwinpr/utils/collections/Queue.c b/winpr/libwinpr/utils/collections/Queue.c index 2e8abd6c2832..bb789b6589ac 100644 --- a/winpr/libwinpr/utils/collections/Queue.c +++ b/winpr/libwinpr/utils/collections/Queue.c @@ -137,43 +137,85 @@ BOOL Queue_Contains(wQueue* queue, void* obj) return found; } -/** - * Adds an object to the end of the Queue. - */ - -BOOL Queue_Enqueue(wQueue* queue, void* obj) +static BOOL Queue_EnsureCapacity(wQueue* queue, size_t count) { - BOOL ret = TRUE; + const size_t blocksize = 32ull; + WINPR_ASSERT(queue); - if (queue->synchronized) - EnterCriticalSection(&queue->lock); + if (queue->growthFactor > SIZE_MAX / blocksize) + return FALSE; + + const size_t increment = blocksize * queue->growthFactor; + if (queue->size > SIZE_MAX - count) + return FALSE; - if (queue->size == queue->capacity) + const size_t required = queue->size + count; + if (required > queue->capacity) { - int old_capacity; - int new_capacity; - void** newArray; - old_capacity = queue->capacity; - new_capacity = queue->capacity * queue->growthFactor; - newArray = (void**)realloc(queue->array, sizeof(void*) * new_capacity); + const size_t old_capacity = queue->capacity; + if (required > SIZE_MAX - increment) + return FALSE; + + const size_t new_capacity = required + increment - required % increment; + if (new_capacity > SIZE_MAX / sizeof(BYTE*)) + return FALSE; + + uintptr_t* newArray = (uintptr_t*)realloc(queue->array, sizeof(uintptr_t) * new_capacity); if (!newArray) - { - ret = FALSE; - goto out; - } + return FALSE; queue->capacity = new_capacity; queue->array = newArray; - ZeroMemory(&(queue->array[old_capacity]), (new_capacity - old_capacity) * sizeof(void*)); + ZeroMemory(&(queue->array[old_capacity]), + (new_capacity - old_capacity) * sizeof(uintptr_t)); /* rearrange wrapped entries */ if (queue->tail <= queue->head) { - CopyMemory(&(queue->array[old_capacity]), queue->array, queue->tail * sizeof(void*)); - queue->tail += old_capacity; + const size_t tocopy = queue->tail; + const size_t slots = new_capacity - old_capacity; + const size_t batch = (tocopy < slots) ? tocopy : slots; + + CopyMemory(&(queue->array[old_capacity]), queue->array, batch * sizeof(uintptr_t)); + + /* Tail is decremented. if the whole thing is appended + * just move the existing tail by old_capacity */ + if (tocopy < slots) + { + ZeroMemory(queue->array, batch * sizeof(uintptr_t)); + queue->tail += old_capacity; + } + else + { + const size_t remain = queue->tail - batch; + const size_t movesize = remain * sizeof(uintptr_t); + memmove_s(queue->array, queue->tail * sizeof(uintptr_t), &queue->array[batch], + movesize); + + const size_t zerooffset = remain; + const size_t zerosize = (queue->tail - remain) * sizeof(uintptr_t); + ZeroMemory(&queue->array[zerooffset], zerosize); + queue->tail -= batch; + } } } + return TRUE; +} + +/** + * Adds an object to the end of the Queue. + */ + +BOOL Queue_Enqueue(wQueue* queue, void* obj) +{ + BOOL ret = TRUE; + + if (queue->synchronized) + EnterCriticalSection(&queue->lock); + + if (!Queue_EnsureCapacity(queue, 1)) + goto out; queue->array[queue->tail] = obj; queue->tail = (queue->tail + 1) % queue->capacity; @@ -252,20 +294,18 @@ wQueue* Queue_New(BOOL synchronized, int capacity, int growthFactor) if (!queue) return NULL; - queue->capacity = 32; + size_t scapacity = 32; queue->growthFactor = 2; queue->synchronized = synchronized; if (capacity > 0) - queue->capacity = capacity; + scapacity = capacity; if (growthFactor > 0) queue->growthFactor = growthFactor; - queue->array = (void**)calloc(queue->capacity, sizeof(void*)); - - if (!queue->array) - goto out_free; + if (!Queue_EnsureCapacity(queue, scapacity)) + goto out_free_array; queue->event = CreateEvent(NULL, TRUE, FALSE, NULL); diff --git a/winpr/libwinpr/utils/stream.c b/winpr/libwinpr/utils/stream.c index cc119c771762..009559dbd82f 100644 --- a/winpr/libwinpr/utils/stream.c +++ b/winpr/libwinpr/utils/stream.c @@ -28,43 +28,38 @@ BOOL Stream_EnsureCapacity(wStream* s, size_t size) { - if (s->capacity < size) - { - size_t position; - size_t old_capacity; - size_t new_capacity; - BYTE* new_buf; - - old_capacity = s->capacity; - new_capacity = old_capacity; - - do - { - new_capacity *= 2; - } while (new_capacity < size); - - position = Stream_GetPosition(s); - - if (!s->isOwner) - { - new_buf = (BYTE*)malloc(new_capacity); - CopyMemory(new_buf, s->buffer, s->capacity); - s->isOwner = TRUE; - } - else - { - new_buf = (BYTE*)realloc(s->buffer, new_capacity); - } + WINPR_ASSERT(s); + if (s->capacity >= size) + return TRUE; + + const size_t increment = 128ull; + const size_t old_capacity = s->capacity; + const size_t new_capacity = size + increment - size % increment; + const size_t position = Stream_GetPosition(s); + BYTE* new_buf = NULL; + if (!s->isOwner) + { + new_buf = (BYTE*)malloc(new_capacity); if (!new_buf) return FALSE; - s->buffer = new_buf; - s->capacity = new_capacity; - s->length = new_capacity; - ZeroMemory(&s->buffer[old_capacity], s->capacity - old_capacity); - Stream_SetPosition(s, position); + CopyMemory(new_buf, s->buffer, s->capacity); + s->isOwner = TRUE; + } + else + { + new_buf = (BYTE*)realloc(s->buffer, new_capacity); + if (!new_buf) + return FALSE; } + + s->buffer = new_buf; + s->capacity = new_capacity; + s->length = new_capacity; + ZeroMemory(&s->buffer[old_capacity], s->capacity - old_capacity); + + Stream_SetPosition(s, position); return TRUE; } From 9b678b6d5a40ce01607d8c3b1b1416437c8416c4 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Mon, 23 Feb 2026 09:24:57 +0100 Subject: [PATCH 468/496] changelog & release 2.11.8 --- ChangeLog | 19 +++++++++++++++++++ client/Android/android_freerdp.c | 2 +- winpr/CMakeLists.txt | 2 +- 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/ChangeLog b/ChangeLog index a2209be5f71b..a7ab1ae20579 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,22 @@ +# 2026-02-25 Version 2.11.8 + +This release will be the last official one for the 2.x series of FreeRDP. +From this point on we will no longer maintain this branch and urge all to +upgrade to FreeRDP 3.x. + +Noteworthy changes: +* Backported #12319 bugfixes from 3.x +* Fix incompatible pointer type issues by @AlessandroBono (#10172) +* X11: fix pointer/integer type mismatch by @floppym (#10207) +* Warn backport by @akallabeth (#10456) +* [core] eliminate rdpRdp::instance by @akallabeth (#10782) +* X11 client: ignore grab related LeaveNotify events by @akallabeth (#10888) +* [winpr,pubsub] add NULL parameter checks by @akallabeth (#10898) +* fix: correct server port assignment logic by @LeeEirc (#11793) + +For a complete and detailed change log since the last release run: +git log 2.11.8...2.11.7 + # 2024-04-22 Version 2.11.7 Noteworthy changes: diff --git a/client/Android/android_freerdp.c b/client/Android/android_freerdp.c index e30a0f43bad7..406707dc7b09 100644 --- a/client/Android/android_freerdp.c +++ b/client/Android/android_freerdp.c @@ -57,7 +57,7 @@ #define TAG CLIENT_TAG("android") /* Defines the JNI version supported by this library. */ -#define FREERDP_JNI_VERSION "2.11.8-dev" +#define FREERDP_JNI_VERSION "2.11.8" static void android_OnChannelConnectedEventHandler(void* context, ChannelConnectedEventArgs* e) { diff --git a/winpr/CMakeLists.txt b/winpr/CMakeLists.txt index 77ff2330227a..03f458e1d92e 100644 --- a/winpr/CMakeLists.txt +++ b/winpr/CMakeLists.txt @@ -57,7 +57,7 @@ if (NOT WIN32) endif() # Soname versioning -set(RAW_VERSION_STRING "2.11.8-dev") +set(RAW_VERSION_STRING "2.11.8") if(EXISTS "${CMAKE_SOURCE_DIR}/.source_tag") file(READ ${CMAKE_SOURCE_DIR}/.source_tag RAW_VERSION_STRING) elseif(USE_VERSION_FROM_GIT_TAG) From d552b266d5bb3afd3e514ef0b16650877f24ac7f Mon Sep 17 00:00:00 2001 From: joshua2a <35690947+joshua2a@users.noreply.github.com> Date: Thu, 19 Mar 2026 08:40:44 +0100 Subject: [PATCH 469/496] Fix Queue.c to make stable-2.0 build --- winpr/libwinpr/utils/collections/Queue.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/winpr/libwinpr/utils/collections/Queue.c b/winpr/libwinpr/utils/collections/Queue.c index bb789b6589ac..57f5801a7928 100644 --- a/winpr/libwinpr/utils/collections/Queue.c +++ b/winpr/libwinpr/utils/collections/Queue.c @@ -160,7 +160,7 @@ static BOOL Queue_EnsureCapacity(wQueue* queue, size_t count) if (new_capacity > SIZE_MAX / sizeof(BYTE*)) return FALSE; - uintptr_t* newArray = (uintptr_t*)realloc(queue->array, sizeof(uintptr_t) * new_capacity); + void **newArray = (void**)realloc(queue->array, sizeof(void*) * new_capacity); if (!newArray) return FALSE; From a4f32b049bcf08ca3f158133c6860ef29a0db7ab Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Mon, 9 Mar 2026 08:11:19 +0100 Subject: [PATCH 470/496] [codec,nsc] limit copy area in nsc_process_message the rectangle decoded might not fit into the destination buffer. Limit width and height of the area to copy to the one fitting. (cherry picked from commit 83d9aedea278a74af3e490ff5eeb889c016dbb2b) --- libfreerdp/codec/nsc.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/libfreerdp/codec/nsc.c b/libfreerdp/codec/nsc.c index 5dd2646ea9e3..7cc1067dd83c 100644 --- a/libfreerdp/codec/nsc.c +++ b/libfreerdp/codec/nsc.c @@ -515,7 +515,15 @@ BOOL nsc_process_message(NSC_CONTEXT* context, UINT16 bpp, UINT32 width, UINT32 return FALSE; } - if (!freerdp_image_copy(pDstData, DstFormat, nDstStride, nXDst, nYDst, width, height, + UINT32 cwidth = width; + if (1ull * nXDst + width > nWidth) + cwidth = nWidth - nXDst; + + UINT32 cheight = height; + if (1ull * nYDst + height > nHeight) + cheight = nHeight - nYDst; + + if (!freerdp_image_copy(pDstData, DstFormat, nDstStride, nXDst, nYDst, cwidth, cheight, context->BitmapData, PIXEL_FORMAT_BGRA32, 0, 0, 0, NULL, flip)) return FALSE; From a63afe0f161764dd1af3b211e61bc135c0a3291f Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Sun, 15 Feb 2026 19:32:38 +0100 Subject: [PATCH 471/496] [codec,nsc] bounds checks and doxygen * Improve doxygen for nsc_process_message * Improve bounds checks for nsc_process_message (cherry picked from commit f4d74c33fd58e9e9e4e52d75b0d1255af8fa4b53) --- include/freerdp/codec/nsc.h | 21 +++++++++++++++++++++ libfreerdp/codec/nsc.c | 11 +++++++++-- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/include/freerdp/codec/nsc.h b/include/freerdp/codec/nsc.h index 6a1c35c40810..44ef209314c2 100644 --- a/include/freerdp/codec/nsc.h +++ b/include/freerdp/codec/nsc.h @@ -52,6 +52,27 @@ extern "C" FREERDP_API BOOL nsc_context_set_parameters(NSC_CONTEXT* context, NSC_PARAMETER what, UINT32 value); + /** @brief decode a NSC message + * + * @param context The context to work on + * @param bpp The bit depth of the data + * @param width The width in pixels of the NSC surface + * @param height The height in pixels of the NSC surface + * @param data The data to decode + * @param length The length of \ref data in bytes + * @param pDstData The destination buffer. Must be at least \n nDstStride * nHeight in size. + * @param DstFormat The color format of the destination + * @param nDstStride The number of bytes per destination buffer line. Must be larger than + * bytes(DstFormat) * nWidth or \0 (in which case it is set to former minimum bound) + * @param nXDst The X offset in the destination buffer in pixels + * @param nYDst The Y offset in the destination buffer in pixels + * @param nWidth The width of the destination buffer in pixels + * @param nHeight The height of the destination buffer in pixels + * @param flip Image flipping flags FREERDP_FLIP_NONE et al passed on to \ref + * freerdp_image_copy + * + * @return \b TRUE in case of success, \b FALSE for any error. Check WLog for details. + */ FREERDP_API BOOL nsc_process_message(NSC_CONTEXT* context, UINT16 bpp, UINT32 width, UINT32 height, const BYTE* data, UINT32 length, BYTE* pDstData, UINT32 DstFormat, UINT32 nDstStride, diff --git a/libfreerdp/codec/nsc.c b/libfreerdp/codec/nsc.c index 7cc1067dd83c..ed7ef083dae1 100644 --- a/libfreerdp/codec/nsc.c +++ b/libfreerdp/codec/nsc.c @@ -451,13 +451,20 @@ BOOL nsc_process_message(NSC_CONTEXT* context, UINT16 bpp, UINT32 width, UINT32 if (!context || !data || !pDstData) return FALSE; - s = Stream_New((BYTE*)data, length); + if (nXDst > nWidth) + return FALSE; + if (nYDst > nHeight) + return FALSE; + s = Stream_New((BYTE*)data, length); if (!s) return FALSE; + const UINT32 minStride = nWidth * GetBytesPerPixel(DstFormat); if (nDstStride == 0) - nDstStride = nWidth * GetBytesPerPixel(DstFormat); + nDstStride = minStride; + if (nDstStride < minStride) + return FALSE; switch (bpp) { From 7a2663b9f4d59075cd23cb1360917ec966ecfcc3 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Mon, 26 Jan 2026 11:07:25 +0100 Subject: [PATCH 472/496] [channels,urbdrc] cancel all usb transfers on channel close (cherry picked from commit 414f701464929c217f2509bcbd6d2c1f00f7ed73) --- channels/urbdrc/client/libusb/libusb_udevice.c | 1 + 1 file changed, 1 insertion(+) diff --git a/channels/urbdrc/client/libusb/libusb_udevice.c b/channels/urbdrc/client/libusb/libusb_udevice.c index ef87f195f380..38f76f5593dd 100644 --- a/channels/urbdrc/client/libusb/libusb_udevice.c +++ b/channels/urbdrc/client/libusb/libusb_udevice.c @@ -1116,6 +1116,7 @@ static void libusb_udev_mark_channel_closed(IUDEVICE* idev) const uint8_t devNr = idev->get_dev_number(idev); pdev->status |= URBDRC_DEVICE_CHANNEL_CLOSED; + pdev->iface.cancel_all_transfer_request(&pdev->iface); urbdrc->udevman->unregister_udevice(urbdrc->udevman, busNr, devNr); } } From c496a9ba8ed65c4f98239d472358c657ae147375 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Mon, 9 Feb 2026 15:50:19 +0100 Subject: [PATCH 473/496] [client,x11] fix xf_rail_window_common cleanup leave the appWindow for later cleanup. (cherry picked from commit b4f0f0a18fe53aa8d47d062f91471f4e9c5e0d51) --- client/X11/xf_rail.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/client/X11/xf_rail.c b/client/X11/xf_rail.c index 6995bdd3e4af..fdc2244e9f90 100644 --- a/client/X11/xf_rail.c +++ b/client/X11/xf_rail.c @@ -259,11 +259,10 @@ void xf_rail_paint(xfContext* xfc, INT32 uleft, INT32 utop, UINT32 uright, UINT3 static BOOL xf_rail_window_common(rdpContext* context, const WINDOW_ORDER_INFO* orderInfo, const WINDOW_STATE_ORDER* windowState) { - xfAppWindow* appWindow = NULL; xfContext* xfc = (xfContext*)context; UINT32 fieldFlags = orderInfo->fieldFlags; BOOL position_or_size_updated = FALSE; - appWindow = xf_rail_get_window(xfc, orderInfo->windowId); + xfAppWindow* appWindow = xf_rail_get_window(xfc, orderInfo->windowId); if (fieldFlags & WINDOW_ORDER_STATE_NEW) { @@ -308,10 +307,7 @@ static BOOL xf_rail_window_common(rdpContext* context, const WINDOW_ORDER_INFO* } if (!appWindow->title) - { - free(appWindow); return FALSE; - } xf_AppWindowInit(xfc, appWindow); } From 978e9dc6dab5464dbff687af4a19d9329eeab400 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Mon, 19 Jan 2026 20:11:24 +0100 Subject: [PATCH 474/496] [core,info] fix missing NULL check (cherry picked from commit 4d44e3c097656a8b9ec696353647b0888ca45860) --- libfreerdp/core/info.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/libfreerdp/core/info.c b/libfreerdp/core/info.c index 534f09989f59..a5ca5eb42260 100644 --- a/libfreerdp/core/info.c +++ b/libfreerdp/core/info.c @@ -1368,7 +1368,7 @@ static BOOL rdp_write_logon_info_v1(wStream* s, logon_info* info) return TRUE; } -static BOOL rdp_write_logon_info_v2(wStream* s, logon_info* info) +static BOOL rdp_write_logon_info_v2(wStream* s, const logon_info* info) { UINT32 Size = 2 + 4 + 4 + 4 + 4 + 558; size_t domainLen, usernameLen; @@ -1381,11 +1381,13 @@ static BOOL rdp_write_logon_info_v2(wStream* s, logon_info* info) Stream_Write_UINT16(s, SAVE_SESSION_PDU_VERSION_ONE); Stream_Write_UINT32(s, Size); Stream_Write_UINT32(s, info->sessionId); - domainLen = strlen(info->domain); + if (info->domain) + domainLen = strlen(info->domain); if (domainLen > UINT32_MAX) return FALSE; Stream_Write_UINT32(s, (UINT32)(domainLen + 1) * 2); - usernameLen = strlen(info->username); + if (info->username) + usernameLen = strlen(info->username); if (usernameLen > UINT32_MAX) return FALSE; Stream_Write_UINT32(s, (UINT32)(usernameLen + 1) * 2); @@ -1464,6 +1466,7 @@ BOOL rdp_send_save_session_info(rdpContext* context, UINT32 type, void* data) { wStream* s; BOOL status; + WINPR_ASSERT(context); rdpRdp* rdp = context->rdp; s = rdp_data_pdu_init(rdp); From b35d51d3dd248be16786cb91242cb62af268b516 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Thu, 23 Apr 2026 03:08:56 +0800 Subject: [PATCH 475/496] [client,X11] fix clipboard update Synchronize channel thread with RDP thread when accessing clipboard formats (cherry picked from commit 58409406afe7c2a8a71ed2dc8e22075be4f41c0c) --- client/X11/xf_cliprdr.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/client/X11/xf_cliprdr.c b/client/X11/xf_cliprdr.c index 37ed538e63c9..6c83fadaaf38 100644 --- a/client/X11/xf_cliprdr.c +++ b/client/X11/xf_cliprdr.c @@ -577,7 +577,13 @@ static BOOL xf_clipboard_changed(xfClipboard* clipboard, const CLIPRDR_FORMAT* f static void xf_clipboard_formats_free(xfClipboard* clipboard) { + WINPR_ASSERT(clipboard); + + /* Synchronize RDP/X11 thread with channel thread */ + xf_lock_x11(clipboard->xfc); xf_cliprdr_free_formats(clipboard->lastSentFormats, clipboard->lastSentNumFormats); + xf_unlock_x11(clipboard->xfc); + clipboard->lastSentFormats = NULL; clipboard->lastSentNumFormats = 0; } From 363de214f9131ce0eb27fe495bd6f75583cbc10b Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Tue, 3 Mar 2026 13:58:09 +0100 Subject: [PATCH 476/496] [core,orders] improve input validation check length before subtracting. Might underflow and be cought by the next check, but lets be strict. (cherry picked from commit a9e0abf2eac8c2e370fa155bf1abb9d044c0ca8a) --- libfreerdp/core/orders.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libfreerdp/core/orders.c b/libfreerdp/core/orders.c index d8bf58d92b9e..a616a22898f5 100644 --- a/libfreerdp/core/orders.c +++ b/libfreerdp/core/orders.c @@ -2144,6 +2144,8 @@ static CACHE_BITMAP_ORDER* update_read_cache_bitmap_order(rdpUpdate* update, wSt goto fail; Stream_Read(s, bitmapComprHdr, 8); /* bitmapComprHdr (8 bytes) */ + if (cache_bitmap->bitmapLength < 8) + goto fail; cache_bitmap->bitmapLength -= 8; } } From 4e8d48e7f0521c037cf347db911f93ee1d56b62f Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Mon, 16 Feb 2026 19:56:55 +0100 Subject: [PATCH 477/496] [codec,clear] fix destination checks check against the correct nDstWidth/nDstHeight (cherry picked from commit 7d8fdce2d0ef337cb86cb37fc0c436c905e04d77) --- libfreerdp/codec/clear.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/libfreerdp/codec/clear.c b/libfreerdp/codec/clear.c index e38fa0dcfbef..40976e5cd581 100644 --- a/libfreerdp/codec/clear.c +++ b/libfreerdp/codec/clear.c @@ -492,6 +492,18 @@ static BOOL clear_decompress_subcodecs_data(CLEAR_CONTEXT* clear, wStream* s, nXDstRel = nXDst + xStart; nYDstRel = nYDst + yStart; + if (1ull * nXDstRel + width > nDstWidth) + { + WLog_ERR(TAG, "nXDstRel %" PRIu32 " + width %" PRIu16 " > nDstWidth %" PRIu32 "", + nXDstRel, width, nDstWidth); + return FALSE; + } + if (1ull * nYDstRel + height > nDstHeight) + { + WLog_ERR(TAG, "nYDstRel %" PRIu32 " + height %" PRIu16 " > nDstHeight %" PRIu32 "", + nYDstRel, height, nDstHeight); + return FALSE; + } if (width > nWidth) { From bc0fda1cbd9880116fe822653e0cdc9feb291a67 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Mon, 16 Feb 2026 09:45:58 +0100 Subject: [PATCH 478/496] [codec,planar] fix missing destination bounds checks (cherry picked from commit a0be5cb87d760bb1c803ad1bb835aa1e73e62abc) --- libfreerdp/codec/planar.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/libfreerdp/codec/planar.c b/libfreerdp/codec/planar.c index fe27011e1a08..5af3d82b26e7 100644 --- a/libfreerdp/codec/planar.c +++ b/libfreerdp/codec/planar.c @@ -616,6 +616,11 @@ BOOL planar_decompress(BITMAP_PLANAR_CONTEXT* planar, const BYTE* pSrcData, UINT WINPR_ASSERT(planar); WINPR_ASSERT(prims); + if (planar->maxWidth < nSrcWidth) + return FALSE; + if (planar->maxHeight < nSrcHeight) + return FALSE; + if (nDstStep <= 0) nDstStep = nDstWidth * GetBytesPerPixel(DstFormat); @@ -826,6 +831,24 @@ BOOL planar_decompress(BITMAP_PLANAR_CONTEXT* planar, const BYTE* pSrcData, UINT } else /* RLE */ { + if (nYDst + nSrcHeight > nTotalHeight) + { + WLog_ERR(TAG, + "planar plane destination Y %" PRIu32 " + height %" PRIu32 + " exceeds totalHeight %" PRIu32, + nYDst, nSrcHeight, nTotalHeight); + return FALSE; + } + + if ((nXDst + nSrcWidth) * GetBytesPerPixel(DstFormat) > nDstStep) + { + WLog_ERR(TAG, + "planar plane destination (X %" PRIu32 " + width %" PRIu32 + ") * bpp %" PRIu32 " exceeds stride %" PRIu32, + nXDst, nSrcWidth, GetBytesPerPixel(DstFormat), nDstStep); + return FALSE; + } + status = planar_decompress_plane_rle(planes[0], rleSizes[0], pTempData, nTempStep, nXDst, nYDst, nSrcWidth, nSrcHeight, 2, vFlip); /* RedPlane */ From 4da3d3c3338777ce1b4a01b81033b030ac304b7d Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Sat, 28 Feb 2026 11:38:23 +0100 Subject: [PATCH 479/496] [codec,h264] validate rectangles before use (cherry picked from commit 6482b7a92fff3959582cef052d1967ad6bde3738) --- libfreerdp/codec/h264.c | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/libfreerdp/codec/h264.c b/libfreerdp/codec/h264.c index 3f1ddb34090f..7bc4a147cc00 100644 --- a/libfreerdp/codec/h264.c +++ b/libfreerdp/codec/h264.c @@ -165,6 +165,36 @@ static BOOL avc_yuv_to_rgb(H264_CONTEXT* h264, const RECTANGLE_16* regionRects, return TRUE; } +static BOOL isRectValid(UINT32 width, UINT32 height, const RECTANGLE_16* rect) +{ + WINPR_ASSERT(rect); + if (rect->left > width) + return FALSE; + if (rect->right > width) + return FALSE; + if (rect->left >= rect->right) + return FALSE; + if (rect->top > height) + return FALSE; + if (rect->bottom > height) + return FALSE; + if (rect->top >= rect->bottom) + return FALSE; + return TRUE; +} + +static BOOL areRectsValid(UINT32 width, UINT32 height, const RECTANGLE_16* rects, UINT32 count) +{ + WINPR_ASSERT(rects || (count == 0)); + for (size_t x = 0; x < count; x++) + { + const RECTANGLE_16* rect = &rects[x]; + if (!isRectValid(width, height, rect)) + return FALSE; + } + return TRUE; +} + INT32 avc420_decompress(H264_CONTEXT* h264, const BYTE* pSrcData, UINT32 SrcSize, BYTE* pDstData, DWORD DstFormat, UINT32 nDstStep, UINT32 nDstWidth, UINT32 nDstHeight, RECTANGLE_16* regionRects, UINT32 numRegionRects) @@ -174,6 +204,9 @@ INT32 avc420_decompress(H264_CONTEXT* h264, const BYTE* pSrcData, UINT32 SrcSize if (!h264) return -1001; + if (!areRectsValid(nDstWidth, nDstHeight, regionRects, numRegionRects)) + return -1013; + status = h264->subsystem->Decompress(h264, pSrcData, SrcSize); if (status == 0) @@ -414,6 +447,11 @@ INT32 avc444_decompress(H264_CONTEXT* h264, BYTE op, RECTANGLE_16* regionRects, if (!h264 || !regionRects || !pSrcData || !pDstData) return -1001; + if (!areRectsValid(nDstWidth, nDstHeight, regionRects, numRegionRects)) + return -1013; + if (!areRectsValid(nDstWidth, nDstHeight, auxRegionRects, numAuxRegionRect)) + return -1014; + switch (op) { case 0: /* YUV420 in stream 1 From b2345d0142bc741cb35894db06dddca2e4c19439 Mon Sep 17 00:00:00 2001 From: akallabeth Date: Mon, 26 Jan 2026 10:59:39 +0100 Subject: [PATCH 480/496] [channels,urbdrc] ensure InterfaceNumber is within range (cherry picked from commit 2d563a50be17c1b407ca448b1321378c0726dd31) --- channels/urbdrc/client/libusb/libusb_udevice.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/channels/urbdrc/client/libusb/libusb_udevice.c b/channels/urbdrc/client/libusb/libusb_udevice.c index 38f76f5593dd..5cc6726c8736 100644 --- a/channels/urbdrc/client/libusb/libusb_udevice.c +++ b/channels/urbdrc/client/libusb/libusb_udevice.c @@ -528,19 +528,19 @@ static int libusb_udev_select_interface(IUDEVICE* idev, BYTE InterfaceNumber, BY { int error = 0, diff = 0; UDEVICE* pdev = (UDEVICE*)idev; - URBDRC_PLUGIN* urbdrc; - MSUSB_CONFIG_DESCRIPTOR* MsConfig; - MSUSB_INTERFACE_DESCRIPTOR** MsInterfaces; if (!pdev || !pdev->urbdrc) return -1; - urbdrc = pdev->urbdrc; - MsConfig = pdev->MsConfig; + URBDRC_PLUGIN* urbdrc = pdev->urbdrc; + MSUSB_CONFIG_DESCRIPTOR* MsConfig = pdev->MsConfig; if (MsConfig) { - MsInterfaces = MsConfig->MsInterfaces; + if (InterfaceNumber >= MsConfig->NumInterfaces) + return -2; + + MSUSB_INTERFACE_DESCRIPTOR** MsInterfaces = MsConfig->MsInterfaces; if (MsInterfaces) { WLog_Print(urbdrc->log, WLOG_INFO, From 713a243a6088237c659682a18406db54e731fefd Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Thu, 23 Apr 2026 19:36:17 +0800 Subject: [PATCH 481/496] [codec,clear] Update CLEAR_GLYPH_ENTRY::count after alloc Ensure the value is always properly related to an existing buffer. (cherry picked from commit c49d1ad43b8c7b32794d0250f2623c2dccd7ef25) --- libfreerdp/codec/clear.c | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/libfreerdp/codec/clear.c b/libfreerdp/codec/clear.c index e38fa0dcfbef..a4b7e9baf3d1 100644 --- a/libfreerdp/codec/clear.c +++ b/libfreerdp/codec/clear.c @@ -979,23 +979,35 @@ static BOOL clear_decompress_glyph_data(CLEAR_CONTEXT* clear, wStream* s, UINT32 { const UINT32 bpp = GetBytesPerPixel(clear->format); CLEAR_GLYPH_ENTRY* glyphEntry = &(clear->GlyphCache[glyphIndex]); - glyphEntry->count = nWidth * nHeight; + const size_t count = 1ull * nWidth * nHeight; + const size_t hlimit = SIZE_MAX / ((nWidth > 0) ? nWidth : 1); + if ((nWidth == 0) || (nHeight == 0) || (hlimit < nHeight)) + { + WLog_ERR(TAG, + "CLEARCODEC_FLAG_GLYPH_INDEX: invalid dimensions nWidth=%" PRIu32 + " nHeight=%" PRIu32, + nWidth, nHeight); + return FALSE; + } - if (glyphEntry->count > glyphEntry->size) + if (count > glyphEntry->size) { - BYTE* tmp; - tmp = realloc(glyphEntry->pixels, 1ull * glyphEntry->count * bpp); + BYTE* tmp = realloc(glyphEntry->pixels, count * bpp); if (!tmp) { - WLog_ERR(TAG, "glyphEntry->pixels realloc %" PRIu32 " failed!", - glyphEntry->count * bpp); + WLog_ERR(TAG, "glyphEntry->pixels realloc %zu failed!", count * bpp); return FALSE; } + glyphEntry->count = (UINT32)count; glyphEntry->size = glyphEntry->count; glyphEntry->pixels = (UINT32*)tmp; } + else + { + glyphEntry->count = (UINT32)count; + } if (!glyphEntry->pixels) { From 9f6e61c006149ea49181c723fcbc70c0d021248f Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Wed, 25 Mar 2026 10:03:56 +0100 Subject: [PATCH 482/496] [codec,progressive] Fail progressive_rfx_quant_sub on invalid values (cherry picked from commit 78188ab479c8e6eb9ba2475b3732c76b4bbe5425) --- libfreerdp/codec/progressive.c | 42 ++++++++++++++++++++++++++++++---- 1 file changed, 38 insertions(+), 4 deletions(-) diff --git a/libfreerdp/codec/progressive.c b/libfreerdp/codec/progressive.c index 8894b35c8845..41e658c8fd66 100644 --- a/libfreerdp/codec/progressive.c +++ b/libfreerdp/codec/progressive.c @@ -155,20 +155,51 @@ static INLINE void progressive_rfx_quant_lsub(RFX_COMPONENT_CODEC_QUANT* q, int q->LL3 -= val; /* LL3 */ } -static INLINE void progressive_rfx_quant_sub(const RFX_COMPONENT_CODEC_QUANT* q1, +static INLINE BOOL progressive_rfx_quant_sub(const RFX_COMPONENT_CODEC_QUANT* q1, const RFX_COMPONENT_CODEC_QUANT* q2, RFX_COMPONENT_CODEC_QUANT* dst) { + if (q1->HH1 < q2->HL1) + return FALSE; dst->HL1 = q1->HL1 - q2->HL1; /* HL1 */ + + if (q1->LH1 < q2->LH1) + return FALSE; dst->LH1 = q1->LH1 - q2->LH1; /* LH1 */ + + if (q1->HH1 < q2->HH1) + return FALSE; dst->HH1 = q1->HH1 - q2->HH1; /* HH1 */ + + if (q1->HL2 < q2->HL2) + return FALSE; dst->HL2 = q1->HL2 - q2->HL2; /* HL2 */ + + if (q1->LH2 < q2->LH2) + return FALSE; dst->LH2 = q1->LH2 - q2->LH2; /* LH2 */ + + if (q1->HH2 < q2->HH2) + return FALSE; dst->HH2 = q1->HH2 - q2->HH2; /* HH2 */ + + if (q1->HL3 < q2->HL3) + return FALSE; dst->HL3 = q1->HL3 - q2->HL3; /* HL3 */ + + if (q1->LH3 < q2->LH3) + return FALSE; dst->LH3 = q1->LH3 - q2->LH3; /* LH3 */ + + if (q1->HH3 < q2->HH3) + return FALSE; dst->HH3 = q1->HH3 - q2->HH3; /* HH3 */ + + if (q1->LL3 < q2->LL3) + return FALSE; dst->LL3 = q1->LL3 - q2->LL3; /* LL3 */ + + return TRUE; } static INLINE BOOL progressive_rfx_quant_lcmp_less_equal(const RFX_COMPONENT_CODEC_QUANT* q, @@ -1433,9 +1464,12 @@ static INLINE int progressive_decompress_tile_upgrade(PROGRESSIVE_CONTEXT* progr progressive_rfx_quant_add(quantY, quantProgY, &yBitPos); progressive_rfx_quant_add(quantCb, quantProgCb, &cbBitPos); progressive_rfx_quant_add(quantCr, quantProgCr, &crBitPos); - progressive_rfx_quant_sub(&(tile->yBitPos), &yBitPos, &yNumBits); - progressive_rfx_quant_sub(&(tile->cbBitPos), &cbBitPos, &cbNumBits); - progressive_rfx_quant_sub(&(tile->crBitPos), &crBitPos, &crNumBits); + if (!progressive_rfx_quant_sub(&(tile->yBitPos), &yBitPos, &yNumBits)) + goto fail; + if (!progressive_rfx_quant_sub(&(tile->cbBitPos), &cbBitPos, &cbNumBits)) + goto fail; + if (!progressive_rfx_quant_sub(&(tile->crBitPos), &crBitPos, &crNumBits)) + goto fail; progressive_rfx_quant_add(quantY, quantProgY, &shiftY); progressive_rfx_quant_lsub(&shiftY, 1); /* -6 + 5 = -1 */ progressive_rfx_quant_add(quantCb, quantProgCb, &shiftCb); From 062d6e1cd743a8b198e3ce7bdacec77ff8a568ea Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Wed, 25 Mar 2026 09:04:43 +0100 Subject: [PATCH 483/496] [core,gateway] Check rpcconn_common_hdr_t::auth_length is valid Do sanity checks for rpcconn_common_hdr_t::auth_length read from network, abort if the value is out of range. (cherry picked from commit 4ac0b6467d371a1ad47c1f751c5b305e4c068adb) --- libfreerdp/core/gateway/rts.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libfreerdp/core/gateway/rts.c b/libfreerdp/core/gateway/rts.c index ccbe0becaddf..85e65b0de3c6 100644 --- a/libfreerdp/core/gateway/rts.c +++ b/libfreerdp/core/gateway/rts.c @@ -200,6 +200,8 @@ BOOL rts_read_common_pdu_header(wStream* s, rpcconn_common_hdr_t* header) if (header->frag_length < sizeof(rpcconn_common_hdr_t)) return FALSE; + if (header->auth_length > header->frag_length - 8ull) + return FALSE; left = Stream_GetRemainingLength(s); if (left < header->frag_length - sizeof(rpcconn_common_hdr_t)) From 85541cace657819aaf064f4c2797d82d4c4f9d03 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Tue, 10 Mar 2026 09:17:23 +0100 Subject: [PATCH 484/496] [codec,planar] add early length check to avoid oob read (cherry picked from commit cd27c8faca0eeb0d4309cc5837dfdf3c42eba4e7) --- libfreerdp/codec/planar.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libfreerdp/codec/planar.c b/libfreerdp/codec/planar.c index 5af3d82b26e7..c728dd8ea507 100644 --- a/libfreerdp/codec/planar.c +++ b/libfreerdp/codec/planar.c @@ -626,9 +626,9 @@ BOOL planar_decompress(BITMAP_PLANAR_CONTEXT* planar, const BYTE* pSrcData, UINT srcp = pSrcData; - if (!pSrcData) + if (!pSrcData || (SrcSize < 1)) { - WLog_ERR(TAG, "Invalid argument pSrcData=NULL"); + WLog_ERR(TAG, "Invalid argument pSrcData=%p [size=%" PRIu32 "]", pSrcData, SrcSize); return FALSE; } From d473cef5549e699709b511510f201d9ee4948230 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Wed, 25 Mar 2026 09:23:18 +0100 Subject: [PATCH 485/496] [codec,dsp] fix IMA ADPCM sample clamping (cherry picked from commit 9be3f03d94a50892fd58a9f7dee72b2313c69b47) --- libfreerdp/codec/dsp.c | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/libfreerdp/codec/dsp.c b/libfreerdp/codec/dsp.c index a18d044cd2b6..0de86027867b 100644 --- a/libfreerdp/codec/dsp.c +++ b/libfreerdp/codec/dsp.c @@ -292,6 +292,17 @@ static const INT16 ima_step_size_table[] = { 12635, 13899, 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767 }; +static inline void dsp_ima_clamp_step(ADPCM* adpcm, unsigned int channel) +{ + WINPR_ASSERT(adpcm); + if (adpcm->ima.last_step[channel] < 0) + adpcm->ima.last_step[channel] = 0; + + const size_t size = ARRAYSIZE(ima_step_size_table); + if (adpcm->ima.last_step[channel] > size) + adpcm->ima.last_step[channel] = size; +} + static UINT16 dsp_decode_ima_adpcm_sample(ADPCM* adpcm, unsigned int channel, BYTE sample) { INT32 ss; @@ -321,10 +332,7 @@ static UINT16 dsp_decode_ima_adpcm_sample(ADPCM* adpcm, unsigned int channel, BY adpcm->ima.last_sample[channel] = (INT16)d; adpcm->ima.last_step[channel] += ima_step_index_table[sample]; - if (adpcm->ima.last_step[channel] < 0) - adpcm->ima.last_step[channel] = 0; - else if (adpcm->ima.last_step[channel] > 88) - adpcm->ima.last_step[channel] = 88; + dsp_ima_clamp_step(adpcm, channel); return (UINT16)d; } @@ -353,6 +361,9 @@ static BOOL freerdp_dsp_decode_ima_adpcm(FREERDP_DSP_CONTEXT* context, const BYT context->adpcm.ima.last_sample[0] = (INT16)(((UINT16)(*src)) | (((UINT16)(*(src + 1))) << 8)); context->adpcm.ima.last_step[0] = (INT16)(*(src + 2)); + + dsp_ima_clamp_step(&context->adpcm, 0); + src += 4; size -= 4; out_size -= 16; @@ -362,6 +373,8 @@ static BOOL freerdp_dsp_decode_ima_adpcm(FREERDP_DSP_CONTEXT* context, const BYT context->adpcm.ima.last_sample[1] = (INT16)(((UINT16)(*src)) | (((UINT16)(*(src + 1))) << 8)); context->adpcm.ima.last_step[1] = (INT16)(*(src + 2)); + + dsp_ima_clamp_step(&context->adpcm, 1); src += 4; size -= 4; out_size -= 16; @@ -698,10 +711,7 @@ static BYTE dsp_encode_ima_adpcm_sample(ADPCM* adpcm, int channel, INT16 sample) adpcm->ima.last_sample[channel] = (INT16)diff; adpcm->ima.last_step[channel] += ima_step_index_table[enc]; - if (adpcm->ima.last_step[channel] < 0) - adpcm->ima.last_step[channel] = 0; - else if (adpcm->ima.last_step[channel] > 88) - adpcm->ima.last_step[channel] = 88; + dsp_ima_clamp_step(adpcm, channel); return enc; } From c3d85cb2c7a70e8a37d0af099bbfd6fcb63c259f Mon Sep 17 00:00:00 2001 From: akallabeth Date: Sun, 21 Apr 2024 13:56:13 +0200 Subject: [PATCH 486/496] [core,info] fix missing check in rdp_write_logon_info_v1 (cherry picked from commit 71e463e31b4d69f4022d36bfc814592f56600793) --- libfreerdp/core/info.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libfreerdp/core/info.c b/libfreerdp/core/info.c index a5ca5eb42260..2f1bf21b9cbb 100644 --- a/libfreerdp/core/info.c +++ b/libfreerdp/core/info.c @@ -1327,6 +1327,10 @@ static BOOL rdp_write_logon_info_v1(wStream* s, logon_info* info) return FALSE; /* domain */ + WINPR_ASSERT(info); + if (!info->domain || !info->username) + return FALSE; + ilen = ConvertToUnicode(CP_UTF8, 0, info->domain, -1, &wString, 0); if (ilen < 0) From 3adb5f9e96f3922335b17c9ef916d050ad42e43c Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Tue, 10 Mar 2026 09:57:16 +0100 Subject: [PATCH 487/496] [codec,dsp] add format checks To avoid issues with invalid audio format settings always check before use. (cherry picked from commit 03b48b3601d867afccac1cdc6081de7a275edce7) --- libfreerdp/codec/dsp.c | 83 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 83 insertions(+) diff --git a/libfreerdp/codec/dsp.c b/libfreerdp/codec/dsp.c index 0de86027867b..ea7fc61a1f06 100644 --- a/libfreerdp/codec/dsp.c +++ b/libfreerdp/codec/dsp.c @@ -337,6 +337,21 @@ static UINT16 dsp_decode_ima_adpcm_sample(ADPCM* adpcm, unsigned int channel, BY return (UINT16)d; } +static BOOL valid_ima_adpcm_format(const FREERDP_DSP_CONTEXT* context) +{ + if (!context) + return FALSE; + if (context->format.wFormatTag != WAVE_FORMAT_DVI_ADPCM) + return FALSE; + if (context->format.nBlockAlign <= 4ULL) + return FALSE; + if (context->format.nChannels < 1) + return FALSE; + if (context->format.wBitsPerSample == 0) + return FALSE; + return TRUE; +} + static BOOL freerdp_dsp_decode_ima_adpcm(FREERDP_DSP_CONTEXT* context, const BYTE* src, size_t size, wStream* out) { @@ -349,6 +364,9 @@ static BOOL freerdp_dsp_decode_ima_adpcm(FREERDP_DSP_CONTEXT* context, const BYT const UINT32 channels = context->format.nChannels; size_t i; + if (!valid_ima_adpcm_format(context)) + return FALSE; + if (!Stream_EnsureCapacity(out, out_size)) return FALSE; @@ -477,6 +495,21 @@ static BOOL freerdp_dsp_encode_gsm610(FREERDP_DSP_CONTEXT* context, const BYTE* #endif #if defined(WITH_LAME) +static BOOL valid_mp3_format(const FREERDP_DSP_CONTEXT* context) +{ + if (!context) + return FALSE; + if (context->format.wFormatTag != WAVE_FORMAT_MPEGLAYER3) + return FALSE; + if (context->format.nChannels < 1) + return FALSE; + if (context->format.wBitsPerSample == 0) + return FALSE; + if (context->format.nSamplesPerSec == 0) + return FALSE; + return TRUE; +} + static BOOL freerdp_dsp_decode_mp3(FREERDP_DSP_CONTEXT* context, const BYTE* src, size_t size, wStream* out) { @@ -488,6 +521,9 @@ static BOOL freerdp_dsp_decode_mp3(FREERDP_DSP_CONTEXT* context, const BYTE* src if (!context || !src || !out) return FALSE; + if (!valid_mp3_format(context)) + return FALSE; + buffer_size = 2 * context->format.nChannels * context->format.nSamplesPerSec; if (!Stream_EnsureCapacity(context->buffer, 2 * buffer_size)) @@ -522,6 +558,9 @@ static BOOL freerdp_dsp_encode_mp3(FREERDP_DSP_CONTEXT* context, const BYTE* src if (!context || !src || !out) return FALSE; + if (!valid_mp3_format(context)) + return FALSE; + samples_per_channel = size / context->format.nChannels / context->format.wBitsPerSample / 8; /* Ensure worst case buffer size for mp3 stream taken from LAME header */ @@ -728,6 +767,8 @@ static BOOL freerdp_dsp_encode_ima_adpcm(FREERDP_DSP_CONTEXT* context, const BYT size_t align; out_size = size / 2; + if (!valid_ima_adpcm_format(context)) + return FALSE; if (!Stream_EnsureRemainingCapacity(out, size)) return FALSE; @@ -823,11 +864,28 @@ static INLINE INT16 freerdp_dsp_decode_ms_adpcm_sample(ADPCM* adpcm, BYTE sample return (INT16)presample; } +static BOOL valid_ms_adpcm_format(const FREERDP_DSP_CONTEXT* context) +{ + if (!context) + return FALSE; + if (context->format.wFormatTag != WAVE_FORMAT_ADPCM) + return FALSE; + if (context->format.nBlockAlign <= 4ULL) + return FALSE; + if (context->format.nChannels < 1) + return FALSE; + if (context->format.wBitsPerSample == 0) + return FALSE; + return TRUE; +} + static BOOL freerdp_dsp_decode_ms_adpcm(FREERDP_DSP_CONTEXT* context, const BYTE* src, size_t size, wStream* out) { BYTE* dst; BYTE sample; + if (!valid_ms_adpcm_format(context)) + return FALSE; const size_t out_size = size * 4; const UINT32 channels = context->format.nChannels; const UINT32 block_size = context->format.nBlockAlign; @@ -959,6 +1017,9 @@ static BOOL freerdp_dsp_encode_ms_adpcm(FREERDP_DSP_CONTEXT* context, const BYTE const size_t step = 8 + ((context->format.nChannels > 1) ? 4 : 0); out_size = size / 2; + if (!valid_ms_adpcm_format(context)) + return FALSE; + if (!Stream_EnsureRemainingCapacity(out, size)) return FALSE; @@ -1318,6 +1379,28 @@ BOOL freerdp_dsp_context_reset(FREERDP_DSP_CONTEXT* context, const AUDIO_FORMAT* return FALSE; context->format = *targetFormat; + + switch (context->format.wFormatTag) + { +#if defined(WITH_LAME) + case WAVE_FORMAT_MPEGLAYER3: + if (!valid_mp3_format(context)) + return FALSE; + break; +#endif + case WAVE_FORMAT_ADPCM: + if (!valid_ms_adpcm_format(context)) + return FALSE; + break; + case WAVE_FORMAT_DVI_ADPCM: + if (!valid_ima_adpcm_format(context)) + return FALSE; + break; + default: + break; + } + + #if defined(WITH_FAAD2) context->faadSetup = FALSE; #endif From 46be2a60f65024d4419cbd80ca545d178ff18507 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Tue, 10 Mar 2026 10:21:40 +0100 Subject: [PATCH 488/496] [codec,dsp] fix array bounds checks * assert array indices where caller value is an internal constant * add missing length/bounds checks (cherry picked from commit 16df2300e1e3f5a51f68fb1626429e58b531b7c8) --- libfreerdp/codec/dsp.c | 90 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 82 insertions(+), 8 deletions(-) diff --git a/libfreerdp/codec/dsp.c b/libfreerdp/codec/dsp.c index 0de86027867b..bd4b1c9c6fc6 100644 --- a/libfreerdp/codec/dsp.c +++ b/libfreerdp/codec/dsp.c @@ -307,7 +307,16 @@ static UINT16 dsp_decode_ima_adpcm_sample(ADPCM* adpcm, unsigned int channel, BY { INT32 ss; INT32 d; - ss = ima_step_size_table[adpcm->ima.last_step[channel]]; + INT16 offset; + + WINPR_ASSERT(channel < ARRAYSIZE(adpcm->ima.last_step)); + WINPR_ASSERT(channel < ARRAYSIZE(adpcm->ima.last_sample)); + + offset = adpcm->ima.last_step[channel]; + WINPR_ASSERT(offset >= 0); + WINPR_ASSERT(offset < ARRAYSIZE(ima_step_size_table)); + + ss = ima_step_size_table[offset]; d = (ss >> 3); if (sample & 1) @@ -330,6 +339,7 @@ static UINT16 dsp_decode_ima_adpcm_sample(ADPCM* adpcm, unsigned int channel, BY d = 32767; adpcm->ima.last_sample[channel] = (INT16)d; + WINPR_ASSERT(sample < ARRAYSIZE(ima_step_index_table)); adpcm->ima.last_step[channel] += ima_step_index_table[sample]; dsp_ima_clamp_step(adpcm, channel); @@ -358,6 +368,9 @@ static BOOL freerdp_dsp_decode_ima_adpcm(FREERDP_DSP_CONTEXT* context, const BYT { if (size % block_size == 0) { + if (size < 4) + return FALSE; + context->adpcm.ima.last_sample[0] = (INT16)(((UINT16)(*src)) | (((UINT16)(*(src + 1))) << 8)); context->adpcm.ima.last_step[0] = (INT16)(*(src + 2)); @@ -370,6 +383,8 @@ static BOOL freerdp_dsp_decode_ima_adpcm(FREERDP_DSP_CONTEXT* context, const BYT if (channels > 1) { + if (size < 4) + return FALSE; context->adpcm.ima.last_sample[1] = (INT16)(((UINT16)(*src)) | (((UINT16)(*(src + 1))) << 8)); context->adpcm.ima.last_step[1] = (INT16)(*(src + 2)); @@ -383,6 +398,8 @@ static BOOL freerdp_dsp_decode_ima_adpcm(FREERDP_DSP_CONTEXT* context, const BYT if (channels > 1) { + if (size < 8) + return FALSE; for (i = 0; i < 8; i++) { channel = (i < 4 ? 0 : 1); @@ -402,6 +419,8 @@ static BOOL freerdp_dsp_decode_ima_adpcm(FREERDP_DSP_CONTEXT* context, const BYT } else { + if (size < 1) + return FALSE; sample = ((*src) & 0x0f); decoded = dsp_decode_ima_adpcm_sample(&context->adpcm, 0, sample); *dst++ = (decoded & 0xFF); @@ -663,7 +682,16 @@ static BYTE dsp_encode_ima_adpcm_sample(ADPCM* adpcm, int channel, INT16 sample) INT32 ss; BYTE enc; INT32 diff; - ss = ima_step_size_table[adpcm->ima.last_step[channel]]; + INT16 offset; + + WINPR_ASSERT(channel < ARRAYSIZE(adpcm->ima.last_step)); + WINPR_ASSERT(channel < ARRAYSIZE(adpcm->ima.last_sample)); + + offset = adpcm->ima.last_step[channel]; + WINPR_ASSERT(offset >= 0); + WINPR_ASSERT(offset < ARRAYSIZE(ima_step_size_table)); + + ss = ima_step_size_table[offset]; d = e = sample - adpcm->ima.last_sample[channel]; diff = ss >> 3; enc = 0; @@ -709,6 +737,7 @@ static BYTE dsp_encode_ima_adpcm_sample(ADPCM* adpcm, int channel, INT16 sample) diff = 32767; adpcm->ima.last_sample[channel] = (INT16)diff; + WINPR_ASSERT(enc < ARRAYSIZE(ima_step_index_table)); adpcm->ima.last_step[channel] += ima_step_index_table[enc]; dsp_ima_clamp_step(adpcm, channel); @@ -802,10 +831,29 @@ static INLINE INT16 freerdp_dsp_decode_ms_adpcm_sample(ADPCM* adpcm, BYTE sample { INT8 nibble; INT32 presample; + BYTE predictor; + INT32 coeff1; + INT32 coeff2; + INT32 tableval; + + WINPR_ASSERT(channel < ARRAYSIZE(adpcm->ms.sample1)); + WINPR_ASSERT(channel < ARRAYSIZE(adpcm->ms.sample2)); + WINPR_ASSERT(channel < ARRAYSIZE(adpcm->ms.delta)); + WINPR_ASSERT(channel < ARRAYSIZE(adpcm->ms.predictor)); + nibble = (sample & 0x08 ? (INT8)sample - 16 : (INT8)sample); - presample = ((adpcm->ms.sample1[channel] * ms_adpcm_coeffs1[adpcm->ms.predictor[channel]]) + - (adpcm->ms.sample2[channel] * ms_adpcm_coeffs2[adpcm->ms.predictor[channel]])) / - 256; + predictor = adpcm->ms.predictor[channel]; + + coeff1 = 0; + if (predictor < ARRAYSIZE(ms_adpcm_coeffs1)) + coeff1 = ms_adpcm_coeffs1[predictor]; + + coeff2 = 0; + if (predictor < ARRAYSIZE(ms_adpcm_coeffs2)) + coeff2 = ms_adpcm_coeffs2[predictor]; + + presample = + ((adpcm->ms.sample1[channel] * coeff1) + (adpcm->ms.sample2[channel] * coeff2)) / 256; presample += nibble * adpcm->ms.delta[channel]; if (presample > 32767) @@ -815,7 +863,12 @@ static INLINE INT16 freerdp_dsp_decode_ms_adpcm_sample(ADPCM* adpcm, BYTE sample adpcm->ms.sample2[channel] = adpcm->ms.sample1[channel]; adpcm->ms.sample1[channel] = presample; - adpcm->ms.delta[channel] = adpcm->ms.delta[channel] * ms_adpcm_adaptation_table[sample] / 256; + + tableval = 0; + if (sample < ARRAYSIZE(ms_adpcm_adaptation_table)) + tableval = ms_adpcm_adaptation_table[sample]; + + adpcm->ms.delta[channel] = adpcm->ms.delta[channel] * tableval / 256; if (adpcm->ms.delta[channel] < 16) adpcm->ms.delta[channel] = 16; @@ -843,6 +896,9 @@ static BOOL freerdp_dsp_decode_ms_adpcm(FREERDP_DSP_CONTEXT* context, const BYTE { if (channels > 1) { + if (size < 14) + return FALSE; + context->adpcm.ms.predictor[0] = *src++; context->adpcm.ms.predictor[1] = *src++; context->adpcm.ms.delta[0] = read_int16(src); @@ -869,6 +925,9 @@ static BOOL freerdp_dsp_decode_ms_adpcm(FREERDP_DSP_CONTEXT* context, const BYTE } else { + if (size < 7) + return FALSE; + context->adpcm.ms.predictor[0] = *src++; context->adpcm.ms.delta[0] = read_int16(src); src += 2; @@ -886,12 +945,16 @@ static BOOL freerdp_dsp_decode_ms_adpcm(FREERDP_DSP_CONTEXT* context, const BYTE if (channels > 1) { + if (size < 1) + return FALSE; sample = *src++; size--; write_int16(dst, freerdp_dsp_decode_ms_adpcm_sample(&context->adpcm, sample >> 4, 0)); dst += 2; write_int16(dst, freerdp_dsp_decode_ms_adpcm_sample(&context->adpcm, sample & 0x0F, 1)); dst += 2; + if (size < 1) + return FALSE; sample = *src++; size--; write_int16(dst, freerdp_dsp_decode_ms_adpcm_sample(&context->adpcm, sample >> 4, 0)); @@ -901,6 +964,8 @@ static BOOL freerdp_dsp_decode_ms_adpcm(FREERDP_DSP_CONTEXT* context, const BYTE } else { + if (size < 1) + return FALSE; sample = *src++; size--; write_int16(dst, freerdp_dsp_decode_ms_adpcm_sample(&context->adpcm, sample >> 4, 0)); @@ -918,6 +983,14 @@ static BYTE freerdp_dsp_encode_ms_adpcm_sample(ADPCM* adpcm, INT32 sample, int c { INT32 presample; INT32 errordelta; + size_t offset; + + WINPR_ASSERT(channel >= 0); + WINPR_ASSERT((size_t)channel < ARRAYSIZE(adpcm->ms.sample1)); + WINPR_ASSERT((size_t)channel < ARRAYSIZE(adpcm->ms.sample2)); + WINPR_ASSERT((size_t)channel < ARRAYSIZE(adpcm->ms.delta)); + WINPR_ASSERT((size_t)channel < ARRAYSIZE(adpcm->ms.predictor)); + presample = ((adpcm->ms.sample1[channel] * ms_adpcm_coeffs1[adpcm->ms.predictor[channel]]) + (adpcm->ms.sample2[channel] * ms_adpcm_coeffs2[adpcm->ms.predictor[channel]])) / 256; @@ -940,8 +1013,9 @@ static BYTE freerdp_dsp_encode_ms_adpcm_sample(ADPCM* adpcm, INT32 sample, int c adpcm->ms.sample2[channel] = adpcm->ms.sample1[channel]; adpcm->ms.sample1[channel] = presample; - adpcm->ms.delta[channel] = - adpcm->ms.delta[channel] * ms_adpcm_adaptation_table[(((BYTE)errordelta) & 0x0F)] / 256; + offset = (((BYTE)errordelta) & 0x0F); + WINPR_ASSERT(offset < ARRAYSIZE(ms_adpcm_adaptation_table)); + adpcm->ms.delta[channel] = adpcm->ms.delta[channel] * ms_adpcm_adaptation_table[offset] / 256; if (adpcm->ms.delta[channel] < 16) adpcm->ms.delta[channel] = 16; From dea45312c1aa9f2797696ad5f56a8809de1f03c3 Mon Sep 17 00:00:00 2001 From: vulgraph <216388001+vulgraph@users.noreply.github.com> Date: Fri, 1 May 2026 20:53:56 +0800 Subject: [PATCH 489/496] [channels,ainput] lock context when updating listener Backport of d9ca272dce7a776ab475e9b1a8e8c3d2968c8486 to stable-2.0. Adapted to stable-2.0 plugin layout (no GENERIC_DYNVC_PLUGIN base): - Lock initialization moved to DVCPluginEntry where the plugin is allocated; deletion added to ainput_plugin_terminated. - Callback type adjusted: AINPUT_CHANNEL_CALLBACK (vs upstream's GENERIC_CHANNEL_CALLBACK) accessed via ainput->listener_callback rather than ainput->base.listener_callback. - Variable declarations hoisted to start of function for stable-2.0 C89-compatible style. (cherry picked from commit d9ca272dce7a776ab475e9b1a8e8c3d2968c8486) --- channels/ainput/client/ainput_main.c | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/channels/ainput/client/ainput_main.c b/channels/ainput/client/ainput_main.c index d8eb8ec594b6..0f44b309213c 100644 --- a/channels/ainput/client/ainput_main.c +++ b/channels/ainput/client/ainput_main.c @@ -69,6 +69,7 @@ struct AINPUT_PLUGIN_ UINT32 MajorVersion; UINT32 MinorVersion; BOOL initialized; + CRITICAL_SECTION lock; }; /** @@ -113,6 +114,7 @@ static UINT ainput_send_input_event(AInputClientContext* context, UINT64 flags, AINPUT_CHANNEL_CALLBACK* callback; BYTE buffer[32] = { 0 }; UINT64 time; + UINT rc; wStream sbuffer = { 0 }; wStream* s = &sbuffer; @@ -132,8 +134,6 @@ static UINT ainput_send_input_event(AInputClientContext* context, UINT64 flags, ainput->MajorVersion, ainput->MinorVersion); return CHANNEL_RC_UNSUPPORTED_VERSION; } - callback = ainput->listener_callback->channel_callback; - WINPR_ASSERT(callback); { char buffer[128] = { 0 }; @@ -152,10 +152,15 @@ static UINT ainput_send_input_event(AInputClientContext* context, UINT64 flags, Stream_SealLength(s); /* ainput back what we have received. AINPUT does not have any message IDs. */ + EnterCriticalSection(&ainput->lock); + callback = ainput->listener_callback->channel_callback; + WINPR_ASSERT(callback); WINPR_ASSERT(callback->channel); WINPR_ASSERT(callback->channel->Write); - return callback->channel->Write(callback->channel, (ULONG)Stream_Length(s), Stream_Buffer(s), - NULL); + rc = callback->channel->Write(callback->channel, (ULONG)Stream_Length(s), Stream_Buffer(s), + NULL); + LeaveCriticalSection(&ainput->lock); + return rc; } /** @@ -167,8 +172,16 @@ static UINT ainput_on_close(IWTSVirtualChannelCallback* pChannelCallback) { AINPUT_CHANNEL_CALLBACK* callback = (AINPUT_CHANNEL_CALLBACK*)pChannelCallback; - free(callback); + if (callback) + { + AINPUT_PLUGIN* ainput = (AINPUT_PLUGIN*)callback->plugin; + WINPR_ASSERT(ainput); + /* Lock here to ensure that no ainput_send_input_event is in progress. */ + EnterCriticalSection(&ainput->lock); + free(callback); + LeaveCriticalSection(&ainput->lock); + } return CHANNEL_RC_OK; } @@ -263,6 +276,7 @@ static UINT ainput_plugin_terminated(IWTSPlugin* pPlugin) } if (ainput) { + DeleteCriticalSection(&ainput->lock); free(ainput->listener_callback); free(ainput->iface.pInterface); } @@ -304,6 +318,8 @@ UINT DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints) ainput->iface.Initialize = ainput_plugin_initialize; ainput->iface.Terminated = ainput_plugin_terminated; + InitializeCriticalSection(&ainput->lock); + context->handle = (void*)ainput; context->AInputSendInputEvent = ainput_send_input_event; ainput->iface.pInterface = (void*)context; From 75fb359eebf2c5248362c8259d932eeab5134e59 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Mon, 9 Feb 2026 13:39:28 +0100 Subject: [PATCH 490/496] [client,x11] stringfiy functions for RAILS --- client/X11/xf_rail.c | 68 ++++++++++++++++++++++++++++++++------------ 1 file changed, 50 insertions(+), 18 deletions(-) diff --git a/client/X11/xf_rail.c b/client/X11/xf_rail.c index fdc2244e9f90..c4f7173af502 100644 --- a/client/X11/xf_rail.c +++ b/client/X11/xf_rail.c @@ -33,22 +33,51 @@ #define TAG CLIENT_TAG("x11") -static const char* error_code_names[] = { "RAIL_EXEC_S_OK", - "RAIL_EXEC_E_HOOK_NOT_LOADED", - "RAIL_EXEC_E_DECODE_FAILED", - "RAIL_EXEC_E_NOT_IN_ALLOWLIST", - "RAIL_EXEC_E_FILE_NOT_FOUND", - "RAIL_EXEC_E_FAIL", - "RAIL_EXEC_E_SESSION_LOCKED" }; - -#ifdef WITH_DEBUG_RAIL -static const char* movetype_names[] = { - "(invalid)", "RAIL_WMSZ_LEFT", "RAIL_WMSZ_RIGHT", - "RAIL_WMSZ_TOP", "RAIL_WMSZ_TOPLEFT", "RAIL_WMSZ_TOPRIGHT", - "RAIL_WMSZ_BOTTOM", "RAIL_WMSZ_BOTTOMLEFT", "RAIL_WMSZ_BOTTOMRIGHT", - "RAIL_WMSZ_MOVE", "RAIL_WMSZ_KEYMOVE", "RAIL_WMSZ_KEYSIZE" -}; -#endif +static const char* error_code2str(UINT32 code) +{ +#define EVCASE(x) \ + case x: \ + return #x + switch (code) + { + EVCASE(RAIL_EXEC_S_OK); + EVCASE(RAIL_EXEC_E_HOOK_NOT_LOADED); + EVCASE(RAIL_EXEC_E_DECODE_FAILED); + EVCASE(RAIL_EXEC_E_NOT_IN_ALLOWLIST); + EVCASE(RAIL_EXEC_E_FILE_NOT_FOUND); + EVCASE(RAIL_EXEC_E_FAIL); + EVCASE(RAIL_EXEC_E_SESSION_LOCKED); + default: + return "RAIL_EXEC_E_UNKNOWN"; + } +#undef EVCASE +} + +static const char* movetype2str(UINT32 code) +{ +#define EVCASE(x) \ + case x: \ + return #x + + switch (code) + { + + EVCASE(RAIL_WMSZ_LEFT); + EVCASE(RAIL_WMSZ_RIGHT); + EVCASE(RAIL_WMSZ_TOP); + EVCASE(RAIL_WMSZ_TOPLEFT); + EVCASE(RAIL_WMSZ_TOPRIGHT); + EVCASE(RAIL_WMSZ_BOTTOM); + EVCASE(RAIL_WMSZ_BOTTOMLEFT); + EVCASE(RAIL_WMSZ_BOTTOMRIGHT); + EVCASE(RAIL_WMSZ_MOVE); + EVCASE(RAIL_WMSZ_KEYMOVE); + EVCASE(RAIL_WMSZ_KEYSIZE); + default: + return "RAIL_WMSZ_INVALID"; + } +#undef EVCASE +} struct xf_rail_icon { @@ -804,8 +833,9 @@ static UINT xf_rail_server_execute_result(RailClientContext* context, if (execResult->execResult != RAIL_EXEC_S_OK) { - WLog_ERR(TAG, "RAIL exec error: execResult=%s NtError=0x%X\n", - error_code_names[execResult->execResult], execResult->rawResult); + WLog_ERR(TAG, "RAIL exec error: execResult=%s [0x%08" PRIx32 "] NtError=0x%X\n", + error_code2str(execResult->execResult), execResult->execResult, + execResult->rawResult); freerdp_abort_connect(xfc->context.instance); } else @@ -936,6 +966,8 @@ static UINT xf_rail_server_local_move_size(RailClientContext* context, if (!appWindow) return ERROR_INTERNAL_ERROR; + WLog_DBG(TAG, "%s [0x%08" PRIx32 "]", + movetype2str(localMoveSize->moveSizeType), localMoveSize->moveSizeType); switch (localMoveSize->moveSizeType) { case RAIL_WMSZ_LEFT: From 62826906f848cc72cee07443e0f7f3f6b26c6c80 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Mon, 9 Feb 2026 17:52:37 +0100 Subject: [PATCH 491/496] [client,x11] lock cache when providing data (CVE-2026-25959) Backport of upstream commit d3e8b3b9365be96a4f11dda149d71b3287227d0a to stable-2.0. The stable-2.0 cliprdr cache is a pair of plain pointers (clipboard->data and clipboard->data_raw), not the upstream wHashTable introduced after the 2.x line. The same race exists, however: - xf_cliprdr_server_format_data_response runs on the cliprdr channel thread. It calls xf_cliprdr_clear_cached_data (free + NULL) and then re-populates clipboard->data / data_raw. - xf_cliprdr_process_selection_request runs on the X11 event thread and reads clipboard->data / data_raw, passing them to xf_cliprdr_provide_data -> XChangeProperty. If the channel thread's free races with the X11 thread's read, the X11 thread can hand a freed buffer to XChangeProperty (heap UAF). Mirror the upstream fix by introducing a CRITICAL_SECTION protecting the cache, and lock around every site that reads, writes, or frees clipboard->data / data_raw: * xf_cliprdr_process_selection_request - lock around the read + provide_data + (else branch) clear+request_data block. * xf_cliprdr_server_format_list - lock around the clear call. * xf_cliprdr_server_format_data_response - lock from the initial clear through provide_data, including the early-return on SrcSize == 0. Lock is initialized in xf_clipboard_new (with a clean-up in the error path) and destroyed in xf_clipboard_free. Source: https://github.com/FreeRDP/FreeRDP/commit/d3e8b3b9365be96a4f11dda149d71b3287227d0a --- client/X11/xf_cliprdr.c | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/client/X11/xf_cliprdr.c b/client/X11/xf_cliprdr.c index 6c83fadaaf38..513c79c2462c 100644 --- a/client/X11/xf_cliprdr.c +++ b/client/X11/xf_cliprdr.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include @@ -115,6 +116,14 @@ struct xf_clipboard /* last sent data */ CLIPRDR_FORMAT* lastSentFormats; UINT32 lastSentNumFormats; + + /* Lock protecting clipboard->data / data_raw cache against races + * between the X11 event thread (reader in + * xf_cliprdr_process_selection_request) and the cliprdr channel + * thread (writer in xf_cliprdr_server_format_data_response and + * xf_cliprdr_clear_cached_data). Backport of upstream commit + * d3e8b3b9365be96a4f11dda149d71b3287227d0a (CVE-2026-25959). */ + CRITICAL_SECTION lock; }; static UINT xf_cliprdr_send_client_format_list(xfClipboard* clipboard); @@ -1002,6 +1011,13 @@ static BOOL xf_cliprdr_process_selection_request(xfClipboard* clipboard, matchingFormat = (formatId == clipboard->data_format_id) && (formatName == clipboard->data_format_name); + /* Lock the cached data while we read/free it. The cliprdr + * channel thread may concurrently free and re-populate + * clipboard->data / clipboard->data_raw via + * xf_cliprdr_server_format_data_response, leading to a heap + * use-after-free passed to XChangeProperty (CVE-2026-25959). */ + EnterCriticalSection(&clipboard->lock); + if (matchingFormat && (clipboard->data != 0) && !rawTransfer) { /* Cached converted clipboard data available. Send it now */ @@ -1035,6 +1051,8 @@ static BOOL xf_cliprdr_process_selection_request(xfClipboard* clipboard, delayRespond = TRUE; xf_cliprdr_send_data_request(clipboard, formatId); } + + LeaveCriticalSection(&clipboard->lock); } } @@ -1360,7 +1378,9 @@ static UINT xf_cliprdr_server_format_list(CliprdrClientContext* context, xfContext* xfc = clipboard->xfc; UINT ret; xf_clipboard_formats_free(clipboard); + EnterCriticalSection(&clipboard->lock); xf_cliprdr_clear_cached_data(clipboard); + LeaveCriticalSection(&clipboard->lock); clipboard->data_format_id = -1; clipboard->data_format_name = NULL; @@ -1510,6 +1530,12 @@ xf_cliprdr_server_format_data_response(CliprdrClientContext* context, if (!clipboard->respond) return CHANNEL_RC_OK; + /* Hold the cache lock from the moment we drop the previous cached + * data through producing and consuming the new cached data, so the + * X11 event thread can never observe a freed pointer. Backport of + * upstream commit d3e8b3b9365be96a4f11dda149d71b3287227d0a + * (CVE-2026-25959). */ + EnterCriticalSection(&clipboard->lock); xf_cliprdr_clear_cached_data(clipboard); pDstData = NULL; DstSize = 0; @@ -1579,6 +1605,7 @@ xf_cliprdr_server_format_data_response(CliprdrClientContext* context, WLog_DBG(TAG, "skipping, empty data detected!"); free(clipboard->respond); clipboard->respond = NULL; + LeaveCriticalSection(&clipboard->lock); return CHANNEL_RC_OK; } @@ -1620,6 +1647,7 @@ xf_cliprdr_server_format_data_response(CliprdrClientContext* context, } xf_cliprdr_provide_data(clipboard, clipboard->respond, pDstData, DstSize); + LeaveCriticalSection(&clipboard->lock); { union { @@ -1795,6 +1823,13 @@ xfClipboard* xf_clipboard_new(xfContext* xfc, BOOL relieveFilenameRestriction) return NULL; } + if (!InitializeCriticalSectionAndSpinCount(&clipboard->lock, 4000)) + { + WLog_ERR(TAG, "failed to initialize clipboard cache lock"); + free(clipboard); + return NULL; + } + xfc->clipboard = clipboard; clipboard->xfc = xfc; channels = ((rdpContext*)xfc)->channels; @@ -1925,6 +1960,7 @@ xfClipboard* xf_clipboard_new(xfContext* xfc, BOOL relieveFilenameRestriction) free(clipboard->clientFormats[i].formatName); ClipboardDestroy(clipboard->system); + DeleteCriticalSection(&clipboard->lock); free(clipboard); return NULL; } @@ -1957,6 +1993,7 @@ void xf_clipboard_free(xfClipboard* clipboard) free(clipboard->data_raw); free(clipboard->respond); free(clipboard->incr_data); + DeleteCriticalSection(&clipboard->lock); free(clipboard); } From 13dd4912e28b7a699afc2b7ad24797f9702b75fc Mon Sep 17 00:00:00 2001 From: vulgraph Date: Sun, 3 May 2026 20:44:15 +0800 Subject: [PATCH 492/496] [channels,rdpsnd] terminate thread before free Backport of upstream commit 622bb7b4402491ca003f47472d0e478132673696 to the stable-2.0 branch. Addresses CVE-2026-24684. The original cleanup_internals() did not terminate the rdpsnd helper thread before releasing channel context memory, so any pending callback on that thread could observe freed audio_formats / pool state. This change extracts the existing terminate-and-free logic into rdpsnd_terminate_thread() and calls it at the start of cleanup_internals(). rdpsnd_virtual_channel_event_terminated() now uses the same helper, mirroring the upstream layout. Compiles cleanly on stable-2.0; no public API change. --- channels/rdpsnd/client/rdpsnd_main.c | 30 ++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/channels/rdpsnd/client/rdpsnd_main.c b/channels/rdpsnd/client/rdpsnd_main.c index 3de4cbc66bb0..9af5ead32f2c 100644 --- a/channels/rdpsnd/client/rdpsnd_main.c +++ b/channels/rdpsnd/client/rdpsnd_main.c @@ -1244,11 +1244,32 @@ static UINT rdpsnd_virtual_channel_event_connected(rdpsndPlugin* rdpsnd, LPVOID return CHANNEL_RC_NO_MEMORY; } +static void rdpsnd_terminate_thread(rdpsndPlugin* rdpsnd) +{ + if (!rdpsnd) + return; + + if (rdpsnd->queue) + MessageQueue_PostQuit(rdpsnd->queue, 0); + + if (rdpsnd->thread) + { + WaitForSingleObject(rdpsnd->thread, INFINITE); + CloseHandle(rdpsnd->thread); + } + + MessageQueue_Free(rdpsnd->queue); + rdpsnd->thread = NULL; + rdpsnd->queue = NULL; +} + static void cleanup_internals(rdpsndPlugin* rdpsnd) { if (!rdpsnd) return; + rdpsnd_terminate_thread(rdpsnd); + if (rdpsnd->pool) StreamPool_Return(rdpsnd->pool, rdpsnd->data_in); @@ -1396,14 +1417,7 @@ void rdpsnd_virtual_channel_event_terminated(rdpsndPlugin* rdpsnd) { if (rdpsnd) { - if (rdpsnd->queue) - MessageQueue_PostQuit(rdpsnd->queue, 0); - if (rdpsnd->thread) - { - WaitForSingleObject(rdpsnd->thread, INFINITE); - CloseHandle(rdpsnd->thread); - } - MessageQueue_Free(rdpsnd->queue); + rdpsnd_terminate_thread(rdpsnd); free_internals(rdpsnd); audio_formats_free(rdpsnd->fixed_format, 1); From 37dec34f8b2db84162f7834cb0c03ef9cdca4f1c Mon Sep 17 00:00:00 2001 From: vulgraph Date: Sun, 3 May 2026 20:48:47 +0800 Subject: [PATCH 493/496] [cache,bitmap] overallocate bitmap cache Backport of upstream commit ffad58fd2b329efd81a3239e9d7e3c927b8e503f to stable-2.0. Addresses CVE-2026-29775. Older RDP servers can send a cache index that is one past the configured BitmapCacheV2NumCells, causing an out-of-bounds write into bitmapCache->cells. Fix by overallocating one extra cell slot, matching the upstream remediation. stable-2.0 reads BitmapCacheV2NumCells through the settings struct directly rather than freerdp_settings_get_uint32(), so the cast and field access differ slightly from upstream while the security change (+1ull) is identical. --- libfreerdp/cache/bitmap.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libfreerdp/cache/bitmap.c b/libfreerdp/cache/bitmap.c index 0ce2599b3239..2fd324b6d5d6 100644 --- a/libfreerdp/cache/bitmap.c +++ b/libfreerdp/cache/bitmap.c @@ -281,8 +281,9 @@ rdpBitmapCache* bitmap_cache_new(rdpSettings* settings) bitmapCache->settings = settings; bitmapCache->update = ((freerdp*)settings->instance)->update; bitmapCache->context = bitmapCache->update->context; - bitmapCache->cells = - (BITMAP_V2_CELL*)calloc(settings->BitmapCacheV2NumCells, sizeof(BITMAP_V2_CELL)); + /* overallocate by 1. older RDP servers do send a off by 1 cache index. */ + bitmapCache->cells = (BITMAP_V2_CELL*)calloc( + (size_t)settings->BitmapCacheV2NumCells + 1ull, sizeof(BITMAP_V2_CELL)); if (!bitmapCache->cells) goto fail; From af7048d3f855be7275b20b3ef341c51a8fbbedf7 Mon Sep 17 00:00:00 2001 From: Ben Hillis Date: Tue, 19 May 2026 15:42:45 +0000 Subject: [PATCH 494/496] channels/server: port WSLg gfxredir support and AF_VSOCK listener MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Port the WSLg-specific server-side additions from microsoft/FreeRDP-mirror working branch (commit a0c6bcd2 by Hideyuki Nagase, originally based on FreeRDP 2.4.0) onto current upstream stable-2.0. Carries: * New server-side virtual channel: channels/gfxredir/ (graphics redirection PDUs consumed by microsoft/weston-mirror rdp-backend). * Public headers: include/freerdp/{channels,server}/gfxredir.h * include/freerdp/types.h: add RECTANGLE_32 (used by gfxredir). * config.h.in: add WITH_CHANNEL_GFXREDIR and the three CHANNEL_GFXREDIR / _CLIENT / _SERVER cmakedefines. * channels/server/channels.c: register gfxredir alongside the existing upstream-registered channels. * libfreerdp/core/listener.c: replace CreateFileDescriptorEvent with WSAEventSelect(FD_READ|FD_ACCEPT|FD_CLOSE) and treat AF_VSOCK peers as local (needed for WSLg's HV_SOCK transport between the Linux guest and mstsc on the Windows host). Deliberately NOT carried from a0c6bcd2: * channels/rdpapplist/ — added in a0c6bcd2 then removed in 81cfc08b (mirror PR #1); it now lives in microsoft/wslg.git/rdpapplist as an external project consumed by weston-rdp-backend. Skipping both commits avoids the net-null add/remove churn. * azure-pipelines.yml — stale Microsoft-internal CI from the original pipeline (real CI now lives in the wslg-build repo). Not wired up. * channels/rdpsnd/server/rdpsnd_main.c additions (use_dynamic_virtual_channel + ChannelIdAssigned callback) — upstream has incorporated this functionality verbatim since 2.4.0. * include/freerdp/server/rdpsnd.h additions — same: upstream now declares the field and callback type. * include/freerdp/rail.h additions — upstream now exposes the TS_RAIL_CLIENTSTATUS_* constants as a typedef enum (and also adds TS_RAIL_CLIENTSTATUS_SUPPRESS_ICON_ORDERS which Microsoft's old patch lacked). * libfreerdp/core/nego.c additions — purely two explanatory comments and whitespace; upstream's logic is identical. * include/freerdp/update.h offsetOrders field — upstream now exposes this as 'size_t offsetOrders' in the same struct; Microsoft's 'UINT16 offsetOrders' is redundant and would produce a duplicate- member compile error. The size_t type from upstream is the correct one for the Stream_GetLength/SetPosition consumers in libfreerdp/core/update.c. Also drops Microsoft's original WSACreateEvent();; double-semicolon typo and over-indented WSAEventSelect call while we are touching the hunk. Originally-from: a0c6bcd2c8a0a3a5b88b22d6c40d5d22aac4f1d0 "Minor fixes on FreeRDP" by Hideyuki Nagase (Microsoft, 2020-05-30) Co-authored-by: Hideyuki Nagase Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- channels/gfxredir/CMakeLists.txt | 23 + channels/gfxredir/ChannelOptions.cmake | 12 + channels/gfxredir/gfxredir_common.c | 60 ++ channels/gfxredir/gfxredir_common.h | 32 + channels/gfxredir/server/CMakeLists.txt | 32 + channels/gfxredir/server/gfxredir_main.c | 793 +++++++++++++++++++++++ channels/gfxredir/server/gfxredir_main.h | 37 ++ channels/server/channels.c | 8 + config.h.in | 5 + include/freerdp/channels/gfxredir.h | 183 ++++++ include/freerdp/server/gfxredir.h | 93 +++ include/freerdp/types.h | 9 + libfreerdp/core/listener.c | 7 +- 13 files changed, 1291 insertions(+), 3 deletions(-) create mode 100644 channels/gfxredir/CMakeLists.txt create mode 100644 channels/gfxredir/ChannelOptions.cmake create mode 100644 channels/gfxredir/gfxredir_common.c create mode 100644 channels/gfxredir/gfxredir_common.h create mode 100644 channels/gfxredir/server/CMakeLists.txt create mode 100644 channels/gfxredir/server/gfxredir_main.c create mode 100644 channels/gfxredir/server/gfxredir_main.h create mode 100644 include/freerdp/channels/gfxredir.h create mode 100644 include/freerdp/server/gfxredir.h diff --git a/channels/gfxredir/CMakeLists.txt b/channels/gfxredir/CMakeLists.txt new file mode 100644 index 000000000000..bfea7571cf16 --- /dev/null +++ b/channels/gfxredir/CMakeLists.txt @@ -0,0 +1,23 @@ +# FreeRDP: A Remote Desktop Protocol Implementation +# FreeRDP cmake build script +# +# Copyright 2020 Microsoft +# +# 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. + +if(WITH_CHANNEL_GFXREDIR) + define_channel("gfxredir") + if(WITH_SERVER_CHANNELS) + add_channel_server(${MODULE_PREFIX} ${CHANNEL_NAME}) + endif() +endif() diff --git a/channels/gfxredir/ChannelOptions.cmake b/channels/gfxredir/ChannelOptions.cmake new file mode 100644 index 000000000000..62cdceba6306 --- /dev/null +++ b/channels/gfxredir/ChannelOptions.cmake @@ -0,0 +1,12 @@ +if(WITH_CHANNEL_GFXREDIR) + set(OPTION_DEFAULT OFF) + set(OPTION_CLIENT_DEFAULT OFF) + set(OPTION_SERVER_DEFAULT ON) + + define_channel_options(NAME "gfxredir" TYPE "dynamic" + DESCRIPTION "Graphics Redirection Virtual Channel Extension" + SPECIFICATIONS "[MS-RDPXXXX]" + DEFAULT ${OPTION_DEFAULT}) + + define_channel_server_options(${OPTION_SERVER_DEFAULT}) +endif() diff --git a/channels/gfxredir/gfxredir_common.c b/channels/gfxredir/gfxredir_common.c new file mode 100644 index 000000000000..b8a298f14421 --- /dev/null +++ b/channels/gfxredir/gfxredir_common.c @@ -0,0 +1,60 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * RDPXXXX Remote App Graphics Redirection Virtual Channel Extension + * + * Copyright 2020 Microsoft + * + * 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include +#include +#include + +#define TAG CHANNELS_TAG("gfxredir.common") + +#include "gfxredir_common.h" + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +UINT gfxredir_read_header(wStream* s, GFXREDIR_HEADER* header) +{ + if (Stream_GetRemainingLength(s) < 8) + { + WLog_ERR(TAG, "header parsing failed: not enough data!"); + return ERROR_INVALID_DATA; + } + + Stream_Read_UINT32(s, header->cmdId); + Stream_Read_UINT32(s, header->length); + return CHANNEL_RC_OK; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +UINT gfxredir_write_header(wStream* s, const GFXREDIR_HEADER* header) +{ + Stream_Write_UINT32(s, header->cmdId); + Stream_Write_UINT32(s, header->length); + return CHANNEL_RC_OK; +} diff --git a/channels/gfxredir/gfxredir_common.h b/channels/gfxredir/gfxredir_common.h new file mode 100644 index 000000000000..18710a9ab2bd --- /dev/null +++ b/channels/gfxredir/gfxredir_common.h @@ -0,0 +1,32 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * RDPXXXX Remote App Graphics Redirection Virtual Channel Extension + * + * Copyright 2020 Microsoft + * + * 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_CHANNEL_GFXREDIR_COMMON_H +#define FREERDP_CHANNEL_GFXREDIR_COMMON_H + +#include +#include + +#include +#include + +FREERDP_LOCAL UINT gfxredir_read_header(wStream* s, GFXREDIR_HEADER* header); +FREERDP_LOCAL UINT gfxredir_write_header(wStream* s, const GFXREDIR_HEADER* header); + +#endif /* FREERDP_CHANNEL_GFXREDIR_COMMON_H */ diff --git a/channels/gfxredir/server/CMakeLists.txt b/channels/gfxredir/server/CMakeLists.txt new file mode 100644 index 000000000000..41cf225e6eb5 --- /dev/null +++ b/channels/gfxredir/server/CMakeLists.txt @@ -0,0 +1,32 @@ +# FreeRDP: A Remote Desktop Protocol Implementation +# FreeRDP cmake build script +# +# Copyright 2020 Microsoft +# +# 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. + +define_channel_server("gfxredir") + +set(${MODULE_PREFIX}_SRCS + gfxredir_main.c + gfxredir_main.h + ../gfxredir_common.c + ../gfxredir_common.h + ) + +include_directories(..) + +add_channel_server_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} FALSE "DVCPluginEntry") + +target_link_libraries(${MODULE_NAME} freerdp) +set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "Channels/${CHANNEL_NAME}/Server") diff --git a/channels/gfxredir/server/gfxredir_main.c b/channels/gfxredir/server/gfxredir_main.c new file mode 100644 index 000000000000..2379b1d98de2 --- /dev/null +++ b/channels/gfxredir/server/gfxredir_main.c @@ -0,0 +1,793 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * RDPXXXX Remote App Graphics Redirection Virtual Channel Extension + * + * Copyright 2020 Microsoft + * + * 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. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "gfxredir_main.h" +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include "../gfxredir_common.h" + +#define TAG CHANNELS_TAG("gfxredir.server") + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT gfxredir_recv_legacy_caps_pdu(wStream* s, GfxRedirServerContext* context) +{ + UINT32 error = CHANNEL_RC_OK; + GFXREDIR_LEGACY_CAPS_PDU pdu; + + if (Stream_GetRemainingLength(s) < 2) + { + WLog_ERR(TAG, "not enough data!"); + return ERROR_INVALID_DATA; + } + + Stream_Read_UINT16(s, pdu.version); /* version (2 bytes) */ + + if (context) + IFCALLRET(context->GraphicsRedirectionLegacyCaps, error, context, &pdu); + + return error; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT gfxredir_recv_caps_advertise_pdu(wStream* s, UINT32 length, GfxRedirServerContext* context) +{ + UINT32 error = CHANNEL_RC_OK; + GFXREDIR_CAPS_ADVERTISE_PDU pdu; + + if (Stream_GetRemainingLength(s) < length) + { + WLog_ERR(TAG, "not enough data!"); + return ERROR_INVALID_DATA; + } + + pdu.length = length; + Stream_GetPointer(s, pdu.caps); + Stream_Seek(s, length); + + if (!context->GraphicsRedirectionCapsAdvertise) + { + WLog_ERR(TAG, "server does not support CapsAdvertise PDU!"); + return ERROR_NOT_SUPPORTED; + } + else if (context) + { + IFCALLRET(context->GraphicsRedirectionCapsAdvertise, error, context, &pdu); + } + + return error; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT gfxredir_recv_present_buffer_ack_pdu(wStream* s, GfxRedirServerContext* context) +{ + UINT32 error = CHANNEL_RC_OK; + GFXREDIR_PRESENT_BUFFER_ACK_PDU pdu; + + if (Stream_GetRemainingLength(s) < 16) + { + WLog_ERR(TAG, "not enough data!"); + return ERROR_INVALID_DATA; + } + + Stream_Read_UINT64(s, pdu.windowId); /* windowId (8 bytes) */ + Stream_Read_UINT64(s, pdu.presentId); /* presentId (8 bytes) */ + + if (context) + { + IFCALLRET(context->PresentBufferAck, error, context, &pdu); + } + + return error; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT gfxredir_server_receive_pdu(GfxRedirServerContext* context, wStream* s) +{ + UINT error = CHANNEL_RC_OK; + size_t beg, end; + GFXREDIR_HEADER header; + beg = Stream_GetPosition(s); + + if ((error = gfxredir_read_header(s, &header))) + { + WLog_ERR(TAG, "gfxredir_read_header failed with error %" PRIu32 "!", error); + return error; + } + + switch (header.cmdId) + { + case GFXREDIR_CMDID_LEGACY_CAPS: + if ((error = gfxredir_recv_legacy_caps_pdu(s, context))) + WLog_ERR(TAG, + "gfxredir_recv_legacy_caps_pdu " + "failed with error %" PRIu32 "!", + error); + + break; + + case GFXREDIR_CMDID_CAPS_ADVERTISE: + if ((error = gfxredir_recv_caps_advertise_pdu(s, header.length - 8, context))) + WLog_ERR(TAG, + "gfxredir_recv_caps_advertise " + "failed with error %" PRIu32 "!", + error); + break; + + case GFXREDIR_CMDID_PRESENT_BUFFER_ACK: + if ((error = gfxredir_recv_present_buffer_ack_pdu(s, context))) + WLog_ERR(TAG, + "gfxredir_recv_present_buffer_ask_pdu " + "failed with error %" PRIu32 "!", + error); + break; + + default: + error = CHANNEL_RC_BAD_PROC; + WLog_WARN(TAG, "Received unknown PDU type: %" PRIu32 "", header.cmdId); + break; + } + + end = Stream_GetPosition(s); + + if (end != (beg + header.length)) + { + WLog_ERR(TAG, "Unexpected GFXREDIR pdu end: Actual: %d, Expected: %" PRIu32 "", end, + (beg + header.length)); + Stream_SetPosition(s, (beg + header.length)); + } + + return error; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT gfxredir_server_handle_messages(GfxRedirServerContext* context) +{ + DWORD BytesReturned; + void* buffer; + UINT ret = CHANNEL_RC_OK; + GfxRedirServerPrivate* priv = context->priv; + wStream* s = priv->input_stream; + + /* Check whether the dynamic channel is ready */ + if (!priv->isReady) + { + if (WTSVirtualChannelQuery(priv->gfxredir_channel, WTSVirtualChannelReady, &buffer, + &BytesReturned) == FALSE) + { + if (GetLastError() == ERROR_NO_DATA) + return ERROR_NO_DATA; + + WLog_ERR(TAG, "WTSVirtualChannelQuery failed"); + return ERROR_INTERNAL_ERROR; + } + + priv->isReady = *((BOOL*)buffer); + WTSFreeMemory(buffer); + } + + /* Consume channel event only after the dynamic channel is ready */ + if (priv->isReady) + { + Stream_SetPosition(s, 0); + + if (!WTSVirtualChannelRead(priv->gfxredir_channel, 0, NULL, 0, &BytesReturned)) + { + if (GetLastError() == ERROR_NO_DATA) + return ERROR_NO_DATA; + + WLog_ERR(TAG, "WTSVirtualChannelRead failed!"); + return ERROR_INTERNAL_ERROR; + } + + if (BytesReturned < 1) + return CHANNEL_RC_OK; + + if (!Stream_EnsureRemainingCapacity(s, BytesReturned)) + { + WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!"); + return CHANNEL_RC_NO_MEMORY; + } + + if (WTSVirtualChannelRead(priv->gfxredir_channel, 0, (PCHAR)Stream_Buffer(s), Stream_Capacity(s), + &BytesReturned) == FALSE) + { + WLog_ERR(TAG, "WTSVirtualChannelRead failed!"); + return ERROR_INTERNAL_ERROR; + } + + Stream_SetLength(s, BytesReturned); + Stream_SetPosition(s, 0); + + while (Stream_GetPosition(s) < Stream_Length(s)) + { + if ((ret = gfxredir_server_receive_pdu(context, s))) + { + WLog_ERR(TAG, + "gfxredir_server_receive_pdu " + "failed with error %" PRIu32 "!", + ret); + return ret; + } + } + } + + return ret; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static DWORD WINAPI gfxredir_server_thread_func(LPVOID arg) +{ + GfxRedirServerContext* context = (GfxRedirServerContext*)arg; + GfxRedirServerPrivate* priv = context->priv; + DWORD status; + DWORD nCount; + HANDLE events[8]; + UINT error = CHANNEL_RC_OK; + nCount = 0; + events[nCount++] = priv->stopEvent; + events[nCount++] = priv->channelEvent; + + while (TRUE) + { + status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE); + + if (status == WAIT_FAILED) + { + error = GetLastError(); + WLog_ERR(TAG, "WaitForMultipleObjects failed with error %" PRIu32 "", error); + break; + } + + /* Stop Event */ + if (status == WAIT_OBJECT_0) + break; + + if ((error = gfxredir_server_handle_messages(context))) + { + WLog_ERR(TAG, "gfxredir_server_handle_messages failed with error %" PRIu32 "", error); + break; + } + } + + ExitThread(error); + return error; +} + +/** + * Function description + * Create new stream for single gfxredir packet. The new stream length + * would be required data length + header. The header will be written + * to the stream before return. + * + * @param cmdId + * @param length - data length without header + * + * @return new stream + */ +static wStream* gfxredir_server_single_packet_new(UINT32 cmdId, UINT32 length) +{ + UINT error; + GFXREDIR_HEADER header; + wStream* s = Stream_New(NULL, GFXREDIR_HEADER_SIZE + length); + + if (!s) + { + WLog_ERR(TAG, "Stream_New failed!"); + goto error; + } + + header.cmdId = cmdId; + header.length = GFXREDIR_HEADER_SIZE + length; + + if ((error = gfxredir_write_header(s, &header))) + { + WLog_ERR(TAG, "Failed to write header with error %" PRIu32 "!", error); + goto error; + } + + return s; +error: + Stream_Free(s, TRUE); + return NULL; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT gfxredir_server_packet_send(GfxRedirServerContext* context, wStream* s) +{ + UINT ret; + ULONG written; + + if (!WTSVirtualChannelWrite(context->priv->gfxredir_channel, (PCHAR)Stream_Buffer(s), + Stream_GetPosition(s), &written)) + { + WLog_ERR(TAG, "WTSVirtualChannelWrite failed!"); + ret = ERROR_INTERNAL_ERROR; + goto out; + } + + if (written < Stream_GetPosition(s)) + { + WLog_WARN(TAG, "Unexpected bytes written: %" PRIu32 "/%" PRIuz "", written, + Stream_GetPosition(s)); + } + + ret = CHANNEL_RC_OK; +out: + Stream_Free(s, TRUE); + return ret; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT gfxredir_send_error(GfxRedirServerContext* context, const GFXREDIR_ERROR_PDU *error) +{ + wStream* s = gfxredir_server_single_packet_new(GFXREDIR_CMDID_ERROR, 4); + + if (!s) + { + WLog_ERR(TAG, "gfxredir_server_single_packet_new failed!"); + return CHANNEL_RC_NO_MEMORY; + } + + Stream_Write_UINT32(s, error->errorCode); + return gfxredir_server_packet_send(context, s); +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT gfxredir_send_caps_confirm(GfxRedirServerContext* context, const GFXREDIR_CAPS_CONFIRM_PDU *graphicsCapsConfirm) +{ + UINT ret; + wStream* s; + + if (graphicsCapsConfirm->length < GFXREDIR_CAPS_HEADER_SIZE) + { + WLog_ERR(TAG, "length must be greater than header size, failed!"); + return ERROR_INVALID_DATA; + } + + s = gfxredir_server_single_packet_new(GFXREDIR_CMDID_CAPS_CONFIRM, graphicsCapsConfirm->length); + + if (!s) + { + WLog_ERR(TAG, "gfxredir_server_single_packet_new failed!"); + return CHANNEL_RC_NO_MEMORY; + } + + Stream_Write_UINT32(s, GFXREDIR_CAPS_SIGNATURE); + Stream_Write_UINT32(s, graphicsCapsConfirm->version); + Stream_Write_UINT32(s, graphicsCapsConfirm->length); + if (graphicsCapsConfirm->length > GFXREDIR_CAPS_HEADER_SIZE) + Stream_Write(s, graphicsCapsConfirm->capsData, graphicsCapsConfirm->length - GFXREDIR_CAPS_HEADER_SIZE); + ret = gfxredir_server_packet_send(context, s); + if (ret == CHANNEL_RC_OK) + context->confirmedCapsVersion = graphicsCapsConfirm->version; + return ret; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT gfxredir_send_open_pool(GfxRedirServerContext* context, const GFXREDIR_OPEN_POOL_PDU *openPool) +{ + wStream* s; + + if (context->confirmedCapsVersion != GFXREDIR_CAPS_VERSION2_0) + { + WLog_ERR(TAG, "open_pool is called with invalid version!"); + return ERROR_INTERNAL_ERROR; + } + + if (openPool->sectionNameLength == 0 || openPool->sectionName == NULL) { + WLog_ERR(TAG, "section name must be provided!"); + return ERROR_INVALID_DATA; + } + + /* make sure null-terminate */ + if (openPool->sectionName[openPool->sectionNameLength-1] != 0) { + WLog_ERR(TAG, "section name must be terminated with NULL!"); + return ERROR_INVALID_DATA; + } + + s = gfxredir_server_single_packet_new(GFXREDIR_CMDID_OPEN_POOL, 20 + (openPool->sectionNameLength * 2)); + + if (!s) + { + WLog_ERR(TAG, "gfxredir_server_single_packet_new failed!"); + return CHANNEL_RC_NO_MEMORY; + } + + Stream_Write_UINT64(s, openPool->poolId); + Stream_Write_UINT64(s, openPool->poolSize); + Stream_Write_UINT32(s, openPool->sectionNameLength); + Stream_Write(s, openPool->sectionName, (openPool->sectionNameLength * 2)); + return gfxredir_server_packet_send(context, s); +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT gfxredir_send_close_pool(GfxRedirServerContext* context, const GFXREDIR_CLOSE_POOL_PDU *closePool) +{ + wStream* s; + + if (context->confirmedCapsVersion != GFXREDIR_CAPS_VERSION2_0) + { + WLog_ERR(TAG, "close_pool is called with invalid version!"); + return ERROR_INTERNAL_ERROR; + } + + s = gfxredir_server_single_packet_new(GFXREDIR_CMDID_CLOSE_POOL, 8); + + if (!s) + { + WLog_ERR(TAG, "gfxredir_server_single_packet_new failed!"); + return CHANNEL_RC_NO_MEMORY; + } + + Stream_Write_UINT64(s, closePool->poolId); + return gfxredir_server_packet_send(context, s); +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT gfxredir_send_create_buffer(GfxRedirServerContext* context, const GFXREDIR_CREATE_BUFFER_PDU *createBuffer) +{ + wStream* s; + + if (context->confirmedCapsVersion != GFXREDIR_CAPS_VERSION2_0) + { + WLog_ERR(TAG, "create_buffer is called with invalid version!"); + return ERROR_INTERNAL_ERROR; + } + + s = gfxredir_server_single_packet_new(GFXREDIR_CMDID_CREATE_BUFFER, 40); + + if (!s) + { + WLog_ERR(TAG, "gfxredir_server_single_packet_new failed!"); + return CHANNEL_RC_NO_MEMORY; + } + + Stream_Write_UINT64(s, createBuffer->poolId); + Stream_Write_UINT64(s, createBuffer->bufferId); + Stream_Write_UINT64(s, createBuffer->offset); + Stream_Write_UINT32(s, createBuffer->stride); + Stream_Write_UINT32(s, createBuffer->width); + Stream_Write_UINT32(s, createBuffer->height); + Stream_Write_UINT32(s, createBuffer->format); + return gfxredir_server_packet_send(context, s); +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT gfxredir_send_destroy_buffer(GfxRedirServerContext* context, const GFXREDIR_DESTROY_BUFFER_PDU *destroyBuffer) +{ + wStream* s; + + if (context->confirmedCapsVersion != GFXREDIR_CAPS_VERSION2_0) + { + WLog_ERR(TAG, "destroy_buffer is called with invalid version!"); + return ERROR_INTERNAL_ERROR; + } + + s = gfxredir_server_single_packet_new(GFXREDIR_CMDID_DESTROY_BUFFER, 8); + + if (!s) + { + WLog_ERR(TAG, "gfxredir_server_single_packet_new failed!"); + return CHANNEL_RC_NO_MEMORY; + } + + Stream_Write_UINT64(s, destroyBuffer->bufferId); + return gfxredir_server_packet_send(context, s); +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT gfxredir_send_present_buffer(GfxRedirServerContext* context, const GFXREDIR_PRESENT_BUFFER_PDU *presentBuffer) +{ + UINT32 length; + wStream* s; + RECTANGLE_32 dummyRect = {0, 0, 0, 0}; + + if (context->confirmedCapsVersion != GFXREDIR_CAPS_VERSION2_0) + { + WLog_ERR(TAG, "present_buffer is called with invalid version!"); + return ERROR_INTERNAL_ERROR; + } + + if (presentBuffer->numOpaqueRects > GFXREDIR_MAX_OPAQUE_RECTS) + { + WLog_ERR(TAG, "numOpaqueRects is larger than its limit!"); + return ERROR_INVALID_DATA; + } + + length = 64 + + ((presentBuffer->numOpaqueRects ? presentBuffer->numOpaqueRects : 1) * sizeof(RECTANGLE_32)); + + s = gfxredir_server_single_packet_new(GFXREDIR_CMDID_PRESENT_BUFFER, length); + + if (!s) + { + WLog_ERR(TAG, "gfxredir_server_single_packet_new failed!"); + return CHANNEL_RC_NO_MEMORY; + } + + Stream_Write_UINT64(s, presentBuffer->timestamp); + Stream_Write_UINT64(s, presentBuffer->presentId); + Stream_Write_UINT64(s, presentBuffer->windowId); + Stream_Write_UINT64(s, presentBuffer->bufferId); + Stream_Write_UINT32(s, presentBuffer->orientation); + Stream_Write_UINT32(s, presentBuffer->targetWidth); + Stream_Write_UINT32(s, presentBuffer->targetHeight); + Stream_Write_UINT32(s, presentBuffer->dirtyRect.left); + Stream_Write_UINT32(s, presentBuffer->dirtyRect.top); + Stream_Write_UINT32(s, presentBuffer->dirtyRect.width); + Stream_Write_UINT32(s, presentBuffer->dirtyRect.height); + Stream_Write_UINT32(s, presentBuffer->numOpaqueRects); + if (presentBuffer->numOpaqueRects) + Stream_Write(s, presentBuffer->opaqueRects, (presentBuffer->numOpaqueRects * sizeof(RECTANGLE_32))); + else + Stream_Write(s, &dummyRect, sizeof(RECTANGLE_32)); + return gfxredir_server_packet_send(context, s); +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT gfxredir_server_open(GfxRedirServerContext* context) +{ + UINT rc = ERROR_INTERNAL_ERROR; + GfxRedirServerPrivate* priv = context->priv; + DWORD BytesReturned = 0; + PULONG pSessionId = NULL; + void* buffer; + buffer = NULL; + priv->SessionId = WTS_CURRENT_SESSION; + + if (WTSQuerySessionInformationA(context->vcm, WTS_CURRENT_SESSION, WTSSessionId, + (LPSTR*)&pSessionId, &BytesReturned) == FALSE) + { + WLog_ERR(TAG, "WTSQuerySessionInformationA failed!"); + rc = ERROR_INTERNAL_ERROR; + goto out_close; + } + + priv->SessionId = (DWORD)*pSessionId; + WTSFreeMemory(pSessionId); + priv->gfxredir_channel = (HANDLE)WTSVirtualChannelOpenEx(priv->SessionId, GFXREDIR_DVC_CHANNEL_NAME, + WTS_CHANNEL_OPTION_DYNAMIC); + + if (!priv->gfxredir_channel) + { + WLog_ERR(TAG, "WTSVirtualChannelOpenEx failed!"); + rc = GetLastError(); + goto out_close; + } + + /* Query for channel event handle */ + if (!WTSVirtualChannelQuery(priv->gfxredir_channel, WTSVirtualEventHandle, &buffer, + &BytesReturned) || + (BytesReturned != sizeof(HANDLE))) + { + WLog_ERR(TAG, + "WTSVirtualChannelQuery failed " + "or invalid returned size(%" PRIu32 ")", + BytesReturned); + + if (buffer) + WTSFreeMemory(buffer); + + rc = ERROR_INTERNAL_ERROR; + goto out_close; + } + + CopyMemory(&priv->channelEvent, buffer, sizeof(HANDLE)); + WTSFreeMemory(buffer); + + if (priv->thread == NULL) + { + if (!(priv->stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL))) + { + WLog_ERR(TAG, "CreateEvent failed!"); + rc = ERROR_INTERNAL_ERROR; + } + + if (!(priv->thread = + CreateThread(NULL, 0, gfxredir_server_thread_func, (void*)context, 0, NULL))) + { + WLog_ERR(TAG, "CreateEvent failed!"); + CloseHandle(priv->stopEvent); + priv->stopEvent = NULL; + rc = ERROR_INTERNAL_ERROR; + } + } + + return CHANNEL_RC_OK; +out_close: + WTSVirtualChannelClose(priv->gfxredir_channel); + priv->gfxredir_channel = NULL; + priv->channelEvent = NULL; + return rc; +} + +/** + * Function description + * + * @return 0 on success, otherwise a Win32 error code + */ +static UINT gfxredir_server_close(GfxRedirServerContext* context) +{ + UINT error = CHANNEL_RC_OK; + GfxRedirServerPrivate* priv = context->priv; + + if (priv->thread) + { + SetEvent(priv->stopEvent); + + if (WaitForSingleObject(priv->thread, INFINITE) == WAIT_FAILED) + { + error = GetLastError(); + WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "", error); + return error; + } + + CloseHandle(priv->thread); + CloseHandle(priv->stopEvent); + priv->thread = NULL; + priv->stopEvent = NULL; + } + + if (priv->gfxredir_channel) + { + WTSVirtualChannelClose(priv->gfxredir_channel); + priv->gfxredir_channel = NULL; + } + + return error; +} + +GfxRedirServerContext* gfxredir_server_context_new(HANDLE vcm) +{ + GfxRedirServerContext* context; + GfxRedirServerPrivate* priv; + context = (GfxRedirServerContext*)calloc(1, sizeof(GfxRedirServerContext)); + + if (!context) + { + WLog_ERR(TAG, "gfxredir_server_context_new(): calloc GfxRedirServerContext failed!"); + return NULL; + } + + priv = context->priv = (GfxRedirServerPrivate*)calloc(1, sizeof(GfxRedirServerPrivate)); + + if (!context->priv) + { + WLog_ERR(TAG, "gfxredir_server_context_new(): calloc GfxRedirServerPrivate failed!"); + goto out_free; + } + + priv->input_stream = Stream_New(NULL, 4); + + if (!priv->input_stream) + { + WLog_ERR(TAG, "Stream_New failed!"); + goto out_free_priv; + } + + context->vcm = vcm; + context->Open = gfxredir_server_open; + context->Close = gfxredir_server_close; + context->Error = gfxredir_send_error; + context->GraphicsRedirectionCapsConfirm = gfxredir_send_caps_confirm; + context->OpenPool = gfxredir_send_open_pool; + context->ClosePool = gfxredir_send_close_pool; + context->CreateBuffer = gfxredir_send_create_buffer; + context->DestroyBuffer = gfxredir_send_destroy_buffer; + context->PresentBuffer = gfxredir_send_present_buffer; + context->confirmedCapsVersion = GFXREDIR_CAPS_VERSION1; + priv->isReady = FALSE; + return context; +out_free_priv: + free(context->priv); +out_free: + free(context); + return NULL; +} + +void gfxredir_server_context_free(GfxRedirServerContext* context) +{ + if (!context) + return; + + gfxredir_server_close(context); + + if (context->priv) + { + Stream_Free(context->priv->input_stream, TRUE); + free(context->priv); + } + + free(context); +} diff --git a/channels/gfxredir/server/gfxredir_main.h b/channels/gfxredir/server/gfxredir_main.h new file mode 100644 index 000000000000..e44e16a56b4e --- /dev/null +++ b/channels/gfxredir/server/gfxredir_main.h @@ -0,0 +1,37 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * RDPXXXX Remote App Graphics Redirection Virtual Channel Extension + * + * Copyright 2020 Microsoft + * + * 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_CHANNEL_GFXREDIR_SERVER_MAIN_H +#define FREERDP_CHANNEL_GFXREDIR_SERVER_MAIN_H + +#include + +struct _gfxredir_server_private +{ + BOOL isReady; + wStream* input_stream; + HANDLE channelEvent; + HANDLE thread; + HANDLE stopEvent; + DWORD SessionId; + + void* gfxredir_channel; +}; + +#endif /* FREERDP_CHANNEL_GFXREDIR_SERVER_MAIN_H */ diff --git a/channels/server/channels.c b/channels/server/channels.c index 2223ef82c48d..68641a6fc892 100644 --- a/channels/server/channels.c +++ b/channels/server/channels.c @@ -53,6 +53,7 @@ #include #include #include +#include #if defined(CHANNEL_RDPECAM_SERVER) #include @@ -84,6 +85,9 @@ void freerdp_channels_dummy(void) CamDevEnumServerContext* camera_enumerator; CameraDeviceServerContext* camera_device; #endif +#ifdef WITH_CHANNEL_GFXREDIR + GfxRedirServerContext* gfxredir; +#endif // WITH_CHANNEL_GFXREDIR audin = audin_server_context_new(NULL); audin_server_context_free(audin); rdpsnd = rdpsnd_server_context_new(NULL); @@ -124,6 +128,10 @@ void freerdp_channels_dummy(void) ainput_server_context_free(ainput); } #endif +#ifdef WITH_CHANNEL_GFXREDIR + gfxredir = gfxredir_server_context_new(NULL); + gfxredir_server_context_free(gfxredir); +#endif // WITH_CHANNEL_GFXREDIR } /** diff --git a/config.h.in b/config.h.in index 9644ab909899..2edd6ba37fd8 100644 --- a/config.h.in +++ b/config.h.in @@ -70,6 +70,8 @@ #cmakedefine WITH_VAAPI +#cmakedefine WITH_CHANNEL_GFXREDIR + /* Plugins */ #cmakedefine BUILTIN_CHANNELS #cmakedefine WITH_RDPDR @@ -99,6 +101,9 @@ #cmakedefine CHANNEL_ENCOMSP #cmakedefine CHANNEL_ENCOMSP_CLIENT #cmakedefine CHANNEL_ENCOMSP_SERVER +#cmakedefine CHANNEL_GFXREDIR +#cmakedefine CHANNEL_GFXREDIR_CLIENT +#cmakedefine CHANNEL_GFXREDIR_SERVER #cmakedefine CHANNEL_PARALLEL #cmakedefine CHANNEL_PARALLEL_CLIENT #cmakedefine CHANNEL_PARALLEL_SERVER diff --git a/include/freerdp/channels/gfxredir.h b/include/freerdp/channels/gfxredir.h new file mode 100644 index 000000000000..297911564c0b --- /dev/null +++ b/include/freerdp/channels/gfxredir.h @@ -0,0 +1,183 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * RDPXXXX Remote App Graphics Redirection Virtual Channel Extension + * + * Copyright 2020 Hideyuki Nagase + * + * 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_CHANNEL_GFXREDIR_H +#define FREERDP_CHANNEL_GFXREDIR_H + +#include +#include + +#define GFXREDIR_DVC_CHANNEL_NAME "Microsoft::Windows::RDS::RemoteAppGraphicsRedirection" + +/* GFXREDIR_LEGACY_CAPS_PDU.version */ +#define GFXREDIR_CHANNEL_VERSION_LEGACY 1 + +#define GFXREDIR_CHANNEL_VERSION_MAJOR 2 +#define GFXREDIR_CHANNEL_VERSION_MINOR 0 + +/* GFXREDIR_CAPS_VERSION1 */ +#define GFXREDIR_CMDID_LEGACY_CAPS 0x00000001 +#define GFXREDIR_CMDID_ERROR 0x00000006 +#define GFXREDIR_CMDID_CAPS_ADVERTISE 0x00000008 +#define GFXREDIR_CMDID_CAPS_CONFIRM 0x00000009 +/* GFXREDIR_CAPS_VERSION2_0 */ +#define GFXREDIR_CMDID_OPEN_POOL 0x0000000a +#define GFXREDIR_CMDID_CLOSE_POOL 0x0000000b +#define GFXREDIR_CMDID_CREATE_BUFFER 0x0000000c +#define GFXREDIR_CMDID_DESTROY_BUFFER 0x0000000d +#define GFXREDIR_CMDID_PRESENT_BUFFER 0x0000000e +#define GFXREDIR_CMDID_PRESENT_BUFFER_ACK 0x0000000f + +/* GFXREDIR_HEADER */ +#define GFXREDIR_HEADER_SIZE 8 + +/* GFXREDIR_CAPS_HEADER */ +#define GFXREDIR_CAPS_HEADER_SIZE 12 +/* GFXREDIR_CAPS_HEADER.signature */ +#define GFXREDIR_CAPS_SIGNATURE 0x53504143 /* = 'SPAC' */ +/* GFXREDIR_CAPS_HEADER.version */ +#define GFXREDIR_CAPS_VERSION1 0x1 +#define GFXREDIR_CAPS_VERSION2_0 0x2000 + +/* GFXREDIR_CREATE_BUFFER_PDU.format */ +#define GFXREDIR_BUFFER_PIXEL_FORMAT_XRGB_8888 1 +#define GFXREDIR_BUFFER_PIXEL_FORMAT_ARGB_8888 2 + +/* GFXREDIR_PRESENT_BUFFER_PDU.numOpaqueRects */ +#define GFXREDIR_MAX_OPAQUE_RECTS 0x10 + +struct _GFXREDIR_HEADER +{ + UINT32 cmdId; + UINT32 length; +}; + +typedef struct _GFXREDIR_HEADER GFXREDIR_HEADER; + +struct _GFXREDIR_LEGACY_CAPS_PDU +{ + UINT16 version; // GFXREDIR_CHANNEL_VERSION_LEGACY +}; + +typedef struct _GFXREDIR_LEGACY_CAPS_PDU GFXREDIR_LEGACY_CAPS_PDU; + +struct _GFXREDIR_CAPS_HEADER +{ + UINT32 signature; // GFXREDIR_CAPS_SIGNATURE + UINT32 version; // GFXREDIR_CAPS_VERSION + UINT32 length; // GFXREDIR_CAPS_HEADER_SIZE + size of capsData + const BYTE capsData[0]; // GFXREDIR_CAPS_HEADER.length - GFXREDIR_CAPS_HEADER_SIZE +}; + +typedef struct _GFXREDIR_CAPS_HEADER GFXREDIR_CAPS_HEADER; + +struct _GFXREDIR_CAPS_V2_0_PDU +{ + GFXREDIR_CAPS_HEADER header; + UINT32 supportedFeatures; /* Reserved for future extensions */ +}; + +typedef struct _GFXREDIR_CAPS_V2_0_PDU GFXREDIR_CAPS_V2_0_PDU; + +struct _GFXREDIR_ERROR_PDU +{ + UINT32 errorCode; +}; + +typedef struct _GFXREDIR_ERROR_PDU GFXREDIR_ERROR_PDU; + +struct _GFXREDIR_CAPS_ADVERTISE_PDU +{ + UINT32 length; // length of caps; + const BYTE *caps; // points variable length array of GFXREDIR_CAPS_HEADER. +}; + +typedef struct _GFXREDIR_CAPS_ADVERTISE_PDU GFXREDIR_CAPS_ADVERTISE_PDU; + +struct _GFXREDIR_CAPS_CONFIRM_PDU +{ + UINT32 version; // confirmed version, must be one of advertised by client. + UINT32 length; // GFXREDIR_CAPS_HEADER_SIZE + size of capsData. + const BYTE *capsData; // confirmed capsData from selected GFXREDIR_CAPS_HEADER.capsData. +}; + +typedef struct _GFXREDIR_CAPS_CONFIRM_PDU GFXREDIR_CAPS_CONFIRM_PDU; + +struct _GFXREDIR_OPEN_POOL_PDU +{ + UINT64 poolId; + UINT64 poolSize; + UINT32 sectionNameLength; // number of charactor, must include null terminated char. + const unsigned short *sectionName; // Windows-style 2 bytes wchar_t with null-terminated. +}; + +typedef struct _GFXREDIR_OPEN_POOL_PDU GFXREDIR_OPEN_POOL_PDU; + +struct _GFXREDIR_CLOSE_POOL_PDU +{ + UINT64 poolId; +}; + +typedef struct _GFXREDIR_CLOSE_POOL_PDU GFXREDIR_CLOSE_POOL_PDU; + +struct _GFXREDIR_CREATE_BUFFER_PDU +{ + UINT64 poolId; + UINT64 bufferId; + UINT64 offset; + UINT32 stride; + UINT32 width; + UINT32 height; + UINT32 format; // GFXREDIR_BUFFER_PIXEL_FORMAT_ +}; + +typedef struct _GFXREDIR_CREATE_BUFFER_PDU GFXREDIR_CREATE_BUFFER_PDU; + +struct _GFXREDIR_DESTROY_BUFFER_PDU +{ + UINT64 bufferId; +}; + +typedef struct _GFXREDIR_DESTROY_BUFFER_PDU GFXREDIR_DESTROY_BUFFER_PDU; + +struct _GFXREDIR_PRESENT_BUFFER_PDU +{ + UINT64 timestamp; + UINT64 presentId; + UINT64 windowId; + UINT64 bufferId; + UINT32 orientation; // 0, 90, 180 or 270. + UINT32 targetWidth; + UINT32 targetHeight; + RECTANGLE_32 dirtyRect; + UINT32 numOpaqueRects; + RECTANGLE_32* opaqueRects; +}; + +typedef struct _GFXREDIR_PRESENT_BUFFER_PDU GFXREDIR_PRESENT_BUFFER_PDU; + +struct _GFXREDIR_PRESENT_BUFFER_ACK_PDU +{ + UINT64 windowId; + UINT64 presentId; +}; + +typedef struct _GFXREDIR_PRESENT_BUFFER_ACK_PDU GFXREDIR_PRESENT_BUFFER_ACK_PDU; + +#endif /* FREERDP_CHANNEL_GFXREDIR_H */ diff --git a/include/freerdp/server/gfxredir.h b/include/freerdp/server/gfxredir.h new file mode 100644 index 000000000000..559008037589 --- /dev/null +++ b/include/freerdp/server/gfxredir.h @@ -0,0 +1,93 @@ +/** + * FreeRDP: A Remote Desktop Protocol Implementation + * RDPXXXX Remote App Graphics Redirection Virtual Channel Extension + * + * Copyright 2020 Microsoft + * + * 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_CHANNEL_GFXREDIR_SERVER_GFXREDIR_H +#define FREERDP_CHANNEL_GFXREDIR_SERVER_GFXREDIR_H + +#include + +#include +#include +#include + +typedef struct _gfxredir_server_private GfxRedirServerPrivate; +typedef struct _gfxredir_server_context GfxRedirServerContext; + +typedef UINT (*psGfxRedirOpen)(GfxRedirServerContext* context); +typedef UINT (*psGfxRedirClose)(GfxRedirServerContext* context); + +typedef UINT (*psGfxRedirError)(GfxRedirServerContext* context, const GFXREDIR_ERROR_PDU *error); + +typedef UINT (*psGfxRedirGraphicsRedirectionLegacyCaps)(GfxRedirServerContext* context, const GFXREDIR_LEGACY_CAPS_PDU *graphicsCaps); + +typedef UINT (*psGfxRedirGraphicsRedirectionCapsAdvertise)(GfxRedirServerContext* context, const GFXREDIR_CAPS_ADVERTISE_PDU *graphicsCapsAdvertise); +typedef UINT (*psGfxRedirGraphicsRedirectionCapsConfirm)(GfxRedirServerContext* context, const GFXREDIR_CAPS_CONFIRM_PDU *graphicsCapsConfirm); + +typedef UINT (*psGfxRedirOpenPool)(GfxRedirServerContext* context, const GFXREDIR_OPEN_POOL_PDU *openPool); +typedef UINT (*psGfxRedirClosePool)(GfxRedirServerContext* context, const GFXREDIR_CLOSE_POOL_PDU *closePool); + +typedef UINT (*psGfxRedirCreateBuffer)(GfxRedirServerContext* context, const GFXREDIR_CREATE_BUFFER_PDU *createBuffer); +typedef UINT (*psGfxRedirDestroyBuffer)(GfxRedirServerContext* context, const GFXREDIR_DESTROY_BUFFER_PDU *destroyBuffer); + +typedef UINT (*psGfxRedirPresentBuffer)(GfxRedirServerContext* context, const GFXREDIR_PRESENT_BUFFER_PDU *presentBuffer); +typedef UINT (*psGfxRedirPresentBufferAck)(GfxRedirServerContext* context, const GFXREDIR_PRESENT_BUFFER_ACK_PDU *presentBufferAck); + +struct _gfxredir_server_context +{ + void* custom; + HANDLE vcm; + + psGfxRedirOpen Open; + psGfxRedirClose Close; + + psGfxRedirError Error; + + psGfxRedirGraphicsRedirectionLegacyCaps GraphicsRedirectionLegacyCaps; + + psGfxRedirGraphicsRedirectionCapsAdvertise GraphicsRedirectionCapsAdvertise; + psGfxRedirGraphicsRedirectionCapsConfirm GraphicsRedirectionCapsConfirm; + + psGfxRedirOpenPool OpenPool; + psGfxRedirClosePool ClosePool; + + psGfxRedirCreateBuffer CreateBuffer; + psGfxRedirDestroyBuffer DestroyBuffer; + + psGfxRedirPresentBuffer PresentBuffer; + psGfxRedirPresentBufferAck PresentBufferAck; + + GfxRedirServerPrivate* priv; + rdpContext* rdpcontext; + + UINT32 confirmedCapsVersion; +}; + +#ifdef __cplusplus +extern "C" +{ +#endif + + FREERDP_API GfxRedirServerContext* gfxredir_server_context_new(HANDLE vcm); + FREERDP_API void gfxredir_server_context_free(GfxRedirServerContext* context); + +#ifdef __cplusplus +} +#endif + +#endif /* FREERDP_CHANNEL_GFXREDIR_SERVER_GFXREDIR_H */ diff --git a/include/freerdp/types.h b/include/freerdp/types.h index 165c1717e00b..32b4fbfd209f 100644 --- a/include/freerdp/types.h +++ b/include/freerdp/types.h @@ -74,6 +74,15 @@ struct _RECTANGLE_16 }; typedef struct _RECTANGLE_16 RECTANGLE_16; +struct _RECTANGLE_32 +{ + UINT32 left; + UINT32 top; + UINT32 width; + UINT32 height; +}; +typedef struct _RECTANGLE_32 RECTANGLE_32; + /* Plugin events */ #include diff --git a/libfreerdp/core/listener.c b/libfreerdp/core/listener.c index 3d0a1b164a4a..dadc73dd5932 100644 --- a/libfreerdp/core/listener.c +++ b/libfreerdp/core/listener.c @@ -224,12 +224,13 @@ static BOOL freerdp_listener_open_from_socket(freerdp_listener* instance, int fd return FALSE; listener->sockfds[listener->num_sockfds] = fd; - listener->events[listener->num_sockfds] = - CreateFileDescriptorEvent(NULL, FALSE, FALSE, fd, WINPR_FD_READ); + listener->events[listener->num_sockfds] = WSACreateEvent(); if (!listener->events[listener->num_sockfds]) return FALSE; + WSAEventSelect(fd, listener->events[listener->num_sockfds], FD_READ | FD_ACCEPT | FD_CLOSE); + listener->num_sockfds++; WLog_INFO(TAG, "Listening on socket %d.", fd); return TRUE; @@ -357,7 +358,7 @@ static BOOL freerdp_listener_check_fds(freerdp_listener* instance) } #ifndef _WIN32 - else if (peer_addr.ss_family == AF_UNIX) + else if (peer_addr.ss_family == AF_UNIX || peer_addr.ss_family == AF_VSOCK) client->local = TRUE; #endif From e7729b2b9b4ec3ab58f72d06bb5b7c97da9df4c3 Mon Sep 17 00:00:00 2001 From: Hideyuki Nagase Date: Tue, 22 Mar 2022 13:20:51 -0700 Subject: [PATCH 495/496] add Hebrew (Standard) keyboard layout ID (#3) Co-authored-by: Hideyuki Nagase (cherry picked from commit c574044a10003e50453acb4cf42801c5833fb572) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- include/freerdp/locale/keyboard.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/freerdp/locale/keyboard.h b/include/freerdp/locale/keyboard.h index ed2e6be6fcdf..a325afe66f02 100644 --- a/include/freerdp/locale/keyboard.h +++ b/include/freerdp/locale/keyboard.h @@ -171,6 +171,7 @@ typedef struct _RDP_KEYBOARD_LAYOUT RDP_KEYBOARD_LAYOUT; #define KBD_CZECH_PROGRAMMERS 0x00020405 #define KBD_GREEK_319 0x00020408 #define KBD_UNITED_STATES_INTERNATIONAL 0x00020409 +#define KBD_HEBREW_STANDARD 0x0002040D #define KBD_THAI_KEDMANEE_NON_SHIFTLOCK 0x0002041E #define KBD_SAMI_EXTENDED_FINLAND_SWEDEN 0x0002083B #define KBD_GREEK_220_LATIN 0x00030408 From 0eb5f289a78f8f13e79ba92c8909ce23a679fea2 Mon Sep 17 00:00:00 2001 From: "microsoft-github-policy-service[bot]" <77245923+microsoft-github-policy-service[bot]@users.noreply.github.com> Date: Fri, 2 Jun 2023 16:59:48 +0000 Subject: [PATCH 496/496] Microsoft mandatory file (cherry picked from commit 18d1e7aa48ceee6aace7549fd55cd10897fae21f) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- SECURITY.md | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 SECURITY.md diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 000000000000..e138ec5d6a77 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,41 @@ + + +## Security + +Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/). + +If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://aka.ms/opensource/security/definition), please report it to us as described below. + +## Reporting Security Issues + +**Please do not report security vulnerabilities through public GitHub issues.** + +Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://aka.ms/opensource/security/create-report). + +If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://aka.ms/opensource/security/pgpkey). + +You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://aka.ms/opensource/security/msrc). + +Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue: + + * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.) + * Full paths of source file(s) related to the manifestation of the issue + * The location of the affected source code (tag/branch/commit or direct URL) + * Any special configuration required to reproduce the issue + * Step-by-step instructions to reproduce the issue + * Proof-of-concept or exploit code (if possible) + * Impact of the issue, including how an attacker might exploit the issue + +This information will help us triage your report more quickly. + +If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://aka.ms/opensource/security/bounty) page for more details about our active programs. + +## Preferred Languages + +We prefer all communications to be in English. + +## Policy + +Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://aka.ms/opensource/security/cvd). + +