[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Re: bookworm-pu: package freerdp2/2.11.2+dfsg1-1~deb12u1



Control: retitle -1 bookworm-pu: package freerdp2/2.11.7+dfsg1-6~deb12u1
Control: tags -1 -moreinfo

Dear Release Team,

Attached is a full source diff. 

I'm moving the target version to 2.11.7, as packaged previously as
2.11.7+dfsg1-6 as new CVEs were discovered and fixed with this version.

Since 2.10.0+dfsg1-1, the version currently in stable, those CVEs will
be fixed with the 2.11.7+dfsg1-6: 
CVE-2024-32661 CVE-2024-32660 CVE-2024-32659 CVE-2024-32658
CVE-2024-32460 CVE-2024-32459 CVE-2024-32458 CVE-2024-32041
CVE-2024-32040 CVE-2024-32039 CVE-2024-22211 CVE-2023-40589
CVE-2023-40569 CVE-2023-40188 CVE-2023-40186 CVE-2023-40181
CVE-2023-39356 CVE-2023-39354 CVE-2023-39353 CVE-2023-39352
CVE-2023-39351 CVE-2023-39350

As said in the initial mail: 

Backporting the fixes is of course possible, but bears a significant
risk for regression, therefor I would prefer to use the new upstream
version, given also that upstream changes are only a few and fixing also
a few bugs that would be nice to be fixed. 

As far as I understood it, the maintainers would also prefer the new
version over patching the one in stable. (They are in CC, so can
intervene if I got that wrong…)

The version 2.11.7 has been in unstable since 2024-07-15, in testing
since 2024-10-07, so the new upstream version has been seen some
testing. (it now has been removed from unstable for freerdp3, #1090342)
Looking at the BTS I don't see reported regressions as well.

It seems to me that the 2.x series only get (significant) bug fixes and
security updates; new features seems only to go into FreeRDP 3.x.

To assess the risks, I did an extensive triage of the changes, looking
at the actual git commits in the version range; (this seems to confirm
that 2.x only gets fixes and security updates)


Triaging upstream changes:

2.10.0 -> 2.11.0 is the most significant changeset with 52 commits, see
below.

2.11.x (upstream branch stable-2.0) seems to be focusing on bugfixes and
security fixes. Looking at the upstream changelog [1]:

[1] https://github.com/FreeRDP/FreeRDP/blob/stable-2.0/ChangeLog

I see for 
 - 2.11.7 [2] just fixes, including one potential out of bound read.
 
   should fix: CVE-2024-32658 to 60.
   
 - 2.11.6 [3] is targeting CVE-2024-32039 to 41, CVE-2024-32458 to 60
   (out of bound reads, Integer overflow) and a bugfix backported from 
   3.5.0 (upstream PR#[10077], which are adding additional input lenght
   checks and fix an integer overflow)

 - 2.11.5 [4] another integer overflow, previnting deref of NULL, and a
   compatiblity fix for newer OpenSSL [4a], with an version guard for
   OpenSSL >3, so I guess we want this fix too.
   via security tracker: CVE-2024-22211

 - 2.11.4 [5] is a FTBFS fix of 2.11.3, sinlge important commit.

 - 2.11.3 [6] is a version that have more noteworthy changes:
   ("->" are my comments)

    * Disabled windows MEDIA FOUNDATION h264 decoder due to reported
      issues (#9469)
    -> this is Windows only.  

    * Fix issues with drive redirection (#9530,9554, #9586, #9617)
    -> bugfix to fix several error cases when connecting 
       (upstream issue #9506 explains the context)

    * Use endian safe ICU string converter (#9631)
    -> fix for issue observed on big-endian machines, introduced with
       2.11.0, upstream bug #9616)

    * Improve AAC support (#9577)
    -> bugfixes the AAC encoder, when a ffmpeg conversion yields NaN or 
       infinity. Details upstream bug #9576.

    * Fix swiss german keyboard layout (#9560)
    -> bugfix for not encoding umlauts correctly. (details upstream
       bug #9560)

    * Enable rfx-mode:image (#9428)
    -> bugfix for rfx-mode:image (details upstream bug #9425)

    There seems to be more smaller commits that aid to improve
    compatiblity or avoid race conditions ( e.g message order.)
    I'd say those are bugfixes. One change is a small feature to
    remember audio volume when reconnecting, I could imagine that could
    save a few eardrums :))

 - 2.11.2 [7] has two changes, both backported from FreeRDP3
     - more robus OpenSSL certificate hash algorithm detection. [7a]
     - regression fix, bug introduced with 2.11.1 (upstream issue #9377)
       [7b]

 - 2.11.1 [8] single change, bugfix see [8a], 
     Regression fix for CVE-2023-39356

 - 2.11.0 [9] is the biggest changeset:

    Noteworthy changes:
    * Various input validation fixes
    * Added various CMake options #9317
    -> refactoring of CMakeLists.txt, should not have an effect on the
       build results. 
    * LibreSSL build fixes #8709
    -> fix only for LibreSSL. (gated by #if .. #endif)

    Fixed issues:
    * Backported #9233: Big endian support
    -> bugfix
    * Backported #9099: Mouse grabbing support
    -> PR title: mouse move restrict, seems feature related to mouse
       grabbing.
    * Backported #6851: wayland scrolling fix
    -> bugfix for wayland.
    * Backported #8690: Update h264 to use new FFMPEG API
    -> add #if-guards against FFPEG version, to use h264 api on new
       enough ffmpeg (>59.18.100), which is not the case on stable.
      (LIBAVUTIL_VERSION_MAJOR is 57 on my bookworm VM)
    * Backported #7306: early bail from update_read_window_state_order
      breaks protocol
    -> bugfix.
    * Backported #8903: rdpecam/server: Remove wrong assertion
    -> bugfix, avoids crash when asserts are enabled.
    * Backported #8994: bounds checks for gdi/gfx rectangles
    -> bugfix, potential security impact.
    * Backported #9023: enforce rdpdr client side state checks
    -> bugfix
    * Backported #6331: deactivate mouse grabbing by default
    -> support command line option "grab-mouse"
    * Cherry-pick out of #9172: channels/cliprdr: Fix writing incorrect
      PDU type for unlock PDUs
    -> bugfix, cherry-picked from FreeRDP3.

    according to the security-tracker 2.11.0 fixes:
    CVE-2023-39350 to 54, CVE-2023-39356, CVE-2023-40181, CVE-2023-40186
    CVE-2023-40188, CVE-2023-40567, CVE-2023-40569, CVE-2023-40589
    

[2] https://github.com/FreeRDP/FreeRDP/compare/2.11.6...2.11.7
[3] https://github.com/FreeRDP/FreeRDP/compare/2.11.5...2.11.6
[4] https://github.com/FreeRDP/FreeRDP/compare/2.11.4...2.11.5
[4a] https://github.com/FreeRDP/FreeRDP/commit/d3f62748c6662ce03
[5] https://github.com/FreeRDP/FreeRDP/compare/2.11.3...2.11.4
    namely: https://github.com/FreeRDP/FreeRDP/commit/52663d581cb
[6] https://github.com/FreeRDP/FreeRDP/compare/2.11.2...2.11.3
[7] https://github.com/FreeRDP/FreeRDP/compare/2.11.1...2.11.2
[7a] https://github.com/FreeRDP/FreeRDP/commit/e93433fb21231db
[7b] https://github.com/FreeRDP/FreeRDP/commit/0472543b019d01280
[8] https://github.com/FreeRDP/FreeRDP/compare/2.11.0...2.11.1
[8a] https://github.com/FreeRDP/FreeRDP/commit/23db2f4e6ba71f1c1
[9]https://github.com/FreeRDP/FreeRDP/compare/2.10.0...2.11.0

[10077] https://github.com/FreeRDP/FreeRDP/pull/10077/commits


Debian packaging changes:

The proposed packaging is based on the last version from testing,
2.11.7+dfsg1-6, but reverting the changes for:
- t64 changes
- turning off Keberos support, as it was not available in bookworm as
  well.
- Using pkg-config instead of pkgconf, as the current bookworm package
  does. 
- not applying the ffmpeg7 compatibility patch, as its not needed for
  bookworm.

A diff generated by git diff debian/2.11.7+dfsg1-6 is attached as
"freerdp2-debian.diff" to show the changes compared to said testing
version. (The git repo is at: [10], branch "debian/bookworm-WIP-tobi"

[10] https://salsa.debian.org/lts-team/packages/freerdp2

Compared to upstream 2.11.7, there are some additional patches
in the Debian package to fix some FTBFS to to type mismatches.
They could theoretically be dropped, but do not do harm either.


Testing

I've tested the package against a Windows 10 VM, both as RDP client and
server, using gnome's RDP facility, also testing with remmina and
vinagre and the testing I've done so far did not show any regressions.



Cheers,
tobi



diff --git a/channels/ainput/server/ainput_main.c b/channels/ainput/server/ainput_main.c
index 943d0fa..fc61f9b 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/client/Wayland/wlfreerdp.c b/client/Wayland/wlfreerdp.c
index 65e29bc..5988aed 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;
diff --git a/client/X11/xf_graphics.c b/client/X11/xf_graphics.c
index 5aa1fd4..fe81e0e 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;
 }
 
diff --git a/debian/changelog b/debian/changelog
index ca142d7..21cb271 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,13 @@
+freerdp2 (2.11.7+dfsg1-6~deb12u1) bookworm-UNRELEASED; urgency=high
+
+  * Non-maintainer upload by the LTS Team for stable proposed updated.
+  * Revert time64_t transition commits, as they are not applicable to bookworm.
+  * Revert turning on keberos support.
+  * Reverting B-D: Depend on pkg-config instead of pkgconf.
+  * Do not use ffmpeg7 patch, bookworm is still at ffmpeg5.
+
+ -- Tobias Frost <tobi@debian.org>  Sat, 01 Feb 2025 09:00:48 +0100
+
 freerdp2 (2.11.7+dfsg1-6) unstable; urgency=medium
 
   * Team upload
diff --git a/debian/control b/debian/control
index 9be5844..5700c61 100644
--- a/debian/control
+++ b/debian/control
@@ -17,7 +17,6 @@ Build-Depends:
  libgsm1-dev,
  libicu-dev,
  libjpeg-dev,
- libkrb5-dev,
  libpam0g-dev,
  libpcsclite-dev,
  libpulse-dev,
@@ -40,7 +39,7 @@ Build-Depends:
  libxrender-dev,
  libxtst-dev,
  libxv-dev,
- pkgconf,
+ pkg-config,
  uuid-dev,
  xmlto,
  xsltproc,
@@ -55,7 +54,7 @@ Architecture: any
 Depends:
  ${misc:Depends},
  ${shlibs:Depends},
- libfreerdp-client2-2t64 (= ${binary:Version}),
+ libfreerdp-client2-2 (= ${binary:Version}),
 Provides:
  freerdp,
 Replaces:
@@ -81,8 +80,7 @@ Description: RDP client for Windows Terminal Services (X11 client)
  .
  This package contains the X11 based client.
 
-Package: libfreerdp2-2t64
-Provides: ${t64:Provides}
+Package: libfreerdp2-2
 Architecture: any
 Section: libs
 Pre-Depends:
@@ -90,7 +88,7 @@ Pre-Depends:
 Depends:
  ${misc:Depends},
  ${shlibs:Depends},
- libwinpr2-2t64 (= ${binary:Version}),
+ libwinpr2-2 (= ${binary:Version}),
 Breaks:
  libfreerdp2-2 (<< ${source:Version}),
  libfreerdp2 (<< 2.0.0~git20170725.1.1648deb+dfsg1-1~),
@@ -106,8 +104,7 @@ Description: Free Remote Desktop Protocol library (core library)
  .
  This package contains the shared library with all core functionality.
 
-Package: libfreerdp-client2-2t64
-Provides: ${t64:Provides}
+Package: libfreerdp-client2-2
 Architecture: any
 Section: libs
 Pre-Depends:
@@ -115,7 +112,7 @@ Pre-Depends:
 Depends:
  ${misc:Depends},
  ${shlibs:Depends},
- libfreerdp2-2t64 (= ${binary:Version}),
+ libfreerdp2-2 (= ${binary:Version}),
 Breaks:
  libfreerdp-client2-2 (<< ${source:Version}),
  libfreerdp-client2 (<< 2.0.0~git20170725.1.1648deb+dfsg1-1~),
@@ -129,8 +126,7 @@ Description: Free Remote Desktop Protocol library (client library)
  .
  This package contains the shared library for common client functionality.
 
-Package: libfreerdp-server2-2t64
-Provides: ${t64:Provides}
+Package: libfreerdp-server2-2
 Architecture: any
 Section: libs
 Pre-Depends:
@@ -138,7 +134,7 @@ Pre-Depends:
 Depends:
  ${misc:Depends},
  ${shlibs:Depends},
- libfreerdp2-2t64 (= ${binary:Version}),
+ libfreerdp2-2 (= ${binary:Version}),
 Breaks:
  libfreerdp-server2-2 (<< ${source:Version}),
  libfreerdp-server2 (<< 2.0.0~git20170725.1.1648deb+dfsg1-1~),
@@ -152,8 +148,7 @@ Description: Free Remote Desktop Protocol library (server library)
  .
  This package contains the shared library with common server functionality.
 
-Package: libwinpr2-2t64
-Provides: ${t64:Provides}
+Package: libwinpr2-2
 Architecture: any
 Section: libs
 Pre-Depends:
@@ -182,8 +177,7 @@ Description: Windows Portable Runtime library
  .
  This package contains the WinPR shared library.
 
-Package: libwinpr-tools2-2t64
-Provides: ${t64:Provides}
+Package: libwinpr-tools2-2
 Architecture: any
 Section: libs
 Pre-Depends:
@@ -191,7 +185,7 @@ Pre-Depends:
 Depends:
  ${misc:Depends},
  ${shlibs:Depends},
- libwinpr2-2t64 (= ${binary:Version}),
+ libwinpr2-2 (= ${binary:Version}),
 Breaks:
  libwinpr-tools2-2 (<< ${source:Version}),
  libwinpr-tools2 (<< 2.0.0~git20170725.1.1648deb+dfsg1-1~),
@@ -212,8 +206,8 @@ Architecture: any
 Multi-Arch: same
 Depends:
  libssl-dev,
- libwinpr-tools2-2t64 (= ${binary:Version}),
- libwinpr2-2t64 (= ${binary:Version}),
+ libwinpr-tools2-2 (= ${binary:Version}),
+ libwinpr2-2 (= ${binary:Version}),
  ${misc:Depends},
 Description: Windows Portable Runtime library (development files)
  WinPR is a spin-off project of FreeRDP which aims at providing a portable
@@ -231,11 +225,11 @@ Package: freerdp2-dev
 Section: devel
 Architecture: any
 Depends:
- libfreerdp-client2-2t64 (= ${binary:Version}),
- libfreerdp-server2-2t64 (= ${binary:Version}),
- libfreerdp-shadow-subsystem2-2t64 (= ${binary:Version}),
- libfreerdp-shadow2-2t64 (= ${binary:Version}),
- libfreerdp2-2t64 (= ${binary:Version}),
+ libfreerdp-client2-2 (= ${binary:Version}),
+ libfreerdp-server2-2 (= ${binary:Version}),
+ libfreerdp-shadow-subsystem2-2 (= ${binary:Version}),
+ libfreerdp-shadow2-2 (= ${binary:Version}),
+ libfreerdp2-2 (= ${binary:Version}),
  libwinpr2-dev (= ${binary:Version}),
  winpr-utils (= ${binary:Version}),
  ${misc:Depends},
@@ -252,7 +246,7 @@ Architecture: any
 Depends:
  ${misc:Depends},
  ${shlibs:Depends},
- libwinpr-tools2-2t64 (= ${binary:Version}),
+ libwinpr-tools2-2 (= ${binary:Version}),
 Description: Windows Portable Runtime library command line utilities
  WinPR is a spin-off project of FreeRDP which aims at providing a portable
  implementation of important portions of the Windows API. Just like FreeRDP,
@@ -265,8 +259,7 @@ Description: Windows Portable Runtime library command line utilities
  .
  This package contains WinPR command line utils (winpr-hash, winpr-makecert).
 
-Package: libfreerdp-shadow2-2t64
-Provides: ${t64:Provides}
+Package: libfreerdp-shadow2-2
 Architecture: any
 Section: libs
 Pre-Depends:
@@ -274,8 +267,8 @@ Pre-Depends:
 Depends:
  ${misc:Depends},
  ${shlibs:Depends},
- libfreerdp-server2-2t64 (= ${binary:Version}),
- libwinpr-tools2-2t64 (= ${binary:Version}),
+ libfreerdp-server2-2 (= ${binary:Version}),
+ libwinpr-tools2-2 (= ${binary:Version}),
 Breaks:
  libfreerdp-shadow2-2 (<< ${source:Version}),
  libfreerdp-shadow2 (<< 2.0.0~git20170725.1.1648deb+dfsg1-1~),
@@ -289,8 +282,7 @@ Description: FreeRDP Remote Desktop Protocol shadow libraries
  .
  This package contains the shadow libraries.
 
-Package: libfreerdp-shadow-subsystem2-2t64
-Provides: ${t64:Provides}
+Package: libfreerdp-shadow-subsystem2-2
 Architecture: any
 Section: libs
 Pre-Depends:
@@ -298,7 +290,7 @@ Pre-Depends:
 Depends:
  ${misc:Depends},
  ${shlibs:Depends},
- libfreerdp-shadow2-2t64 (= ${binary:Version}),
+ libfreerdp-shadow2-2 (= ${binary:Version}),
 Breaks:
  libfreerdp-shadow-subsystem2-2 (<< ${source:Version}),
  libfreerdp-shadow2 (<< 2.0.0~git20170725.1.1648deb+dfsg1-1~),
@@ -317,7 +309,7 @@ Architecture: any
 Depends:
  ${misc:Depends},
  ${shlibs:Depends},
- libfreerdp-shadow-subsystem2-2t64 (= ${binary:Version}),
+ libfreerdp-shadow-subsystem2-2 (= ${binary:Version}),
 Provides:
  freerdp,
 Description: FreeRDP x11 shadowing server
@@ -327,8 +319,7 @@ Description: FreeRDP x11 shadowing server
  This package contains a "shadowing" server that can be used to
  share an already started X11 DISPLAY.
 
-Package: libuwac0-0t64
-Provides: ${t64:Provides}
+Package: libuwac0-0
 Architecture: linux-any
 Section: libs
 Pre-Depends:
@@ -336,7 +327,7 @@ Pre-Depends:
 Depends:
  ${misc:Depends},
  ${shlibs:Depends},
- libfreerdp2-2t64 (= ${binary:Version}),
+ libfreerdp2-2 (= ${binary:Version}),
 Breaks:
  libuwac0-0 (<< ${source:Version}),
  libuwac0 (<< 2.0.0~git20170725.1.1648deb+dfsg1-1~),
@@ -355,7 +346,7 @@ Section: libdevel
 Architecture: linux-any
 Multi-Arch: same
 Depends:
- libuwac0-0t64 (= ${binary:Version}),
+ libuwac0-0 (= ${binary:Version}),
  ${misc:Depends},
 Description: Using wayland as a client (development files)
  Using wayland as a client (uwac) is a library to provide common
@@ -368,8 +359,8 @@ Architecture: linux-any
 Depends:
  ${misc:Depends},
  ${shlibs:Depends},
- libfreerdp-client2-2t64 (= ${binary:Version}),
- libuwac0-0t64 (= ${binary:Version}),
+ libfreerdp-client2-2 (= ${binary:Version}),
+ libuwac0-0 (= ${binary:Version}),
 Description: RDP client for Windows Terminal Services (wayland client)
  FreeRDP is a libre client/server implementation of the Remote
  Desktop Protocol (RDP).
diff --git a/debian/libfreerdp-client2-2t64.install b/debian/libfreerdp-client2-2.install
similarity index 100%
rename from debian/libfreerdp-client2-2t64.install
rename to debian/libfreerdp-client2-2.install
diff --git a/debian/libfreerdp-client2-2t64.symbols b/debian/libfreerdp-client2-2.symbols
similarity index 98%
rename from debian/libfreerdp-client2-2t64.symbols
rename to debian/libfreerdp-client2-2.symbols
index 4d36c18..7598bb1 100644
--- a/debian/libfreerdp-client2-2t64.symbols
+++ b/debian/libfreerdp-client2-2.symbols
@@ -1,4 +1,4 @@
-libfreerdp-client2.so.2 libfreerdp-client2-2t64 #MINVER#
+libfreerdp-client2.so.2 libfreerdp-client2-2 #MINVER#
 * Build-Depends-Package: freerdp2-dev
  add_device@Base 2.1.0+dfsg1
  client_auto_reconnect@Base 2.0.0~git20181120.1.e21b72c95+dfsg1
diff --git a/debian/libfreerdp-server2-2t64.install b/debian/libfreerdp-server2-2.install
similarity index 100%
rename from debian/libfreerdp-server2-2t64.install
rename to debian/libfreerdp-server2-2.install
diff --git a/debian/libfreerdp-server2-2t64.symbols b/debian/libfreerdp-server2-2.symbols
similarity index 98%
rename from debian/libfreerdp-server2-2t64.symbols
rename to debian/libfreerdp-server2-2.symbols
index a1ed5e4..79c8e01 100644
--- a/debian/libfreerdp-server2-2t64.symbols
+++ b/debian/libfreerdp-server2-2.symbols
@@ -1,4 +1,4 @@
-libfreerdp-server2.so.2 libfreerdp-server2-2t64 #MINVER#
+libfreerdp-server2.so.2 libfreerdp-server2-2 #MINVER#
 * Build-Depends-Package: freerdp2-dev
  ainput_server_context_free@Base 2.6.0+dfsg1
  ainput_server_context_new@Base 2.6.0+dfsg1
diff --git a/debian/libfreerdp-shadow-subsystem2-2t64.install b/debian/libfreerdp-shadow-subsystem2-2.install
similarity index 100%
rename from debian/libfreerdp-shadow-subsystem2-2t64.install
rename to debian/libfreerdp-shadow-subsystem2-2.install
diff --git a/debian/libfreerdp-shadow-subsystem2-2t64.symbols b/debian/libfreerdp-shadow-subsystem2-2.symbols
similarity index 94%
rename from debian/libfreerdp-shadow-subsystem2-2t64.symbols
rename to debian/libfreerdp-shadow-subsystem2-2.symbols
index 48fe6b4..1388462 100644
--- a/debian/libfreerdp-shadow-subsystem2-2t64.symbols
+++ b/debian/libfreerdp-shadow-subsystem2-2.symbols
@@ -1,4 +1,4 @@
-libfreerdp-shadow-subsystem2.so.2 libfreerdp-shadow-subsystem2-2t64 #MINVER#
+libfreerdp-shadow-subsystem2.so.2 libfreerdp-shadow-subsystem2-2 #MINVER#
 * Build-Depends-Package: freerdp2-dev
  X11_ShadowSubsystemEntry@Base 2.0.0~git20160317.1.75ae3f5+dfsg1
  shadow_subsystem_set_entry_builtin@Base 2.0.0~git20160317.1.75ae3f5+dfsg1
diff --git a/debian/libfreerdp-shadow2-2t64.install b/debian/libfreerdp-shadow2-2.install
similarity index 100%
rename from debian/libfreerdp-shadow2-2t64.install
rename to debian/libfreerdp-shadow2-2.install
diff --git a/debian/libfreerdp-shadow2-2t64.symbols b/debian/libfreerdp-shadow2-2.symbols
similarity index 96%
rename from debian/libfreerdp-shadow2-2t64.symbols
rename to debian/libfreerdp-shadow2-2.symbols
index 03eb71c..3936ad8 100644
--- a/debian/libfreerdp-shadow2-2t64.symbols
+++ b/debian/libfreerdp-shadow2-2.symbols
@@ -1,4 +1,4 @@
-libfreerdp-shadow2.so.2 libfreerdp-shadow2-2t64 #MINVER#
+libfreerdp-shadow2.so.2 libfreerdp-shadow2-2 #MINVER#
 * Build-Depends-Package: freerdp2-dev
  shadow_capture_align_clip_rect@Base 2.0.0~git20160317.1.75ae3f5+dfsg1
  shadow_capture_compare@Base 2.0.0~git20160317.1.75ae3f5+dfsg1
diff --git a/debian/libfreerdp2-2t64.install b/debian/libfreerdp2-2.install
similarity index 100%
rename from debian/libfreerdp2-2t64.install
rename to debian/libfreerdp2-2.install
diff --git a/debian/libfreerdp2-2t64.symbols b/debian/libfreerdp2-2.symbols
similarity index 99%
rename from debian/libfreerdp2-2t64.symbols
rename to debian/libfreerdp2-2.symbols
index e8cffdb..f6eea21 100644
--- a/debian/libfreerdp2-2t64.symbols
+++ b/debian/libfreerdp2-2.symbols
@@ -1,4 +1,4 @@
-libfreerdp2.so.2 libfreerdp2-2t64 #MINVER#
+libfreerdp2.so.2 libfreerdp2-2 #MINVER#
 * Build-Depends-Package: freerdp2-dev
  Bitmap_Alloc@Base 2.0.0~git20160317.1.75ae3f5+dfsg1
  Bitmap_SetDimensions@Base 2.0.0~git20160317.1.75ae3f5+dfsg1
diff --git a/debian/libuwac0-0t64.install b/debian/libuwac0-0.install
similarity index 100%
rename from debian/libuwac0-0t64.install
rename to debian/libuwac0-0.install
diff --git a/debian/libuwac0-0t64.symbols b/debian/libuwac0-0.symbols
similarity index 99%
rename from debian/libuwac0-0t64.symbols
rename to debian/libuwac0-0.symbols
index 83aa153..1c4df89 100644
--- a/debian/libuwac0-0t64.symbols
+++ b/debian/libuwac0-0.symbols
@@ -1,4 +1,4 @@
-libuwac0.so.0 libuwac0-0t64 #MINVER#
+libuwac0.so.0 libuwac0-0 #MINVER#
 * Build-Depends-Package: libuwac0-dev
  UwacClipboardDataGet@Base 2.0.0~git20190204.1.2693389a+dfsg1
  UwacClipboardOfferAnnounce@Base 2.0.0~git20190204.1.2693389a+dfsg1
diff --git a/debian/libwinpr-tools2-2t64.install b/debian/libwinpr-tools2-2.install
similarity index 100%
rename from debian/libwinpr-tools2-2t64.install
rename to debian/libwinpr-tools2-2.install
diff --git a/debian/libwinpr-tools2-2t64.symbols b/debian/libwinpr-tools2-2.symbols
similarity index 90%
rename from debian/libwinpr-tools2-2t64.symbols
rename to debian/libwinpr-tools2-2.symbols
index bf7702b..034e428 100644
--- a/debian/libwinpr-tools2-2t64.symbols
+++ b/debian/libwinpr-tools2-2.symbols
@@ -1,4 +1,4 @@
-libwinpr-tools2.so.2 libwinpr-tools2-2t64 #MINVER#
+libwinpr-tools2.so.2 libwinpr-tools2-2 #MINVER#
 * Build-Depends-Package: libwinpr2-dev
  makecert_context_free@Base 2.0.0~git20160503.1.f828595+dfsg1
  makecert_context_new@Base 2.0.0~git20160503.1.f828595+dfsg1
diff --git a/debian/libwinpr2-2t64.docs b/debian/libwinpr2-2.docs
similarity index 100%
rename from debian/libwinpr2-2t64.docs
rename to debian/libwinpr2-2.docs
diff --git a/debian/libwinpr2-2t64.install b/debian/libwinpr2-2.install
similarity index 100%
rename from debian/libwinpr2-2t64.install
rename to debian/libwinpr2-2.install
diff --git a/debian/libwinpr2-2t64.symbols b/debian/libwinpr2-2.symbols
similarity index 99%
rename from debian/libwinpr2-2t64.symbols
rename to debian/libwinpr2-2.symbols
index 9089491..0be74f0 100644
--- a/debian/libwinpr2-2t64.symbols
+++ b/debian/libwinpr2-2.symbols
@@ -1,4 +1,4 @@
-libwinpr2.so.2 libwinpr2-2t64 #MINVER#
+libwinpr2.so.2 libwinpr2-2 #MINVER#
 * Build-Depends-Package: libwinpr2-dev
  ASN1DecSetError@Base 2.0.0~git20160317.1.75ae3f5+dfsg1
  ASN1EncSetError@Base 2.0.0~git20160317.1.75ae3f5+dfsg1
diff --git a/debian/libwinpr2-2t64.hurd-i386 b/debian/libwinpr2-2.symbols.hurd-i386
similarity index 100%
rename from debian/libwinpr2-2t64.hurd-i386
rename to debian/libwinpr2-2.symbols.hurd-i386
diff --git a/debian/libwinpr2-2t64.kfreebsd-amd64 b/debian/libwinpr2-2.symbols.kfreebsd-amd64
similarity index 100%
rename from debian/libwinpr2-2t64.kfreebsd-amd64
rename to debian/libwinpr2-2.symbols.kfreebsd-amd64
diff --git a/debian/libwinpr2-2t64.kfreebsd-i386 b/debian/libwinpr2-2.symbols.kfreebsd-i386
similarity index 100%
rename from debian/libwinpr2-2t64.kfreebsd-i386
rename to debian/libwinpr2-2.symbols.kfreebsd-i386
diff --git a/debian/patches/series b/debian/patches/series
index b8cfb1f..cd231db 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -5,5 +5,5 @@
 0005-client-wayland-fix-const-correctness.patch
 0006-warnings-fix-Wincompatible-pointer-types.patch
 0007-server-proxy-deactivate-capture-module.patch
-1000-ffmpeg7.patch
+#1000-ffmpeg7.patch
 CVE-2024-32661.patch
diff --git a/debian/rules b/debian/rules
index 19be556..c6950e9 100755
--- a/debian/rules
+++ b/debian/rules
@@ -31,7 +31,6 @@ DEB_CMAKE_EXTRA_FLAGS = \
     -DWITH_CUPS=ON \
     -DWITH_PCSC=ON \
     -DWITH_JPEG=ON \
-    -DWITH_KERBEROS=ON \
     $(empty)
 
 ifneq (,$(filter armel,$(DEB_HOST_ARCH)))
diff --git a/libfreerdp/codec/dsp_ffmpeg.c b/libfreerdp/codec/dsp_ffmpeg.c
index ef67914..80df188 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/libfreerdp/core/info.c b/libfreerdp/core/info.c
index 9aaa6cf..dc72b61 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;
@@ -1322,6 +1322,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)
diff --git a/libfreerdp/core/redirection.c b/libfreerdp/core/redirection.c
index 59c6dbc..4872d4b 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);
 
@@ -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:
diff --git a/server/proxy/modules/capture/CMakeLists.txt b/server/proxy/modules/capture/CMakeLists.txt
index 80ba3b7..4004aaa 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}")
diff --git a/winpr/libwinpr/crt/unicode.c b/winpr/libwinpr/crt/unicode.c
index dc3533a..acbec01 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;
 		}
 
diff -Nru freerdp2-2.10.0+dfsg1/ChangeLog freerdp2-2.11.7+dfsg1/ChangeLog
--- freerdp2-2.10.0+dfsg1/ChangeLog	2023-02-16 10:55:03.000000000 +0100
+++ freerdp2-2.11.7+dfsg1/ChangeLog	2024-04-22 11:26:59.000000000 +0200
@@ -1,6 +1,97 @@
+# 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:
+ 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:
+* 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:
+* 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:
+* 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:
+* Various input validation fixes
+* Added various CMake options #9317
+* 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
+* 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
+* 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
 
-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 +114,7 @@
 
 # 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 +140,7 @@
 
 # 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)
diff -Nru freerdp2-2.10.0+dfsg1/channels/cliprdr/cliprdr_common.c freerdp2-2.11.7+dfsg1/channels/cliprdr/cliprdr_common.c
--- freerdp2-2.10.0+dfsg1/channels/cliprdr/cliprdr_common.c	2023-02-16 10:55:03.000000000 +0100
+++ freerdp2-2.11.7+dfsg1/channels/cliprdr/cliprdr_common.c	2024-04-22 11:26:59.000000000 +0200
@@ -138,7 +138,7 @@
 	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;
diff -Nru freerdp2-2.10.0+dfsg1/channels/rdpdr/client/devman.c freerdp2-2.11.7+dfsg1/channels/rdpdr/client/devman.c
--- freerdp2-2.10.0+dfsg1/channels/rdpdr/client/devman.c	2023-02-16 10:55:03.000000000 +0100
+++ freerdp2-2.11.7+dfsg1/channels/rdpdr/client/devman.c	2024-04-22 11:26:59.000000000 +0200
@@ -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 @@
 
 	if (!devman)
 	{
-		WLog_INFO(TAG, "calloc failed!");
+		WLog_Print(rdpdr->log, WLOG_INFO, "calloc failed!");
 		return NULL;
 	}
 
@@ -72,7 +74,7 @@
 
 	if (!devman->devices)
 	{
-		WLog_INFO(TAG, "ListDictionary_New failed!");
+		WLog_Print(rdpdr->log, WLOG_INFO, "ListDictionary_New failed!");
 		free(devman);
 		return NULL;
 	}
diff -Nru freerdp2-2.10.0+dfsg1/channels/rdpdr/client/irp.c freerdp2-2.11.7+dfsg1/channels/rdpdr/client/irp.c
--- freerdp2-2.10.0+dfsg1/channels/rdpdr/client/irp.c	2023-02-16 10:55:03.000000000 +0100
+++ freerdp2-2.11.7+dfsg1/channels/rdpdr/client/irp.c	2024-04-22 11:26:59.000000000 +0200
@@ -76,13 +76,13 @@
 	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 @@
 
 	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 @@
 
 	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->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 -Nru freerdp2-2.10.0+dfsg1/channels/rdpdr/client/irp.h freerdp2-2.11.7+dfsg1/channels/rdpdr/client/irp.h
--- freerdp2-2.10.0+dfsg1/channels/rdpdr/client/irp.h	2023-02-16 10:55:03.000000000 +0100
+++ freerdp2-2.11.7+dfsg1/channels/rdpdr/client/irp.h	2024-04-22 11:26:59.000000000 +0200
@@ -21,8 +21,9 @@
 #ifndef FREERDP_CHANNEL_RDPDR_CLIENT_IRP_H
 #define FREERDP_CHANNEL_RDPDR_CLIENT_IRP_H
 
+#include <winpr/wlog.h>
 #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 -Nru freerdp2-2.10.0+dfsg1/channels/rdpdr/client/rdpdr_capabilities.c freerdp2-2.11.7+dfsg1/channels/rdpdr/client/rdpdr_capabilities.c
--- freerdp2-2.10.0+dfsg1/channels/rdpdr/client/rdpdr_capabilities.c	2023-02-16 10:55:03.000000000 +0100
+++ freerdp2-2.11.7+dfsg1/channels/rdpdr/client/rdpdr_capabilities.c	2024-04-22 11:26:59.000000000 +0200
@@ -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_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_GetRemainingLength(s) < 2)
-		return ERROR_INVALID_DATA;
-
-	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_GetRemainingLength(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;
 }
 
@@ -92,23 +114,14 @@
 }
 
 /* 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_GetRemainingLength(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_GetRemainingLength(s) < capabilityLength - 4U)
-		return ERROR_INVALID_DATA;
-
-	Stream_Seek(s, capabilityLength - 4U);
+	Stream_Seek(s, capabilityLength);
 	return CHANNEL_RC_OK;
 }
 
@@ -120,23 +133,14 @@
 }
 
 /* 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_GetRemainingLength(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_GetRemainingLength(s) < capabilityLength - 4U)
-		return ERROR_INVALID_DATA;
-
-	Stream_Seek(s, capabilityLength - 4U);
+	Stream_Seek(s, capabilityLength);
 	return CHANNEL_RC_OK;
 }
 
@@ -148,23 +152,14 @@
 }
 
 /* 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_GetRemainingLength(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_GetRemainingLength(s) < capabilityLength - 4U)
-		return ERROR_INVALID_DATA;
-
-	Stream_Seek(s, capabilityLength - 4U);
+	Stream_Seek(s, capabilityLength);
 	return CHANNEL_RC_OK;
 }
 
@@ -176,23 +171,14 @@
 }
 
 /* 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_GetRemainingLength(s) < 2)
-		return ERROR_INVALID_DATA;
-
-	Stream_Read_UINT16(s, capabilityLength);
-
-	if (capabilityLength < 4)
+	if (!Stream_CheckAndLogRequiredLengthWLog(rdpdr->log, s, capabilityLength))
 		return ERROR_INVALID_DATA;
 
-	if (Stream_GetRemainingLength(s) < capabilityLength - 4U)
-		return ERROR_INVALID_DATA;
-
-	Stream_Seek(s, capabilityLength - 4U);
+	Stream_Seek(s, capabilityLength);
 	return CHANNEL_RC_OK;
 }
 
@@ -201,12 +187,14 @@
 	UINT status = CHANNEL_RC_OK;
 	UINT16 i;
 	UINT16 numCapabilities;
-	UINT16 capabilityType;
 
 	if (!rdpdr || !s)
 		return CHANNEL_RC_NULL_DATA;
 
-	if (Stream_GetRemainingLength(s) < 4)
+	WINPR_ASSERT(rdpdr->state == RDPDR_CHANNEL_STATE_SERVER_CAPS);
+	rdpdr_state_advance(rdpdr, RDPDR_CHANNEL_STATE_CLIENT_CAPS);
+
+	if (!Stream_CheckAndLogRequiredLengthWLog(rdpdr->log, s, 4))
 		return ERROR_INVALID_DATA;
 
 	Stream_Read_UINT16(s, numCapabilities);
@@ -214,31 +202,44 @@
 
 	for (i = 0; i < numCapabilities; i++)
 	{
-		if (Stream_GetRemainingLength(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:
@@ -264,7 +265,7 @@
 
 	if (!s)
 	{
-		WLog_ERR(TAG, "Stream_New failed!");
+		WLog_Print(rdpdr->log, WLOG_ERROR, "Stream_New failed!");
 		return CHANNEL_RC_NO_MEMORY;
 	}
 
diff -Nru freerdp2-2.10.0+dfsg1/channels/rdpdr/client/rdpdr_main.c freerdp2-2.11.7+dfsg1/channels/rdpdr/client/rdpdr_main.c
--- freerdp2-2.10.0+dfsg1/channels/rdpdr/client/rdpdr_main.c	2023-02-16 10:55:03.000000000 +0100
+++ freerdp2-2.11.7+dfsg1/channels/rdpdr/client/rdpdr_main.c	2024-04-22 11:26:59.000000000 +0200
@@ -79,12 +79,142 @@
 	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)
+	{
+		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";
+	}
+}
+
+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);
+
+	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
@@ -95,11 +225,21 @@
 {
 	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)
 	{
-		WLog_ERR(TAG, "Stream_New failed!");
+		WLog_Print(rdpdr->log, WLOG_ERROR, "Stream_New failed!");
 		return CHANNEL_RC_NO_MEMORY;
 	}
 
@@ -212,7 +352,7 @@
 									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);
 								}
 							}
 
@@ -261,8 +401,8 @@
 											         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);
@@ -358,7 +498,7 @@
 	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;
@@ -475,9 +615,9 @@
 
 			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;
 			}
 		}
@@ -506,7 +646,7 @@
 			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;
 			}
@@ -540,10 +680,11 @@
 		{
 			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_send_device_list_announce_request(rdpdr, TRUE);
+				rdpdr_try_send_device_list_announce_request(rdpdr);
 
 			return;
 		}
@@ -556,7 +697,7 @@
 
 	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);
 	}
 }
 
@@ -661,14 +802,14 @@
 
 #ifdef __sun
 #include <sys/mnttab.h>
-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;
 	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)
@@ -682,7 +823,7 @@
 
 #if defined(__FreeBSD__) || defined(__OpenBSD__)
 #include <sys/mount.h>
-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;
@@ -692,7 +833,7 @@
 	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++)
@@ -706,14 +847,14 @@
 
 #if defined(__LINUX__) || defined(__linux__)
 #include <mntent.h>
-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;
 	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)
@@ -725,14 +866,14 @@
 }
 #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 +931,7 @@
 	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);
@@ -834,9 +975,9 @@
 
 			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;
 			}
 		}
@@ -858,7 +999,7 @@
 
 			if (!drive.Name)
 			{
-				WLog_ERR(TAG, "_strdup failed!");
+				WLog_Print(rdpdr->log, WLOG_ERROR, "_strdup failed!");
 				error = CHANNEL_RC_NO_MEMORY;
 				goto cleanup;
 			}
@@ -866,7 +1007,7 @@
 			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;
 			}
 		}
@@ -887,7 +1028,7 @@
 
 	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);
 	}
 }
 
@@ -905,7 +1046,7 @@
 
 	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;
 	}
@@ -922,7 +1063,8 @@
 		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;
 		}
 
@@ -934,11 +1076,12 @@
 			/* 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
-				rdpdr_send_device_list_announce_request(rdpdr, TRUE);
+				rdpdr_try_send_device_list_announce_request(rdpdr);
 		}
 
 		FD_ZERO(&rfds);
@@ -978,7 +1121,8 @@
 		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;
 		}
 
@@ -1007,7 +1151,7 @@
 
 	if (!rdpdr->devman)
 	{
-		WLog_ERR(TAG, "devman_new failed!");
+		WLog_Print(rdpdr->log, WLOG_ERROR, "devman_new failed!");
 		return CHANNEL_RC_NO_MEMORY;
 	}
 
@@ -1036,7 +1180,7 @@
 
 				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;
 				}
 
@@ -1045,7 +1189,7 @@
 				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;
@@ -1059,7 +1203,8 @@
 
 		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;
 		}
 	}
@@ -1072,10 +1217,19 @@
 	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;
 }
 
@@ -1087,18 +1241,23 @@
 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)
 	{
-		WLog_ERR(TAG, "Stream_New failed!");
+		WLog_Print(rdpdr->log, WLOG_ERROR, "Stream_New failed!");
 		return CHANNEL_RC_NO_MEMORY;
 	}
 
 	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);
 }
@@ -1114,6 +1273,10 @@
 	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;
@@ -1126,7 +1289,7 @@
 	if (!s)
 	{
 		free(computerNameW);
-		WLog_ERR(TAG, "Stream_New failed!");
+		WLog_Print(rdpdr->log, WLOG_ERROR, "Stream_New failed!");
 		return CHANNEL_RC_NO_MEMORY;
 	}
 
@@ -1147,17 +1310,20 @@
 	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);
 	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)
@@ -1184,11 +1350,15 @@
 	DEVICE* device;
 	int keyCount;
 	ULONG_PTR* pKeys = NULL;
+
+	if (userLoggedOn)
+		rdpdr->userLoggedOn = TRUE;
+
 	s = Stream_New(NULL, 256);
 
 	if (!s)
 	{
-		WLog_ERR(TAG, "Stream_New failed!");
+		WLog_Print(rdpdr->log, WLOG_ERROR, "Stream_New failed!");
 		return CHANNEL_RC_NO_MEMORY;
 	}
 
@@ -1211,8 +1381,8 @@
 		 * 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));
 
@@ -1220,7 +1390,7 @@
 			{
 				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;
 			}
 
@@ -1244,8 +1414,9 @@
 				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);
 		}
 	}
 
@@ -1258,6 +1429,19 @@
 	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)
 {
 
@@ -1268,7 +1452,7 @@
 	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;
 	}
 
@@ -1301,11 +1485,11 @@
 {
 	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)
 		{
@@ -1317,8 +1501,11 @@
 
 	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;
 }
@@ -1360,6 +1547,8 @@
 	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);
 
@@ -1370,7 +1559,7 @@
 
 		if (error != CHANNEL_RC_OK)
 		{
-			WLog_ERR(TAG, "Init failed!");
+			WLog_Print(rdpdr->log, WLOG_ERROR, "Init failed!");
 			free(pKeys);
 			return error;
 		}
@@ -1380,6 +1569,97 @@
 	return CHANNEL_RC_OK;
 }
 
+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);
+
+	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 %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;
+	}
+	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_ANNOUNCE, 1,
+			                         RDPDR_CHANNEL_STATE_INITIAL);
+		case PAKID_CORE_SERVER_CAPABILITY:
+			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,
+			                         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;
+			return rdpdr_state_check(rdpdr, packetid, state, 1, state);
+		}
+	}
+}
+
 /**
  * Function description
  *
@@ -1403,6 +1683,9 @@
 
 		if (component == RDPDR_CTYP_CORE)
 		{
+			if (!rdpdr_check_channel_state(rdpdr, packetId))
+				return CHANNEL_RC_OK;
+
 			switch (packetId)
 			{
 				case PAKID_CORE_SERVER_ANNOUNCE:
@@ -1411,19 +1694,20 @@
 					}
 					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;
@@ -1434,9 +1718,9 @@
 					}
 					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;
@@ -1447,22 +1731,29 @@
 					}
 					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);
 					}
-
+					else if (!rdpdr_state_advance(rdpdr, RDPDR_CHANNEL_STATE_READY))
+					{
+						error = ERROR_INTERNAL_ERROR;
+					}
 					break;
 
 				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);
 					}
+					else if (!rdpdr_state_advance(rdpdr, RDPDR_CHANNEL_STATE_READY))
+					{
+						error = ERROR_INTERNAL_ERROR;
+					}
 
 					break;
 
@@ -1481,7 +1772,8 @@
 				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
@@ -1490,7 +1782,8 @@
 					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;
 			}
@@ -1501,9 +1794,10 @@
 
 			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);
 			}
 		}
 	}
@@ -1543,8 +1837,8 @@
 	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;
@@ -1581,7 +1875,7 @@
 
 		if (!rdpdr->data_in)
 		{
-			WLog_ERR(TAG, "Stream_New failed!");
+			WLog_Print(rdpdr->log, WLOG_ERROR, "Stream_New failed!");
 			return CHANNEL_RC_NO_MEMORY;
 		}
 	}
@@ -1590,7 +1884,7 @@
 
 	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;
 	}
 
@@ -1600,7 +1894,8 @@
 	{
 		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;
 		}
 
@@ -1610,7 +1905,7 @@
 
 		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;
 		}
 	}
@@ -1631,14 +1926,15 @@
 		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;
 
@@ -1676,7 +1972,8 @@
 
 	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,
@@ -1702,7 +1999,8 @@
 
 				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,
@@ -1740,8 +2038,8 @@
 
 	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;
 	}
 
@@ -1749,7 +2047,7 @@
 
 	if (!rdpdr->queue)
 	{
-		WLog_ERR(TAG, "MessageQueue_New failed!");
+		WLog_Print(rdpdr->log, WLOG_ERROR, "MessageQueue_New failed!");
 		return CHANNEL_RC_NO_MEMORY;
 	}
 
@@ -1758,7 +2056,7 @@
 	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;
 	}
 
@@ -1781,7 +2079,8 @@
 	    (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;
 	}
 
@@ -1792,7 +2091,8 @@
 
 	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;
 	}
 
@@ -1800,8 +2100,8 @@
 
 	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;
@@ -1835,7 +2135,7 @@
 
 	if (!rdpdr || (rdpdr->InitHandle != pInitHandle))
 	{
-		WLog_ERR(TAG, "error no match");
+		WLog_Print(rdpdr->log, WLOG_ERROR, "error no match");
 		return;
 	}
 
@@ -1846,17 +2146,18 @@
 
 		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;
 
@@ -1867,7 +2168,7 @@
 		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;
 	}
 
@@ -1877,6 +2178,7 @@
 }
 
 /* rdpdr is always built-in */
+#define TAG CHANNELS_TAG("rdpdr.client")
 #define VirtualChannelEntryEx rdpdr_VirtualChannelEntryEx
 
 BOOL VCAPITYPE VirtualChannelEntryEx(PCHANNEL_ENTRY_POINTS pEntryPoints, PVOID pInitHandle)
@@ -1884,13 +2186,30 @@
 	UINT rc;
 	rdpdrPlugin* rdpdr;
 	CHANNEL_ENTRY_POINTS_FREERDP_EX* pEntryPointsEx;
+
+	WINPR_ASSERT(pEntryPoints);
+	WINPR_ASSERT(pInitHandle);
+
 	rdpdr = (rdpdrPlugin*)calloc(1, sizeof(rdpdrPlugin));
 
 	if (!rdpdr)
 	{
-		WLog_ERR(TAG, "calloc failed!");
+		WLog_Print(rdpdr->log, WLOG_ERROR, "calloc failed!");
 		return FALSE;
 	}
+	rdpdr->log = WLog_Get(TAG);
+
+	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;
@@ -1912,8 +2231,8 @@
 
 	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 -Nru freerdp2-2.10.0+dfsg1/channels/rdpdr/client/rdpdr_main.h freerdp2-2.11.7+dfsg1/channels/rdpdr/client/rdpdr_main.h
--- freerdp2-2.10.0+dfsg1/channels/rdpdr/client/rdpdr_main.h	2023-02-16 10:55:03.000000000 +0100
+++ freerdp2-2.11.7+dfsg1/channels/rdpdr/client/rdpdr_main.h	2024-04-22 11:26:59.000000000 +0200
@@ -42,15 +42,33 @@
 #include <CoreServices/CoreServices.h>
 #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;
 
+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;
@@ -59,12 +77,33 @@
 
 	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;
@@ -78,8 +117,10 @@
 	HANDLE stopEvent;
 #endif
 	rdpContext* rdpcontext;
+	wLog* log;
 };
 
+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 */
diff -Nru freerdp2-2.10.0+dfsg1/channels/rdpdr/server/rdpdr_main.h freerdp2-2.11.7+dfsg1/channels/rdpdr/server/rdpdr_main.h
--- freerdp2-2.10.0+dfsg1/channels/rdpdr/server/rdpdr_main.h	2023-02-16 10:55:03.000000000 +0100
+++ freerdp2-2.11.7+dfsg1/channels/rdpdr/server/rdpdr_main.h	2024-04-22 11:26:59.000000000 +0200
@@ -57,13 +57,6 @@
 };
 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 -Nru freerdp2-2.10.0+dfsg1/channels/rdpecam/server/camera_device_main.c freerdp2-2.11.7+dfsg1/channels/rdpecam/server/camera_device_main.c
--- freerdp2-2.10.0+dfsg1/channels/rdpecam/server/camera_device_main.c	2023-02-16 10:55:03.000000000 +0100
+++ freerdp2-2.11.7+dfsg1/channels/rdpecam/server/camera_device_main.c	2024-04-22 11:26:59.000000000 +0200
@@ -686,8 +686,6 @@
 {
 	wStream* s;
 
-	WINPR_ASSERT(size > 0);
-
 	/* Allocate what we need plus header bytes */
 	s = Stream_New(NULL, size + CAM_HEADER_SIZE);
 	if (!s)
diff -Nru freerdp2-2.10.0+dfsg1/channels/rdpsnd/client/pulse/rdpsnd_pulse.c freerdp2-2.11.7+dfsg1/channels/rdpsnd/client/pulse/rdpsnd_pulse.c
--- freerdp2-2.10.0+dfsg1/channels/rdpsnd/client/pulse/rdpsnd_pulse.c	2023-02-16 10:55:03.000000000 +0100
+++ freerdp2-2.11.7+dfsg1/channels/rdpsnd/client/pulse/rdpsnd_pulse.c	2024-04-22 11:26:59.000000000 +0200
@@ -23,11 +23,15 @@
 #include "config.h"
 #endif
 
+#include <errno.h>
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <time.h>
 
 #include <winpr/crt.h>
+#include <winpr/assert.h>
 #include <winpr/stream.h>
 #include <winpr/cmdline.h>
 
@@ -51,8 +55,39 @@
 	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 @@
 	;
 	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 @@
 {
 	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 @@
 			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 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 @@
 	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 @@
 {
 	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 @@
 
 		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_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 @@
 {
 	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 @@
 {
 	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 @@
 	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];
 	rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*)device;
 
-	if (!pulse->context || pulse->stream)
-		return TRUE;
+	pulse->context = pa_context_new(pa_threaded_mainloop_get_api(pulse->mainloop), "freerdp");
 
-	if (!rdpsnd_pulse_set_format_spec(pulse, format))
+	if (!pulse->context)
 		return FALSE;
 
-	pulse->latency = latency;
+	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] = { 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)
@@ -320,19 +413,22 @@
 
 	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 @@
 	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 @@
 	rdpsnd_pulse_close(device);
 
 	if (pulse->mainloop)
-	{
 		pa_threaded_mainloop_stop(pulse->mainloop);
-	}
 
 	if (pulse->context)
 	{
@@ -394,6 +506,7 @@
                                         AUDIO_FORMAT* defaultFormat)
 {
 	rdpsndPulsePlugin* pulse = (rdpsndPulsePlugin*)device;
+
 	if (!pulse || !defaultFormat)
 		return FALSE;
 
@@ -415,6 +528,9 @@
 
 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 @@
 	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 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 @@
 	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,
-		                                              "<device>", 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, "<device>", NULL, NULL, -1, NULL, "device" },
+		{ "reconnect_delay_seconds", COMMAND_LINE_VALUE_REQUIRED, "<reconnect_delay_seconds>", 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 @@
 			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 @@
 #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 @@
 			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 @@
 	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 -Nru freerdp2-2.10.0+dfsg1/channels/rdpsnd/client/rdpsnd_main.c freerdp2-2.11.7+dfsg1/channels/rdpsnd/client/rdpsnd_main.c
--- freerdp2-2.10.0+dfsg1/channels/rdpsnd/client/rdpsnd_main.c	2023-02-16 10:55:03.000000000 +0100
+++ freerdp2-2.11.7+dfsg1/channels/rdpsnd/client/rdpsnd_main.c	2024-04-22 11:26:59.000000000 +0200
@@ -126,6 +126,10 @@
 	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_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 @@
 	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 @@
 
 	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 @@
 	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 @@
 		rdpsnd->totalPlaySize = 0;
 	}
 
-	return TRUE;
+	return rdpsnd_apply_volume(rdpsnd);
 }
 
 /**
@@ -710,7 +728,7 @@
  */
 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 @@
 	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 -Nru freerdp2-2.10.0+dfsg1/channels/rdpsnd/server/rdpsnd_main.c freerdp2-2.11.7+dfsg1/channels/rdpsnd/server/rdpsnd_main.c
--- freerdp2-2.10.0+dfsg1/channels/rdpsnd/server/rdpsnd_main.c	2023-02-16 10:55:03.000000000 +0100
+++ freerdp2-2.11.7+dfsg1/channels/rdpsnd/server/rdpsnd_main.c	2024-04-22 11:26:59.000000000 +0200
@@ -523,7 +523,7 @@
 	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 -Nru freerdp2-2.10.0+dfsg1/channels/tsmf/client/ffmpeg/tsmf_ffmpeg.c freerdp2-2.11.7+dfsg1/channels/tsmf/client/ffmpeg/tsmf_ffmpeg.c
--- freerdp2-2.10.0+dfsg1/channels/tsmf/client/ffmpeg/tsmf_ffmpeg.c	2023-02-16 10:55:03.000000000 +0100
+++ freerdp2-2.11.7+dfsg1/channels/tsmf/client/ffmpeg/tsmf_ffmpeg.c	2024-04-22 11:26:59.000000000 +0200
@@ -235,8 +235,10 @@
 		}
 	}
 
+#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 -Nru freerdp2-2.10.0+dfsg1/.clang-format freerdp2-2.11.7+dfsg1/.clang-format
--- freerdp2-2.10.0+dfsg1/.clang-format	2023-02-16 10:55:03.000000000 +0100
+++ freerdp2-2.11.7+dfsg1/.clang-format	2024-04-22 11:26:59.000000000 +0200
@@ -104,7 +104,6 @@
 ...
 Language:        ObjC
 PointerBindsToType: false
-ObjCSpaceAfterProperty: true
 SortIncludes: false
 ObjCBlockIndentWidth: 4
 ObjCSpaceAfterProperty: false
diff -Nru freerdp2-2.10.0+dfsg1/client/common/cmdline.c freerdp2-2.11.7+dfsg1/client/common/cmdline.c
--- freerdp2-2.10.0+dfsg1/client/common/cmdline.c	2023-02-16 10:55:03.000000000 +0100
+++ freerdp2-2.11.7+dfsg1/client/common/cmdline.c	2024-04-22 11:26:59.000000000 +0200
@@ -2728,7 +2728,10 @@
 			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")
 		{
@@ -2996,6 +2999,10 @@
 		{
 			settings->GrabKeyboard = enable;
 		}
+		CommandLineSwitchCase(arg, "grab-mouse")
+		{
+			settings->GrabMouse = enable;
+		}
 		CommandLineSwitchCase(arg, "unmap-buttons")
 		{
 			settings->UnmapButtons = enable;
diff -Nru freerdp2-2.10.0+dfsg1/client/common/cmdline.h freerdp2-2.11.7+dfsg1/client/common/cmdline.h
--- freerdp2-2.10.0+dfsg1/client/common/cmdline.h	2023-02-16 10:55:03.000000000 +0100
+++ freerdp2-2.11.7+dfsg1/client/common/cmdline.h	2024-04-22 11:26:59.000000000 +0200
@@ -184,6 +184,7 @@
 	{ "gp", COMMAND_LINE_VALUE_REQUIRED, "<password>", 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, "[[<domain>\\]<user>|<user>[@<domain>]]", NULL, NULL, -1,
diff -Nru freerdp2-2.10.0+dfsg1/client/Wayland/wlf_input.c freerdp2-2.11.7+dfsg1/client/Wayland/wlf_input.c
--- freerdp2-2.10.0+dfsg1/client/Wayland/wlf_input.c	2023-02-16 10:55:03.000000000 +0100
+++ freerdp2-2.11.7+dfsg1/client/Wayland/wlf_input.c	2024-04-22 11:26:59.000000000 +0200
@@ -135,25 +135,43 @@
 
 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;
-
-	if (!instance || !ev || !instance->input)
-		return FALSE;
+	uint32_t avalue = abs(value);
 
-	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 @@
 	 * 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 -Nru freerdp2-2.10.0+dfsg1/client/Wayland/wlf_input.h freerdp2-2.11.7+dfsg1/client/Wayland/wlf_input.h
--- freerdp2-2.10.0+dfsg1/client/Wayland/wlf_input.h	2023-02-16 10:55:03.000000000 +0100
+++ freerdp2-2.11.7+dfsg1/client/Wayland/wlf_input.h	2024-04-22 11:26:59.000000000 +0200
@@ -30,6 +30,9 @@
 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 -Nru freerdp2-2.10.0+dfsg1/client/Wayland/wlfreerdp.c freerdp2-2.11.7+dfsg1/client/Wayland/wlfreerdp.c
--- freerdp2-2.10.0+dfsg1/client/Wayland/wlfreerdp.c	2023-02-16 10:55:03.000000000 +0100
+++ freerdp2-2.11.7+dfsg1/client/Wayland/wlfreerdp.c	2024-04-22 11:26:59.000000000 +0200
@@ -362,12 +362,22 @@
 				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 @@
 	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 @@
 	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 -Nru freerdp2-2.10.0+dfsg1/client/Wayland/wlfreerdp.h freerdp2-2.11.7+dfsg1/client/Wayland/wlfreerdp.h
--- freerdp2-2.10.0+dfsg1/client/Wayland/wlfreerdp.h	2023-02-16 10:55:03.000000000 +0100
+++ freerdp2-2.11.7+dfsg1/client/Wayland/wlfreerdp.h	2024-04-22 11:26:59.000000000 +0200
@@ -53,6 +53,7 @@
 	wlfDispContext* disp;
 	wLog* log;
 	CRITICAL_SECTION critical;
+	wArrayList* events;
 };
 
 BOOL wlf_scale_coordinates(rdpContext* context, UINT32* px, UINT32* py, BOOL fromLocalToRDP);
diff -Nru freerdp2-2.10.0+dfsg1/client/X11/xf_gdi.c freerdp2-2.11.7+dfsg1/client/X11/xf_gdi.c
--- freerdp2-2.10.0+dfsg1/client/X11/xf_gdi.c	2023-02-16 10:55:03.000000000 +0100
+++ freerdp2-2.11.7+dfsg1/client/X11/xf_gdi.c	2024-04-22 11:26:59.000000000 +0200
@@ -1066,7 +1066,7 @@
 		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 -Nru freerdp2-2.10.0+dfsg1/client/X11/xf_gfx.c freerdp2-2.11.7+dfsg1/client/X11/xf_gfx.c
--- freerdp2-2.10.0+dfsg1/client/X11/xf_gfx.c	2023-02-16 10:55:03.000000000 +0100
+++ freerdp2-2.11.7+dfsg1/client/X11/xf_gfx.c	2024-04-22 11:26:59.000000000 +0200
@@ -288,7 +288,7 @@
 
 	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 @@
 		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 -Nru freerdp2-2.10.0+dfsg1/client/X11/xf_graphics.c freerdp2-2.11.7+dfsg1/client/X11/xf_graphics.c
--- freerdp2-2.10.0+dfsg1/client/X11/xf_graphics.c	2023-02-16 10:55:03.000000000 +0100
+++ freerdp2-2.11.7+dfsg1/client/X11/xf_graphics.c	2024-04-22 11:26:59.000000000 +0200
@@ -311,7 +311,7 @@
 		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 @@
 	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;
@@ -560,7 +560,7 @@
 	}
 
 	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 @@
 		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;
diff -Nru freerdp2-2.10.0+dfsg1/client/X11/xf_rail.c freerdp2-2.11.7+dfsg1/client/X11/xf_rail.c
--- freerdp2-2.10.0+dfsg1/client/X11/xf_rail.c	2023-02-16 10:55:03.000000000 +0100
+++ freerdp2-2.11.7+dfsg1/client/X11/xf_rail.c	2024-04-22 11:26:59.000000000 +0200
@@ -544,7 +544,7 @@
 
 	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 @@
 	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 -Nru freerdp2-2.10.0+dfsg1/cmake/ClangDetectTool.cmake freerdp2-2.11.7+dfsg1/cmake/ClangDetectTool.cmake
--- freerdp2-2.10.0+dfsg1/cmake/ClangDetectTool.cmake	1970-01-01 01:00:00.000000000 +0100
+++ freerdp2-2.11.7+dfsg1/cmake/ClangDetectTool.cmake	2024-04-22 11:26:59.000000000 +0200
@@ -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 -Nru freerdp2-2.10.0+dfsg1/cmake/ClangFormat.cmake freerdp2-2.11.7+dfsg1/cmake/ClangFormat.cmake
--- freerdp2-2.10.0+dfsg1/cmake/ClangFormat.cmake	2023-02-16 10:55:03.000000000 +0100
+++ freerdp2-2.11.7+dfsg1/cmake/ClangFormat.cmake	2024-04-22 11:26:59.000000000 +0200
@@ -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}
diff -Nru freerdp2-2.10.0+dfsg1/cmake/ConfigOptions.cmake freerdp2-2.11.7+dfsg1/cmake/ConfigOptions.cmake
--- freerdp2-2.10.0+dfsg1/cmake/ConfigOptions.cmake	2023-02-16 10:55:03.000000000 +0100
+++ freerdp2-2.11.7+dfsg1/cmake/ConfigOptions.cmake	2024-04-22 11:26:59.000000000 +0200
@@ -47,12 +47,12 @@
 	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_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 @@
 
 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 @@
 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_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 -Nru freerdp2-2.10.0+dfsg1/cmake/FindOpenSSL.cmake freerdp2-2.11.7+dfsg1/cmake/FindOpenSSL.cmake
--- freerdp2-2.10.0+dfsg1/cmake/FindOpenSSL.cmake	2023-02-16 10:55:03.000000000 +0100
+++ freerdp2-2.11.7+dfsg1/cmake/FindOpenSSL.cmake	2024-04-22 11:26:59.000000000 +0200
@@ -55,7 +55,7 @@
   NAMES
     openssl/ssl.h
   PATH_SUFFIXES
-	"include"
+    "include"
   HINTS
     ${_OPENSSL_INCLUDEDIR}
   ${_OPENSSL_ROOT_HINTS_AND_PATHS}
@@ -172,8 +172,8 @@
     )
 
     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 @@
 
     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")
+     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}")
+        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)
 
