Version in base suite: 3.15.0+dfsg-2.1 Base version: freerdp3_3.15.0+dfsg-2.1 Target version: freerdp3_3.15.0+dfsg-2.1+deb13u1 Base file: /srv/ftp-master.debian.org/ftp/pool/main/f/freerdp3/freerdp3_3.15.0+dfsg-2.1.dsc Target file: /srv/ftp-master.debian.org/policy/pool/main/f/freerdp3/freerdp3_3.15.0+dfsg-2.1+deb13u1.dsc changelog | 197 control | 2 gbp.conf | 1 libfreerdp3-3.symbols | 4 libwinpr3-3.symbols | 3 patches/CVE-2025-4478.patch | 8 patches/README | 3 patches/cache-offscreen-invalidate-bitmap-before-free-CVE-2026-23884.patch | 48 patches/channel-rdpsnd-only-clean-up-thread-before-free-CVE-2026-24684.patch | 119 patches/channels-ainput-lock-context-when-updating-listener-CVE-2026-24683.patch | 114 patches/channels-audin-fix-audin_server_recv_formats-cleanup-CVE-2026-24682.patch | 31 patches/channels-audin-free-up-old-audio-formats-CVE-2026-22852.patch | 30 patches/channels-audin-reset-audin-format-CVE-2026-24676.patch | 35 patches/channels-drdynvc-check-pointer-before-reset.patch | 32 patches/channels-drdynvc-reset-channel_callback-before-close-CVE-2026-24491.patch | 51 patches/channels-drive-fix-constant-type-CVE-2026-22854.patch | 29 patches/channels-rdpear-add-checks-for-itemSize-CVE-2026-22853.patch | 72 patches/channels-rdpecam-add-value-range-checks.patch | 581 + patches/channels-rdpecam-ensure-all-streams-are-stopped-CVE-2026-24678.patch | 29 patches/channels-rdpecam-ensure-sws-context-size-matches-CVE-2026-24677.patch | 162 patches/channels-rdpecam-fix-PROPERTY_DESCRIPTION-parsing.patch | 167 patches/channels-rdpecam-improve-log-messages.patch | 68 patches/channels-rdpgfx-check-available-stream-length-CVE-2026-25941.patch | 28 patches/channels-rdpsnd-terminate-thread-before-free-CVE-2026-24684.patch | 67 patches/channels-rpdecam-log-dropped-samples.patch | 65 patches/channels-serial-explicitly-lock-serial-IrpThreads-CVE-2026-22856.patch | 41 patches/channels-serial-fix-use-after-free-CVE-2026-22857.patch | 50 patches/channels-urbdrc-cancel-all-usb-transfers-on-channel--CVE-2026-24681.patch | 26 patches/channels-urbdrc-check-interface-indices-before-use-CVE-2026-22859.patch | 200 patches/channels-urbdrc-do-not-free-MsConfig-on-failure-CVE-2026-24675.patch | 31 patches/channels-urbdrc-ensure-InterfaceNumber-is-within-ran-CVE-2026-24679.patch | 44 patches/clang-warnings-fix-Wjump-misses-init-drdynvc_main.patch | 35 patches/clang-warnings-fix-Wjump-misses-init-remdesk_main.patch | 163 patches/client-X11-fix-clipboard-update-CVE-2026-25997.patch | 63 patches/client-desktop-fix-StartupWMClass-setting.patch | 74 patches/client-sdl-lock-primary-while-used-CVE-2026-22851.patch | 37 patches/client-sdl-reset-pointer-after-memory-release-CVE-2026-24680.patch | 26 patches/client-x11-destroy-XImage-on-window-unmap-CVE-2026-25955.patch | 104 patches/client-x11-fix-clipboard-issues.patch | 248 patches/client-x11-fix-double-free-in-case-of-invalid-pointe-CVE-2026-23883.patch | 51 patches/client-x11-fix-missing-includes.patch | 36 patches/client-x11-fix-xf_rail_window_common-cleanup-CVE-2026-26986.patch | 47 patches/client-x11-lock-appWindow-CVE-2026-25952-CVE-2026-25953-CVE-2026-25954.patch | 404 patches/client-x11-lock-cache-when-providing-data-CVE-2026-25959.patch | 43 patches/client-x11-stringfiy-functions-for-RAILS-CVE-2026-25942.patch | 103 patches/codec-clear-fix-clear_resize_buffer-checks-CVE-2026-23533.patch | 60 patches/codec-clear-fix-destination-checks-CVE-2026-26955.patch | 42 patches/codec-clear-fix-missing-destination-boundary-checks-CVE-2026-26955.patch | 98 patches/codec-clear-fix-missing-length-checks-CVE-2026-23531.patch | 32 patches/codec-clear-fix-off-by-one-length-check-CVE-2026-23534.patch | 34 patches/codec-color-add-freerdp_glyph_convert_ex-CVE-2026-23732.patch | 99 patches/codec-color-fix-input-length-checks-CVE-2026-26271.patch | 95 patches/codec-planar-fix-decoder-length-checks-CVE-2026-23530.patch | 31 patches/codec-planar-fix-missing-destination-bounds-checks-CVE-2026-26965.patch | 54 patches/core-info-fix-missing-NULL-check-CVE-2026-23948.patch | 58 patches/core-redirection-Ensure-stream-has-space-for-all-params.patch | 50 patches/core-redirection-Ensure-stream-has-space-for-cert.patch | 34 patches/crypto-base64-do-proper-length-checks-CVE-2026-22858.patch | 211 patches/crypto-base64-ensure-char-is-singend.patch | 28 patches/gdi-gfx-properly-clamp-SurfaceToSurface-CVE-2026-23532.patch | 51 patches/gdi-graphics-Use-freerdp_glyph_convert_ex-CVE-2026-23732.patch | 42 patches/rdpecam-fix-camera-sample-grabbing.patch | 324 patches/series | 68 patches/utils-smartcard-add-length-validity-checks-CVE-2026-22855.patch | 83 patches/utils-smartcard-better-logging-and-error-checks.patch | 4053 ++++++++++ patches/utils-smartcard-check-stream-length-on-padding-CVE-2026-27015.patch | 101 patches/utils-smartcard-handle-output-buffer-too-small.patch | 63 patches/utils-smartcard-improve-trace-log.patch | 2114 +++++ patches/warnings-Fix-format-string-errors-partial.patch | 1515 +++ patches/winpr-wlog-Add-specialized-text-log-functions.patch | 217 70 files changed, 13322 insertions(+), 7 deletions(-) dpkg-source: warning: cannot verify inline signature for /srv/release.debian.org/tmp/tmpt0h_f0p2/freerdp3_3.15.0+dfsg-2.1.dsc: no acceptable signature found dpkg-source: warning: cannot verify inline signature for /srv/release.debian.org/tmp/tmpt0h_f0p2/freerdp3_3.15.0+dfsg-2.1+deb13u1.dsc: no acceptable signature found diff -Nru freerdp3-3.15.0+dfsg/debian/changelog freerdp3-3.15.0+dfsg/debian/changelog --- freerdp3-3.15.0+dfsg/debian/changelog 2025-05-26 12:38:19.000000000 +0000 +++ freerdp3-3.15.0+dfsg/debian/changelog 2026-03-28 17:59:33.000000000 +0000 @@ -1,3 +1,200 @@ +freerdp3 (3.15.0+dfsg-2.1+deb13u1) trixie; urgency=medium + + * two patches from upstream (from 3.16) (Closes: #1112191): + core-redirection-Ensure-stream-has-space-for-cert.patch + core-redirection-Ensure-stream-has-space-for-all-params.patch + * client-x11-fix-clipboard-issues.patch (Closes: #1121299) + * client-desktop-fix-StartupWMClass-setting.patch: + restore x11 desktop icon for xfreerdp3 + * d/patches/README: remove obsolete file + + * security fixes for client from 3.20.1 (medium): + + CVE-2026-22851: RDPGFX ResetGraphics race leads to use after free + in SDL3 client (sdl->primary) + https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-8g87-6pvc-wh99 + client-sdl-lock-primary-while-used-CVE-2026-22851.patch + CVE-2026-22852: Heap buffer overflow in audin_process_formats + https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-9chc-g79v-4qq4 + channels-audin-free-up-old-audio-formats-CVE-2026-22852.patch + CVE-2026-22853: Heap buffer overflow in ndr_read_uint8Array + https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-47v9-p4gp-w5ch + channels-rdpear-add-checks-for-itemSize-CVE-2026-22853.patch + CVE-2026-22854: Heap buffer overflow in drive_process_irp_read + https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-47vj-g3c3-3rmf + channels-drive-fix-constant-type-CVE-2026-22854.patch + CVE-2026-22855: Heap buffer overflow in smartcard_unpack_set_attrib_call + https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-rwp3-g84r-6mx9 + utils-smartcard-add-length-validity-checks-CVE-2026-22855.patch + also pick: + utils-smartcard-handle-output-buffer-too-small.patch + utils-smartcard-improve-trace-log.patch + utils-smartcard-better-logging-and-error-checks.patch + CVE-2026-22856: Heap use after free in create_irp_thread + https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-w842-c386-fxhv + channels-serial-explicitly-lock-serial-IrpThreads-CVE-2026-22856.patch + CVE-2026-22857: Heap use after free in irp_thread_func + https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-4gxq-jhq6-4cr8 + channels-serial-fix-use-after-free-CVE-2026-22857.patch + CVE-2026-22858: Global buffer overflow in crypto_base64_decode + https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-qmqf-m84q-x896 + (this also affects freerdp proxy, not just client) + crypto-base64-do-proper-length-checks-CVE-2026-22858.patch + also pick: + crypto-base64-ensure-char-is-singend.patch + CVE-2026-22859: Heap buffer overflow in urb_select_configuration + https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-56f5-76qv-2r36 + channels-urbdrc-check-interface-indices-before-use-CVE-2026-22859.patch + + * security fixes for client from 3.21 (medium): + + CVE-2026-23530: Heap buffer overflow in planar_decompress_plane_rle + https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-r4hv-852m-fq7p + codec-planar-fix-decoder-length-checks-CVE-2026-23530.patch + CVE-2026-23531: Heap buffer overflow in clear_decompress + https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-xj5h-9cr5-23c5 + codec-clear-fix-missing-length-checks-CVE-2026-23531.patch + CVE-2026-23532: Heap buffer overflow in gdi_SurfaceToSurface + https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-fq8c-87hj-7gvr + gdi-gfx-properly-clamp-SurfaceToSurface-CVE-2026-23532.patch + CVE-2026-23533: Heap buffer overflow in clear_decompress_residual_data + https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-32q9-m5qr-9j2v + codec-clear-fix-clear_resize_buffer-checks-CVE-2026-23533.patch + CVE-2026-23534: Heap buffer overflow in clear_decompress_bands_data + https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-3frr-mp8w-4599 + codec-clear-fix-off-by-one-length-check-CVE-2026-23534.patch + CVE-2026-23732: Heap buffer overflow in Glyph_Alloc + https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-7qxp-j2fj-c3pp + codec-color-add-freerdp_glyph_convert_ex-CVE-2026-23732.patch + gdi-graphics-Use-freerdp_glyph_convert_ex-CVE-2026-23732.patch + CVE-2026-23883: Heap use after free in update_pointer_new + https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-qcrr-85qx-4p6x + client-x11-fix-double-free-in-case-of-invalid-pointe-CVE-2026-23883.patch + CVE-2026-23884: Heap use after free in gdi_set_bounds + https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-cfgj-vc84-f3pp + cache-offscreen-invalidate-bitmap-before-free-CVE-2026-23884.patch + + * security fixes for client from 3.22 (medium): + + CVE-2026-23948: NULL Pointer Dereference in rdp_write_logon_info_v2() + https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-6f3c-qvqq-2px5 + core-info-fix-missing-NULL-check-CVE-2026-23948.patch + CVE-2026-24491: Heap-use-after-free in video_timer + https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-4x6j-w49r-869g + channels-drdynvc-reset-channel_callback-before-close-CVE-2026-24491.patch + also pick: + clang-warnings-fix-Wjump-misses-init-drdynvc_main.patch + channels-drdynvc-check-pointer-before-reset.patch (fixup on top) + CVE-2026-24675: Heap-use-after-free in urb_select_interface + https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-x9jr-99h2-g7mj + channels-urbdrc-do-not-free-MsConfig-on-failure-CVE-2026-24491.patch + CVE-2026-24676: Heap-use-after-free in audio_format_compatible + https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-qh5p-frq4-pgxj + channels-audin-reset-audin-format-CVE-2026-24676.patch + CVE-2026-24677: Heap-buffer-overflow in ecam_encoder_compress_h264 + https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-xw37-j744-f8v7 + channels-rdpecam-ensure-sws-context-size-matches-CVE-2026-24677.patch + also pick: + clang-warnings-fix-Wjump-misses-init-remdesk_main.patch + channels-rdpecam-improve-log-messages.patch + rdpecam-fix-camera-sample-grabbing.patch + channels-rpdecam-log-dropped-samples.patch + fix-camera-sample-grabbing is a separate bugfix, but it also + removes the need to back-port the main fix to 3.15 + CVE-2026-24678: Heap-use-after-free in cam_v4l_stream_capture_thread + https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-6gvg-29wx-6v7h + channels-rdpecam-ensure-all-streams-are-stopped-CVE-2026-24678.patch + CVE-2026-24679: Heap-buffer-overflow in urb_select_interface + https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-2jp4-67x6-gv7x + channels-urbdrc-ensure-InterfaceNumber-is-within-ran-CVE-2026-24679.patch + CVE-2026-24680: Heap-use-after-free in update_pointer_new(SDL) + https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-j893-9wg8-33rc + client-sdl-reset-pointer-after-memory-release-CVE-2026-24680.patch + CVE-2026-24681: Heap-use-after-free in urb_bulk_transfer_cb + https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-ccvv-hg2w-6x9j + channels-urbdrc-cancel-all-usb-transfers-on-channel--CVE-2026-24681.patch + CVE-2026-24682: Heap-buffer-overflow in audio_formats_free + https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-vcw2-pqgw-mx6g + channels-audin-fix-audin_server_recv_formats-cleanup-CVE-2026-24682.patch + CVE-2026-24683: Heap-use-after-free in ainput_send_input_event + https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-45pf-68pj-fg8q + channels-ainput-lock-context-when-updating-listener-CVE-2026-24683.patch + CVE-2026-24684: Heap-use-after-free in play_thread + https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-vcgv-xgjp-h83q + channel-rdpsnd-only-clean-up-thread-before-free-CVE-2026-24684.patch + channels-rdpsnd-terminate-thread-before-free-CVE-2026-24684.patch + + * security fixes for client from 3.23 (medium): + + CVE-2026-25941 Out-of-bounds read in rdpgfx_recv_wire_to_surface_2_pdu + https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-3546-x645-5cf8 + channels-rdpgfx-check-available-stream-length-CVE-2026-25941.patch + CVE-2026-25942 Global-buffer-overflow in xf_rail_server_execute_result + https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-78q6-67m7-wwf6 + client-x11-stringfiy-functions-for-RAILS-CVE-2026-25942.patch + CVE-2026-25952 CVE-2026-25953 CVE-2026-25954 + Heap-use-after-free in xf_SetWindowMinMaxInfo + https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-cgqm-cwjg-7w9x + Heap-use-after-free in xf_AppUpdateWindowFromSurface (freed appWindow) + https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-p6rq-rxpc-rh3p + Heap-use-after-free in xf_rail_server_local_move_size + https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-cc88-4j37-mw6j + client-x11-lock-appWindow-CVE-2026-25952-CVE-2026-25953-CVE-2026-25954.patch + CVE-2026-25955 Heap-use-after-free in xf_AppUpdateWindowFromSurface + (stale XImage) + https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-4g54-x8v7-559x + client-x11-destroy-XImage-on-window-unmap-CVE-2026-25955.patch + (also client-x11-fix-missing-includes.patch) + CVE-2026-25959 Heap-use-after-free in xf_cliprdr_provide_data_ + https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-78xg-v4p2-4w3c + client-x11-lock-cache-when-providing-data-CVE-2026-25959.patch + CVE-2026-25997 Heap-use-after-free in xf_clipboard_format_equal + https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-q5j3-m6jf-3jq4 + client-X11-fix-clipboard-update-CVE-2026-25997.patch + CVE-2026-26271 Buffer Overread in FreeRDP Icon Processing + https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-hr4m-ph4g-48j6 + codec-color-fix-input-length-checks-CVE-2026-26271.patch + CVE-2026-26986 Heap-use-after-free in rail_window_free + https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-crqx-g6x5-rx47 + client-x11-fix-xf_rail_window_common-cleanup-CVE-2026-26986.patch + CVE-2026-27015 Smartcard NDR Alignment Padding Triggers Reachable + WINPR_ASSERT Abort (Client DoS) + https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-7g72-39pq-4725 + utils-smartcard-check-stream-length-on-padding-CVE-2026-27015.patch + CVE-2026-26955 Heap Out-of-Bounds Write in ClearCodec Surface Command + Handler via Missing Bounds Validation + https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-mr6w-ch7c-mqqj + codec-clear-fix-missing-destination-boundary-checks.patch + codec-clear-fix-destination-checks-CVE-2026-26955.patch + CVE-2026-26965 Heap Out-of-Bounds Write in Planar Bitmap RLE Decompression + via Destination Offset + https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-5vgf-mw4f-r33h + codec-planar-fix-missing-destination-bounds-checks-CVE-2026-26965.patch + + * These fixes introduces symbols into libfreerdp3, which don't exist in + versions before 3.21.0, - add them to this version with a virtual package + libfreerdp3-partial-api-3-21, with an alternative Depends field: + libfreerdp3-partial-api-3-21 | libfreerdp3-3 (>>3.21.0) + so apt dependency solver does the right thing for users of these symbols. + This virtual package (libfreerdp3-partial-api-3-21) exists in trixie only. + + * additional 4 upstream patches fixing a range of issues in rdpecam + + winpr-wlog-Add-specialized-text-log-functions.patch - + preparational (two new log functions, libwinpr3-partial-api-3-17) + warnings-Fix-format-string-errors-partial.patch - + printf string fixes in existing code after the above patch + (partial, only hunks which applies cleanly are kept, + no attempt to back-port other hunks) + channels-rdpecam-add-value-range-checks.patch - + missing range checking in rdpecam code + channels-rdpecam-fix-PROPERTY_DESCRIPTION-parsing.patch - + additional fix for CVE-2026-24677 fix + + * CVE-2025-4478.patch: add DEP-3 headers + + -- Michael Tokarev Sat, 28 Mar 2026 20:59:33 +0300 + freerdp3 (3.15.0+dfsg-2.1) unstable; urgency=medium * Non-maintainer upload. diff -Nru freerdp3-3.15.0+dfsg/debian/control freerdp3-3.15.0+dfsg/debian/control --- freerdp3-3.15.0+dfsg/debian/control 2025-04-24 07:36:08.000000000 +0000 +++ freerdp3-3.15.0+dfsg/debian/control 2026-02-25 20:31:28.000000000 +0000 @@ -87,6 +87,7 @@ ${misc:Depends}, ${shlibs:Depends}, libwinpr3-3 (= ${binary:Version}), +Provides: libfreerdp3-partial-api-3-21 Multi-Arch: same Suggests: freerdp3-x11, @@ -133,6 +134,7 @@ Multi-Arch: same Suggests: freerdp3-x11, +Provides: libwinpr3-partial-api-3-17 Description: Windows Portable Runtime library 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, diff -Nru freerdp3-3.15.0+dfsg/debian/gbp.conf freerdp3-3.15.0+dfsg/debian/gbp.conf --- freerdp3-3.15.0+dfsg/debian/gbp.conf 2025-04-11 09:10:27.000000000 +0000 +++ freerdp3-3.15.0+dfsg/debian/gbp.conf 2026-01-21 14:42:33.000000000 +0000 @@ -1,2 +1,3 @@ [DEFAULT] pristine-tar = True +debian-branch = debian/trixie diff -Nru freerdp3-3.15.0+dfsg/debian/libfreerdp3-3.symbols freerdp3-3.15.0+dfsg/debian/libfreerdp3-3.symbols --- freerdp3-3.15.0+dfsg/debian/libfreerdp3-3.symbols 2025-04-11 09:10:27.000000000 +0000 +++ freerdp3-3.15.0+dfsg/debian/libfreerdp3-3.symbols 2026-02-09 18:48:59.000000000 +0000 @@ -1,4 +1,8 @@ libfreerdp3.so.3 libfreerdp3-3 #MINVER# +| libfreerdp3-partial-api-3-21 | libfreerdp3-3 (>>3.21.0) +# dpkg-gensymbols disallows symbol version > $DEB_VERSION + freerdp_glyph_convert_ex@Base 3.15.0+dfsg-2+deb13u1 1 + scard_log_status_error_wlog@Base 3.15.0+dfsg-2+deb13u1 1 * Build-Depends-Package: freerdp3-dev Bitmap_Alloc@Base 3.0.0 Bitmap_SetDimensions@Base 3.0.0 diff -Nru freerdp3-3.15.0+dfsg/debian/libwinpr3-3.symbols freerdp3-3.15.0+dfsg/debian/libwinpr3-3.symbols --- freerdp3-3.15.0+dfsg/debian/libwinpr3-3.symbols 2025-04-11 09:10:27.000000000 +0000 +++ freerdp3-3.15.0+dfsg/debian/libwinpr3-3.symbols 2026-02-25 20:31:28.000000000 +0000 @@ -1,4 +1,7 @@ libwinpr3.so.3 libwinpr3-3 #MINVER# +| libwinpr3-partial-api-3-17 | libwinpr3-3 (>>3.17.0) + WLog_PrintTextMessage@Base 3.15.0+dfsg-2.1+deb13u1 1 + WLog_PrintTextMessageVA@Base 3.15.0+dfsg-2.1+deb13u1 1 * Build-Depends-Package: winpr3-dev AddDllDirectory@Base 3.0.0 AddVectoredContinueHandler@Base 3.0.0 diff -Nru freerdp3-3.15.0+dfsg/debian/patches/CVE-2025-4478.patch freerdp3-3.15.0+dfsg/debian/patches/CVE-2025-4478.patch --- freerdp3-3.15.0+dfsg/debian/patches/CVE-2025-4478.patch 2025-05-26 12:38:19.000000000 +0000 +++ freerdp3-3.15.0+dfsg/debian/patches/CVE-2025-4478.patch 2026-02-25 20:31:28.000000000 +0000 @@ -1,8 +1,8 @@ -From a4bb702aa62e4fad91ca99142de075265555ec18 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Jonas=20=C3=85dahl?= +From: Jonas Ådahl Date: Tue, 13 May 2025 10:34:08 +0200 -Subject: [PATCH] transport: Initialize function pointers after resource - allocation +Subject: transport: Initialize function pointers after resource allocation +Origin: upstream, https://github.com/FreeRDP/FreeRDP/commit/a4bb702aa62e4fad91ca99142de075265555ec18 +Forwarded: not-needed The transport instance is freed when an error occurs. If the TransportDisconnect function pointer is initialized it diff -Nru freerdp3-3.15.0+dfsg/debian/patches/README freerdp3-3.15.0+dfsg/debian/patches/README --- freerdp3-3.15.0+dfsg/debian/patches/README 2025-04-11 09:10:27.000000000 +0000 +++ freerdp3-3.15.0+dfsg/debian/patches/README 1970-01-01 00:00:00.000000000 +0000 @@ -1,3 +0,0 @@ -0xxx: Grabbed from upstream development. -1xxx: Possibly relevant for upstream adoption. -2xxx: Only relevant for official Debian release. diff -Nru freerdp3-3.15.0+dfsg/debian/patches/cache-offscreen-invalidate-bitmap-before-free-CVE-2026-23884.patch freerdp3-3.15.0+dfsg/debian/patches/cache-offscreen-invalidate-bitmap-before-free-CVE-2026-23884.patch --- freerdp3-3.15.0+dfsg/debian/patches/cache-offscreen-invalidate-bitmap-before-free-CVE-2026-23884.patch 1970-01-01 00:00:00.000000000 +0000 +++ freerdp3-3.15.0+dfsg/debian/patches/cache-offscreen-invalidate-bitmap-before-free-CVE-2026-23884.patch 2026-02-09 18:48:59.000000000 +0000 @@ -0,0 +1,48 @@ +From: akallabeth +Date: Mon, 19 Jan 2026 08:58:22 +0100 +Subject: [cache,offscreen] invalidate bitmap before free +Origin: upstream, https://github.com/FreeRDP/FreeRDP/commit/52106a26726a2aba77aa6d86014d2eb3507f0783 +Forwarded: not-needed +Bug: https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-cfgj-vc84-f3pp +Bug: https://security-tracker.debian.org/tracker/CVE-2026-23884 + +First ensure the bitmap is no longer used for drawing before calling the +free function. +--- + libfreerdp/cache/offscreen.c | 10 +++++++--- + 1 file changed, 7 insertions(+), 3 deletions(-) + +diff --git a/libfreerdp/cache/offscreen.c b/libfreerdp/cache/offscreen.c +index 91fa38f32..d3c85f95d 100644 +--- a/libfreerdp/cache/offscreen.c ++++ b/libfreerdp/cache/offscreen.c +@@ -164,8 +164,6 @@ void offscreen_cache_put(rdpOffscreenCache* offscreenCache, UINT32 index, rdpBit + + void offscreen_cache_delete(rdpOffscreenCache* offscreenCache, UINT32 index) + { +- rdpBitmap* prevBitmap = NULL; +- + WINPR_ASSERT(offscreenCache); + + if (index >= offscreenCache->maxEntries) +@@ -174,10 +172,16 @@ void offscreen_cache_delete(rdpOffscreenCache* offscreenCache, UINT32 index) + return; + } + +- prevBitmap = offscreenCache->entries[index]; ++ rdpBitmap* prevBitmap = offscreenCache->entries[index]; + + if (prevBitmap != NULL) ++ { ++ WINPR_ASSERT(offscreenCache->context); ++ ++ /* Ensure that the bitmap is no longer used in GDI */ ++ IFCALL(prevBitmap->SetSurface, offscreenCache->context, NULL, FALSE); + Bitmap_Free(offscreenCache->context, prevBitmap); ++ } + + offscreenCache->entries[index] = NULL; + } +-- +2.47.3 + diff -Nru freerdp3-3.15.0+dfsg/debian/patches/channel-rdpsnd-only-clean-up-thread-before-free-CVE-2026-24684.patch freerdp3-3.15.0+dfsg/debian/patches/channel-rdpsnd-only-clean-up-thread-before-free-CVE-2026-24684.patch --- freerdp3-3.15.0+dfsg/debian/patches/channel-rdpsnd-only-clean-up-thread-before-free-CVE-2026-24684.patch 1970-01-01 00:00:00.000000000 +0000 +++ freerdp3-3.15.0+dfsg/debian/patches/channel-rdpsnd-only-clean-up-thread-before-free-CVE-2026-24684.patch 2026-02-09 18:48:59.000000000 +0000 @@ -0,0 +1,119 @@ +From: akallabeth +Date: Wed, 28 Jan 2026 09:31:06 +0100 +Subject: [channel,rdpsnd] only clean up thread before free +Origin: upstream, https://github.com/FreeRDP/FreeRDP/commit/afa6851dc80835d3101e40fcef51b6c5c0f43ea5 +Forwarded: not-needed +Bug: https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-vcgv-xgjp-h83q +Bug: https://security-tracker.debian.org/tracker/CVE-2026-24684 + +rdpsnd channel usually has multiple instances (static, dynamic, ...) so +ensure only to terminate the handler thread when the channel is actually +closed for good. +--- + channels/rdpsnd/client/rdpsnd_main.c | 43 ++++++++++++++++------------ + 1 file changed, 25 insertions(+), 18 deletions(-) + +diff --git a/channels/rdpsnd/client/rdpsnd_main.c b/channels/rdpsnd/client/rdpsnd_main.c +--- a/channels/rdpsnd/client/rdpsnd_main.c ++++ b/channels/rdpsnd/client/rdpsnd_main.c +@@ -117,6 +117,8 @@ struct rdpsnd_plugin + BOOL async; + }; + ++static DWORD WINAPI play_thread(LPVOID arg); ++ + static const char* rdpsnd_is_dyn_str(BOOL dynamic) + { + if (dynamic) +@@ -1300,7 +1302,6 @@ static void cleanup_internals(rdpsndPlugin* rdpsnd) + if (!rdpsnd) + return; + +- rdpsnd_terminate_thread(rdpsnd); + if (rdpsnd->pool) + StreamPool_Return(rdpsnd->pool, rdpsnd->data_in); + +@@ -1376,6 +1377,7 @@ static void free_internals(rdpsndPlugin* rdpsnd) + if (rdpsnd->references > 0) + return; + ++ rdpsnd_terminate_thread(rdpsnd); + freerdp_dsp_context_free(rdpsnd->dsp_context); + StreamPool_Free(rdpsnd->pool); + rdpsnd->pool = NULL; +@@ -1399,6 +1401,27 @@ static BOOL allocate_internals(rdpsndPlugin* rdpsnd) + if (!rdpsnd->dsp_context) + return FALSE; + } ++ ++ if (rdpsnd->async) ++ { ++ if (!rdpsnd->queue) ++ { ++ wObject obj = { 0 }; ++ ++ obj.fnObjectFree = queue_free; ++ rdpsnd->queue = MessageQueue_New(&obj); ++ if (!rdpsnd->queue) ++ return CHANNEL_RC_NO_MEMORY; ++ } ++ ++ if (!rdpsnd->thread) ++ { ++ rdpsnd->thread = CreateThread(NULL, 0, play_thread, rdpsnd, 0, NULL); ++ if (!rdpsnd->thread) ++ return CHANNEL_RC_INITIALIZATION_ERROR; ++ } ++ } ++ + rdpsnd->references++; + + return TRUE; +@@ -1454,20 +1477,6 @@ static UINT rdpsnd_virtual_channel_event_initialized(rdpsndPlugin* rdpsnd) + if (!rdpsnd) + return ERROR_INVALID_PARAMETER; + +- if (rdpsnd->async) +- { +- wObject obj = { 0 }; +- +- obj.fnObjectFree = queue_free; +- rdpsnd->queue = MessageQueue_New(&obj); +- if (!rdpsnd->queue) +- return CHANNEL_RC_NO_MEMORY; +- +- rdpsnd->thread = CreateThread(NULL, 0, play_thread, rdpsnd, 0, NULL); +- if (!rdpsnd->thread) +- return CHANNEL_RC_INITIALIZATION_ERROR; +- } +- + if (!allocate_internals(rdpsnd)) + return CHANNEL_RC_NO_MEMORY; + +@@ -1478,8 +1487,6 @@ void rdpsnd_virtual_channel_event_terminated(rdpsndPlugin* rdpsnd) + { + if (rdpsnd) + { +- rdpsnd_terminate_thread(rdpsnd); +- + free_internals(rdpsnd); + audio_formats_free(rdpsnd->fixed_format, 1); + free(rdpsnd->subsystem); +@@ -1701,13 +1708,13 @@ static UINT rdpsnd_on_close(IWTSVirtualChannelCallback* pChannelCallback) + + cleanup_internals(rdpsnd); + ++ free_internals(rdpsnd); + if (rdpsnd->device) + { + IFCALL(rdpsnd->device->Free, rdpsnd->device); + rdpsnd->device = NULL; + } + +- free_internals(rdpsnd); + free(pChannelCallback); + return CHANNEL_RC_OK; + } +-- +2.47.3 + diff -Nru freerdp3-3.15.0+dfsg/debian/patches/channels-ainput-lock-context-when-updating-listener-CVE-2026-24683.patch freerdp3-3.15.0+dfsg/debian/patches/channels-ainput-lock-context-when-updating-listener-CVE-2026-24683.patch --- freerdp3-3.15.0+dfsg/debian/patches/channels-ainput-lock-context-when-updating-listener-CVE-2026-24683.patch 1970-01-01 00:00:00.000000000 +0000 +++ freerdp3-3.15.0+dfsg/debian/patches/channels-ainput-lock-context-when-updating-listener-CVE-2026-24683.patch 2026-02-09 18:48:59.000000000 +0000 @@ -0,0 +1,114 @@ +From: akallabeth +Date: Mon, 26 Jan 2026 12:08:48 +0100 +Subject: [channels,ainput] lock context when updating listener +Origin: upstream, https://github.com/FreeRDP/FreeRDP/commit/d9ca272dce7a776ab475e9b1a8e8c3d2968c8486 +Forwarded: not-needed +Bug: https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-45pf-68pj-fg8q +Bug: https://security-tracker.debian.org/tracker/CVE-2026-24683 + +--- + channels/ainput/client/ainput_main.c | 36 ++++++++++++++++++++-------- + 1 file changed, 26 insertions(+), 10 deletions(-) + +diff --git a/channels/ainput/client/ainput_main.c b/channels/ainput/client/ainput_main.c +--- a/channels/ainput/client/ainput_main.c ++++ b/channels/ainput/client/ainput_main.c +@@ -45,6 +45,7 @@ struct AINPUT_PLUGIN_ + AInputClientContext* context; + UINT32 MajorVersion; + UINT32 MinorVersion; ++ CRITICAL_SECTION lock; + }; + + /** +@@ -85,18 +86,15 @@ static UINT ainput_on_data_received(IWTSVirtualChannelCallback* pChannelCallback + + static UINT ainput_send_input_event(AInputClientContext* context, UINT64 flags, INT32 x, INT32 y) + { +- AINPUT_PLUGIN* ainput = NULL; +- GENERIC_CHANNEL_CALLBACK* callback = NULL; + BYTE buffer[32] = { 0 }; +- UINT64 time = 0; + wStream sbuffer = { 0 }; + wStream* s = Stream_StaticInit(&sbuffer, buffer, sizeof(buffer)); + + WINPR_ASSERT(s); + WINPR_ASSERT(context); + +- time = GetTickCount64(); +- ainput = (AINPUT_PLUGIN*)context->handle; ++ const UINT64 time = GetTickCount64(); ++ AINPUT_PLUGIN* ainput = (AINPUT_PLUGIN*)context->handle; + WINPR_ASSERT(ainput); + + if (ainput->MajorVersion != AINPUT_VERSION_MAJOR) +@@ -105,8 +103,6 @@ static UINT ainput_send_input_event(AInputClientContext* context, UINT64 flags, + ainput->MajorVersion, ainput->MinorVersion); + return CHANNEL_RC_UNSUPPORTED_VERSION; + } +- callback = ainput->base.listener_callback->channel_callback; +- WINPR_ASSERT(callback); + + { + char ebuffer[128] = { 0 }; +@@ -125,10 +121,15 @@ static UINT ainput_send_input_event(AInputClientContext* context, UINT64 flags, + Stream_SealLength(s); + + /* ainput back what we have received. AINPUT does not have any message IDs. */ ++ EnterCriticalSection(&ainput->lock); ++ GENERIC_CHANNEL_CALLBACK* callback = ainput->base.listener_callback->channel_callback; ++ WINPR_ASSERT(callback); + WINPR_ASSERT(callback->channel); + WINPR_ASSERT(callback->channel->Write); +- return callback->channel->Write(callback->channel, (ULONG)Stream_Length(s), Stream_Buffer(s), +- NULL); ++ const UINT rc = callback->channel->Write(callback->channel, (ULONG)Stream_Length(s), ++ Stream_Buffer(s), NULL); ++ LeaveCriticalSection(&ainput->lock); ++ return rc; + } + + /** +@@ -140,8 +141,16 @@ static UINT ainput_on_close(IWTSVirtualChannelCallback* pChannelCallback) + { + GENERIC_CHANNEL_CALLBACK* callback = (GENERIC_CHANNEL_CALLBACK*)pChannelCallback; + +- free(callback); ++ if (callback) ++ { ++ AINPUT_PLUGIN* ainput = (AINPUT_PLUGIN*)callback->plugin; ++ WINPR_ASSERT(ainput); + ++ /* Lock here to ensure that no ainput_send_input_event is in progress. */ ++ EnterCriticalSection(&ainput->lock); ++ free(callback); ++ LeaveCriticalSection(&ainput->lock); ++ } + return CHANNEL_RC_OK; + } + +@@ -156,14 +165,21 @@ static UINT init_plugin_cb(GENERIC_DYNVC_PLUGIN* base, WINPR_ATTR_UNUSED rdpCont + context->handle = (void*)base; + context->AInputSendInputEvent = ainput_send_input_event; + ++ InitializeCriticalSection(&ainput->lock); ++ ++ EnterCriticalSection(&ainput->lock); + ainput->context = context; + ainput->base.iface.pInterface = context; ++ LeaveCriticalSection(&ainput->lock); + return CHANNEL_RC_OK; + } + + static void terminate_plugin_cb(GENERIC_DYNVC_PLUGIN* base) + { + AINPUT_PLUGIN* ainput = (AINPUT_PLUGIN*)base; ++ WINPR_ASSERT(ainput); ++ ++ DeleteCriticalSection(&ainput->lock); + free(ainput->context); + } + +-- +2.47.3 + diff -Nru freerdp3-3.15.0+dfsg/debian/patches/channels-audin-fix-audin_server_recv_formats-cleanup-CVE-2026-24682.patch freerdp3-3.15.0+dfsg/debian/patches/channels-audin-fix-audin_server_recv_formats-cleanup-CVE-2026-24682.patch --- freerdp3-3.15.0+dfsg/debian/patches/channels-audin-fix-audin_server_recv_formats-cleanup-CVE-2026-24682.patch 1970-01-01 00:00:00.000000000 +0000 +++ freerdp3-3.15.0+dfsg/debian/patches/channels-audin-fix-audin_server_recv_formats-cleanup-CVE-2026-24682.patch 2026-02-09 18:48:59.000000000 +0000 @@ -0,0 +1,31 @@ +From: akallabeth +Date: Mon, 26 Jan 2026 10:14:08 +0100 +Subject: [channels,audin] fix audin_server_recv_formats cleanup +Origin: upstream, https://github.com/FreeRDP/FreeRDP/commit/1c5c74223179d425a1ce6dbbb6a3dd2a958b7aee +Forwarded: not-needed +Bug: https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-vcw2-pqgw-mx6g +Bug: https://security-tracker.debian.org/tracker/CVE-2026-24682 + +--- + channels/audin/server/audin.c | 6 +----- + 1 file changed, 1 insertion(+), 5 deletions(-) + +diff --git a/channels/audin/server/audin.c b/channels/audin/server/audin.c +--- a/channels/audin/server/audin.c ++++ b/channels/audin/server/audin.c +@@ -146,11 +146,7 @@ static UINT audin_server_recv_formats(audin_server_context* context, wStream* s, + AUDIO_FORMAT* format = &pdu.SoundFormats[i]; + + if (!audio_format_read(s, format)) +- { +- WLog_Print(audin->log, WLOG_ERROR, "Failed to read audio format"); +- audio_formats_free(pdu.SoundFormats, i + i); +- return ERROR_INVALID_DATA; +- } ++ goto fail; + + audio_format_print(audin->log, WLOG_DEBUG, format); + } +-- +2.47.3 + diff -Nru freerdp3-3.15.0+dfsg/debian/patches/channels-audin-free-up-old-audio-formats-CVE-2026-22852.patch freerdp3-3.15.0+dfsg/debian/patches/channels-audin-free-up-old-audio-formats-CVE-2026-22852.patch --- freerdp3-3.15.0+dfsg/debian/patches/channels-audin-free-up-old-audio-formats-CVE-2026-22852.patch 1970-01-01 00:00:00.000000000 +0000 +++ freerdp3-3.15.0+dfsg/debian/patches/channels-audin-free-up-old-audio-formats-CVE-2026-22852.patch 2026-02-09 18:48:59.000000000 +0000 @@ -0,0 +1,30 @@ +From: akallabeth +Date: Sat, 10 Jan 2026 08:36:38 +0100 +Subject: [channels,audin] free up old audio formats +Origin: upstream, https://github.com/FreeRDP/FreeRDP/commit/cd1ffa112cfbe1b40a9fd57e299a8ea12e23df0d +Forwarded: not-needed +Bug: https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-9chc-g79v-4qq4 +Bug: https://security-tracker.debian.org/tracker/CVE-2026-22852 + +--- + channels/audin/client/audin_main.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/channels/audin/client/audin_main.c b/channels/audin/client/audin_main.c +index bcaf1a646..b4c8ba580 100644 +--- a/channels/audin/client/audin_main.c ++++ b/channels/audin/client/audin_main.c +@@ -206,6 +206,10 @@ static UINT audin_process_formats(AUDIN_PLUGIN* audin, AUDIN_CHANNEL_CALLBACK* c + } + + Stream_Seek_UINT32(s); /* cbSizeFormatsPacket */ ++ ++ audio_formats_free(callback->formats, callback->formats_count); ++ callback->formats_count = 0; ++ + callback->formats = audio_formats_new(NumFormats); + + if (!callback->formats) +-- +2.47.3 + diff -Nru freerdp3-3.15.0+dfsg/debian/patches/channels-audin-reset-audin-format-CVE-2026-24676.patch freerdp3-3.15.0+dfsg/debian/patches/channels-audin-reset-audin-format-CVE-2026-24676.patch --- freerdp3-3.15.0+dfsg/debian/patches/channels-audin-reset-audin-format-CVE-2026-24676.patch 1970-01-01 00:00:00.000000000 +0000 +++ freerdp3-3.15.0+dfsg/debian/patches/channels-audin-reset-audin-format-CVE-2026-24676.patch 2026-02-09 18:48:59.000000000 +0000 @@ -0,0 +1,35 @@ +From: akallabeth +Date: Mon, 26 Jan 2026 10:20:23 +0100 +Subject: [channels,audin] reset audin->format +Origin: upstream, https://github.com/FreeRDP/FreeRDP/commit/026b81ae5831ac1598d8f7371e0d0996fac7db00 +Forwarded: not-needed +Bug: https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-qh5p-frq4-pgxj +Bug: https://security-tracker.debian.org/tracker/CVE-2026-24676 + +Whenever the underlying structure changes reset the pointer to NULL +--- + channels/audin/client/audin_main.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/channels/audin/client/audin_main.c b/channels/audin/client/audin_main.c +--- a/channels/audin/client/audin_main.c ++++ b/channels/audin/client/audin_main.c +@@ -207,6 +207,7 @@ static UINT audin_process_formats(AUDIN_PLUGIN* audin, AUDIN_CHANNEL_CALLBACK* c + + Stream_Seek_UINT32(s); /* cbSizeFormatsPacket */ + ++ audin->format = NULL; + audio_formats_free(callback->formats, callback->formats_count); + callback->formats_count = 0; + +@@ -284,6 +285,7 @@ out: + + if (error != CHANNEL_RC_OK) + { ++ audin->format = NULL; + audio_formats_free(callback->formats, NumFormats); + callback->formats = NULL; + } +-- +2.47.3 + diff -Nru freerdp3-3.15.0+dfsg/debian/patches/channels-drdynvc-check-pointer-before-reset.patch freerdp3-3.15.0+dfsg/debian/patches/channels-drdynvc-check-pointer-before-reset.patch --- freerdp3-3.15.0+dfsg/debian/patches/channels-drdynvc-check-pointer-before-reset.patch 1970-01-01 00:00:00.000000000 +0000 +++ freerdp3-3.15.0+dfsg/debian/patches/channels-drdynvc-check-pointer-before-reset.patch 2026-02-09 18:48:59.000000000 +0000 @@ -0,0 +1,32 @@ +From: Armin Novak +Date: Tue, 27 Jan 2026 08:58:21 +0100 +Subject: [channels,drdynvc] check pointer before reset +Origin: upstream, https://github.com/FreeRDP/FreeRDP/commit/cb7f295bc750de86480d60a3b58cebc56a57a1c4 +Forwarded: not-needed +Comment: additional fix after CVE-2026-24491 fix + +--- + channels/drdynvc/client/drdynvc_main.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/channels/drdynvc/client/drdynvc_main.c b/channels/drdynvc/client/drdynvc_main.c +index fe2821a6a..c14d66dff 100644 +--- a/channels/drdynvc/client/drdynvc_main.c ++++ b/channels/drdynvc/client/drdynvc_main.c +@@ -509,11 +509,12 @@ static UINT dvcman_channel_close(DVCMAN_CHANNEL* channel, BOOL perRequest, BOOL + channel->state = DVC_CHANNEL_CLOSED; + + { ++ check_open_close_receive(channel); ++ + IWTSVirtualChannelCallback* cb = channel->channel_callback; + channel->channel_callback = NULL; + if (cb) + { +- check_open_close_receive(channel); + IFCALL(cb->OnClose, cb); + } + } +-- +2.47.3 + diff -Nru freerdp3-3.15.0+dfsg/debian/patches/channels-drdynvc-reset-channel_callback-before-close-CVE-2026-24491.patch freerdp3-3.15.0+dfsg/debian/patches/channels-drdynvc-reset-channel_callback-before-close-CVE-2026-24491.patch --- freerdp3-3.15.0+dfsg/debian/patches/channels-drdynvc-reset-channel_callback-before-close-CVE-2026-24491.patch 1970-01-01 00:00:00.000000000 +0000 +++ freerdp3-3.15.0+dfsg/debian/patches/channels-drdynvc-reset-channel_callback-before-close-CVE-2026-24491.patch 2026-02-09 18:48:59.000000000 +0000 @@ -0,0 +1,51 @@ +From: akallabeth +Date: Mon, 26 Jan 2026 10:06:29 +0100 +Subject: [channels,drdynvc] reset channel_callback before close +Origin: upstream, https://github.com/FreeRDP/FreeRDP/commit/e02e052f6692550e539d10f99de9c35a23492db2 +Forwarded: not-needed +Bug: https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-4x6j-w49r-869g +Bug: https://security-tracker.debian.org/tracker/CVE-2026-24491 + +The channel_callback usually frees up the memory of the callback. To +ensure that there is no access to any of the data structures in it +invalidate the pointer used to access it before a free. + +diff --git a/channels/drdynvc/client/drdynvc_main.c b/channels/drdynvc/client/drdynvc_main.c +--- a/channels/drdynvc/client/drdynvc_main.c ++++ b/channels/drdynvc/client/drdynvc_main.c +@@ -510,6 +510,7 @@ static UINT dvcman_channel_close(DVCMAN_CHANNEL* channel, BOOL perRequest, BOOL + + { + IWTSVirtualChannelCallback* cb = channel->channel_callback; ++ channel->channel_callback = NULL; + if (cb) + { + check_open_close_receive(channel); +@@ -517,8 +518,6 @@ static UINT dvcman_channel_close(DVCMAN_CHANNEL* channel, BOOL perRequest, BOOL + } + } + +- channel->channel_callback = NULL; +- + if (channel->dvcman && channel->dvcman->drdynvc) + { + if (context) +@@ -796,14 +795,13 @@ out: + */ + static UINT dvcman_open_channel(drdynvcPlugin* drdynvc, DVCMAN_CHANNEL* channel) + { +- IWTSVirtualChannelCallback* pCallback = NULL; + UINT error = CHANNEL_RC_OK; + + WINPR_ASSERT(drdynvc); + WINPR_ASSERT(channel); + if (channel->state == DVC_CHANNEL_RUNNING) + { +- pCallback = channel->channel_callback; ++ IWTSVirtualChannelCallback* pCallback = channel->channel_callback; + + if (pCallback->OnOpen) + { +-- +2.47.3 + diff -Nru freerdp3-3.15.0+dfsg/debian/patches/channels-drive-fix-constant-type-CVE-2026-22854.patch freerdp3-3.15.0+dfsg/debian/patches/channels-drive-fix-constant-type-CVE-2026-22854.patch --- freerdp3-3.15.0+dfsg/debian/patches/channels-drive-fix-constant-type-CVE-2026-22854.patch 1970-01-01 00:00:00.000000000 +0000 +++ freerdp3-3.15.0+dfsg/debian/patches/channels-drive-fix-constant-type-CVE-2026-22854.patch 2026-02-09 18:48:59.000000000 +0000 @@ -0,0 +1,29 @@ +From: akallabeth +Date: Mon, 12 Jan 2026 03:44:06 +0100 +Subject: [channels,drive] fix constant type +Origin: upstream, https://github.com/FreeRDP/FreeRDP/commit/3da319570c8a6be0a79b3306f1ed354c4a943259 +Forwarded: not-needed +Bug: https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-47vj-g3c3-3rmf +Bug: https://security-tracker.debian.org/tracker/CVE-2026-22854 + +ensure constant is of 64bit integer type +--- + channels/drive/client/drive_main.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/channels/drive/client/drive_main.c b/channels/drive/client/drive_main.c +index 1dce5c348..13188fbc6 100644 +--- a/channels/drive/client/drive_main.c ++++ b/channels/drive/client/drive_main.c +@@ -302,7 +302,7 @@ static UINT drive_process_irp_read(DRIVE_DEVICE* drive, IRP* irp) + Length = 0; + } + +- if (!Stream_EnsureRemainingCapacity(irp->output, Length + 4)) ++ if (!Stream_EnsureRemainingCapacity(irp->output, 4ull + Length)) + { + WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!"); + return ERROR_INTERNAL_ERROR; +-- +2.47.3 + diff -Nru freerdp3-3.15.0+dfsg/debian/patches/channels-rdpear-add-checks-for-itemSize-CVE-2026-22853.patch freerdp3-3.15.0+dfsg/debian/patches/channels-rdpear-add-checks-for-itemSize-CVE-2026-22853.patch --- freerdp3-3.15.0+dfsg/debian/patches/channels-rdpear-add-checks-for-itemSize-CVE-2026-22853.patch 1970-01-01 00:00:00.000000000 +0000 +++ freerdp3-3.15.0+dfsg/debian/patches/channels-rdpear-add-checks-for-itemSize-CVE-2026-22853.patch 2026-02-09 18:48:59.000000000 +0000 @@ -0,0 +1,72 @@ +From: akallabeth +Date: Mon, 12 Jan 2026 15:02:53 +0100 +Subject: [channels,rdpear] add checks for itemSize +Origin: upstream, https://github.com/FreeRDP/FreeRDP/commit/19f48dc7d615984a24a9be89f50ef9eb8f9bdb6a +Forwarded: not-needed +Bug: https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-47v9-p4gp-w5ch +Bug: https://security-tracker.debian.org/tracker/CVE-2026-22853 + +when a ndr read function is called with invalid arguments abort early. +--- + channels/rdpear/common/ndr.c | 22 ++++++++++++++++++---- + 1 file changed, 18 insertions(+), 4 deletions(-) + +diff --git a/channels/rdpear/common/ndr.c b/channels/rdpear/common/ndr.c +index 697d6742e..4b22fa62b 100644 +--- a/channels/rdpear/common/ndr.c ++++ b/channels/rdpear/common/ndr.c +@@ -519,6 +519,9 @@ BOOL ndr_read_uconformant_varying_array(NdrContext* context, wStream* s, + WINPR_ASSERT(itemType); + WINPR_ASSERT(ptarget); + ++ if (itemType->itemSize == 0) ++ return FALSE; ++ + UINT32 maxCount = 0; + UINT32 offset = 0; + UINT32 length = 0; +@@ -527,10 +530,10 @@ BOOL ndr_read_uconformant_varying_array(NdrContext* context, wStream* s, + !ndr_read_uint32(context, s, &length)) + return FALSE; + +- if ((length * itemType->itemSize) < hints->length) ++ if ((1ull * length * itemType->itemSize) > hints->length) + return FALSE; + +- if ((maxCount * itemType->itemSize) < hints->maxLength) ++ if ((1ull * maxCount * itemType->itemSize) > hints->maxLength) + return FALSE; + + BYTE* target = (BYTE*)ptarget; +@@ -553,6 +556,9 @@ BOOL ndr_write_uconformant_varying_array(NdrContext* context, wStream* s, + WINPR_ASSERT(itemType); + WINPR_ASSERT(psrc); + ++ if (itemType->itemSize == 0) ++ return FALSE; ++ + if (!ndr_write_uint32(context, s, hints->maxLength) || !ndr_write_uint32(context, s, 0) || + !ndr_write_uint32(context, s, hints->length)) + return FALSE; +@@ -580,8 +586,16 @@ BOOL ndr_read_uconformant_array(NdrContext* context, wStream* s, const NdrArrayH + if (!ndr_read_uint32(context, s, &count)) + return FALSE; + +- if ((count * itemType->itemSize < hints->count)) +- return FALSE; ++ if (itemType->arity == NDR_ARITY_SIMPLE) ++ { ++ if (count > hints->count) ++ return FALSE; ++ } ++ else ++ { ++ if ((1ull * count * itemType->itemSize) > hints->count) ++ return FALSE; ++ } + + BYTE* target = (BYTE*)vtarget; + for (UINT32 i = 0; i < count; i++, target += itemType->itemSize) +-- +2.47.3 + diff -Nru freerdp3-3.15.0+dfsg/debian/patches/channels-rdpecam-add-value-range-checks.patch freerdp3-3.15.0+dfsg/debian/patches/channels-rdpecam-add-value-range-checks.patch --- freerdp3-3.15.0+dfsg/debian/patches/channels-rdpecam-add-value-range-checks.patch 1970-01-01 00:00:00.000000000 +0000 +++ freerdp3-3.15.0+dfsg/debian/patches/channels-rdpecam-add-value-range-checks.patch 2026-02-25 20:31:28.000000000 +0000 @@ -0,0 +1,581 @@ +From: akallabeth +Date: Fri, 9 Jan 2026 09:18:24 +0100 +Subject: [channels,rdpecam] add value range checks +Origin: upstream, https://github.com/FreeRDP/FreeRDP/commit/508a0db07c8216e86edd1ce7f7f8398342868a91 +Forwarded: not-needed +Comment: + +When reading a enum value from network, first check the value range and +abort with a log message if an invalid value is found +--- + channels/rdpecam/server/CMakeLists.txt | 2 +- + .../server/camera_device_enumerator_main.c | 9 +- + channels/rdpecam/server/camera_device_main.c | 111 +++++- + channels/rdpecam/server/rdpecam-utils.h | 325 ++++++++++++++++++ + 4 files changed, 428 insertions(+), 19 deletions(-) + create mode 100644 channels/rdpecam/server/rdpecam-utils.h + +diff --git a/channels/rdpecam/server/CMakeLists.txt b/channels/rdpecam/server/CMakeLists.txt +index bd843379f..8d7d25abf 100644 +--- a/channels/rdpecam/server/CMakeLists.txt ++++ b/channels/rdpecam/server/CMakeLists.txt +@@ -17,7 +17,7 @@ + + define_channel_server("rdpecam") + +-set(${MODULE_PREFIX}_SRCS camera_device_enumerator_main.c camera_device_main.c) ++set(${MODULE_PREFIX}_SRCS camera_device_enumerator_main.c camera_device_main.c rdpecam-utils.h) + + set(${MODULE_PREFIX}_LIBS freerdp) + +diff --git a/channels/rdpecam/server/camera_device_enumerator_main.c b/channels/rdpecam/server/camera_device_enumerator_main.c +index 8b99fac10..33ac6b727 100644 +--- a/channels/rdpecam/server/camera_device_enumerator_main.c ++++ b/channels/rdpecam/server/camera_device_enumerator_main.c +@@ -25,6 +25,8 @@ + #include + #include + ++#include "rdpecam-utils.h" ++ + #define TAG CHANNELS_TAG("rdpecam-enumerator.server") + + typedef enum +@@ -301,7 +303,12 @@ static UINT enumerator_process_message(enumerator_server* enumerator) + return ERROR_NO_DATA; + + Stream_Read_UINT8(s, header.Version); +- Stream_Read_UINT8(s, header.MessageId); ++ { ++ const UINT8 id = Stream_Get_UINT8(s); ++ if (!rdpecam_valid_messageId(id)) ++ return ERROR_INVALID_DATA; ++ header.MessageId = (CAM_MSG_ID)id; ++ } + + switch (header.MessageId) + { +diff --git a/channels/rdpecam/server/camera_device_main.c b/channels/rdpecam/server/camera_device_main.c +index 0741eb094..b5abe9d1d 100644 +--- a/channels/rdpecam/server/camera_device_main.c ++++ b/channels/rdpecam/server/camera_device_main.c +@@ -25,6 +25,8 @@ + #include + #include + ++#include "rdpecam-utils.h" ++ + #define TAG CHANNELS_TAG("rdpecam.server") + + typedef enum +@@ -156,7 +158,12 @@ static UINT device_server_recv_error_response(CameraDeviceServerContext* context + if (!Stream_CheckAndLogRequiredLength(TAG, s, 4)) + return ERROR_NO_DATA; + +- Stream_Read_UINT32(s, pdu.ErrorCode); ++ { ++ const UINT32 val = Stream_Get_UINT32(s); ++ if (!rdpecam_valid_CamErrorCode(val)) ++ return ERROR_INVALID_DATA; ++ pdu.ErrorCode = (CAM_ERROR_CODE)val; ++ } + + IFCALLRET(context->ErrorResponse, error, context, &pdu); + if (error) +@@ -188,8 +195,18 @@ static UINT device_server_recv_stream_list_response(CameraDeviceServerContext* c + { + CAM_STREAM_DESCRIPTION* StreamDescription = &pdu.StreamDescriptions[i]; + +- Stream_Read_UINT16(s, StreamDescription->FrameSourceTypes); +- Stream_Read_UINT8(s, StreamDescription->StreamCategory); ++ { ++ const UINT16 val = Stream_Get_UINT16(s); ++ if (!rdpecam_valid_CamStreamFrameSourceType(val)) ++ return ERROR_INVALID_DATA; ++ StreamDescription->FrameSourceTypes = (CAM_STREAM_FRAME_SOURCE_TYPES)val; ++ } ++ { ++ const UINT8 val = Stream_Get_UINT8(s); ++ if (!rdpecam_valid_CamStreamCategory(val)) ++ return ERROR_INVALID_DATA; ++ StreamDescription->StreamCategory = (CAM_STREAM_CATEGORY)val; ++ } + Stream_Read_UINT8(s, StreamDescription->Selected); + Stream_Read_UINT8(s, StreamDescription->CanBeShared); + } +@@ -230,14 +247,30 @@ static UINT device_server_recv_media_type_list_response(CameraDeviceServerContex + { + CAM_MEDIA_TYPE_DESCRIPTION* MediaTypeDescriptions = &pdu.MediaTypeDescriptions[i]; + +- Stream_Read_UINT8(s, MediaTypeDescriptions->Format); ++ { ++ const UINT8 val = Stream_Get_UINT8(s); ++ if (!rdpecam_valid_CamMediaFormat(val)) ++ { ++ free(pdu.MediaTypeDescriptions); ++ return ERROR_INVALID_DATA; ++ } ++ MediaTypeDescriptions->Format = (CAM_MEDIA_FORMAT)val; ++ } + Stream_Read_UINT32(s, MediaTypeDescriptions->Width); + Stream_Read_UINT32(s, MediaTypeDescriptions->Height); + Stream_Read_UINT32(s, MediaTypeDescriptions->FrameRateNumerator); + Stream_Read_UINT32(s, MediaTypeDescriptions->FrameRateDenominator); + Stream_Read_UINT32(s, MediaTypeDescriptions->PixelAspectRatioNumerator); + Stream_Read_UINT32(s, MediaTypeDescriptions->PixelAspectRatioDenominator); +- Stream_Read_UINT8(s, MediaTypeDescriptions->Flags); ++ { ++ const UINT8 val = Stream_Get_UINT8(s); ++ if (!rdpecam_valid_MediaTypeDescriptionFlags(val)) ++ { ++ free(pdu.MediaTypeDescriptions); ++ return ERROR_INVALID_DATA; ++ } ++ MediaTypeDescriptions->Flags = (CAM_MEDIA_TYPE_DESCRIPTION_FLAGS)val; ++ } + } + + IFCALLRET(context->MediaTypeListResponse, error, context, &pdu); +@@ -264,14 +297,25 @@ static UINT device_server_recv_current_media_type_response(CameraDeviceServerCon + if (!Stream_CheckAndLogRequiredLength(TAG, s, 26)) + return ERROR_NO_DATA; + +- Stream_Read_UINT8(s, pdu.MediaTypeDescription.Format); ++ { ++ const UINT8 val = Stream_Get_UINT8(s); ++ if (!rdpecam_valid_CamMediaFormat(val)) ++ return ERROR_INVALID_DATA; ++ pdu.MediaTypeDescription.Format = (CAM_MEDIA_FORMAT)val; ++ } ++ + Stream_Read_UINT32(s, pdu.MediaTypeDescription.Width); + Stream_Read_UINT32(s, pdu.MediaTypeDescription.Height); + Stream_Read_UINT32(s, pdu.MediaTypeDescription.FrameRateNumerator); + Stream_Read_UINT32(s, pdu.MediaTypeDescription.FrameRateDenominator); + Stream_Read_UINT32(s, pdu.MediaTypeDescription.PixelAspectRatioNumerator); + Stream_Read_UINT32(s, pdu.MediaTypeDescription.PixelAspectRatioDenominator); +- Stream_Read_UINT8(s, pdu.MediaTypeDescription.Flags); ++ { ++ const UINT8 val = Stream_Get_UINT8(s); ++ if (!rdpecam_valid_MediaTypeDescriptionFlags(val)) ++ return ERROR_INVALID_DATA; ++ pdu.MediaTypeDescription.Flags = (CAM_MEDIA_TYPE_DESCRIPTION_FLAGS)val; ++ } + + IFCALLRET(context->CurrentMediaTypeResponse, error, context, &pdu); + if (error) +@@ -321,7 +365,12 @@ static UINT device_server_recv_sample_error_response(CameraDeviceServerContext* + return ERROR_NO_DATA; + + Stream_Read_UINT8(s, pdu.StreamIndex); +- Stream_Read_UINT32(s, pdu.ErrorCode); ++ { ++ const UINT32 val = Stream_Get_UINT32(s); ++ if (!rdpecam_valid_CamErrorCode(val)) ++ return ERROR_INVALID_DATA; ++ pdu.ErrorCode = (CAM_ERROR_CODE)val; ++ } + + IFCALLRET(context->SampleErrorResponse, error, context, &pdu); + if (error) +@@ -356,13 +405,30 @@ static UINT device_server_recv_property_list_response(CameraDeviceServerContext* + + for (size_t i = 0; i < pdu.N_Properties; ++i) + { +- Stream_Read_UINT8(s, pdu.Properties[i].PropertySet); +- Stream_Read_UINT8(s, pdu.Properties[i].PropertyId); +- Stream_Read_UINT8(s, pdu.Properties[i].Capabilities); +- Stream_Read_INT32(s, pdu.Properties[i].MinValue); +- Stream_Read_INT32(s, pdu.Properties[i].MaxValue); +- Stream_Read_INT32(s, pdu.Properties[i].Step); +- Stream_Read_INT32(s, pdu.Properties[i].DefaultValue); ++ CAM_PROPERTY_DESCRIPTION* cur = &pdu.Properties[i]; ++ { ++ const UINT8 val = Stream_Get_UINT8(s); ++ if (!rdpecam_valid_CamPropertySet(val)) ++ { ++ free(pdu.Properties); ++ return ERROR_INVALID_DATA; ++ } ++ cur->PropertySet = (CAM_PROPERTY_SET)val; ++ } ++ Stream_Read_UINT8(s, cur->PropertyId); ++ { ++ const UINT8 val = Stream_Get_UINT8(s); ++ if (!rdpecam_valid_CamPropertyCapabilities(val)) ++ { ++ free(pdu.Properties); ++ return ERROR_INVALID_DATA; ++ } ++ cur->Capabilities = (CAM_PROPERTY_CAPABILITIES)val; ++ } ++ Stream_Read_INT32(s, cur->MinValue); ++ Stream_Read_INT32(s, cur->MaxValue); ++ Stream_Read_INT32(s, cur->Step); ++ Stream_Read_INT32(s, cur->DefaultValue); + } + } + +@@ -390,7 +456,13 @@ static UINT device_server_recv_property_value_response(CameraDeviceServerContext + if (!Stream_CheckAndLogRequiredLength(TAG, s, 5)) + return ERROR_NO_DATA; + +- Stream_Read_UINT8(s, pdu.PropertyValue.Mode); ++ { ++ const UINT8 val = Stream_Get_UINT8(s); ++ if (!rdpecam_valid_CamPropertyMode(val)) ++ return ERROR_INVALID_DATA; ++ pdu.PropertyValue.Mode = (CAM_PROPERTY_MODE)val; ++ } ++ + Stream_Read_INT32(s, pdu.PropertyValue.Value); + + IFCALLRET(context->PropertyValueResponse, error, context, &pdu); +@@ -444,7 +516,12 @@ static UINT device_process_message(device_server* device) + return ERROR_NO_DATA; + + Stream_Read_UINT8(s, header.Version); +- Stream_Read_UINT8(s, header.MessageId); ++ { ++ const UINT8 id = Stream_Get_UINT8(s); ++ if (!rdpecam_valid_messageId(id)) ++ return ERROR_INVALID_DATA; ++ header.MessageId = (CAM_MSG_ID)id; ++ } + + switch (header.MessageId) + { +diff --git a/channels/rdpecam/server/rdpecam-utils.h b/channels/rdpecam/server/rdpecam-utils.h +new file mode 100644 +index 000000000..38186a24d +--- /dev/null ++++ b/channels/rdpecam/server/rdpecam-utils.h +@@ -0,0 +1,325 @@ ++/** ++ * FreeRDP: A Remote Desktop Protocol Implementation ++ * Video Capture Virtual Channel Extension ++ * ++ * Copyright 2026 Armin Novak ++ * Copyright 2026 Thincast Technologies GmbH ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++ ++#pragma once ++ ++#include ++ ++#if defined(CHANNEL_RDPECAM) ++#include ++#include ++#include ++ ++WINPR_ATTR_FORMAT_ARG(5, 6) ++static inline void rdpecam_PrintWarning(wLog* log, const char* file, const char* fkt, size_t line, ++ WINPR_FORMAT_ARG const char* fmt, ...) ++{ ++ const DWORD level = WLOG_WARN; ++ va_list ap; ++ ++ va_start(ap, fmt); ++ if (WLog_IsLevelActive(log, level)) ++ WLog_PrintTextMessageVA(log, level, line, file, fkt, fmt, ap); ++ va_end(ap); ++} ++ ++/** @brief check input data is a valid \ref CAM_MSG_ID value ++ * ++ * @param id The message id to check ++ * @param log The logger to use ++ * @param file The file name the function is called from ++ * @param fkt The function calling this function ++ * @param line The line number where the function is called ++ * ++ * @return \b true for success, \b false if invalid ++ * @since version 3.20.1 ++ */ ++#define rdpecam_valid_messageId(id) \ ++ rdpecam_valid_messageId_((id), WLog_Get(TAG), __FILE__, __func__, __LINE__) ++static inline bool rdpecam_valid_messageId_(UINT8 id, wLog* log, const char* file, const char* fkt, ++ size_t line) ++{ ++ switch (id) ++ { ++ case CAM_MSG_ID_SuccessResponse: ++ case CAM_MSG_ID_ErrorResponse: ++ case CAM_MSG_ID_SelectVersionRequest: ++ case CAM_MSG_ID_SelectVersionResponse: ++ case CAM_MSG_ID_DeviceAddedNotification: ++ case CAM_MSG_ID_DeviceRemovedNotification: ++ case CAM_MSG_ID_ActivateDeviceRequest: ++ case CAM_MSG_ID_DeactivateDeviceRequest: ++ case CAM_MSG_ID_StreamListRequest: ++ case CAM_MSG_ID_StreamListResponse: ++ case CAM_MSG_ID_MediaTypeListRequest: ++ case CAM_MSG_ID_MediaTypeListResponse: ++ case CAM_MSG_ID_CurrentMediaTypeRequest: ++ case CAM_MSG_ID_CurrentMediaTypeResponse: ++ case CAM_MSG_ID_StartStreamsRequest: ++ case CAM_MSG_ID_StopStreamsRequest: ++ case CAM_MSG_ID_SampleRequest: ++ case CAM_MSG_ID_SampleResponse: ++ case CAM_MSG_ID_SampleErrorResponse: ++ case CAM_MSG_ID_PropertyListRequest: ++ case CAM_MSG_ID_PropertyListResponse: ++ case CAM_MSG_ID_PropertyValueRequest: ++ case CAM_MSG_ID_PropertyValueResponse: ++ case CAM_MSG_ID_SetPropertyValueRequest: ++ return true; ++ default: ++ rdpecam_PrintWarning(log, file, fkt, line, "Invalid CAM_MSG_ID %" PRIu8, id); ++ return false; ++ } ++} ++ ++/** @brief check input data is a valid \ref CAM_ERROR_CODE value ++ * ++ * @param code The code to check ++ * @param log The logger to use ++ * @param file The file name the function is called from ++ * @param fkt The function calling this function ++ * @param line The line number where the function is called ++ * ++ * @return \b true for success, \b false if invalid ++ * @since version 3.20.1 ++ */ ++#define rdpecam_valid_CamErrorCode(code) \ ++ rdpecam_valid_CamErrorCode_((code), WLog_Get(TAG), __FILE__, __func__, __LINE__) ++static inline bool rdpecam_valid_CamErrorCode_(UINT32 code, wLog* log, const char* file, ++ const char* fkt, size_t line) ++{ ++ switch (code) ++ { ++ case CAM_ERROR_CODE_UnexpectedError: ++ case CAM_ERROR_CODE_InvalidMessage: ++ case CAM_ERROR_CODE_NotInitialized: ++ case CAM_ERROR_CODE_InvalidRequest: ++ case CAM_ERROR_CODE_InvalidStreamNumber: ++ case CAM_ERROR_CODE_InvalidMediaType: ++ case CAM_ERROR_CODE_OutOfMemory: ++ case CAM_ERROR_CODE_ItemNotFound: ++ case CAM_ERROR_CODE_SetNotFound: ++ case CAM_ERROR_CODE_OperationNotSupported: ++ return true; ++ default: ++ rdpecam_PrintWarning(log, file, fkt, line, "Invalid CAM_ERROR_CODE %" PRIu32, code); ++ return false; ++ } ++} ++ ++/** @brief check input data is a valid \ref CAM_STREAM_FRAME_SOURCE_TYPES value ++ * ++ * @param val The value to check ++ * @param log The logger to use ++ * @param file The file name the function is called from ++ * @param fkt The function calling this function ++ * @param line The line number where the function is called ++ * ++ * @return \b true for success, \b false if invalid ++ * @since version 3.20.1 ++ */ ++#define rdpecam_valid_CamStreamFrameSourceType(val) \ ++ rdpecam_valid_CamStreamFrameSourceType_((val), WLog_Get(TAG), __FILE__, __func__, __LINE__) ++static inline bool rdpecam_valid_CamStreamFrameSourceType_(UINT16 val, wLog* log, const char* file, ++ const char* fkt, size_t line) ++{ ++ switch (val) ++ { ++ case CAM_STREAM_FRAME_SOURCE_TYPE_Color: ++ case CAM_STREAM_FRAME_SOURCE_TYPE_Infrared: ++ case CAM_STREAM_FRAME_SOURCE_TYPE_Custom: ++ return true; ++ default: ++ rdpecam_PrintWarning(log, file, fkt, line, ++ "Invalid CAM_STREAM_FRAME_SOURCE_TYPES %" PRIu16, val); ++ return false; ++ } ++} ++ ++/** @brief check input data is a valid \ref CAM_STREAM_CATEGORY value ++ * ++ * @param val The value to check ++ * @param log The logger to use ++ * @param file The file name the function is called from ++ * @param fkt The function calling this function ++ * @param line The line number where the function is called ++ * ++ * @return \b true for success, \b false if invalid ++ * @since version 3.20.1 ++ */ ++#define rdpecam_valid_CamStreamCategory(val) \ ++ rdpecam_valid_CamStreamCategory_((val), WLog_Get(TAG), __FILE__, __func__, __LINE__) ++static inline bool rdpecam_valid_CamStreamCategory_(UINT8 val, wLog* log, const char* file, ++ const char* fkt, size_t line) ++{ ++ switch (val) ++ { ++ case CAM_STREAM_CATEGORY_Capture: ++ return true; ++ default: ++ rdpecam_PrintWarning(log, file, fkt, line, "Invalid CAM_STREAM_CATEGORY %" PRIu8, val); ++ return false; ++ } ++} ++ ++/** @brief check input data is a valid \ref CAM_MEDIA_FORMAT value ++ * ++ * @param val The value to check ++ * @param log The logger to use ++ * @param file The file name the function is called from ++ * @param fkt The function calling this function ++ * @param line The line number where the function is called ++ * ++ * @return \b true for success, \b false if invalid ++ * @since version 3.20.1 ++ */ ++#define rdpecam_valid_CamMediaFormat(val) \ ++ rdpecam_valid_CamMediaFormat_((val), WLog_Get(TAG), __FILE__, __func__, __LINE__) ++static inline bool rdpecam_valid_CamMediaFormat_(UINT8 val, wLog* log, const char* file, ++ const char* fkt, size_t line) ++{ ++ switch (val) ++ { ++ case CAM_MEDIA_FORMAT_INVALID: ++ case CAM_MEDIA_FORMAT_H264: ++ case CAM_MEDIA_FORMAT_MJPG: ++ case CAM_MEDIA_FORMAT_YUY2: ++ case CAM_MEDIA_FORMAT_NV12: ++ case CAM_MEDIA_FORMAT_I420: ++ case CAM_MEDIA_FORMAT_RGB24: ++ case CAM_MEDIA_FORMAT_RGB32: ++ return true; ++ default: ++ rdpecam_PrintWarning(log, file, fkt, line, "Invalid CAM_MEDIA_FORMAT %" PRIu8, val); ++ return false; ++ } ++} ++ ++/** @brief check input data is a valid \ref CAM_MEDIA_TYPE_DESCRIPTION_FLAGS value ++ * ++ * @param val The value to check ++ * @param log The logger to use ++ * @param file The file name the function is called from ++ * @param fkt The function calling this function ++ * @param line The line number where the function is called ++ * ++ * @return \b true for success, \b false if invalid ++ * @since version 3.20.1 ++ */ ++#define rdpecam_valid_MediaTypeDescriptionFlags(val) \ ++ rdpecam_valid_MediaTypeDescriptionFlags_((val), WLog_Get(TAG), __FILE__, __func__, __LINE__) ++static inline bool rdpecam_valid_MediaTypeDescriptionFlags_(UINT8 val, wLog* log, const char* file, ++ const char* fkt, size_t line) ++{ ++ switch (val) ++ { ++ case CAM_MEDIA_TYPE_DESCRIPTION_FLAG_DecodingRequired: ++ case CAM_MEDIA_TYPE_DESCRIPTION_FLAG_BottomUpImage: ++ return true; ++ default: ++ rdpecam_PrintWarning(log, file, fkt, line, ++ "Invalid CAM_MEDIA_TYPE_DESCRIPTION_FLAGS %" PRIu8, val); ++ return false; ++ } ++} ++ ++/** @brief check input data is a valid \ref CAM_PROPERTY_MODE value ++ * ++ * @param val The value to check ++ * @param log The logger to use ++ * @param file The file name the function is called from ++ * @param fkt The function calling this function ++ * @param line The line number where the function is called ++ * ++ * @return \b true for success, \b false if invalid ++ * @since version 3.20.1 ++ */ ++#define rdpecam_valid_CamPropertyMode(val) \ ++ rdpecam_valid_CamPropertyMode_((val), WLog_Get(TAG), __FILE__, __func__, __LINE__) ++static inline bool rdpecam_valid_CamPropertyMode_(UINT8 val, wLog* log, const char* file, ++ const char* fkt, size_t line) ++{ ++ switch (val) ++ { ++ case CAM_PROPERTY_MODE_Manual: ++ case CAM_PROPERTY_MODE_Auto: ++ return true; ++ default: ++ rdpecam_PrintWarning(log, file, fkt, line, "Invalid CAM_PROPERTY_MODE %" PRIu8, val); ++ return false; ++ } ++} ++ ++/** @brief check input data is a valid \ref CAM_PROPERTY_SET value ++ * ++ * @param val The value to check ++ * @param log The logger to use ++ * @param file The file name the function is called from ++ * @param fkt The function calling this function ++ * @param line The line number where the function is called ++ * ++ * @return \b true for success, \b false if invalid ++ * @since version 3.20.1 ++ */ ++#define rdpecam_valid_CamPropertySet(val) \ ++ rdpecam_valid_CamPropertySet_((val), WLog_Get(TAG), __FILE__, __func__, __LINE__) ++static inline bool rdpecam_valid_CamPropertySet_(UINT8 val, wLog* log, const char* file, ++ const char* fkt, size_t line) ++{ ++ switch (val) ++ { ++ case CAM_PROPERTY_SET_CameraControl: ++ case CAM_PROPERTY_SET_VideoProcAmp: ++ return true; ++ default: ++ rdpecam_PrintWarning(log, file, fkt, line, "Invalid CAM_PROPERTY_SET %" PRIu8, val); ++ return false; ++ } ++} ++ ++/** @brief check input data is a valid \ref CAM_PROPERTY_CAPABILITIES value ++ * ++ * @param val The value to check ++ * @param log The logger to use ++ * @param file The file name the function is called from ++ * @param fkt The function calling this function ++ * @param line The line number where the function is called ++ * ++ * @return \b true for success, \b false if invalid ++ * @since version 3.20.1 ++ */ ++#define rdpecam_valid_CamPropertyCapabilities(val) \ ++ rdpecam_valid_CamPropertyCapabilities_((val), WLog_Get(TAG), __FILE__, __func__, __LINE__) ++static inline bool rdpecam_valid_CamPropertyCapabilities_(UINT8 val, wLog* log, const char* file, ++ const char* fkt, size_t line) ++{ ++ switch (val) ++ { ++ case CAM_PROPERTY_CAPABILITY_Manual: ++ case CAM_PROPERTY_CAPABILITY_Auto: ++ return true; ++ default: ++ rdpecam_PrintWarning(log, file, fkt, line, "Invalid CAM_PROPERTY_CAPABILITIES %" PRIu8, ++ val); ++ return false; ++ } ++} ++ ++#endif +-- +2.47.3 + diff -Nru freerdp3-3.15.0+dfsg/debian/patches/channels-rdpecam-ensure-all-streams-are-stopped-CVE-2026-24678.patch freerdp3-3.15.0+dfsg/debian/patches/channels-rdpecam-ensure-all-streams-are-stopped-CVE-2026-24678.patch --- freerdp3-3.15.0+dfsg/debian/patches/channels-rdpecam-ensure-all-streams-are-stopped-CVE-2026-24678.patch 1970-01-01 00:00:00.000000000 +0000 +++ freerdp3-3.15.0+dfsg/debian/patches/channels-rdpecam-ensure-all-streams-are-stopped-CVE-2026-24678.patch 2026-02-09 18:48:59.000000000 +0000 @@ -0,0 +1,29 @@ +From: akallabeth +Date: Mon, 26 Jan 2026 10:54:33 +0100 +Subject: [channels,rdpecam] ensure all streams are stopped +Origin: upstream, https://github.com/FreeRDP/FreeRDP/commit/f3ab1a16139036179d9852745fdade18fec11600 +Forwarded: not-needed +Bug: https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-6gvg-29wx-6v7h +Bug: https://security-tracker.debian.org/tracker/CVE-2026-24678 + +When closing the channel ensure there are no more streams running. +--- + channels/rdpecam/client/camera_device_main.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/channels/rdpecam/client/camera_device_main.c b/channels/rdpecam/client/camera_device_main.c +--- a/channels/rdpecam/client/camera_device_main.c ++++ b/channels/rdpecam/client/camera_device_main.c +@@ -789,6 +789,9 @@ static UINT ecam_dev_on_close(IWTSVirtualChannelCallback* pChannelCallback) + + WLog_DBG(TAG, "entered"); + ++ for (size_t i = 0; i < ECAM_DEVICE_MAX_STREAMS; i++) ++ ecam_dev_stop_stream(dev, i); ++ + /* make sure this channel is not used for sample responses */ + for (size_t i = 0; i < ECAM_DEVICE_MAX_STREAMS; i++) + if (dev->streams[i].hSampleReqChannel == hchannel) +-- +2.47.3 + diff -Nru freerdp3-3.15.0+dfsg/debian/patches/channels-rdpecam-ensure-sws-context-size-matches-CVE-2026-24677.patch freerdp3-3.15.0+dfsg/debian/patches/channels-rdpecam-ensure-sws-context-size-matches-CVE-2026-24677.patch --- freerdp3-3.15.0+dfsg/debian/patches/channels-rdpecam-ensure-sws-context-size-matches-CVE-2026-24677.patch 1970-01-01 00:00:00.000000000 +0000 +++ freerdp3-3.15.0+dfsg/debian/patches/channels-rdpecam-ensure-sws-context-size-matches-CVE-2026-24677.patch 2026-02-09 18:48:59.000000000 +0000 @@ -0,0 +1,162 @@ +From: akallabeth +Date: Mon, 26 Jan 2026 10:38:03 +0100 +Subject: [channels,rdpecam] ensure sws context size matches +Origin: upstream, https://github.com/FreeRDP/FreeRDP/commit/d2d4f449312ddafd4a4c6c8a4f856c7f0d44a3b5 +Forwarded: not-needed +Bug: https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-xw37-j744-f8v7 +Bug: https://security-tracker.debian.org/tracker/CVE-2026-24677 + +--- + channels/rdpecam/client/camera.h | 2 + + channels/rdpecam/client/camera_device_main.c | 7 ++- + channels/rdpecam/client/encoding.c | 48 ++++++++++++++++---- + channels/remdesk/server/remdesk_main.c | 3 +- + 4 files changed, 47 insertions(+), 13 deletions(-) + +diff --git a/channels/rdpecam/client/camera.h b/channels/rdpecam/client/camera.h +--- a/channels/rdpecam/client/camera.h ++++ b/channels/rdpecam/client/camera.h +@@ -121,6 +121,8 @@ typedef struct + #endif + + /* sws_scale */ ++ uint32_t swsWidth; ++ uint32_t swsHeight; + struct SwsContext* sws; + + } CameraDeviceStream; +diff --git a/channels/rdpecam/client/camera_device_main.c b/channels/rdpecam/client/camera_device_main.c +--- a/channels/rdpecam/client/camera_device_main.c ++++ b/channels/rdpecam/client/camera_device_main.c +@@ -121,7 +121,7 @@ static BOOL mediaSupportDrops(CAM_MEDIA_FORMAT format) + } + } + +-static UINT ecam_dev_send_pending(CameraDevice* dev, int streamIndex, CameraDeviceStream* stream) ++static UINT ecam_dev_send_pending(CameraDevice* dev, size_t streamIndex, CameraDeviceStream* stream) + { + WINPR_ASSERT(dev); + WINPR_ASSERT(stream); +@@ -160,8 +160,7 @@ static UINT ecam_dev_send_pending(CameraDevice* dev, int streamIndex, CameraDevi + stream->samplesRequested--; + stream->haveSample = FALSE; + +- return ecam_dev_send_sample_response(dev, WINPR_ASSERTING_INT_CAST(size_t, streamIndex), +- encodedSample, encodedSize); ++ return ecam_dev_send_sample_response(dev, streamIndex, encodedSample, encodedSize); + } + + static UINT ecam_dev_sample_captured_callback(CameraDevice* dev, int streamIndex, +@@ -229,7 +228,7 @@ static UINT ecam_dev_sample_captured_callback(CameraDevice* dev, int streamIndex + Stream_SealLength(stream->pendingSample); + stream->haveSample = TRUE; + +- ret = ecam_dev_send_pending(dev, streamIndex, stream); ++ ret = ecam_dev_send_pending(dev, WINPR_ASSERTING_INT_CAST(size_t, streamIndex), stream); + + out: + LeaveCriticalSection(&stream->lock); +diff --git a/channels/rdpecam/client/encoding.c b/channels/rdpecam/client/encoding.c +--- a/channels/rdpecam/client/encoding.c ++++ b/channels/rdpecam/client/encoding.c +@@ -220,6 +220,30 @@ static enum AVPixelFormat ecamToAVPixFormat(CAM_MEDIA_FORMAT ecamFormat) + } + } + ++static void ecam_sws_free(CameraDeviceStream* stream) ++{ ++ if (stream->sws) ++ { ++ sws_freeContext(stream->sws); ++ stream->sws = NULL; ++ } ++} ++ ++static BOOL ecam_sws_valid(const CameraDeviceStream* stream) ++{ ++ if (!stream->sws) ++ return FALSE; ++ if (stream->swsWidth != stream->currMediaType.Width) ++ return FALSE; ++ if (stream->swsHeight != stream->currMediaType.Height) ++ return FALSE; ++ if (stream->currMediaType.Width > INT32_MAX) ++ return FALSE; ++ if (stream->currMediaType.Height > INT32_MAX) ++ return FALSE; ++ return TRUE; ++} ++ + /** + * Function description + * initialize libswscale +@@ -230,9 +254,16 @@ static BOOL ecam_init_sws_context(CameraDeviceStream* stream, enum AVPixelFormat + { + WINPR_ASSERT(stream); + +- if (stream->sws) ++ if (stream->currMediaType.Width > INT32_MAX) ++ return FALSE; ++ if (stream->currMediaType.Height > INT32_MAX) ++ return FALSE; ++ ++ if (ecam_sws_valid(stream)) + return TRUE; + ++ ecam_sws_free(stream); ++ + /* replacing deprecated JPEG formats, still produced by decoder */ + switch (pixFormat) + { +@@ -260,8 +291,10 @@ static BOOL ecam_init_sws_context(CameraDeviceStream* stream, enum AVPixelFormat + break; + } + +- const int width = (int)stream->currMediaType.Width; +- const int height = (int)stream->currMediaType.Height; ++ stream->swsWidth = stream->currMediaType.Width; ++ stream->swsHeight = stream->currMediaType.Height; ++ const int width = WINPR_ASSERTING_INT_CAST(int, stream->currMediaType.Width); ++ const int height = WINPR_ASSERTING_INT_CAST(int, stream->currMediaType.Height); + + const enum AVPixelFormat outPixFormat = + h264_context_get_option(stream->h264, H264_CONTEXT_OPTION_HW_ACCEL) ? AV_PIX_FMT_NV12 +@@ -295,6 +328,9 @@ static BOOL ecam_encoder_compress_h264(CameraDeviceStream* stream, const BYTE* s + CAM_MEDIA_FORMAT inputFormat = streamInputFormat(stream); + enum AVPixelFormat pixFormat = AV_PIX_FMT_NONE; + ++ if (!ecam_sws_valid(stream)) ++ return FALSE; ++ + #if defined(WITH_INPUT_FORMAT_H264) + if (inputFormat == CAM_MEDIA_FORMAT_MJPG_H264) + { +@@ -385,11 +421,7 @@ static void ecam_encoder_context_free_h264(CameraDeviceStream* stream) + { + WINPR_ASSERT(stream); + +- if (stream->sws) +- { +- sws_freeContext(stream->sws); +- stream->sws = NULL; +- } ++ ecam_sws_free(stream); + + #if defined(WITH_INPUT_FORMAT_MJPG) + if (stream->avOutFrame) +diff --git a/channels/remdesk/server/remdesk_main.c b/channels/remdesk/server/remdesk_main.c +--- a/channels/remdesk/server/remdesk_main.c ++++ b/channels/remdesk/server/remdesk_main.c +@@ -526,7 +526,8 @@ static DWORD WINAPI remdesk_server_thread(LPVOID arg) + Stream_SealLength(s); + Stream_SetPosition(s, 0); + +- if ((error = remdesk_server_receive_pdu(context, s))) ++ error = remdesk_server_receive_pdu(context, s); ++ if (error) + { + WLog_ERR(TAG, "remdesk_server_receive_pdu failed with error %" PRIu32 "!", + error); +-- +2.47.3 + diff -Nru freerdp3-3.15.0+dfsg/debian/patches/channels-rdpecam-fix-PROPERTY_DESCRIPTION-parsing.patch freerdp3-3.15.0+dfsg/debian/patches/channels-rdpecam-fix-PROPERTY_DESCRIPTION-parsing.patch --- freerdp3-3.15.0+dfsg/debian/patches/channels-rdpecam-fix-PROPERTY_DESCRIPTION-parsing.patch 1970-01-01 00:00:00.000000000 +0000 +++ freerdp3-3.15.0+dfsg/debian/patches/channels-rdpecam-fix-PROPERTY_DESCRIPTION-parsing.patch 2026-02-25 20:31:28.000000000 +0000 @@ -0,0 +1,167 @@ +From: akallabeth +Date: Wed, 28 Jan 2026 08:33:50 +0100 +Subject: [channels,rdpecam] fix PROPERTY_DESCRIPTION parsing +Origin: upstream, https://github.com/FreeRDP/FreeRDP/commit/067524438a284d06c78b124c5858d8773279f70f +Forwarded: not-needed +Comment: correctness fixup after CVE-2026-24677 fix + +* The Capabilities field is a mask, so allow combination of all valid + values. +* Adjust header to hold a mask +* Use enum to define constants for parsed values +--- + channels/rdpecam/server/camera_device_main.c | 33 +++++++----------- + channels/rdpecam/server/rdpecam-utils.h | 15 ++++---- + include/freerdp/channels/rdpecam.h | 36 ++++++++++++-------- + 3 files changed, 40 insertions(+), 44 deletions(-) + +diff --git a/channels/rdpecam/server/camera_device_main.c b/channels/rdpecam/server/camera_device_main.c +index b5abe9d1d..0f799e7f6 100644 +--- a/channels/rdpecam/server/camera_device_main.c ++++ b/channels/rdpecam/server/camera_device_main.c +@@ -384,7 +384,7 @@ static UINT device_server_recv_property_list_response(CameraDeviceServerContext* + const CAM_SHARED_MSG_HEADER* header) + { + CAM_PROPERTY_LIST_RESPONSE pdu = { 0 }; +- UINT error = CHANNEL_RC_OK; ++ UINT error = ERROR_INVALID_DATA; + + WINPR_ASSERT(context); + WINPR_ASSERT(header); +@@ -409,30 +409,23 @@ static UINT device_server_recv_property_list_response(CameraDeviceServerContext* + { + const UINT8 val = Stream_Get_UINT8(s); + if (!rdpecam_valid_CamPropertySet(val)) +- { +- free(pdu.Properties); +- return ERROR_INVALID_DATA; +- } ++ goto fail; + cur->PropertySet = (CAM_PROPERTY_SET)val; + } +- Stream_Read_UINT8(s, cur->PropertyId); +- { +- const UINT8 val = Stream_Get_UINT8(s); +- if (!rdpecam_valid_CamPropertyCapabilities(val)) +- { +- free(pdu.Properties); +- return ERROR_INVALID_DATA; +- } +- cur->Capabilities = (CAM_PROPERTY_CAPABILITIES)val; +- } +- Stream_Read_INT32(s, cur->MinValue); +- Stream_Read_INT32(s, cur->MaxValue); +- Stream_Read_INT32(s, cur->Step); +- Stream_Read_INT32(s, cur->DefaultValue); ++ cur->PropertyId = Stream_Get_UINT8(s); ++ cur->Capabilities = Stream_Get_UINT8(s); ++ if (!rdpecam_valid_CamPropertyCapabilities(cur->Capabilities)) ++ goto fail; ++ cur->MinValue = Stream_Get_INT32(s); ++ cur->MaxValue = Stream_Get_INT32(s); ++ cur->Step = Stream_Get_INT32(s); ++ cur->DefaultValue = Stream_Get_INT32(s); + } + } + +- IFCALLRET(context->PropertyListResponse, error, context, &pdu); ++ error = IFCALLRESULT(CHANNEL_RC_OK, context->PropertyListResponse, context, &pdu); ++ ++fail: + if (error) + WLog_ERR(TAG, "context->PropertyListResponse failed with error %" PRIu32 "", error); + +diff --git a/channels/rdpecam/server/rdpecam-utils.h b/channels/rdpecam/server/rdpecam-utils.h +index 38186a24d..b1a81a8bf 100644 +--- a/channels/rdpecam/server/rdpecam-utils.h ++++ b/channels/rdpecam/server/rdpecam-utils.h +@@ -307,19 +307,16 @@ static inline bool rdpecam_valid_CamPropertySet_(UINT8 val, wLog* log, const cha + */ + #define rdpecam_valid_CamPropertyCapabilities(val) \ + rdpecam_valid_CamPropertyCapabilities_((val), WLog_Get(TAG), __FILE__, __func__, __LINE__) +-static inline bool rdpecam_valid_CamPropertyCapabilities_(UINT8 val, wLog* log, const char* file, ++static inline bool rdpecam_valid_CamPropertyCapabilities_(UINT32 val, wLog* log, const char* file, + const char* fkt, size_t line) + { +- switch (val) ++ if ((val & ~(CAM_PROPERTY_CAPABILITY_Manual | CAM_PROPERTY_CAPABILITY_Auto)) != 0) + { +- case CAM_PROPERTY_CAPABILITY_Manual: +- case CAM_PROPERTY_CAPABILITY_Auto: +- return true; +- default: +- rdpecam_PrintWarning(log, file, fkt, line, "Invalid CAM_PROPERTY_CAPABILITIES %" PRIu8, +- val); +- return false; ++ rdpecam_PrintWarning(log, file, fkt, line, "Invalid CAM_PROPERTY_CAPABILITIES %" PRIu8, ++ val); ++ return false; + } ++ return true; + } + + #endif +diff --git a/include/freerdp/channels/rdpecam.h b/include/freerdp/channels/rdpecam.h +index e1ce73172..36075252e 100644 +--- a/include/freerdp/channels/rdpecam.h ++++ b/include/freerdp/channels/rdpecam.h +@@ -269,35 +269,41 @@ typedef struct + typedef enum + { + CAM_PROPERTY_SET_CameraControl = 0x01, +- CAM_PROPERTY_SET_VideoProcAmp = 0x02, ++ CAM_PROPERTY_SET_VideoProcAmp = 0x02 + } CAM_PROPERTY_SET; + + /* CameraControl properties */ +-#define CAM_PROPERTY_ID_CAMERA_CONTROL_Exposure 0x01 +-#define CAM_PROPERTY_ID_CAMERA_CONTROL_Focus 0x02 +-#define CAM_PROPERTY_ID_CAMERA_CONTROL_Pan 0x03 +-#define CAM_PROPERTY_ID_CAMERA_CONTROL_Roll 0x04 +-#define CAM_PROPERTY_ID_CAMERA_CONTROL_Tilt 0x05 +-#define CAM_PROPERTY_ID_CAMERA_CONTROL_Zoom 0x06 ++typedef enum ++{ ++ CAM_PROPERTY_ID_CAMERA_CONTROL_Exposure = 0x01, ++ CAM_PROPERTY_ID_CAMERA_CONTROL_Focus = 0x02, ++ CAM_PROPERTY_ID_CAMERA_CONTROL_Pan = 0x03, ++ CAM_PROPERTY_ID_CAMERA_CONTROL_Roll = 0x04, ++ CAM_PROPERTY_ID_CAMERA_CONTROL_Tilt = 0x05, ++ CAM_PROPERTY_ID_CAMERA_CONTROL_Zoom = 0x06 ++} CAM_PROPERTY_ID; + + /* VideoProcAmp properties */ +-#define CAM_PROPERTY_ID_VIDEO_PROC_AMP_BacklightCompensation 0x01 +-#define CAM_PROPERTY_ID_VIDEO_PROC_AMP_Brightness 0x02 +-#define CAM_PROPERTY_ID_VIDEO_PROC_AMP_Contrast 0x03 +-#define CAM_PROPERTY_ID_VIDEO_PROC_AMP_Hue 0x04 +-#define CAM_PROPERTY_ID_VIDEO_PROC_AMP_WhiteBalance 0x05 ++typedef enum ++{ ++ CAM_PROPERTY_ID_VIDEO_PROC_AMP_BacklightCompensation = 0x01, ++ CAM_PROPERTY_ID_VIDEO_PROC_AMP_Brightness = 0x02, ++ CAM_PROPERTY_ID_VIDEO_PROC_AMP_Contrast = 0x03, ++ CAM_PROPERTY_ID_VIDEO_PROC_AMP_Hue = 0x04, ++ CAM_PROPERTY_ID_VIDEO_PROC_AMP_WhiteBalance = 0x05 ++} CAM_PROPERTY_ID_VIDEO; + + typedef enum + { +- CAM_PROPERTY_CAPABILITY_Manual = 0x01, +- CAM_PROPERTY_CAPABILITY_Auto = 0x02, ++ CAM_PROPERTY_CAPABILITY_Manual = 0x01u, ++ CAM_PROPERTY_CAPABILITY_Auto = 0x02u + } CAM_PROPERTY_CAPABILITIES; + + typedef struct + { + CAM_PROPERTY_SET PropertySet; + BYTE PropertyId; +- CAM_PROPERTY_CAPABILITIES Capabilities; ++ UINT32 Capabilities; + INT32 MinValue; + INT32 MaxValue; + INT32 Step; +-- +2.47.3 + diff -Nru freerdp3-3.15.0+dfsg/debian/patches/channels-rdpecam-improve-log-messages.patch freerdp3-3.15.0+dfsg/debian/patches/channels-rdpecam-improve-log-messages.patch --- freerdp3-3.15.0+dfsg/debian/patches/channels-rdpecam-improve-log-messages.patch 1970-01-01 00:00:00.000000000 +0000 +++ freerdp3-3.15.0+dfsg/debian/patches/channels-rdpecam-improve-log-messages.patch 2026-02-09 18:48:59.000000000 +0000 @@ -0,0 +1,68 @@ +From: akallabeth +Date: Mon, 1 Dec 2025 09:12:11 +0100 +Subject: [channels,rdpecam] improve log messages +Origin: upstream, https://github.com/FreeRDP/FreeRDP/commit/d80d9bf2ce5f117c69ff760f377c1bdf4060b082 +Forwarded: not-needed +Comment: preparation for CVE-2026-24677 fix + +diff --git a/channels/rdpecam/client/camera_device_main.c b/channels/rdpecam/client/camera_device_main.c +--- a/channels/rdpecam/client/camera_device_main.c ++++ b/channels/rdpecam/client/camera_device_main.c +@@ -442,8 +442,8 @@ static UINT ecam_dev_process_media_type_list_request(CameraDevice* dev, + { + UINT error = CHANNEL_RC_OK; + BYTE streamIndex = 0; +- CAM_MEDIA_TYPE_DESCRIPTION* mediaTypes = NULL; +- size_t nMediaTypes = ECAM_MAX_MEDIA_TYPE_DESCRIPTORS; ++ CAM_MEDIA_TYPE_DESCRIPTION mediaTypes[ECAM_MAX_MEDIA_TYPE_DESCRIPTORS] = { 0 }; ++ size_t nMediaTypes = ARRAYSIZE(mediaTypes); + + WINPR_ASSERT(dev); + +@@ -460,24 +460,17 @@ static UINT ecam_dev_process_media_type_list_request(CameraDevice* dev, + } + CameraDeviceStream* stream = &dev->streams[streamIndex]; + +- mediaTypes = +- (CAM_MEDIA_TYPE_DESCRIPTION*)calloc(nMediaTypes, sizeof(CAM_MEDIA_TYPE_DESCRIPTION)); +- if (!mediaTypes) +- { +- WLog_ERR(TAG, "calloc failed"); +- ecam_channel_send_error_response(dev->ecam, hchannel, CAM_ERROR_CODE_OutOfMemory); +- return CHANNEL_RC_NO_MEMORY; +- } +- + INT16 formatIndex = + dev->ihal->GetMediaTypeDescriptions(dev->ihal, dev->deviceId, streamIndex, supportedFormats, + nSupportedFormats, mediaTypes, &nMediaTypes); +- if (formatIndex == -1 || nMediaTypes == 0) ++ if ((formatIndex < 0) || (nMediaTypes == 0)) + { +- WLog_ERR(TAG, "Camera doesn't support any compatible video formats"); ++ WLog_ERR(TAG, ++ "Camera doesn't support any compatible video formats [streamIndex=%" PRIu32 ++ ", formatIndex=%" PRId16 ", nMediaTypes=%" PRIu32 "]", ++ streamIndex, formatIndex, nMediaTypes); + ecam_channel_send_error_response(dev->ecam, hchannel, CAM_ERROR_CODE_ItemNotFound); +- error = ERROR_DEVICE_FEATURE_NOT_SUPPORTED; +- goto error; ++ return ERROR_DEVICE_FEATURE_NOT_SUPPORTED; + } + + stream->formats = supportedFormats[formatIndex]; +@@ -495,11 +488,7 @@ static UINT ecam_dev_process_media_type_list_request(CameraDevice* dev, + stream->currMediaType = mediaTypes[0]; + } + +- error = ecam_dev_send_media_type_list_response(dev, hchannel, mediaTypes, nMediaTypes); +- +-error: +- free(mediaTypes); +- return error; ++ return ecam_dev_send_media_type_list_response(dev, hchannel, mediaTypes, nMediaTypes); + } + + /** +-- +2.47.3 + diff -Nru freerdp3-3.15.0+dfsg/debian/patches/channels-rdpgfx-check-available-stream-length-CVE-2026-25941.patch freerdp3-3.15.0+dfsg/debian/patches/channels-rdpgfx-check-available-stream-length-CVE-2026-25941.patch --- freerdp3-3.15.0+dfsg/debian/patches/channels-rdpgfx-check-available-stream-length-CVE-2026-25941.patch 1970-01-01 00:00:00.000000000 +0000 +++ freerdp3-3.15.0+dfsg/debian/patches/channels-rdpgfx-check-available-stream-length-CVE-2026-25941.patch 2026-02-25 20:34:19.000000000 +0000 @@ -0,0 +1,28 @@ +From: Armin Novak +Date: Mon, 9 Feb 2026 13:18:51 +0100 +Subject: [channels,rdpgfx] check available stream length +Origin: upstream, https://github.com/FreeRDP/FreeRDP/commit/2e3b77e28ac6a398897d28ba464dcc5dfab9c9e2 +Forwarded: not-needed +Bug: https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-3546-x645-5cf8 +Bug: https://security-tracker.debian.org/tracker/CVE-2026-25941 + +--- + channels/rdpgfx/client/rdpgfx_main.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/channels/rdpgfx/client/rdpgfx_main.c b/channels/rdpgfx/client/rdpgfx_main.c +--- a/channels/rdpgfx/client/rdpgfx_main.c ++++ b/channels/rdpgfx/client/rdpgfx_main.c +@@ -1306,7 +1306,8 @@ static UINT rdpgfx_recv_wire_to_surface_2_pdu(GENERIC_CHANNEL_CALLBACK* callback + Stream_Read_UINT8(s, pdu.pixelFormat); /* pixelFormat (1 byte) */ + Stream_Read_UINT32(s, pdu.bitmapDataLength); /* bitmapDataLength (4 bytes) */ + pdu.bitmapData = Stream_Pointer(s); +- Stream_Seek(s, pdu.bitmapDataLength); ++ if (!Stream_SafeSeek(s, pdu.bitmapDataLength)) ++ return ERROR_INVALID_DATA; + + DEBUG_RDPGFX(gfx->log, + "RecvWireToSurface2Pdu: surfaceId: %" PRIu16 " codecId: %s (0x%04" PRIX16 ") " +-- +2.47.3 + diff -Nru freerdp3-3.15.0+dfsg/debian/patches/channels-rdpsnd-terminate-thread-before-free-CVE-2026-24684.patch freerdp3-3.15.0+dfsg/debian/patches/channels-rdpsnd-terminate-thread-before-free-CVE-2026-24684.patch --- freerdp3-3.15.0+dfsg/debian/patches/channels-rdpsnd-terminate-thread-before-free-CVE-2026-24684.patch 1970-01-01 00:00:00.000000000 +0000 +++ freerdp3-3.15.0+dfsg/debian/patches/channels-rdpsnd-terminate-thread-before-free-CVE-2026-24684.patch 2026-02-09 18:48:59.000000000 +0000 @@ -0,0 +1,67 @@ +From: akallabeth +Date: Mon, 26 Jan 2026 10:48:14 +0100 +Subject: [channels,rdpsnd] terminate thread before free +Origin: upstream, https://github.com/FreeRDP/FreeRDP/commit/622bb7b4402491ca003f47472d0e478132673696 +Forwarded: not-needed +Bug: https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-vcgv-xgjp-h83q +Bug: https://security-tracker.debian.org/tracker/CVE-2026-24684 + +Ensure that the optional rdpsnd thread is terminated and the message +queue freed up before releasing the channel context memory +--- + channels/rdpsnd/client/rdpsnd_main.c | 28 +++++++++++++++++++--------- + 1 file changed, 19 insertions(+), 9 deletions(-) + +diff --git a/channels/rdpsnd/client/rdpsnd_main.c b/channels/rdpsnd/client/rdpsnd_main.c +--- a/channels/rdpsnd/client/rdpsnd_main.c ++++ b/channels/rdpsnd/client/rdpsnd_main.c +@@ -1278,11 +1278,29 @@ fail: + return CHANNEL_RC_NO_MEMORY; + } + ++static void rdpsnd_terminate_thread(rdpsndPlugin* rdpsnd) ++{ ++ WINPR_ASSERT(rdpsnd); ++ if (rdpsnd->queue) ++ MessageQueue_PostQuit(rdpsnd->queue, 0); ++ ++ if (rdpsnd->thread) ++ { ++ (void)WaitForSingleObject(rdpsnd->thread, INFINITE); ++ (void)CloseHandle(rdpsnd->thread); ++ } ++ ++ MessageQueue_Free(rdpsnd->queue); ++ rdpsnd->thread = NULL; ++ rdpsnd->queue = NULL; ++} ++ + static void cleanup_internals(rdpsndPlugin* rdpsnd) + { + if (!rdpsnd) + return; + ++ rdpsnd_terminate_thread(rdpsnd); + if (rdpsnd->pool) + StreamPool_Return(rdpsnd->pool, rdpsnd->data_in); + +@@ -1460,15 +1478,7 @@ void rdpsnd_virtual_channel_event_terminated(rdpsndPlugin* rdpsnd) + { + if (rdpsnd) + { +- if (rdpsnd->queue) +- MessageQueue_PostQuit(rdpsnd->queue, 0); +- +- if (rdpsnd->thread) +- { +- (void)WaitForSingleObject(rdpsnd->thread, INFINITE); +- (void)CloseHandle(rdpsnd->thread); +- } +- MessageQueue_Free(rdpsnd->queue); ++ rdpsnd_terminate_thread(rdpsnd); + + free_internals(rdpsnd); + audio_formats_free(rdpsnd->fixed_format, 1); +-- +2.47.3 + diff -Nru freerdp3-3.15.0+dfsg/debian/patches/channels-rpdecam-log-dropped-samples.patch freerdp3-3.15.0+dfsg/debian/patches/channels-rpdecam-log-dropped-samples.patch --- freerdp3-3.15.0+dfsg/debian/patches/channels-rpdecam-log-dropped-samples.patch 1970-01-01 00:00:00.000000000 +0000 +++ freerdp3-3.15.0+dfsg/debian/patches/channels-rpdecam-log-dropped-samples.patch 2026-02-09 18:48:59.000000000 +0000 @@ -0,0 +1,65 @@ +From: akallabeth +Date: Fri, 5 Dec 2025 08:19:57 +0100 +Subject: [channels,rpdecam] log dropped samples +Origin: upstream, https://github.com/FreeRDP/FreeRDP/commit/c118d3df18dd6884ef110ffffafc5494f82cd438 +Forwarded: not-needed +Comment: preparation for CVE-2026-24677 fix + +--- + channels/rdpecam/client/camera_device_main.c | 24 ++++++++++---------- + 1 file changed, 12 insertions(+), 12 deletions(-) + +diff --git a/channels/rdpecam/client/camera_device_main.c b/channels/rdpecam/client/camera_device_main.c +--- a/channels/rdpecam/client/camera_device_main.c ++++ b/channels/rdpecam/client/camera_device_main.c +@@ -123,13 +123,20 @@ static BOOL mediaSupportDrops(CAM_MEDIA_FORMAT format) + + static UINT ecam_dev_send_pending(CameraDevice* dev, int streamIndex, CameraDeviceStream* stream) + { +- BYTE* encodedSample = NULL; +- size_t encodedSize = 0; ++ WINPR_ASSERT(dev); ++ WINPR_ASSERT(stream); ++ ++ if (stream->samplesRequested <= 0) ++ { ++ WLog_DBG(TAG, "Frame drop: No sample requested"); ++ return CHANNEL_RC_OK; ++ } + ++ BYTE* encodedSample = Stream_Buffer(stream->pendingSample); ++ size_t encodedSize = Stream_Length(stream->pendingSample); + if (streamInputFormat(stream) != streamOutputFormat(stream)) + { +- if (!ecam_encoder_compress(stream, Stream_Buffer(stream->pendingSample), +- Stream_Length(stream->pendingSample), &encodedSample, ++ if (!ecam_encoder_compress(stream, encodedSample, encodedSize, &encodedSample, + &encodedSize)) + { + WLog_DBG(TAG, "Frame drop or error in ecam_encoder_compress"); +@@ -139,11 +146,6 @@ static UINT ecam_dev_send_pending(CameraDevice* dev, int streamIndex, CameraDevi + if (!stream->streaming) + return CHANNEL_RC_OK; + } +- else /* passthrough */ +- { +- encodedSample = Stream_Buffer(stream->pendingSample); +- encodedSize = Stream_Length(stream->pendingSample); +- } + + stream->samplesRequested--; + stream->haveSample = FALSE; +@@ -213,9 +215,7 @@ static UINT ecam_dev_sample_captured_callback(CameraDevice* dev, int streamIndex + Stream_SealLength(stream->pendingSample); + stream->haveSample = TRUE; + +- ret = CHANNEL_RC_OK; +- if (stream->samplesRequested) +- ret = ecam_dev_send_pending(dev, streamIndex, stream); ++ ret = ecam_dev_send_pending(dev, streamIndex, stream); + + out: + LeaveCriticalSection(&stream->lock); +-- +2.47.3 + diff -Nru freerdp3-3.15.0+dfsg/debian/patches/channels-serial-explicitly-lock-serial-IrpThreads-CVE-2026-22856.patch freerdp3-3.15.0+dfsg/debian/patches/channels-serial-explicitly-lock-serial-IrpThreads-CVE-2026-22856.patch --- freerdp3-3.15.0+dfsg/debian/patches/channels-serial-explicitly-lock-serial-IrpThreads-CVE-2026-22856.patch 1970-01-01 00:00:00.000000000 +0000 +++ freerdp3-3.15.0+dfsg/debian/patches/channels-serial-explicitly-lock-serial-IrpThreads-CVE-2026-22856.patch 2026-02-09 18:48:59.000000000 +0000 @@ -0,0 +1,41 @@ +From: akallabeth +Date: Tue, 13 Jan 2026 09:39:33 +0100 +Subject: [channels,serial] explicitly lock serial->IrpThreads +Origin: upstream, https://github.com/FreeRDP/FreeRDP/commit/675c20f08f32ca5ec06297108bdf30147d6e2cd9 +Forwarded: not-needed +Bug: https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-w842-c386-fxhv +Bug: https://security-tracker.debian.org/tracker/CVE-2026-22856 + +--- + channels/serial/client/serial_main.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/channels/serial/client/serial_main.c b/channels/serial/client/serial_main.c +index 212fee99b..279869a9f 100644 +--- a/channels/serial/client/serial_main.c ++++ b/channels/serial/client/serial_main.c +@@ -622,7 +622,10 @@ static void create_irp_thread(SERIAL_DEVICE* serial, IRP* irp) + * observed with FreeRDP). + */ + key = irp->CompletionId + 1ull; ++ ++ ListDictionary_Lock(serial->IrpThreads); + previousIrpThread = ListDictionary_GetItemValue(serial->IrpThreads, (void*)key); ++ ListDictionary_Unlock(serial->IrpThreads); + + if (previousIrpThread) + { +@@ -735,7 +738,10 @@ static DWORD WINAPI serial_thread_func(LPVOID arg) + create_irp_thread(serial, irp); + } + ++ ListDictionary_Lock(serial->IrpThreads); + ListDictionary_Clear(serial->IrpThreads); ++ ListDictionary_Unlock(serial->IrpThreads); ++ + if (error && serial->rdpcontext) + setChannelError(serial->rdpcontext, error, "serial_thread_func reported an error"); + +-- +2.47.3 + diff -Nru freerdp3-3.15.0+dfsg/debian/patches/channels-serial-fix-use-after-free-CVE-2026-22857.patch freerdp3-3.15.0+dfsg/debian/patches/channels-serial-fix-use-after-free-CVE-2026-22857.patch --- freerdp3-3.15.0+dfsg/debian/patches/channels-serial-fix-use-after-free-CVE-2026-22857.patch 1970-01-01 00:00:00.000000000 +0000 +++ freerdp3-3.15.0+dfsg/debian/patches/channels-serial-fix-use-after-free-CVE-2026-22857.patch 2026-02-09 18:48:59.000000000 +0000 @@ -0,0 +1,50 @@ +From: akallabeth +Date: Sun, 11 Jan 2026 09:12:37 +0100 +Subject: [channels,serial] fix use after free +Origin: upstream, https://github.com/FreeRDP/FreeRDP/commit/e99e33aea8c5e480e224f4a167947dfacf4584a2 +Forwarded: not-needed +Bug: https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-4gxq-jhq6-4cr8 +Bug: https://security-tracker.debian.org/tracker/CVE-2026-22857 + +--- + channels/serial/client/serial_main.c | 8 +++----- + 1 file changed, 3 insertions(+), 5 deletions(-) + +diff --git a/channels/serial/client/serial_main.c b/channels/serial/client/serial_main.c +index da82ae025..212fee99b 100644 +--- a/channels/serial/client/serial_main.c ++++ b/channels/serial/client/serial_main.c +@@ -514,17 +514,18 @@ static UINT serial_process_irp(SERIAL_DEVICE* serial, IRP* irp) + static DWORD WINAPI irp_thread_func(LPVOID arg) + { + IRP_THREAD_DATA* data = (IRP_THREAD_DATA*)arg; +- UINT error = 0; + + WINPR_ASSERT(data); + WINPR_ASSERT(data->serial); + WINPR_ASSERT(data->irp); + + /* blocks until the end of the request */ +- if ((error = serial_process_irp(data->serial, data->irp))) ++ UINT error = serial_process_irp(data->serial, data->irp); ++ if (error) + { + WLog_Print(data->serial->log, WLOG_ERROR, + "serial_process_irp failed with error %" PRIu32 "", error); ++ data->irp->Discard(data->irp); + goto error_out; + } + +@@ -537,9 +538,6 @@ error_out: + if (error && data->serial->rdpcontext) + setChannelError(data->serial->rdpcontext, error, "irp_thread_func reported an error"); + +- if (error) +- data->irp->Discard(data->irp); +- + /* NB: At this point, the server might already being reusing + * the CompletionId whereas the thread is not yet + * terminated */ +-- +2.47.3 + diff -Nru freerdp3-3.15.0+dfsg/debian/patches/channels-urbdrc-cancel-all-usb-transfers-on-channel--CVE-2026-24681.patch freerdp3-3.15.0+dfsg/debian/patches/channels-urbdrc-cancel-all-usb-transfers-on-channel--CVE-2026-24681.patch --- freerdp3-3.15.0+dfsg/debian/patches/channels-urbdrc-cancel-all-usb-transfers-on-channel--CVE-2026-24681.patch 1970-01-01 00:00:00.000000000 +0000 +++ freerdp3-3.15.0+dfsg/debian/patches/channels-urbdrc-cancel-all-usb-transfers-on-channel--CVE-2026-24681.patch 2026-02-09 18:48:59.000000000 +0000 @@ -0,0 +1,26 @@ +From: akallabeth +Date: Mon, 26 Jan 2026 11:07:25 +0100 +Subject: [channels,urbdrc] cancel all usb transfers on channel close +Origin: upstream, https://github.com/FreeRDP/FreeRDP/commit/414f701464929c217f2509bcbd6d2c1f00f7ed73 +Forwarded: not-needed +Bug: https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-ccvv-hg2w-6x9j +Bug: https://security-tracker.debian.org/tracker/CVE-2026-24681 + +--- + channels/urbdrc/client/libusb/libusb_udevice.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/channels/urbdrc/client/libusb/libusb_udevice.c b/channels/urbdrc/client/libusb/libusb_udevice.c +--- a/channels/urbdrc/client/libusb/libusb_udevice.c ++++ b/channels/urbdrc/client/libusb/libusb_udevice.c +@@ -1165,6 +1165,7 @@ static void libusb_udev_mark_channel_closed(IUDEVICE* idev) + const uint8_t devNr = idev->get_dev_number(idev); + + pdev->status |= URBDRC_DEVICE_CHANNEL_CLOSED; ++ pdev->iface.cancel_all_transfer_request(&pdev->iface); + urbdrc->udevman->unregister_udevice(urbdrc->udevman, busNr, devNr); + } + } +-- +2.47.3 + diff -Nru freerdp3-3.15.0+dfsg/debian/patches/channels-urbdrc-check-interface-indices-before-use-CVE-2026-22859.patch freerdp3-3.15.0+dfsg/debian/patches/channels-urbdrc-check-interface-indices-before-use-CVE-2026-22859.patch --- freerdp3-3.15.0+dfsg/debian/patches/channels-urbdrc-check-interface-indices-before-use-CVE-2026-22859.patch 1970-01-01 00:00:00.000000000 +0000 +++ freerdp3-3.15.0+dfsg/debian/patches/channels-urbdrc-check-interface-indices-before-use-CVE-2026-22859.patch 2026-02-09 18:48:59.000000000 +0000 @@ -0,0 +1,200 @@ +From: akallabeth +Date: Sat, 10 Jan 2026 08:43:40 +0100 +Subject: [channels,urbdrc] check interface indices before use +Origin: upstream, https://github.com/FreeRDP/FreeRDP/commit/7b7e6de8fe427a2f01d331056774aec69710590b +Forwarded: not-needed +Bug: https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-56f5-76qv-2r36 +Bug: https://security-tracker.debian.org/tracker/CVE-2026-22859 + +--- + channels/urbdrc/client/data_transfer.c | 6 +- + .../urbdrc/client/libusb/libusb_udevice.c | 78 ++++++++++++------- + channels/urbdrc/common/msusb.c | 6 +- + 3 files changed, 54 insertions(+), 36 deletions(-) + +diff --git a/channels/urbdrc/client/data_transfer.c b/channels/urbdrc/client/data_transfer.c +index 768c5446b..1cba9c126 100644 +--- a/channels/urbdrc/client/data_transfer.c ++++ b/channels/urbdrc/client/data_transfer.c +@@ -454,14 +454,12 @@ static void func_select_all_interface_for_msconfig(IUDEVICE* pdev, + MSUSB_CONFIG_DESCRIPTOR* MsConfig) + { + MSUSB_INTERFACE_DESCRIPTOR** MsInterfaces = MsConfig->MsInterfaces; +- BYTE InterfaceNumber = 0; +- BYTE AlternateSetting = 0; + UINT32 NumInterfaces = MsConfig->NumInterfaces; + + for (UINT32 inum = 0; inum < NumInterfaces; inum++) + { +- InterfaceNumber = MsInterfaces[inum]->InterfaceNumber; +- AlternateSetting = MsInterfaces[inum]->AlternateSetting; ++ const BYTE InterfaceNumber = MsInterfaces[inum]->InterfaceNumber; ++ const BYTE AlternateSetting = MsInterfaces[inum]->AlternateSetting; + pdev->select_interface(pdev, InterfaceNumber, AlternateSetting); + } + } +diff --git a/channels/urbdrc/client/libusb/libusb_udevice.c b/channels/urbdrc/client/libusb/libusb_udevice.c +index 8cdfe9ee8..21878f008 100644 +--- a/channels/urbdrc/client/libusb/libusb_udevice.c ++++ b/channels/urbdrc/client/libusb/libusb_udevice.c +@@ -582,25 +582,13 @@ static MSUSB_CONFIG_DESCRIPTOR* + libusb_udev_complete_msconfig_setup(IUDEVICE* idev, MSUSB_CONFIG_DESCRIPTOR* MsConfig) + { + UDEVICE* pdev = (UDEVICE*)idev; +- MSUSB_INTERFACE_DESCRIPTOR** MsInterfaces = NULL; +- MSUSB_INTERFACE_DESCRIPTOR* MsInterface = NULL; +- MSUSB_PIPE_DESCRIPTOR** MsPipes = NULL; +- MSUSB_PIPE_DESCRIPTOR* MsPipe = NULL; +- MSUSB_PIPE_DESCRIPTOR** t_MsPipes = NULL; +- MSUSB_PIPE_DESCRIPTOR* t_MsPipe = NULL; +- LIBUSB_CONFIG_DESCRIPTOR* LibusbConfig = NULL; +- const LIBUSB_INTERFACE* LibusbInterface = NULL; +- const LIBUSB_INTERFACE_DESCRIPTOR* LibusbAltsetting = NULL; +- const LIBUSB_ENDPOINT_DESCEIPTOR* LibusbEndpoint = NULL; +- BYTE LibusbNumEndpoint = 0; +- URBDRC_PLUGIN* urbdrc = NULL; + UINT32 MsOutSize = 0; + + if (!pdev || !pdev->LibusbConfig || !pdev->urbdrc || !MsConfig) + return NULL; + +- urbdrc = pdev->urbdrc; +- LibusbConfig = pdev->LibusbConfig; ++ URBDRC_PLUGIN* urbdrc = pdev->urbdrc; ++ LIBUSB_CONFIG_DESCRIPTOR* LibusbConfig = pdev->LibusbConfig; + + if (LibusbConfig->bNumInterfaces != MsConfig->NumInterfaces) + { +@@ -608,28 +596,57 @@ libusb_udev_complete_msconfig_setup(IUDEVICE* idev, MSUSB_CONFIG_DESCRIPTOR* MsC + "Select Configuration: Libusb NumberInterfaces(%" PRIu8 ") is different " + "with MsConfig NumberInterfaces(%" PRIu32 ")", + LibusbConfig->bNumInterfaces, MsConfig->NumInterfaces); ++ return NULL; + } + + /* replace MsPipes for libusb */ +- MsInterfaces = MsConfig->MsInterfaces; ++ MSUSB_INTERFACE_DESCRIPTOR** MsInterfaces = MsConfig->MsInterfaces; + + for (UINT32 inum = 0; inum < MsConfig->NumInterfaces; inum++) + { +- MsInterface = MsInterfaces[inum]; ++ MSUSB_INTERFACE_DESCRIPTOR* MsInterface = MsInterfaces[inum]; ++ if (MsInterface->InterfaceNumber >= MsConfig->NumInterfaces) ++ { ++ WLog_Print(urbdrc->log, WLOG_ERROR, ++ "MSUSB_CONFIG_DESCRIPTOR::NumInterfaces (%" PRIu32 ++ " <= MSUSB_INTERFACE_DESCRIPTOR::InterfaceNumber( %" PRIu8 ")", ++ MsConfig->NumInterfaces, MsInterface->InterfaceNumber); ++ return NULL; ++ } ++ ++ const LIBUSB_INTERFACE* LibusbInterface = ++ &LibusbConfig->interface[MsInterface->InterfaceNumber]; ++ if (MsInterface->AlternateSetting >= LibusbInterface->num_altsetting) ++ { ++ WLog_Print(urbdrc->log, WLOG_ERROR, ++ "LIBUSB_INTERFACE::num_altsetting (%" PRId32 ++ " <= MSUSB_INTERFACE_DESCRIPTOR::AlternateSetting( %" PRIu8 ")", ++ LibusbInterface->num_altsetting, MsInterface->AlternateSetting); ++ return NULL; ++ } ++ } ++ ++ for (UINT32 inum = 0; inum < MsConfig->NumInterfaces; inum++) ++ { ++ MSUSB_INTERFACE_DESCRIPTOR* MsInterface = MsInterfaces[inum]; ++ + /* get libusb's number of endpoints */ +- LibusbInterface = &LibusbConfig->interface[MsInterface->InterfaceNumber]; +- LibusbAltsetting = &LibusbInterface->altsetting[MsInterface->AlternateSetting]; +- LibusbNumEndpoint = LibusbAltsetting->bNumEndpoints; +- t_MsPipes = ++ const LIBUSB_INTERFACE* LibusbInterface = ++ &LibusbConfig->interface[MsInterface->InterfaceNumber]; ++ const LIBUSB_INTERFACE_DESCRIPTOR* LibusbAltsetting = ++ &LibusbInterface->altsetting[MsInterface->AlternateSetting]; ++ const BYTE LibusbNumEndpoint = LibusbAltsetting->bNumEndpoints; ++ MSUSB_PIPE_DESCRIPTOR** t_MsPipes = + (MSUSB_PIPE_DESCRIPTOR**)calloc(LibusbNumEndpoint, sizeof(MSUSB_PIPE_DESCRIPTOR*)); + + for (UINT32 pnum = 0; pnum < LibusbNumEndpoint; pnum++) + { +- t_MsPipe = (MSUSB_PIPE_DESCRIPTOR*)calloc(1, sizeof(MSUSB_PIPE_DESCRIPTOR)); ++ MSUSB_PIPE_DESCRIPTOR* t_MsPipe = ++ (MSUSB_PIPE_DESCRIPTOR*)calloc(1, sizeof(MSUSB_PIPE_DESCRIPTOR)); + + if (pnum < MsInterface->NumberOfPipes && MsInterface->MsPipes) + { +- MsPipe = MsInterface->MsPipes[pnum]; ++ MSUSB_PIPE_DESCRIPTOR* MsPipe = MsInterface->MsPipes[pnum]; + t_MsPipe->MaximumPacketSize = MsPipe->MaximumPacketSize; + t_MsPipe->MaximumTransferSize = MsPipe->MaximumTransferSize; + t_MsPipe->PipeFlags = MsPipe->PipeFlags; +@@ -668,10 +685,12 @@ libusb_udev_complete_msconfig_setup(IUDEVICE* idev, MSUSB_CONFIG_DESCRIPTOR* MsC + for (UINT32 inum = 0; inum < MsConfig->NumInterfaces; inum++) + { + MsOutSize += 16; +- MsInterface = MsInterfaces[inum]; ++ MSUSB_INTERFACE_DESCRIPTOR* MsInterface = MsInterfaces[inum]; + /* get libusb's interface */ +- LibusbInterface = &LibusbConfig->interface[MsInterface->InterfaceNumber]; +- LibusbAltsetting = &LibusbInterface->altsetting[MsInterface->AlternateSetting]; ++ const LIBUSB_INTERFACE* LibusbInterface = ++ &LibusbConfig->interface[MsInterface->InterfaceNumber]; ++ const LIBUSB_INTERFACE_DESCRIPTOR* LibusbAltsetting = ++ &LibusbInterface->altsetting[MsInterface->AlternateSetting]; + /* InterfaceHandle: 4 bytes + * --------------------------------------------------------------- + * ||<<< 1 byte >>>|<<< 1 byte >>>|<<< 1 byte >>>|<<< 1 byte >>>|| +@@ -688,15 +707,16 @@ libusb_udev_complete_msconfig_setup(IUDEVICE* idev, MSUSB_CONFIG_DESCRIPTOR* MsC + MsInterface->bInterfaceSubClass = LibusbAltsetting->bInterfaceSubClass; + MsInterface->bInterfaceProtocol = LibusbAltsetting->bInterfaceProtocol; + MsInterface->InitCompleted = 1; +- MsPipes = MsInterface->MsPipes; +- LibusbNumEndpoint = LibusbAltsetting->bNumEndpoints; ++ MSUSB_PIPE_DESCRIPTOR** MsPipes = MsInterface->MsPipes; ++ const BYTE LibusbNumEndpoint = LibusbAltsetting->bNumEndpoints; + + for (UINT32 pnum = 0; pnum < LibusbNumEndpoint; pnum++) + { + MsOutSize += 20; +- MsPipe = MsPipes[pnum]; ++ ++ MSUSB_PIPE_DESCRIPTOR* MsPipe = MsPipes[pnum]; + /* get libusb's endpoint */ +- LibusbEndpoint = &LibusbAltsetting->endpoint[pnum]; ++ const LIBUSB_ENDPOINT_DESCEIPTOR* LibusbEndpoint = &LibusbAltsetting->endpoint[pnum]; + /* PipeHandle: 4 bytes + * --------------------------------------------------------------- + * ||<<< 1 byte >>>|<<< 1 byte >>>|<<<<<<<<<< 2 byte >>>>>>>>>>>|| +diff --git a/channels/urbdrc/common/msusb.c b/channels/urbdrc/common/msusb.c +index 8d6809741..1b6e29aeb 100644 +--- a/channels/urbdrc/common/msusb.c ++++ b/channels/urbdrc/common/msusb.c +@@ -134,6 +134,8 @@ BOOL msusb_msinterface_replace(MSUSB_CONFIG_DESCRIPTOR* MsConfig, BYTE Interface + { + if (!MsConfig || !MsConfig->MsInterfaces) + return FALSE; ++ if (MsConfig->NumInterfaces <= InterfaceNumber) ++ return FALSE; + + msusb_msinterface_free(MsConfig->MsInterfaces[InterfaceNumber]); + MsConfig->MsInterfaces[InterfaceNumber] = NewMsInterface; +@@ -142,12 +144,10 @@ BOOL msusb_msinterface_replace(MSUSB_CONFIG_DESCRIPTOR* MsConfig, BYTE Interface + + MSUSB_INTERFACE_DESCRIPTOR* msusb_msinterface_read(wStream* s) + { +- MSUSB_INTERFACE_DESCRIPTOR* MsInterface = NULL; +- + if (!Stream_CheckAndLogRequiredCapacity(TAG, (s), 12)) + return NULL; + +- MsInterface = msusb_msinterface_new(); ++ MSUSB_INTERFACE_DESCRIPTOR* MsInterface = msusb_msinterface_new(); + + if (!MsInterface) + return NULL; +-- +2.47.3 + diff -Nru freerdp3-3.15.0+dfsg/debian/patches/channels-urbdrc-do-not-free-MsConfig-on-failure-CVE-2026-24675.patch freerdp3-3.15.0+dfsg/debian/patches/channels-urbdrc-do-not-free-MsConfig-on-failure-CVE-2026-24675.patch --- freerdp3-3.15.0+dfsg/debian/patches/channels-urbdrc-do-not-free-MsConfig-on-failure-CVE-2026-24675.patch 1970-01-01 00:00:00.000000000 +0000 +++ freerdp3-3.15.0+dfsg/debian/patches/channels-urbdrc-do-not-free-MsConfig-on-failure-CVE-2026-24675.patch 2026-02-09 18:48:59.000000000 +0000 @@ -0,0 +1,31 @@ +From: akallabeth +Date: Mon, 26 Jan 2026 11:54:56 +0100 +Subject: [channels,urbdrc] do not free MsConfig on failure +Origin: upstream, https://github.com/FreeRDP/FreeRDP/commit/d676518809c319eec15911c705c13536036af2ae +Forwarded: not-needed +Bug: https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-x9jr-99h2-g7mj +Bug: https://security-tracker.debian.org/tracker/CVE-2026-24491 + +let the channel handle it later. +--- + channels/urbdrc/client/data_transfer.c | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +diff --git a/channels/urbdrc/client/data_transfer.c b/channels/urbdrc/client/data_transfer.c +--- a/channels/urbdrc/client/data_transfer.c ++++ b/channels/urbdrc/client/data_transfer.c +@@ -662,10 +662,8 @@ static UINT urb_select_interface(IUDEVICE* pdev, GENERIC_CHANNEL_CALLBACK* callb + MSUSB_CONFIG_DESCRIPTOR* MsConfig = pdev->get_MsConfig(pdev); + const uint8_t InterfaceNumber = MsInterface->InterfaceNumber; + if (!msusb_msinterface_replace(MsConfig, InterfaceNumber, MsInterface)) +- { +- msusb_msconfig_free(MsConfig); + return ERROR_BAD_CONFIGURATION; +- } ++ + /* complete configuration setup */ + if (!pdev->complete_msconfig_setup(pdev, MsConfig)) + return ERROR_BAD_CONFIGURATION; +-- +2.47.3 + diff -Nru freerdp3-3.15.0+dfsg/debian/patches/channels-urbdrc-ensure-InterfaceNumber-is-within-ran-CVE-2026-24679.patch freerdp3-3.15.0+dfsg/debian/patches/channels-urbdrc-ensure-InterfaceNumber-is-within-ran-CVE-2026-24679.patch --- freerdp3-3.15.0+dfsg/debian/patches/channels-urbdrc-ensure-InterfaceNumber-is-within-ran-CVE-2026-24679.patch 1970-01-01 00:00:00.000000000 +0000 +++ freerdp3-3.15.0+dfsg/debian/patches/channels-urbdrc-ensure-InterfaceNumber-is-within-ran-CVE-2026-24679.patch 2026-02-09 18:48:59.000000000 +0000 @@ -0,0 +1,44 @@ +From: akallabeth +Date: Mon, 26 Jan 2026 10:59:39 +0100 +Subject: [channels,urbdrc] ensure InterfaceNumber is within range +Origin: upstream, https://github.com/FreeRDP/FreeRDP/commit/2d563a50be17c1b407ca448b1321378c0726dd31 +Forwarded: not-needed +Bug: https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-2jp4-67x6-gv7x +Bug: https://security-tracker.debian.org/tracker/CVE-2026-24679 + +--- + channels/urbdrc/client/libusb/libusb_udevice.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/channels/urbdrc/client/libusb/libusb_udevice.c b/channels/urbdrc/client/libusb/libusb_udevice.c +--- a/channels/urbdrc/client/libusb/libusb_udevice.c ++++ b/channels/urbdrc/client/libusb/libusb_udevice.c +@@ -539,19 +539,19 @@ static int libusb_udev_select_interface(IUDEVICE* idev, BYTE InterfaceNumber, BY + int error = 0; + int diff = 0; + UDEVICE* pdev = (UDEVICE*)idev; +- URBDRC_PLUGIN* urbdrc = NULL; +- MSUSB_CONFIG_DESCRIPTOR* MsConfig = NULL; +- MSUSB_INTERFACE_DESCRIPTOR** MsInterfaces = NULL; + + if (!pdev || !pdev->urbdrc) + return -1; + +- urbdrc = pdev->urbdrc; +- MsConfig = pdev->MsConfig; ++ URBDRC_PLUGIN* urbdrc = pdev->urbdrc; ++ MSUSB_CONFIG_DESCRIPTOR* MsConfig = pdev->MsConfig; + + if (MsConfig) + { +- MsInterfaces = MsConfig->MsInterfaces; ++ if (InterfaceNumber >= MsConfig->NumInterfaces) ++ return -2; ++ ++ MSUSB_INTERFACE_DESCRIPTOR** MsInterfaces = MsConfig->MsInterfaces; + if (MsInterfaces) + { + WLog_Print(urbdrc->log, WLOG_INFO, +-- +2.47.3 + diff -Nru freerdp3-3.15.0+dfsg/debian/patches/clang-warnings-fix-Wjump-misses-init-drdynvc_main.patch freerdp3-3.15.0+dfsg/debian/patches/clang-warnings-fix-Wjump-misses-init-drdynvc_main.patch --- freerdp3-3.15.0+dfsg/debian/patches/clang-warnings-fix-Wjump-misses-init-drdynvc_main.patch 1970-01-01 00:00:00.000000000 +0000 +++ freerdp3-3.15.0+dfsg/debian/patches/clang-warnings-fix-Wjump-misses-init-drdynvc_main.patch 2026-02-09 18:48:59.000000000 +0000 @@ -0,0 +1,35 @@ +From: Armin Novak +Date: Thu, 8 Jan 2026 10:32:29 +0100 +Subject: [clang,warnings] fix Wjump-misses-init +Origin: upstream, https://github.com/FreeRDP/FreeRDP/commit/3c95b2729bb8f6dfb7e6926f52dc7edb9bb5fc58 +Forwarded: not-needed +Comment: preparation for CVE-2026-24491 fix + +--- + channels/drdynvc/client/drdynvc_main.c | 10 ++++++---- + 1 file changed, 6 insertions(+), 4 deletions(-) + +diff --git a/channels/drdynvc/client/drdynvc_main.c b/channels/drdynvc/client/drdynvc_main.c +--- a/channels/drdynvc/client/drdynvc_main.c ++++ b/channels/drdynvc/client/drdynvc_main.c +@@ -506,11 +506,13 @@ static UINT dvcman_channel_close(DVCMAN_CHANNEL* channel, BOOL perRequest, BOOL + + channel->state = DVC_CHANNEL_CLOSED; + +- IWTSVirtualChannelCallback* cb = channel->channel_callback; +- if (cb) + { +- check_open_close_receive(channel); +- IFCALL(cb->OnClose, cb); ++ IWTSVirtualChannelCallback* cb = channel->channel_callback; ++ if (cb) ++ { ++ check_open_close_receive(channel); ++ IFCALL(cb->OnClose, cb); ++ } + } + + channel->channel_callback = NULL; +-- +2.47.3 + diff -Nru freerdp3-3.15.0+dfsg/debian/patches/clang-warnings-fix-Wjump-misses-init-remdesk_main.patch freerdp3-3.15.0+dfsg/debian/patches/clang-warnings-fix-Wjump-misses-init-remdesk_main.patch --- freerdp3-3.15.0+dfsg/debian/patches/clang-warnings-fix-Wjump-misses-init-remdesk_main.patch 1970-01-01 00:00:00.000000000 +0000 +++ freerdp3-3.15.0+dfsg/debian/patches/clang-warnings-fix-Wjump-misses-init-remdesk_main.patch 2026-02-09 18:48:59.000000000 +0000 @@ -0,0 +1,163 @@ +From: Armin Novak +Date: Thu, 8 Jan 2026 10:32:29 +0100 +Subject: [clang,warnings] fix Wjump-misses-init +Origin: upstream, https://github.com/FreeRDP/FreeRDP/commit/f7ee8dadcee9aa567bb13f99ce349a1f5f87fde4 +Forwarded: not-needed +Comment: preparation for CVE-2026-24677 fix + +--- + channels/remdesk/server/remdesk_main.c | 118 +++++++++++++------------ + 1 file changed, 60 insertions(+), 58 deletions(-) + +diff --git a/channels/remdesk/server/remdesk_main.c b/channels/remdesk/server/remdesk_main.c +--- a/channels/remdesk/server/remdesk_main.c ++++ b/channels/remdesk/server/remdesk_main.c +@@ -457,85 +457,87 @@ static DWORD WINAPI remdesk_server_thread(LPVOID arg) + goto out; + } + +- DWORD nCount = 0; +- events[nCount++] = ChannelEvent; +- events[nCount++] = context->priv->StopEvent; +- +- if ((error = remdesk_send_ctl_version_info_pdu(context))) +- { +- WLog_ERR(TAG, "remdesk_send_ctl_version_info_pdu failed with error %" PRIu32 "!", error); +- goto out; +- } +- +- while (1) + { +- DWORD status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE); ++ DWORD nCount = 0; ++ events[nCount++] = ChannelEvent; ++ events[nCount++] = context->priv->StopEvent; + +- if (status == WAIT_FAILED) ++ if ((error = remdesk_send_ctl_version_info_pdu(context))) + { +- error = GetLastError(); +- WLog_ERR(TAG, "WaitForMultipleObjects failed with error %" PRIu32 "", error); +- break; ++ WLog_ERR(TAG, "remdesk_send_ctl_version_info_pdu failed with error %" PRIu32 "!", ++ error); ++ goto out; + } + +- status = WaitForSingleObject(context->priv->StopEvent, 0); +- +- if (status == WAIT_FAILED) ++ while (1) + { +- error = GetLastError(); +- WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "", error); +- break; +- } ++ DWORD status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE); + +- if (status == WAIT_OBJECT_0) +- { +- break; +- } +- +- const size_t len = Stream_Capacity(s); +- if (len > UINT32_MAX) +- { +- error = ERROR_INTERNAL_ERROR; +- break; +- } +- if (WTSVirtualChannelRead(context->priv->ChannelHandle, 0, Stream_BufferAs(s, char), +- (UINT32)len, &BytesReturned)) +- { +- if (BytesReturned) +- Stream_Seek(s, BytesReturned); +- } +- else +- { +- if (!Stream_EnsureRemainingCapacity(s, BytesReturned)) ++ if (status == WAIT_FAILED) + { +- WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!"); +- error = CHANNEL_RC_NO_MEMORY; ++ error = GetLastError(); ++ WLog_ERR(TAG, "WaitForMultipleObjects failed with error %" PRIu32 "", error); + break; + } +- } + +- if (Stream_GetPosition(s) >= 8) +- { +- const UINT32* pHeader = Stream_BufferAs(s, UINT32); +- const UINT32 PduLength = pHeader[0] + pHeader[1] + 8; ++ status = WaitForSingleObject(context->priv->StopEvent, 0); + +- if (PduLength >= Stream_GetPosition(s)) ++ if (status == WAIT_FAILED) + { +- Stream_SealLength(s); +- Stream_SetPosition(s, 0); ++ error = GetLastError(); ++ WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "", error); ++ break; ++ } ++ ++ if (status == WAIT_OBJECT_0) ++ { ++ break; ++ } + +- if ((error = remdesk_server_receive_pdu(context, s))) ++ const size_t len = Stream_Capacity(s); ++ if (len > UINT32_MAX) ++ { ++ error = ERROR_INTERNAL_ERROR; ++ break; ++ } ++ if (WTSVirtualChannelRead(context->priv->ChannelHandle, 0, Stream_BufferAs(s, char), ++ (UINT32)len, &BytesReturned)) ++ { ++ if (BytesReturned) ++ Stream_Seek(s, BytesReturned); ++ } ++ else ++ { ++ if (!Stream_EnsureRemainingCapacity(s, BytesReturned)) + { +- WLog_ERR(TAG, "remdesk_server_receive_pdu failed with error %" PRIu32 "!", +- error); ++ WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!"); ++ error = CHANNEL_RC_NO_MEMORY; + break; + } ++ } ++ ++ if (Stream_GetPosition(s) >= 8) ++ { ++ const UINT32* pHeader = Stream_BufferAs(s, UINT32); ++ const UINT32 PduLength = pHeader[0] + pHeader[1] + 8; + +- Stream_SetPosition(s, 0); ++ if (PduLength >= Stream_GetPosition(s)) ++ { ++ Stream_SealLength(s); ++ Stream_SetPosition(s, 0); ++ ++ if ((error = remdesk_server_receive_pdu(context, s))) ++ { ++ WLog_ERR(TAG, "remdesk_server_receive_pdu failed with error %" PRIu32 "!", ++ error); ++ break; ++ } ++ ++ Stream_SetPosition(s, 0); ++ } + } + } + } +- + out: + Stream_Free(s, TRUE); + +-- +2.47.3 + diff -Nru freerdp3-3.15.0+dfsg/debian/patches/client-X11-fix-clipboard-update-CVE-2026-25997.patch freerdp3-3.15.0+dfsg/debian/patches/client-X11-fix-clipboard-update-CVE-2026-25997.patch --- freerdp3-3.15.0+dfsg/debian/patches/client-X11-fix-clipboard-update-CVE-2026-25997.patch 1970-01-01 00:00:00.000000000 +0000 +++ freerdp3-3.15.0+dfsg/debian/patches/client-X11-fix-clipboard-update-CVE-2026-25997.patch 2026-02-25 20:34:19.000000000 +0000 @@ -0,0 +1,63 @@ +From: Armin Novak +Date: Mon, 9 Feb 2026 12:58:42 +0100 +Subject: [client,X11] fix clipboard update +Origin: upstream, https://github.com/FreeRDP/FreeRDP/commit/58409406afe7c2a8a71ed2dc8e22075be4f41c0c +Forwarded: not-needed +Bug: https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-q5j3-m6jf-3jq4 +Bug: https://security-tracker.debian.org/tracker/CVE-2026-25997 + +Synchronize channel thread with RDP thread when accessing clipboard +formats +--- + client/X11/xf_cliprdr.c | 17 ++++++++++------- + 1 file changed, 10 insertions(+), 7 deletions(-) + +diff --git a/client/X11/xf_cliprdr.c b/client/X11/xf_cliprdr.c +--- a/client/X11/xf_cliprdr.c ++++ b/client/X11/xf_cliprdr.c +@@ -869,7 +869,11 @@ static void xf_clipboard_formats_free(xfClipboard* clipboard) + { + WINPR_ASSERT(clipboard); + ++ /* Synchronize RDP/X11 thread with channel thread */ ++ xf_lock_x11(clipboard->xfc); + xf_cliprdr_free_formats(clipboard->lastSentFormats, clipboard->lastSentNumFormats); ++ xf_unlock_x11(clipboard->xfc); ++ + clipboard->lastSentFormats = NULL; + clipboard->lastSentNumFormats = 0; + } +@@ -1867,24 +1871,23 @@ static UINT xf_cliprdr_send_client_format_list_response(xfClipboard* clipboard, + static UINT xf_cliprdr_monitor_ready(CliprdrClientContext* context, + const CLIPRDR_MONITOR_READY* monitorReady) + { +- UINT ret = 0; +- xfClipboard* clipboard = NULL; +- + WINPR_ASSERT(context); + WINPR_ASSERT(monitorReady); + +- clipboard = cliprdr_file_context_get_context(context->custom); ++ xfClipboard* clipboard = cliprdr_file_context_get_context(context->custom); + WINPR_ASSERT(clipboard); + + WINPR_UNUSED(monitorReady); + +- if ((ret = xf_cliprdr_send_client_capabilities(clipboard)) != CHANNEL_RC_OK) ++ const UINT ret = xf_cliprdr_send_client_capabilities(clipboard); ++ if (ret != CHANNEL_RC_OK) + return ret; + + xf_clipboard_formats_free(clipboard); + +- if ((ret = xf_cliprdr_send_client_format_list(clipboard, TRUE)) != CHANNEL_RC_OK) +- return ret; ++ const UINT ret2 = xf_cliprdr_send_client_format_list(clipboard, TRUE); ++ if (ret2 != CHANNEL_RC_OK) ++ return ret2; + + clipboard->sync = TRUE; + return CHANNEL_RC_OK; +-- +2.47.3 + diff -Nru freerdp3-3.15.0+dfsg/debian/patches/client-desktop-fix-StartupWMClass-setting.patch freerdp3-3.15.0+dfsg/debian/patches/client-desktop-fix-StartupWMClass-setting.patch --- freerdp3-3.15.0+dfsg/debian/patches/client-desktop-fix-StartupWMClass-setting.patch 1970-01-01 00:00:00.000000000 +0000 +++ freerdp3-3.15.0+dfsg/debian/patches/client-desktop-fix-StartupWMClass-setting.patch 2026-01-29 22:17:24.000000000 +0000 @@ -0,0 +1,74 @@ +From f48b129414c9bdc62c9475c67caa60b96d16d695 Mon Sep 17 00:00:00 2001 +From: akallabeth +Date: Thu, 26 Jun 2025 10:09:27 +0200 +Subject: [client,desktop] fix StartupWMClass setting +Comment: do not touch SDL parts since it works fine on trixie already +Forwarded: not-needed +Origin: upstream, https://github.com/FreeRDP/FreeRDP/pull/11708 + +--- + client/SDL/SDL2/CMakeLists.txt | 4 ++-- + client/SDL/SDL3/CMakeLists.txt | 2 +- + cmake/InstallFreeRDPDesktop.cmake | 6 ++++++ + resources/freerdp.desktop.template | 2 +- + 4 files changed, 10 insertions(+), 4 deletions(-) + +#diff --git a/client/SDL/SDL2/CMakeLists.txt b/client/SDL/SDL2/CMakeLists.txt +#index a22b8da30..e29f73826 100644 +#--- a/client/SDL/SDL2/CMakeLists.txt +#+++ b/client/SDL/SDL2/CMakeLists.txt +#@@ -79,10 +79,10 @@ if(NOT WITH_CLIENT_SDL_VERSIONED) +# endif() +# +# string(TIMESTAMP SDL_CLIENT_YEAR "%Y") +#-set(SDL_CLIENT_UUID "com.freerdp.client.sdl3") +#+set(SDL_CLIENT_UUID "com.freerdp.client.sdl2") +# configure_file(${CMAKE_CURRENT_SOURCE_DIR}/sdl_config.hpp.in ${CMAKE_CURRENT_BINARY_DIR}/sdl_config.hpp @ONLY) +# +# install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT client) +#-install_freerdp_desktop("${MODULE_NAME}") +#+install_freerdp_desktop("${MODULE_NAME}" "${SDL_CLIENT_UUID}") +# +# add_subdirectory(man) +#diff --git a/client/SDL/SDL3/CMakeLists.txt b/client/SDL/SDL3/CMakeLists.txt +#index d6b8e4851..0b4f5016d 100644 +#--- a/client/SDL/SDL3/CMakeLists.txt +#+++ b/client/SDL/SDL3/CMakeLists.txt +#@@ -85,6 +85,6 @@ set(SDL_CLIENT_UUID "com.freerdp.client.sdl3") +# configure_file(${CMAKE_CURRENT_SOURCE_DIR}/sdl_config.hpp.in ${CMAKE_CURRENT_BINARY_DIR}/sdl_config.hpp @ONLY) +# +# install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_BINDIR} COMPONENT client) +#-install_freerdp_desktop("${MODULE_NAME}" "${MODULE_NAME}") +#+install_freerdp_desktop("${MODULE_NAME}" "${SDL_CLIENT_UUID}") +# +# add_subdirectory(man) +diff --git a/cmake/InstallFreeRDPDesktop.cmake b/cmake/InstallFreeRDPDesktop.cmake +index 015a6b5ce..1e37c0ac3 100644 +--- a/cmake/InstallFreeRDPDesktop.cmake ++++ b/cmake/InstallFreeRDPDesktop.cmake +@@ -6,6 +6,12 @@ set(DESKTOP_RESOURCE_DIR "${CMAKE_CURRENT_LIST_DIR}/../resources" CACHE INTERNAL + + function(install_freerdp_desktop name) + if(WITH_INSTALL_CLIENT_DESKTOP_FILES) ++ if(${ARGC} GREATER 1) ++ set(FREERDP_STARTUP_CLASS ${ARGV1}) ++ else() ++ set(FREERDP_STARTUP_CLASS ${name}) ++ endif() ++ + get_target_property(FREERDP_APP_NAME ${name} OUTPUT_NAME) + set(FREERDP_BIN_NAME "${CMAKE_INSTALL_FULL_BINDIR}/${FREERDP_APP_NAME}") + set(FREERDP_DESKTOP_NAME "${CMAKE_CURRENT_BINARY_DIR}/${FREERDP_BIN_NAME}.desktop") +diff --git a/resources/freerdp.desktop.template b/resources/freerdp.desktop.template +index d77730023..82458775a 100644 +--- a/resources/freerdp.desktop.template ++++ b/resources/freerdp.desktop.template +@@ -10,4 +10,4 @@ Type=Application + Keywords=remote desktop;rdp; + Categories=GTK;GNOME;X-GNOME-NetworkSettings;Network; + StartupNotify=true +-StartupWMClass=com.freerdp.FreeRDP ++StartupWMClass=@FREERDP_STARTUP_CLASS@ +-- +2.47.3 + diff -Nru freerdp3-3.15.0+dfsg/debian/patches/client-sdl-lock-primary-while-used-CVE-2026-22851.patch freerdp3-3.15.0+dfsg/debian/patches/client-sdl-lock-primary-while-used-CVE-2026-22851.patch --- freerdp3-3.15.0+dfsg/debian/patches/client-sdl-lock-primary-while-used-CVE-2026-22851.patch 1970-01-01 00:00:00.000000000 +0000 +++ freerdp3-3.15.0+dfsg/debian/patches/client-sdl-lock-primary-while-used-CVE-2026-22851.patch 2026-02-09 18:48:59.000000000 +0000 @@ -0,0 +1,37 @@ +From: akallabeth +Date: Wed, 31 Dec 2025 15:43:12 +0100 +Subject: [client,sdl] lock primary while used +Origin: upstream, https://github.com/FreeRDP/FreeRDP/commit/98deec9ec0a048cd5fb99076f40253cc387b4864 +Forwarded: not-needed +Bug: https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-8g87-6pvc-wh99 +Bug: https://security-tracker.debian.org/tracker/CVE-2026-22851 + +Mjt: in the upstream commit 98deec9ec0a048cd5fb99076f40253cc387b4864 +"[client,sdl] lock primary while used", not only single missing +lock were added, but the lock type has been changed in other places. +In 3.15 the lock type was std::lock_guard, later it +were changed to std::scoped_lock, and when adding the missing lock, +the lock type were changed again to std::unique_lock. + +Here for 3.15, add just the missing lock, of the same type as used +elsewhere (std::lock_guard). So the fix becomes +a one-liner. +--- + client/SDL/SDL3/sdl_freerdp.cpp | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/client/SDL/SDL3/sdl_freerdp.cpp b/client/SDL/SDL3/sdl_freerdp.cpp +index 554529880..597eb3225 100644 +--- a/client/SDL/SDL3/sdl_freerdp.cpp ++++ b/client/SDL/SDL3/sdl_freerdp.cpp +@@ -363,6 +363,7 @@ static BOOL sdl_draw_to_window(SdlContext* sdl, SdlWindow& window, + window.setOffsetY((size.h - gdi->height) / 2); + } + ++ std::lock_guard lock(sdl->critical); + auto surface = sdl->primary.get(); + if (!sdl_draw_to_window_rect(sdl, window, surface, { window.offsetX(), window.offsetY() }, + rects)) +-- +2.47.3 + diff -Nru freerdp3-3.15.0+dfsg/debian/patches/client-sdl-reset-pointer-after-memory-release-CVE-2026-24680.patch freerdp3-3.15.0+dfsg/debian/patches/client-sdl-reset-pointer-after-memory-release-CVE-2026-24680.patch --- freerdp3-3.15.0+dfsg/debian/patches/client-sdl-reset-pointer-after-memory-release-CVE-2026-24680.patch 1970-01-01 00:00:00.000000000 +0000 +++ freerdp3-3.15.0+dfsg/debian/patches/client-sdl-reset-pointer-after-memory-release-CVE-2026-24680.patch 2026-02-09 18:48:59.000000000 +0000 @@ -0,0 +1,26 @@ +From: akallabeth +Date: Mon, 26 Jan 2026 11:01:17 +0100 +Subject: [client,sdl] reset pointer after memory release +Origin: upstream, https://github.com/FreeRDP/FreeRDP/commit/c42ecbd183b001e76bfc3614cddfad0034acc758 +Forwarded: not-needed +Bug: https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-j893-9wg8-33rc +Bug: https://security-tracker.debian.org/tracker/CVE-2026-24680 + +--- + client/SDL/SDL3/sdl_pointer.cpp | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/client/SDL/SDL3/sdl_pointer.cpp b/client/SDL/SDL3/sdl_pointer.cpp +--- a/client/SDL/SDL3/sdl_pointer.cpp ++++ b/client/SDL/SDL3/sdl_pointer.cpp +@@ -61,6 +61,7 @@ static BOOL sdl_Pointer_New(rdpContext* context, rdpPointer* pointer) + &context->gdi->palette)) + { + winpr_aligned_free(ptr->data); ++ ptr->data = nullptr; + return FALSE; + } + +-- +2.47.3 + diff -Nru freerdp3-3.15.0+dfsg/debian/patches/client-x11-destroy-XImage-on-window-unmap-CVE-2026-25955.patch freerdp3-3.15.0+dfsg/debian/patches/client-x11-destroy-XImage-on-window-unmap-CVE-2026-25955.patch --- freerdp3-3.15.0+dfsg/debian/patches/client-x11-destroy-XImage-on-window-unmap-CVE-2026-25955.patch 1970-01-01 00:00:00.000000000 +0000 +++ freerdp3-3.15.0+dfsg/debian/patches/client-x11-destroy-XImage-on-window-unmap-CVE-2026-25955.patch 2026-02-25 20:34:19.000000000 +0000 @@ -0,0 +1,104 @@ +From: Armin Novak +Date: Mon, 9 Feb 2026 16:58:20 +0100 +Subject: [client,x11] destroy XImage on window unmap +Origin: upstream, https://github.com/FreeRDP/FreeRDP/commit/169d358734509e82663a0d6a0085ae726d439d8e +Forwarded: not-needed +Bug: https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-4g54-x8v7-559x +Bug: https://security-tracker.debian.org/tracker/CVE-2026-25955 + +When unmapping rails window destroy the cached XImage of appWindow +--- + client/X11/xf_gfx.c | 24 ++++++++++++++++++++++++ + client/X11/xf_window.c | 2 +- + client/X11/xf_window.h | 6 +++++- + 3 files changed, 30 insertions(+), 2 deletions(-) + +diff --git a/client/X11/xf_gfx.c b/client/X11/xf_gfx.c +--- a/client/X11/xf_gfx.c ++++ b/client/X11/xf_gfx.c +@@ -30,6 +30,7 @@ + #include "xf_gfx.h" + #include "xf_rail.h" + #include "xf_utils.h" ++#include "xf_window.h" + + #include + +@@ -444,6 +445,27 @@ static UINT xf_DeleteSurface(RdpgfxClientContext* context, + return status; + } + ++static UINT xf_UnmapWindowForSurface(RdpgfxClientContext* context, UINT64 windowID) ++{ ++ WINPR_ASSERT(context); ++ rdpGdi* gdi = (rdpGdi*)context->custom; ++ WINPR_ASSERT(gdi); ++ ++ xfContext* xfc = (xfContext*)gdi->context; ++ WINPR_ASSERT(gdi->context); ++ ++ if (freerdp_settings_get_bool(gdi->context->settings, FreeRDP_RemoteApplicationMode)) ++ { ++ xfAppWindow* appWindow = xf_rail_get_window(xfc, windowID); ++ if (appWindow) ++ xf_AppWindowDestroyImage(appWindow); ++ xf_rail_return_window(appWindow); ++ } ++ ++ WLog_WARN(TAG, "function not implemented"); ++ return CHANNEL_RC_OK; ++} ++ + static UINT xf_UpdateWindowFromSurface(RdpgfxClientContext* context, gdiGfxSurface* surface) + { + WINPR_ASSERT(context); +@@ -482,7 +504,9 @@ void xf_graphics_pipeline_init(xfContext* xfc, RdpgfxClientContext* gfx) + gfx->CreateSurface = xf_CreateSurface; + gfx->DeleteSurface = xf_DeleteSurface; + } ++ + gfx->UpdateWindowFromSurface = xf_UpdateWindowFromSurface; ++ gfx->UnmapWindowForSurface = xf_UnmapWindowForSurface; + } + + void xf_graphics_pipeline_uninit(xfContext* xfc, RdpgfxClientContext* gfx) +diff --git a/client/X11/xf_window.c b/client/X11/xf_window.c +--- a/client/X11/xf_window.c ++++ b/client/X11/xf_window.c +@@ -1380,7 +1380,7 @@ void xf_UpdateWindowArea(xfContext* xfc, xfAppWindow* appWindow, int x, int y, i + xf_unlock_x11(xfc); + } + +-static void xf_AppWindowDestroyImage(xfAppWindow* appWindow) ++void xf_AppWindowDestroyImage(xfAppWindow* appWindow) + { + WINPR_ASSERT(appWindow); + if (appWindow->image) +diff --git a/client/X11/xf_window.h b/client/X11/xf_window.h +--- a/client/X11/xf_window.h ++++ b/client/X11/xf_window.h +@@ -167,9 +167,12 @@ void xf_SetWindowMinimized(xfContext* xfc, xfWindow* window); + void xf_SetWindowDecorations(xfContext* xfc, Window window, BOOL show); + void xf_SetWindowUnlisted(xfContext* xfc, Window window); + ++void xf_DestroyDesktopWindow(xfContext* xfc, xfWindow* window); ++ ++WINPR_ATTR_MALLOC(xf_DestroyDesktopWindow, 2) + xfWindow* xf_CreateDesktopWindow(xfContext* xfc, char* name, int width, int height); ++ + void xf_ResizeDesktopWindow(xfContext* xfc, xfWindow* window, int width, int height); +-void xf_DestroyDesktopWindow(xfContext* xfc, xfWindow* window); + + Window xf_CreateDummyWindow(xfContext* xfc); + void xf_DestroyDummyWindow(xfContext* xfc, Window window); +@@ -196,6 +199,7 @@ void xf_UpdateWindowArea(xfContext* xfc, xfAppWindow* appWindow, int x, int y, i + int height); + UINT xf_AppUpdateWindowFromSurface(xfContext* xfc, gdiGfxSurface* surface); + ++void xf_AppWindowDestroyImage(xfAppWindow* appWindow); + void xf_DestroyWindow(xfContext* xfc, xfAppWindow* appWindow); + void xf_SetWindowMinMaxInfo(xfContext* xfc, xfAppWindow* appWindow, int maxWidth, int maxHeight, + int maxPosX, int maxPosY, int minTrackWidth, int minTrackHeight, +-- +2.47.3 + diff -Nru freerdp3-3.15.0+dfsg/debian/patches/client-x11-fix-clipboard-issues.patch freerdp3-3.15.0+dfsg/debian/patches/client-x11-fix-clipboard-issues.patch --- freerdp3-3.15.0+dfsg/debian/patches/client-x11-fix-clipboard-issues.patch 1970-01-01 00:00:00.000000000 +0000 +++ freerdp3-3.15.0+dfsg/debian/patches/client-x11-fix-clipboard-issues.patch 2026-01-29 22:17:24.000000000 +0000 @@ -0,0 +1,248 @@ +From 671381da7436f564880b7242315ab788553b5a9e Mon Sep 17 00:00:00 2001 +From: akallabeth +Date: Thu, 3 Jul 2025 06:47:40 +0200 +Subject: [client,x11] fix clipboard issues +Bug-Debian: https://bugs.debian.org/1121299 +Bug: https://github.com/FreeRDP/FreeRDP/issues/11720 +Bug: https://github.com/FreeRDP/FreeRDP/issues/11714 +Origin: upstream, https://github.com/FreeRDP/FreeRDP/pull/11724 +Forwarded: not-needed + +* better logging of requested formats +* properly remember local format ID to paste + +diff --git a/client/X11/xf_cliprdr.c b/client/X11/xf_cliprdr.c +--- a/client/X11/xf_cliprdr.c ++++ b/client/X11/xf_cliprdr.c +@@ -54,14 +54,7 @@ + + #define MAX_CLIPBOARD_FORMATS 255 + +-#ifdef WITH_DEBUG_CLIPRDR + #define DEBUG_CLIPRDR(...) WLog_DBG(TAG, __VA_ARGS__) +-#else +-#define DEBUG_CLIPRDR(...) \ +- do \ +- { \ +- } while (0) +-#endif + + typedef struct + { +@@ -178,8 +171,8 @@ static void requested_format_free(RequestedFormat** ppRequestedFormat) + *ppRequestedFormat = NULL; + } + +-static BOOL requested_format_replace(RequestedFormat** ppRequestedFormat, UINT32 formatId, +- const char* formatName) ++static BOOL requested_format_replace(RequestedFormat** ppRequestedFormat, UINT32 remoteFormatId, ++ UINT32 localFormatId, const char* formatName) + { + if (!ppRequestedFormat) + return FALSE; +@@ -188,8 +181,8 @@ static BOOL requested_format_replace(RequestedFormat** ppRequestedFormat, UINT32 + RequestedFormat* requested = calloc(1, sizeof(RequestedFormat)); + if (!requested) + return FALSE; +- requested->localFormat = formatId; +- requested->formatToRequest = formatId; ++ requested->localFormat = localFormatId; ++ requested->formatToRequest = remoteFormatId; + if (formatName) + { + requested->formatName = _strdup(formatName); +@@ -480,9 +473,11 @@ static UINT xf_cliprdr_send_data_response(xfClipboard* clipboard, const xfCliprd + else + { + WINPR_ASSERT(format); +- DEBUG_CLIPRDR("send response format 0x%08" PRIx32 " [%s] {local 0x%08" PRIx32 "} [%s]", ++ DEBUG_CLIPRDR("send response format 0x%08" PRIx32 " [%s] {local 0x%08" PRIx32 " [%s]} [%s]", + format->formatToRequest, ClipboardGetFormatIdString(format->formatToRequest), +- format->localFormat, format->formatName); ++ format->localFormat, ++ ClipboardGetFormatName(clipboard->system, format->localFormat), ++ format->formatName); + } + /* Request handled, reset to invalid */ + clipboard->requestedFormatId = UINT32_MAX; +@@ -1224,21 +1219,22 @@ static void xf_cliprdr_provide_timestamp(xfClipboard* clipboard, const XSelectio + } + } + +-static void xf_cliprdr_provide_data(xfClipboard* clipboard, const XSelectionEvent* respond, +- const BYTE* data, UINT32 size) ++#define xf_cliprdr_provide_data(clipboard, respond, data, size) \ ++ xf_cliprdr_provide_data_((clipboard), (respond), (data), (size), __FILE__, __func__, __LINE__) ++static void xf_cliprdr_provide_data_(xfClipboard* clipboard, const XSelectionEvent* respond, ++ const BYTE* data, UINT32 size, const char* file, ++ const char* fkt, size_t line) + { +- xfContext* xfc = NULL; +- + WINPR_ASSERT(clipboard); + +- xfc = clipboard->xfc; ++ xfContext* xfc = clipboard->xfc; + WINPR_ASSERT(xfc); + + if (respond->property != None) + { +- LogTagAndXChangeProperty(TAG, xfc->display, respond->requestor, respond->property, +- respond->target, 8, PropModeReplace, data, +- WINPR_ASSERTING_INT_CAST(int32_t, size)); ++ LogTagAndXChangeProperty_ex(TAG, file, fkt, line, xfc->display, respond->requestor, ++ respond->property, respond->target, 8, PropModeReplace, data, ++ WINPR_ASSERTING_INT_CAST(int32_t, size)); + } + } + +@@ -1430,9 +1426,6 @@ static xfCachedData* convert_data_from_existing_raw_data(xfClipboard* clipboard, + UINT32 srcFormatId, BOOL nullTerminated, + UINT32 dstFormatId) + { +- xfCachedData* cached_data = NULL; +- BOOL success = 0; +- BYTE* dst_data = NULL; + UINT32 dst_size = 0; + + WINPR_ASSERT(clipboard); +@@ -1440,8 +1433,8 @@ static xfCachedData* convert_data_from_existing_raw_data(xfClipboard* clipboard, + WINPR_ASSERT(cached_raw_data->data); + + ClipboardLock(clipboard->system); +- success = ClipboardSetData(clipboard->system, srcFormatId, cached_raw_data->data, +- cached_raw_data->data_length); ++ BOOL success = ClipboardSetData(clipboard->system, srcFormatId, cached_raw_data->data, ++ cached_raw_data->data_length); + if (!success) + { + WLog_WARN(TAG, "Failed to set clipboard data (formatId: %u, data: %p, data_length: %u)", +@@ -1450,7 +1443,7 @@ static xfCachedData* convert_data_from_existing_raw_data(xfClipboard* clipboard, + return NULL; + } + +- dst_data = ClipboardGetData(clipboard->system, dstFormatId, &dst_size); ++ BYTE* dst_data = ClipboardGetData(clipboard->system, dstFormatId, &dst_size); + if (!dst_data) + { + WLog_WARN(TAG, "Failed to get converted clipboard data"); +@@ -1471,7 +1464,7 @@ static xfCachedData* convert_data_from_existing_raw_data(xfClipboard* clipboard, + } + } + +- cached_data = xf_cached_data_new(dst_data, dst_size); ++ xfCachedData* cached_data = xf_cached_data_new(dst_data, dst_size); + if (!cached_data) + { + WLog_WARN(TAG, "Failed to allocate cache entry"); +@@ -1552,7 +1545,6 @@ static BOOL xf_cliprdr_process_selection_request(xfClipboard* clipboard, + formatId = format->formatId; + rawTransfer = FALSE; + xfCachedData* cached_data = NULL; +- UINT32 dstFormatId = 0; + + if (formatId == CF_RAW) + { +@@ -1570,8 +1562,9 @@ static BOOL xf_cliprdr_process_selection_request(xfClipboard* clipboard, + } + } + +- dstFormatId = get_dst_format_id_for_local_request(clipboard, cformat); +- DEBUG_CLIPRDR("formatId: %u, dstFormatId: %u", formatId, dstFormatId); ++ const UINT32 dstFormatId = get_dst_format_id_for_local_request(clipboard, cformat); ++ DEBUG_CLIPRDR("formatId: 0x%08" PRIx32 ", dstFormatId: 0x%08" PRIx32 "", formatId, ++ dstFormatId); + + if (!rawTransfer) + cached_data = HashTable_GetItemValue(clipboard->cachedData, +@@ -1626,7 +1619,7 @@ static BOOL xf_cliprdr_process_selection_request(xfClipboard* clipboard, + */ + respond->property = xevent->property; + clipboard->respond = respond; +- requested_format_replace(&clipboard->requestedFormat, formatId, ++ requested_format_replace(&clipboard->requestedFormat, formatId, dstFormatId, + cformat->formatName); + clipboard->data_raw_format = rawTransfer; + delayRespond = TRUE; +@@ -2136,9 +2129,11 @@ xf_cliprdr_server_format_data_request(CliprdrClientContext* context, + if (!format) + return xf_cliprdr_send_data_response(clipboard, format, NULL, 0); + +- DEBUG_CLIPRDR("requested format 0x%08" PRIx32 " [%s] {local 0x%08" PRIx32 "} [%s]", ++ DEBUG_CLIPRDR("requested format 0x%08" PRIx32 " [%s] {local 0x%08" PRIx32 " [%s]} [%s]", + format->formatToRequest, ClipboardGetFormatIdString(format->formatToRequest), +- format->localFormat, format->formatName); ++ format->localFormat, ++ ClipboardGetFormatName(clipboard->system, format->localFormat), ++ format->formatName); + LogTagAndXConvertSelection(TAG, xfc->display, clipboard->clipboard_atom, format->atom, + clipboard->property_atom, xfc->drawable, CurrentTime); + XFlush(xfc->display); +@@ -2162,23 +2157,19 @@ xf_cliprdr_server_format_data_response(CliprdrClientContext* context, + UINT32 srcFormatId = 0; + UINT32 dstFormatId = 0; + BOOL nullTerminated = FALSE; +- UINT32 size = 0; +- const BYTE* data = NULL; +- xfContext* xfc = NULL; +- xfClipboard* clipboard = NULL; + xfCachedData* cached_data = NULL; + + WINPR_ASSERT(context); + WINPR_ASSERT(formatDataResponse); + +- clipboard = cliprdr_file_context_get_context(context->custom); ++ xfClipboard* clipboard = cliprdr_file_context_get_context(context->custom); + WINPR_ASSERT(clipboard); + +- xfc = clipboard->xfc; ++ xfContext* xfc = clipboard->xfc; + WINPR_ASSERT(xfc); + +- size = formatDataResponse->common.dataLen; +- data = formatDataResponse->requestedFormatData; ++ const UINT32 size = formatDataResponse->common.dataLen; ++ const BYTE* data = formatDataResponse->requestedFormatData; + + if (formatDataResponse->common.msgFlags == CB_RESPONSE_FAIL) + { +@@ -2191,11 +2182,6 @@ xf_cliprdr_server_format_data_response(CliprdrClientContext* context, + if (!clipboard->respond) + return CHANNEL_RC_OK; + +- pDstData = NULL; +- DstSize = 0; +- srcFormatId = 0; +- dstFormatId = 0; +- + const RequestedFormat* format = clipboard->requestedFormat; + if (clipboard->data_raw_format) + { +@@ -2206,6 +2192,8 @@ xf_cliprdr_server_format_data_response(CliprdrClientContext* context, + return ERROR_INTERNAL_ERROR; + else if (format->formatName) + { ++ dstFormatId = format->localFormat; ++ + ClipboardLock(clipboard->system); + if (strcmp(format->formatName, type_HtmlFormat) == 0) + { +@@ -2267,12 +2255,15 @@ xf_cliprdr_server_format_data_response(CliprdrClientContext* context, + } + } + +- DEBUG_CLIPRDR("requested format 0x%08" PRIx32 " [%s] {local 0x%08" PRIx32 "} [%s]", ++ DEBUG_CLIPRDR("requested format 0x%08" PRIx32 " [%s] {local 0x%08" PRIx32 " [%s]} [%s]", + format->formatToRequest, ClipboardGetFormatIdString(format->formatToRequest), +- format->localFormat, format->formatName); ++ format->localFormat, ++ ClipboardGetFormatName(clipboard->system, format->localFormat), ++ format->formatName); + SrcSize = size; + +- DEBUG_CLIPRDR("srcFormatId: %u, dstFormatId: %u", srcFormatId, dstFormatId); ++ DEBUG_CLIPRDR("srcFormatId: 0x%08" PRIx32 ", dstFormatId: 0x%08" PRIx32 "", srcFormatId, ++ dstFormatId); + + ClipboardLock(clipboard->system); + bSuccess = ClipboardSetData(clipboard->system, srcFormatId, data, SrcSize); diff -Nru freerdp3-3.15.0+dfsg/debian/patches/client-x11-fix-double-free-in-case-of-invalid-pointe-CVE-2026-23883.patch freerdp3-3.15.0+dfsg/debian/patches/client-x11-fix-double-free-in-case-of-invalid-pointe-CVE-2026-23883.patch --- freerdp3-3.15.0+dfsg/debian/patches/client-x11-fix-double-free-in-case-of-invalid-pointe-CVE-2026-23883.patch 1970-01-01 00:00:00.000000000 +0000 +++ freerdp3-3.15.0+dfsg/debian/patches/client-x11-fix-double-free-in-case-of-invalid-pointe-CVE-2026-23883.patch 2026-02-09 18:48:59.000000000 +0000 @@ -0,0 +1,51 @@ +From: akallabeth +Date: Mon, 19 Jan 2026 08:52:51 +0100 +Subject: [client,x11] fix double free in case of invalid pointer +Origin: upstream, https://github.com/FreeRDP/FreeRDP/commit/0421b53fcb4a80c95f51342e4a2c40c68a4101d3 +Forwarded: not-needed +Bug: https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-qcrr-85qx-4p6x +Bug: https://security-tracker.debian.org/tracker/CVE-2026-23883 + +--- + client/X11/xf_graphics.c | 10 ++++------ + 1 file changed, 4 insertions(+), 6 deletions(-) + +diff --git a/client/X11/xf_graphics.c b/client/X11/xf_graphics.c +index df95a22b5..9d432c98b 100644 +--- a/client/X11/xf_graphics.c ++++ b/client/X11/xf_graphics.c +@@ -289,7 +289,6 @@ static BOOL xf_Pointer_New(rdpContext* context, rdpPointer* pointer) + + #ifdef WITH_XCURSOR + UINT32 CursorFormat = 0; +- size_t size = 0; + xfContext* xfc = (xfContext*)context; + xfPointer* xpointer = (xfPointer*)pointer; + +@@ -304,19 +303,18 @@ static BOOL xf_Pointer_New(rdpContext* context, rdpPointer* pointer) + xpointer->nCursors = 0; + xpointer->mCursors = 0; + +- size = 1ull * pointer->height * pointer->width * FreeRDPGetBytesPerPixel(CursorFormat); ++ const size_t size = ++ 1ull * pointer->height * pointer->width * FreeRDPGetBytesPerPixel(CursorFormat); + +- if (!(xpointer->cursorPixels = (XcursorPixel*)winpr_aligned_malloc(size, 16))) ++ xpointer->cursorPixels = (XcursorPixel*)winpr_aligned_malloc(size, 16); ++ if (!xpointer->cursorPixels) + goto fail; + + if (!freerdp_image_copy_from_pointer_data( + (BYTE*)xpointer->cursorPixels, CursorFormat, 0, 0, 0, pointer->width, pointer->height, + pointer->xorMaskData, pointer->lengthXorMask, pointer->andMaskData, + pointer->lengthAndMask, pointer->xorBpp, &context->gdi->palette)) +- { +- winpr_aligned_free(xpointer->cursorPixels); + goto fail; +- } + + #endif + +-- +2.47.3 + diff -Nru freerdp3-3.15.0+dfsg/debian/patches/client-x11-fix-missing-includes.patch freerdp3-3.15.0+dfsg/debian/patches/client-x11-fix-missing-includes.patch --- freerdp3-3.15.0+dfsg/debian/patches/client-x11-fix-missing-includes.patch 1970-01-01 00:00:00.000000000 +0000 +++ freerdp3-3.15.0+dfsg/debian/patches/client-x11-fix-missing-includes.patch 2026-02-25 20:34:19.000000000 +0000 @@ -0,0 +1,36 @@ +From: akallabeth +Date: Thu, 22 May 2025 16:17:50 +0200 +Subject: [client,x11] fix missing includes +Origin: upstream, https://github.com/FreeRDP/FreeRDP/commit/479cea48ccc40c1e28b77043dc58d475367a80b5 +Forwarded: not-needed + +--- + client/X11/xf_gfx.c | 1 + + client/X11/xf_video.c | 1 + + 2 files changed, 2 insertions(+) + +diff --git a/client/X11/xf_gfx.c b/client/X11/xf_gfx.c +--- a/client/X11/xf_gfx.c ++++ b/client/X11/xf_gfx.c +@@ -29,6 +29,7 @@ + #include + #include "xf_gfx.h" + #include "xf_rail.h" ++#include "xf_utils.h" + + #include + +diff --git a/client/X11/xf_video.c b/client/X11/xf_video.c +--- a/client/X11/xf_video.c ++++ b/client/X11/xf_video.c +@@ -23,6 +23,7 @@ + #include + + #include "xf_video.h" ++#include "xf_utils.h" + + #include + #define TAG CLIENT_TAG("video") +-- +2.47.3 + diff -Nru freerdp3-3.15.0+dfsg/debian/patches/client-x11-fix-xf_rail_window_common-cleanup-CVE-2026-26986.patch freerdp3-3.15.0+dfsg/debian/patches/client-x11-fix-xf_rail_window_common-cleanup-CVE-2026-26986.patch --- freerdp3-3.15.0+dfsg/debian/patches/client-x11-fix-xf_rail_window_common-cleanup-CVE-2026-26986.patch 1970-01-01 00:00:00.000000000 +0000 +++ freerdp3-3.15.0+dfsg/debian/patches/client-x11-fix-xf_rail_window_common-cleanup-CVE-2026-26986.patch 2026-02-25 20:34:19.000000000 +0000 @@ -0,0 +1,47 @@ +From: Armin Novak +Date: Mon, 9 Feb 2026 15:50:19 +0100 +Subject: [client,x11] fix xf_rail_window_common cleanup +Origin: upstream, https://github.com/FreeRDP/FreeRDP/commit/b4f0f0a18fe53aa8d47d062f91471f4e9c5e0d51 +Forwarded: not-needed +Bug: https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-crqx-g6x5-rx47 +Bug: https://security-tracker.debian.org/tracker/CVE-2026-26986 + +leave the appWindow for later cleanup. +--- + client/X11/xf_rail.c | 6 +----- + 1 file changed, 1 insertion(+), 5 deletions(-) + +diff --git a/client/X11/xf_rail.c b/client/X11/xf_rail.c +--- a/client/X11/xf_rail.c ++++ b/client/X11/xf_rail.c +@@ -368,7 +368,6 @@ static void window_state_log_style_int(wLog* log, const WINDOW_STATE_ORDER* wind + static BOOL xf_rail_window_common(rdpContext* context, const WINDOW_ORDER_INFO* orderInfo, + const WINDOW_STATE_ORDER* windowState) + { +- xfAppWindow* appWindow = NULL; + xfContext* xfc = (xfContext*)context; + + WINPR_ASSERT(xfc); +@@ -377,7 +376,7 @@ static BOOL xf_rail_window_common(rdpContext* context, const WINDOW_ORDER_INFO* + + UINT32 fieldFlags = orderInfo->fieldFlags; + BOOL position_or_size_updated = FALSE; +- appWindow = xf_rail_get_window(xfc, orderInfo->windowId); ++ xfAppWindow* appWindow = xf_rail_get_window(xfc, orderInfo->windowId); + + if (fieldFlags & WINDOW_ORDER_STATE_NEW) + { +@@ -428,10 +427,7 @@ static BOOL xf_rail_window_common(rdpContext* context, const WINDOW_ORDER_INFO* + } + + if (!appWindow->title) +- { +- free(appWindow); + return FALSE; +- } + + xf_AppWindowInit(xfc, appWindow); + } +-- +2.47.3 + diff -Nru freerdp3-3.15.0+dfsg/debian/patches/client-x11-lock-appWindow-CVE-2026-25952-CVE-2026-25953-CVE-2026-25954.patch freerdp3-3.15.0+dfsg/debian/patches/client-x11-lock-appWindow-CVE-2026-25952-CVE-2026-25953-CVE-2026-25954.patch --- freerdp3-3.15.0+dfsg/debian/patches/client-x11-lock-appWindow-CVE-2026-25952-CVE-2026-25953-CVE-2026-25954.patch 1970-01-01 00:00:00.000000000 +0000 +++ freerdp3-3.15.0+dfsg/debian/patches/client-x11-lock-appWindow-CVE-2026-25952-CVE-2026-25953-CVE-2026-25954.patch 2026-02-25 20:34:19.000000000 +0000 @@ -0,0 +1,404 @@ +From: Armin Novak +Date: Mon, 9 Feb 2026 16:09:51 +0100 +Subject: [client,x11] lock appWindow +Origin: upstream, https://github.com/FreeRDP/FreeRDP/commit/1994e9844212a6dfe0ff12309fef520e888986b5 +Forwarded: not-needed +Bug: https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-cgqm-cwjg-7w9x +Bug: https://security-tracker.debian.org/tracker/CVE-2026-25952 +Bug: https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-p6rq-rxpc-rh3p +Bug: https://security-tracker.debian.org/tracker/CVE-2026-25954 +Bug: https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-cc88-4j37-mw6j +Bug: https://security-tracker.debian.org/tracker/CVE-2026-25955 +Comment: back-ported to 3.15 by mjt + +When using xf_rail_get_window lock the hash talbe until xf_rail_return_window + +diff --git a/client/X11/xf_event.c b/client/X11/xf_event.c +--- a/client/X11/xf_event.c ++++ b/client/X11/xf_event.c +@@ -429,7 +429,9 @@ BOOL xf_generic_MotionNotify(xfContext* xfc, int x, int y, int state, Window win + if (app) + { + /* make sure window exists */ +- if (!xf_AppWindowFromX11Window(xfc, window)) ++ xfAppWindow* appWindow = xf_AppWindowFromX11Window(xfc, window); ++ xf_rail_return_window(appWindow); ++ if (!appWindow) + return TRUE; + + /* Translate to desktop coordinates */ +@@ -526,7 +528,9 @@ BOOL xf_generic_ButtonEvent(xfContext* xfc, int x, int y, int button, Window win + if (app) + { + /* make sure window exists */ +- if (!xf_AppWindowFromX11Window(xfc, window)) ++ xfAppWindow* appWindow = xf_AppWindowFromX11Window(xfc, window); ++ xf_rail_return_window(appWindow); ++ if (!appWindow) + return TRUE; + + /* Translate to desktop coordinates */ +@@ -687,6 +691,7 @@ static BOOL xf_event_FocusIn(xfContext* xfc, const XFocusInEvent* event, BOOL ap + */ + if (appWindow) + xf_rail_adjust_position(xfc, appWindow); ++ xf_rail_return_window(appWindow); + } + + xf_keyboard_focus_in(xfc); +@@ -741,12 +746,13 @@ static BOOL xf_event_ClientMessage(xfContext* xfc, const XClientMessageEvent* ev + { + if (app) + { ++ BOOL rc = TRUE; + xfAppWindow* appWindow = xf_AppWindowFromX11Window(xfc, event->window); + + if (appWindow) +- return xf_rail_send_client_system_command(xfc, appWindow->windowId, SC_CLOSE); +- +- return TRUE; ++ rc = xf_rail_send_client_system_command(xfc, appWindow->windowId, SC_CLOSE); ++ xf_rail_return_window(appWindow); ++ return rc; + } + else + { +@@ -779,6 +785,7 @@ static BOOL xf_event_EnterNotify(xfContext* xfc, const XEnterWindowEvent* event, + + /* keep track of which window has focus so that we can apply pointer updates */ + xfc->appWindow = appWindow; ++ xf_rail_return_window(appWindow); + } + + return TRUE; +@@ -800,6 +807,7 @@ static BOOL xf_event_LeaveNotify(xfContext* xfc, const XLeaveWindowEvent* event, + /* keep track of which window has focus so that we can apply pointer updates */ + if (xfc->appWindow == appWindow) + xfc->appWindow = NULL; ++ xf_rail_return_window(appWindow); + } + return TRUE; + } +@@ -905,6 +913,7 @@ static BOOL xf_event_ConfigureNotify(xfContext* xfc, const XConfigureEvent* even + xf_rail_adjust_position(xfc, appWindow); + } + } ++ xf_rail_return_window(appWindow); + } + return xf_pointer_update_scale(xfc); + } +@@ -928,6 +937,7 @@ static BOOL xf_event_MapNotify(xfContext* xfc, const XMapEvent* event, BOOL app) + // xf_rail_send_client_system_command(xfc, appWindow->windowId, SC_RESTORE); + appWindow->is_mapped = TRUE; + } ++ xf_rail_return_window(appWindow); + } + + return TRUE; +@@ -942,13 +952,14 @@ static BOOL xf_event_UnmapNotify(xfContext* xfc, const XUnmapEvent* event, BOOL + xf_keyboard_release_all_keypress(xfc); + + if (!app) +- gdi_send_suppress_output(xfc->common.context.gdi, TRUE); +- else ++ return gdi_send_suppress_output(xfc->common.context.gdi, TRUE); ++ + { + xfAppWindow* appWindow = xf_AppWindowFromX11Window(xfc, event->window); + + if (appWindow) + appWindow->is_mapped = FALSE; ++ xf_rail_return_window(appWindow); + } + + return TRUE; +@@ -956,6 +967,7 @@ static BOOL xf_event_UnmapNotify(xfContext* xfc, const XUnmapEvent* event, BOOL + + static BOOL xf_event_PropertyNotify(xfContext* xfc, const XPropertyEvent* event, BOOL app) + { ++ BOOL rc = TRUE; + WINPR_ASSERT(xfc); + WINPR_ASSERT(event); + +@@ -980,7 +992,7 @@ static BOOL xf_event_PropertyNotify(xfContext* xfc, const XPropertyEvent* event, + appWindow = xf_AppWindowFromX11Window(xfc, event->window); + + if (!appWindow) +- return TRUE; ++ goto fail; + } + + if (event->atom == xfc->NET_WM_STATE) +@@ -1052,8 +1064,7 @@ static BOOL xf_event_PropertyNotify(xfContext* xfc, const XPropertyEvent* event, + if (appWindow->rail_state != WINDOW_SHOW_MAXIMIZED) + { + appWindow->rail_state = WINDOW_SHOW_MAXIMIZED; +- return xf_rail_send_client_system_command(xfc, appWindow->windowId, +- SC_MAXIMIZE); ++ rc = xf_rail_send_client_system_command(xfc, appWindow->windowId, SC_MAXIMIZE); + } + } + else if (appWindow->minimized) +@@ -1061,8 +1072,7 @@ static BOOL xf_event_PropertyNotify(xfContext* xfc, const XPropertyEvent* event, + if (appWindow->rail_state != WINDOW_SHOW_MINIMIZED) + { + appWindow->rail_state = WINDOW_SHOW_MINIMIZED; +- return xf_rail_send_client_system_command(xfc, appWindow->windowId, +- SC_MINIMIZE); ++ rc = xf_rail_send_client_system_command(xfc, appWindow->windowId, SC_MINIMIZE); + } + } + else +@@ -1070,15 +1080,18 @@ static BOOL xf_event_PropertyNotify(xfContext* xfc, const XPropertyEvent* event, + if (appWindow->rail_state != WINDOW_SHOW && appWindow->rail_state != WINDOW_HIDE) + { + appWindow->rail_state = WINDOW_SHOW; +- return xf_rail_send_client_system_command(xfc, appWindow->windowId, SC_RESTORE); ++ rc = xf_rail_send_client_system_command(xfc, appWindow->windowId, SC_RESTORE); + } + } + } + else if (minimizedChanged) +- gdi_send_suppress_output(xfc->common.context.gdi, minimized); ++ rc = gdi_send_suppress_output(xfc->common.context.gdi, minimized); ++ ++ fail: ++ xf_rail_return_window(appWindow); + } + +- return TRUE; ++ return rc; + } + + static BOOL xf_event_suppress_events(xfContext* xfc, xfAppWindow* appWindow, const XEvent* event) +@@ -1194,7 +1207,9 @@ BOOL xf_event_process(freerdp* instance, const XEvent* event) + /* Update "current" window for cursor change orders */ + xfc->appWindow = appWindow; + +- if (xf_event_suppress_events(xfc, appWindow, event)) ++ const BOOL rc = xf_event_suppress_events(xfc, appWindow, event); ++ xf_rail_return_window(appWindow); ++ if (rc) + return TRUE; + } + } +diff --git a/client/X11/xf_graphics.c b/client/X11/xf_graphics.c +--- a/client/X11/xf_graphics.c ++++ b/client/X11/xf_graphics.c +@@ -252,12 +252,14 @@ static Window xf_Pointer_get_window(xfContext* xfc) + } + if (xfc->remote_app) + { ++ Window w = 0; ++ HashTable_Lock(xfc->railWindows); + if (!xfc->appWindow) +- { + WLog_WARN(TAG, "xf_Pointer: Invalid appWindow"); +- return 0; +- } +- return xfc->appWindow->handle; ++ else ++ w = xfc->appWindow->handle; ++ HashTable_Unlock(xfc->railWindows); ++ return w; + } + else + { +diff --git a/client/X11/xf_rail.c b/client/X11/xf_rail.c +--- a/client/X11/xf_rail.c ++++ b/client/X11/xf_rail.c +@@ -143,6 +143,7 @@ void xf_rail_send_activate(xfContext* xfc, Window xwindow, BOOL enabled) + activate.windowId = (UINT32)appWindow->windowId; + activate.enabled = enabled; + xfc->rail->ClientActivate(xfc->rail, &activate); ++ xf_rail_return_window(appWindow); + } + + BOOL xf_rail_send_client_system_command(xfContext* xfc, UINT64 windowId, UINT16 command) +@@ -300,6 +301,7 @@ BOOL xf_rail_paint_surface(xfContext* xfc, UINT64 windowId, const RECTANGLE_16* + updateRect.right - updateRect.left, updateRect.bottom - updateRect.top); + } + region16_uninit(&windowInvalidRegion); ++ xf_rail_return_window(appWindow); + return TRUE; + } + +@@ -794,6 +796,7 @@ static void xf_rail_set_window_icon(xfContext* xfc, xfAppWindow* railWindow, xfR + static BOOL xf_rail_window_icon(rdpContext* context, const WINDOW_ORDER_INFO* orderInfo, + const WINDOW_ICON_ORDER* windowIcon) + { ++ BOOL rc = FALSE; + xfContext* xfc = (xfContext*)context; + BOOL replaceIcon = 0; + xfAppWindow* railWindow = xf_rail_get_window(xfc, orderInfo->windowId); +@@ -811,23 +814,25 @@ static BOOL xf_rail_window_icon(rdpContext* context, const WINDOW_ORDER_INFO* or + { + WLog_WARN(TAG, "failed to get icon from cache %02X:%04X", windowIcon->iconInfo->cacheId, + windowIcon->iconInfo->cacheEntry); +- return FALSE; + } +- +- if (!convert_rail_icon(windowIcon->iconInfo, icon)) ++ else if (!convert_rail_icon(windowIcon->iconInfo, icon)) + { + WLog_WARN(TAG, "failed to convert icon for window %08X", orderInfo->windowId); +- return FALSE; + } +- +- replaceIcon = !!(orderInfo->fieldFlags & WINDOW_ORDER_STATE_NEW); +- xf_rail_set_window_icon(xfc, railWindow, icon, replaceIcon); +- return TRUE; ++ else ++ { ++ replaceIcon = !!(orderInfo->fieldFlags & WINDOW_ORDER_STATE_NEW); ++ xf_rail_set_window_icon(xfc, railWindow, icon, replaceIcon); ++ rc = TRUE; ++ } ++ xf_rail_return_window(railWindow); ++ return rc; + } + + static BOOL xf_rail_window_cached_icon(rdpContext* context, const WINDOW_ORDER_INFO* orderInfo, + const WINDOW_CACHED_ICON_ORDER* windowCachedIcon) + { ++ BOOL rc = FALSE; + xfContext* xfc = (xfContext*)context; + WINPR_ASSERT(orderInfo); + +@@ -847,12 +852,15 @@ static BOOL xf_rail_window_cached_icon(rdpContext* context, const WINDOW_ORDER_I + { + WLog_WARN(TAG, "failed to get icon from cache %02X:%04X", + windowCachedIcon->cachedIcon.cacheId, windowCachedIcon->cachedIcon.cacheEntry); +- return FALSE; + } +- +- replaceIcon = !!(orderInfo->fieldFlags & WINDOW_ORDER_STATE_NEW); +- xf_rail_set_window_icon(xfc, railWindow, icon, replaceIcon); +- return TRUE; ++ else ++ { ++ replaceIcon = !!(orderInfo->fieldFlags & WINDOW_ORDER_STATE_NEW); ++ xf_rail_set_window_icon(xfc, railWindow, icon, replaceIcon); ++ rc = TRUE; ++ } ++ xf_rail_return_window(railWindow); ++ return rc; + } + + static BOOL +@@ -1111,6 +1119,7 @@ static UINT xf_rail_server_local_move_size(RailClientContext* context, + else + xf_EndLocalMoveSize(xfc, appWindow); + ++ xf_rail_return_window(appWindow); + return CHANNEL_RC_OK; + } + +@@ -1135,6 +1144,7 @@ static UINT xf_rail_server_min_max_info(RailClientContext* context, + minMaxInfo->minTrackHeight, minMaxInfo->maxTrackWidth, + minMaxInfo->maxTrackHeight); + } ++ xf_rail_return_window(appWindow); + + return CHANNEL_RC_OK; + } +@@ -1308,7 +1318,20 @@ xfAppWindow* xf_rail_get_window(xfContext* xfc, UINT64 id) + return NULL; + + if (!xfc->railWindows) +- return FALSE; ++ return NULL; ++ ++ HashTable_Lock(xfc->railWindows); ++ xfAppWindow* window = HashTable_GetItemValue(xfc->railWindows, &id); ++ if (!window) ++ HashTable_Unlock(xfc->railWindows); ++ ++ return window; ++} ++ ++void xf_rail_return_window(xfAppWindow* window) ++{ ++ if (!window) ++ return; + +- return HashTable_GetItemValue(xfc->railWindows, &id); ++ HashTable_Unlock(window->xfc->railWindows); + } +diff --git a/client/X11/xf_rail.h b/client/X11/xf_rail.h +--- a/client/X11/xf_rail.h ++++ b/client/X11/xf_rail.h +@@ -37,6 +37,10 @@ void xf_rail_disable_remoteapp_mode(xfContext* xfc); + + xfAppWindow* xf_rail_add_window(xfContext* xfc, UINT64 id, INT32 x, INT32 y, UINT32 width, + UINT32 height, UINT32 surfaceId); ++ ++void xf_rail_return_window(xfAppWindow* window); ++ ++WINPR_ATTR_MALLOC(xf_rail_return_window, 1) + xfAppWindow* xf_rail_get_window(xfContext* xfc, UINT64 id); + + BOOL xf_rail_del_window(xfContext* xfc, UINT64 id); +diff --git a/client/X11/xf_window.c b/client/X11/xf_window.c +--- a/client/X11/xf_window.c ++++ b/client/X11/xf_window.c +@@ -1425,6 +1425,7 @@ xfAppWindow* xf_AppWindowFromX11Window(xfContext* xfc, Window wnd) + if (!xfc->railWindows) + return NULL; + ++ HashTable_Lock(xfc->railWindows); + size_t count = HashTable_GetKeys(xfc->railWindows, &pKeys); + + for (size_t index = 0; index < count; index++) +@@ -1433,17 +1434,20 @@ xfAppWindow* xf_AppWindowFromX11Window(xfContext* xfc, Window wnd) + + if (!appWindow) + { ++ HashTable_Unlock(xfc->railWindows); + free(pKeys); + return NULL; + } + + if (appWindow->handle == wnd) + { ++ HashTable_Unlock(xfc->railWindows); + free(pKeys); + return appWindow; + } + } + ++ HashTable_Unlock(xfc->railWindows); + free(pKeys); + return NULL; + } +@@ -1523,6 +1527,7 @@ UINT xf_AppUpdateWindowFromSurface(xfContext* xfc, gdiGfxSurface* surface) + + rc = CHANNEL_RC_OK; + fail: ++ xf_rail_return_window(appWindow); + XFlush(xfc->display); + xf_unlock_x11(xfc); + return rc; +@@ -1565,4 +1570,5 @@ void xf_XSetTransientForHint(xfContext* xfc, xfAppWindow* window) + WLog_WARN(TAG, "XSetTransientForHint [%d]{%s}", rc, + x11_error_to_string(xfc, rc, buffer, sizeof(buffer))); + } ++ xf_rail_return_window(parent); + } +diff --git a/client/X11/xf_window.h b/client/X11/xf_window.h +--- a/client/X11/xf_window.h ++++ b/client/X11/xf_window.h +@@ -202,6 +202,10 @@ void xf_SetWindowMinMaxInfo(xfContext* xfc, xfAppWindow* appWindow, int maxWidth + int maxTrackWidth, int maxTrackHeight); + void xf_StartLocalMoveSize(xfContext* xfc, xfAppWindow* appWindow, int direction, int x, int y); + void xf_EndLocalMoveSize(xfContext* xfc, xfAppWindow* appWindow); ++ ++void xf_rail_return_window(xfAppWindow* window); ++ ++WINPR_ATTR_MALLOC(xf_rail_return_window, 1) + xfAppWindow* xf_AppWindowFromX11Window(xfContext* xfc, Window wnd); + + const char* window_styles_to_string(UINT32 style, char* buffer, size_t length); +-- +2.47.3 + diff -Nru freerdp3-3.15.0+dfsg/debian/patches/client-x11-lock-cache-when-providing-data-CVE-2026-25959.patch freerdp3-3.15.0+dfsg/debian/patches/client-x11-lock-cache-when-providing-data-CVE-2026-25959.patch --- freerdp3-3.15.0+dfsg/debian/patches/client-x11-lock-cache-when-providing-data-CVE-2026-25959.patch 1970-01-01 00:00:00.000000000 +0000 +++ freerdp3-3.15.0+dfsg/debian/patches/client-x11-lock-cache-when-providing-data-CVE-2026-25959.patch 2026-02-25 20:34:19.000000000 +0000 @@ -0,0 +1,43 @@ +From: Armin Novak +Date: Mon, 9 Feb 2026 17:52:37 +0100 +Subject: [client,x11] lock cache when providing data +Origin: upstream, https://github.com/FreeRDP/FreeRDP/commit/d3e8b3b9365be96a4f11dda149d71b3287227d0a +Forwarded: not-needed +Bug: https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-78xg-v4p2-4w3c +Bug: https://security-tracker.debian.org/tracker/CVE-2026-25959 + +--- + client/X11/xf_cliprdr.c | 13 +++++++++---- + 1 file changed, 9 insertions(+), 4 deletions(-) + +--- a/client/X11/xf_cliprdr.c ++++ b/client/X11/xf_cliprdr.c +@@ -1570,12 +1570,16 @@ static BOOL xf_cliprdr_process_selection + DEBUG_CLIPRDR("formatId: 0x%08" PRIx32 ", dstFormatId: 0x%08" PRIx32 "", formatId, + dstFormatId); + ++ wHashTable* table = clipboard->cachedData; ++ if (rawTransfer) ++ table = clipboard->cachedRawData; ++ ++ HashTable_Lock(table); ++ + if (!rawTransfer) +- cached_data = HashTable_GetItemValue(clipboard->cachedData, +- format_to_cache_slot(dstFormatId)); ++ cached_data = HashTable_GetItemValue(table, format_to_cache_slot(dstFormatId)); + else +- cached_data = HashTable_GetItemValue(clipboard->cachedRawData, +- format_to_cache_slot(formatId)); ++ cached_data = HashTable_GetItemValue(table, format_to_cache_slot(formatId)); + + DEBUG_CLIPRDR("hasCachedData: %u, rawTransfer: %u", cached_data ? 1 : 0, rawTransfer); + +@@ -1629,6 +1633,7 @@ static BOOL xf_cliprdr_process_selection + delayRespond = TRUE; + xf_cliprdr_send_data_request(clipboard, formatId, cformat); + } ++ HashTable_Unlock(table); + } + } + diff -Nru freerdp3-3.15.0+dfsg/debian/patches/client-x11-stringfiy-functions-for-RAILS-CVE-2026-25942.patch freerdp3-3.15.0+dfsg/debian/patches/client-x11-stringfiy-functions-for-RAILS-CVE-2026-25942.patch --- freerdp3-3.15.0+dfsg/debian/patches/client-x11-stringfiy-functions-for-RAILS-CVE-2026-25942.patch 1970-01-01 00:00:00.000000000 +0000 +++ freerdp3-3.15.0+dfsg/debian/patches/client-x11-stringfiy-functions-for-RAILS-CVE-2026-25942.patch 2026-02-25 20:34:19.000000000 +0000 @@ -0,0 +1,103 @@ +From: Armin Novak +Date: Mon, 9 Feb 2026 13:39:28 +0100 +Subject: [client,x11] stringfiy functions for RAILS +Origin: upstream, https://github.com/FreeRDP/FreeRDP/commit/9362a0bf8dda04eedbca07d5dfaec1044e67cc6b +Forwarded: not-needed +Bug: https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-78q6-67m7-wwf6 +Bug: https://security-tracker.debian.org/tracker/CVE-2026-25942 + +--- + client/X11/xf_rail.c | 68 ++++++++++++++++++++++++++++++++------------ + 1 file changed, 50 insertions(+), 18 deletions(-) + +--- a/client/X11/xf_rail.c ++++ b/client/X11/xf_rail.c +@@ -37,22 +37,51 @@ + #include + #define TAG CLIENT_TAG("x11") + +-static const char* error_code_names[] = { "RAIL_EXEC_S_OK", +- "RAIL_EXEC_E_HOOK_NOT_LOADED", +- "RAIL_EXEC_E_DECODE_FAILED", +- "RAIL_EXEC_E_NOT_IN_ALLOWLIST", +- "RAIL_EXEC_E_FILE_NOT_FOUND", +- "RAIL_EXEC_E_FAIL", +- "RAIL_EXEC_E_SESSION_LOCKED" }; +- +-#ifdef WITH_DEBUG_RAIL +-static const char* movetype_names[] = { +- "(invalid)", "RAIL_WMSZ_LEFT", "RAIL_WMSZ_RIGHT", +- "RAIL_WMSZ_TOP", "RAIL_WMSZ_TOPLEFT", "RAIL_WMSZ_TOPRIGHT", +- "RAIL_WMSZ_BOTTOM", "RAIL_WMSZ_BOTTOMLEFT", "RAIL_WMSZ_BOTTOMRIGHT", +- "RAIL_WMSZ_MOVE", "RAIL_WMSZ_KEYMOVE", "RAIL_WMSZ_KEYSIZE" +-}; +-#endif ++static const char* error_code2str(UINT32 code) ++{ ++#define EVCASE(x) \ ++ case x: \ ++ return #x ++ switch (code) ++ { ++ EVCASE(RAIL_EXEC_S_OK); ++ EVCASE(RAIL_EXEC_E_HOOK_NOT_LOADED); ++ EVCASE(RAIL_EXEC_E_DECODE_FAILED); ++ EVCASE(RAIL_EXEC_E_NOT_IN_ALLOWLIST); ++ EVCASE(RAIL_EXEC_E_FILE_NOT_FOUND); ++ EVCASE(RAIL_EXEC_E_FAIL); ++ EVCASE(RAIL_EXEC_E_SESSION_LOCKED); ++ default: ++ return "RAIL_EXEC_E_UNKNOWN"; ++ } ++#undef EVCASE ++} ++ ++static const char* movetype2str(UINT32 code) ++{ ++#define EVCASE(x) \ ++ case x: \ ++ return #x ++ ++ switch (code) ++ { ++ ++ EVCASE(RAIL_WMSZ_LEFT); ++ EVCASE(RAIL_WMSZ_RIGHT); ++ EVCASE(RAIL_WMSZ_TOP); ++ EVCASE(RAIL_WMSZ_TOPLEFT); ++ EVCASE(RAIL_WMSZ_TOPRIGHT); ++ EVCASE(RAIL_WMSZ_BOTTOM); ++ EVCASE(RAIL_WMSZ_BOTTOMLEFT); ++ EVCASE(RAIL_WMSZ_BOTTOMRIGHT); ++ EVCASE(RAIL_WMSZ_MOVE); ++ EVCASE(RAIL_WMSZ_KEYMOVE); ++ EVCASE(RAIL_WMSZ_KEYSIZE); ++ default: ++ return "RAIL_WMSZ_INVALID"; ++ } ++#undef EVCASE ++} + + struct xf_rail_icon + { +@@ -928,8 +957,9 @@ static UINT xf_rail_server_execute_resul + + if (execResult->execResult != RAIL_EXEC_S_OK) + { +- WLog_ERR(TAG, "RAIL exec error: execResult=%s NtError=0x%X\n", +- error_code_names[execResult->execResult], execResult->rawResult); ++ WLog_ERR(TAG, "RAIL exec error: execResult=%s [0x%08" PRIx32 "] NtError=0x%X\n", ++ error_code2str(execResult->execResult), execResult->execResult, ++ execResult->rawResult); + freerdp_abort_connect_context(&xfc->common.context); + } + else +@@ -997,6 +1027,8 @@ static UINT xf_rail_server_local_move_si + if (!appWindow) + return ERROR_INTERNAL_ERROR; + ++ WLog_Print(xfc->log, WLOG_TRACE, "%s [0x%08" PRIx32 "]", ++ movetype2str(localMoveSize->moveSizeType), localMoveSize->moveSizeType); + switch (localMoveSize->moveSizeType) + { + case RAIL_WMSZ_LEFT: diff -Nru freerdp3-3.15.0+dfsg/debian/patches/codec-clear-fix-clear_resize_buffer-checks-CVE-2026-23533.patch freerdp3-3.15.0+dfsg/debian/patches/codec-clear-fix-clear_resize_buffer-checks-CVE-2026-23533.patch --- freerdp3-3.15.0+dfsg/debian/patches/codec-clear-fix-clear_resize_buffer-checks-CVE-2026-23533.patch 1970-01-01 00:00:00.000000000 +0000 +++ freerdp3-3.15.0+dfsg/debian/patches/codec-clear-fix-clear_resize_buffer-checks-CVE-2026-23533.patch 2026-02-09 18:48:59.000000000 +0000 @@ -0,0 +1,60 @@ +From: akallabeth +Date: Thu, 15 Jan 2026 12:11:57 +0100 +Subject: [codec,clear] fix clear_resize_buffer checks +Origin: upstream, https://github.com/FreeRDP/FreeRDP/commit/c4391827d7facfc874ca7f61a92afb82232a5748 +Forwarded: not-needed +Bug: https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-32q9-m5qr-9j2v +Bug: https://security-tracker.debian.org/tracker/CVE-2026-23533 + +--- + libfreerdp/codec/clear.c | 15 ++++++++------- + 1 file changed, 8 insertions(+), 7 deletions(-) + +diff --git a/libfreerdp/codec/clear.c b/libfreerdp/codec/clear.c +index ad5752909..aa36baa9b 100644 +--- a/libfreerdp/codec/clear.c ++++ b/libfreerdp/codec/clear.c +@@ -58,7 +58,7 @@ struct S_CLEAR_CONTEXT + NSC_CONTEXT* nsc; + UINT32 seqNumber; + BYTE* TempBuffer; +- UINT32 TempSize; ++ size_t TempSize; + UINT32 nTempStep; + UINT32 TempFormat; + UINT32 format; +@@ -328,16 +328,17 @@ static BOOL clear_decompress_subcode_rlex(wStream* WINPR_RESTRICT s, UINT32 bitm + + static BOOL clear_resize_buffer(CLEAR_CONTEXT* WINPR_RESTRICT clear, UINT32 width, UINT32 height) + { +- UINT32 size = 0; +- + if (!clear) + return FALSE; + +- size = ((width + 16) * (height + 16) * FreeRDPGetBytesPerPixel(clear->format)); ++ const UINT64 size = 1ull * (width + 16ull) * (height + 16ull); ++ const size_t bpp = FreeRDPGetBytesPerPixel(clear->format); ++ if (size > UINT32_MAX / bpp) ++ return FALSE; + +- if (size > clear->TempSize) ++ if (size > clear->TempSize / bpp) + { +- BYTE* tmp = (BYTE*)winpr_aligned_recalloc(clear->TempBuffer, size, sizeof(BYTE), 32); ++ BYTE* tmp = (BYTE*)winpr_aligned_recalloc(clear->TempBuffer, size, bpp, 32); + + if (!tmp) + { +@@ -346,7 +347,7 @@ static BOOL clear_resize_buffer(CLEAR_CONTEXT* WINPR_RESTRICT clear, UINT32 widt + return FALSE; + } + +- clear->TempSize = size; ++ clear->TempSize = size * bpp; + clear->TempBuffer = tmp; + } + +-- +2.47.3 + diff -Nru freerdp3-3.15.0+dfsg/debian/patches/codec-clear-fix-destination-checks-CVE-2026-26955.patch freerdp3-3.15.0+dfsg/debian/patches/codec-clear-fix-destination-checks-CVE-2026-26955.patch --- freerdp3-3.15.0+dfsg/debian/patches/codec-clear-fix-destination-checks-CVE-2026-26955.patch 1970-01-01 00:00:00.000000000 +0000 +++ freerdp3-3.15.0+dfsg/debian/patches/codec-clear-fix-destination-checks-CVE-2026-26955.patch 2026-02-25 20:34:19.000000000 +0000 @@ -0,0 +1,42 @@ +From: Armin Novak +Date: Mon, 16 Feb 2026 19:56:55 +0100 +Subject: [codec,clear] fix destination checks +Origin: upstream, https://github.com/FreeRDP/FreeRDP/commit/7d8fdce2d0ef337cb86cb37fc0c436c905e04d77 +Forwarded: not-needed +Bug: https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-mr6w-ch7c-mqqj +Bug: https://security-tracker.debian.org/tracker/CVE-2026-26955 + +check against the correct nDstWidth/nDstHeight +--- + libfreerdp/codec/clear.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +diff --git a/libfreerdp/codec/clear.c b/libfreerdp/codec/clear.c +--- a/libfreerdp/codec/clear.c ++++ b/libfreerdp/codec/clear.c +@@ -478,16 +478,16 @@ static BOOL clear_decompress_subcodecs_data(CLEAR_CONTEXT* WINPR_RESTRICT clear, + + const UINT32 nXDstRel = nXDst + xStart; + const UINT32 nYDstRel = nYDst + yStart; +- if (1ull * nXDstRel + width > nWidth) ++ if (1ull * nXDstRel + width > nDstWidth) + { +- WLog_ERR(TAG, "nXDstRel %" PRIu16 " + width %" PRIu16 " > nWidth %" PRIu32 "", xStart, +- width, nWidth); ++ WLog_ERR(TAG, "nXDstRel %" PRIu32 " + width %" PRIu16 " > nDstWidth %" PRIu32 "", ++ nXDstRel, width, nDstWidth); + return FALSE; + } +- if (1ull * nYDstRel + height > nHeight) ++ if (1ull * nYDstRel + height > nDstHeight) + { +- WLog_ERR(TAG, "nYDstRel %" PRIu16 " + height %" PRIu16 " > nHeight %" PRIu32 "", yStart, +- height, nHeight); ++ WLog_ERR(TAG, "nYDstRel %" PRIu32 " + height %" PRIu16 " > nDstHeight %" PRIu32 "", ++ nYDstRel, height, nDstHeight); + return FALSE; + } + +-- +2.47.3 + diff -Nru freerdp3-3.15.0+dfsg/debian/patches/codec-clear-fix-missing-destination-boundary-checks-CVE-2026-26955.patch freerdp3-3.15.0+dfsg/debian/patches/codec-clear-fix-missing-destination-boundary-checks-CVE-2026-26955.patch --- freerdp3-3.15.0+dfsg/debian/patches/codec-clear-fix-missing-destination-boundary-checks-CVE-2026-26955.patch 1970-01-01 00:00:00.000000000 +0000 +++ freerdp3-3.15.0+dfsg/debian/patches/codec-clear-fix-missing-destination-boundary-checks-CVE-2026-26955.patch 2026-02-25 20:34:19.000000000 +0000 @@ -0,0 +1,98 @@ +From: Armin Novak +Date: Sun, 15 Feb 2026 19:19:07 +0100 +Subject: [codec,clear] fix missing destination boundary checks +Origin: upstream, https://github.com/FreeRDP/FreeRDP/commit/0746639629cc0eb1eb61e880c626c8db393665cf +Forwarded: not-needed +Bug: https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-mr6w-ch7c-mqqj +Bug: https://security-tracker.debian.org/tracker/CVE-2026-26955 + +--- + libfreerdp/codec/clear.c | 51 +++++++++++++++++++++++++--------------- + 1 file changed, 32 insertions(+), 19 deletions(-) + +diff --git a/libfreerdp/codec/clear.c b/libfreerdp/codec/clear.c +--- a/libfreerdp/codec/clear.c ++++ b/libfreerdp/codec/clear.c +@@ -455,40 +455,41 @@ static BOOL clear_decompress_subcodecs_data(CLEAR_CONTEXT* WINPR_RESTRICT clear, + UINT32 nDstWidth, UINT32 nDstHeight, + const gdiPalette* WINPR_RESTRICT palette) + { +- UINT16 xStart = 0; +- UINT16 yStart = 0; +- UINT16 width = 0; +- UINT16 height = 0; +- UINT32 bitmapDataByteCount = 0; +- BYTE subcodecId = 0; + UINT32 suboffset = 0; + + if (!Stream_CheckAndLogRequiredLength(TAG, s, subcodecByteCount)) + return FALSE; + +- suboffset = 0; +- + while (suboffset < subcodecByteCount) + { +- UINT32 nXDstRel = 0; +- UINT32 nYDstRel = 0; +- + if (!Stream_CheckAndLogRequiredLength(TAG, s, 13)) + return FALSE; + +- Stream_Read_UINT16(s, xStart); +- Stream_Read_UINT16(s, yStart); +- Stream_Read_UINT16(s, width); +- Stream_Read_UINT16(s, height); +- Stream_Read_UINT32(s, bitmapDataByteCount); +- Stream_Read_UINT8(s, subcodecId); ++ const UINT16 xStart = Stream_Get_UINT16(s); ++ const UINT16 yStart = Stream_Get_UINT16(s); ++ const UINT16 width = Stream_Get_UINT16(s); ++ const UINT16 height = Stream_Get_UINT16(s); ++ const UINT32 bitmapDataByteCount = Stream_Get_UINT32(s); ++ const UINT8 subcodecId = Stream_Get_UINT8(s); + suboffset += 13; + + if (!Stream_CheckAndLogRequiredLength(TAG, s, bitmapDataByteCount)) + return FALSE; + +- nXDstRel = nXDst + xStart; +- nYDstRel = nYDst + yStart; ++ const UINT32 nXDstRel = nXDst + xStart; ++ const UINT32 nYDstRel = nYDst + yStart; ++ if (1ull * nXDstRel + width > nWidth) ++ { ++ WLog_ERR(TAG, "nXDstRel %" PRIu16 " + width %" PRIu16 " > nWidth %" PRIu32 "", xStart, ++ width, nWidth); ++ return FALSE; ++ } ++ if (1ull * nYDstRel + height > nHeight) ++ { ++ WLog_ERR(TAG, "nYDstRel %" PRIu16 " + height %" PRIu16 " > nHeight %" PRIu32 "", yStart, ++ height, nHeight); ++ return FALSE; ++ } + + if (1ull * xStart + width > nWidth) + { +@@ -1045,6 +1046,18 @@ INT32 clear_decompress(CLEAR_CONTEXT* WINPR_RESTRICT clear, const BYTE* WINPR_RE + if ((nWidth > 0xFFFF) || (nHeight > 0xFFFF)) + return -1004; + ++ if (nXDst > nDstWidth) ++ { ++ WLog_WARN(TAG, "nXDst %" PRIu32 " > nDstWidth %" PRIu32, nXDst, nDstWidth); ++ return -1005; ++ } ++ ++ if (nYDst > nDstHeight) ++ { ++ WLog_WARN(TAG, "nYDst %" PRIu32 " > nDstHeight %" PRIu32, nYDst, nDstHeight); ++ return -1006; ++ } ++ + s = Stream_StaticConstInit(&sbuffer, pSrcData, SrcSize); + + if (!s) +-- +2.47.3 + diff -Nru freerdp3-3.15.0+dfsg/debian/patches/codec-clear-fix-missing-length-checks-CVE-2026-23531.patch freerdp3-3.15.0+dfsg/debian/patches/codec-clear-fix-missing-length-checks-CVE-2026-23531.patch --- freerdp3-3.15.0+dfsg/debian/patches/codec-clear-fix-missing-length-checks-CVE-2026-23531.patch 1970-01-01 00:00:00.000000000 +0000 +++ freerdp3-3.15.0+dfsg/debian/patches/codec-clear-fix-missing-length-checks-CVE-2026-23531.patch 2026-02-09 18:48:59.000000000 +0000 @@ -0,0 +1,32 @@ +From: akallabeth +Date: Thu, 15 Jan 2026 12:17:33 +0100 +Subject: [codec,clear] fix missing length checks +Origin: upstream, https://github.com/FreeRDP/FreeRDP/commit/25102b432fb37916a1a553d7ef8fd940c6e52c3f +Forwarded: not-needed +Bug: https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-xj5h-9cr5-23c5 +Bug: https://security-tracker.debian.org/tracker/CVE-2026-23531 + +--- + libfreerdp/codec/clear.c | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/libfreerdp/codec/clear.c b/libfreerdp/codec/clear.c +index aa36baa9b..4a67a8ed6 100644 +--- a/libfreerdp/codec/clear.c ++++ b/libfreerdp/codec/clear.c +@@ -1139,8 +1139,10 @@ INT32 clear_decompress(CLEAR_CONTEXT* WINPR_RESTRICT clear, const BYTE* WINPR_RE + + if (glyphData) + { +- if (!freerdp_image_copy_no_overlap(glyphData, clear->format, 0, 0, 0, nWidth, nHeight, +- pDstData, DstFormat, nDstStep, nXDst, nYDst, palette, ++ const uint32_t w = MIN(nWidth, nDstWidth); ++ const uint32_t h = MIN(nHeight, nDstHeight); ++ if (!freerdp_image_copy_no_overlap(glyphData, clear->format, 0, 0, 0, w, h, pDstData, ++ DstFormat, nDstStep, nXDst, nYDst, palette, + FREERDP_KEEP_DST_ALPHA)) + goto fail; + } +-- +2.47.3 + diff -Nru freerdp3-3.15.0+dfsg/debian/patches/codec-clear-fix-off-by-one-length-check-CVE-2026-23534.patch freerdp3-3.15.0+dfsg/debian/patches/codec-clear-fix-off-by-one-length-check-CVE-2026-23534.patch --- freerdp3-3.15.0+dfsg/debian/patches/codec-clear-fix-off-by-one-length-check-CVE-2026-23534.patch 1970-01-01 00:00:00.000000000 +0000 +++ freerdp3-3.15.0+dfsg/debian/patches/codec-clear-fix-off-by-one-length-check-CVE-2026-23534.patch 2026-02-09 18:48:59.000000000 +0000 @@ -0,0 +1,34 @@ +From: akallabeth +Date: Thu, 15 Jan 2026 12:19:53 +0100 +Subject: [codec,clear] fix off by one length check +Origin: upstream, https://github.com/FreeRDP/FreeRDP/commit/f8688b57f6cfad9a0b05475a6afbde355ffab720 +Forwarded: not-needed +Bug: https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-3frr-mp8w-4599 +Bug: https://security-tracker.debian.org/tracker/CVE-2026-23534 + +--- + libfreerdp/codec/clear.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/libfreerdp/codec/clear.c b/libfreerdp/codec/clear.c +index 4a67a8ed6..0efa89f8d 100644 +--- a/libfreerdp/codec/clear.c ++++ b/libfreerdp/codec/clear.c +@@ -876,12 +876,12 @@ static BOOL clear_decompress_bands_data(CLEAR_CONTEXT* WINPR_RESTRICT clear, + if (count > nHeight) + count = nHeight; + +- if (nXDstRel + i > nDstWidth) ++ if (nXDstRel + i >= nDstWidth) + return FALSE; + + for (UINT32 y = 0; y < count; y++) + { +- if (nYDstRel + y > nDstHeight) ++ if (nYDstRel + y >= nDstHeight) + return FALSE; + + BYTE* pDstPixel8 = +-- +2.47.3 + diff -Nru freerdp3-3.15.0+dfsg/debian/patches/codec-color-add-freerdp_glyph_convert_ex-CVE-2026-23732.patch freerdp3-3.15.0+dfsg/debian/patches/codec-color-add-freerdp_glyph_convert_ex-CVE-2026-23732.patch --- freerdp3-3.15.0+dfsg/debian/patches/codec-color-add-freerdp_glyph_convert_ex-CVE-2026-23732.patch 1970-01-01 00:00:00.000000000 +0000 +++ freerdp3-3.15.0+dfsg/debian/patches/codec-color-add-freerdp_glyph_convert_ex-CVE-2026-23732.patch 2026-02-09 18:48:59.000000000 +0000 @@ -0,0 +1,99 @@ +From: akallabeth +Date: Fri, 16 Jan 2026 12:00:15 +0100 +Subject: [codec,color] add freerdp_glyph_convert_ex +Origin: upstream, https://github.com/FreeRDP/FreeRDP/commit/3bc1eeb4f63ceec9a696af194e4c1ea0e67ff60c +Forwarded: not-needed +Bug: https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-7qxp-j2fj-c3pp +Bug: https://security-tracker.debian.org/tracker/CVE-2026-23732 + +The function freerdp_glyph_convert does not check input buffer length, +deprecate it and provide a replacement that does properly check. +--- + include/freerdp/codec/color.h | 23 +++++++++++++++++++++-- + libfreerdp/codec/color.c | 21 ++++++++++++++++++++- + 2 files changed, 41 insertions(+), 3 deletions(-) + +diff --git a/include/freerdp/codec/color.h b/include/freerdp/codec/color.h +index 79200bee1..c7e6cca3f 100644 +--- a/include/freerdp/codec/color.h ++++ b/include/freerdp/codec/color.h +@@ -288,6 +288,7 @@ typedef struct gdi_palette gdiPalette; + return (FreeRDPGetBitsPerPixel(format) + 7) / 8; + } + ++#if !defined(WITHOUT_FREERDP_3x_DEPRECATED) + /*** + * + * @param width width to copy in pixels +@@ -297,9 +298,27 @@ typedef struct gdi_palette gdiPalette; + * @return A buffer allocated with winpr_aligned_malloc(width * height, 16) + * if successful, NULL otherwise. + */ ++ ++ WINPR_DEPRECATED_VAR("[since 3.21.0] use freerdp_glyph_convert_ex instead", ++ WINPR_ATTR_MALLOC(winpr_aligned_free, 1) ++ FREERDP_API BYTE* freerdp_glyph_convert( ++ UINT32 width, UINT32 height, const BYTE* WINPR_RESTRICT data)); ++#endif ++ ++ /*** ++ * ++ * @param width width to copy in pixels ++ * @param height height to copy in pixels ++ * @param data source buffer, must be (nWidth + 7) / 8 bytes long ++ * @param len the length of \ref data in bytes ++ * ++ * @return A buffer allocated with winpr_aligned_malloc(width * height, 16) ++ * if successful, NULL otherwise. ++ * @since version 3.21.0 ++ */ + WINPR_ATTR_MALLOC(winpr_aligned_free, 1) +- FREERDP_API BYTE* freerdp_glyph_convert(UINT32 width, UINT32 height, +- const BYTE* WINPR_RESTRICT data); ++ FREERDP_API BYTE* freerdp_glyph_convert_ex(UINT32 width, UINT32 height, ++ const BYTE* WINPR_RESTRICT data, size_t len); + + /*** + * +diff --git a/libfreerdp/codec/color.c b/libfreerdp/codec/color.c +index 2dd33ebc0..2659c92e6 100644 +--- a/libfreerdp/codec/color.c ++++ b/libfreerdp/codec/color.c +@@ -242,14 +242,33 @@ fail: + } + #endif + ++#if !defined(WITHOUT_FREERDP_3x_DEPRECATED) + BYTE* freerdp_glyph_convert(UINT32 width, UINT32 height, const BYTE* WINPR_RESTRICT data) ++{ ++ const size_t scanline = (width + 7ull) / 8ull; ++ const size_t required = scanline * height; ++ return freerdp_glyph_convert_ex(width, height, data, required); ++} ++#endif ++ ++BYTE* freerdp_glyph_convert_ex(UINT32 width, UINT32 height, const BYTE* WINPR_RESTRICT data, ++ size_t len) + { + /* + * converts a 1-bit-per-pixel glyph to a one-byte-per-pixel glyph: + * this approach uses a little more memory, but provides faster + * means of accessing individual pixels in blitting operations + */ +- const UINT32 scanline = (width + 7) / 8; ++ const size_t scanline = (width + 7ull) / 8ull; ++ const size_t required = scanline * height; ++ if (len < required) ++ return NULL; ++ ++ if ((len == 0) || (width == 0) || (height == 0)) ++ return NULL; ++ ++ WINPR_ASSERT(data); ++ + BYTE* dstData = (BYTE*)winpr_aligned_malloc(1ull * width * height, 16); + + if (!dstData) +-- +2.47.3 + diff -Nru freerdp3-3.15.0+dfsg/debian/patches/codec-color-fix-input-length-checks-CVE-2026-26271.patch freerdp3-3.15.0+dfsg/debian/patches/codec-color-fix-input-length-checks-CVE-2026-26271.patch --- freerdp3-3.15.0+dfsg/debian/patches/codec-color-fix-input-length-checks-CVE-2026-26271.patch 1970-01-01 00:00:00.000000000 +0000 +++ freerdp3-3.15.0+dfsg/debian/patches/codec-color-fix-input-length-checks-CVE-2026-26271.patch 2026-02-25 20:34:19.000000000 +0000 @@ -0,0 +1,95 @@ +From: Armin Novak +Date: Fri, 13 Feb 2026 19:38:20 +0100 +Subject: [codec,color] fix input length checks +Origin: upstream, https://github.com/FreeRDP/FreeRDP/commit/f5e20403d6e325e11b68129803f967fb5aeec1cb +Forwarded: not-needed +Bug: https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-hr4m-ph4g-48j6 +Bug: https://security-tracker.debian.org/tracker/CVE-2026-26271 + +* check cbBitsMask meets expected length +* Add logging for length failures +--- + libfreerdp/codec/color.c | 36 ++++++++++++++++++++++++------------ + 1 file changed, 24 insertions(+), 12 deletions(-) + +diff --git a/libfreerdp/codec/color.c b/libfreerdp/codec/color.c +--- a/libfreerdp/codec/color.c ++++ b/libfreerdp/codec/color.c +@@ -404,6 +404,9 @@ BOOL freerdp_image_copy_from_icon_data(BYTE* WINPR_RESTRICT pDstData, UINT32 Dst + if (!pDstData || !bitsColor) + return FALSE; + ++ if ((nWidth == 0) || (nHeight == 0)) ++ return TRUE; ++ + /* + * Color formats used by icons are DIB bitmap formats (2-bit format + * is not used by MS-RDPERP). Note that 16-bit is RGB555, not RGB565, +@@ -446,7 +449,13 @@ BOOL freerdp_image_copy_from_icon_data(BYTE* WINPR_RESTRICT pDstData, UINT32 Dst + + /* Ensure we have enough source data bytes for image copy. */ + if (cbBitsColor < nWidth * nHeight * FreeRDPGetBytesPerPixel(format)) ++ { ++ WLog_ERR(TAG, ++ "cbBitsColor{%" PRIu32 "} < nWidth{%" PRIu32 "} * nHeight{%" PRIu32 ++ "} * bpp{%" PRIu32 "}", ++ cbBitsColor, nWidth, nHeight, FreeRDPGetBytesPerPixel(format)); + return FALSE; ++ } + + fill_gdi_palette_for_icon(colorTable, cbColorTable, &palette); + if (!freerdp_image_copy_no_overlap(pDstData, DstFormat, nDstStep, nXDst, nYDst, nWidth, nHeight, +@@ -454,14 +463,8 @@ BOOL freerdp_image_copy_from_icon_data(BYTE* WINPR_RESTRICT pDstData, UINT32 Dst + return FALSE; + + /* apply alpha mask */ +- if (FreeRDPColorHasAlpha(DstFormat) && cbBitsMask) ++ if (FreeRDPColorHasAlpha(DstFormat) && (cbBitsMask > 0)) + { +- BYTE nextBit = 0; +- const BYTE* maskByte = NULL; +- UINT32 stride = 0; +- BYTE r = 0; +- BYTE g = 0; +- BYTE b = 0; + BYTE* dstBuf = pDstData; + UINT32 dstBpp = FreeRDPGetBytesPerPixel(DstFormat); + +@@ -470,20 +473,29 @@ BOOL freerdp_image_copy_from_icon_data(BYTE* WINPR_RESTRICT pDstData, UINT32 Dst + * And due to hysterical raisins, stride of DIB bitmaps must be + * a multiple of 4 bytes. + */ +- stride = round_up(div_ceil(nWidth, 8), 4); ++ const size_t stride = round_up(div_ceil(nWidth, 8), 4); ++ if (cbBitsMask < stride * (nHeight - 1ULL)) ++ { ++ WLog_ERR(TAG, ++ "cbBitsMask{%" PRIu32 "} < stride{%" PRIuz "} * (nHeight{%" PRIu32 "} - 1)", ++ cbBitsMask, stride, nHeight); ++ return FALSE; ++ } + + for (UINT32 y = 0; y < nHeight; y++) + { +- maskByte = &bitsMask[1ULL * stride * (nHeight - 1 - y)]; +- nextBit = 0x80; ++ const BYTE* maskByte = &bitsMask[stride * (nHeight - 1ULL - y)]; ++ BYTE nextBit = 0x80; + + for (UINT32 x = 0; x < nWidth; x++) + { +- UINT32 color = 0; ++ BYTE r = 0; ++ BYTE g = 0; ++ BYTE b = 0; + BYTE alpha = (*maskByte & nextBit) ? 0x00 : 0xFF; + + /* read color back, add alpha and write it back */ +- color = FreeRDPReadColor_int(dstBuf, DstFormat); ++ UINT32 color = FreeRDPReadColor_int(dstBuf, DstFormat); + FreeRDPSplitColor(color, DstFormat, &r, &g, &b, NULL, &palette); + color = FreeRDPGetColor(DstFormat, r, g, b, alpha); + FreeRDPWriteColor_int(dstBuf, DstFormat, color); +-- +2.47.3 + diff -Nru freerdp3-3.15.0+dfsg/debian/patches/codec-planar-fix-decoder-length-checks-CVE-2026-23530.patch freerdp3-3.15.0+dfsg/debian/patches/codec-planar-fix-decoder-length-checks-CVE-2026-23530.patch --- freerdp3-3.15.0+dfsg/debian/patches/codec-planar-fix-decoder-length-checks-CVE-2026-23530.patch 1970-01-01 00:00:00.000000000 +0000 +++ freerdp3-3.15.0+dfsg/debian/patches/codec-planar-fix-decoder-length-checks-CVE-2026-23530.patch 2026-02-09 18:48:59.000000000 +0000 @@ -0,0 +1,31 @@ +From: akallabeth +Date: Thu, 15 Jan 2026 12:02:02 +0100 +Subject: [codec,planar] fix decoder length checks +Origin: upstream, https://github.com/FreeRDP/FreeRDP/commit/1bab198a2edd0d0e6e1627d21a433151ea190500 +Forwarded: not-needed +Bug: https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-r4hv-852m-fq7p +Bug: https://security-tracker.debian.org/tracker/CVE-2026-23530 + +--- + libfreerdp/codec/planar.c | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/libfreerdp/codec/planar.c b/libfreerdp/codec/planar.c +index 1a06e36ed..94a640a55 100644 +--- a/libfreerdp/codec/planar.c ++++ b/libfreerdp/codec/planar.c +@@ -727,6 +727,11 @@ BOOL freerdp_bitmap_decompress_planar(BITMAP_PLANAR_CONTEXT* WINPR_RESTRICT plan + WINPR_ASSERT(planar); + WINPR_ASSERT(prims); + ++ if (planar->maxWidth < nSrcWidth) ++ return FALSE; ++ if (planar->maxHeight < nSrcHeight) ++ return FALSE; ++ + if (nDstStep <= 0) + nDstStep = nDstWidth * FreeRDPGetBytesPerPixel(DstFormat); + +-- +2.47.3 + diff -Nru freerdp3-3.15.0+dfsg/debian/patches/codec-planar-fix-missing-destination-bounds-checks-CVE-2026-26965.patch freerdp3-3.15.0+dfsg/debian/patches/codec-planar-fix-missing-destination-bounds-checks-CVE-2026-26965.patch --- freerdp3-3.15.0+dfsg/debian/patches/codec-planar-fix-missing-destination-bounds-checks-CVE-2026-26965.patch 1970-01-01 00:00:00.000000000 +0000 +++ freerdp3-3.15.0+dfsg/debian/patches/codec-planar-fix-missing-destination-bounds-checks-CVE-2026-26965.patch 2026-02-25 20:34:19.000000000 +0000 @@ -0,0 +1,54 @@ +From: Armin Novak +Date: Mon, 16 Feb 2026 09:45:58 +0100 +Subject: [codec,planar] fix missing destination bounds checks +Origin: upstream, https://github.com/FreeRDP/FreeRDP/commit/a0be5cb87d760bb1c803ad1bb835aa1e73e62abc +Forwarded: not-needed +Bug: https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-5vgf-mw4f-r33h +Bug: https://security-tracker.debian.org/tracker/CVE-2026-26965 + +--- + libfreerdp/codec/planar.c | 21 ++++++++++++++++++++- + 1 file changed, 20 insertions(+), 1 deletion(-) + +diff --git a/libfreerdp/codec/planar.c b/libfreerdp/codec/planar.c +--- a/libfreerdp/codec/planar.c ++++ b/libfreerdp/codec/planar.c +@@ -732,8 +732,9 @@ BOOL freerdp_bitmap_decompress_planar(BITMAP_PLANAR_CONTEXT* WINPR_RESTRICT plan + if (planar->maxHeight < nSrcHeight) + return FALSE; + ++ const UINT32 bpp = FreeRDPGetBytesPerPixel(DstFormat); + if (nDstStep <= 0) +- nDstStep = nDstWidth * FreeRDPGetBytesPerPixel(DstFormat); ++ nDstStep = nDstWidth * bpp; + + const BYTE* srcp = pSrcData; + +@@ -955,6 +956,24 @@ BOOL freerdp_bitmap_decompress_planar(BITMAP_PLANAR_CONTEXT* WINPR_RESTRICT plan + } + else /* RLE */ + { ++ if (nYDst + nSrcHeight > nTotalHeight) ++ { ++ WLog_ERR(TAG, ++ "planar plane destination Y %" PRIu32 " + height %" PRIu32 ++ " exceeds totalHeight %" PRIu32, ++ nYDst, nSrcHeight, nTotalHeight); ++ return FALSE; ++ } ++ ++ if ((nXDst + nSrcWidth) * bpp > nDstStep) ++ { ++ WLog_ERR(TAG, ++ "planar plane destination (X %" PRIu32 " + width %" PRIu32 ++ ") * bpp %" PRIu32 " exceeds stride %" PRIu32, ++ nXDst, nSrcWidth, bpp, nDstStep); ++ return FALSE; ++ } ++ + status = planar_decompress_plane_rle( + planes[0], WINPR_ASSERTING_INT_CAST(uint32_t, rleSizes[0]), pTempData, nTempStep, + nXDst, nYDst, nSrcWidth, nSrcHeight, 2, vFlip); /* RedPlane */ +-- +2.47.3 + diff -Nru freerdp3-3.15.0+dfsg/debian/patches/core-info-fix-missing-NULL-check-CVE-2026-23948.patch freerdp3-3.15.0+dfsg/debian/patches/core-info-fix-missing-NULL-check-CVE-2026-23948.patch --- freerdp3-3.15.0+dfsg/debian/patches/core-info-fix-missing-NULL-check-CVE-2026-23948.patch 1970-01-01 00:00:00.000000000 +0000 +++ freerdp3-3.15.0+dfsg/debian/patches/core-info-fix-missing-NULL-check-CVE-2026-23948.patch 2026-02-09 18:48:59.000000000 +0000 @@ -0,0 +1,58 @@ +From: akallabeth +Date: Mon, 19 Jan 2026 20:11:24 +0100 +Subject: [core,info] fix missing NULL check +Origin: upstream, https://github.com/FreeRDP/FreeRDP/commit/4d44e3c097656a8b9ec696353647b0888ca45860 +Forwarded: not-needed +Bug: https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-6f3c-qvqq-2px5 +Bug: https://security-tracker.debian.org/tracker/CVE-2026-23948 + +--- + libfreerdp/core/info.c | 14 +++++++++----- + 1 file changed, 9 insertions(+), 5 deletions(-) + +diff --git a/libfreerdp/core/info.c b/libfreerdp/core/info.c +--- a/libfreerdp/core/info.c ++++ b/libfreerdp/core/info.c +@@ -1447,7 +1447,7 @@ static BOOL rdp_write_logon_info_v1(wStream* s, logon_info* info) + return TRUE; + } + +-static BOOL rdp_write_logon_info_v2(wStream* s, logon_info* info) ++static BOOL rdp_write_logon_info_v2(wStream* s, const logon_info* info) + { + size_t domainLen = 0; + size_t usernameLen = 0; +@@ -1462,11 +1462,14 @@ static BOOL rdp_write_logon_info_v2(wStream* s, logon_info* info) + */ + Stream_Write_UINT32(s, logonInfoV2Size); + Stream_Write_UINT32(s, info->sessionId); +- domainLen = strnlen(info->domain, 256); /* lmcons.h UNLEN */ ++ if (info->domain) ++ domainLen = strnlen(info->domain, 256); /* lmcons.h UNLEN */ + if (domainLen >= UINT32_MAX / sizeof(WCHAR)) + return FALSE; + Stream_Write_UINT32(s, (UINT32)(domainLen + 1) * sizeof(WCHAR)); +- usernameLen = strnlen(info->username, 256); /* lmcons.h UNLEN */ ++ ++ if (info->username) ++ usernameLen = strnlen(info->username, 256); /* lmcons.h UNLEN */ + if (usernameLen >= UINT32_MAX / sizeof(WCHAR)) + return FALSE; + Stream_Write_UINT32(s, (UINT32)(usernameLen + 1) * sizeof(WCHAR)); +@@ -1534,10 +1537,11 @@ static BOOL rdp_write_logon_info_ex(wStream* s, logon_info_ex* info) + BOOL rdp_send_save_session_info(rdpContext* context, UINT32 type, void* data) + { + UINT16 sec_flags = 0; +- wStream* s = NULL; + BOOL status = 0; ++ ++ WINPR_ASSERT(context); + rdpRdp* rdp = context->rdp; +- s = rdp_data_pdu_init(rdp, &sec_flags); ++ wStream* s = rdp_data_pdu_init(rdp, &sec_flags); + + if (!s) + return FALSE; +-- +2.47.3 + diff -Nru freerdp3-3.15.0+dfsg/debian/patches/core-redirection-Ensure-stream-has-space-for-all-params.patch freerdp3-3.15.0+dfsg/debian/patches/core-redirection-Ensure-stream-has-space-for-all-params.patch --- freerdp3-3.15.0+dfsg/debian/patches/core-redirection-Ensure-stream-has-space-for-all-params.patch 1970-01-01 00:00:00.000000000 +0000 +++ freerdp3-3.15.0+dfsg/debian/patches/core-redirection-Ensure-stream-has-space-for-all-params.patch 2026-01-29 22:17:24.000000000 +0000 @@ -0,0 +1,50 @@ +From 25e51878a1c80d4c7e2acae837d36bd97737662b Mon Sep 17 00:00:00 2001 +From: Pascal Nowack +Date: Sun, 31 Aug 2025 11:50:38 +0200 +Subject: core/redirection: Ensure stream has enough space for all parameters +Bug-Debian: https://bugs.debian.org/1112191 +Forwarded: not-needed +Origin: upstream, https://github.com/FreeRDP/FreeRDP/pull/11830 + +While commit a08e3fc5315af8a10c9b1d1333ec3c3d1066a172 fixed the case, +where the stream did not have enough space for the target certificate, +it did miss out a few other cases where the remaining length is just +checked, but not increased when needed. Fix this by now also covering +the remaining cases. + +Fixes: a08e3fc5315af8a10c9b1d1333ec3c3d1066a172 +--- + libfreerdp/core/redirection.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/libfreerdp/core/redirection.c b/libfreerdp/core/redirection.c +index b4324e99c..e9cdfc6cb 100644 +--- a/libfreerdp/core/redirection.c ++++ b/libfreerdp/core/redirection.c +@@ -203,12 +203,12 @@ static BOOL rdp_redirection_write_data(wStream* s, size_t length, const void* da + WINPR_ASSERT(data || (length == 0)); + WINPR_ASSERT(length <= UINT32_MAX); + +- if (!Stream_CheckAndLogRequiredCapacity(TAG, s, 4)) ++ if (!Stream_EnsureRemainingCapacity(s, 4)) + return FALSE; + + Stream_Write_UINT32(s, (UINT32)length); + +- if (!Stream_CheckAndLogRequiredCapacity(TAG, s, length)) ++ if (!Stream_EnsureRemainingCapacity(s, length)) + return FALSE; + + Stream_Write(s, data, length); +@@ -332,7 +332,7 @@ static BOOL rdp_target_cert_write_element(wStream* s, UINT32 Type, UINT32 Encodi + WINPR_ASSERT(data || (length == 0)); + WINPR_ASSERT(length <= UINT32_MAX); + +- if (!Stream_CheckAndLogRequiredCapacity(TAG, s, 12)) ++ if (!Stream_EnsureRemainingCapacity(s, 12)) + return FALSE; + + Stream_Write_UINT32(s, Type); +-- +2.47.3 + diff -Nru freerdp3-3.15.0+dfsg/debian/patches/core-redirection-Ensure-stream-has-space-for-cert.patch freerdp3-3.15.0+dfsg/debian/patches/core-redirection-Ensure-stream-has-space-for-cert.patch --- freerdp3-3.15.0+dfsg/debian/patches/core-redirection-Ensure-stream-has-space-for-cert.patch 1970-01-01 00:00:00.000000000 +0000 +++ freerdp3-3.15.0+dfsg/debian/patches/core-redirection-Ensure-stream-has-space-for-cert.patch 2026-01-29 22:17:24.000000000 +0000 @@ -0,0 +1,34 @@ +From a08e3fc5315af8a10c9b1d1333ec3c3d1066a172 Mon Sep 17 00:00:00 2001 +From: Pascal Nowack +Date: Wed, 6 Aug 2025 09:08:01 +0200 +Subject: core/redirection: Ensure stream has enough space for the certificate +Bug-Debian: https://bugs.debian.org/1112191 +Forwarded: not-needed +Origin: upstream, https://github.com/FreeRDP/FreeRDP/pull/11762 + +Instead of checking whether enough space for the certificate is +available, simply use Stream_EnsureRemainingCapacity() to extend the +buffer size if needed. Otherwise, server redirection might fail despite +having a valid certificate. + +See also: https://gitlab.gnome.org/GNOME/gnome-remote-desktop/-/issues/274 +--- + 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 57d1f056a..b4324e99c 100644 +--- a/libfreerdp/core/redirection.c ++++ b/libfreerdp/core/redirection.c +@@ -339,7 +339,7 @@ static BOOL rdp_target_cert_write_element(wStream* s, UINT32 Type, UINT32 Encodi + Stream_Write_UINT32(s, Encoding); + Stream_Write_UINT32(s, (UINT32)length); + +- if (!Stream_CheckAndLogRequiredCapacity(TAG, s, length)) ++ if (!Stream_EnsureRemainingCapacity(s, length)) + return FALSE; + + Stream_Write(s, data, length); +-- +2.47.3 + diff -Nru freerdp3-3.15.0+dfsg/debian/patches/crypto-base64-do-proper-length-checks-CVE-2026-22858.patch freerdp3-3.15.0+dfsg/debian/patches/crypto-base64-do-proper-length-checks-CVE-2026-22858.patch --- freerdp3-3.15.0+dfsg/debian/patches/crypto-base64-do-proper-length-checks-CVE-2026-22858.patch 1970-01-01 00:00:00.000000000 +0000 +++ freerdp3-3.15.0+dfsg/debian/patches/crypto-base64-do-proper-length-checks-CVE-2026-22858.patch 2026-02-09 18:48:59.000000000 +0000 @@ -0,0 +1,211 @@ +From: akallabeth +Date: Sat, 10 Jan 2026 10:21:10 +0100 +Subject: [crypto,base64] do proper length checks +Origin: upstream, https://github.com/FreeRDP/FreeRDP/commit/011737296d0aa674a086fdc89839951b08129e54 +Forwarded: not-needed +Bug: https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-qmqf-m84q-x896 +Bug: https://security-tracker.debian.org/tracker/CVE-2026-22858 + +relying on casting is error prone, so do proper index range checks. + +(Mjt: adjust inline=>INLINE) +--- + libfreerdp/crypto/base64.c | 99 +++++++++++++++++++++++++------------- + 1 file changed, 65 insertions(+), 34 deletions(-) + +diff --git a/libfreerdp/crypto/base64.c b/libfreerdp/crypto/base64.c +index 8d49d352e..39599e08a 100644 +--- a/libfreerdp/crypto/base64.c ++++ b/libfreerdp/crypto/base64.c +@@ -303,10 +303,10 @@ static const signed char dec_base64[] = { + }; + + static INLINE char* base64_encode_ex(const BYTE* WINPR_RESTRICT alphabet, ++ WINPR_ATTR_UNUSED size_t alphabetCount, + const BYTE* WINPR_RESTRICT data, size_t length, BOOL pad, + BOOL crLf, size_t lineSize) + { +- int c = 0; + size_t blocks = 0; + size_t outLen = (length + 3) * 4 / 3; + size_t extra = 0; +@@ -340,12 +340,21 @@ static INLINE char* base64_encode_ex(const BYTE* WINPR_RESTRICT alphabet, + blocks = length - (length % 3); + for (size_t i = 0; i < blocks; i += 3, q += 3) + { +- c = (q[0] << 16) + (q[1] << 8) + q[2]; +- +- *p++ = alphabet[(c & 0x00FC0000) >> 18]; +- *p++ = alphabet[(c & 0x0003F000) >> 12]; +- *p++ = alphabet[(c & 0x00000FC0) >> 6]; +- *p++ = alphabet[c & 0x0000003F]; ++ const unsigned c = ((unsigned)q[0] << 16) + ((unsigned)q[1] << 8) + q[2]; ++ const unsigned idx0 = (c & 0x00FC0000) >> 18; ++ const unsigned idx1 = (c & 0x0003F000) >> 12; ++ const unsigned idx2 = (c & 0x00000FC0) >> 6; ++ const unsigned idx3 = c & 0x0000003F; ++ ++ WINPR_ASSERT(idx0 < alphabetCount); ++ WINPR_ASSERT(idx1 < alphabetCount); ++ WINPR_ASSERT(idx2 < alphabetCount); ++ WINPR_ASSERT(idx3 < alphabetCount); ++ ++ *p++ = alphabet[idx0]; ++ *p++ = alphabet[idx1]; ++ *p++ = alphabet[idx2]; ++ *p++ = alphabet[idx3]; + + outCounter += 4; + if (crLf && (outCounter % lineSize == 0)) +@@ -361,23 +370,41 @@ static INLINE char* base64_encode_ex(const BYTE* WINPR_RESTRICT alphabet, + case 0: + break; + case 1: +- c = (q[0] << 16); +- *p++ = alphabet[(c & 0x00FC0000) >> 18]; +- *p++ = alphabet[(c & 0x0003F000) >> 12]; ++ { ++ const unsigned c = ((unsigned)q[0] << 16); ++ const unsigned idx0 = (c & 0x00FC0000) >> 18; ++ const unsigned idx1 = (c & 0x0003F000) >> 12; ++ ++ WINPR_ASSERT(idx0 < alphabetCount); ++ WINPR_ASSERT(idx1 < alphabetCount); ++ ++ *p++ = alphabet[idx0]; ++ *p++ = alphabet[idx1]; + if (pad) + { + *p++ = '='; + *p++ = '='; + } +- break; ++ } ++ break; + case 2: +- c = (q[0] << 16) + (q[1] << 8); +- *p++ = alphabet[(c & 0x00FC0000) >> 18]; +- *p++ = alphabet[(c & 0x0003F000) >> 12]; +- *p++ = alphabet[(c & 0x00000FC0) >> 6]; ++ { ++ const unsigned c = ((unsigned)q[0] << 16) + ((unsigned)q[1] << 8); ++ const unsigned idx0 = (c & 0x00FC0000) >> 18; ++ const unsigned idx1 = (c & 0x0003F000) >> 12; ++ const unsigned idx2 = (c & 0x00000FC0) >> 6; ++ ++ WINPR_ASSERT(idx0 < alphabetCount); ++ WINPR_ASSERT(idx1 < alphabetCount); ++ WINPR_ASSERT(idx2 < alphabetCount); ++ ++ *p++ = alphabet[idx0]; ++ *p++ = alphabet[idx1]; ++ *p++ = alphabet[idx2]; + if (pad) + *p++ = '='; +- break; ++ } ++ break; + default: + break; + } +@@ -392,22 +419,24 @@ static INLINE char* base64_encode_ex(const BYTE* WINPR_RESTRICT alphabet, + return ret; + } + +-static INLINE char* base64_encode(const BYTE* WINPR_RESTRICT alphabet, ++static INLINE char* base64_encode(const BYTE* WINPR_RESTRICT alphabet, size_t alphabetCount, + const BYTE* WINPR_RESTRICT data, size_t length, BOOL pad) + { +- return base64_encode_ex(alphabet, data, length, pad, FALSE, 64); ++ return base64_encode_ex(alphabet, alphabetCount, data, length, pad, FALSE, 64); + } + +-static INLINE int base64_decode_char(const signed char* WINPR_RESTRICT alphabet, char c) ++static INLINE int base64_decode_char(const signed char* WINPR_RESTRICT alphabet, ++ size_t alphabetCount, char c) + { + /* ensure char is signed for this check */ +- if ((int)c <= '\0') ++ const int ic = (int)c; ++ if ((ic <= 0) || ((size_t)ic >= alphabetCount)) + return -1; + + return alphabet[(size_t)c]; + } + +-static INLINE void* base64_decode(const signed char* WINPR_RESTRICT alphabet, ++static INLINE void* base64_decode(const signed char* WINPR_RESTRICT alphabet, size_t alphabetCount, + const char* WINPR_RESTRICT s, size_t length, + size_t* WINPR_RESTRICT data_len, BOOL pad) + { +@@ -437,10 +466,10 @@ static INLINE void* base64_decode(const signed char* WINPR_RESTRICT alphabet, + + for (size_t i = 0; i < nBlocks - 1; i++, q += 3) + { +- n[0] = base64_decode_char(alphabet, *s++); +- n[1] = base64_decode_char(alphabet, *s++); +- n[2] = base64_decode_char(alphabet, *s++); +- n[3] = base64_decode_char(alphabet, *s++); ++ n[0] = base64_decode_char(alphabet, alphabetCount, *s++); ++ n[1] = base64_decode_char(alphabet, alphabetCount, *s++); ++ n[2] = base64_decode_char(alphabet, alphabetCount, *s++); ++ n[3] = base64_decode_char(alphabet, alphabetCount, *s++); + + if ((n[0] == -1) || (n[1] == -1) || (n[2] == -1) || (n[3] == -1)) + goto out_free; +@@ -452,13 +481,13 @@ static INLINE void* base64_decode(const signed char* WINPR_RESTRICT alphabet, + } + + /* treat last block */ +- n[0] = base64_decode_char(alphabet, *s++); +- n[1] = base64_decode_char(alphabet, *s++); ++ n[0] = base64_decode_char(alphabet, alphabetCount, *s++); ++ n[1] = base64_decode_char(alphabet, alphabetCount, *s++); + if ((n[0] == -1) || (n[1] == -1)) + goto out_free; + +- n[2] = remainder == 2 ? -1 : base64_decode_char(alphabet, *s++); +- n[3] = remainder >= 2 ? -1 : base64_decode_char(alphabet, *s++); ++ n[2] = remainder == 2 ? -1 : base64_decode_char(alphabet, alphabetCount, *s++); ++ n[3] = remainder >= 2 ? -1 : base64_decode_char(alphabet, alphabetCount, *s++); + + q[0] = (BYTE)((n[0] << 2) + (n[1] >> 4)); + if (n[2] == -1) +@@ -498,27 +527,29 @@ out_free: + + char* crypto_base64_encode_ex(const BYTE* WINPR_RESTRICT data, size_t length, BOOL withCrLf) + { +- return base64_encode_ex(enc_base64, data, length, TRUE, withCrLf, 64); ++ return base64_encode_ex(enc_base64, ARRAYSIZE(enc_base64), data, length, TRUE, withCrLf, 64); + } + + char* crypto_base64_encode(const BYTE* WINPR_RESTRICT data, size_t length) + { +- return base64_encode(enc_base64, data, length, TRUE); ++ return base64_encode(enc_base64, ARRAYSIZE(enc_base64), data, length, TRUE); + } + + void crypto_base64_decode(const char* WINPR_RESTRICT enc_data, size_t length, + BYTE** WINPR_RESTRICT dec_data, size_t* WINPR_RESTRICT res_length) + { +- *dec_data = base64_decode(dec_base64, enc_data, length, res_length, TRUE); ++ *dec_data = ++ base64_decode(dec_base64, ARRAYSIZE(dec_base64), enc_data, length, res_length, TRUE); + } + + char* crypto_base64url_encode(const BYTE* WINPR_RESTRICT data, size_t length) + { +- return base64_encode(enc_base64url, data, length, FALSE); ++ return base64_encode(enc_base64url, ARRAYSIZE(enc_base64url), data, length, FALSE); + } + + void crypto_base64url_decode(const char* WINPR_RESTRICT enc_data, size_t length, + BYTE** WINPR_RESTRICT dec_data, size_t* WINPR_RESTRICT res_length) + { +- *dec_data = base64_decode(dec_base64url, enc_data, length, res_length, FALSE); ++ *dec_data = ++ base64_decode(dec_base64url, ARRAYSIZE(dec_base64url), enc_data, length, res_length, FALSE); + } +-- +2.47.3 + diff -Nru freerdp3-3.15.0+dfsg/debian/patches/crypto-base64-ensure-char-is-singend.patch freerdp3-3.15.0+dfsg/debian/patches/crypto-base64-ensure-char-is-singend.patch --- freerdp3-3.15.0+dfsg/debian/patches/crypto-base64-ensure-char-is-singend.patch 1970-01-01 00:00:00.000000000 +0000 +++ freerdp3-3.15.0+dfsg/debian/patches/crypto-base64-ensure-char-is-singend.patch 2026-02-09 18:48:59.000000000 +0000 @@ -0,0 +1,28 @@ +From: akallabeth +Date: Sat, 10 Jan 2026 08:31:07 +0100 +Subject: [crypto,base64] ensure char is singend +Origin: upstream, https://github.com/FreeRDP/FreeRDP/commit/62a9e787edb2cfce9858fa4ceda5461680efc590 +Forwarded: not-needed +Comment: bugfix by its own and a preparation for CVE-2026-22858 fix + +--- + libfreerdp/crypto/base64.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/libfreerdp/crypto/base64.c b/libfreerdp/crypto/base64.c +index 315da9203..8d49d352e 100644 +--- a/libfreerdp/crypto/base64.c ++++ b/libfreerdp/crypto/base64.c +@@ -400,7 +400,8 @@ static INLINE char* base64_encode(const BYTE* WINPR_RESTRICT alphabet, + + static INLINE int base64_decode_char(const signed char* WINPR_RESTRICT alphabet, char c) + { +- if (c <= '\0') ++ /* ensure char is signed for this check */ ++ if ((int)c <= '\0') + return -1; + + return alphabet[(size_t)c]; +-- +2.47.3 + diff -Nru freerdp3-3.15.0+dfsg/debian/patches/gdi-gfx-properly-clamp-SurfaceToSurface-CVE-2026-23532.patch freerdp3-3.15.0+dfsg/debian/patches/gdi-gfx-properly-clamp-SurfaceToSurface-CVE-2026-23532.patch --- freerdp3-3.15.0+dfsg/debian/patches/gdi-gfx-properly-clamp-SurfaceToSurface-CVE-2026-23532.patch 1970-01-01 00:00:00.000000000 +0000 +++ freerdp3-3.15.0+dfsg/debian/patches/gdi-gfx-properly-clamp-SurfaceToSurface-CVE-2026-23532.patch 2026-02-09 18:48:59.000000000 +0000 @@ -0,0 +1,51 @@ +From: akallabeth +Date: Thu, 15 Jan 2026 12:04:36 +0100 +Subject: [gdi,gfx] properly clamp SurfaceToSurface +Origin: upstream, https://github.com/FreeRDP/FreeRDP/commit/c4a7c371342edf0d307cea728f56d3302f0ab38c +Forwarded: not-needed +Bug: https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-fq8c-87hj-7gvr +Bug: https://security-tracker.debian.org/tracker/CVE-2026-23532 + +--- + libfreerdp/gdi/gfx.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/libfreerdp/gdi/gfx.c b/libfreerdp/gdi/gfx.c +index 56e6ff9ed..96ce10070 100644 +--- a/libfreerdp/gdi/gfx.c ++++ b/libfreerdp/gdi/gfx.c +@@ -1335,8 +1335,6 @@ static UINT gdi_SurfaceToSurface(RdpgfxClientContext* context, + { + UINT status = ERROR_INTERNAL_ERROR; + BOOL sameSurface = 0; +- UINT32 nWidth = 0; +- UINT32 nHeight = 0; + const RECTANGLE_16* rectSrc = NULL; + RECTANGLE_16 invalidRect; + gdiGfxSurface* surfaceSrc = NULL; +@@ -1362,8 +1360,8 @@ static UINT gdi_SurfaceToSurface(RdpgfxClientContext* context, + if (!is_rect_valid(rectSrc, surfaceSrc->width, surfaceSrc->height)) + goto fail; + +- nWidth = rectSrc->right - rectSrc->left; +- nHeight = rectSrc->bottom - rectSrc->top; ++ const UINT32 nWidth = rectSrc->right - rectSrc->left; ++ const UINT32 nHeight = rectSrc->bottom - rectSrc->top; + + for (UINT16 index = 0; index < surfaceToSurface->destPtsCount; index++) + { +@@ -1374,8 +1372,10 @@ static UINT gdi_SurfaceToSurface(RdpgfxClientContext* context, + if (!is_rect_valid(&rect, surfaceDst->width, surfaceDst->height)) + goto fail; + ++ const UINT32 rwidth = rect.right - rect.left; ++ const UINT32 rheight = rect.bottom - rect.top; + if (!freerdp_image_copy(surfaceDst->data, surfaceDst->format, surfaceDst->scanline, +- destPt->x, destPt->y, nWidth, nHeight, surfaceSrc->data, ++ destPt->x, destPt->y, rwidth, rheight, surfaceSrc->data, + surfaceSrc->format, surfaceSrc->scanline, rectSrc->left, + rectSrc->top, NULL, FREERDP_FLIP_NONE)) + goto fail; +-- +2.47.3 + diff -Nru freerdp3-3.15.0+dfsg/debian/patches/gdi-graphics-Use-freerdp_glyph_convert_ex-CVE-2026-23732.patch freerdp3-3.15.0+dfsg/debian/patches/gdi-graphics-Use-freerdp_glyph_convert_ex-CVE-2026-23732.patch --- freerdp3-3.15.0+dfsg/debian/patches/gdi-graphics-Use-freerdp_glyph_convert_ex-CVE-2026-23732.patch 1970-01-01 00:00:00.000000000 +0000 +++ freerdp3-3.15.0+dfsg/debian/patches/gdi-graphics-Use-freerdp_glyph_convert_ex-CVE-2026-23732.patch 2026-02-09 18:48:59.000000000 +0000 @@ -0,0 +1,42 @@ +From: akallabeth +Date: Fri, 16 Jan 2026 12:00:57 +0100 +Subject: [gdi,graphics] Use freerdp_glyph_convert_ex +Origin: upstream, https://github.com/FreeRDP/FreeRDP/commit/9f0eb3b7d43069a1e973464bcb43d1ef965ae65e +Forwarded: not-needed +Bug: https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-7qxp-j2fj-c3pp +Bug: https://security-tracker.debian.org/tracker/CVE-2026-23732 + +--- + libfreerdp/gdi/graphics.c | 7 ++----- + 1 file changed, 2 insertions(+), 5 deletions(-) + +diff --git a/libfreerdp/gdi/graphics.c b/libfreerdp/gdi/graphics.c +index 2f616148c..1521dbbaf 100644 +--- a/libfreerdp/gdi/graphics.c ++++ b/libfreerdp/gdi/graphics.c +@@ -270,20 +270,17 @@ static BOOL gdi_Bitmap_SetSurface(rdpContext* context, rdpBitmap* bitmap, BOOL p + /* Glyph Class */ + static BOOL gdi_Glyph_New(rdpContext* context, rdpGlyph* glyph) + { +- BYTE* data = NULL; +- gdiGlyph* gdi_glyph = NULL; +- + if (!context || !glyph) + return FALSE; + +- gdi_glyph = (gdiGlyph*)glyph; ++ gdiGlyph* gdi_glyph = (gdiGlyph*)glyph; + gdi_glyph->hdc = gdi_GetDC(); + + if (!gdi_glyph->hdc) + return FALSE; + + gdi_glyph->hdc->format = PIXEL_FORMAT_MONO; +- data = freerdp_glyph_convert(glyph->cx, glyph->cy, glyph->aj); ++ BYTE* data = freerdp_glyph_convert_ex(glyph->cx, glyph->cy, glyph->aj, glyph->cb); + + if (!data) + { +-- +2.47.3 + diff -Nru freerdp3-3.15.0+dfsg/debian/patches/rdpecam-fix-camera-sample-grabbing.patch freerdp3-3.15.0+dfsg/debian/patches/rdpecam-fix-camera-sample-grabbing.patch --- freerdp3-3.15.0+dfsg/debian/patches/rdpecam-fix-camera-sample-grabbing.patch 1970-01-01 00:00:00.000000000 +0000 +++ freerdp3-3.15.0+dfsg/debian/patches/rdpecam-fix-camera-sample-grabbing.patch 2026-02-09 18:48:59.000000000 +0000 @@ -0,0 +1,324 @@ +From: David Fort +Date: Thu, 4 Dec 2025 13:14:09 +0100 +Subject: rdpecam: fix camera sample grabbing +Origin: upstream, https://github.com/FreeRDP/FreeRDP/commit/32e64c1e98d9218944a054a5046fc012c15f38aa +Forwarded: not-needed +Comment: preparation for CVE-2026-24677 fix, and a fix by its own + +Before this patch we had a behavior where there was a credit of 8 samples that +could be sent to the server with no corresponding sample request. So in the right +conditions, we were having situations where the server was receiving samples that +it has not requested, and so it was dropping them. The visible effect was small +artifacts in the camera stream when i-frames where dropped, and more serious ones +when the dropped content was containing key frames. + +This issue has also been reported when xfreerdp connects on g-r-d as #11990. + +This patch reworks the frame grabbing workflow: when the frame grabbing thread calls +the sample callback we check if a sample is already pending, waiting to be sent to the +server. If that's the case and the camera's input format supports frame dropping we just +refresh the pending frame with the new one. If the input format can't drop frames (like +with h264 and mjpg) we wait until the current pending frame is sent. +So now frames can be sent either when we receive a sample request from the server, +or when the sample callback is invoked. +--- + channels/rdpecam/client/camera.h | 5 +- + channels/rdpecam/client/camera_device_main.c | 183 +++++++++++++++---- + 2 files changed, 149 insertions(+), 39 deletions(-) + +diff --git a/channels/rdpecam/client/camera.h b/channels/rdpecam/client/camera.h +--- a/channels/rdpecam/client/camera.h ++++ b/channels/rdpecam/client/camera.h +@@ -101,7 +101,10 @@ typedef struct + CAM_MEDIA_TYPE_DESCRIPTION currMediaType; + + GENERIC_CHANNEL_CALLBACK* hSampleReqChannel; +- INT nSampleCredits; ++ CRITICAL_SECTION lock; ++ volatile LONG samplesRequested; ++ wStream* pendingSample; ++ volatile BOOL haveSample; + wStream* sampleRespBuffer; + + H264_CONTEXT* h264; +diff --git a/channels/rdpecam/client/camera_device_main.c b/channels/rdpecam/client/camera_device_main.c +--- a/channels/rdpecam/client/camera_device_main.c ++++ b/channels/rdpecam/client/camera_device_main.c +@@ -19,6 +19,7 @@ + + #include + #include ++#include + + #include "camera.h" + +@@ -108,17 +109,52 @@ static UINT ecam_dev_send_sample_response(CameraDevice* dev, size_t streamIndex, + FALSE /* don't free stream */); + } + +-/** +- * Function description +- * +- * @return 0 on success, otherwise a Win32 error code +- */ +-static UINT ecam_dev_sample_captured_callback(CameraDevice* dev, int streamIndex, +- const BYTE* sample, size_t size) ++static BOOL mediaSupportDrops(CAM_MEDIA_FORMAT format) ++{ ++ switch (format) ++ { ++ case CAM_MEDIA_FORMAT_H264: ++ case CAM_MEDIA_FORMAT_MJPG: ++ return FALSE; ++ default: ++ return TRUE; ++ } ++} ++ ++static UINT ecam_dev_send_pending(CameraDevice* dev, int streamIndex, CameraDeviceStream* stream) + { + BYTE* encodedSample = NULL; + size_t encodedSize = 0; + ++ if (streamInputFormat(stream) != streamOutputFormat(stream)) ++ { ++ if (!ecam_encoder_compress(stream, Stream_Buffer(stream->pendingSample), ++ Stream_Length(stream->pendingSample), &encodedSample, ++ &encodedSize)) ++ { ++ WLog_DBG(TAG, "Frame drop or error in ecam_encoder_compress"); ++ return CHANNEL_RC_OK; ++ } ++ ++ if (!stream->streaming) ++ return CHANNEL_RC_OK; ++ } ++ else /* passthrough */ ++ { ++ encodedSample = Stream_Buffer(stream->pendingSample); ++ encodedSize = Stream_Length(stream->pendingSample); ++ } ++ ++ stream->samplesRequested--; ++ stream->haveSample = FALSE; ++ ++ return ecam_dev_send_sample_response(dev, WINPR_ASSERTING_INT_CAST(size_t, streamIndex), ++ encodedSample, encodedSize); ++} ++ ++static UINT ecam_dev_sample_captured_callback(CameraDevice* dev, int streamIndex, ++ const BYTE* sample, size_t size) ++{ + WINPR_ASSERT(dev); + + if (streamIndex >= ECAM_DEVICE_MAX_STREAMS) +@@ -129,32 +165,61 @@ static UINT ecam_dev_sample_captured_callback(CameraDevice* dev, int streamIndex + if (!stream->streaming) + return CHANNEL_RC_OK; + +- if (streamInputFormat(stream) != streamOutputFormat(stream)) ++ EnterCriticalSection(&stream->lock); ++ UINT ret = CHANNEL_RC_NO_MEMORY; ++ ++ /* If we already have a waiting sample, let's see if the input format support dropping ++ * frames so that we could just "refresh" the pending sample, otherwise we must wait until ++ * a frame request flushes it ++ */ ++ ++ if (stream->haveSample && !mediaSupportDrops(stream->formats.inputFormat)) + { +- if (!ecam_encoder_compress(stream, sample, size, &encodedSample, &encodedSize)) ++ /* we can't drop samples, so we have to wait until the pending sample is ++ * sent, by a sample request. ++ * ++ * When we're here we already have a sample ready to be sent, the delay between 2 frames ++ * seems like a reasonable wait delay. For instance 60 FPS means a frame every 16ms. ++ * We also cap that wait delay to not spinloop and not get stuck for too long. ++ * */ ++ DWORD waitDelay = (1000 * stream->currMediaType.FrameRateDenominator) / ++ stream->currMediaType.FrameRateNumerator; ++ if (waitDelay < 16) ++ waitDelay = 16; ++ if (waitDelay > 100) ++ waitDelay = 100; ++ ++ while (stream->haveSample && stream->streaming) + { +- WLog_DBG(TAG, "Frame drop or error in ecam_encoder_compress"); +- return CHANNEL_RC_OK; ++ LeaveCriticalSection(&stream->lock); ++ ++ SleepEx(waitDelay, TRUE); ++ ++ EnterCriticalSection(&stream->lock); + } + + if (!stream->streaming) +- return CHANNEL_RC_OK; +- } +- else /* passthrough */ +- { +- encodedSample = WINPR_CAST_CONST_PTR_AWAY(sample, BYTE*); +- encodedSize = size; ++ { ++ ret = CHANNEL_RC_OK; ++ goto out; ++ } + } + +- if (stream->nSampleCredits == 0) +- { +- WLog_DBG(TAG, "Skip sample: no credits left"); +- return CHANNEL_RC_OK; +- } +- stream->nSampleCredits--; ++ Stream_SetPosition(stream->pendingSample, 0); ++ if (!Stream_EnsureRemainingCapacity(stream->pendingSample, size)) ++ goto out; + +- return ecam_dev_send_sample_response(dev, WINPR_ASSERTING_INT_CAST(size_t, streamIndex), +- encodedSample, encodedSize); ++ Stream_Write(stream->pendingSample, sample, size); ++ Stream_SealLength(stream->pendingSample); ++ stream->haveSample = TRUE; ++ ++ ret = CHANNEL_RC_OK; ++ if (stream->samplesRequested) ++ ret = ecam_dev_send_pending(dev, streamIndex, stream); ++ ++out: ++ LeaveCriticalSection(&stream->lock); ++ return ret; + } + + static void ecam_dev_stop_stream(CameraDevice* dev, size_t streamIndex) +@@ -170,6 +235,8 @@ static void ecam_dev_stop_stream(CameraDevice* dev, size_t streamIndex) + { + stream->streaming = FALSE; + dev->ihal->StopStream(dev->ihal, dev->deviceId, 0); ++ ++ DeleteCriticalSection(&stream->lock); + } + + if (stream->sampleRespBuffer) +@@ -178,6 +245,12 @@ static void ecam_dev_stop_stream(CameraDevice* dev, size_t streamIndex) + stream->sampleRespBuffer = NULL; + } + ++ if (stream->pendingSample) ++ { ++ Stream_Free(stream->pendingSample, TRUE); ++ stream->pendingSample = NULL; ++ } ++ + ecam_encoder_context_free(stream); + } + +@@ -267,7 +340,25 @@ static UINT ecam_dev_process_start_streams_request(CameraDevice* dev, + /* replacing outputFormat with inputFormat in mediaType before starting stream */ + mediaType.Format = streamInputFormat(stream); + +- stream->nSampleCredits = 0; ++ stream->samplesRequested = 0; ++ stream->haveSample = FALSE; ++ ++ if (!InitializeCriticalSectionEx(&stream->lock, 0, 0)) ++ { ++ WLog_ERR(TAG, "InitializeCriticalSectionEx failed"); ++ ecam_dev_stop_stream(dev, streamIndex); ++ ecam_channel_send_error_response(dev->ecam, hchannel, CAM_ERROR_CODE_OutOfMemory); ++ return ERROR_INVALID_DATA; ++ } ++ ++ stream->pendingSample = Stream_New(NULL, mediaType.Width * mediaType.Height * 4ull); ++ if (!stream->pendingSample) ++ { ++ WLog_ERR(TAG, "pending stream failed"); ++ ecam_dev_stop_stream(dev, streamIndex); ++ ecam_channel_send_error_response(dev->ecam, hchannel, CAM_ERROR_CODE_OutOfMemory); ++ return ERROR_INVALID_DATA; ++ } + + UINT error = dev->ihal->StartStream(dev->ihal, dev, streamIndex, &mediaType, + ecam_dev_sample_captured_callback); +@@ -352,14 +443,19 @@ static UINT ecam_dev_process_sample_request(CameraDevice* dev, GENERIC_CHANNEL_C + + CameraDeviceStream* stream = &dev->streams[streamIndex]; + ++ EnterCriticalSection(&stream->lock); ++ + /* need to save channel because responses are asynchronous and coming from capture thread */ + if (stream->hSampleReqChannel != hchannel) + stream->hSampleReqChannel = hchannel; + +- /* allow to send that many unsolicited samples */ +- stream->nSampleCredits = ECAM_MAX_SAMPLE_CREDITS; ++ UINT ret = CHANNEL_RC_OK; ++ stream->samplesRequested++; ++ if (stream->pendingSample) ++ ret = ecam_dev_send_pending(dev, streamIndex, stream); + +- return CHANNEL_RC_OK; ++ LeaveCriticalSection(&stream->lock); ++ return ret; + } + + /** +@@ -442,8 +538,8 @@ static UINT ecam_dev_process_media_type_list_request(CameraDevice* dev, + { + UINT error = CHANNEL_RC_OK; + BYTE streamIndex = 0; +- CAM_MEDIA_TYPE_DESCRIPTION mediaTypes[ECAM_MAX_MEDIA_TYPE_DESCRIPTORS] = { 0 }; +- size_t nMediaTypes = ARRAYSIZE(mediaTypes); ++ CAM_MEDIA_TYPE_DESCRIPTION* mediaTypes = NULL; ++ size_t nMediaTypes = ECAM_MAX_MEDIA_TYPE_DESCRIPTORS; + + WINPR_ASSERT(dev); + +@@ -460,17 +556,24 @@ static UINT ecam_dev_process_media_type_list_request(CameraDevice* dev, + } + CameraDeviceStream* stream = &dev->streams[streamIndex]; + ++ mediaTypes = ++ (CAM_MEDIA_TYPE_DESCRIPTION*)calloc(nMediaTypes, sizeof(CAM_MEDIA_TYPE_DESCRIPTION)); ++ if (!mediaTypes) ++ { ++ WLog_ERR(TAG, "calloc failed"); ++ ecam_channel_send_error_response(dev->ecam, hchannel, CAM_ERROR_CODE_OutOfMemory); ++ return CHANNEL_RC_NO_MEMORY; ++ } ++ + INT16 formatIndex = + dev->ihal->GetMediaTypeDescriptions(dev->ihal, dev->deviceId, streamIndex, supportedFormats, + nSupportedFormats, mediaTypes, &nMediaTypes); +- if ((formatIndex < 0) || (nMediaTypes == 0)) ++ if (formatIndex == -1 || nMediaTypes == 0) + { +- WLog_ERR(TAG, +- "Camera doesn't support any compatible video formats [streamIndex=%" PRIu32 +- ", formatIndex=%" PRId16 ", nMediaTypes=%" PRIu32 "]", +- streamIndex, formatIndex, nMediaTypes); ++ WLog_ERR(TAG, "Camera doesn't support any compatible video formats"); + ecam_channel_send_error_response(dev->ecam, hchannel, CAM_ERROR_CODE_ItemNotFound); +- return ERROR_DEVICE_FEATURE_NOT_SUPPORTED; ++ error = ERROR_DEVICE_FEATURE_NOT_SUPPORTED; ++ goto error; + } + + stream->formats = supportedFormats[formatIndex]; +@@ -488,7 +591,11 @@ static UINT ecam_dev_process_media_type_list_request(CameraDevice* dev, + stream->currMediaType = mediaTypes[0]; + } + +- return ecam_dev_send_media_type_list_response(dev, hchannel, mediaTypes, nMediaTypes); ++ error = ecam_dev_send_media_type_list_response(dev, hchannel, mediaTypes, nMediaTypes); ++ ++error: ++ free(mediaTypes); ++ return error; + } + + /** +-- +2.47.3 + diff -Nru freerdp3-3.15.0+dfsg/debian/patches/series freerdp3-3.15.0+dfsg/debian/patches/series --- freerdp3-3.15.0+dfsg/debian/patches/series 2025-05-26 12:32:22.000000000 +0000 +++ freerdp3-3.15.0+dfsg/debian/patches/series 2026-02-25 20:34:19.000000000 +0000 @@ -10,3 +10,71 @@ fix-resources-remove-MimeType-from-desktop-file.patch gcc-fix-server-side-connection-with-multiple-monitor.patch CVE-2025-4478.patch +core-redirection-Ensure-stream-has-space-for-cert.patch +core-redirection-Ensure-stream-has-space-for-all-params.patch +client-desktop-fix-StartupWMClass-setting.patch +client-x11-fix-clipboard-issues.patch +client-sdl-lock-primary-while-used-CVE-2026-22851.patch +channels-audin-free-up-old-audio-formats-CVE-2026-22852.patch +channels-rdpear-add-checks-for-itemSize-CVE-2026-22853.patch +channels-drive-fix-constant-type-CVE-2026-22854.patch +# 3 fixes & logging improvements to prepare for CVE-2026-22855: +utils-smartcard-handle-output-buffer-too-small.patch +utils-smartcard-improve-trace-log.patch +utils-smartcard-better-logging-and-error-checks.patch +utils-smartcard-add-length-validity-checks-CVE-2026-22855.patch +channels-serial-explicitly-lock-serial-IrpThreads-CVE-2026-22856.patch +channels-serial-fix-use-after-free-CVE-2026-22857.patch +# bugfix and preparation for CVE-2026-22858: +crypto-base64-ensure-char-is-singend.patch +crypto-base64-do-proper-length-checks-CVE-2026-22858.patch +channels-urbdrc-check-interface-indices-before-use-CVE-2026-22859.patch +codec-planar-fix-decoder-length-checks-CVE-2026-23530.patch +codec-clear-fix-missing-length-checks-CVE-2026-23531.patch +gdi-gfx-properly-clamp-SurfaceToSurface-CVE-2026-23532.patch +codec-clear-fix-clear_resize_buffer-checks-CVE-2026-23533.patch +codec-clear-fix-off-by-one-length-check-CVE-2026-23534.patch +codec-color-add-freerdp_glyph_convert_ex-CVE-2026-23732.patch +gdi-graphics-Use-freerdp_glyph_convert_ex-CVE-2026-23732.patch +client-x11-fix-double-free-in-case-of-invalid-pointe-CVE-2026-23883.patch +cache-offscreen-invalidate-bitmap-before-free-CVE-2026-23884.patch +# fixes from 3.22: +core-info-fix-missing-NULL-check-CVE-2026-23948.patch +clang-warnings-fix-Wjump-misses-init-drdynvc_main.patch +channels-drdynvc-reset-channel_callback-before-close-CVE-2026-24491.patch +channels-drdynvc-check-pointer-before-reset.patch +channels-urbdrc-do-not-free-MsConfig-on-failure-CVE-2026-24675.patch +channels-audin-reset-audin-format-CVE-2026-24676.patch +# 4 patches to sync context for CVE-2026-24677 +clang-warnings-fix-Wjump-misses-init-remdesk_main.patch +channels-rdpecam-improve-log-messages.patch +rdpecam-fix-camera-sample-grabbing.patch +channels-rpdecam-log-dropped-samples.patch +channels-rdpecam-ensure-sws-context-size-matches-CVE-2026-24677.patch +channels-rdpecam-ensure-all-streams-are-stopped-CVE-2026-24678.patch +channels-urbdrc-ensure-InterfaceNumber-is-within-ran-CVE-2026-24679.patch +client-sdl-reset-pointer-after-memory-release-CVE-2026-24680.patch +channels-urbdrc-cancel-all-usb-transfers-on-channel--CVE-2026-24681.patch +channels-audin-fix-audin_server_recv_formats-cleanup-CVE-2026-24682.patch +channels-ainput-lock-context-when-updating-listener-CVE-2026-24683.patch +channels-rdpsnd-terminate-thread-before-free-CVE-2026-24684.patch +channel-rdpsnd-only-clean-up-thread-before-free-CVE-2026-24684.patch +# fix for CVE-2026-24677 fix: +winpr-wlog-Add-specialized-text-log-functions.patch +warnings-Fix-format-string-errors-partial.patch +channels-rdpecam-add-value-range-checks.patch +channels-rdpecam-fix-PROPERTY_DESCRIPTION-parsing.patch +# +channels-rdpgfx-check-available-stream-length-CVE-2026-25941.patch +client-x11-fix-xf_rail_window_common-cleanup-CVE-2026-26986.patch +client-x11-stringfiy-functions-for-RAILS-CVE-2026-25942.patch +client-X11-fix-clipboard-update-CVE-2026-25997.patch +client-x11-lock-appWindow-CVE-2026-25952-CVE-2026-25953-CVE-2026-25954.patch +client-x11-fix-missing-includes.patch +client-x11-destroy-XImage-on-window-unmap-CVE-2026-25955.patch +client-x11-lock-cache-when-providing-data-CVE-2026-25959.patch +codec-color-fix-input-length-checks-CVE-2026-26271.patch +utils-smartcard-check-stream-length-on-padding-CVE-2026-27015.patch +codec-clear-fix-missing-destination-boundary-checks-CVE-2026-26955.patch +codec-clear-fix-destination-checks-CVE-2026-26955.patch +codec-planar-fix-missing-destination-bounds-checks-CVE-2026-26965.patch diff -Nru freerdp3-3.15.0+dfsg/debian/patches/utils-smartcard-add-length-validity-checks-CVE-2026-22855.patch freerdp3-3.15.0+dfsg/debian/patches/utils-smartcard-add-length-validity-checks-CVE-2026-22855.patch --- freerdp3-3.15.0+dfsg/debian/patches/utils-smartcard-add-length-validity-checks-CVE-2026-22855.patch 1970-01-01 00:00:00.000000000 +0000 +++ freerdp3-3.15.0+dfsg/debian/patches/utils-smartcard-add-length-validity-checks-CVE-2026-22855.patch 2026-02-09 18:48:59.000000000 +0000 @@ -0,0 +1,83 @@ +From: akallabeth +Date: Sun, 11 Jan 2026 09:03:57 +0100 +Subject: [utils,smartcard] add length validity checks +Origin: upstream, https://github.com/FreeRDP/FreeRDP/commit/57c5647d98c2a026de8b681159cb188ca0439ef8 +Forwarded: not-needed +Bug: https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-rwp3-g84r-6mx9 +Bug: https://security-tracker.debian.org/tracker/CVE-2026-22855 + +in smartcard_unpack_set_attrib_call input length validity checks were +missing. +--- + libfreerdp/utils/smartcard_pack.c | 27 +++++++++++++++++++++------ + 1 file changed, 21 insertions(+), 6 deletions(-) + +diff --git a/libfreerdp/utils/smartcard_pack.c b/libfreerdp/utils/smartcard_pack.c +index b37825b9b..6a82d99d8 100644 +--- a/libfreerdp/utils/smartcard_pack.c ++++ b/libfreerdp/utils/smartcard_pack.c +@@ -111,8 +111,8 @@ static BOOL smartcard_ndr_pointer_read_(wLog* log, wStream* s, UINT32* index, UI + return TRUE; + } + +-static LONG smartcard_ndr_read(wLog* log, wStream* s, BYTE** data, size_t min, size_t elementSize, +- ndr_ptr_t type) ++static LONG smartcard_ndr_read_ex(wLog* log, wStream* s, BYTE** data, size_t min, ++ size_t elementSize, ndr_ptr_t type, size_t* plen) + { + size_t len = 0; + size_t offset = 0; +@@ -121,6 +121,9 @@ static LONG smartcard_ndr_read(wLog* log, wStream* s, BYTE** data, size_t min, s + size_t required = 0; + + *data = NULL; ++ if (plen) ++ *plen = 0; ++ + switch (type) + { + case NDR_PTR_FULL: +@@ -196,11 +199,20 @@ static LONG smartcard_ndr_read(wLog* log, wStream* s, BYTE** data, size_t min, s + if (!r) + return SCARD_E_NO_MEMORY; + Stream_Read(s, r, len); +- smartcard_unpack_read_size_align(s, len, 4); ++ const LONG pad = smartcard_unpack_read_size_align(s, len, 4); ++ len += (size_t)pad; + *data = r; ++ if (plen) ++ *plen = len; + return STATUS_SUCCESS; + } + ++static LONG smartcard_ndr_read(wLog* log, wStream* s, BYTE** data, size_t min, size_t elementSize, ++ ndr_ptr_t type) ++{ ++ return smartcard_ndr_read_ex(log, s, data, min, elementSize, type, NULL); ++} ++ + static BOOL smartcard_ndr_pointer_write(wStream* s, UINT32* index, DWORD length) + { + const UINT32 ndrPtr = 0x20000 + (*index) * 4; +@@ -3507,12 +3519,15 @@ LONG smartcard_unpack_set_attrib_call(wStream* s, SetAttrib_Call* call) + + if (ndrPtr) + { +- // TODO: call->cbAttrLen was larger than the pointer value. +- // TODO: Maybe need to refine the checks? +- status = smartcard_ndr_read(log, s, &call->pbAttr, 0, 1, NDR_PTR_SIMPLE); ++ size_t len = 0; ++ status = smartcard_ndr_read_ex(log, s, &call->pbAttr, 0, 1, NDR_PTR_SIMPLE, &len); + if (status != SCARD_S_SUCCESS) + return status; ++ if (call->cbAttrLen > len) ++ call->cbAttrLen = WINPR_ASSERTING_INT_CAST(DWORD, len); + } ++ else ++ call->cbAttrLen = 0; + smartcard_trace_set_attrib_call(log, call); + return SCARD_S_SUCCESS; + } +-- +2.47.3 + diff -Nru freerdp3-3.15.0+dfsg/debian/patches/utils-smartcard-better-logging-and-error-checks.patch freerdp3-3.15.0+dfsg/debian/patches/utils-smartcard-better-logging-and-error-checks.patch --- freerdp3-3.15.0+dfsg/debian/patches/utils-smartcard-better-logging-and-error-checks.patch 1970-01-01 00:00:00.000000000 +0000 +++ freerdp3-3.15.0+dfsg/debian/patches/utils-smartcard-better-logging-and-error-checks.patch 2026-02-09 18:48:59.000000000 +0000 @@ -0,0 +1,4053 @@ +From: akallabeth +Date: Tue, 27 May 2025 08:51:20 +0200 +Subject: [utils,smartcard] better logging and error checks +Origin: upstream, https://github.com/FreeRDP/FreeRDP/commit/6b80a2d4ef934a8e9355fcf5131490e5f256fa67 +Forwarded: not-needed +Comment: Logging improvements and better error checking in preparation for CVE-2026-22852 + +* Use wLog as argument where possible to reduce the number of WLog_Get + calls +* Do better failure checks to avoid reading invalid memory +--- + include/freerdp/utils/rdpdr_utils.h | 11 + + libfreerdp/utils/CMakeLists.txt | 1 + + libfreerdp/utils/rdpdr_utils.c | 8 +- + libfreerdp/utils/smartcard_call.c | 162 +-- + libfreerdp/utils/smartcard_operations.c | 12 +- + libfreerdp/utils/smartcard_pack.c | 1284 +++++++++++++---------- + libfreerdp/utils/smartcard_pack.h | 28 + + 7 files changed, 863 insertions(+), 643 deletions(-) + create mode 100644 libfreerdp/utils/smartcard_pack.h + +diff --git a/include/freerdp/utils/rdpdr_utils.h b/include/freerdp/utils/rdpdr_utils.h +index 1ef53fe02..1085ba97c 100644 +--- a/include/freerdp/utils/rdpdr_utils.h ++++ b/include/freerdp/utils/rdpdr_utils.h +@@ -51,6 +51,17 @@ extern "C" + FREERDP_API const char* rdpdr_cap_type_string(UINT16 capability); + + FREERDP_API LONG scard_log_status_error(const char* tag, const char* what, LONG status); ++ ++ /** @brief log a smartcard related issue with a wLog ++ * ++ * @param log The logger to use ++ * @param what The module affected ++ * @param status The status to log ++ * ++ * @return The \ref status logged ++ * @since version 3.16.0 ++ */ ++ FREERDP_API LONG scard_log_status_error_wlog(wLog* log, const char* what, LONG status); + FREERDP_API const char* scard_get_ioctl_string(UINT32 ioControlCode, BOOL funcName); + + FREERDP_API BOOL rdpdr_write_iocompletion_header(wStream* out, UINT32 DeviceId, +diff --git a/libfreerdp/utils/CMakeLists.txt b/libfreerdp/utils/CMakeLists.txt +index 5040f9b0b..c72d02158 100644 +--- a/libfreerdp/utils/CMakeLists.txt ++++ b/libfreerdp/utils/CMakeLists.txt +@@ -32,6 +32,7 @@ set(${MODULE_PREFIX}_SRCS + gfx.c + drdynvc.c + smartcard_operations.c ++ smartcard_pack.h + smartcard_pack.c + smartcard_call.c + stopwatch.c +diff --git a/libfreerdp/utils/rdpdr_utils.c b/libfreerdp/utils/rdpdr_utils.c +index 5ceb82246..5f7f26604 100644 +--- a/libfreerdp/utils/rdpdr_utils.c ++++ b/libfreerdp/utils/rdpdr_utils.c +@@ -29,6 +29,12 @@ + #include + + LONG scard_log_status_error(const char* tag, const char* what, LONG status) ++{ ++ wLog* log = WLog_Get(tag); ++ return scard_log_status_error_wlog(log, what, status); ++} ++ ++LONG scard_log_status_error_wlog(wLog* log, const char* what, LONG status) + { + if (status != SCARD_S_SUCCESS) + { +@@ -44,7 +50,7 @@ LONG scard_log_status_error(const char* tag, const char* what, LONG status) + default: + break; + } +- WLog_Print(WLog_Get(tag), level, "%s failed with error %s [%" PRId32 "]", what, ++ WLog_Print(log, level, "%s failed with error %s [%" PRId32 "]", what, + SCardGetErrorString(status), status); + } + return status; +diff --git a/libfreerdp/utils/smartcard_call.c b/libfreerdp/utils/smartcard_call.c +index 1209ced47..b66030664 100644 +--- a/libfreerdp/utils/smartcard_call.c ++++ b/libfreerdp/utils/smartcard_call.c +@@ -41,8 +41,10 @@ + #include + #include + ++#include "smartcard_pack.h" ++ + #include +-#define TAG FREERDP_TAG("utils.smartcard.call") ++#define SCARD_TAG FREERDP_TAG("utils.smartcard.call") + + #if defined(WITH_SMARTCARD_EMULATE) + #include +@@ -75,6 +77,7 @@ struct s_scard_call_context + + void* (*fn_new)(void*, SCARDCONTEXT); + void (*fn_free)(void*); ++ wLog* log; + }; + + struct s_scard_context_element +@@ -117,14 +120,14 @@ static LONG smartcard_EstablishContext_Call(scard_call_context* smartcard, wStre + + if (!HashTable_Insert(smartcard->rgSCardContextList, key, (void*)pContext)) + { +- WLog_ERR(TAG, "ListDictionary_Add failed!"); ++ WLog_Print(smartcard->log, WLOG_ERROR, "ListDictionary_Add failed!"); + context_free(pContext); + return STATUS_INTERNAL_ERROR; + } + } + else + { +- return scard_log_status_error(TAG, "SCardEstablishContext", status); ++ return scard_log_status_error_wlog(smartcard->log, "SCardEstablishContext", status); + } + + // NOLINTNEXTLINE(clang-analyzer-unix.Malloc): HashTable_Insert takes ownership of pContext +@@ -133,7 +136,8 @@ static LONG smartcard_EstablishContext_Call(scard_call_context* smartcard, wStre + status = smartcard_pack_establish_context_return(out, &ret); + if (status != SCARD_S_SUCCESS) + { +- return scard_log_status_error(TAG, "smartcard_pack_establish_context_return", status); ++ return scard_log_status_error_wlog(smartcard->log, ++ "smartcard_pack_establish_context_return", status); + } + + return ret.ReturnCode; +@@ -155,10 +159,10 @@ static LONG smartcard_ReleaseContext_Call(scard_call_context* smartcard, + HashTable_Remove(smartcard->rgSCardContextList, (void*)operation->hContext); + else + { +- return scard_log_status_error(TAG, "SCardReleaseContext", ret.ReturnCode); ++ return scard_log_status_error_wlog(smartcard->log, "SCardReleaseContext", ret.ReturnCode); + } + +- smartcard_trace_long_return(&ret, "ReleaseContext"); ++ smartcard_trace_long_return_int(smartcard->log, &ret, "ReleaseContext"); + return ret.ReturnCode; + } + +@@ -173,7 +177,7 @@ static LONG smartcard_IsValidContext_Call(scard_call_context* smartcard, + WINPR_ASSERT(operation); + + ret.ReturnCode = wrap(smartcard, SCardIsValidContext, operation->hContext); +- smartcard_trace_long_return(&ret, "IsValidContext"); ++ smartcard_trace_long_return_int(smartcard->log, &ret, "IsValidContext"); + return ret.ReturnCode; + } + +@@ -356,7 +360,7 @@ static LONG smartcard_ListReadersA_Call(scard_call_context* smartcard, wStream* + + if (status != SCARD_S_SUCCESS) + { +- (void)scard_log_status_error(TAG, "SCardListReadersA", status); ++ (void)scard_log_status_error_wlog(smartcard->log, "SCardListReadersA", status); + return smartcard_pack_list_readers_return(out, &ret, FALSE); + } + +@@ -369,7 +373,8 @@ static LONG smartcard_ListReadersA_Call(scard_call_context* smartcard, wStream* + wrap(smartcard, SCardFreeMemory, operation->hContext, mszReaders); + + if (status != SCARD_S_SUCCESS) +- return scard_log_status_error(TAG, "smartcard_pack_list_readers_return", status); ++ return scard_log_status_error_wlog(smartcard->log, "smartcard_pack_list_readers_return", ++ status); + + return ret.ReturnCode; + } +@@ -412,7 +417,7 @@ static LONG smartcard_ListReadersW_Call(scard_call_context* smartcard, wStream* + + if (status != SCARD_S_SUCCESS) + { +- (void)scard_log_status_error(TAG, "SCardListReadersW", status); ++ (void)scard_log_status_error_wlog(smartcard->log, "SCardListReadersW", status); + return smartcard_pack_list_readers_return(out, &ret, TRUE); + } + +@@ -443,8 +448,8 @@ static LONG smartcard_IntroduceReaderGroupA_Call(scard_call_context* smartcard, + + call = &operation->call.contextAndStringA; + ret.ReturnCode = wrap(smartcard, SCardIntroduceReaderGroupA, operation->hContext, call->sz); +- scard_log_status_error(TAG, "SCardIntroduceReaderGroupA", ret.ReturnCode); +- smartcard_trace_long_return(&ret, "IntroduceReaderGroupA"); ++ scard_log_status_error_wlog(smartcard->log, "SCardIntroduceReaderGroupA", ret.ReturnCode); ++ smartcard_trace_long_return_int(smartcard->log, &ret, "IntroduceReaderGroupA"); + return ret.ReturnCode; + } + +@@ -461,8 +466,8 @@ static LONG smartcard_IntroduceReaderGroupW_Call(scard_call_context* smartcard, + + call = &operation->call.contextAndStringW; + ret.ReturnCode = wrap(smartcard, SCardIntroduceReaderGroupW, operation->hContext, call->sz); +- scard_log_status_error(TAG, "SCardIntroduceReaderGroupW", ret.ReturnCode); +- smartcard_trace_long_return(&ret, "IntroduceReaderGroupW"); ++ scard_log_status_error_wlog(smartcard->log, "SCardIntroduceReaderGroupW", ret.ReturnCode); ++ smartcard_trace_long_return_int(smartcard->log, &ret, "IntroduceReaderGroupW"); + return ret.ReturnCode; + } + +@@ -480,8 +485,8 @@ static LONG smartcard_IntroduceReaderA_Call(scard_call_context* smartcard, + call = &operation->call.contextAndTwoStringA; + ret.ReturnCode = + wrap(smartcard, SCardIntroduceReaderA, operation->hContext, call->sz1, call->sz2); +- scard_log_status_error(TAG, "SCardIntroduceReaderA", ret.ReturnCode); +- smartcard_trace_long_return(&ret, "IntroduceReaderA"); ++ scard_log_status_error_wlog(smartcard->log, "SCardIntroduceReaderA", ret.ReturnCode); ++ smartcard_trace_long_return_int(smartcard->log, &ret, "IntroduceReaderA"); + return ret.ReturnCode; + } + +@@ -499,8 +504,8 @@ static LONG smartcard_IntroduceReaderW_Call(scard_call_context* smartcard, + call = &operation->call.contextAndTwoStringW; + ret.ReturnCode = + wrap(smartcard, SCardIntroduceReaderW, operation->hContext, call->sz1, call->sz2); +- scard_log_status_error(TAG, "SCardIntroduceReaderW", ret.ReturnCode); +- smartcard_trace_long_return(&ret, "IntroduceReaderW"); ++ scard_log_status_error_wlog(smartcard->log, "SCardIntroduceReaderW", ret.ReturnCode); ++ smartcard_trace_long_return_int(smartcard->log, &ret, "IntroduceReaderW"); + return ret.ReturnCode; + } + +@@ -517,8 +522,8 @@ static LONG smartcard_ForgetReaderA_Call(scard_call_context* smartcard, + + call = &operation->call.contextAndStringA; + ret.ReturnCode = wrap(smartcard, SCardForgetReaderA, operation->hContext, call->sz); +- scard_log_status_error(TAG, "SCardForgetReaderA", ret.ReturnCode); +- smartcard_trace_long_return(&ret, "SCardForgetReaderA"); ++ scard_log_status_error_wlog(smartcard->log, "SCardForgetReaderA", ret.ReturnCode); ++ smartcard_trace_long_return_int(smartcard->log, &ret, "SCardForgetReaderA"); + return ret.ReturnCode; + } + +@@ -535,8 +540,8 @@ static LONG smartcard_ForgetReaderW_Call(scard_call_context* smartcard, + + call = &operation->call.contextAndStringW; + ret.ReturnCode = wrap(smartcard, SCardForgetReaderW, operation->hContext, call->sz); +- scard_log_status_error(TAG, "SCardForgetReaderW", ret.ReturnCode); +- smartcard_trace_long_return(&ret, "SCardForgetReaderW"); ++ scard_log_status_error_wlog(smartcard->log, "SCardForgetReaderW", ret.ReturnCode); ++ smartcard_trace_long_return_int(smartcard->log, &ret, "SCardForgetReaderW"); + return ret.ReturnCode; + } + +@@ -554,8 +559,8 @@ static LONG smartcard_AddReaderToGroupA_Call(scard_call_context* smartcard, + call = &operation->call.contextAndTwoStringA; + ret.ReturnCode = + wrap(smartcard, SCardAddReaderToGroupA, operation->hContext, call->sz1, call->sz2); +- scard_log_status_error(TAG, "SCardAddReaderToGroupA", ret.ReturnCode); +- smartcard_trace_long_return(&ret, "SCardAddReaderToGroupA"); ++ scard_log_status_error_wlog(smartcard->log, "SCardAddReaderToGroupA", ret.ReturnCode); ++ smartcard_trace_long_return_int(smartcard->log, &ret, "SCardAddReaderToGroupA"); + return ret.ReturnCode; + } + +@@ -573,8 +578,8 @@ static LONG smartcard_AddReaderToGroupW_Call(scard_call_context* smartcard, + call = &operation->call.contextAndTwoStringW; + ret.ReturnCode = + wrap(smartcard, SCardAddReaderToGroupW, operation->hContext, call->sz1, call->sz2); +- scard_log_status_error(TAG, "SCardAddReaderToGroupW", ret.ReturnCode); +- smartcard_trace_long_return(&ret, "SCardAddReaderToGroupA"); ++ scard_log_status_error_wlog(smartcard->log, "SCardAddReaderToGroupW", ret.ReturnCode); ++ smartcard_trace_long_return_int(smartcard->log, &ret, "SCardAddReaderToGroupA"); + return ret.ReturnCode; + } + +@@ -592,8 +597,8 @@ static LONG smartcard_RemoveReaderFromGroupA_Call(scard_call_context* smartcard, + call = &operation->call.contextAndTwoStringA; + ret.ReturnCode = + wrap(smartcard, SCardRemoveReaderFromGroupA, operation->hContext, call->sz1, call->sz2); +- scard_log_status_error(TAG, "SCardRemoveReaderFromGroupA", ret.ReturnCode); +- smartcard_trace_long_return(&ret, "SCardRemoveReaderFromGroupA"); ++ scard_log_status_error_wlog(smartcard->log, "SCardRemoveReaderFromGroupA", ret.ReturnCode); ++ smartcard_trace_long_return_int(smartcard->log, &ret, "SCardRemoveReaderFromGroupA"); + return ret.ReturnCode; + } + +@@ -611,8 +616,8 @@ static LONG smartcard_RemoveReaderFromGroupW_Call(scard_call_context* smartcard, + call = &operation->call.contextAndTwoStringW; + ret.ReturnCode = + wrap(smartcard, SCardRemoveReaderFromGroupW, operation->hContext, call->sz1, call->sz2); +- scard_log_status_error(TAG, "SCardRemoveReaderFromGroupW", ret.ReturnCode); +- smartcard_trace_long_return(&ret, "SCardRemoveReaderFromGroupW"); ++ scard_log_status_error_wlog(smartcard->log, "SCardRemoveReaderFromGroupW", ret.ReturnCode); ++ smartcard_trace_long_return_int(smartcard->log, &ret, "SCardRemoveReaderFromGroupW"); + return ret.ReturnCode; + } + +@@ -630,7 +635,7 @@ static LONG smartcard_LocateCardsA_Call(scard_call_context* smartcard, wStream* + + ret.ReturnCode = wrap(smartcard, SCardLocateCardsA, operation->hContext, call->mszCards, + call->rgReaderStates, call->cReaders); +- scard_log_status_error(TAG, "SCardLocateCardsA", ret.ReturnCode); ++ scard_log_status_error_wlog(smartcard->log, "SCardLocateCardsA", ret.ReturnCode); + ret.cReaders = call->cReaders; + ret.rgReaderStates = NULL; + +@@ -673,7 +678,7 @@ static LONG smartcard_LocateCardsW_Call(scard_call_context* smartcard, wStream* + + ret.ReturnCode = wrap(smartcard, SCardLocateCardsW, operation->hContext, call->mszCards, + call->rgReaderStates, call->cReaders); +- scard_log_status_error(TAG, "SCardLocateCardsW", ret.ReturnCode); ++ scard_log_status_error_wlog(smartcard->log, "SCardLocateCardsW", ret.ReturnCode); + ret.cReaders = call->cReaders; + ret.rgReaderStates = NULL; + +@@ -739,7 +744,7 @@ static LONG smartcard_ReadCacheA_Call(scard_call_context* smartcard, wStream* ou + if ((ret.ReturnCode != SCARD_W_CACHE_ITEM_NOT_FOUND) && + (ret.ReturnCode != SCARD_W_CACHE_ITEM_STALE)) + { +- scard_log_status_error(TAG, "SCardReadCacheA", ret.ReturnCode); ++ scard_log_status_error_wlog(smartcard->log, "SCardReadCacheA", ret.ReturnCode); + } + + status = smartcard_pack_read_cache_return(out, &ret); +@@ -776,7 +781,7 @@ static LONG smartcard_ReadCacheW_Call(scard_call_context* smartcard, wStream* ou + if ((ret.ReturnCode != SCARD_W_CACHE_ITEM_NOT_FOUND) && + (ret.ReturnCode != SCARD_W_CACHE_ITEM_STALE)) + { +- scard_log_status_error(TAG, "SCardReadCacheW", ret.ReturnCode); ++ scard_log_status_error_wlog(smartcard->log, "SCardReadCacheW", ret.ReturnCode); + } + + status = smartcard_pack_read_cache_return(out, &ret); +@@ -805,8 +810,8 @@ static LONG smartcard_WriteCacheA_Call(scard_call_context* smartcard, + ret.ReturnCode = wrap(smartcard, SCardWriteCacheA, operation->hContext, + call->Common.CardIdentifier, call->Common.FreshnessCounter, + call->szLookupName, call->Common.pbData, call->Common.cbDataLen); +- scard_log_status_error(TAG, "SCardWriteCacheA", ret.ReturnCode); +- smartcard_trace_long_return(&ret, "SCardWriteCacheA"); ++ scard_log_status_error_wlog(smartcard->log, "SCardWriteCacheA", ret.ReturnCode); ++ smartcard_trace_long_return_int(smartcard->log, &ret, "SCardWriteCacheA"); + return ret.ReturnCode; + } + +@@ -826,8 +831,8 @@ static LONG smartcard_WriteCacheW_Call(scard_call_context* smartcard, + ret.ReturnCode = wrap(smartcard, SCardWriteCacheW, operation->hContext, + call->Common.CardIdentifier, call->Common.FreshnessCounter, + call->szLookupName, call->Common.pbData, call->Common.cbDataLen); +- scard_log_status_error(TAG, "SCardWriteCacheW", ret.ReturnCode); +- smartcard_trace_long_return(&ret, "SCardWriteCacheW"); ++ scard_log_status_error_wlog(smartcard->log, "SCardWriteCacheW", ret.ReturnCode); ++ smartcard_trace_long_return_int(smartcard->log, &ret, "SCardWriteCacheW"); + return ret.ReturnCode; + } + +@@ -842,7 +847,7 @@ static LONG smartcard_GetTransmitCount_Call(scard_call_context* smartcard, wStre + WINPR_ASSERT(operation); + + ret.ReturnCode = wrap(smartcard, SCardGetTransmitCount, operation->hCard, &ret.cTransmitCount); +- scard_log_status_error(TAG, "SCardGetTransmitCount", ret.ReturnCode); ++ scard_log_status_error_wlog(smartcard->log, "SCardGetTransmitCount", ret.ReturnCode); + status = smartcard_pack_get_transmit_count_return(out, &ret); + if (status != SCARD_S_SUCCESS) + return status; +@@ -857,8 +862,9 @@ static LONG smartcard_ReleaseStartedEvent_Call(scard_call_context* smartcard, wS + WINPR_UNUSED(out); + WINPR_UNUSED(operation); + +- WLog_WARN(TAG, "According to [MS-RDPESC] 3.1.4 Message Processing Events and Sequencing Rules " +- "this is not supported?!?"); ++ WLog_Print(smartcard->log, WLOG_WARN, ++ "According to [MS-RDPESC] 3.1.4 Message Processing Events and Sequencing Rules " ++ "this is not supported?!?"); + return SCARD_E_UNSUPPORTED_FEATURE; + } + +@@ -878,7 +884,7 @@ static LONG smartcard_GetReaderIcon_Call(scard_call_context* smartcard, wStream* + ret.cbDataLen = SCARD_AUTOALLOCATE; + ret.ReturnCode = wrap(smartcard, SCardGetReaderIconW, operation->hContext, call->szReaderName, + (LPBYTE)&ret.pbData, &ret.cbDataLen); +- scard_log_status_error(TAG, "SCardGetReaderIconW", ret.ReturnCode); ++ scard_log_status_error_wlog(smartcard->log, "SCardGetReaderIconW", ret.ReturnCode); + if ((ret.ReturnCode == SCARD_S_SUCCESS) && (ret.cbDataLen == SCARD_AUTOALLOCATE)) + return SCARD_F_UNKNOWN_ERROR; + +@@ -905,7 +911,7 @@ static LONG smartcard_GetDeviceTypeId_Call(scard_call_context* smartcard, wStrea + + ret.ReturnCode = wrap(smartcard, SCardGetDeviceTypeIdW, operation->hContext, call->szReaderName, + &ret.dwDeviceId); +- scard_log_status_error(TAG, "SCardGetDeviceTypeIdW", ret.ReturnCode); ++ scard_log_status_error_wlog(smartcard->log, "SCardGetDeviceTypeIdW", ret.ReturnCode); + + status = smartcard_pack_device_type_id_return(out, &ret); + if (status != SCARD_S_SUCCESS) +@@ -954,7 +960,7 @@ static LONG smartcard_GetStatusChangeA_Call(scard_call_context* smartcard, wStre + if (dwTimeOut != INFINITE) + x += dwTimeStep; + } +- scard_log_status_error(TAG, "SCardGetStatusChangeA", ret.ReturnCode); ++ scard_log_status_error_wlog(smartcard->log, "SCardGetStatusChangeA", ret.ReturnCode); + + for (UINT32 index = 0; index < ret.cReaders; index++) + { +@@ -1017,7 +1023,7 @@ static LONG smartcard_GetStatusChangeW_Call(scard_call_context* smartcard, wStre + if (dwTimeOut != INFINITE) + x += dwTimeStep; + } +- scard_log_status_error(TAG, "SCardGetStatusChangeW", ret.ReturnCode); ++ scard_log_status_error_wlog(smartcard->log, "SCardGetStatusChangeW", ret.ReturnCode); + + for (UINT32 index = 0; index < ret.cReaders; index++) + { +@@ -1049,8 +1055,8 @@ static LONG smartcard_Cancel_Call(scard_call_context* smartcard, WINPR_ATTR_UNUS + WINPR_ASSERT(operation); + + ret.ReturnCode = wrap(smartcard, SCardCancel, operation->hContext); +- scard_log_status_error(TAG, "SCardCancel", ret.ReturnCode); +- smartcard_trace_long_return(&ret, "Cancel"); ++ scard_log_status_error_wlog(smartcard->log, "SCardCancel", ret.ReturnCode); ++ smartcard_trace_long_return_int(smartcard->log, &ret, "Cancel"); + return ret.ReturnCode; + } + +@@ -1141,7 +1147,7 @@ static LONG smartcard_Reconnect_Call(scard_call_context* smartcard, wStream* out + ret.ReturnCode = + wrap(smartcard, SCardReconnect, operation->hCard, call->dwShareMode, + call->dwPreferredProtocols, call->dwInitialization, &ret.dwActiveProtocol); +- scard_log_status_error(TAG, "SCardReconnect", ret.ReturnCode); ++ scard_log_status_error_wlog(smartcard->log, "SCardReconnect", ret.ReturnCode); + status = smartcard_pack_reconnect_return(out, &ret); + if (status != SCARD_S_SUCCESS) + return status; +@@ -1162,8 +1168,8 @@ static LONG smartcard_Disconnect_Call(scard_call_context* smartcard, WINPR_ATTR_ + call = &operation->call.hCardAndDisposition; + + ret.ReturnCode = wrap(smartcard, SCardDisconnect, operation->hCard, call->dwDisposition); +- scard_log_status_error(TAG, "SCardDisconnect", ret.ReturnCode); +- smartcard_trace_long_return(&ret, "Disconnect"); ++ scard_log_status_error_wlog(smartcard->log, "SCardDisconnect", ret.ReturnCode); ++ smartcard_trace_long_return_int(smartcard->log, &ret, "Disconnect"); + + return ret.ReturnCode; + } +@@ -1179,8 +1185,8 @@ static LONG smartcard_BeginTransaction_Call(scard_call_context* smartcard, + WINPR_ASSERT(operation); + + ret.ReturnCode = wrap(smartcard, SCardBeginTransaction, operation->hCard); +- scard_log_status_error(TAG, "SCardBeginTransaction", ret.ReturnCode); +- smartcard_trace_long_return(&ret, "BeginTransaction"); ++ scard_log_status_error_wlog(smartcard->log, "SCardBeginTransaction", ret.ReturnCode); ++ smartcard_trace_long_return_int(smartcard->log, &ret, "BeginTransaction"); + return ret.ReturnCode; + } + +@@ -1198,8 +1204,8 @@ static LONG smartcard_EndTransaction_Call(scard_call_context* smartcard, + call = &operation->call.hCardAndDisposition; + + ret.ReturnCode = wrap(smartcard, SCardEndTransaction, operation->hCard, call->dwDisposition); +- scard_log_status_error(TAG, "SCardEndTransaction", ret.ReturnCode); +- smartcard_trace_long_return(&ret, "EndTransaction"); ++ scard_log_status_error_wlog(smartcard->log, "SCardEndTransaction", ret.ReturnCode); ++ smartcard_trace_long_return_int(smartcard->log, &ret, "EndTransaction"); + return ret.ReturnCode; + } + +@@ -1217,7 +1223,7 @@ static LONG smartcard_State_Call(scard_call_context* smartcard, wStream* out, + ret.ReturnCode = wrap(smartcard, SCardState, operation->hCard, &ret.dwState, &ret.dwProtocol, + (BYTE*)&ret.rgAtr, &ret.cbAtrLen); + +- scard_log_status_error(TAG, "SCardState", ret.ReturnCode); ++ scard_log_status_error_wlog(smartcard->log, "SCardState", ret.ReturnCode); + status = smartcard_pack_state_return(out, &ret); + if (status != SCARD_S_SUCCESS) + return status; +@@ -1254,7 +1260,7 @@ static LONG smartcard_StatusA_Call(scard_call_context* smartcard, wStream* out, + call->fmszReaderNamesIsNULL ? NULL : (LPSTR)&mszReaderNames, &cchReaderLen, + &ret.dwState, &ret.dwProtocol, cbAtrLen ? (BYTE*)&ret.pbAtr : NULL, &cbAtrLen); + +- scard_log_status_error(TAG, "SCardStatusA", status); ++ scard_log_status_error_wlog(smartcard->log, "SCardStatusA", status); + if ((ret.ReturnCode == SCARD_S_SUCCESS) && (cchReaderLen == SCARD_AUTOALLOCATE)) + return SCARD_F_UNKNOWN_ERROR; + +@@ -1309,7 +1315,7 @@ static LONG smartcard_StatusW_Call(scard_call_context* smartcard, wStream* out, + wrap(smartcard, SCardStatusW, operation->hCard, + call->fmszReaderNamesIsNULL ? NULL : (LPWSTR)&mszReaderNames, &ret.cBytes, + &ret.dwState, &ret.dwProtocol, (BYTE*)&ret.pbAtr, &cbAtrLen); +- scard_log_status_error(TAG, "SCardStatusW", status); ++ scard_log_status_error_wlog(smartcard->log, "SCardStatusW", status); + if ((ret.ReturnCode == SCARD_S_SUCCESS) && (ret.cBytes == SCARD_AUTOALLOCATE)) + return SCARD_F_UNKNOWN_ERROR; + +@@ -1369,7 +1375,7 @@ static LONG smartcard_Transmit_Call(scard_call_context* smartcard, wStream* out, + wrap(smartcard, SCardTransmit, operation->hCard, call->pioSendPci, call->pbSendBuffer, + call->cbSendLength, ret.pioRecvPci, ret.pbRecvBuffer, &(ret.cbRecvLength)); + +- scard_log_status_error(TAG, "SCardTransmit", ret.ReturnCode); ++ scard_log_status_error_wlog(smartcard->log, "SCardTransmit", ret.ReturnCode); + + status = smartcard_pack_transmit_return(out, &ret); + free(ret.pbRecvBuffer); +@@ -1400,7 +1406,7 @@ static LONG smartcard_Control_Call(scard_call_context* smartcard, wStream* out, + ret.ReturnCode = + wrap(smartcard, SCardControl, operation->hCard, call->dwControlCode, call->pvInBuffer, + call->cbInBufferSize, ret.pvOutBuffer, call->cbOutBufferSize, &ret.cbOutBufferSize); +- scard_log_status_error(TAG, "SCardControl", ret.ReturnCode); ++ scard_log_status_error_wlog(smartcard->log, "SCardControl", ret.ReturnCode); + status = smartcard_pack_control_return(out, &ret); + + free(ret.pvOutBuffer); +@@ -1441,7 +1447,7 @@ static LONG smartcard_GetAttrib_Call(scard_call_context* smartcard, wStream* out + + ret.ReturnCode = + wrap(smartcard, SCardGetAttrib, operation->hCard, call->dwAttrId, pbAttr, &cbAttrLen); +- scard_log_status_error(TAG, "SCardGetAttrib", ret.ReturnCode); ++ scard_log_status_error_wlog(smartcard->log, "SCardGetAttrib", ret.ReturnCode); + if ((ret.ReturnCode == SCARD_S_SUCCESS) && (cbAttrLen == SCARD_AUTOALLOCATE)) + return SCARD_F_UNKNOWN_ERROR; + +@@ -1470,8 +1476,8 @@ static LONG smartcard_SetAttrib_Call(scard_call_context* smartcard, WINPR_ATTR_U + + ret.ReturnCode = wrap(smartcard, SCardSetAttrib, operation->hCard, call->dwAttrId, call->pbAttr, + call->cbAttrLen); +- scard_log_status_error(TAG, "SCardSetAttrib", ret.ReturnCode); +- smartcard_trace_long_return(&ret, "SetAttrib"); ++ scard_log_status_error_wlog(smartcard->log, "SCardSetAttrib", ret.ReturnCode); ++ smartcard_trace_long_return_int(smartcard->log, &ret, "SetAttrib"); + + return ret.ReturnCode; + } +@@ -1525,7 +1531,7 @@ static LONG smartcard_LocateCardsByATRA_Call(scard_call_context* smartcard, wStr + status = ret.ReturnCode = wrap(smartcard, SCardGetStatusChangeA, operation->hContext, + 0x000001F4, states, call->cReaders); + +- scard_log_status_error(TAG, "SCardGetStatusChangeA", status); ++ scard_log_status_error_wlog(smartcard->log, "SCardGetStatusChangeA", status); + for (UINT32 i = 0; i < call->cAtrs; i++) + { + for (UINT32 j = 0; j < call->cReaders; j++) +@@ -1822,9 +1828,10 @@ LONG smartcard_irp_device_control_call(scard_call_context* smartcard, wStream* o + (result != SCARD_E_NO_READERS_AVAILABLE) && (result != SCARD_E_NO_SERVICE) && + (result != SCARD_W_CACHE_ITEM_NOT_FOUND) && (result != SCARD_W_CACHE_ITEM_STALE)) + { +- WLog_WARN(TAG, "IRP failure: %s (0x%08" PRIX32 "), status: %s (0x%08" PRIX32 ")", +- scard_get_ioctl_string(ioControlCode, TRUE), ioControlCode, +- SCardGetErrorString(result), result); ++ WLog_Print(smartcard->log, WLOG_WARN, ++ "IRP failure: %s (0x%08" PRIX32 "), status: %s (0x%08" PRIX32 ")", ++ scard_get_ioctl_string(ioControlCode, TRUE), ioControlCode, ++ SCardGetErrorString(result), result); + } + + *pIoStatus = STATUS_SUCCESS; +@@ -1833,8 +1840,9 @@ LONG smartcard_irp_device_control_call(scard_call_context* smartcard, wStream* o + { + /* NTSTATUS error */ + *pIoStatus = result; +- WLog_WARN(TAG, "IRP failure: %s (0x%08" PRIX32 "), ntstatus: 0x%08" PRIX32 "", +- scard_get_ioctl_string(ioControlCode, TRUE), ioControlCode, result); ++ WLog_Print(smartcard->log, WLOG_WARN, ++ "IRP failure: %s (0x%08" PRIX32 "), ntstatus: 0x%08" PRIX32 "", ++ scard_get_ioctl_string(ioControlCode, TRUE), ioControlCode, result); + } + + Stream_SealLength(out); +@@ -1856,10 +1864,10 @@ LONG smartcard_irp_device_control_call(scard_call_context* smartcard, wStream* o + */ + if (outputBufferLength > operation->outputBufferLength) + { +- WLog_WARN(TAG, +- "IRP warn: expected outputBufferLength %" PRIu32 ", but current limit %" PRIu32 +- ", respond with STATUS_BUFFER_TOO_SMALL", +- operation->outputBufferLength, outputBufferLength); ++ WLog_Print(smartcard->log, WLOG_WARN, ++ "IRP warn: expected outputBufferLength %" PRIu32 ", but current limit %" PRIu32 ++ ", respond with STATUS_BUFFER_TOO_SMALL", ++ operation->outputBufferLength, outputBufferLength); + + *pIoStatus = STATUS_BUFFER_TOO_SMALL; + result = *pIoStatus; +@@ -1898,6 +1906,9 @@ scard_call_context* smartcard_call_context_new(const rdpSettings* settings) + if (!ctx) + goto fail; + ++ ctx->log = WLog_Get(SCARD_TAG); ++ WINPR_ASSERT(ctx->log); ++ + ctx->stopEvent = CreateEventA(NULL, TRUE, FALSE, NULL); + if (!ctx->stopEvent) + goto fail; +@@ -1917,7 +1928,7 @@ scard_call_context* smartcard_call_context_new(const rdpSettings* settings) + if (!ctx->emulation) + goto fail; + #else +- WLog_ERR(TAG, "Smartcard emulation requested, but not supported!"); ++ WLog_Print(ctx->log, WLOG_ERROR, "Smartcard emulation requested, but not supported!"); + goto fail; + #endif + } +@@ -1930,7 +1941,8 @@ scard_call_context* smartcard_call_context_new(const rdpSettings* settings) + + if (!ctx->hWinSCardLibrary) + { +- WLog_ERR(TAG, "Failed to load WinSCard library: '%s'", WinSCardModule); ++ WLog_Print(ctx->log, WLOG_ERROR, "Failed to load WinSCard library: '%s'", ++ WinSCardModule); + goto fail; + } + +@@ -1945,7 +1957,7 @@ scard_call_context* smartcard_call_context_new(const rdpSettings* settings) + + if (!ctx->pWinSCardApi) + { +- WLog_ERR(TAG, "Failed to load WinSCard API!"); ++ WLog_Print(ctx->log, WLOG_ERROR, "Failed to load WinSCard API!"); + goto fail; + } + } +diff --git a/libfreerdp/utils/smartcard_operations.c b/libfreerdp/utils/smartcard_operations.c +index d317abb5c..2b0127a78 100644 +--- a/libfreerdp/utils/smartcard_operations.c ++++ b/libfreerdp/utils/smartcard_operations.c +@@ -221,26 +221,18 @@ static LONG smartcard_LocateCardsW_Decode(wStream* s, SMARTCARD_OPERATION* opera + + static LONG smartcard_GetStatusChangeA_Decode(wStream* s, SMARTCARD_OPERATION* operation) + { +- LONG status = 0; +- + WINPR_ASSERT(s); + WINPR_ASSERT(operation); + +- status = smartcard_unpack_get_status_change_a_call(s, &operation->call.getStatusChangeA); +- +- return status; ++ return smartcard_unpack_get_status_change_a_call(s, &operation->call.getStatusChangeA); + } + + static LONG smartcard_GetStatusChangeW_Decode(wStream* s, SMARTCARD_OPERATION* operation) + { +- LONG status = 0; +- + WINPR_ASSERT(s); + WINPR_ASSERT(operation); + +- status = smartcard_unpack_get_status_change_w_call(s, &operation->call.getStatusChangeW); +- +- return status; ++ return smartcard_unpack_get_status_change_w_call(s, &operation->call.getStatusChangeW); + } + + static LONG smartcard_Cancel_Decode(wStream* s, SMARTCARD_OPERATION* operation) +diff --git a/libfreerdp/utils/smartcard_pack.c b/libfreerdp/utils/smartcard_pack.c +index 8220571d7..57ae9166d 100644 +--- a/libfreerdp/utils/smartcard_pack.c ++++ b/libfreerdp/utils/smartcard_pack.c +@@ -28,34 +28,48 @@ + + #include + #include ++#include "smartcard_pack.h" + + #include +-#define TAG FREERDP_TAG("scard.pack") ++#define SCARD_TAG FREERDP_TAG("scard.pack") + + static const DWORD g_LogLevel = WLOG_DEBUG; + +-#define smartcard_unpack_redir_scard_context(s, context, index, ndr) \ +- smartcard_unpack_redir_scard_context_((s), (context), (index), (ndr), __FILE__, __func__, \ +- __LINE__) +-#define smartcard_unpack_redir_scard_handle(s, context, index) \ +- smartcard_unpack_redir_scard_handle_((s), (context), (index), __FILE__, __func__, __LINE__) +- +-static LONG smartcard_unpack_redir_scard_context_(wStream* s, REDIR_SCARDCONTEXT* context, +- UINT32* index, UINT32* ppbContextNdrPtr, +- const char* file, const char* function, int line); +-static LONG smartcard_pack_redir_scard_context(wStream* s, const REDIR_SCARDCONTEXT* context, +- DWORD* index); +-static LONG smartcard_unpack_redir_scard_handle_(wStream* s, REDIR_SCARDHANDLE* handle, ++static wLog* scard_log(void) ++{ ++ static wLog* log = NULL; ++ if (!log) ++ log = WLog_Get(SCARD_TAG); ++ return log; ++} ++ ++#define smartcard_unpack_redir_scard_context(log, s, context, index, ndr) \ ++ smartcard_unpack_redir_scard_context_((log), (s), (context), (index), (ndr), __FILE__, \ ++ __func__, __LINE__) ++#define smartcard_unpack_redir_scard_handle(log, s, context, index) \ ++ smartcard_unpack_redir_scard_handle_((log), (s), (context), (index), __FILE__, __func__, \ ++ __LINE__) ++ ++static LONG smartcard_unpack_redir_scard_context_(wLog* log, wStream* s, ++ REDIR_SCARDCONTEXT* context, UINT32* index, ++ UINT32* ppbContextNdrPtr, const char* file, ++ const char* function, size_t line); ++static LONG smartcard_pack_redir_scard_context(wLog* log, wStream* s, ++ const REDIR_SCARDCONTEXT* context, DWORD* index); ++static LONG smartcard_unpack_redir_scard_handle_(wLog* log, wStream* s, REDIR_SCARDHANDLE* handle, + UINT32* index, const char* file, +- const char* function, int line); +-static LONG smartcard_pack_redir_scard_handle(wStream* s, const REDIR_SCARDHANDLE* handle, +- DWORD* index); +-static LONG smartcard_unpack_redir_scard_context_ref(wStream* s, UINT32 pbContextNdrPtr, ++ const char* function, size_t line); ++static LONG smartcard_pack_redir_scard_handle(wLog* log, wStream* s, ++ const REDIR_SCARDHANDLE* handle, DWORD* index); ++static LONG smartcard_unpack_redir_scard_context_ref(wLog* log, wStream* s, UINT32 pbContextNdrPtr, + REDIR_SCARDCONTEXT* context); +-static LONG smartcard_pack_redir_scard_context_ref(wStream* s, const REDIR_SCARDCONTEXT* context); ++static LONG smartcard_pack_redir_scard_context_ref(wLog* log, wStream* s, ++ const REDIR_SCARDCONTEXT* context); + +-static LONG smartcard_unpack_redir_scard_handle_ref(wStream* s, REDIR_SCARDHANDLE* handle); +-static LONG smartcard_pack_redir_scard_handle_ref(wStream* s, const REDIR_SCARDHANDLE* handle); ++static LONG smartcard_unpack_redir_scard_handle_ref(wLog* log, wStream* s, ++ REDIR_SCARDHANDLE* handle); ++static LONG smartcard_pack_redir_scard_handle_ref(wLog* log, wStream* s, ++ const REDIR_SCARDHANDLE* handle); + + typedef enum + { +@@ -66,17 +80,17 @@ typedef enum + + /* Reads a NDR pointer and checks if the value read has the expected relative + * addressing */ +-#define smartcard_ndr_pointer_read(s, index, ptr) \ +- smartcard_ndr_pointer_read_((s), (index), (ptr), __FILE__, __func__, __LINE__) +-static BOOL smartcard_ndr_pointer_read_(wStream* s, UINT32* index, UINT32* ptr, const char* file, +- const char* fkt, size_t line) ++#define smartcard_ndr_pointer_read(log, s, index, ptr) \ ++ smartcard_ndr_pointer_read_((log), (s), (index), (ptr), __FILE__, __func__, __LINE__) ++static BOOL smartcard_ndr_pointer_read_(wLog* log, wStream* s, UINT32* index, UINT32* ptr, ++ const char* file, const char* fkt, size_t line) + { + const UINT32 expect = 0x20000 + (*index) * 4; + UINT32 ndrPtr = 0; + WINPR_UNUSED(file); + if (!s) + return FALSE; +- if (!Stream_CheckAndLogRequiredLength(TAG, s, 4)) ++ if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4)) + return FALSE; + + Stream_Read_UINT32(s, ndrPtr); /* mszGroupsNdrPtr (4 bytes) */ +@@ -87,9 +101,9 @@ static BOOL smartcard_ndr_pointer_read_(wStream* s, UINT32* index, UINT32* ptr, + /* Allow NULL pointer if we read the result */ + if (ptr && (ndrPtr == 0)) + return TRUE; +- WLog_WARN(TAG, +- "[%s:%" PRIuz "] Read context pointer 0x%08" PRIx32 ", expected 0x%08" PRIx32, +- fkt, line, ndrPtr, expect); ++ WLog_Print(log, WLOG_WARN, ++ "[%s:%" PRIuz "] Read context pointer 0x%08" PRIx32 ", expected 0x%08" PRIx32, ++ fkt, line, ndrPtr, expect); + return FALSE; + } + +@@ -97,7 +111,7 @@ static BOOL smartcard_ndr_pointer_read_(wStream* s, UINT32* index, UINT32* ptr, + return TRUE; + } + +-static LONG smartcard_ndr_read(wStream* s, BYTE** data, size_t min, size_t elementSize, ++static LONG smartcard_ndr_read(wLog* log, wStream* s, BYTE** data, size_t min, size_t elementSize, + ndr_ptr_t type) + { + size_t len = 0; +@@ -122,7 +136,7 @@ static LONG smartcard_ndr_read(wStream* s, BYTE** data, size_t min, size_t eleme + return STATUS_INVALID_PARAMETER; + } + +- if (!Stream_CheckAndLogRequiredLength(TAG, s, required)) ++ if (!Stream_CheckAndLogRequiredLengthWLog(log, s, required)) + return STATUS_BUFFER_TOO_SMALL; + + switch (type) +@@ -133,10 +147,10 @@ static LONG smartcard_ndr_read(wStream* s, BYTE** data, size_t min, size_t eleme + Stream_Read_UINT32(s, len2); + if (len != offset + len2) + { +- WLog_ERR(TAG, +- "Invalid data when reading full NDR pointer: total=%" PRIu32 +- ", offset=%" PRIu32 ", remaining=%" PRIu32, +- len, offset, len2); ++ WLog_Print(log, WLOG_ERROR, ++ "Invalid data when reading full NDR pointer: total=%" PRIu32 ++ ", offset=%" PRIu32 ", remaining=%" PRIu32, ++ len, offset, len2); + return STATUS_BUFFER_TOO_SMALL; + } + break; +@@ -145,10 +159,10 @@ static LONG smartcard_ndr_read(wStream* s, BYTE** data, size_t min, size_t eleme + + if ((len != min) && (min > 0)) + { +- WLog_ERR(TAG, +- "Invalid data when reading simple NDR pointer: total=%" PRIu32 +- ", expected=%" PRIu32, +- len, min); ++ WLog_Print(log, WLOG_ERROR, ++ "Invalid data when reading simple NDR pointer: total=%" PRIu32 ++ ", expected=%" PRIu32, ++ len, min); + return STATUS_BUFFER_TOO_SMALL; + } + break; +@@ -161,15 +175,16 @@ static LONG smartcard_ndr_read(wStream* s, BYTE** data, size_t min, size_t eleme + + if (min > len) + { +- WLog_ERR(TAG, "Invalid length read from NDR pointer, minimum %" PRIu32 ", got %" PRIu32, +- min, len); ++ WLog_Print(log, WLOG_ERROR, ++ "Invalid length read from NDR pointer, minimum %" PRIu32 ", got %" PRIu32, min, ++ len); + return STATUS_DATA_ERROR; + } + + if (len > SIZE_MAX / 2) + return STATUS_BUFFER_TOO_SMALL; + +- if (!Stream_CheckAndLogRequiredLengthOfSize(TAG, s, len, elementSize)) ++ if (!Stream_CheckAndLogRequiredLengthOfSizeWLog(log, s, len, elementSize)) + return STATUS_BUFFER_TOO_SMALL; + + len *= elementSize; +@@ -271,8 +286,8 @@ static LONG smartcard_ndr_write_state(wStream* s, const ReaderState_Return* data + return smartcard_ndr_write(s, cnv.data, size, sizeof(ReaderState_Return), type); + } + +-static LONG smartcard_ndr_read_atrmask(wStream* s, LocateCards_ATRMask** data, size_t min, +- ndr_ptr_t type) ++static LONG smartcard_ndr_read_atrmask(wLog* log, wStream* s, LocateCards_ATRMask** data, ++ size_t min, ndr_ptr_t type) + { + union + { +@@ -280,10 +295,11 @@ static LONG smartcard_ndr_read_atrmask(wStream* s, LocateCards_ATRMask** data, s + BYTE** ppv; + } u; + u.ppc = data; +- return smartcard_ndr_read(s, u.ppv, min, sizeof(LocateCards_ATRMask), type); ++ return smartcard_ndr_read(log, s, u.ppv, min, sizeof(LocateCards_ATRMask), type); + } + +-static LONG smartcard_ndr_read_fixed_string_a(wStream* s, CHAR** data, size_t min, ndr_ptr_t type) ++static LONG smartcard_ndr_read_fixed_string_a(wLog* log, wStream* s, CHAR** data, size_t min, ++ ndr_ptr_t type) + { + union + { +@@ -291,10 +307,11 @@ static LONG smartcard_ndr_read_fixed_string_a(wStream* s, CHAR** data, size_t mi + BYTE** ppv; + } u; + u.ppc = data; +- return smartcard_ndr_read(s, u.ppv, min, sizeof(CHAR), type); ++ return smartcard_ndr_read(log, s, u.ppv, min, sizeof(CHAR), type); + } + +-static LONG smartcard_ndr_read_fixed_string_w(wStream* s, WCHAR** data, size_t min, ndr_ptr_t type) ++static LONG smartcard_ndr_read_fixed_string_w(wLog* log, wStream* s, WCHAR** data, size_t min, ++ ndr_ptr_t type) + { + union + { +@@ -302,10 +319,10 @@ static LONG smartcard_ndr_read_fixed_string_w(wStream* s, WCHAR** data, size_t m + BYTE** ppv; + } u; + u.ppc = data; +- return smartcard_ndr_read(s, u.ppv, min, sizeof(WCHAR), type); ++ return smartcard_ndr_read(log, s, u.ppv, min, sizeof(WCHAR), type); + } + +-static LONG smartcard_ndr_read_a(wStream* s, CHAR** data, ndr_ptr_t type) ++static LONG smartcard_ndr_read_a(wLog* log, wStream* s, CHAR** data, ndr_ptr_t type) + { + union + { +@@ -313,10 +330,10 @@ static LONG smartcard_ndr_read_a(wStream* s, CHAR** data, ndr_ptr_t type) + BYTE** ppv; + } u; + u.ppc = data; +- return smartcard_ndr_read(s, u.ppv, 0, sizeof(CHAR), type); ++ return smartcard_ndr_read(log, s, u.ppv, 0, sizeof(CHAR), type); + } + +-static LONG smartcard_ndr_read_w(wStream* s, WCHAR** data, ndr_ptr_t type) ++static LONG smartcard_ndr_read_w(wLog* log, wStream* s, WCHAR** data, ndr_ptr_t type) + { + union + { +@@ -324,10 +341,10 @@ static LONG smartcard_ndr_read_w(wStream* s, WCHAR** data, ndr_ptr_t type) + BYTE** ppv; + } u; + u.ppc = data; +- return smartcard_ndr_read(s, u.ppv, 0, sizeof(WCHAR), type); ++ return smartcard_ndr_read(log, s, u.ppv, 0, sizeof(WCHAR), type); + } + +-static LONG smartcard_ndr_read_u(wStream* s, UUID** data) ++static LONG smartcard_ndr_read_u(wLog* log, wStream* s, UUID** data) + { + union + { +@@ -335,7 +352,7 @@ static LONG smartcard_ndr_read_u(wStream* s, UUID** data) + BYTE** ppv; + } u; + u.ppc = data; +- return smartcard_ndr_read(s, u.ppv, 1, sizeof(UUID), NDR_PTR_FIXED); ++ return smartcard_ndr_read(log, s, u.ppv, 1, sizeof(UUID), NDR_PTR_FIXED); + } + + static char* smartcard_convert_string_list(const void* in, size_t bytes, BOOL unicode) +@@ -432,15 +449,8 @@ static char* smartcard_array_dump(const void* pd, size_t len, char* buffer, size + goto fail; + } + +- /* Ensure '\0' termination */ +- if (bufferLen > 0) +- { +- buffer[bufferLen - 1] = '\0'; +- bufferLen--; +- } +- + rc = _snprintf(buffer, bufferLen, "{ "); +- if ((rc < 0) || ((size_t)rc > bufferLen)) ++ if ((rc < 0) || ((size_t)rc >= bufferLen)) + goto fail; + buffer += rc; + bufferLen -= (size_t)rc; +@@ -448,14 +458,14 @@ static char* smartcard_array_dump(const void* pd, size_t len, char* buffer, size + for (size_t x = 0; x < len; x++) + { + rc = _snprintf(buffer, bufferLen, "%02X", data[x]); +- if ((rc < 0) || ((size_t)rc > bufferLen)) ++ if ((rc < 0) || ((size_t)rc >= bufferLen)) + goto fail; + buffer += rc; + bufferLen -= (size_t)rc; + } + + rc = _snprintf(buffer, bufferLen, " }"); +- if ((rc < 0) || ((size_t)rc > bufferLen)) ++ if ((rc < 0) || ((size_t)rc >= bufferLen)) + goto fail; + + fail: +@@ -481,11 +491,10 @@ static void smartcard_log_context(wLog* log, const REDIR_SCARDCONTEXT* phContext + smartcard_array_dump(phContext->pbContext, phContext->cbContext, buffer, sizeof(buffer))); + } + +-static void smartcard_trace_context_and_string_call_a(const char* name, ++static void smartcard_trace_context_and_string_call_a(wLog* log, const char* name, + const REDIR_SCARDCONTEXT* phContext, + const CHAR* sz) + { +- wLog* log = WLog_Get(TAG); + if (!WLog_IsLevelActive(log, g_LogLevel)) + return; + +@@ -496,12 +505,12 @@ static void smartcard_trace_context_and_string_call_a(const char* name, + WLog_Print(log, g_LogLevel, "}"); + } + +-static void smartcard_trace_context_and_string_call_w(const char* name, ++static void smartcard_trace_context_and_string_call_w(wLog* log, const char* name, + const REDIR_SCARDCONTEXT* phContext, + const WCHAR* sz) + { + char tmp[1024] = { 0 }; +- wLog* log = WLog_Get(TAG); ++ + if (!WLog_IsLevelActive(log, g_LogLevel)) + return; + +@@ -514,11 +523,10 @@ static void smartcard_trace_context_and_string_call_w(const char* name, + WLog_Print(log, g_LogLevel, "}"); + } + +-static void smartcard_trace_context_call(const Context_Call* call, const char* name) ++static void smartcard_trace_context_call(wLog* log, const Context_Call* call, const char* name) + { + WINPR_ASSERT(call); + +- wLog* log = WLog_Get(TAG); + if (!WLog_IsLevelActive(log, g_LogLevel)) + return; + +@@ -528,11 +536,11 @@ static void smartcard_trace_context_call(const Context_Call* call, const char* n + WLog_Print(log, g_LogLevel, "}"); + } + +-static void smartcard_trace_list_reader_groups_call(const ListReaderGroups_Call* call, BOOL unicode) ++static void smartcard_trace_list_reader_groups_call(wLog* log, const ListReaderGroups_Call* call, ++ BOOL unicode) + { + WINPR_ASSERT(call); + +- wLog* log = WLog_Get(TAG); + if (!WLog_IsLevelActive(log, g_LogLevel)) + return; + +@@ -578,6 +586,7 @@ static void dump_reader_states_a(wLog* log, const SCARD_READERSTATEA* rgReaderSt + char buffer[1024] = { 0 }; + + const SCARD_READERSTATEA* readerState = &rgReaderStates[index]; ++ + WLog_Print(log, g_LogLevel, "\t[%" PRIu32 "]: szReader: %s cbAtr: %" PRIu32 "", index, + readerState->szReader, readerState->cbAtr); + char* szCurrentState = SCardGetReaderStateString(readerState->dwCurrentState); +@@ -624,11 +633,10 @@ static void dump_reader_states_w(wLog* log, const SCARD_READERSTATEW* rgReaderSt + } + } + +-static void smartcard_trace_get_status_change_w_call(const GetStatusChangeW_Call* call) ++static void smartcard_trace_get_status_change_w_call(wLog* log, const GetStatusChangeW_Call* call) + { + WINPR_ASSERT(call); + +- wLog* log = WLog_Get(TAG); + if (!WLog_IsLevelActive(log, g_LogLevel)) + return; + +@@ -643,12 +651,11 @@ static void smartcard_trace_get_status_change_w_call(const GetStatusChangeW_Call + WLog_Print(log, g_LogLevel, "}"); + } + +-static void smartcard_trace_list_reader_groups_return(const ListReaderGroups_Return* ret, ++static void smartcard_trace_list_reader_groups_return(wLog* log, const ListReaderGroups_Return* ret, + BOOL unicode) + { + WINPR_ASSERT(ret); + +- wLog* log = WLog_Get(TAG); + if (!WLog_IsLevelActive(log, g_LogLevel)) + return; + +@@ -662,11 +669,10 @@ static void smartcard_trace_list_reader_groups_return(const ListReaderGroups_Ret + free(mszA); + } + +-static void smartcard_trace_list_readers_call(const ListReaders_Call* call, BOOL unicode) ++static void smartcard_trace_list_readers_call(wLog* log, const ListReaders_Call* call, BOOL unicode) + { + WINPR_ASSERT(call); + +- wLog* log = WLog_Get(TAG); + if (!WLog_IsLevelActive(log, g_LogLevel)) + return; + +@@ -684,11 +690,11 @@ static void smartcard_trace_list_readers_call(const ListReaders_Call* call, BOOL + free(mszGroupsA); + } + +-static void smartcard_trace_locate_cards_by_atr_a_call(const LocateCardsByATRA_Call* call) ++static void smartcard_trace_locate_cards_by_atr_a_call(wLog* log, ++ const LocateCardsByATRA_Call* call) + { + WINPR_ASSERT(call); + +- wLog* log = WLog_Get(TAG); + if (!WLog_IsLevelActive(log, g_LogLevel)) + return; + +@@ -700,13 +706,12 @@ static void smartcard_trace_locate_cards_by_atr_a_call(const LocateCardsByATRA_C + WLog_Print(log, g_LogLevel, "}"); + } + +-static void smartcard_trace_locate_cards_a_call(const LocateCardsA_Call* call) ++static void smartcard_trace_locate_cards_a_call(wLog* log, const LocateCardsA_Call* call) + { + char buffer[8192] = { 0 }; + + WINPR_ASSERT(call); + +- wLog* log = WLog_Get(TAG); + if (!WLog_IsLevelActive(log, g_LogLevel)) + return; + +@@ -721,11 +726,10 @@ static void smartcard_trace_locate_cards_a_call(const LocateCardsA_Call* call) + WLog_Print(log, g_LogLevel, "}"); + } + +-static void smartcard_trace_locate_cards_return(const LocateCards_Return* ret) ++static void smartcard_trace_locate_cards_return(wLog* log, const LocateCards_Return* ret) + { + WINPR_ASSERT(ret); + +- wLog* log = WLog_Get(TAG); + if (!WLog_IsLevelActive(log, g_LogLevel)) + return; + +@@ -740,11 +744,10 @@ static void smartcard_trace_locate_cards_return(const LocateCards_Return* ret) + WLog_Print(log, g_LogLevel, "}"); + } + +-static void smartcard_trace_get_reader_icon_return(const GetReaderIcon_Return* ret) ++static void smartcard_trace_get_reader_icon_return(wLog* log, const GetReaderIcon_Return* ret) + { + WINPR_ASSERT(ret); + +- wLog* log = WLog_Get(TAG); + if (!WLog_IsLevelActive(log, g_LogLevel)) + return; + +@@ -759,10 +762,10 @@ static void smartcard_trace_get_reader_icon_return(const GetReaderIcon_Return* r + WLog_Print(log, g_LogLevel, "}"); + } + +-static void smartcard_trace_get_transmit_count_return(const GetTransmitCount_Return* ret) ++static void smartcard_trace_get_transmit_count_return(wLog* log, const GetTransmitCount_Return* ret) + { + WINPR_ASSERT(ret); +- wLog* log = WLog_Get(TAG); ++ + if (!WLog_IsLevelActive(log, g_LogLevel)) + return; + +@@ -774,10 +777,10 @@ static void smartcard_trace_get_transmit_count_return(const GetTransmitCount_Ret + WLog_Print(log, g_LogLevel, "}"); + } + +-static void smartcard_trace_read_cache_return(const ReadCache_Return* ret) ++static void smartcard_trace_read_cache_return(wLog* log, const ReadCache_Return* ret) + { + WINPR_ASSERT(ret); +- wLog* log = WLog_Get(TAG); ++ + if (!WLog_IsLevelActive(log, g_LogLevel)) + return; + +@@ -795,12 +798,11 @@ static void smartcard_trace_read_cache_return(const ReadCache_Return* ret) + WLog_Print(log, g_LogLevel, "}"); + } + +-static void smartcard_trace_locate_cards_w_call(const LocateCardsW_Call* call) ++static void smartcard_trace_locate_cards_w_call(wLog* log, const LocateCardsW_Call* call) + { + WINPR_ASSERT(call); + char buffer[8192] = { 0 }; + +- wLog* log = WLog_Get(TAG); + if (!WLog_IsLevelActive(log, g_LogLevel)) + return; + +@@ -814,11 +816,11 @@ static void smartcard_trace_locate_cards_w_call(const LocateCardsW_Call* call) + WLog_Print(log, g_LogLevel, "}"); + } + +-static void smartcard_trace_list_readers_return(const ListReaders_Return* ret, BOOL unicode) ++static void smartcard_trace_list_readers_return(wLog* log, const ListReaders_Return* ret, ++ BOOL unicode) + { + WINPR_ASSERT(ret); + +- wLog* log = WLog_Get(TAG); + if (!WLog_IsLevelActive(log, g_LogLevel)) + return; + +@@ -839,11 +841,11 @@ static void smartcard_trace_list_readers_return(const ListReaders_Return* ret, B + free(mszA); + } + +-static void smartcard_trace_get_status_change_return(const GetStatusChange_Return* ret, ++static void smartcard_trace_get_status_change_return(wLog* log, const GetStatusChange_Return* ret, + BOOL unicode) + { + WINPR_ASSERT(ret); +- wLog* log = WLog_Get(TAG); ++ + if (!WLog_IsLevelActive(log, g_LogLevel)) + return; + +@@ -888,10 +890,11 @@ static void smartcard_trace_get_status_change_return(const GetStatusChange_Retur + WLog_Print(log, g_LogLevel, "}"); + } + +-static void smartcard_trace_context_and_two_strings_a_call(const ContextAndTwoStringA_Call* call) ++static void smartcard_trace_context_and_two_strings_a_call(wLog* log, ++ const ContextAndTwoStringA_Call* call) + { + WINPR_ASSERT(call); +- wLog* log = WLog_Get(TAG); ++ + if (!WLog_IsLevelActive(log, g_LogLevel)) + return; + +@@ -902,13 +905,13 @@ static void smartcard_trace_context_and_two_strings_a_call(const ContextAndTwoSt + WLog_Print(log, g_LogLevel, "}"); + } + +-static void smartcard_trace_context_and_two_strings_w_call(const ContextAndTwoStringW_Call* call) ++static void smartcard_trace_context_and_two_strings_w_call(wLog* log, ++ const ContextAndTwoStringW_Call* call) + { + WINPR_ASSERT(call); + char sz1[1024] = { 0 }; + char sz2[1024] = { 0 }; + +- wLog* log = WLog_Get(TAG); + if (!WLog_IsLevelActive(log, g_LogLevel)) + return; + if (call->sz1) +@@ -923,10 +926,10 @@ static void smartcard_trace_context_and_two_strings_w_call(const ContextAndTwoSt + WLog_Print(log, g_LogLevel, "}"); + } + +-static void smartcard_trace_get_transmit_count_call(const GetTransmitCount_Call* call) ++static void smartcard_trace_get_transmit_count_call(wLog* log, const GetTransmitCount_Call* call) + { + WINPR_ASSERT(call); +- wLog* log = WLog_Get(TAG); ++ + if (!WLog_IsLevelActive(log, g_LogLevel)) + return; + +@@ -937,12 +940,11 @@ static void smartcard_trace_get_transmit_count_call(const GetTransmitCount_Call* + WLog_Print(log, g_LogLevel, "}"); + } + +-static void smartcard_trace_write_cache_a_call(const WriteCacheA_Call* call) ++static void smartcard_trace_write_cache_a_call(wLog* log, const WriteCacheA_Call* call) + { + WINPR_ASSERT(call); + char buffer[1024] = { 0 }; + +- wLog* log = WLog_Get(TAG); + if (!WLog_IsLevelActive(log, g_LogLevel)) + return; + +@@ -951,24 +953,23 @@ static void smartcard_trace_write_cache_a_call(const WriteCacheA_Call* call) + WLog_Print(log, g_LogLevel, " szLookupName=%s", call->szLookupName); + + smartcard_log_context(log, &call->Common.handles.hContext); +- WLog_DBG( +- TAG, "..CardIdentifier=%s", ++ WLog_Print( ++ log, g_LogLevel, "..CardIdentifier=%s", + smartcard_array_dump(call->Common.CardIdentifier, sizeof(UUID), buffer, sizeof(buffer))); + WLog_Print(log, g_LogLevel, " FreshnessCounter=%" PRIu32, call->Common.FreshnessCounter); + WLog_Print(log, g_LogLevel, " cbDataLen=%" PRIu32, call->Common.cbDataLen); +- WLog_DBG( +- TAG, " pbData=%s", ++ WLog_Print( ++ log, g_LogLevel, " pbData=%s", + smartcard_array_dump(call->Common.pbData, call->Common.cbDataLen, buffer, sizeof(buffer))); + WLog_Print(log, g_LogLevel, "}"); + } + +-static void smartcard_trace_write_cache_w_call(const WriteCacheW_Call* call) ++static void smartcard_trace_write_cache_w_call(wLog* log, const WriteCacheW_Call* call) + { + WINPR_ASSERT(call); + char tmp[1024] = { 0 }; + char buffer[1024] = { 0 }; + +- wLog* log = WLog_Get(TAG); + if (!WLog_IsLevelActive(log, g_LogLevel)) + return; + +@@ -979,23 +980,22 @@ static void smartcard_trace_write_cache_w_call(const WriteCacheW_Call* call) + WLog_Print(log, g_LogLevel, " szLookupName=%s", tmp); + + smartcard_log_context(log, &call->Common.handles.hContext); +- WLog_DBG( +- TAG, "..CardIdentifier=%s", ++ WLog_Print( ++ log, g_LogLevel, "..CardIdentifier=%s", + smartcard_array_dump(call->Common.CardIdentifier, sizeof(UUID), buffer, sizeof(buffer))); + WLog_Print(log, g_LogLevel, " FreshnessCounter=%" PRIu32, call->Common.FreshnessCounter); + WLog_Print(log, g_LogLevel, " cbDataLen=%" PRIu32, call->Common.cbDataLen); +- WLog_DBG( +- TAG, " pbData=%s", ++ WLog_Print( ++ log, g_LogLevel, " pbData=%s", + smartcard_array_dump(call->Common.pbData, call->Common.cbDataLen, buffer, sizeof(buffer))); + WLog_Print(log, g_LogLevel, "}"); + } + +-static void smartcard_trace_read_cache_a_call(const ReadCacheA_Call* call) ++static void smartcard_trace_read_cache_a_call(wLog* log, const ReadCacheA_Call* call) + { + WINPR_ASSERT(call); + char buffer[1024] = { 0 }; + +- wLog* log = WLog_Get(TAG); + if (!WLog_IsLevelActive(log, g_LogLevel)) + return; + +@@ -1003,8 +1003,8 @@ static void smartcard_trace_read_cache_a_call(const ReadCacheA_Call* call) + + WLog_Print(log, g_LogLevel, " szLookupName=%s", call->szLookupName); + smartcard_log_context(log, &call->Common.handles.hContext); +- WLog_DBG( +- TAG, "..CardIdentifier=%s", ++ WLog_Print( ++ log, g_LogLevel, "..CardIdentifier=%s", + smartcard_array_dump(call->Common.CardIdentifier, sizeof(UUID), buffer, sizeof(buffer))); + WLog_Print(log, g_LogLevel, " FreshnessCounter=%" PRIu32, call->Common.FreshnessCounter); + WLog_Print(log, g_LogLevel, " fPbDataIsNULL=%" PRId32, call->Common.fPbDataIsNULL); +@@ -1013,13 +1013,12 @@ static void smartcard_trace_read_cache_a_call(const ReadCacheA_Call* call) + WLog_Print(log, g_LogLevel, "}"); + } + +-static void smartcard_trace_read_cache_w_call(const ReadCacheW_Call* call) ++static void smartcard_trace_read_cache_w_call(wLog* log, const ReadCacheW_Call* call) + { + WINPR_ASSERT(call); + char tmp[1024] = { 0 }; + char buffer[1024] = { 0 }; + +- wLog* log = WLog_Get(TAG); + if (!WLog_IsLevelActive(log, g_LogLevel)) + return; + +@@ -1029,8 +1028,8 @@ static void smartcard_trace_read_cache_w_call(const ReadCacheW_Call* call) + WLog_Print(log, g_LogLevel, " szLookupName=%s", tmp); + + smartcard_log_context(log, &call->Common.handles.hContext); +- WLog_DBG( +- TAG, "..CardIdentifier=%s", ++ WLog_Print( ++ log, g_LogLevel, "..CardIdentifier=%s", + smartcard_array_dump(call->Common.CardIdentifier, sizeof(UUID), buffer, sizeof(buffer))); + WLog_Print(log, g_LogLevel, " FreshnessCounter=%" PRIu32, call->Common.FreshnessCounter); + WLog_Print(log, g_LogLevel, " fPbDataIsNULL=%" PRId32, call->Common.fPbDataIsNULL); +@@ -1039,13 +1038,12 @@ static void smartcard_trace_read_cache_w_call(const ReadCacheW_Call* call) + WLog_Print(log, g_LogLevel, "}"); + } + +-static void smartcard_trace_transmit_call(const Transmit_Call* call) ++static void smartcard_trace_transmit_call(wLog* log, const Transmit_Call* call) + { + WINPR_ASSERT(call); + UINT32 cbExtraBytes = 0; + BYTE* pbExtraBytes = NULL; + +- wLog* log = WLog_Get(TAG); + if (!WLog_IsLevelActive(log, g_LogLevel)) + return; + +@@ -1077,8 +1075,8 @@ static void smartcard_trace_transmit_call(const Transmit_Call* call) + if (call->pbSendBuffer) + { + char buffer[1024] = { 0 }; +- WLog_DBG( +- TAG, "pbSendBuffer: %s", ++ WLog_Print( ++ log, g_LogLevel, "pbSendBuffer: %s", + smartcard_array_dump(call->pbSendBuffer, call->cbSendLength, buffer, sizeof(buffer))); + } + else +@@ -1110,10 +1108,11 @@ static void smartcard_trace_transmit_call(const Transmit_Call* call) + WLog_Print(log, g_LogLevel, "}"); + } + +-static void smartcard_trace_locate_cards_by_atr_w_call(const LocateCardsByATRW_Call* call) ++static void smartcard_trace_locate_cards_by_atr_w_call(wLog* log, ++ const LocateCardsByATRW_Call* call) + { + WINPR_ASSERT(call); +- wLog* log = WLog_Get(TAG); ++ + if (!WLog_IsLevelActive(log, g_LogLevel)) + return; + +@@ -1125,13 +1124,12 @@ static void smartcard_trace_locate_cards_by_atr_w_call(const LocateCardsByATRW_C + WLog_Print(log, g_LogLevel, "}"); + } + +-static void smartcard_trace_transmit_return(const Transmit_Return* ret) ++static void smartcard_trace_transmit_return(wLog* log, const Transmit_Return* ret) + { + WINPR_ASSERT(ret); + UINT32 cbExtraBytes = 0; + BYTE* pbExtraBytes = NULL; + +- wLog* log = WLog_Get(TAG); + if (!WLog_IsLevelActive(log, g_LogLevel)) + return; + +@@ -1164,8 +1162,8 @@ static void smartcard_trace_transmit_return(const Transmit_Return* ret) + if (ret->pbRecvBuffer) + { + char buffer[1024] = { 0 }; +- WLog_DBG( +- TAG, " pbRecvBuffer: %s", ++ WLog_Print( ++ log, g_LogLevel, " pbRecvBuffer: %s", + smartcard_array_dump(ret->pbRecvBuffer, ret->cbRecvLength, buffer, sizeof(buffer))); + } + else +@@ -1176,10 +1174,10 @@ static void smartcard_trace_transmit_return(const Transmit_Return* ret) + WLog_Print(log, g_LogLevel, "}"); + } + +-static void smartcard_trace_control_return(const Control_Return* ret) ++static void smartcard_trace_control_return(wLog* log, const Control_Return* ret) + { + WINPR_ASSERT(ret); +- wLog* log = WLog_Get(TAG); ++ + if (!WLog_IsLevelActive(log, g_LogLevel)) + return; + +@@ -1191,8 +1189,8 @@ static void smartcard_trace_control_return(const Control_Return* ret) + if (ret->pvOutBuffer) + { + char buffer[1024] = { 0 }; +- WLog_DBG( +- TAG, "pvOutBuffer: %s", ++ WLog_Print( ++ log, g_LogLevel, "pvOutBuffer: %s", + smartcard_array_dump(ret->pvOutBuffer, ret->cbOutBufferSize, buffer, sizeof(buffer))); + } + else +@@ -1203,10 +1201,10 @@ static void smartcard_trace_control_return(const Control_Return* ret) + WLog_Print(log, g_LogLevel, "}"); + } + +-static void smartcard_trace_control_call(const Control_Call* call) ++static void smartcard_trace_control_call(wLog* log, const Control_Call* call) + { + WINPR_ASSERT(call); +- wLog* log = WLog_Get(TAG); ++ + if (!WLog_IsLevelActive(log, g_LogLevel)) + return; + +@@ -1223,8 +1221,8 @@ static void smartcard_trace_control_call(const Control_Call* call) + if (call->pvInBuffer) + { + char buffer[1024] = { 0 }; +- WLog_DBG( +- TAG, "pbInBuffer: %s", ++ WLog_Print( ++ log, WLOG_DEBUG, "pbInBuffer: %s", + smartcard_array_dump(call->pvInBuffer, call->cbInBufferSize, buffer, sizeof(buffer))); + } + else +@@ -1235,12 +1233,11 @@ static void smartcard_trace_control_call(const Control_Call* call) + WLog_Print(log, g_LogLevel, "}"); + } + +-static void smartcard_trace_set_attrib_call(const SetAttrib_Call* call) ++static void smartcard_trace_set_attrib_call(wLog* log, const SetAttrib_Call* call) + { + WINPR_ASSERT(call); + char buffer[8192] = { 0 }; + +- wLog* log = WLog_Get(TAG); + if (!WLog_IsLevelActive(log, g_LogLevel)) + return; + +@@ -1254,11 +1251,12 @@ static void smartcard_trace_set_attrib_call(const SetAttrib_Call* call) + WLog_Print(log, g_LogLevel, "}"); + } + +-static void smartcard_trace_get_attrib_return(const GetAttrib_Return* ret, DWORD dwAttrId) ++static void smartcard_trace_get_attrib_return(wLog* log, const GetAttrib_Return* ret, ++ DWORD dwAttrId) + { + WINPR_ASSERT(ret); + char buffer[1024] = { 0 }; +- wLog* log = WLog_Get(TAG); ++ + if (!WLog_IsLevelActive(log, g_LogLevel)) + return; + +@@ -1273,10 +1271,10 @@ static void smartcard_trace_get_attrib_return(const GetAttrib_Return* ret, DWORD + WLog_Print(log, g_LogLevel, "}"); + } + +-static void smartcard_trace_get_attrib_call(const GetAttrib_Call* call) ++static void smartcard_trace_get_attrib_call(wLog* log, const GetAttrib_Call* call) + { + WINPR_ASSERT(call); +- wLog* log = WLog_Get(TAG); ++ + if (!WLog_IsLevelActive(log, g_LogLevel)) + return; + +@@ -1292,10 +1290,10 @@ static void smartcard_trace_get_attrib_call(const GetAttrib_Call* call) + WLog_Print(log, g_LogLevel, "}"); + } + +-static void smartcard_trace_status_call(const Status_Call* call, BOOL unicode) ++static void smartcard_trace_status_call(wLog* log, const Status_Call* call, BOOL unicode) + { + WINPR_ASSERT(call); +- wLog* log = WLog_Get(TAG); ++ + if (!WLog_IsLevelActive(log, g_LogLevel)) + return; + +@@ -1309,14 +1307,13 @@ static void smartcard_trace_status_call(const Status_Call* call, BOOL unicode) + WLog_Print(log, g_LogLevel, "}"); + } + +-static void smartcard_trace_status_return(const Status_Return* ret, BOOL unicode) ++static void smartcard_trace_status_return(wLog* log, const Status_Return* ret, BOOL unicode) + { + WINPR_ASSERT(ret); + char* mszReaderNamesA = NULL; + char buffer[1024] = { 0 }; + DWORD cBytes = 0; + +- wLog* log = WLog_Get(TAG); + if (!WLog_IsLevelActive(log, g_LogLevel)) + return; + cBytes = ret->cBytes; +@@ -1342,13 +1339,12 @@ static void smartcard_trace_status_return(const Status_Return* ret, BOOL unicode + free(mszReaderNamesA); + } + +-static void smartcard_trace_state_return(const State_Return* ret) ++static void smartcard_trace_state_return(wLog* log, const State_Return* ret) + { + WINPR_ASSERT(ret); + char buffer[1024] = { 0 }; + char* state = NULL; + +- wLog* log = WLog_Get(TAG); + if (!WLog_IsLevelActive(log, g_LogLevel)) + return; + +@@ -1366,10 +1362,10 @@ static void smartcard_trace_state_return(const State_Return* ret) + free(state); + } + +-static void smartcard_trace_reconnect_return(const Reconnect_Return* ret) ++static void smartcard_trace_reconnect_return(wLog* log, const Reconnect_Return* ret) + { + WINPR_ASSERT(ret); +- wLog* log = WLog_Get(TAG); ++ + if (!WLog_IsLevelActive(log, g_LogLevel)) + return; + +@@ -1381,10 +1377,10 @@ static void smartcard_trace_reconnect_return(const Reconnect_Return* ret) + WLog_Print(log, g_LogLevel, "}"); + } + +-static void smartcard_trace_connect_a_call(const ConnectA_Call* call) ++static void smartcard_trace_connect_a_call(wLog* log, const ConnectA_Call* call) + { + WINPR_ASSERT(call); +- wLog* log = WLog_Get(TAG); ++ + if (!WLog_IsLevelActive(log, g_LogLevel)) + return; + +@@ -1400,12 +1396,11 @@ static void smartcard_trace_connect_a_call(const ConnectA_Call* call) + WLog_Print(log, g_LogLevel, "}"); + } + +-static void smartcard_trace_connect_w_call(const ConnectW_Call* call) ++static void smartcard_trace_connect_w_call(wLog* log, const ConnectW_Call* call) + { + WINPR_ASSERT(call); + char szReaderA[1024] = { 0 }; + +- wLog* log = WLog_Get(TAG); + if (!WLog_IsLevelActive(log, g_LogLevel)) + return; + +@@ -1423,11 +1418,12 @@ static void smartcard_trace_connect_w_call(const ConnectW_Call* call) + WLog_Print(log, g_LogLevel, "}"); + } + +-static void smartcard_trace_hcard_and_disposition_call(const HCardAndDisposition_Call* call, ++static void smartcard_trace_hcard_and_disposition_call(wLog* log, ++ const HCardAndDisposition_Call* call, + const char* name) + { + WINPR_ASSERT(call); +- wLog* log = WLog_Get(TAG); ++ + if (!WLog_IsLevelActive(log, g_LogLevel)) + return; + +@@ -1440,10 +1436,10 @@ static void smartcard_trace_hcard_and_disposition_call(const HCardAndDisposition + WLog_Print(log, g_LogLevel, "}"); + } + +-static void smartcard_trace_establish_context_call(const EstablishContext_Call* call) ++static void smartcard_trace_establish_context_call(wLog* log, const EstablishContext_Call* call) + { + WINPR_ASSERT(call); +- wLog* log = WLog_Get(TAG); ++ + if (!WLog_IsLevelActive(log, g_LogLevel)) + return; + +@@ -1453,10 +1449,10 @@ static void smartcard_trace_establish_context_call(const EstablishContext_Call* + WLog_Print(log, g_LogLevel, "}"); + } + +-static void smartcard_trace_establish_context_return(const EstablishContext_Return* ret) ++static void smartcard_trace_establish_context_return(wLog* log, const EstablishContext_Return* ret) + { + WINPR_ASSERT(ret); +- wLog* log = WLog_Get(TAG); ++ + if (!WLog_IsLevelActive(log, g_LogLevel)) + return; + +@@ -1469,9 +1465,15 @@ static void smartcard_trace_establish_context_return(const EstablishContext_Retu + } + + void smartcard_trace_long_return(const Long_Return* ret, const char* name) ++{ ++ wLog* log = scard_log(); ++ smartcard_trace_long_return_int(log, ret, name); ++} ++ ++void smartcard_trace_long_return_int(wLog* log, const Long_Return* ret, const char* name) + { + WINPR_ASSERT(ret); +- wLog* log = WLog_Get(TAG); ++ + if (!WLog_IsLevelActive(log, g_LogLevel)) + return; + +@@ -1481,10 +1483,10 @@ void smartcard_trace_long_return(const Long_Return* ret, const char* name) + WLog_Print(log, g_LogLevel, "}"); + } + +-static void smartcard_trace_connect_return(const Connect_Return* ret) ++static void smartcard_trace_connect_return(wLog* log, const Connect_Return* ret) + { + WINPR_ASSERT(ret); +- wLog* log = WLog_Get(TAG); ++ + if (!WLog_IsLevelActive(log, g_LogLevel)) + return; + +@@ -1499,10 +1501,10 @@ static void smartcard_trace_connect_return(const Connect_Return* ret) + WLog_Print(log, g_LogLevel, "}"); + } + +-static void smartcard_trace_reconnect_call(const Reconnect_Call* call) ++static void smartcard_trace_reconnect_call(wLog* log, const Reconnect_Call* call) + { + WINPR_ASSERT(call); +- wLog* log = WLog_Get(TAG); ++ + if (!WLog_IsLevelActive(log, g_LogLevel)) + return; + +@@ -1519,10 +1521,10 @@ static void smartcard_trace_reconnect_call(const Reconnect_Call* call) + WLog_Print(log, g_LogLevel, "}"); + } + +-static void smartcard_trace_device_type_id_return(const GetDeviceTypeId_Return* ret) ++static void smartcard_trace_device_type_id_return(wLog* log, const GetDeviceTypeId_Return* ret) + { + WINPR_ASSERT(ret); +- wLog* log = WLog_Get(TAG); ++ + if (!WLog_IsLevelActive(log, g_LogLevel)) + return; + +@@ -1534,63 +1536,66 @@ static void smartcard_trace_device_type_id_return(const GetDeviceTypeId_Return* + WLog_Print(log, g_LogLevel, "}"); + } + +-static LONG smartcard_unpack_common_context_and_string_a(wStream* s, REDIR_SCARDCONTEXT* phContext, ++static LONG smartcard_unpack_common_context_and_string_a(wLog* log, wStream* s, ++ REDIR_SCARDCONTEXT* phContext, + CHAR** pszReaderName) + { + UINT32 index = 0; + UINT32 pbContextNdrPtr = 0; +- LONG status = smartcard_unpack_redir_scard_context(s, phContext, &index, &pbContextNdrPtr); ++ LONG status = smartcard_unpack_redir_scard_context(log, s, phContext, &index, &pbContextNdrPtr); + if (status != SCARD_S_SUCCESS) + return status; + +- if (!smartcard_ndr_pointer_read(s, &index, NULL)) ++ if (!smartcard_ndr_pointer_read(log, s, &index, NULL)) + return ERROR_INVALID_DATA; + +- status = smartcard_unpack_redir_scard_context_ref(s, pbContextNdrPtr, phContext); ++ status = smartcard_unpack_redir_scard_context_ref(log, s, pbContextNdrPtr, phContext); + if (status != SCARD_S_SUCCESS) + return status; + +- status = smartcard_ndr_read_a(s, pszReaderName, NDR_PTR_FULL); ++ status = smartcard_ndr_read_a(log, s, pszReaderName, NDR_PTR_FULL); + if (status != SCARD_S_SUCCESS) + return status; + +- smartcard_trace_context_and_string_call_a(__func__, phContext, *pszReaderName); ++ smartcard_trace_context_and_string_call_a(log, __func__, phContext, *pszReaderName); + return SCARD_S_SUCCESS; + } + +-static LONG smartcard_unpack_common_context_and_string_w(wStream* s, REDIR_SCARDCONTEXT* phContext, ++static LONG smartcard_unpack_common_context_and_string_w(wLog* log, wStream* s, ++ REDIR_SCARDCONTEXT* phContext, + WCHAR** pszReaderName) + { + UINT32 index = 0; + UINT32 pbContextNdrPtr = 0; + +- LONG status = smartcard_unpack_redir_scard_context(s, phContext, &index, &pbContextNdrPtr); ++ LONG status = smartcard_unpack_redir_scard_context(log, s, phContext, &index, &pbContextNdrPtr); + if (status != SCARD_S_SUCCESS) + return status; + +- if (!smartcard_ndr_pointer_read(s, &index, NULL)) ++ if (!smartcard_ndr_pointer_read(log, s, &index, NULL)) + return ERROR_INVALID_DATA; + +- status = smartcard_unpack_redir_scard_context_ref(s, pbContextNdrPtr, phContext); ++ status = smartcard_unpack_redir_scard_context_ref(log, s, pbContextNdrPtr, phContext); + if (status != SCARD_S_SUCCESS) + return status; + +- status = smartcard_ndr_read_w(s, pszReaderName, NDR_PTR_FULL); ++ status = smartcard_ndr_read_w(log, s, pszReaderName, NDR_PTR_FULL); + if (status != SCARD_S_SUCCESS) + return status; + +- smartcard_trace_context_and_string_call_w(__func__, phContext, *pszReaderName); ++ smartcard_trace_context_and_string_call_w(log, __func__, phContext, *pszReaderName); + return SCARD_S_SUCCESS; + } + + LONG smartcard_unpack_common_type_header(wStream* s) + { ++ wLog* log = scard_log(); + UINT8 version = 0; + UINT32 filler = 0; + UINT8 endianness = 0; + UINT16 commonHeaderLength = 0; + +- if (!Stream_CheckAndLogRequiredLength(TAG, s, 8)) ++ if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 8)) + return STATUS_BUFFER_TOO_SMALL; + + /* Process CommonTypeHeader */ +@@ -1601,26 +1606,27 @@ LONG smartcard_unpack_common_type_header(wStream* s) + + if (version != 1) + { +- WLog_WARN(TAG, "Unsupported CommonTypeHeader Version %" PRIu8 "", version); ++ WLog_Print(log, WLOG_WARN, "Unsupported CommonTypeHeader Version %" PRIu8 "", version); + return STATUS_INVALID_PARAMETER; + } + + if (endianness != 0x10) + { +- WLog_WARN(TAG, "Unsupported CommonTypeHeader Endianness %" PRIu8 "", endianness); ++ WLog_Print(log, WLOG_WARN, "Unsupported CommonTypeHeader Endianness %" PRIu8 "", ++ endianness); + return STATUS_INVALID_PARAMETER; + } + + if (commonHeaderLength != 8) + { +- WLog_WARN(TAG, "Unsupported CommonTypeHeader CommonHeaderLength %" PRIu16 "", +- commonHeaderLength); ++ WLog_Print(log, WLOG_WARN, "Unsupported CommonTypeHeader CommonHeaderLength %" PRIu16 "", ++ commonHeaderLength); + return STATUS_INVALID_PARAMETER; + } + + if (filler != 0xCCCCCCCC) + { +- WLog_WARN(TAG, "Unexpected CommonTypeHeader Filler 0x%08" PRIX32 "", filler); ++ WLog_Print(log, WLOG_WARN, "Unexpected CommonTypeHeader Filler 0x%08" PRIX32 "", filler); + return STATUS_INVALID_PARAMETER; + } + +@@ -1637,10 +1643,11 @@ void smartcard_pack_common_type_header(wStream* s) + + LONG smartcard_unpack_private_type_header(wStream* s) + { ++ wLog* log = scard_log(); + UINT32 filler = 0; + UINT32 objectBufferLength = 0; + +- if (!Stream_CheckAndLogRequiredLength(TAG, s, 8)) ++ if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 8)) + return STATUS_BUFFER_TOO_SMALL; + + Stream_Read_UINT32(s, objectBufferLength); /* ObjectBufferLength (4 bytes) */ +@@ -1648,11 +1655,11 @@ LONG smartcard_unpack_private_type_header(wStream* s) + + if (filler != 0x00000000) + { +- WLog_WARN(TAG, "Unexpected PrivateTypeHeader Filler 0x%08" PRIX32 "", filler); ++ WLog_Print(log, WLOG_WARN, "Unexpected PrivateTypeHeader Filler 0x%08" PRIX32 "", filler); + return STATUS_INVALID_PARAMETER; + } + +- if (!Stream_CheckAndLogRequiredLength(TAG, s, objectBufferLength)) ++ if (!Stream_CheckAndLogRequiredLengthWLog(log, s, objectBufferLength)) + return STATUS_INVALID_PARAMETER; + + return SCARD_S_SUCCESS; +@@ -1690,7 +1697,8 @@ LONG smartcard_pack_write_size_align(wStream* s, size_t size, UINT32 alignment) + { + if (!Stream_EnsureRemainingCapacity(s, pad)) + { +- WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!"); ++ wLog* log = scard_log(); ++ WLog_Print(log, WLOG_ERROR, "Stream_EnsureRemainingCapacity failed!"); + return SCARD_F_INTERNAL_ERROR; + } + +@@ -1707,10 +1715,11 @@ SCARDCONTEXT smartcard_scard_context_native_from_redir(REDIR_SCARDCONTEXT* conte + WINPR_ASSERT(context); + if ((context->cbContext != sizeof(ULONG_PTR)) && (context->cbContext != 0)) + { +- WLog_WARN(TAG, +- "REDIR_SCARDCONTEXT does not match native size: Actual: %" PRIu32 +- ", Expected: %" PRIuz "", +- context->cbContext, sizeof(ULONG_PTR)); ++ wLog* log = scard_log(); ++ WLog_Print(log, WLOG_WARN, ++ "REDIR_SCARDCONTEXT does not match native size: Actual: %" PRIu32 ++ ", Expected: %" PRIuz "", ++ context->cbContext, sizeof(ULONG_PTR)); + return 0; + } + +@@ -1738,10 +1747,11 @@ SCARDHANDLE smartcard_scard_handle_native_from_redir(REDIR_SCARDHANDLE* handle) + + if (handle->cbHandle != sizeof(ULONG_PTR)) + { +- WLog_WARN(TAG, +- "REDIR_SCARDHANDLE does not match native size: Actual: %" PRIu32 +- ", Expected: %" PRIuz "", +- handle->cbHandle, sizeof(ULONG_PTR)); ++ wLog* log = scard_log(); ++ WLog_Print(log, WLOG_WARN, ++ "REDIR_SCARDHANDLE does not match native size: Actual: %" PRIu32 ++ ", Expected: %" PRIuz "", ++ handle->cbHandle, sizeof(ULONG_PTR)); + return 0; + } + +@@ -1759,9 +1769,33 @@ void smartcard_scard_handle_native_to_redir(REDIR_SCARDHANDLE* handle, SCARDHAND + CopyMemory(&(handle->pbHandle), &hCard, handle->cbHandle); + } + +-LONG smartcard_unpack_redir_scard_context_(wStream* s, REDIR_SCARDCONTEXT* context, UINT32* index, +- UINT32* ppbContextNdrPtr, const char* file, +- const char* function, int line) ++#define smartcard_context_supported(log, size) \ ++ smartcard_context_supported_((log), (size), __FILE__, __func__, __LINE__) ++static LONG smartcard_context_supported_(wLog* log, uint32_t size, const char* file, ++ const char* fkt, size_t line) ++{ ++ switch (size) ++ { ++ case 0: ++ case 4: ++ case 8: ++ return SCARD_S_SUCCESS; ++ default: ++ { ++ const uint32_t level = WLOG_WARN; ++ if (WLog_IsLevelActive(log, level)) ++ { ++ WLog_PrintMessage(log, WLOG_MESSAGE_TEXT, level, line, file, fkt, ++ "REDIR_SCARDCONTEXT length is not 0, 4 or 8: %" PRIu32 "", size); ++ } ++ return STATUS_INVALID_PARAMETER; ++ } ++ } ++} ++ ++LONG smartcard_unpack_redir_scard_context_(wLog* log, wStream* s, REDIR_SCARDCONTEXT* context, ++ UINT32* index, UINT32* ppbContextNdrPtr, ++ const char* file, const char* function, size_t line) + { + UINT32 pbContextNdrPtr = 0; + +@@ -1770,43 +1804,39 @@ LONG smartcard_unpack_redir_scard_context_(wStream* s, REDIR_SCARDCONTEXT* conte + + ZeroMemory(context, sizeof(REDIR_SCARDCONTEXT)); + +- if (!Stream_CheckAndLogRequiredLength(TAG, s, 4)) ++ if (!Stream_CheckAndLogRequiredLengthWLogEx(log, WLOG_WARN, s, 4, 1, "%s(%s:%" PRIuz ")", file, ++ function, line)) + return STATUS_BUFFER_TOO_SMALL; + +- Stream_Read_UINT32(s, context->cbContext); /* cbContext (4 bytes) */ +- +- if (!Stream_CheckAndLogRequiredLength(TAG, s, context->cbContext)) +- return STATUS_BUFFER_TOO_SMALL; ++ const LONG status = smartcard_context_supported_(log, context->cbContext, file, function, line); ++ if (status != SCARD_S_SUCCESS) ++ return status; + +- if ((context->cbContext != 0) && (context->cbContext != 4) && (context->cbContext != 8)) +- { +- WLog_WARN(TAG, "REDIR_SCARDCONTEXT length is not 0, 4 or 8: %" PRIu32 "", +- context->cbContext); +- return STATUS_INVALID_PARAMETER; +- } ++ Stream_Read_UINT32(s, context->cbContext); /* cbContext (4 bytes) */ + +- if (!smartcard_ndr_pointer_read_(s, index, &pbContextNdrPtr, file, function, +- WINPR_ASSERTING_INT_CAST(size_t, line))) ++ if (!smartcard_ndr_pointer_read_(log, s, index, &pbContextNdrPtr, file, function, line)) + return ERROR_INVALID_DATA; + + if (((context->cbContext == 0) && pbContextNdrPtr) || + ((context->cbContext != 0) && !pbContextNdrPtr)) + { +- WLog_WARN(TAG, +- "REDIR_SCARDCONTEXT cbContext (%" PRIu32 ") pbContextNdrPtr (%" PRIu32 +- ") inconsistency", +- context->cbContext, pbContextNdrPtr); ++ WLog_Print(log, WLOG_WARN, ++ "REDIR_SCARDCONTEXT cbContext (%" PRIu32 ") pbContextNdrPtr (%" PRIu32 ++ ") inconsistency", ++ context->cbContext, pbContextNdrPtr); + return STATUS_INVALID_PARAMETER; + } + +- if (!Stream_CheckAndLogRequiredLength(TAG, s, context->cbContext)) ++ if (!Stream_CheckAndLogRequiredLengthWLogEx(log, WLOG_WARN, s, context->cbContext, 1, ++ "%s(%s:%" PRIuz ")", file, function, line)) + return STATUS_INVALID_PARAMETER; + + *ppbContextNdrPtr = pbContextNdrPtr; + return SCARD_S_SUCCESS; + } + +-LONG smartcard_pack_redir_scard_context(wStream* s, const REDIR_SCARDCONTEXT* context, DWORD* index) ++LONG smartcard_pack_redir_scard_context(WINPR_ATTR_UNUSED wLog* log, wStream* s, ++ const REDIR_SCARDCONTEXT* context, DWORD* index) + { + const UINT32 pbContextNdrPtr = 0x00020000 + *index * 4; + +@@ -1823,7 +1853,8 @@ LONG smartcard_pack_redir_scard_context(wStream* s, const REDIR_SCARDCONTEXT* co + return SCARD_S_SUCCESS; + } + +-LONG smartcard_unpack_redir_scard_context_ref(wStream* s, WINPR_ATTR_UNUSED UINT32 pbContextNdrPtr, ++LONG smartcard_unpack_redir_scard_context_ref(wLog* log, wStream* s, ++ WINPR_ATTR_UNUSED UINT32 pbContextNdrPtr, + REDIR_SCARDCONTEXT* context) + { + UINT32 length = 0; +@@ -1832,25 +1863,24 @@ LONG smartcard_unpack_redir_scard_context_ref(wStream* s, WINPR_ATTR_UNUSED UINT + if (context->cbContext == 0) + return SCARD_S_SUCCESS; + +- if (!Stream_CheckAndLogRequiredLength(TAG, s, 4)) ++ if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4)) + return STATUS_BUFFER_TOO_SMALL; + + Stream_Read_UINT32(s, length); /* Length (4 bytes) */ + + if (length != context->cbContext) + { +- WLog_WARN(TAG, "REDIR_SCARDCONTEXT length (%" PRIu32 ") cbContext (%" PRIu32 ") mismatch", +- length, context->cbContext); ++ WLog_Print(log, WLOG_WARN, ++ "REDIR_SCARDCONTEXT length (%" PRIu32 ") cbContext (%" PRIu32 ") mismatch", ++ length, context->cbContext); + return STATUS_INVALID_PARAMETER; + } + +- if ((context->cbContext != 0) && (context->cbContext != 4) && (context->cbContext != 8)) +- { +- WLog_WARN(TAG, "REDIR_SCARDCONTEXT length is not 4 or 8: %" PRIu32 "", context->cbContext); +- return STATUS_INVALID_PARAMETER; +- } ++ const LONG status = smartcard_context_supported(log, context->cbContext); ++ if (status != SCARD_S_SUCCESS) ++ return status; + +- if (!Stream_CheckAndLogRequiredLength(TAG, s, context->cbContext)) ++ if (!Stream_CheckAndLogRequiredLengthWLog(log, s, context->cbContext)) + return STATUS_BUFFER_TOO_SMALL; + + if (context->cbContext) +@@ -1861,7 +1891,8 @@ LONG smartcard_unpack_redir_scard_context_ref(wStream* s, WINPR_ATTR_UNUSED UINT + return SCARD_S_SUCCESS; + } + +-LONG smartcard_pack_redir_scard_context_ref(wStream* s, const REDIR_SCARDCONTEXT* context) ++LONG smartcard_pack_redir_scard_context_ref(WINPR_ATTR_UNUSED wLog* log, wStream* s, ++ const REDIR_SCARDCONTEXT* context) + { + WINPR_ASSERT(context); + Stream_Write_UINT32(s, context->cbContext); /* Length (4 bytes) */ +@@ -1874,28 +1905,29 @@ LONG smartcard_pack_redir_scard_context_ref(wStream* s, const REDIR_SCARDCONTEXT + return SCARD_S_SUCCESS; + } + +-LONG smartcard_unpack_redir_scard_handle_(wStream* s, REDIR_SCARDHANDLE* handle, UINT32* index, +- const char* file, const char* function, int line) ++LONG smartcard_unpack_redir_scard_handle_(wLog* log, wStream* s, REDIR_SCARDHANDLE* handle, ++ UINT32* index, const char* file, const char* function, ++ size_t line) + { + WINPR_ASSERT(handle); + ZeroMemory(handle, sizeof(REDIR_SCARDHANDLE)); + +- if (!Stream_CheckAndLogRequiredLength(TAG, s, 4)) ++ if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4)) + return STATUS_BUFFER_TOO_SMALL; + + Stream_Read_UINT32(s, handle->cbHandle); /* Length (4 bytes) */ + +- if (!Stream_CheckAndLogRequiredLength(TAG, s, handle->cbHandle)) ++ if (!Stream_CheckAndLogRequiredLengthWLog(log, s, handle->cbHandle)) + return STATUS_BUFFER_TOO_SMALL; + +- if (!smartcard_ndr_pointer_read_(s, index, NULL, file, function, +- WINPR_ASSERTING_INT_CAST(size_t, line))) ++ if (!smartcard_ndr_pointer_read_(log, s, index, NULL, file, function, line)) + return ERROR_INVALID_DATA; + + return SCARD_S_SUCCESS; + } + +-LONG smartcard_pack_redir_scard_handle(wStream* s, const REDIR_SCARDHANDLE* handle, DWORD* index) ++LONG smartcard_pack_redir_scard_handle(WINPR_ATTR_UNUSED wLog* log, wStream* s, ++ const REDIR_SCARDHANDLE* handle, DWORD* index) + { + const UINT32 pbContextNdrPtr = 0x00020000 + *index * 4; + +@@ -1911,30 +1943,32 @@ LONG smartcard_pack_redir_scard_handle(wStream* s, const REDIR_SCARDHANDLE* hand + return SCARD_S_SUCCESS; + } + +-LONG smartcard_unpack_redir_scard_handle_ref(wStream* s, REDIR_SCARDHANDLE* handle) ++LONG smartcard_unpack_redir_scard_handle_ref(wLog* log, wStream* s, REDIR_SCARDHANDLE* handle) + { + UINT32 length = 0; + + WINPR_ASSERT(handle); +- if (!Stream_CheckAndLogRequiredLength(TAG, s, 4)) ++ if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4)) + return STATUS_BUFFER_TOO_SMALL; + + Stream_Read_UINT32(s, length); /* Length (4 bytes) */ + + if (length != handle->cbHandle) + { +- WLog_WARN(TAG, "REDIR_SCARDHANDLE length (%" PRIu32 ") cbHandle (%" PRIu32 ") mismatch", +- length, handle->cbHandle); ++ WLog_Print(log, WLOG_WARN, ++ "REDIR_SCARDHANDLE length (%" PRIu32 ") cbHandle (%" PRIu32 ") mismatch", length, ++ handle->cbHandle); + return STATUS_INVALID_PARAMETER; + } + + if ((handle->cbHandle != 4) && (handle->cbHandle != 8)) + { +- WLog_WARN(TAG, "REDIR_SCARDHANDLE length is not 4 or 8: %" PRIu32 "", handle->cbHandle); ++ WLog_Print(log, WLOG_WARN, "REDIR_SCARDHANDLE length is not 4 or 8: %" PRIu32 "", ++ handle->cbHandle); + return STATUS_INVALID_PARAMETER; + } + +- if (!Stream_CheckAndLogRequiredLength(TAG, s, handle->cbHandle)) ++ if (!Stream_CheckAndLogRequiredLengthWLog(log, s, handle->cbHandle)) + return STATUS_BUFFER_TOO_SMALL; + + if (handle->cbHandle) +@@ -1943,7 +1977,8 @@ LONG smartcard_unpack_redir_scard_handle_ref(wStream* s, REDIR_SCARDHANDLE* hand + return SCARD_S_SUCCESS; + } + +-LONG smartcard_pack_redir_scard_handle_ref(wStream* s, const REDIR_SCARDHANDLE* handle) ++LONG smartcard_pack_redir_scard_handle_ref(WINPR_ATTR_UNUSED wLog* log, wStream* s, ++ const REDIR_SCARDHANDLE* handle) + { + WINPR_ASSERT(handle); + Stream_Write_UINT32(s, handle->cbHandle); /* Length (4 bytes) */ +@@ -1957,47 +1992,54 @@ LONG smartcard_pack_redir_scard_handle_ref(wStream* s, const REDIR_SCARDHANDLE* + LONG smartcard_unpack_establish_context_call(wStream* s, EstablishContext_Call* call) + { + WINPR_ASSERT(call); +- if (!Stream_CheckAndLogRequiredLength(TAG, s, 4)) ++ wLog* log = scard_log(); ++ ++ if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4)) + return STATUS_BUFFER_TOO_SMALL; + + Stream_Read_UINT32(s, call->dwScope); /* dwScope (4 bytes) */ +- smartcard_trace_establish_context_call(call); ++ smartcard_trace_establish_context_call(log, call); + return SCARD_S_SUCCESS; + } + + LONG smartcard_pack_establish_context_return(wStream* s, const EstablishContext_Return* ret) + { + WINPR_ASSERT(ret); ++ wLog* log = scard_log(); + LONG status = 0; + DWORD index = 0; + +- smartcard_trace_establish_context_return(ret); ++ smartcard_trace_establish_context_return(log, ret); + if (ret->ReturnCode != SCARD_S_SUCCESS) + return ret->ReturnCode; + +- if ((status = smartcard_pack_redir_scard_context(s, &(ret->hContext), &index))) ++ status = smartcard_pack_redir_scard_context(log, s, &(ret->hContext), &index); ++ if (status != SCARD_S_SUCCESS) + return status; + +- return smartcard_pack_redir_scard_context_ref(s, &(ret->hContext)); ++ return smartcard_pack_redir_scard_context_ref(log, s, &(ret->hContext)); + } + + LONG smartcard_unpack_context_call(wStream* s, Context_Call* call, const char* name) + { + UINT32 index = 0; + UINT32 pbContextNdrPtr = 0; ++ wLog* log = scard_log(); + + WINPR_ASSERT(call); +- LONG status = smartcard_unpack_redir_scard_context(s, &(call->handles.hContext), &index, ++ LONG status = smartcard_unpack_redir_scard_context(log, s, &(call->handles.hContext), &index, + &pbContextNdrPtr); + if (status != SCARD_S_SUCCESS) + return status; + +- if ((status = smartcard_unpack_redir_scard_context_ref(s, pbContextNdrPtr, +- &(call->handles.hContext)))) +- WLog_ERR(TAG, "smartcard_unpack_redir_scard_context_ref failed with error %" PRId32 "", +- status); ++ status = smartcard_unpack_redir_scard_context_ref(log, s, pbContextNdrPtr, ++ &(call->handles.hContext)); ++ if (status != SCARD_S_SUCCESS) ++ WLog_Print(log, WLOG_ERROR, ++ "smartcard_unpack_redir_scard_context_ref failed with error %" PRId32 "", ++ status); + +- smartcard_trace_context_call(call, name); ++ smartcard_trace_context_call(log, call, name); + return status; + } + +@@ -2005,26 +2047,27 @@ LONG smartcard_unpack_list_reader_groups_call(wStream* s, ListReaderGroups_Call* + { + UINT32 index = 0; + UINT32 pbContextNdrPtr = 0; ++ wLog* log = scard_log(); + + WINPR_ASSERT(call); +- LONG status = smartcard_unpack_redir_scard_context(s, &(call->handles.hContext), &index, ++ LONG status = smartcard_unpack_redir_scard_context(log, s, &(call->handles.hContext), &index, + &pbContextNdrPtr); + + if (status != SCARD_S_SUCCESS) + return status; + +- if (!Stream_CheckAndLogRequiredLength(TAG, s, 8)) ++ if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 8)) + return STATUS_BUFFER_TOO_SMALL; + + Stream_Read_INT32(s, call->fmszGroupsIsNULL); /* fmszGroupsIsNULL (4 bytes) */ + Stream_Read_UINT32(s, call->cchGroups); /* cchGroups (4 bytes) */ +- status = +- smartcard_unpack_redir_scard_context_ref(s, pbContextNdrPtr, &(call->handles.hContext)); ++ status = smartcard_unpack_redir_scard_context_ref(log, s, pbContextNdrPtr, ++ &(call->handles.hContext)); + + if (status != SCARD_S_SUCCESS) + return status; + +- smartcard_trace_list_reader_groups_call(call, unicode); ++ smartcard_trace_list_reader_groups_call(log, call, unicode); + return SCARD_S_SUCCESS; + } + +@@ -2032,11 +2075,12 @@ LONG smartcard_pack_list_reader_groups_return(wStream* s, const ListReaderGroups + BOOL unicode) + { + WINPR_ASSERT(ret); ++ wLog* log = scard_log(); + LONG status = 0; + DWORD cBytes = ret->cBytes; + UINT32 index = 0; + +- smartcard_trace_list_reader_groups_return(ret, unicode); ++ smartcard_trace_list_reader_groups_return(log, ret, unicode); + if (ret->ReturnCode != SCARD_S_SUCCESS) + cBytes = 0; + if (cBytes == SCARD_AUTOALLOCATE) +@@ -2060,53 +2104,59 @@ LONG smartcard_unpack_list_readers_call(wStream* s, ListReaders_Call* call, BOOL + UINT32 index = 0; + UINT32 mszGroupsNdrPtr = 0; + UINT32 pbContextNdrPtr = 0; ++ wLog* log = scard_log(); + + WINPR_ASSERT(call); + call->mszGroups = NULL; + +- LONG status = smartcard_unpack_redir_scard_context(s, &(call->handles.hContext), &index, ++ LONG status = smartcard_unpack_redir_scard_context(log, s, &(call->handles.hContext), &index, + &pbContextNdrPtr); + if (status != SCARD_S_SUCCESS) + return status; + +- if (!Stream_CheckAndLogRequiredLength(TAG, s, 16)) ++ if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4)) + return STATUS_BUFFER_TOO_SMALL; + + Stream_Read_UINT32(s, call->cBytes); /* cBytes (4 bytes) */ +- if (!smartcard_ndr_pointer_read(s, &index, &mszGroupsNdrPtr)) ++ if (!smartcard_ndr_pointer_read(log, s, &index, &mszGroupsNdrPtr)) + return ERROR_INVALID_DATA; ++ ++ if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 8)) ++ return STATUS_BUFFER_TOO_SMALL; + Stream_Read_INT32(s, call->fmszReadersIsNULL); /* fmszReadersIsNULL (4 bytes) */ + Stream_Read_UINT32(s, call->cchReaders); /* cchReaders (4 bytes) */ + +- if ((status = smartcard_unpack_redir_scard_context_ref(s, pbContextNdrPtr, +- &(call->handles.hContext)))) ++ status = smartcard_unpack_redir_scard_context_ref(log, s, pbContextNdrPtr, ++ &(call->handles.hContext)); ++ if (status != SCARD_S_SUCCESS) + return status; + + if (mszGroupsNdrPtr) + { +- status = smartcard_ndr_read(s, &call->mszGroups, call->cBytes, 1, NDR_PTR_SIMPLE); ++ status = smartcard_ndr_read(log, s, &call->mszGroups, call->cBytes, 1, NDR_PTR_SIMPLE); + if (status != SCARD_S_SUCCESS) + return status; + } + +- smartcard_trace_list_readers_call(call, unicode); ++ smartcard_trace_list_readers_call(log, call, unicode); + return SCARD_S_SUCCESS; + } + + LONG smartcard_pack_list_readers_return(wStream* s, const ListReaders_Return* ret, BOOL unicode) + { + WINPR_ASSERT(ret); ++ wLog* log = scard_log(); + LONG status = 0; + UINT32 index = 0; + UINT32 size = ret->cBytes; + +- smartcard_trace_list_readers_return(ret, unicode); ++ smartcard_trace_list_readers_return(log, ret, unicode); + if (ret->ReturnCode != SCARD_S_SUCCESS) + size = 0; + + if (!Stream_EnsureRemainingCapacity(s, 4)) + { +- WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!"); ++ WLog_Print(log, WLOG_ERROR, "Stream_EnsureRemainingCapacity failed!"); + return SCARD_F_INTERNAL_ERROR; + } + +@@ -2120,16 +2170,16 @@ LONG smartcard_pack_list_readers_return(wStream* s, const ListReaders_Return* re + return ret->ReturnCode; + } + +-static LONG smartcard_unpack_connect_common(wStream* s, Connect_Common_Call* common, UINT32* index, +- UINT32* ppbContextNdrPtr) ++static LONG smartcard_unpack_connect_common(wLog* log, wStream* s, Connect_Common_Call* common, ++ UINT32* index, UINT32* ppbContextNdrPtr) + { + WINPR_ASSERT(common); +- LONG status = smartcard_unpack_redir_scard_context(s, &(common->handles.hContext), index, ++ LONG status = smartcard_unpack_redir_scard_context(log, s, &(common->handles.hContext), index, + ppbContextNdrPtr); + if (status != SCARD_S_SUCCESS) + return status; + +- if (!Stream_CheckAndLogRequiredLength(TAG, s, 8)) ++ if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 8)) + return STATUS_BUFFER_TOO_SMALL; + + Stream_Read_UINT32(s, common->dwShareMode); /* dwShareMode (4 bytes) */ +@@ -2144,27 +2194,33 @@ LONG smartcard_unpack_connect_a_call(wStream* s, ConnectA_Call* call) + UINT32 pbContextNdrPtr = 0; + + WINPR_ASSERT(call); ++ wLog* log = scard_log(); ++ + call->szReader = NULL; + +- if (!smartcard_ndr_pointer_read(s, &index, NULL)) ++ if (!smartcard_ndr_pointer_read(log, s, &index, NULL)) + return ERROR_INVALID_DATA; + +- if ((status = smartcard_unpack_connect_common(s, &(call->Common), &index, &pbContextNdrPtr))) ++ status = smartcard_unpack_connect_common(log, s, &(call->Common), &index, &pbContextNdrPtr); ++ if (status != SCARD_S_SUCCESS) + { +- WLog_ERR(TAG, "smartcard_unpack_connect_common failed with error %" PRId32 "", status); ++ WLog_Print(log, WLOG_ERROR, "smartcard_unpack_connect_common failed with error %" PRId32 "", ++ status); + return status; + } + +- status = smartcard_ndr_read_a(s, &call->szReader, NDR_PTR_FULL); ++ status = smartcard_ndr_read_a(log, s, &call->szReader, NDR_PTR_FULL); + if (status != SCARD_S_SUCCESS) + return status; + +- if ((status = smartcard_unpack_redir_scard_context_ref(s, pbContextNdrPtr, +- &(call->Common.handles.hContext)))) +- WLog_ERR(TAG, "smartcard_unpack_redir_scard_context_ref failed with error %" PRId32 "", +- status); ++ status = smartcard_unpack_redir_scard_context_ref(log, s, pbContextNdrPtr, ++ &(call->Common.handles.hContext)); ++ if (status != SCARD_S_SUCCESS) ++ WLog_Print(log, WLOG_ERROR, ++ "smartcard_unpack_redir_scard_context_ref failed with error %" PRId32 "", ++ status); + +- smartcard_trace_connect_a_call(call); ++ smartcard_trace_connect_a_call(log, call); + return status; + } + +@@ -2175,27 +2231,32 @@ LONG smartcard_unpack_connect_w_call(wStream* s, ConnectW_Call* call) + UINT32 pbContextNdrPtr = 0; + + WINPR_ASSERT(call); ++ wLog* log = scard_log(); + call->szReader = NULL; + +- if (!smartcard_ndr_pointer_read(s, &index, NULL)) ++ if (!smartcard_ndr_pointer_read(log, s, &index, NULL)) + return ERROR_INVALID_DATA; + +- if ((status = smartcard_unpack_connect_common(s, &(call->Common), &index, &pbContextNdrPtr))) ++ status = smartcard_unpack_connect_common(log, s, &(call->Common), &index, &pbContextNdrPtr); ++ if (status != SCARD_S_SUCCESS) + { +- WLog_ERR(TAG, "smartcard_unpack_connect_common failed with error %" PRId32 "", status); ++ WLog_Print(log, WLOG_ERROR, "smartcard_unpack_connect_common failed with error %" PRId32 "", ++ status); + return status; + } + +- status = smartcard_ndr_read_w(s, &call->szReader, NDR_PTR_FULL); ++ status = smartcard_ndr_read_w(log, s, &call->szReader, NDR_PTR_FULL); + if (status != SCARD_S_SUCCESS) + return status; + +- if ((status = smartcard_unpack_redir_scard_context_ref(s, pbContextNdrPtr, +- &(call->Common.handles.hContext)))) +- WLog_ERR(TAG, "smartcard_unpack_redir_scard_context_ref failed with error %" PRId32 "", +- status); ++ status = smartcard_unpack_redir_scard_context_ref(log, s, pbContextNdrPtr, ++ &(call->Common.handles.hContext)); ++ if (status != SCARD_S_SUCCESS) ++ WLog_Print(log, WLOG_ERROR, ++ "smartcard_unpack_redir_scard_context_ref failed with error %" PRId32 "", ++ status); + +- smartcard_trace_connect_w_call(call); ++ smartcard_trace_connect_w_call(log, call); + return status; + } + +@@ -2205,13 +2266,14 @@ LONG smartcard_pack_connect_return(wStream* s, const Connect_Return* ret) + DWORD index = 0; + + WINPR_ASSERT(ret); +- smartcard_trace_connect_return(ret); ++ wLog* log = scard_log(); ++ smartcard_trace_connect_return(log, ret); + +- status = smartcard_pack_redir_scard_context(s, &ret->hContext, &index); ++ status = smartcard_pack_redir_scard_context(log, s, &ret->hContext, &index); + if (status != SCARD_S_SUCCESS) + return status; + +- status = smartcard_pack_redir_scard_handle(s, &ret->hCard, &index); ++ status = smartcard_pack_redir_scard_handle(log, s, &ret->hCard, &index); + if (status != SCARD_S_SUCCESS) + return status; + +@@ -2219,10 +2281,10 @@ LONG smartcard_pack_connect_return(wStream* s, const Connect_Return* ret) + return SCARD_E_NO_MEMORY; + + Stream_Write_UINT32(s, ret->dwActiveProtocol); /* dwActiveProtocol (4 bytes) */ +- status = smartcard_pack_redir_scard_context_ref(s, &ret->hContext); ++ status = smartcard_pack_redir_scard_context_ref(log, s, &ret->hContext); + if (status != SCARD_S_SUCCESS) + return status; +- return smartcard_pack_redir_scard_handle_ref(s, &(ret->hCard)); ++ return smartcard_pack_redir_scard_handle_ref(log, s, &(ret->hCard)); + } + + LONG smartcard_unpack_reconnect_call(wStream* s, Reconnect_Call* call) +@@ -2231,42 +2293,47 @@ LONG smartcard_unpack_reconnect_call(wStream* s, Reconnect_Call* call) + UINT32 pbContextNdrPtr = 0; + + WINPR_ASSERT(call); +- LONG status = smartcard_unpack_redir_scard_context(s, &(call->handles.hContext), &index, ++ wLog* log = scard_log(); ++ LONG status = smartcard_unpack_redir_scard_context(log, s, &(call->handles.hContext), &index, + &pbContextNdrPtr); + if (status != SCARD_S_SUCCESS) + return status; + +- status = smartcard_unpack_redir_scard_handle(s, &(call->handles.hCard), &index); ++ status = smartcard_unpack_redir_scard_handle(log, s, &(call->handles.hCard), &index); + if (status != SCARD_S_SUCCESS) + return status; + +- if (!Stream_CheckAndLogRequiredLength(TAG, s, 12)) ++ if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 12)) + return STATUS_BUFFER_TOO_SMALL; + + Stream_Read_UINT32(s, call->dwShareMode); /* dwShareMode (4 bytes) */ + Stream_Read_UINT32(s, call->dwPreferredProtocols); /* dwPreferredProtocols (4 bytes) */ + Stream_Read_UINT32(s, call->dwInitialization); /* dwInitialization (4 bytes) */ + +- if ((status = smartcard_unpack_redir_scard_context_ref(s, pbContextNdrPtr, +- &(call->handles.hContext)))) ++ status = smartcard_unpack_redir_scard_context_ref(log, s, pbContextNdrPtr, ++ &(call->handles.hContext)); ++ if (status != SCARD_S_SUCCESS) + { +- WLog_ERR(TAG, "smartcard_unpack_redir_scard_context_ref failed with error %" PRId32 "", +- status); ++ WLog_Print(log, WLOG_ERROR, ++ "smartcard_unpack_redir_scard_context_ref failed with error %" PRId32 "", ++ status); + return status; + } + +- if ((status = smartcard_unpack_redir_scard_handle_ref(s, &(call->handles.hCard)))) +- WLog_ERR(TAG, "smartcard_unpack_redir_scard_handle_ref failed with error %" PRId32 "", +- status); ++ status = smartcard_unpack_redir_scard_handle_ref(log, s, &(call->handles.hCard)); ++ if (status != SCARD_S_SUCCESS) ++ WLog_Print(log, WLOG_ERROR, ++ "smartcard_unpack_redir_scard_handle_ref failed with error %" PRId32 "", status); + +- smartcard_trace_reconnect_call(call); ++ smartcard_trace_reconnect_call(log, call); + return status; + } + + LONG smartcard_pack_reconnect_return(wStream* s, const Reconnect_Return* ret) + { + WINPR_ASSERT(ret); +- smartcard_trace_reconnect_return(ret); ++ wLog* log = scard_log(); ++ smartcard_trace_reconnect_return(log, ret); + + if (!Stream_EnsureRemainingCapacity(s, 4)) + return SCARD_E_NO_MEMORY; +@@ -2281,35 +2348,39 @@ LONG smartcard_unpack_hcard_and_disposition_call(wStream* s, HCardAndDisposition + UINT32 pbContextNdrPtr = 0; + + WINPR_ASSERT(call); +- LONG status = smartcard_unpack_redir_scard_context(s, &(call->handles.hContext), &index, ++ wLog* log = scard_log(); ++ ++ LONG status = smartcard_unpack_redir_scard_context(log, s, &(call->handles.hContext), &index, + &pbContextNdrPtr); + if (status != SCARD_S_SUCCESS) + return status; + +- status = smartcard_unpack_redir_scard_handle(s, &(call->handles.hCard), &index); ++ status = smartcard_unpack_redir_scard_handle(log, s, &(call->handles.hCard), &index); + if (status != SCARD_S_SUCCESS) + return status; + +- if (!Stream_CheckAndLogRequiredLength(TAG, s, 4)) ++ if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4)) + return STATUS_BUFFER_TOO_SMALL; + + Stream_Read_UINT32(s, call->dwDisposition); /* dwDisposition (4 bytes) */ + +- if ((status = smartcard_unpack_redir_scard_context_ref(s, pbContextNdrPtr, +- &(call->handles.hContext)))) ++ status = smartcard_unpack_redir_scard_context_ref(log, s, pbContextNdrPtr, ++ &(call->handles.hContext)); ++ if (status != SCARD_S_SUCCESS) + return status; + +- if ((status = smartcard_unpack_redir_scard_handle_ref(s, &(call->handles.hCard)))) ++ status = smartcard_unpack_redir_scard_handle_ref(log, s, &(call->handles.hCard)); ++ if (status != SCARD_S_SUCCESS) + return status; + +- smartcard_trace_hcard_and_disposition_call(call, name); ++ smartcard_trace_hcard_and_disposition_call(log, call, name); + return status; + } + +-static void smartcard_trace_get_status_change_a_call(const GetStatusChangeA_Call* call) ++static void smartcard_trace_get_status_change_a_call(wLog* log, const GetStatusChangeA_Call* call) + { + WINPR_ASSERT(call); +- wLog* log = WLog_Get(TAG); ++ + if (!WLog_IsLevelActive(log, g_LogLevel)) + return; + +@@ -2324,19 +2395,19 @@ static void smartcard_trace_get_status_change_a_call(const GetStatusChangeA_Call + WLog_Print(log, g_LogLevel, "}"); + } + +-static LONG smartcard_unpack_reader_state_a(wStream* s, LPSCARD_READERSTATEA* ppcReaders, ++static LONG smartcard_unpack_reader_state_a(wLog* log, wStream* s, LPSCARD_READERSTATEA* ppcReaders, + UINT32 cReaders, UINT32* ptrIndex) + { + LONG status = SCARD_E_NO_MEMORY; + + WINPR_ASSERT(ppcReaders || (cReaders == 0)); +- if (!Stream_CheckAndLogRequiredLength(TAG, s, 4)) ++ if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4)) + return status; + + const UINT32 len = Stream_Get_UINT32(s); + if (len != cReaders) + { +- WLog_ERR(TAG, "Count mismatch when reading LPSCARD_READERSTATEA"); ++ WLog_Print(log, WLOG_ERROR, "Count mismatch when reading LPSCARD_READERSTATEA"); + return status; + } + +@@ -2352,10 +2423,10 @@ static LONG smartcard_unpack_reader_state_a(wStream* s, LPSCARD_READERSTATEA* pp + UINT32 ptr = UINT32_MAX; + LPSCARD_READERSTATEA readerState = &rgReaderStates[index]; + +- if (!Stream_CheckAndLogRequiredLength(TAG, s, 52)) ++ if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 52)) + goto fail; + +- if (!smartcard_ndr_pointer_read(s, ptrIndex, &ptr)) ++ if (!smartcard_ndr_pointer_read(log, s, ptrIndex, &ptr)) + { + if (ptr != 0) + goto fail; +@@ -2375,7 +2446,7 @@ static LONG smartcard_unpack_reader_state_a(wStream* s, LPSCARD_READERSTATEA* pp + /* Ignore empty strings */ + if (!states[index]) + continue; +- status = smartcard_ndr_read_a(s, &readerState->szReader, NDR_PTR_FULL); ++ status = smartcard_ndr_read_a(log, s, &readerState->szReader, NDR_PTR_FULL); + if (status != SCARD_S_SUCCESS) + goto fail; + } +@@ -2397,19 +2468,19 @@ fail: + return status; + } + +-static LONG smartcard_unpack_reader_state_w(wStream* s, LPSCARD_READERSTATEW* ppcReaders, ++static LONG smartcard_unpack_reader_state_w(wLog* log, wStream* s, LPSCARD_READERSTATEW* ppcReaders, + UINT32 cReaders, UINT32* ptrIndex) + { + LONG status = SCARD_E_NO_MEMORY; + + WINPR_ASSERT(ppcReaders || (cReaders == 0)); +- if (!Stream_CheckAndLogRequiredLength(TAG, s, 4)) ++ if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4)) + return status; + + const UINT32 len = Stream_Get_UINT32(s); + if (len != cReaders) + { +- WLog_ERR(TAG, "Count mismatch when reading LPSCARD_READERSTATEW"); ++ WLog_Print(log, WLOG_ERROR, "Count mismatch when reading LPSCARD_READERSTATEW"); + return status; + } + +@@ -2426,10 +2497,10 @@ static LONG smartcard_unpack_reader_state_w(wStream* s, LPSCARD_READERSTATEW* pp + UINT32 ptr = UINT32_MAX; + LPSCARD_READERSTATEW readerState = &rgReaderStates[index]; + +- if (!Stream_CheckAndLogRequiredLength(TAG, s, 52)) ++ if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 52)) + goto fail; + +- if (!smartcard_ndr_pointer_read(s, ptrIndex, &ptr)) ++ if (!smartcard_ndr_pointer_read(log, s, ptrIndex, &ptr)) + { + if (ptr != 0) + goto fail; +@@ -2450,7 +2521,7 @@ static LONG smartcard_unpack_reader_state_w(wStream* s, LPSCARD_READERSTATEW* pp + if (!states[index]) + continue; + +- status = smartcard_ndr_read_w(s, &readerState->szReader, NDR_PTR_FULL); ++ status = smartcard_ndr_read_w(log, s, &readerState->szReader, NDR_PTR_FULL); + if (status != SCARD_S_SUCCESS) + goto fail; + } +@@ -2483,33 +2554,42 @@ LONG smartcard_unpack_get_status_change_a_call(wStream* s, GetStatusChangeA_Call + UINT32 pbContextNdrPtr = 0; + + WINPR_ASSERT(call); ++ wLog* log = scard_log(); ++ + call->rgReaderStates = NULL; + +- LONG status = smartcard_unpack_redir_scard_context(s, &(call->handles.hContext), &index, ++ LONG status = smartcard_unpack_redir_scard_context(log, s, &(call->handles.hContext), &index, + &pbContextNdrPtr); + if (status != SCARD_S_SUCCESS) + return status; + +- if (!Stream_CheckAndLogRequiredLength(TAG, s, 12)) ++ if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 8)) + return STATUS_BUFFER_TOO_SMALL; + + Stream_Read_UINT32(s, call->dwTimeOut); /* dwTimeOut (4 bytes) */ + Stream_Read_UINT32(s, call->cReaders); /* cReaders (4 bytes) */ +- if (!smartcard_ndr_pointer_read(s, &index, &ndrPtr)) ++ if (!smartcard_ndr_pointer_read(log, s, &index, &ndrPtr)) + return ERROR_INVALID_DATA; + +- if ((status = smartcard_unpack_redir_scard_context_ref(s, pbContextNdrPtr, +- &(call->handles.hContext)))) ++ status = smartcard_unpack_redir_scard_context_ref(log, s, pbContextNdrPtr, ++ &(call->handles.hContext)); ++ if (status != SCARD_S_SUCCESS) + return status; + + if (ndrPtr) + { +- status = smartcard_unpack_reader_state_a(s, &call->rgReaderStates, call->cReaders, &index); ++ status = ++ smartcard_unpack_reader_state_a(log, s, &call->rgReaderStates, call->cReaders, &index); + if (status != SCARD_S_SUCCESS) + return status; + } ++ else ++ { ++ WLog_Print(log, WLOG_WARN, "ndrPtr=0x%08" PRIx32 ", can not read rgReaderStates", ndrPtr); ++ return SCARD_E_UNEXPECTED; ++ } + +- smartcard_trace_get_status_change_a_call(call); ++ smartcard_trace_get_status_change_a_call(log, call); + return SCARD_S_SUCCESS; + } + +@@ -2520,33 +2600,41 @@ LONG smartcard_unpack_get_status_change_w_call(wStream* s, GetStatusChangeW_Call + UINT32 pbContextNdrPtr = 0; + + WINPR_ASSERT(call); ++ wLog* log = scard_log(); + call->rgReaderStates = NULL; + +- LONG status = smartcard_unpack_redir_scard_context(s, &(call->handles.hContext), &index, ++ LONG status = smartcard_unpack_redir_scard_context(log, s, &(call->handles.hContext), &index, + &pbContextNdrPtr); + if (status != SCARD_S_SUCCESS) + return status; + +- if (!Stream_CheckAndLogRequiredLength(TAG, s, 12)) ++ if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 8)) + return STATUS_BUFFER_TOO_SMALL; + + Stream_Read_UINT32(s, call->dwTimeOut); /* dwTimeOut (4 bytes) */ + Stream_Read_UINT32(s, call->cReaders); /* cReaders (4 bytes) */ +- if (!smartcard_ndr_pointer_read(s, &index, &ndrPtr)) ++ if (!smartcard_ndr_pointer_read(log, s, &index, &ndrPtr)) + return ERROR_INVALID_DATA; + +- if ((status = smartcard_unpack_redir_scard_context_ref(s, pbContextNdrPtr, +- &(call->handles.hContext)))) ++ status = smartcard_unpack_redir_scard_context_ref(log, s, pbContextNdrPtr, ++ &(call->handles.hContext)); ++ if (status != SCARD_S_SUCCESS) + return status; + + if (ndrPtr) + { +- status = smartcard_unpack_reader_state_w(s, &call->rgReaderStates, call->cReaders, &index); ++ status = ++ smartcard_unpack_reader_state_w(log, s, &call->rgReaderStates, call->cReaders, &index); + if (status != SCARD_S_SUCCESS) + return status; + } ++ else ++ { ++ WLog_Print(log, WLOG_WARN, "ndrPtr=0x%08" PRIx32 ", can not read rgReaderStates", ndrPtr); ++ return SCARD_E_UNEXPECTED; ++ } + +- smartcard_trace_get_status_change_w_call(call); ++ smartcard_trace_get_status_change_w_call(log, call); + return SCARD_S_SUCCESS; + } + +@@ -2554,12 +2642,13 @@ LONG smartcard_pack_get_status_change_return(wStream* s, const GetStatusChange_R + BOOL unicode) + { + WINPR_ASSERT(ret); ++ wLog* log = scard_log(); + + LONG status = 0; + DWORD cReaders = ret->cReaders; + UINT32 index = 0; + +- smartcard_trace_get_status_change_return(ret, unicode); ++ smartcard_trace_get_status_change_return(log, ret, unicode); + if (ret->ReturnCode != SCARD_S_SUCCESS) + cReaders = 0; + if (cReaders == SCARD_AUTOALLOCATE) +@@ -2582,27 +2671,31 @@ LONG smartcard_unpack_state_call(wStream* s, State_Call* call) + UINT32 index = 0; + UINT32 pbContextNdrPtr = 0; + ++ wLog* log = scard_log(); ++ + WINPR_ASSERT(call); +- LONG status = smartcard_unpack_redir_scard_context(s, &(call->handles.hContext), &index, ++ LONG status = smartcard_unpack_redir_scard_context(log, s, &(call->handles.hContext), &index, + &pbContextNdrPtr); + if (status != SCARD_S_SUCCESS) + return status; + +- status = smartcard_unpack_redir_scard_handle(s, &(call->handles.hCard), &index); ++ status = smartcard_unpack_redir_scard_handle(log, s, &(call->handles.hCard), &index); + if (status != SCARD_S_SUCCESS) + return status; + +- if (!Stream_CheckAndLogRequiredLength(TAG, s, 8)) ++ if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 8)) + return STATUS_BUFFER_TOO_SMALL; + + Stream_Read_INT32(s, call->fpbAtrIsNULL); /* fpbAtrIsNULL (4 bytes) */ + Stream_Read_UINT32(s, call->cbAtrLen); /* cbAtrLen (4 bytes) */ + +- if ((status = smartcard_unpack_redir_scard_context_ref(s, pbContextNdrPtr, +- &(call->handles.hContext)))) ++ status = smartcard_unpack_redir_scard_context_ref(log, s, pbContextNdrPtr, ++ &(call->handles.hContext)); ++ if (status != SCARD_S_SUCCESS) + return status; + +- if ((status = smartcard_unpack_redir_scard_handle_ref(s, &(call->handles.hCard)))) ++ status = smartcard_unpack_redir_scard_handle_ref(log, s, &(call->handles.hCard)); ++ if (status != SCARD_S_SUCCESS) + return status; + + return status; +@@ -2611,11 +2704,12 @@ LONG smartcard_unpack_state_call(wStream* s, State_Call* call) + LONG smartcard_pack_state_return(wStream* s, const State_Return* ret) + { + WINPR_ASSERT(ret); ++ wLog* log = scard_log(); + LONG status = 0; + DWORD cbAtrLen = ret->cbAtrLen; + UINT32 index = 0; + +- smartcard_trace_state_return(ret); ++ smartcard_trace_state_return(log, ret); + if (ret->ReturnCode != SCARD_S_SUCCESS) + cbAtrLen = 0; + if (cbAtrLen == SCARD_AUTOALLOCATE) +@@ -2638,41 +2732,47 @@ LONG smartcard_unpack_status_call(wStream* s, Status_Call* call, BOOL unicode) + UINT32 pbContextNdrPtr = 0; + + WINPR_ASSERT(call); +- LONG status = smartcard_unpack_redir_scard_context(s, &(call->handles.hContext), &index, ++ wLog* log = scard_log(); ++ ++ LONG status = smartcard_unpack_redir_scard_context(log, s, &(call->handles.hContext), &index, + &pbContextNdrPtr); + if (status != SCARD_S_SUCCESS) + return status; + +- status = smartcard_unpack_redir_scard_handle(s, &(call->handles.hCard), &index); ++ status = smartcard_unpack_redir_scard_handle(log, s, &(call->handles.hCard), &index); + if (status != SCARD_S_SUCCESS) + return status; + +- if (!Stream_CheckAndLogRequiredLength(TAG, s, 12)) ++ if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 12)) + return STATUS_BUFFER_TOO_SMALL; + + Stream_Read_INT32(s, call->fmszReaderNamesIsNULL); /* fmszReaderNamesIsNULL (4 bytes) */ + Stream_Read_UINT32(s, call->cchReaderLen); /* cchReaderLen (4 bytes) */ + Stream_Read_UINT32(s, call->cbAtrLen); /* cbAtrLen (4 bytes) */ + +- if ((status = smartcard_unpack_redir_scard_context_ref(s, pbContextNdrPtr, +- &(call->handles.hContext)))) ++ status = smartcard_unpack_redir_scard_context_ref(log, s, pbContextNdrPtr, ++ &(call->handles.hContext)); ++ if (status != SCARD_S_SUCCESS) + return status; + +- if ((status = smartcard_unpack_redir_scard_handle_ref(s, &(call->handles.hCard)))) ++ status = smartcard_unpack_redir_scard_handle_ref(log, s, &(call->handles.hCard)); ++ if (status != SCARD_S_SUCCESS) + return status; + +- smartcard_trace_status_call(call, unicode); ++ smartcard_trace_status_call(log, call, unicode); + return status; + } + + LONG smartcard_pack_status_return(wStream* s, const Status_Return* ret, BOOL unicode) + { + WINPR_ASSERT(ret); ++ wLog* log = scard_log(); ++ + LONG status = 0; + UINT32 index = 0; + DWORD cBytes = ret->cBytes; + +- smartcard_trace_status_return(ret, unicode); ++ smartcard_trace_status_return(log, ret, unicode); + if (ret->ReturnCode != SCARD_S_SUCCESS) + cBytes = 0; + if (cBytes == SCARD_AUTOALLOCATE) +@@ -2701,33 +2801,36 @@ LONG smartcard_pack_status_return(wStream* s, const Status_Return* ret, BOOL uni + LONG smartcard_unpack_get_attrib_call(wStream* s, GetAttrib_Call* call) + { + WINPR_ASSERT(call); ++ wLog* log = scard_log(); + UINT32 index = 0; + UINT32 pbContextNdrPtr = 0; + +- LONG status = smartcard_unpack_redir_scard_context(s, &(call->handles.hContext), &index, ++ LONG status = smartcard_unpack_redir_scard_context(log, s, &(call->handles.hContext), &index, + &pbContextNdrPtr); + if (status != SCARD_S_SUCCESS) + return status; + +- status = smartcard_unpack_redir_scard_handle(s, &(call->handles.hCard), &index); ++ status = smartcard_unpack_redir_scard_handle(log, s, &(call->handles.hCard), &index); + if (status != SCARD_S_SUCCESS) + return status; + +- if (!Stream_CheckAndLogRequiredLength(TAG, s, 12)) ++ if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 12)) + return STATUS_BUFFER_TOO_SMALL; + + Stream_Read_UINT32(s, call->dwAttrId); /* dwAttrId (4 bytes) */ + Stream_Read_INT32(s, call->fpbAttrIsNULL); /* fpbAttrIsNULL (4 bytes) */ + Stream_Read_UINT32(s, call->cbAttrLen); /* cbAttrLen (4 bytes) */ + +- if ((status = smartcard_unpack_redir_scard_context_ref(s, pbContextNdrPtr, +- &(call->handles.hContext)))) ++ status = smartcard_unpack_redir_scard_context_ref(log, s, pbContextNdrPtr, ++ &(call->handles.hContext)); ++ if (status != SCARD_S_SUCCESS) + return status; + +- if ((status = smartcard_unpack_redir_scard_handle_ref(s, &(call->handles.hCard)))) ++ status = smartcard_unpack_redir_scard_handle_ref(log, s, &(call->handles.hCard)); ++ if (status != SCARD_S_SUCCESS) + return status; + +- smartcard_trace_get_attrib_call(call); ++ smartcard_trace_get_attrib_call(log, call); + return status; + } + +@@ -2735,10 +2838,11 @@ LONG smartcard_pack_get_attrib_return(wStream* s, const GetAttrib_Return* ret, D + DWORD cbAttrCallLen) + { + WINPR_ASSERT(ret); ++ wLog* log = scard_log(); + LONG status = 0; + DWORD cbAttrLen = 0; + UINT32 index = 0; +- smartcard_trace_get_attrib_return(ret, dwAttrId); ++ smartcard_trace_get_attrib_return(log, ret, dwAttrId); + + if (!Stream_EnsureRemainingCapacity(s, 4)) + return SCARD_F_INTERNAL_ERROR; +@@ -2767,57 +2871,65 @@ LONG smartcard_pack_get_attrib_return(wStream* s, const GetAttrib_Return* ret, D + LONG smartcard_unpack_control_call(wStream* s, Control_Call* call) + { + WINPR_ASSERT(call); ++ wLog* log = scard_log(); ++ + UINT32 index = 0; + UINT32 pvInBufferNdrPtr = 0; + UINT32 pbContextNdrPtr = 0; + + call->pvInBuffer = NULL; + +- LONG status = smartcard_unpack_redir_scard_context(s, &(call->handles.hContext), &index, ++ LONG status = smartcard_unpack_redir_scard_context(log, s, &(call->handles.hContext), &index, + &pbContextNdrPtr); + if (status != SCARD_S_SUCCESS) + return status; + +- status = smartcard_unpack_redir_scard_handle(s, &(call->handles.hCard), &index); ++ status = smartcard_unpack_redir_scard_handle(log, s, &(call->handles.hCard), &index); + if (status != SCARD_S_SUCCESS) + return status; + +- if (!Stream_CheckAndLogRequiredLength(TAG, s, 20)) ++ if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 20)) + return STATUS_BUFFER_TOO_SMALL; + + Stream_Read_UINT32(s, call->dwControlCode); /* dwControlCode (4 bytes) */ + Stream_Read_UINT32(s, call->cbInBufferSize); /* cbInBufferSize (4 bytes) */ +- if (!smartcard_ndr_pointer_read(s, &index, &pvInBufferNdrPtr)) /* pvInBufferNdrPtr (4 bytes) */ ++ if (!smartcard_ndr_pointer_read(log, s, &index, ++ &pvInBufferNdrPtr)) /* pvInBufferNdrPtr (4 bytes) */ + return ERROR_INVALID_DATA; + Stream_Read_INT32(s, call->fpvOutBufferIsNULL); /* fpvOutBufferIsNULL (4 bytes) */ + Stream_Read_UINT32(s, call->cbOutBufferSize); /* cbOutBufferSize (4 bytes) */ + +- if ((status = smartcard_unpack_redir_scard_context_ref(s, pbContextNdrPtr, +- &(call->handles.hContext)))) ++ status = smartcard_unpack_redir_scard_context_ref(log, s, pbContextNdrPtr, ++ &(call->handles.hContext)); ++ if (status != SCARD_S_SUCCESS) + return status; + +- if ((status = smartcard_unpack_redir_scard_handle_ref(s, &(call->handles.hCard)))) ++ status = smartcard_unpack_redir_scard_handle_ref(log, s, &(call->handles.hCard)); ++ if (status != SCARD_S_SUCCESS) + return status; + + if (pvInBufferNdrPtr) + { +- status = smartcard_ndr_read(s, &call->pvInBuffer, call->cbInBufferSize, 1, NDR_PTR_SIMPLE); ++ status = ++ smartcard_ndr_read(log, s, &call->pvInBuffer, call->cbInBufferSize, 1, NDR_PTR_SIMPLE); + if (status != SCARD_S_SUCCESS) + return status; + } + +- smartcard_trace_control_call(call); ++ smartcard_trace_control_call(log, call); + return SCARD_S_SUCCESS; + } + + LONG smartcard_pack_control_return(wStream* s, const Control_Return* ret) + { + WINPR_ASSERT(ret); ++ wLog* log = scard_log(); ++ + LONG status = 0; + DWORD cbDataLen = ret->cbOutBufferSize; + UINT32 index = 0; + +- smartcard_trace_control_return(ret); ++ smartcard_trace_control_return(log, ret); + if (ret->ReturnCode != SCARD_S_SUCCESS) + cbDataLen = 0; + if (cbDataLen == SCARD_AUTOALLOCATE) +@@ -2849,34 +2961,37 @@ LONG smartcard_unpack_transmit_call(wStream* s, Transmit_Call* call) + UINT32 pbContextNdrPtr = 0; + + WINPR_ASSERT(call); ++ wLog* log = scard_log(); ++ + call->pioSendPci = NULL; + call->pioRecvPci = NULL; + call->pbSendBuffer = NULL; + +- LONG status = smartcard_unpack_redir_scard_context(s, &(call->handles.hContext), &index, ++ LONG status = smartcard_unpack_redir_scard_context(log, s, &(call->handles.hContext), &index, + &pbContextNdrPtr); + if (status != SCARD_S_SUCCESS) + return status; + +- status = smartcard_unpack_redir_scard_handle(s, &(call->handles.hCard), &index); ++ status = smartcard_unpack_redir_scard_handle(log, s, &(call->handles.hCard), &index); + if (status != SCARD_S_SUCCESS) + return status; + +- if (!Stream_CheckAndLogRequiredLength(TAG, s, 32)) ++ if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 32)) + return STATUS_BUFFER_TOO_SMALL; + + Stream_Read_UINT32(s, ioSendPci.dwProtocol); /* dwProtocol (4 bytes) */ + Stream_Read_UINT32(s, ioSendPci.cbExtraBytes); /* cbExtraBytes (4 bytes) */ +- if (!smartcard_ndr_pointer_read(s, &index, ++ if (!smartcard_ndr_pointer_read(log, s, &index, + &pbExtraBytesNdrPtr)) /* pbExtraBytesNdrPtr (4 bytes) */ + return ERROR_INVALID_DATA; + + Stream_Read_UINT32(s, call->cbSendLength); /* cbSendLength (4 bytes) */ +- if (!smartcard_ndr_pointer_read(s, &index, ++ if (!smartcard_ndr_pointer_read(log, s, &index, + &pbSendBufferNdrPtr)) /* pbSendBufferNdrPtr (4 bytes) */ + return ERROR_INVALID_DATA; + +- if (!smartcard_ndr_pointer_read(s, &index, &pioRecvPciNdrPtr)) /* pioRecvPciNdrPtr (4 bytes) */ ++ if (!smartcard_ndr_pointer_read(log, s, &index, ++ &pioRecvPciNdrPtr)) /* pioRecvPciNdrPtr (4 bytes) */ + return ERROR_INVALID_DATA; + + Stream_Read_INT32(s, call->fpbRecvBufferIsNULL); /* fpbRecvBufferIsNULL (4 bytes) */ +@@ -2884,42 +2999,46 @@ LONG smartcard_unpack_transmit_call(wStream* s, Transmit_Call* call) + + if (ioSendPci.cbExtraBytes > 1024) + { +- WLog_WARN(TAG, +- "Transmit_Call ioSendPci.cbExtraBytes is out of bounds: %" PRIu32 " (max: 1024)", +- ioSendPci.cbExtraBytes); ++ WLog_Print(log, WLOG_WARN, ++ "Transmit_Call ioSendPci.cbExtraBytes is out of bounds: %" PRIu32 " (max: 1024)", ++ ioSendPci.cbExtraBytes); + return STATUS_INVALID_PARAMETER; + } + + if (call->cbSendLength > 66560) + { +- WLog_WARN(TAG, "Transmit_Call cbSendLength is out of bounds: %" PRIu32 " (max: 66560)", +- ioSendPci.cbExtraBytes); ++ WLog_Print(log, WLOG_WARN, ++ "Transmit_Call cbSendLength is out of bounds: %" PRIu32 " (max: 66560)", ++ ioSendPci.cbExtraBytes); + return STATUS_INVALID_PARAMETER; + } + +- if ((status = smartcard_unpack_redir_scard_context_ref(s, pbContextNdrPtr, +- &(call->handles.hContext)))) ++ status = smartcard_unpack_redir_scard_context_ref(log, s, pbContextNdrPtr, ++ &(call->handles.hContext)); ++ if (status != SCARD_S_SUCCESS) + return status; + +- if ((status = smartcard_unpack_redir_scard_handle_ref(s, &(call->handles.hCard)))) ++ status = smartcard_unpack_redir_scard_handle_ref(log, s, &(call->handles.hCard)); ++ if (status != SCARD_S_SUCCESS) + return status; + + if (ioSendPci.cbExtraBytes && !pbExtraBytesNdrPtr) + { +- WLog_WARN( +- TAG, "Transmit_Call ioSendPci.cbExtraBytes is non-zero but pbExtraBytesNdrPtr is null"); ++ WLog_Print( ++ log, WLOG_WARN, ++ "Transmit_Call ioSendPci.cbExtraBytes is non-zero but pbExtraBytesNdrPtr is null"); + return STATUS_INVALID_PARAMETER; + } + + if (pbExtraBytesNdrPtr) + { + // TODO: Use unified pointer reading +- if (!Stream_CheckAndLogRequiredLength(TAG, s, 4)) ++ if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4)) + return STATUS_BUFFER_TOO_SMALL; + + Stream_Read_UINT32(s, length); /* Length (4 bytes) */ + +- if (!Stream_CheckAndLogRequiredLength(TAG, s, ioSendPci.cbExtraBytes)) ++ if (!Stream_CheckAndLogRequiredLengthWLog(log, s, ioSendPci.cbExtraBytes)) + return STATUS_BUFFER_TOO_SMALL; + + ioSendPci.pbExtraBytes = Stream_Pointer(s); +@@ -2928,7 +3047,7 @@ LONG smartcard_unpack_transmit_call(wStream* s, Transmit_Call* call) + + if (!call->pioSendPci) + { +- WLog_WARN(TAG, "Transmit_Call out of memory error (pioSendPci)"); ++ WLog_Print(log, WLOG_WARN, "Transmit_Call out of memory error (pioSendPci)"); + return STATUS_NO_MEMORY; + } + +@@ -2944,7 +3063,7 @@ LONG smartcard_unpack_transmit_call(wStream* s, Transmit_Call* call) + + if (!call->pioSendPci) + { +- WLog_WARN(TAG, "Transmit_Call out of memory error (pioSendPci)"); ++ WLog_Print(log, WLOG_WARN, "Transmit_Call out of memory error (pioSendPci)"); + return STATUS_NO_MEMORY; + } + +@@ -2954,26 +3073,27 @@ LONG smartcard_unpack_transmit_call(wStream* s, Transmit_Call* call) + + if (pbSendBufferNdrPtr) + { +- status = smartcard_ndr_read(s, &call->pbSendBuffer, call->cbSendLength, 1, NDR_PTR_SIMPLE); ++ status = ++ smartcard_ndr_read(log, s, &call->pbSendBuffer, call->cbSendLength, 1, NDR_PTR_SIMPLE); + if (status != SCARD_S_SUCCESS) + return status; + } + + if (pioRecvPciNdrPtr) + { +- if (!Stream_CheckAndLogRequiredLength(TAG, s, 12)) ++ if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 12)) + return STATUS_BUFFER_TOO_SMALL; + + Stream_Read_UINT32(s, ioRecvPci.dwProtocol); /* dwProtocol (4 bytes) */ + Stream_Read_UINT32(s, ioRecvPci.cbExtraBytes); /* cbExtraBytes (4 bytes) */ +- if (!smartcard_ndr_pointer_read(s, &index, ++ if (!smartcard_ndr_pointer_read(log, s, &index, + &pbExtraBytesNdrPtr)) /* pbExtraBytesNdrPtr (4 bytes) */ + return ERROR_INVALID_DATA; + + if (ioRecvPci.cbExtraBytes && !pbExtraBytesNdrPtr) + { +- WLog_WARN( +- TAG, ++ WLog_Print( ++ log, WLOG_WARN, + "Transmit_Call ioRecvPci.cbExtraBytes is non-zero but pbExtraBytesNdrPtr is null"); + return STATUS_INVALID_PARAMETER; + } +@@ -2981,30 +3101,30 @@ LONG smartcard_unpack_transmit_call(wStream* s, Transmit_Call* call) + if (pbExtraBytesNdrPtr) + { + // TODO: Unify ndr pointer reading +- if (!Stream_CheckAndLogRequiredLength(TAG, s, 4)) ++ if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4)) + return STATUS_BUFFER_TOO_SMALL; + + Stream_Read_UINT32(s, length); /* Length (4 bytes) */ + + if (ioRecvPci.cbExtraBytes > 1024) + { +- WLog_WARN(TAG, +- "Transmit_Call ioRecvPci.cbExtraBytes is out of bounds: %" PRIu32 +- " (max: 1024)", +- ioRecvPci.cbExtraBytes); ++ WLog_Print(log, WLOG_WARN, ++ "Transmit_Call ioRecvPci.cbExtraBytes is out of bounds: %" PRIu32 ++ " (max: 1024)", ++ ioRecvPci.cbExtraBytes); + return STATUS_INVALID_PARAMETER; + } + + if (length != ioRecvPci.cbExtraBytes) + { +- WLog_WARN(TAG, +- "Transmit_Call unexpected length: Actual: %" PRIu32 ", Expected: %" PRIu32 +- " (ioRecvPci.cbExtraBytes)", +- length, ioRecvPci.cbExtraBytes); ++ WLog_Print(log, WLOG_WARN, ++ "Transmit_Call unexpected length: Actual: %" PRIu32 ++ ", Expected: %" PRIu32 " (ioRecvPci.cbExtraBytes)", ++ length, ioRecvPci.cbExtraBytes); + return STATUS_INVALID_PARAMETER; + } + +- if (!Stream_CheckAndLogRequiredLength(TAG, s, ioRecvPci.cbExtraBytes)) ++ if (!Stream_CheckAndLogRequiredLengthWLog(log, s, ioRecvPci.cbExtraBytes)) + return STATUS_BUFFER_TOO_SMALL; + + ioRecvPci.pbExtraBytes = Stream_Pointer(s); +@@ -3013,7 +3133,7 @@ LONG smartcard_unpack_transmit_call(wStream* s, Transmit_Call* call) + + if (!call->pioRecvPci) + { +- WLog_WARN(TAG, "Transmit_Call out of memory error (pioRecvPci)"); ++ WLog_Print(log, WLOG_WARN, "Transmit_Call out of memory error (pioRecvPci)"); + return STATUS_NO_MEMORY; + } + +@@ -3030,7 +3150,7 @@ LONG smartcard_unpack_transmit_call(wStream* s, Transmit_Call* call) + + if (!call->pioRecvPci) + { +- WLog_WARN(TAG, "Transmit_Call out of memory error (pioRecvPci)"); ++ WLog_Print(log, WLOG_WARN, "Transmit_Call out of memory error (pioRecvPci)"); + return STATUS_NO_MEMORY; + } + +@@ -3039,20 +3159,22 @@ LONG smartcard_unpack_transmit_call(wStream* s, Transmit_Call* call) + } + } + +- smartcard_trace_transmit_call(call); ++ smartcard_trace_transmit_call(log, call); + return SCARD_S_SUCCESS; + } + + LONG smartcard_pack_transmit_return(wStream* s, const Transmit_Return* ret) + { + WINPR_ASSERT(ret); ++ wLog* log = scard_log(); ++ + LONG status = 0; + UINT32 index = 0; + LONG error = 0; + UINT32 cbRecvLength = ret->cbRecvLength; + UINT32 cbRecvPci = ret->pioRecvPci ? ret->pioRecvPci->cbPciLength : 0; + +- smartcard_trace_transmit_return(ret); ++ smartcard_trace_transmit_return(log, ret); + + if (!ret->pbRecvBuffer) + cbRecvLength = 0; +@@ -3072,7 +3194,7 @@ LONG smartcard_pack_transmit_return(wStream* s, const Transmit_Return* ret) + + if (!Stream_EnsureRemainingCapacity(s, cbExtraBytes + 16)) + { +- WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!"); ++ WLog_Print(log, WLOG_ERROR, "Stream_EnsureRemainingCapacity failed!"); + return SCARD_F_INTERNAL_ERROR; + } + +@@ -3099,51 +3221,55 @@ LONG smartcard_unpack_locate_cards_by_atr_a_call(wStream* s, LocateCardsByATRA_C + UINT32 pbContextNdrPtr = 0; + + WINPR_ASSERT(call); ++ wLog* log = scard_log(); ++ + call->rgReaderStates = NULL; + +- LONG status = smartcard_unpack_redir_scard_context(s, &(call->handles.hContext), &index, ++ LONG status = smartcard_unpack_redir_scard_context(log, s, &(call->handles.hContext), &index, + &pbContextNdrPtr); + if (status != SCARD_S_SUCCESS) + return status; + +- if (!Stream_CheckAndLogRequiredLength(TAG, s, 16)) ++ if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 16)) + return STATUS_BUFFER_TOO_SMALL; + + Stream_Read_UINT32(s, call->cAtrs); +- if (!smartcard_ndr_pointer_read(s, &index, &rgAtrMasksNdrPtr)) ++ if (!smartcard_ndr_pointer_read(log, s, &index, &rgAtrMasksNdrPtr)) + return ERROR_INVALID_DATA; + Stream_Read_UINT32(s, call->cReaders); /* cReaders (4 bytes) */ +- if (!smartcard_ndr_pointer_read(s, &index, &rgReaderStatesNdrPtr)) ++ if (!smartcard_ndr_pointer_read(log, s, &index, &rgReaderStatesNdrPtr)) + return ERROR_INVALID_DATA; + +- if ((status = smartcard_unpack_redir_scard_context_ref(s, pbContextNdrPtr, +- &(call->handles.hContext)))) ++ status = smartcard_unpack_redir_scard_context_ref(log, s, pbContextNdrPtr, ++ &(call->handles.hContext)); ++ if (status != SCARD_S_SUCCESS) + return status; + + if ((rgAtrMasksNdrPtr && !call->cAtrs) || (!rgAtrMasksNdrPtr && call->cAtrs)) + { +- WLog_WARN(TAG, +- "LocateCardsByATRA_Call rgAtrMasksNdrPtr (0x%08" PRIX32 +- ") and cAtrs (0x%08" PRIX32 ") inconsistency", +- rgAtrMasksNdrPtr, call->cAtrs); ++ WLog_Print(log, WLOG_WARN, ++ "LocateCardsByATRA_Call rgAtrMasksNdrPtr (0x%08" PRIX32 ++ ") and cAtrs (0x%08" PRIX32 ") inconsistency", ++ rgAtrMasksNdrPtr, call->cAtrs); + return STATUS_INVALID_PARAMETER; + } + + if (rgAtrMasksNdrPtr) + { +- status = smartcard_ndr_read_atrmask(s, &call->rgAtrMasks, call->cAtrs, NDR_PTR_SIMPLE); ++ status = smartcard_ndr_read_atrmask(log, s, &call->rgAtrMasks, call->cAtrs, NDR_PTR_SIMPLE); + if (status != SCARD_S_SUCCESS) + return status; + } + + if (rgReaderStatesNdrPtr) + { +- status = smartcard_unpack_reader_state_a(s, &call->rgReaderStates, call->cReaders, &index); ++ status = ++ smartcard_unpack_reader_state_a(log, s, &call->rgReaderStates, call->cReaders, &index); + if (status != SCARD_S_SUCCESS) + return status; + } + +- smartcard_trace_locate_cards_by_atr_a_call(call); ++ smartcard_trace_locate_cards_by_atr_a_call(log, call); + return SCARD_S_SUCCESS; + } + +@@ -3155,33 +3281,36 @@ LONG smartcard_unpack_context_and_two_strings_a_call(wStream* s, ContextAndTwoSt + UINT32 pbContextNdrPtr = 0; + + WINPR_ASSERT(call); +- LONG status = smartcard_unpack_redir_scard_context(s, &(call->handles.hContext), &index, ++ wLog* log = scard_log(); ++ ++ LONG status = smartcard_unpack_redir_scard_context(log, s, &(call->handles.hContext), &index, + &pbContextNdrPtr); + if (status != SCARD_S_SUCCESS) + return status; + +- if (!smartcard_ndr_pointer_read(s, &index, &sz1NdrPtr)) ++ if (!smartcard_ndr_pointer_read(log, s, &index, &sz1NdrPtr)) + return ERROR_INVALID_DATA; +- if (!smartcard_ndr_pointer_read(s, &index, &sz2NdrPtr)) ++ if (!smartcard_ndr_pointer_read(log, s, &index, &sz2NdrPtr)) + return ERROR_INVALID_DATA; + +- status = smartcard_unpack_redir_scard_context_ref(s, pbContextNdrPtr, &call->handles.hContext); ++ status = ++ smartcard_unpack_redir_scard_context_ref(log, s, pbContextNdrPtr, &call->handles.hContext); + if (status != SCARD_S_SUCCESS) + return status; + + if (sz1NdrPtr) + { +- status = smartcard_ndr_read_a(s, &call->sz1, NDR_PTR_FULL); ++ status = smartcard_ndr_read_a(log, s, &call->sz1, NDR_PTR_FULL); + if (status != SCARD_S_SUCCESS) + return status; + } + if (sz2NdrPtr) + { +- status = smartcard_ndr_read_a(s, &call->sz2, NDR_PTR_FULL); ++ status = smartcard_ndr_read_a(log, s, &call->sz2, NDR_PTR_FULL); + if (status != SCARD_S_SUCCESS) + return status; + } +- smartcard_trace_context_and_two_strings_a_call(call); ++ smartcard_trace_context_and_two_strings_a_call(log, call); + return SCARD_S_SUCCESS; + } + +@@ -3193,33 +3322,36 @@ LONG smartcard_unpack_context_and_two_strings_w_call(wStream* s, ContextAndTwoSt + UINT32 pbContextNdrPtr = 0; + + WINPR_ASSERT(call); +- LONG status = smartcard_unpack_redir_scard_context(s, &(call->handles.hContext), &index, ++ wLog* log = scard_log(); ++ ++ LONG status = smartcard_unpack_redir_scard_context(log, s, &(call->handles.hContext), &index, + &pbContextNdrPtr); + if (status != SCARD_S_SUCCESS) + return status; + +- if (!smartcard_ndr_pointer_read(s, &index, &sz1NdrPtr)) ++ if (!smartcard_ndr_pointer_read(log, s, &index, &sz1NdrPtr)) + return ERROR_INVALID_DATA; +- if (!smartcard_ndr_pointer_read(s, &index, &sz2NdrPtr)) ++ if (!smartcard_ndr_pointer_read(log, s, &index, &sz2NdrPtr)) + return ERROR_INVALID_DATA; + +- status = smartcard_unpack_redir_scard_context_ref(s, pbContextNdrPtr, &call->handles.hContext); ++ status = ++ smartcard_unpack_redir_scard_context_ref(log, s, pbContextNdrPtr, &call->handles.hContext); + if (status != SCARD_S_SUCCESS) + return status; + + if (sz1NdrPtr) + { +- status = smartcard_ndr_read_w(s, &call->sz1, NDR_PTR_FULL); ++ status = smartcard_ndr_read_w(log, s, &call->sz1, NDR_PTR_FULL); + if (status != SCARD_S_SUCCESS) + return status; + } + if (sz2NdrPtr) + { +- status = smartcard_ndr_read_w(s, &call->sz2, NDR_PTR_FULL); ++ status = smartcard_ndr_read_w(log, s, &call->sz2, NDR_PTR_FULL); + if (status != SCARD_S_SUCCESS) + return status; + } +- smartcard_trace_context_and_two_strings_w_call(call); ++ smartcard_trace_context_and_two_strings_w_call(log, call); + return SCARD_S_SUCCESS; + } + +@@ -3231,40 +3363,44 @@ LONG smartcard_unpack_locate_cards_a_call(wStream* s, LocateCardsA_Call* call) + UINT32 pbContextNdrPtr = 0; + + WINPR_ASSERT(call); +- LONG status = smartcard_unpack_redir_scard_context(s, &(call->handles.hContext), &index, ++ wLog* log = scard_log(); ++ ++ LONG status = smartcard_unpack_redir_scard_context(log, s, &(call->handles.hContext), &index, + &pbContextNdrPtr); + if (status != SCARD_S_SUCCESS) + return status; + +- if (!Stream_CheckAndLogRequiredLength(TAG, s, 16)) ++ if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 16)) + return STATUS_BUFFER_TOO_SMALL; + + Stream_Read_UINT32(s, call->cBytes); +- if (!smartcard_ndr_pointer_read(s, &index, &sz1NdrPtr)) ++ if (!smartcard_ndr_pointer_read(log, s, &index, &sz1NdrPtr)) + return ERROR_INVALID_DATA; + + Stream_Read_UINT32(s, call->cReaders); +- if (!smartcard_ndr_pointer_read(s, &index, &sz2NdrPtr)) ++ if (!smartcard_ndr_pointer_read(log, s, &index, &sz2NdrPtr)) + return ERROR_INVALID_DATA; + +- if ((status = smartcard_unpack_redir_scard_context_ref(s, pbContextNdrPtr, +- &(call->handles.hContext)))) ++ status = smartcard_unpack_redir_scard_context_ref(log, s, pbContextNdrPtr, ++ &(call->handles.hContext)); ++ if (status != SCARD_S_SUCCESS) + return status; + + if (sz1NdrPtr) + { +- status = +- smartcard_ndr_read_fixed_string_a(s, &call->mszCards, call->cBytes, NDR_PTR_SIMPLE); ++ status = smartcard_ndr_read_fixed_string_a(log, s, &call->mszCards, call->cBytes, ++ NDR_PTR_SIMPLE); + if (status != SCARD_S_SUCCESS) + return status; + } + if (sz2NdrPtr) + { +- status = smartcard_unpack_reader_state_a(s, &call->rgReaderStates, call->cReaders, &index); ++ status = ++ smartcard_unpack_reader_state_a(log, s, &call->rgReaderStates, call->cReaders, &index); + if (status != SCARD_S_SUCCESS) + return status; + } +- smartcard_trace_locate_cards_a_call(call); ++ smartcard_trace_locate_cards_a_call(log, call); + return SCARD_S_SUCCESS; + } + +@@ -3276,40 +3412,44 @@ LONG smartcard_unpack_locate_cards_w_call(wStream* s, LocateCardsW_Call* call) + UINT32 pbContextNdrPtr = 0; + + WINPR_ASSERT(call); +- LONG status = smartcard_unpack_redir_scard_context(s, &(call->handles.hContext), &index, ++ wLog* log = scard_log(); ++ ++ LONG status = smartcard_unpack_redir_scard_context(log, s, &(call->handles.hContext), &index, + &pbContextNdrPtr); + if (status != SCARD_S_SUCCESS) + return status; + +- if (!Stream_CheckAndLogRequiredLength(TAG, s, 16)) ++ if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 16)) + return STATUS_BUFFER_TOO_SMALL; + + Stream_Read_UINT32(s, call->cBytes); +- if (!smartcard_ndr_pointer_read(s, &index, &sz1NdrPtr)) ++ if (!smartcard_ndr_pointer_read(log, s, &index, &sz1NdrPtr)) + return ERROR_INVALID_DATA; + + Stream_Read_UINT32(s, call->cReaders); +- if (!smartcard_ndr_pointer_read(s, &index, &sz2NdrPtr)) ++ if (!smartcard_ndr_pointer_read(log, s, &index, &sz2NdrPtr)) + return ERROR_INVALID_DATA; + +- if ((status = smartcard_unpack_redir_scard_context_ref(s, pbContextNdrPtr, +- &(call->handles.hContext)))) ++ status = smartcard_unpack_redir_scard_context_ref(log, s, pbContextNdrPtr, ++ &(call->handles.hContext)); ++ if (status != SCARD_S_SUCCESS) + return status; + + if (sz1NdrPtr) + { +- status = +- smartcard_ndr_read_fixed_string_w(s, &call->mszCards, call->cBytes, NDR_PTR_SIMPLE); ++ status = smartcard_ndr_read_fixed_string_w(log, s, &call->mszCards, call->cBytes, ++ NDR_PTR_SIMPLE); + if (status != SCARD_S_SUCCESS) + return status; + } + if (sz2NdrPtr) + { +- status = smartcard_unpack_reader_state_w(s, &call->rgReaderStates, call->cReaders, &index); ++ status = ++ smartcard_unpack_reader_state_w(log, s, &call->rgReaderStates, call->cReaders, &index); + if (status != SCARD_S_SUCCESS) + return status; + } +- smartcard_trace_locate_cards_w_call(call); ++ smartcard_trace_locate_cards_w_call(log, call); + return SCARD_S_SUCCESS; + } + +@@ -3320,38 +3460,42 @@ LONG smartcard_unpack_set_attrib_call(wStream* s, SetAttrib_Call* call) + UINT32 pbContextNdrPtr = 0; + + WINPR_ASSERT(call); +- LONG status = smartcard_unpack_redir_scard_context(s, &(call->handles.hContext), &index, ++ wLog* log = scard_log(); ++ ++ LONG status = smartcard_unpack_redir_scard_context(log, s, &(call->handles.hContext), &index, + &pbContextNdrPtr); + if (status != SCARD_S_SUCCESS) + return status; +- status = smartcard_unpack_redir_scard_handle(s, &(call->handles.hCard), &index); ++ status = smartcard_unpack_redir_scard_handle(log, s, &(call->handles.hCard), &index); + if (status != SCARD_S_SUCCESS) + return status; + +- if (!Stream_CheckAndLogRequiredLength(TAG, s, 12)) ++ if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 12)) + return STATUS_BUFFER_TOO_SMALL; + Stream_Read_UINT32(s, call->dwAttrId); + Stream_Read_UINT32(s, call->cbAttrLen); + +- if (!smartcard_ndr_pointer_read(s, &index, &ndrPtr)) ++ if (!smartcard_ndr_pointer_read(log, s, &index, &ndrPtr)) + return ERROR_INVALID_DATA; + +- if ((status = smartcard_unpack_redir_scard_context_ref(s, pbContextNdrPtr, +- &(call->handles.hContext)))) ++ status = smartcard_unpack_redir_scard_context_ref(log, s, pbContextNdrPtr, ++ &(call->handles.hContext)); ++ if (status != SCARD_S_SUCCESS) + return status; + +- if ((status = smartcard_unpack_redir_scard_handle_ref(s, &(call->handles.hCard)))) ++ status = smartcard_unpack_redir_scard_handle_ref(log, s, &(call->handles.hCard)); ++ if (status != SCARD_S_SUCCESS) + return status; + + if (ndrPtr) + { + // TODO: call->cbAttrLen was larger than the pointer value. + // TODO: Maybe need to refine the checks? +- status = smartcard_ndr_read(s, &call->pbAttr, 0, 1, NDR_PTR_SIMPLE); ++ status = smartcard_ndr_read(log, s, &call->pbAttr, 0, 1, NDR_PTR_SIMPLE); + if (status != SCARD_S_SUCCESS) + return status; + } +- smartcard_trace_set_attrib_call(call); ++ smartcard_trace_set_attrib_call(log, call); + return SCARD_S_SUCCESS; + } + +@@ -3363,52 +3507,56 @@ LONG smartcard_unpack_locate_cards_by_atr_w_call(wStream* s, LocateCardsByATRW_C + UINT32 pbContextNdrPtr = 0; + + WINPR_ASSERT(call); ++ wLog* log = scard_log(); ++ + call->rgReaderStates = NULL; + +- LONG status = smartcard_unpack_redir_scard_context(s, &(call->handles.hContext), &index, ++ LONG status = smartcard_unpack_redir_scard_context(log, s, &(call->handles.hContext), &index, + &pbContextNdrPtr); + if (status != SCARD_S_SUCCESS) + return status; + +- if (!Stream_CheckAndLogRequiredLength(TAG, s, 16)) ++ if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 16)) + return STATUS_BUFFER_TOO_SMALL; + + Stream_Read_UINT32(s, call->cAtrs); +- if (!smartcard_ndr_pointer_read(s, &index, &rgAtrMasksNdrPtr)) ++ if (!smartcard_ndr_pointer_read(log, s, &index, &rgAtrMasksNdrPtr)) + return ERROR_INVALID_DATA; + + Stream_Read_UINT32(s, call->cReaders); /* cReaders (4 bytes) */ +- if (!smartcard_ndr_pointer_read(s, &index, &rgReaderStatesNdrPtr)) ++ if (!smartcard_ndr_pointer_read(log, s, &index, &rgReaderStatesNdrPtr)) + return ERROR_INVALID_DATA; + +- if ((status = smartcard_unpack_redir_scard_context_ref(s, pbContextNdrPtr, +- &(call->handles.hContext)))) ++ status = smartcard_unpack_redir_scard_context_ref(log, s, pbContextNdrPtr, ++ &(call->handles.hContext)); ++ if (status != SCARD_S_SUCCESS) + return status; + + if ((rgAtrMasksNdrPtr && !call->cAtrs) || (!rgAtrMasksNdrPtr && call->cAtrs)) + { +- WLog_WARN(TAG, +- "LocateCardsByATRW_Call rgAtrMasksNdrPtr (0x%08" PRIX32 +- ") and cAtrs (0x%08" PRIX32 ") inconsistency", +- rgAtrMasksNdrPtr, call->cAtrs); ++ WLog_Print(log, WLOG_WARN, ++ "LocateCardsByATRW_Call rgAtrMasksNdrPtr (0x%08" PRIX32 ++ ") and cAtrs (0x%08" PRIX32 ") inconsistency", ++ rgAtrMasksNdrPtr, call->cAtrs); + return STATUS_INVALID_PARAMETER; + } + + if (rgAtrMasksNdrPtr) + { +- status = smartcard_ndr_read_atrmask(s, &call->rgAtrMasks, call->cAtrs, NDR_PTR_SIMPLE); ++ status = smartcard_ndr_read_atrmask(log, s, &call->rgAtrMasks, call->cAtrs, NDR_PTR_SIMPLE); + if (status != SCARD_S_SUCCESS) + return status; + } + + if (rgReaderStatesNdrPtr) + { +- status = smartcard_unpack_reader_state_w(s, &call->rgReaderStates, call->cReaders, &index); ++ status = ++ smartcard_unpack_reader_state_w(log, s, &call->rgReaderStates, call->cReaders, &index); + if (status != SCARD_S_SUCCESS) + return status; + } + +- smartcard_trace_locate_cards_by_atr_w_call(call); ++ smartcard_trace_locate_cards_by_atr_w_call(log, call); + return SCARD_S_SUCCESS; + } + +@@ -3420,18 +3568,20 @@ LONG smartcard_unpack_read_cache_a_call(wStream* s, ReadCacheA_Call* call) + UINT32 pbContextNdrPtr = 0; + + WINPR_ASSERT(call); +- if (!smartcard_ndr_pointer_read(s, &index, &mszNdrPtr)) ++ wLog* log = scard_log(); ++ ++ if (!smartcard_ndr_pointer_read(log, s, &index, &mszNdrPtr)) + return ERROR_INVALID_DATA; + +- LONG status = smartcard_unpack_redir_scard_context(s, &(call->Common.handles.hContext), &index, +- &pbContextNdrPtr); ++ LONG status = smartcard_unpack_redir_scard_context(log, s, &(call->Common.handles.hContext), ++ &index, &pbContextNdrPtr); + if (status != SCARD_S_SUCCESS) + return status; + +- if (!smartcard_ndr_pointer_read(s, &index, &contextNdrPtr)) ++ if (!smartcard_ndr_pointer_read(log, s, &index, &contextNdrPtr)) + return ERROR_INVALID_DATA; + +- if (!Stream_CheckAndLogRequiredLength(TAG, s, 12)) ++ if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 12)) + return STATUS_BUFFER_TOO_SMALL; + Stream_Read_UINT32(s, call->Common.FreshnessCounter); + Stream_Read_INT32(s, call->Common.fPbDataIsNULL); +@@ -3440,23 +3590,23 @@ LONG smartcard_unpack_read_cache_a_call(wStream* s, ReadCacheA_Call* call) + call->szLookupName = NULL; + if (mszNdrPtr) + { +- status = smartcard_ndr_read_a(s, &call->szLookupName, NDR_PTR_FULL); ++ status = smartcard_ndr_read_a(log, s, &call->szLookupName, NDR_PTR_FULL); + if (status != SCARD_S_SUCCESS) + return status; + } + +- status = smartcard_unpack_redir_scard_context_ref(s, pbContextNdrPtr, ++ status = smartcard_unpack_redir_scard_context_ref(log, s, pbContextNdrPtr, + &call->Common.handles.hContext); + if (status != SCARD_S_SUCCESS) + return status; + + if (contextNdrPtr) + { +- status = smartcard_ndr_read_u(s, &call->Common.CardIdentifier); ++ status = smartcard_ndr_read_u(log, s, &call->Common.CardIdentifier); + if (status != SCARD_S_SUCCESS) + return status; + } +- smartcard_trace_read_cache_a_call(call); ++ smartcard_trace_read_cache_a_call(log, call); + return SCARD_S_SUCCESS; + } + +@@ -3468,18 +3618,20 @@ LONG smartcard_unpack_read_cache_w_call(wStream* s, ReadCacheW_Call* call) + UINT32 pbContextNdrPtr = 0; + + WINPR_ASSERT(call); +- if (!smartcard_ndr_pointer_read(s, &index, &mszNdrPtr)) ++ wLog* log = scard_log(); ++ ++ if (!smartcard_ndr_pointer_read(log, s, &index, &mszNdrPtr)) + return ERROR_INVALID_DATA; + +- LONG status = smartcard_unpack_redir_scard_context(s, &(call->Common.handles.hContext), &index, +- &pbContextNdrPtr); ++ LONG status = smartcard_unpack_redir_scard_context(log, s, &(call->Common.handles.hContext), ++ &index, &pbContextNdrPtr); + if (status != SCARD_S_SUCCESS) + return status; + +- if (!smartcard_ndr_pointer_read(s, &index, &contextNdrPtr)) ++ if (!smartcard_ndr_pointer_read(log, s, &index, &contextNdrPtr)) + return ERROR_INVALID_DATA; + +- if (!Stream_CheckAndLogRequiredLength(TAG, s, 12)) ++ if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 12)) + return STATUS_BUFFER_TOO_SMALL; + Stream_Read_UINT32(s, call->Common.FreshnessCounter); + Stream_Read_INT32(s, call->Common.fPbDataIsNULL); +@@ -3488,23 +3640,23 @@ LONG smartcard_unpack_read_cache_w_call(wStream* s, ReadCacheW_Call* call) + call->szLookupName = NULL; + if (mszNdrPtr) + { +- status = smartcard_ndr_read_w(s, &call->szLookupName, NDR_PTR_FULL); ++ status = smartcard_ndr_read_w(log, s, &call->szLookupName, NDR_PTR_FULL); + if (status != SCARD_S_SUCCESS) + return status; + } + +- status = smartcard_unpack_redir_scard_context_ref(s, pbContextNdrPtr, ++ status = smartcard_unpack_redir_scard_context_ref(log, s, pbContextNdrPtr, + &call->Common.handles.hContext); + if (status != SCARD_S_SUCCESS) + return status; + + if (contextNdrPtr) + { +- status = smartcard_ndr_read_u(s, &call->Common.CardIdentifier); ++ status = smartcard_ndr_read_u(log, s, &call->Common.CardIdentifier); + if (status != SCARD_S_SUCCESS) + return status; + } +- smartcard_trace_read_cache_w_call(call); ++ smartcard_trace_read_cache_w_call(log, call); + return SCARD_S_SUCCESS; + } + +@@ -3517,35 +3669,37 @@ LONG smartcard_unpack_write_cache_a_call(wStream* s, WriteCacheA_Call* call) + UINT32 pbContextNdrPtr = 0; + + WINPR_ASSERT(call); +- if (!smartcard_ndr_pointer_read(s, &index, &mszNdrPtr)) ++ wLog* log = scard_log(); ++ ++ if (!smartcard_ndr_pointer_read(log, s, &index, &mszNdrPtr)) + return ERROR_INVALID_DATA; + +- LONG status = smartcard_unpack_redir_scard_context(s, &(call->Common.handles.hContext), &index, +- &pbContextNdrPtr); ++ LONG status = smartcard_unpack_redir_scard_context(log, s, &(call->Common.handles.hContext), ++ &index, &pbContextNdrPtr); + if (status != SCARD_S_SUCCESS) + return status; + +- if (!smartcard_ndr_pointer_read(s, &index, &contextNdrPtr)) ++ if (!smartcard_ndr_pointer_read(log, s, &index, &contextNdrPtr)) + return ERROR_INVALID_DATA; + +- if (!Stream_CheckAndLogRequiredLength(TAG, s, 8)) ++ if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 8)) + return STATUS_BUFFER_TOO_SMALL; + + Stream_Read_UINT32(s, call->Common.FreshnessCounter); + Stream_Read_UINT32(s, call->Common.cbDataLen); + +- if (!smartcard_ndr_pointer_read(s, &index, &pbDataNdrPtr)) ++ if (!smartcard_ndr_pointer_read(log, s, &index, &pbDataNdrPtr)) + return ERROR_INVALID_DATA; + + call->szLookupName = NULL; + if (mszNdrPtr) + { +- status = smartcard_ndr_read_a(s, &call->szLookupName, NDR_PTR_FULL); ++ status = smartcard_ndr_read_a(log, s, &call->szLookupName, NDR_PTR_FULL); + if (status != SCARD_S_SUCCESS) + return status; + } + +- status = smartcard_unpack_redir_scard_context_ref(s, pbContextNdrPtr, ++ status = smartcard_unpack_redir_scard_context_ref(log, s, pbContextNdrPtr, + &call->Common.handles.hContext); + if (status != SCARD_S_SUCCESS) + return status; +@@ -3553,7 +3707,7 @@ LONG smartcard_unpack_write_cache_a_call(wStream* s, WriteCacheA_Call* call) + call->Common.CardIdentifier = NULL; + if (contextNdrPtr) + { +- status = smartcard_ndr_read_u(s, &call->Common.CardIdentifier); ++ status = smartcard_ndr_read_u(log, s, &call->Common.CardIdentifier); + if (status != SCARD_S_SUCCESS) + return status; + } +@@ -3561,12 +3715,12 @@ LONG smartcard_unpack_write_cache_a_call(wStream* s, WriteCacheA_Call* call) + call->Common.pbData = NULL; + if (pbDataNdrPtr) + { +- status = +- smartcard_ndr_read(s, &call->Common.pbData, call->Common.cbDataLen, 1, NDR_PTR_SIMPLE); ++ status = smartcard_ndr_read(log, s, &call->Common.pbData, call->Common.cbDataLen, 1, ++ NDR_PTR_SIMPLE); + if (status != SCARD_S_SUCCESS) + return status; + } +- smartcard_trace_write_cache_a_call(call); ++ smartcard_trace_write_cache_a_call(log, call); + return SCARD_S_SUCCESS; + } + +@@ -3579,35 +3733,36 @@ LONG smartcard_unpack_write_cache_w_call(wStream* s, WriteCacheW_Call* call) + UINT32 pbContextNdrPtr = 0; + + WINPR_ASSERT(call); ++ wLog* log = scard_log(); + +- if (!smartcard_ndr_pointer_read(s, &index, &mszNdrPtr)) ++ if (!smartcard_ndr_pointer_read(log, s, &index, &mszNdrPtr)) + return ERROR_INVALID_DATA; + +- LONG status = smartcard_unpack_redir_scard_context(s, &(call->Common.handles.hContext), &index, +- &pbContextNdrPtr); ++ LONG status = smartcard_unpack_redir_scard_context(log, s, &(call->Common.handles.hContext), ++ &index, &pbContextNdrPtr); + if (status != SCARD_S_SUCCESS) + return status; + +- if (!smartcard_ndr_pointer_read(s, &index, &contextNdrPtr)) ++ if (!smartcard_ndr_pointer_read(log, s, &index, &contextNdrPtr)) + return ERROR_INVALID_DATA; + +- if (!Stream_CheckAndLogRequiredLength(TAG, s, 8)) ++ if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 8)) + return STATUS_BUFFER_TOO_SMALL; + Stream_Read_UINT32(s, call->Common.FreshnessCounter); + Stream_Read_UINT32(s, call->Common.cbDataLen); + +- if (!smartcard_ndr_pointer_read(s, &index, &pbDataNdrPtr)) ++ if (!smartcard_ndr_pointer_read(log, s, &index, &pbDataNdrPtr)) + return ERROR_INVALID_DATA; + + call->szLookupName = NULL; + if (mszNdrPtr) + { +- status = smartcard_ndr_read_w(s, &call->szLookupName, NDR_PTR_FULL); ++ status = smartcard_ndr_read_w(log, s, &call->szLookupName, NDR_PTR_FULL); + if (status != SCARD_S_SUCCESS) + return status; + } + +- status = smartcard_unpack_redir_scard_context_ref(s, pbContextNdrPtr, ++ status = smartcard_unpack_redir_scard_context_ref(log, s, pbContextNdrPtr, + &call->Common.handles.hContext); + if (status != SCARD_S_SUCCESS) + return status; +@@ -3615,7 +3770,7 @@ LONG smartcard_unpack_write_cache_w_call(wStream* s, WriteCacheW_Call* call) + call->Common.CardIdentifier = NULL; + if (contextNdrPtr) + { +- status = smartcard_ndr_read_u(s, &call->Common.CardIdentifier); ++ status = smartcard_ndr_read_u(log, s, &call->Common.CardIdentifier); + if (status != SCARD_S_SUCCESS) + return status; + } +@@ -3623,80 +3778,90 @@ LONG smartcard_unpack_write_cache_w_call(wStream* s, WriteCacheW_Call* call) + call->Common.pbData = NULL; + if (pbDataNdrPtr) + { +- status = +- smartcard_ndr_read(s, &call->Common.pbData, call->Common.cbDataLen, 1, NDR_PTR_SIMPLE); ++ status = smartcard_ndr_read(log, s, &call->Common.pbData, call->Common.cbDataLen, 1, ++ NDR_PTR_SIMPLE); + if (status != SCARD_S_SUCCESS) + return status; + } +- smartcard_trace_write_cache_w_call(call); ++ smartcard_trace_write_cache_w_call(log, call); + return status; + } + + LONG smartcard_unpack_get_transmit_count_call(wStream* s, GetTransmitCount_Call* call) + { + WINPR_ASSERT(call); ++ wLog* log = scard_log(); ++ + UINT32 index = 0; + UINT32 pbContextNdrPtr = 0; + +- LONG status = smartcard_unpack_redir_scard_context(s, &(call->handles.hContext), &index, ++ LONG status = smartcard_unpack_redir_scard_context(log, s, &(call->handles.hContext), &index, + &pbContextNdrPtr); + if (status != SCARD_S_SUCCESS) + return status; + +- status = smartcard_unpack_redir_scard_handle(s, &(call->handles.hCard), &index); ++ status = smartcard_unpack_redir_scard_handle(log, s, &(call->handles.hCard), &index); + if (status != SCARD_S_SUCCESS) + return status; + +- if ((status = smartcard_unpack_redir_scard_context_ref(s, pbContextNdrPtr, +- &(call->handles.hContext)))) ++ status = smartcard_unpack_redir_scard_context_ref(log, s, pbContextNdrPtr, ++ &(call->handles.hContext)); ++ if (status != SCARD_S_SUCCESS) + { +- WLog_ERR(TAG, "smartcard_unpack_redir_scard_context_ref failed with error %" PRId32 "", +- status); ++ WLog_Print(log, WLOG_ERROR, ++ "smartcard_unpack_redir_scard_context_ref failed with error %" PRId32 "", ++ status); + return status; + } + +- if ((status = smartcard_unpack_redir_scard_handle_ref(s, &(call->handles.hCard)))) +- WLog_ERR(TAG, "smartcard_unpack_redir_scard_handle_ref failed with error %" PRId32 "", +- status); ++ status = smartcard_unpack_redir_scard_handle_ref(log, s, &(call->handles.hCard)); ++ if (status != SCARD_S_SUCCESS) ++ WLog_Print(log, WLOG_ERROR, ++ "smartcard_unpack_redir_scard_handle_ref failed with error %" PRId32 "", status); + +- smartcard_trace_get_transmit_count_call(call); ++ smartcard_trace_get_transmit_count_call(log, call); + return status; + } + + LONG smartcard_unpack_get_reader_icon_call(wStream* s, GetReaderIcon_Call* call) + { + WINPR_ASSERT(call); +- return smartcard_unpack_common_context_and_string_w(s, &call->handles.hContext, ++ wLog* log = scard_log(); ++ return smartcard_unpack_common_context_and_string_w(log, s, &call->handles.hContext, + &call->szReaderName); + } + + LONG smartcard_unpack_context_and_string_a_call(wStream* s, ContextAndStringA_Call* call) + { + WINPR_ASSERT(call); +- return smartcard_unpack_common_context_and_string_a(s, &call->handles.hContext, &call->sz); ++ wLog* log = scard_log(); ++ return smartcard_unpack_common_context_and_string_a(log, s, &call->handles.hContext, &call->sz); + } + + LONG smartcard_unpack_context_and_string_w_call(wStream* s, ContextAndStringW_Call* call) + { + WINPR_ASSERT(call); +- return smartcard_unpack_common_context_and_string_w(s, &call->handles.hContext, &call->sz); ++ wLog* log = scard_log(); ++ return smartcard_unpack_common_context_and_string_w(log, s, &call->handles.hContext, &call->sz); + } + + LONG smartcard_unpack_get_device_type_id_call(wStream* s, GetDeviceTypeId_Call* call) + { + WINPR_ASSERT(call); +- return smartcard_unpack_common_context_and_string_w(s, &call->handles.hContext, ++ wLog* log = scard_log(); ++ return smartcard_unpack_common_context_and_string_w(log, s, &call->handles.hContext, + &call->szReaderName); + } + + LONG smartcard_pack_device_type_id_return(wStream* s, const GetDeviceTypeId_Return* ret) + { + WINPR_ASSERT(ret); +- smartcard_trace_device_type_id_return(ret); ++ wLog* log = scard_log(); ++ smartcard_trace_device_type_id_return(log, ret); + + if (!Stream_EnsureRemainingCapacity(s, 4)) + { +- WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!"); ++ WLog_Print(log, WLOG_ERROR, "Stream_EnsureRemainingCapacity failed!"); + return SCARD_F_INTERNAL_ERROR; + } + +@@ -3708,12 +3873,13 @@ LONG smartcard_pack_device_type_id_return(wStream* s, const GetDeviceTypeId_Retu + LONG smartcard_pack_locate_cards_return(wStream* s, const LocateCards_Return* ret) + { + WINPR_ASSERT(ret); ++ wLog* log = scard_log(); + + LONG status = 0; + DWORD cbDataLen = ret->cReaders; + UINT32 index = 0; + +- smartcard_trace_locate_cards_return(ret); ++ smartcard_trace_locate_cards_return(log, ret); + if (ret->ReturnCode != SCARD_S_SUCCESS) + cbDataLen = 0; + if (cbDataLen == SCARD_AUTOALLOCATE) +@@ -3721,7 +3887,7 @@ LONG smartcard_pack_locate_cards_return(wStream* s, const LocateCards_Return* re + + if (!Stream_EnsureRemainingCapacity(s, 4)) + { +- WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!"); ++ WLog_Print(log, WLOG_ERROR, "Stream_EnsureRemainingCapacity failed!"); + return SCARD_F_INTERNAL_ERROR; + } + +@@ -3738,11 +3904,12 @@ LONG smartcard_pack_locate_cards_return(wStream* s, const LocateCards_Return* re + LONG smartcard_pack_get_reader_icon_return(wStream* s, const GetReaderIcon_Return* ret) + { + WINPR_ASSERT(ret); ++ wLog* log = scard_log(); + + LONG status = 0; + UINT32 index = 0; + DWORD cbDataLen = ret->cbDataLen; +- smartcard_trace_get_reader_icon_return(ret); ++ smartcard_trace_get_reader_icon_return(log, ret); + if (ret->ReturnCode != SCARD_S_SUCCESS) + cbDataLen = 0; + if (cbDataLen == SCARD_AUTOALLOCATE) +@@ -3750,7 +3917,7 @@ LONG smartcard_pack_get_reader_icon_return(wStream* s, const GetReaderIcon_Retur + + if (!Stream_EnsureRemainingCapacity(s, 4)) + { +- WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!"); ++ WLog_Print(log, WLOG_ERROR, "Stream_EnsureRemainingCapacity failed!"); + return SCARD_F_INTERNAL_ERROR; + } + +@@ -3767,11 +3934,13 @@ LONG smartcard_pack_get_reader_icon_return(wStream* s, const GetReaderIcon_Retur + LONG smartcard_pack_get_transmit_count_return(wStream* s, const GetTransmitCount_Return* ret) + { + WINPR_ASSERT(ret); +- smartcard_trace_get_transmit_count_return(ret); ++ wLog* log = scard_log(); ++ ++ smartcard_trace_get_transmit_count_return(log, ret); + + if (!Stream_EnsureRemainingCapacity(s, 4)) + { +- WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!"); ++ WLog_Print(log, WLOG_ERROR, "Stream_EnsureRemainingCapacity failed!"); + return SCARD_F_INTERNAL_ERROR; + } + +@@ -3783,11 +3952,12 @@ LONG smartcard_pack_get_transmit_count_return(wStream* s, const GetTransmitCount + LONG smartcard_pack_read_cache_return(wStream* s, const ReadCache_Return* ret) + { + WINPR_ASSERT(ret); ++ wLog* log = scard_log(); + + LONG status = 0; + UINT32 index = 0; + DWORD cbDataLen = ret->cbDataLen; +- smartcard_trace_read_cache_return(ret); ++ smartcard_trace_read_cache_return(log, ret); + if (ret->ReturnCode != SCARD_S_SUCCESS) + cbDataLen = 0; + +@@ -3796,7 +3966,7 @@ LONG smartcard_pack_read_cache_return(wStream* s, const ReadCache_Return* ret) + + if (!Stream_EnsureRemainingCapacity(s, 4)) + { +- WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!"); ++ WLog_Print(log, WLOG_ERROR, "Stream_EnsureRemainingCapacity failed!"); + return SCARD_F_INTERNAL_ERROR; + } + +diff --git a/libfreerdp/utils/smartcard_pack.h b/libfreerdp/utils/smartcard_pack.h +new file mode 100644 +index 000000000..372006251 +--- /dev/null ++++ b/libfreerdp/utils/smartcard_pack.h +@@ -0,0 +1,28 @@ ++/** ++ * FreeRDP: A Remote Desktop Protocol Implementation ++ * Smart Card Structure Packing ++ * ++ * Copyright 2025 Armin Novak ++ * Copyright 2025 Thincast Technologies GmbH ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ */ ++ ++#pragma once ++ ++#include ++#include ++#include ++ ++FREERDP_LOCAL void smartcard_trace_long_return_int(wLog* log, const Long_Return* ret, ++ const char* name); +-- +2.47.3 + diff -Nru freerdp3-3.15.0+dfsg/debian/patches/utils-smartcard-check-stream-length-on-padding-CVE-2026-27015.patch freerdp3-3.15.0+dfsg/debian/patches/utils-smartcard-check-stream-length-on-padding-CVE-2026-27015.patch --- freerdp3-3.15.0+dfsg/debian/patches/utils-smartcard-check-stream-length-on-padding-CVE-2026-27015.patch 1970-01-01 00:00:00.000000000 +0000 +++ freerdp3-3.15.0+dfsg/debian/patches/utils-smartcard-check-stream-length-on-padding-CVE-2026-27015.patch 2026-02-25 20:34:19.000000000 +0000 @@ -0,0 +1,101 @@ +From: Armin Novak +Date: Sun, 15 Feb 2026 09:15:20 +0100 +Subject: [utils,smartcard] check stream length on padding +Origin: upstream, https://github.com/FreeRDP/FreeRDP/commit/65d59d3b3c2f630f2ea862687ecf5f95f8115244 +Forwarded: not-needed +Bug: https://github.com/FreeRDP/FreeRDP/security/advisories/GHSA-7g72-39pq-4725 +Bug: https://security-tracker.debian.org/tracker/CVE-2026-27015 + +When reading optional padding in smartcard channel check if padding is +actually there. +--- + libfreerdp/utils/smartcard_operations.c | 3 ++- + libfreerdp/utils/smartcard_pack.c | 32 ++++++++++++++----------- + 2 files changed, 20 insertions(+), 15 deletions(-) + +diff --git a/libfreerdp/utils/smartcard_operations.c b/libfreerdp/utils/smartcard_operations.c +--- a/libfreerdp/utils/smartcard_operations.c ++++ b/libfreerdp/utils/smartcard_operations.c +@@ -786,7 +786,8 @@ LONG smartcard_irp_device_control_decode(wStream* s, UINT32 CompletionId, UINT32 + (ioControlCode != SCARD_IOCTL_RELEASETARTEDEVENT)) + { + offset = (RDPDR_DEVICE_IO_REQUEST_LENGTH + RDPDR_DEVICE_IO_CONTROL_REQ_HDR_LENGTH); +- smartcard_unpack_read_size_align(s, Stream_GetPosition(s) - offset, 8); ++ if (smartcard_unpack_read_size_align(s, Stream_GetPosition(s) - offset, 8) < 0) ++ return STATUS_INVALID_PARAMETER; + } + + if (Stream_GetPosition(s) < Stream_Length(s)) +diff --git a/libfreerdp/utils/smartcard_pack.c b/libfreerdp/utils/smartcard_pack.c +--- a/libfreerdp/utils/smartcard_pack.c ++++ b/libfreerdp/utils/smartcard_pack.c +@@ -200,6 +200,11 @@ static LONG smartcard_ndr_read_ex(wLog* log, wStream* s, BYTE** data, size_t min + return SCARD_E_NO_MEMORY; + Stream_Read(s, r, len); + const LONG pad = smartcard_unpack_read_size_align(s, len, 4); ++ if (pad < 0) ++ { ++ free(r); ++ return STATUS_INVALID_PARAMETER; ++ } + len += (size_t)pad; + *data = r; + if (plen) +@@ -1702,25 +1707,22 @@ void smartcard_pack_private_type_header(wStream* s, UINT32 objectBufferLength) + + LONG smartcard_unpack_read_size_align(wStream* s, size_t size, UINT32 alignment) + { +- size_t pad = 0; ++ const size_t padsize = (size + alignment - 1) & ~(alignment - 1); ++ const size_t pad = padsize - size; + +- pad = size; +- size = (size + alignment - 1) & ~(alignment - 1); +- pad = size - pad; +- +- if (pad) +- Stream_Seek(s, pad); ++ if (pad > 0) ++ { ++ if (!Stream_SafeSeek(s, pad)) ++ return -1; ++ } + + return (LONG)pad; + } + + LONG smartcard_pack_write_size_align(wStream* s, size_t size, UINT32 alignment) + { +- size_t pad = 0; +- +- pad = size; +- size = (size + alignment - 1) & ~(alignment - 1); +- pad = size - pad; ++ const size_t padsize = (size + alignment - 1) & ~(alignment - 1); ++ const size_t pad = padsize - size; + + if (pad) + { +@@ -3085,7 +3087,8 @@ LONG smartcard_unpack_transmit_call(wStream* s, Transmit_Call* call) + call->pioSendPci->cbPciLength = (DWORD)(ioSendPci.cbExtraBytes + sizeof(SCARD_IO_REQUEST)); + pbExtraBytes = &((BYTE*)call->pioSendPci)[sizeof(SCARD_IO_REQUEST)]; + Stream_Read(s, pbExtraBytes, ioSendPci.cbExtraBytes); +- smartcard_unpack_read_size_align(s, ioSendPci.cbExtraBytes, 4); ++ if (smartcard_unpack_read_size_align(s, ioSendPci.cbExtraBytes, 4) < 0) ++ return STATUS_INVALID_PARAMETER; + } + else + { +@@ -3172,7 +3175,8 @@ LONG smartcard_unpack_transmit_call(wStream* s, Transmit_Call* call) + (DWORD)(ioRecvPci.cbExtraBytes + sizeof(SCARD_IO_REQUEST)); + pbExtraBytes = &((BYTE*)call->pioRecvPci)[sizeof(SCARD_IO_REQUEST)]; + Stream_Read(s, pbExtraBytes, ioRecvPci.cbExtraBytes); +- smartcard_unpack_read_size_align(s, ioRecvPci.cbExtraBytes, 4); ++ if (smartcard_unpack_read_size_align(s, ioRecvPci.cbExtraBytes, 4) < 0) ++ return STATUS_INVALID_PARAMETER; + } + else + { +-- +2.47.3 + diff -Nru freerdp3-3.15.0+dfsg/debian/patches/utils-smartcard-handle-output-buffer-too-small.patch freerdp3-3.15.0+dfsg/debian/patches/utils-smartcard-handle-output-buffer-too-small.patch --- freerdp3-3.15.0+dfsg/debian/patches/utils-smartcard-handle-output-buffer-too-small.patch 1970-01-01 00:00:00.000000000 +0000 +++ freerdp3-3.15.0+dfsg/debian/patches/utils-smartcard-handle-output-buffer-too-small.patch 2026-02-09 18:48:59.000000000 +0000 @@ -0,0 +1,63 @@ +From: akallabeth +Date: Wed, 7 May 2025 21:13:21 +0200 +Subject: [utils,smartcard] handle output buffer too small +Origin: upstream, https://github.com/FreeRDP/FreeRDP/commit/60330fc7715070e8633f17ad46fd2f61503dfa2c +Forwarded: not-needed +Comment: Bugfix and preparation for CVE-2026-22852 + +--- + libfreerdp/utils/smartcard_call.c | 21 +++++++++++++++++---- + 1 file changed, 17 insertions(+), 4 deletions(-) + +diff --git a/libfreerdp/utils/smartcard_call.c b/libfreerdp/utils/smartcard_call.c +index f4590395a..1209ced47 100644 +--- a/libfreerdp/utils/smartcard_call.c ++++ b/libfreerdp/utils/smartcard_call.c +@@ -1580,7 +1580,6 @@ LONG smartcard_irp_device_control_call(scard_call_context* smartcard, wStream* o + { + LONG result = 0; + UINT32 offset = 0; +- size_t outputBufferLength = 0; + size_t objectBufferLength = 0; + + WINPR_ASSERT(smartcard); +@@ -1839,8 +1838,8 @@ LONG smartcard_irp_device_control_call(scard_call_context* smartcard, wStream* o + } + + Stream_SealLength(out); +- outputBufferLength = Stream_Length(out); +- WINPR_ASSERT(outputBufferLength >= RDPDR_DEVICE_IO_RESPONSE_LENGTH - 4U); ++ size_t outputBufferLength = Stream_Length(out); ++ WINPR_ASSERT(outputBufferLength >= RDPDR_DEVICE_IO_RESPONSE_LENGTH + 4U); + outputBufferLength -= (RDPDR_DEVICE_IO_RESPONSE_LENGTH + 4U); + WINPR_ASSERT(outputBufferLength >= RDPDR_DEVICE_IO_RESPONSE_LENGTH); + objectBufferLength = outputBufferLength - RDPDR_DEVICE_IO_RESPONSE_LENGTH; +@@ -1848,10 +1847,24 @@ LONG smartcard_irp_device_control_call(scard_call_context* smartcard, wStream* o + WINPR_ASSERT(objectBufferLength <= UINT32_MAX); + Stream_SetPosition(out, RDPDR_DEVICE_IO_RESPONSE_LENGTH); + ++ /* [MS-RDPESC] 3.2.5.2 Processing Incoming Replies ++ * ++ * if the output buffer is too small, reply with STATUS_BUFFER_TOO_SMALL ++ * and a outputBufferLength of 0. ++ * The message should then be retransmitted from the server with a doubled ++ * buffer size. ++ */ + if (outputBufferLength > operation->outputBufferLength) + { +- WLog_WARN(TAG, "IRP warn: expected outputBufferLength %" PRIu32 ", but have %" PRIu32, ++ WLog_WARN(TAG, ++ "IRP warn: expected outputBufferLength %" PRIu32 ", but current limit %" PRIu32 ++ ", respond with STATUS_BUFFER_TOO_SMALL", + operation->outputBufferLength, outputBufferLength); ++ ++ *pIoStatus = STATUS_BUFFER_TOO_SMALL; ++ result = *pIoStatus; ++ outputBufferLength = 0; ++ objectBufferLength = 0; + } + + /* Device Control Response */ +-- +2.47.3 + diff -Nru freerdp3-3.15.0+dfsg/debian/patches/utils-smartcard-improve-trace-log.patch freerdp3-3.15.0+dfsg/debian/patches/utils-smartcard-improve-trace-log.patch --- freerdp3-3.15.0+dfsg/debian/patches/utils-smartcard-improve-trace-log.patch 1970-01-01 00:00:00.000000000 +0000 +++ freerdp3-3.15.0+dfsg/debian/patches/utils-smartcard-improve-trace-log.patch 2026-02-09 18:48:59.000000000 +0000 @@ -0,0 +1,2114 @@ +From: akallabeth +Date: Mon, 14 Apr 2025 21:00:10 +0200 +Subject: [utils,smartcard] improve trace log +Origin: upstream, https://github.com/FreeRDP/FreeRDP/commit/2e7e6dde87f1e1e117a05ff737361aebbd57d770 +Forwarded: not-needed +Comment: Logging improvements in preparation for CVE-2026-22852 + +--- + libfreerdp/utils/smartcard_call.c | 19 +- + libfreerdp/utils/smartcard_pack.c | 1100 ++++++++++++++++------------- + 2 files changed, 627 insertions(+), 492 deletions(-) + +diff --git a/libfreerdp/utils/smartcard_call.c b/libfreerdp/utils/smartcard_call.c +index f6111faaa..f4590395a 100644 +--- a/libfreerdp/utils/smartcard_call.c ++++ b/libfreerdp/utils/smartcard_call.c +@@ -967,7 +967,7 @@ static LONG smartcard_GetStatusChangeA_Call(scard_call_context* smartcard, wStre + CopyMemory(&(rout->rgbAtr), cur->rgbAtr, sizeof(rout->rgbAtr)); + } + +- status = smartcard_pack_get_status_change_return(out, &ret, TRUE); ++ status = smartcard_pack_get_status_change_return(out, &ret, FALSE); + fail: + free(ret.rgReaderStates); + free(rgReaderStates); +@@ -983,14 +983,13 @@ static LONG smartcard_GetStatusChangeW_Call(scard_call_context* smartcard, wStre + DWORD dwTimeOut = 0; + const DWORD dwTimeStep = 100; + GetStatusChange_Return ret = { 0 }; +- GetStatusChangeW_Call* call = NULL; + LPSCARD_READERSTATEW rgReaderStates = NULL; + + WINPR_ASSERT(smartcard); + WINPR_ASSERT(out); + WINPR_ASSERT(operation); + +- call = &operation->call.getStatusChangeW; ++ GetStatusChangeW_Call* call = &operation->call.getStatusChangeW; + dwTimeOut = call->dwTimeOut; + + if (call->cReaders > 0) +@@ -1501,7 +1500,6 @@ static LONG smartcard_LocateCardsByATRA_Call(scard_call_context* smartcard, wStr + { + LONG status = 0; + GetStatusChange_Return ret = { 0 }; +- LPSCARD_READERSTATEA state = NULL; + LPSCARD_READERSTATEA states = NULL; + LocateCardsByATRA_Call* call = NULL; + +@@ -1516,11 +1514,12 @@ static LONG smartcard_LocateCardsByATRA_Call(scard_call_context* smartcard, wStr + + for (UINT32 i = 0; i < call->cReaders; i++) + { +- states[i].szReader = call->rgReaderStates[i].szReader; +- states[i].dwCurrentState = call->rgReaderStates[i].dwCurrentState; +- states[i].dwEventState = call->rgReaderStates[i].dwEventState; +- states[i].cbAtr = call->rgReaderStates[i].cbAtr; +- CopyMemory(&(states[i].rgbAtr), &(call->rgReaderStates[i].rgbAtr), 36); ++ LPSCARD_READERSTATEA state = &states[i]; ++ state->szReader = call->rgReaderStates[i].szReader; ++ state->dwCurrentState = call->rgReaderStates[i].dwCurrentState; ++ state->dwEventState = call->rgReaderStates[i].dwEventState; ++ state->cbAtr = call->rgReaderStates[i].cbAtr; ++ CopyMemory(&(state->rgbAtr), &(call->rgReaderStates[i].rgbAtr), 36); + } + + status = ret.ReturnCode = wrap(smartcard, SCardGetStatusChangeA, operation->hContext, +@@ -1558,7 +1557,7 @@ static LONG smartcard_LocateCardsByATRA_Call(scard_call_context* smartcard, wStr + + for (UINT32 i = 0; i < ret.cReaders; i++) + { +- state = &states[i]; ++ LPSCARD_READERSTATEA state = &states[i]; + ret.rgReaderStates[i].dwCurrentState = state->dwCurrentState; + ret.rgReaderStates[i].dwEventState = state->dwEventState; + ret.rgReaderStates[i].cbAtr = state->cbAtr; +diff --git a/libfreerdp/utils/smartcard_pack.c b/libfreerdp/utils/smartcard_pack.c +index f1fcbc24f..6fcb2ac29 100644 +--- a/libfreerdp/utils/smartcard_pack.c ++++ b/libfreerdp/utils/smartcard_pack.c +@@ -424,6 +424,14 @@ static char* smartcard_array_dump(const void* pd, size_t len, char* buffer, size + int rc = 0; + char* start = buffer; + ++ WINPR_ASSERT(buffer || (bufferLen == 0)); ++ ++ if (!data && (len > 0)) ++ { ++ (void)_snprintf(buffer, bufferLen, "{ NULL [%" PRIuz "] }", len); ++ goto fail; ++ } ++ + /* Ensure '\0' termination */ + if (bufferLen > 0) + { +@@ -453,19 +461,23 @@ static char* smartcard_array_dump(const void* pd, size_t len, char* buffer, size + fail: + return start; + } +-static void smartcard_log_redir_handle(const char* tag, const REDIR_SCARDHANDLE* pHandle) ++ ++static void smartcard_log_redir_handle(wLog* log, const REDIR_SCARDHANDLE* pHandle) + { +- char buffer[128]; ++ char buffer[128] = { 0 }; + +- WLog_LVL(tag, g_LogLevel, " hContext: %s", +- smartcard_array_dump(pHandle->pbHandle, pHandle->cbHandle, buffer, sizeof(buffer))); ++ WINPR_ASSERT(pHandle); ++ WLog_Print(log, g_LogLevel, " hContext: %s", ++ smartcard_array_dump(pHandle->pbHandle, pHandle->cbHandle, buffer, sizeof(buffer))); + } + +-static void smartcard_log_context(const char* tag, const REDIR_SCARDCONTEXT* phContext) ++static void smartcard_log_context(wLog* log, const REDIR_SCARDCONTEXT* phContext) + { +- char buffer[128]; +- WLog_DBG( +- tag, "hContext: %s", ++ char buffer[128] = { 0 }; ++ ++ WINPR_ASSERT(phContext); ++ WLog_Print( ++ log, g_LogLevel, "hContext: %s", + smartcard_array_dump(phContext->pbContext, phContext->cbContext, buffer, sizeof(buffer))); + } + +@@ -473,14 +485,15 @@ static void smartcard_trace_context_and_string_call_a(const char* name, + const REDIR_SCARDCONTEXT* phContext, + const CHAR* sz) + { +- if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel)) ++ wLog* log = WLog_Get(TAG); ++ if (!WLog_IsLevelActive(log, g_LogLevel)) + return; + +- WLog_LVL(TAG, g_LogLevel, "%s {", name); +- smartcard_log_context(TAG, phContext); +- WLog_LVL(TAG, g_LogLevel, " sz=%s", sz); ++ WLog_Print(log, g_LogLevel, "%s {", name); ++ smartcard_log_context(log, phContext); ++ WLog_Print(log, g_LogLevel, " sz=%s", sz); + +- WLog_LVL(TAG, g_LogLevel, "}"); ++ WLog_Print(log, g_LogLevel, "}"); + } + + static void smartcard_trace_context_and_string_call_w(const char* name, +@@ -488,288 +501,348 @@ static void smartcard_trace_context_and_string_call_w(const char* name, + const WCHAR* sz) + { + char tmp[1024] = { 0 }; +- if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel)) ++ wLog* log = WLog_Get(TAG); ++ if (!WLog_IsLevelActive(log, g_LogLevel)) + return; + + if (sz) + (void)ConvertWCharToUtf8(sz, tmp, ARRAYSIZE(tmp)); + +- WLog_LVL(TAG, g_LogLevel, "%s {", name); +- smartcard_log_context(TAG, phContext); +- WLog_LVL(TAG, g_LogLevel, " sz=%s", tmp); +- WLog_LVL(TAG, g_LogLevel, "}"); ++ WLog_Print(log, g_LogLevel, "%s {", name); ++ smartcard_log_context(log, phContext); ++ WLog_Print(log, g_LogLevel, " sz=%s", tmp); ++ WLog_Print(log, g_LogLevel, "}"); + } + + static void smartcard_trace_context_call(const Context_Call* call, const char* name) + { ++ WINPR_ASSERT(call); + +- if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel)) ++ wLog* log = WLog_Get(TAG); ++ if (!WLog_IsLevelActive(log, g_LogLevel)) + return; + +- WLog_LVL(TAG, g_LogLevel, "%s_Call {", name); +- smartcard_log_context(TAG, &call->handles.hContext); ++ WLog_Print(log, g_LogLevel, "%s_Call {", name); ++ smartcard_log_context(log, &call->handles.hContext); + +- WLog_LVL(TAG, g_LogLevel, "}"); ++ WLog_Print(log, g_LogLevel, "}"); + } + + static void smartcard_trace_list_reader_groups_call(const ListReaderGroups_Call* call, BOOL unicode) + { ++ WINPR_ASSERT(call); + +- if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel)) ++ wLog* log = WLog_Get(TAG); ++ if (!WLog_IsLevelActive(log, g_LogLevel)) + return; + +- WLog_LVL(TAG, g_LogLevel, "ListReaderGroups%S_Call {", unicode ? "W" : "A"); +- smartcard_log_context(TAG, &call->handles.hContext); ++ WLog_Print(log, g_LogLevel, "ListReaderGroups%S_Call {", unicode ? "W" : "A"); ++ smartcard_log_context(log, &call->handles.hContext); + +- WLog_LVL(TAG, g_LogLevel, "fmszGroupsIsNULL: %" PRId32 " cchGroups: 0x%08" PRIx32, +- call->fmszGroupsIsNULL, call->cchGroups); +- WLog_LVL(TAG, g_LogLevel, "}"); ++ WLog_Print(log, g_LogLevel, "fmszGroupsIsNULL: %" PRId32 " cchGroups: 0x%08" PRIx32, ++ call->fmszGroupsIsNULL, call->cchGroups); ++ WLog_Print(log, g_LogLevel, "}"); + } + +-static void smartcard_trace_get_status_change_w_call(const GetStatusChangeW_Call* call) ++static void dump_reader_states_return(wLog* log, const ReaderState_Return* rgReaderStates, ++ UINT32 cReaders) + { +- char* szEventState = NULL; +- char* szCurrentState = NULL; +- +- if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel)) +- return; ++ WINPR_ASSERT(rgReaderStates || (cReaders == 0)); ++ for (UINT32 index = 0; index < cReaders; index++) ++ { ++ char buffer[1024] = { 0 }; + +- WLog_LVL(TAG, g_LogLevel, "GetStatusChangeW_Call {"); +- smartcard_log_context(TAG, &call->handles.hContext); ++ const ReaderState_Return* readerState = &rgReaderStates[index]; ++ char* szCurrentState = SCardGetReaderStateString(readerState->dwCurrentState); ++ char* szEventState = SCardGetReaderStateString(readerState->dwEventState); ++ WLog_Print(log, g_LogLevel, "\t[%" PRIu32 "]: dwCurrentState: %s (0x%08" PRIX32 ")", index, ++ szCurrentState, readerState->dwCurrentState); ++ WLog_Print(log, g_LogLevel, "\t[%" PRIu32 "]: dwEventState: %s (0x%08" PRIX32 ")", index, ++ szEventState, readerState->dwEventState); ++ free(szCurrentState); ++ free(szEventState); + +- WLog_LVL(TAG, g_LogLevel, "dwTimeOut: 0x%08" PRIX32 " cReaders: %" PRIu32 "", call->dwTimeOut, +- call->cReaders); ++ WLog_Print( ++ log, g_LogLevel, "\t[%" PRIu32 "]: cbAttr: %" PRIu32 " { %s }", index, ++ readerState->cbAtr, ++ smartcard_array_dump(readerState->rgbAtr, readerState->cbAtr, buffer, sizeof(buffer))); ++ } ++} + +- for (UINT32 index = 0; index < call->cReaders; index++) ++static void dump_reader_states_a(wLog* log, const SCARD_READERSTATEA* rgReaderStates, ++ UINT32 cReaders) ++{ ++ WINPR_ASSERT(rgReaderStates || (cReaders == 0)); ++ for (UINT32 index = 0; index < cReaders; index++) + { +- const LPSCARD_READERSTATEW readerState = &call->rgReaderStates[index]; +- char szReaderA[1024] = { 0 }; ++ char buffer[1024] = { 0 }; ++ ++ const SCARD_READERSTATEA* readerState = &rgReaderStates[index]; ++ WLog_Print(log, g_LogLevel, "\t[%" PRIu32 "]: szReader: %s cbAtr: %" PRIu32 "", index, ++ readerState->szReader, readerState->cbAtr); ++ char* szCurrentState = SCardGetReaderStateString(readerState->dwCurrentState); ++ char* szEventState = SCardGetReaderStateString(readerState->dwEventState); ++ WLog_Print(log, g_LogLevel, "\t[%" PRIu32 "]: dwCurrentState: %s (0x%08" PRIX32 ")", index, ++ szCurrentState, readerState->dwCurrentState); ++ WLog_Print(log, g_LogLevel, "\t[%" PRIu32 "]: dwEventState: %s (0x%08" PRIX32 ")", index, ++ szEventState, readerState->dwEventState); ++ free(szCurrentState); ++ free(szEventState); + +- (void)ConvertWCharToUtf8(readerState->szReader, szReaderA, ARRAYSIZE(szReaderA)); ++ WLog_Print( ++ log, g_LogLevel, "\t[%" PRIu32 "]: cbAttr: %" PRIu32 " { %s }", index, ++ readerState->cbAtr, ++ smartcard_array_dump(readerState->rgbAtr, readerState->cbAtr, buffer, sizeof(buffer))); ++ } ++} + +- WLog_LVL(TAG, g_LogLevel, "\t[%" PRIu32 "]: szReader: %s cbAtr: %" PRIu32 "", index, +- szReaderA, readerState->cbAtr); +- szCurrentState = SCardGetReaderStateString(readerState->dwCurrentState); +- szEventState = SCardGetReaderStateString(readerState->dwEventState); +- WLog_LVL(TAG, g_LogLevel, "\t[%" PRIu32 "]: dwCurrentState: %s (0x%08" PRIX32 ")", index, +- szCurrentState, readerState->dwCurrentState); +- WLog_LVL(TAG, g_LogLevel, "\t[%" PRIu32 "]: dwEventState: %s (0x%08" PRIX32 ")", index, +- szEventState, readerState->dwEventState); ++static void dump_reader_states_w(wLog* log, const SCARD_READERSTATEW* rgReaderStates, ++ UINT32 cReaders) ++{ ++ WINPR_ASSERT(rgReaderStates || (cReaders == 0)); ++ for (UINT32 index = 0; index < cReaders; index++) ++ { ++ char buffer[1024] = { 0 }; ++ ++ const SCARD_READERSTATEW* readerState = &rgReaderStates[index]; ++ ConvertWCharToUtf8(readerState->szReader, buffer, sizeof(buffer)); ++ WLog_Print(log, g_LogLevel, "\t[%" PRIu32 "]: szReader: %s cbAtr: %" PRIu32 "", index, ++ buffer, readerState->cbAtr); ++ char* szCurrentState = SCardGetReaderStateString(readerState->dwCurrentState); ++ char* szEventState = SCardGetReaderStateString(readerState->dwEventState); ++ WLog_Print(log, g_LogLevel, "\t[%" PRIu32 "]: dwCurrentState: %s (0x%08" PRIX32 ")", index, ++ szCurrentState, readerState->dwCurrentState); ++ WLog_Print(log, g_LogLevel, "\t[%" PRIu32 "]: dwEventState: %s (0x%08" PRIX32 ")", index, ++ szEventState, readerState->dwEventState); + free(szCurrentState); + free(szEventState); ++ ++ WLog_Print( ++ log, g_LogLevel, "\t[%" PRIu32 "]: cbAttr: %" PRIu32 " { %s }", index, ++ readerState->cbAtr, ++ smartcard_array_dump(readerState->rgbAtr, readerState->cbAtr, buffer, sizeof(buffer))); + } ++} ++ ++static void smartcard_trace_get_status_change_w_call(const GetStatusChangeW_Call* call) ++{ ++ WINPR_ASSERT(call); ++ ++ wLog* log = WLog_Get(TAG); ++ if (!WLog_IsLevelActive(log, g_LogLevel)) ++ return; ++ ++ WLog_Print(log, g_LogLevel, "GetStatusChangeW_Call {"); ++ smartcard_log_context(log, &call->handles.hContext); + +- WLog_LVL(TAG, g_LogLevel, "}"); ++ WLog_Print(log, g_LogLevel, "dwTimeOut: 0x%08" PRIX32 " cReaders: %" PRIu32 "", call->dwTimeOut, ++ call->cReaders); ++ ++ dump_reader_states_w(log, call->rgReaderStates, call->cReaders); ++ ++ WLog_Print(log, g_LogLevel, "}"); + } + + static void smartcard_trace_list_reader_groups_return(const ListReaderGroups_Return* ret, + BOOL unicode) + { +- char* mszA = NULL; ++ WINPR_ASSERT(ret); + +- if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel)) ++ wLog* log = WLog_Get(TAG); ++ if (!WLog_IsLevelActive(log, g_LogLevel)) + return; + +- mszA = smartcard_convert_string_list(ret->msz, ret->cBytes, unicode); ++ char* mszA = smartcard_convert_string_list(ret->msz, ret->cBytes, unicode); + +- WLog_LVL(TAG, g_LogLevel, "ListReaderGroups%s_Return {", unicode ? "W" : "A"); +- WLog_LVL(TAG, g_LogLevel, " ReturnCode: %s (0x%08" PRIx32 ")", +- SCardGetErrorString(ret->ReturnCode), ret->ReturnCode); +- WLog_LVL(TAG, g_LogLevel, " cBytes: %" PRIu32 " msz: %s", ret->cBytes, mszA); +- WLog_LVL(TAG, g_LogLevel, "}"); ++ WLog_Print(log, g_LogLevel, "ListReaderGroups%s_Return {", unicode ? "W" : "A"); ++ WLog_Print(log, g_LogLevel, " ReturnCode: %s (0x%08" PRIx32 ")", ++ SCardGetErrorString(ret->ReturnCode), ret->ReturnCode); ++ WLog_Print(log, g_LogLevel, " cBytes: %" PRIu32 " msz: %s", ret->cBytes, mszA); ++ WLog_Print(log, g_LogLevel, "}"); + free(mszA); + } + + static void smartcard_trace_list_readers_call(const ListReaders_Call* call, BOOL unicode) + { +- char* mszGroupsA = NULL; ++ WINPR_ASSERT(call); + +- if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel)) ++ wLog* log = WLog_Get(TAG); ++ if (!WLog_IsLevelActive(log, g_LogLevel)) + return; + +- mszGroupsA = smartcard_convert_string_list(call->mszGroups, call->cBytes, unicode); ++ char* mszGroupsA = smartcard_convert_string_list(call->mszGroups, call->cBytes, unicode); + +- WLog_LVL(TAG, g_LogLevel, "ListReaders%s_Call {", unicode ? "W" : "A"); +- smartcard_log_context(TAG, &call->handles.hContext); ++ WLog_Print(log, g_LogLevel, "ListReaders%s_Call {", unicode ? "W" : "A"); ++ smartcard_log_context(log, &call->handles.hContext); + +- WLog_LVL(TAG, g_LogLevel, +- "cBytes: %" PRIu32 " mszGroups: %s fmszReadersIsNULL: %" PRId32 +- " cchReaders: 0x%08" PRIX32 "", +- call->cBytes, mszGroupsA, call->fmszReadersIsNULL, call->cchReaders); +- WLog_LVL(TAG, g_LogLevel, "}"); ++ WLog_Print(log, g_LogLevel, ++ "cBytes: %" PRIu32 " mszGroups: %s fmszReadersIsNULL: %" PRId32 ++ " cchReaders: 0x%08" PRIX32 "", ++ call->cBytes, mszGroupsA, call->fmszReadersIsNULL, call->cchReaders); ++ WLog_Print(log, g_LogLevel, "}"); + + free(mszGroupsA); + } + + static void smartcard_trace_locate_cards_by_atr_a_call(const LocateCardsByATRA_Call* call) + { +- char* szEventState = NULL; +- char* szCurrentState = NULL; ++ WINPR_ASSERT(call); + +- if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel)) ++ wLog* log = WLog_Get(TAG); ++ if (!WLog_IsLevelActive(log, g_LogLevel)) + return; + +- WLog_LVL(TAG, g_LogLevel, "LocateCardsByATRA_Call {"); +- smartcard_log_context(TAG, &call->handles.hContext); +- +- for (UINT32 index = 0; index < call->cReaders; index++) +- { +- char buffer[1024]; +- const LPSCARD_READERSTATEA readerState = &call->rgReaderStates[index]; ++ WLog_Print(log, g_LogLevel, "LocateCardsByATRA_Call {"); ++ smartcard_log_context(log, &call->handles.hContext); + +- WLog_LVL(TAG, g_LogLevel, "\t[%" PRIu32 "]: szReader: %s cbAtr: %" PRIu32 "", index, +- readerState->szReader, readerState->cbAtr); +- szCurrentState = SCardGetReaderStateString(readerState->dwCurrentState); +- szEventState = SCardGetReaderStateString(readerState->dwEventState); +- WLog_LVL(TAG, g_LogLevel, "\t[%" PRIu32 "]: dwCurrentState: %s (0x%08" PRIX32 ")", index, +- szCurrentState, readerState->dwCurrentState); +- WLog_LVL(TAG, g_LogLevel, "\t[%" PRIu32 "]: dwEventState: %s (0x%08" PRIX32 ")", index, +- szEventState, readerState->dwEventState); ++ dump_reader_states_a(log, call->rgReaderStates, call->cReaders); + +- WLog_DBG( +- TAG, "\t[%" PRIu32 "]: cbAtr: %" PRIu32 " rgbAtr: %s", index, readerState->cbAtr, +- smartcard_array_dump(readerState->rgbAtr, readerState->cbAtr, buffer, sizeof(buffer))); +- +- free(szCurrentState); +- free(szEventState); +- } +- +- WLog_LVL(TAG, g_LogLevel, "}"); ++ WLog_Print(log, g_LogLevel, "}"); + } + + static void smartcard_trace_locate_cards_a_call(const LocateCardsA_Call* call) + { +- char buffer[8192]; ++ char buffer[8192] = { 0 }; ++ ++ WINPR_ASSERT(call); + +- if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel)) ++ wLog* log = WLog_Get(TAG); ++ if (!WLog_IsLevelActive(log, g_LogLevel)) + return; + +- WLog_LVL(TAG, g_LogLevel, "LocateCardsA_Call {"); +- smartcard_log_context(TAG, &call->handles.hContext); +- WLog_LVL(TAG, g_LogLevel, " cBytes=%" PRId32, call->cBytes); +- WLog_LVL(TAG, g_LogLevel, " mszCards=%s", +- smartcard_msz_dump_a(call->mszCards, call->cBytes, buffer, sizeof(buffer))); +- WLog_LVL(TAG, g_LogLevel, " cReaders=%" PRId32, call->cReaders); +- // WLog_LVL(TAG, g_LogLevel, " cReaders=%" PRId32, call->rgReaderStates); ++ WLog_Print(log, g_LogLevel, "LocateCardsA_Call {"); ++ smartcard_log_context(log, &call->handles.hContext); ++ WLog_Print(log, g_LogLevel, " cBytes=%" PRId32, call->cBytes); ++ WLog_Print(log, g_LogLevel, " mszCards=%s", ++ smartcard_msz_dump_a(call->mszCards, call->cBytes, buffer, sizeof(buffer))); ++ WLog_Print(log, g_LogLevel, " cReaders=%" PRId32, call->cReaders); ++ dump_reader_states_a(log, call->rgReaderStates, call->cReaders); + +- WLog_LVL(TAG, g_LogLevel, "}"); ++ WLog_Print(log, g_LogLevel, "}"); + } + + static void smartcard_trace_locate_cards_return(const LocateCards_Return* ret) + { ++ WINPR_ASSERT(ret); + +- if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel)) ++ wLog* log = WLog_Get(TAG); ++ if (!WLog_IsLevelActive(log, g_LogLevel)) + return; + +- WLog_LVL(TAG, g_LogLevel, "LocateCards_Return {"); +- WLog_LVL(TAG, g_LogLevel, " ReturnCode: %s (0x%08" PRIX32 ")", +- SCardGetErrorString(ret->ReturnCode), ret->ReturnCode); ++ WLog_Print(log, g_LogLevel, "LocateCards_Return {"); ++ WLog_Print(log, g_LogLevel, " ReturnCode: %s (0x%08" PRIX32 ")", ++ SCardGetErrorString(ret->ReturnCode), ret->ReturnCode); + + if (ret->ReturnCode == SCARD_S_SUCCESS) + { +- WLog_LVL(TAG, g_LogLevel, " cReaders=%" PRId32, ret->cReaders); ++ WLog_Print(log, g_LogLevel, " cReaders=%" PRId32, ret->cReaders); + } +- WLog_LVL(TAG, g_LogLevel, "}"); ++ WLog_Print(log, g_LogLevel, "}"); + } + + static void smartcard_trace_get_reader_icon_return(const GetReaderIcon_Return* ret) + { ++ WINPR_ASSERT(ret); + +- if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel)) ++ wLog* log = WLog_Get(TAG); ++ if (!WLog_IsLevelActive(log, g_LogLevel)) + return; + +- WLog_LVL(TAG, g_LogLevel, "GetReaderIcon_Return {"); +- WLog_LVL(TAG, g_LogLevel, " ReturnCode: %s (0x%08" PRIX32 ")", +- SCardGetErrorString(ret->ReturnCode), ret->ReturnCode); ++ WLog_Print(log, g_LogLevel, "GetReaderIcon_Return {"); ++ WLog_Print(log, g_LogLevel, " ReturnCode: %s (0x%08" PRIX32 ")", ++ SCardGetErrorString(ret->ReturnCode), ret->ReturnCode); + + if (ret->ReturnCode == SCARD_S_SUCCESS) + { +- WLog_LVL(TAG, g_LogLevel, " cbDataLen=%" PRId32, ret->cbDataLen); ++ WLog_Print(log, g_LogLevel, " cbDataLen=%" PRId32, ret->cbDataLen); + } +- WLog_LVL(TAG, g_LogLevel, "}"); ++ WLog_Print(log, g_LogLevel, "}"); + } + + static void smartcard_trace_get_transmit_count_return(const GetTransmitCount_Return* ret) + { +- +- if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel)) ++ WINPR_ASSERT(ret); ++ wLog* log = WLog_Get(TAG); ++ if (!WLog_IsLevelActive(log, g_LogLevel)) + return; + +- WLog_LVL(TAG, g_LogLevel, "GetTransmitCount_Return {"); +- WLog_LVL(TAG, g_LogLevel, " ReturnCode: %s (0x%08" PRIX32 ")", +- SCardGetErrorString(ret->ReturnCode), ret->ReturnCode); ++ WLog_Print(log, g_LogLevel, "GetTransmitCount_Return {"); ++ WLog_Print(log, g_LogLevel, " ReturnCode: %s (0x%08" PRIX32 ")", ++ SCardGetErrorString(ret->ReturnCode), ret->ReturnCode); + +- WLog_LVL(TAG, g_LogLevel, " cTransmitCount=%" PRIu32, ret->cTransmitCount); +- WLog_LVL(TAG, g_LogLevel, "}"); ++ WLog_Print(log, g_LogLevel, " cTransmitCount=%" PRIu32, ret->cTransmitCount); ++ WLog_Print(log, g_LogLevel, "}"); + } + + static void smartcard_trace_read_cache_return(const ReadCache_Return* ret) + { +- +- if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel)) ++ WINPR_ASSERT(ret); ++ wLog* log = WLog_Get(TAG); ++ if (!WLog_IsLevelActive(log, g_LogLevel)) + return; + +- WLog_LVL(TAG, g_LogLevel, "ReadCache_Return {"); +- WLog_LVL(TAG, g_LogLevel, " ReturnCode: %s (0x%08" PRIX32 ")", +- SCardGetErrorString(ret->ReturnCode), ret->ReturnCode); ++ WLog_Print(log, g_LogLevel, "ReadCache_Return {"); ++ WLog_Print(log, g_LogLevel, " ReturnCode: %s (0x%08" PRIX32 ")", ++ SCardGetErrorString(ret->ReturnCode), ret->ReturnCode); + + if (ret->ReturnCode == SCARD_S_SUCCESS) + { +- char buffer[1024]; +- WLog_LVL(TAG, g_LogLevel, " cbDataLen=%" PRId32, ret->cbDataLen); +- WLog_LVL(TAG, g_LogLevel, " cbData: %s", +- smartcard_array_dump(ret->pbData, ret->cbDataLen, buffer, sizeof(buffer))); ++ char buffer[1024] = { 0 }; ++ WLog_Print(log, g_LogLevel, " cbDataLen=%" PRId32, ret->cbDataLen); ++ WLog_Print(log, g_LogLevel, " cbData: %s", ++ smartcard_array_dump(ret->pbData, ret->cbDataLen, buffer, sizeof(buffer))); + } +- WLog_LVL(TAG, g_LogLevel, "}"); ++ WLog_Print(log, g_LogLevel, "}"); + } + + static void smartcard_trace_locate_cards_w_call(const LocateCardsW_Call* call) + { +- char buffer[8192]; ++ WINPR_ASSERT(call); ++ char buffer[8192] = { 0 }; + +- if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel)) ++ wLog* log = WLog_Get(TAG); ++ if (!WLog_IsLevelActive(log, g_LogLevel)) + return; + +- WLog_LVL(TAG, g_LogLevel, "LocateCardsW_Call {"); +- smartcard_log_context(TAG, &call->handles.hContext); +- WLog_LVL(TAG, g_LogLevel, " cBytes=%" PRId32, call->cBytes); +- WLog_LVL(TAG, g_LogLevel, " sz2=%s", +- smartcard_msz_dump_w(call->mszCards, call->cBytes, buffer, sizeof(buffer))); +- WLog_LVL(TAG, g_LogLevel, " cReaders=%" PRId32, call->cReaders); +- // WLog_LVL(TAG, g_LogLevel, " sz2=%s", call->rgReaderStates); +- WLog_LVL(TAG, g_LogLevel, "}"); ++ WLog_Print(log, g_LogLevel, "LocateCardsW_Call {"); ++ smartcard_log_context(log, &call->handles.hContext); ++ WLog_Print(log, g_LogLevel, " cBytes=%" PRId32, call->cBytes); ++ WLog_Print(log, g_LogLevel, " sz2=%s", ++ smartcard_msz_dump_w(call->mszCards, call->cBytes, buffer, sizeof(buffer))); ++ WLog_Print(log, g_LogLevel, " cReaders=%" PRId32, call->cReaders); ++ dump_reader_states_w(log, call->rgReaderStates, call->cReaders); ++ WLog_Print(log, g_LogLevel, "}"); + } + + static void smartcard_trace_list_readers_return(const ListReaders_Return* ret, BOOL unicode) + { +- char* mszA = NULL; ++ WINPR_ASSERT(ret); + +- if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel)) ++ wLog* log = WLog_Get(TAG); ++ if (!WLog_IsLevelActive(log, g_LogLevel)) + return; + +- WLog_LVL(TAG, g_LogLevel, "ListReaders%s_Return {", unicode ? "W" : "A"); +- WLog_LVL(TAG, g_LogLevel, " ReturnCode: %s (0x%08" PRIX32 ")", +- SCardGetErrorString(ret->ReturnCode), ret->ReturnCode); ++ WLog_Print(log, g_LogLevel, "ListReaders%s_Return {", unicode ? "W" : "A"); ++ WLog_Print(log, g_LogLevel, " ReturnCode: %s (0x%08" PRIX32 ")", ++ SCardGetErrorString(ret->ReturnCode), ret->ReturnCode); + + if (ret->ReturnCode != SCARD_S_SUCCESS) + { +- WLog_LVL(TAG, g_LogLevel, "}"); ++ WLog_Print(log, g_LogLevel, "}"); + return; + } + +- mszA = smartcard_convert_string_list(ret->msz, ret->cBytes, unicode); ++ char* mszA = smartcard_convert_string_list(ret->msz, ret->cBytes, unicode); + +- WLog_LVL(TAG, g_LogLevel, " cBytes: %" PRIu32 " msz: %s", ret->cBytes, mszA); +- WLog_LVL(TAG, g_LogLevel, "}"); ++ WLog_Print(log, g_LogLevel, " cBytes: %" PRIu32 " msz: %s", ret->cBytes, mszA); ++ WLog_Print(log, g_LogLevel, "}"); + free(mszA); + } + + static void smartcard_trace_get_status_change_return(const GetStatusChange_Return* ret, + BOOL unicode) + { +- char* szEventState = NULL; +- char* szCurrentState = NULL; +- ++ WINPR_ASSERT(ret); + wLog* log = WLog_Get(TAG); + if (!WLog_IsLevelActive(log, g_LogLevel)) + return; +@@ -779,19 +852,26 @@ static void smartcard_trace_get_status_change_return(const GetStatusChange_Retur + SCardGetErrorString(ret->ReturnCode), ret->ReturnCode); + WLog_Print(log, g_LogLevel, " cReaders: %" PRIu32 "", ret->cReaders); + ++ dump_reader_states_return(log, ret->rgReaderStates, ret->cReaders); ++ + if (!ret->rgReaderStates && (ret->cReaders > 0)) + { + WLog_Print(log, g_LogLevel, " [INVALID STATE] rgReaderStates=NULL, cReaders=%" PRIu32, + ret->cReaders); + } ++ else if (ret->ReturnCode != SCARD_S_SUCCESS) ++ { ++ WLog_Print(log, g_LogLevel, " [INVALID RETURN] rgReaderStates, cReaders=%" PRIu32, ++ ret->cReaders); ++ } + else + { + for (UINT32 index = 0; index < ret->cReaders; index++) + { + char buffer[1024] = { 0 }; + const ReaderState_Return* rgReaderState = &(ret->rgReaderStates[index]); +- szCurrentState = SCardGetReaderStateString(rgReaderState->dwCurrentState); +- szEventState = SCardGetReaderStateString(rgReaderState->dwEventState); ++ char* szCurrentState = SCardGetReaderStateString(rgReaderState->dwCurrentState); ++ char* szEventState = SCardGetReaderStateString(rgReaderState->dwEventState); + WLog_Print(log, g_LogLevel, " [%" PRIu32 "]: dwCurrentState: %s (0x%08" PRIX32 ")", + index, szCurrentState, rgReaderState->dwCurrentState); + WLog_Print(log, g_LogLevel, " [%" PRIu32 "]: dwEventState: %s (0x%08" PRIX32 ")", +@@ -810,446 +890,434 @@ static void smartcard_trace_get_status_change_return(const GetStatusChange_Retur + + static void smartcard_trace_context_and_two_strings_a_call(const ContextAndTwoStringA_Call* call) + { +- if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel)) ++ WINPR_ASSERT(call); ++ wLog* log = WLog_Get(TAG); ++ if (!WLog_IsLevelActive(log, g_LogLevel)) + return; + +- WLog_LVL(TAG, g_LogLevel, "ContextAndTwoStringW_Call {"); +- smartcard_log_context(TAG, &call->handles.hContext); +- WLog_LVL(TAG, g_LogLevel, " sz1=%s", call->sz1); +- WLog_LVL(TAG, g_LogLevel, " sz2=%s", call->sz2); +- WLog_LVL(TAG, g_LogLevel, "}"); ++ WLog_Print(log, g_LogLevel, "ContextAndTwoStringW_Call {"); ++ smartcard_log_context(log, &call->handles.hContext); ++ WLog_Print(log, g_LogLevel, " sz1=%s", call->sz1); ++ WLog_Print(log, g_LogLevel, " sz2=%s", call->sz2); ++ WLog_Print(log, g_LogLevel, "}"); + } + + static void smartcard_trace_context_and_two_strings_w_call(const ContextAndTwoStringW_Call* call) + { ++ WINPR_ASSERT(call); + char sz1[1024] = { 0 }; + char sz2[1024] = { 0 }; + +- if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel)) ++ wLog* log = WLog_Get(TAG); ++ if (!WLog_IsLevelActive(log, g_LogLevel)) + return; + if (call->sz1) + (void)ConvertWCharToUtf8(call->sz1, sz1, ARRAYSIZE(sz1)); + if (call->sz2) + (void)ConvertWCharToUtf8(call->sz2, sz2, ARRAYSIZE(sz2)); + +- WLog_LVL(TAG, g_LogLevel, "ContextAndTwoStringW_Call {"); +- smartcard_log_context(TAG, &call->handles.hContext); +- WLog_LVL(TAG, g_LogLevel, " sz1=%s", sz1); +- WLog_LVL(TAG, g_LogLevel, " sz2=%s", sz2); +- WLog_LVL(TAG, g_LogLevel, "}"); ++ WLog_Print(log, g_LogLevel, "ContextAndTwoStringW_Call {"); ++ smartcard_log_context(log, &call->handles.hContext); ++ WLog_Print(log, g_LogLevel, " sz1=%s", sz1); ++ WLog_Print(log, g_LogLevel, " sz2=%s", sz2); ++ WLog_Print(log, g_LogLevel, "}"); + } + + static void smartcard_trace_get_transmit_count_call(const GetTransmitCount_Call* call) + { +- if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel)) ++ WINPR_ASSERT(call); ++ wLog* log = WLog_Get(TAG); ++ if (!WLog_IsLevelActive(log, g_LogLevel)) + return; + +- WLog_LVL(TAG, g_LogLevel, "GetTransmitCount_Call {"); +- smartcard_log_context(TAG, &call->handles.hContext); +- smartcard_log_redir_handle(TAG, &call->handles.hCard); ++ WLog_Print(log, g_LogLevel, "GetTransmitCount_Call {"); ++ smartcard_log_context(log, &call->handles.hContext); ++ smartcard_log_redir_handle(log, &call->handles.hCard); + +- WLog_LVL(TAG, g_LogLevel, "}"); ++ WLog_Print(log, g_LogLevel, "}"); + } + + static void smartcard_trace_write_cache_a_call(const WriteCacheA_Call* call) + { +- char buffer[1024]; ++ WINPR_ASSERT(call); ++ char buffer[1024] = { 0 }; + +- if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel)) ++ wLog* log = WLog_Get(TAG); ++ if (!WLog_IsLevelActive(log, g_LogLevel)) + return; + +- WLog_LVL(TAG, g_LogLevel, "WriteCacheA_Call {"); ++ WLog_Print(log, g_LogLevel, "WriteCacheA_Call {"); + +- WLog_LVL(TAG, g_LogLevel, " szLookupName=%s", call->szLookupName); ++ WLog_Print(log, g_LogLevel, " szLookupName=%s", call->szLookupName); + +- smartcard_log_context(TAG, &call->Common.handles.hContext); ++ smartcard_log_context(log, &call->Common.handles.hContext); + WLog_DBG( + TAG, "..CardIdentifier=%s", + smartcard_array_dump(call->Common.CardIdentifier, sizeof(UUID), buffer, sizeof(buffer))); +- WLog_LVL(TAG, g_LogLevel, " FreshnessCounter=%" PRIu32, call->Common.FreshnessCounter); +- WLog_LVL(TAG, g_LogLevel, " cbDataLen=%" PRIu32, call->Common.cbDataLen); ++ WLog_Print(log, g_LogLevel, " FreshnessCounter=%" PRIu32, call->Common.FreshnessCounter); ++ WLog_Print(log, g_LogLevel, " cbDataLen=%" PRIu32, call->Common.cbDataLen); + WLog_DBG( + TAG, " pbData=%s", + smartcard_array_dump(call->Common.pbData, call->Common.cbDataLen, buffer, sizeof(buffer))); +- WLog_LVL(TAG, g_LogLevel, "}"); ++ WLog_Print(log, g_LogLevel, "}"); + } + + static void smartcard_trace_write_cache_w_call(const WriteCacheW_Call* call) + { ++ WINPR_ASSERT(call); + char tmp[1024] = { 0 }; + char buffer[1024] = { 0 }; + +- if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel)) ++ wLog* log = WLog_Get(TAG); ++ if (!WLog_IsLevelActive(log, g_LogLevel)) + return; + +- WLog_LVL(TAG, g_LogLevel, "WriteCacheW_Call {"); ++ WLog_Print(log, g_LogLevel, "WriteCacheW_Call {"); + + if (call->szLookupName) + (void)ConvertWCharToUtf8(call->szLookupName, tmp, ARRAYSIZE(tmp)); +- WLog_LVL(TAG, g_LogLevel, " szLookupName=%s", tmp); ++ WLog_Print(log, g_LogLevel, " szLookupName=%s", tmp); + +- smartcard_log_context(TAG, &call->Common.handles.hContext); ++ smartcard_log_context(log, &call->Common.handles.hContext); + WLog_DBG( + TAG, "..CardIdentifier=%s", + smartcard_array_dump(call->Common.CardIdentifier, sizeof(UUID), buffer, sizeof(buffer))); +- WLog_LVL(TAG, g_LogLevel, " FreshnessCounter=%" PRIu32, call->Common.FreshnessCounter); +- WLog_LVL(TAG, g_LogLevel, " cbDataLen=%" PRIu32, call->Common.cbDataLen); ++ WLog_Print(log, g_LogLevel, " FreshnessCounter=%" PRIu32, call->Common.FreshnessCounter); ++ WLog_Print(log, g_LogLevel, " cbDataLen=%" PRIu32, call->Common.cbDataLen); + WLog_DBG( + TAG, " pbData=%s", + smartcard_array_dump(call->Common.pbData, call->Common.cbDataLen, buffer, sizeof(buffer))); +- WLog_LVL(TAG, g_LogLevel, "}"); ++ WLog_Print(log, g_LogLevel, "}"); + } + + static void smartcard_trace_read_cache_a_call(const ReadCacheA_Call* call) + { +- char buffer[1024]; ++ WINPR_ASSERT(call); ++ char buffer[1024] = { 0 }; + +- if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel)) ++ wLog* log = WLog_Get(TAG); ++ if (!WLog_IsLevelActive(log, g_LogLevel)) + return; + +- WLog_LVL(TAG, g_LogLevel, "ReadCacheA_Call {"); ++ WLog_Print(log, g_LogLevel, "ReadCacheA_Call {"); + +- WLog_LVL(TAG, g_LogLevel, " szLookupName=%s", call->szLookupName); +- smartcard_log_context(TAG, &call->Common.handles.hContext); ++ WLog_Print(log, g_LogLevel, " szLookupName=%s", call->szLookupName); ++ smartcard_log_context(log, &call->Common.handles.hContext); + WLog_DBG( + TAG, "..CardIdentifier=%s", + smartcard_array_dump(call->Common.CardIdentifier, sizeof(UUID), buffer, sizeof(buffer))); +- WLog_LVL(TAG, g_LogLevel, " FreshnessCounter=%" PRIu32, call->Common.FreshnessCounter); +- WLog_LVL(TAG, g_LogLevel, " fPbDataIsNULL=%" PRId32, call->Common.fPbDataIsNULL); +- WLog_LVL(TAG, g_LogLevel, " cbDataLen=%" PRIu32, call->Common.cbDataLen); ++ WLog_Print(log, g_LogLevel, " FreshnessCounter=%" PRIu32, call->Common.FreshnessCounter); ++ WLog_Print(log, g_LogLevel, " fPbDataIsNULL=%" PRId32, call->Common.fPbDataIsNULL); ++ WLog_Print(log, g_LogLevel, " cbDataLen=%" PRIu32, call->Common.cbDataLen); + +- WLog_LVL(TAG, g_LogLevel, "}"); ++ WLog_Print(log, g_LogLevel, "}"); + } + + static void smartcard_trace_read_cache_w_call(const ReadCacheW_Call* call) + { ++ WINPR_ASSERT(call); + char tmp[1024] = { 0 }; + char buffer[1024] = { 0 }; + +- if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel)) ++ wLog* log = WLog_Get(TAG); ++ if (!WLog_IsLevelActive(log, g_LogLevel)) + return; + +- WLog_LVL(TAG, g_LogLevel, "ReadCacheW_Call {"); ++ WLog_Print(log, g_LogLevel, "ReadCacheW_Call {"); + if (call->szLookupName) + (void)ConvertWCharToUtf8(call->szLookupName, tmp, ARRAYSIZE(tmp)); +- WLog_LVL(TAG, g_LogLevel, " szLookupName=%s", tmp); ++ WLog_Print(log, g_LogLevel, " szLookupName=%s", tmp); + +- smartcard_log_context(TAG, &call->Common.handles.hContext); ++ smartcard_log_context(log, &call->Common.handles.hContext); + WLog_DBG( + TAG, "..CardIdentifier=%s", + smartcard_array_dump(call->Common.CardIdentifier, sizeof(UUID), buffer, sizeof(buffer))); +- WLog_LVL(TAG, g_LogLevel, " FreshnessCounter=%" PRIu32, call->Common.FreshnessCounter); +- WLog_LVL(TAG, g_LogLevel, " fPbDataIsNULL=%" PRId32, call->Common.fPbDataIsNULL); +- WLog_LVL(TAG, g_LogLevel, " cbDataLen=%" PRIu32, call->Common.cbDataLen); ++ WLog_Print(log, g_LogLevel, " FreshnessCounter=%" PRIu32, call->Common.FreshnessCounter); ++ WLog_Print(log, g_LogLevel, " fPbDataIsNULL=%" PRId32, call->Common.fPbDataIsNULL); ++ WLog_Print(log, g_LogLevel, " cbDataLen=%" PRIu32, call->Common.cbDataLen); + +- WLog_LVL(TAG, g_LogLevel, "}"); ++ WLog_Print(log, g_LogLevel, "}"); + } + + static void smartcard_trace_transmit_call(const Transmit_Call* call) + { ++ WINPR_ASSERT(call); + UINT32 cbExtraBytes = 0; + BYTE* pbExtraBytes = NULL; + +- if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel)) ++ wLog* log = WLog_Get(TAG); ++ if (!WLog_IsLevelActive(log, g_LogLevel)) + return; + +- WLog_LVL(TAG, g_LogLevel, "Transmit_Call {"); +- smartcard_log_context(TAG, &call->handles.hContext); +- smartcard_log_redir_handle(TAG, &call->handles.hCard); ++ WLog_Print(log, g_LogLevel, "Transmit_Call {"); ++ smartcard_log_context(log, &call->handles.hContext); ++ smartcard_log_redir_handle(log, &call->handles.hCard); + + if (call->pioSendPci) + { + cbExtraBytes = (UINT32)(call->pioSendPci->cbPciLength - sizeof(SCARD_IO_REQUEST)); + pbExtraBytes = &((BYTE*)call->pioSendPci)[sizeof(SCARD_IO_REQUEST)]; +- WLog_LVL(TAG, g_LogLevel, "pioSendPci: dwProtocol: %" PRIu32 " cbExtraBytes: %" PRIu32 "", +- call->pioSendPci->dwProtocol, cbExtraBytes); ++ WLog_Print(log, g_LogLevel, "pioSendPci: dwProtocol: %" PRIu32 " cbExtraBytes: %" PRIu32 "", ++ call->pioSendPci->dwProtocol, cbExtraBytes); + + if (cbExtraBytes) + { +- char buffer[1024]; +- WLog_LVL(TAG, g_LogLevel, "pbExtraBytes: %s", +- smartcard_array_dump(pbExtraBytes, cbExtraBytes, buffer, sizeof(buffer))); ++ char buffer[1024] = { 0 }; ++ WLog_Print(log, g_LogLevel, "pbExtraBytes: %s", ++ smartcard_array_dump(pbExtraBytes, cbExtraBytes, buffer, sizeof(buffer))); + } + } + else + { +- WLog_LVL(TAG, g_LogLevel, "pioSendPci: null"); ++ WLog_Print(log, g_LogLevel, "pioSendPci: null"); + } + +- WLog_LVL(TAG, g_LogLevel, "cbSendLength: %" PRIu32 "", call->cbSendLength); ++ WLog_Print(log, g_LogLevel, "cbSendLength: %" PRIu32 "", call->cbSendLength); + + if (call->pbSendBuffer) + { +- char buffer[1024]; ++ char buffer[1024] = { 0 }; + WLog_DBG( + TAG, "pbSendBuffer: %s", + smartcard_array_dump(call->pbSendBuffer, call->cbSendLength, buffer, sizeof(buffer))); + } + else + { +- WLog_LVL(TAG, g_LogLevel, "pbSendBuffer: null"); ++ WLog_Print(log, g_LogLevel, "pbSendBuffer: null"); + } + + if (call->pioRecvPci) + { + cbExtraBytes = (UINT32)(call->pioRecvPci->cbPciLength - sizeof(SCARD_IO_REQUEST)); + pbExtraBytes = &((BYTE*)call->pioRecvPci)[sizeof(SCARD_IO_REQUEST)]; +- WLog_LVL(TAG, g_LogLevel, "pioRecvPci: dwProtocol: %" PRIu32 " cbExtraBytes: %" PRIu32 "", +- call->pioRecvPci->dwProtocol, cbExtraBytes); ++ WLog_Print(log, g_LogLevel, "pioRecvPci: dwProtocol: %" PRIu32 " cbExtraBytes: %" PRIu32 "", ++ call->pioRecvPci->dwProtocol, cbExtraBytes); + + if (cbExtraBytes) + { +- char buffer[1024]; +- WLog_LVL(TAG, g_LogLevel, "pbExtraBytes: %s", +- smartcard_array_dump(pbExtraBytes, cbExtraBytes, buffer, sizeof(buffer))); ++ char buffer[1024] = { 0 }; ++ WLog_Print(log, g_LogLevel, "pbExtraBytes: %s", ++ smartcard_array_dump(pbExtraBytes, cbExtraBytes, buffer, sizeof(buffer))); + } + } + else + { +- WLog_LVL(TAG, g_LogLevel, "pioRecvPci: null"); ++ WLog_Print(log, g_LogLevel, "pioRecvPci: null"); + } + +- WLog_LVL(TAG, g_LogLevel, "fpbRecvBufferIsNULL: %" PRId32 " cbRecvLength: %" PRIu32 "", +- call->fpbRecvBufferIsNULL, call->cbRecvLength); +- WLog_LVL(TAG, g_LogLevel, "}"); ++ WLog_Print(log, g_LogLevel, "fpbRecvBufferIsNULL: %" PRId32 " cbRecvLength: %" PRIu32 "", ++ call->fpbRecvBufferIsNULL, call->cbRecvLength); ++ WLog_Print(log, g_LogLevel, "}"); + } + + static void smartcard_trace_locate_cards_by_atr_w_call(const LocateCardsByATRW_Call* call) + { +- char* szEventState = NULL; +- char* szCurrentState = NULL; +- +- if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel)) ++ WINPR_ASSERT(call); ++ wLog* log = WLog_Get(TAG); ++ if (!WLog_IsLevelActive(log, g_LogLevel)) + return; + +- WLog_LVL(TAG, g_LogLevel, "LocateCardsByATRW_Call {"); +- smartcard_log_context(TAG, &call->handles.hContext); +- +- for (UINT32 index = 0; index < call->cReaders; index++) +- { +- char buffer[1024] = { 0 }; +- char tmp[1024] = { 0 }; +- const LPSCARD_READERSTATEW readerState = +- (const LPSCARD_READERSTATEW)&call->rgReaderStates[index]; +- +- if (readerState->szReader) +- (void)ConvertWCharToUtf8(readerState->szReader, tmp, ARRAYSIZE(tmp)); +- WLog_LVL(TAG, g_LogLevel, "\t[%" PRIu32 "]: szReader: %s cbAtr: %" PRIu32 "", index, tmp, +- readerState->cbAtr); +- szCurrentState = SCardGetReaderStateString(readerState->dwCurrentState); +- szEventState = SCardGetReaderStateString(readerState->dwEventState); +- WLog_LVL(TAG, g_LogLevel, "\t[%" PRIu32 "]: dwCurrentState: %s (0x%08" PRIX32 ")", index, +- szCurrentState, readerState->dwCurrentState); +- WLog_LVL(TAG, g_LogLevel, "\t[%" PRIu32 "]: dwEventState: %s (0x%08" PRIX32 ")", index, +- szEventState, readerState->dwEventState); ++ WLog_Print(log, g_LogLevel, "LocateCardsByATRW_Call {"); ++ smartcard_log_context(log, &call->handles.hContext); + +- WLog_DBG( +- TAG, "\t[%" PRIu32 "]: cbAtr: %" PRIu32 " rgbAtr: %s", index, readerState->cbAtr, +- smartcard_array_dump(readerState->rgbAtr, readerState->cbAtr, buffer, sizeof(buffer))); +- +- free(szCurrentState); +- free(szEventState); +- } ++ dump_reader_states_w(log, call->rgReaderStates, call->cReaders); + +- WLog_LVL(TAG, g_LogLevel, "}"); ++ WLog_Print(log, g_LogLevel, "}"); + } + + static void smartcard_trace_transmit_return(const Transmit_Return* ret) + { ++ WINPR_ASSERT(ret); + UINT32 cbExtraBytes = 0; + BYTE* pbExtraBytes = NULL; + +- if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel)) ++ wLog* log = WLog_Get(TAG); ++ if (!WLog_IsLevelActive(log, g_LogLevel)) + return; + +- WLog_LVL(TAG, g_LogLevel, "Transmit_Return {"); +- WLog_LVL(TAG, g_LogLevel, " ReturnCode: %s (0x%08" PRIX32 ")", +- SCardGetErrorString(ret->ReturnCode), ret->ReturnCode); ++ WLog_Print(log, g_LogLevel, "Transmit_Return {"); ++ WLog_Print(log, g_LogLevel, " ReturnCode: %s (0x%08" PRIX32 ")", ++ SCardGetErrorString(ret->ReturnCode), ret->ReturnCode); + + if (ret->pioRecvPci) + { + cbExtraBytes = (UINT32)(ret->pioRecvPci->cbPciLength - sizeof(SCARD_IO_REQUEST)); + pbExtraBytes = &((BYTE*)ret->pioRecvPci)[sizeof(SCARD_IO_REQUEST)]; +- WLog_LVL(TAG, g_LogLevel, " pioRecvPci: dwProtocol: %" PRIu32 " cbExtraBytes: %" PRIu32 "", +- ret->pioRecvPci->dwProtocol, cbExtraBytes); ++ WLog_Print(log, g_LogLevel, ++ " pioRecvPci: dwProtocol: %" PRIu32 " cbExtraBytes: %" PRIu32 "", ++ ret->pioRecvPci->dwProtocol, cbExtraBytes); + + if (cbExtraBytes) + { +- char buffer[1024]; +- WLog_LVL(TAG, g_LogLevel, " pbExtraBytes: %s", +- smartcard_array_dump(pbExtraBytes, cbExtraBytes, buffer, sizeof(buffer))); ++ char buffer[1024] = { 0 }; ++ WLog_Print(log, g_LogLevel, " pbExtraBytes: %s", ++ smartcard_array_dump(pbExtraBytes, cbExtraBytes, buffer, sizeof(buffer))); + } + } + else + { +- WLog_LVL(TAG, g_LogLevel, " pioRecvPci: null"); ++ WLog_Print(log, g_LogLevel, " pioRecvPci: null"); + } + +- WLog_LVL(TAG, g_LogLevel, " cbRecvLength: %" PRIu32 "", ret->cbRecvLength); ++ WLog_Print(log, g_LogLevel, " cbRecvLength: %" PRIu32 "", ret->cbRecvLength); + + if (ret->pbRecvBuffer) + { +- char buffer[1024]; ++ char buffer[1024] = { 0 }; + WLog_DBG( + TAG, " pbRecvBuffer: %s", + smartcard_array_dump(ret->pbRecvBuffer, ret->cbRecvLength, buffer, sizeof(buffer))); + } + else + { +- WLog_LVL(TAG, g_LogLevel, " pbRecvBuffer: null"); ++ WLog_Print(log, g_LogLevel, " pbRecvBuffer: null"); + } + +- WLog_LVL(TAG, g_LogLevel, "}"); ++ WLog_Print(log, g_LogLevel, "}"); + } + + static void smartcard_trace_control_return(const Control_Return* ret) + { +- if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel)) ++ WINPR_ASSERT(ret); ++ wLog* log = WLog_Get(TAG); ++ if (!WLog_IsLevelActive(log, g_LogLevel)) + return; + +- WLog_LVL(TAG, g_LogLevel, "Control_Return {"); +- WLog_LVL(TAG, g_LogLevel, " ReturnCode: %s (0x%08" PRIX32 ")", +- SCardGetErrorString(ret->ReturnCode), ret->ReturnCode); +- WLog_LVL(TAG, g_LogLevel, " cbOutBufferSize: %" PRIu32 "", ret->cbOutBufferSize); ++ WLog_Print(log, g_LogLevel, "Control_Return {"); ++ WLog_Print(log, g_LogLevel, " ReturnCode: %s (0x%08" PRIX32 ")", ++ SCardGetErrorString(ret->ReturnCode), ret->ReturnCode); ++ WLog_Print(log, g_LogLevel, " cbOutBufferSize: %" PRIu32 "", ret->cbOutBufferSize); + + if (ret->pvOutBuffer) + { +- char buffer[1024]; ++ char buffer[1024] = { 0 }; + WLog_DBG( + TAG, "pvOutBuffer: %s", + smartcard_array_dump(ret->pvOutBuffer, ret->cbOutBufferSize, buffer, sizeof(buffer))); + } + else + { +- WLog_LVL(TAG, g_LogLevel, "pvOutBuffer: null"); ++ WLog_Print(log, g_LogLevel, "pvOutBuffer: null"); + } + +- WLog_LVL(TAG, g_LogLevel, "}"); ++ WLog_Print(log, g_LogLevel, "}"); + } + + static void smartcard_trace_control_call(const Control_Call* call) + { +- if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel)) ++ WINPR_ASSERT(call); ++ wLog* log = WLog_Get(TAG); ++ if (!WLog_IsLevelActive(log, g_LogLevel)) + return; + +- WLog_LVL(TAG, g_LogLevel, "Control_Call {"); +- smartcard_log_context(TAG, &call->handles.hContext); +- smartcard_log_redir_handle(TAG, &call->handles.hCard); ++ WLog_Print(log, g_LogLevel, "Control_Call {"); ++ smartcard_log_context(log, &call->handles.hContext); ++ smartcard_log_redir_handle(log, &call->handles.hCard); + +- WLog_LVL(TAG, g_LogLevel, +- "dwControlCode: 0x%08" PRIX32 " cbInBufferSize: %" PRIu32 +- " fpvOutBufferIsNULL: %" PRId32 " cbOutBufferSize: %" PRIu32 "", +- call->dwControlCode, call->cbInBufferSize, call->fpvOutBufferIsNULL, +- call->cbOutBufferSize); ++ WLog_Print(log, g_LogLevel, ++ "dwControlCode: 0x%08" PRIX32 " cbInBufferSize: %" PRIu32 ++ " fpvOutBufferIsNULL: %" PRId32 " cbOutBufferSize: %" PRIu32 "", ++ call->dwControlCode, call->cbInBufferSize, call->fpvOutBufferIsNULL, ++ call->cbOutBufferSize); + + if (call->pvInBuffer) + { +- char buffer[1024]; ++ char buffer[1024] = { 0 }; + WLog_DBG( + TAG, "pbInBuffer: %s", + smartcard_array_dump(call->pvInBuffer, call->cbInBufferSize, buffer, sizeof(buffer))); + } + else + { +- WLog_LVL(TAG, g_LogLevel, "pvInBuffer: null"); ++ WLog_Print(log, g_LogLevel, "pvInBuffer: null"); + } + +- WLog_LVL(TAG, g_LogLevel, "}"); ++ WLog_Print(log, g_LogLevel, "}"); + } + + static void smartcard_trace_set_attrib_call(const SetAttrib_Call* call) + { +- char buffer[8192]; ++ WINPR_ASSERT(call); ++ char buffer[8192] = { 0 }; + +- if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel)) ++ wLog* log = WLog_Get(TAG); ++ if (!WLog_IsLevelActive(log, g_LogLevel)) + return; + +- WLog_LVL(TAG, g_LogLevel, "GetAttrib_Call {"); +- smartcard_log_context(TAG, &call->handles.hContext); +- smartcard_log_redir_handle(TAG, &call->handles.hCard); +- WLog_LVL(TAG, g_LogLevel, "dwAttrId: 0x%08" PRIX32, call->dwAttrId); +- WLog_LVL(TAG, g_LogLevel, "cbAttrLen: 0x%08" PRId32, call->cbAttrLen); +- WLog_LVL(TAG, g_LogLevel, "pbAttr: %s", +- smartcard_array_dump(call->pbAttr, call->cbAttrLen, buffer, sizeof(buffer))); +- WLog_LVL(TAG, g_LogLevel, "}"); ++ WLog_Print(log, g_LogLevel, "GetAttrib_Call {"); ++ smartcard_log_context(log, &call->handles.hContext); ++ smartcard_log_redir_handle(log, &call->handles.hCard); ++ WLog_Print(log, g_LogLevel, "dwAttrId: 0x%08" PRIX32, call->dwAttrId); ++ WLog_Print(log, g_LogLevel, "cbAttrLen: 0x%08" PRId32, call->cbAttrLen); ++ WLog_Print(log, g_LogLevel, "pbAttr: %s", ++ smartcard_array_dump(call->pbAttr, call->cbAttrLen, buffer, sizeof(buffer))); ++ WLog_Print(log, g_LogLevel, "}"); + } + + static void smartcard_trace_get_attrib_return(const GetAttrib_Return* ret, DWORD dwAttrId) + { +- +- if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel)) ++ WINPR_ASSERT(ret); ++ char buffer[1024] = { 0 }; ++ wLog* log = WLog_Get(TAG); ++ if (!WLog_IsLevelActive(log, g_LogLevel)) + return; + +- WLog_LVL(TAG, g_LogLevel, "GetAttrib_Return {"); +- WLog_LVL(TAG, g_LogLevel, " ReturnCode: %s (0x%08" PRIX32 ")", +- SCardGetErrorString(ret->ReturnCode), ret->ReturnCode); +- WLog_LVL(TAG, g_LogLevel, " dwAttrId: %s (0x%08" PRIX32 ") cbAttrLen: 0x%08" PRIX32 "", +- SCardGetAttributeString(dwAttrId), dwAttrId, ret->cbAttrLen); +- +- if (dwAttrId == SCARD_ATTR_VENDOR_NAME) +- { +- WLog_LVL(TAG, g_LogLevel, " pbAttr: %.*s", ret->cbAttrLen, (char*)ret->pbAttr); +- } +- else if (dwAttrId == SCARD_ATTR_CURRENT_PROTOCOL_TYPE) +- { +- union +- { +- BYTE* pb; +- DWORD* pd; +- } attr; +- attr.pb = ret->pbAttr; +- if (!ret->pbAttr) +- { +- WLog_LVL(TAG, g_LogLevel, " dwProtocolType: NULL"); +- } +- else +- { +- WLog_LVL(TAG, g_LogLevel, " dwProtocolType: %s (0x%08" PRIX32 ")", +- SCardGetProtocolString(*attr.pd), *attr.pd); +- } +- } ++ WLog_Print(log, g_LogLevel, "GetAttrib_Return {"); ++ WLog_Print(log, g_LogLevel, " ReturnCode: %s (0x%08" PRIX32 ")", ++ SCardGetErrorString(ret->ReturnCode), ret->ReturnCode); ++ WLog_Print(log, g_LogLevel, " dwAttrId: %s (0x%08" PRIX32 ") cbAttrLen: 0x%08" PRIX32 "", ++ SCardGetAttributeString(dwAttrId), dwAttrId, ret->cbAttrLen); ++ WLog_Print(log, g_LogLevel, " %s", ++ smartcard_array_dump(ret->pbAttr, ret->cbAttrLen, buffer, sizeof(buffer))); + +- WLog_LVL(TAG, g_LogLevel, "}"); ++ WLog_Print(log, g_LogLevel, "}"); + } + + static void smartcard_trace_get_attrib_call(const GetAttrib_Call* call) + { +- if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel)) ++ WINPR_ASSERT(call); ++ wLog* log = WLog_Get(TAG); ++ if (!WLog_IsLevelActive(log, g_LogLevel)) + return; + +- WLog_LVL(TAG, g_LogLevel, "GetAttrib_Call {"); +- smartcard_log_context(TAG, &call->handles.hContext); +- smartcard_log_redir_handle(TAG, &call->handles.hCard); ++ WLog_Print(log, g_LogLevel, "GetAttrib_Call {"); ++ smartcard_log_context(log, &call->handles.hContext); ++ smartcard_log_redir_handle(log, &call->handles.hCard); + +- WLog_LVL(TAG, g_LogLevel, +- "dwAttrId: %s (0x%08" PRIX32 ") fpbAttrIsNULL: %" PRId32 " cbAttrLen: 0x%08" PRIX32 "", +- SCardGetAttributeString(call->dwAttrId), call->dwAttrId, call->fpbAttrIsNULL, +- call->cbAttrLen); +- WLog_LVL(TAG, g_LogLevel, "}"); ++ WLog_Print(log, g_LogLevel, ++ "dwAttrId: %s (0x%08" PRIX32 ") fpbAttrIsNULL: %" PRId32 " cbAttrLen: 0x%08" PRIX32 ++ "", ++ SCardGetAttributeString(call->dwAttrId), call->dwAttrId, call->fpbAttrIsNULL, ++ call->cbAttrLen); ++ WLog_Print(log, g_LogLevel, "}"); + } + + static void smartcard_trace_status_call(const Status_Call* call, BOOL unicode) + { +- if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel)) ++ WINPR_ASSERT(call); ++ wLog* log = WLog_Get(TAG); ++ if (!WLog_IsLevelActive(log, g_LogLevel)) + return; + +- WLog_LVL(TAG, g_LogLevel, "Status%s_Call {", unicode ? "W" : "A"); +- smartcard_log_context(TAG, &call->handles.hContext); +- smartcard_log_redir_handle(TAG, &call->handles.hCard); ++ WLog_Print(log, g_LogLevel, "Status%s_Call {", unicode ? "W" : "A"); ++ smartcard_log_context(log, &call->handles.hContext); ++ smartcard_log_redir_handle(log, &call->handles.hCard); + +- WLog_LVL(TAG, g_LogLevel, +- "fmszReaderNamesIsNULL: %" PRId32 " cchReaderLen: %" PRIu32 " cbAtrLen: %" PRIu32 "", +- call->fmszReaderNamesIsNULL, call->cchReaderLen, call->cbAtrLen); +- WLog_LVL(TAG, g_LogLevel, "}"); ++ WLog_Print(log, g_LogLevel, ++ "fmszReaderNamesIsNULL: %" PRId32 " cchReaderLen: %" PRIu32 " cbAtrLen: %" PRIu32 "", ++ call->fmszReaderNamesIsNULL, call->cchReaderLen, call->cbAtrLen); ++ WLog_Print(log, g_LogLevel, "}"); + } + + static void smartcard_trace_status_return(const Status_Return* ret, BOOL unicode) + { ++ WINPR_ASSERT(ret); + char* mszReaderNamesA = NULL; +- char buffer[1024]; ++ char buffer[1024] = { 0 }; + DWORD cBytes = 0; + +- if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel)) ++ wLog* log = WLog_Get(TAG); ++ if (!WLog_IsLevelActive(log, g_LogLevel)) + return; + cBytes = ret->cBytes; + if (ret->ReturnCode != SCARD_S_SUCCESS) +@@ -1258,194 +1326,212 @@ static void smartcard_trace_status_return(const Status_Return* ret, BOOL unicode + cBytes = 0; + mszReaderNamesA = smartcard_convert_string_list(ret->mszReaderNames, cBytes, unicode); + +- WLog_LVL(TAG, g_LogLevel, "Status%s_Return {", unicode ? "W" : "A"); +- WLog_LVL(TAG, g_LogLevel, " ReturnCode: %s (0x%08" PRIX32 ")", +- SCardGetErrorString(ret->ReturnCode), ret->ReturnCode); +- WLog_LVL(TAG, g_LogLevel, " dwState: %s (0x%08" PRIX32 ") dwProtocol: %s (0x%08" PRIX32 ")", +- SCardGetCardStateString(ret->dwState), ret->dwState, +- SCardGetProtocolString(ret->dwProtocol), ret->dwProtocol); ++ WLog_Print(log, g_LogLevel, "Status%s_Return {", unicode ? "W" : "A"); ++ WLog_Print(log, g_LogLevel, " ReturnCode: %s (0x%08" PRIX32 ")", ++ SCardGetErrorString(ret->ReturnCode), ret->ReturnCode); ++ WLog_Print(log, g_LogLevel, " dwState: %s (0x%08" PRIX32 ") dwProtocol: %s (0x%08" PRIX32 ")", ++ SCardGetCardStateString(ret->dwState), ret->dwState, ++ SCardGetProtocolString(ret->dwProtocol), ret->dwProtocol); + +- WLog_LVL(TAG, g_LogLevel, " cBytes: %" PRIu32 " mszReaderNames: %s", ret->cBytes, +- mszReaderNamesA); ++ WLog_Print(log, g_LogLevel, " cBytes: %" PRIu32 " mszReaderNames: %s", ret->cBytes, ++ mszReaderNamesA); + +- WLog_LVL(TAG, g_LogLevel, " cbAtrLen: %" PRIu32 " pbAtr: %s", ret->cbAtrLen, +- smartcard_array_dump(ret->pbAtr, ret->cbAtrLen, buffer, sizeof(buffer))); +- WLog_LVL(TAG, g_LogLevel, "}"); ++ WLog_Print(log, g_LogLevel, " cbAtrLen: %" PRIu32 " pbAtr: %s", ret->cbAtrLen, ++ smartcard_array_dump(ret->pbAtr, ret->cbAtrLen, buffer, sizeof(buffer))); ++ WLog_Print(log, g_LogLevel, "}"); + free(mszReaderNamesA); + } + + static void smartcard_trace_state_return(const State_Return* ret) + { +- char buffer[1024]; ++ WINPR_ASSERT(ret); ++ char buffer[1024] = { 0 }; + char* state = NULL; + +- if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel)) ++ wLog* log = WLog_Get(TAG); ++ if (!WLog_IsLevelActive(log, g_LogLevel)) + return; + + state = SCardGetReaderStateString(ret->dwState); +- WLog_LVL(TAG, g_LogLevel, "Reconnect_Return {"); +- WLog_LVL(TAG, g_LogLevel, " ReturnCode: %s (0x%08" PRIX32 ")", +- SCardGetErrorString(ret->ReturnCode), ret->ReturnCode); +- WLog_LVL(TAG, g_LogLevel, " dwState: %s (0x%08" PRIX32 ")", state, ret->dwState); +- WLog_LVL(TAG, g_LogLevel, " dwProtocol: %s (0x%08" PRIX32 ")", +- SCardGetProtocolString(ret->dwProtocol), ret->dwProtocol); +- WLog_LVL(TAG, g_LogLevel, " cbAtrLen: (0x%08" PRIX32 ")", ret->cbAtrLen); +- WLog_LVL(TAG, g_LogLevel, " rgAtr: %s", +- smartcard_array_dump(ret->rgAtr, sizeof(ret->rgAtr), buffer, sizeof(buffer))); +- WLog_LVL(TAG, g_LogLevel, "}"); ++ WLog_Print(log, g_LogLevel, "Reconnect_Return {"); ++ WLog_Print(log, g_LogLevel, " ReturnCode: %s (0x%08" PRIX32 ")", ++ SCardGetErrorString(ret->ReturnCode), ret->ReturnCode); ++ WLog_Print(log, g_LogLevel, " dwState: %s (0x%08" PRIX32 ")", state, ret->dwState); ++ WLog_Print(log, g_LogLevel, " dwProtocol: %s (0x%08" PRIX32 ")", ++ SCardGetProtocolString(ret->dwProtocol), ret->dwProtocol); ++ WLog_Print(log, g_LogLevel, " cbAtrLen: (0x%08" PRIX32 ")", ret->cbAtrLen); ++ WLog_Print(log, g_LogLevel, " rgAtr: %s", ++ smartcard_array_dump(ret->rgAtr, sizeof(ret->rgAtr), buffer, sizeof(buffer))); ++ WLog_Print(log, g_LogLevel, "}"); + free(state); + } + + static void smartcard_trace_reconnect_return(const Reconnect_Return* ret) + { +- +- if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel)) ++ WINPR_ASSERT(ret); ++ wLog* log = WLog_Get(TAG); ++ if (!WLog_IsLevelActive(log, g_LogLevel)) + return; + +- WLog_LVL(TAG, g_LogLevel, "Reconnect_Return {"); +- WLog_LVL(TAG, g_LogLevel, " ReturnCode: %s (0x%08" PRIX32 ")", +- SCardGetErrorString(ret->ReturnCode), ret->ReturnCode); +- WLog_LVL(TAG, g_LogLevel, " dwActiveProtocol: %s (0x%08" PRIX32 ")", +- SCardGetProtocolString(ret->dwActiveProtocol), ret->dwActiveProtocol); +- WLog_LVL(TAG, g_LogLevel, "}"); ++ WLog_Print(log, g_LogLevel, "Reconnect_Return {"); ++ WLog_Print(log, g_LogLevel, " ReturnCode: %s (0x%08" PRIX32 ")", ++ SCardGetErrorString(ret->ReturnCode), ret->ReturnCode); ++ WLog_Print(log, g_LogLevel, " dwActiveProtocol: %s (0x%08" PRIX32 ")", ++ SCardGetProtocolString(ret->dwActiveProtocol), ret->dwActiveProtocol); ++ WLog_Print(log, g_LogLevel, "}"); + } + + static void smartcard_trace_connect_a_call(const ConnectA_Call* call) + { +- +- if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel)) ++ WINPR_ASSERT(call); ++ wLog* log = WLog_Get(TAG); ++ if (!WLog_IsLevelActive(log, g_LogLevel)) + return; + +- WLog_LVL(TAG, g_LogLevel, "ConnectA_Call {"); +- smartcard_log_context(TAG, &call->Common.handles.hContext); ++ WLog_Print(log, g_LogLevel, "ConnectA_Call {"); ++ smartcard_log_context(log, &call->Common.handles.hContext); + +- WLog_LVL(TAG, g_LogLevel, +- "szReader: %s dwShareMode: %s (0x%08" PRIX32 ") dwPreferredProtocols: %s (0x%08" PRIX32 +- ")", +- call->szReader, SCardGetShareModeString(call->Common.dwShareMode), +- call->Common.dwShareMode, SCardGetProtocolString(call->Common.dwPreferredProtocols), +- call->Common.dwPreferredProtocols); +- WLog_LVL(TAG, g_LogLevel, "}"); ++ WLog_Print(log, g_LogLevel, ++ "szReader: %s dwShareMode: %s (0x%08" PRIX32 ++ ") dwPreferredProtocols: %s (0x%08" PRIX32 ")", ++ call->szReader, SCardGetShareModeString(call->Common.dwShareMode), ++ call->Common.dwShareMode, SCardGetProtocolString(call->Common.dwPreferredProtocols), ++ call->Common.dwPreferredProtocols); ++ WLog_Print(log, g_LogLevel, "}"); + } + + static void smartcard_trace_connect_w_call(const ConnectW_Call* call) + { ++ WINPR_ASSERT(call); + char szReaderA[1024] = { 0 }; + +- if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel)) ++ wLog* log = WLog_Get(TAG); ++ if (!WLog_IsLevelActive(log, g_LogLevel)) + return; + + if (call->szReader) + (void)ConvertWCharToUtf8(call->szReader, szReaderA, ARRAYSIZE(szReaderA)); +- WLog_LVL(TAG, g_LogLevel, "ConnectW_Call {"); +- smartcard_log_context(TAG, &call->Common.handles.hContext); +- +- WLog_LVL(TAG, g_LogLevel, +- "szReader: %s dwShareMode: %s (0x%08" PRIX32 ") dwPreferredProtocols: %s (0x%08" PRIX32 +- ")", +- szReaderA, SCardGetShareModeString(call->Common.dwShareMode), call->Common.dwShareMode, +- SCardGetProtocolString(call->Common.dwPreferredProtocols), +- call->Common.dwPreferredProtocols); +- WLog_LVL(TAG, g_LogLevel, "}"); ++ WLog_Print(log, g_LogLevel, "ConnectW_Call {"); ++ smartcard_log_context(log, &call->Common.handles.hContext); ++ ++ WLog_Print(log, g_LogLevel, ++ "szReader: %s dwShareMode: %s (0x%08" PRIX32 ++ ") dwPreferredProtocols: %s (0x%08" PRIX32 ")", ++ szReaderA, SCardGetShareModeString(call->Common.dwShareMode), ++ call->Common.dwShareMode, SCardGetProtocolString(call->Common.dwPreferredProtocols), ++ call->Common.dwPreferredProtocols); ++ WLog_Print(log, g_LogLevel, "}"); + } + + static void smartcard_trace_hcard_and_disposition_call(const HCardAndDisposition_Call* call, + const char* name) + { +- if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel)) ++ WINPR_ASSERT(call); ++ wLog* log = WLog_Get(TAG); ++ if (!WLog_IsLevelActive(log, g_LogLevel)) + return; + +- WLog_LVL(TAG, g_LogLevel, "%s_Call {", name); +- smartcard_log_context(TAG, &call->handles.hContext); +- smartcard_log_redir_handle(TAG, &call->handles.hCard); ++ WLog_Print(log, g_LogLevel, "%s_Call {", name); ++ smartcard_log_context(log, &call->handles.hContext); ++ smartcard_log_redir_handle(log, &call->handles.hCard); + +- WLog_LVL(TAG, g_LogLevel, "dwDisposition: %s (0x%08" PRIX32 ")", +- SCardGetDispositionString(call->dwDisposition), call->dwDisposition); +- WLog_LVL(TAG, g_LogLevel, "}"); ++ WLog_Print(log, g_LogLevel, "dwDisposition: %s (0x%08" PRIX32 ")", ++ SCardGetDispositionString(call->dwDisposition), call->dwDisposition); ++ WLog_Print(log, g_LogLevel, "}"); + } + + static void smartcard_trace_establish_context_call(const EstablishContext_Call* call) + { +- +- if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel)) ++ WINPR_ASSERT(call); ++ wLog* log = WLog_Get(TAG); ++ if (!WLog_IsLevelActive(log, g_LogLevel)) + return; + +- WLog_LVL(TAG, g_LogLevel, "EstablishContext_Call {"); +- WLog_LVL(TAG, g_LogLevel, "dwScope: %s (0x%08" PRIX32 ")", SCardGetScopeString(call->dwScope), +- call->dwScope); +- WLog_LVL(TAG, g_LogLevel, "}"); ++ WLog_Print(log, g_LogLevel, "EstablishContext_Call {"); ++ WLog_Print(log, g_LogLevel, "dwScope: %s (0x%08" PRIX32 ")", SCardGetScopeString(call->dwScope), ++ call->dwScope); ++ WLog_Print(log, g_LogLevel, "}"); + } + + static void smartcard_trace_establish_context_return(const EstablishContext_Return* ret) + { +- +- if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel)) ++ WINPR_ASSERT(ret); ++ wLog* log = WLog_Get(TAG); ++ if (!WLog_IsLevelActive(log, g_LogLevel)) + return; + +- WLog_LVL(TAG, g_LogLevel, "EstablishContext_Return {"); +- WLog_LVL(TAG, g_LogLevel, " ReturnCode: %s (0x%08" PRIX32 ")", +- SCardGetErrorString(ret->ReturnCode), ret->ReturnCode); +- smartcard_log_context(TAG, &ret->hContext); ++ WLog_Print(log, g_LogLevel, "EstablishContext_Return {"); ++ WLog_Print(log, g_LogLevel, " ReturnCode: %s (0x%08" PRIX32 ")", ++ SCardGetErrorString(ret->ReturnCode), ret->ReturnCode); ++ smartcard_log_context(log, &ret->hContext); + +- WLog_LVL(TAG, g_LogLevel, "}"); ++ WLog_Print(log, g_LogLevel, "}"); + } + + void smartcard_trace_long_return(const Long_Return* ret, const char* name) + { +- if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel)) ++ WINPR_ASSERT(ret); ++ wLog* log = WLog_Get(TAG); ++ if (!WLog_IsLevelActive(log, g_LogLevel)) + return; + +- WLog_LVL(TAG, g_LogLevel, "%s_Return {", name); +- WLog_LVL(TAG, g_LogLevel, " ReturnCode: %s (0x%08" PRIX32 ")", +- SCardGetErrorString(ret->ReturnCode), ret->ReturnCode); +- WLog_LVL(TAG, g_LogLevel, "}"); ++ WLog_Print(log, g_LogLevel, "%s_Return {", name); ++ WLog_Print(log, g_LogLevel, " ReturnCode: %s (0x%08" PRIX32 ")", ++ SCardGetErrorString(ret->ReturnCode), ret->ReturnCode); ++ WLog_Print(log, g_LogLevel, "}"); + } + + static void smartcard_trace_connect_return(const Connect_Return* ret) + { +- if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel)) ++ WINPR_ASSERT(ret); ++ wLog* log = WLog_Get(TAG); ++ if (!WLog_IsLevelActive(log, g_LogLevel)) + return; + +- WLog_LVL(TAG, g_LogLevel, "Connect_Return {"); +- WLog_LVL(TAG, g_LogLevel, " ReturnCode: %s (0x%08" PRIX32 ")", +- SCardGetErrorString(ret->ReturnCode), ret->ReturnCode); +- smartcard_log_context(TAG, &ret->hContext); +- smartcard_log_redir_handle(TAG, &ret->hCard); ++ WLog_Print(log, g_LogLevel, "Connect_Return {"); ++ WLog_Print(log, g_LogLevel, " ReturnCode: %s (0x%08" PRIX32 ")", ++ SCardGetErrorString(ret->ReturnCode), ret->ReturnCode); ++ smartcard_log_context(log, &ret->hContext); ++ smartcard_log_redir_handle(log, &ret->hCard); + +- WLog_LVL(TAG, g_LogLevel, " dwActiveProtocol: %s (0x%08" PRIX32 ")", +- SCardGetProtocolString(ret->dwActiveProtocol), ret->dwActiveProtocol); +- WLog_LVL(TAG, g_LogLevel, "}"); ++ WLog_Print(log, g_LogLevel, " dwActiveProtocol: %s (0x%08" PRIX32 ")", ++ SCardGetProtocolString(ret->dwActiveProtocol), ret->dwActiveProtocol); ++ WLog_Print(log, g_LogLevel, "}"); + } + + static void smartcard_trace_reconnect_call(const Reconnect_Call* call) + { +- if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel)) ++ WINPR_ASSERT(call); ++ wLog* log = WLog_Get(TAG); ++ if (!WLog_IsLevelActive(log, g_LogLevel)) + return; + +- WLog_LVL(TAG, g_LogLevel, "Reconnect_Call {"); +- smartcard_log_context(TAG, &call->handles.hContext); +- smartcard_log_redir_handle(TAG, &call->handles.hCard); ++ WLog_Print(log, g_LogLevel, "Reconnect_Call {"); ++ smartcard_log_context(log, &call->handles.hContext); ++ smartcard_log_redir_handle(log, &call->handles.hCard); + +- WLog_LVL(TAG, g_LogLevel, +- "dwShareMode: %s (0x%08" PRIX32 ") dwPreferredProtocols: %s (0x%08" PRIX32 +- ") dwInitialization: %s (0x%08" PRIX32 ")", +- SCardGetShareModeString(call->dwShareMode), call->dwShareMode, +- SCardGetProtocolString(call->dwPreferredProtocols), call->dwPreferredProtocols, +- SCardGetDispositionString(call->dwInitialization), call->dwInitialization); +- WLog_LVL(TAG, g_LogLevel, "}"); ++ WLog_Print(log, g_LogLevel, ++ "dwShareMode: %s (0x%08" PRIX32 ") dwPreferredProtocols: %s (0x%08" PRIX32 ++ ") dwInitialization: %s (0x%08" PRIX32 ")", ++ SCardGetShareModeString(call->dwShareMode), call->dwShareMode, ++ SCardGetProtocolString(call->dwPreferredProtocols), call->dwPreferredProtocols, ++ SCardGetDispositionString(call->dwInitialization), call->dwInitialization); ++ WLog_Print(log, g_LogLevel, "}"); + } + + static void smartcard_trace_device_type_id_return(const GetDeviceTypeId_Return* ret) + { +- if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel)) ++ WINPR_ASSERT(ret); ++ wLog* log = WLog_Get(TAG); ++ if (!WLog_IsLevelActive(log, g_LogLevel)) + return; + +- WLog_LVL(TAG, g_LogLevel, "GetDeviceTypeId_Return {"); +- WLog_LVL(TAG, g_LogLevel, " ReturnCode: %s (0x%08" PRIX32 ")", +- SCardGetErrorString(ret->ReturnCode), ret->ReturnCode); +- WLog_LVL(TAG, g_LogLevel, " dwDeviceId=%08" PRIx32, ret->dwDeviceId); ++ WLog_Print(log, g_LogLevel, "GetDeviceTypeId_Return {"); ++ WLog_Print(log, g_LogLevel, " ReturnCode: %s (0x%08" PRIX32 ")", ++ SCardGetErrorString(ret->ReturnCode), ret->ReturnCode); ++ WLog_Print(log, g_LogLevel, " dwDeviceId=%08" PRIx32, ret->dwDeviceId); + +- WLog_LVL(TAG, g_LogLevel, "}"); ++ WLog_Print(log, g_LogLevel, "}"); + } + + static LONG smartcard_unpack_common_context_and_string_a(wStream* s, REDIR_SCARDCONTEXT* phContext, +@@ -1618,6 +1704,7 @@ SCARDCONTEXT smartcard_scard_context_native_from_redir(REDIR_SCARDCONTEXT* conte + { + SCARDCONTEXT hContext = { 0 }; + ++ WINPR_ASSERT(context); + if ((context->cbContext != sizeof(ULONG_PTR)) && (context->cbContext != 0)) + { + WLog_WARN(TAG, +@@ -1645,6 +1732,7 @@ SCARDHANDLE smartcard_scard_handle_native_from_redir(REDIR_SCARDHANDLE* handle) + { + SCARDHANDLE hCard = 0; + ++ WINPR_ASSERT(handle); + if (handle->cbHandle == 0) + return hCard; + +@@ -1722,6 +1810,7 @@ LONG smartcard_pack_redir_scard_context(wStream* s, const REDIR_SCARDCONTEXT* co + { + const UINT32 pbContextNdrPtr = 0x00020000 + *index * 4; + ++ WINPR_ASSERT(context); + if (context->cbContext != 0) + { + Stream_Write_UINT32(s, context->cbContext); /* cbContext (4 bytes) */ +@@ -1774,7 +1863,7 @@ LONG smartcard_unpack_redir_scard_context_ref(wStream* s, WINPR_ATTR_UNUSED UINT + + LONG smartcard_pack_redir_scard_context_ref(wStream* s, const REDIR_SCARDCONTEXT* context) + { +- ++ WINPR_ASSERT(context); + Stream_Write_UINT32(s, context->cbContext); /* Length (4 bytes) */ + + if (context->cbContext) +@@ -1810,6 +1899,7 @@ LONG smartcard_pack_redir_scard_handle(wStream* s, const REDIR_SCARDHANDLE* hand + { + const UINT32 pbContextNdrPtr = 0x00020000 + *index * 4; + ++ WINPR_ASSERT(handle); + if (handle->cbHandle != 0) + { + Stream_Write_UINT32(s, handle->cbHandle); /* cbContext (4 bytes) */ +@@ -1825,6 +1915,7 @@ LONG smartcard_unpack_redir_scard_handle_ref(wStream* s, REDIR_SCARDHANDLE* hand + { + UINT32 length = 0; + ++ WINPR_ASSERT(handle); + if (!Stream_CheckAndLogRequiredLength(TAG, s, 4)) + return STATUS_BUFFER_TOO_SMALL; + +@@ -1854,7 +1945,7 @@ LONG smartcard_unpack_redir_scard_handle_ref(wStream* s, REDIR_SCARDHANDLE* hand + + LONG smartcard_pack_redir_scard_handle_ref(wStream* s, const REDIR_SCARDHANDLE* handle) + { +- ++ WINPR_ASSERT(handle); + Stream_Write_UINT32(s, handle->cbHandle); /* Length (4 bytes) */ + + if (handle->cbHandle) +@@ -1865,6 +1956,7 @@ LONG smartcard_pack_redir_scard_handle_ref(wStream* s, const REDIR_SCARDHANDLE* + + LONG smartcard_unpack_establish_context_call(wStream* s, EstablishContext_Call* call) + { ++ WINPR_ASSERT(call); + if (!Stream_CheckAndLogRequiredLength(TAG, s, 4)) + return STATUS_BUFFER_TOO_SMALL; + +@@ -1875,6 +1967,7 @@ LONG smartcard_unpack_establish_context_call(wStream* s, EstablishContext_Call* + + LONG smartcard_pack_establish_context_return(wStream* s, const EstablishContext_Return* ret) + { ++ WINPR_ASSERT(ret); + LONG status = 0; + DWORD index = 0; + +@@ -1893,6 +1986,7 @@ LONG smartcard_unpack_context_call(wStream* s, Context_Call* call, const char* n + UINT32 index = 0; + UINT32 pbContextNdrPtr = 0; + ++ WINPR_ASSERT(call); + LONG status = smartcard_unpack_redir_scard_context(s, &(call->handles.hContext), &index, + &pbContextNdrPtr); + if (status != SCARD_S_SUCCESS) +@@ -1912,6 +2006,7 @@ LONG smartcard_unpack_list_reader_groups_call(wStream* s, ListReaderGroups_Call* + UINT32 index = 0; + UINT32 pbContextNdrPtr = 0; + ++ WINPR_ASSERT(call); + LONG status = smartcard_unpack_redir_scard_context(s, &(call->handles.hContext), &index, + &pbContextNdrPtr); + +@@ -1936,6 +2031,7 @@ LONG smartcard_unpack_list_reader_groups_call(wStream* s, ListReaderGroups_Call* + LONG smartcard_pack_list_reader_groups_return(wStream* s, const ListReaderGroups_Return* ret, + BOOL unicode) + { ++ WINPR_ASSERT(ret); + LONG status = 0; + DWORD cBytes = ret->cBytes; + UINT32 index = 0; +@@ -1965,6 +2061,7 @@ LONG smartcard_unpack_list_readers_call(wStream* s, ListReaders_Call* call, BOOL + UINT32 mszGroupsNdrPtr = 0; + UINT32 pbContextNdrPtr = 0; + ++ WINPR_ASSERT(call); + call->mszGroups = NULL; + + LONG status = smartcard_unpack_redir_scard_context(s, &(call->handles.hContext), &index, +@@ -1998,6 +2095,7 @@ LONG smartcard_unpack_list_readers_call(wStream* s, ListReaders_Call* call, BOOL + + LONG smartcard_pack_list_readers_return(wStream* s, const ListReaders_Return* ret, BOOL unicode) + { ++ WINPR_ASSERT(ret); + LONG status = 0; + UINT32 index = 0; + UINT32 size = ret->cBytes; +@@ -2025,6 +2123,7 @@ LONG smartcard_pack_list_readers_return(wStream* s, const ListReaders_Return* re + static LONG smartcard_unpack_connect_common(wStream* s, Connect_Common_Call* common, UINT32* index, + UINT32* ppbContextNdrPtr) + { ++ WINPR_ASSERT(common); + LONG status = smartcard_unpack_redir_scard_context(s, &(common->handles.hContext), index, + ppbContextNdrPtr); + if (status != SCARD_S_SUCCESS) +@@ -2043,6 +2142,8 @@ LONG smartcard_unpack_connect_a_call(wStream* s, ConnectA_Call* call) + LONG status = 0; + UINT32 index = 0; + UINT32 pbContextNdrPtr = 0; ++ ++ WINPR_ASSERT(call); + call->szReader = NULL; + + if (!smartcard_ndr_pointer_read(s, &index, NULL)) +@@ -2073,6 +2174,7 @@ LONG smartcard_unpack_connect_w_call(wStream* s, ConnectW_Call* call) + UINT32 index = 0; + UINT32 pbContextNdrPtr = 0; + ++ WINPR_ASSERT(call); + call->szReader = NULL; + + if (!smartcard_ndr_pointer_read(s, &index, NULL)) +@@ -2102,6 +2204,7 @@ LONG smartcard_pack_connect_return(wStream* s, const Connect_Return* ret) + LONG status = 0; + DWORD index = 0; + ++ WINPR_ASSERT(ret); + smartcard_trace_connect_return(ret); + + status = smartcard_pack_redir_scard_context(s, &ret->hContext, &index); +@@ -2126,6 +2229,8 @@ LONG smartcard_unpack_reconnect_call(wStream* s, Reconnect_Call* call) + { + UINT32 index = 0; + UINT32 pbContextNdrPtr = 0; ++ ++ WINPR_ASSERT(call); + LONG status = smartcard_unpack_redir_scard_context(s, &(call->handles.hContext), &index, + &pbContextNdrPtr); + if (status != SCARD_S_SUCCESS) +@@ -2160,6 +2265,7 @@ LONG smartcard_unpack_reconnect_call(wStream* s, Reconnect_Call* call) + + LONG smartcard_pack_reconnect_return(wStream* s, const Reconnect_Return* ret) + { ++ WINPR_ASSERT(ret); + smartcard_trace_reconnect_return(ret); + + if (!Stream_EnsureRemainingCapacity(s, 4)) +@@ -2174,6 +2280,7 @@ LONG smartcard_unpack_hcard_and_disposition_call(wStream* s, HCardAndDisposition + UINT32 index = 0; + UINT32 pbContextNdrPtr = 0; + ++ WINPR_ASSERT(call); + LONG status = smartcard_unpack_redir_scard_context(s, &(call->handles.hContext), &index, + &pbContextNdrPtr); + if (status != SCARD_S_SUCCESS) +@@ -2201,31 +2308,20 @@ LONG smartcard_unpack_hcard_and_disposition_call(wStream* s, HCardAndDisposition + + static void smartcard_trace_get_status_change_a_call(const GetStatusChangeA_Call* call) + { +- if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel)) ++ WINPR_ASSERT(call); ++ wLog* log = WLog_Get(TAG); ++ if (!WLog_IsLevelActive(log, g_LogLevel)) + return; + +- WLog_LVL(TAG, g_LogLevel, "GetStatusChangeA_Call {"); +- smartcard_log_context(TAG, &call->handles.hContext); ++ WLog_Print(log, g_LogLevel, "GetStatusChangeA_Call {"); ++ smartcard_log_context(log, &call->handles.hContext); + +- WLog_LVL(TAG, g_LogLevel, "dwTimeOut: 0x%08" PRIX32 " cReaders: %" PRIu32 "", call->dwTimeOut, +- call->cReaders); ++ WLog_Print(log, g_LogLevel, "dwTimeOut: 0x%08" PRIX32 " cReaders: %" PRIu32 "", call->dwTimeOut, ++ call->cReaders); + +- for (UINT32 index = 0; index < call->cReaders; index++) +- { +- LPSCARD_READERSTATEA readerState = &call->rgReaderStates[index]; +- WLog_LVL(TAG, g_LogLevel, "\t[%" PRIu32 "]: szReader: %s cbAtr: %" PRIu32 "", index, +- readerState->szReader, readerState->cbAtr); +- char* szCurrentState = SCardGetReaderStateString(readerState->dwCurrentState); +- char* szEventState = SCardGetReaderStateString(readerState->dwEventState); +- WLog_LVL(TAG, g_LogLevel, "\t[%" PRIu32 "]: dwCurrentState: %s (0x%08" PRIX32 ")", index, +- szCurrentState, readerState->dwCurrentState); +- WLog_LVL(TAG, g_LogLevel, "\t[%" PRIu32 "]: dwEventState: %s (0x%08" PRIX32 ")", index, +- szEventState, readerState->dwEventState); +- free(szCurrentState); +- free(szEventState); +- } ++ dump_reader_states_a(log, call->rgReaderStates, call->cReaders); + +- WLog_LVL(TAG, g_LogLevel, "}"); ++ WLog_Print(log, g_LogLevel, "}"); + } + + static LONG smartcard_unpack_reader_state_a(wStream* s, LPSCARD_READERSTATEA* ppcReaders, +@@ -2233,6 +2329,7 @@ static LONG smartcard_unpack_reader_state_a(wStream* s, LPSCARD_READERSTATEA* pp + { + LONG status = SCARD_E_NO_MEMORY; + ++ WINPR_ASSERT(ppcReaders || (cReaders == 0)); + if (!Stream_CheckAndLogRequiredLength(TAG, s, 4)) + return status; + +@@ -2305,6 +2402,7 @@ static LONG smartcard_unpack_reader_state_w(wStream* s, LPSCARD_READERSTATEW* pp + { + LONG status = SCARD_E_NO_MEMORY; + ++ WINPR_ASSERT(ppcReaders || (cReaders == 0)); + if (!Stream_CheckAndLogRequiredLength(TAG, s, 4)) + return status; + +@@ -2384,6 +2482,7 @@ LONG smartcard_unpack_get_status_change_a_call(wStream* s, GetStatusChangeA_Call + UINT32 index = 0; + UINT32 pbContextNdrPtr = 0; + ++ WINPR_ASSERT(call); + call->rgReaderStates = NULL; + + LONG status = smartcard_unpack_redir_scard_context(s, &(call->handles.hContext), &index, +@@ -2420,6 +2519,7 @@ LONG smartcard_unpack_get_status_change_w_call(wStream* s, GetStatusChangeW_Call + UINT32 index = 0; + UINT32 pbContextNdrPtr = 0; + ++ WINPR_ASSERT(call); + call->rgReaderStates = NULL; + + LONG status = smartcard_unpack_redir_scard_context(s, &(call->handles.hContext), &index, +@@ -2481,6 +2581,8 @@ LONG smartcard_unpack_state_call(wStream* s, State_Call* call) + { + UINT32 index = 0; + UINT32 pbContextNdrPtr = 0; ++ ++ WINPR_ASSERT(call); + LONG status = smartcard_unpack_redir_scard_context(s, &(call->handles.hContext), &index, + &pbContextNdrPtr); + if (status != SCARD_S_SUCCESS) +@@ -2508,6 +2610,7 @@ LONG smartcard_unpack_state_call(wStream* s, State_Call* call) + + LONG smartcard_pack_state_return(wStream* s, const State_Return* ret) + { ++ WINPR_ASSERT(ret); + LONG status = 0; + DWORD cbAtrLen = ret->cbAtrLen; + UINT32 index = 0; +@@ -2534,6 +2637,7 @@ LONG smartcard_unpack_status_call(wStream* s, Status_Call* call, BOOL unicode) + UINT32 index = 0; + UINT32 pbContextNdrPtr = 0; + ++ WINPR_ASSERT(call); + LONG status = smartcard_unpack_redir_scard_context(s, &(call->handles.hContext), &index, + &pbContextNdrPtr); + if (status != SCARD_S_SUCCESS) +@@ -2563,6 +2667,7 @@ LONG smartcard_unpack_status_call(wStream* s, Status_Call* call, BOOL unicode) + + LONG smartcard_pack_status_return(wStream* s, const Status_Return* ret, BOOL unicode) + { ++ WINPR_ASSERT(ret); + LONG status = 0; + UINT32 index = 0; + DWORD cBytes = ret->cBytes; +@@ -2595,6 +2700,7 @@ LONG smartcard_pack_status_return(wStream* s, const Status_Return* ret, BOOL uni + + LONG smartcard_unpack_get_attrib_call(wStream* s, GetAttrib_Call* call) + { ++ WINPR_ASSERT(call); + UINT32 index = 0; + UINT32 pbContextNdrPtr = 0; + +@@ -2628,6 +2734,7 @@ LONG smartcard_unpack_get_attrib_call(wStream* s, GetAttrib_Call* call) + LONG smartcard_pack_get_attrib_return(wStream* s, const GetAttrib_Return* ret, DWORD dwAttrId, + DWORD cbAttrCallLen) + { ++ WINPR_ASSERT(ret); + LONG status = 0; + DWORD cbAttrLen = 0; + UINT32 index = 0; +@@ -2659,6 +2766,7 @@ LONG smartcard_pack_get_attrib_return(wStream* s, const GetAttrib_Return* ret, D + + LONG smartcard_unpack_control_call(wStream* s, Control_Call* call) + { ++ WINPR_ASSERT(call); + UINT32 index = 0; + UINT32 pvInBufferNdrPtr = 0; + UINT32 pbContextNdrPtr = 0; +@@ -2704,6 +2812,7 @@ LONG smartcard_unpack_control_call(wStream* s, Control_Call* call) + + LONG smartcard_pack_control_return(wStream* s, const Control_Return* ret) + { ++ WINPR_ASSERT(ret); + LONG status = 0; + DWORD cbDataLen = ret->cbOutBufferSize; + UINT32 index = 0; +@@ -2739,6 +2848,7 @@ LONG smartcard_unpack_transmit_call(wStream* s, Transmit_Call* call) + UINT32 index = 0; + UINT32 pbContextNdrPtr = 0; + ++ WINPR_ASSERT(call); + call->pioSendPci = NULL; + call->pioRecvPci = NULL; + call->pbSendBuffer = NULL; +@@ -2935,6 +3045,7 @@ LONG smartcard_unpack_transmit_call(wStream* s, Transmit_Call* call) + + LONG smartcard_pack_transmit_return(wStream* s, const Transmit_Return* ret) + { ++ WINPR_ASSERT(ret); + LONG status = 0; + UINT32 index = 0; + LONG error = 0; +@@ -2987,6 +3098,7 @@ LONG smartcard_unpack_locate_cards_by_atr_a_call(wStream* s, LocateCardsByATRA_C + UINT32 index = 0; + UINT32 pbContextNdrPtr = 0; + ++ WINPR_ASSERT(call); + call->rgReaderStates = NULL; + + LONG status = smartcard_unpack_redir_scard_context(s, &(call->handles.hContext), &index, +@@ -3042,6 +3154,7 @@ LONG smartcard_unpack_context_and_two_strings_a_call(wStream* s, ContextAndTwoSt + UINT32 index = 0; + UINT32 pbContextNdrPtr = 0; + ++ WINPR_ASSERT(call); + LONG status = smartcard_unpack_redir_scard_context(s, &(call->handles.hContext), &index, + &pbContextNdrPtr); + if (status != SCARD_S_SUCCESS) +@@ -3079,6 +3192,7 @@ LONG smartcard_unpack_context_and_two_strings_w_call(wStream* s, ContextAndTwoSt + UINT32 index = 0; + UINT32 pbContextNdrPtr = 0; + ++ WINPR_ASSERT(call); + LONG status = smartcard_unpack_redir_scard_context(s, &(call->handles.hContext), &index, + &pbContextNdrPtr); + if (status != SCARD_S_SUCCESS) +@@ -3116,6 +3230,7 @@ LONG smartcard_unpack_locate_cards_a_call(wStream* s, LocateCardsA_Call* call) + UINT32 index = 0; + UINT32 pbContextNdrPtr = 0; + ++ WINPR_ASSERT(call); + LONG status = smartcard_unpack_redir_scard_context(s, &(call->handles.hContext), &index, + &pbContextNdrPtr); + if (status != SCARD_S_SUCCESS) +@@ -3160,6 +3275,7 @@ LONG smartcard_unpack_locate_cards_w_call(wStream* s, LocateCardsW_Call* call) + UINT32 index = 0; + UINT32 pbContextNdrPtr = 0; + ++ WINPR_ASSERT(call); + LONG status = smartcard_unpack_redir_scard_context(s, &(call->handles.hContext), &index, + &pbContextNdrPtr); + if (status != SCARD_S_SUCCESS) +@@ -3203,6 +3319,7 @@ LONG smartcard_unpack_set_attrib_call(wStream* s, SetAttrib_Call* call) + UINT32 ndrPtr = 0; + UINT32 pbContextNdrPtr = 0; + ++ WINPR_ASSERT(call); + LONG status = smartcard_unpack_redir_scard_context(s, &(call->handles.hContext), &index, + &pbContextNdrPtr); + if (status != SCARD_S_SUCCESS) +@@ -3245,6 +3362,7 @@ LONG smartcard_unpack_locate_cards_by_atr_w_call(wStream* s, LocateCardsByATRW_C + UINT32 index = 0; + UINT32 pbContextNdrPtr = 0; + ++ WINPR_ASSERT(call); + call->rgReaderStates = NULL; + + LONG status = smartcard_unpack_redir_scard_context(s, &(call->handles.hContext), &index, +@@ -3301,6 +3419,7 @@ LONG smartcard_unpack_read_cache_a_call(wStream* s, ReadCacheA_Call* call) + UINT32 index = 0; + UINT32 pbContextNdrPtr = 0; + ++ WINPR_ASSERT(call); + if (!smartcard_ndr_pointer_read(s, &index, &mszNdrPtr)) + return ERROR_INVALID_DATA; + +@@ -3348,6 +3467,7 @@ LONG smartcard_unpack_read_cache_w_call(wStream* s, ReadCacheW_Call* call) + UINT32 index = 0; + UINT32 pbContextNdrPtr = 0; + ++ WINPR_ASSERT(call); + if (!smartcard_ndr_pointer_read(s, &index, &mszNdrPtr)) + return ERROR_INVALID_DATA; + +@@ -3396,6 +3516,7 @@ LONG smartcard_unpack_write_cache_a_call(wStream* s, WriteCacheA_Call* call) + UINT32 index = 0; + UINT32 pbContextNdrPtr = 0; + ++ WINPR_ASSERT(call); + if (!smartcard_ndr_pointer_read(s, &index, &mszNdrPtr)) + return ERROR_INVALID_DATA; + +@@ -3457,6 +3578,8 @@ LONG smartcard_unpack_write_cache_w_call(wStream* s, WriteCacheW_Call* call) + UINT32 index = 0; + UINT32 pbContextNdrPtr = 0; + ++ WINPR_ASSERT(call); ++ + if (!smartcard_ndr_pointer_read(s, &index, &mszNdrPtr)) + return ERROR_INVALID_DATA; + +@@ -3511,6 +3634,7 @@ LONG smartcard_unpack_write_cache_w_call(wStream* s, WriteCacheW_Call* call) + + LONG smartcard_unpack_get_transmit_count_call(wStream* s, GetTransmitCount_Call* call) + { ++ WINPR_ASSERT(call); + UINT32 index = 0; + UINT32 pbContextNdrPtr = 0; + +@@ -3541,28 +3665,33 @@ LONG smartcard_unpack_get_transmit_count_call(wStream* s, GetTransmitCount_Call* + + LONG smartcard_unpack_get_reader_icon_call(wStream* s, GetReaderIcon_Call* call) + { ++ WINPR_ASSERT(call); + return smartcard_unpack_common_context_and_string_w(s, &call->handles.hContext, + &call->szReaderName); + } + + LONG smartcard_unpack_context_and_string_a_call(wStream* s, ContextAndStringA_Call* call) + { ++ WINPR_ASSERT(call); + return smartcard_unpack_common_context_and_string_a(s, &call->handles.hContext, &call->sz); + } + + LONG smartcard_unpack_context_and_string_w_call(wStream* s, ContextAndStringW_Call* call) + { ++ WINPR_ASSERT(call); + return smartcard_unpack_common_context_and_string_w(s, &call->handles.hContext, &call->sz); + } + + LONG smartcard_unpack_get_device_type_id_call(wStream* s, GetDeviceTypeId_Call* call) + { ++ WINPR_ASSERT(call); + return smartcard_unpack_common_context_and_string_w(s, &call->handles.hContext, + &call->szReaderName); + } + + LONG smartcard_pack_device_type_id_return(wStream* s, const GetDeviceTypeId_Return* ret) + { ++ WINPR_ASSERT(ret); + smartcard_trace_device_type_id_return(ret); + + if (!Stream_EnsureRemainingCapacity(s, 4)) +@@ -3578,6 +3707,8 @@ LONG smartcard_pack_device_type_id_return(wStream* s, const GetDeviceTypeId_Retu + + LONG smartcard_pack_locate_cards_return(wStream* s, const LocateCards_Return* ret) + { ++ WINPR_ASSERT(ret); ++ + LONG status = 0; + DWORD cbDataLen = ret->cReaders; + UINT32 index = 0; +@@ -3606,6 +3737,8 @@ LONG smartcard_pack_locate_cards_return(wStream* s, const LocateCards_Return* re + + LONG smartcard_pack_get_reader_icon_return(wStream* s, const GetReaderIcon_Return* ret) + { ++ WINPR_ASSERT(ret); ++ + LONG status = 0; + UINT32 index = 0; + DWORD cbDataLen = ret->cbDataLen; +@@ -3633,6 +3766,7 @@ LONG smartcard_pack_get_reader_icon_return(wStream* s, const GetReaderIcon_Retur + + LONG smartcard_pack_get_transmit_count_return(wStream* s, const GetTransmitCount_Return* ret) + { ++ WINPR_ASSERT(ret); + smartcard_trace_get_transmit_count_return(ret); + + if (!Stream_EnsureRemainingCapacity(s, 4)) +@@ -3648,6 +3782,8 @@ LONG smartcard_pack_get_transmit_count_return(wStream* s, const GetTransmitCount + + LONG smartcard_pack_read_cache_return(wStream* s, const ReadCache_Return* ret) + { ++ WINPR_ASSERT(ret); ++ + LONG status = 0; + UINT32 index = 0; + DWORD cbDataLen = ret->cbDataLen; +-- +2.47.3 + diff -Nru freerdp3-3.15.0+dfsg/debian/patches/warnings-Fix-format-string-errors-partial.patch freerdp3-3.15.0+dfsg/debian/patches/warnings-Fix-format-string-errors-partial.patch --- freerdp3-3.15.0+dfsg/debian/patches/warnings-Fix-format-string-errors-partial.patch 1970-01-01 00:00:00.000000000 +0000 +++ freerdp3-3.15.0+dfsg/debian/patches/warnings-Fix-format-string-errors-partial.patch 2026-02-25 20:31:28.000000000 +0000 @@ -0,0 +1,1515 @@ +From: akallabeth +Date: Wed, 13 Aug 2025 09:00:25 +0200 +Subject: [warnings] Fix format string errors +Origin: upstream, https://github.com/FreeRDP/FreeRDP/commit/65f18983edfcfbf02614273f2b9da405f96562fe +Forwarded: not-needed +Comment: after winpr-wlog-Add-specialized-text-log-functions.patch, a lot of issues + has been identified and fixed in usage of printf-format-strings. This is a partial + upstream commit, with only hunks which can be applied to 3.15 are left, and hunks + which don't apply, were deleted. Diffstat is for the original upstream patch. + +* Fix casts of format string arguments (%p requires void*) +* Fix format string to match type of arguments +--- + channels/audin/client/alsa/audin_alsa.c | 4 +- + channels/audin/client/audin_main.c | 2 +- + channels/audin/server/audin.c | 2 +- + channels/cliprdr/client/cliprdr_format.c | 4 +- + channels/cliprdr/client/cliprdr_main.c | 6 +- + channels/drdynvc/client/drdynvc_main.c | 32 ++++- + channels/parallel/client/parallel_main.c | 2 +- + channels/rdpdr/client/rdpdr_main.c | 3 +- + channels/rdpdr/server/rdpdr_main.c | 20 +-- + channels/rdpear/common/rdpear_common.c | 2 +- + channels/rdpsnd/client/rdpsnd_main.c | 2 +- + channels/serial/client/serial_main.c | 4 +- + channels/urbdrc/client/data_transfer.c | 9 +- + channels/urbdrc/client/urbdrc_main.c | 3 +- + client/SDL/SDL3/sdl_clip.cpp | 2 +- + client/X11/xf_keyboard.c | 5 +- + client/X11/xf_utils.c | 146 +++++++++---------- + client/common/client_cliprdr_file.c | 8 +- + libfreerdp/codec/dsp.c | 4 +- + libfreerdp/codec/progressive.c | 25 ++-- + libfreerdp/codec/rfx.c | 12 +- + libfreerdp/common/assistance.c | 6 +- + libfreerdp/core/aad.c | 4 +- + libfreerdp/core/autodetect.c | 6 +- + libfreerdp/core/capabilities.c | 27 ++-- + libfreerdp/core/gateway/arm.c | 4 +- + libfreerdp/core/gateway/rdg.c | 7 +- + libfreerdp/core/gateway/rpc_client.c | 2 +- + libfreerdp/core/gateway/rts.c | 18 +-- + libfreerdp/core/gateway/tsg.c | 2 +- + libfreerdp/core/gcc.c | 4 +- + libfreerdp/core/license.c | 27 ++-- + libfreerdp/core/orders.c | 10 +- + libfreerdp/core/rdp.c | 20 +-- + libfreerdp/core/rdstls.c | 29 ++-- + libfreerdp/core/tpkt.c | 4 +- + libfreerdp/core/transport.c | 15 +- + libfreerdp/core/window.c | 4 +- + libfreerdp/emu/scard/smartcard_emulate.c | 157 +++++++++++---------- + libfreerdp/utils/smartcard_call.c | 7 +- + libfreerdp/utils/smartcard_pack.c | 79 +++++++---- + server/proxy/channels/pf_channel_drdynvc.c | 4 +- + server/proxy/channels/pf_channel_rdpdr.c | 4 +- + winpr/libwinpr/comm/comm.c | 8 +- + winpr/libwinpr/comm/comm_ioctl.c | 2 +- + winpr/libwinpr/comm/comm_serial_sys.c | 4 +- + winpr/libwinpr/ncrypt/ncrypt_pkcs11.c | 3 +- + winpr/libwinpr/sspi/sspi.c | 60 ++++---- + winpr/libwinpr/timezone/timezone.c | 6 +- + winpr/libwinpr/utils/print.c | 2 +- + winpr/libwinpr/utils/stream.c | 2 +- + 51 files changed, 439 insertions(+), 385 deletions(-) + +diff --git a/channels/audin/client/alsa/audin_alsa.c b/channels/audin/client/alsa/audin_alsa.c +index 82ce66e64..96649568b 100644 +--- a/channels/audin/client/alsa/audin_alsa.c ++++ b/channels/audin/client/alsa/audin_alsa.c +@@ -195,4 +195,4 @@ static DWORD WINAPI audin_alsa_thread_func(LPVOID arg) + { +- WLog_Print(alsa->log, WLOG_ERROR, "audin_alsa_thread_receive failed with error %ld", +- error); ++ WLog_Print(alsa->log, WLOG_ERROR, ++ "audin_alsa_thread_receive failed with error %" PRIu32, error); + break; +diff --git a/channels/audin/client/audin_main.c b/channels/audin/client/audin_main.c +index eaf7281d0..d3676b96f 100644 +--- a/channels/audin/client/audin_main.c ++++ b/channels/audin/client/audin_main.c +@@ -388,3 +388,3 @@ static UINT audin_receive_wave_data(const AUDIO_FORMAT* format, const BYTE* data + audio_format_print(audin->log, WLOG_TRACE, audin->format); +- WLog_Print(audin->log, WLOG_TRACE, "[%" PRIdz "/%" PRIdz "]", size, ++ WLog_Print(audin->log, WLOG_TRACE, "[%" PRIuz "/%" PRIuz "]", size, + Stream_GetPosition(audin->data) - 1); +diff --git a/channels/audin/server/audin.c b/channels/audin/server/audin.c +index f32ac5e5d..73e5fbb5d 100644 +--- a/channels/audin/server/audin.c ++++ b/channels/audin/server/audin.c +@@ -816,3 +816,3 @@ static UINT audin_server_open_reply_default(audin_server_context* context, + /* TODO: Implement failure handling */ +- WLog_Print(audin->log, WLOG_DEBUG, "Open Reply PDU: Result: %i", open_reply->Result); ++ WLog_Print(audin->log, WLOG_DEBUG, "Open Reply PDU: Result: %" PRIu32, open_reply->Result); + return CHANNEL_RC_OK; +diff --git a/channels/cliprdr/client/cliprdr_format.c b/channels/cliprdr/client/cliprdr_format.c +index 6c0415438..c76e3b6e3 100644 +--- a/channels/cliprdr/client/cliprdr_format.c ++++ b/channels/cliprdr/client/cliprdr_format.c +@@ -142,3 +142,3 @@ UINT cliprdr_process_format_list(cliprdrPlugin* cliprdr, wStream* s, UINT32 data + const CLIPRDR_FORMAT* format = &formatList.formats[x]; +- WLog_Print(cliprdr->log, level, "[%" PRIu32 "]: id=0x%08" PRIx32 " [%s|%s]", x, ++ WLog_Print(cliprdr->log, level, "[%" PRIuz "]: id=0x%08" PRIx32 " [%s|%s]", x, + format->formatId, ClipboardGetFormatIdString(format->formatId), +@@ -152,3 +152,3 @@ UINT cliprdr_process_format_list(cliprdrPlugin* cliprdr, wStream* s, UINT32 data + const CLIPRDR_FORMAT* format = &filteredFormatList.formats[x]; +- WLog_Print(cliprdr->log, level, "[%" PRIu32 "]: id=0x%08" PRIx32 " [%s|%s]", x, ++ WLog_Print(cliprdr->log, level, "[%" PRIuz "]: id=0x%08" PRIx32 " [%s|%s]", x, + format->formatId, ClipboardGetFormatIdString(format->formatId), +diff --git a/channels/cliprdr/client/cliprdr_main.c b/channels/cliprdr/client/cliprdr_main.c +index 613a5247d..5a9c40a88 100644 +--- a/channels/cliprdr/client/cliprdr_main.c ++++ b/channels/cliprdr/client/cliprdr_main.c +@@ -68,3 +68,3 @@ static UINT cliprdr_packet_send(cliprdrPlugin* cliprdr, wStream* s) + const size_t pos = Stream_GetPosition(s); +- const size_t dataLen = pos - 8; ++ const size_t dataLen = pos - 8ULL; + WINPR_ASSERT(dataLen <= UINT32_MAX); +@@ -75,3 +75,3 @@ static UINT cliprdr_packet_send(cliprdrPlugin* cliprdr, wStream* s) + +- WLog_Print(cliprdr->log, WLOG_DEBUG, "Cliprdr Sending (%" PRIu32 " bytes)", dataLen + 8); ++ WLog_Print(cliprdr->log, WLOG_DEBUG, "Cliprdr Sending (%" PRIuz " bytes)", dataLen + 8UL); + +@@ -702,3 +702,3 @@ static UINT cliprdr_client_format_list(CliprdrClientContext* context, + const CLIPRDR_FORMAT* format = &filterList.formats[x]; +- WLog_Print(cliprdr->log, level, "[%" PRIu32 "]: id=0x%08" PRIx32 " [%s|%s]", x, ++ WLog_Print(cliprdr->log, level, "[%" PRIuz "]: id=0x%08" PRIx32 " [%s|%s]", x, + format->formatId, ClipboardGetFormatIdString(format->formatId), +diff --git a/channels/drdynvc/client/drdynvc_main.c b/channels/drdynvc/client/drdynvc_main.c +index 65dc5fd4f..5a970909c 100644 +--- a/channels/drdynvc/client/drdynvc_main.c ++++ b/channels/drdynvc/client/drdynvc_main.c +@@ -36,2 +36,17 @@ + ++static const char* channel_state2str(DVC_CHANNEL_STATE state) ++{ ++ switch (state) ++ { ++ case DVC_CHANNEL_INIT: ++ return "DVC_CHANNEL_INIT"; ++ case DVC_CHANNEL_RUNNING: ++ return "DVC_CHANNEL_RUNNING"; ++ case DVC_CHANNEL_CLOSED: ++ return "DVC_CHANNEL_CLOSED"; ++ default: ++ return "DVC_CHANNEL_UNKNOWN"; ++ } ++} ++ + static void dvcman_channel_free(DVCMAN_CHANNEL* channel); +@@ -476,7 +491,10 @@ static UINT dvcman_channel_close(DVCMAN_CHANNEL* channel, BOOL perRequest, BOOL + { +- const char* msg = "error when sending close confirm for '%s'"; + if (perRequest) +- msg = "error when sending closeRequest for '%s'"; +- +- WLog_Print(drdynvc->log, WLOG_DEBUG, msg, channel->channel_name); ++ WLog_Print(drdynvc->log, WLOG_DEBUG, ++ "error when sending closeRequest for '%s'", ++ channel->channel_name); ++ else ++ WLog_Print(drdynvc->log, WLOG_DEBUG, ++ "error when sending close confirm for '%s'", ++ channel->channel_name); + } +@@ -690,6 +708,8 @@ static DVCMAN_CHANNEL* dvcman_create_channel(drdynvcPlugin* drdynvc, + default: +- WLog_Print(drdynvc->log, WLOG_ERROR, "not expecting a createChannel from state %d", +- channel->state); ++ { ++ WLog_Print(drdynvc->log, WLOG_ERROR, "not expecting a createChannel from state %s", ++ channel_state2str(channel->state)); + *res = CHANNEL_RC_INITIALIZATION_ERROR; + goto out; ++ } + } +diff --git a/channels/parallel/client/parallel_main.c b/channels/parallel/client/parallel_main.c +index 44d7a23fc..59ff9a08e 100644 +--- a/channels/parallel/client/parallel_main.c ++++ b/channels/parallel/client/parallel_main.c +@@ -318,3 +318,3 @@ static UINT parallel_process_irp(PARALLEL_DEVICE* parallel, IRP* irp) + rdpdr_irp_string(irp->MajorFunction), irp->MajorFunction, WTSErrorToString(error), +- error, NtStatus2Tag(irp->IoStatus), irp->IoStatus); ++ error, NtStatus2Tag(irp->IoStatus), WINPR_CXX_COMPAT_CAST(UINT32, irp->IoStatus)); + +diff --git a/channels/rdpdr/client/rdpdr_main.c b/channels/rdpdr/client/rdpdr_main.c +index 66b6b7a9a..efed61ac0 100644 +--- a/channels/rdpdr/client/rdpdr_main.c ++++ b/channels/rdpdr/client/rdpdr_main.c +@@ -1456,4 +1456,3 @@ static BOOL device_announce(ULONG_PTR key, void* element, void* data) + WLog_Print(rdpdr->log, WLOG_INFO, +- "registered [%09s] device #%" PRIu32 ": %05s (type=%2" PRIu32 " id=%2" PRIu32 +- ")", ++ "registered [%9s] device #%" PRIu32 ": %5s (type=%2" PRIu32 " id=%2" PRIu32 ")", + rdpdr_device_type_string(device->type), arg->count, device->name, device->type, +diff --git a/channels/rdpdr/server/rdpdr_main.c b/channels/rdpdr/server/rdpdr_main.c +index 48c3e486a..cd31fcbb1 100644 +--- a/channels/rdpdr/server/rdpdr_main.c ++++ b/channels/rdpdr/server/rdpdr_main.c +@@ -227,3 +227,3 @@ static const WCHAR* rdpdr_read_ustring(wLog* log, wStream* s, size_t bytelen) + { +- WLog_Print(log, WLOG_WARN, "[rdpdr] unicode string not '\0' terminated"); ++ WLog_Print(log, WLOG_WARN, "[rdpdr] unicode string not '\\0' terminated"); + return NULL; +@@ -1333,3 +1333,3 @@ static UINT rdpdr_server_receive_io_write_request(RdpdrServerContext* context, w + "[MS-RDPEFS] 2.2.1.4.4 Device Write Request (DR_WRITE_REQ) not implemented"); +- WLog_Print(context->priv->log, WLOG_WARN, "TODO: parse %p", data); ++ WLog_Print(context->priv->log, WLOG_WARN, "TODO: parse %p", (const void*)data); + +@@ -1366,4 +1366,4 @@ static UINT rdpdr_server_receive_io_device_control_request(RdpdrServerContext* c + WLog_Print(context->priv->log, WLOG_WARN, +- "TODO: parse %p [%" PRIu32 "], OutputBufferLength=%" PRIu32, InputBuffer, +- InputBufferLength, OutputBufferLength); ++ "TODO: parse %p [%" PRIu32 "], OutputBufferLength=%" PRIu32, ++ (const void*)InputBuffer, InputBufferLength, OutputBufferLength); + +@@ -1399,3 +1399,3 @@ static UINT rdpdr_server_receive_io_query_volume_information_request( + "(DR_DRIVE_QUERY_VOLUME_INFORMATION_REQ) not implemented"); +- WLog_Print(context->priv->log, WLOG_WARN, "TODO: parse %p", QueryVolumeBuffer); ++ WLog_Print(context->priv->log, WLOG_WARN, "TODO: parse %p", (const void*)QueryVolumeBuffer); + +@@ -1433,3 +1433,3 @@ static UINT rdpdr_server_receive_io_set_volume_information_request( + "(DR_DRIVE_SET_VOLUME_INFORMATION_REQ) not implemented"); +- WLog_Print(context->priv->log, WLOG_WARN, "TODO: parse %p", SetVolumeBuffer); ++ WLog_Print(context->priv->log, WLOG_WARN, "TODO: parse %p", (const void*)SetVolumeBuffer); + +@@ -1469,3 +1469,3 @@ static UINT rdpdr_server_receive_io_query_information_request(RdpdrServerContext + "(DR_DRIVE_QUERY_INFORMATION_REQ) not implemented"); +- WLog_Print(context->priv->log, WLOG_WARN, "TODO: parse %p", QueryBuffer); ++ WLog_Print(context->priv->log, WLOG_WARN, "TODO: parse %p", (const void*)QueryBuffer); + +@@ -1504,3 +1504,3 @@ static UINT rdpdr_server_receive_io_set_information_request(RdpdrServerContext* + "(DR_DRIVE_SET_INFORMATION_REQ) not implemented"); +- WLog_Print(context->priv->log, WLOG_WARN, "TODO: parse %p", SetBuffer); ++ WLog_Print(context->priv->log, WLOG_WARN, "TODO: parse %p", (const void*)SetBuffer); + +@@ -1619,3 +1619,3 @@ static UINT rdpdr_server_receive_io_lock_control_request(RdpdrServerContext* con + "IRP_MJ_LOCK_CONTROL, Operation=%s, Lock=0x%08" PRIx32 ", NumLocks=%" PRIu32, +- DR_DRIVE_LOCK_REQ2str(Operation)); ++ DR_DRIVE_LOCK_REQ2str(Operation), Lock, NumLocks); + +@@ -1867,3 +1867,3 @@ static UINT rdpdr_server_receive_prn_cache_update_printer(RdpdrServerContext* co + "[MS-RDPEPC] 2.2.2.4 Update Printer Cachedata (DR_PRN_UPDATE_CACHEDATA) not implemented"); +- WLog_Print(context->priv->log, WLOG_WARN, "TODO: parse %p", config); ++ WLog_Print(context->priv->log, WLOG_WARN, "TODO: parse %p", (const void*)config); + return CHANNEL_RC_OK; +diff --git a/channels/rdpear/common/rdpear_common.c b/channels/rdpear/common/rdpear_common.c +index f47af1858..616b83cc6 100644 +--- a/channels/rdpear/common/rdpear_common.c ++++ b/channels/rdpear/common/rdpear_common.c +@@ -231,3 +231,3 @@ void ndr_dump_RPC_UNICODE_STRING(wLog* logger, UINT32 lvl, size_t indentLevel, + WINPR_UNUSED(indentLevel); +- WLog_Print(logger, lvl, "\tLength=%d MaximumLength=%d", obj->lenHints.length, ++ WLog_Print(logger, lvl, "\tLength=%u MaximumLength=%u", obj->lenHints.length, + obj->lenHints.maxLength); +diff --git a/channels/rdpsnd/client/rdpsnd_main.c b/channels/rdpsnd/client/rdpsnd_main.c +index 5be4f179b..af313f8d7 100644 +--- a/channels/rdpsnd/client/rdpsnd_main.c ++++ b/channels/rdpsnd/client/rdpsnd_main.c +@@ -625,3 +625,3 @@ static UINT rdpsnd_treat_wave(rdpsndPlugin* rdpsnd, wStream* s, size_t size) + WLog_Print(rdpsnd->log, WLOG_DEBUG, +- "%s Wave: cBlockNo: %" PRIu8 " wTimeStamp: %" PRIu16 ", size: %" PRIdz, ++ "%s Wave: cBlockNo: %" PRIu8 " wTimeStamp: %" PRIu16 ", size: %" PRIuz, + rdpsnd_is_dyn_str(rdpsnd->dynamic), rdpsnd->cBlockNo, rdpsnd->wTimeStamp, size); +diff --git a/channels/serial/client/serial_main.c b/channels/serial/client/serial_main.c +index b3012c620..f8f95ce53 100644 +--- a/channels/serial/client/serial_main.c ++++ b/channels/serial/client/serial_main.c +@@ -508,3 +508,3 @@ static UINT serial_process_irp(SERIAL_DEVICE* serial, IRP* irp) + rdpdr_irp_string(irp->MajorFunction), irp->MajorFunction, WTSErrorToString(error), +- error, NtStatus2Tag(irp->IoStatus), irp->IoStatus); ++ error, NtStatus2Tag(irp->IoStatus), WINPR_CXX_COMPAT_CAST(UINT32, irp->IoStatus)); + +@@ -949,3 +949,3 @@ FREERDP_ENTRY_POINT( + +- WLog_Print(serial->log, WLOG_DEBUG, "Server's serial driver: %s (id: %d)", driver, ++ WLog_Print(serial->log, WLOG_DEBUG, "Server's serial driver: %s (id: %u)", driver, + serial->ServerSerialDriverId); +diff --git a/channels/urbdrc/client/data_transfer.c b/channels/urbdrc/client/data_transfer.c +index 768c5446b..e2270e565 100644 +--- a/channels/urbdrc/client/data_transfer.c ++++ b/channels/urbdrc/client/data_transfer.c +@@ -395,3 +395,3 @@ static UINT urbdrc_process_internal_io_control(IUDEVICE* pdev, GENERIC_CHANNEL_C + { +- WLog_Print(urbdrc->log, WLOG_DEBUG, "out_size %" PRIu32 " > OutputBufferSize %" PRIu32, 4, ++ WLog_Print(urbdrc->log, WLOG_DEBUG, "out_size %" PRIu32 " > OutputBufferSize %" PRIu32, 4u, + OutputBufferSize); +@@ -1316,3 +1316,3 @@ static UINT urb_pipe_request(IUDEVICE* pdev, GENERIC_CHANNEL_CALLBACK* callback, + if (rc < 0) +- WLog_Print(urbdrc->log, WLOG_DEBUG, "PIPE SET HALT: error %d", ret); ++ WLog_Print(urbdrc->log, WLOG_DEBUG, "PIPE SET HALT: error %u", ret); + else +@@ -1329,3 +1329,3 @@ static UINT urb_pipe_request(IUDEVICE* pdev, GENERIC_CHANNEL_CALLBACK* callback, + if (rc < 0) +- WLog_Print(urbdrc->log, WLOG_DEBUG, "PIPE RESET: error %d", ret); ++ WLog_Print(urbdrc->log, WLOG_DEBUG, "PIPE RESET: error %u", ret); + else +@@ -1411,3 +1411,4 @@ static UINT urb_get_current_frame_number(IUDEVICE* pdev, GENERIC_CHANNEL_CALLBAC + { +- WLog_Print(urbdrc->log, WLOG_WARN, "OutputBufferSize=%" PRIu32 ", expected 0"); ++ WLog_Print(urbdrc->log, WLOG_WARN, "OutputBufferSize=%" PRIu32 ", expected 0", ++ OutputBufferSize); + } +diff --git a/channels/urbdrc/client/urbdrc_main.c b/channels/urbdrc/client/urbdrc_main.c +index b94dd357c..f10962b8f 100644 +--- a/channels/urbdrc/client/urbdrc_main.c ++++ b/channels/urbdrc/client/urbdrc_main.c +@@ -206,3 +206,4 @@ static UINT urbdrc_process_channel_create(GENERIC_CHANNEL_CALLBACK* callback, wS + WLog_Print(urbdrc->log, WLOG_WARN, +- "server supports USB channel version %" PRIu32 ".%" PRIu32); ++ "server supports USB channel version %" PRIu32 ".%" PRIu32, MajorVersion, ++ MinorVersion); + WLog_Print(urbdrc->log, WLOG_WARN, "we only support channel version 1.0"); +diff --git a/client/SDL/SDL3/sdl_clip.cpp b/client/SDL/SDL3/sdl_clip.cpp +index 9ea0c0549..ccf81b49b 100644 +--- a/client/SDL/SDL3/sdl_clip.cpp ++++ b/client/SDL/SDL3/sdl_clip.cpp +@@ -229,3 +229,3 @@ bool sdlClip::handle_update(const SDL_ClipboardEvent& ev) + +- WLog_Print(_log, WLOG_TRACE, "SDL has %d formats", nformats); ++ WLog_Print(_log, WLOG_TRACE, "SDL has %" PRIuz " formats", nformats); + +diff --git a/client/X11/xf_keyboard.c b/client/X11/xf_keyboard.c +index 94ede4404..0347c0f2b 100644 +--- a/client/X11/xf_keyboard.c ++++ b/client/X11/xf_keyboard.c +@@ -505,4 +505,5 @@ static int load_map_from_xkbfile(xfContext* xfc) + { +- WLog_Print(xfc->log, WLOG_WARN, "%4s: keycode: 0x%02X -> no RDP scancode found", +- xkb_keyname, i); ++ WLog_Print(xfc->log, WLOG_WARN, ++ "%4s: keycode: 0x%02" PRIx32 " -> no RDP scancode found", xkb_keyname, ++ WINPR_ASSERTING_INT_CAST(UINT32, i)); + } +diff --git a/client/X11/xf_utils.c b/client/X11/xf_utils.c +index f44d85cd8..0cd7d5bf1 100644 +--- a/client/X11/xf_utils.c ++++ b/client/X11/xf_utils.c +@@ -133,4 +123,5 @@ Atom Logging_XInternAtom(wLog* log, Display* display, _Xconst char* atom_name, B + { +- WLog_Print(log, log_level, "XInternAtom(0x%08" PRIx32 ", %s, %s) -> 0x%08" PRIx32, display, +- atom_name, only_if_exists ? "True" : "False", atom); ++ WLog_Print(log, log_level, "XInternAtom(%p, %s, %s) -> 0x%08" PRIx32, (void*)display, ++ atom_name, only_if_exists ? "True" : "False", ++ WINPR_CXX_COMPAT_CAST(UINT32, atom)); + } +@@ -154,4 +145,4 @@ int LogDynAndXChangeProperty_ex(wLog* log, const char* file, const char* fkt, si + write_log(log, log_level, file, fkt, line, +- "XChangeProperty(%p, %d, %s [%d], %s [%d], %d, %d, %p, %d)", display, w, propstr, +- property, typestr, type, format, mode, data, nelements); ++ "XChangeProperty(%p, %lu, %s [%lu], %s [%lu], %d, %d, %p, %d)", (void*)display, w, ++ propstr, property, typestr, type, format, mode, (const void*)data, nelements); + XFree(propstr); +@@ -170,4 +161,4 @@ int LogDynAndXDeleteProperty_ex(wLog* log, const char* file, const char* fkt, si + char* propstr = Safe_XGetAtomName(log, display, property); +- write_log(log, log_level, file, fkt, line, "XDeleteProperty(%p, %d, %s [%d])", display, w, +- propstr, property); ++ write_log(log, log_level, file, fkt, line, "XDeleteProperty(%p, %lu, %s [%lu])", ++ (void*)display, w, propstr, property); + XFree(propstr); +@@ -189,4 +180,4 @@ int LogDynAndXConvertSelection_ex(wLog* log, const char* file, const char* fkt, + write_log(log, log_level, file, fkt, line, +- "XConvertSelection(%p, %s [%d], %s [%d], %s [%d], %d, %lu)", display, selectstr, +- selection, targetstr, target, propstr, property, requestor, time); ++ "XConvertSelection(%p, %s [%lu], %s [%lu], %s [%lu], %lu, %lu)", (void*)display, ++ selectstr, selection, targetstr, target, propstr, property, requestor, time); + XFree(propstr); +@@ -211,7 +202,8 @@ int LogDynAndXGetWindowProperty_ex(wLog* log, const char* file, const char* fkt, + char* req_type_str = Safe_XGetAtomName(log, display, req_type); +- write_log(log, log_level, file, fkt, line, +- "XGetWindowProperty(%p, %d, %s [%d], %ld, %ld, %d, %s [%d], %p, %p, %p, %p, %p)", +- display, w, propstr, property, long_offset, long_length, delete, req_type_str, +- req_type, actual_type_return, actual_format_return, nitems_return, +- bytes_after_return, prop_return); ++ write_log( ++ log, log_level, file, fkt, line, ++ "XGetWindowProperty(%p, %lu, %s [%lu], %ld, %ld, %d, %s [%lu], %p, %p, %p, %p, %p)", ++ (void*)display, w, propstr, property, long_offset, long_length, delete, req_type_str, ++ req_type, (void*)actual_type_return, (void*)actual_format_return, (void*)nitems_return, ++ (void*)bytes_after_return, (void*)prop_return); + XFree(propstr); +diff --git a/client/common/client_cliprdr_file.c b/client/common/client_cliprdr_file.c +index 9769b9298..3f4c513bc 100644 +--- a/client/common/client_cliprdr_file.c ++++ b/client/common/client_cliprdr_file.c +@@ -1355,4 +1355,4 @@ static BOOL dump_streams(const void* key, void* value, WINPR_ATTR_UNUSED void* a + const CliprdrLocalFile* file = &cur->files[x]; +- writelog(cur->context->log, WLOG_WARN, __FILE__, __func__, __LINE__, "file [%" PRIuz "] ", +- x, file->name, file->size); ++ writelog(cur->context->log, WLOG_WARN, __FILE__, __func__, __LINE__, ++ "file [%" PRIuz "] %s: %" PRId64, x, file->name, file->size); + } +@@ -1377,3 +1377,3 @@ static CliprdrLocalFile* file_info_for_request(CliprdrFileContext* file, UINT32 + writelog(file->log, WLOG_WARN, __FILE__, __func__, __LINE__, +- "invalid entry index for lockID %" PRIu32 ", index %" PRIu32 " [count %" PRIu32 ++ "invalid entry index for lockID %" PRIu32 ", index %" PRIu32 " [count %" PRIuz + "] [locked %d]", +@@ -2499,3 +2499,3 @@ BOOL cliprdr_file_context_update_client_data(CliprdrFileContext* file, const cha + +- WLog_Print(file->log, WLOG_DEBUG, "update client file list (stream=%p)...", stream); ++ WLog_Print(file->log, WLOG_DEBUG, "update client file list (stream=%p)...", (void*)stream); + if (stream) +diff --git a/libfreerdp/codec/dsp.c b/libfreerdp/codec/dsp.c +index cf0d70a09..dbd11f1b0 100644 +--- a/libfreerdp/codec/dsp.c ++++ b/libfreerdp/codec/dsp.c +@@ -748,3 +748,3 @@ static const struct + +-static BYTE dsp_encode_ima_adpcm_sample(ADPCM* WINPR_RESTRICT adpcm, int channel, INT16 sample) ++static BYTE dsp_encode_ima_adpcm_sample(ADPCM* WINPR_RESTRICT adpcm, size_t channel, INT16 sample) + { +@@ -894,3 +894,3 @@ static const INT32 ms_adpcm_coeffs2[7] = { 0, -256, 0, 64, 0, -208, -232 }; + static INLINE INT16 freerdp_dsp_decode_ms_adpcm_sample(ADPCM* WINPR_RESTRICT adpcm, BYTE sample, +- int channel) ++ size_t channel) + { +diff --git a/libfreerdp/codec/progressive.c b/libfreerdp/codec/progressive.c +index c7ccf730f..6396e0f2a 100644 +--- a/libfreerdp/codec/progressive.c ++++ b/libfreerdp/codec/progressive.c +@@ -1630,4 +1630,4 @@ static INLINE SSIZE_T progressive_process_tiles( + { +- WLog_Print(progressive->log, WLOG_ERROR, "Expected >= %" PRIu32 " remaining %" PRIuz, 6, +- blockLen); ++ WLog_Print(progressive->log, WLOG_ERROR, "Expected >= %" PRIu32 " remaining %" PRIu32, ++ 6u, blockLen); + return -1003; +@@ -1760,3 +1760,3 @@ static INLINE SSIZE_T progressive_wb_sync(PROGRESSIVE_CONTEXT* WINPR_RESTRICT pr + "PROGRESSIVE_BLOCK_SYNC::blockLen = 0x%08" PRIx32 " != 0x%08" PRIx32, +- sync.blockLen, 12); ++ sync.blockLen, 12u); + return -1005; +@@ -1810,3 +1810,3 @@ static INLINE SSIZE_T progressive_wb_frame_begin(PROGRESSIVE_CONTEXT* WINPR_REST + " RFX_PROGRESSIVE_FRAME_BEGIN::blockLen = 0x%08" PRIx32 " != 0x%08" PRIx32, +- frameBegin.blockLen, 12); ++ frameBegin.blockLen, 12u); + return -1005; +@@ -1862,3 +1862,3 @@ static INLINE SSIZE_T progressive_wb_frame_end(PROGRESSIVE_CONTEXT* WINPR_RESTRI + " RFX_PROGRESSIVE_FRAME_END::blockLen = 0x%08" PRIx32 " != 0x%08" PRIx32, +- frameEnd.blockLen, 6); ++ frameEnd.blockLen, 6u); + return -1005; +@@ -1869,4 +1869,4 @@ static INLINE SSIZE_T progressive_wb_frame_end(PROGRESSIVE_CONTEXT* WINPR_RESTRI + WLog_Print(progressive->log, WLOG_ERROR, +- "ProgressiveFrameEnd short %" PRIuz ", expected %" PRIuz, +- Stream_GetRemainingLength(s), 0); ++ "ProgressiveFrameEnd short %" PRIuz ", expected %u", ++ Stream_GetRemainingLength(s), 0U); + return -1008; +@@ -1898,4 +1898,4 @@ static INLINE SSIZE_T progressive_wb_context(PROGRESSIVE_CONTEXT* WINPR_RESTRICT + WLog_Print(progressive->log, WLOG_ERROR, +- "RFX_PROGRESSIVE_CONTEXT::blockLen = 0x%08" PRIx32 " != 0x%08" PRIx32, +- context->blockLen, 10); ++ "RFX_PROGRESSIVE_CONTEXT::blockLen = 0x%08" PRIx32 " != 0x%08x", ++ context->blockLen, 10u); + return -1005; +@@ -1957,4 +1957,3 @@ static INLINE SSIZE_T progressive_wb_read_region_header( + WLog_Print(progressive->log, WLOG_ERROR, +- "ProgressiveRegion tile size %" PRIu8 ", expected %" PRIuz, region->tileSize, +- 64); ++ "ProgressiveRegion tile size %" PRIu8 ", expected %u", region->tileSize, 64U); + return -1012; +@@ -1972,4 +1971,4 @@ static INLINE SSIZE_T progressive_wb_read_region_header( + WLog_Print(progressive->log, WLOG_ERROR, +- "ProgressiveRegion quant count too high %" PRIu8 ", expected < %" PRIuz, +- region->numQuant, 7); ++ "ProgressiveRegion quant count too high %" PRIu8 ", expected < %u", ++ region->numQuant, 7U); + return -1014; +diff --git a/libfreerdp/codec/rfx.c b/libfreerdp/codec/rfx.c +index 12f17e213..8832cd740 100644 +--- a/libfreerdp/codec/rfx.c ++++ b/libfreerdp/codec/rfx.c +@@ -924,4 +924,4 @@ static INLINE BOOL rfx_process_message_tileset(RFX_CONTEXT* WINPR_RESTRICT conte + WLog_Print(context->priv->log, WLOG_DEBUG, +- "quant %d (%" PRIu32 " %" PRIu32 " %" PRIu32 " %" PRIu32 " %" PRIu32 " %" PRIu32 +- " %" PRIu32 " %" PRIu32 " %" PRIu32 " %" PRIu32 ").", ++ "quant %" PRIuz " (%" PRIu32 " %" PRIu32 " %" PRIu32 " %" PRIu32 " %" PRIu32 ++ " %" PRIu32 " %" PRIu32 " %" PRIu32 " %" PRIu32 " %" PRIu32 ").", + i, context->quants[i * 10], context->quants[i * 10 + 1], +@@ -987,4 +987,4 @@ static INLINE BOOL rfx_process_message_tileset(RFX_CONTEXT* WINPR_RESTRICT conte + WLog_Print(context->priv->log, WLOG_ERROR, +- "RfxMessageTileSet packet too small to read tile %d/%" PRIu16 "", i, +- message->numTiles); ++ "RfxMessageTileSet packet too small to read tile %" PRIuz "/%" PRIu16 "", ++ i, message->numTiles); + rc = FALSE; +@@ -1007,3 +1007,3 @@ static INLINE BOOL rfx_process_message_tileset(RFX_CONTEXT* WINPR_RESTRICT conte + WLog_Print(context->priv->log, WLOG_ERROR, +- "RfxMessageTileSet not enough bytes to read tile %d/%" PRIu16 ++ "RfxMessageTileSet not enough bytes to read tile %" PRIuz "/%" PRIu16 + " with blocklen=%" PRIu32 "", +@@ -1224,3 +1224,3 @@ BOOL rfx_process_message(RFX_CONTEXT* WINPR_RESTRICT context, const BYTE* WINPR_ + WLog_Print(context->priv->log, WLOG_ERROR, +- "blockLen too small(%" PRIu32 "), must be >= 6 + %" PRIu16, blockLen, ++ "blockLen too small(%" PRIu32 "), must be >= 6 + %" PRIuz, blockLen, + extraBlockLen); +diff --git a/libfreerdp/common/assistance.c b/libfreerdp/common/assistance.c +index dfdfff890..d45017ec1 100644 +--- a/libfreerdp/common/assistance.c ++++ b/libfreerdp/common/assistance.c +@@ -1470,5 +1470,5 @@ void freerdp_assistance_print_file(rdpAssistanceFile* file, wLog* log, DWORD lev + +- WLog_Print(log, level, "MachineAddress [%" PRIdz ": %s", x, addr); +- WLog_Print(log, level, "MachinePort [%" PRIdz ": %" PRIu32, x, port); +- WLog_Print(log, level, "MachineURI [%" PRIdz ": %s", x, uri); ++ WLog_Print(log, level, "MachineAddress [%" PRIuz ": %s", x, addr); ++ WLog_Print(log, level, "MachinePort [%" PRIuz ": %" PRIu32, x, port); ++ WLog_Print(log, level, "MachineURI [%" PRIuz ": %s", x, uri); + } +diff --git a/libfreerdp/core/aad.c b/libfreerdp/core/aad.c +index 5bbfca9bb..7099c2422 100644 +--- a/libfreerdp/core/aad.c ++++ b/libfreerdp/core/aad.c +@@ -508,3 +508,3 @@ static int aad_send_auth_request(rdpAad* aad, const char* ts_nonce) + { +- WLog_Print(aad->log, WLOG_ERROR, "transport_write [%" PRIdz " bytes] failed", ++ WLog_Print(aad->log, WLOG_ERROR, "transport_write [%" PRIuz " bytes] failed", + Stream_Length(s)); +@@ -595,3 +595,3 @@ int aad_recv(rdpAad* aad, wStream* s) + default: +- WLog_Print(aad->log, WLOG_ERROR, "Invalid AAD_STATE %d", aad->state); ++ WLog_Print(aad->log, WLOG_ERROR, "Invalid AAD_STATE %u", aad->state); + return -1; +diff --git a/libfreerdp/core/autodetect.c b/libfreerdp/core/autodetect.c +index 0262ee630..90f65ee53 100644 +--- a/libfreerdp/core/autodetect.c ++++ b/libfreerdp/core/autodetect.c +@@ -239,4 +239,4 @@ autodetect_send_bandwidth_measure_payload(rdpAutoDetect* autodetect, + { +- WLog_Print(autodetect->log, WLOG_ERROR, "Failed to ensure %" PRIuz " bytes in stream", +- 8ull + payloadLength); ++ WLog_Print(autodetect->log, WLOG_ERROR, "Failed to ensure %lu bytes in stream", ++ 8ul + payloadLength); + Stream_Release(s); +@@ -300,3 +300,3 @@ static BOOL autodetect_send_bandwidth_measure_stop(rdpAutoDetect* autodetect, + WLog_Print(autodetect->log, WLOG_ERROR, +- "Failed to ensure %" PRIuz " bytes in stream", payloadLength); ++ "Failed to ensure %" PRIu16 " bytes in stream", payloadLength); + Stream_Release(s); +diff --git a/libfreerdp/core/capabilities.c b/libfreerdp/core/capabilities.c +index d6062caad..b52f71f33 100644 +--- a/libfreerdp/core/capabilities.c ++++ b/libfreerdp/core/capabilities.c +@@ -218,3 +218,4 @@ static BOOL rdp_read_general_capability_set(wLog* log, wStream* s, rdpSettings* + ") != TS_CAPS_PROTOCOLVERSION(0x%04" PRIx32 ")", +- settings->CapsProtocolVersion, TS_CAPS_PROTOCOLVERSION); ++ settings->CapsProtocolVersion, ++ WINPR_CXX_COMPAT_CAST(UINT32, TS_CAPS_PROTOCOLVERSION)); + if (settings->CapsProtocolVersion == 0x0000) +@@ -286,4 +287,5 @@ static BOOL rdp_write_general_capability_set(wLog* log, wStream* s, const rdpSet + "OsMajorType=%08" PRIx32 ", OsMinorType=%08" PRIx32 +- " they need to be smaller %04" PRIx16, +- settings->OsMajorType, settings->OsMinorType, UINT16_MAX); ++ " they need to be smaller %04" PRIx32, ++ settings->OsMajorType, settings->OsMinorType, ++ WINPR_CXX_COMPAT_CAST(UINT32, UINT16_MAX)); + return FALSE; +@@ -295,3 +297,4 @@ static BOOL rdp_write_general_capability_set(wLog* log, wStream* s, const rdpSet + ") != TS_CAPS_PROTOCOLVERSION(0x%04" PRIx32 ")", +- settings->CapsProtocolVersion, TS_CAPS_PROTOCOLVERSION); ++ settings->CapsProtocolVersion, ++ WINPR_CXX_COMPAT_CAST(UINT32, TS_CAPS_PROTOCOLVERSION)); + return FALSE; +@@ -1134,3 +1137,4 @@ static BOOL rdp_read_pointer_capability_set(wLog* log, wStream* s, rdpSettings* + "(TS_POINTER_CAPABILITYSET)::colorPointerFlag received is %" PRIu16 +- ". Value is ignored and always assumed to be TRUE"); ++ ". Value is ignored and always assumed to be TRUE", ++ colorPointerFlag); + } +@@ -2876,3 +2880,4 @@ static BOOL rdp_read_large_pointer_capability_set(wLog* log, wStream* s, rdpSett + "TS_LARGE_POINTER_CAPABILITYSET with unsupported flags %04X (all flags %04X) received", +- largePointerSupportFlags & ~(LARGE_POINTER_FLAG_96x96 | LARGE_POINTER_FLAG_384x384), ++ WINPR_CXX_COMPAT_CAST(UINT32, largePointerSupportFlags & ~(LARGE_POINTER_FLAG_96x96 | ++ LARGE_POINTER_FLAG_384x384)), + largePointerSupportFlags); +@@ -3158,3 +3163,3 @@ static BOOL rdp_read_codec_ts_rfx_icap(wLog* log, wStream* sub, rdpSettings* set + " unsupported, expecting size %" PRIu16 " not supported", +- icapLen, 8); ++ icapLen, 8u); + return FALSE; +@@ -3236,4 +3241,4 @@ static BOOL rdp_read_codec_ts_rfx_icap(wLog* log, wStream* sub, rdpSettings* set + "[MS-RDPRFX] 2.2.1.1.1.1.1 TS_RFX_ICAP::flags unknown value " +- "0x%02" PRIx8, +- (codecFlags & ~CODEC_MODE)); ++ "0x%02" PRIx32, ++ WINPR_CXX_COMPAT_CAST(UINT32, (codecFlags & ~CODEC_MODE))); + +@@ -3364,3 +3369,3 @@ static BOOL rdp_read_codec_ts_rfx_caps(wLog* log, wStream* sub, rdpSettings* set + WLog_Print(log, WLOG_ERROR, +- "[MS_RDPRFX] 2.2.1.1.1.1 TS_RFX_CAPSET::numIcaps[" PRIu16 "] != 1", numCapsets); ++ "[MS_RDPRFX] 2.2.1.1.1.1 TS_RFX_CAPSET::numIcaps[%" PRIu16 "] != 1", numCapsets); + return FALSE; +@@ -4564,3 +4569,3 @@ static BOOL rdp_read_capability_sets(wLog* log, wStream* s, rdpSettings* setting + { +- WLog_Print(log, WLOG_ERROR, "Capability length expected %" PRIu16 ", actual %" PRIdz, ++ WLog_Print(log, WLOG_ERROR, "Capability length expected %" PRIu16 ", actual %" PRIuz, + totalLength, len); +diff --git a/libfreerdp/core/gateway/arm.c b/libfreerdp/core/gateway/arm.c +index 6afebaf03..42e281ee4 100644 +--- a/libfreerdp/core/gateway/arm.c ++++ b/libfreerdp/core/gateway/arm.c +@@ -411,4 +411,4 @@ static WINPR_CIPHER_CTX* treatAuthBlob(wLog* log, const BYTE* pbInput, size_t cb + { +- WLog_Print(log, WLOG_ERROR, "unsupported authBlob version %d, expecting %d", dwVersion, +- BCRYPT_KEY_DATA_BLOB_VERSION1); ++ WLog_Print(log, WLOG_ERROR, "unsupported authBlob version %" PRIu32 ", expecting %d", ++ dwVersion, BCRYPT_KEY_DATA_BLOB_VERSION1); + return NULL; +diff --git a/libfreerdp/core/gateway/rdg.c b/libfreerdp/core/gateway/rdg.c +index a7b0591ea..0b16142bd 100644 +--- a/libfreerdp/core/gateway/rdg.c ++++ b/libfreerdp/core/gateway/rdg.c +@@ -1002,3 +1002,3 @@ static BOOL rdg_process_extauth_sspi(rdpRdg* rdg, wStream* s) + WLog_Print(rdg->log, WLOG_ERROR, "EXTAUTH_SSPI_NTLM failed with error %s [0x%08X]", +- GetSecurityStatusString(errorCode), errorCode); ++ GetSecurityStatusString(errorCode), WINPR_CXX_COMPAT_CAST(UINT32, errorCode)); + return FALSE; +@@ -1086,3 +1086,3 @@ static BOOL rdg_process_packet(rdpRdg* rdg, wStream* s) + { +- WLog_Print(rdg->log, WLOG_ERROR, "Short packet %" PRIuz ", expected %" PRIuz, ++ WLog_Print(rdg->log, WLOG_ERROR, "Short packet %" PRIuz ", expected %" PRIu32, + Stream_Length(s), packetLength); +@@ -1779,3 +1779,4 @@ static BOOL rdg_process_unknown_packet(rdpRdg* rdg, int type) + WINPR_UNUSED(type); +- WLog_Print(rdg->log, WLOG_WARN, "Unknown Control Packet received: %X", type); ++ WLog_Print(rdg->log, WLOG_WARN, "Unknown Control Packet received: %" PRIX32, ++ WINPR_CXX_COMPAT_CAST(UINT32, type)); + return TRUE; +diff --git a/libfreerdp/core/gateway/rpc_client.c b/libfreerdp/core/gateway/rpc_client.c +index ce6de8ea4..b1a1fda83 100644 +--- a/libfreerdp/core/gateway/rpc_client.c ++++ b/libfreerdp/core/gateway/rpc_client.c +@@ -327,3 +327,3 @@ static int rpc_client_recv_pdu_int(rdpRpc* rpc, RPC_PDU* pdu) + { +- WLog_Print(rpc->log, WLOG_ERROR, "invalid rpc->State: %d", rpc->State); ++ WLog_Print(rpc->log, WLOG_ERROR, "invalid rpc->State: %u", rpc->State); + } +diff --git a/libfreerdp/core/gateway/rts.c b/libfreerdp/core/gateway/rts.c +index c0b851c33..fc1d56169 100644 +--- a/libfreerdp/core/gateway/rts.c ++++ b/libfreerdp/core/gateway/rts.c +@@ -1256,5 +1256,6 @@ static BOOL rts_receive_window_size_command_read(rdpRpc* rpc, wStream* buffer, + WLog_Print(rpc->log, WLOG_ERROR, +- "[MS-RPCH] 2.2.3.5.1 ReceiveWindowSize::CommandType must be 0x08" PRIx32 ", got " ++ "[MS-RPCH] 2.2.3.5.1 ReceiveWindowSize::CommandType must be 0x%08" PRIx32 ++ ", got " + "0x%08" PRIx32, +- RTS_CMD_RECEIVE_WINDOW_SIZE, CommandType); ++ WINPR_CXX_COMPAT_CAST(UINT32, RTS_CMD_RECEIVE_WINDOW_SIZE), CommandType); + return FALSE; +@@ -1356,5 +1357,6 @@ static BOOL rts_connection_timeout_command_read(WINPR_ATTR_UNUSED rdpRpc* rpc, w + WLog_Print(rpc->log, WLOG_ERROR, +- "[MS-RPCH] 2.2.3.5.3 ConnectionTimeout::CommandType must be 0x08" PRIx32 ", got " ++ "[MS-RPCH] 2.2.3.5.3 ConnectionTimeout::CommandType must be 0x%08" PRIx32 ++ ", got " + "0x%08" PRIx32, +- RTS_CMD_CONNECTION_TIMEOUT, CommandType); ++ WINPR_CXX_COMPAT_CAST(UINT32, RTS_CMD_CONNECTION_TIMEOUT), CommandType); + return FALSE; +@@ -1424,5 +1426,5 @@ static BOOL rts_version_command_read(rdpRpc* rpc, wStream* buffer, uint32_t* pve + WLog_Print(rpc->log, WLOG_ERROR, +- "[MS-RPCH] 2.2.3.5.7 Version::CommandType must be 0x08" PRIx32 ", got " ++ "[MS-RPCH] 2.2.3.5.7 Version::CommandType must be 0x%08" PRIx32 ", got " + "0x%08" PRIx32, +- RTS_CMD_VERSION, CommandType); ++ WINPR_CXX_COMPAT_CAST(UINT32, RTS_CMD_VERSION), CommandType); + return FALSE; +@@ -1660,3 +1662,3 @@ BOOL rts_recv_CONN_A3_pdu(rdpRpc* rpc, wStream* buffer) + ", expected 0x%08" PRIx32, +- header.rts.Flags, RTS_FLAG_NONE); ++ header.rts.Flags, WINPR_CXX_COMPAT_CAST(UINT32, RTS_FLAG_NONE)); + goto fail; +@@ -1769,3 +1771,3 @@ BOOL rts_recv_CONN_C2_pdu(rdpRpc* rpc, wStream* buffer) + ", expected 0x%08" PRIx32, +- header.rts.Flags, RTS_FLAG_NONE); ++ header.rts.Flags, WINPR_CXX_COMPAT_CAST(UINT32, RTS_FLAG_NONE)); + goto fail; +diff --git a/libfreerdp/core/gateway/tsg.c b/libfreerdp/core/gateway/tsg.c +index 873adf977..85640f820 100644 +--- a/libfreerdp/core/gateway/tsg.c ++++ b/libfreerdp/core/gateway/tsg.c +@@ -1572,3 +1572,3 @@ static BOOL tsg_ndr_read_TSG_PACKET_MSG_RESPONSE(wLog* log, rdpContext* context, + WLog_Print(log, WLOG_DEBUG, +- "Message {0x%08" PRIx32 "} [%s]::isMsgPresent=%" PRIu32 ", MsgPtr=0x%08" PRIx32, ++ "Message {0x%08" PRIx32 "} [%s]::isMsgPresent=%" PRId32 ", MsgPtr=0x%08" PRIx32, + pkg->msgType, tsg_packet_id_to_string(pkg->msgType), pkg->isMsgPresent, MsgPtr); +diff --git a/libfreerdp/core/license.c b/libfreerdp/core/license.c +index 2449af948..0115f0dd8 100644 +--- a/libfreerdp/core/license.c ++++ b/libfreerdp/core/license.c +@@ -1187,4 +1187,4 @@ BOOL license_encrypt_premaster_secret(rdpLicense* license) + { +- WLog_Print(license->log, WLOG_ERROR, "info=%p, license->certificate=%p", info, +- license->certificate); ++ WLog_Print(license->log, WLOG_ERROR, "info=%p, license->certificate=%p", (const void*)info, ++ (void*)license->certificate); + return FALSE; +@@ -1204,3 +1204,3 @@ BOOL license_encrypt_premaster_secret(rdpLicense* license) + "EncryptedPremasterSecret=%p, info->ModulusLength=%" PRIu32, +- EncryptedPremasterSecret, info->ModulusLength); ++ (const void*)EncryptedPremasterSecret, info->ModulusLength); + return FALSE; +@@ -1217,5 +1217,4 @@ BOOL license_encrypt_premaster_secret(rdpLicense* license) + { +- WLog_Print(license->log, WLOG_ERROR, +- "RSA public encrypt length=%" PRIdz " < 0 || > %" PRIu16, length, +- UINT16_MAX); ++ WLog_Print(license->log, WLOG_ERROR, "RSA public encrypt length=%" PRIdz " < 0 || > %d", ++ length, UINT16_MAX); + return FALSE; +@@ -1262,3 +1261,3 @@ error_buffer: + WLog_Print(license->log, WLOG_ERROR, "Failed to create/update RC4: len=%" PRIuz ", buffer=%p", +- len, buffer); ++ len, (const void*)buffer); + winpr_RC4_Free(rc4); +@@ -1504,3 +1503,3 @@ BOOL license_read_binary_blob_data(wLog* log, LICENSE_BLOB* blob, UINT16 wBlobTy + WLog_Print(log, WLOG_ERROR, "license binary blob::length=%" PRIu16 ", blob::data=%p", +- blob->length, blob->data); ++ blob->length, (const void*)blob->data); + return FALSE; +@@ -2186,4 +2185,4 @@ BOOL license_read_new_or_upgrade_license_packet(rdpLicense* license, wStream* s) + WLog_Print(license->log, WLOG_ERROR, +- "license::blob::data=%p, license::blob::length=%" PRIu16, calBlob->data, +- calBlob->length); ++ "license::blob::data=%p, license::blob::length=%" PRIu16, ++ (const void*)calBlob->data, calBlob->length); + goto fail; +@@ -2908,4 +2907,4 @@ static BOOL license_set_string(wLog* log, const char* what, const char* value, B + { +- WLog_Print(log, WLOG_ERROR, "license->ProductInfo: %s == %p || %" PRIu32 " > UINT32_MAX", +- what, *cnv.w, len); ++ WLog_Print(log, WLOG_ERROR, "license->ProductInfo: %s == %p || %" PRIuz " > UINT32_MAX", ++ what, (void*)(*cnv.w), len); + return FALSE; +@@ -2993,4 +2992,4 @@ BOOL license_server_configure(rdpLicense* license) + WLog_Print(license->log, WLOG_WARN, +- "%s: Invalid issuer at position %" PRIuz ": length 0 < %" PRIuz +- " <= %" PRIu16 " ['%s']", ++ "Invalid issuer at position %" PRIuz ": length 0 < %" PRIuz " <= %d" ++ " ['%s']", + x, length, UINT16_MAX, name); +diff --git a/libfreerdp/core/rdp.c b/libfreerdp/core/rdp.c +index f50059b70..6e105fa42 100644 +--- a/libfreerdp/core/rdp.c ++++ b/libfreerdp/core/rdp.c +@@ -278,5 +278,5 @@ BOOL rdp_read_share_control_header(rdpRdp* rdp, wStream* s, UINT16* tpktLength, + WLog_Print(rdp->log, WLOG_DEBUG, +- "[Flow control PDU] type=%s, tpktLength=%" PRIuz ", remainingLength=%" PRIuz, +- pdu_type_to_str(*type, buffer, sizeof(buffer)), tpktLength ? *tpktLength : 0, +- remainingLength ? *remainingLength : 0); ++ "[Flow control PDU] type=%s, tpktLength=%" PRIu16 ", remainingLength=%" PRIu16, ++ pdu_type_to_str(*type, buffer, sizeof(buffer)), tpktLength ? *tpktLength : 0u, ++ remainingLength ? *remainingLength : 0u); + return TRUE; +@@ -313,3 +313,3 @@ BOOL rdp_read_share_control_header(rdpRdp* rdp, wStream* s, UINT16* tpktLength, + char buffer[128] = { 0 }; +- WLog_Print(rdp->log, WLOG_DEBUG, "type=%s, tpktLength=%" PRIuz ", remainingLength=%" PRIuz, ++ WLog_Print(rdp->log, WLOG_DEBUG, "type=%s, tpktLength=%" PRIu16 ", remainingLength=%" PRIuz, + pdu_type_to_str(*type, buffer, sizeof(buffer)), len, remLen); +@@ -504,3 +504,3 @@ BOOL rdp_set_error_info(rdpRdp* rdp, UINT32 errorInfo) + else +- WLog_Print(rdp->log, WLOG_ERROR, "missing context=%p", context); ++ WLog_Print(rdp->log, WLOG_ERROR, "missing context=%p", (void*)context); + } +@@ -1037,3 +1037,3 @@ static BOOL rdp_recv_server_set_keyboard_indicators_pdu(rdpRdp* rdp, wStream* s) + "[MS-RDPBCGR] 2.2.8.2.1.1 Set Keyboard Indicators PDU Data " +- "(TS_SET_KEYBOARD_INDICATORS_PDU)::unitId should be 0, is %" PRIu8, ++ "(TS_SET_KEYBOARD_INDICATORS_PDU)::unitId should be 0, is %" PRIu16, + unitId); +@@ -1057,3 +1057,3 @@ static BOOL rdp_recv_server_set_keyboard_ime_status_pdu(rdpRdp* rdp, wStream* s) + "[MS-RDPBCGR] 2.2.8.2.2.1 Set Keyboard IME Status PDU Data " +- "(TS_SET_KEYBOARD_IME_STATUS_PDU)::unitId should be 0, is %" PRIu8, ++ "(TS_SET_KEYBOARD_IME_STATUS_PDU)::unitId should be 0, is %" PRIu16, + unitId); +@@ -1776,3 +1776,3 @@ static state_run_t rdp_recv_tpkt_pdu(rdpRdp* rdp, wStream* s) + WLog_Print(rdp->log, WLOG_WARN, +- "pduType %s not properly parsed, %" PRIdz ++ "pduType %s not properly parsed, %" PRIuz + " bytes remaining unhandled. Skipping.", +@@ -2173,3 +2173,3 @@ static state_run_t rdp_recv_callback_int(WINPR_ATTR_UNUSED rdpTransport* transpo + default: +- WLog_Print(rdp->log, WLOG_ERROR, "%s state %d", rdp_get_state_string(rdp), ++ WLog_Print(rdp->log, WLOG_ERROR, "%s state %u", rdp_get_state_string(rdp), + rdp_get_state(rdp)); +@@ -2965,3 +2965,3 @@ static void log_build_warn(rdpRdp* rdp, const char* what, const char* msg, + } +- WLog_Print(rdp->log, WLOG_WARN, ""); ++ WLog_Print(rdp->log, WLOG_WARN, "*"); + WLog_Print(rdp->log, WLOG_WARN, "[%s] build options %s", what, msg); +diff --git a/libfreerdp/core/rdstls.c b/libfreerdp/core/rdstls.c +index de35c73dc..8a896997e 100644 +--- a/libfreerdp/core/rdstls.c ++++ b/libfreerdp/core/rdstls.c +@@ -174,3 +174,3 @@ static BOOL check_transition(wLog* log, RDSTLS_STATE current, RDSTLS_STATE expec + WLog_Print(log, WLOG_ERROR, +- "Unexpected rdstls state transition from %s [%d] to %s [%d], expected %s [%d]", ++ "Unexpected rdstls state transition from %s [%u] to %s [%u], expected %s [%u]", + rdstls_get_state_str(current), current, rdstls_get_state_str(requested), +@@ -209,3 +209,3 @@ static BOOL rdstls_set_state(rdpRdstls* rdstls, RDSTLS_STATE state) + WLog_Print(rdstls->log, WLOG_ERROR, +- "Invalid rdstls state %s [%d], requested transition to %s [%d]", ++ "Invalid rdstls state %s [%u], requested transition to %s [%u]", + rdstls_get_state_str(rdstls->state), rdstls->state, +@@ -337,4 +337,4 @@ static BOOL rdstls_process_capabilities(rdpRdstls* rdstls, wStream* s) + WLog_Print(rdstls->log, WLOG_ERROR, +- "received invalid DataType=0x%04" PRIX16 ", expected 0x%04" PRIX16, dataType, +- RDSTLS_DATA_CAPABILITIES); ++ "received invalid DataType=0x%04" PRIX16 ", expected 0x%04" PRIX32, dataType, ++ WINPR_CXX_COMPAT_CAST(UINT32, RDSTLS_DATA_CAPABILITIES)); + return FALSE; +@@ -346,4 +346,4 @@ static BOOL rdstls_process_capabilities(rdpRdstls* rdstls, wStream* s) + WLog_Print(rdstls->log, WLOG_ERROR, +- "received invalid supportedVersions=0x%04" PRIX16 ", expected 0x%04" PRIX16, +- supportedVersions, RDSTLS_VERSION_1); ++ "received invalid supportedVersions=0x%04" PRIX16 ", expected 0x%04" PRIX32, ++ supportedVersions, WINPR_CXX_COMPAT_CAST(UINT32, RDSTLS_VERSION_1)); + return FALSE; +@@ -542,5 +542,6 @@ static BOOL rdstls_process_authentication_request(rdpRdstls* rdstls, wStream* s) + WLog_Print(rdstls->log, WLOG_ERROR, +- "received invalid DataType=0x%04" PRIX16 ", expected 0x%04" PRIX16 +- " or 0x%04" PRIX16, +- dataType, RDSTLS_DATA_PASSWORD_CREDS, RDSTLS_DATA_AUTORECONNECT_COOKIE); ++ "received invalid DataType=0x%04" PRIX16 ", expected 0x%04" PRIX32 ++ " or 0x%04" PRIX32, ++ dataType, WINPR_CXX_COMPAT_CAST(UINT32, RDSTLS_DATA_PASSWORD_CREDS), ++ WINPR_CXX_COMPAT_CAST(UINT32, RDSTLS_DATA_AUTORECONNECT_COOKIE)); + return FALSE; +@@ -563,4 +564,4 @@ static BOOL rdstls_process_authentication_response(rdpRdstls* rdstls, wStream* s + WLog_Print(rdstls->log, WLOG_ERROR, +- "received invalid DataType=0x%04" PRIX16 ", expected 0x%04" PRIX16, dataType, +- RDSTLS_DATA_RESULT_CODE); ++ "received invalid DataType=0x%04" PRIX16 ", expected 0x%04" PRIX32, dataType, ++ WINPR_CXX_COMPAT_CAST(UINT32, RDSTLS_DATA_RESULT_CODE)); + return FALSE; +@@ -657,3 +658,3 @@ static BOOL rdstls_send(WINPR_ATTR_UNUSED rdpTransport* transport, wStream* s, v + default: +- WLog_Print(rdstls->log, WLOG_ERROR, "Invalid rdstls state %s [%d]", ++ WLog_Print(rdstls->log, WLOG_ERROR, "Invalid rdstls state %s [%" PRIu32 "]", + rdstls_get_state_str(state), state); +@@ -686,3 +687,3 @@ static int rdstls_recv(WINPR_ATTR_UNUSED rdpTransport* transport, wStream* s, vo + "received invalid RDSTLS Version=0x%04" PRIX16 ", expected 0x%04" PRIX16, +- version, RDSTLS_VERSION_1); ++ version, WINPR_CXX_COMPAT_CAST(UINT32, RDSTLS_VERSION_1)); + return -1; +diff --git a/libfreerdp/core/tpkt.c b/libfreerdp/core/tpkt.c +index 5d7beef20..d446b953a 100644 +--- a/libfreerdp/core/tpkt.c ++++ b/libfreerdp/core/tpkt.c +@@ -138,3 +138,3 @@ BOOL tpkt_ensure_stream_consumed_(wLog* log, wStream* s, size_t length, const ch + { +- WLog_Print(log, WLOG_ERROR, "[%s] length %" PRIuz " > %" PRIu16, fkt, length, UINT16_MAX); ++ WLog_Print(log, WLOG_ERROR, "[%s] length %" PRIuz " > %d", fkt, length, UINT16_MAX); + return FALSE; +@@ -146,3 +146,3 @@ BOOL tpkt_ensure_stream_consumed_(wLog* log, wStream* s, size_t length, const ch + WLog_Print(log, WLOG_ERROR, +- "[%s] Received invalid TPKT header length %" PRIu16 ", %" PRIdz ++ "[%s] Received invalid TPKT header length %" PRIuz ", %" PRIuz + " bytes too long!", +diff --git a/libfreerdp/core/window.c b/libfreerdp/core/window.c +index 9ce080cf8..e51a0cf7c 100644 +--- a/libfreerdp/core/window.c ++++ b/libfreerdp/core/window.c +@@ -804,3 +804,3 @@ static void dump_window_state_order(wLog* log, const char* msg, const WINDOW_ORD + +- WLog_Print(log, WLOG_DEBUG, buffer); ++ WLog_Print(log, WLOG_DEBUG, "%s", buffer); + } +@@ -1082,3 +1082,3 @@ static void dump_monitored_desktop(wLog* log, const char* msg, const WINDOW_ORDE + } +- WLog_Print(log, WLOG_DEBUG, buffer); ++ WLog_Print(log, WLOG_DEBUG, "%s", buffer); + } +diff --git a/libfreerdp/emu/scard/smartcard_emulate.c b/libfreerdp/emu/scard/smartcard_emulate.c +index bb613c33b..f8c67dd78 100644 +--- a/libfreerdp/emu/scard/smartcard_emulate.c ++++ b/libfreerdp/emu/scard/smartcard_emulate.c +@@ -407,3 +407,3 @@ LONG WINAPI Emulate_SCardEstablishContext(SmartcardEmulationContext* smartcard, + "SCardEstablishContext } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status), +- status); ++ WINPR_CXX_COMPAT_CAST(UINT32, status)); + +@@ -434,3 +434,3 @@ LONG WINAPI Emulate_SCardReleaseContext(SmartcardEmulationContext* smartcard, SC + "SCardReleaseContext } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status), +- status); ++ WINPR_CXX_COMPAT_CAST(UINT32, status)); + +@@ -461,3 +461,3 @@ LONG WINAPI Emulate_SCardIsValidContext(SmartcardEmulationContext* smartcard, SC + "SCardIsValidContext } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status), +- status); ++ WINPR_CXX_COMPAT_CAST(UINT32, status)); + +@@ -484,3 +484,3 @@ LONG WINAPI Emulate_SCardListReaderGroupsA( + "SCardListReaderGroupsA } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status), +- status); ++ WINPR_CXX_COMPAT_CAST(UINT32, status)); + +@@ -507,3 +507,3 @@ LONG WINAPI Emulate_SCardListReaderGroupsW( + "SCardListReaderGroupsW } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status), +- status); ++ WINPR_CXX_COMPAT_CAST(UINT32, status)); + +@@ -546,3 +546,3 @@ LONG WINAPI Emulate_SCardListReadersA(SmartcardEmulationContext* smartcard, SCAR + "SCardListReadersA } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status), +- status); ++ WINPR_CXX_COMPAT_CAST(UINT32, status)); + +@@ -590,3 +590,3 @@ LONG WINAPI Emulate_SCardListReadersW(SmartcardEmulationContext* smartcard, SCAR + "SCardListReadersW } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status), +- status); ++ WINPR_CXX_COMPAT_CAST(UINT32, status)); + +@@ -618,3 +618,3 @@ LONG WINAPI Emulate_SCardListCardsA(SmartcardEmulationContext* smartcard, SCARDC + "SCardListCardsA } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status), +- status); ++ WINPR_CXX_COMPAT_CAST(UINT32, status)); + +@@ -646,3 +646,3 @@ LONG WINAPI Emulate_SCardListCardsW(SmartcardEmulationContext* smartcard, SCARDC + "SCardListCardsW } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status), +- status); ++ WINPR_CXX_COMPAT_CAST(UINT32, status)); + +@@ -670,3 +670,3 @@ LONG WINAPI Emulate_SCardListInterfacesA( + "SCardListInterfacesA } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status), +- status); ++ WINPR_CXX_COMPAT_CAST(UINT32, status)); + +@@ -694,3 +694,3 @@ LONG WINAPI Emulate_SCardListInterfacesW( + "SCardListInterfacesW } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status), +- status); ++ WINPR_CXX_COMPAT_CAST(UINT32, status)); + +@@ -716,3 +716,3 @@ LONG WINAPI Emulate_SCardGetProviderIdA(SmartcardEmulationContext* smartcard, SC + "SCardGetProviderIdA } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status), +- status); ++ WINPR_CXX_COMPAT_CAST(UINT32, status)); + +@@ -738,3 +738,3 @@ LONG WINAPI Emulate_SCardGetProviderIdW(SmartcardEmulationContext* smartcard, SC + "SCardGetProviderIdW } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status), +- status); ++ WINPR_CXX_COMPAT_CAST(UINT32, status)); + +@@ -764,3 +764,3 @@ LONG WINAPI Emulate_SCardGetCardTypeProviderNameA( + "SCardGetCardTypeProviderNameA } status: %s (0x%08" PRIX32 ")", +- SCardGetErrorString(status), status); ++ SCardGetErrorString(status), WINPR_CXX_COMPAT_CAST(UINT32, status)); + +@@ -790,3 +790,3 @@ LONG WINAPI Emulate_SCardGetCardTypeProviderNameW( + "SCardGetCardTypeProviderNameW } status: %s (0x%08" PRIX32 ")", +- SCardGetErrorString(status), status); ++ SCardGetErrorString(status), WINPR_CXX_COMPAT_CAST(UINT32, status)); + +@@ -811,3 +811,3 @@ LONG WINAPI Emulate_SCardIntroduceReaderGroupA(SmartcardEmulationContext* smartc + "SCardIntroduceReaderGroupA } status: %s (0x%08" PRIX32 ")", +- SCardGetErrorString(status), status); ++ SCardGetErrorString(status), WINPR_CXX_COMPAT_CAST(UINT32, status)); + +@@ -832,3 +832,3 @@ LONG WINAPI Emulate_SCardIntroduceReaderGroupW(SmartcardEmulationContext* smartc + "SCardIntroduceReaderGroupW } status: %s (0x%08" PRIX32 ")", +- SCardGetErrorString(status), status); ++ SCardGetErrorString(status), WINPR_CXX_COMPAT_CAST(UINT32, status)); + +@@ -853,3 +853,3 @@ LONG WINAPI Emulate_SCardForgetReaderGroupA(SmartcardEmulationContext* smartcard + "SCardForgetReaderGroupA } status: %s (0x%08" PRIX32 ")", +- SCardGetErrorString(status), status); ++ SCardGetErrorString(status), WINPR_CXX_COMPAT_CAST(UINT32, status)); + +@@ -874,3 +874,3 @@ LONG WINAPI Emulate_SCardForgetReaderGroupW(SmartcardEmulationContext* smartcard + "SCardForgetReaderGroupW } status: %s (0x%08" PRIX32 ")", +- SCardGetErrorString(status), status); ++ SCardGetErrorString(status), WINPR_CXX_COMPAT_CAST(UINT32, status)); + +@@ -899,3 +899,3 @@ LONG WINAPI Emulate_SCardIntroduceReaderA(SmartcardEmulationContext* smartcard, + "SCardIntroduceReaderA } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status), +- status); ++ WINPR_CXX_COMPAT_CAST(UINT32, status)); + +@@ -924,3 +924,3 @@ LONG WINAPI Emulate_SCardIntroduceReaderW(SmartcardEmulationContext* smartcard, + "SCardIntroduceReaderW } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status), +- status); ++ WINPR_CXX_COMPAT_CAST(UINT32, status)); + +@@ -946,3 +946,3 @@ LONG WINAPI Emulate_SCardForgetReaderA(SmartcardEmulationContext* smartcard, SCA + "SCardForgetReaderA } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status), +- status); ++ WINPR_CXX_COMPAT_CAST(UINT32, status)); + +@@ -968,3 +968,3 @@ LONG WINAPI Emulate_SCardForgetReaderW(SmartcardEmulationContext* smartcard, SCA + "SCardForgetReaderW } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status), +- status); ++ WINPR_CXX_COMPAT_CAST(UINT32, status)); + +@@ -993,3 +993,3 @@ LONG WINAPI Emulate_SCardAddReaderToGroupA(SmartcardEmulationContext* smartcard, + "SCardAddReaderToGroupA } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status), +- status); ++ WINPR_CXX_COMPAT_CAST(UINT32, status)); + +@@ -1018,3 +1018,3 @@ LONG WINAPI Emulate_SCardAddReaderToGroupW(SmartcardEmulationContext* smartcard, + "SCardAddReaderToGroupW } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status), +- status); ++ WINPR_CXX_COMPAT_CAST(UINT32, status)); + +@@ -1043,3 +1043,3 @@ LONG WINAPI Emulate_SCardRemoveReaderFromGroupA(SmartcardEmulationContext* smart + "SCardRemoveReaderFromGroupA } status: %s (0x%08" PRIX32 ")", +- SCardGetErrorString(status), status); ++ SCardGetErrorString(status), WINPR_CXX_COMPAT_CAST(UINT32, status)); + +@@ -1068,3 +1068,3 @@ LONG WINAPI Emulate_SCardRemoveReaderFromGroupW(SmartcardEmulationContext* smart + "SCardRemoveReaderFromGroupW } status: %s (0x%08" PRIX32 ")", +- SCardGetErrorString(status), status); ++ SCardGetErrorString(status), WINPR_CXX_COMPAT_CAST(UINT32, status)); + +@@ -1098,3 +1098,3 @@ LONG WINAPI Emulate_SCardIntroduceCardTypeA(SmartcardEmulationContext* smartcard + "SCardIntroduceCardTypeA } status: %s (0x%08" PRIX32 ")", +- SCardGetErrorString(status), status); ++ SCardGetErrorString(status), WINPR_CXX_COMPAT_CAST(UINT32, status)); + +@@ -1128,3 +1128,3 @@ LONG WINAPI Emulate_SCardIntroduceCardTypeW(SmartcardEmulationContext* smartcard + "SCardIntroduceCardTypeW } status: %s (0x%08" PRIX32 ")", +- SCardGetErrorString(status), status); ++ SCardGetErrorString(status), WINPR_CXX_COMPAT_CAST(UINT32, status)); + +@@ -1152,3 +1152,3 @@ LONG WINAPI Emulate_SCardSetCardTypeProviderNameA(SmartcardEmulationContext* sma + "SCardSetCardTypeProviderNameA } status: %s (0x%08" PRIX32 ")", +- SCardGetErrorString(status), status); ++ SCardGetErrorString(status), WINPR_CXX_COMPAT_CAST(UINT32, status)); + +@@ -1176,3 +1176,3 @@ LONG WINAPI Emulate_SCardSetCardTypeProviderNameW(SmartcardEmulationContext* sma + "SCardSetCardTypeProviderNameW } status: %s (0x%08" PRIX32 ")", +- SCardGetErrorString(status), status); ++ SCardGetErrorString(status), WINPR_CXX_COMPAT_CAST(UINT32, status)); + +@@ -1197,3 +1197,3 @@ LONG WINAPI Emulate_SCardForgetCardTypeA(SmartcardEmulationContext* smartcard, + "SCardForgetCardTypeA } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status), +- status); ++ WINPR_CXX_COMPAT_CAST(UINT32, status)); + +@@ -1218,3 +1218,3 @@ LONG WINAPI Emulate_SCardForgetCardTypeW(SmartcardEmulationContext* smartcard, + "SCardForgetCardTypeW } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status), +- status); ++ WINPR_CXX_COMPAT_CAST(UINT32, status)); + +@@ -1241,3 +1241,3 @@ LONG WINAPI Emulate_SCardFreeMemory(SmartcardEmulationContext* smartcard, SCARDC + "SCardFreeMemory } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status), +- status); ++ WINPR_CXX_COMPAT_CAST(UINT32, status)); + +@@ -1293,3 +1293,3 @@ LONG WINAPI Emulate_SCardLocateCardsA(SmartcardEmulationContext* smartcard, SCAR + "SCardLocateCardsA } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status), +- status); ++ WINPR_CXX_COMPAT_CAST(UINT32, status)); + +@@ -1317,3 +1317,3 @@ LONG WINAPI Emulate_SCardLocateCardsW(SmartcardEmulationContext* smartcard, SCAR + "SCardLocateCardsW } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status), +- status); ++ WINPR_CXX_COMPAT_CAST(UINT32, status)); + +@@ -1343,3 +1343,3 @@ LONG WINAPI Emulate_SCardLocateCardsByATRA(SmartcardEmulationContext* smartcard, + "SCardLocateCardsByATRA } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status), +- status); ++ WINPR_CXX_COMPAT_CAST(UINT32, status)); + +@@ -1369,3 +1369,3 @@ LONG WINAPI Emulate_SCardLocateCardsByATRW(SmartcardEmulationContext* smartcard, + "SCardLocateCardsByATRW } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status), +- status); ++ WINPR_CXX_COMPAT_CAST(UINT32, status)); + +@@ -1451,3 +1451,3 @@ LONG WINAPI Emulate_SCardGetStatusChangeA(SmartcardEmulationContext* smartcard, + "SCardGetStatusChangeA } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status), +- status); ++ WINPR_CXX_COMPAT_CAST(UINT32, status)); + +@@ -1532,3 +1532,3 @@ LONG WINAPI Emulate_SCardGetStatusChangeW(SmartcardEmulationContext* smartcard, + "SCardGetStatusChangeW } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status), +- status); ++ WINPR_CXX_COMPAT_CAST(UINT32, status)); + +@@ -1552,3 +1552,4 @@ LONG WINAPI Emulate_SCardCancel(SmartcardEmulationContext* smartcard, SCARDCONTE + WLog_Print(smartcard->log, smartcard->log_default_level, +- "SCardCancel } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status), status); ++ "SCardCancel } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status), ++ WINPR_CXX_COMPAT_CAST(UINT32, status)); + +@@ -1651,3 +1652,4 @@ LONG WINAPI Emulate_SCardConnectA(SmartcardEmulationContext* smartcard, SCARDCON + WLog_Print(smartcard->log, smartcard->log_default_level, +- "SCardConnectA } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status), status); ++ "SCardConnectA } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status), ++ WINPR_CXX_COMPAT_CAST(UINT32, status)); + +@@ -1676,3 +1678,4 @@ LONG WINAPI Emulate_SCardConnectW(SmartcardEmulationContext* smartcard, SCARDCON + WLog_Print(smartcard->log, smartcard->log_default_level, +- "SCardConnectW } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status), status); ++ "SCardConnectW } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status), ++ WINPR_CXX_COMPAT_CAST(UINT32, status)); + +@@ -1708,3 +1711,3 @@ LONG WINAPI Emulate_SCardReconnect(SmartcardEmulationContext* smartcard, SCARDHA + "SCardReconnect } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status), +- status); ++ WINPR_CXX_COMPAT_CAST(UINT32, status)); + +@@ -1735,3 +1738,3 @@ LONG WINAPI Emulate_SCardDisconnect(SmartcardEmulationContext* smartcard, SCARDH + "SCardDisconnect } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status), +- status); ++ WINPR_CXX_COMPAT_CAST(UINT32, status)); + +@@ -1759,3 +1762,3 @@ LONG WINAPI Emulate_SCardBeginTransaction(SmartcardEmulationContext* smartcard, + "SCardBeginTransaction } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status), +- status); ++ WINPR_CXX_COMPAT_CAST(UINT32, status)); + +@@ -1786,3 +1789,3 @@ LONG WINAPI Emulate_SCardEndTransaction(SmartcardEmulationContext* smartcard, SC + "SCardEndTransaction } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status), +- status); ++ WINPR_CXX_COMPAT_CAST(UINT32, status)); + +@@ -1810,3 +1813,3 @@ LONG WINAPI Emulate_SCardCancelTransaction(SmartcardEmulationContext* smartcard, + "SCardCancelTransaction } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status), +- status); ++ WINPR_CXX_COMPAT_CAST(UINT32, status)); + +@@ -1868,3 +1871,4 @@ LONG WINAPI Emulate_SCardState(SmartcardEmulationContext* smartcard, SCARDHANDLE + WLog_Print(smartcard->log, smartcard->log_default_level, +- "SCardState } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status), status); ++ "SCardState } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status), ++ WINPR_CXX_COMPAT_CAST(UINT32, status)); + +@@ -1916,3 +1920,4 @@ LONG WINAPI Emulate_SCardStatusA(SmartcardEmulationContext* smartcard, SCARDHAND + WLog_Print(smartcard->log, smartcard->log_default_level, +- "SCardStatusA } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status), status); ++ "SCardStatusA } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status), ++ WINPR_CXX_COMPAT_CAST(UINT32, status)); + +@@ -1963,3 +1968,4 @@ LONG WINAPI Emulate_SCardStatusW(SmartcardEmulationContext* smartcard, SCARDHAND + WLog_Print(smartcard->log, smartcard->log_default_level, +- "SCardStatusW } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status), status); ++ "SCardStatusW } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status), ++ WINPR_CXX_COMPAT_CAST(UINT32, status)); + +@@ -2009,3 +2015,4 @@ LONG WINAPI Emulate_SCardTransmit(SmartcardEmulationContext* smartcard, SCARDHAN + WLog_Print(smartcard->log, smartcard->log_default_level, +- "SCardTransmit } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status), status); ++ "SCardTransmit } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status), ++ WINPR_CXX_COMPAT_CAST(UINT32, status)); + +@@ -2035,3 +2042,3 @@ LONG WINAPI Emulate_SCardGetTransmitCount(SmartcardEmulationContext* smartcard, + "SCardGetTransmitCount } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status), +- status); ++ WINPR_CXX_COMPAT_CAST(UINT32, status)); + +@@ -2064,3 +2071,4 @@ LONG WINAPI Emulate_SCardControl( + WLog_Print(smartcard->log, smartcard->log_default_level, +- "SCardControl } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status), status); ++ "SCardControl } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status), ++ WINPR_CXX_COMPAT_CAST(UINT32, status)); + +@@ -2089,3 +2097,3 @@ LONG WINAPI Emulate_SCardGetAttrib(SmartcardEmulationContext* smartcard, SCARDHA + "SCardGetAttrib } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status), +- status); ++ WINPR_CXX_COMPAT_CAST(UINT32, status)); + +@@ -2112,3 +2120,3 @@ LONG WINAPI Emulate_SCardSetAttrib(SmartcardEmulationContext* smartcard, SCARDHA + "SCardSetAttrib } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status), +- status); ++ WINPR_CXX_COMPAT_CAST(UINT32, status)); + +@@ -2133,3 +2141,3 @@ LONG WINAPI Emulate_SCardUIDlgSelectCardA(SmartcardEmulationContext* smartcard, + "SCardUIDlgSelectCardA } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status), +- status); ++ WINPR_CXX_COMPAT_CAST(UINT32, status)); + +@@ -2154,3 +2162,3 @@ LONG WINAPI Emulate_SCardUIDlgSelectCardW(SmartcardEmulationContext* smartcard, + "SCardUIDlgSelectCardW } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status), +- status); ++ WINPR_CXX_COMPAT_CAST(UINT32, status)); + +@@ -2175,3 +2183,3 @@ LONG WINAPI Emulate_GetOpenCardNameA(SmartcardEmulationContext* smartcard, + "GetOpenCardNameA } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status), +- status); ++ WINPR_CXX_COMPAT_CAST(UINT32, status)); + +@@ -2196,3 +2204,3 @@ LONG WINAPI Emulate_GetOpenCardNameW(SmartcardEmulationContext* smartcard, + "GetOpenCardNameW } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status), +- status); ++ WINPR_CXX_COMPAT_CAST(UINT32, status)); + +@@ -2214,3 +2222,3 @@ LONG WINAPI Emulate_SCardDlgExtendedError(SmartcardEmulationContext* smartcard) + "SCardDlgExtendedError } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status), +- status); ++ WINPR_CXX_COMPAT_CAST(UINT32, status)); + +@@ -2258,3 +2266,3 @@ LONG WINAPI Emulate_SCardReadCacheA(SmartcardEmulationContext* smartcard, SCARDC + "SCardReadCacheA } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status), +- status); ++ WINPR_CXX_COMPAT_CAST(UINT32, status)); + +@@ -2301,3 +2309,3 @@ LONG WINAPI Emulate_SCardReadCacheW(SmartcardEmulationContext* smartcard, SCARDC + "SCardReadCacheW } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status), +- status); ++ WINPR_CXX_COMPAT_CAST(UINT32, status)); + +@@ -2375,3 +2383,3 @@ LONG WINAPI Emulate_SCardWriteCacheA(SmartcardEmulationContext* smartcard, SCARD + "SCardWriteCacheA } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status), +- status); ++ WINPR_CXX_COMPAT_CAST(UINT32, status)); + +@@ -2409,3 +2417,3 @@ LONG WINAPI Emulate_SCardWriteCacheW(SmartcardEmulationContext* smartcard, SCARD + "SCardWriteCacheW } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status), +- status); ++ WINPR_CXX_COMPAT_CAST(UINT32, status)); + +@@ -2442,3 +2450,3 @@ LONG WINAPI Emulate_SCardGetReaderIconA(SmartcardEmulationContext* smartcard, SC + "SCardGetReaderIconA } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status), +- status); ++ WINPR_CXX_COMPAT_CAST(UINT32, status)); + +@@ -2475,3 +2483,3 @@ LONG WINAPI Emulate_SCardGetReaderIconW(SmartcardEmulationContext* smartcard, SC + "SCardGetReaderIconW } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status), +- status); ++ WINPR_CXX_COMPAT_CAST(UINT32, status)); + +@@ -2502,3 +2510,3 @@ LONG WINAPI Emulate_SCardGetDeviceTypeIdA(SmartcardEmulationContext* smartcard, + "SCardGetDeviceTypeIdA } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status), +- status); ++ WINPR_CXX_COMPAT_CAST(UINT32, status)); + +@@ -2529,3 +2537,3 @@ LONG WINAPI Emulate_SCardGetDeviceTypeIdW(SmartcardEmulationContext* smartcard, + "SCardGetDeviceTypeIdW } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status), +- status); ++ WINPR_CXX_COMPAT_CAST(UINT32, status)); + +@@ -2556,3 +2564,3 @@ LONG WINAPI Emulate_SCardGetReaderDeviceInstanceIdA( + "SCardGetReaderDeviceInstanceIdA } status: %s (0x%08" PRIX32 ")", +- SCardGetErrorString(status), status); ++ SCardGetErrorString(status), WINPR_CXX_COMPAT_CAST(UINT32, status)); + +@@ -2583,3 +2591,3 @@ LONG WINAPI Emulate_SCardGetReaderDeviceInstanceIdW( + "SCardGetReaderDeviceInstanceIdW } status: %s (0x%08" PRIX32 ")", +- SCardGetErrorString(status), status); ++ SCardGetErrorString(status), WINPR_CXX_COMPAT_CAST(UINT32, status)); + +@@ -2608,3 +2616,3 @@ LONG WINAPI Emulate_SCardListReadersWithDeviceInstanceIdA( + "SCardListReadersWithDeviceInstanceIdA } status: %s (0x%08" PRIX32 ")", +- SCardGetErrorString(status), status); ++ SCardGetErrorString(status), WINPR_CXX_COMPAT_CAST(UINT32, status)); + +@@ -2632,3 +2640,3 @@ LONG WINAPI Emulate_SCardListReadersWithDeviceInstanceIdW( + "SCardListReadersWithDeviceInstanceIdW } status: %s (0x%08" PRIX32 ")", +- SCardGetErrorString(status), status); ++ SCardGetErrorString(status), WINPR_CXX_COMPAT_CAST(UINT32, status)); + +@@ -2652,3 +2660,4 @@ LONG WINAPI Emulate_SCardAudit(SmartcardEmulationContext* smartcard, SCARDCONTEX + WLog_Print(smartcard->log, smartcard->log_default_level, +- "SCardAudit } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status), status); ++ "SCardAudit } status: %s (0x%08" PRIX32 ")", SCardGetErrorString(status), ++ WINPR_CXX_COMPAT_CAST(UINT32, status)); + +diff --git a/server/proxy/channels/pf_channel_drdynvc.c b/server/proxy/channels/pf_channel_drdynvc.c +index 0d0ba6e90..afcc5532a 100644 +--- a/server/proxy/channels/pf_channel_drdynvc.c ++++ b/server/proxy/channels/pf_channel_drdynvc.c +@@ -402,3 +402,3 @@ static PfChannelResult DynvcTrackerPeekFn(ChannelStateTracker* tracker, BOOL fir + +- WLog_Print(dynChannelContext->log, WLOG_DEBUG, "Adding channel '%s'[%d]", ++ WLog_Print(dynChannelContext->log, WLOG_DEBUG, "Adding channel '%s'[%" PRIu32 "]", + dynChannel->channelName, dynChannel->channelId); +@@ -589,3 +589,3 @@ static PfChannelResult DynvcTrackerPeekFn(ChannelStateTracker* tracker, BOOL fir + default: +- WLog_Print(dynChannelContext->log, WLOG_ERROR, "unknown channel mode %d", ++ WLog_Print(dynChannelContext->log, WLOG_ERROR, "unknown channel mode %u", + dynChannel->channelMode); +diff --git a/server/proxy/channels/pf_channel_rdpdr.c b/server/proxy/channels/pf_channel_rdpdr.c +index e46f5d956..0025997a1 100644 +--- a/server/proxy/channels/pf_channel_rdpdr.c ++++ b/server/proxy/channels/pf_channel_rdpdr.c +@@ -321,3 +321,3 @@ static BOOL rdpdr_check_version(BOOL server, wLog* log, UINT16 versionMajor, UIN + { +- RX_LOG(server, log, WLOG_WARN, "[%s | %s] expected MajorVersion %" PRIu16 ", got %" PRIu16, ++ RX_LOG(server, log, WLOG_WARN, "[%s | %s] expected MajorVersion %d, got %" PRIu16, + rdpdr_component_string(component), rdpdr_packetid_string(PacketId), +@@ -468,3 +468,3 @@ static UINT rdpdr_process_client_name_request(pf_channel_server_context* rdpdr, + SERVER_RX_LOG( +- rdpdr->log, WLOG_WARN, "[%s | %s]: missing data, got %" PRIu32 ", expected %" PRIu32, ++ rdpdr->log, WLOG_WARN, "[%s | %s]: missing data, got %" PRIuz ", expected %" PRIu32, + rdpdr_component_string(RDPDR_CTYP_CORE), rdpdr_packetid_string(PAKID_CORE_CLIENT_NAME), +diff --git a/winpr/libwinpr/comm/comm.c b/winpr/libwinpr/comm/comm.c +index 8dd5b74e7..301af0529 100644 +--- a/winpr/libwinpr/comm/comm.c ++++ b/winpr/libwinpr/comm/comm.c +@@ -647,3 +647,3 @@ BOOL SetCommState(HANDLE hFile, LPDCB lpDCB) + default: +- CommLog_Print(WLOG_WARN, "Unexpected fDtrControl value: %" PRIu32 "\n", ++ CommLog_Print(WLOG_WARN, "Unexpected fDtrControl value: %" PRId32 "\n", + lpDCB->fDtrControl); +@@ -702,3 +702,3 @@ BOOL SetCommState(HANDLE hFile, LPDCB lpDCB) + default: +- CommLog_Print(WLOG_WARN, "Unexpected fRtsControl value: %" PRIu32 "\n", ++ CommLog_Print(WLOG_WARN, "Unexpected fRtsControl value: %" PRId32 "\n", + lpDCB->fRtsControl); +diff --git a/winpr/libwinpr/comm/comm_ioctl.c b/winpr/libwinpr/comm/comm_ioctl.c +index 979f1e7b8..5e4bd594d 100644 +--- a/winpr/libwinpr/comm/comm_ioctl.c ++++ b/winpr/libwinpr/comm/comm_ioctl.c +@@ -103,3 +103,3 @@ static BOOL s_CommDeviceIoControl(HANDLE hDevice, DWORD dwIoControlCode, LPVOID + default: +- CommLog_Print(WLOG_DEBUG, "Unknown remote serial driver (%d), using SerCx2.sys", ++ CommLog_Print(WLOG_DEBUG, "Unknown remote serial driver (%u), using SerCx2.sys", + pComm->serverSerialDriverId); +diff --git a/winpr/libwinpr/comm/comm_serial_sys.c b/winpr/libwinpr/comm/comm_serial_sys.c +index 039234dc2..131cacca9 100644 +--- a/winpr/libwinpr/comm/comm_serial_sys.c ++++ b/winpr/libwinpr/comm/comm_serial_sys.c +@@ -1153,3 +1153,3 @@ static BOOL set_queue_size(WINPR_ATTR_UNUSED WINPR_COMM* pComm, const SERIAL_QUE + "Requested an incompatible input buffer size: %" PRIu32 +- ", keeping on with a %" PRIu32 " bytes buffer.", ++ ", keeping on with a %d bytes buffer.", + pQueueSize->InSize, N_TTY_BUF_SIZE); +@@ -1159,3 +1159,3 @@ static BOOL set_queue_size(WINPR_ATTR_UNUSED WINPR_COMM* pComm, const SERIAL_QUE + "Requested an incompatible output buffer size: %" PRIu32 +- ", keeping on with a %" PRIu32 " bytes buffer.", ++ ", keeping on with a %d bytes buffer.", + pQueueSize->OutSize, N_TTY_BUF_SIZE); +diff --git a/winpr/libwinpr/sspi/sspi.c b/winpr/libwinpr/sspi/sspi.c +index d795cb491..01076856f 100644 +--- a/winpr/libwinpr/sspi/sspi.c ++++ b/winpr/libwinpr/sspi/sspi.c +@@ -525,3 +525,3 @@ SECURITY_STATUS SEC_ENTRY sspi_EnumerateSecurityPackagesW(ULONG* pcPackages, + WLog_Print(g_Log, WLOG_DEBUG, "EnumerateSecurityPackagesW: %s (0x%08" PRIX32 ")", +- GetSecurityStatusString(status), status); ++ GetSecurityStatusString(status), WINPR_CXX_COMPAT_CAST(UINT32, status)); + return status; +@@ -544,3 +544,3 @@ SECURITY_STATUS SEC_ENTRY sspi_EnumerateSecurityPackagesA(ULONG* pcPackages, + WLog_Print(g_Log, WLOG_DEBUG, "EnumerateSecurityPackagesA: %s (0x%08" PRIX32 ")", +- GetSecurityStatusString(status), status); ++ GetSecurityStatusString(status), WINPR_CXX_COMPAT_CAST(UINT32, status)); + return status; +@@ -577,3 +577,3 @@ SECURITY_STATUS SEC_ENTRY sspi_QuerySecurityPackageInfoW(SEC_WCHAR* pszPackageNa + WLog_Print(g_Log, WLOG_DEBUG, "QuerySecurityPackageInfoW: %s (0x%08" PRIX32 ")", +- GetSecurityStatusString(status), status); ++ GetSecurityStatusString(status), WINPR_CXX_COMPAT_CAST(UINT32, status)); + return status; +@@ -596,3 +596,3 @@ SECURITY_STATUS SEC_ENTRY sspi_QuerySecurityPackageInfoA(SEC_CHAR* pszPackageNam + WLog_Print(g_Log, WLOG_DEBUG, "QuerySecurityPackageInfoA: %s (0x%08" PRIX32 ")", +- GetSecurityStatusString(status), status); ++ GetSecurityStatusString(status), WINPR_CXX_COMPAT_CAST(UINT32, status)); + return status; +@@ -621,3 +621,3 @@ SECURITY_STATUS SEC_ENTRY sspi_AcquireCredentialsHandleW( + WLog_Print(g_Log, WLOG_DEBUG, "AcquireCredentialsHandleW: %s (0x%08" PRIX32 ")", +- GetSecurityStatusString(status), status); ++ GetSecurityStatusString(status), WINPR_CXX_COMPAT_CAST(UINT32, status)); + return status; +@@ -644,3 +644,3 @@ SECURITY_STATUS SEC_ENTRY sspi_AcquireCredentialsHandleA( + WLog_Print(g_Log, WLOG_DEBUG, "AcquireCredentialsHandleA: %s (0x%08" PRIX32 ")", +- GetSecurityStatusString(status), status); ++ GetSecurityStatusString(status), WINPR_CXX_COMPAT_CAST(UINT32, status)); + return status; +@@ -663,3 +663,3 @@ SECURITY_STATUS SEC_ENTRY sspi_ExportSecurityContext(PCtxtHandle phContext, ULON + WLog_Print(g_Log, WLOG_DEBUG, "ExportSecurityContext: %s (0x%08" PRIX32 ")", +- GetSecurityStatusString(status), status); ++ GetSecurityStatusString(status), WINPR_CXX_COMPAT_CAST(UINT32, status)); + return status; +@@ -681,3 +681,3 @@ SECURITY_STATUS SEC_ENTRY sspi_FreeCredentialsHandle(PCredHandle phCredential) + WLog_Print(g_Log, WLOG_DEBUG, "FreeCredentialsHandle: %s (0x%08" PRIX32 ")", +- GetSecurityStatusString(status), status); ++ GetSecurityStatusString(status), WINPR_CXX_COMPAT_CAST(UINT32, status)); + return status; +@@ -701,3 +701,3 @@ SECURITY_STATUS SEC_ENTRY sspi_ImportSecurityContextW(SEC_WCHAR* pszPackage, + WLog_Print(g_Log, WLOG_DEBUG, "ImportSecurityContextW: %s (0x%08" PRIX32 ")", +- GetSecurityStatusString(status), status); ++ GetSecurityStatusString(status), WINPR_CXX_COMPAT_CAST(UINT32, status)); + return status; +@@ -721,3 +721,3 @@ SECURITY_STATUS SEC_ENTRY sspi_ImportSecurityContextA(SEC_CHAR* pszPackage, + WLog_Print(g_Log, WLOG_DEBUG, "ImportSecurityContextA: %s (0x%08" PRIX32 ")", +- GetSecurityStatusString(status), status); ++ GetSecurityStatusString(status), WINPR_CXX_COMPAT_CAST(UINT32, status)); + return status; +@@ -740,3 +740,3 @@ SECURITY_STATUS SEC_ENTRY sspi_QueryCredentialsAttributesW(PCredHandle phCredent + WLog_Print(g_Log, WLOG_DEBUG, "QueryCredentialsAttributesW: %s (0x%08" PRIX32 ")", +- GetSecurityStatusString(status), status); ++ GetSecurityStatusString(status), WINPR_CXX_COMPAT_CAST(UINT32, status)); + return status; +@@ -759,3 +759,3 @@ SECURITY_STATUS SEC_ENTRY sspi_QueryCredentialsAttributesA(PCredHandle phCredent + WLog_Print(g_Log, WLOG_DEBUG, "QueryCredentialsAttributesA: %s (0x%08" PRIX32 ")", +- GetSecurityStatusString(status), status); ++ GetSecurityStatusString(status), WINPR_CXX_COMPAT_CAST(UINT32, status)); + return status; +@@ -786,3 +786,3 @@ SECURITY_STATUS SEC_ENTRY sspi_AcceptSecurityContext(PCredHandle phCredential, + WLog_Print(g_Log, WLOG_DEBUG, "AcceptSecurityContext: %s (0x%08" PRIX32 ")", +- GetSecurityStatusString(status), status); ++ GetSecurityStatusString(status), WINPR_CXX_COMPAT_CAST(UINT32, status)); + return status; +@@ -804,3 +804,3 @@ SECURITY_STATUS SEC_ENTRY sspi_ApplyControlToken(PCtxtHandle phContext, PSecBuff + WLog_Print(g_Log, WLOG_DEBUG, "ApplyControlToken: %s (0x%08" PRIX32 ")", +- GetSecurityStatusString(status), status); ++ GetSecurityStatusString(status), WINPR_CXX_COMPAT_CAST(UINT32, status)); + return status; +@@ -822,3 +822,3 @@ SECURITY_STATUS SEC_ENTRY sspi_CompleteAuthToken(PCtxtHandle phContext, PSecBuff + WLog_Print(g_Log, WLOG_DEBUG, "CompleteAuthToken: %s (0x%08" PRIX32 ")", +- GetSecurityStatusString(status), status); ++ GetSecurityStatusString(status), WINPR_CXX_COMPAT_CAST(UINT32, status)); + return status; +@@ -840,3 +840,3 @@ SECURITY_STATUS SEC_ENTRY sspi_DeleteSecurityContext(PCtxtHandle phContext) + WLog_Print(g_Log, WLOG_DEBUG, "DeleteSecurityContext: %s (0x%08" PRIX32 ")", +- GetSecurityStatusString(status), status); ++ GetSecurityStatusString(status), WINPR_CXX_COMPAT_CAST(UINT32, status)); + return status; +@@ -858,3 +858,3 @@ SECURITY_STATUS SEC_ENTRY sspi_FreeContextBuffer(void* pvContextBuffer) + WLog_Print(g_Log, WLOG_DEBUG, "FreeContextBuffer: %s (0x%08" PRIX32 ")", +- GetSecurityStatusString(status), status); ++ GetSecurityStatusString(status), WINPR_CXX_COMPAT_CAST(UINT32, status)); + return status; +@@ -876,3 +876,3 @@ SECURITY_STATUS SEC_ENTRY sspi_ImpersonateSecurityContext(PCtxtHandle phContext) + WLog_Print(g_Log, WLOG_DEBUG, "ImpersonateSecurityContext: %s (0x%08" PRIX32 ")", +- GetSecurityStatusString(status), status); ++ GetSecurityStatusString(status), WINPR_CXX_COMPAT_CAST(UINT32, status)); + return status; +@@ -899,3 +899,3 @@ SECURITY_STATUS SEC_ENTRY sspi_InitializeSecurityContextW( + WLog_Print(g_Log, WLOG_DEBUG, "InitializeSecurityContextW: %s (0x%08" PRIX32 ")", +- GetSecurityStatusString(status), status); ++ GetSecurityStatusString(status), WINPR_CXX_COMPAT_CAST(UINT32, status)); + return status; +@@ -922,3 +922,3 @@ SECURITY_STATUS SEC_ENTRY sspi_InitializeSecurityContextA( + WLog_Print(g_Log, WLOG_DEBUG, "InitializeSecurityContextA: %s (0x%08" PRIX32 ")", +- GetSecurityStatusString(status), status); ++ GetSecurityStatusString(status), WINPR_CXX_COMPAT_CAST(UINT32, status)); + return status; +@@ -941,3 +941,3 @@ SECURITY_STATUS SEC_ENTRY sspi_QueryContextAttributesW(PCtxtHandle phContext, UL + WLog_Print(g_Log, WLOG_DEBUG, "QueryContextAttributesW: %s (0x%08" PRIX32 ")", +- GetSecurityStatusString(status), status); ++ GetSecurityStatusString(status), WINPR_CXX_COMPAT_CAST(UINT32, status)); + return status; +@@ -960,3 +960,3 @@ SECURITY_STATUS SEC_ENTRY sspi_QueryContextAttributesA(PCtxtHandle phContext, UL + WLog_Print(g_Log, WLOG_DEBUG, "QueryContextAttributesA: %s (0x%08" PRIX32 ")", +- GetSecurityStatusString(status), status); ++ GetSecurityStatusString(status), WINPR_CXX_COMPAT_CAST(UINT32, status)); + return status; +@@ -978,3 +978,3 @@ SECURITY_STATUS SEC_ENTRY sspi_QuerySecurityContextToken(PCtxtHandle phContext, + WLog_Print(g_Log, WLOG_DEBUG, "QuerySecurityContextToken: %s (0x%08" PRIX32 ")", +- GetSecurityStatusString(status), status); ++ GetSecurityStatusString(status), WINPR_CXX_COMPAT_CAST(UINT32, status)); + return status; +@@ -997,3 +997,3 @@ SECURITY_STATUS SEC_ENTRY sspi_SetContextAttributesW(PCtxtHandle phContext, ULON + WLog_Print(g_Log, WLOG_DEBUG, "SetContextAttributesW: %s (0x%08" PRIX32 ")", +- GetSecurityStatusString(status), status); ++ GetSecurityStatusString(status), WINPR_CXX_COMPAT_CAST(UINT32, status)); + return status; +@@ -1016,3 +1016,3 @@ SECURITY_STATUS SEC_ENTRY sspi_SetContextAttributesA(PCtxtHandle phContext, ULON + WLog_Print(g_Log, WLOG_DEBUG, "SetContextAttributesA: %s (0x%08" PRIX32 ")", +- GetSecurityStatusString(status), status); ++ GetSecurityStatusString(status), WINPR_CXX_COMPAT_CAST(UINT32, status)); + return status; +@@ -1034,3 +1034,3 @@ SECURITY_STATUS SEC_ENTRY sspi_RevertSecurityContext(PCtxtHandle phContext) + WLog_Print(g_Log, WLOG_DEBUG, "RevertSecurityContext: %s (0x%08" PRIX32 ")", +- GetSecurityStatusString(status), status); ++ GetSecurityStatusString(status), WINPR_CXX_COMPAT_CAST(UINT32, status)); + return status; +@@ -1055,3 +1055,3 @@ SECURITY_STATUS SEC_ENTRY sspi_DecryptMessage(PCtxtHandle phContext, PSecBufferD + WLog_Print(g_Log, WLOG_DEBUG, "DecryptMessage: %s (0x%08" PRIX32 ")", +- GetSecurityStatusString(status), status); ++ GetSecurityStatusString(status), WINPR_CXX_COMPAT_CAST(UINT32, status)); + return status; +@@ -1074,3 +1074,3 @@ SECURITY_STATUS SEC_ENTRY sspi_EncryptMessage(PCtxtHandle phContext, ULONG fQOP, + WLog_Print(g_Log, WLOG_DEBUG, "EncryptMessage: %s (0x%08" PRIX32 ")", +- GetSecurityStatusString(status), status); ++ GetSecurityStatusString(status), WINPR_CXX_COMPAT_CAST(UINT32, status)); + return status; +@@ -1093,3 +1093,3 @@ SECURITY_STATUS SEC_ENTRY sspi_MakeSignature(PCtxtHandle phContext, ULONG fQOP, + WLog_Print(g_Log, WLOG_DEBUG, "MakeSignature: %s (0x%08" PRIX32 ")", +- GetSecurityStatusString(status), status); ++ GetSecurityStatusString(status), WINPR_CXX_COMPAT_CAST(UINT32, status)); + return status; +@@ -1112,3 +1112,3 @@ SECURITY_STATUS SEC_ENTRY sspi_VerifySignature(PCtxtHandle phContext, PSecBuffer + WLog_Print(g_Log, WLOG_DEBUG, "VerifySignature: %s (0x%08" PRIX32 ")", +- GetSecurityStatusString(status), status); ++ GetSecurityStatusString(status), WINPR_CXX_COMPAT_CAST(UINT32, status)); + return status; +diff --git a/winpr/libwinpr/timezone/timezone.c b/winpr/libwinpr/timezone/timezone.c +index bd3454374..2166c00c2 100644 +--- a/winpr/libwinpr/timezone/timezone.c ++++ b/winpr/libwinpr/timezone/timezone.c +@@ -618,3 +618,3 @@ static void log_timezone_(const DYNAMIC_TIME_ZONE_INFORMATION* tzif, DWORD resul + +- log_print(log, level, file, fkt, line, " Bias=%" PRIu32, tzif->Bias); ++ log_print(log, level, file, fkt, line, " Bias=%" PRId32, tzif->Bias); + (void)ConvertWCharNToUtf8(tzif->StandardName, ARRAYSIZE(tzif->StandardName), buffer, +@@ -624,3 +624,3 @@ static void log_timezone_(const DYNAMIC_TIME_ZONE_INFORMATION* tzif, DWORD resul + systemtime2str(&tzif->StandardDate, buffer, sizeof(buffer))); +- log_print(log, level, file, fkt, line, " StandardBias=%" PRIu32, tzif->StandardBias); ++ log_print(log, level, file, fkt, line, " StandardBias=%" PRId32, tzif->StandardBias); + +@@ -631,3 +631,3 @@ static void log_timezone_(const DYNAMIC_TIME_ZONE_INFORMATION* tzif, DWORD resul + systemtime2str(&tzif->DaylightDate, buffer, sizeof(buffer))); +- log_print(log, level, file, fkt, line, " DaylightBias=%" PRIu32, tzif->DaylightBias); ++ log_print(log, level, file, fkt, line, " DaylightBias=%" PRId32, tzif->DaylightBias); + (void)ConvertWCharNToUtf8(tzif->TimeZoneKeyName, ARRAYSIZE(tzif->TimeZoneKeyName), buffer, +diff --git a/winpr/libwinpr/utils/print.c b/winpr/libwinpr/utils/print.c +index 4ab89edeb..7ecd305c9 100644 +--- a/winpr/libwinpr/utils/print.c ++++ b/winpr/libwinpr/utils/print.c +@@ -72,3 +72,3 @@ void winpr_HexLogDump(wLog* log, UINT32 level, const void* data, size_t length) + char ebuffer[256] = { 0 }; +- WLog_Print(log, WLOG_ERROR, "malloc(%" PRIuz ") failed with [%" PRIuz "] %s", blen, errno, ++ WLog_Print(log, WLOG_ERROR, "malloc(%" PRIuz ") failed with [%d] %s", blen, errno, + winpr_strerror(errno, ebuffer, sizeof(ebuffer))); +diff --git a/winpr/libwinpr/utils/stream.c b/winpr/libwinpr/utils/stream.c +index 0572c4177..7a43e57e1 100644 +--- a/winpr/libwinpr/utils/stream.c ++++ b/winpr/libwinpr/utils/stream.c +@@ -360,3 +360,3 @@ BOOL Stream_CheckAndLogRequiredCapacityWLogExVa(wLog* log, DWORD level, wStream* + WLog_Print(log, level, +- "[%s] invalid remaining capacity, got %" PRIuz ", require at least %" PRIu64 ++ "[%s] invalid remaining capacity, got %" PRIuz ", require at least %" PRIuz + " [element size=%" PRIuz "]", +-- +2.47.3 + diff -Nru freerdp3-3.15.0+dfsg/debian/patches/winpr-wlog-Add-specialized-text-log-functions.patch freerdp3-3.15.0+dfsg/debian/patches/winpr-wlog-Add-specialized-text-log-functions.patch --- freerdp3-3.15.0+dfsg/debian/patches/winpr-wlog-Add-specialized-text-log-functions.patch 1970-01-01 00:00:00.000000000 +0000 +++ freerdp3-3.15.0+dfsg/debian/patches/winpr-wlog-Add-specialized-text-log-functions.patch 2026-02-25 20:31:28.000000000 +0000 @@ -0,0 +1,217 @@ +From: akallabeth +Date: Wed, 13 Aug 2025 09:00:53 +0200 +Subject: [winpr,wlog] Add specialized text log functions +Origin: upstream, https://github.com/FreeRDP/FreeRDP/commit/df89b04424599bed520461f10c1893509189f862 +Forwarded: not-needed +Comment: preparation for the subsequent patch + (channels-rdpecam-add-value-range-checks.patch) + which uses functions provided in this change. +Comment: this patch introduces a build failure due to wrong printf()-like + format strings usage, which is fixed by the next upstream patch. + The issues the next patch fixes, were in the code for a long time, + but due to missing arguments checking, went unnoticed. +Comment: This change introduces two new symbols into libwinpr3-3, + so to be backwards- and forward-compatible, we use libwinpr3-partial-api-3-17 + trick in the symbols and control files. + +The generic WLog_PrintMessage(VA) functions lack proper checks of the +supplied format strings. +Add WLog_PrintTextMessage(VA) functions that do compile time checks of +supplied format strings to uncover usage errors early and use them in +the logger macros. +--- + winpr/include/winpr/wlog.h | 86 +++++++++++++++++++++++++++----- + winpr/libwinpr/utils/wlog/wlog.c | 47 +++++++++++++++++ + 2 files changed, 121 insertions(+), 12 deletions(-) + +diff --git a/winpr/include/winpr/wlog.h b/winpr/include/winpr/wlog.h +index 2749897c6..61afed879 100644 +--- a/winpr/include/winpr/wlog.h ++++ b/winpr/include/winpr/wlog.h +@@ -47,13 +47,16 @@ extern "C" + #define WLOG_OFF 6 + #define WLOG_LEVEL_INHERIT 0xFFFF + +-/** +- * Log Message ++/** @defgroup LogMessageTypes Log Message ++ * @{ + */ + #define WLOG_MESSAGE_TEXT 0 + #define WLOG_MESSAGE_DATA 1 + #define WLOG_MESSAGE_IMAGE 2 + #define WLOG_MESSAGE_PACKET 3 ++/** ++ * @} ++ */ + + /** + * Log Appenders +@@ -106,8 +109,69 @@ extern "C" + #define WLOG_PACKET_INBOUND 1 + #define WLOG_PACKET_OUTBOUND 2 + ++ /** @brief specialized function to print text log messages. ++ * Same as @ref WLog_PrintMessage with \b type = WLOG_MESSAGE_TEXT but with compile time checks ++ * for issues in format string. ++ * ++ * @param log A pointer to the logger to use ++ * @param line the file line the log message originates from ++ * @param file the file name the log message originates from ++ * @param function the function name the log message originates from ++ * @param fmt the printf style format string ++ * ++ * @return \b TRUE for success, \b FALSE otherwise. ++ * @since version 3.17.0 ++ */ ++ WINPR_ATTR_FORMAT_ARG(6, 7) ++ WINPR_API BOOL WLog_PrintTextMessage(wLog* log, DWORD level, size_t line, const char* file, ++ const char* function, WINPR_FORMAT_ARG const char* fmt, ++ ...); ++ ++ /** @brief specialized function to print text log messages. ++ * Same as @ref WLog_PrintMessageVA with \b type = WLOG_MESSAGE_TEXT but with compile time ++ * checks for issues in format string. ++ * ++ * @param log A pointer to the logger to use ++ * @param line the file line the log message originates from ++ * @param file the file name the log message originates from ++ * @param function the function name the log message originates from ++ * @param fmt the printf style format string ++ * ++ * @return \b TRUE for success, \b FALSE otherwise. ++ * @since version 3.17.0 ++ */ ++ WINPR_ATTR_FORMAT_ARG(6, 0) ++ WINPR_API BOOL WLog_PrintTextMessageVA(wLog* log, DWORD level, size_t line, const char* file, ++ const char* function, WINPR_FORMAT_ARG const char* fmt, ++ va_list args); ++ ++ /** @brief log something of a specified type. ++ * @bug For /b WLOG_MESSAGE_TEXT the format string is not validated at compile time. Use \ref ++ * WLog_PrintTextMessage instead. ++ * ++ * @param log A pointer to the logger to use ++ * @param type The type of message to log, can be any of \ref LogMessageTypes ++ * @param line the file line the log message originates from ++ * @param file the file name the log message originates from ++ * @param function the function name the log message originates from ++ * ++ * @return \b TRUE for success, \b FALSE otherwise. ++ */ + WINPR_API BOOL WLog_PrintMessage(wLog* log, DWORD type, DWORD level, size_t line, + const char* file, const char* function, ...); ++ ++ /** @brief log something of a specified type. ++ * @bug For /b WLOG_MESSAGE_TEXT the format string is not validated at compile time. Use \ref ++ * WLog_PrintTextMessageVA instead. ++ * ++ * @param log A pointer to the logger to use ++ * @param type The type of message to log, can be any of \ref LogMessageTypes ++ * @param line the file line the log message originates from ++ * @param file the file name the log message originates from ++ * @param function the function name the log message originates from ++ * ++ * @return \b TRUE for success, \b FALSE otherwise. ++ */ + WINPR_API BOOL WLog_PrintMessageVA(wLog* log, DWORD type, DWORD level, size_t line, + const char* file, const char* function, va_list args); + +@@ -128,11 +192,10 @@ extern "C" + */ + WINPR_API BOOL WLog_SetContext(wLog* log, const char* (*fkt)(void*), void* context); + +-#define WLog_Print_unchecked(_log, _log_level, ...) \ +- do \ +- { \ +- WLog_PrintMessage(_log, WLOG_MESSAGE_TEXT, _log_level, __LINE__, __FILE__, __func__, \ +- __VA_ARGS__); \ ++#define WLog_Print_unchecked(_log, _log_level, ...) \ ++ do \ ++ { \ ++ WLog_PrintTextMessage(_log, _log_level, __LINE__, __FILE__, __func__, __VA_ARGS__); \ + } while (0) + + #define WLog_Print(_log, _log_level, ...) \ +@@ -153,11 +216,10 @@ extern "C" + WLog_Print(_log_cached_ptr, _log_level, __VA_ARGS__); \ + } while (0) + +-#define WLog_PrintVA_unchecked(_log, _log_level, _args) \ +- do \ +- { \ +- WLog_PrintMessageVA(_log, WLOG_MESSAGE_TEXT, _log_level, __LINE__, __FILE__, __func__, \ +- _args); \ ++#define WLog_PrintVA_unchecked(_log, _log_level, _args) \ ++ do \ ++ { \ ++ WLog_PrintTextMessageVA(_log, _log_level, __LINE__, __FILE__, __func__, _args); \ + } while (0) + + #define WLog_PrintVA(_log, _log_level, _args) \ +diff --git a/winpr/libwinpr/utils/wlog/wlog.c b/winpr/libwinpr/utils/wlog/wlog.c +index e8a88373e..d69d2403f 100644 +--- a/winpr/libwinpr/utils/wlog/wlog.c ++++ b/winpr/libwinpr/utils/wlog/wlog.c +@@ -415,6 +415,42 @@ BOOL WLog_PrintMessageVA(wLog* log, DWORD type, DWORD level, size_t line, const + return status; + } + ++BOOL WLog_PrintTextMessageVA(wLog* log, DWORD level, size_t line, const char* file, ++ const char* function, const char* fmt, va_list args) ++{ ++ BOOL status = FALSE; ++ wLogMessage message = { 0 }; ++ message.Type = WLOG_MESSAGE_TEXT; ++ message.Level = level; ++ message.LineNumber = line; ++ message.FileName = file; ++ message.FunctionName = function; ++ ++ message.FormatString = fmt; ++ ++ if (!strchr(message.FormatString, '%')) ++ { ++ message.TextString = message.FormatString; ++ status = WLog_Write(log, &message); ++ } ++ else ++ { ++ char formattedLogMessage[WLOG_MAX_STRING_SIZE] = { 0 }; ++ ++ WINPR_PRAGMA_DIAG_PUSH ++ WINPR_PRAGMA_DIAG_IGNORED_FORMAT_NONLITERAL ++ if (vsnprintf(formattedLogMessage, WLOG_MAX_STRING_SIZE - 1, message.FormatString, args) < ++ 0) ++ return FALSE; ++ WINPR_PRAGMA_DIAG_POP ++ ++ message.TextString = formattedLogMessage; ++ status = WLog_Write(log, &message); ++ } ++ ++ return status; ++} ++ + BOOL WLog_PrintMessage(wLog* log, DWORD type, DWORD level, size_t line, const char* file, + const char* function, ...) + { +@@ -426,6 +462,17 @@ BOOL WLog_PrintMessage(wLog* log, DWORD type, DWORD level, size_t line, const ch + return status; + } + ++BOOL WLog_PrintTextMessage(wLog* log, DWORD level, size_t line, const char* file, ++ const char* function, const char* fmt, ...) ++{ ++ BOOL status = 0; ++ va_list args; ++ va_start(args, fmt); ++ status = WLog_PrintTextMessageVA(log, level, line, file, function, fmt, args); ++ va_end(args); ++ return status; ++} ++ + DWORD WLog_GetLogLevel(wLog* log) + { + if (!log) +