From 995fbfcdd708084446c78760337858e85131b9f2 Mon Sep 17 00:00:00 2001 From: Mike Gabriel Date: Mon, 25 Mar 2024 16:13:49 +0100 Subject: [PATCH] New upstream version 2.11.5+dfsg1 --- .clang-format | 1 - CMakeLists.txt | 2 +- ChangeLog | 33 ++- channels/rdpdr/client/rdpdr_capabilities.c | 156 +++++----- channels/rdpdr/client/rdpdr_main.c | 242 +++++++++++++--- channels/rdpdr/client/rdpdr_main.h | 27 +- channels/rdpdr/server/rdpdr_main.h | 7 - channels/rdpsnd/client/pulse/rdpsnd_pulse.c | 299 +++++++++++++++----- channels/rdpsnd/client/rdpsnd_main.c | 34 ++- client/common/cmdline.c | 3 + cmake/ConfigOptions.cmake | 24 +- include/freerdp/channels/rdpdr.h | 8 + libfreerdp/codec/dsp_ffmpeg.c | 24 +- libfreerdp/codec/planar.c | 8 +- libfreerdp/codec/progressive.c | 13 +- libfreerdp/crypto/crypto.c | 3 +- libfreerdp/locale/xkb_layout_ids.c | 2 +- winpr/CMakeLists.txt | 2 +- winpr/libwinpr/crt/CMakeLists.txt | 2 +- winpr/libwinpr/crt/unicode.c | 39 +++ winpr/libwinpr/crypto/cipher.c | 4 + 21 files changed, 698 insertions(+), 235 deletions(-) diff --git a/.clang-format b/.clang-format index 33a6584..6791025 100644 --- a/.clang-format +++ b/.clang-format @@ -104,7 +104,6 @@ ForEachMacros: ... Language: ObjC PointerBindsToType: false -ObjCSpaceAfterProperty: true SortIncludes: false ObjCBlockIndentWidth: 4 ObjCSpaceAfterProperty: false diff --git a/CMakeLists.txt b/CMakeLists.txt index 45affd5..e2eba2f 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.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/ChangeLog b/ChangeLog index 9405152..545d99b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,34 @@ +# 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) + +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) +* Use endian safe ICU string converter (#9631) +* Improve AAC support (#9577) +* 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: @@ -5,7 +36,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.2...2.11.1 # 2023-09-04 Version 2.11.1 diff --git a/channels/rdpdr/client/rdpdr_capabilities.c b/channels/rdpdr/client/rdpdr_capabilities.c index 7669766..0e6baf8 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,39 +50,59 @@ 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 */ -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)) + 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)) return ERROR_INVALID_DATA; - Stream_Read_UINT16(s, capabilityLength); - - if (capabilityLength < 4) - return ERROR_INVALID_DATA; - - if (!Stream_CheckAndLogRequiredLengthWLog(rdpdr->log, s, capabilityLength - 4U)) - 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; } @@ -92,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)) + if (!Stream_CheckAndLogRequiredLengthWLog(rdpdr->log, s, capabilityLength)) return ERROR_INVALID_DATA; - Stream_Read_UINT16(s, capabilityLength); - - if (capabilityLength < 4) - return ERROR_INVALID_DATA; - - if (!Stream_CheckAndLogRequiredLengthWLog(rdpdr->log, s, capabilityLength - 4U)) - return ERROR_INVALID_DATA; - - Stream_Seek(s, capabilityLength - 4U); + Stream_Seek(s, capabilityLength); return CHANNEL_RC_OK; } @@ -120,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)) + if (!Stream_CheckAndLogRequiredLengthWLog(rdpdr->log, s, capabilityLength)) return ERROR_INVALID_DATA; - Stream_Read_UINT16(s, capabilityLength); - - if (capabilityLength < 4U) - return ERROR_INVALID_DATA; - - if (!Stream_CheckAndLogRequiredLengthWLog(rdpdr->log, s, capabilityLength - 4U)) - return ERROR_INVALID_DATA; - - Stream_Seek(s, capabilityLength - 4U); + Stream_Seek(s, capabilityLength); return CHANNEL_RC_OK; } @@ -148,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)) + if (!Stream_CheckAndLogRequiredLengthWLog(rdpdr->log, s, capabilityLength)) return ERROR_INVALID_DATA; - Stream_Read_UINT16(s, capabilityLength); - - if (capabilityLength < 4) - return ERROR_INVALID_DATA; - - if (!Stream_CheckAndLogRequiredLengthWLog(rdpdr->log, s, capabilityLength - 4U)) - return ERROR_INVALID_DATA; - - Stream_Seek(s, capabilityLength - 4U); + Stream_Seek(s, capabilityLength); return CHANNEL_RC_OK; } @@ -176,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)) + if (!Stream_CheckAndLogRequiredLengthWLog(rdpdr->log, s, capabilityLength)) return ERROR_INVALID_DATA; - Stream_Read_UINT16(s, capabilityLength); - - if (capabilityLength < 4) - return ERROR_INVALID_DATA; - - if (!Stream_CheckAndLogRequiredLengthWLog(rdpdr->log, s, capabilityLength - 4U)) - return ERROR_INVALID_DATA; - - Stream_Seek(s, capabilityLength - 4U); + Stream_Seek(s, capabilityLength); return CHANNEL_RC_OK; } @@ -201,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; @@ -217,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 adaaf1d..a9ac6ec 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) @@ -106,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); @@ -133,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) @@ -1115,10 +1217,19 @@ 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++; + + 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; } @@ -1145,8 +1256,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); } @@ -1209,10 +1320,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) @@ -1241,15 +1352,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); @@ -1278,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->versionMinor == 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)); @@ -1444,6 +1547,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 +1569,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 +1632,30 @@ 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, 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_CLIENT_CAPS, - RDPDR_CHANNEL_STATE_CLIENTID_CONFIRM); - case PAKID_CORE_USER_LOGGEDON: - return rdpdr_state_check(rdpdr, packetid, RDPDR_CHANNEL_STATE_READY, + 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; + + 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 +1736,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 +1750,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; @@ -2035,6 +2186,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) @@ -2043,7 +2198,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 37ffb5f..37766f1 100644 --- a/channels/rdpdr/client/rdpdr_main.h +++ b/channels/rdpdr/client/rdpdr_main.h @@ -77,12 +77,33 @@ 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; + BOOL userLoggedOn; /* hotplug support */ HANDLE hotplugThread; diff --git a/channels/rdpdr/server/rdpdr_main.h b/channels/rdpdr/server/rdpdr_main.h index f3f54cc..c1ec534 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/channels/rdpsnd/client/pulse/rdpsnd_pulse.c b/channels/rdpsnd/client/pulse/rdpsnd_pulse.c index 7a95470..2fd4d7d 100644 --- a/channels/rdpsnd/client/pulse/rdpsnd_pulse.c +++ b/channels/rdpsnd/client/pulse/rdpsnd_pulse.c @@ -23,11 +23,15 @@ #include "config.h" #endif +#include + #include #include #include +#include #include +#include #include #include @@ -51,8 +55,39 @@ 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) +{ + 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 +100,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 +133,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) @@ -106,6 +146,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; @@ -117,21 +165,17 @@ 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; - if (!pulse->context) + 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; @@ -157,27 +201,35 @@ 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) { 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 +245,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) @@ -203,6 +260,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; @@ -214,6 +273,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 +285,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 +306,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)) @@ -281,30 +352,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) +{ + rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*)device; + + pulse->context = pa_context_new(pa_threaded_mainloop_get_api(pulse->mainloop), "freerdp"); + + if (!pulse->context) + return FALSE; + + pa_context_set_state_callback(pulse->context, rdpsnd_pulse_context_state_callback, pulse); + + if (!rdpsnd_pulse_connect((rdpsndDevicePlugin*)pulse)) + return FALSE; + + 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]; + char ss[PA_SAMPLE_SPEC_SNPRINT_MAX] = { 0 }; rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*)device; - if (!pulse->context || pulse->stream) - return TRUE; - - if (!rdpsnd_pulse_set_format_spec(pulse, format)) - return FALSE; - - pulse->latency = latency; - 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) @@ -320,19 +413,22 @@ 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_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; } 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 (;;) @@ -359,6 +455,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; @@ -369,9 +483,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 +506,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 +528,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,39 +555,51 @@ 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); 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; } +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); @@ -483,28 +611,38 @@ 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; rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*)device; - if (!pulse->stream || !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) { - 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) { @@ -522,22 +660,24 @@ 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; 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; + + WINPR_ASSERT(pulse); + WINPR_ASSERT(args); + status = CommandLineParseArgumentsA(args->argc, args->argv, rdpsnd_pulse_args, flags, pulse, NULL, NULL); @@ -558,6 +698,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); @@ -570,16 +719,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) @@ -605,6 +752,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(); @@ -612,15 +761,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); diff --git a/channels/rdpsnd/client/rdpsnd_main.c b/channels/rdpsnd/client/rdpsnd_main.c index f624058..3de4cbc 100644 --- a/channels/rdpsnd/client/rdpsnd_main.c +++ b/channels/rdpsnd/client/rdpsnd_main.c @@ -126,6 +126,10 @@ struct rdpsnd_plugin HANDLE thread; wMessageQueue* queue; BOOL initialized; + + UINT16 wVersion; + UINT32 volume; + BOOL applyVolume; }; static const char* rdpsnd_is_dyn_str(BOOL dynamic) @@ -268,9 +272,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 +289,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 +316,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); } @@ -373,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) { @@ -421,7 +439,7 @@ static BOOL rdpsnd_ensure_device_is_open(rdpsndPlugin* rdpsnd, UINT32 wFormatNo, rdpsnd->totalPlaySize = 0; } - return TRUE; + return rdpsnd_apply_volume(rdpsnd); } /** @@ -710,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) @@ -719,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) { diff --git a/client/common/cmdline.c b/client/common/cmdline.c index 19ece39..df5e8e8 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") { diff --git a/cmake/ConfigOptions.cmake b/cmake/ConfigOptions.cmake index 1a6a359..f16a42c 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) diff --git a/include/freerdp/channels/rdpdr.h b/include/freerdp/channels/rdpdr.h index b61a4c7..6cd283b 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 { diff --git a/libfreerdp/codec/dsp_ffmpeg.c b/libfreerdp/codec/dsp_ffmpeg.c index 086c797..ef67914 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) { diff --git a/libfreerdp/codec/planar.c b/libfreerdp/codec/planar.c index b4815a6..0a5ec58 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); diff --git a/libfreerdp/codec/progressive.c b/libfreerdp/codec/progressive.c index a05a334..8894b35 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) diff --git a/libfreerdp/crypto/crypto.c b/libfreerdp/crypto/crypto.c index f08a4b8..69255c9 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; diff --git a/libfreerdp/locale/xkb_layout_ids.c b/libfreerdp/locale/xkb_layout_ids.c index 223f7d1..9192219 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 */ diff --git a/winpr/CMakeLists.txt b/winpr/CMakeLists.txt index 34dd6df..b332241 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.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/winpr/libwinpr/crt/CMakeLists.txt b/winpr/libwinpr/crt/CMakeLists.txt index c1645b9..5ee4bbd 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 a491979..dc3533a 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", targetStart, 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 diff --git a/winpr/libwinpr/crypto/cipher.c b/winpr/libwinpr/crypto/cipher.c index 41725ab..0fffc6d 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);