diff -Nru freerdp2-2.10.0+dfsg1/CMakeLists.txt freerdp2-2.11.7+dfsg1/CMakeLists.txt
--- freerdp2-2.10.0+dfsg1/CMakeLists.txt	2023-02-16 10:55:03.000000000 +0100
+++ freerdp2-2.11.7+dfsg1/CMakeLists.txt	2024-04-22 11:26:59.000000000 +0200
@@ -34,9 +34,9 @@
 	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/)
@@ -85,7 +85,7 @@
 endif()
 set(WITH_LIBRARY_VERSIONING "ON")
 
-set(RAW_VERSION_STRING "2.10.0")
+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)
@@ -225,7 +225,7 @@
 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)
diff -Nru freerdp2-2.10.0+dfsg1/debian/changelog freerdp2-2.11.7+dfsg1/debian/changelog
--- freerdp2-2.10.0+dfsg1/debian/changelog	2023-02-26 21:59:16.000000000 +0100
+++ freerdp2-2.11.7+dfsg1/debian/changelog	2025-02-01 09:00:48.000000000 +0100
@@ -1,3 +1,150 @@
+freerdp2 (2.11.7+dfsg1-6~deb12u1) bookworm-UNRELEASED; urgency=high
+
+  * Non-maintainer upload by the LTS Team for stable proposed updated.
+  * Revert time64_t transition commits, as they are not applicable to bookworm.
+  * Revert turning on keberos support.
+  * Reverting B-D: Depend on pkg-config instead of pkgconf.
+  * Do not use ffmpeg7 patch, bookworm is still at ffmpeg5.
+
+ -- Tobias Frost <tobi@debian.org>  Sat, 01 Feb 2025 09:00:48 +0100
+
+freerdp2 (2.11.7+dfsg1-6) unstable; urgency=medium
+
+  * Team upload
+  * d/tests/connect: use /cert-tofu to avoid errors with proxies
+
+ -- Adrien Nader <adrien.nader@canonical.com>  Wed, 18 Dec 2024 13:02:02 +0100
+
+freerdp2 (2.11.7+dfsg1-5) unstable; urgency=medium
+
+  * autopkgtest: add Depends: ca-certificates
+
+ -- Jeremy Bícha <jbicha@ubuntu.com>  Mon, 16 Dec 2024 22:57:23 -0500
+
+freerdp2 (2.11.7+dfsg1-4) unstable; urgency=medium
+
+  * Replace autopkgtests with the tests used by freerdp3 (Closes: #1079025)
+
+ -- Jeremy Bícha <jbicha@ubuntu.com>  Fri, 04 Oct 2024 16:21:36 -0400
+
+freerdp2 (2.11.7+dfsg1-3) unstable; urgency=high
+
+  * Team upload
+
+  [ Jeremy Bícha ]
+  * SECURITY UPDATE: NULL access and crash (Closes: #1072112
+    - debian/patches/CVE-2024-32661.patch: fix missing check in
+      rdp_write_logon_info_v1 in libfreerdp/core/info.c.
+    - CVE-2024-32661
+  * Cherry-pick several patches to fix build with gcc-14
+    (Closes: #1074969) (LP: #2075965)
+  * Remove obsolete 32-bit time transition lintian overrides
+
+  [ Sébastien Noel ]
+  * Add patch to fix build with ffmpeg 7 (Closes: #1072413)
+
+  [ Bernhard Übelacker ]
+  * Apply multiple fixes to autopkgtests (Closes: #1079025)
+
+ -- Jeremy Bícha <jbicha@ubuntu.com>  Thu, 03 Oct 2024 11:10:42 -0400
+
+freerdp2 (2.11.7+dfsg1-2) unstable; urgency=medium
+
+  * debian/tests/control:
+    + Add xauth. Fix tests on Debian, where xvfb does not pull-in xauth as
+      dependency (other than in Ubuntu).
+
+ -- Mike Gabriel <sunweaver@debian.org>  Sat, 20 Jul 2024 15:37:09 +0200
+
+freerdp2 (2.11.7+dfsg1-1) unstable; urgency=medium
+
+  [ Mike Gabriel ]
+  * New upstream release. (Closes: #1069728).
+    + 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.
+
+  [ Nathan Pratta Teodosio ]
+  * Add autopkgtest to test whether a client can connect
+    to an XRDP server via freerdp2 and that the login screen shows up
+    (Closes: #1073156) (LP: #2060976)
+
+ -- Mike Gabriel <sunweaver@debian.org>  Mon, 15 Jul 2024 16:46:25 +0200
+
+freerdp2 (2.11.5+dfsg1-1) unstable; urgency=medium
+
+  * New upstream release.
+    - CVE-2024-22211: Fix integer overflow in progressive decoder. (Closes:
+      #1061173).
+  * Upload time_t64 changes to unstable. (Closes: #1061952).
+  * debian/watch:
+    + Adjust so we only see 2.x release.
+  * debian/control:
+    + Switch from pkg-config to pkgconf. Thanks, lintian.
+
+ -- Mike Gabriel <sunweaver@debian.org>  Mon, 25 Mar 2024 16:09:04 +0100
+
+freerdp2 (2.11.2+dfsg1-1.1~exp2) experimental; urgency=medium
+
+  * Non-maintainer upload.
+  * Rename libraries for 64-bit time_t transition.
+  * Account for additional t64 Breaks/Replaces (Closes #1061982).
+
+ -- Lukas Märdian <slyon@debian.org>  Tue, 30 Jan 2024 13:19:02 +0000
+
+freerdp2 (2.11.2+dfsg1-1) unstable; urgency=medium
+
+  * New upstream release. (Closes: #1051638).
+  * Fixed security issues since v2.11.0:
+    - CVE-2023-40589: [codec,ncrush] fix index checks properly verify all
+      offsets while decoding data.
+    - CVE-2023-40567: Fix out-of-bounds write in the
+      `clear_decompress_bands_data` function.
+    - CVE-2023-40188: Fix out-of-bounds read in the `general_LumaToYUV444`
+      function.
+    - CVE-2023-40186: Fix out-of-bounds write in the `gdi_CreateSurface`
+      function.
+    - CVE-2023-40181: Fix out-of-bounds read in the `zgfx_decompress_segment`
+      function.
+    - CVE-2023-39356: Fix out-of-bounds read in the `gdi_multi_opaque_rect`
+      function.
+    - CVE-2023-39355: Fix use-after-free in processing
+      `RDPGFX_CMDID_RESETGRAPHICS` packets.
+    - CVE-2023-39354: Fix out-of-bounds read in the `nsc_rle_decompress_data`
+      function.
+    - CVE-2023-39353: Fix missing offset validation leading to out-of-bounds
+      read in the `libfreerdp/codec/rfx.c` file.
+    - CVE-2023-39352: Fix invalid offset validation leading to out-of-bounds
+      write.
+    - CVE-2023-39351: Fix null-pointer-dereference leading a crash in the
+      RemoteFX (rfx) handling.
+    - CVE-2023-39350: Fix integer underflow leading to DOS (e.g. abort due to
+      `WINPR_ASSERT` with default compilation flags).
+  * debian/patches:
+    + Drop 0001_fix_ftbfs_1041377.patch. Applied upstream.
+  * debian/control:
+    + Add B-D: libkrb5-dev.
+  * debian/rules:
+    + Add -DWITH_KERBEROS=ON configure option. (Closes: #1036095).
+  * debian/watch:
+    + Rework file. Find all released versions of freerdp2. (Closes: #1053317).
+      Thanks to Tobias Frost for sending a patch.
+
+ -- Mike Gabriel <sunweaver@debian.org>  Sun, 01 Oct 2023 23:21:15 +0200
+
+freerdp2 (2.10.0+dfsg1-1.1) unstable; urgency=medium
+
+  * Non-maintainer upload.
+  * debian/patches/0001_fix_ftbfs_1041377.patch:
+    - include upstream fix for FTBFS with FFmpeg 6.0
+      (Closes: #1041377)
+
+ -- Héctor Orón Martínez <zumbi@debian.org>  Fri, 04 Aug 2023 04:08:40 -0400
+
 freerdp2 (2.10.0+dfsg1-1) unstable; urgency=medium
 
   * New upstream release.
diff -Nru freerdp2-2.10.0+dfsg1/debian/control freerdp2-2.11.7+dfsg1/debian/control
--- freerdp2-2.10.0+dfsg1/debian/control	2023-02-26 21:51:31.000000000 +0100
+++ freerdp2-2.11.7+dfsg1/debian/control	2025-02-01 09:00:48.000000000 +0100
@@ -90,8 +90,10 @@
  ${shlibs:Depends},
  libwinpr2-2 (= ${binary:Version}),
 Breaks:
+ libfreerdp2-2 (<< ${source:Version}),
  libfreerdp2 (<< 2.0.0~git20170725.1.1648deb+dfsg1-1~),
 Replaces:
+ libfreerdp2-2,
  libfreerdp2 (<< 2.0.0~git20170725.1.1648deb+dfsg1-1~),
 Multi-Arch: same
 Suggests:
@@ -112,8 +114,10 @@
  ${shlibs:Depends},
  libfreerdp2-2 (= ${binary:Version}),
 Breaks:
+ libfreerdp-client2-2 (<< ${source:Version}),
  libfreerdp-client2 (<< 2.0.0~git20170725.1.1648deb+dfsg1-1~),
 Replaces:
+ libfreerdp-client2-2,
  libfreerdp-client2 (<< 2.0.0~git20170725.1.1648deb+dfsg1-1~),
 Multi-Arch: same
 Description: Free Remote Desktop Protocol library (client library)
@@ -132,8 +136,10 @@
  ${shlibs:Depends},
  libfreerdp2-2 (= ${binary:Version}),
 Breaks:
+ libfreerdp-server2-2 (<< ${source:Version}),
  libfreerdp-server2 (<< 2.0.0~git20170725.1.1648deb+dfsg1-1~),
 Replaces:
+ libfreerdp-server2-2,
  libfreerdp-server2 (<< 2.0.0~git20170725.1.1648deb+dfsg1-1~),
 Multi-Arch: same
 Description: Free Remote Desktop Protocol library (server library)
@@ -151,8 +157,10 @@
  ${misc:Depends},
  ${shlibs:Depends},
 Breaks:
+ libwinpr2-2 (<< ${source:Version}),
  libwinpr2 (<< 2.0.0~git20170725.1.1648deb+dfsg1-1~),
 Replaces:
+ libwinpr2-2,
  libwinpr2 (<< 2.0.0~git20170725.1.1648deb+dfsg1-1~),
 Multi-Arch: same
 Suggests:
@@ -179,8 +187,10 @@
  ${shlibs:Depends},
  libwinpr2-2 (= ${binary:Version}),
 Breaks:
+ libwinpr-tools2-2 (<< ${source:Version}),
  libwinpr-tools2 (<< 2.0.0~git20170725.1.1648deb+dfsg1-1~),
 Replaces:
+ libwinpr-tools2-2,
  libwinpr-tools2 (<< 2.0.0~git20170725.1.1648deb+dfsg1-1~),
 Multi-Arch: same
 Description: Windows Portable Runtime Tools library
@@ -260,8 +270,10 @@
  libfreerdp-server2-2 (= ${binary:Version}),
  libwinpr-tools2-2 (= ${binary:Version}),
 Breaks:
+ libfreerdp-shadow2-2 (<< ${source:Version}),
  libfreerdp-shadow2 (<< 2.0.0~git20170725.1.1648deb+dfsg1-1~),
 Replaces:
+ libfreerdp-shadow2-2,
  libfreerdp-shadow2 (<< 2.0.0~git20170725.1.1648deb+dfsg1-1~),
 Multi-Arch: same
 Description: FreeRDP Remote Desktop Protocol shadow libraries
@@ -280,8 +292,10 @@
  ${shlibs:Depends},
  libfreerdp-shadow2-2 (= ${binary:Version}),
 Breaks:
+ libfreerdp-shadow-subsystem2-2 (<< ${source:Version}),
  libfreerdp-shadow2 (<< 2.0.0~git20170725.1.1648deb+dfsg1-1~),
 Replaces:
+ libfreerdp-shadow-subsystem2-2,
  libfreerdp-shadow2 (<< 2.0.0~git20170725.1.1648deb+dfsg1-1~),
 Multi-Arch: same
 Description: FreeRDP Remote Desktop Protocol shadow subsystem libraries
@@ -315,8 +329,10 @@
  ${shlibs:Depends},
  libfreerdp2-2 (= ${binary:Version}),
 Breaks:
+ libuwac0-0 (<< ${source:Version}),
  libuwac0 (<< 2.0.0~git20170725.1.1648deb+dfsg1-1~),
 Replaces:
+ libuwac0-0,
  libuwac0 (<< 2.0.0~git20170725.1.1648deb+dfsg1-1~),
 Multi-Arch: same
 Description: Using wayland as a client library
diff -Nru freerdp2-2.10.0+dfsg1/debian/patches/0001-info-Fix-incompatible-pointer-type.patch freerdp2-2.11.7+dfsg1/debian/patches/0001-info-Fix-incompatible-pointer-type.patch
--- freerdp2-2.10.0+dfsg1/debian/patches/0001-info-Fix-incompatible-pointer-type.patch	1970-01-01 01:00:00.000000000 +0100
+++ freerdp2-2.11.7+dfsg1/debian/patches/0001-info-Fix-incompatible-pointer-type.patch	2025-02-01 09:00:48.000000000 +0100
@@ -0,0 +1,32 @@
+From: Alessandro Bono <alessandro.bono369@gmail.com>
+Date: Wed, 8 May 2024 16:06:17 +0200
+Subject: 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);
+```
+
+(cherry picked from commit 4f411197dc9d2076f00748b1178a60b2423030bf)
+---
+ 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 9aaa6cf..c9b2fc6 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;
diff -Nru freerdp2-2.10.0+dfsg1/debian/patches/0002-redirection-Fix-incompatible-pointer-type.patch freerdp2-2.11.7+dfsg1/debian/patches/0002-redirection-Fix-incompatible-pointer-type.patch
--- freerdp2-2.10.0+dfsg1/debian/patches/0002-redirection-Fix-incompatible-pointer-type.patch	1970-01-01 01:00:00.000000000 +0100
+++ freerdp2-2.11.7+dfsg1/debian/patches/0002-redirection-Fix-incompatible-pointer-type.patch	2025-02-01 09:00:48.000000000 +0100
@@ -0,0 +1,38 @@
+From: Alessandro Bono <alessandro.bono369@gmail.com>
+Date: Wed, 8 May 2024 16:06:26 +0200
+Subject: 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)
+      |                                   ~~~~~~~^~~
+```
+
+(cherry picked from commit f3ed1f1ac367eb21f93c9fba5047447fdccdb5cc)
+---
+ 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 59c6dbc..63bc8cc 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);
+ 
diff -Nru freerdp2-2.10.0+dfsg1/debian/patches/0003-redirection-Fix-incompatible-pointer-type.patch freerdp2-2.11.7+dfsg1/debian/patches/0003-redirection-Fix-incompatible-pointer-type.patch
--- freerdp2-2.10.0+dfsg1/debian/patches/0003-redirection-Fix-incompatible-pointer-type.patch	1970-01-01 01:00:00.000000000 +0100
+++ freerdp2-2.11.7+dfsg1/debian/patches/0003-redirection-Fix-incompatible-pointer-type.patch	2025-02-01 09:00:48.000000000 +0100
@@ -0,0 +1,33 @@
+From: Alessandro Bono <alessandro.bono369@gmail.com>
+Date: Wed, 8 May 2024 16:06:30 +0200
+Subject: 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;
+      |                               ^
+```
+
+(cherry picked from commit 7894a7dfc5f811cb5dacc57a09236c11744b1ec8)
+---
+ 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 63bc8cc..4872d4b 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:
diff -Nru freerdp2-2.10.0+dfsg1/debian/patches/0004-X11-fix-pointer-integer-type-mismatch.patch freerdp2-2.11.7+dfsg1/debian/patches/0004-X11-fix-pointer-integer-type-mismatch.patch
--- freerdp2-2.10.0+dfsg1/debian/patches/0004-X11-fix-pointer-integer-type-mismatch.patch	1970-01-01 01:00:00.000000000 +0100
+++ freerdp2-2.11.7+dfsg1/debian/patches/0004-X11-fix-pointer-integer-type-mismatch.patch	2025-02-01 09:00:48.000000000 +0100
@@ -0,0 +1,24 @@
+From: Mike Gilbert <floppym@gentoo.org>
+Date: Wed, 22 May 2024 17:04:43 -0400
+Subject: X11: fix pointer/integer type mismatch
+
+Fixed on master in 2da280b8a1748052b70b3f5a1ef0d8e932c33adc.
+
+(cherry picked from commit d2b6771c748e54e659d5f1243a92e499c3beaa36)
+---
+ 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 5aa1fd4..fe81e0e 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;
+ }
+ 
diff -Nru freerdp2-2.10.0+dfsg1/debian/patches/0005-client-wayland-fix-const-correctness.patch freerdp2-2.11.7+dfsg1/debian/patches/0005-client-wayland-fix-const-correctness.patch
--- freerdp2-2.10.0+dfsg1/debian/patches/0005-client-wayland-fix-const-correctness.patch	1970-01-01 01:00:00.000000000 +0100
+++ freerdp2-2.11.7+dfsg1/debian/patches/0005-client-wayland-fix-const-correctness.patch	2025-02-01 09:00:48.000000000 +0100
@@ -0,0 +1,22 @@
+From: akallabeth <akallabeth@posteo.net>
+Date: Thu, 23 May 2024 09:30:33 +0200
+Subject: [client,wayland] fix const correctness
+
+(cherry picked from commit 67818bddb31900cdf3acb26cb0b673cc90b71cc9)
+---
+ 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 65e29bc..5988aed 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;
diff -Nru freerdp2-2.10.0+dfsg1/debian/patches/0006-warnings-fix-Wincompatible-pointer-types.patch freerdp2-2.11.7+dfsg1/debian/patches/0006-warnings-fix-Wincompatible-pointer-types.patch
--- freerdp2-2.10.0+dfsg1/debian/patches/0006-warnings-fix-Wincompatible-pointer-types.patch	1970-01-01 01:00:00.000000000 +0100
+++ freerdp2-2.11.7+dfsg1/debian/patches/0006-warnings-fix-Wincompatible-pointer-types.patch	2025-02-01 09:00:48.000000000 +0100
@@ -0,0 +1,89 @@
+From: Armin Novak <armin.novak@thincast.com>
+Date: Thu, 8 Aug 2024 11:03:24 +0200
+Subject: [warnings] fix -Wincompatible-pointer-types
+
+(cherry picked from commit 5b2b53b15c9af46b85c4ef0007e7fb59d7608289)
+---
+ 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 943d0fa..fc61f9b 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 ef67914..80df188 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 dc3533a..acbec01 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;
+ 		}
+ 
diff -Nru freerdp2-2.10.0+dfsg1/debian/patches/0007-server-proxy-deactivate-capture-module.patch freerdp2-2.11.7+dfsg1/debian/patches/0007-server-proxy-deactivate-capture-module.patch
--- freerdp2-2.10.0+dfsg1/debian/patches/0007-server-proxy-deactivate-capture-module.patch	1970-01-01 01:00:00.000000000 +0100
+++ freerdp2-2.11.7+dfsg1/debian/patches/0007-server-proxy-deactivate-capture-module.patch	2025-02-01 09:00:48.000000000 +0100
@@ -0,0 +1,48 @@
+From: Armin Novak <armin.novak@thincast.com>
+Date: Thu, 8 Aug 2024 11:06:54 +0200
+Subject: [server,proxy] deactivate capture module
+
+the module does not work (and did not for a long time)
+
+(cherry picked from commit be23ed4ba990bd39391a651444fbb9130722c93b)
+---
+ 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 80ba3b7..4004aaa 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}")
diff -Nru freerdp2-2.10.0+dfsg1/debian/patches/1000-ffmpeg7.patch freerdp2-2.11.7+dfsg1/debian/patches/1000-ffmpeg7.patch
--- freerdp2-2.10.0+dfsg1/debian/patches/1000-ffmpeg7.patch	1970-01-01 01:00:00.000000000 +0100
+++ freerdp2-2.11.7+dfsg1/debian/patches/1000-ffmpeg7.patch	2025-02-01 09:00:48.000000000 +0100
@@ -0,0 +1,114 @@
+From: =?utf-8?q?S=C3=A9bastien_Noel?= <sebastien@twolife.be>
+Date: Tue, 30 Jul 2024 11:29:58 +0200
+Subject: Fix build with ffmpeg 7
+
+cherry picked from d0c5b1ae4289c7f3cde3fbc031cb4a3160df05ff
+from freerdp3
+---
+ libfreerdp/codec/dsp_ffmpeg.c | 28 ++++++++++------------------
+ 1 file changed, 10 insertions(+), 18 deletions(-)
+
+diff --git a/libfreerdp/codec/dsp_ffmpeg.c b/libfreerdp/codec/dsp_ffmpeg.c
+index 80df188..68dfe5f 100644
+--- a/libfreerdp/codec/dsp_ffmpeg.c
++++ b/libfreerdp/codec/dsp_ffmpeg.c
+@@ -225,18 +225,15 @@ static void ffmpeg_close_context(FREERDP_DSP_CONTEXT* context)
+ static BOOL ffmpeg_open_context(FREERDP_DSP_CONTEXT* context)
+ {
+ 	int ret;
+-	int layout;
+-	const AUDIO_FORMAT* format;
+ 
+ 	if (!context || context->isOpen)
+ 		return FALSE;
+ 
+-	format = &context->format;
++	const AUDIO_FORMAT* format = &context->format;
+ 
+ 	if (!format)
+ 		return FALSE;
+ 
+-	layout = av_get_default_channel_layout(format->nChannels);
+ 	context->id = ffmpeg_get_avcodec(format);
+ 
+ 	if (ffmpeg_codec_is_filtered(context->id, context->encoder))
+@@ -270,8 +267,7 @@ static BOOL ffmpeg_open_context(FREERDP_DSP_CONTEXT* context)
+ 			break;
+ 	}
+ 
+-	context->context->channels = format->nChannels;
+-	context->context->channel_layout = layout;
++	av_channel_layout_default(&context->context->ch_layout, format->nChannels);
+ 	context->context->sample_rate = format->nSamplesPerSec;
+ 	context->context->block_align = format->nBlockAlign;
+ 	context->context->bit_rate = format->nAvgBytesPerSec * 8;
+@@ -314,8 +310,7 @@ static BOOL ffmpeg_open_context(FREERDP_DSP_CONTEXT* context)
+ 	if (!context->rcontext)
+ 		goto fail;
+ 
+-	context->frame->channel_layout = layout;
+-	context->frame->channels = format->nChannels;
++	av_channel_layout_default(&context->frame->ch_layout, format->nChannels);
+ 	context->frame->sample_rate = format->nSamplesPerSec;
+ 	context->frame->format = AV_SAMPLE_FMT_S16;
+ 
+@@ -330,13 +325,11 @@ static BOOL ffmpeg_open_context(FREERDP_DSP_CONTEXT* context)
+ 		context->resampled->sample_rate = format->nSamplesPerSec;
+ 	}
+ 
+-	context->resampled->channel_layout = layout;
+-	context->resampled->channels = format->nChannels;
++	av_channel_layout_default(&context->resampled->ch_layout, format->nChannels);
+ 
+ 	if (context->context->frame_size > 0)
+ 	{
+-		context->buffered->channel_layout = context->resampled->channel_layout;
+-		context->buffered->channels = context->resampled->channels;
++		av_channel_layout_copy(&context->buffered->ch_layout, &context->resampled->ch_layout);
+ 		context->buffered->format = context->resampled->format;
+ 		context->buffered->nb_samples = context->context->frame_size;
+ 
+@@ -421,7 +414,7 @@ static BOOL ffmpeg_encode_frame(AVCodecContext* context, AVFrame* in, AVPacket*
+ 	if (in->format == AV_SAMPLE_FMT_FLTP)
+ 	{
+ 		uint8_t** pp = in->extended_data;
+-		for (int y = 0; y < in->channels; y++)
++		for (int y = 0; y < in->ch_layout.nb_channels; y++)
+ 		{
+ 			float* data = (float*)pp[y];
+ 			for (int x = 0; x < in->nb_samples; x++)
+@@ -477,14 +470,13 @@ static BOOL ffmpeg_fill_frame(AVFrame* frame, const AUDIO_FORMAT* inputFormat, c
+                               size_t size)
+ {
+ 	int ret, bpp;
+-	frame->channels = inputFormat->nChannels;
++	av_channel_layout_default(&frame->ch_layout, inputFormat->nChannels);
+ 	frame->sample_rate = inputFormat->nSamplesPerSec;
+ 	frame->format = ffmpeg_sample_format(inputFormat);
+-	frame->channel_layout = av_get_default_channel_layout(frame->channels);
+ 	bpp = av_get_bytes_per_sample(frame->format);
+ 	frame->nb_samples = size / inputFormat->nChannels / bpp;
+ 
+-	if ((ret = avcodec_fill_audio_frame(frame, frame->channels, frame->format, data, size, 1)) < 0)
++	if ((ret = avcodec_fill_audio_frame(frame, inputFormat->nChannels, frame->format, data, size, 1)) < 0)
+ 	{
+ 		const char* err = av_err2str(ret);
+ 		WLog_ERR(TAG, "Error during audio frame fill %s [%d]", err, ret);
+@@ -566,7 +558,7 @@ static BOOL ffmpeg_decode(AVCodecContext* dec_ctx, AVPacket* pkt, AVFrame* frame
+ 		}
+ 
+ 		{
+-			const size_t data_size = resampled->channels * resampled->nb_samples * 2;
++			const size_t data_size = resampled->ch_layout.nb_channels * resampled->nb_samples * 2;
+ 			Stream_EnsureRemainingCapacity(out, data_size);
+ 			Stream_Write(out, resampled->data[0], data_size);
+ 		}
+@@ -664,7 +656,7 @@ BOOL freerdp_dsp_ffmpeg_encode(FREERDP_DSP_CONTEXT* context, const AUDIO_FORMAT*
+ 			rc =
+ 			    av_samples_copy(context->buffered->extended_data, context->resampled->extended_data,
+ 			                    (int)context->bufferedSamples, copied, inSamples,
+-			                    context->context->channels, context->context->sample_fmt);
++			                    context->context->ch_layout.nb_channels, context->context->sample_fmt);
+ 			rest -= inSamples;
+ 			copied += inSamples;
+ 			context->bufferedSamples += (UINT32)inSamples;
diff -Nru freerdp2-2.10.0+dfsg1/debian/patches/CVE-2024-32661.patch freerdp2-2.11.7+dfsg1/debian/patches/CVE-2024-32661.patch
--- freerdp2-2.10.0+dfsg1/debian/patches/CVE-2024-32661.patch	1970-01-01 01:00:00.000000000 +0100
+++ freerdp2-2.11.7+dfsg1/debian/patches/CVE-2024-32661.patch	2025-02-01 09:00:48.000000000 +0100
@@ -0,0 +1,24 @@
+From: akallabeth <akallabeth@posteo.net>
+Date: Sun, 21 Apr 2024 13:56:13 +0200
+Subject: fix missing check in rdp_write_logon_info_v1
+
+(cherrypicked 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 c9b2fc6..dc72b61 100644
+--- a/libfreerdp/core/info.c
++++ b/libfreerdp/core/info.c
+@@ -1322,6 +1322,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)
diff -Nru freerdp2-2.10.0+dfsg1/debian/patches/series freerdp2-2.11.7+dfsg1/debian/patches/series
--- freerdp2-2.10.0+dfsg1/debian/patches/series	1970-01-01 01:00:00.000000000 +0100
+++ freerdp2-2.11.7+dfsg1/debian/patches/series	2025-02-01 09:00:48.000000000 +0100
@@ -0,0 +1,9 @@
+0001-info-Fix-incompatible-pointer-type.patch
+0002-redirection-Fix-incompatible-pointer-type.patch
+0003-redirection-Fix-incompatible-pointer-type.patch
+0004-X11-fix-pointer-integer-type-mismatch.patch
+0005-client-wayland-fix-const-correctness.patch
+0006-warnings-fix-Wincompatible-pointer-types.patch
+0007-server-proxy-deactivate-capture-module.patch
+#1000-ffmpeg7.patch
+CVE-2024-32661.patch
diff -Nru freerdp2-2.10.0+dfsg1/debian/tests/connect freerdp2-2.11.7+dfsg1/debian/tests/connect
--- freerdp2-2.10.0+dfsg1/debian/tests/connect	1970-01-01 01:00:00.000000000 +0100
+++ freerdp2-2.11.7+dfsg1/debian/tests/connect	2025-02-01 09:00:48.000000000 +0100
@@ -0,0 +1,22 @@
+#!/bin/sh -x
+isNaturalNumber(){
+    case "$1" in
+        ''|*[!0-9]*) return 0;;
+        *) return 1;;
+    esac
+}
+
+sudo systemctl start xrdp
+# XXX: Is there a better way to get the port number other than by parsing the
+# configuration file?
+port=$(sed -n '/^port=[0123456789]/{s/port=//p;q;}' /etc/xrdp/xrdp.ini)
+if test ! isNaturalNumber "$port"; then
+    exit 1
+fi
+
+timeout 2s xvfb-run -l xfreerdp /v:localhost:"$port" /p: /u: /d: /cert-tofu
+if test $? != 124; then
+    2>&1 printf "%s\n" "Xfreerdp exited before the timeout, it has likely " \
+                       "failed to connect. The test has therefore failed."
+    exit 2
+fi
diff -Nru freerdp2-2.10.0+dfsg1/debian/tests/control freerdp2-2.11.7+dfsg1/debian/tests/control
--- freerdp2-2.10.0+dfsg1/debian/tests/control	1970-01-01 01:00:00.000000000 +0100
+++ freerdp2-2.11.7+dfsg1/debian/tests/control	2025-02-01 09:00:48.000000000 +0100
@@ -0,0 +1,3 @@
+Tests: connect
+Depends: @, ca-certificates, xauth, xrdp, xvfb
+Restrictions: allow-stderr, needs-sudo
diff -Nru freerdp2-2.10.0+dfsg1/debian/watch freerdp2-2.11.7+dfsg1/debian/watch
--- freerdp2-2.10.0+dfsg1/debian/watch	2022-08-16 23:17:34.000000000 +0200
+++ freerdp2-2.11.7+dfsg1/debian/watch	2025-02-01 09:00:48.000000000 +0100
@@ -3,5 +3,5 @@
 filenamemangle=s/.*\/v?([\d\.-]+)\.tar\.gz/freerdp-$1.tar.gz/,\
 dversionmangle=s/\+dfsg1//,\
 repacksuffix=+dfsg1 \
-https://github.com/FreeRDP/FreeRDP/tags .*/archive/refs/tags/v?([\d\.]+).tar.gz \
+https://github.com/FreeRDP/FreeRDP/tags .*/archive/refs/tags/v?(2\.[\d\.]+).tar.gz \
 debian
diff -Nru freerdp2-2.10.0+dfsg1/include/freerdp/channels/rdpdr.h freerdp2-2.11.7+dfsg1/include/freerdp/channels/rdpdr.h
--- freerdp2-2.10.0+dfsg1/include/freerdp/channels/rdpdr.h	2023-02-16 10:55:03.000000000 +0100
+++ freerdp2-2.11.7+dfsg1/include/freerdp/channels/rdpdr.h	2024-04-22 11:26:59.000000000 +0200
@@ -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 -Nru freerdp2-2.10.0+dfsg1/include/freerdp/settings.h freerdp2-2.11.7+dfsg1/include/freerdp/settings.h
--- freerdp2-2.10.0+dfsg1/include/freerdp/settings.h	2023-02-16 10:55:03.000000000 +0100
+++ freerdp2-2.11.7+dfsg1/include/freerdp/settings.h	2024-04-22 11:26:59.000000000 +0200
@@ -730,6 +730,7 @@
 #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 @@
 	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 -Nru freerdp2-2.10.0+dfsg1/libfreerdp/cache/pointer.c freerdp2-2.11.7+dfsg1/libfreerdp/cache/pointer.c
--- freerdp2-2.10.0+dfsg1/libfreerdp/cache/pointer.c	2023-02-16 10:55:03.000000000 +0100
+++ freerdp2-2.11.7+dfsg1/libfreerdp/cache/pointer.c	2024-04-22 11:26:59.000000000 +0200
@@ -68,6 +68,9 @@
 	    !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 -Nru freerdp2-2.10.0+dfsg1/libfreerdp/codec/clear.c freerdp2-2.11.7+dfsg1/libfreerdp/codec/clear.c
--- freerdp2-2.10.0+dfsg1/libfreerdp/codec/clear.c	2023-02-16 10:55:03.000000000 +0100
+++ freerdp2-2.11.7+dfsg1/libfreerdp/codec/clear.c	2024-04-22 11:26:59.000000000 +0200
@@ -410,7 +410,7 @@
 			}
 		}
 
-		if ((pixelIndex + runLengthFactor) > pixelCount)
+		if ((pixelIndex >= pixelCount) || (runLengthFactor > (pixelCount - pixelIndex)))
 		{
 			WLog_ERR(TAG,
 			         "pixelIndex %" PRIu32 " + runLengthFactor %" PRIu32 " > pixelCount %" PRIu32
@@ -512,12 +512,12 @@
 		{
 			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;
 				}
@@ -566,7 +566,7 @@
 		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)
 		{
@@ -591,13 +591,9 @@
 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 @@
 		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 @@
 		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 @@
 
 		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 @@
 				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 @@
 
 				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;
@@ -827,8 +821,15 @@
 					count = (vBarPixelCount > y) ? (vBarPixelCount - y) : 0;
 
 				if (count > 0)
-					pSrcPixel =
-					    &vBarShortEntry->pixels[(y - vBarYOn) * GetBytesPerPixel(clear->format)];
+				{
+					const size_t offset = (1ull * 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++)
 				{
@@ -868,28 +869,31 @@
 					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);
 				}
 			}
 		}
@@ -980,7 +984,7 @@
 		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)
 			{
@@ -1117,7 +1121,7 @@
 	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;
diff -Nru freerdp2-2.10.0+dfsg1/libfreerdp/codec/color.c freerdp2-2.11.7+dfsg1/libfreerdp/codec/color.c
--- freerdp2-2.10.0+dfsg1/libfreerdp/codec/color.c	2023-02-16 10:55:03.000000000 +0100
+++ freerdp2-2.11.7+dfsg1/libfreerdp/codec/color.c	2024-04-22 11:26:59.000000000 +0200
@@ -56,7 +56,7 @@
 	 * 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 @@
 	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)
@@ -613,6 +613,9 @@
 	if (!pDstData || !pSrcData)
 		return FALSE;
 
+	if ((nWidth == 0) || (nHeight == 0))
+		return TRUE;
+
 	if (nDstStep == 0)
 		nDstStep = nWidth * GetBytesPerPixel(DstFormat);
 
@@ -728,21 +731,22 @@
 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);
+		memcpy(pDstLine, pFirstDstLineXOffset, 1ull * nWidth * bpp);
 	}
 
 	return TRUE;
diff -Nru freerdp2-2.10.0+dfsg1/libfreerdp/codec/dsp_ffmpeg.c freerdp2-2.11.7+dfsg1/libfreerdp/codec/dsp_ffmpeg.c
--- freerdp2-2.10.0+dfsg1/libfreerdp/codec/dsp_ffmpeg.c	2023-02-16 10:55:03.000000000 +0100
+++ freerdp2-2.11.7+dfsg1/libfreerdp/codec/dsp_ffmpeg.c	2024-04-22 11:26:59.000000000 +0200
@@ -418,9 +418,29 @@
 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 -Nru freerdp2-2.10.0+dfsg1/libfreerdp/codec/h264.c freerdp2-2.11.7+dfsg1/libfreerdp/codec/h264.c
--- freerdp2-2.10.0+dfsg1/libfreerdp/codec/h264.c	2023-02-16 10:55:03.000000000 +0100
+++ freerdp2-2.11.7+dfsg1/libfreerdp/codec/h264.c	2024-04-22 11:26:59.000000000 +0200
@@ -63,9 +63,9 @@
 		_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 -Nru freerdp2-2.10.0+dfsg1/libfreerdp/codec/h264_ffmpeg.c freerdp2-2.11.7+dfsg1/libfreerdp/codec/h264_ffmpeg.c
--- freerdp2-2.10.0+dfsg1/libfreerdp/codec/h264_ffmpeg.c	2023-02-16 10:55:03.000000000 +0100
+++ freerdp2-2.11.7+dfsg1/libfreerdp/codec/h264_ffmpeg.c	2024-04-22 11:26:59.000000000 +0200
@@ -529,10 +529,12 @@
 			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
 
diff -Nru freerdp2-2.10.0+dfsg1/libfreerdp/codec/include/bitmap.c freerdp2-2.11.7+dfsg1/libfreerdp/codec/include/bitmap.c
--- freerdp2-2.10.0+dfsg1/libfreerdp/codec/include/bitmap.c	2023-02-16 10:55:03.000000000 +0100
+++ freerdp2-2.11.7+dfsg1/libfreerdp/codec/include/bitmap.c	2024-04-22 11:26:59.000000000 +0200
@@ -31,7 +31,10 @@
 	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 @@
 			data = xorPixel;
 
 		DESTWRITEPIXEL(pbDest, data);
-		DESTNEXTPIXEL(pbDest);
 		mask = mask << 1;
 	});
 	return pbDest;
@@ -62,7 +64,10 @@
 	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 @@
 			data = BLACK_PIXEL;
 
 		DESTWRITEPIXEL(pbDest, data);
-		DESTNEXTPIXEL(pbDest);
 		mask = mask << 1;
 	});
 	return pbDest;
@@ -88,6 +92,9 @@
 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 @@
 	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 @@
 		*/
 		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 @@
 						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 @@
 						return FALSE;
 
 					DESTWRITEPIXEL(pbDest, temp ^ fgPel);
-					DESTNEXTPIXEL(pbDest);
 					runLength--;
 				}
 
@@ -176,7 +193,6 @@
 				UNROLL(runLength, {
 					DESTREADPIXEL(temp, pbDest - rowDelta);
 					DESTWRITEPIXEL(pbDest, temp);
-					DESTNEXTPIXEL(pbDest);
 				});
 			}
 
@@ -196,15 +212,16 @@
 			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 @@
 
 				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 @@
 			/* 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 @@
 			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 @@
 				{
 					while (runLength > 8)
 					{
-						bitmask = *pbSrc;
-						pbSrc = pbSrc + 1;
+						bitmask = *pbSrc++;
+
 						pbDest = WRITEFGBGIMAGE(pbDest, pbDestEnd, rowDelta, bitmask, fgPel, 8);
 
 						if (!pbDest)
@@ -319,8 +331,9 @@
 
 				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 @@
 			/* 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 @@
 
 			/* 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 @@
 
 			/* 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 -Nru freerdp2-2.10.0+dfsg1/libfreerdp/codec/interleaved.c freerdp2-2.11.7+dfsg1/libfreerdp/codec/interleaved.c
--- freerdp2-2.10.0+dfsg1/libfreerdp/codec/interleaved.c	2023-02-16 10:55:03.000000000 +0100
+++ freerdp2-2.11.7+dfsg1/libfreerdp/codec/interleaved.c	2024-04-22 11:26:59.000000000 +0200
@@ -21,6 +21,7 @@
  * limitations under the License.
  */
 
+#include <winpr/assert.h>
 #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_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 @@
 /**
  * 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, 2, 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, 2, 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, 3, 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, 2, 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 @@
 		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 @@
 	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_16(BYTE* _buf, UINT16 _pix)
 {
+	WINPR_ASSERT(_buf);
 	_buf[0] = _pix & 0xFF;
 	_buf[1] = (_pix >> 8) & 0xFF;
 }
@@ -239,19 +416,30 @@
 #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 @@
 #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 @@
 #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 @@
 #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 @@
 
 	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 @@
 		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 @@
                           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 @@
 	}
 
 	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 @@
 
 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 @@
 
 	_aligned_free(interleaved->TempBuffer);
 	Stream_Free(interleaved->bts, TRUE);
-	free(interleaved);
+	_aligned_free(interleaved);
 }
diff -Nru freerdp2-2.10.0+dfsg1/libfreerdp/codec/ncrush.c freerdp2-2.11.7+dfsg1/libfreerdp/codec/ncrush.c
--- freerdp2-2.10.0+dfsg1/libfreerdp/codec/ncrush.c	2023-02-16 10:55:03.000000000 +0100
+++ freerdp2-2.11.7+dfsg1/libfreerdp/codec/ncrush.c	2024-04-22 11:26:59.000000000 +0200
@@ -1994,15 +1994,9 @@
                       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 @@
 	UINT32 LengthOfMatch;
 	UINT32 CopyOffsetIndex;
 	UINT32 OffsetCacheIndex;
-	BYTE* HistoryPtr;
-	BYTE* HistoryBuffer;
-	BYTE* HistoryBufferEnd;
 	UINT32 CopyOffsetBits;
 	UINT32 CopyOffsetBase;
 	UINT32 LengthOfMatchBits;
@@ -2021,8 +2012,8 @@
 	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 @@
 		ZeroMemory(&(ncrush->OffsetCache), sizeof(ncrush->OffsetCache));
 	}
 
-	HistoryPtr = ncrush->HistoryPtr;
+	BYTE* HistoryPtr = ncrush->HistoryPtr;
 
 	if (!(flags & PACKET_COMPRESSED))
 	{
@@ -2050,17 +2041,25 @@
 		return 1;
 	}
 
-	SrcEnd = &pSrcData[SrcSize];
-	nbits = 32;
-	bits = get_dword(pSrcData);
-	SrcPtr = pSrcData + 4;
+	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;
 
+	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 +2095,10 @@
 				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 +2107,23 @@
 			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 +2138,28 @@
 		}
 		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 +2167,11 @@
 					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 +2180,23 @@
 			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 +2620,12 @@
 			}
 
 			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 +2708,18 @@
 					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 +2738,23 @@
 				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 +2762,11 @@
 			{
 				/* 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 +2779,24 @@
 				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 +2821,10 @@
 		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 +2897,11 @@
 		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;
 	}
diff -Nru freerdp2-2.10.0+dfsg1/libfreerdp/codec/nsc.c freerdp2-2.11.7+dfsg1/libfreerdp/codec/nsc.c
--- freerdp2-2.10.0+dfsg1/libfreerdp/codec/nsc.c	2023-02-16 10:55:03.000000000 +0100
+++ freerdp2-2.11.7+dfsg1/libfreerdp/codec/nsc.c	2024-04-22 11:26:59.000000000 +0200
@@ -29,6 +29,8 @@
 #include <string.h>
 
 #include <winpr/crt.h>
+#include <winpr/assert.h>
+#include <winpr/stream.h>
 
 #include <freerdp/codec/nsc.h>
 #include <freerdp/codec/color.h>
@@ -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                              \
@@ -87,8 +95,8 @@
 		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;
@@ -111,12 +119,17 @@
 	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;
 
@@ -129,17 +142,26 @@
 			*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;
@@ -147,7 +169,7 @@
 				len |= ((UINT32)(*in++)) << 24U;
 			}
 
-			if (outSize < len)
+			if ((outSize < len) || (left < len))
 				return FALSE;
 
 			outSize -= len;
@@ -169,26 +191,28 @@
 	if ((outSize < 4) || (left < 4))
 		return FALSE;
 
+	if (inSize < 4)
+		return FALSE;
 	memcpy(out, in, 4);
 	return TRUE;
 }
 
 static BOOL nsc_rle_decompress_data(NSC_CONTEXT* context)
 {
-	UINT16 i;
-	BYTE* rle;
-	UINT32 planeSize;
-	UINT32 originalSize;
-
 	if (!context)
 		return FALSE;
 
-	rle = context->Planes;
+	const BYTE* rle = context->Planes;
+	size_t rleSize = context->PlanesSize;
+	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 (rleSize < planeSize)
+			return FALSE;
 
 		if (planeSize == 0)
 		{
@@ -199,7 +223,7 @@
 		}
 		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;
 		}
@@ -208,6 +232,9 @@
 			if (context->priv->PlaneBuffersLength < originalSize)
 				return FALSE;
 
+			if (rleSize < originalSize)
+				return FALSE;
+
 			CopyMemory(context->priv->PlaneBuffers[i], rle, originalSize);
 		}
 
@@ -219,64 +246,71 @@
 
 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) */
+	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);
-	return TRUE;
+	context->PlanesSize = total;
+	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 * 4ull;
 
 	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 = 1ull * 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 +318,11 @@
 			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)
 	{
diff -Nru freerdp2-2.10.0+dfsg1/libfreerdp/codec/nsc_encode.c freerdp2-2.11.7+dfsg1/libfreerdp/codec/nsc_encode.c
--- freerdp2-2.10.0+dfsg1/libfreerdp/codec/nsc_encode.c	2023-02-16 10:55:03.000000000 +0100
+++ freerdp2-2.11.7+dfsg1/libfreerdp/codec/nsc_encode.c	2024-04-22 11:26:59.000000000 +0200
@@ -119,6 +119,8 @@
 	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 @@
 		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 @@
 					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 -Nru freerdp2-2.10.0+dfsg1/libfreerdp/codec/nsc_types.h freerdp2-2.11.7+dfsg1/libfreerdp/codec/nsc_types.h
--- freerdp2-2.10.0+dfsg1/libfreerdp/codec/nsc_types.h	2023-02-16 10:55:03.000000000 +0100
+++ freerdp2-2.11.7+dfsg1/libfreerdp/codec/nsc_types.h	2024-04-22 11:26:59.000000000 +0200
@@ -61,6 +61,7 @@
 	UINT32 BitmapDataLength;
 
 	BYTE* Planes;
+	size_t PlanesSize;
 	UINT32 PlaneByteCount[4];
 	UINT32 ColorLossLevel;
 	UINT32 ChromaSubsamplingLevel;
diff -Nru freerdp2-2.10.0+dfsg1/libfreerdp/codec/planar.c freerdp2-2.11.7+dfsg1/libfreerdp/codec/planar.c
--- freerdp2-2.10.0+dfsg1/libfreerdp/codec/planar.c	2023-02-16 10:55:03.000000000 +0100
+++ freerdp2-2.11.7+dfsg1/libfreerdp/codec/planar.c	2024-04-22 11:26:59.000000000 +0200
@@ -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)
@@ -612,11 +613,20 @@
 	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");
@@ -679,6 +689,13 @@
 		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;
@@ -687,8 +704,12 @@
 
 		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 */
@@ -700,8 +721,11 @@
 		}
 		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 */
@@ -716,8 +740,8 @@
 		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;
@@ -727,22 +751,41 @@
 		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;
@@ -1484,9 +1527,15 @@
 		return FALSE;
 
 	context->bgr = FALSE;
-	context->maxWidth = ALIGN(width, 4);
-	context->maxHeight = ALIGN(height, 4);
-	context->maxPlaneSize = context->maxWidth * context->maxHeight;
+	context->maxWidth = PLANAR_ALIGN(width, 4);
+	context->maxHeight = PLANAR_ALIGN(height, 4);
+	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 -Nru freerdp2-2.10.0+dfsg1/libfreerdp/codec/progressive.c freerdp2-2.11.7+dfsg1/libfreerdp/codec/progressive.c
--- freerdp2-2.10.0+dfsg1/libfreerdp/codec/progressive.c	2023-02-16 10:55:03.000000000 +0100
+++ freerdp2-2.11.7+dfsg1/libfreerdp/codec/progressive.c	2024-04-22 11:26:59.000000000 +0200
@@ -415,7 +415,7 @@
 	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);
 	}
 
@@ -1796,13 +1796,13 @@
 	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*)&params[index],
 			          &progressive->rfx_context->priv->ThreadPoolEnv)))
@@ -1817,7 +1817,10 @@
 		}
 		else
 		{
-			progressive_process_tiles_tile_work_callback(0, &params[index], 0);
+			PROGRESSIVE_TILE_PROCESS_WORK_PARAM param = {
+				.progressive = progressive, .region = region, .context = context, .tile = tile
+			};
+			progressive_process_tiles_tile_work_callback(0, &param, 0);
 		}
 
 		if (status < 0)
@@ -2422,11 +2425,17 @@
 		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))
diff -Nru freerdp2-2.10.0+dfsg1/libfreerdp/codec/rfx.c freerdp2-2.11.7+dfsg1/libfreerdp/codec/rfx.c
--- freerdp2-2.10.0+dfsg1/libfreerdp/codec/rfx.c	2023-02-16 10:55:03.000000000 +0100
+++ freerdp2-2.11.7+dfsg1/libfreerdp/codec/rfx.c	2024-04-22 11:26:59.000000000 +0200
@@ -936,6 +936,27 @@
 		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;
+		}
+		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) */
@@ -1109,8 +1130,18 @@
 			}
 		}
 
-		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)
 		{
@@ -1231,6 +1262,11 @@
 		region16_uninit(&clippingRects);
 		return TRUE;
 	}
+	else
+	{
+		rfx_message_free(context, message);
+		context->currentMessage.freeArray = TRUE;
+	}
 
 	WLog_ERR(TAG, "%s failed", __FUNCTION__);
 	return FALSE;
diff -Nru freerdp2-2.10.0+dfsg1/libfreerdp/codec/rfx_encode.c freerdp2-2.11.7+dfsg1/libfreerdp/codec/rfx_encode.c
--- freerdp2-2.10.0+dfsg1/libfreerdp/codec/rfx_encode.c	2023-02-16 10:55:03.000000000 +0100
+++ freerdp2-2.11.7+dfsg1/libfreerdp/codec/rfx_encode.c	2024-04-22 11:26:59.000000000 +0200
@@ -49,6 +49,8 @@
 	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 @@
 	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 @@
 			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 @@
 			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 @@
 			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 @@
 			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 @@
 			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 @@
 			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 @@
 			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 @@
 			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 @@
 					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;
diff -Nru freerdp2-2.10.0+dfsg1/libfreerdp/codec/xcrush.c freerdp2-2.11.7+dfsg1/libfreerdp/codec/xcrush.c
--- freerdp2-2.10.0+dfsg1/libfreerdp/codec/xcrush.c	2023-02-16 10:55:03.000000000 +0100
+++ freerdp2-2.11.7+dfsg1/libfreerdp/codec/xcrush.c	2024-04-22 11:26:59.000000000 +0200
@@ -674,7 +674,7 @@
 	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 @@
 
 	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 -Nru freerdp2-2.10.0+dfsg1/libfreerdp/codec/zgfx.c freerdp2-2.11.7+dfsg1/libfreerdp/codec/zgfx.c
--- freerdp2-2.10.0+dfsg1/libfreerdp/codec/zgfx.c	2023-02-16 10:55:03.000000000 +0100
+++ freerdp2-2.11.7+dfsg1/libfreerdp/codec/zgfx.c	2024-04-22 11:26:59.000000000 +0200
@@ -230,7 +230,10 @@
 	BYTE* pbSegment;
 	size_t cbSegment;
 
-	if (!zgfx || !stream || (segmentSize < 2))
+	WINPR_ASSERT(zgfx);
+	WINPR_ASSERT(stream);
+
+	if (segmentSize < 2)
 		return FALSE;
 
 	cbSegment = segmentSize - 1;
@@ -259,7 +262,11 @@
 	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;
 
@@ -345,8 +352,9 @@
 
 						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,
@@ -377,15 +385,45 @@
 	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);
 
-	if (!stream)
-		return -1;
+	WINPR_ASSERT(zgfx);
+	WINPR_ASSERT(stream);
+	WINPR_ASSERT(ppDstData);
+	WINPR_ASSERT(pDstSize);
+
+	*ppDstData = NULL;
+	*pDstSize = 0;
 
 	if (Stream_GetRemainingLength(stream) < 1)
 		goto fail;
@@ -397,16 +435,15 @@
 		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)
 	{
@@ -414,8 +451,6 @@
 		UINT16 segmentNumber;
 		UINT16 segmentCount;
 		UINT32 uncompressedSize;
-		BYTE* pConcatenated;
-		size_t used = 0;
 
 		if (Stream_GetRemainingLength(stream) < 6)
 			goto fail;
@@ -423,17 +458,6 @@
 		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))
@@ -444,16 +468,15 @@
 			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
 	{
@@ -462,6 +485,8 @@
 
 	status = 1;
 fail:
+	if (status < 0)
+		free(pConcatenated);
 	Stream_Free(stream, FALSE);
 	return status;
 }
diff -Nru freerdp2-2.10.0+dfsg1/libfreerdp/common/settings_getters.c freerdp2-2.11.7+dfsg1/libfreerdp/common/settings_getters.c
--- freerdp2-2.10.0+dfsg1/libfreerdp/common/settings_getters.c	2023-02-16 10:55:03.000000000 +0100
+++ freerdp2-2.11.7+dfsg1/libfreerdp/common/settings_getters.c	2024-04-22 11:26:59.000000000 +0200
@@ -231,6 +231,9 @@
 		case FreeRDP_GrabKeyboard:
 			return settings->GrabKeyboard;
 
+		case FreeRDP_GrabMouse:
+			return settings->GrabMouse;
+
 		case FreeRDP_HasExtendedMouseEvent:
 			return settings->HasExtendedMouseEvent;
 
@@ -809,6 +812,10 @@
 			settings->GrabKeyboard = val;
 			break;
 
+		case FreeRDP_GrabMouse:
+			settings->GrabMouse = val;
+			break;
+
 		case FreeRDP_HasExtendedMouseEvent:
 			settings->HasExtendedMouseEvent = val;
 			break;
diff -Nru freerdp2-2.10.0+dfsg1/libfreerdp/common/settings_str.c freerdp2-2.11.7+dfsg1/libfreerdp/common/settings_str.c
--- freerdp2-2.10.0+dfsg1/libfreerdp/common/settings_str.c	2023-02-16 10:55:03.000000000 +0100
+++ freerdp2-2.11.7+dfsg1/libfreerdp/common/settings_str.c	2024-04-22 11:26:59.000000000 +0200
@@ -87,6 +87,7 @@
 	{ 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 -Nru freerdp2-2.10.0+dfsg1/libfreerdp/core/orders.c freerdp2-2.11.7+dfsg1/libfreerdp/core/orders.c
--- freerdp2-2.10.0+dfsg1/libfreerdp/core/orders.c	2023-02-16 10:55:03.000000000 +0100
+++ freerdp2-2.11.7+dfsg1/libfreerdp/core/orders.c	2024-04-22 11:26:59.000000000 +0200
@@ -27,6 +27,7 @@
 
 #include <winpr/wtypes.h>
 #include <winpr/crt.h>
+#include <winpr/assert.h>
 
 #include <freerdp/api.h>
 #include <freerdp/log.h>
@@ -796,6 +797,7 @@
 static INLINE BOOL update_read_delta(wStream* s, INT32* value)
 {
 	BYTE byte;
+	UINT32 uvalue = 0;
 
 	if (Stream_GetRemainingLength(s) < 1)
 	{
@@ -806,9 +808,9 @@
 	Stream_Read_UINT8(s, byte);
 
 	if (byte & 0x40)
-		*value = (byte | ~0x3F);
+		uvalue = (byte | ~0x3F);
 	else
-		*value = (byte & 0x3F);
+		uvalue = (byte & 0x3F);
 
 	if (byte & 0x80)
 	{
@@ -819,8 +821,9 @@
 		}
 
 		Stream_Read_UINT8(s, byte);
-		*value = (*value << 8) | byte;
+		uvalue = (uvalue << 8) | byte;
 	}
+	*value = (INT32)uvalue;
 
 	return TRUE;
 }
@@ -1373,12 +1376,13 @@
 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)
@@ -1386,12 +1390,21 @@
 		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);
 	}
-
+	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)
 {
@@ -1407,7 +1420,8 @@
 	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)
@@ -1415,17 +1429,31 @@
 		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;
 	}
 
+	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;
 }
 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);
+
+	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) ||
@@ -1433,7 +1461,7 @@
 	    !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)
@@ -1441,10 +1469,20 @@
 		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);
 	}
 
+	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,
@@ -1484,7 +1522,8 @@
 		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)
@@ -1492,22 +1531,32 @@
 		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 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)
@@ -1515,11 +1564,21 @@
 		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);
 	}
 
+	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,
@@ -1610,6 +1669,14 @@
 		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;
 }
@@ -1942,6 +2009,13 @@
 		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;
 }
@@ -1987,6 +2061,14 @@
 			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;
diff -Nru freerdp2-2.10.0+dfsg1/libfreerdp/core/server.c freerdp2-2.11.7+dfsg1/libfreerdp/core/server.c
--- freerdp2-2.10.0+dfsg1/libfreerdp/core/server.c	2023-02-16 10:55:03.000000000 +0100
+++ freerdp2-2.11.7+dfsg1/libfreerdp/core/server.c	2024-04-22 11:26:59.000000000 +0200
@@ -493,7 +493,7 @@
 		{
 			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;
diff -Nru freerdp2-2.10.0+dfsg1/libfreerdp/core/test/settings_property_lists.h freerdp2-2.11.7+dfsg1/libfreerdp/core/test/settings_property_lists.h
--- freerdp2-2.10.0+dfsg1/libfreerdp/core/test/settings_property_lists.h	2023-02-16 10:55:03.000000000 +0100
+++ freerdp2-2.11.7+dfsg1/libfreerdp/core/test/settings_property_lists.h	2024-04-22 11:26:59.000000000 +0200
@@ -76,6 +76,7 @@
 	FreeRDP_GfxSmallCache,
 	FreeRDP_GfxThinClient,
 	FreeRDP_GrabKeyboard,
+	FreeRDP_GrabMouse,
 	FreeRDP_HasExtendedMouseEvent,
 	FreeRDP_HasHorizontalWheel,
 	FreeRDP_HasMonitorAttributes,
diff -Nru freerdp2-2.10.0+dfsg1/libfreerdp/core/window.c freerdp2-2.11.7+dfsg1/libfreerdp/core/window.c
--- freerdp2-2.10.0+dfsg1/libfreerdp/core/window.c	2023-02-16 10:55:03.000000000 +0100
+++ freerdp2-2.11.7+dfsg1/libfreerdp/core/window.c	2024-04-22 11:26:59.000000000 +0200
@@ -359,33 +359,31 @@
 
 		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);
-
-		if (!newRect)
-		{
-			free(windowState->windowRects);
-			windowState->windowRects = NULL;
-			return FALSE;
-		}
-
-		windowState->windowRects = newRect;
+			size = sizeof(RECTANGLE_16) * windowState->numWindowRects;
+			newRect = (RECTANGLE_16*)realloc(windowState->windowRects, size);
 
-		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) */
+			if (!newRect)
+			{
+				free(windowState->windowRects);
+				windowState->windowRects = NULL;
+				return FALSE;
+			}
+
+			windowState->windowRects = newRect;
+
+			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) */
+			}
 		}
 	}
 
diff -Nru freerdp2-2.10.0+dfsg1/libfreerdp/crypto/crypto.c freerdp2-2.11.7+dfsg1/libfreerdp/crypto/crypto.c
--- freerdp2-2.10.0+dfsg1/libfreerdp/crypto/crypto.c	2023-02-16 10:55:03.000000000 +0100
+++ freerdp2-2.11.7+dfsg1/libfreerdp/crypto/crypto.c	2024-04-22 11:26:59.000000000 +0200
@@ -950,10 +950,13 @@
 {
 	WINPR_ASSERT(xcert);
 
-	const int nid = X509_get_signature_nid(xcert);
+	EVP_PKEY* evp = X509_get_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);
+	EVP_PKEY_free(evp);
+	if (res <= 0)
 		return WINPR_MD_NONE;
 
 	switch (hash_nid)
@@ -976,7 +979,7 @@
 			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 +988,11 @@
 			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;
diff -Nru freerdp2-2.10.0+dfsg1/libfreerdp/gdi/bitmap.c freerdp2-2.11.7+dfsg1/libfreerdp/gdi/bitmap.c
--- freerdp2-2.10.0+dfsg1/libfreerdp/gdi/bitmap.c	2023-02-16 10:55:03.000000000 +0100
+++ freerdp2-2.11.7+dfsg1/libfreerdp/gdi/bitmap.c	2024-04-22 11:26:59.000000000 +0200
@@ -148,7 +148,7 @@
 	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 -Nru freerdp2-2.10.0+dfsg1/libfreerdp/gdi/gdi.c freerdp2-2.11.7+dfsg1/libfreerdp/gdi/gdi.c
--- freerdp2-2.10.0+dfsg1/libfreerdp/gdi/gdi.c	2023-02-16 10:55:03.000000000 +0100
+++ freerdp2-2.11.7+dfsg1/libfreerdp/gdi/gdi.c	2024-04-22 11:26:59.000000000 +0200
@@ -997,16 +997,46 @@
 	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 @@
 	    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(&region);
-	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,
 			                         &region))
 			{
@@ -1042,11 +1071,11 @@
 		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;
@@ -1057,17 +1086,18 @@
 
 		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,
 				         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 @@
 	if (!(rects = region16_rects(&region, &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;
diff -Nru freerdp2-2.10.0+dfsg1/libfreerdp/gdi/gfx.c freerdp2-2.11.7+dfsg1/libfreerdp/gdi/gfx.c
--- freerdp2-2.10.0+dfsg1/libfreerdp/gdi/gfx.c	2023-02-16 10:55:03.000000000 +0100
+++ freerdp2-2.11.7+dfsg1/libfreerdp/gdi/gfx.c	2024-04-22 11:26:59.000000000 +0200
@@ -726,7 +726,7 @@
 	{
 		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 @@
 	}
 
 	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)
 	{
@@ -1079,6 +1079,28 @@
 	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_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;
+		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, rect->left,
-		                        rect->top, nWidth, nHeight, color))
+		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);
diff -Nru freerdp2-2.10.0+dfsg1/libfreerdp/gdi/graphics.c freerdp2-2.11.7+dfsg1/libfreerdp/gdi/graphics.c
--- freerdp2-2.10.0+dfsg1/libfreerdp/gdi/graphics.c	2023-02-16 10:55:03.000000000 +0100
+++ freerdp2-2.11.7+dfsg1/libfreerdp/gdi/graphics.c	2024-04-22 11:26:59.000000000 +0200
@@ -52,7 +52,7 @@
 		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 -Nru freerdp2-2.10.0+dfsg1/libfreerdp/gdi/shape.c freerdp2-2.11.7+dfsg1/libfreerdp/gdi/shape.c
--- freerdp2-2.10.0+dfsg1/libfreerdp/gdi/shape.c	2023-02-16 10:55:03.000000000 +0100
+++ freerdp2-2.11.7+dfsg1/libfreerdp/gdi/shape.c	2024-04-22 11:26:59.000000000 +0200
@@ -158,7 +158,7 @@
 			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 -Nru freerdp2-2.10.0+dfsg1/libfreerdp/gdi/video.c freerdp2-2.11.7+dfsg1/libfreerdp/gdi/video.c
--- freerdp2-2.10.0+dfsg1/libfreerdp/gdi/video.c	2023-02-16 10:55:03.000000000 +0100
+++ freerdp2-2.11.7+dfsg1/libfreerdp/gdi/video.c	2024-04-22 11:26:59.000000000 +0200
@@ -66,7 +66,7 @@
 	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 -Nru freerdp2-2.10.0+dfsg1/libfreerdp/locale/xkb_layout_ids.c freerdp2-2.11.7+dfsg1/libfreerdp/locale/xkb_layout_ids.c
--- freerdp2-2.10.0+dfsg1/libfreerdp/locale/xkb_layout_ids.c	2023-02-16 10:55:03.000000000 +0100
+++ freerdp2-2.11.7+dfsg1/libfreerdp/locale/xkb_layout_ids.c	2024-04-22 11:26:59.000000000 +0200
@@ -806,7 +806,7 @@
 	{ "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 -Nru freerdp2-2.10.0+dfsg1/libfreerdp/primitives/prim_copy.c freerdp2-2.11.7+dfsg1/libfreerdp/primitives/prim_copy.c
--- freerdp2-2.10.0+dfsg1/libfreerdp/primitives/prim_copy.c	2023-02-16 10:55:03.000000000 +0100
+++ freerdp2-2.11.7+dfsg1/libfreerdp/primitives/prim_copy.c	2024-04-22 11:26:59.000000000 +0200
@@ -60,14 +60,14 @@
 
 	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 -Nru freerdp2-2.10.0+dfsg1/libfreerdp/primitives/primitives.c freerdp2-2.11.7+dfsg1/libfreerdp/primitives/primitives.c
--- freerdp2-2.10.0+dfsg1/libfreerdp/primitives/primitives.c	2023-02-16 10:55:03.000000000 +0100
+++ freerdp2-2.11.7+dfsg1/libfreerdp/primitives/primitives.c	2024-04-22 11:26:59.000000000 +0200
@@ -157,7 +157,7 @@
 		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 -Nru freerdp2-2.10.0+dfsg1/uwac/CMakeLists.txt freerdp2-2.11.7+dfsg1/uwac/CMakeLists.txt
--- freerdp2-2.10.0+dfsg1/uwac/CMakeLists.txt	2023-02-16 10:55:03.000000000 +0100
+++ freerdp2-2.11.7+dfsg1/uwac/CMakeLists.txt	2024-04-22 11:26:59.000000000 +0200
@@ -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}")
diff -Nru freerdp2-2.10.0+dfsg1/uwac/include/uwac/uwac.h freerdp2-2.11.7+dfsg1/uwac/include/uwac/uwac.h
--- freerdp2-2.10.0+dfsg1/uwac/include/uwac/uwac.h	2023-02-16 10:55:03.000000000 +0100
+++ freerdp2-2.11.7+dfsg1/uwac/include/uwac/uwac.h	2024-04-22 11:26:59.000000000 +0200
@@ -107,7 +107,9 @@
 	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 @@
 };
 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 @@
 	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 -Nru freerdp2-2.10.0+dfsg1/uwac/libuwac/uwac-input.c freerdp2-2.11.7+dfsg1/uwac/libuwac/uwac-input.c
--- freerdp2-2.10.0+dfsg1/uwac/libuwac/uwac-input.c	2023-02-16 10:55:03.000000000 +0100
+++ freerdp2-2.11.7+dfsg1/uwac/libuwac/uwac-input.c	2024-04-22 11:26:59.000000000 +0200
@@ -846,12 +846,37 @@
 
 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)
 {
-	/*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,
diff -Nru freerdp2-2.10.0+dfsg1/uwac/libuwac/uwac-window.c freerdp2-2.11.7+dfsg1/uwac/libuwac/uwac-window.c
--- freerdp2-2.10.0+dfsg1/uwac/libuwac/uwac-window.c	2023-02-16 10:55:03.000000000 +0100
+++ freerdp2-2.11.7+dfsg1/uwac/libuwac/uwac-window.c	2024-04-22 11:26:59.000000000 +0200
@@ -320,14 +320,14 @@
 
 	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 @@
 
 	if (!pool)
 	{
-		munmap(data, allocSize * nbuffers * 1ULL);
+		munmap(data, 1ull * allocSize * nbuffers);
 		ret = UWAC_ERROR_NOMEMORY;
 		goto error_mmap;
 	}
@@ -764,7 +764,7 @@
 
 	if (copyContentForNextFrame)
 		memcpy(nextDrawingBuffer->data, pendingBuffer->data,
-		       window->stride * window->height * 1ULL);
+		       1ull * window->stride * window->height);
 
 	UwacSubmitBufferPtr(window, pendingBuffer);
 	return UWAC_SUCCESS;
diff -Nru freerdp2-2.10.0+dfsg1/winpr/CMakeLists.txt freerdp2-2.11.7+dfsg1/winpr/CMakeLists.txt
--- freerdp2-2.10.0+dfsg1/winpr/CMakeLists.txt	2023-02-16 10:55:03.000000000 +0100
+++ freerdp2-2.11.7+dfsg1/winpr/CMakeLists.txt	2024-04-22 11:26:59.000000000 +0200
@@ -57,7 +57,7 @@
 endif()
 
 # Soname versioning
-set(RAW_VERSION_STRING "2.10.0")
+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 -Nru freerdp2-2.10.0+dfsg1/winpr/include/winpr/wtypes.h.in freerdp2-2.11.7+dfsg1/winpr/include/winpr/wtypes.h.in
--- freerdp2-2.10.0+dfsg1/winpr/include/winpr/wtypes.h.in	2023-02-16 10:55:03.000000000 +0100
+++ freerdp2-2.11.7+dfsg1/winpr/include/winpr/wtypes.h.in	2024-04-22 11:26:59.000000000 +0200
@@ -161,8 +161,9 @@
 #ifndef __APPLE__
 typedef __int32 BOOL;
 #else /* __APPLE__ */
+#include <TargetConditionals.h>
 /* 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;
diff -Nru freerdp2-2.10.0+dfsg1/winpr/libwinpr/credui/CMakeLists.txt freerdp2-2.11.7+dfsg1/winpr/libwinpr/credui/CMakeLists.txt
--- freerdp2-2.10.0+dfsg1/winpr/libwinpr/credui/CMakeLists.txt	2023-02-16 10:55:03.000000000 +0100
+++ freerdp2-2.11.7+dfsg1/winpr/libwinpr/credui/CMakeLists.txt	2024-04-22 11:26:59.000000000 +0200
@@ -19,8 +19,8 @@
 
 if(WIN32)
 	winpr_library_add_public(credui)
-endif()
-
-if(BUILD_TESTING)
-	add_subdirectory(test)
+else()
+    if(BUILD_TESTING)
+        add_subdirectory(test)
+    endif()
 endif()
diff -Nru freerdp2-2.10.0+dfsg1/winpr/libwinpr/crt/CMakeLists.txt freerdp2-2.11.7+dfsg1/winpr/libwinpr/crt/CMakeLists.txt
--- freerdp2-2.10.0+dfsg1/winpr/libwinpr/crt/CMakeLists.txt	2023-02-16 10:55:03.000000000 +0100
+++ freerdp2-2.11.7+dfsg1/winpr/libwinpr/crt/CMakeLists.txt	2024-04-22 11:26:59.000000000 +0200
@@ -29,7 +29,7 @@
 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 -Nru freerdp2-2.10.0+dfsg1/winpr/libwinpr/crt/unicode.c freerdp2-2.11.7+dfsg1/winpr/libwinpr/crt/unicode.c
--- freerdp2-2.10.0+dfsg1/winpr/libwinpr/crt/unicode.c	2023-02-16 10:55:03.000000000 +0100
+++ freerdp2-2.11.7+dfsg1/winpr/libwinpr/crt/unicode.c	2024-04-22 11:26:59.000000000 +0200
@@ -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 @@
 		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 @@
 			              &error);
 			cchWideChar = U_SUCCESS(error) ? targetLength : 0;
 		}
+#endif
 	}
 #else
 
@@ -327,6 +350,21 @@
 		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 @@
 			            &error);
 			cbMultiByte = U_SUCCESS(error) ? targetLength : 0;
 		}
+#endif
 	}
 #else
 
diff -Nru freerdp2-2.10.0+dfsg1/winpr/libwinpr/crypto/cipher.c freerdp2-2.11.7+dfsg1/winpr/libwinpr/crypto/cipher.c
--- freerdp2-2.10.0+dfsg1/winpr/libwinpr/crypto/cipher.c	2023-02-16 10:55:03.000000000 +0100
+++ freerdp2-2.11.7+dfsg1/winpr/libwinpr/crypto/cipher.c	2024-04-22 11:26:59.000000000 +0200
@@ -66,7 +66,11 @@
 	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);
diff -Nru freerdp2-2.10.0+dfsg1/winpr/libwinpr/utils/collections/ArrayList.c freerdp2-2.11.7+dfsg1/winpr/libwinpr/utils/collections/ArrayList.c
--- freerdp2-2.10.0+dfsg1/winpr/libwinpr/utils/collections/ArrayList.c	2023-02-16 10:55:03.000000000 +0100
+++ freerdp2-2.11.7+dfsg1/winpr/libwinpr/utils/collections/ArrayList.c	2024-04-22 11:26:59.000000000 +0200
@@ -233,6 +233,18 @@
  * 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 @@
 		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 @@
 		}
 		else
 		{
-			arrayList->array[index] = obj;
+			insert(arrayList, index, obj);
 		}
 	}
 
diff -Nru freerdp2-2.10.0+dfsg1/winpr/libwinpr/utils/lodepng/lodepng.c freerdp2-2.11.7+dfsg1/winpr/libwinpr/utils/lodepng/lodepng.c
--- freerdp2-2.10.0+dfsg1/winpr/libwinpr/utils/lodepng/lodepng.c	2023-02-16 10:55:03.000000000 +0100
+++ freerdp2-2.11.7+dfsg1/winpr/libwinpr/utils/lodepng/lodepng.c	2024-04-22 11:26:59.000000000 +0200
@@ -3815,7 +3815,7 @@
 {
 	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 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 @@
 		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 @@
 				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 @@
 					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 @@
 					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);

Attachment: signature.asc
Description: This is a digitally signed message part


Reply to: