From d8e8413c9caad95d5298457c17823a6f050db84e Mon Sep 17 00:00:00 2001 From: Ondrej Holy Date: Mon, 13 Jul 2026 14:37:06 +0000 Subject: [PATCH] Update to 3.28.0 It fixes CVE-2026-57156, CVE-2026-57157 and CVE-2026-57158. Resolves: RHEL-171999 --- .gitignore | 1 + ...CHANNEL_OPTION_SHOW_PROTOCOL-server-.patch | 551 - ...ix-off-by-one-scan-length-in-rdpdr_r.patch | 26 - freerdp.spec | 25 +- sources | 2 +- support-rdpdr-device-control-responses.patch | 14826 ---------------- ...er-clean-up-warnings-fix-poll-return.patch | 156 - ...r-increase-capacity-for-fragmented-P.patch | 26 - utils-scard-fix-endianess-issue.patch | 36 - ...validate-cbAtr-against-rgbAtr-size-o.patch | 189 - utils-test-replace-NULL.patch | 46 - 11 files changed, 8 insertions(+), 15876 deletions(-) delete mode 100644 channels-handle-CHANNEL_OPTION_SHOW_PROTOCOL-server-.patch delete mode 100644 channels-rdpdr-fix-off-by-one-scan-length-in-rdpdr_r.patch delete mode 100644 support-rdpdr-device-control-responses.patch delete mode 100644 utils-pdu-tracker-clean-up-warnings-fix-poll-return.patch delete mode 100644 utils-pdu-tracker-increase-capacity-for-fragmented-P.patch delete mode 100644 utils-scard-fix-endianess-issue.patch delete mode 100644 utils-smartcard-validate-cbAtr-against-rgbAtr-size-o.patch delete mode 100644 utils-test-replace-NULL.patch diff --git a/.gitignore b/.gitignore index 707fa18..0caf3d6 100644 --- a/.gitignore +++ b/.gitignore @@ -76,3 +76,4 @@ /FreeRDP-3.10.3-repack.tar.gz /FreeRDP-3.24.2-repack.tar.gz /FreeRDP-3.27.1-repack.tar.gz +/FreeRDP-3.28.0-repack.tar.gz diff --git a/channels-handle-CHANNEL_OPTION_SHOW_PROTOCOL-server-.patch b/channels-handle-CHANNEL_OPTION_SHOW_PROTOCOL-server-.patch deleted file mode 100644 index 956310f..0000000 --- a/channels-handle-CHANNEL_OPTION_SHOW_PROTOCOL-server-.patch +++ /dev/null @@ -1,551 +0,0 @@ -From 2e1113794d125269f30fc7acf4d0f3d898d74d52 Mon Sep 17 00:00:00 2001 -From: David Fort -Date: Mon, 15 Jun 2026 16:30:40 +0200 -Subject: [PATCH] [channels] handle CHANNEL_OPTION_SHOW_PROTOCOL server-side - -With some static channels like rdpdr or clipdr there's no marking of packet -length so in theory you can't handle packets that you don't know (you don't know -how many bytes to skip) or that are badly encoded (WTSVirtualChannelRead linearizes -the traffic so you can't know which bytes are part of the current PDU and which -bytes are from the next one). To solve that this patch adds server-side the handling -of a CHANNEL_OPTION_SHOW_PROTOCOL with WTSVirtualChannelOpen, when you set that -option you get CHANNEL_PDU_HEADER before the packet payload, and so you can do the -reassembly of a PDU. This allows to skip a PDU when you don't know the type, and -go to the next one correctly if for instance the padding at the end of the PDU is -incorrect (think of some smartcard commands invalidly padded by FreeRDP). - -The patch also provides a ChannelPduTracker component that can do the reassembly -for you. ---- - include/freerdp/utils/channel_pdu_tracker.h | 65 +++++++++++ - libfreerdp/core/peer.c | 60 +++++----- - libfreerdp/core/server.c | 82 ++++++++------ - libfreerdp/utils/CMakeLists.txt | 1 + - libfreerdp/utils/channel_pdu_tracker.c | 119 ++++++++++++++++++++ - 5 files changed, 259 insertions(+), 68 deletions(-) - create mode 100644 include/freerdp/utils/channel_pdu_tracker.h - create mode 100644 libfreerdp/utils/channel_pdu_tracker.c - -diff --git a/include/freerdp/utils/channel_pdu_tracker.h b/include/freerdp/utils/channel_pdu_tracker.h -new file mode 100644 -index 0000000..96c52b5 ---- /dev/null -+++ b/include/freerdp/utils/channel_pdu_tracker.h -@@ -0,0 +1,65 @@ -+/** -+ * FreeRDP: A Remote Desktop Protocol Implementation -+ * static channel utility functions -+ * -+ * Copyright 2026 David Fort -+ * -+ * Licensed under the Apache License, Version 2.0 (the "License"); -+ * you may not use this file except in compliance with the License. -+ * You may obtain a copy of the License at -+ * -+ * http://www.apache.org/licenses/LICENSE-2.0 -+ * -+ * Unless required by applicable law or agreed to in writing, software -+ * distributed under the License is distributed on an "AS IS" BASIS, -+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -+ * See the License for the specific language governing permissions and -+ * limitations under the License. -+ */ -+ -+#ifndef FREERDP_UTILS_CHANNEL_TRACKER_H_ -+#define FREERDP_UTILS_CHANNEL_TRACKER_H_ -+ -+#include -+#include -+ -+#include -+ -+#ifdef __cplusplus -+extern "C" -+{ -+#endif -+ -+ typedef struct ChannelPduTracker ChannelPduTracker; -+ -+ /** -+ * frees a ChannelPduTracker -+ * @param tracker the tracker to release -+ * @since version 3.28.0 -+ */ -+ FREERDP_API void ChannelPduTracker_free(ChannelPduTracker* tracker); -+ -+ /** -+ * Creates a ChannelPduTracker -+ * @param vc the HANDLE of the channel -+ * @return the created ChannelPduTracker, nullptr if something failed -+ * @since version 3.28.0 -+ */ -+ WINPR_ATTR_MALLOC(ChannelPduTracker_free, 1) -+ FREERDP_API ChannelPduTracker* ChannelPduTracker_new(HANDLE vc); -+ -+ /** -+ * Polls the channel and return a PDU if a whole PDU was reassembled -+ * @param tracker the ChannelPduTracker to poll a packet from -+ * @param ok a pointer to a status BOOL -+ * @return the reassembled PDU if any -+ * @since version 3.28.0 -+ */ -+ WINPR_ATTR_MALLOC(Stream_Release, 1) -+ FREERDP_API wStream* ChannelPduTracker_poll(ChannelPduTracker* tracker, BOOL* ok); -+ -+#ifdef __cplusplus -+} -+#endif -+ -+#endif /* FREERDP_UTILS_CHANNEL_TRACKER_H_ */ -diff --git a/libfreerdp/core/peer.c b/libfreerdp/core/peer.c -index 3e3f024..355c578 100644 ---- a/libfreerdp/core/peer.c -+++ b/libfreerdp/core/peer.c -@@ -48,17 +48,11 @@ static state_run_t peer_recv_pdu(freerdp_peer* client, wStream* s); - static HANDLE freerdp_peer_virtual_channel_open(freerdp_peer* client, const char* name, - UINT32 flags) - { -- UINT32 index = 0; -- BOOL joined = FALSE; -- rdpMcsChannel* mcsChannel = nullptr; -- rdpPeerChannel* peerChannel = nullptr; -- rdpMcs* mcs = nullptr; -- - WINPR_ASSERT(client); - WINPR_ASSERT(client->context); - WINPR_ASSERT(client->context->rdp); - WINPR_ASSERT(name); -- mcs = client->context->rdp->mcs; -+ rdpMcs* mcs = client->context->rdp->mcs; - WINPR_ASSERT(mcs); - - if (flags & WTS_CHANNEL_OPTION_DYNAMIC) -@@ -69,6 +63,9 @@ static HANDLE freerdp_peer_virtual_channel_open(freerdp_peer* client, const char - if (length > 8) - return nullptr; /* SVC maximum name length is 8 */ - -+ BOOL joined = FALSE; -+ UINT32 index = 0; -+ rdpMcsChannel* mcsChannel = nullptr; - for (; index < mcs->channelCount; index++) - { - mcsChannel = &(mcs->channels[index]); -@@ -86,7 +83,7 @@ static HANDLE freerdp_peer_virtual_channel_open(freerdp_peer* client, const char - if (!joined) - return nullptr; /* channel is not joined */ - -- peerChannel = (rdpPeerChannel*)mcsChannel->handle; -+ rdpPeerChannel* peerChannel = (rdpPeerChannel*)mcsChannel->handle; - - if (peerChannel) - { -@@ -1473,33 +1470,30 @@ freerdp_peer* freerdp_peer_new(int sockfd) - (void)freerdp_tcp_set_nodelay(WLog_Get(TAG), WLOG_DEBUG, sockfd); - } - -- if (client) -- { -- client->sockfd = sockfd; -- client->ContextSize = sizeof(rdpContext); -- client->Initialize = freerdp_peer_initialize; -+ client->sockfd = sockfd; -+ client->ContextSize = sizeof(rdpContext); -+ client->Initialize = freerdp_peer_initialize; - #if defined(WITH_FREERDP_DEPRECATED) -- client->GetFileDescriptor = freerdp_peer_get_fds; -+ client->GetFileDescriptor = freerdp_peer_get_fds; - #endif -- client->GetEventHandle = freerdp_peer_get_event_handle; -- client->GetEventHandles = freerdp_peer_get_event_handles; -- client->CheckFileDescriptor = freerdp_peer_check_fds; -- client->Close = freerdp_peer_close; -- client->Disconnect = freerdp_peer_disconnect; -- client->SendChannelData = freerdp_peer_send_channel_data; -- client->SendChannelPacket = freerdp_peer_send_channel_packet; -- client->SendServerRedirection = freerdp_peer_send_server_redirection_pdu; -- client->IsWriteBlocked = freerdp_peer_is_write_blocked; -- client->DrainOutputBuffer = freerdp_peer_drain_output_buffer; -- client->HasMoreToRead = freerdp_peer_has_more_to_read; -- client->VirtualChannelOpen = freerdp_peer_virtual_channel_open; -- client->VirtualChannelClose = freerdp_peer_virtual_channel_close; -- client->VirtualChannelWrite = freerdp_peer_virtual_channel_write; -- client->VirtualChannelRead = nullptr; /* must be defined by server application */ -- client->VirtualChannelGetData = freerdp_peer_virtual_channel_get_data; -- client->VirtualChannelSetData = freerdp_peer_virtual_channel_set_data; -- client->SetState = freerdp_peer_set_state; -- } -+ client->GetEventHandle = freerdp_peer_get_event_handle; -+ client->GetEventHandles = freerdp_peer_get_event_handles; -+ client->CheckFileDescriptor = freerdp_peer_check_fds; -+ client->Close = freerdp_peer_close; -+ client->Disconnect = freerdp_peer_disconnect; -+ client->SendChannelData = freerdp_peer_send_channel_data; -+ client->SendChannelPacket = freerdp_peer_send_channel_packet; -+ client->SendServerRedirection = freerdp_peer_send_server_redirection_pdu; -+ client->IsWriteBlocked = freerdp_peer_is_write_blocked; -+ client->DrainOutputBuffer = freerdp_peer_drain_output_buffer; -+ client->HasMoreToRead = freerdp_peer_has_more_to_read; -+ client->VirtualChannelOpen = freerdp_peer_virtual_channel_open; -+ client->VirtualChannelClose = freerdp_peer_virtual_channel_close; -+ client->VirtualChannelWrite = freerdp_peer_virtual_channel_write; -+ client->VirtualChannelRead = nullptr; /* must be defined by server application */ -+ client->VirtualChannelGetData = freerdp_peer_virtual_channel_get_data; -+ client->VirtualChannelSetData = freerdp_peer_virtual_channel_set_data; -+ client->SetState = freerdp_peer_set_state; - - return client; - } -diff --git a/libfreerdp/core/server.c b/libfreerdp/core/server.c -index 3c998f0..7afcb62 100644 ---- a/libfreerdp/core/server.c -+++ b/libfreerdp/core/server.c -@@ -76,23 +76,27 @@ static rdpPeerChannel* wts_get_dvc_channel_by_id(WTSVirtualChannelManager* vcm, - return HashTable_GetItemValue(vcm->dynamicVirtualChannels, &ChannelId); - } - --static BOOL wts_queue_receive_data(rdpPeerChannel* channel, const BYTE* Buffer, UINT32 Length) -+static BOOL wts_queue_receive_data(rdpPeerChannel* channel, const BYTE* Buffer1, UINT32 Length1, -+ const BYTE* Buffer2, UINT32 Length2) - { -- BYTE* buffer = nullptr; -- wtsChannelMessage* messageCtx = nullptr; -- - WINPR_ASSERT(channel); -- messageCtx = (wtsChannelMessage*)malloc(sizeof(wtsChannelMessage) + Length); - -+ wtsChannelMessage* messageCtx = -+ (wtsChannelMessage*)malloc(sizeof(wtsChannelMessage) + Length1 + Length2); - if (!messageCtx) - return FALSE; - - WINPR_ASSERT(channel->channelId <= UINT16_MAX); - messageCtx->channelId = (UINT16)channel->channelId; -- messageCtx->length = Length; -+ messageCtx->length = Length1 + Length2; - messageCtx->offset = 0; -- buffer = (BYTE*)(messageCtx + 1); -- CopyMemory(buffer, Buffer, Length); -+ BYTE* buffer = (BYTE*)(messageCtx + 1); -+ CopyMemory(buffer, Buffer1, Length1); -+ if (Length2 && Buffer2) -+ { -+ buffer += Length1; -+ CopyMemory(buffer, Buffer2, Length2); -+ } - return MessageQueue_Post(channel->queue, messageCtx, 0, nullptr, nullptr); - } - -@@ -252,7 +256,7 @@ static BOOL wts_read_drdynvc_data(rdpPeerChannel* channel, wStream* s, UINT32 le - if (Stream_GetPosition(channel->receiveData) >= channel->dvc_total_length) - { - ret = wts_queue_receive_data(channel, Stream_Buffer(channel->receiveData), -- channel->dvc_total_length); -+ channel->dvc_total_length, nullptr, 0); - channel->dvc_total_length = 0; - } - else -@@ -260,7 +264,7 @@ static BOOL wts_read_drdynvc_data(rdpPeerChannel* channel, wStream* s, UINT32 le - } - else - { -- ret = wts_queue_receive_data(channel, Stream_ConstPointer(s), length); -+ ret = wts_queue_receive_data(channel, Stream_ConstPointer(s), length, nullptr, 0); - } - - return ret; -@@ -454,6 +458,17 @@ static BOOL WTSProcessChannelData(rdpPeerChannel* channel, UINT16 channelId, con - WINPR_ASSERT(channel->vcm); - WINPR_UNUSED(channelId); - -+ if (channel->channelFlags & CHANNEL_OPTION_SHOW_PROTOCOL) -+ { -+ const CHANNEL_PDU_HEADER header = { -+ .length = (UINT32)size, -+ .flags = flags, -+ }; -+ -+ return wts_queue_receive_data(channel, (const BYTE*)&header, sizeof(header), data, -+ (UINT32)size); -+ } -+ - if (flags & CHANNEL_FLAG_FIRST) - { - Stream_ResetPosition(channel->receiveData); -@@ -482,7 +497,7 @@ static BOOL WTSProcessChannelData(rdpPeerChannel* channel, UINT16 channelId, con - ret = FALSE; - else - ret = wts_queue_receive_data(channel, Stream_Buffer(channel->receiveData), -- (UINT32)pos); -+ (UINT32)pos, nullptr, 0); - } - - Stream_ResetPosition(channel->receiveData); -@@ -1353,7 +1368,7 @@ static void peer_channel_queue_free_message(void* obj) - - static rdpPeerChannel* channel_new(WTSVirtualChannelManager* vcm, freerdp_peer* client, - UINT32 ChannelId, UINT16 index, UINT16 type, size_t chunkSize, -- const char* name) -+ const char* name, UINT32 flags) - { - wObject queueCallbacks = WINPR_C_ARRAY_INIT; - queueCallbacks.fnObjectFree = peer_channel_queue_free_message; -@@ -1371,6 +1386,7 @@ static rdpPeerChannel* channel_new(WTSVirtualChannelManager* vcm, freerdp_peer* - channel->channelType = type; - channel->creationStatus = - (type == RDP_PEER_CHANNEL_TYPE_SVC) ? ERROR_SUCCESS : ERROR_OPERATION_IN_PROGRESS; -+ channel->channelFlags = flags; - - return channel; - fail: -@@ -1378,44 +1394,35 @@ fail: - return nullptr; - } - --HANDLE WINAPI FreeRDP_WTSVirtualChannelOpen(HANDLE hServer, WINPR_ATTR_UNUSED DWORD SessionId, -- LPSTR pVirtualName) -+HANDLE WINAPI FreeRDP_WTSVirtualChannelOpenStatic(HANDLE hServer, WINPR_ATTR_UNUSED DWORD SessionId, -+ LPSTR pVirtualName, UINT32 Flags) - { -- size_t length = 0; -- rdpMcs* mcs = nullptr; -- rdpMcsChannel* joined_channel = nullptr; -- freerdp_peer* client = nullptr; -- rdpPeerChannel* channel = nullptr; -- WTSVirtualChannelManager* vcm = nullptr; -- HANDLE hChannelHandle = nullptr; -- rdpContext* context = nullptr; -- vcm = (WTSVirtualChannelManager*)hServer; -- -+ WTSVirtualChannelManager* vcm = (WTSVirtualChannelManager*)hServer; - if (!vcm) - { - SetLastError(ERROR_INVALID_DATA); - return nullptr; - } - -- client = vcm->client; -+ freerdp_peer* client = vcm->client; - WINPR_ASSERT(client); - -- context = client->context; -+ rdpContext* context = client->context; - WINPR_ASSERT(context); - WINPR_ASSERT(context->rdp); - WINPR_ASSERT(context->settings); - -- mcs = context->rdp->mcs; -+ rdpMcs* mcs = context->rdp->mcs; - WINPR_ASSERT(mcs); - -- length = strnlen(pVirtualName, CHANNEL_NAME_LEN + 1); -- -+ size_t length = strnlen(pVirtualName, CHANNEL_NAME_LEN + 1); - if (length > CHANNEL_NAME_LEN) - { - SetLastError(ERROR_NOT_FOUND); - return nullptr; - } - -+ rdpMcsChannel* joined_channel = nullptr; - UINT32 index = 0; - for (; index < mcs->channelCount; index++) - { -@@ -1433,8 +1440,7 @@ HANDLE WINAPI FreeRDP_WTSVirtualChannelOpen(HANDLE hServer, WINPR_ATTR_UNUSED DW - return nullptr; - } - -- channel = (rdpPeerChannel*)joined_channel->handle; -- -+ rdpPeerChannel* channel = (rdpPeerChannel*)joined_channel->handle; - if (!channel) - { - const UINT32 VCChunkSize = -@@ -1442,7 +1448,7 @@ HANDLE WINAPI FreeRDP_WTSVirtualChannelOpen(HANDLE hServer, WINPR_ATTR_UNUSED DW - - WINPR_ASSERT(index <= UINT16_MAX); - channel = channel_new(vcm, client, joined_channel->ChannelId, (UINT16)index, -- RDP_PEER_CHANNEL_TYPE_SVC, VCChunkSize, pVirtualName); -+ RDP_PEER_CHANNEL_TYPE_SVC, VCChunkSize, pVirtualName, Flags); - - if (!channel) - goto fail; -@@ -1450,7 +1456,7 @@ HANDLE WINAPI FreeRDP_WTSVirtualChannelOpen(HANDLE hServer, WINPR_ATTR_UNUSED DW - joined_channel->handle = channel; - } - -- hChannelHandle = (HANDLE)channel; -+ HANDLE hChannelHandle = (HANDLE)channel; - return hChannelHandle; - fail: - channel_free(channel); -@@ -1458,6 +1464,11 @@ fail: - return nullptr; - } - -+HANDLE WINAPI FreeRDP_WTSVirtualChannelOpen(HANDLE hServer, DWORD SessionId, LPSTR pVirtualName) -+{ -+ return FreeRDP_WTSVirtualChannelOpenStatic(hServer, SessionId, pVirtualName, 0); -+} -+ - HANDLE WINAPI FreeRDP_WTSVirtualChannelOpenEx(DWORD SessionId, LPSTR pVirtualName, DWORD flags) - { - wStream* s = nullptr; -@@ -1481,7 +1492,7 @@ HANDLE WINAPI FreeRDP_WTSVirtualChannelOpenEx(DWORD SessionId, LPSTR pVirtualNam - if (!(flags & WTS_CHANNEL_OPTION_DYNAMIC)) - { - HashTable_Unlock(g_ServerHandles); -- return FreeRDP_WTSVirtualChannelOpen((HANDLE)vcm, SessionId, pVirtualName); -+ return FreeRDP_WTSVirtualChannelOpenStatic((HANDLE)vcm, SessionId, pVirtualName, flags); - } - - freerdp_peer* client = vcm->client; -@@ -1521,7 +1532,8 @@ HANDLE WINAPI FreeRDP_WTSVirtualChannelOpenEx(DWORD SessionId, LPSTR pVirtualNam - - const UINT32 VCChunkSize = - freerdp_settings_get_uint32(client->context->settings, FreeRDP_VCChunkSize); -- channel = channel_new(vcm, client, 0, 0, RDP_PEER_CHANNEL_TYPE_DVC, VCChunkSize, pVirtualName); -+ channel = -+ channel_new(vcm, client, 0, 0, RDP_PEER_CHANNEL_TYPE_DVC, VCChunkSize, pVirtualName, flags); - - if (!channel) - { -diff --git a/libfreerdp/utils/CMakeLists.txt b/libfreerdp/utils/CMakeLists.txt -index 6f821a6..30b7ca9 100644 ---- a/libfreerdp/utils/CMakeLists.txt -+++ b/libfreerdp/utils/CMakeLists.txt -@@ -19,6 +19,7 @@ set(MODULE_NAME "freerdp-utils") - set(MODULE_PREFIX "FREERDP_UTILS") - - set(${MODULE_PREFIX}_SRCS -+ channel_pdu_tracker.c - encoded_types.c - helpers.c - passphrase.c -diff --git a/libfreerdp/utils/channel_pdu_tracker.c b/libfreerdp/utils/channel_pdu_tracker.c -new file mode 100644 -index 0000000..18e9aab ---- /dev/null -+++ b/libfreerdp/utils/channel_pdu_tracker.c -@@ -0,0 +1,119 @@ -+/** -+ * FreeRDP: A Remote Desktop Protocol Implementation -+ * static channel utility functions -+ * -+ * Copyright 2026 David Fort -+ * -+ * Licensed under the Apache License, Version 2.0 (the "License"); -+ * you may not use this file except in compliance with the License. -+ * You may obtain a copy of the License at -+ * -+ * http://www.apache.org/licenses/LICENSE-2.0 -+ * -+ * Unless required by applicable law or agreed to in writing, software -+ * distributed under the License is distributed on an "AS IS" BASIS, -+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -+ * See the License for the specific language governing permissions and -+ * limitations under the License. -+ */ -+ -+#include -+ -+#include -+ -+struct ChannelPduTracker -+{ -+ HANDLE vc; -+ wStream* currentPacket; -+ BYTE buffer[CHANNEL_PDU_LENGTH]; -+ BYTE* writePtr; -+}; -+ -+#define TAG "ChannelPduTracker" -+ -+wStream* ChannelPduTracker_poll(ChannelPduTracker* tracker, BOOL* ok) -+{ -+ WINPR_ASSERT(tracker); -+ WINPR_ASSERT(ok); -+ -+ ULONG sz = 0; -+ *ok = FALSE; -+ const ULONG readSz = -+ WINPR_ASSERTING_INT_CAST(ULONG, CHANNEL_PDU_LENGTH - (tracker->writePtr - tracker->buffer)); -+ if (!WTSVirtualChannelRead(tracker->vc, INFINITE, (char*)tracker->writePtr, readSz, &sz)) -+ return nullptr; -+ -+ tracker->writePtr += sz; -+ const size_t recvSz = (tracker->writePtr - tracker->buffer); -+ if (recvSz < sizeof(CHANNEL_PDU_HEADER)) -+ { -+ *ok = TRUE; -+ return nullptr; -+ } -+ -+ CHANNEL_PDU_HEADER* header = (CHANNEL_PDU_HEADER*)tracker->buffer; -+ if (header->length > CHANNEL_CHUNK_LENGTH) -+ { -+ WLog_ERR(TAG, "chunk size %" PRIu32 " is too big", header->length); -+ return nullptr; -+ } -+ -+ if (recvSz - sizeof(CHANNEL_PDU_HEADER) < header->length) -+ { -+ WLog_ERR(TAG, "chunk size %" PRIu32 " is too big", header->length); -+ return nullptr; -+ } -+ -+ tracker->writePtr = tracker->buffer; -+ if (header->flags & CHANNEL_FLAG_FIRST) -+ Stream_ResetPosition(tracker->currentPacket); -+ -+ if (!Stream_EnsureRemainingCapacity(tracker->currentPacket, header->length)) -+ return nullptr; -+ -+ Stream_Write(tracker->currentPacket, header + 1, header->length); -+ -+ if (header->flags & CHANNEL_FLAG_LAST) -+ { -+ Stream_SealLength(tracker->currentPacket); -+ Stream_ResetPosition(tracker->currentPacket); -+ wStream* ret = tracker->currentPacket; -+ -+ tracker->currentPacket = Stream_New(nullptr, 4096); -+ if (!tracker->currentPacket) -+ { -+ Stream_Release(ret); -+ WLog_ERR(TAG, "error allocating new currentPacket"); -+ return nullptr; -+ } -+ } -+ -+ *ok = TRUE; -+ return nullptr; -+} -+ -+void ChannelPduTracker_free(ChannelPduTracker* tracker) -+{ -+ if (!tracker) -+ return; -+ -+ Stream_Release(tracker->currentPacket); -+ free(tracker); -+} -+ -+ChannelPduTracker* ChannelPduTracker_new(HANDLE vc) -+{ -+ ChannelPduTracker* ret = calloc(1, sizeof(*ret)); -+ if (!ret) -+ return nullptr; -+ -+ ret->currentPacket = Stream_New(nullptr, 4096); -+ if (!ret->currentPacket) -+ { -+ free(ret); -+ return nullptr; -+ } -+ ret->vc = vc; -+ ret->writePtr = ret->buffer; -+ return ret; -+} --- -2.54.0 - diff --git a/channels-rdpdr-fix-off-by-one-scan-length-in-rdpdr_r.patch b/channels-rdpdr-fix-off-by-one-scan-length-in-rdpdr_r.patch deleted file mode 100644 index 3264d6e..0000000 --- a/channels-rdpdr-fix-off-by-one-scan-length-in-rdpdr_r.patch +++ /dev/null @@ -1,26 +0,0 @@ -From 8223c5a0abdf4d5eae40c66e1329d62766578ce1 Mon Sep 17 00:00:00 2001 -From: Sayed Kaif -Date: Wed, 24 Jun 2026 17:44:53 +0530 -Subject: [PATCH] [channels,rdpdr] fix off-by-one scan length in - rdpdr_read_ustring - ---- - channels/rdpdr/server/rdpdr_main.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/channels/rdpdr/server/rdpdr_main.c b/channels/rdpdr/server/rdpdr_main.c -index bbb3b7e..62e5b90 100644 ---- a/channels/rdpdr/server/rdpdr_main.c -+++ b/channels/rdpdr/server/rdpdr_main.c -@@ -222,7 +222,7 @@ static UINT32 g_ClientId = 0; - - static const WCHAR* rdpdr_read_ustring(wLog* log, wStream* s, size_t bytelen) - { -- const size_t charlen = (bytelen + 1) / sizeof(WCHAR); -+ const size_t charlen = bytelen / sizeof(WCHAR); - const WCHAR* str = Stream_ConstPointer(s); - if (!Stream_CheckAndLogRequiredLengthWLog(log, s, bytelen)) - return nullptr; --- -2.54.0 - diff --git a/freerdp.spec b/freerdp.spec index a5c84cd..def0096 100644 --- a/freerdp.spec +++ b/freerdp.spec @@ -29,8 +29,8 @@ Name: freerdp Epoch: 2 -Version: 3.27.1 -Release: 2%{?dist} +Version: 3.28.0 +Release: 1%{?dist} Summary: Free implementation of the Remote Desktop Protocol (RDP) # The effective license is Apache-2.0 but: @@ -47,23 +47,6 @@ URL: http://www.freerdp.com/ Source0: FreeRDP-%{version}-repack.tar.gz Source1: freerdp_download_and_repack.sh -# Add RDP Smart Card Redirection Support -# https://github.com/FreeRDP/FreeRDP/pull/12928 -# https://github.com/FreeRDP/FreeRDP/commit/2a6d532a1d633145ae48e55ae471f2f2d8e56157 -# https://github.com/FreeRDP/FreeRDP/commit/5cdd46594ec792715a00ecb935dcac7aadde0fc3 -# https://github.com/FreeRDP/FreeRDP/commit/2e1113794d125269f30fc7acf4d0f3d898d74d52 -# https://github.com/FreeRDP/FreeRDP/commit/8223c5a0abdf4d5eae40c66e1329d62766578ce1 -# https://github.com/FreeRDP/FreeRDP/commit/1a15128e93705d5680c84b9e6368245d247fe893 -# https://github.com/FreeRDP/FreeRDP/commit/a41855e88ea37b92a4d506430bce4b09e76f7d76 -# https://github.com/FreeRDP/FreeRDP/pull/12756 -Patch: channels-handle-CHANNEL_OPTION_SHOW_PROTOCOL-server-.patch -Patch: utils-smartcard-validate-cbAtr-against-rgbAtr-size-o.patch -Patch: utils-scard-fix-endianess-issue.patch -Patch: utils-test-replace-NULL.patch -Patch: channels-rdpdr-fix-off-by-one-scan-length-in-rdpdr_r.patch -Patch: utils-pdu-tracker-clean-up-warnings-fix-poll-return.patch -Patch: utils-pdu-tracker-increase-capacity-for-fragmented-P.patch -Patch: support-rdpdr-device-control-responses.patch BuildRequires: gcc BuildRequires: gcc-c++ @@ -396,6 +379,10 @@ find %{buildroot} -name "*.a" -delete %{_libdir}/pkgconfig/winpr-tools3.pc %changelog +* Mon Jul 13 2026 Ondrej Holy - 2:3.28.0-1 +- Update to 3.28.0 (CVE-2026-57156, CVE-2026-57157, CVE-2026-57158) + Resolves: RHEL-171999 + * Wed Jul 01 2026 Ondrej Holy - 2:3.27.1-2 - Add RDP Smart Card Redirection Support Resolves: RHEL-171999 diff --git a/sources b/sources index 24b97ce..4dd4f60 100644 --- a/sources +++ b/sources @@ -1 +1 @@ -SHA512 (FreeRDP-3.27.1-repack.tar.gz) = a8268fdbd9cd9a1ad6df56fdfa233bb2d282026d8dd295cdb0c47ae42e98fc1de8d428d0eecef3c302c3b42415cedf78ae29e6dc475a51a590f99d6ee69f6851 +SHA512 (FreeRDP-3.28.0-repack.tar.gz) = 78db993b80eea8efeb85cd9814c8a2bd3ccd0773101942de5d02674ff16da83b1b0b7b899132e5a0f79173437db66deb765e7350d38e1ac47cdcfc101699877d diff --git a/support-rdpdr-device-control-responses.patch b/support-rdpdr-device-control-responses.patch deleted file mode 100644 index c3981c2..0000000 --- a/support-rdpdr-device-control-responses.patch +++ /dev/null @@ -1,14826 +0,0 @@ -From 9088b82c20844abf72d51368a3b14d3e95128937 Mon Sep 17 00:00:00 2001 -From: Joan Torres Lopez -Date: Wed, 6 May 2026 16:32:49 +0200 -Subject: [PATCH 01/31] [channels,rdpdr] fix capability type check - -caps was accumulated using CAP_*_TYPE enum values (sequential: 1-5) -but compared against context->supported which uses RDPDR_DTYP_* -bitmask values. Map CAP_*_TYPE to the corresponding RDPDR_DTYP_* -bitmask before accumulating into caps. - -Also moved the supported-check and deactivation out of the -per-capability loop to avoid prematurely clearing context->supported -bits before all capabilities were accumulated. ---- - channels/rdpdr/server/rdpdr_main.c | 41 ++++++++++++++++++++---------- - 1 file changed, 27 insertions(+), 14 deletions(-) - -diff --git a/channels/rdpdr/server/rdpdr_main.c b/channels/rdpdr/server/rdpdr_main.c -index 62e5b90448a3..1de60b6688df 100644 ---- a/channels/rdpdr/server/rdpdr_main.c -+++ b/channels/rdpdr/server/rdpdr_main.c -@@ -904,6 +904,24 @@ static UINT rdpdr_server_send_core_capability_request(RdpdrServerContext* contex - return error; - } - -+static UINT16 rdpdr_cap_type_to_dtyp(UINT16 capabilityType) -+{ -+ switch (capabilityType) -+ { -+ case CAP_PRINTER_TYPE: -+ return RDPDR_DTYP_PRINT; -+ case CAP_PORT_TYPE: -+ return RDPDR_DTYP_SERIAL | RDPDR_DTYP_PARALLEL; -+ case CAP_DRIVE_TYPE: -+ return RDPDR_DTYP_FILESYSTEM; -+ case CAP_SMARTCARD_TYPE: -+ return RDPDR_DTYP_SMARTCARD; -+ case CAP_GENERAL_TYPE: -+ default: -+ return 0; -+ } -+} -+ - /** - * Function description - * -@@ -943,7 +961,6 @@ static UINT rdpdr_server_receive_core_capability_response(RdpdrServerContext* co - if (status != CHANNEL_RC_OK) - return status; - -- caps |= capabilityHeader.CapabilityType; - switch (capabilityHeader.CapabilityType) - { - case CAP_GENERAL_TYPE: -@@ -1007,21 +1024,14 @@ static UINT rdpdr_server_receive_core_capability_response(RdpdrServerContext* co - return ERROR_INVALID_DATA; - } - -- for (UINT16 x = 0; x < 16; x++) -+ const UINT16 client_dtyp = rdpdr_cap_type_to_dtyp(capabilityHeader.CapabilityType); -+ if ((client_dtyp != 0) && ((client_dtyp & context->supported) == 0)) - { -- const UINT16 mask = (UINT16)(1u << x); -- if (((caps & mask) != 0) && ((context->supported & mask) == 0)) -- { -- WLog_Print(context->priv->log, WLOG_WARN, -- "client sent capability %s we did not announce!", -- freerdp_rdpdr_dtyp_string(mask)); -- } -- -- /* we assume the server supports the capability. so only deactivate what the client did -- * not respond with */ -- if ((caps & mask) == 0) -- context->supported &= ~mask; -+ WLog_Print(context->priv->log, WLOG_WARN, -+ "client sent capability %s we did not announce!", -+ rdpdr_cap_type_string(capabilityHeader.CapabilityType)); - } -+ caps |= client_dtyp; - - const size_t end = Stream_GetPosition(s); - const size_t diff = end - start; -@@ -1035,6 +1045,9 @@ static UINT rdpdr_server_receive_core_capability_response(RdpdrServerContext* co - } - } - -+ /* Only deactivate what the client did not respond with */ -+ context->supported &= caps; -+ - return CHANNEL_RC_OK; - } - - -From 0e5bcdbb78657828098b290579da03c080e40333 Mon Sep 17 00:00:00 2001 -From: Joan Torres Lopez -Date: Wed, 6 May 2026 19:02:19 +0200 -Subject: [PATCH 02/31] [channels,smartcard] fix DeviceDataLength in - DEVICE_ANNOUNCE - -Per MS-RDPEFS 2.2.1.3, the DeviceDataLength field in the -DEVICE_ANNOUNCE message for smartcard devices must be 0. -Remove the "SCARD" device data that was incorrectly sent, -which caused the server to reject the announcement. ---- - channels/smartcard/client/smartcard_main.c | 11 ----------- - 1 file changed, 11 deletions(-) - -diff --git a/channels/smartcard/client/smartcard_main.c b/channels/smartcard/client/smartcard_main.c -index d186ddfa7ad8..bf08b8c08c7e 100644 ---- a/channels/smartcard/client/smartcard_main.c -+++ b/channels/smartcard/client/smartcard_main.c -@@ -632,7 +632,6 @@ static void smartcard_free_irp(void* obj) - */ - FREERDP_ENTRY_POINT(UINT VCAPITYPE DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints)) - { -- size_t length = 0; - UINT error = CHANNEL_RC_NO_MEMORY; - - SMARTCARD_DEVICE* smartcard = (SMARTCARD_DEVICE*)calloc(1, sizeof(SMARTCARD_DEVICE)); -@@ -649,16 +648,6 @@ FREERDP_ENTRY_POINT(UINT VCAPITYPE DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POIN - smartcard->device.Init = smartcard_init; - smartcard->device.Free = smartcard_free; - smartcard->rdpcontext = pEntryPoints->rdpcontext; -- length = strlen(smartcard->device.name); -- smartcard->device.data = Stream_New(nullptr, length + 1); -- -- if (!smartcard->device.data) -- { -- WLog_ERR(TAG, "Stream_New failed!"); -- goto fail; -- } -- -- Stream_Write(smartcard->device.data, "SCARD", 6); - smartcard->IrpQueue = MessageQueue_New(nullptr); - - if (!smartcard->IrpQueue) - -From 8a9b9d3b0e30f1e5454fb377bd5400c75175ae2e Mon Sep 17 00:00:00 2001 -From: Joan Torres Lopez -Date: Thu, 7 May 2026 19:05:10 +0200 -Subject: [PATCH 03/31] [utils,smartcard] use - RDPDR_DEVICE_IO_CONTROL_REQ_HDR_LENGTH constant - -Replace hardcoded 32 with the named constant for the device control -request header length check. ---- - libfreerdp/utils/smartcard_operations.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/libfreerdp/utils/smartcard_operations.c b/libfreerdp/utils/smartcard_operations.c -index b7a754831b30..dfbdfeacb08c 100644 ---- a/libfreerdp/utils/smartcard_operations.c -+++ b/libfreerdp/utils/smartcard_operations.c -@@ -547,7 +547,7 @@ LONG smartcard_irp_device_control_decode(wStream* s, UINT32 CompletionId, UINT32 - - /* Device Control Request */ - -- if (!Stream_CheckAndLogRequiredLength(TAG, s, 32)) -+ if (!Stream_CheckAndLogRequiredLength(TAG, s, RDPDR_DEVICE_IO_CONTROL_REQ_HDR_LENGTH)) - return SCARD_F_INTERNAL_ERROR; - - const UINT32 outputBufferLength = Stream_Get_UINT32(s); /* OutputBufferLength (4 bytes) */ - -From be8358d457f18dd9b6ace7abd9a04f5338676a05 Mon Sep 17 00:00:00 2001 -From: Joan Torres Lopez -Date: Thu, 7 May 2026 19:08:06 +0200 -Subject: [PATCH 04/31] [utils,smartcard] rename decode to decode_request - -smartcard_irp_device_control_decode only decodes device control request -types (DR_CONTROL_REQ), not response types. Rename to decode_request to -make this explicit and allow a symmetric decode_response counterpart. ---- - channels/smartcard/client/smartcard_main.c | 4 +- - include/freerdp/utils/smartcard_operations.h | 31 ++++ - libfreerdp/utils/smartcard_operations.c | 184 ++++++++++--------- - server/proxy/channels/pf_channel_smartcard.c | 2 +- - 4 files changed, 130 insertions(+), 91 deletions(-) - -diff --git a/channels/smartcard/client/smartcard_main.c b/channels/smartcard/client/smartcard_main.c -index bf08b8c08c7e..0093a1955d8a 100644 ---- a/channels/smartcard/client/smartcard_main.c -+++ b/channels/smartcard/client/smartcard_main.c -@@ -378,8 +378,8 @@ static UINT smartcard_process_irp(SMARTCARD_DEVICE* smartcard, IRP* irp, BOOL* h - element->irp = irp; - element->operation.completionID = irp->CompletionId; - -- status = smartcard_irp_device_control_decode(irp->input, irp->CompletionId, irp->FileId, -- &element->operation); -+ status = smartcard_irp_device_control_decode_request(irp->input, irp->CompletionId, -+ irp->FileId, &element->operation); - - if (status != SCARD_S_SUCCESS) - { -diff --git a/include/freerdp/utils/smartcard_operations.h b/include/freerdp/utils/smartcard_operations.h -index 90c71baf7dee..41a5fd6b043a 100644 ---- a/include/freerdp/utils/smartcard_operations.h -+++ b/include/freerdp/utils/smartcard_operations.h -@@ -86,11 +86,42 @@ extern "C" - UINT32 outputBufferLength; /** @since version 3.13.0 */ - } SMARTCARD_OPERATION; - -+ /** @brief Alias for \ref smartcard_irp_device_control_decode_request. -+ * -+ * Kept for backward compatibility; new code should use the _request variant. -+ */ - WINPR_ATTR_NODISCARD - FREERDP_API LONG smartcard_irp_device_control_decode(wStream* s, UINT32 CompletionId, - UINT32 FileId, - SMARTCARD_OPERATION* operation); - -+ /** @brief Decode a smartcard IOCTL request received from the client. -+ * -+ * Parses the Device Control Request fields (OutputBufferLength, InputBufferLength, -+ * IoControlCode, Padding), then unpacks the Common Type Header, Private Type Header, -+ * and the IOCTL-specific call payload into \p operation->call. -+ * -+ * @param s Stream positioned at OutputBufferLength, after the DeviceIoRequest header. -+ * @param CompletionId The CompletionId from the DeviceIoRequest header. -+ * @param FileId The FileId from the DeviceIoRequest header. -+ * @param operation [out] The decoded ioControlCode, call union, and context handles. -+ * @return \b SCARD_S_SUCCESS on success, a smartcard error code on failure. -+ * -+ * @since version 3.28.0 -+ */ -+ WINPR_ATTR_NODISCARD -+ FREERDP_API LONG smartcard_irp_device_control_decode_request(wStream* s, UINT32 CompletionId, -+ UINT32 FileId, -+ SMARTCARD_OPERATION* operation); -+ -+ /** @brief Free resources held by a SMARTCARD_OPERATION. -+ * -+ * Releases any memory allocated inside the call and ret unions (e.g., reader name -+ * strings, reader state arrays, receive buffers). -+ * -+ * @param op The operation to clean up. May be NULL (no-op). -+ * @param allocated If TRUE, also frees the SMARTCARD_OPERATION struct itself. -+ */ - FREERDP_API void smartcard_operation_free(SMARTCARD_OPERATION* op, BOOL allocated); - - #ifdef __cplusplus -diff --git a/libfreerdp/utils/smartcard_operations.c b/libfreerdp/utils/smartcard_operations.c -index dfbdfeacb08c..a56e4e23c3f0 100644 ---- a/libfreerdp/utils/smartcard_operations.c -+++ b/libfreerdp/utils/smartcard_operations.c -@@ -55,7 +55,7 @@ static LONG smartcard_call_to_operation_handle(SMARTCARD_OPERATION* operation) - return SCARD_S_SUCCESS; - } - --static LONG smartcard_EstablishContext_Decode(wStream* s, SMARTCARD_OPERATION* operation) -+static LONG smartcard_EstablishContext_decode_request(wStream* s, SMARTCARD_OPERATION* operation) - { - LONG status = 0; - -@@ -71,7 +71,7 @@ static LONG smartcard_EstablishContext_Decode(wStream* s, SMARTCARD_OPERATION* o - return SCARD_S_SUCCESS; - } - --static LONG smartcard_ReleaseContext_Decode(wStream* s, SMARTCARD_OPERATION* operation) -+static LONG smartcard_ReleaseContext_decode_request(wStream* s, SMARTCARD_OPERATION* operation) - { - LONG status = 0; - -@@ -85,7 +85,7 @@ static LONG smartcard_ReleaseContext_Decode(wStream* s, SMARTCARD_OPERATION* ope - return status; - } - --static LONG smartcard_IsValidContext_Decode(wStream* s, SMARTCARD_OPERATION* operation) -+static LONG smartcard_IsValidContext_decode_request(wStream* s, SMARTCARD_OPERATION* operation) - { - LONG status = 0; - -@@ -97,7 +97,7 @@ static LONG smartcard_IsValidContext_Decode(wStream* s, SMARTCARD_OPERATION* ope - return status; - } - --static LONG smartcard_ListReaderGroupsA_Decode(wStream* s, SMARTCARD_OPERATION* operation) -+static LONG smartcard_ListReaderGroupsA_decode_request(wStream* s, SMARTCARD_OPERATION* operation) - { - LONG status = 0; - -@@ -109,7 +109,7 @@ static LONG smartcard_ListReaderGroupsA_Decode(wStream* s, SMARTCARD_OPERATION* - return status; - } - --static LONG smartcard_ListReaderGroupsW_Decode(wStream* s, SMARTCARD_OPERATION* operation) -+static LONG smartcard_ListReaderGroupsW_decode_request(wStream* s, SMARTCARD_OPERATION* operation) - { - LONG status = 0; - -@@ -121,7 +121,7 @@ static LONG smartcard_ListReaderGroupsW_Decode(wStream* s, SMARTCARD_OPERATION* - return status; - } - --static LONG smartcard_ListReadersA_Decode(wStream* s, SMARTCARD_OPERATION* operation) -+static LONG smartcard_ListReadersA_decode_request(wStream* s, SMARTCARD_OPERATION* operation) - { - LONG status = 0; - -@@ -133,7 +133,7 @@ static LONG smartcard_ListReadersA_Decode(wStream* s, SMARTCARD_OPERATION* opera - return status; - } - --static LONG smartcard_ListReadersW_Decode(wStream* s, SMARTCARD_OPERATION* operation) -+static LONG smartcard_ListReadersW_decode_request(wStream* s, SMARTCARD_OPERATION* operation) - { - LONG status = 0; - -@@ -145,7 +145,8 @@ static LONG smartcard_ListReadersW_Decode(wStream* s, SMARTCARD_OPERATION* opera - return status; - } - --static LONG smartcard_context_and_two_strings_a_Decode(wStream* s, SMARTCARD_OPERATION* operation) -+static LONG smartcard_ContextAndTwoStringA_decode_request(wStream* s, -+ SMARTCARD_OPERATION* operation) - { - LONG status = 0; - -@@ -158,7 +159,8 @@ static LONG smartcard_context_and_two_strings_a_Decode(wStream* s, SMARTCARD_OPE - return status; - } - --static LONG smartcard_context_and_two_strings_w_Decode(wStream* s, SMARTCARD_OPERATION* operation) -+static LONG smartcard_ContextAndTwoStringW_decode_request(wStream* s, -+ SMARTCARD_OPERATION* operation) - { - LONG status = 0; - -@@ -171,7 +173,7 @@ static LONG smartcard_context_and_two_strings_w_Decode(wStream* s, SMARTCARD_OPE - return status; - } - --static LONG smartcard_context_and_string_a_Decode(wStream* s, SMARTCARD_OPERATION* operation) -+static LONG smartcard_ContextAndStringA_decode_request(wStream* s, SMARTCARD_OPERATION* operation) - { - LONG status = 0; - -@@ -183,7 +185,7 @@ static LONG smartcard_context_and_string_a_Decode(wStream* s, SMARTCARD_OPERATIO - return status; - } - --static LONG smartcard_context_and_string_w_Decode(wStream* s, SMARTCARD_OPERATION* operation) -+static LONG smartcard_ContextAndStringW_decode_request(wStream* s, SMARTCARD_OPERATION* operation) - { - LONG status = 0; - -@@ -195,7 +197,7 @@ static LONG smartcard_context_and_string_w_Decode(wStream* s, SMARTCARD_OPERATIO - return status; - } - --static LONG smartcard_LocateCardsA_Decode(wStream* s, SMARTCARD_OPERATION* operation) -+static LONG smartcard_LocateCardsA_decode_request(wStream* s, SMARTCARD_OPERATION* operation) - { - LONG status = 0; - -@@ -207,7 +209,7 @@ static LONG smartcard_LocateCardsA_Decode(wStream* s, SMARTCARD_OPERATION* opera - return status; - } - --static LONG smartcard_LocateCardsW_Decode(wStream* s, SMARTCARD_OPERATION* operation) -+static LONG smartcard_LocateCardsW_decode_request(wStream* s, SMARTCARD_OPERATION* operation) - { - LONG status = 0; - -@@ -219,7 +221,7 @@ static LONG smartcard_LocateCardsW_Decode(wStream* s, SMARTCARD_OPERATION* opera - return status; - } - --static LONG smartcard_GetStatusChangeA_Decode(wStream* s, SMARTCARD_OPERATION* operation) -+static LONG smartcard_GetStatusChangeA_decode_request(wStream* s, SMARTCARD_OPERATION* operation) - { - WINPR_ASSERT(s); - WINPR_ASSERT(operation); -@@ -227,7 +229,7 @@ static LONG smartcard_GetStatusChangeA_Decode(wStream* s, SMARTCARD_OPERATION* o - return smartcard_unpack_get_status_change_a_call(s, &operation->call.getStatusChangeA); - } - --static LONG smartcard_GetStatusChangeW_Decode(wStream* s, SMARTCARD_OPERATION* operation) -+static LONG smartcard_GetStatusChangeW_decode_request(wStream* s, SMARTCARD_OPERATION* operation) - { - WINPR_ASSERT(s); - WINPR_ASSERT(operation); -@@ -235,7 +237,7 @@ static LONG smartcard_GetStatusChangeW_Decode(wStream* s, SMARTCARD_OPERATION* o - return smartcard_unpack_get_status_change_w_call(s, &operation->call.getStatusChangeW); - } - --static LONG smartcard_Cancel_Decode(wStream* s, SMARTCARD_OPERATION* operation) -+static LONG smartcard_Cancel_decode_request(wStream* s, SMARTCARD_OPERATION* operation) - { - LONG status = 0; - -@@ -247,7 +249,7 @@ static LONG smartcard_Cancel_Decode(wStream* s, SMARTCARD_OPERATION* operation) - return status; - } - --static LONG smartcard_ConnectA_Decode(wStream* s, SMARTCARD_OPERATION* operation) -+static LONG smartcard_ConnectA_decode_request(wStream* s, SMARTCARD_OPERATION* operation) - { - LONG status = 0; - -@@ -259,7 +261,7 @@ static LONG smartcard_ConnectA_Decode(wStream* s, SMARTCARD_OPERATION* operation - return status; - } - --static LONG smartcard_ConnectW_Decode(wStream* s, SMARTCARD_OPERATION* operation) -+static LONG smartcard_ConnectW_decode_request(wStream* s, SMARTCARD_OPERATION* operation) - { - LONG status = 0; - -@@ -271,7 +273,7 @@ static LONG smartcard_ConnectW_Decode(wStream* s, SMARTCARD_OPERATION* operation - return status; - } - --static LONG smartcard_Reconnect_Decode(wStream* s, SMARTCARD_OPERATION* operation) -+static LONG smartcard_Reconnect_decode_request(wStream* s, SMARTCARD_OPERATION* operation) - { - LONG status = 0; - -@@ -283,7 +285,7 @@ static LONG smartcard_Reconnect_Decode(wStream* s, SMARTCARD_OPERATION* operatio - return status; - } - --static LONG smartcard_Disconnect_Decode(wStream* s, SMARTCARD_OPERATION* operation) -+static LONG smartcard_Disconnect_decode_request(wStream* s, SMARTCARD_OPERATION* operation) - { - LONG status = 0; - -@@ -296,7 +298,7 @@ static LONG smartcard_Disconnect_Decode(wStream* s, SMARTCARD_OPERATION* operati - return status; - } - --static LONG smartcard_BeginTransaction_Decode(wStream* s, SMARTCARD_OPERATION* operation) -+static LONG smartcard_BeginTransaction_decode_request(wStream* s, SMARTCARD_OPERATION* operation) - { - LONG status = 0; - -@@ -309,7 +311,7 @@ static LONG smartcard_BeginTransaction_Decode(wStream* s, SMARTCARD_OPERATION* o - return status; - } - --static LONG smartcard_EndTransaction_Decode(wStream* s, SMARTCARD_OPERATION* operation) -+static LONG smartcard_EndTransaction_decode_request(wStream* s, SMARTCARD_OPERATION* operation) - { - LONG status = 0; - -@@ -322,7 +324,7 @@ static LONG smartcard_EndTransaction_Decode(wStream* s, SMARTCARD_OPERATION* ope - return status; - } - --static LONG smartcard_State_Decode(wStream* s, SMARTCARD_OPERATION* operation) -+static LONG smartcard_State_decode_request(wStream* s, SMARTCARD_OPERATION* operation) - { - LONG status = 0; - -@@ -334,7 +336,7 @@ static LONG smartcard_State_Decode(wStream* s, SMARTCARD_OPERATION* operation) - return status; - } - --static LONG smartcard_StatusA_Decode(wStream* s, SMARTCARD_OPERATION* operation) -+static LONG smartcard_StatusA_decode_request(wStream* s, SMARTCARD_OPERATION* operation) - { - LONG status = 0; - -@@ -346,7 +348,7 @@ static LONG smartcard_StatusA_Decode(wStream* s, SMARTCARD_OPERATION* operation) - return status; - } - --static LONG smartcard_StatusW_Decode(wStream* s, SMARTCARD_OPERATION* operation) -+static LONG smartcard_StatusW_decode_request(wStream* s, SMARTCARD_OPERATION* operation) - { - LONG status = 0; - -@@ -358,7 +360,7 @@ static LONG smartcard_StatusW_Decode(wStream* s, SMARTCARD_OPERATION* operation) - return status; - } - --static LONG smartcard_Transmit_Decode(wStream* s, SMARTCARD_OPERATION* operation) -+static LONG smartcard_Transmit_decode_request(wStream* s, SMARTCARD_OPERATION* operation) - { - LONG status = 0; - -@@ -370,7 +372,7 @@ static LONG smartcard_Transmit_Decode(wStream* s, SMARTCARD_OPERATION* operation - return status; - } - --static LONG smartcard_Control_Decode(wStream* s, SMARTCARD_OPERATION* operation) -+static LONG smartcard_Control_decode_request(wStream* s, SMARTCARD_OPERATION* operation) - { - LONG status = 0; - -@@ -382,7 +384,7 @@ static LONG smartcard_Control_Decode(wStream* s, SMARTCARD_OPERATION* operation) - return status; - } - --static LONG smartcard_GetAttrib_Decode(wStream* s, SMARTCARD_OPERATION* operation) -+static LONG smartcard_GetAttrib_decode_request(wStream* s, SMARTCARD_OPERATION* operation) - { - LONG status = 0; - -@@ -394,7 +396,7 @@ static LONG smartcard_GetAttrib_Decode(wStream* s, SMARTCARD_OPERATION* operatio - return status; - } - --static LONG smartcard_SetAttrib_Decode(wStream* s, SMARTCARD_OPERATION* operation) -+static LONG smartcard_SetAttrib_decode_request(wStream* s, SMARTCARD_OPERATION* operation) - { - LONG status = 0; - -@@ -406,7 +408,7 @@ static LONG smartcard_SetAttrib_Decode(wStream* s, SMARTCARD_OPERATION* operatio - return status; - } - --static LONG smartcard_AccessStartedEvent_Decode(wStream* s, SMARTCARD_OPERATION* operation) -+static LONG smartcard_AccessStartedEvent_decode_request(wStream* s, SMARTCARD_OPERATION* operation) - { - WINPR_ASSERT(s); - WINPR_ASSERT(operation); -@@ -419,7 +421,7 @@ static LONG smartcard_AccessStartedEvent_Decode(wStream* s, SMARTCARD_OPERATION* - return SCARD_S_SUCCESS; - } - --static LONG smartcard_LocateCardsByATRA_Decode(wStream* s, SMARTCARD_OPERATION* operation) -+static LONG smartcard_LocateCardsByATRA_decode_request(wStream* s, SMARTCARD_OPERATION* operation) - { - LONG status = 0; - -@@ -431,7 +433,7 @@ static LONG smartcard_LocateCardsByATRA_Decode(wStream* s, SMARTCARD_OPERATION* - return status; - } - --static LONG smartcard_LocateCardsByATRW_Decode(wStream* s, SMARTCARD_OPERATION* operation) -+static LONG smartcard_LocateCardsByATRW_decode_request(wStream* s, SMARTCARD_OPERATION* operation) - { - LONG status = 0; - -@@ -443,7 +445,7 @@ static LONG smartcard_LocateCardsByATRW_Decode(wStream* s, SMARTCARD_OPERATION* - return status; - } - --static LONG smartcard_ReadCacheA_Decode(wStream* s, SMARTCARD_OPERATION* operation) -+static LONG smartcard_ReadCacheA_decode_request(wStream* s, SMARTCARD_OPERATION* operation) - { - LONG status = 0; - -@@ -455,7 +457,7 @@ static LONG smartcard_ReadCacheA_Decode(wStream* s, SMARTCARD_OPERATION* operati - return status; - } - --static LONG smartcard_ReadCacheW_Decode(wStream* s, SMARTCARD_OPERATION* operation) -+static LONG smartcard_ReadCacheW_decode_request(wStream* s, SMARTCARD_OPERATION* operation) - { - LONG status = 0; - -@@ -467,7 +469,7 @@ static LONG smartcard_ReadCacheW_Decode(wStream* s, SMARTCARD_OPERATION* operati - return status; - } - --static LONG smartcard_WriteCacheA_Decode(wStream* s, SMARTCARD_OPERATION* operation) -+static LONG smartcard_WriteCacheA_decode_request(wStream* s, SMARTCARD_OPERATION* operation) - { - LONG status = 0; - -@@ -479,7 +481,7 @@ static LONG smartcard_WriteCacheA_Decode(wStream* s, SMARTCARD_OPERATION* operat - return status; - } - --static LONG smartcard_WriteCacheW_Decode(wStream* s, SMARTCARD_OPERATION* operation) -+static LONG smartcard_WriteCacheW_decode_request(wStream* s, SMARTCARD_OPERATION* operation) - { - LONG status = 0; - -@@ -491,7 +493,7 @@ static LONG smartcard_WriteCacheW_Decode(wStream* s, SMARTCARD_OPERATION* operat - return status; - } - --static LONG smartcard_GetTransmitCount_Decode(wStream* s, SMARTCARD_OPERATION* operation) -+static LONG smartcard_GetTransmitCount_decode_request(wStream* s, SMARTCARD_OPERATION* operation) - { - LONG status = 0; - -@@ -503,7 +505,7 @@ static LONG smartcard_GetTransmitCount_Decode(wStream* s, SMARTCARD_OPERATION* o - return status; - } - --static LONG smartcard_ReleaseStartedEvent_Decode(wStream* s, SMARTCARD_OPERATION* operation) -+static LONG smartcard_ReleaseStartedEvent_decode_request(wStream* s, SMARTCARD_OPERATION* operation) - { - WINPR_UNUSED(s); - WINPR_UNUSED(operation); -@@ -512,7 +514,7 @@ static LONG smartcard_ReleaseStartedEvent_Decode(wStream* s, SMARTCARD_OPERATION - return SCARD_E_UNSUPPORTED_FEATURE; - } - --static LONG smartcard_GetReaderIcon_Decode(wStream* s, SMARTCARD_OPERATION* operation) -+static LONG smartcard_GetReaderIcon_decode_request(wStream* s, SMARTCARD_OPERATION* operation) - { - LONG status = 0; - -@@ -524,7 +526,7 @@ static LONG smartcard_GetReaderIcon_Decode(wStream* s, SMARTCARD_OPERATION* oper - return status; - } - --static LONG smartcard_GetDeviceTypeId_Decode(wStream* s, SMARTCARD_OPERATION* operation) -+static LONG smartcard_GetDeviceTypeId_decode_request(wStream* s, SMARTCARD_OPERATION* operation) - { - LONG status = 0; - -@@ -538,6 +540,12 @@ static LONG smartcard_GetDeviceTypeId_Decode(wStream* s, SMARTCARD_OPERATION* op - - LONG smartcard_irp_device_control_decode(wStream* s, UINT32 CompletionId, UINT32 FileId, - SMARTCARD_OPERATION* operation) -+{ -+ return smartcard_irp_device_control_decode_request(s, CompletionId, FileId, operation); -+} -+ -+LONG smartcard_irp_device_control_decode_request(wStream* s, UINT32 CompletionId, UINT32 FileId, -+ SMARTCARD_OPERATION* operation) - { - LONG status = 0; - UINT32 offset = 0; -@@ -584,195 +592,195 @@ LONG smartcard_irp_device_control_decode(wStream* s, UINT32 CompletionId, UINT32 - switch (ioControlCode) - { - case SCARD_IOCTL_ESTABLISHCONTEXT: -- status = smartcard_EstablishContext_Decode(s, operation); -+ status = smartcard_EstablishContext_decode_request(s, operation); - break; - - case SCARD_IOCTL_RELEASECONTEXT: -- status = smartcard_ReleaseContext_Decode(s, operation); -+ status = smartcard_ReleaseContext_decode_request(s, operation); - break; - - case SCARD_IOCTL_ISVALIDCONTEXT: -- status = smartcard_IsValidContext_Decode(s, operation); -+ status = smartcard_IsValidContext_decode_request(s, operation); - break; - - case SCARD_IOCTL_LISTREADERGROUPSA: -- status = smartcard_ListReaderGroupsA_Decode(s, operation); -+ status = smartcard_ListReaderGroupsA_decode_request(s, operation); - break; - - case SCARD_IOCTL_LISTREADERGROUPSW: -- status = smartcard_ListReaderGroupsW_Decode(s, operation); -+ status = smartcard_ListReaderGroupsW_decode_request(s, operation); - break; - - case SCARD_IOCTL_LISTREADERSA: -- status = smartcard_ListReadersA_Decode(s, operation); -+ status = smartcard_ListReadersA_decode_request(s, operation); - break; - - case SCARD_IOCTL_LISTREADERSW: -- status = smartcard_ListReadersW_Decode(s, operation); -+ status = smartcard_ListReadersW_decode_request(s, operation); - break; - - case SCARD_IOCTL_INTRODUCEREADERGROUPA: -- status = smartcard_context_and_string_a_Decode(s, operation); -+ status = smartcard_ContextAndStringA_decode_request(s, operation); - break; - - case SCARD_IOCTL_INTRODUCEREADERGROUPW: -- status = smartcard_context_and_string_w_Decode(s, operation); -+ status = smartcard_ContextAndStringW_decode_request(s, operation); - break; - - case SCARD_IOCTL_FORGETREADERGROUPA: -- status = smartcard_context_and_string_a_Decode(s, operation); -+ status = smartcard_ContextAndStringA_decode_request(s, operation); - break; - - case SCARD_IOCTL_FORGETREADERGROUPW: -- status = smartcard_context_and_string_w_Decode(s, operation); -+ status = smartcard_ContextAndStringW_decode_request(s, operation); - break; - - case SCARD_IOCTL_INTRODUCEREADERA: -- status = smartcard_context_and_two_strings_a_Decode(s, operation); -+ status = smartcard_ContextAndTwoStringA_decode_request(s, operation); - break; - - case SCARD_IOCTL_INTRODUCEREADERW: -- status = smartcard_context_and_two_strings_w_Decode(s, operation); -+ status = smartcard_ContextAndTwoStringW_decode_request(s, operation); - break; - - case SCARD_IOCTL_FORGETREADERA: -- status = smartcard_context_and_string_a_Decode(s, operation); -+ status = smartcard_ContextAndStringA_decode_request(s, operation); - break; - - case SCARD_IOCTL_FORGETREADERW: -- status = smartcard_context_and_string_w_Decode(s, operation); -+ status = smartcard_ContextAndStringW_decode_request(s, operation); - break; - - case SCARD_IOCTL_ADDREADERTOGROUPA: -- status = smartcard_context_and_two_strings_a_Decode(s, operation); -+ status = smartcard_ContextAndTwoStringA_decode_request(s, operation); - break; - - case SCARD_IOCTL_ADDREADERTOGROUPW: -- status = smartcard_context_and_two_strings_w_Decode(s, operation); -+ status = smartcard_ContextAndTwoStringW_decode_request(s, operation); - break; - - case SCARD_IOCTL_REMOVEREADERFROMGROUPA: -- status = smartcard_context_and_two_strings_a_Decode(s, operation); -+ status = smartcard_ContextAndTwoStringA_decode_request(s, operation); - break; - - case SCARD_IOCTL_REMOVEREADERFROMGROUPW: -- status = smartcard_context_and_two_strings_w_Decode(s, operation); -+ status = smartcard_ContextAndTwoStringW_decode_request(s, operation); - break; - - case SCARD_IOCTL_LOCATECARDSA: -- status = smartcard_LocateCardsA_Decode(s, operation); -+ status = smartcard_LocateCardsA_decode_request(s, operation); - break; - - case SCARD_IOCTL_LOCATECARDSW: -- status = smartcard_LocateCardsW_Decode(s, operation); -+ status = smartcard_LocateCardsW_decode_request(s, operation); - break; - - case SCARD_IOCTL_GETSTATUSCHANGEA: -- status = smartcard_GetStatusChangeA_Decode(s, operation); -+ status = smartcard_GetStatusChangeA_decode_request(s, operation); - break; - - case SCARD_IOCTL_GETSTATUSCHANGEW: -- status = smartcard_GetStatusChangeW_Decode(s, operation); -+ status = smartcard_GetStatusChangeW_decode_request(s, operation); - break; - - case SCARD_IOCTL_CANCEL: -- status = smartcard_Cancel_Decode(s, operation); -+ status = smartcard_Cancel_decode_request(s, operation); - break; - - case SCARD_IOCTL_CONNECTA: -- status = smartcard_ConnectA_Decode(s, operation); -+ status = smartcard_ConnectA_decode_request(s, operation); - break; - - case SCARD_IOCTL_CONNECTW: -- status = smartcard_ConnectW_Decode(s, operation); -+ status = smartcard_ConnectW_decode_request(s, operation); - break; - - case SCARD_IOCTL_RECONNECT: -- status = smartcard_Reconnect_Decode(s, operation); -+ status = smartcard_Reconnect_decode_request(s, operation); - break; - - case SCARD_IOCTL_DISCONNECT: -- status = smartcard_Disconnect_Decode(s, operation); -+ status = smartcard_Disconnect_decode_request(s, operation); - break; - - case SCARD_IOCTL_BEGINTRANSACTION: -- status = smartcard_BeginTransaction_Decode(s, operation); -+ status = smartcard_BeginTransaction_decode_request(s, operation); - break; - - case SCARD_IOCTL_ENDTRANSACTION: -- status = smartcard_EndTransaction_Decode(s, operation); -+ status = smartcard_EndTransaction_decode_request(s, operation); - break; - - case SCARD_IOCTL_STATE: -- status = smartcard_State_Decode(s, operation); -+ status = smartcard_State_decode_request(s, operation); - break; - - case SCARD_IOCTL_STATUSA: -- status = smartcard_StatusA_Decode(s, operation); -+ status = smartcard_StatusA_decode_request(s, operation); - break; - - case SCARD_IOCTL_STATUSW: -- status = smartcard_StatusW_Decode(s, operation); -+ status = smartcard_StatusW_decode_request(s, operation); - break; - - case SCARD_IOCTL_TRANSMIT: -- status = smartcard_Transmit_Decode(s, operation); -+ status = smartcard_Transmit_decode_request(s, operation); - break; - - case SCARD_IOCTL_CONTROL: -- status = smartcard_Control_Decode(s, operation); -+ status = smartcard_Control_decode_request(s, operation); - break; - - case SCARD_IOCTL_GETATTRIB: -- status = smartcard_GetAttrib_Decode(s, operation); -+ status = smartcard_GetAttrib_decode_request(s, operation); - break; - - case SCARD_IOCTL_SETATTRIB: -- status = smartcard_SetAttrib_Decode(s, operation); -+ status = smartcard_SetAttrib_decode_request(s, operation); - break; - - case SCARD_IOCTL_ACCESSSTARTEDEVENT: -- status = smartcard_AccessStartedEvent_Decode(s, operation); -+ status = smartcard_AccessStartedEvent_decode_request(s, operation); - break; - - case SCARD_IOCTL_LOCATECARDSBYATRA: -- status = smartcard_LocateCardsByATRA_Decode(s, operation); -+ status = smartcard_LocateCardsByATRA_decode_request(s, operation); - break; - - case SCARD_IOCTL_LOCATECARDSBYATRW: -- status = smartcard_LocateCardsByATRW_Decode(s, operation); -+ status = smartcard_LocateCardsByATRW_decode_request(s, operation); - break; - - case SCARD_IOCTL_READCACHEA: -- status = smartcard_ReadCacheA_Decode(s, operation); -+ status = smartcard_ReadCacheA_decode_request(s, operation); - break; - - case SCARD_IOCTL_READCACHEW: -- status = smartcard_ReadCacheW_Decode(s, operation); -+ status = smartcard_ReadCacheW_decode_request(s, operation); - break; - - case SCARD_IOCTL_WRITECACHEA: -- status = smartcard_WriteCacheA_Decode(s, operation); -+ status = smartcard_WriteCacheA_decode_request(s, operation); - break; - - case SCARD_IOCTL_WRITECACHEW: -- status = smartcard_WriteCacheW_Decode(s, operation); -+ status = smartcard_WriteCacheW_decode_request(s, operation); - break; - - case SCARD_IOCTL_GETTRANSMITCOUNT: -- status = smartcard_GetTransmitCount_Decode(s, operation); -+ status = smartcard_GetTransmitCount_decode_request(s, operation); - break; - - case SCARD_IOCTL_RELEASETARTEDEVENT: -- status = smartcard_ReleaseStartedEvent_Decode(s, operation); -+ status = smartcard_ReleaseStartedEvent_decode_request(s, operation); - break; - - case SCARD_IOCTL_GETREADERICON: -- status = smartcard_GetReaderIcon_Decode(s, operation); -+ status = smartcard_GetReaderIcon_decode_request(s, operation); - break; - - case SCARD_IOCTL_GETDEVICETYPEID: -- status = smartcard_GetDeviceTypeId_Decode(s, operation); -+ status = smartcard_GetDeviceTypeId_decode_request(s, operation); - break; - - default: -diff --git a/server/proxy/channels/pf_channel_smartcard.c b/server/proxy/channels/pf_channel_smartcard.c -index 3bd9360bb0c7..a69dc55b9250 100644 ---- a/server/proxy/channels/pf_channel_smartcard.c -+++ b/server/proxy/channels/pf_channel_smartcard.c -@@ -214,7 +214,7 @@ BOOL pf_channel_smartcard_client_handle(wLog* log, pClientContext* pc, wStream* - return FALSE; - } - -- status = smartcard_irp_device_control_decode(s, CompletionId, FileId, &e.op); -+ status = smartcard_irp_device_control_decode_request(s, CompletionId, FileId, &e.op); - if (status != 0) - goto fail; - - -From 6efff92ae960647bd48afb1c0e913610a1768f81 Mon Sep 17 00:00:00 2001 -From: Joan Torres Lopez -Date: Thu, 14 May 2026 13:02:38 +0200 -Subject: [PATCH 05/31] [utils,smartcard] remove extra line breaks in - smartcard_operation_free - -In the switch some entries had line breaks and others didn't. -This ensures there's a consistent style. ---- - libfreerdp/utils/smartcard_operations.c | 9 --------- - 1 file changed, 9 deletions(-) - -diff --git a/libfreerdp/utils/smartcard_operations.c b/libfreerdp/utils/smartcard_operations.c -index a56e4e23c3f0..61c5761a41f6 100644 ---- a/libfreerdp/utils/smartcard_operations.c -+++ b/libfreerdp/utils/smartcard_operations.c -@@ -871,7 +871,6 @@ void smartcard_operation_free(SMARTCARD_OPERATION* op, BOOL allocated) - case SCARD_IOCTL_GETATTRIB: - case SCARD_IOCTL_GETTRANSMITCOUNT: - break; -- - case SCARD_IOCTL_LOCATECARDSA: - { - LocateCardsA_Call* call = &op->call.locateCardsA; -@@ -888,7 +887,6 @@ void smartcard_operation_free(SMARTCARD_OPERATION* op, BOOL allocated) - free_reader_states_w(call->rgReaderStates, call->cReaders); - } - break; -- - case SCARD_IOCTL_LOCATECARDSBYATRA: - { - LocateCardsByATRA_Call* call = &op->call.locateCardsByATRA; -@@ -910,7 +908,6 @@ void smartcard_operation_free(SMARTCARD_OPERATION* op, BOOL allocated) - free(call->sz); - } - break; -- - case SCARD_IOCTL_FORGETREADERW: - case SCARD_IOCTL_INTRODUCEREADERGROUPW: - case SCARD_IOCTL_FORGETREADERGROUPW: -@@ -919,29 +916,24 @@ void smartcard_operation_free(SMARTCARD_OPERATION* op, BOOL allocated) - free(call->sz); - } - break; -- - case SCARD_IOCTL_INTRODUCEREADERA: - case SCARD_IOCTL_REMOVEREADERFROMGROUPA: - case SCARD_IOCTL_ADDREADERTOGROUPA: -- - { - ContextAndTwoStringA_Call* call = &op->call.contextAndTwoStringA; - free(call->sz1); - free(call->sz2); - } - break; -- - case SCARD_IOCTL_INTRODUCEREADERW: - case SCARD_IOCTL_REMOVEREADERFROMGROUPW: - case SCARD_IOCTL_ADDREADERTOGROUPW: -- - { - ContextAndTwoStringW_Call* call = &op->call.contextAndTwoStringW; - free(call->sz1); - free(call->sz2); - } - break; -- - case SCARD_IOCTL_LISTREADERSA: - case SCARD_IOCTL_LISTREADERSW: - { -@@ -955,7 +947,6 @@ void smartcard_operation_free(SMARTCARD_OPERATION* op, BOOL allocated) - free_reader_states_a(call->rgReaderStates, call->cReaders); - } - break; -- - case SCARD_IOCTL_GETSTATUSCHANGEW: - { - GetStatusChangeW_Call* call = &op->call.getStatusChangeW; - -From ed6f3bc1306313f94acc694d60686f2278a3fdb5 Mon Sep 17 00:00:00 2001 -From: Joan Torres Lopez -Date: Wed, 13 May 2026 12:34:46 +0200 -Subject: [PATCH 06/31] [utils,smartcard] document smartcard_pack.h public API - -Add comments to all public functions describing parameters, return -values and stream positioning, preparing for additional unpack methods. - -Co-Authored-By: Claude ---- - include/freerdp/utils/smartcard_pack.h | 315 ++++++++++++++++++++++++- - 1 file changed, 313 insertions(+), 2 deletions(-) - -diff --git a/include/freerdp/utils/smartcard_pack.h b/include/freerdp/utils/smartcard_pack.h -index 4dc31b4a1a64..96cae2387abb 100644 ---- a/include/freerdp/utils/smartcard_pack.h -+++ b/include/freerdp/utils/smartcard_pack.h -@@ -39,197 +39,508 @@ extern "C" - { - #endif - -+ /** @brief Write adding bytes to align to \p alignment. -+ * @param s Stream to write padding into. -+ * @param size Number of data bytes written so far. -+ * @param alignment Required alignment boundary. -+ * @return \b SCARD_S_SUCCESS on success, an error code on failure. -+ */ - WINPR_ATTR_NODISCARD - FREERDP_API LONG smartcard_pack_write_size_align(wStream* s, size_t size, UINT32 alignment); - -+ /** @brief Read and skip padding bytes to align to \p alignment. -+ * @param s Stream to read padding from. -+ * @param size Number of data bytes read so far. -+ * @param alignment Required alignment boundary. -+ * @return \b SCARD_S_SUCCESS on success, an error code on failure. -+ */ - WINPR_ATTR_NODISCARD - FREERDP_API LONG smartcard_unpack_read_size_align(wStream* s, size_t size, UINT32 alignment); - -+ /** @brief Convert a REDIR_SCARDCONTEXT to a native SCARDCONTEXT. -+ * @param context The redirected context to convert. -+ * @return The native SCARDCONTEXT value. -+ */ - WINPR_ATTR_NODISCARD - FREERDP_API SCARDCONTEXT smartcard_scard_context_native_from_redir(REDIR_SCARDCONTEXT* context); -+ -+ /** @brief Convert a native SCARDCONTEXT to a REDIR_SCARDCONTEXT. -+ * @param context [out] The redirected context to populate. -+ * @param hContext The native SCARDCONTEXT value. -+ */ - FREERDP_API void smartcard_scard_context_native_to_redir(REDIR_SCARDCONTEXT* context, - SCARDCONTEXT hContext); - -+ /** @brief Convert a REDIR_SCARDHANDLE to a native SCARDHANDLE. -+ * @param handle The redirected handle to convert. -+ * @return The native SCARDHANDLE value. -+ */ - WINPR_ATTR_NODISCARD - FREERDP_API SCARDHANDLE smartcard_scard_handle_native_from_redir(REDIR_SCARDHANDLE* handle); -+ -+ /** @brief Convert a native SCARDHANDLE to a REDIR_SCARDHANDLE. -+ * @param handle [out] The redirected handle to populate. -+ * @param hCard The native SCARDHANDLE value. -+ */ - FREERDP_API void smartcard_scard_handle_native_to_redir(REDIR_SCARDHANDLE* handle, - SCARDHANDLE hCard); - -+ /** @brief Unpack the Common Type Header [MS-RPCE] from a stream. -+ * @param s Stream to read from. -+ * @return \b SCARD_S_SUCCESS on success, an error code on failure. -+ */ - WINPR_ATTR_NODISCARD - FREERDP_API LONG smartcard_unpack_common_type_header(wStream* s); -+ -+ /** @brief Pack the Common Type Header [MS-RPCE] into a stream. -+ * @param s Stream to write into. -+ */ - FREERDP_API void smartcard_pack_common_type_header(wStream* s); - -+ /** @brief Unpack the Private Type Header [MS-RPCE] from a stream. -+ * @param s Stream to read from. -+ * @return \b SCARD_S_SUCCESS on success, an error code on failure. -+ */ - WINPR_ATTR_NODISCARD - FREERDP_API LONG smartcard_unpack_private_type_header(wStream* s); -+ -+ /** @brief Pack the Private Type Header [MS-RPCE] into a stream. -+ * @param s Stream to write into. -+ * @param objectBufferLength Length of the payload following this header. -+ */ - FREERDP_API void smartcard_pack_private_type_header(wStream* s, UINT32 objectBufferLength); - -+ /** @brief Unpack an EstablishContext_Call from a stream. -+ * @param s Stream positioned after the Common/Private Type Headers. -+ * @param call [out] The decoded EstablishContext_Call. -+ * @return \b SCARD_S_SUCCESS on success, an error code on failure. -+ */ - WINPR_ATTR_NODISCARD - FREERDP_API LONG smartcard_unpack_establish_context_call(wStream* s, - EstablishContext_Call* call); - -+ /** @brief Pack an EstablishContext_Return into a stream. -+ * @param s Stream to write into after the Common/Private Type Headers and the ReturnCode. -+ * @param ret The EstablishContext_Return to encode. -+ * @return \b SCARD_S_SUCCESS on success, an error code on failure. -+ */ - WINPR_ATTR_NODISCARD - FREERDP_API LONG smartcard_pack_establish_context_return(wStream* s, - const EstablishContext_Return* ret); - -+ /** @brief Unpack a Context_Call from a stream. -+ * @param s Stream positioned after the Common/Private Type Headers. -+ * @param call [out] The decoded Context_Call. -+ * @param name Operation name used for trace logging. -+ * @return \b SCARD_S_SUCCESS on success, an error code on failure. -+ */ - WINPR_ATTR_NODISCARD - FREERDP_API LONG smartcard_unpack_context_call(wStream* s, Context_Call* call, - const char* name); - -+ /** @brief Log a Long_Return for tracing purposes. -+ * @param ret The Long_Return to trace. -+ * @param name Operation name used for the log message. -+ */ - FREERDP_API void smartcard_trace_long_return(const Long_Return* ret, const char* name); - -+ /** @brief Unpack a ListReaderGroups_Call from a stream. -+ * @param s Stream positioned after the Common/Private Type Headers. -+ * @param call [out] The decoded ListReaderGroups_Call. -+ * @param unicode TRUE for wide-char (W) variant, FALSE for ANSI (A). -+ * @return \b SCARD_S_SUCCESS on success, an error code on failure. -+ */ - WINPR_ATTR_NODISCARD - FREERDP_API LONG smartcard_unpack_list_reader_groups_call(wStream* s, - ListReaderGroups_Call* call, - BOOL unicode); - -+ /** @brief Pack a ListReaderGroups_Return into a stream. -+ * @param s Stream positioned after the the Common/Private Type Headers and the -+ * ReturnCode. -+ * @param ret The ListReaderGroups_Return to encode. -+ * @param unicode TRUE for wide-char (W) variant, FALSE for ANSI (A). -+ * @return \b SCARD_S_SUCCESS on success, an error code on failure. -+ */ - WINPR_ATTR_NODISCARD - FREERDP_API LONG smartcard_pack_list_reader_groups_return(wStream* s, - const ListReaderGroups_Return* ret, - BOOL unicode); - -+ /** @brief Unpack a ListReaders_Call from a stream. -+ * @param s Stream positioned after the Common/Private Type Headers. -+ * @param call [out] The decoded ListReaders_Call. -+ * @param unicode TRUE for wide-char (W) variant, FALSE for ANSI (A). -+ * @return \b SCARD_S_SUCCESS on success, an error code on failure. -+ */ - WINPR_ATTR_NODISCARD - FREERDP_API LONG smartcard_unpack_list_readers_call(wStream* s, ListReaders_Call* call, - BOOL unicode); - -+ /** @brief Pack a ListReaders_Return into a stream. -+ * @param s Stream to write into after the Common/Private Type Headers and the -+ * ReturnCode. -+ * @param ret The ListReaders_Return to encode. -+ * @param unicode TRUE for wide-char (W) variant, FALSE for ANSI (A). -+ * @return \b SCARD_S_SUCCESS on success, an error code on failure. -+ */ - WINPR_ATTR_NODISCARD - FREERDP_API LONG smartcard_pack_list_readers_return(wStream* s, const ListReaders_Return* ret, - BOOL unicode); - -+ /** @brief Unpack a ContextAndTwoStringA_Call from a stream. -+ * @param s Stream positioned after the Common/Private Type Headers. -+ * @param call [out] The decoded ContextAndTwoStringA_Call. -+ * @return \b SCARD_S_SUCCESS on success, an error code on failure. -+ */ - WINPR_ATTR_NODISCARD - FREERDP_API LONG - smartcard_unpack_context_and_two_strings_a_call(wStream* s, ContextAndTwoStringA_Call* call); - -+ /** @brief Unpack a ContextAndTwoStringW_Call from a stream. -+ * @param s Stream positioned after the Common/Private Type Headers. -+ * @param call [out] The decoded ContextAndTwoStringW_Call. -+ * @return \b SCARD_S_SUCCESS on success, an error code on failure. -+ */ - WINPR_ATTR_NODISCARD - FREERDP_API LONG - smartcard_unpack_context_and_two_strings_w_call(wStream* s, ContextAndTwoStringW_Call* call); - -+ /** @brief Unpack a ContextAndStringA_Call from a stream. -+ * @param s Stream positioned after the Common/Private Type Headers. -+ * @param call [out] The decoded ContextAndStringA_Call. -+ * @return \b SCARD_S_SUCCESS on success, an error code on failure. -+ */ - WINPR_ATTR_NODISCARD - FREERDP_API LONG smartcard_unpack_context_and_string_a_call(wStream* s, - ContextAndStringA_Call* call); - -+ /** @brief Unpack a ContextAndStringW_Call from a stream. -+ * @param s Stream positioned after the Common/Private Type Headers. -+ * @param call [out] The decoded ContextAndStringW_Call. -+ * @return \b SCARD_S_SUCCESS on success, an error code on failure. -+ */ - WINPR_ATTR_NODISCARD - FREERDP_API LONG smartcard_unpack_context_and_string_w_call(wStream* s, - ContextAndStringW_Call* call); - -+ /** @brief Unpack a LocateCardsA_Call from a stream. -+ * @param s Stream positioned after the Common/Private Type Headers. -+ * @param call [out] The decoded LocateCardsA_Call. -+ * @return \b SCARD_S_SUCCESS on success, an error code on failure. -+ */ - WINPR_ATTR_NODISCARD - FREERDP_API LONG smartcard_unpack_locate_cards_a_call(wStream* s, LocateCardsA_Call* call); - -+ /** @brief Pack a LocateCards_Return into a stream. -+ * @param s Stream to write into after the Common/Private Type Headers and the ReturnCode. -+ * @param ret The LocateCards_Return to encode. -+ * @return \b SCARD_S_SUCCESS on success, an error code on failure. -+ */ - WINPR_ATTR_NODISCARD - FREERDP_API LONG smartcard_pack_locate_cards_return(wStream* s, const LocateCards_Return* ret); - -+ /** @brief Unpack a LocateCardsW_Call from a stream. -+ * @param s Stream positioned after the Common/Private Type Headers. -+ * @param call [out] The decoded LocateCardsW_Call. -+ * @return \b SCARD_S_SUCCESS on success, an error code on failure. -+ */ - WINPR_ATTR_NODISCARD - FREERDP_API LONG smartcard_unpack_locate_cards_w_call(wStream* s, LocateCardsW_Call* call); - -+ /** @brief Pack a LocateCardsW return into a stream. -+ * @param s Stream to write into after the Common/Private Type Headers and the ReturnCode. -+ * @param ret The LocateCards_Return containing the return data to encode. -+ * @return \b SCARD_S_SUCCESS on success, an error code on failure. -+ */ - WINPR_ATTR_NODISCARD -- FREERDP_API LONG smartcard_pack_locate_cards_w_return(wStream* s, const LocateCardsW_Call* ret); -+ FREERDP_API LONG smartcard_pack_locate_cards_w_return(wStream* s, -+ const LocateCards_Return* ret); - -+ /** @brief Unpack a ConnectA_Call from a stream. -+ * @param s Stream positioned after the Common/Private Type Headers. -+ * @param call [out] The decoded ConnectA_Call. -+ * @return \b SCARD_S_SUCCESS on success, an error code on failure. -+ */ - WINPR_ATTR_NODISCARD - FREERDP_API LONG smartcard_unpack_connect_a_call(wStream* s, ConnectA_Call* call); - -+ /** @brief Unpack a ConnectW_Call from a stream. -+ * @param s Stream positioned after the Common/Private Type Headers. -+ * @param call [out] The decoded ConnectW_Call. -+ * @return \b SCARD_S_SUCCESS on success, an error code on failure. -+ */ - WINPR_ATTR_NODISCARD - FREERDP_API LONG smartcard_unpack_connect_w_call(wStream* s, ConnectW_Call* call); - -+ /** @brief Pack a Connect_Return into a stream. -+ * @param s Stream to write into after the Common/Private Type Headers and the ReturnCode. -+ * @param ret The Connect_Return to encode. -+ * @return \b SCARD_S_SUCCESS on success, an error code on failure. -+ */ - WINPR_ATTR_NODISCARD - FREERDP_API LONG smartcard_pack_connect_return(wStream* s, const Connect_Return* ret); - -+ /** @brief Unpack a Reconnect_Call from a stream. -+ * @param s Stream positioned after the Common/Private Type Headers. -+ * @param call [out] The decoded Reconnect_Call. -+ * @return \b SCARD_S_SUCCESS on success, an error code on failure. -+ */ - WINPR_ATTR_NODISCARD - FREERDP_API LONG smartcard_unpack_reconnect_call(wStream* s, Reconnect_Call* call); - -+ /** @brief Pack a Reconnect_Return into a stream. -+ * @param s Stream to write into after the Common/Private Type Headers and the ReturnCode. -+ * @param ret The Reconnect_Return to encode. -+ * @return \b SCARD_S_SUCCESS on success, an error code on failure. -+ */ - WINPR_ATTR_NODISCARD - FREERDP_API LONG smartcard_pack_reconnect_return(wStream* s, const Reconnect_Return* ret); - -+ /** @brief Unpack a HCardAndDisposition_Call from a stream. -+ * @param s Stream positioned after the Common/Private Type Headers. -+ * @param call [out] The decoded HCardAndDisposition_Call. -+ * @param name Operation name used for trace logging. -+ * @return \b SCARD_S_SUCCESS on success, an error code on failure. -+ */ - WINPR_ATTR_NODISCARD - FREERDP_API LONG smartcard_unpack_hcard_and_disposition_call(wStream* s, - HCardAndDisposition_Call* call, - const char* name); - -+ /** @brief Unpack a GetStatusChangeA_Call from a stream. -+ * @param s Stream positioned after the Common/Private Type Headers. -+ * @param call [out] The decoded GetStatusChangeA_Call. -+ * @return \b SCARD_S_SUCCESS on success, an error code on failure. -+ */ - WINPR_ATTR_NODISCARD - FREERDP_API LONG smartcard_unpack_get_status_change_a_call(wStream* s, - GetStatusChangeA_Call* call); - -+ /** @brief Unpack a GetStatusChangeW_Call from a stream. -+ * @param s Stream positioned after the Common/Private Type Headers. -+ * @param call [out] The decoded GetStatusChangeW_Call. -+ * @return \b SCARD_S_SUCCESS on success, an error code on failure. -+ */ - WINPR_ATTR_NODISCARD - FREERDP_API LONG smartcard_unpack_get_status_change_w_call(wStream* s, - GetStatusChangeW_Call* call); - -+ /** @brief Pack a GetStatusChange_Return into a stream. -+ * @param s Stream to write into after the Common/Private Type Headers and the -+ * ReturnCode. -+ * @param ret The GetStatusChange_Return to encode. -+ * @param unicode TRUE for wide-char (W) variant, FALSE for ANSI (A). -+ * @return \b SCARD_S_SUCCESS on success, an error code on failure. -+ */ - WINPR_ATTR_NODISCARD - FREERDP_API LONG smartcard_pack_get_status_change_return(wStream* s, - const GetStatusChange_Return* ret, - BOOL unicode); - -+ /** @brief Unpack a State_Call from a stream. -+ * @param s Stream positioned after the Common/Private Type Headers. -+ * @param call [out] The decoded State_Call. -+ * @return \b SCARD_S_SUCCESS on success, an error code on failure. -+ */ - WINPR_ATTR_NODISCARD - FREERDP_API LONG smartcard_unpack_state_call(wStream* s, State_Call* call); -+ -+ /** @brief Pack a State_Return into a stream. -+ * @param s Stream to write into after the Common/Private Type Headers and the ReturnCode. -+ * @param ret The State_Return to encode. -+ * @return \b SCARD_S_SUCCESS on success, an error code on failure. -+ */ - WINPR_ATTR_NODISCARD - FREERDP_API LONG smartcard_pack_state_return(wStream* s, const State_Return* ret); - -+ /** @brief Unpack a Status_Call from a stream. -+ * @param s Stream positioned after the Common/Private Type Headers. -+ * @param call [out] The decoded Status_Call. -+ * @param unicode TRUE for wide-char (W) variant, FALSE for ANSI (A). -+ * @return \b SCARD_S_SUCCESS on success, an error code on failure. -+ */ - WINPR_ATTR_NODISCARD - FREERDP_API LONG smartcard_unpack_status_call(wStream* s, Status_Call* call, BOOL unicode); - -+ /** @brief Pack a Status_Return into a stream. -+ * @param s Stream to write into after the Common/Private Type Headers and the -+ * ReturnCode. -+ * @param ret The Status_Return to encode. -+ * @param unicode TRUE for wide-char (W) variant, FALSE for ANSI (A). -+ * @return \b SCARD_S_SUCCESS on success, an error code on failure. -+ */ - WINPR_ATTR_NODISCARD - FREERDP_API LONG smartcard_pack_status_return(wStream* s, const Status_Return* ret, - BOOL unicode); - -+ /** @brief Unpack a GetAttrib_Call from a stream. -+ * @param s Stream positioned after the Common/Private Type Headers. -+ * @param call [out] The decoded GetAttrib_Call. -+ * @return \b SCARD_S_SUCCESS on success, an error code on failure. -+ */ - WINPR_ATTR_NODISCARD - FREERDP_API LONG smartcard_unpack_get_attrib_call(wStream* s, GetAttrib_Call* call); - -+ /** @brief Pack a GetAttrib_Return into a stream. -+ * @param s Stream to write into after the Common/Private Type Headers and the -+ * ReturnCode. -+ * @param ret The GetAttrib_Return to encode. -+ * @param dwAttrId The attribute ID from the original request. -+ * @param cbAttrCallLen The cbAttrLen from the original request. -+ * @return \b SCARD_S_SUCCESS on success, an error code on failure. -+ */ - WINPR_ATTR_NODISCARD - FREERDP_API LONG smartcard_pack_get_attrib_return(wStream* s, const GetAttrib_Return* ret, - DWORD dwAttrId, DWORD cbAttrCallLen); - -+ /** @brief Unpack a SetAttrib_Call from a stream. -+ * @param s Stream positioned after the Common/Private Type Headers. -+ * @param call [out] The decoded SetAttrib_Call. -+ * @return \b SCARD_S_SUCCESS on success, an error code on failure. -+ */ - WINPR_ATTR_NODISCARD - FREERDP_API LONG smartcard_unpack_set_attrib_call(wStream* s, SetAttrib_Call* call); - -+ /** @brief Unpack a Control_Call from a stream. -+ * @param s Stream positioned after the Common/Private Type Headers. -+ * @param call [out] The decoded Control_Call. -+ * @return \b SCARD_S_SUCCESS on success, an error code on failure. -+ */ - WINPR_ATTR_NODISCARD - FREERDP_API LONG smartcard_unpack_control_call(wStream* s, Control_Call* call); - -+ /** @brief Pack a Control_Return into a stream. -+ * @param s Stream to write into after the Common/Private Type Headers and the ReturnCode. -+ * @param ret The Control_Return to encode. -+ * @return \b SCARD_S_SUCCESS on success, an error code on failure. -+ */ - WINPR_ATTR_NODISCARD - FREERDP_API LONG smartcard_pack_control_return(wStream* s, const Control_Return* ret); - -+ /** @brief Unpack a Transmit_Call from a stream. -+ * @param s Stream positioned after the Common/Private Type Headers. -+ * @param call [out] The decoded Transmit_Call. -+ * @return \b SCARD_S_SUCCESS on success, an error code on failure. -+ */ - WINPR_ATTR_NODISCARD - FREERDP_API LONG smartcard_unpack_transmit_call(wStream* s, Transmit_Call* call); - -+ /** @brief Pack a Transmit_Return into a stream. -+ * @param s Stream to write into after the Common/Private Type Headers and the ReturnCode. -+ * @param ret The Transmit_Return to encode. -+ * @return \b SCARD_S_SUCCESS on success, an error code on failure. -+ */ - WINPR_ATTR_NODISCARD - FREERDP_API LONG smartcard_pack_transmit_return(wStream* s, const Transmit_Return* ret); - -+ /** @brief Unpack a LocateCardsByATRA_Call from a stream. -+ * @param s Stream positioned after the Common/Private Type Headers. -+ * @param call [out] The decoded LocateCardsByATRA_Call. -+ * @return \b SCARD_S_SUCCESS on success, an error code on failure. -+ */ - WINPR_ATTR_NODISCARD - FREERDP_API LONG smartcard_unpack_locate_cards_by_atr_a_call(wStream* s, - LocateCardsByATRA_Call* call); - -+ /** @brief Unpack a LocateCardsByATRW_Call from a stream. -+ * @param s Stream positioned after the Common/Private Type Headers. -+ * @param call [out] The decoded LocateCardsByATRW_Call. -+ * @return \b SCARD_S_SUCCESS on success, an error code on failure. -+ */ - WINPR_ATTR_NODISCARD - FREERDP_API LONG smartcard_unpack_locate_cards_by_atr_w_call(wStream* s, - LocateCardsByATRW_Call* call); - -+ /** @brief Unpack a ReadCacheA_Call from a stream. -+ * @param s Stream positioned after the Common/Private Type Headers. -+ * @param call [out] The decoded ReadCacheA_Call. -+ * @return \b SCARD_S_SUCCESS on success, an error code on failure. -+ */ - WINPR_ATTR_NODISCARD - FREERDP_API LONG smartcard_unpack_read_cache_a_call(wStream* s, ReadCacheA_Call* call); - -+ /** @brief Unpack a ReadCacheW_Call from a stream. -+ * @param s Stream positioned after the Common/Private Type Headers. -+ * @param call [out] The decoded ReadCacheW_Call. -+ * @return \b SCARD_S_SUCCESS on success, an error code on failure. -+ */ - WINPR_ATTR_NODISCARD - FREERDP_API LONG smartcard_unpack_read_cache_w_call(wStream* s, ReadCacheW_Call* call); - -+ /** @brief Pack a ReadCache_Return into a stream. -+ * @param s Stream to write into after the Common/Private Type Headers and the ReturnCode. -+ * @param ret The ReadCache_Return to encode. -+ * @return \b SCARD_S_SUCCESS on success, an error code on failure. -+ */ - WINPR_ATTR_NODISCARD - FREERDP_API LONG smartcard_pack_read_cache_return(wStream* s, const ReadCache_Return* ret); - -+ /** @brief Unpack a WriteCacheA_Call from a stream. -+ * @param s Stream positioned after the Common/Private Type Headers. -+ * @param call [out] The decoded WriteCacheA_Call. -+ * @return \b SCARD_S_SUCCESS on success, an error code on failure. -+ */ - WINPR_ATTR_NODISCARD - FREERDP_API LONG smartcard_unpack_write_cache_a_call(wStream* s, WriteCacheA_Call* call); - -+ /** @brief Unpack a WriteCacheW_Call from a stream. -+ * @param s Stream positioned after the Common/Private Type Headers. -+ * @param call [out] The decoded WriteCacheW_Call. -+ * @return \b SCARD_S_SUCCESS on success, an error code on failure. -+ */ - WINPR_ATTR_NODISCARD - FREERDP_API LONG smartcard_unpack_write_cache_w_call(wStream* s, WriteCacheW_Call* call); - -+ /** @brief Unpack a GetTransmitCount_Call from a stream. -+ * @param s Stream positioned after the Common/Private Type Headers. -+ * @param call [out] The decoded GetTransmitCount_Call. -+ * @return \b SCARD_S_SUCCESS on success, an error code on failure. -+ */ - WINPR_ATTR_NODISCARD - FREERDP_API LONG smartcard_unpack_get_transmit_count_call(wStream* s, - GetTransmitCount_Call* call); -+ -+ /** @brief Pack a GetTransmitCount_Return into a stream. -+ * @param s Stream to write into after the Common/Private Type Headers and the ReturnCode. -+ * @param ret The GetTransmitCount_Return to encode. -+ * @return \b SCARD_S_SUCCESS on success, an error code on failure. -+ */ - WINPR_ATTR_NODISCARD - FREERDP_API LONG smartcard_pack_get_transmit_count_return(wStream* s, -- const GetTransmitCount_Return* call); -+ const GetTransmitCount_Return* ret); - -+ /** @brief Unpack a GetReaderIcon_Call from a stream. -+ * @param s Stream positioned after the Common/Private Type Headers. -+ * @param call [out] The decoded GetReaderIcon_Call. -+ * @return \b SCARD_S_SUCCESS on success, an error code on failure. -+ */ - WINPR_ATTR_NODISCARD - FREERDP_API LONG smartcard_unpack_get_reader_icon_call(wStream* s, GetReaderIcon_Call* call); -+ -+ /** @brief Pack a GetReaderIcon_Return into a stream. -+ * @param s Stream to write into after the Common/Private Type Headers and the ReturnCode. -+ * @param ret The GetReaderIcon_Return to encode. -+ * @return \b SCARD_S_SUCCESS on success, an error code on failure. -+ */ - WINPR_ATTR_NODISCARD - FREERDP_API LONG smartcard_pack_get_reader_icon_return(wStream* s, - const GetReaderIcon_Return* ret); - -+ /** @brief Unpack a GetDeviceTypeId_Call from a stream. -+ * @param s Stream positioned after the Common/Private Type Headers. -+ * @param call [out] The decoded GetDeviceTypeId_Call. -+ * @return \b SCARD_S_SUCCESS on success, an error code on failure. -+ */ - WINPR_ATTR_NODISCARD - FREERDP_API LONG smartcard_unpack_get_device_type_id_call(wStream* s, - GetDeviceTypeId_Call* call); - -+ /** @brief Pack a GetDeviceTypeId_Return into a stream. -+ * @param s Stream to write into after the Common/Private Type Headers and the ReturnCode. -+ * @param ret The GetDeviceTypeId_Return to encode. -+ * @return \b SCARD_S_SUCCESS on success, an error code on failure. -+ */ - WINPR_ATTR_NODISCARD - FREERDP_API LONG smartcard_pack_device_type_id_return(wStream* s, - const GetDeviceTypeId_Return* ret); - -From 4374e3045325e5587ca18e35dca1e6fb14aa7382 Mon Sep 17 00:00:00 2001 -From: Joan Torres Lopez -Date: Fri, 12 Jun 2026 21:29:42 +0200 -Subject: [PATCH 07/31] [utils,smartcard] fix NDR write alignment to use byte - count instead of element count - ---- - libfreerdp/utils/smartcard_pack.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/libfreerdp/utils/smartcard_pack.c b/libfreerdp/utils/smartcard_pack.c -index 83d1fbd4a384..b978e2fb8209 100644 ---- a/libfreerdp/utils/smartcard_pack.c -+++ b/libfreerdp/utils/smartcard_pack.c -@@ -286,7 +286,7 @@ static LONG smartcard_ndr_write(wStream* s, const BYTE* data, UINT32 size, UINT3 - Stream_Write(s, data, dataLen); - else - Stream_Zero(s, dataLen); -- return smartcard_pack_write_size_align(s, len, 4); -+ return smartcard_pack_write_size_align(s, dataLen, 4); - } - - static LONG smartcard_ndr_write_state(wStream* s, const ReaderState_Return* data, UINT32 size, - -From 24ff58507f09ca7d1c5ca806500433254d94b232 Mon Sep 17 00:00:00 2001 -From: Joan Torres Lopez -Date: Wed, 13 May 2026 12:34:46 +0200 -Subject: [PATCH 08/31] [utils,smartcard] add pack and unpack helpers for - MS-RDPESC messages - -Add pack_call and unpack_return functions for smartcard IOCTL messages -defined in the Smart Card Virtual Channel Extension (MS-RDPESC). -These messages are wrapped in device control requests and responses. - -Co-authored-by: David Fort ---- - include/freerdp/utils/smartcard_pack.h | 249 +++++++ - libfreerdp/utils/smartcard_pack.c | 961 ++++++++++++++++++++++++- - 2 files changed, 1206 insertions(+), 4 deletions(-) - -diff --git a/include/freerdp/utils/smartcard_pack.h b/include/freerdp/utils/smartcard_pack.h -index 96cae2387abb..040db784be39 100644 ---- a/include/freerdp/utils/smartcard_pack.h -+++ b/include/freerdp/utils/smartcard_pack.h -@@ -119,6 +119,16 @@ extern "C" - FREERDP_API LONG smartcard_unpack_establish_context_call(wStream* s, - EstablishContext_Call* call); - -+ /** @brief Pack an EstablishContext_Call into a stream. -+ * @param s Stream positioned after the Common/Private Type Headers. -+ * @param call The EstablishContext_Call to encode. -+ * @return \b SCARD_S_SUCCESS on success, an error code on failure. -+ * @since version 3.28.0 -+ */ -+ WINPR_ATTR_NODISCARD -+ FREERDP_API LONG smartcard_pack_establish_context_call(wStream* s, -+ const EstablishContext_Call* call); -+ - /** @brief Pack an EstablishContext_Return into a stream. - * @param s Stream to write into after the Common/Private Type Headers and the ReturnCode. - * @param ret The EstablishContext_Return to encode. -@@ -128,6 +138,16 @@ extern "C" - FREERDP_API LONG smartcard_pack_establish_context_return(wStream* s, - const EstablishContext_Return* ret); - -+ /** @brief Unpack an EstablishContext_Return from a stream. -+ * @param s Stream positioned after the the Common/Private Type Headers and the ReturnCode. -+ * @param ret [out] The decoded EstablishContext_Return. -+ * @return \b SCARD_S_SUCCESS on success, an error code on failure. -+ * @since version 3.28.0 -+ */ -+ WINPR_ATTR_NODISCARD -+ FREERDP_API LONG smartcard_unpack_establish_context_return(wStream* s, -+ EstablishContext_Return* ret); -+ - /** @brief Unpack a Context_Call from a stream. - * @param s Stream positioned after the Common/Private Type Headers. - * @param call [out] The decoded Context_Call. -@@ -155,6 +175,18 @@ extern "C" - ListReaderGroups_Call* call, - BOOL unicode); - -+ /** @brief Pack a ListReaderGroups_Call into a stream. -+ * @param s Stream positioned after the Common/Private Type Headers. -+ * @param call The ListReaderGroups_Call to encode. -+ * @param unicode TRUE for wide-char (W) variant, FALSE for ANSI (A). -+ * @return \b SCARD_S_SUCCESS on success, an error code on failure. -+ * @since version 3.28.0 -+ */ -+ WINPR_ATTR_NODISCARD -+ FREERDP_API LONG smartcard_pack_list_reader_groups_call(wStream* s, -+ const ListReaderGroups_Call* call, -+ BOOL unicode); -+ - /** @brief Pack a ListReaderGroups_Return into a stream. - * @param s Stream positioned after the the Common/Private Type Headers and the - * ReturnCode. -@@ -167,6 +199,18 @@ extern "C" - const ListReaderGroups_Return* ret, - BOOL unicode); - -+ /** @brief Unpack a ListReaderGroups_Return from a stream. -+ * @param s Stream positioned after the Common/Private Type Headers and the ReturnCode. -+ * @param ret [out] The decoded ListReaderGroups_Return. -+ * @param unicode TRUE for the W variant, FALSE for the A variant. -+ * @return \b SCARD_S_SUCCESS on success, an error code on failure. -+ * @since version 3.28.0 -+ */ -+ WINPR_ATTR_NODISCARD -+ FREERDP_API LONG smartcard_unpack_list_reader_groups_return(wStream* s, -+ ListReaderGroups_Return* ret, -+ BOOL unicode); -+ - /** @brief Unpack a ListReaders_Call from a stream. - * @param s Stream positioned after the Common/Private Type Headers. - * @param call [out] The decoded ListReaders_Call. -@@ -281,6 +325,33 @@ extern "C" - WINPR_ATTR_NODISCARD - FREERDP_API LONG smartcard_pack_connect_return(wStream* s, const Connect_Return* ret); - -+ /** @brief Unpack a Connect_Return from a stream. -+ * @param s Stream positioned after the Common/Private Type Headers and the ReturnCode. -+ * @param ret [out] The decoded Connect_Return. -+ * @return \b SCARD_S_SUCCESS on success, an error code on failure. -+ * @since version 3.28.0 -+ */ -+ WINPR_ATTR_NODISCARD -+ FREERDP_API LONG smartcard_unpack_connect_return(wStream* s, Connect_Return* ret); -+ -+ /** @brief Pack a Control_Call into a stream. -+ * @param s Stream to write into after the Common/Private Type Headers and the ReturnCode. -+ * @param call The Control_Call to encode. -+ * @return \b SCARD_S_SUCCESS on success, an error code on failure. -+ * @since version 3.28.0 -+ */ -+ WINPR_ATTR_NODISCARD -+ FREERDP_API LONG smartcard_pack_control_call(wStream* s, const Control_Call* call); -+ -+ /** @brief Unpack a Control_return from a stream. -+ * @param s Stream positioned after the Common/Private Type Headers. -+ * @param ret [out] the decoded Control_Return. -+ * @return \b SCARD_S_SUCCESS on success, an error code on failure. -+ * @since version 3.28.0 -+ */ -+ WINPR_ATTR_NODISCARD -+ FREERDP_API LONG smartcard_unpack_control_return(wStream* s, Control_Return* ret); -+ - /** @brief Unpack a Reconnect_Call from a stream. - * @param s Stream positioned after the Common/Private Type Headers. - * @param call [out] The decoded Reconnect_Call. -@@ -289,6 +360,15 @@ extern "C" - WINPR_ATTR_NODISCARD - FREERDP_API LONG smartcard_unpack_reconnect_call(wStream* s, Reconnect_Call* call); - -+ /** @brief Pack a Reconnect_Call into a stream. -+ * @param s Stream positioned after the Common/Private Type Headers. -+ * @param call The Reconnect_Call to encode. -+ * @return \b SCARD_S_SUCCESS on success, an error code on failure. -+ * @since version 3.28.0 -+ */ -+ WINPR_ATTR_NODISCARD -+ FREERDP_API LONG smartcard_pack_reconnect_call(wStream* s, const Reconnect_Call* call); -+ - /** @brief Pack a Reconnect_Return into a stream. - * @param s Stream to write into after the Common/Private Type Headers and the ReturnCode. - * @param ret The Reconnect_Return to encode. -@@ -297,6 +377,15 @@ extern "C" - WINPR_ATTR_NODISCARD - FREERDP_API LONG smartcard_pack_reconnect_return(wStream* s, const Reconnect_Return* ret); - -+ /** @brief Unpack a Reconnect_Return from a stream. -+ * @param s Stream positioned after the Common/Private Type Headers and the ReturnCode. -+ * @param ret [out] The decoded Reconnect_Return. -+ * @return \b SCARD_S_SUCCESS on success, an error code on failure. -+ * @since version 3.28.0 -+ */ -+ WINPR_ATTR_NODISCARD -+ FREERDP_API LONG smartcard_unpack_reconnect_return(wStream* s, Reconnect_Return* ret); -+ - /** @brief Unpack a HCardAndDisposition_Call from a stream. - * @param s Stream positioned after the Common/Private Type Headers. - * @param call [out] The decoded HCardAndDisposition_Call. -@@ -363,6 +452,16 @@ extern "C" - WINPR_ATTR_NODISCARD - FREERDP_API LONG smartcard_unpack_status_call(wStream* s, Status_Call* call, BOOL unicode); - -+ /** @brief Pack a Status_Call into a stream. -+ * @param s Stream positioned after the Common/Private Type Headers. -+ * @param call The Status_Call to encode. -+ * @param unicode TRUE for wide-char (W) variant, FALSE for ANSI (A). -+ * @return \b SCARD_S_SUCCESS on success, an error code on failure. -+ * @since version 3.28.0 -+ */ -+ WINPR_ATTR_NODISCARD -+ FREERDP_API LONG smartcard_pack_status_call(wStream* s, const Status_Call* call, BOOL unicode); -+ - /** @brief Pack a Status_Return into a stream. - * @param s Stream to write into after the Common/Private Type Headers and the - * ReturnCode. -@@ -374,6 +473,16 @@ extern "C" - FREERDP_API LONG smartcard_pack_status_return(wStream* s, const Status_Return* ret, - BOOL unicode); - -+ /** @brief Unpack a Status_Return from a stream. -+ * @param s Stream positioned after the Common/Private Type Headers and the ReturnCode. -+ * @param ret [out] The decoded Status_Return. -+ * @param unicode TRUE for the W variant, FALSE for the A variant. -+ * @return \b SCARD_S_SUCCESS on success, an error code on failure. -+ * @since version 3.28.0 -+ */ -+ WINPR_ATTR_NODISCARD -+ FREERDP_API LONG smartcard_unpack_status_return(wStream* s, Status_Return* ret, BOOL unicode); -+ - /** @brief Unpack a GetAttrib_Call from a stream. - * @param s Stream positioned after the Common/Private Type Headers. - * @param call [out] The decoded GetAttrib_Call. -@@ -382,6 +491,15 @@ extern "C" - WINPR_ATTR_NODISCARD - FREERDP_API LONG smartcard_unpack_get_attrib_call(wStream* s, GetAttrib_Call* call); - -+ /** @brief Pack a GetAttrib_Call to a stream. -+ * @param s wStream to write to. -+ * @param call The GetAttrib_Call to encode. -+ * @return \b SCARD_S_SUCCESS on success, an error code on failure. -+ * @since version 3.28.0 -+ */ -+ WINPR_ATTR_NODISCARD -+ FREERDP_API LONG smartcard_pack_get_attrib_call(wStream* s, const GetAttrib_Call* call); -+ - /** @brief Pack a GetAttrib_Return into a stream. - * @param s Stream to write into after the Common/Private Type Headers and the - * ReturnCode. -@@ -394,6 +512,15 @@ extern "C" - FREERDP_API LONG smartcard_pack_get_attrib_return(wStream* s, const GetAttrib_Return* ret, - DWORD dwAttrId, DWORD cbAttrCallLen); - -+ /** @brief Unpack a GetAttrib_Return from a stream. -+ * @param s Stream positioned after the Common/Private Type Headers and the ReturnCode. -+ * @param ret [out] The decoded GetAttrib_Return. -+ * @return \b SCARD_S_SUCCESS on success, an error code on failure. -+ * @since version 3.28.0 -+ */ -+ WINPR_ATTR_NODISCARD -+ FREERDP_API LONG smartcard_unpack_get_attrib_return(wStream* s, GetAttrib_Return* ret); -+ - /** @brief Unpack a SetAttrib_Call from a stream. - * @param s Stream positioned after the Common/Private Type Headers. - * @param call [out] The decoded SetAttrib_Call. -@@ -402,6 +529,15 @@ extern "C" - WINPR_ATTR_NODISCARD - FREERDP_API LONG smartcard_unpack_set_attrib_call(wStream* s, SetAttrib_Call* call); - -+ /** @brief Pack a SetAttrib_Call into a stream. -+ * @param s Stream positioned after the Common/Private Type Headers. -+ * @param call The SetAttrib_Call to encode. -+ * @return \b SCARD_S_SUCCESS on success, an error code on failure. -+ * @since version 3.28.0 -+ */ -+ WINPR_ATTR_NODISCARD -+ FREERDP_API LONG smartcard_pack_set_attrib_call(wStream* s, const SetAttrib_Call* call); -+ - /** @brief Unpack a Control_Call from a stream. - * @param s Stream positioned after the Common/Private Type Headers. - * @param call [out] The decoded Control_Call. -@@ -434,6 +570,15 @@ extern "C" - WINPR_ATTR_NODISCARD - FREERDP_API LONG smartcard_pack_transmit_return(wStream* s, const Transmit_Return* ret); - -+ /** @brief Unpack a Transmit_Return from a stream. -+ * @param s Stream positioned after the Common/Private Type Headers and the ReturnCode. -+ * @param ret [out] The decoded Transmit_Return. -+ * @return \b SCARD_S_SUCCESS on success, an error code on failure. -+ * @since version 3.28.0 -+ */ -+ WINPR_ATTR_NODISCARD -+ FREERDP_API LONG smartcard_unpack_transmit_return(wStream* s, Transmit_Return* ret); -+ - /** @brief Unpack a LocateCardsByATRA_Call from a stream. - * @param s Stream positioned after the Common/Private Type Headers. - * @param call [out] The decoded LocateCardsByATRA_Call. -@@ -545,6 +690,110 @@ extern "C" - FREERDP_API LONG smartcard_pack_device_type_id_return(wStream* s, - const GetDeviceTypeId_Return* ret); - -+ /** @brief Pack a Context_Call into a stream. -+ * @param s Stream positioned after the Common/Private Type Headers. -+ * @param call The Context_Call to encode. -+ * @param name Operation name used for trace logging. -+ * @return \b SCARD_S_SUCCESS on success, an error code on failure. -+ * @since version 3.28.0 -+ */ -+ WINPR_ATTR_NODISCARD -+ FREERDP_API LONG smartcard_pack_context_call(wStream* s, const Context_Call* call, -+ const char* name); -+ -+ /** @brief Pack a ListReaders_Call into a stream. -+ * @param s Stream positioned after the Common/Private Type Headers. -+ * @param call The ListReaders_Call to encode. -+ * @param unicode TRUE for wide-char (W) variant, FALSE for ANSI (A). -+ * @return \b SCARD_S_SUCCESS on success, an error code on failure. -+ * @since version 3.28.0 -+ */ -+ WINPR_ATTR_NODISCARD -+ FREERDP_API LONG smartcard_pack_list_readers_call(wStream* s, const ListReaders_Call* call, -+ BOOL unicode); -+ -+ /** @brief Pack a GetStatusChangeA_Call into a stream. -+ * @param s Stream positioned after the Common/Private Type Headers. -+ * @param call The GetStatusChangeA_Call to encode. -+ * @return \b SCARD_S_SUCCESS on success, an error code on failure. -+ * @since version 3.28.0 -+ */ -+ WINPR_ATTR_NODISCARD -+ FREERDP_API LONG smartcard_pack_get_status_change_a_call(wStream* s, -+ const GetStatusChangeA_Call* call); -+ -+ /** @brief Pack a GetStatusChangeW_Call into a stream. -+ * @param s Stream positioned after the Common/Private Type Headers. -+ * @param call The GetStatusChangeW_Call to encode. -+ * @return \b SCARD_S_SUCCESS on success, an error code on failure. -+ * @since version 3.28.0 -+ */ -+ WINPR_ATTR_NODISCARD -+ FREERDP_API LONG smartcard_pack_get_status_change_w_call(wStream* s, -+ const GetStatusChangeW_Call* call); -+ -+ /** @brief Pack a ConnectA_Call into a stream. -+ * @param s Stream positioned after the Common/Private Type Headers. -+ * @param call The ConnectA_Call to encode. -+ * @return \b SCARD_S_SUCCESS on success, an error code on failure. -+ * @since version 3.28.0 -+ */ -+ WINPR_ATTR_NODISCARD -+ FREERDP_API LONG smartcard_pack_connect_a_call(wStream* s, const ConnectA_Call* call); -+ -+ /** @brief Pack a ConnectW_Call into a stream. -+ * @param s Stream positioned after the Common/Private Type Headers. -+ * @param call The ConnectW_Call to encode. -+ * @return \b SCARD_S_SUCCESS on success, an error code on failure. -+ * @since version 3.28.0 -+ */ -+ WINPR_ATTR_NODISCARD -+ FREERDP_API LONG smartcard_pack_connect_w_call(wStream* s, const ConnectW_Call* call); -+ -+ /** @brief Pack a HCardAndDisposition_Call into a stream. -+ * @param s Stream positioned after the Common/Private Type Headers. -+ * @param call The HCardAndDisposition_Call to encode. -+ * @param name Operation name used for trace logging. -+ * @return \b SCARD_S_SUCCESS on success, an error code on failure. -+ * @since version 3.28.0 -+ */ -+ WINPR_ATTR_NODISCARD -+ FREERDP_API LONG smartcard_pack_hcard_and_disposition_call(wStream* s, -+ const HCardAndDisposition_Call* call, -+ const char* name); -+ -+ /** @brief Pack a Transmit_Call into a stream. -+ * @param s Stream positioned after the Common/Private Type Headers. -+ * @param call The Transmit_Call to encode. -+ * @return \b SCARD_S_SUCCESS on success, an error code on failure. -+ * @since version 3.28.0 -+ */ -+ WINPR_ATTR_NODISCARD -+ FREERDP_API LONG smartcard_pack_transmit_call(wStream* s, const Transmit_Call* call); -+ -+ /** @brief Unpack a ListReaders_Return from a stream. -+ * @param s Stream positioned after the Common/Private Type Headers and the ReturnCode. -+ * @param ret [out] The decoded ListReaders_Return. -+ * @param unicode TRUE for the W variant, FALSE for the A variant. -+ * @return \b SCARD_S_SUCCESS on success, an error code on failure. -+ * @since version 3.28.0 -+ */ -+ WINPR_ATTR_NODISCARD -+ FREERDP_API LONG smartcard_unpack_list_readers_return(wStream* s, ListReaders_Return* ret, -+ BOOL unicode); -+ -+ /** @brief Unpack a GetStatusChange_Return from a stream. -+ * @param s Stream positioned after the Common/Private Type Headers and the ReturnCode. -+ * @param ret [out] The decoded GetStatusChange_Return. -+ * @param unicode TRUE for the W variant, FALSE for the A variant. -+ * @return \b SCARD_S_SUCCESS on success, an error code on failure. -+ * @since version 3.28.0 -+ */ -+ WINPR_ATTR_NODISCARD -+ FREERDP_API LONG smartcard_unpack_get_status_change_return(wStream* s, -+ GetStatusChange_Return* ret, -+ BOOL unicode); -+ - #ifdef __cplusplus - } - #endif -diff --git a/libfreerdp/utils/smartcard_pack.c b/libfreerdp/utils/smartcard_pack.c -index b978e2fb8209..5aa54590f4fc 100644 ---- a/libfreerdp/utils/smartcard_pack.c -+++ b/libfreerdp/utils/smartcard_pack.c -@@ -303,6 +303,18 @@ 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_state(wLog* log, wStream* s, ReaderState_Return** data, size_t min, -+ ndr_ptr_t type) -+{ -+ union -+ { -+ ReaderState_Return** ppc; -+ BYTE** ppv; -+ } u; -+ u.ppc = data; -+ return smartcard_ndr_read(log, s, u.ppv, min, sizeof(ReaderState_Return), type); -+} -+ - static LONG smartcard_ndr_read_atrmask(wLog* log, wStream* s, LocateCards_ATRMask** data, - size_t min, ndr_ptr_t type) - { -@@ -382,6 +394,28 @@ static LONG smartcard_ndr_read_w(wLog* log, wStream* s, WCHAR** data, ndr_ptr_t - return smartcard_ndr_read(log, s, u.ppv, 0, sizeof(WCHAR), type); - } - -+static LONG smartcard_ndr_write_w(wStream* s, const WCHAR* data, UINT32 size, ndr_ptr_t type) -+{ -+ union -+ { -+ const WCHAR* wz; -+ const BYTE* bp; -+ } cnv; -+ cnv.wz = data; -+ return smartcard_ndr_write(s, cnv.bp, size, sizeof(WCHAR), type); -+} -+ -+static LONG smartcard_ndr_write_a(wStream* s, const CHAR* data, UINT32 size, ndr_ptr_t type) -+{ -+ union -+ { -+ const CHAR* sz; -+ const BYTE* bp; -+ } cnv; -+ cnv.sz = data; -+ return smartcard_ndr_write(s, cnv.bp, size, sizeof(CHAR), type); -+} -+ - static LONG smartcard_ndr_read_u(wLog* log, wStream* s, UUID** data) - { - union -@@ -546,7 +580,7 @@ static void smartcard_dump_array(wLog* log, DWORD level, WINPR_FORMAT_ARG const - va_start(ap, len); - winpr_vasprintf(&fprefix, &flen, prefix, ap); - va_end(ap); -- WLog_Print(log, level, "%s%s%s", prefix, buffer, postfix); -+ WLog_Print(log, level, "%s%s%s", fprefix, buffer, postfix); - free(buffer); - free(fprefix); - } -@@ -554,7 +588,7 @@ static void smartcard_dump_array(wLog* log, DWORD level, WINPR_FORMAT_ARG const - static void smartcard_log_redir_handle(wLog* log, const REDIR_SCARDHANDLE* pHandle) - { - WINPR_ASSERT(pHandle); -- smartcard_dump_array(log, g_LogLevel, " hContext: ", "", pHandle->pbHandle, pHandle->cbHandle); -+ smartcard_dump_array(log, g_LogLevel, "handle: ", "", pHandle->pbHandle, pHandle->cbHandle); - } - - static void smartcard_log_context(wLog* log, const REDIR_SCARDCONTEXT* phContext) -@@ -2041,6 +2075,21 @@ LONG smartcard_unpack_establish_context_call(wStream* s, EstablishContext_Call* - return SCARD_S_SUCCESS; - } - -+LONG smartcard_pack_establish_context_call(wStream* s, const EstablishContext_Call* call) -+{ -+ WINPR_ASSERT(call); -+ wLog* log = scard_log(); -+ -+ smartcard_trace_establish_context_call(log, call); -+ -+ if (!Stream_EnsureRemainingCapacity(s, 4)) -+ return SCARD_E_NO_MEMORY; -+ -+ Stream_Write_UINT32(s, call->dwScope); -+ -+ return SCARD_S_SUCCESS; -+} -+ - LONG smartcard_pack_establish_context_return(wStream* s, const EstablishContext_Return* ret) - { - WINPR_ASSERT(ret); -@@ -2059,6 +2108,26 @@ LONG smartcard_pack_establish_context_return(wStream* s, const EstablishContext_ - return smartcard_pack_redir_scard_context_ref(log, s, &(ret->hContext)); - } - -+LONG smartcard_unpack_establish_context_return(wStream* s, EstablishContext_Return* ret) -+{ -+ WINPR_ASSERT(ret); -+ wLog* log = scard_log(); -+ UINT32 index = 0; -+ UINT32 pbContextNdrPtr = 0; -+ -+ LONG status = -+ smartcard_unpack_redir_scard_context(log, s, &(ret->hContext), &index, &pbContextNdrPtr); -+ if (status != SCARD_S_SUCCESS) -+ return status; -+ -+ status = smartcard_unpack_redir_scard_context_ref(log, s, pbContextNdrPtr, &(ret->hContext)); -+ if (status != SCARD_S_SUCCESS) -+ return status; -+ -+ smartcard_trace_establish_context_return(log, ret); -+ return SCARD_S_SUCCESS; -+} -+ - LONG smartcard_unpack_context_call(wStream* s, Context_Call* call, const char* name) - { - UINT32 index = 0; -@@ -2110,6 +2179,28 @@ LONG smartcard_unpack_list_reader_groups_call(wStream* s, ListReaderGroups_Call* - return SCARD_S_SUCCESS; - } - -+LONG smartcard_pack_list_reader_groups_call(wStream* s, const ListReaderGroups_Call* call, -+ BOOL unicode) -+{ -+ WINPR_ASSERT(call); -+ wLog* log = scard_log(); -+ DWORD index = 0; -+ -+ smartcard_trace_list_reader_groups_call(log, call, unicode); -+ -+ LONG status = smartcard_pack_redir_scard_context(log, s, &call->handles.hContext, &index); -+ if (status != SCARD_S_SUCCESS) -+ return status; -+ -+ if (!Stream_EnsureRemainingCapacity(s, 8)) -+ return SCARD_E_NO_MEMORY; -+ -+ Stream_Write_INT32(s, call->fmszGroupsIsNULL); -+ Stream_Write_UINT32(s, call->cchGroups); -+ -+ return smartcard_pack_redir_scard_context_ref(log, s, &call->handles.hContext); -+} -+ - LONG smartcard_pack_list_reader_groups_return(wStream* s, const ListReaderGroups_Return* ret, - BOOL unicode) - { -@@ -2138,6 +2229,33 @@ LONG smartcard_pack_list_reader_groups_return(wStream* s, const ListReaderGroups - return ret->ReturnCode; - } - -+LONG smartcard_unpack_list_reader_groups_return(wStream* s, ListReaderGroups_Return* ret, -+ BOOL unicode) -+{ -+ WINPR_ASSERT(ret); -+ wLog* log = scard_log(); -+ UINT32 index = 0; -+ UINT32 mszNdrPtr = 0; -+ -+ if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4)) -+ return STATUS_BUFFER_TOO_SMALL; -+ -+ Stream_Read_UINT32(s, ret->cBytes); -+ -+ if (!smartcard_ndr_pointer_read(log, s, &index, &mszNdrPtr)) -+ return ERROR_INVALID_DATA; -+ -+ if (mszNdrPtr) -+ { -+ LONG status = smartcard_ndr_read(log, s, &ret->msz, ret->cBytes, 1, NDR_PTR_SIMPLE); -+ if (status != SCARD_S_SUCCESS) -+ return status; -+ } -+ -+ smartcard_trace_list_reader_groups_return(log, ret, unicode); -+ return SCARD_S_SUCCESS; -+} -+ - LONG smartcard_unpack_list_readers_call(wStream* s, ListReaders_Call* call, BOOL unicode) - { - UINT32 index = 0; -@@ -2368,6 +2486,36 @@ LONG smartcard_unpack_reconnect_call(wStream* s, Reconnect_Call* call) - return status; - } - -+LONG smartcard_pack_reconnect_call(wStream* s, const Reconnect_Call* call) -+{ -+ WINPR_ASSERT(call); -+ wLog* log = scard_log(); -+ DWORD index = 0; -+ -+ smartcard_trace_reconnect_call(log, call); -+ -+ LONG status = smartcard_pack_redir_scard_context(log, s, &call->handles.hContext, &index); -+ if (status != SCARD_S_SUCCESS) -+ return status; -+ -+ status = smartcard_pack_redir_scard_handle(log, s, &call->handles.hCard, &index); -+ if (status != SCARD_S_SUCCESS) -+ return status; -+ -+ if (!Stream_EnsureRemainingCapacity(s, 12)) -+ return SCARD_E_NO_MEMORY; -+ -+ Stream_Write_UINT32(s, call->dwShareMode); -+ Stream_Write_UINT32(s, call->dwPreferredProtocols); -+ Stream_Write_UINT32(s, call->dwInitialization); -+ -+ status = smartcard_pack_redir_scard_context_ref(log, s, &call->handles.hContext); -+ if (status != SCARD_S_SUCCESS) -+ return status; -+ -+ return smartcard_pack_redir_scard_handle_ref(log, s, &call->handles.hCard); -+} -+ - LONG smartcard_pack_reconnect_return(wStream* s, const Reconnect_Return* ret) - { - WINPR_ASSERT(ret); -@@ -2380,6 +2528,20 @@ LONG smartcard_pack_reconnect_return(wStream* s, const Reconnect_Return* ret) - return ret->ReturnCode; - } - -+LONG smartcard_unpack_reconnect_return(wStream* s, Reconnect_Return* ret) -+{ -+ WINPR_ASSERT(ret); -+ wLog* log = scard_log(); -+ -+ if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4)) -+ return STATUS_BUFFER_TOO_SMALL; -+ -+ Stream_Read_UINT32(s, ret->dwActiveProtocol); -+ -+ smartcard_trace_reconnect_return(log, ret); -+ return SCARD_S_SUCCESS; -+} -+ - LONG smartcard_unpack_hcard_and_disposition_call(wStream* s, HCardAndDisposition_Call* call, - const char* name) - { -@@ -2816,6 +2978,36 @@ LONG smartcard_unpack_status_call(wStream* s, Status_Call* call, BOOL unicode) - return status; - } - -+LONG smartcard_pack_status_call(wStream* s, const Status_Call* call, BOOL unicode) -+{ -+ WINPR_ASSERT(call); -+ wLog* log = scard_log(); -+ DWORD index = 0; -+ -+ smartcard_trace_status_call(log, call, unicode); -+ -+ LONG status = smartcard_pack_redir_scard_context(log, s, &call->handles.hContext, &index); -+ if (status != SCARD_S_SUCCESS) -+ return status; -+ -+ status = smartcard_pack_redir_scard_handle(log, s, &call->handles.hCard, &index); -+ if (status != SCARD_S_SUCCESS) -+ return status; -+ -+ if (!Stream_EnsureRemainingCapacity(s, 12)) -+ return SCARD_E_NO_MEMORY; -+ -+ Stream_Write_INT32(s, call->fmszReaderNamesIsNULL); -+ Stream_Write_UINT32(s, call->cchReaderLen); -+ Stream_Write_UINT32(s, call->cbAtrLen); -+ -+ status = smartcard_pack_redir_scard_context_ref(log, s, &call->handles.hContext); -+ if (status != SCARD_S_SUCCESS) -+ return status; -+ -+ return smartcard_pack_redir_scard_handle_ref(log, s, &call->handles.hCard); -+} -+ - LONG smartcard_pack_status_return(wStream* s, const Status_Return* ret, BOOL unicode) - { - WINPR_ASSERT(ret); -@@ -2851,6 +3043,41 @@ LONG smartcard_pack_status_return(wStream* s, const Status_Return* ret, BOOL uni - return ret->ReturnCode; - } - -+LONG smartcard_unpack_status_return(wStream* s, Status_Return* ret, BOOL unicode) -+{ -+ WINPR_ASSERT(ret); -+ wLog* log = scard_log(); -+ UINT32 index = 0; -+ UINT32 mszNdrPtr = 0; -+ -+ if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4)) -+ return STATUS_BUFFER_TOO_SMALL; -+ -+ Stream_Read_UINT32(s, ret->cBytes); -+ -+ if (!smartcard_ndr_pointer_read(log, s, &index, &mszNdrPtr)) -+ return ERROR_INVALID_DATA; -+ -+ if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 44)) -+ return STATUS_BUFFER_TOO_SMALL; -+ -+ Stream_Read_UINT32(s, ret->dwState); -+ Stream_Read_UINT32(s, ret->dwProtocol); -+ Stream_Read(s, ret->pbAtr, sizeof(ret->pbAtr)); -+ Stream_Read_UINT32(s, ret->cbAtrLen); -+ -+ if (mszNdrPtr) -+ { -+ LONG status = -+ smartcard_ndr_read(log, s, &ret->mszReaderNames, ret->cBytes, 1, NDR_PTR_SIMPLE); -+ if (status != SCARD_S_SUCCESS) -+ return status; -+ } -+ -+ smartcard_trace_status_return(log, ret, unicode); -+ return SCARD_S_SUCCESS; -+} -+ - LONG smartcard_unpack_get_attrib_call(wStream* s, GetAttrib_Call* call) - { - WINPR_ASSERT(call); -@@ -2944,8 +3171,8 @@ LONG smartcard_unpack_control_call(wStream* s, Control_Call* call) - 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) */ -+ Stream_Read_UINT32(s, call->dwControlCode); /* dwControlCode (4 bytes) */ -+ Stream_Read_UINT32(s, call->cbInBufferSize); /* cbInBufferSize (4 bytes) */ - if (!smartcard_ndr_pointer_read(log, s, &index, - &pvInBufferNdrPtr)) /* pvInBufferNdrPtr (4 bytes) */ - return ERROR_INVALID_DATA; -@@ -3557,6 +3784,46 @@ LONG smartcard_unpack_set_attrib_call(wStream* s, SetAttrib_Call* call) - return SCARD_S_SUCCESS; - } - -+LONG smartcard_pack_set_attrib_call(wStream* s, const SetAttrib_Call* call) -+{ -+ WINPR_ASSERT(call); -+ wLog* log = scard_log(); -+ DWORD index = 0; -+ -+ smartcard_trace_set_attrib_call(log, call); -+ -+ LONG status = smartcard_pack_redir_scard_context(log, s, &call->handles.hContext, &index); -+ if (status != SCARD_S_SUCCESS) -+ return status; -+ -+ status = smartcard_pack_redir_scard_handle(log, s, &call->handles.hCard, &index); -+ if (status != SCARD_S_SUCCESS) -+ return status; -+ -+ if (!Stream_EnsureRemainingCapacity(s, 8)) -+ return SCARD_E_NO_MEMORY; -+ -+ Stream_Write_UINT32(s, call->dwAttrId); -+ Stream_Write_UINT32(s, call->cbAttrLen); -+ -+ if (!smartcard_ndr_pointer_write(s, &index, call->cbAttrLen)) -+ return SCARD_E_NO_MEMORY; -+ -+ status = smartcard_pack_redir_scard_context_ref(log, s, &call->handles.hContext); -+ if (status != SCARD_S_SUCCESS) -+ return status; -+ -+ status = smartcard_pack_redir_scard_handle_ref(log, s, &call->handles.hCard); -+ if (status != SCARD_S_SUCCESS) -+ return status; -+ -+ status = smartcard_ndr_write(s, call->pbAttr, call->cbAttrLen, 1, NDR_PTR_SIMPLE); -+ if (status != SCARD_S_SUCCESS) -+ return status; -+ -+ return SCARD_S_SUCCESS; -+} -+ - LONG smartcard_unpack_locate_cards_by_atr_w_call(wStream* s, LocateCardsByATRW_Call* call) - { - UINT32 rgReaderStatesNdrPtr = 0; -@@ -4037,3 +4304,689 @@ LONG smartcard_pack_read_cache_return(wStream* s, const ReadCache_Return* ret) - return status; - return ret->ReturnCode; - } -+ -+LONG smartcard_pack_context_call(wStream* s, const Context_Call* call, const char* name) -+{ -+ WINPR_ASSERT(call); -+ wLog* log = scard_log(); -+ DWORD index = 0; -+ -+ smartcard_trace_context_call(log, call, name); -+ -+ LONG status = smartcard_pack_redir_scard_context(log, s, &call->handles.hContext, &index); -+ if (status != SCARD_S_SUCCESS) -+ return status; -+ -+ return smartcard_pack_redir_scard_context_ref(log, s, &call->handles.hContext); -+} -+ -+LONG smartcard_pack_list_readers_call(wStream* s, const ListReaders_Call* call, BOOL unicode) -+{ -+ WINPR_ASSERT(call); -+ wLog* log = scard_log(); -+ DWORD index = 0; -+ -+ smartcard_trace_list_readers_call(log, call, unicode); -+ -+ LONG status = smartcard_pack_redir_scard_context(log, s, &call->handles.hContext, &index); -+ if (status != SCARD_S_SUCCESS) -+ return status; -+ -+ if (!Stream_EnsureRemainingCapacity(s, 4)) -+ return SCARD_E_NO_MEMORY; -+ -+ Stream_Write_UINT32(s, call->cBytes); -+ if (!smartcard_ndr_pointer_write(s, &index, call->cBytes)) -+ return SCARD_E_NO_MEMORY; -+ -+ if (!Stream_EnsureRemainingCapacity(s, 8)) -+ return SCARD_E_NO_MEMORY; -+ -+ Stream_Write_INT32(s, call->fmszReadersIsNULL); -+ Stream_Write_UINT32(s, call->cchReaders); -+ -+ status = smartcard_pack_redir_scard_context_ref(log, s, &call->handles.hContext); -+ if (status != SCARD_S_SUCCESS) -+ return status; -+ -+ if (call->cBytes > 0) -+ { -+ status = smartcard_ndr_write(s, call->mszGroups, call->cBytes, 1, NDR_PTR_SIMPLE); -+ if (status != SCARD_S_SUCCESS) -+ return status; -+ } -+ -+ return SCARD_S_SUCCESS; -+} -+ -+static LONG smartcard_pack_reader_state_a(wStream* s, const LPSCARD_READERSTATEA rgReaderStates, -+ UINT32 cReaders, UINT32* ptrIndex) -+{ -+ WINPR_ASSERT(rgReaderStates || (cReaders == 0)); -+ -+ if (!Stream_EnsureRemainingCapacity(s, 4)) -+ return SCARD_E_NO_MEMORY; -+ -+ Stream_Write_UINT32(s, cReaders); -+ -+ for (UINT32 i = 0; i < cReaders; i++) -+ { -+ const SCARD_READERSTATEA* state = &rgReaderStates[i]; -+ -+ if (!Stream_EnsureRemainingCapacity(s, 52)) -+ return SCARD_E_NO_MEMORY; -+ -+ const DWORD nameLen = state->szReader ? (DWORD)(strlen(state->szReader) + 1) : 0; -+ if (!smartcard_ndr_pointer_write(s, ptrIndex, nameLen)) -+ return SCARD_E_NO_MEMORY; -+ -+ Stream_Write_UINT32(s, state->dwCurrentState); -+ Stream_Write_UINT32(s, state->dwEventState); -+ Stream_Write_UINT32(s, state->cbAtr); -+ Stream_Write(s, state->rgbAtr, 36); -+ } -+ -+ for (UINT32 i = 0; i < cReaders; i++) -+ { -+ const SCARD_READERSTATEA* state = &rgReaderStates[i]; -+ -+ if (state->szReader) -+ { -+ const UINT32 nameLen = (UINT32)(strlen(state->szReader) + 1); -+ LONG status = smartcard_ndr_write_a(s, state->szReader, nameLen, NDR_PTR_FULL); -+ if (status != SCARD_S_SUCCESS) -+ return status; -+ } -+ } -+ -+ return SCARD_S_SUCCESS; -+} -+ -+static LONG smartcard_pack_reader_state_w(wStream* s, const LPSCARD_READERSTATEW rgReaderStates, -+ UINT32 cReaders, UINT32* ptrIndex) -+{ -+ WINPR_ASSERT(rgReaderStates || (cReaders == 0)); -+ -+ if (!Stream_EnsureRemainingCapacity(s, 4)) -+ return SCARD_E_NO_MEMORY; -+ -+ Stream_Write_UINT32(s, cReaders); -+ -+ for (UINT32 i = 0; i < cReaders; i++) -+ { -+ const SCARD_READERSTATEW* state = &rgReaderStates[i]; -+ -+ if (!Stream_EnsureRemainingCapacity(s, 52)) -+ return SCARD_E_NO_MEMORY; -+ -+ const DWORD nameLen = state->szReader ? (DWORD)(_wcslen(state->szReader) + 1) : 0; -+ if (!smartcard_ndr_pointer_write(s, ptrIndex, nameLen)) -+ return SCARD_E_NO_MEMORY; -+ -+ Stream_Write_UINT32(s, state->dwCurrentState); -+ Stream_Write_UINT32(s, state->dwEventState); -+ Stream_Write_UINT32(s, state->cbAtr); -+ Stream_Write(s, state->rgbAtr, 36); -+ } -+ -+ for (UINT32 i = 0; i < cReaders; i++) -+ { -+ const SCARD_READERSTATEW* state = &rgReaderStates[i]; -+ -+ if (state->szReader) -+ { -+ const UINT32 nameLen = (UINT32)(_wcslen(state->szReader) + 1); -+ LONG status = smartcard_ndr_write_w(s, state->szReader, nameLen, NDR_PTR_FULL); -+ if (status != SCARD_S_SUCCESS) -+ return status; -+ } -+ } -+ -+ return SCARD_S_SUCCESS; -+} -+ -+LONG smartcard_pack_get_status_change_a_call(wStream* s, const GetStatusChangeA_Call* call) -+{ -+ WINPR_ASSERT(call); -+ wLog* log = scard_log(); -+ DWORD index = 0; -+ -+ smartcard_trace_get_status_change_a_call(log, call); -+ -+ LONG status = smartcard_pack_redir_scard_context(log, s, &call->handles.hContext, &index); -+ if (status != SCARD_S_SUCCESS) -+ return status; -+ -+ if (!Stream_EnsureRemainingCapacity(s, 8)) -+ return SCARD_E_NO_MEMORY; -+ -+ Stream_Write_UINT32(s, call->dwTimeOut); -+ Stream_Write_UINT32(s, call->cReaders); -+ -+ if (!smartcard_ndr_pointer_write(s, &index, call->cReaders)) -+ return SCARD_E_NO_MEMORY; -+ -+ status = smartcard_pack_redir_scard_context_ref(log, s, &call->handles.hContext); -+ if (status != SCARD_S_SUCCESS) -+ return status; -+ -+ if (call->cReaders > 0) -+ { -+ status = smartcard_pack_reader_state_a(s, call->rgReaderStates, call->cReaders, &index); -+ if (status != SCARD_S_SUCCESS) -+ return status; -+ } -+ -+ return SCARD_S_SUCCESS; -+} -+ -+LONG smartcard_pack_get_status_change_w_call(wStream* s, const GetStatusChangeW_Call* call) -+{ -+ WINPR_ASSERT(call); -+ wLog* log = scard_log(); -+ DWORD index = 0; -+ -+ smartcard_trace_get_status_change_w_call(log, call); -+ -+ LONG status = smartcard_pack_redir_scard_context(log, s, &call->handles.hContext, &index); -+ if (status != SCARD_S_SUCCESS) -+ return status; -+ -+ if (!Stream_EnsureRemainingCapacity(s, 8)) -+ return SCARD_E_NO_MEMORY; -+ -+ Stream_Write_UINT32(s, call->dwTimeOut); -+ Stream_Write_UINT32(s, call->cReaders); -+ -+ if (!smartcard_ndr_pointer_write(s, &index, call->cReaders)) -+ return SCARD_E_NO_MEMORY; -+ -+ status = smartcard_pack_redir_scard_context_ref(log, s, &call->handles.hContext); -+ if (status != SCARD_S_SUCCESS) -+ return status; -+ -+ if (call->cReaders > 0) -+ { -+ status = smartcard_pack_reader_state_w(s, call->rgReaderStates, call->cReaders, &index); -+ if (status != SCARD_S_SUCCESS) -+ return status; -+ } -+ -+ return SCARD_S_SUCCESS; -+} -+ -+LONG smartcard_pack_connect_a_call(wStream* s, const ConnectA_Call* call) -+{ -+ WINPR_ASSERT(call); -+ wLog* log = scard_log(); -+ DWORD index = 0; -+ -+ smartcard_trace_connect_a_call(log, call); -+ -+ const DWORD readerLen = call->szReader ? (DWORD)(strlen(call->szReader) + 1) : 0; -+ if (!smartcard_ndr_pointer_write(s, &index, readerLen)) -+ return SCARD_E_NO_MEMORY; -+ -+ LONG status = -+ smartcard_pack_redir_scard_context(log, s, &call->Common.handles.hContext, &index); -+ if (status != SCARD_S_SUCCESS) -+ return status; -+ -+ if (!Stream_EnsureRemainingCapacity(s, 8)) -+ return SCARD_E_NO_MEMORY; -+ -+ Stream_Write_UINT32(s, call->Common.dwShareMode); -+ Stream_Write_UINT32(s, call->Common.dwPreferredProtocols); -+ -+ if (call->szReader) -+ { -+ status = smartcard_ndr_write_a(s, call->szReader, readerLen, NDR_PTR_FULL); -+ if (status != SCARD_S_SUCCESS) -+ return status; -+ } -+ -+ return smartcard_pack_redir_scard_context_ref(log, s, &call->Common.handles.hContext); -+} -+ -+LONG smartcard_pack_connect_w_call(wStream* s, const ConnectW_Call* call) -+{ -+ WINPR_ASSERT(call); -+ wLog* log = scard_log(); -+ DWORD index = 0; -+ -+ smartcard_trace_connect_w_call(log, call); -+ -+ const DWORD readerLen = call->szReader ? (DWORD)(_wcslen(call->szReader) + 1) : 0; -+ if (!smartcard_ndr_pointer_write(s, &index, readerLen)) -+ return SCARD_E_NO_MEMORY; -+ -+ LONG status = -+ smartcard_pack_redir_scard_context(log, s, &call->Common.handles.hContext, &index); -+ if (status != SCARD_S_SUCCESS) -+ return status; -+ -+ if (!Stream_EnsureRemainingCapacity(s, 8)) -+ return SCARD_E_NO_MEMORY; -+ -+ Stream_Write_UINT32(s, call->Common.dwShareMode); -+ Stream_Write_UINT32(s, call->Common.dwPreferredProtocols); -+ -+ if (call->szReader) -+ { -+ status = smartcard_ndr_write_w(s, call->szReader, readerLen, NDR_PTR_FULL); -+ if (status != SCARD_S_SUCCESS) -+ return status; -+ } -+ -+ return smartcard_pack_redir_scard_context_ref(log, s, &call->Common.handles.hContext); -+} -+ -+LONG smartcard_pack_control_call(wStream* s, const Control_Call* call) -+{ -+ WINPR_ASSERT(call); -+ wLog* log = scard_log(); -+ DWORD index = 0; -+ -+ smartcard_trace_control_call(log, call); -+ -+ LONG status = smartcard_pack_redir_scard_context(log, s, &call->handles.hContext, &index); -+ if (status != SCARD_S_SUCCESS) -+ return status; -+ -+ status = smartcard_pack_redir_scard_handle(log, s, &call->handles.hCard, &index); -+ if (status != SCARD_S_SUCCESS) -+ return status; -+ -+ if (!Stream_EnsureRemainingCapacity(s, 8)) -+ return SCARD_E_NO_MEMORY; -+ -+ Stream_Write_UINT32(s, call->dwControlCode); -+ Stream_Write_UINT32(s, call->cbInBufferSize); -+ if (!smartcard_ndr_pointer_write(s, &index, call->cbInBufferSize)) -+ return SCARD_E_NO_MEMORY; -+ -+ Stream_Write_INT32(s, call->fpvOutBufferIsNULL); -+ Stream_Write_UINT32(s, call->cbOutBufferSize); -+ -+ status = smartcard_pack_redir_scard_context_ref(log, s, &call->handles.hContext); -+ if (status != SCARD_S_SUCCESS) -+ return status; -+ -+ status = smartcard_pack_redir_scard_handle_ref(log, s, &call->handles.hCard); -+ if (status != SCARD_S_SUCCESS) -+ return status; -+ -+ if (call->cbInBufferSize) -+ { -+ status = smartcard_ndr_write(s, call->pvInBuffer, call->cbInBufferSize, 1, NDR_PTR_SIMPLE); -+ if (status != SCARD_S_SUCCESS) -+ return status; -+ } -+ -+ return status; -+} -+ -+LONG smartcard_pack_hcard_and_disposition_call(wStream* s, const HCardAndDisposition_Call* call, -+ const char* name) -+{ -+ WINPR_ASSERT(call); -+ wLog* log = scard_log(); -+ DWORD index = 0; -+ -+ smartcard_trace_hcard_and_disposition_call(log, call, name); -+ -+ LONG status = smartcard_pack_redir_scard_context(log, s, &call->handles.hContext, &index); -+ if (status != SCARD_S_SUCCESS) -+ return status; -+ -+ status = smartcard_pack_redir_scard_handle(log, s, &call->handles.hCard, &index); -+ if (status != SCARD_S_SUCCESS) -+ return status; -+ -+ if (!Stream_EnsureRemainingCapacity(s, 4)) -+ return SCARD_E_NO_MEMORY; -+ -+ Stream_Write_UINT32(s, call->dwDisposition); -+ -+ status = smartcard_pack_redir_scard_context_ref(log, s, &call->handles.hContext); -+ if (status != SCARD_S_SUCCESS) -+ return status; -+ -+ return smartcard_pack_redir_scard_handle_ref(log, s, &call->handles.hCard); -+} -+ -+LONG smartcard_pack_transmit_call(wStream* s, const Transmit_Call* call) -+{ -+ WINPR_ASSERT(call); -+ wLog* log = scard_log(); -+ DWORD index = 0; -+ -+ smartcard_trace_transmit_call(log, call); -+ -+ LONG status = smartcard_pack_redir_scard_context(log, s, &call->handles.hContext, &index); -+ if (status != SCARD_S_SUCCESS) -+ return status; -+ -+ status = smartcard_pack_redir_scard_handle(log, s, &call->handles.hCard, &index); -+ if (status != SCARD_S_SUCCESS) -+ return status; -+ -+ UINT32 cbExtraBytes = 0; -+ const BYTE* pbExtraBytes = NULL; -+ if (call->pioSendPci) -+ { -+ cbExtraBytes = (UINT32)(call->pioSendPci->cbPciLength - sizeof(SCARD_IO_REQUEST)); -+ if (cbExtraBytes > 0) -+ pbExtraBytes = &((const BYTE*)call->pioSendPci)[sizeof(SCARD_IO_REQUEST)]; -+ } -+ -+ if (!Stream_EnsureRemainingCapacity(s, 32)) -+ return SCARD_E_NO_MEMORY; -+ -+ Stream_Write_UINT32(s, call->pioSendPci ? call->pioSendPci->dwProtocol : 0); -+ Stream_Write_UINT32(s, cbExtraBytes); -+ if (!smartcard_ndr_pointer_write(s, &index, cbExtraBytes)) -+ return SCARD_E_NO_MEMORY; -+ -+ Stream_Write_UINT32(s, call->cbSendLength); -+ if (!smartcard_ndr_pointer_write(s, &index, call->cbSendLength)) -+ return SCARD_E_NO_MEMORY; -+ -+ const UINT32 recvPciLen = call->pioRecvPci ? (UINT32)call->pioRecvPci->cbPciLength : 0; -+ if (!smartcard_ndr_pointer_write(s, &index, recvPciLen)) -+ return SCARD_E_NO_MEMORY; -+ -+ Stream_Write_INT32(s, call->fpbRecvBufferIsNULL); -+ Stream_Write_UINT32(s, call->cbRecvLength); -+ -+ status = smartcard_pack_redir_scard_context_ref(log, s, &call->handles.hContext); -+ if (status != SCARD_S_SUCCESS) -+ return status; -+ -+ status = smartcard_pack_redir_scard_handle_ref(log, s, &call->handles.hCard); -+ if (status != SCARD_S_SUCCESS) -+ return status; -+ -+ if (cbExtraBytes > 0) -+ { -+ status = smartcard_ndr_write(s, pbExtraBytes, cbExtraBytes, 1, NDR_PTR_SIMPLE); -+ if (status != SCARD_S_SUCCESS) -+ return status; -+ } -+ -+ if (call->cbSendLength > 0) -+ { -+ status = smartcard_ndr_write(s, call->pbSendBuffer, call->cbSendLength, 1, NDR_PTR_SIMPLE); -+ if (status != SCARD_S_SUCCESS) -+ return status; -+ } -+ -+ if (call->pioRecvPci && recvPciLen > 0) -+ { -+ UINT32 cbRecvExtra = (UINT32)(call->pioRecvPci->cbPciLength - sizeof(SCARD_IO_REQUEST)); -+ const BYTE* pbRecvExtra = &((const BYTE*)call->pioRecvPci)[sizeof(SCARD_IO_REQUEST)]; -+ -+ if (!Stream_EnsureRemainingCapacity(s, 12)) -+ return SCARD_E_NO_MEMORY; -+ -+ Stream_Write_UINT32(s, call->pioRecvPci->dwProtocol); -+ Stream_Write_UINT32(s, cbRecvExtra); -+ if (!smartcard_ndr_pointer_write(s, &index, cbRecvExtra)) -+ return SCARD_E_NO_MEMORY; -+ -+ if (cbRecvExtra > 0) -+ { -+ status = smartcard_ndr_write(s, pbRecvExtra, cbRecvExtra, 1, NDR_PTR_SIMPLE); -+ if (status != SCARD_S_SUCCESS) -+ return status; -+ } -+ } -+ -+ return SCARD_S_SUCCESS; -+} -+ -+LONG smartcard_pack_get_attrib_call(wStream* s, const GetAttrib_Call* call) -+{ -+ WINPR_ASSERT(call); -+ wLog* log = scard_log(); -+ DWORD index = 0; -+ -+ smartcard_trace_get_attrib_call(log, call); -+ -+ LONG status = smartcard_pack_redir_scard_context(log, s, &call->handles.hContext, &index); -+ if (status != SCARD_S_SUCCESS) -+ return status; -+ -+ status = smartcard_pack_redir_scard_handle(log, s, &call->handles.hCard, &index); -+ if (status != SCARD_S_SUCCESS) -+ return status; -+ -+ if (!Stream_EnsureRemainingCapacity(s, 12)) -+ return STATUS_NO_MEMORY; -+ -+ Stream_Write_UINT32(s, call->dwAttrId); -+ Stream_Write_INT32(s, call->fpbAttrIsNULL); -+ Stream_Write_UINT32(s, call->cbAttrLen); -+ -+ status = smartcard_pack_redir_scard_context_ref(log, s, &call->handles.hContext); -+ if (status != SCARD_S_SUCCESS) -+ return status; -+ -+ return smartcard_pack_redir_scard_handle_ref(log, s, &call->handles.hCard); -+} -+ -+LONG smartcard_unpack_list_readers_return(wStream* s, ListReaders_Return* ret, BOOL unicode) -+{ -+ WINPR_ASSERT(ret); -+ wLog* log = scard_log(); -+ UINT32 index = 0; -+ UINT32 mszNdrPtr = 0; -+ -+ if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4)) -+ return STATUS_BUFFER_TOO_SMALL; -+ -+ Stream_Read_UINT32(s, ret->cBytes); -+ -+ if (!smartcard_ndr_pointer_read(log, s, &index, &mszNdrPtr)) -+ return ERROR_INVALID_DATA; -+ -+ if (mszNdrPtr) -+ { -+ LONG status = smartcard_ndr_read(log, s, &ret->msz, ret->cBytes, 1, NDR_PTR_SIMPLE); -+ if (status != SCARD_S_SUCCESS) -+ return status; -+ } -+ -+ smartcard_trace_list_readers_return(log, ret, unicode); -+ return SCARD_S_SUCCESS; -+} -+ -+LONG smartcard_unpack_get_status_change_return(wStream* s, GetStatusChange_Return* ret, -+ BOOL unicode) -+{ -+ WINPR_ASSERT(ret); -+ wLog* log = scard_log(); -+ UINT32 index = 0; -+ UINT32 ndrPtr = 0; -+ -+ if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4)) -+ return STATUS_BUFFER_TOO_SMALL; -+ -+ Stream_Read_UINT32(s, ret->cReaders); -+ -+ if (!smartcard_ndr_pointer_read(log, s, &index, &ndrPtr)) -+ return ERROR_INVALID_DATA; -+ -+ if (ndrPtr && ret->cReaders > 0) -+ { -+ LONG status = -+ smartcard_ndr_read_state(log, s, &ret->rgReaderStates, ret->cReaders, NDR_PTR_SIMPLE); -+ if (status != SCARD_S_SUCCESS) -+ return status; -+ } -+ else -+ ret->rgReaderStates = NULL; -+ -+ smartcard_trace_get_status_change_return(log, ret, unicode); -+ return SCARD_S_SUCCESS; -+} -+ -+LONG smartcard_unpack_connect_return(wStream* s, Connect_Return* ret) -+{ -+ WINPR_ASSERT(ret); -+ wLog* log = scard_log(); -+ UINT32 index = 0; -+ UINT32 pbContextNdrPtr = 0; -+ -+ LONG status = -+ smartcard_unpack_redir_scard_context(log, s, &ret->hContext, &index, &pbContextNdrPtr); -+ if (status != SCARD_S_SUCCESS) -+ return status; -+ -+ status = smartcard_unpack_redir_scard_handle(log, s, &ret->hCard, &index); -+ if (status != SCARD_S_SUCCESS) -+ return status; -+ -+ if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4)) -+ return STATUS_BUFFER_TOO_SMALL; -+ -+ Stream_Read_UINT32(s, ret->dwActiveProtocol); -+ -+ status = smartcard_unpack_redir_scard_context_ref(log, s, pbContextNdrPtr, &ret->hContext); -+ if (status != SCARD_S_SUCCESS) -+ return status; -+ -+ status = smartcard_unpack_redir_scard_handle_ref(log, s, &ret->hCard); -+ if (status != SCARD_S_SUCCESS) -+ return status; -+ -+ smartcard_trace_connect_return(log, ret); -+ return SCARD_S_SUCCESS; -+} -+ -+LONG smartcard_unpack_control_return(wStream* s, Control_Return* ret) -+{ -+ WINPR_ASSERT(ret); -+ wLog* log = scard_log(); -+ UINT32 index = 0; -+ UINT32 pvOutBufferNdrPtr = 0; -+ -+ if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 8)) -+ return STATUS_BUFFER_TOO_SMALL; -+ -+ Stream_Read_UINT32(s, ret->cbOutBufferSize); -+ -+ if (!smartcard_ndr_pointer_read(log, s, &index, &pvOutBufferNdrPtr)) -+ return ERROR_INVALID_DATA; -+ -+ if (pvOutBufferNdrPtr && ret->cbOutBufferSize) -+ { -+ LONG status = -+ smartcard_ndr_read(log, s, &ret->pvOutBuffer, ret->cbOutBufferSize, 1, NDR_PTR_SIMPLE); -+ if (status != SCARD_S_SUCCESS) -+ return status; -+ } -+ smartcard_trace_control_return(log, ret); -+ return SCARD_S_SUCCESS; -+} -+ -+LONG smartcard_unpack_transmit_return(wStream* s, Transmit_Return* ret) -+{ -+ WINPR_ASSERT(ret); -+ wLog* log = scard_log(); -+ UINT32 index = 0; -+ UINT32 recvPciNdrPtr = 0; -+ UINT32 recvBufferNdrPtr = 0; -+ -+ if (!smartcard_ndr_pointer_read(log, s, &index, &recvPciNdrPtr)) -+ return ERROR_INVALID_DATA; -+ -+ if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4)) -+ return STATUS_BUFFER_TOO_SMALL; -+ -+ Stream_Read_UINT32(s, ret->cbRecvLength); -+ -+ if (!smartcard_ndr_pointer_read(log, s, &index, &recvBufferNdrPtr)) -+ return ERROR_INVALID_DATA; -+ -+ if (recvPciNdrPtr) -+ { -+ if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 8)) -+ return STATUS_BUFFER_TOO_SMALL; -+ -+ UINT32 dwProtocol = 0; -+ UINT32 cbExtraBytes = 0; -+ Stream_Read_UINT32(s, dwProtocol); -+ Stream_Read_UINT32(s, cbExtraBytes); -+ -+ UINT32 pbExtraBytesNdrPtr = 0; -+ if (!smartcard_ndr_pointer_read(log, s, &index, &pbExtraBytesNdrPtr)) -+ return ERROR_INVALID_DATA; -+ -+ if (pbExtraBytesNdrPtr) -+ { -+ if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4)) -+ return STATUS_BUFFER_TOO_SMALL; -+ -+ UINT32 length = 0; -+ Stream_Read_UINT32(s, length); -+ if (length != cbExtraBytes) -+ { -+ WLog_Print(log, WLOG_WARN, -+ "Transmit_Return unexpected length: Actual: %" PRIu32 -+ ", Expected: %" PRIu32 " (pioRecvPci.cbExtraBytes)", -+ length, cbExtraBytes); -+ return STATUS_INVALID_PARAMETER; -+ } -+ -+ if (!Stream_CheckAndLogRequiredLengthWLog(log, s, cbExtraBytes)) -+ return STATUS_BUFFER_TOO_SMALL; -+ -+ ret->pioRecvPci = (LPSCARD_IO_REQUEST)malloc(sizeof(SCARD_IO_REQUEST) + cbExtraBytes); -+ if (!ret->pioRecvPci) -+ return SCARD_E_NO_MEMORY; -+ -+ ret->pioRecvPci->dwProtocol = dwProtocol; -+ ret->pioRecvPci->cbPciLength = (DWORD)(sizeof(SCARD_IO_REQUEST) + cbExtraBytes); -+ -+ BYTE* pbExtraBytes = &((BYTE*)ret->pioRecvPci)[sizeof(SCARD_IO_REQUEST)]; -+ Stream_Read(s, pbExtraBytes, length); -+ if (smartcard_unpack_read_size_align(s, cbExtraBytes, 4) < 0) -+ return STATUS_INVALID_PARAMETER; -+ } -+ } -+ -+ if (recvBufferNdrPtr && ret->cbRecvLength > 0) -+ { -+ LONG status = -+ smartcard_ndr_read(log, s, &ret->pbRecvBuffer, ret->cbRecvLength, 1, NDR_PTR_SIMPLE); -+ if (status != SCARD_S_SUCCESS) -+ return status; -+ } -+ -+ smartcard_trace_transmit_return(log, ret); -+ return SCARD_S_SUCCESS; -+} -+ -+LONG smartcard_unpack_get_attrib_return(wStream* s, GetAttrib_Return* ret) -+{ -+ WINPR_ASSERT(ret); -+ wLog* log = scard_log(); -+ UINT32 index = 0; -+ UINT32 pbAttrPtr = 0; -+ -+ if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4)) -+ return STATUS_BUFFER_TOO_SMALL; -+ -+ ret->cbAttrLen = Stream_Get_UINT32(s); -+ -+ if (!smartcard_ndr_pointer_read(log, s, &index, &pbAttrPtr)) -+ return ERROR_INVALID_DATA; -+ -+ LONG status = smartcard_ndr_read(log, s, &ret->pbAttr, ret->cbAttrLen, 1, NDR_PTR_SIMPLE); -+ if (status != SCARD_S_SUCCESS) -+ return status; -+ -+ smartcard_trace_get_attrib_return(log, ret, 0); -+ return SCARD_S_SUCCESS; -+} - -From c3cbf5dc622e1f00a3176694829c1e151135b75a Mon Sep 17 00:00:00 2001 -From: Joan Torres Lopez -Date: Fri, 8 May 2026 10:44:30 +0200 -Subject: [PATCH 09/31] [utils,smartcard] add decode_response for server-side - IOCTL parsing - -Add smartcard_irp_device_control_decode_response as the symmetric -counterpart to decode_request. It decodes DR_CONTROL_RSP: reads -OutputBufferLength, CommonTypeHeader, PrivateTypeHeader, then dispatches -to per-IOCTL decode functions. - -Add a ret union to SMARTCARD_OPERATION for decoded response data, and a -returnCode field since all smartcard IOCTL responses share a common -ReturnCode as their first field before the per-operation return data. - -There are some responses that aren't supported for decoding yet. ---- - include/freerdp/utils/smartcard_operations.h | 46 +++ - libfreerdp/utils/smartcard_operations.c | 382 ++++++++++++++++++- - 2 files changed, 427 insertions(+), 1 deletion(-) - -diff --git a/include/freerdp/utils/smartcard_operations.h b/include/freerdp/utils/smartcard_operations.h -index 41a5fd6b043a..a090b64fdfad 100644 ---- a/include/freerdp/utils/smartcard_operations.h -+++ b/include/freerdp/utils/smartcard_operations.h -@@ -84,6 +84,19 @@ extern "C" - SCARDHANDLE hCard; - const char* ioControlCodeName; - UINT32 outputBufferLength; /** @since version 3.13.0 */ -+ union -+ { -+ EstablishContext_Return establishContext; -+ ListReaders_Return listReaders; -+ GetStatusChange_Return getStatusChange; -+ Connect_Return connect; -+ Control_Return control; -+ Transmit_Return transmit; -+ GetAttrib_Return getAttrib; -+ Reconnect_Return reconnect; -+ Status_Return status; -+ } ret; /** @since version 3.28.0 */ -+ LONG returnCode; /** @since version 3.28.0 */ - } SMARTCARD_OPERATION; - - /** @brief Alias for \ref smartcard_irp_device_control_decode_request. -@@ -114,6 +127,39 @@ extern "C" - UINT32 FileId, - SMARTCARD_OPERATION* operation); - -+ /** @brief Decode a smartcard IOCTL response received from the client. -+ * -+ * Parses the OutputBufferLength, Common Type Header, Private Type Header, and the -+ * ReturnCode, then unpacks the IOCTL-specific return payload into \p operation->ret. -+ * -+ * @param s Stream positioned at OutputBufferLength, after the DeviceIoReply -+ * header. -+ * @param ioControlCode The SCARD_IOCTL_* code identifying the response type. -+ * @param operation [out] The decoded returnCode and ret union. -+ * @return \b SCARD_S_SUCCESS on success, a smartcard error code on failure. -+ * -+ * @since version 3.28.0 -+ */ -+ WINPR_ATTR_NODISCARD -+ FREERDP_API LONG smartcard_irp_device_control_decode_response(wStream* s, UINT32 ioControlCode, -+ SMARTCARD_OPERATION* operation); -+ -+ /** @brief Encode a smartcard IOCTL request to send to the client. -+ * -+ * Writes the Common Type Header, Private Type Header, and the IOCTL-specific -+ * call payload from \p operation->call into the stream. The ioControlCode field -+ * in \p operation selects which pack_call function is dispatched. -+ * -+ * @param s Stream to write into, positioned where the type headers should start. -+ * @param operation with the populated call union and ioControlCode to encode. -+ * @return \b SCARD_S_SUCCESS on success, a smartcard error code on failure. -+ * -+ * @since version 3.28.0 -+ */ -+ WINPR_ATTR_NODISCARD -+ FREERDP_API LONG -+ smartcard_irp_device_control_encode_request(wStream* s, const SMARTCARD_OPERATION* operation); -+ - /** @brief Free resources held by a SMARTCARD_OPERATION. - * - * Releases any memory allocated inside the call and ret unions (e.g., reader name -diff --git a/libfreerdp/utils/smartcard_operations.c b/libfreerdp/utils/smartcard_operations.c -index 61c5761a41f6..906923fc7ecc 100644 ---- a/libfreerdp/utils/smartcard_operations.c -+++ b/libfreerdp/utils/smartcard_operations.c -@@ -561,7 +561,7 @@ LONG smartcard_irp_device_control_decode_request(wStream* s, UINT32 CompletionId - const UINT32 outputBufferLength = Stream_Get_UINT32(s); /* OutputBufferLength (4 bytes) */ - const UINT32 inputBufferLength = Stream_Get_UINT32(s); /* InputBufferLength (4 bytes) */ - const UINT32 ioControlCode = Stream_Get_UINT32(s); /* IoControlCode (4 bytes) */ -- Stream_Seek(s, 20); /* Padding (20 bytes) */ -+ Stream_Seek(s, 20); /* Padding (20 bytes) */ - operation->ioControlCode = ioControlCode; - operation->ioControlCodeName = scard_get_ioctl_string(ioControlCode, FALSE); - operation->outputBufferLength = outputBufferLength; -@@ -825,6 +825,347 @@ LONG smartcard_irp_device_control_decode_request(wStream* s, UINT32 CompletionId - return status; - } - -+static LONG smartcard_EstablishContext_decode_response(wStream* s, SMARTCARD_OPERATION* operation) -+{ -+ WINPR_ASSERT(s); -+ WINPR_ASSERT(operation); -+ -+ return smartcard_unpack_establish_context_return(s, &operation->ret.establishContext); -+} -+ -+static LONG smartcard_ReleaseContext_decode_response(wStream* s, SMARTCARD_OPERATION* operation) -+{ -+ WINPR_UNUSED(s); -+ WINPR_ASSERT(operation); -+ -+ const Long_Return ret = { .ReturnCode = operation->returnCode }; -+ smartcard_trace_long_return(&ret, "ReleaseContext"); -+ return SCARD_S_SUCCESS; -+} -+ -+static LONG smartcard_IsValidContext_decode_response(wStream* s, SMARTCARD_OPERATION* operation) -+{ -+ WINPR_UNUSED(s); -+ WINPR_ASSERT(operation); -+ -+ const Long_Return ret = { .ReturnCode = operation->returnCode }; -+ smartcard_trace_long_return(&ret, "IsValidContext"); -+ return SCARD_S_SUCCESS; -+} -+ -+static LONG smartcard_ListReaderGroupsA_decode_response(wStream* s, SMARTCARD_OPERATION* operation) -+{ -+ WINPR_ASSERT(s); -+ WINPR_ASSERT(operation); -+ -+ return smartcard_unpack_list_reader_groups_return(s, &operation->ret.listReaders, FALSE); -+} -+ -+static LONG smartcard_ListReaderGroupsW_decode_response(wStream* s, SMARTCARD_OPERATION* operation) -+{ -+ WINPR_ASSERT(s); -+ WINPR_ASSERT(operation); -+ -+ return smartcard_unpack_list_reader_groups_return(s, &operation->ret.listReaders, TRUE); -+} -+ -+static LONG smartcard_ListReadersA_decode_response(wStream* s, SMARTCARD_OPERATION* operation) -+{ -+ WINPR_ASSERT(s); -+ WINPR_ASSERT(operation); -+ -+ return smartcard_unpack_list_readers_return(s, &operation->ret.listReaders, FALSE); -+} -+ -+static LONG smartcard_ListReadersW_decode_response(wStream* s, SMARTCARD_OPERATION* operation) -+{ -+ WINPR_ASSERT(s); -+ WINPR_ASSERT(operation); -+ -+ return smartcard_unpack_list_readers_return(s, &operation->ret.listReaders, TRUE); -+} -+ -+static LONG smartcard_GetStatusChangeA_decode_response(wStream* s, SMARTCARD_OPERATION* operation) -+{ -+ WINPR_ASSERT(s); -+ WINPR_ASSERT(operation); -+ -+ return smartcard_unpack_get_status_change_return(s, &operation->ret.getStatusChange, FALSE); -+} -+ -+static LONG smartcard_GetStatusChangeW_decode_response(wStream* s, SMARTCARD_OPERATION* operation) -+{ -+ WINPR_ASSERT(s); -+ WINPR_ASSERT(operation); -+ -+ return smartcard_unpack_get_status_change_return(s, &operation->ret.getStatusChange, TRUE); -+} -+ -+static LONG smartcard_Cancel_decode_response(wStream* s, SMARTCARD_OPERATION* operation) -+{ -+ WINPR_UNUSED(s); -+ WINPR_ASSERT(operation); -+ -+ const Long_Return ret = { .ReturnCode = operation->returnCode }; -+ smartcard_trace_long_return(&ret, "Cancel"); -+ return SCARD_S_SUCCESS; -+} -+ -+static LONG smartcard_ConnectA_decode_response(wStream* s, SMARTCARD_OPERATION* operation) -+{ -+ WINPR_ASSERT(s); -+ WINPR_ASSERT(operation); -+ -+ return smartcard_unpack_connect_return(s, &operation->ret.connect); -+} -+ -+static LONG smartcard_ConnectW_decode_response(wStream* s, SMARTCARD_OPERATION* operation) -+{ -+ WINPR_ASSERT(s); -+ WINPR_ASSERT(operation); -+ -+ return smartcard_unpack_connect_return(s, &operation->ret.connect); -+} -+ -+static LONG smartcard_Reconnect_decode_response(wStream* s, SMARTCARD_OPERATION* operation) -+{ -+ WINPR_ASSERT(s); -+ WINPR_ASSERT(operation); -+ -+ return smartcard_unpack_reconnect_return(s, &operation->ret.reconnect); -+} -+ -+static LONG smartcard_Disconnect_decode_response(wStream* s, SMARTCARD_OPERATION* operation) -+{ -+ WINPR_UNUSED(s); -+ WINPR_ASSERT(operation); -+ -+ const Long_Return ret = { .ReturnCode = operation->returnCode }; -+ smartcard_trace_long_return(&ret, "Disconnect"); -+ return SCARD_S_SUCCESS; -+} -+ -+static LONG smartcard_BeginTransaction_decode_response(wStream* s, SMARTCARD_OPERATION* operation) -+{ -+ WINPR_UNUSED(s); -+ WINPR_ASSERT(operation); -+ -+ const Long_Return ret = { .ReturnCode = operation->returnCode }; -+ smartcard_trace_long_return(&ret, "BeginTransaction"); -+ return SCARD_S_SUCCESS; -+} -+ -+static LONG smartcard_EndTransaction_decode_response(wStream* s, SMARTCARD_OPERATION* operation) -+{ -+ WINPR_UNUSED(s); -+ WINPR_ASSERT(operation); -+ -+ const Long_Return ret = { .ReturnCode = operation->returnCode }; -+ smartcard_trace_long_return(&ret, "EndTransaction"); -+ return SCARD_S_SUCCESS; -+} -+ -+static LONG smartcard_StatusA_decode_response(wStream* s, SMARTCARD_OPERATION* operation) -+{ -+ WINPR_ASSERT(s); -+ WINPR_ASSERT(operation); -+ -+ return smartcard_unpack_status_return(s, &operation->ret.status, FALSE); -+} -+ -+static LONG smartcard_StatusW_decode_response(wStream* s, SMARTCARD_OPERATION* operation) -+{ -+ WINPR_ASSERT(s); -+ WINPR_ASSERT(operation); -+ -+ return smartcard_unpack_status_return(s, &operation->ret.status, TRUE); -+} -+ -+static LONG smartcard_Transmit_decode_response(wStream* s, SMARTCARD_OPERATION* operation) -+{ -+ WINPR_ASSERT(s); -+ WINPR_ASSERT(operation); -+ -+ return smartcard_unpack_transmit_return(s, &operation->ret.transmit); -+} -+ -+static LONG smartcard_Control_decode_response(wStream* s, SMARTCARD_OPERATION* operation) -+{ -+ WINPR_ASSERT(s); -+ WINPR_ASSERT(operation); -+ -+ return smartcard_unpack_control_return(s, &operation->ret.control); -+} -+ -+static LONG smartcard_GetAttrib_decode_response(wStream* s, SMARTCARD_OPERATION* operation) -+{ -+ WINPR_ASSERT(s); -+ WINPR_ASSERT(operation); -+ -+ return smartcard_unpack_get_attrib_return(s, &operation->ret.getAttrib); -+} -+ -+static LONG smartcard_SetAttrib_decode_response(wStream* s, SMARTCARD_OPERATION* operation) -+{ -+ WINPR_UNUSED(s); -+ WINPR_ASSERT(operation); -+ -+ const Long_Return ret = { .ReturnCode = operation->returnCode }; -+ smartcard_trace_long_return(&ret, "SetAttrib"); -+ return SCARD_S_SUCCESS; -+} -+ -+LONG smartcard_irp_device_control_decode_response(wStream* s, UINT32 ioControlCode, -+ SMARTCARD_OPERATION* operation) -+{ -+ LONG status = SCARD_S_SUCCESS; -+ -+ WINPR_ASSERT(s); -+ WINPR_ASSERT(operation); -+ -+ if (!Stream_CheckAndLogRequiredLength(TAG, s, RDPDR_DEVICE_IO_CONTROL_RSP_HDR_LENGTH)) -+ return SCARD_F_INTERNAL_ERROR; -+ -+ const size_t startPosition = Stream_GetPosition(s); -+ -+ const UINT32 outputBufferLength = Stream_Get_UINT32(s); -+ operation->ioControlCode = ioControlCode; -+ operation->ioControlCodeName = scard_get_ioctl_string(ioControlCode, FALSE); -+ operation->outputBufferLength = outputBufferLength; -+ -+ if (outputBufferLength == 0) -+ return SCARD_S_SUCCESS; -+ -+ if (!Stream_CheckAndLogRequiredLength(TAG, s, outputBufferLength)) -+ return SCARD_F_INTERNAL_ERROR; -+ -+ status = smartcard_unpack_common_type_header(s); -+ if (status != SCARD_S_SUCCESS) -+ return status; -+ -+ status = smartcard_unpack_private_type_header(s); -+ if (status != SCARD_S_SUCCESS) -+ return status; -+ -+ if (!Stream_CheckAndLogRequiredLength(TAG, s, 4)) -+ return SCARD_F_INTERNAL_ERROR; -+ -+ Stream_Read_INT32(s, operation->returnCode); -+ -+ if (operation->returnCode != SCARD_S_SUCCESS) -+ { -+ WLog_WARN(TAG, "%s failed with ReturnCode %s [0x%08" PRIX32 "]", -+ scard_get_ioctl_string(ioControlCode, TRUE), -+ SCardGetErrorString(operation->returnCode), (UINT32)operation->returnCode); -+ return SCARD_S_SUCCESS; -+ } -+ -+ switch (ioControlCode) -+ { -+ case SCARD_IOCTL_ESTABLISHCONTEXT: -+ status = smartcard_EstablishContext_decode_response(s, operation); -+ break; -+ -+ case SCARD_IOCTL_RELEASECONTEXT: -+ status = smartcard_ReleaseContext_decode_response(s, operation); -+ break; -+ -+ case SCARD_IOCTL_ISVALIDCONTEXT: -+ status = smartcard_IsValidContext_decode_response(s, operation); -+ break; -+ -+ case SCARD_IOCTL_LISTREADERGROUPSA: -+ status = smartcard_ListReaderGroupsA_decode_response(s, operation); -+ break; -+ -+ case SCARD_IOCTL_LISTREADERGROUPSW: -+ status = smartcard_ListReaderGroupsW_decode_response(s, operation); -+ break; -+ -+ case SCARD_IOCTL_LISTREADERSA: -+ status = smartcard_ListReadersA_decode_response(s, operation); -+ break; -+ -+ case SCARD_IOCTL_LISTREADERSW: -+ status = smartcard_ListReadersW_decode_response(s, operation); -+ break; -+ -+ case SCARD_IOCTL_GETSTATUSCHANGEA: -+ status = smartcard_GetStatusChangeA_decode_response(s, operation); -+ break; -+ -+ case SCARD_IOCTL_GETSTATUSCHANGEW: -+ status = smartcard_GetStatusChangeW_decode_response(s, operation); -+ break; -+ -+ case SCARD_IOCTL_CANCEL: -+ status = smartcard_Cancel_decode_response(s, operation); -+ break; -+ -+ case SCARD_IOCTL_CONNECTA: -+ status = smartcard_ConnectA_decode_response(s, operation); -+ break; -+ -+ case SCARD_IOCTL_CONNECTW: -+ status = smartcard_ConnectW_decode_response(s, operation); -+ break; -+ -+ case SCARD_IOCTL_RECONNECT: -+ status = smartcard_Reconnect_decode_response(s, operation); -+ break; -+ -+ case SCARD_IOCTL_DISCONNECT: -+ status = smartcard_Disconnect_decode_response(s, operation); -+ break; -+ -+ case SCARD_IOCTL_BEGINTRANSACTION: -+ status = smartcard_BeginTransaction_decode_response(s, operation); -+ break; -+ -+ case SCARD_IOCTL_ENDTRANSACTION: -+ status = smartcard_EndTransaction_decode_response(s, operation); -+ break; -+ -+ case SCARD_IOCTL_STATUSA: -+ status = smartcard_StatusA_decode_response(s, operation); -+ break; -+ -+ case SCARD_IOCTL_STATUSW: -+ status = smartcard_StatusW_decode_response(s, operation); -+ break; -+ -+ case SCARD_IOCTL_TRANSMIT: -+ status = smartcard_Transmit_decode_response(s, operation); -+ break; -+ -+ case SCARD_IOCTL_CONTROL: -+ status = smartcard_Control_decode_response(s, operation); -+ break; -+ -+ case SCARD_IOCTL_GETATTRIB: -+ status = smartcard_GetAttrib_decode_response(s, operation); -+ break; -+ -+ case SCARD_IOCTL_SETATTRIB: -+ status = smartcard_SetAttrib_decode_response(s, operation); -+ break; -+ -+ default: -+ WLog_WARN(TAG, "unsupported response for %s (0x%08" PRIX32 ")", -+ scard_get_ioctl_string(ioControlCode, TRUE), ioControlCode); -+ break; -+ } -+ -+ if (status != SCARD_S_SUCCESS) -+ return status; -+ -+ const size_t offset = startPosition + RDPDR_DEVICE_IO_CONTROL_RSP_HDR_LENGTH; -+ if (smartcard_unpack_read_size_align(s, Stream_GetPosition(s) - offset, 8) < 0) -+ return STATUS_INVALID_PARAMETER; -+ -+ return status; -+} -+ - static void free_reader_states_a(LPSCARD_READERSTATEA rgReaderStates, UINT32 cReaders) - { - for (UINT32 x = 0; x < cReaders; x++) -@@ -851,6 +1192,8 @@ void smartcard_operation_free(SMARTCARD_OPERATION* op, BOOL allocated) - { - if (!op) - return; -+ -+ /* Free resources in the call union */ - switch (op->ioControlCode) - { - case SCARD_IOCTL_CANCEL: -@@ -1028,6 +1371,43 @@ void smartcard_operation_free(SMARTCARD_OPERATION* op, BOOL allocated) - break; - } - -+ /* Free resources in the ret union */ -+ switch (op->ioControlCode) -+ { -+ case SCARD_IOCTL_LISTREADERSA: -+ case SCARD_IOCTL_LISTREADERSW: -+ case SCARD_IOCTL_LISTREADERGROUPSA: -+ case SCARD_IOCTL_LISTREADERGROUPSW: -+ { -+ ListReaders_Return* ret = &op->ret.listReaders; -+ free(ret->msz); -+ } -+ break; -+ case SCARD_IOCTL_STATUSA: -+ case SCARD_IOCTL_STATUSW: -+ { -+ Status_Return* ret = &op->ret.status; -+ free(ret->mszReaderNames); -+ } -+ break; -+ case SCARD_IOCTL_GETSTATUSCHANGEA: -+ case SCARD_IOCTL_GETSTATUSCHANGEW: -+ { -+ GetStatusChange_Return* ret = &op->ret.getStatusChange; -+ free(ret->rgReaderStates); -+ } -+ break; -+ case SCARD_IOCTL_TRANSMIT: -+ { -+ Transmit_Return* ret = &op->ret.transmit; -+ free(ret->pbRecvBuffer); -+ free(ret->pioRecvPci); -+ } -+ break; -+ default: -+ break; -+ } -+ - { - SMARTCARD_OPERATION empty = WINPR_C_ARRAY_INIT; - *op = empty; - -From 4c83cecd3bb108e0643020c2b2a21514d316b976 Mon Sep 17 00:00:00 2001 -From: Joan Torres Lopez -Date: Thu, 14 May 2026 16:44:31 +0200 -Subject: [PATCH 10/31] [utils,smartcard] add encode_request for server-side - IOCTL encoding - -Add smartcard_irp_device_control_encode_request as the symmetric -counterpart to decode_request. It encodes DR_CONTROL_REQ: writes -CommonTypeHeader, PrivateTypeHeader, then dispatches to per-IOCTL -encode functions. - -There are some requests that aren't supported for encoding yet. - -Co-authored-by: David Fort ---- - libfreerdp/utils/smartcard_operations.c | 329 ++++++++++++++++++++++++ - 1 file changed, 329 insertions(+) - -diff --git a/libfreerdp/utils/smartcard_operations.c b/libfreerdp/utils/smartcard_operations.c -index 906923fc7ecc..a38e0d102487 100644 ---- a/libfreerdp/utils/smartcard_operations.c -+++ b/libfreerdp/utils/smartcard_operations.c -@@ -1166,6 +1166,335 @@ LONG smartcard_irp_device_control_decode_response(wStream* s, UINT32 ioControlCo - return status; - } - -+static LONG smartcard_EstablishContext_encode_request(wStream* s, -+ const SMARTCARD_OPERATION* operation) -+{ -+ WINPR_ASSERT(s); -+ WINPR_ASSERT(operation); -+ -+ return smartcard_pack_establish_context_call(s, &operation->call.establishContext); -+} -+ -+static LONG smartcard_ReleaseContext_encode_request(wStream* s, -+ const SMARTCARD_OPERATION* operation) -+{ -+ WINPR_ASSERT(s); -+ WINPR_ASSERT(operation); -+ -+ return smartcard_pack_context_call(s, &operation->call.context, "ReleaseContext"); -+} -+ -+static LONG smartcard_IsValidContext_encode_request(wStream* s, -+ const SMARTCARD_OPERATION* operation) -+{ -+ WINPR_ASSERT(s); -+ WINPR_ASSERT(operation); -+ -+ return smartcard_pack_context_call(s, &operation->call.context, "IsValidContext"); -+} -+ -+static LONG smartcard_ListReaderGroupsA_encode_request(wStream* s, -+ const SMARTCARD_OPERATION* operation) -+{ -+ WINPR_ASSERT(s); -+ WINPR_ASSERT(operation); -+ -+ return smartcard_pack_list_reader_groups_call(s, &operation->call.listReaderGroups, FALSE); -+} -+ -+static LONG smartcard_ListReaderGroupsW_encode_request(wStream* s, -+ const SMARTCARD_OPERATION* operation) -+{ -+ WINPR_ASSERT(s); -+ WINPR_ASSERT(operation); -+ -+ return smartcard_pack_list_reader_groups_call(s, &operation->call.listReaderGroups, TRUE); -+} -+ -+static LONG smartcard_ListReadersA_encode_request(wStream* s, const SMARTCARD_OPERATION* operation) -+{ -+ WINPR_ASSERT(s); -+ WINPR_ASSERT(operation); -+ -+ return smartcard_pack_list_readers_call(s, &operation->call.listReaders, FALSE); -+} -+ -+static LONG smartcard_ListReadersW_encode_request(wStream* s, const SMARTCARD_OPERATION* operation) -+{ -+ WINPR_ASSERT(s); -+ WINPR_ASSERT(operation); -+ -+ return smartcard_pack_list_readers_call(s, &operation->call.listReaders, TRUE); -+} -+ -+static LONG smartcard_GetStatusChangeA_encode_request(wStream* s, -+ const SMARTCARD_OPERATION* operation) -+{ -+ WINPR_ASSERT(s); -+ WINPR_ASSERT(operation); -+ -+ return smartcard_pack_get_status_change_a_call(s, &operation->call.getStatusChangeA); -+} -+ -+static LONG smartcard_GetStatusChangeW_encode_request(wStream* s, -+ const SMARTCARD_OPERATION* operation) -+{ -+ WINPR_ASSERT(s); -+ WINPR_ASSERT(operation); -+ -+ return smartcard_pack_get_status_change_w_call(s, &operation->call.getStatusChangeW); -+} -+ -+static LONG smartcard_Cancel_encode_request(wStream* s, const SMARTCARD_OPERATION* operation) -+{ -+ WINPR_ASSERT(s); -+ WINPR_ASSERT(operation); -+ -+ return smartcard_pack_context_call(s, &operation->call.context, "Cancel"); -+} -+ -+static LONG smartcard_ConnectA_encode_request(wStream* s, const SMARTCARD_OPERATION* operation) -+{ -+ WINPR_ASSERT(s); -+ WINPR_ASSERT(operation); -+ -+ return smartcard_pack_connect_a_call(s, &operation->call.connectA); -+} -+ -+static LONG smartcard_ConnectW_encode_request(wStream* s, const SMARTCARD_OPERATION* operation) -+{ -+ WINPR_ASSERT(s); -+ WINPR_ASSERT(operation); -+ -+ return smartcard_pack_connect_w_call(s, &operation->call.connectW); -+} -+ -+static LONG smartcard_Reconnect_encode_request(wStream* s, const SMARTCARD_OPERATION* operation) -+{ -+ WINPR_ASSERT(s); -+ WINPR_ASSERT(operation); -+ -+ return smartcard_pack_reconnect_call(s, &operation->call.reconnect); -+} -+ -+static LONG smartcard_Disconnect_encode_request(wStream* s, const SMARTCARD_OPERATION* operation) -+{ -+ WINPR_ASSERT(s); -+ WINPR_ASSERT(operation); -+ -+ return smartcard_pack_hcard_and_disposition_call(s, &operation->call.hCardAndDisposition, -+ "Disconnect"); -+} -+ -+static LONG smartcard_BeginTransaction_encode_request(wStream* s, -+ const SMARTCARD_OPERATION* operation) -+{ -+ WINPR_ASSERT(s); -+ WINPR_ASSERT(operation); -+ -+ return smartcard_pack_hcard_and_disposition_call(s, &operation->call.hCardAndDisposition, -+ "BeginTransaction"); -+} -+ -+static LONG smartcard_EndTransaction_encode_request(wStream* s, -+ const SMARTCARD_OPERATION* operation) -+{ -+ WINPR_ASSERT(s); -+ WINPR_ASSERT(operation); -+ -+ return smartcard_pack_hcard_and_disposition_call(s, &operation->call.hCardAndDisposition, -+ "EndTransaction"); -+} -+ -+static LONG smartcard_StatusA_encode_request(wStream* s, const SMARTCARD_OPERATION* operation) -+{ -+ WINPR_ASSERT(s); -+ WINPR_ASSERT(operation); -+ -+ return smartcard_pack_status_call(s, &operation->call.status, FALSE); -+} -+ -+static LONG smartcard_StatusW_encode_request(wStream* s, const SMARTCARD_OPERATION* operation) -+{ -+ WINPR_ASSERT(s); -+ WINPR_ASSERT(operation); -+ -+ return smartcard_pack_status_call(s, &operation->call.status, TRUE); -+} -+ -+static LONG smartcard_Transmit_encode_request(wStream* s, const SMARTCARD_OPERATION* operation) -+{ -+ WINPR_ASSERT(s); -+ WINPR_ASSERT(operation); -+ -+ return smartcard_pack_transmit_call(s, &operation->call.transmit); -+} -+ -+static LONG smartcard_Control_encode_request(wStream* s, const SMARTCARD_OPERATION* operation) -+{ -+ WINPR_ASSERT(s); -+ WINPR_ASSERT(operation); -+ -+ return smartcard_pack_control_call(s, &operation->call.control); -+} -+ -+static LONG smartcard_GetAttrib_encode_request(wStream* s, const SMARTCARD_OPERATION* operation) -+{ -+ WINPR_ASSERT(s); -+ WINPR_ASSERT(operation); -+ -+ return smartcard_pack_get_attrib_call(s, &operation->call.getAttrib); -+} -+ -+static LONG smartcard_SetAttrib_encode_request(wStream* s, const SMARTCARD_OPERATION* operation) -+{ -+ WINPR_ASSERT(s); -+ WINPR_ASSERT(operation); -+ -+ return smartcard_pack_set_attrib_call(s, &operation->call.setAttrib); -+} -+ -+LONG smartcard_irp_device_control_encode_request(wStream* s, const SMARTCARD_OPERATION* operation) -+{ -+ LONG status = SCARD_S_SUCCESS; -+ -+ WINPR_ASSERT(s); -+ WINPR_ASSERT(operation); -+ -+ const UINT32 ioControlCode = operation->ioControlCode; -+ -+ const size_t headerPos = Stream_GetPosition(s); -+ Stream_Zero(s, SMARTCARD_COMMON_TYPE_HEADER_LENGTH); /* CommonTypeHeader (8 bytes) */ -+ Stream_Zero(s, SMARTCARD_PRIVATE_TYPE_HEADER_LENGTH); /* PrivateTypeHeader (8 bytes) */ -+ -+ switch (ioControlCode) -+ { -+ case SCARD_IOCTL_ESTABLISHCONTEXT: -+ status = smartcard_EstablishContext_encode_request(s, operation); -+ break; -+ -+ case SCARD_IOCTL_RELEASECONTEXT: -+ status = smartcard_ReleaseContext_encode_request(s, operation); -+ break; -+ -+ case SCARD_IOCTL_ISVALIDCONTEXT: -+ status = smartcard_IsValidContext_encode_request(s, operation); -+ break; -+ -+ case SCARD_IOCTL_LISTREADERGROUPSA: -+ status = smartcard_ListReaderGroupsA_encode_request(s, operation); -+ break; -+ -+ case SCARD_IOCTL_LISTREADERGROUPSW: -+ status = smartcard_ListReaderGroupsW_encode_request(s, operation); -+ break; -+ -+ case SCARD_IOCTL_LISTREADERSA: -+ status = smartcard_ListReadersA_encode_request(s, operation); -+ break; -+ -+ case SCARD_IOCTL_LISTREADERSW: -+ status = smartcard_ListReadersW_encode_request(s, operation); -+ break; -+ -+ case SCARD_IOCTL_GETSTATUSCHANGEA: -+ status = smartcard_GetStatusChangeA_encode_request(s, operation); -+ break; -+ -+ case SCARD_IOCTL_GETSTATUSCHANGEW: -+ status = smartcard_GetStatusChangeW_encode_request(s, operation); -+ break; -+ -+ case SCARD_IOCTL_CANCEL: -+ status = smartcard_Cancel_encode_request(s, operation); -+ break; -+ -+ case SCARD_IOCTL_CONNECTA: -+ status = smartcard_ConnectA_encode_request(s, operation); -+ break; -+ -+ case SCARD_IOCTL_CONNECTW: -+ status = smartcard_ConnectW_encode_request(s, operation); -+ break; -+ -+ case SCARD_IOCTL_RECONNECT: -+ status = smartcard_Reconnect_encode_request(s, operation); -+ break; -+ -+ case SCARD_IOCTL_DISCONNECT: -+ status = smartcard_Disconnect_encode_request(s, operation); -+ break; -+ -+ case SCARD_IOCTL_BEGINTRANSACTION: -+ status = smartcard_BeginTransaction_encode_request(s, operation); -+ break; -+ -+ case SCARD_IOCTL_ENDTRANSACTION: -+ status = smartcard_EndTransaction_encode_request(s, operation); -+ break; -+ -+ case SCARD_IOCTL_STATUSA: -+ status = smartcard_StatusA_encode_request(s, operation); -+ break; -+ -+ case SCARD_IOCTL_STATUSW: -+ status = smartcard_StatusW_encode_request(s, operation); -+ break; -+ -+ case SCARD_IOCTL_TRANSMIT: -+ status = smartcard_Transmit_encode_request(s, operation); -+ break; -+ -+ case SCARD_IOCTL_CONTROL: -+ status = smartcard_Control_encode_request(s, operation); -+ break; -+ -+ case SCARD_IOCTL_GETATTRIB: -+ status = smartcard_GetAttrib_encode_request(s, operation); -+ break; -+ -+ case SCARD_IOCTL_SETATTRIB: -+ status = smartcard_SetAttrib_encode_request(s, operation); -+ break; -+ -+ default: -+ WLog_WARN(TAG, "unsupported request for %s (0x%08" PRIX32 ")", -+ scard_get_ioctl_string(ioControlCode, TRUE), ioControlCode); -+ return SCARD_E_UNSUPPORTED_FEATURE; -+ } -+ -+ if (status != SCARD_S_SUCCESS) -+ return status; -+ -+ if ((ioControlCode != SCARD_IOCTL_ACCESSSTARTEDEVENT) && -+ (ioControlCode != SCARD_IOCTL_RELEASETARTEDEVENT)) -+ { -+ const LONG rc = smartcard_pack_write_size_align(s, Stream_GetPosition(s), 8); -+ if (rc != SCARD_S_SUCCESS) -+ return rc; -+ } -+ -+ const size_t dataEndPos = Stream_GetPosition(s); -+ const size_t payloadSize = dataEndPos - headerPos; -+ const size_t objectBufferLength = -+ payloadSize - SMARTCARD_COMMON_TYPE_HEADER_LENGTH - SMARTCARD_PRIVATE_TYPE_HEADER_LENGTH; -+ -+ status = smartcard_pack_write_size_align(s, payloadSize, 8); -+ if (status != SCARD_S_SUCCESS) -+ return status; -+ -+ const size_t endPos = Stream_GetPosition(s); -+ if (!Stream_SetPosition(s, headerPos)) -+ return SCARD_E_BAD_SEEK; -+ smartcard_pack_common_type_header(s); -+ smartcard_pack_private_type_header(s, (UINT32)objectBufferLength); -+ if (!Stream_SetPosition(s, endPos)) -+ return SCARD_E_BAD_SEEK; -+ Stream_SealLength(s); -+ -+ return status; -+} -+ - static void free_reader_states_a(LPSCARD_READERSTATEA rgReaderStates, UINT32 cReaders) - { - for (UINT32 x = 0; x < cReaders; x++) - -From 41fa3da3f479ea6967c6e37f8935f8e4d143b61d Mon Sep 17 00:00:00 2001 -From: Joan Torres Lopez -Date: Tue, 23 Jun 2026 19:10:08 +0200 -Subject: [PATCH 11/31] [channels,rdpdr] cache context->priv in local variable - -Common subexpression elimination: extract RdpdrServerPrivate* priv -to avoid repeated context->priv pointer dereferences. - -Co-Authored-By: David Fort ---- - channels/rdpdr/server/rdpdr_main.c | 759 +++++++++++++++++------------ - 1 file changed, 438 insertions(+), 321 deletions(-) - -diff --git a/channels/rdpdr/server/rdpdr_main.c b/channels/rdpdr/server/rdpdr_main.c -index 1de60b6688df..5f37a3c7a3d0 100644 ---- a/channels/rdpdr/server/rdpdr_main.c -+++ b/channels/rdpdr/server/rdpdr_main.c -@@ -250,8 +250,10 @@ static BOOL rdpdr_server_enqueue_irp(RdpdrServerContext* context, RDPDR_IRP* irp - { - WINPR_ASSERT(context); - WINPR_ASSERT(context->priv); -+ -+ RdpdrServerPrivate* priv = context->priv; - const uintptr_t key = irp->CompletionId + 1ull; -- return ListDictionary_Add(context->priv->IrpList, (void*)key, irp); -+ return ListDictionary_Add(priv->IrpList, (void*)key, irp); - } - - static RDPDR_IRP* rdpdr_server_dequeue_irp(RdpdrServerContext* context, UINT32 completionId) -@@ -260,8 +262,9 @@ static RDPDR_IRP* rdpdr_server_dequeue_irp(RdpdrServerContext* context, UINT32 c - WINPR_ASSERT(context); - WINPR_ASSERT(context->priv); - -+ RdpdrServerPrivate* priv = context->priv; - const uintptr_t key = completionId + 1ull; -- irp = (RDPDR_IRP*)ListDictionary_Take(context->priv->IrpList, (void*)key); -+ irp = (RDPDR_IRP*)ListDictionary_Take(priv->IrpList, (void*)key); - return irp; - } - -@@ -274,6 +277,7 @@ static UINT rdpdr_seal_send_free_request(RdpdrServerContext* context, wStream* s - WINPR_ASSERT(context->priv); - WINPR_ASSERT(s); - -+ RdpdrServerPrivate* priv = context->priv; - Stream_SealLength(s); - const size_t length = Stream_Length(s); - WINPR_ASSERT(length <= UINT32_MAX); -@@ -285,14 +289,14 @@ static UINT rdpdr_seal_send_free_request(RdpdrServerContext* context, wStream* s - Stream_Read_UINT16(s, header.Component); - Stream_Read_UINT16(s, header.PacketId); - -- WLog_Print(context->priv->log, WLOG_DEBUG, -+ WLog_Print(priv->log, WLOG_DEBUG, - "sending message {Component %s[%04" PRIx16 "], PacketId %s[%04" PRIx16 "]", - rdpdr_component_string(header.Component), header.Component, - rdpdr_packetid_string(header.PacketId), header.PacketId); - } -- winpr_HexLogDump(context->priv->log, WLOG_DEBUG, Stream_Buffer(s), Stream_Length(s)); -- status = WTSVirtualChannelWrite(context->priv->ChannelHandle, Stream_BufferAs(s, char), -- (ULONG)length, &written); -+ winpr_HexLogDump(priv->log, WLOG_DEBUG, Stream_Buffer(s), Stream_Length(s)); -+ status = WTSVirtualChannelWrite(priv->ChannelHandle, Stream_BufferAs(s, char), (ULONG)length, -+ &written); - Stream_Free(s, TRUE); - return status ? CHANNEL_RC_OK : ERROR_INTERNAL_ERROR; - } -@@ -318,19 +322,20 @@ static UINT rdpdr_server_send_announce_request(RdpdrServerContext* context) - if (error != CHANNEL_RC_OK) - return error; - -+ RdpdrServerPrivate* priv = context->priv; - s = Stream_New(nullptr, RDPDR_HEADER_LENGTH + 8); - - if (!s) - { -- WLog_Print(context->priv->log, WLOG_ERROR, "Stream_New failed!"); -+ WLog_Print(priv->log, WLOG_ERROR, "Stream_New failed!"); - return CHANNEL_RC_NO_MEMORY; - } - - Stream_Write_UINT16(s, header.Component); /* Component (2 bytes) */ - Stream_Write_UINT16(s, header.PacketId); /* PacketId (2 bytes) */ -- Stream_Write_UINT16(s, context->priv->VersionMajor); /* VersionMajor (2 bytes) */ -- Stream_Write_UINT16(s, context->priv->VersionMinor); /* VersionMinor (2 bytes) */ -- Stream_Write_UINT32(s, context->priv->ClientId); /* ClientId (4 bytes) */ -+ Stream_Write_UINT16(s, priv->VersionMajor); /* VersionMajor (2 bytes) */ -+ Stream_Write_UINT16(s, priv->VersionMinor); /* VersionMinor (2 bytes) */ -+ Stream_Write_UINT32(s, priv->ClientId); /* ClientId (4 bytes) */ - return rdpdr_seal_send_free_request(context, s); - } - -@@ -349,19 +354,21 @@ static UINT rdpdr_server_receive_announce_response(RdpdrServerContext* context, - WINPR_ASSERT(context->priv); - WINPR_ASSERT(header); - -+ RdpdrServerPrivate* priv = context->priv; -+ - WINPR_UNUSED(header); - -- if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 8)) -+ if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 8)) - return ERROR_INVALID_DATA; - - Stream_Read_UINT16(s, VersionMajor); /* VersionMajor (2 bytes) */ - Stream_Read_UINT16(s, VersionMinor); /* VersionMinor (2 bytes) */ - Stream_Read_UINT32(s, ClientId); /* ClientId (4 bytes) */ -- WLog_Print(context->priv->log, WLOG_DEBUG, -+ WLog_Print(priv->log, WLOG_DEBUG, - "Client Announce Response: VersionMajor: 0x%08" PRIX16 " VersionMinor: 0x%04" PRIX16 - " ClientId: 0x%08" PRIX32 "", - VersionMajor, VersionMinor, ClientId); -- context->priv->ClientId = ClientId; -+ priv->ClientId = ClientId; - - return IFCALLRESULT(CHANNEL_RC_OK, context->ReceiveAnnounceResponse, context, VersionMajor, - VersionMinor, ClientId); -@@ -385,7 +392,9 @@ static UINT rdpdr_server_receive_client_name_request(RdpdrServerContext* context - WINPR_ASSERT(header); - WINPR_UNUSED(header); - -- if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 12)) -+ RdpdrServerPrivate* priv = context->priv; -+ -+ if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 12)) - return ERROR_INVALID_DATA; - - Stream_Read_UINT32(s, UnicodeFlag); /* UnicodeFlag (4 bytes) */ -@@ -396,7 +405,7 @@ static UINT rdpdr_server_receive_client_name_request(RdpdrServerContext* context - UnicodeFlag = UnicodeFlag & 0x00000001; - - if (CodePage != 0) -- WLog_Print(context->priv->log, WLOG_WARN, -+ WLog_Print(priv->log, WLOG_WARN, - "[MS-RDPEFS] 2.2.2.4 Client Name Request (DR_CORE_CLIENT_NAME_REQ)::CodePage " - "must be 0, but is 0x%08" PRIx32, - CodePage); -@@ -410,8 +419,8 @@ static UINT rdpdr_server_receive_client_name_request(RdpdrServerContext* context - { - if ((ComputerNameLen % 2) || ComputerNameLen > 512 || ComputerNameLen < 2) - { -- WLog_Print(context->priv->log, WLOG_ERROR, -- "invalid unicode computer name length: %" PRIu32 "", ComputerNameLen); -+ WLog_Print(priv->log, WLOG_ERROR, "invalid unicode computer name length: %" PRIu32 "", -+ ComputerNameLen); - return ERROR_INVALID_DATA; - } - } -@@ -419,56 +428,55 @@ static UINT rdpdr_server_receive_client_name_request(RdpdrServerContext* context - { - if (ComputerNameLen > 256 || ComputerNameLen < 1) - { -- WLog_Print(context->priv->log, WLOG_ERROR, -- "invalid ascii computer name length: %" PRIu32 "", ComputerNameLen); -+ WLog_Print(priv->log, WLOG_ERROR, "invalid ascii computer name length: %" PRIu32 "", -+ ComputerNameLen); - return ERROR_INVALID_DATA; - } - } - -- if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, ComputerNameLen)) -+ if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, ComputerNameLen)) - return ERROR_INVALID_DATA; - - /* ComputerName must be null terminated, check if it really is */ - const char* computerName = Stream_ConstPointer(s); - if (computerName[ComputerNameLen - 1] || (UnicodeFlag && computerName[ComputerNameLen - 2])) - { -- WLog_Print(context->priv->log, WLOG_ERROR, "computer name must be null terminated"); -+ WLog_Print(priv->log, WLOG_ERROR, "computer name must be null terminated"); - return ERROR_INVALID_DATA; - } - -- if (context->priv->ClientComputerName) -+ if (priv->ClientComputerName) - { -- free(context->priv->ClientComputerName); -- context->priv->ClientComputerName = nullptr; -+ free(priv->ClientComputerName); -+ priv->ClientComputerName = nullptr; - } - - if (UnicodeFlag) - { -- context->priv->ClientComputerName = -+ priv->ClientComputerName = - Stream_Read_UTF16_String_As_UTF8(s, ComputerNameLen / sizeof(WCHAR), nullptr); -- if (!context->priv->ClientComputerName) -+ if (!priv->ClientComputerName) - { -- WLog_Print(context->priv->log, WLOG_ERROR, "failed to convert client computer name"); -+ WLog_Print(priv->log, WLOG_ERROR, "failed to convert client computer name"); - return ERROR_INVALID_DATA; - } - } - else - { - const char* name = Stream_ConstPointer(s); -- context->priv->ClientComputerName = _strdup(name); -+ priv->ClientComputerName = _strdup(name); - Stream_Seek(s, ComputerNameLen); - -- if (!context->priv->ClientComputerName) -+ if (!priv->ClientComputerName) - { -- WLog_Print(context->priv->log, WLOG_ERROR, "failed to duplicate client computer name"); -+ WLog_Print(priv->log, WLOG_ERROR, "failed to duplicate client computer name"); - return CHANNEL_RC_NO_MEMORY; - } - } - -- WLog_Print(context->priv->log, WLOG_DEBUG, "ClientComputerName: %s", -- context->priv->ClientComputerName); -+ WLog_Print(priv->log, WLOG_DEBUG, "ClientComputerName: %s", priv->ClientComputerName); - return IFCALLRESULT(CHANNEL_RC_OK, context->ReceiveClientNameRequest, context, ComputerNameLen, -- context->priv->ClientComputerName); -+ priv->ClientComputerName); - } - - static UINT rdpdr_server_write_capability_set_header_cb(RdpdrServerContext* context, wStream* s, -@@ -476,7 +484,9 @@ static UINT rdpdr_server_write_capability_set_header_cb(RdpdrServerContext* cont - { - WINPR_ASSERT(context); - WINPR_ASSERT(context->priv); -- UINT error = rdpdr_write_capset_header(context->priv->log, s, header); -+ -+ RdpdrServerPrivate* priv = context->priv; -+ UINT error = rdpdr_write_capset_header(priv->log, s, header); - if (error != CHANNEL_RC_OK) - return error; - -@@ -495,7 +505,9 @@ static UINT rdpdr_server_read_general_capability_set(RdpdrServerContext* context - WINPR_ASSERT(context->priv); - WINPR_ASSERT(header); - -- if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 32)) -+ RdpdrServerPrivate* priv = context->priv; -+ -+ if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 32)) - return ERROR_INVALID_DATA; - - const UINT32 OsType = Stream_Get_UINT32(s); /* osType (4 bytes), ignored on receipt */ -@@ -513,7 +525,7 @@ static UINT rdpdr_server_read_general_capability_set(RdpdrServerContext* context - - { - char buffer[1024] = WINPR_C_ARRAY_INIT; -- WLog_Print(context->priv->log, WLOG_TRACE, -+ WLog_Print(priv->log, WLOG_TRACE, - "OsType=%" PRIu32 ", OsVersion=%" PRIu32 ", VersionMajor=%" PRIu32 - ", VersionMinor=%" PRIu32 ", IoCode1=%s, IoCode2=%" PRIu32 - ", ExtendedPdu=%" PRIu32 ", ExtraFlags1=%" PRIu32 ", ExtraFlags2=%" PRIu32, -@@ -524,7 +536,7 @@ static UINT rdpdr_server_read_general_capability_set(RdpdrServerContext* context - - if (VersionMajor != RDPDR_MAJOR_RDP_VERSION) - { -- WLog_Print(context->priv->log, WLOG_ERROR, "unsupported RDPDR version %" PRIu16 ".%" PRIu16, -+ WLog_Print(priv->log, WLOG_ERROR, "unsupported RDPDR version %" PRIu16 ".%" PRIu16, - VersionMajor, VersionMinor); - return ERROR_INVALID_DATA; - } -@@ -538,21 +550,20 @@ static UINT rdpdr_server_read_general_capability_set(RdpdrServerContext* context - case RDPDR_MINOR_RDP_VERSION_5_0: - break; - default: -- WLog_Print(context->priv->log, WLOG_WARN, -- "unsupported RDPDR minor version %" PRIu16 ".%" PRIu16, VersionMajor, -- VersionMinor); -+ WLog_Print(priv->log, WLOG_WARN, "unsupported RDPDR minor version %" PRIu16 ".%" PRIu16, -+ VersionMajor, VersionMinor); - break; - } - - UINT32 SpecialTypeDeviceCap = 0; - if (header->Version == GENERAL_CAPABILITY_VERSION_02) - { -- if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 4)) -+ if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 4)) - return ERROR_INVALID_DATA; - - SpecialTypeDeviceCap = Stream_Get_UINT32(s); /* SpecialTypeDeviceCap (4 bytes) */ - } -- context->priv->SpecialDeviceTypeCap = SpecialTypeDeviceCap; -+ priv->SpecialDeviceTypeCap = SpecialTypeDeviceCap; - - const UINT32 mask = - RDPDR_IRP_MJ_CREATE | RDPDR_IRP_MJ_CLEANUP | RDPDR_IRP_MJ_CLOSE | RDPDR_IRP_MJ_READ | -@@ -564,15 +575,15 @@ static UINT rdpdr_server_read_general_capability_set(RdpdrServerContext* context - if ((IoCode1 & mask) == 0) - { - char buffer[1024] = WINPR_C_ARRAY_INIT; -- WLog_Print(context->priv->log, WLOG_ERROR, "Missing IRP mask values %s", -+ WLog_Print(priv->log, WLOG_ERROR, "Missing IRP mask values %s", - rdpdr_irp_mask2str(IoCode1 & mask, buffer, sizeof(buffer))); - return ERROR_INVALID_DATA; - } -- context->priv->IoCode1 = IoCode1; -+ priv->IoCode1 = IoCode1; - - if (IoCode2 != 0) - { -- WLog_Print(context->priv->log, WLOG_WARN, -+ WLog_Print(priv->log, WLOG_WARN, - "[MS-RDPEFS] 2.2.2.7.1 General Capability Set (GENERAL_CAPS_SET) ioCode2 is " - "reserved for future use, expected value 0 got %" PRIu32, - IoCode2); -@@ -580,17 +591,17 @@ static UINT rdpdr_server_read_general_capability_set(RdpdrServerContext* context - - if ((ExtendedPdu & RDPDR_CLIENT_DISPLAY_NAME_PDU) == 0) - { -- WLog_Print(context->priv->log, WLOG_WARN, -+ WLog_Print(priv->log, WLOG_WARN, - "[MS-RDPEFS] 2.2.2.7.1 General Capability Set (GENERAL_CAPS_SET) extendedPDU " - "should always set RDPDR_CLIENT_DISPLAY_NAME_PDU[0x00000002]"); - } - -- context->priv->ExtendedPDU = ExtendedPdu; -- context->priv->UserLoggedOnPdu = (ExtendedPdu & RDPDR_USER_LOGGEDON_PDU) != 0; -+ priv->ExtendedPDU = ExtendedPdu; -+ priv->UserLoggedOnPdu = (ExtendedPdu & RDPDR_USER_LOGGEDON_PDU) != 0; - - if (ExtraFlags2 != 0) - { -- WLog_Print(context->priv->log, WLOG_WARN, -+ WLog_Print(priv->log, WLOG_WARN, - "[MS-RDPEFS] 2.2.2.7.1 General Capability Set (GENERAL_CAPS_SET) ExtraFlags2 is " - "reserved for future use, expected value 0 got %" PRIu32, - ExtraFlags2); -@@ -637,14 +648,15 @@ static UINT rdpdr_server_write_general_capability_set(RdpdrServerContext* contex - extendedPdu |= RDPDR_CLIENT_DISPLAY_NAME_PDU; /* always set */ - extendedPdu |= RDPDR_DEVICE_REMOVE_PDUS; /* optional */ - -- if (context->priv->UserLoggedOnPdu) -+ RdpdrServerPrivate* priv = context->priv; -+ if (priv->UserLoggedOnPdu) - extendedPdu |= RDPDR_USER_LOGGEDON_PDU; /* optional */ - - extraFlags1 = 0; - extraFlags1 |= ENABLE_ASYNCIO; /* optional */ - SpecialTypeDeviceCap = 0; - -- UINT error = rdpdr_write_capset_header(context->priv->log, s, &header); -+ UINT error = rdpdr_write_capset_header(priv->log, s, &header); - if (error != CHANNEL_RC_OK) - return error; - -@@ -652,8 +664,8 @@ static UINT rdpdr_server_write_general_capability_set(RdpdrServerContext* contex - const size_t start = Stream_GetPosition(s); - Stream_Write_UINT32(s, 0); /* osType (4 bytes), ignored on receipt */ - Stream_Write_UINT32(s, 0); /* osVersion (4 bytes), unused and must be set to zero */ -- Stream_Write_UINT16(s, context->priv->VersionMajor); /* protocolMajorVersion (2 bytes) */ -- Stream_Write_UINT16(s, context->priv->VersionMinor); /* protocolMinorVersion (2 bytes) */ -+ Stream_Write_UINT16(s, priv->VersionMajor); /* protocolMajorVersion (2 bytes) */ -+ Stream_Write_UINT16(s, priv->VersionMinor); /* protocolMinorVersion (2 bytes) */ - Stream_Write_UINT32(s, ioCode1); /* ioCode1 (4 bytes) */ - Stream_Write_UINT32(s, 0); /* ioCode2 (4 bytes), must be set to zero, reserved for future use */ - Stream_Write_UINT32(s, extendedPdu); /* extendedPdu (4 bytes) */ -@@ -832,11 +844,12 @@ static UINT rdpdr_server_send_core_capability_request(RdpdrServerContext* contex - if ((context->supported & RDPDR_DTYP_SMARTCARD) != 0) - numCapabilities++; - -+ RdpdrServerPrivate* priv = context->priv; - s = Stream_New(nullptr, RDPDR_HEADER_LENGTH + 512); - - if (!s) - { -- WLog_Print(context->priv->log, WLOG_ERROR, "Stream_New failed!"); -+ WLog_Print(priv->log, WLOG_ERROR, "Stream_New failed!"); - return CHANNEL_RC_NO_MEMORY; - } - -@@ -847,7 +860,7 @@ static UINT rdpdr_server_send_core_capability_request(RdpdrServerContext* contex - - if ((error = rdpdr_server_write_general_capability_set(context, s))) - { -- WLog_Print(context->priv->log, WLOG_ERROR, -+ WLog_Print(priv->log, WLOG_ERROR, - "rdpdr_server_write_general_capability_set failed with error %" PRIu32 "!", - error); - goto out; -@@ -857,7 +870,7 @@ static UINT rdpdr_server_send_core_capability_request(RdpdrServerContext* contex - { - if ((error = rdpdr_server_write_drive_capability_set(context, s))) - { -- WLog_Print(context->priv->log, WLOG_ERROR, -+ WLog_Print(priv->log, WLOG_ERROR, - "rdpdr_server_write_drive_capability_set failed with error %" PRIu32 "!", - error); - goto out; -@@ -869,7 +882,7 @@ static UINT rdpdr_server_send_core_capability_request(RdpdrServerContext* contex - { - if ((error = rdpdr_server_write_port_capability_set(context, s))) - { -- WLog_Print(context->priv->log, WLOG_ERROR, -+ WLog_Print(priv->log, WLOG_ERROR, - "rdpdr_server_write_port_capability_set failed with error %" PRIu32 "!", - error); - goto out; -@@ -880,7 +893,7 @@ static UINT rdpdr_server_send_core_capability_request(RdpdrServerContext* contex - { - if ((error = rdpdr_server_write_printer_capability_set(context, s))) - { -- WLog_Print(context->priv->log, WLOG_ERROR, -+ WLog_Print(priv->log, WLOG_ERROR, - "rdpdr_server_write_printer_capability_set failed with error %" PRIu32 "!", - error); - goto out; -@@ -891,7 +904,7 @@ static UINT rdpdr_server_send_core_capability_request(RdpdrServerContext* contex - { - if ((error = rdpdr_server_write_smartcard_capability_set(context, s))) - { -- WLog_Print(context->priv->log, WLOG_ERROR, -+ WLog_Print(priv->log, WLOG_ERROR, - "rdpdr_server_write_printer_capability_set failed with error %" PRIu32 "!", - error); - goto out; -@@ -936,9 +949,11 @@ static UINT rdpdr_server_receive_core_capability_response(RdpdrServerContext* co - WINPR_ASSERT(context); - WINPR_ASSERT(context->priv); - -+ RdpdrServerPrivate* priv = context->priv; -+ - WINPR_UNUSED(header); - -- if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 4)) -+ if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 4)) - return ERROR_INVALID_DATA; - - Stream_Read_UINT16(s, numCapabilities); /* numCapabilities (2 bytes) */ -@@ -950,9 +965,9 @@ static UINT rdpdr_server_receive_core_capability_response(RdpdrServerContext* co - RDPDR_CAPABILITY_HEADER capabilityHeader = WINPR_C_ARRAY_INIT; - const size_t start = Stream_GetPosition(s); - -- if ((status = rdpdr_read_capset_header(context->priv->log, s, &capabilityHeader))) -+ if ((status = rdpdr_read_capset_header(priv->log, s, &capabilityHeader))) - { -- WLog_Print(context->priv->log, WLOG_ERROR, "failed with error %" PRIu32 "!", status); -+ WLog_Print(priv->log, WLOG_ERROR, "failed with error %" PRIu32 "!", status); - return status; - } - -@@ -967,8 +982,7 @@ static UINT rdpdr_server_receive_core_capability_response(RdpdrServerContext* co - if ((status = - rdpdr_server_read_general_capability_set(context, s, &capabilityHeader))) - { -- WLog_Print(context->priv->log, WLOG_ERROR, "failed with error %" PRIu32 "!", -- status); -+ WLog_Print(priv->log, WLOG_ERROR, "failed with error %" PRIu32 "!", status); - return status; - } - -@@ -978,8 +992,7 @@ static UINT rdpdr_server_receive_core_capability_response(RdpdrServerContext* co - if ((status = - rdpdr_server_read_printer_capability_set(context, s, &capabilityHeader))) - { -- WLog_Print(context->priv->log, WLOG_ERROR, "failed with error %" PRIu32 "!", -- status); -+ WLog_Print(priv->log, WLOG_ERROR, "failed with error %" PRIu32 "!", status); - return status; - } - -@@ -988,8 +1001,7 @@ static UINT rdpdr_server_receive_core_capability_response(RdpdrServerContext* co - case CAP_PORT_TYPE: - if ((status = rdpdr_server_read_port_capability_set(context, s, &capabilityHeader))) - { -- WLog_Print(context->priv->log, WLOG_ERROR, "failed with error %" PRIu32 "!", -- status); -+ WLog_Print(priv->log, WLOG_ERROR, "failed with error %" PRIu32 "!", status); - return status; - } - -@@ -999,8 +1011,7 @@ static UINT rdpdr_server_receive_core_capability_response(RdpdrServerContext* co - if ((status = - rdpdr_server_read_drive_capability_set(context, s, &capabilityHeader))) - { -- WLog_Print(context->priv->log, WLOG_ERROR, "failed with error %" PRIu32 "!", -- status); -+ WLog_Print(priv->log, WLOG_ERROR, "failed with error %" PRIu32 "!", status); - return status; - } - -@@ -1010,15 +1021,14 @@ static UINT rdpdr_server_receive_core_capability_response(RdpdrServerContext* co - if ((status = - rdpdr_server_read_smartcard_capability_set(context, s, &capabilityHeader))) - { -- WLog_Print(context->priv->log, WLOG_ERROR, "failed with error %" PRIu32 "!", -- status); -+ WLog_Print(priv->log, WLOG_ERROR, "failed with error %" PRIu32 "!", status); - return status; - } - - break; - - default: -- WLog_Print(context->priv->log, WLOG_WARN, "Unknown capabilityType %" PRIu16 "", -+ WLog_Print(priv->log, WLOG_WARN, "Unknown capabilityType %" PRIu16 "", - capabilityHeader.CapabilityType); - Stream_Seek(s, capabilityHeader.CapabilityLength); - return ERROR_INVALID_DATA; -@@ -1027,8 +1037,7 @@ static UINT rdpdr_server_receive_core_capability_response(RdpdrServerContext* co - const UINT16 client_dtyp = rdpdr_cap_type_to_dtyp(capabilityHeader.CapabilityType); - if ((client_dtyp != 0) && ((client_dtyp & context->supported) == 0)) - { -- WLog_Print(context->priv->log, WLOG_WARN, -- "client sent capability %s we did not announce!", -+ WLog_Print(priv->log, WLOG_WARN, "client sent capability %s we did not announce!", - rdpdr_cap_type_string(capabilityHeader.CapabilityType)); - } - caps |= client_dtyp; -@@ -1037,7 +1046,7 @@ static UINT rdpdr_server_receive_core_capability_response(RdpdrServerContext* co - const size_t diff = end - start; - if (diff != capabilityHeader.CapabilityLength + RDPDR_CAPABILITY_HEADER_LENGTH) - { -- WLog_Print(context->priv->log, WLOG_WARN, -+ WLog_Print(priv->log, WLOG_WARN, - "{capability %s[0x%04" PRIx16 "]} processed %" PRIuz - " bytes, but expected to be %" PRIu16, - rdpdr_cap_type_string(capabilityHeader.CapabilityType), -@@ -1066,19 +1075,21 @@ static UINT rdpdr_server_send_client_id_confirm(RdpdrServerContext* context) - - header.Component = RDPDR_CTYP_CORE; - header.PacketId = PAKID_CORE_CLIENTID_CONFIRM; -+ -+ RdpdrServerPrivate* priv = context->priv; - s = Stream_New(nullptr, RDPDR_HEADER_LENGTH + 8); - - if (!s) - { -- WLog_Print(context->priv->log, WLOG_ERROR, "Stream_New failed!"); -+ WLog_Print(priv->log, WLOG_ERROR, "Stream_New failed!"); - return CHANNEL_RC_NO_MEMORY; - } - - Stream_Write_UINT16(s, header.Component); /* Component (2 bytes) */ - Stream_Write_UINT16(s, header.PacketId); /* PacketId (2 bytes) */ -- Stream_Write_UINT16(s, context->priv->VersionMajor); /* VersionMajor (2 bytes) */ -- Stream_Write_UINT16(s, context->priv->VersionMinor); /* VersionMinor (2 bytes) */ -- Stream_Write_UINT32(s, context->priv->ClientId); /* ClientId (4 bytes) */ -+ Stream_Write_UINT16(s, priv->VersionMajor); /* VersionMajor (2 bytes) */ -+ Stream_Write_UINT16(s, priv->VersionMinor); /* VersionMinor (2 bytes) */ -+ Stream_Write_UINT32(s, priv->ClientId); /* ClientId (4 bytes) */ - return rdpdr_seal_send_free_request(context, s); - } - -@@ -1096,20 +1107,22 @@ static UINT rdpdr_server_receive_device_list_announce_request(RdpdrServerContext - WINPR_ASSERT(context); - WINPR_ASSERT(context->priv); - -+ RdpdrServerPrivate* priv = context->priv; -+ - WINPR_UNUSED(header); - -- if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 4)) -+ if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 4)) - return ERROR_INVALID_DATA; - - Stream_Read_UINT32(s, DeviceCount); /* DeviceCount (4 bytes) */ -- WLog_Print(context->priv->log, WLOG_DEBUG, "DeviceCount: %" PRIu32 "", DeviceCount); -+ WLog_Print(priv->log, WLOG_DEBUG, "DeviceCount: %" PRIu32 "", DeviceCount); - - for (UINT32 i = 0; i < DeviceCount; i++) - { - UINT error = 0; - RdpdrDevice device = WINPR_C_ARRAY_INIT; - -- if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 20)) -+ if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 20)) - return ERROR_INVALID_DATA; - - Stream_Read_UINT32(s, device.DeviceType); /* DeviceType (4 bytes) */ -@@ -1118,7 +1131,7 @@ static UINT rdpdr_server_receive_device_list_announce_request(RdpdrServerContext - Stream_Read_UINT32(s, device.DeviceDataLength); /* DeviceDataLength (4 bytes) */ - device.DeviceData = Stream_Pointer(s); - -- if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, device.DeviceDataLength)) -+ if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, device.DeviceDataLength)) - return ERROR_INVALID_DATA; - - if (!rdpdr_add_device(context->priv, &device)) -@@ -1143,7 +1156,7 @@ static UINT rdpdr_server_receive_device_list_announce_request(RdpdrServerContext - case RDPDR_DTYP_SERIAL: - if (device.DeviceDataLength != 0) - { -- WLog_Print(context->priv->log, WLOG_WARN, -+ WLog_Print(priv->log, WLOG_WARN, - "[rdpdr] RDPDR_DTYP_SERIAL::DeviceDataLength != 0 [%" PRIu32 "]", - device.DeviceDataLength); - error = ERROR_INVALID_DATA; -@@ -1156,7 +1169,7 @@ static UINT rdpdr_server_receive_device_list_announce_request(RdpdrServerContext - case RDPDR_DTYP_PARALLEL: - if (device.DeviceDataLength != 0) - { -- WLog_Print(context->priv->log, WLOG_WARN, -+ WLog_Print(priv->log, WLOG_WARN, - "[rdpdr] RDPDR_DTYP_PARALLEL::DeviceDataLength != 0 [%" PRIu32 "]", - device.DeviceDataLength); - error = ERROR_INVALID_DATA; -@@ -1169,7 +1182,7 @@ static UINT rdpdr_server_receive_device_list_announce_request(RdpdrServerContext - case RDPDR_DTYP_SMARTCARD: - if (device.DeviceDataLength != 0) - { -- WLog_Print(context->priv->log, WLOG_WARN, -+ WLog_Print(priv->log, WLOG_WARN, - "[rdpdr] RDPDR_DTYP_SMARTCARD::DeviceDataLength != 0 [%" PRIu32 "]", - device.DeviceDataLength); - error = ERROR_INVALID_DATA; -@@ -1180,7 +1193,7 @@ static UINT rdpdr_server_receive_device_list_announce_request(RdpdrServerContext - break; - - default: -- WLog_Print(context->priv->log, WLOG_WARN, -+ WLog_Print(priv->log, WLOG_WARN, - "[MS-RDPEFS] 2.2.2.9 Client Device List Announce Request " - "(DR_CORE_DEVICELIST_ANNOUNCE_REQ) unknown device type %04" PRIx16 - " at position %" PRIu32, -@@ -1212,26 +1225,27 @@ static UINT rdpdr_server_receive_device_list_remove_request(RdpdrServerContext* - WINPR_ASSERT(context); - WINPR_ASSERT(context->priv); - -+ RdpdrServerPrivate* priv = context->priv; -+ - WINPR_UNUSED(header); - -- if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 4)) -+ if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 4)) - return ERROR_INVALID_DATA; - - Stream_Read_UINT32(s, DeviceCount); /* DeviceCount (4 bytes) */ -- WLog_Print(context->priv->log, WLOG_DEBUG, "DeviceCount: %" PRIu32 "", DeviceCount); -+ WLog_Print(priv->log, WLOG_DEBUG, "DeviceCount: %" PRIu32 "", DeviceCount); - - for (UINT32 i = 0; i < DeviceCount; i++) - { - UINT error = 0; - const RdpdrDevice* device = nullptr; - -- if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 4)) -+ if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 4)) - return ERROR_INVALID_DATA; - - Stream_Read_UINT32(s, DeviceId); /* DeviceId (4 bytes) */ - device = rdpdr_get_device_by_id(context->priv, DeviceId); -- WLog_Print(context->priv->log, WLOG_DEBUG, "Device %" PRIu32 " Id: 0x%08" PRIX32 "", i, -- DeviceId); -+ WLog_Print(priv->log, WLOG_DEBUG, "Device %" PRIu32 " Id: 0x%08" PRIX32 "", i, DeviceId); - DeviceType = 0; - if (device) - DeviceType = device->DeviceType; -@@ -1301,7 +1315,9 @@ static UINT rdpdr_server_receive_io_create_request(RdpdrServerContext* context, - UINT32 PathLength = 0; - - WINPR_ASSERT(context); -- if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 32)) -+ -+ RdpdrServerPrivate* priv = context->priv; -+ if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 32)) - return ERROR_INVALID_DATA; - - Stream_Read_UINT32(s, DesiredAccess); -@@ -1312,13 +1328,13 @@ static UINT rdpdr_server_receive_io_create_request(RdpdrServerContext* context, - Stream_Read_UINT32(s, CreateOptions); - Stream_Read_UINT32(s, PathLength); - -- path = rdpdr_read_ustring(context->priv->log, s, PathLength); -+ path = rdpdr_read_ustring(priv->log, s, PathLength); - if (!path && (PathLength > 0)) - return ERROR_INVALID_DATA; - -- WLog_Print(context->priv->log, WLOG_WARN, -+ WLog_Print(priv->log, WLOG_WARN, - "[MS-RDPEFS] 2.2.1.4.1 Device Create Request (DR_CREATE_REQ) not implemented"); -- WLog_Print(context->priv->log, WLOG_WARN, "TODO"); -+ WLog_Print(priv->log, WLOG_WARN, "TODO"); - - return CHANNEL_RC_OK; - } -@@ -1331,14 +1347,16 @@ static UINT rdpdr_server_receive_io_close_request(RdpdrServerContext* context, w - WINPR_ASSERT(context); - WINPR_ASSERT(context->priv); - -- if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 32)) -+ RdpdrServerPrivate* priv = context->priv; -+ -+ if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 32)) - return ERROR_INVALID_DATA; - - Stream_Seek(s, 32); /* Padding */ - -- WLog_Print(context->priv->log, WLOG_WARN, -+ WLog_Print(priv->log, WLOG_WARN, - "[MS-RDPEFS] 2.2.1.4.2 Device Close Request (DR_CLOSE_REQ) not implemented"); -- WLog_Print(context->priv->log, WLOG_WARN, "TODO"); -+ WLog_Print(priv->log, WLOG_WARN, "TODO"); - - return CHANNEL_RC_OK; - } -@@ -1353,19 +1371,21 @@ static UINT rdpdr_server_receive_io_read_request(RdpdrServerContext* context, wS - - WINPR_ASSERT(context); - WINPR_ASSERT(context->priv); -- if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 32)) -+ -+ RdpdrServerPrivate* priv = context->priv; -+ if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 32)) - return ERROR_INVALID_DATA; - - Stream_Read_UINT32(s, Length); - Stream_Read_UINT64(s, Offset); - Stream_Seek(s, 20); /* Padding */ - -- WLog_Print(context->priv->log, WLOG_DEBUG, "Got Offset [0x%016" PRIx64 "], Length %" PRIu32, -- Offset, Length); -+ WLog_Print(priv->log, WLOG_DEBUG, "Got Offset [0x%016" PRIx64 "], Length %" PRIu32, Offset, -+ Length); - -- WLog_Print(context->priv->log, WLOG_WARN, -+ WLog_Print(priv->log, WLOG_WARN, - "[MS-RDPEFS] 2.2.1.4.3 Device Read Request (DR_READ_REQ) not implemented"); -- WLog_Print(context->priv->log, WLOG_WARN, "TODO"); -+ WLog_Print(priv->log, WLOG_WARN, "TODO"); - - return CHANNEL_RC_OK; - } -@@ -1381,24 +1401,26 @@ static UINT rdpdr_server_receive_io_write_request(RdpdrServerContext* context, w - WINPR_ASSERT(context); - WINPR_ASSERT(context->priv); - -- if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 32)) -+ RdpdrServerPrivate* priv = context->priv; -+ -+ if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 32)) - return ERROR_INVALID_DATA; - - Stream_Read_UINT32(s, Length); - Stream_Read_UINT64(s, Offset); - Stream_Seek(s, 20); /* Padding */ - -- WLog_Print(context->priv->log, WLOG_DEBUG, "Got Offset [0x%016" PRIx64 "], Length %" PRIu32, -- Offset, Length); -+ WLog_Print(priv->log, WLOG_DEBUG, "Got Offset [0x%016" PRIx64 "], Length %" PRIu32, Offset, -+ Length); - - const BYTE* data = Stream_ConstPointer(s); -- if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, Length)) -+ if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, Length)) - return ERROR_INVALID_DATA; - Stream_Seek(s, Length); - -- WLog_Print(context->priv->log, WLOG_WARN, -+ WLog_Print(priv->log, WLOG_WARN, - "[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", (const void*)data); -+ WLog_Print(priv->log, WLOG_WARN, "TODO: parse %p", (const void*)data); - - return CHANNEL_RC_OK; - } -@@ -1415,7 +1437,9 @@ static UINT rdpdr_server_receive_io_device_control_request(RdpdrServerContext* c - WINPR_ASSERT(context); - WINPR_ASSERT(context->priv); - -- if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 32)) -+ RdpdrServerPrivate* priv = context->priv; -+ -+ if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 32)) - return ERROR_INVALID_DATA; - - Stream_Read_UINT32(s, OutputBufferLength); -@@ -1424,14 +1448,13 @@ static UINT rdpdr_server_receive_io_device_control_request(RdpdrServerContext* c - Stream_Seek(s, 20); /* Padding */ - - const BYTE* InputBuffer = Stream_ConstPointer(s); -- if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, InputBufferLength)) -+ if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, InputBufferLength)) - return ERROR_INVALID_DATA; - Stream_Seek(s, InputBufferLength); - -- WLog_Print(context->priv->log, WLOG_WARN, -+ WLog_Print(priv->log, WLOG_WARN, - "[MS-RDPEFS] 2.2.1.4.5 Device Control Request (DR_CONTROL_REQ) not implemented"); -- WLog_Print(context->priv->log, WLOG_WARN, -- "TODO: parse %p [%" PRIu32 "], OutputBufferLength=%" PRIu32, -+ WLog_Print(priv->log, WLOG_WARN, "TODO: parse %p [%" PRIu32 "], OutputBufferLength=%" PRIu32, - (const void*)InputBuffer, InputBufferLength, OutputBufferLength); - - return CHANNEL_RC_OK; -@@ -1445,26 +1468,28 @@ static UINT rdpdr_server_receive_io_query_volume_information_request( - UINT32 Length = 0; - - WINPR_ASSERT(context); -- if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 32)) -+ -+ RdpdrServerPrivate* priv = context->priv; -+ if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 32)) - return ERROR_INVALID_DATA; - - Stream_Read_UINT32(s, FsInformationClass); - Stream_Read_UINT32(s, Length); - Stream_Seek(s, 24); /* Padding */ - -- WLog_Print(context->priv->log, WLOG_DEBUG, -+ WLog_Print(priv->log, WLOG_DEBUG, - "Got FSInformationClass %s [0x%08" PRIx32 "], Length %" PRIu32, - FSInformationClass2Tag(FsInformationClass), FsInformationClass, Length); - - const BYTE* QueryVolumeBuffer = Stream_ConstPointer(s); -- if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, Length)) -+ if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, Length)) - return ERROR_INVALID_DATA; - Stream_Seek(s, Length); - -- WLog_Print(context->priv->log, WLOG_WARN, -+ WLog_Print(priv->log, WLOG_WARN, - "[MS-RDPEFS] 2.2.3.3.6 Server Drive Query Volume Information Request " - "(DR_DRIVE_QUERY_VOLUME_INFORMATION_REQ) not implemented"); -- WLog_Print(context->priv->log, WLOG_WARN, "TODO: parse %p", (const void*)QueryVolumeBuffer); -+ WLog_Print(priv->log, WLOG_WARN, "TODO: parse %p", (const void*)QueryVolumeBuffer); - - return CHANNEL_RC_OK; - } -@@ -1479,26 +1504,28 @@ static UINT rdpdr_server_receive_io_set_volume_information_request( - WINPR_ASSERT(context); - WINPR_ASSERT(context->priv); - -- if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 32)) -+ RdpdrServerPrivate* priv = context->priv; -+ -+ if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 32)) - return ERROR_INVALID_DATA; - - Stream_Read_UINT32(s, FsInformationClass); - Stream_Read_UINT32(s, Length); - Stream_Seek(s, 24); /* Padding */ - -- WLog_Print(context->priv->log, WLOG_DEBUG, -+ WLog_Print(priv->log, WLOG_DEBUG, - "Got FSInformationClass %s [0x%08" PRIx32 "], Length %" PRIu32, - FSInformationClass2Tag(FsInformationClass), FsInformationClass, Length); - - const BYTE* SetVolumeBuffer = Stream_ConstPointer(s); -- if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, Length)) -+ if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, Length)) - return ERROR_INVALID_DATA; - Stream_Seek(s, Length); - -- WLog_Print(context->priv->log, WLOG_WARN, -+ WLog_Print(priv->log, WLOG_WARN, - "[MS-RDPEFS] 2.2.3.3.7 Server Drive Set Volume Information Request " - "(DR_DRIVE_SET_VOLUME_INFORMATION_REQ) not implemented"); -- WLog_Print(context->priv->log, WLOG_WARN, "TODO: parse %p", (const void*)SetVolumeBuffer); -+ WLog_Print(priv->log, WLOG_WARN, "TODO: parse %p", (const void*)SetVolumeBuffer); - - return CHANNEL_RC_OK; - } -@@ -1515,26 +1542,28 @@ static UINT rdpdr_server_receive_io_query_information_request(RdpdrServerContext - WINPR_ASSERT(context); - WINPR_ASSERT(context->priv); - -- if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 32)) -+ RdpdrServerPrivate* priv = context->priv; -+ -+ if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 32)) - return ERROR_INVALID_DATA; - - Stream_Read_UINT32(s, FsInformationClass); - Stream_Read_UINT32(s, Length); - Stream_Seek(s, 24); /* Padding */ - -- WLog_Print(context->priv->log, WLOG_DEBUG, -+ WLog_Print(priv->log, WLOG_DEBUG, - "Got FSInformationClass %s [0x%08" PRIx32 "], Length %" PRIu32, - FSInformationClass2Tag(FsInformationClass), FsInformationClass, Length); - - const BYTE* QueryBuffer = Stream_ConstPointer(s); -- if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, Length)) -+ if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, Length)) - return ERROR_INVALID_DATA; - Stream_Seek(s, Length); - -- WLog_Print(context->priv->log, WLOG_WARN, -+ WLog_Print(priv->log, WLOG_WARN, - "[MS-RDPEFS] 2.2.3.3.8 Server Drive Query Information Request " - "(DR_DRIVE_QUERY_INFORMATION_REQ) not implemented"); -- WLog_Print(context->priv->log, WLOG_WARN, "TODO: parse %p", (const void*)QueryBuffer); -+ WLog_Print(priv->log, WLOG_WARN, "TODO: parse %p", (const void*)QueryBuffer); - - return CHANNEL_RC_OK; - } -@@ -1550,26 +1579,28 @@ static UINT rdpdr_server_receive_io_set_information_request(RdpdrServerContext* - WINPR_ASSERT(context); - WINPR_ASSERT(context->priv); - -- if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 32)) -+ RdpdrServerPrivate* priv = context->priv; -+ -+ if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 32)) - return ERROR_INVALID_DATA; - - Stream_Read_UINT32(s, FsInformationClass); - Stream_Read_UINT32(s, Length); - Stream_Seek(s, 24); /* Padding */ - -- WLog_Print(context->priv->log, WLOG_DEBUG, -+ WLog_Print(priv->log, WLOG_DEBUG, - "Got FSInformationClass %s [0x%08" PRIx32 "], Length %" PRIu32, - FSInformationClass2Tag(FsInformationClass), FsInformationClass, Length); - - const BYTE* SetBuffer = Stream_ConstPointer(s); -- if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, Length)) -+ if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, Length)) - return ERROR_INVALID_DATA; - Stream_Seek(s, Length); - -- WLog_Print(context->priv->log, WLOG_WARN, -+ WLog_Print(priv->log, WLOG_WARN, - "[MS-RDPEFS] 2.2.3.3.9 Server Drive Set Information Request " - "(DR_DRIVE_SET_INFORMATION_REQ) not implemented"); -- WLog_Print(context->priv->log, WLOG_WARN, "TODO: parse %p", (const void*)SetBuffer); -+ WLog_Print(priv->log, WLOG_WARN, "TODO: parse %p", (const void*)SetBuffer); - - return CHANNEL_RC_OK; - } -@@ -1586,7 +1617,9 @@ static UINT rdpdr_server_receive_io_query_directory_request(RdpdrServerContext* - WINPR_ASSERT(context); - WINPR_ASSERT(context->priv); - -- if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 32)) -+ RdpdrServerPrivate* priv = context->priv; -+ -+ if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 32)) - return ERROR_INVALID_DATA; - - Stream_Read_UINT32(s, FsInformationClass); -@@ -1594,22 +1627,22 @@ static UINT rdpdr_server_receive_io_query_directory_request(RdpdrServerContext* - Stream_Read_UINT32(s, PathLength); - Stream_Seek(s, 23); /* Padding */ - -- const WCHAR* wPath = rdpdr_read_ustring(context->priv->log, s, PathLength); -+ const WCHAR* wPath = rdpdr_read_ustring(priv->log, s, PathLength); - if (!wPath && (PathLength > 0)) - return ERROR_INVALID_DATA; - - char* Path = ConvertWCharNToUtf8Alloc(wPath, PathLength / sizeof(WCHAR), nullptr); -- WLog_Print(context->priv->log, WLOG_DEBUG, -+ WLog_Print(priv->log, WLOG_DEBUG, - "Got FSInformationClass %s [0x%08" PRIx32 "], InitialQuery [%" PRIu8 - "] Path[%" PRIu32 "] %s", - FSInformationClass2Tag(FsInformationClass), FsInformationClass, InitialQuery, - PathLength, Path); - free(Path); - -- WLog_Print(context->priv->log, WLOG_WARN, -+ WLog_Print(priv->log, WLOG_WARN, - "[MS-RDPEFS] 2.2.3.3.10 Server Drive Query Directory Request " - "(DR_DRIVE_QUERY_DIRECTORY_REQ) not implemented"); -- WLog_Print(context->priv->log, WLOG_WARN, "TODO"); -+ WLog_Print(priv->log, WLOG_WARN, "TODO"); - - return CHANNEL_RC_OK; - } -@@ -1626,17 +1659,19 @@ static UINT rdpdr_server_receive_io_change_directory_request(RdpdrServerContext* - WINPR_ASSERT(context); - WINPR_ASSERT(context->priv); - -- if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 32)) -+ RdpdrServerPrivate* priv = context->priv; -+ -+ if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 32)) - return ERROR_INVALID_DATA; - - Stream_Read_UINT8(s, WatchTree); - Stream_Read_UINT32(s, CompletionFilter); - Stream_Seek(s, 27); /* Padding */ - -- WLog_Print(context->priv->log, WLOG_WARN, -+ WLog_Print(priv->log, WLOG_WARN, - "[MS-RDPEFS] 2.2.3.3.11 Server Drive NotifyChange Directory Request " - "(DR_DRIVE_NOTIFY_CHANGE_DIRECTORY_REQ) not implemented"); -- WLog_Print(context->priv->log, WLOG_WARN, "TODO"); -+ WLog_Print(priv->log, WLOG_WARN, "TODO"); - - return CHANNEL_RC_OK; - } -@@ -1649,6 +1684,7 @@ static UINT rdpdr_server_receive_io_directory_control_request(RdpdrServerContext - WINPR_ASSERT(context); - WINPR_ASSERT(context->priv); - -+ RdpdrServerPrivate* priv = context->priv; - switch (MinorFunction) - { - case IRP_MN_QUERY_DIRECTORY: -@@ -1658,7 +1694,7 @@ static UINT rdpdr_server_receive_io_directory_control_request(RdpdrServerContext - return rdpdr_server_receive_io_change_directory_request(context, s, DeviceId, FileId, - CompletionId); - default: -- WLog_Print(context->priv->log, WLOG_WARN, -+ WLog_Print(priv->log, WLOG_WARN, - "[MS-RDPEFS] 2.2.1.4 Device I/O Request (DR_DEVICE_IOREQUEST) " - "MajorFunction=%s, MinorFunction=%08" PRIx32 " is not supported", - rdpdr_irp_string(IRP_MJ_DIRECTORY_CONTROL), MinorFunction); -@@ -1674,7 +1710,9 @@ static UINT rdpdr_server_receive_io_lock_control_request(RdpdrServerContext* con - WINPR_ASSERT(context); - WINPR_ASSERT(context->priv); - -- if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 32)) -+ RdpdrServerPrivate* priv = context->priv; -+ -+ if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 32)) - return ERROR_INVALID_DATA; - - const uint32_t Operation = Stream_Get_UINT32(s); -@@ -1682,7 +1720,7 @@ static UINT rdpdr_server_receive_io_lock_control_request(RdpdrServerContext* con - const uint32_t NumLocks = Stream_Get_UINT32(s); - Stream_Seek(s, 20); /* Padding */ - -- WLog_Print(context->priv->log, WLOG_DEBUG, -+ WLog_Print(priv->log, WLOG_DEBUG, - "IRP_MJ_LOCK_CONTROL, Operation=%s, Lock=0x%08" PRIx32 ", NumLocks=%" PRIu32, - DR_DRIVE_LOCK_REQ2str(Operation), Lock, NumLocks); - -@@ -1693,22 +1731,22 @@ static UINT rdpdr_server_receive_io_lock_control_request(RdpdrServerContext* con - UINT64 Length = 0; - UINT64 Offset = 0; - -- if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 16)) -+ if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 16)) - return ERROR_INVALID_DATA; - - Stream_Read_UINT64(s, Length); - Stream_Read_UINT64(s, Offset); - -- WLog_Print(context->priv->log, WLOG_DEBUG, -- "Locking at Offset=0x%08" PRIx64 " [Length %" PRIu64 "]", Offset, Length); -+ WLog_Print(priv->log, WLOG_DEBUG, "Locking at Offset=0x%08" PRIx64 " [Length %" PRIu64 "]", -+ Offset, Length); - } - -- WLog_Print(context->priv->log, WLOG_WARN, -+ WLog_Print(priv->log, WLOG_WARN, - "[MS-RDPEFS] 2.2.3.3.12 Server Drive Lock Control Request (DR_DRIVE_LOCK_REQ) " - "[Lock=0x%08" PRIx32 "]" - "not implemented", - Lock); -- WLog_Print(context->priv->log, WLOG_WARN, "TODO"); -+ WLog_Print(priv->log, WLOG_WARN, "TODO"); - - return CHANNEL_RC_OK; - } -@@ -1726,7 +1764,9 @@ static UINT rdpdr_server_receive_device_io_request(RdpdrServerContext* context, - WINPR_ASSERT(context->priv); - WINPR_ASSERT(header); - -- if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 20)) -+ RdpdrServerPrivate* priv = context->priv; -+ -+ if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 20)) - return ERROR_INVALID_DATA; - - Stream_Read_UINT32(s, DeviceId); -@@ -1735,7 +1775,7 @@ static UINT rdpdr_server_receive_device_io_request(RdpdrServerContext* context, - Stream_Read_UINT32(s, MajorFunction); - Stream_Read_UINT32(s, MinorFunction); - if ((MinorFunction != 0) && (MajorFunction != IRP_MJ_DIRECTORY_CONTROL)) -- WLog_Print(context->priv->log, WLOG_WARN, -+ WLog_Print(priv->log, WLOG_WARN, - "[MS-RDPEFS] 2.2.1.4 Device I/O Request (DR_DEVICE_IOREQUEST) MajorFunction=%s, " - "MinorFunction=0x%08" PRIx32 " != 0", - rdpdr_irp_string(MajorFunction), MinorFunction); -@@ -1777,9 +1817,9 @@ static UINT rdpdr_server_receive_device_io_request(RdpdrServerContext* context, - - default: - WLog_Print( -- context->priv->log, WLOG_WARN, -+ priv->log, WLOG_WARN, - "[MS-RDPEFS] 2.2.1.4 Device I/O Request (DR_DEVICE_IOREQUEST) not implemented"); -- WLog_Print(context->priv->log, WLOG_WARN, -+ WLog_Print(priv->log, WLOG_WARN, - "got DeviceId=0x%08" PRIx32 ", FileId=0x%08" PRIx32 - ", CompletionId=0x%08" PRIx32 ", MajorFunction=0x%08" PRIx32 - ", MinorFunction=0x%08" PRIx32, -@@ -1806,22 +1846,24 @@ static UINT rdpdr_server_receive_device_io_completion(RdpdrServerContext* contex - WINPR_ASSERT(s); - WINPR_ASSERT(header); - -+ RdpdrServerPrivate* priv = context->priv; -+ - WINPR_UNUSED(header); - -- if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 12)) -+ if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 12)) - return ERROR_INVALID_DATA; - - Stream_Read_UINT32(s, deviceId); - Stream_Read_UINT32(s, completionId); - Stream_Read_UINT32(s, ioStatus); -- WLog_Print(context->priv->log, WLOG_DEBUG, -+ WLog_Print(priv->log, WLOG_DEBUG, - "deviceId=%" PRIu32 ", completionId=0x%" PRIx32 ", ioStatus=0x%" PRIx32 "", deviceId, - completionId, ioStatus); - irp = rdpdr_server_dequeue_irp(context, completionId); - - if (!irp) - { -- WLog_Print(context->priv->log, WLOG_ERROR, "IRP not found for completionId=0x%" PRIx32 "", -+ WLog_Print(priv->log, WLOG_ERROR, "IRP not found for completionId=0x%" PRIx32 "", - completionId); - return CHANNEL_RC_OK; - } -@@ -1850,11 +1892,13 @@ static UINT rdpdr_server_send_user_logged_on(RdpdrServerContext* context) - - header.Component = RDPDR_CTYP_CORE; - header.PacketId = PAKID_CORE_USER_LOGGEDON; -+ -+ RdpdrServerPrivate* priv = context->priv; - s = Stream_New(nullptr, RDPDR_HEADER_LENGTH); - - if (!s) - { -- WLog_Print(context->priv->log, WLOG_ERROR, "Stream_New failed!"); -+ WLog_Print(priv->log, WLOG_ERROR, "Stream_New failed!"); - return CHANNEL_RC_NO_MEMORY; - } - -@@ -1877,7 +1921,9 @@ static UINT rdpdr_server_receive_prn_cache_add_printer(RdpdrServerContext* conte - WINPR_ASSERT(context); - WINPR_ASSERT(context->priv); - -- if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 24)) -+ RdpdrServerPrivate* priv = context->priv; -+ -+ if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 24)) - return ERROR_INVALID_DATA; - - Stream_Read(s, PortDosName, 8); -@@ -1886,23 +1932,23 @@ static UINT rdpdr_server_receive_prn_cache_add_printer(RdpdrServerContext* conte - Stream_Read_UINT32(s, PrinterNameLen); - Stream_Read_UINT32(s, CachedFieldsLen); - -- PnPName = rdpdr_read_ustring(context->priv->log, s, PnPNameLen); -+ PnPName = rdpdr_read_ustring(priv->log, s, PnPNameLen); - if (!PnPName && (PnPNameLen > 0)) - return ERROR_INVALID_DATA; -- DriverName = rdpdr_read_ustring(context->priv->log, s, DriverNameLen); -+ DriverName = rdpdr_read_ustring(priv->log, s, DriverNameLen); - if (!DriverName && (DriverNameLen > 0)) - return ERROR_INVALID_DATA; -- PrinterName = rdpdr_read_ustring(context->priv->log, s, PrinterNameLen); -+ PrinterName = rdpdr_read_ustring(priv->log, s, PrinterNameLen); - if (!PrinterName && (PrinterNameLen > 0)) - return ERROR_INVALID_DATA; - -- if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, CachedFieldsLen)) -+ if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, CachedFieldsLen)) - return ERROR_INVALID_DATA; - Stream_Seek(s, CachedFieldsLen); - -- WLog_Print(context->priv->log, WLOG_WARN, -+ WLog_Print(priv->log, WLOG_WARN, - "[MS-RDPEPC] 2.2.2.3 Add Printer Cachedata (DR_PRN_ADD_CACHEDATA) not implemented"); -- WLog_Print(context->priv->log, WLOG_WARN, "TODO"); -+ WLog_Print(priv->log, WLOG_WARN, "TODO"); - return CHANNEL_RC_OK; - } - -@@ -1914,25 +1960,27 @@ static UINT rdpdr_server_receive_prn_cache_update_printer(RdpdrServerContext* co - - WINPR_ASSERT(context); - -- if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 8)) -+ RdpdrServerPrivate* priv = context->priv; -+ -+ if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 8)) - return ERROR_INVALID_DATA; - - Stream_Read_UINT32(s, PrinterNameLen); - Stream_Read_UINT32(s, CachedFieldsLen); - -- PrinterName = rdpdr_read_ustring(context->priv->log, s, PrinterNameLen); -+ PrinterName = rdpdr_read_ustring(priv->log, s, PrinterNameLen); - if (!PrinterName && (PrinterNameLen > 0)) - return ERROR_INVALID_DATA; - - const BYTE* config = Stream_ConstPointer(s); -- if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, CachedFieldsLen)) -+ if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, CachedFieldsLen)) - return ERROR_INVALID_DATA; - Stream_Seek(s, CachedFieldsLen); - - WLog_Print( -- context->priv->log, WLOG_WARN, -+ priv->log, WLOG_WARN, - "[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", (const void*)config); -+ WLog_Print(priv->log, WLOG_WARN, "TODO: parse %p", (const void*)config); - return CHANNEL_RC_OK; - } - -@@ -1944,19 +1992,21 @@ static UINT rdpdr_server_receive_prn_cache_delete_printer(RdpdrServerContext* co - WINPR_ASSERT(context); - WINPR_ASSERT(context->priv); - -- if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 4)) -+ RdpdrServerPrivate* priv = context->priv; -+ -+ if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 4)) - return ERROR_INVALID_DATA; - - Stream_Read_UINT32(s, PrinterNameLen); - -- PrinterName = rdpdr_read_ustring(context->priv->log, s, PrinterNameLen); -+ PrinterName = rdpdr_read_ustring(priv->log, s, PrinterNameLen); - if (!PrinterName && (PrinterNameLen > 0)) - return ERROR_INVALID_DATA; - - WLog_Print( -- context->priv->log, WLOG_WARN, -+ priv->log, WLOG_WARN, - "[MS-RDPEPC] 2.2.2.5 Delete Printer Cachedata (DR_PRN_DELETE_CACHEDATA) not implemented"); -- WLog_Print(context->priv->log, WLOG_WARN, "TODO"); -+ WLog_Print(priv->log, WLOG_WARN, "TODO"); - return CHANNEL_RC_OK; - } - -@@ -1970,23 +2020,25 @@ static UINT rdpdr_server_receive_prn_cache_rename_cachedata(RdpdrServerContext* - WINPR_ASSERT(context); - WINPR_ASSERT(context->priv); - -- if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 8)) -+ RdpdrServerPrivate* priv = context->priv; -+ -+ if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 8)) - return ERROR_INVALID_DATA; - - Stream_Read_UINT32(s, OldPrinterNameLen); - Stream_Read_UINT32(s, NewPrinterNameLen); - -- OldPrinterName = rdpdr_read_ustring(context->priv->log, s, OldPrinterNameLen); -+ OldPrinterName = rdpdr_read_ustring(priv->log, s, OldPrinterNameLen); - if (!OldPrinterName && (OldPrinterNameLen > 0)) - return ERROR_INVALID_DATA; -- NewPrinterName = rdpdr_read_ustring(context->priv->log, s, NewPrinterNameLen); -+ NewPrinterName = rdpdr_read_ustring(priv->log, s, NewPrinterNameLen); - if (!NewPrinterName && (NewPrinterNameLen > 0)) - return ERROR_INVALID_DATA; - - WLog_Print( -- context->priv->log, WLOG_WARN, -+ priv->log, WLOG_WARN, - "[MS-RDPEPC] 2.2.2.6 Rename Printer Cachedata (DR_PRN_RENAME_CACHEDATA) not implemented"); -- WLog_Print(context->priv->log, WLOG_WARN, "TODO"); -+ WLog_Print(priv->log, WLOG_WARN, "TODO"); - return CHANNEL_RC_OK; - } - -@@ -2000,7 +2052,8 @@ rdpdr_server_receive_prn_cache_data_request(RdpdrServerContext* context, wStream - WINPR_ASSERT(context->priv); - WINPR_ASSERT(header); - -- if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 4)) -+ RdpdrServerPrivate* priv = context->priv; -+ if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 4)) - return ERROR_INVALID_DATA; - - Stream_Read_UINT32(s, EventId); -@@ -2015,7 +2068,7 @@ rdpdr_server_receive_prn_cache_data_request(RdpdrServerContext* context, wStream - case RDPDR_RENAME_PRINTER_EVENT: - return rdpdr_server_receive_prn_cache_rename_cachedata(context, s); - default: -- WLog_Print(context->priv->log, WLOG_WARN, -+ WLog_Print(priv->log, WLOG_WARN, - "[MS-RDPEPC] PAKID_PRN_CACHE_DATA unknown EventId=0x%08" PRIx32, EventId); - return ERROR_INVALID_DATA; - } -@@ -2031,17 +2084,19 @@ static UINT rdpdr_server_receive_prn_using_xps_request(RdpdrServerContext* conte - WINPR_ASSERT(context->priv); - WINPR_ASSERT(header); - -- if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 8)) -+ RdpdrServerPrivate* priv = context->priv; -+ -+ if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 8)) - return ERROR_INVALID_DATA; - - Stream_Read_UINT32(s, PrinterId); - Stream_Read_UINT32(s, Flags); - - WLog_Print( -- context->priv->log, WLOG_WARN, -+ priv->log, WLOG_WARN, - "[MS-RDPEPC] 2.2.2.2 Server Printer Set XPS Mode (DR_PRN_USING_XPS) not implemented"); -- WLog_Print(context->priv->log, WLOG_WARN, "PrinterId=0x%08" PRIx32 ", Flags=0x%08" PRIx32, -- PrinterId, Flags); -+ WLog_Print(priv->log, WLOG_WARN, "PrinterId=0x%08" PRIx32 ", Flags=0x%08" PRIx32, PrinterId, -+ Flags); - return CHANNEL_RC_OK; - } - -@@ -2059,7 +2114,8 @@ static UINT rdpdr_server_receive_pdu(RdpdrServerContext* context, wStream* s, - WINPR_ASSERT(s); - WINPR_ASSERT(header); - -- WLog_Print(context->priv->log, WLOG_DEBUG, -+ RdpdrServerPrivate* priv = context->priv; -+ WLog_Print(priv->log, WLOG_DEBUG, - "receiving message {Component %s[%04" PRIx16 "], PacketId %s[%04" PRIx16 "]", - rdpdr_component_string(header->Component), header->Component, - rdpdr_packetid_string(header->PacketId), header->PacketId); -@@ -2069,7 +2125,7 @@ static UINT rdpdr_server_receive_pdu(RdpdrServerContext* context, wStream* s, - switch (header->PacketId) - { - case PAKID_CORE_SERVER_ANNOUNCE: -- WLog_Print(context->priv->log, WLOG_ERROR, -+ WLog_Print(priv->log, WLOG_ERROR, - "[MS-RDPEFS] 2.2.2.2 Server Announce Request " - "(DR_CORE_SERVER_ANNOUNCE_REQ) must not be sent by a client!"); - break; -@@ -2087,13 +2143,13 @@ static UINT rdpdr_server_receive_pdu(RdpdrServerContext* context, wStream* s, - break; - - case PAKID_CORE_USER_LOGGEDON: -- WLog_Print(context->priv->log, WLOG_ERROR, -+ WLog_Print(priv->log, WLOG_ERROR, - "[MS-RDPEFS] 2.2.2.5 Server User Logged On (DR_CORE_USER_LOGGEDON) " - "must not be sent by a client!"); - break; - - case PAKID_CORE_SERVER_CAPABILITY: -- WLog_Print(context->priv->log, WLOG_ERROR, -+ WLog_Print(priv->log, WLOG_ERROR, - "[MS-RDPEFS] 2.2.2.7 Server Core Capability Request " - "(DR_CORE_CAPABILITY_REQ) must not be sent by a client!"); - break; -@@ -2102,7 +2158,7 @@ static UINT rdpdr_server_receive_pdu(RdpdrServerContext* context, wStream* s, - error = rdpdr_server_receive_core_capability_response(context, s, header); - if (error == CHANNEL_RC_OK) - { -- if (context->priv->UserLoggedOnPdu) -+ if (priv->UserLoggedOnPdu) - error = rdpdr_server_send_user_logged_on(context); - } - -@@ -2117,7 +2173,7 @@ static UINT rdpdr_server_receive_pdu(RdpdrServerContext* context, wStream* s, - break; - - case PAKID_CORE_DEVICE_REPLY: -- WLog_Print(context->priv->log, WLOG_ERROR, -+ WLog_Print(priv->log, WLOG_ERROR, - "[MS-RDPEFS] 2.2.2.1 Server Device Announce Response " - "(DR_CORE_DEVICE_ANNOUNCE_RSP) must not be sent by a client!"); - break; -@@ -2131,7 +2187,7 @@ static UINT rdpdr_server_receive_pdu(RdpdrServerContext* context, wStream* s, - break; - - default: -- WLog_Print(context->priv->log, WLOG_WARN, -+ WLog_Print(priv->log, WLOG_WARN, - "Unknown RDPDR_HEADER.Component: %s [0x%04" PRIx16 "], PacketId: %s", - rdpdr_component_string(header->Component), header->Component, - rdpdr_packetid_string(header->PacketId)); -@@ -2151,7 +2207,7 @@ static UINT rdpdr_server_receive_pdu(RdpdrServerContext* context, wStream* s, - break; - - default: -- WLog_Print(context->priv->log, WLOG_WARN, -+ WLog_Print(priv->log, WLOG_WARN, - "Unknown RDPDR_HEADER.Component: %s [0x%04" PRIx16 "], PacketId: %s", - rdpdr_component_string(header->Component), header->Component, - rdpdr_packetid_string(header->PacketId)); -@@ -2160,7 +2216,7 @@ static UINT rdpdr_server_receive_pdu(RdpdrServerContext* context, wStream* s, - } - else - { -- WLog_Print(context->priv->log, WLOG_WARN, -+ WLog_Print(priv->log, WLOG_WARN, - "Unknown RDPDR_HEADER.Component: %s [0x%04" PRIx16 "], PacketId: %s", - rdpdr_component_string(header->Component), header->Component, - rdpdr_packetid_string(header->PacketId)); -@@ -2184,14 +2240,16 @@ static DWORD WINAPI rdpdr_server_thread(LPVOID arg) - WINPR_ASSERT(context); - WINPR_ASSERT(context->priv); - -+ RdpdrServerPrivate* priv = context->priv; -+ - if (!s) - { -- WLog_Print(context->priv->log, WLOG_ERROR, "Stream_New failed!"); -+ WLog_Print(priv->log, WLOG_ERROR, "Stream_New failed!"); - error = CHANNEL_RC_NO_MEMORY; - goto out; - } - -- if (WTSVirtualChannelQuery(context->priv->ChannelHandle, WTSVirtualEventHandle, &buffer, -+ if (WTSVirtualChannelQuery(priv->ChannelHandle, WTSVirtualEventHandle, &buffer, - &BytesReturned) == TRUE) - { - if (BytesReturned == sizeof(HANDLE)) -@@ -2202,11 +2260,11 @@ static DWORD WINAPI rdpdr_server_thread(LPVOID arg) - - nCount = 0; - events[nCount++] = ChannelEvent; -- events[nCount++] = context->priv->StopEvent; -+ events[nCount++] = priv->StopEvent; - - if ((error = rdpdr_server_send_announce_request(context))) - { -- WLog_Print(context->priv->log, WLOG_ERROR, -+ WLog_Print(priv->log, WLOG_ERROR, - "rdpdr_server_send_announce_request failed with error %" PRIu32 "!", error); - goto out_stream; - } -@@ -2220,42 +2278,42 @@ static DWORD WINAPI rdpdr_server_thread(LPVOID arg) - if (status == WAIT_FAILED) - { - error = GetLastError(); -- WLog_Print(context->priv->log, WLOG_ERROR, -+ WLog_Print(priv->log, WLOG_ERROR, - "WaitForMultipleObjects failed with error %" PRIu32 "!", error); - goto out_stream; - } - -- status = WaitForSingleObject(context->priv->StopEvent, 0); -+ status = WaitForSingleObject(priv->StopEvent, 0); - - if (status == WAIT_FAILED) - { - error = GetLastError(); -- WLog_Print(context->priv->log, WLOG_ERROR, -- "WaitForSingleObject failed with error %" PRIu32 "!", error); -+ WLog_Print(priv->log, WLOG_ERROR, "WaitForSingleObject failed with error %" PRIu32 "!", -+ error); - goto out_stream; - } - - if (status == WAIT_OBJECT_0) - break; - -- if (!WTSVirtualChannelRead(context->priv->ChannelHandle, 0, nullptr, 0, &BytesReturned)) -+ if (!WTSVirtualChannelRead(priv->ChannelHandle, 0, nullptr, 0, &BytesReturned)) - { -- WLog_Print(context->priv->log, WLOG_ERROR, "WTSVirtualChannelRead failed!"); -+ WLog_Print(priv->log, WLOG_ERROR, "WTSVirtualChannelRead failed!"); - error = ERROR_INTERNAL_ERROR; - break; - } - if (!Stream_EnsureRemainingCapacity(s, BytesReturned)) - { -- WLog_Print(context->priv->log, WLOG_ERROR, "Stream_EnsureRemainingCapacity failed!"); -+ WLog_Print(priv->log, WLOG_ERROR, "Stream_EnsureRemainingCapacity failed!"); - error = ERROR_INTERNAL_ERROR; - break; - } - - capacity = MIN(Stream_Capacity(s), UINT32_MAX); -- if (!WTSVirtualChannelRead(context->priv->ChannelHandle, 0, Stream_BufferAs(s, char), -+ if (!WTSVirtualChannelRead(priv->ChannelHandle, 0, Stream_BufferAs(s, char), - (ULONG)capacity, &BytesReturned)) - { -- WLog_Print(context->priv->log, WLOG_ERROR, "WTSVirtualChannelRead failed!"); -+ WLog_Print(priv->log, WLOG_ERROR, "WTSVirtualChannelRead failed!"); - error = ERROR_INTERNAL_ERROR; - break; - } -@@ -2278,7 +2336,7 @@ static DWORD WINAPI rdpdr_server_thread(LPVOID arg) - - if ((error = rdpdr_server_receive_pdu(context, s, &header))) - { -- WLog_Print(context->priv->log, WLOG_ERROR, -+ WLog_Print(priv->log, WLOG_ERROR, - "rdpdr_server_receive_pdu failed with error %" PRIu32 "!", error); - goto out_stream; - } -@@ -2306,27 +2364,28 @@ static UINT rdpdr_server_start(RdpdrServerContext* context) - { - WINPR_ASSERT(context); - WINPR_ASSERT(context->priv); -- context->priv->ChannelHandle = -+ -+ RdpdrServerPrivate* priv = context->priv; -+ priv->ChannelHandle = - WTSVirtualChannelOpen(context->vcm, WTS_CURRENT_SESSION, RDPDR_SVC_CHANNEL_NAME); - -- if (!context->priv->ChannelHandle) -+ if (!priv->ChannelHandle) - { -- WLog_Print(context->priv->log, WLOG_ERROR, "WTSVirtualChannelOpen failed!"); -+ WLog_Print(priv->log, WLOG_ERROR, "WTSVirtualChannelOpen failed!"); - return CHANNEL_RC_BAD_CHANNEL; - } - -- if (!(context->priv->StopEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr))) -+ if (!(priv->StopEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr))) - { -- WLog_Print(context->priv->log, WLOG_ERROR, "CreateEvent failed!"); -+ WLog_Print(priv->log, WLOG_ERROR, "CreateEvent failed!"); - return ERROR_INTERNAL_ERROR; - } - -- if (!(context->priv->Thread = -- CreateThread(nullptr, 0, rdpdr_server_thread, (void*)context, 0, nullptr))) -+ if (!(priv->Thread = CreateThread(nullptr, 0, rdpdr_server_thread, (void*)context, 0, nullptr))) - { -- WLog_Print(context->priv->log, WLOG_ERROR, "CreateThread failed!"); -- (void)CloseHandle(context->priv->StopEvent); -- context->priv->StopEvent = nullptr; -+ WLog_Print(priv->log, WLOG_ERROR, "CreateThread failed!"); -+ (void)CloseHandle(priv->StopEvent); -+ priv->StopEvent = nullptr; - return ERROR_INTERNAL_ERROR; - } - -@@ -2344,28 +2403,30 @@ static UINT rdpdr_server_stop(RdpdrServerContext* context) - WINPR_ASSERT(context); - WINPR_ASSERT(context->priv); - -- if (context->priv->StopEvent) -+ RdpdrServerPrivate* priv = context->priv; -+ -+ if (priv->StopEvent) - { -- (void)SetEvent(context->priv->StopEvent); -+ (void)SetEvent(priv->StopEvent); - -- if (WaitForSingleObject(context->priv->Thread, INFINITE) == WAIT_FAILED) -+ if (WaitForSingleObject(priv->Thread, INFINITE) == WAIT_FAILED) - { - error = GetLastError(); -- WLog_Print(context->priv->log, WLOG_ERROR, -- "WaitForSingleObject failed with error %" PRIu32 "!", error); -+ WLog_Print(priv->log, WLOG_ERROR, "WaitForSingleObject failed with error %" PRIu32 "!", -+ error); - return error; - } - -- (void)CloseHandle(context->priv->Thread); -- context->priv->Thread = nullptr; -- (void)CloseHandle(context->priv->StopEvent); -- context->priv->StopEvent = nullptr; -+ (void)CloseHandle(priv->Thread); -+ priv->Thread = nullptr; -+ (void)CloseHandle(priv->StopEvent); -+ priv->StopEvent = nullptr; - } - -- if (context->priv->ChannelHandle) -+ if (priv->ChannelHandle) - { -- (void)WTSVirtualChannelClose(context->priv->ChannelHandle); -- context->priv->ChannelHandle = nullptr; -+ (void)WTSVirtualChannelClose(priv->ChannelHandle); -+ priv->ChannelHandle = nullptr; - } - return CHANNEL_RC_OK; - } -@@ -2441,7 +2502,9 @@ static UINT rdpdr_server_send_device_create_request(RdpdrServerContext* context, - WINPR_ASSERT(context); - WINPR_ASSERT(context->priv); - -- WLog_Print(context->priv->log, WLOG_DEBUG, -+ RdpdrServerPrivate* priv = context->priv; -+ -+ WLog_Print(priv->log, WLOG_DEBUG, - "RdpdrServerSendDeviceCreateRequest: deviceId=%" PRIu32 - ", path=%s, desiredAccess=0x%" PRIx32 " createOptions=0x%" PRIx32 - " createDisposition=0x%" PRIx32 "", -@@ -2452,7 +2515,7 @@ static UINT rdpdr_server_send_device_create_request(RdpdrServerContext* context, - - if (!s) - { -- WLog_Print(context->priv->log, WLOG_ERROR, "Stream_New failed!"); -+ WLog_Print(priv->log, WLOG_ERROR, "Stream_New failed!"); - return CHANNEL_RC_NO_MEMORY; - } - -@@ -2488,14 +2551,16 @@ static UINT rdpdr_server_send_device_close_request(RdpdrServerContext* context, - WINPR_ASSERT(context); - WINPR_ASSERT(context->priv); - -- WLog_Print(context->priv->log, WLOG_DEBUG, -+ RdpdrServerPrivate* priv = context->priv; -+ -+ WLog_Print(priv->log, WLOG_DEBUG, - "RdpdrServerSendDeviceCloseRequest: deviceId=%" PRIu32 ", fileId=%" PRIu32 "", - deviceId, fileId); - s = Stream_New(nullptr, 128); - - if (!s) - { -- WLog_Print(context->priv->log, WLOG_ERROR, "Stream_New failed!"); -+ WLog_Print(priv->log, WLOG_ERROR, "Stream_New failed!"); - return CHANNEL_RC_NO_MEMORY; - } - -@@ -2517,7 +2582,9 @@ static UINT rdpdr_server_send_device_read_request(RdpdrServerContext* context, U - WINPR_ASSERT(context); - WINPR_ASSERT(context->priv); - -- WLog_Print(context->priv->log, WLOG_DEBUG, -+ RdpdrServerPrivate* priv = context->priv; -+ -+ WLog_Print(priv->log, WLOG_DEBUG, - "RdpdrServerSendDeviceReadRequest: deviceId=%" PRIu32 ", fileId=%" PRIu32 - ", length=%" PRIu32 ", offset=%" PRIu32 "", - deviceId, fileId, length, offset); -@@ -2525,7 +2592,7 @@ static UINT rdpdr_server_send_device_read_request(RdpdrServerContext* context, U - - if (!s) - { -- WLog_Print(context->priv->log, WLOG_ERROR, "Stream_New failed!"); -+ WLog_Print(priv->log, WLOG_ERROR, "Stream_New failed!"); - return CHANNEL_RC_NO_MEMORY; - } - -@@ -2550,7 +2617,9 @@ static UINT rdpdr_server_send_device_write_request(RdpdrServerContext* context, - WINPR_ASSERT(context); - WINPR_ASSERT(context->priv); - -- WLog_Print(context->priv->log, WLOG_DEBUG, -+ RdpdrServerPrivate* priv = context->priv; -+ -+ WLog_Print(priv->log, WLOG_DEBUG, - "RdpdrServerSendDeviceWriteRequest: deviceId=%" PRIu32 ", fileId=%" PRIu32 - ", length=%" PRIu32 ", offset=%" PRIu32 "", - deviceId, fileId, length, offset); -@@ -2558,7 +2627,7 @@ static UINT rdpdr_server_send_device_write_request(RdpdrServerContext* context, - - if (!s) - { -- WLog_Print(context->priv->log, WLOG_ERROR, "Stream_New failed!"); -+ WLog_Print(priv->log, WLOG_ERROR, "Stream_New failed!"); - return CHANNEL_RC_NO_MEMORY; - } - -@@ -2585,7 +2654,9 @@ static UINT rdpdr_server_send_device_query_directory_request(RdpdrServerContext* - WINPR_ASSERT(context); - WINPR_ASSERT(context->priv); - -- WLog_Print(context->priv->log, WLOG_DEBUG, -+ RdpdrServerPrivate* priv = context->priv; -+ -+ WLog_Print(priv->log, WLOG_DEBUG, - "RdpdrServerSendDeviceQueryDirectoryRequest: deviceId=%" PRIu32 ", fileId=%" PRIu32 - ", path=%s", - deviceId, fileId, path); -@@ -2595,7 +2666,7 @@ static UINT rdpdr_server_send_device_query_directory_request(RdpdrServerContext* - - if (!s) - { -- WLog_Print(context->priv->log, WLOG_ERROR, "Stream_New failed!"); -+ WLog_Print(priv->log, WLOG_ERROR, "Stream_New failed!"); - return CHANNEL_RC_NO_MEMORY; - } - -@@ -2635,7 +2706,9 @@ static UINT rdpdr_server_send_device_file_rename_request(RdpdrServerContext* con - WINPR_ASSERT(context); - WINPR_ASSERT(context->priv); - -- WLog_Print(context->priv->log, WLOG_DEBUG, -+ RdpdrServerPrivate* priv = context->priv; -+ -+ WLog_Print(priv->log, WLOG_DEBUG, - "RdpdrServerSendDeviceFileNameRequest: deviceId=%" PRIu32 ", fileId=%" PRIu32 - ", path=%s", - deviceId, fileId, path); -@@ -2645,7 +2718,7 @@ static UINT rdpdr_server_send_device_file_rename_request(RdpdrServerContext* con - - if (!s) - { -- WLog_Print(context->priv->log, WLOG_ERROR, "Stream_New failed!"); -+ WLog_Print(priv->log, WLOG_ERROR, "Stream_New failed!"); - return CHANNEL_RC_NO_MEMORY; - } - -@@ -2704,7 +2777,8 @@ static UINT rdpdr_server_drive_create_directory_callback2(RdpdrServerContext* co - WINPR_ASSERT(irp); - WINPR_UNUSED(s); - -- WLog_Print(context->priv->log, WLOG_DEBUG, -+ RdpdrServerPrivate* priv = context->priv; -+ WLog_Print(priv->log, WLOG_DEBUG, - "RdpdrServerDriveCreateDirectoryCallback2: deviceId=%" PRIu32 - ", completionId=%" PRIu32 ", ioStatus=0x%" PRIx32 "", - deviceId, completionId, ioStatus); -@@ -2728,7 +2802,9 @@ static UINT rdpdr_server_drive_create_directory_callback1(RdpdrServerContext* co - WINPR_ASSERT(context->priv); - WINPR_ASSERT(s); - WINPR_ASSERT(irp); -- WLog_Print(context->priv->log, WLOG_DEBUG, -+ -+ RdpdrServerPrivate* priv = context->priv; -+ WLog_Print(priv->log, WLOG_DEBUG, - "RdpdrServerDriveCreateDirectoryCallback1: deviceId=%" PRIu32 - ", completionId=%" PRIu32 ", ioStatus=0x%" PRIx32 "", - deviceId, completionId, ioStatus); -@@ -2742,23 +2818,23 @@ static UINT rdpdr_server_drive_create_directory_callback1(RdpdrServerContext* co - return CHANNEL_RC_OK; - } - -- if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 5)) -+ if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 5)) - return ERROR_INVALID_DATA; - - const uint32_t fileId = Stream_Get_UINT32(s); /* FileId (4 bytes) */ - const uint8_t information = Stream_Get_UINT8(s); /* Information (1 byte) */ -- WLog_Print(context->priv->log, WLOG_DEBUG, "fileId [0x%08" PRIx32 "], information %s", fileId, -+ WLog_Print(priv->log, WLOG_DEBUG, "fileId [0x%08" PRIx32 "], information %s", fileId, - fileInformation2str(information)); - - /* Setup the IRP. */ -- irp->CompletionId = context->priv->NextCompletionId++; -+ irp->CompletionId = priv->NextCompletionId++; - irp->Callback = rdpdr_server_drive_create_directory_callback2; - irp->DeviceId = deviceId; - irp->FileId = fileId; - - if (!rdpdr_server_enqueue_irp(context, irp)) - { -- WLog_Print(context->priv->log, WLOG_ERROR, "rdpdr_server_enqueue_irp failed!"); -+ WLog_Print(priv->log, WLOG_ERROR, "rdpdr_server_enqueue_irp failed!"); - rdpdr_server_irp_free(irp); - return ERROR_INTERNAL_ERROR; - } -@@ -2780,15 +2856,17 @@ static UINT rdpdr_server_drive_create_directory(RdpdrServerContext* context, voi - WINPR_ASSERT(context->priv); - WINPR_ASSERT(callbackData); - WINPR_ASSERT(path); -+ -+ RdpdrServerPrivate* priv = context->priv; - irp = rdpdr_server_irp_new(); - - if (!irp) - { -- WLog_Print(context->priv->log, WLOG_ERROR, "rdpdr_server_irp_new failed!"); -+ WLog_Print(priv->log, WLOG_ERROR, "rdpdr_server_irp_new failed!"); - return CHANNEL_RC_NO_MEMORY; - } - -- irp->CompletionId = context->priv->NextCompletionId++; -+ irp->CompletionId = priv->NextCompletionId++; - irp->Callback = rdpdr_server_drive_create_directory_callback1; - irp->CallbackData = callbackData; - irp->DeviceId = deviceId; -@@ -2797,7 +2875,7 @@ static UINT rdpdr_server_drive_create_directory(RdpdrServerContext* context, voi - - if (!rdpdr_server_enqueue_irp(context, irp)) - { -- WLog_Print(context->priv->log, WLOG_ERROR, "rdpdr_server_enqueue_irp failed!"); -+ WLog_Print(priv->log, WLOG_ERROR, "rdpdr_server_enqueue_irp failed!"); - rdpdr_server_irp_free(irp); - return ERROR_INTERNAL_ERROR; - } -@@ -2826,7 +2904,8 @@ static UINT rdpdr_server_drive_delete_directory_callback2(RdpdrServerContext* co - WINPR_ASSERT(context->priv); - WINPR_ASSERT(irp); - -- WLog_Print(context->priv->log, WLOG_DEBUG, -+ RdpdrServerPrivate* priv = context->priv; -+ WLog_Print(priv->log, WLOG_DEBUG, - "RdpdrServerDriveDeleteDirectoryCallback2: deviceId=%" PRIu32 - ", completionId=%" PRIu32 ", ioStatus=0x%" PRIx32 "", - deviceId, completionId, ioStatus); -@@ -2849,7 +2928,9 @@ static UINT rdpdr_server_drive_delete_directory_callback1(RdpdrServerContext* co - WINPR_ASSERT(context); - WINPR_ASSERT(context->priv); - WINPR_ASSERT(irp); -- WLog_Print(context->priv->log, WLOG_DEBUG, -+ -+ RdpdrServerPrivate* priv = context->priv; -+ WLog_Print(priv->log, WLOG_DEBUG, - "RdpdrServerDriveDeleteDirectoryCallback1: deviceId=%" PRIu32 - ", completionId=%" PRIu32 ", ioStatus=0x%" PRIx32 "", - deviceId, completionId, ioStatus); -@@ -2863,23 +2944,23 @@ static UINT rdpdr_server_drive_delete_directory_callback1(RdpdrServerContext* co - return CHANNEL_RC_OK; - } - -- if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 5)) -+ if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 5)) - return ERROR_INVALID_DATA; - - const uint32_t fileId = Stream_Get_UINT32(s); /* FileId (4 bytes) */ - const uint8_t information = Stream_Get_UINT8(s); /* Information (1 byte) */ -- WLog_Print(context->priv->log, WLOG_DEBUG, "fileId [0x%08" PRIx32 "], information %s", fileId, -+ WLog_Print(priv->log, WLOG_DEBUG, "fileId [0x%08" PRIx32 "], information %s", fileId, - fileInformation2str(information)); - - /* Setup the IRP. */ -- irp->CompletionId = context->priv->NextCompletionId++; -+ irp->CompletionId = priv->NextCompletionId++; - irp->Callback = rdpdr_server_drive_delete_directory_callback2; - irp->DeviceId = deviceId; - irp->FileId = fileId; - - if (!rdpdr_server_enqueue_irp(context, irp)) - { -- WLog_Print(context->priv->log, WLOG_ERROR, "rdpdr_server_enqueue_irp failed!"); -+ WLog_Print(priv->log, WLOG_ERROR, "rdpdr_server_enqueue_irp failed!"); - rdpdr_server_irp_free(irp); - return ERROR_INTERNAL_ERROR; - } -@@ -2901,13 +2982,15 @@ static UINT rdpdr_server_drive_delete_directory(RdpdrServerContext* context, voi - WINPR_ASSERT(context->priv); - WINPR_ASSERT(irp); - -+ RdpdrServerPrivate* priv = context->priv; -+ - if (!irp) - { -- WLog_Print(context->priv->log, WLOG_ERROR, "rdpdr_server_irp_new failed!"); -+ WLog_Print(priv->log, WLOG_ERROR, "rdpdr_server_irp_new failed!"); - return CHANNEL_RC_NO_MEMORY; - } - -- irp->CompletionId = context->priv->NextCompletionId++; -+ irp->CompletionId = priv->NextCompletionId++; - irp->Callback = rdpdr_server_drive_delete_directory_callback1; - irp->CallbackData = callbackData; - irp->DeviceId = deviceId; -@@ -2916,7 +2999,7 @@ static UINT rdpdr_server_drive_delete_directory(RdpdrServerContext* context, voi - - if (!rdpdr_server_enqueue_irp(context, irp)) - { -- WLog_Print(context->priv->log, WLOG_ERROR, "rdpdr_server_enqueue_irp failed!"); -+ WLog_Print(priv->log, WLOG_ERROR, "rdpdr_server_enqueue_irp failed!"); - rdpdr_server_irp_free(irp); - return ERROR_INTERNAL_ERROR; - } -@@ -2947,21 +3030,23 @@ static UINT rdpdr_server_drive_query_directory_callback2(RdpdrServerContext* con - WINPR_ASSERT(context); - WINPR_ASSERT(context->priv); - WINPR_ASSERT(irp); -- WLog_Print(context->priv->log, WLOG_DEBUG, -+ -+ RdpdrServerPrivate* priv = context->priv; -+ WLog_Print(priv->log, WLOG_DEBUG, - "RdpdrServerDriveQueryDirectoryCallback2: deviceId=%" PRIu32 - ", completionId=%" PRIu32 ", ioStatus=0x%" PRIx32 "", - deviceId, completionId, ioStatus); - -- if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 4)) -+ if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 4)) - return ERROR_INVALID_DATA; - - Stream_Read_UINT32(s, length); /* Length (4 bytes) */ - - if (length > 0) - { -- if ((error = rdpdr_server_read_file_directory_information(context->priv->log, s, &fdi))) -+ if ((error = rdpdr_server_read_file_directory_information(priv->log, s, &fdi))) - { -- WLog_Print(context->priv->log, WLOG_ERROR, -+ WLog_Print(priv->log, WLOG_ERROR, - "rdpdr_server_read_file_directory_information failed with error %" PRIu32 - "!", - error); -@@ -2970,7 +3055,7 @@ static UINT rdpdr_server_drive_query_directory_callback2(RdpdrServerContext* con - } - else - { -- if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 1)) -+ if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 1)) - return ERROR_INVALID_DATA; - - Stream_Seek(s, 1); /* Padding (1 byte) */ -@@ -2982,12 +3067,12 @@ static UINT rdpdr_server_drive_query_directory_callback2(RdpdrServerContext* con - context->OnDriveQueryDirectoryComplete(context, irp->CallbackData, ioStatus, - length > 0 ? &fdi : nullptr); - /* Setup the IRP. */ -- irp->CompletionId = context->priv->NextCompletionId++; -+ irp->CompletionId = priv->NextCompletionId++; - irp->Callback = rdpdr_server_drive_query_directory_callback2; - - if (!rdpdr_server_enqueue_irp(context, irp)) - { -- WLog_Print(context->priv->log, WLOG_ERROR, "rdpdr_server_enqueue_irp failed!"); -+ WLog_Print(priv->log, WLOG_ERROR, "rdpdr_server_enqueue_irp failed!"); - rdpdr_server_irp_free(irp); - return ERROR_INTERNAL_ERROR; - } -@@ -3019,7 +3104,9 @@ static UINT rdpdr_server_drive_query_directory_callback1(RdpdrServerContext* con - WINPR_ASSERT(context); - WINPR_ASSERT(context->priv); - WINPR_ASSERT(irp); -- WLog_Print(context->priv->log, WLOG_DEBUG, -+ -+ RdpdrServerPrivate* priv = context->priv; -+ WLog_Print(priv->log, WLOG_DEBUG, - "RdpdrServerDriveQueryDirectoryCallback1: deviceId=%" PRIu32 - ", completionId=%" PRIu32 ", ioStatus=0x%" PRIx32 "", - deviceId, completionId, ioStatus); -@@ -3033,12 +3120,12 @@ static UINT rdpdr_server_drive_query_directory_callback1(RdpdrServerContext* con - return CHANNEL_RC_OK; - } - -- if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 4)) -+ if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 4)) - return ERROR_INVALID_DATA; - - const uint32_t fileId = Stream_Get_UINT32(s); - /* Setup the IRP. */ -- irp->CompletionId = context->priv->NextCompletionId++; -+ irp->CompletionId = priv->NextCompletionId++; - irp->Callback = rdpdr_server_drive_query_directory_callback2; - irp->DeviceId = deviceId; - irp->FileId = fileId; -@@ -3046,7 +3133,7 @@ static UINT rdpdr_server_drive_query_directory_callback1(RdpdrServerContext* con - - if (!rdpdr_server_enqueue_irp(context, irp)) - { -- WLog_Print(context->priv->log, WLOG_ERROR, "rdpdr_server_enqueue_irp failed!"); -+ WLog_Print(priv->log, WLOG_ERROR, "rdpdr_server_enqueue_irp failed!"); - rdpdr_server_irp_free(irp); - return ERROR_INTERNAL_ERROR; - } -@@ -3069,13 +3156,15 @@ static UINT rdpdr_server_drive_query_directory(RdpdrServerContext* context, void - WINPR_ASSERT(context->priv); - WINPR_ASSERT(irp); - -+ RdpdrServerPrivate* priv = context->priv; -+ - if (!irp) - { -- WLog_Print(context->priv->log, WLOG_ERROR, "rdpdr_server_irp_new failed!"); -+ WLog_Print(priv->log, WLOG_ERROR, "rdpdr_server_irp_new failed!"); - return CHANNEL_RC_NO_MEMORY; - } - -- irp->CompletionId = context->priv->NextCompletionId++; -+ irp->CompletionId = priv->NextCompletionId++; - irp->Callback = rdpdr_server_drive_query_directory_callback1; - irp->CallbackData = callbackData; - irp->DeviceId = deviceId; -@@ -3084,7 +3173,7 @@ static UINT rdpdr_server_drive_query_directory(RdpdrServerContext* context, void - - if (!rdpdr_server_enqueue_irp(context, irp)) - { -- WLog_Print(context->priv->log, WLOG_ERROR, "rdpdr_server_enqueue_irp failed!"); -+ WLog_Print(priv->log, WLOG_ERROR, "rdpdr_server_enqueue_irp failed!"); - rdpdr_server_irp_free(irp); - return ERROR_INTERNAL_ERROR; - } -@@ -3111,17 +3200,19 @@ static UINT rdpdr_server_drive_open_file_callback(RdpdrServerContext* context, w - WINPR_ASSERT(context); - WINPR_ASSERT(context->priv); - WINPR_ASSERT(irp); -- WLog_Print(context->priv->log, WLOG_DEBUG, -+ -+ RdpdrServerPrivate* priv = context->priv; -+ WLog_Print(priv->log, WLOG_DEBUG, - "RdpdrServerDriveOpenFileCallback: deviceId=%" PRIu32 ", completionId=%" PRIu32 - ", ioStatus=0x%" PRIx32 "", - deviceId, completionId, ioStatus); - -- if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 5)) -+ if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 5)) - return ERROR_INVALID_DATA; - - const uint32_t fileId = Stream_Get_UINT32(s); /* FileId (4 bytes) */ - const uint8_t information = Stream_Get_UINT8(s); /* Information (1 byte) */ -- WLog_Print(context->priv->log, WLOG_DEBUG, "fileId [0x%08" PRIx32 "], information %s", fileId, -+ WLog_Print(priv->log, WLOG_DEBUG, "fileId [0x%08" PRIx32 "], information %s", fileId, - fileInformation2str(information)); - - /* Invoke the open file completion routine. */ -@@ -3145,13 +3236,15 @@ static UINT rdpdr_server_drive_open_file(RdpdrServerContext* context, void* call - WINPR_ASSERT(context->priv); - WINPR_ASSERT(irp); - -+ RdpdrServerPrivate* priv = context->priv; -+ - if (!irp) - { -- WLog_Print(context->priv->log, WLOG_ERROR, "rdpdr_server_irp_new failed!"); -+ WLog_Print(priv->log, WLOG_ERROR, "rdpdr_server_irp_new failed!"); - return CHANNEL_RC_NO_MEMORY; - } - -- irp->CompletionId = context->priv->NextCompletionId++; -+ irp->CompletionId = priv->NextCompletionId++; - irp->Callback = rdpdr_server_drive_open_file_callback; - irp->CallbackData = callbackData; - irp->DeviceId = deviceId; -@@ -3160,7 +3253,7 @@ static UINT rdpdr_server_drive_open_file(RdpdrServerContext* context, void* call - - if (!rdpdr_server_enqueue_irp(context, irp)) - { -- WLog_Print(context->priv->log, WLOG_ERROR, "rdpdr_server_enqueue_irp failed!"); -+ WLog_Print(priv->log, WLOG_ERROR, "rdpdr_server_enqueue_irp failed!"); - rdpdr_server_irp_free(irp); - return ERROR_INTERNAL_ERROR; - } -@@ -3189,17 +3282,19 @@ static UINT rdpdr_server_drive_read_file_callback(RdpdrServerContext* context, w - WINPR_ASSERT(context); - WINPR_ASSERT(context->priv); - WINPR_ASSERT(irp); -- WLog_Print(context->priv->log, WLOG_DEBUG, -+ -+ RdpdrServerPrivate* priv = context->priv; -+ WLog_Print(priv->log, WLOG_DEBUG, - "RdpdrServerDriveReadFileCallback: deviceId=%" PRIu32 ", completionId=%" PRIu32 - ", ioStatus=0x%" PRIx32 "", - deviceId, completionId, ioStatus); - -- if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 4)) -+ if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 4)) - return ERROR_INVALID_DATA; - - Stream_Read_UINT32(s, length); /* Length (4 bytes) */ - -- if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, length)) -+ if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, length)) - return ERROR_INVALID_DATA; - - if (length > 0) -@@ -3229,13 +3324,15 @@ static UINT rdpdr_server_drive_read_file(RdpdrServerContext* context, void* call - WINPR_ASSERT(context->priv); - WINPR_ASSERT(irp); - -+ RdpdrServerPrivate* priv = context->priv; -+ - if (!irp) - { -- WLog_Print(context->priv->log, WLOG_ERROR, "rdpdr_server_irp_new failed!"); -+ WLog_Print(priv->log, WLOG_ERROR, "rdpdr_server_irp_new failed!"); - return CHANNEL_RC_NO_MEMORY; - } - -- irp->CompletionId = context->priv->NextCompletionId++; -+ irp->CompletionId = priv->NextCompletionId++; - irp->Callback = rdpdr_server_drive_read_file_callback; - irp->CallbackData = callbackData; - irp->DeviceId = deviceId; -@@ -3243,7 +3340,7 @@ static UINT rdpdr_server_drive_read_file(RdpdrServerContext* context, void* call - - if (!rdpdr_server_enqueue_irp(context, irp)) - { -- WLog_Print(context->priv->log, WLOG_ERROR, "rdpdr_server_enqueue_irp failed!"); -+ WLog_Print(priv->log, WLOG_ERROR, "rdpdr_server_enqueue_irp failed!"); - rdpdr_server_irp_free(irp); - return ERROR_INTERNAL_ERROR; - } -@@ -3271,18 +3368,20 @@ static UINT rdpdr_server_drive_write_file_callback(RdpdrServerContext* context, - WINPR_ASSERT(context); - WINPR_ASSERT(context->priv); - WINPR_ASSERT(irp); -- WLog_Print(context->priv->log, WLOG_DEBUG, -+ -+ RdpdrServerPrivate* priv = context->priv; -+ WLog_Print(priv->log, WLOG_DEBUG, - "RdpdrServerDriveWriteFileCallback: deviceId=%" PRIu32 ", completionId=%" PRIu32 - ", ioStatus=0x%" PRIx32 "", - deviceId, completionId, ioStatus); - -- if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 5)) -+ if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 5)) - return ERROR_INVALID_DATA; - - Stream_Read_UINT32(s, length); /* Length (4 bytes) */ - Stream_Seek(s, 1); /* Padding (1 byte) */ - -- if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, length)) -+ if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, length)) - return ERROR_INVALID_DATA; - - /* Invoke the write file completion routine. */ -@@ -3306,13 +3405,15 @@ static UINT rdpdr_server_drive_write_file(RdpdrServerContext* context, void* cal - WINPR_ASSERT(context->priv); - WINPR_ASSERT(irp); - -+ RdpdrServerPrivate* priv = context->priv; -+ - if (!irp) - { -- WLog_Print(context->priv->log, WLOG_ERROR, "rdpdr_server_irp_new failed!"); -+ WLog_Print(priv->log, WLOG_ERROR, "rdpdr_server_irp_new failed!"); - return CHANNEL_RC_NO_MEMORY; - } - -- irp->CompletionId = context->priv->NextCompletionId++; -+ irp->CompletionId = priv->NextCompletionId++; - irp->Callback = rdpdr_server_drive_write_file_callback; - irp->CallbackData = callbackData; - irp->DeviceId = deviceId; -@@ -3320,7 +3421,7 @@ static UINT rdpdr_server_drive_write_file(RdpdrServerContext* context, void* cal - - if (!rdpdr_server_enqueue_irp(context, irp)) - { -- WLog_Print(context->priv->log, WLOG_ERROR, "rdpdr_server_enqueue_irp failed!"); -+ WLog_Print(priv->log, WLOG_ERROR, "rdpdr_server_enqueue_irp failed!"); - rdpdr_server_irp_free(irp); - return ERROR_INTERNAL_ERROR; - } -@@ -3349,13 +3450,15 @@ static UINT rdpdr_server_drive_close_file_callback(RdpdrServerContext* context, - WINPR_ASSERT(context->priv); - WINPR_ASSERT(irp); - -- WLog_Print(context->priv->log, WLOG_DEBUG, -+ RdpdrServerPrivate* priv = context->priv; -+ -+ WLog_Print(priv->log, WLOG_DEBUG, - "RdpdrServerDriveCloseFileCallback: deviceId=%" PRIu32 ", completionId=%" PRIu32 - ", ioStatus=0x%" PRIx32 "", - deviceId, completionId, ioStatus); - - // padding 5 bytes -- if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 5)) -+ if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 5)) - return ERROR_INVALID_DATA; - - Stream_Seek(s, 5); -@@ -3380,13 +3483,15 @@ static UINT rdpdr_server_drive_close_file(RdpdrServerContext* context, void* cal - WINPR_ASSERT(context->priv); - WINPR_ASSERT(irp); - -+ RdpdrServerPrivate* priv = context->priv; -+ - if (!irp) - { -- WLog_Print(context->priv->log, WLOG_ERROR, "rdpdr_server_irp_new failed!"); -+ WLog_Print(priv->log, WLOG_ERROR, "rdpdr_server_irp_new failed!"); - return CHANNEL_RC_NO_MEMORY; - } - -- irp->CompletionId = context->priv->NextCompletionId++; -+ irp->CompletionId = priv->NextCompletionId++; - irp->Callback = rdpdr_server_drive_close_file_callback; - irp->CallbackData = callbackData; - irp->DeviceId = deviceId; -@@ -3394,7 +3499,7 @@ static UINT rdpdr_server_drive_close_file(RdpdrServerContext* context, void* cal - - if (!rdpdr_server_enqueue_irp(context, irp)) - { -- WLog_Print(context->priv->log, WLOG_ERROR, "rdpdr_server_enqueue_irp failed!"); -+ WLog_Print(priv->log, WLOG_ERROR, "rdpdr_server_enqueue_irp failed!"); - rdpdr_server_irp_free(irp); - return ERROR_INTERNAL_ERROR; - } -@@ -3422,7 +3527,8 @@ static UINT rdpdr_server_drive_delete_file_callback2(RdpdrServerContext* context - WINPR_ASSERT(context->priv); - WINPR_ASSERT(irp); - -- WLog_Print(context->priv->log, WLOG_DEBUG, -+ RdpdrServerPrivate* priv = context->priv; -+ WLog_Print(priv->log, WLOG_DEBUG, - "RdpdrServerDriveDeleteFileCallback2: deviceId=%" PRIu32 ", completionId=%" PRIu32 - ", ioStatus=0x%" PRIx32 "", - deviceId, completionId, ioStatus); -@@ -3445,7 +3551,9 @@ static UINT rdpdr_server_drive_delete_file_callback1(RdpdrServerContext* context - WINPR_ASSERT(context); - WINPR_ASSERT(context->priv); - WINPR_ASSERT(irp); -- WLog_Print(context->priv->log, WLOG_DEBUG, -+ -+ RdpdrServerPrivate* priv = context->priv; -+ WLog_Print(priv->log, WLOG_DEBUG, - "RdpdrServerDriveDeleteFileCallback1: deviceId=%" PRIu32 ", completionId=%" PRIu32 - ", ioStatus=0x%" PRIx32 "", - deviceId, completionId, ioStatus); -@@ -3459,23 +3567,23 @@ static UINT rdpdr_server_drive_delete_file_callback1(RdpdrServerContext* context - return CHANNEL_RC_OK; - } - -- if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 5)) -+ if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 5)) - return ERROR_INVALID_DATA; - - const uint32_t fileId = Stream_Get_UINT32(s); /* FileId (4 bytes) */ - const uint8_t information = Stream_Get_UINT8(s); /* Information (1 byte) */ - -- WLog_Print(context->priv->log, WLOG_DEBUG, "fileId [0x%08" PRIx32 "], information %s", fileId, -+ WLog_Print(priv->log, WLOG_DEBUG, "fileId [0x%08" PRIx32 "], information %s", fileId, - fileInformation2str(information)); - /* Setup the IRP. */ -- irp->CompletionId = context->priv->NextCompletionId++; -+ irp->CompletionId = priv->NextCompletionId++; - irp->Callback = rdpdr_server_drive_delete_file_callback2; - irp->DeviceId = deviceId; - irp->FileId = fileId; - - if (!rdpdr_server_enqueue_irp(context, irp)) - { -- WLog_Print(context->priv->log, WLOG_ERROR, "rdpdr_server_enqueue_irp failed!"); -+ WLog_Print(priv->log, WLOG_ERROR, "rdpdr_server_enqueue_irp failed!"); - rdpdr_server_irp_free(irp); - return ERROR_INTERNAL_ERROR; - } -@@ -3497,13 +3605,15 @@ static UINT rdpdr_server_drive_delete_file(RdpdrServerContext* context, void* ca - WINPR_ASSERT(context->priv); - WINPR_ASSERT(irp); - -+ RdpdrServerPrivate* priv = context->priv; -+ - if (!irp) - { -- WLog_Print(context->priv->log, WLOG_ERROR, "rdpdr_server_irp_new failed!"); -+ WLog_Print(priv->log, WLOG_ERROR, "rdpdr_server_irp_new failed!"); - return CHANNEL_RC_NO_MEMORY; - } - -- irp->CompletionId = context->priv->NextCompletionId++; -+ irp->CompletionId = priv->NextCompletionId++; - irp->Callback = rdpdr_server_drive_delete_file_callback1; - irp->CallbackData = callbackData; - irp->DeviceId = deviceId; -@@ -3512,7 +3622,7 @@ static UINT rdpdr_server_drive_delete_file(RdpdrServerContext* context, void* ca - - if (!rdpdr_server_enqueue_irp(context, irp)) - { -- WLog_Print(context->priv->log, WLOG_ERROR, "rdpdr_server_enqueue_irp failed!"); -+ WLog_Print(priv->log, WLOG_ERROR, "rdpdr_server_enqueue_irp failed!"); - rdpdr_server_irp_free(irp); - return ERROR_INTERNAL_ERROR; - } -@@ -3542,7 +3652,8 @@ static UINT rdpdr_server_drive_rename_file_callback3(RdpdrServerContext* context - WINPR_ASSERT(context->priv); - WINPR_ASSERT(irp); - -- WLog_Print(context->priv->log, WLOG_DEBUG, -+ RdpdrServerPrivate* priv = context->priv; -+ WLog_Print(priv->log, WLOG_DEBUG, - "RdpdrServerDriveRenameFileCallback3: deviceId=%" PRIu32 ", completionId=%" PRIu32 - ", ioStatus=0x%" PRIx32 "", - deviceId, completionId, ioStatus); -@@ -3564,12 +3675,14 @@ static UINT rdpdr_server_drive_rename_file_callback2(RdpdrServerContext* context - WINPR_ASSERT(context); - WINPR_ASSERT(context->priv); - WINPR_ASSERT(irp); -- WLog_Print(context->priv->log, WLOG_DEBUG, -+ -+ RdpdrServerPrivate* priv = context->priv; -+ WLog_Print(priv->log, WLOG_DEBUG, - "RdpdrServerDriveRenameFileCallback2: deviceId=%" PRIu32 ", completionId=%" PRIu32 - ", ioStatus=0x%" PRIx32 "", - deviceId, completionId, ioStatus); - -- if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 5)) -+ if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 5)) - return ERROR_INVALID_DATA; - - Stream_Read_UINT32(s, length); /* Length (4 bytes) */ -@@ -3577,13 +3690,13 @@ static UINT rdpdr_server_drive_rename_file_callback2(RdpdrServerContext* context - /* Invoke the rename file completion routine. */ - context->OnDriveRenameFileComplete(context, irp->CallbackData, ioStatus); - /* Setup the IRP. */ -- irp->CompletionId = context->priv->NextCompletionId++; -+ irp->CompletionId = priv->NextCompletionId++; - irp->Callback = rdpdr_server_drive_rename_file_callback3; - irp->DeviceId = deviceId; - - if (!rdpdr_server_enqueue_irp(context, irp)) - { -- WLog_Print(context->priv->log, WLOG_ERROR, "rdpdr_server_enqueue_irp failed!"); -+ WLog_Print(priv->log, WLOG_ERROR, "rdpdr_server_enqueue_irp failed!"); - rdpdr_server_irp_free(irp); - return ERROR_INTERNAL_ERROR; - } -@@ -3605,7 +3718,9 @@ static UINT rdpdr_server_drive_rename_file_callback1(RdpdrServerContext* context - WINPR_ASSERT(context); - WINPR_ASSERT(context->priv); - WINPR_ASSERT(irp); -- WLog_Print(context->priv->log, WLOG_DEBUG, -+ -+ RdpdrServerPrivate* priv = context->priv; -+ WLog_Print(priv->log, WLOG_DEBUG, - "RdpdrServerDriveRenameFileCallback1: deviceId=%" PRIu32 ", completionId=%" PRIu32 - ", ioStatus=0x%" PRIx32 "", - deviceId, completionId, ioStatus); -@@ -3619,23 +3734,23 @@ static UINT rdpdr_server_drive_rename_file_callback1(RdpdrServerContext* context - return CHANNEL_RC_OK; - } - -- if (!Stream_CheckAndLogRequiredLengthWLog(context->priv->log, s, 5)) -+ if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 5)) - return ERROR_INVALID_DATA; - - const uint32_t fileId = Stream_Get_UINT32(s); /* FileId (4 bytes) */ - const uint8_t information = Stream_Get_UINT8(s); /* Information (1 byte) */ -- WLog_Print(context->priv->log, WLOG_DEBUG, "fileId [0x%08" PRIx32 "], information %s", fileId, -+ WLog_Print(priv->log, WLOG_DEBUG, "fileId [0x%08" PRIx32 "], information %s", fileId, - fileInformation2str(information)); - - /* Setup the IRP. */ -- irp->CompletionId = context->priv->NextCompletionId++; -+ irp->CompletionId = priv->NextCompletionId++; - irp->Callback = rdpdr_server_drive_rename_file_callback2; - irp->DeviceId = deviceId; - irp->FileId = fileId; - - if (!rdpdr_server_enqueue_irp(context, irp)) - { -- WLog_Print(context->priv->log, WLOG_ERROR, "rdpdr_server_enqueue_irp failed!"); -+ WLog_Print(priv->log, WLOG_ERROR, "rdpdr_server_enqueue_irp failed!"); - rdpdr_server_irp_free(irp); - return ERROR_INTERNAL_ERROR; - } -@@ -3656,15 +3771,17 @@ static UINT rdpdr_server_drive_rename_file(RdpdrServerContext* context, void* ca - { - WINPR_ASSERT(context); - WINPR_ASSERT(context->priv); -+ -+ RdpdrServerPrivate* priv = context->priv; - RDPDR_IRP* irp = rdpdr_server_irp_new(); - - if (!irp) - { -- WLog_Print(context->priv->log, WLOG_ERROR, "rdpdr_server_irp_new failed!"); -+ WLog_Print(priv->log, WLOG_ERROR, "rdpdr_server_irp_new failed!"); - return CHANNEL_RC_NO_MEMORY; - } - -- irp->CompletionId = context->priv->NextCompletionId++; -+ irp->CompletionId = priv->NextCompletionId++; - irp->Callback = rdpdr_server_drive_rename_file_callback1; - irp->CallbackData = callbackData; - irp->DeviceId = deviceId; -@@ -3675,7 +3792,7 @@ static UINT rdpdr_server_drive_rename_file(RdpdrServerContext* context, void* ca - - if (!rdpdr_server_enqueue_irp(context, irp)) - { -- WLog_Print(context->priv->log, WLOG_ERROR, "rdpdr_server_enqueue_irp failed!"); -+ WLog_Print(priv->log, WLOG_ERROR, "rdpdr_server_enqueue_irp failed!"); - rdpdr_server_irp_free(irp); - return ERROR_INTERNAL_ERROR; - } - -From 65d04a2f4eb13ae313c44c5443ab06b973376049 Mon Sep 17 00:00:00 2001 -From: David Fort -Date: Tue, 23 Jun 2026 19:10:19 +0200 -Subject: [PATCH 12/31] [channels,rdpdr] extract RDPDR_IRP_Callback typedef and - convert RDPDR_IRP to struct - ---- - channels/rdpdr/server/rdpdr_main.h | 12 +++++++----- - 1 file changed, 7 insertions(+), 5 deletions(-) - -diff --git a/channels/rdpdr/server/rdpdr_main.h b/channels/rdpdr/server/rdpdr_main.h -index dabbae24ad8b..b1d86b148ad7 100644 ---- a/channels/rdpdr/server/rdpdr_main.h -+++ b/channels/rdpdr/server/rdpdr_main.h -@@ -31,7 +31,11 @@ - #include - #include - --typedef struct S_RDPDR_IRP -+typedef struct S_RDPDR_IRP RDPDR_IRP; -+typedef UINT (*RDPDR_IRP_Callback)(RdpdrServerContext* context, wStream* s, struct S_RDPDR_IRP* irp, -+ UINT32 deviceId, UINT32 completionId, UINT32 ioStatus); -+ -+struct S_RDPDR_IRP - { - UINT32 CompletionId; - UINT32 DeviceId; -@@ -39,9 +43,7 @@ typedef struct S_RDPDR_IRP - char PathName[256]; - char ExtraBuffer[256]; - void* CallbackData; -- UINT(*Callback) -- (RdpdrServerContext* context, wStream* s, struct S_RDPDR_IRP* irp, UINT32 deviceId, -- UINT32 completionId, UINT32 ioStatus); --} RDPDR_IRP; -+ RDPDR_IRP_Callback Callback; -+}; - - #endif /* FREERDP_CHANNEL_RDPDR_SERVER_MAIN_H */ - -From f29fc22218918fb8b2c8f9f8b04150db2bee7fee Mon Sep 17 00:00:00 2001 -From: Joan Torres Lopez -Date: Tue, 23 Jun 2026 19:10:31 +0200 -Subject: [PATCH 13/31] [channels,rdpdr] declare variables at point of first - use - -Move variable declarations from function tops to just before -their first use. - -Co-Authored-By: David Fort ---- - channels/rdpdr/server/rdpdr_main.c | 378 ++++++++++++----------------- - 1 file changed, 154 insertions(+), 224 deletions(-) - -diff --git a/channels/rdpdr/server/rdpdr_main.c b/channels/rdpdr/server/rdpdr_main.c -index 5f37a3c7a3d0..488efca5bc46 100644 ---- a/channels/rdpdr/server/rdpdr_main.c -+++ b/channels/rdpdr/server/rdpdr_main.c -@@ -191,9 +191,9 @@ static RdpdrDevice* rdpdr_get_device_by_id(RdpdrServerPrivate* priv, UINT32 Devi - - static BOOL rdpdr_remove_device_by_id(RdpdrServerPrivate* priv, UINT32 DeviceId) - { -- const RdpdrDevice* device = rdpdr_get_device_by_id(priv, DeviceId); - WINPR_ASSERT(priv); - -+ const RdpdrDevice* device = rdpdr_get_device_by_id(priv, DeviceId); - if (!device) - { - WLog_Print(priv->log, WLOG_WARN, "[del] Device Id: 0x%08" PRIX32 ": no such device", -@@ -258,21 +258,17 @@ static BOOL rdpdr_server_enqueue_irp(RdpdrServerContext* context, RDPDR_IRP* irp - - static RDPDR_IRP* rdpdr_server_dequeue_irp(RdpdrServerContext* context, UINT32 completionId) - { -- RDPDR_IRP* irp = nullptr; - WINPR_ASSERT(context); - WINPR_ASSERT(context->priv); - - RdpdrServerPrivate* priv = context->priv; - const uintptr_t key = completionId + 1ull; -- irp = (RDPDR_IRP*)ListDictionary_Take(priv->IrpList, (void*)key); -+ RDPDR_IRP* irp = (RDPDR_IRP*)ListDictionary_Take(priv->IrpList, (void*)key); - return irp; - } - - static UINT rdpdr_seal_send_free_request(RdpdrServerContext* context, wStream* s) - { -- BOOL status = 0; -- ULONG written = 0; -- - WINPR_ASSERT(context); - WINPR_ASSERT(context->priv); - WINPR_ASSERT(s); -@@ -295,8 +291,9 @@ static UINT rdpdr_seal_send_free_request(RdpdrServerContext* context, wStream* s - rdpdr_packetid_string(header.PacketId), header.PacketId); - } - winpr_HexLogDump(priv->log, WLOG_DEBUG, Stream_Buffer(s), Stream_Length(s)); -- status = WTSVirtualChannelWrite(priv->ChannelHandle, Stream_BufferAs(s, char), (ULONG)length, -- &written); -+ ULONG written = 0; -+ BOOL status = WTSVirtualChannelWrite(priv->ChannelHandle, Stream_BufferAs(s, char), -+ (ULONG)length, &written); - Stream_Free(s, TRUE); - return status ? CHANNEL_RC_OK : ERROR_INTERNAL_ERROR; - } -@@ -308,29 +305,25 @@ static UINT rdpdr_seal_send_free_request(RdpdrServerContext* context, wStream* s - */ - static UINT rdpdr_server_send_announce_request(RdpdrServerContext* context) - { -- UINT error = 0; -- wStream* s = nullptr; -- RDPDR_HEADER header = WINPR_C_ARRAY_INIT; -- - WINPR_ASSERT(context); - WINPR_ASSERT(context->priv); - -- header.Component = RDPDR_CTYP_CORE; -- header.PacketId = PAKID_CORE_SERVER_ANNOUNCE; -- -- error = IFCALLRESULT(CHANNEL_RC_OK, context->SendServerAnnounce, context); -+ UINT error = IFCALLRESULT(CHANNEL_RC_OK, context->SendServerAnnounce, context); - if (error != CHANNEL_RC_OK) - return error; - - RdpdrServerPrivate* priv = context->priv; -- s = Stream_New(nullptr, RDPDR_HEADER_LENGTH + 8); -- -+ wStream* s = Stream_New(nullptr, RDPDR_HEADER_LENGTH + 8); - if (!s) - { - WLog_Print(priv->log, WLOG_ERROR, "Stream_New failed!"); - return CHANNEL_RC_NO_MEMORY; - } - -+ const RDPDR_HEADER header = { -+ .Component = RDPDR_CTYP_CORE, -+ .PacketId = PAKID_CORE_SERVER_ANNOUNCE, -+ }; - Stream_Write_UINT16(s, header.Component); /* Component (2 bytes) */ - Stream_Write_UINT16(s, header.PacketId); /* PacketId (2 bytes) */ - Stream_Write_UINT16(s, priv->VersionMajor); /* VersionMajor (2 bytes) */ -@@ -347,9 +340,6 @@ static UINT rdpdr_server_send_announce_request(RdpdrServerContext* context) - static UINT rdpdr_server_receive_announce_response(RdpdrServerContext* context, wStream* s, - const RDPDR_HEADER* header) - { -- UINT32 ClientId = 0; -- UINT16 VersionMajor = 0; -- UINT16 VersionMinor = 0; - WINPR_ASSERT(context); - WINPR_ASSERT(context->priv); - WINPR_ASSERT(header); -@@ -361,6 +351,9 @@ static UINT rdpdr_server_receive_announce_response(RdpdrServerContext* context, - if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 8)) - return ERROR_INVALID_DATA; - -+ UINT16 VersionMajor = 0; -+ UINT16 VersionMinor = 0; -+ UINT32 ClientId = 0; - Stream_Read_UINT16(s, VersionMajor); /* VersionMajor (2 bytes) */ - Stream_Read_UINT16(s, VersionMinor); /* VersionMinor (2 bytes) */ - Stream_Read_UINT32(s, ClientId); /* ClientId (4 bytes) */ -@@ -382,10 +375,6 @@ static UINT rdpdr_server_receive_announce_response(RdpdrServerContext* context, - static UINT rdpdr_server_receive_client_name_request(RdpdrServerContext* context, wStream* s, - const RDPDR_HEADER* header) - { -- UINT32 UnicodeFlag = 0; -- UINT32 CodePage = 0; -- UINT32 ComputerNameLen = 0; -- - WINPR_ASSERT(context); - WINPR_ASSERT(context->priv); - WINPR_ASSERT(s); -@@ -397,6 +386,9 @@ static UINT rdpdr_server_receive_client_name_request(RdpdrServerContext* context - if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 12)) - return ERROR_INVALID_DATA; - -+ UINT32 UnicodeFlag = 0; -+ UINT32 CodePage = 0; -+ UINT32 ComputerNameLen = 0; - Stream_Read_UINT32(s, UnicodeFlag); /* UnicodeFlag (4 bytes) */ - Stream_Read_UINT32(s, CodePage); /* CodePage (4 bytes), MUST be set to zero */ - Stream_Read_UINT32(s, ComputerNameLen); /* ComputerNameLen (4 bytes) */ -@@ -617,17 +609,13 @@ static UINT rdpdr_server_read_general_capability_set(RdpdrServerContext* context - */ - static UINT rdpdr_server_write_general_capability_set(RdpdrServerContext* context, wStream* s) - { -- UINT32 ioCode1 = 0; -- UINT32 extendedPdu = 0; -- UINT32 extraFlags1 = 0; -- UINT32 SpecialTypeDeviceCap = 0; -- const RDPDR_CAPABILITY_HEADER header = { CAP_GENERAL_TYPE, RDPDR_CAPABILITY_HEADER_LENGTH + 36, -- GENERAL_CAPABILITY_VERSION_02 }; -- - WINPR_ASSERT(context); - WINPR_ASSERT(context->priv); - -- ioCode1 = 0; -+ const RDPDR_CAPABILITY_HEADER header = { CAP_GENERAL_TYPE, RDPDR_CAPABILITY_HEADER_LENGTH + 36, -+ GENERAL_CAPABILITY_VERSION_02 }; -+ -+ UINT32 ioCode1 = 0; - ioCode1 |= RDPDR_IRP_MJ_CREATE; /* always set */ - ioCode1 |= RDPDR_IRP_MJ_CLEANUP; /* always set */ - ioCode1 |= RDPDR_IRP_MJ_CLOSE; /* always set */ -@@ -644,7 +632,8 @@ static UINT rdpdr_server_write_general_capability_set(RdpdrServerContext* contex - ioCode1 |= RDPDR_IRP_MJ_LOCK_CONTROL; /* always set */ - ioCode1 |= RDPDR_IRP_MJ_QUERY_SECURITY; /* optional */ - ioCode1 |= RDPDR_IRP_MJ_SET_SECURITY; /* optional */ -- extendedPdu = 0; -+ -+ UINT32 extendedPdu = 0; - extendedPdu |= RDPDR_CLIENT_DISPLAY_NAME_PDU; /* always set */ - extendedPdu |= RDPDR_DEVICE_REMOVE_PDUS; /* optional */ - -@@ -652,9 +641,9 @@ static UINT rdpdr_server_write_general_capability_set(RdpdrServerContext* contex - if (priv->UserLoggedOnPdu) - extendedPdu |= RDPDR_USER_LOGGEDON_PDU; /* optional */ - -- extraFlags1 = 0; -+ UINT32 extraFlags1 = 0; - extraFlags1 |= ENABLE_ASYNCIO; /* optional */ -- SpecialTypeDeviceCap = 0; -+ UINT32 SpecialTypeDeviceCap = 0; - - UINT error = rdpdr_write_capset_header(priv->log, s, &header); - if (error != CHANNEL_RC_OK) -@@ -703,12 +692,13 @@ static UINT rdpdr_server_read_printer_capability_set(RdpdrServerContext* context - */ - static UINT rdpdr_server_write_printer_capability_set(RdpdrServerContext* context, wStream* s) - { -- const RDPDR_CAPABILITY_HEADER header = { CAP_PRINTER_TYPE, RDPDR_CAPABILITY_HEADER_LENGTH, -- PRINT_CAPABILITY_VERSION_01 }; - WINPR_UNUSED(context); - WINPR_ASSERT(context); - WINPR_ASSERT(context->priv); - -+ const RDPDR_CAPABILITY_HEADER header = { CAP_PRINTER_TYPE, RDPDR_CAPABILITY_HEADER_LENGTH, -+ PRINT_CAPABILITY_VERSION_01 }; -+ - return rdpdr_server_write_capability_set_header_cb(context, s, &header); - } - -@@ -736,12 +726,13 @@ static UINT rdpdr_server_read_port_capability_set(RdpdrServerContext* context, w - */ - static UINT rdpdr_server_write_port_capability_set(RdpdrServerContext* context, wStream* s) - { -- const RDPDR_CAPABILITY_HEADER header = { CAP_PORT_TYPE, RDPDR_CAPABILITY_HEADER_LENGTH, -- PORT_CAPABILITY_VERSION_01 }; - WINPR_UNUSED(context); - WINPR_ASSERT(context); - WINPR_ASSERT(context->priv); - -+ const RDPDR_CAPABILITY_HEADER header = { CAP_PORT_TYPE, RDPDR_CAPABILITY_HEADER_LENGTH, -+ PORT_CAPABILITY_VERSION_01 }; -+ - return rdpdr_server_write_capability_set_header_cb(context, s, &header); - } - -@@ -769,13 +760,13 @@ static UINT rdpdr_server_read_drive_capability_set(RdpdrServerContext* context, - */ - static UINT rdpdr_server_write_drive_capability_set(RdpdrServerContext* context, wStream* s) - { -- const RDPDR_CAPABILITY_HEADER header = { CAP_DRIVE_TYPE, RDPDR_CAPABILITY_HEADER_LENGTH, -- DRIVE_CAPABILITY_VERSION_02 }; -- - WINPR_ASSERT(context); - WINPR_ASSERT(context->priv); - WINPR_UNUSED(context); - -+ const RDPDR_CAPABILITY_HEADER header = { CAP_DRIVE_TYPE, RDPDR_CAPABILITY_HEADER_LENGTH, -+ DRIVE_CAPABILITY_VERSION_02 }; -+ - return rdpdr_server_write_capability_set_header_cb(context, s, &header); - } - -@@ -803,13 +794,13 @@ static UINT rdpdr_server_read_smartcard_capability_set(RdpdrServerContext* conte - */ - static UINT rdpdr_server_write_smartcard_capability_set(RdpdrServerContext* context, wStream* s) - { -- const RDPDR_CAPABILITY_HEADER header = { CAP_SMARTCARD_TYPE, RDPDR_CAPABILITY_HEADER_LENGTH, -- SMARTCARD_CAPABILITY_VERSION_01 }; - WINPR_ASSERT(context); - WINPR_ASSERT(context->priv); -- - WINPR_UNUSED(context); - -+ const RDPDR_CAPABILITY_HEADER header = { CAP_SMARTCARD_TYPE, RDPDR_CAPABILITY_HEADER_LENGTH, -+ SMARTCARD_CAPABILITY_VERSION_01 }; -+ - return rdpdr_server_write_capability_set_header_cb(context, s, &header); - } - -@@ -820,17 +811,10 @@ static UINT rdpdr_server_write_smartcard_capability_set(RdpdrServerContext* cont - */ - static UINT rdpdr_server_send_core_capability_request(RdpdrServerContext* context) - { -- wStream* s = nullptr; -- RDPDR_HEADER header = WINPR_C_ARRAY_INIT; -- UINT16 numCapabilities = 0; -- UINT error = 0; - WINPR_ASSERT(context); - WINPR_ASSERT(context->priv); - -- header.Component = RDPDR_CTYP_CORE; -- header.PacketId = PAKID_CORE_SERVER_CAPABILITY; -- numCapabilities = 1; -- -+ UINT16 numCapabilities = 1; - if ((context->supported & RDPDR_DTYP_FILESYSTEM) != 0) - numCapabilities++; - -@@ -845,19 +829,23 @@ static UINT rdpdr_server_send_core_capability_request(RdpdrServerContext* contex - numCapabilities++; - - RdpdrServerPrivate* priv = context->priv; -- s = Stream_New(nullptr, RDPDR_HEADER_LENGTH + 512); -- -+ wStream* s = Stream_New(nullptr, RDPDR_HEADER_LENGTH + 512); - if (!s) - { - WLog_Print(priv->log, WLOG_ERROR, "Stream_New failed!"); - return CHANNEL_RC_NO_MEMORY; - } - -+ const RDPDR_HEADER header = { -+ .Component = RDPDR_CTYP_CORE, -+ .PacketId = PAKID_CORE_SERVER_CAPABILITY, -+ }; - Stream_Write_UINT16(s, header.Component); /* Component (2 bytes) */ - Stream_Write_UINT16(s, header.PacketId); /* PacketId (2 bytes) */ - Stream_Write_UINT16(s, numCapabilities); /* numCapabilities (2 bytes) */ - Stream_Write_UINT16(s, 0); /* Padding (2 bytes) */ - -+ UINT error = 0; - if ((error = rdpdr_server_write_general_capability_set(context, s))) - { - WLog_Print(priv->log, WLOG_ERROR, -@@ -943,9 +931,6 @@ static UINT16 rdpdr_cap_type_to_dtyp(UINT16 capabilityType) - static UINT rdpdr_server_receive_core_capability_response(RdpdrServerContext* context, wStream* s, - const RDPDR_HEADER* header) - { -- UINT status = 0; -- UINT16 numCapabilities = 0; -- - WINPR_ASSERT(context); - WINPR_ASSERT(context->priv); - -@@ -956,6 +941,7 @@ static UINT rdpdr_server_receive_core_capability_response(RdpdrServerContext* co - if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 4)) - return ERROR_INVALID_DATA; - -+ UINT16 numCapabilities = 0; - Stream_Read_UINT16(s, numCapabilities); /* numCapabilities (2 bytes) */ - Stream_Seek_UINT16(s); /* Padding (2 bytes) */ - -@@ -965,6 +951,7 @@ static UINT rdpdr_server_receive_core_capability_response(RdpdrServerContext* co - RDPDR_CAPABILITY_HEADER capabilityHeader = WINPR_C_ARRAY_INIT; - const size_t start = Stream_GetPosition(s); - -+ UINT status = 0; - if ((status = rdpdr_read_capset_header(priv->log, s, &capabilityHeader))) - { - WLog_Print(priv->log, WLOG_ERROR, "failed with error %" PRIu32 "!", status); -@@ -1067,24 +1054,21 @@ static UINT rdpdr_server_receive_core_capability_response(RdpdrServerContext* co - */ - static UINT rdpdr_server_send_client_id_confirm(RdpdrServerContext* context) - { -- wStream* s = nullptr; -- RDPDR_HEADER header = WINPR_C_ARRAY_INIT; -- - WINPR_ASSERT(context); - WINPR_ASSERT(context->priv); - -- header.Component = RDPDR_CTYP_CORE; -- header.PacketId = PAKID_CORE_CLIENTID_CONFIRM; -- - RdpdrServerPrivate* priv = context->priv; -- s = Stream_New(nullptr, RDPDR_HEADER_LENGTH + 8); -- -+ wStream* s = Stream_New(nullptr, RDPDR_HEADER_LENGTH + 8); - if (!s) - { - WLog_Print(priv->log, WLOG_ERROR, "Stream_New failed!"); - return CHANNEL_RC_NO_MEMORY; - } - -+ const RDPDR_HEADER header = { -+ .Component = RDPDR_CTYP_CORE, -+ .PacketId = PAKID_CORE_CLIENTID_CONFIRM, -+ }; - Stream_Write_UINT16(s, header.Component); /* Component (2 bytes) */ - Stream_Write_UINT16(s, header.PacketId); /* PacketId (2 bytes) */ - Stream_Write_UINT16(s, priv->VersionMajor); /* VersionMajor (2 bytes) */ -@@ -1102,8 +1086,6 @@ static UINT rdpdr_server_receive_device_list_announce_request(RdpdrServerContext - wStream* s, - const RDPDR_HEADER* header) - { -- UINT32 DeviceCount = 0; -- - WINPR_ASSERT(context); - WINPR_ASSERT(context->priv); - -@@ -1114,17 +1096,16 @@ static UINT rdpdr_server_receive_device_list_announce_request(RdpdrServerContext - if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 4)) - return ERROR_INVALID_DATA; - -+ UINT32 DeviceCount = 0; - Stream_Read_UINT32(s, DeviceCount); /* DeviceCount (4 bytes) */ - WLog_Print(priv->log, WLOG_DEBUG, "DeviceCount: %" PRIu32 "", DeviceCount); - - for (UINT32 i = 0; i < DeviceCount; i++) - { -- UINT error = 0; -- RdpdrDevice device = WINPR_C_ARRAY_INIT; -- - if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 20)) - return ERROR_INVALID_DATA; - -+ RdpdrDevice device = WINPR_C_ARRAY_INIT; - Stream_Read_UINT32(s, device.DeviceType); /* DeviceType (4 bytes) */ - Stream_Read_UINT32(s, device.DeviceId); /* DeviceId (4 bytes) */ - Stream_Read(s, device.PreferredDosName, 8); /* PreferredDosName (8 bytes) */ -@@ -1137,7 +1118,7 @@ static UINT rdpdr_server_receive_device_list_announce_request(RdpdrServerContext - if (!rdpdr_add_device(context->priv, &device)) - return ERROR_INTERNAL_ERROR; - -- error = IFCALLRESULT(CHANNEL_RC_OK, context->ReceiveDeviceAnnounce, context, &device); -+ UINT error = IFCALLRESULT(CHANNEL_RC_OK, context->ReceiveDeviceAnnounce, context, &device); - if (error != CHANNEL_RC_OK) - return error; - -@@ -1219,9 +1200,6 @@ static UINT rdpdr_server_receive_device_list_announce_request(RdpdrServerContext - static UINT rdpdr_server_receive_device_list_remove_request(RdpdrServerContext* context, wStream* s, - const RDPDR_HEADER* header) - { -- UINT32 DeviceCount = 0; -- UINT32 DeviceType = 0; -- UINT32 DeviceId = 0; - WINPR_ASSERT(context); - WINPR_ASSERT(context->priv); - -@@ -1232,6 +1210,7 @@ static UINT rdpdr_server_receive_device_list_remove_request(RdpdrServerContext* - if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 4)) - return ERROR_INVALID_DATA; - -+ UINT32 DeviceCount = 0; - Stream_Read_UINT32(s, DeviceCount); /* DeviceCount (4 bytes) */ - WLog_Print(priv->log, WLOG_DEBUG, "DeviceCount: %" PRIu32 "", DeviceCount); - -@@ -1243,10 +1222,11 @@ static UINT rdpdr_server_receive_device_list_remove_request(RdpdrServerContext* - if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 4)) - return ERROR_INVALID_DATA; - -+ UINT32 DeviceId = 0; - Stream_Read_UINT32(s, DeviceId); /* DeviceId (4 bytes) */ - device = rdpdr_get_device_by_id(context->priv, DeviceId); - WLog_Print(priv->log, WLOG_DEBUG, "Device %" PRIu32 " Id: 0x%08" PRIX32 "", i, DeviceId); -- DeviceType = 0; -+ UINT32 DeviceType = 0; - if (device) - DeviceType = device->DeviceType; - -@@ -1305,7 +1285,12 @@ static UINT rdpdr_server_receive_io_create_request(RdpdrServerContext* context, - WINPR_ATTR_UNUSED UINT32 FileId, - WINPR_ATTR_UNUSED UINT32 CompletionId) - { -- const WCHAR* path = nullptr; -+ WINPR_ASSERT(context); -+ -+ RdpdrServerPrivate* priv = context->priv; -+ if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 32)) -+ return ERROR_INVALID_DATA; -+ - UINT32 DesiredAccess = 0; - UINT32 AllocationSize = 0; - UINT32 FileAttributes = 0; -@@ -1313,13 +1298,6 @@ static UINT rdpdr_server_receive_io_create_request(RdpdrServerContext* context, - UINT32 CreateDisposition = 0; - UINT32 CreateOptions = 0; - UINT32 PathLength = 0; -- -- WINPR_ASSERT(context); -- -- RdpdrServerPrivate* priv = context->priv; -- if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 32)) -- return ERROR_INVALID_DATA; -- - Stream_Read_UINT32(s, DesiredAccess); - Stream_Read_UINT32(s, AllocationSize); - Stream_Read_UINT32(s, FileAttributes); -@@ -1328,7 +1306,7 @@ static UINT rdpdr_server_receive_io_create_request(RdpdrServerContext* context, - Stream_Read_UINT32(s, CreateOptions); - Stream_Read_UINT32(s, PathLength); - -- path = rdpdr_read_ustring(priv->log, s, PathLength); -+ const WCHAR* path = rdpdr_read_ustring(priv->log, s, PathLength); - if (!path && (PathLength > 0)) - return ERROR_INVALID_DATA; - -@@ -1366,9 +1344,6 @@ static UINT rdpdr_server_receive_io_read_request(RdpdrServerContext* context, wS - WINPR_ATTR_UNUSED UINT32 FileId, - WINPR_ATTR_UNUSED UINT32 CompletionId) - { -- UINT32 Length = 0; -- UINT64 Offset = 0; -- - WINPR_ASSERT(context); - WINPR_ASSERT(context->priv); - -@@ -1376,6 +1351,8 @@ static UINT rdpdr_server_receive_io_read_request(RdpdrServerContext* context, wS - if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 32)) - return ERROR_INVALID_DATA; - -+ UINT32 Length = 0; -+ UINT64 Offset = 0; - Stream_Read_UINT32(s, Length); - Stream_Read_UINT64(s, Offset); - Stream_Seek(s, 20); /* Padding */ -@@ -1395,9 +1372,6 @@ static UINT rdpdr_server_receive_io_write_request(RdpdrServerContext* context, w - WINPR_ATTR_UNUSED UINT32 FileId, - WINPR_ATTR_UNUSED UINT32 CompletionId) - { -- UINT32 Length = 0; -- UINT64 Offset = 0; -- - WINPR_ASSERT(context); - WINPR_ASSERT(context->priv); - -@@ -1406,6 +1380,8 @@ static UINT rdpdr_server_receive_io_write_request(RdpdrServerContext* context, w - if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 32)) - return ERROR_INVALID_DATA; - -+ UINT32 Length = 0; -+ UINT64 Offset = 0; - Stream_Read_UINT32(s, Length); - Stream_Read_UINT64(s, Offset); - Stream_Seek(s, 20); /* Padding */ -@@ -1430,10 +1406,6 @@ static UINT rdpdr_server_receive_io_device_control_request(RdpdrServerContext* c - WINPR_ATTR_UNUSED UINT32 FileId, - WINPR_ATTR_UNUSED UINT32 CompletionId) - { -- UINT32 OutputBufferLength = 0; -- UINT32 InputBufferLength = 0; -- UINT32 IoControlCode = 0; -- - WINPR_ASSERT(context); - WINPR_ASSERT(context->priv); - -@@ -1442,6 +1414,9 @@ static UINT rdpdr_server_receive_io_device_control_request(RdpdrServerContext* c - if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 32)) - return ERROR_INVALID_DATA; - -+ UINT32 OutputBufferLength = 0; -+ UINT32 InputBufferLength = 0; -+ UINT32 IoControlCode = 0; - Stream_Read_UINT32(s, OutputBufferLength); - Stream_Read_UINT32(s, InputBufferLength); - Stream_Read_UINT32(s, IoControlCode); -@@ -1464,15 +1439,14 @@ static UINT rdpdr_server_receive_io_query_volume_information_request( - RdpdrServerContext* context, wStream* s, WINPR_ATTR_UNUSED UINT32 DeviceId, - WINPR_ATTR_UNUSED UINT32 FileId, WINPR_ATTR_UNUSED UINT32 CompletionId) - { -- UINT32 FsInformationClass = 0; -- UINT32 Length = 0; -- - WINPR_ASSERT(context); - - RdpdrServerPrivate* priv = context->priv; - if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 32)) - return ERROR_INVALID_DATA; - -+ UINT32 FsInformationClass = 0; -+ UINT32 Length = 0; - Stream_Read_UINT32(s, FsInformationClass); - Stream_Read_UINT32(s, Length); - Stream_Seek(s, 24); /* Padding */ -@@ -1498,9 +1472,6 @@ static UINT rdpdr_server_receive_io_set_volume_information_request( - RdpdrServerContext* context, wStream* s, WINPR_ATTR_UNUSED UINT32 DeviceId, - WINPR_ATTR_UNUSED UINT32 FileId, WINPR_ATTR_UNUSED UINT32 CompletionId) - { -- UINT32 FsInformationClass = 0; -- UINT32 Length = 0; -- - WINPR_ASSERT(context); - WINPR_ASSERT(context->priv); - -@@ -1509,6 +1480,8 @@ static UINT rdpdr_server_receive_io_set_volume_information_request( - if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 32)) - return ERROR_INVALID_DATA; - -+ UINT32 FsInformationClass = 0; -+ UINT32 Length = 0; - Stream_Read_UINT32(s, FsInformationClass); - Stream_Read_UINT32(s, Length); - Stream_Seek(s, 24); /* Padding */ -@@ -1536,9 +1509,6 @@ static UINT rdpdr_server_receive_io_query_information_request(RdpdrServerContext - WINPR_ATTR_UNUSED UINT32 FileId, - WINPR_ATTR_UNUSED UINT32 CompletionId) - { -- UINT32 FsInformationClass = 0; -- UINT32 Length = 0; -- - WINPR_ASSERT(context); - WINPR_ASSERT(context->priv); - -@@ -1547,6 +1517,8 @@ static UINT rdpdr_server_receive_io_query_information_request(RdpdrServerContext - if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 32)) - return ERROR_INVALID_DATA; - -+ UINT32 FsInformationClass = 0; -+ UINT32 Length = 0; - Stream_Read_UINT32(s, FsInformationClass); - Stream_Read_UINT32(s, Length); - Stream_Seek(s, 24); /* Padding */ -@@ -1573,9 +1545,6 @@ static UINT rdpdr_server_receive_io_set_information_request(RdpdrServerContext* - WINPR_ATTR_UNUSED UINT32 FileId, - WINPR_ATTR_UNUSED UINT32 CompletionId) - { -- UINT32 FsInformationClass = 0; -- UINT32 Length = 0; -- - WINPR_ASSERT(context); - WINPR_ASSERT(context->priv); - -@@ -1584,6 +1553,8 @@ static UINT rdpdr_server_receive_io_set_information_request(RdpdrServerContext* - if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 32)) - return ERROR_INVALID_DATA; - -+ UINT32 FsInformationClass = 0; -+ UINT32 Length = 0; - Stream_Read_UINT32(s, FsInformationClass); - Stream_Read_UINT32(s, Length); - Stream_Seek(s, 24); /* Padding */ -@@ -1610,10 +1581,6 @@ static UINT rdpdr_server_receive_io_query_directory_request(RdpdrServerContext* - WINPR_ATTR_UNUSED UINT32 FileId, - WINPR_ATTR_UNUSED UINT32 CompletionId) - { -- BYTE InitialQuery = 0; -- UINT32 FsInformationClass = 0; -- UINT32 PathLength = 0; -- - WINPR_ASSERT(context); - WINPR_ASSERT(context->priv); - -@@ -1622,6 +1589,9 @@ static UINT rdpdr_server_receive_io_query_directory_request(RdpdrServerContext* - if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 32)) - return ERROR_INVALID_DATA; - -+ UINT32 FsInformationClass = 0; -+ BYTE InitialQuery = 0; -+ UINT32 PathLength = 0; - Stream_Read_UINT32(s, FsInformationClass); - Stream_Read_UINT8(s, InitialQuery); - Stream_Read_UINT32(s, PathLength); -@@ -1653,9 +1623,6 @@ static UINT rdpdr_server_receive_io_change_directory_request(RdpdrServerContext* - WINPR_ATTR_UNUSED UINT32 FileId, - WINPR_ATTR_UNUSED UINT32 CompletionId) - { -- BYTE WatchTree = 0; -- UINT32 CompletionFilter = 0; -- - WINPR_ASSERT(context); - WINPR_ASSERT(context->priv); - -@@ -1664,6 +1631,8 @@ static UINT rdpdr_server_receive_io_change_directory_request(RdpdrServerContext* - if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 32)) - return ERROR_INVALID_DATA; - -+ BYTE WatchTree = 0; -+ UINT32 CompletionFilter = 0; - Stream_Read_UINT8(s, WatchTree); - Stream_Read_UINT32(s, CompletionFilter); - Stream_Seek(s, 27); /* Padding */ -@@ -1754,12 +1723,6 @@ static UINT rdpdr_server_receive_io_lock_control_request(RdpdrServerContext* con - static UINT rdpdr_server_receive_device_io_request(RdpdrServerContext* context, wStream* s, - WINPR_ATTR_UNUSED const RDPDR_HEADER* header) - { -- UINT32 DeviceId = 0; -- UINT32 FileId = 0; -- UINT32 CompletionId = 0; -- UINT32 MajorFunction = 0; -- UINT32 MinorFunction = 0; -- - WINPR_ASSERT(context); - WINPR_ASSERT(context->priv); - WINPR_ASSERT(header); -@@ -1769,6 +1732,11 @@ static UINT rdpdr_server_receive_device_io_request(RdpdrServerContext* context, - if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 20)) - return ERROR_INVALID_DATA; - -+ UINT32 DeviceId = 0; -+ UINT32 FileId = 0; -+ UINT32 CompletionId = 0; -+ UINT32 MajorFunction = 0; -+ UINT32 MinorFunction = 0; - Stream_Read_UINT32(s, DeviceId); - Stream_Read_UINT32(s, FileId); - Stream_Read_UINT32(s, CompletionId); -@@ -1836,11 +1804,6 @@ static UINT rdpdr_server_receive_device_io_request(RdpdrServerContext* context, - static UINT rdpdr_server_receive_device_io_completion(RdpdrServerContext* context, wStream* s, - const RDPDR_HEADER* header) - { -- UINT32 deviceId = 0; -- UINT32 completionId = 0; -- UINT32 ioStatus = 0; -- RDPDR_IRP* irp = nullptr; -- UINT error = CHANNEL_RC_OK; - WINPR_ASSERT(context); - WINPR_ASSERT(context->priv); - WINPR_ASSERT(s); -@@ -1853,13 +1816,16 @@ static UINT rdpdr_server_receive_device_io_completion(RdpdrServerContext* contex - if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 12)) - return ERROR_INVALID_DATA; - -+ UINT32 deviceId = 0; -+ UINT32 completionId = 0; -+ UINT32 ioStatus = 0; - Stream_Read_UINT32(s, deviceId); - Stream_Read_UINT32(s, completionId); - Stream_Read_UINT32(s, ioStatus); - WLog_Print(priv->log, WLOG_DEBUG, - "deviceId=%" PRIu32 ", completionId=0x%" PRIx32 ", ioStatus=0x%" PRIx32 "", deviceId, - completionId, ioStatus); -- irp = rdpdr_server_dequeue_irp(context, completionId); -+ RDPDR_IRP* irp = rdpdr_server_dequeue_irp(context, completionId); - - if (!irp) - { -@@ -1869,6 +1835,7 @@ static UINT rdpdr_server_receive_device_io_completion(RdpdrServerContext* contex - } - - /* Invoke the callback. */ -+ UINT error = CHANNEL_RC_OK; - if (irp->Callback) - { - error = (*irp->Callback)(context, s, irp, deviceId, completionId, ioStatus); -@@ -1884,24 +1851,21 @@ static UINT rdpdr_server_receive_device_io_completion(RdpdrServerContext* contex - */ - static UINT rdpdr_server_send_user_logged_on(RdpdrServerContext* context) - { -- wStream* s = nullptr; -- RDPDR_HEADER header = WINPR_C_ARRAY_INIT; -- - WINPR_ASSERT(context); - WINPR_ASSERT(context->priv); - -- header.Component = RDPDR_CTYP_CORE; -- header.PacketId = PAKID_CORE_USER_LOGGEDON; -- - RdpdrServerPrivate* priv = context->priv; -- s = Stream_New(nullptr, RDPDR_HEADER_LENGTH); -- -+ wStream* s = Stream_New(nullptr, RDPDR_HEADER_LENGTH); - if (!s) - { - WLog_Print(priv->log, WLOG_ERROR, "Stream_New failed!"); - return CHANNEL_RC_NO_MEMORY; - } - -+ const RDPDR_HEADER header = { -+ .Component = RDPDR_CTYP_CORE, -+ .PacketId = PAKID_CORE_USER_LOGGEDON, -+ }; - Stream_Write_UINT16(s, header.Component); /* Component (2 bytes) */ - Stream_Write_UINT16(s, header.PacketId); /* PacketId (2 bytes) */ - return rdpdr_seal_send_free_request(context, s); -@@ -1909,15 +1873,6 @@ static UINT rdpdr_server_send_user_logged_on(RdpdrServerContext* context) - - static UINT rdpdr_server_receive_prn_cache_add_printer(RdpdrServerContext* context, wStream* s) - { -- char PortDosName[9] = WINPR_C_ARRAY_INIT; -- UINT32 PnPNameLen = 0; -- UINT32 DriverNameLen = 0; -- UINT32 PrinterNameLen = 0; -- UINT32 CachedFieldsLen = 0; -- const WCHAR* PnPName = nullptr; -- const WCHAR* DriverName = nullptr; -- const WCHAR* PrinterName = nullptr; -- - WINPR_ASSERT(context); - WINPR_ASSERT(context->priv); - -@@ -1926,19 +1881,24 @@ static UINT rdpdr_server_receive_prn_cache_add_printer(RdpdrServerContext* conte - if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 24)) - return ERROR_INVALID_DATA; - -+ char PortDosName[9] = WINPR_C_ARRAY_INIT; -+ UINT32 PnPNameLen = 0; -+ UINT32 DriverNameLen = 0; -+ UINT32 PrinterNameLen = 0; -+ UINT32 CachedFieldsLen = 0; - Stream_Read(s, PortDosName, 8); - Stream_Read_UINT32(s, PnPNameLen); - Stream_Read_UINT32(s, DriverNameLen); - Stream_Read_UINT32(s, PrinterNameLen); - Stream_Read_UINT32(s, CachedFieldsLen); - -- PnPName = rdpdr_read_ustring(priv->log, s, PnPNameLen); -+ const WCHAR* PnPName = rdpdr_read_ustring(priv->log, s, PnPNameLen); - if (!PnPName && (PnPNameLen > 0)) - return ERROR_INVALID_DATA; -- DriverName = rdpdr_read_ustring(priv->log, s, DriverNameLen); -+ const WCHAR* DriverName = rdpdr_read_ustring(priv->log, s, DriverNameLen); - if (!DriverName && (DriverNameLen > 0)) - return ERROR_INVALID_DATA; -- PrinterName = rdpdr_read_ustring(priv->log, s, PrinterNameLen); -+ const WCHAR* PrinterName = rdpdr_read_ustring(priv->log, s, PrinterNameLen); - if (!PrinterName && (PrinterNameLen > 0)) - return ERROR_INVALID_DATA; - -@@ -1954,10 +1914,6 @@ static UINT rdpdr_server_receive_prn_cache_add_printer(RdpdrServerContext* conte - - static UINT rdpdr_server_receive_prn_cache_update_printer(RdpdrServerContext* context, wStream* s) - { -- UINT32 PrinterNameLen = 0; -- UINT32 CachedFieldsLen = 0; -- const WCHAR* PrinterName = nullptr; -- - WINPR_ASSERT(context); - - RdpdrServerPrivate* priv = context->priv; -@@ -1965,10 +1921,12 @@ static UINT rdpdr_server_receive_prn_cache_update_printer(RdpdrServerContext* co - if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 8)) - return ERROR_INVALID_DATA; - -+ UINT32 PrinterNameLen = 0; -+ UINT32 CachedFieldsLen = 0; - Stream_Read_UINT32(s, PrinterNameLen); - Stream_Read_UINT32(s, CachedFieldsLen); - -- PrinterName = rdpdr_read_ustring(priv->log, s, PrinterNameLen); -+ const WCHAR* PrinterName = rdpdr_read_ustring(priv->log, s, PrinterNameLen); - if (!PrinterName && (PrinterNameLen > 0)) - return ERROR_INVALID_DATA; - -@@ -1986,9 +1944,6 @@ static UINT rdpdr_server_receive_prn_cache_update_printer(RdpdrServerContext* co - - static UINT rdpdr_server_receive_prn_cache_delete_printer(RdpdrServerContext* context, wStream* s) - { -- UINT32 PrinterNameLen = 0; -- const WCHAR* PrinterName = nullptr; -- - WINPR_ASSERT(context); - WINPR_ASSERT(context->priv); - -@@ -1997,9 +1952,10 @@ static UINT rdpdr_server_receive_prn_cache_delete_printer(RdpdrServerContext* co - if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 4)) - return ERROR_INVALID_DATA; - -+ UINT32 PrinterNameLen = 0; - Stream_Read_UINT32(s, PrinterNameLen); - -- PrinterName = rdpdr_read_ustring(priv->log, s, PrinterNameLen); -+ const WCHAR* PrinterName = rdpdr_read_ustring(priv->log, s, PrinterNameLen); - if (!PrinterName && (PrinterNameLen > 0)) - return ERROR_INVALID_DATA; - -@@ -2012,11 +1968,6 @@ static UINT rdpdr_server_receive_prn_cache_delete_printer(RdpdrServerContext* co - - static UINT rdpdr_server_receive_prn_cache_rename_cachedata(RdpdrServerContext* context, wStream* s) - { -- UINT32 OldPrinterNameLen = 0; -- UINT32 NewPrinterNameLen = 0; -- const WCHAR* OldPrinterName = nullptr; -- const WCHAR* NewPrinterName = nullptr; -- - WINPR_ASSERT(context); - WINPR_ASSERT(context->priv); - -@@ -2025,13 +1976,15 @@ static UINT rdpdr_server_receive_prn_cache_rename_cachedata(RdpdrServerContext* - if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 8)) - return ERROR_INVALID_DATA; - -+ UINT32 OldPrinterNameLen = 0; -+ UINT32 NewPrinterNameLen = 0; - Stream_Read_UINT32(s, OldPrinterNameLen); - Stream_Read_UINT32(s, NewPrinterNameLen); - -- OldPrinterName = rdpdr_read_ustring(priv->log, s, OldPrinterNameLen); -+ const WCHAR* OldPrinterName = rdpdr_read_ustring(priv->log, s, OldPrinterNameLen); - if (!OldPrinterName && (OldPrinterNameLen > 0)) - return ERROR_INVALID_DATA; -- NewPrinterName = rdpdr_read_ustring(priv->log, s, NewPrinterNameLen); -+ const WCHAR* NewPrinterName = rdpdr_read_ustring(priv->log, s, NewPrinterNameLen); - if (!NewPrinterName && (NewPrinterNameLen > 0)) - return ERROR_INVALID_DATA; - -@@ -2046,8 +1999,6 @@ static UINT - rdpdr_server_receive_prn_cache_data_request(RdpdrServerContext* context, wStream* s, - WINPR_ATTR_UNUSED const RDPDR_HEADER* header) - { -- UINT32 EventId = 0; -- - WINPR_ASSERT(context); - WINPR_ASSERT(context->priv); - WINPR_ASSERT(header); -@@ -2056,6 +2007,7 @@ rdpdr_server_receive_prn_cache_data_request(RdpdrServerContext* context, wStream - if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 4)) - return ERROR_INVALID_DATA; - -+ UINT32 EventId = 0; - Stream_Read_UINT32(s, EventId); - switch (EventId) - { -@@ -2077,9 +2029,6 @@ rdpdr_server_receive_prn_cache_data_request(RdpdrServerContext* context, wStream - static UINT rdpdr_server_receive_prn_using_xps_request(RdpdrServerContext* context, wStream* s, - WINPR_ATTR_UNUSED const RDPDR_HEADER* header) - { -- UINT32 PrinterId = 0; -- UINT32 Flags = 0; -- - WINPR_ASSERT(context); - WINPR_ASSERT(context->priv); - WINPR_ASSERT(header); -@@ -2089,6 +2038,8 @@ static UINT rdpdr_server_receive_prn_using_xps_request(RdpdrServerContext* conte - if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 8)) - return ERROR_INVALID_DATA; - -+ UINT32 PrinterId = 0; -+ UINT32 Flags = 0; - Stream_Read_UINT32(s, PrinterId); - Stream_Read_UINT32(s, Flags); - -@@ -2227,20 +2178,19 @@ static UINT rdpdr_server_receive_pdu(RdpdrServerContext* context, wStream* s, - - static DWORD WINAPI rdpdr_server_thread(LPVOID arg) - { -- DWORD status = 0; -- DWORD nCount = 0; -- void* buffer = nullptr; -- HANDLE events[8] = WINPR_C_ARRAY_INIT; -- HANDLE ChannelEvent = nullptr; -- DWORD BytesReturned = 0; -- UINT error = 0; - RdpdrServerContext* context = (RdpdrServerContext*)arg; -- wStream* s = Stream_New(nullptr, 4096); - - WINPR_ASSERT(context); - WINPR_ASSERT(context->priv); - -+ UINT error = 0; - RdpdrServerPrivate* priv = context->priv; -+ DWORD nCount = 0; -+ void* buffer = nullptr; -+ HANDLE events[8] = WINPR_C_ARRAY_INIT; -+ HANDLE ChannelEvent = nullptr; -+ DWORD BytesReturned = 0; -+ wStream* s = Stream_New(nullptr, 4096); - - if (!s) - { -@@ -2273,7 +2223,7 @@ static DWORD WINAPI rdpdr_server_thread(LPVOID arg) - { - size_t capacity = 0; - BytesReturned = 0; -- status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE); -+ DWORD status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE); - - if (status == WAIT_FAILED) - { -@@ -2399,19 +2349,17 @@ static UINT rdpdr_server_start(RdpdrServerContext* context) - */ - static UINT rdpdr_server_stop(RdpdrServerContext* context) - { -- UINT error = 0; - WINPR_ASSERT(context); - WINPR_ASSERT(context->priv); - - RdpdrServerPrivate* priv = context->priv; -- - if (priv->StopEvent) - { - (void)SetEvent(priv->StopEvent); - - if (WaitForSingleObject(priv->Thread, INFINITE) == WAIT_FAILED) - { -- error = GetLastError(); -+ UINT error = GetLastError(); - WLog_Print(priv->log, WLOG_ERROR, "WaitForSingleObject failed with error %" PRIu32 "!", - error); - return error; -@@ -2452,7 +2400,6 @@ static void rdpdr_server_write_device_iorequest(wStream* s, UINT32 deviceId, UIN - static UINT rdpdr_server_read_file_directory_information(wLog* log, wStream* s, - FILE_DIRECTORY_INFORMATION* fdi) - { -- UINT32 fileNameLength = 0; - WINPR_ASSERT(fdi); - ZeroMemory(fdi, sizeof(FILE_DIRECTORY_INFORMATION)); - -@@ -2468,6 +2415,7 @@ static UINT rdpdr_server_read_file_directory_information(wLog* log, wStream* s, - Stream_Read_INT64(s, fdi->EndOfFile.QuadPart); /* EndOfFile (8 bytes) */ - Stream_Read_INT64(s, fdi->AllocationSize.QuadPart); /* AllocationSize (8 bytes) */ - Stream_Read_UINT32(s, fdi->FileAttributes); /* FileAttributes (4 bytes) */ -+ UINT32 fileNameLength = 0; - Stream_Read_UINT32(s, fileNameLength); /* FileNameLength (4 bytes) */ - - if (!Stream_CheckAndLogRequiredLengthWLog(log, s, fileNameLength)) -@@ -2497,8 +2445,6 @@ static UINT rdpdr_server_send_device_create_request(RdpdrServerContext* context, - UINT32 desiredAccess, UINT32 createOptions, - UINT32 createDisposition) - { -- size_t pathLength = 0; -- wStream* s = nullptr; - WINPR_ASSERT(context); - WINPR_ASSERT(context->priv); - -@@ -2510,8 +2456,8 @@ static UINT rdpdr_server_send_device_create_request(RdpdrServerContext* context, - " createDisposition=0x%" PRIx32 "", - deviceId, path, desiredAccess, createOptions, createDisposition); - /* Compute the required Unicode size. */ -- pathLength = (strlen(path) + 1U) * sizeof(WCHAR); -- s = Stream_New(nullptr, 256U + pathLength); -+ size_t pathLength = (strlen(path) + 1U) * sizeof(WCHAR); -+ wStream* s = Stream_New(nullptr, 256U + pathLength); - - if (!s) - { -@@ -2547,7 +2493,6 @@ static UINT rdpdr_server_send_device_create_request(RdpdrServerContext* context, - static UINT rdpdr_server_send_device_close_request(RdpdrServerContext* context, UINT32 deviceId, - UINT32 fileId, UINT32 completionId) - { -- wStream* s = nullptr; - WINPR_ASSERT(context); - WINPR_ASSERT(context->priv); - -@@ -2556,7 +2501,7 @@ static UINT rdpdr_server_send_device_close_request(RdpdrServerContext* context, - WLog_Print(priv->log, WLOG_DEBUG, - "RdpdrServerSendDeviceCloseRequest: deviceId=%" PRIu32 ", fileId=%" PRIu32 "", - deviceId, fileId); -- s = Stream_New(nullptr, 128); -+ wStream* s = Stream_New(nullptr, 128); - - if (!s) - { -@@ -2578,7 +2523,6 @@ static UINT rdpdr_server_send_device_read_request(RdpdrServerContext* context, U - UINT32 fileId, UINT32 completionId, UINT32 length, - UINT32 offset) - { -- wStream* s = nullptr; - WINPR_ASSERT(context); - WINPR_ASSERT(context->priv); - -@@ -2588,7 +2532,7 @@ static UINT rdpdr_server_send_device_read_request(RdpdrServerContext* context, U - "RdpdrServerSendDeviceReadRequest: deviceId=%" PRIu32 ", fileId=%" PRIu32 - ", length=%" PRIu32 ", offset=%" PRIu32 "", - deviceId, fileId, length, offset); -- s = Stream_New(nullptr, 128); -+ wStream* s = Stream_New(nullptr, 128); - - if (!s) - { -@@ -2613,7 +2557,6 @@ static UINT rdpdr_server_send_device_write_request(RdpdrServerContext* context, - UINT32 fileId, UINT32 completionId, - const char* data, UINT32 length, UINT32 offset) - { -- wStream* s = nullptr; - WINPR_ASSERT(context); - WINPR_ASSERT(context->priv); - -@@ -2623,7 +2566,7 @@ static UINT rdpdr_server_send_device_write_request(RdpdrServerContext* context, - "RdpdrServerSendDeviceWriteRequest: deviceId=%" PRIu32 ", fileId=%" PRIu32 - ", length=%" PRIu32 ", offset=%" PRIu32 "", - deviceId, fileId, length, offset); -- s = Stream_New(nullptr, 64 + length); -+ wStream* s = Stream_New(nullptr, 64 + length); - - if (!s) - { -@@ -2649,8 +2592,6 @@ static UINT rdpdr_server_send_device_query_directory_request(RdpdrServerContext* - UINT32 deviceId, UINT32 fileId, - UINT32 completionId, const char* path) - { -- size_t pathLength = 0; -- wStream* s = nullptr; - WINPR_ASSERT(context); - WINPR_ASSERT(context->priv); - -@@ -2661,8 +2602,8 @@ static UINT rdpdr_server_send_device_query_directory_request(RdpdrServerContext* - ", path=%s", - deviceId, fileId, path); - /* Compute the required Unicode size. */ -- pathLength = path ? (strlen(path) + 1) * sizeof(WCHAR) : 0; -- s = Stream_New(nullptr, 64 + pathLength); -+ size_t pathLength = path ? (strlen(path) + 1) * sizeof(WCHAR) : 0; -+ wStream* s = Stream_New(nullptr, 64 + pathLength); - - if (!s) - { -@@ -2701,8 +2642,6 @@ static UINT rdpdr_server_send_device_file_rename_request(RdpdrServerContext* con - UINT32 deviceId, UINT32 fileId, - UINT32 completionId, const char* path) - { -- size_t pathLength = 0; -- wStream* s = nullptr; - WINPR_ASSERT(context); - WINPR_ASSERT(context->priv); - -@@ -2713,8 +2652,8 @@ static UINT rdpdr_server_send_device_file_rename_request(RdpdrServerContext* con - ", path=%s", - deviceId, fileId, path); - /* Compute the required Unicode size. */ -- pathLength = path ? (strlen(path) + 1) * sizeof(WCHAR) : 0; -- s = Stream_New(nullptr, 64 + pathLength); -+ size_t pathLength = path ? (strlen(path) + 1) * sizeof(WCHAR) : 0; -+ wStream* s = Stream_New(nullptr, 64 + pathLength); - - if (!s) - { -@@ -2851,14 +2790,13 @@ static UINT rdpdr_server_drive_create_directory_callback1(RdpdrServerContext* co - static UINT rdpdr_server_drive_create_directory(RdpdrServerContext* context, void* callbackData, - UINT32 deviceId, const char* path) - { -- RDPDR_IRP* irp = nullptr; - WINPR_ASSERT(context); - WINPR_ASSERT(context->priv); - WINPR_ASSERT(callbackData); - WINPR_ASSERT(path); - - RdpdrServerPrivate* priv = context->priv; -- irp = rdpdr_server_irp_new(); -+ RDPDR_IRP* irp = rdpdr_server_irp_new(); - - if (!irp) - { -@@ -2977,12 +2915,11 @@ static UINT rdpdr_server_drive_delete_directory_callback1(RdpdrServerContext* co - static UINT rdpdr_server_drive_delete_directory(RdpdrServerContext* context, void* callbackData, - UINT32 deviceId, const char* path) - { -- RDPDR_IRP* irp = rdpdr_server_irp_new(); - WINPR_ASSERT(context); - WINPR_ASSERT(context->priv); -- WINPR_ASSERT(irp); - - RdpdrServerPrivate* priv = context->priv; -+ RDPDR_IRP* irp = rdpdr_server_irp_new(); - - if (!irp) - { -@@ -3023,10 +2960,6 @@ static UINT rdpdr_server_drive_query_directory_callback2(RdpdrServerContext* con - RDPDR_IRP* irp, UINT32 deviceId, - UINT32 completionId, UINT32 ioStatus) - { -- UINT error = 0; -- UINT32 length = 0; -- FILE_DIRECTORY_INFORMATION fdi = WINPR_C_ARRAY_INIT; -- - WINPR_ASSERT(context); - WINPR_ASSERT(context->priv); - WINPR_ASSERT(irp); -@@ -3040,11 +2973,14 @@ static UINT rdpdr_server_drive_query_directory_callback2(RdpdrServerContext* con - if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 4)) - return ERROR_INVALID_DATA; - -+ UINT32 length = 0; - Stream_Read_UINT32(s, length); /* Length (4 bytes) */ - -+ FILE_DIRECTORY_INFORMATION fdi = WINPR_C_ARRAY_INIT; - if (length > 0) - { -- if ((error = rdpdr_server_read_file_directory_information(priv->log, s, &fdi))) -+ UINT error = rdpdr_server_read_file_directory_information(priv->log, s, &fdi); -+ if (error) - { - WLog_Print(priv->log, WLOG_ERROR, - "rdpdr_server_read_file_directory_information failed with error %" PRIu32 -@@ -3151,12 +3087,11 @@ static UINT rdpdr_server_drive_query_directory_callback1(RdpdrServerContext* con - static UINT rdpdr_server_drive_query_directory(RdpdrServerContext* context, void* callbackData, - UINT32 deviceId, const char* path) - { -- RDPDR_IRP* irp = rdpdr_server_irp_new(); - WINPR_ASSERT(context); - WINPR_ASSERT(context->priv); -- WINPR_ASSERT(irp); - - RdpdrServerPrivate* priv = context->priv; -+ RDPDR_IRP* irp = rdpdr_server_irp_new(); - - if (!irp) - { -@@ -3231,12 +3166,11 @@ static UINT rdpdr_server_drive_open_file(RdpdrServerContext* context, void* call - UINT32 deviceId, const char* path, UINT32 desiredAccess, - UINT32 createDisposition) - { -- RDPDR_IRP* irp = rdpdr_server_irp_new(); - WINPR_ASSERT(context); - WINPR_ASSERT(context->priv); -- WINPR_ASSERT(irp); - - RdpdrServerPrivate* priv = context->priv; -+ RDPDR_IRP* irp = rdpdr_server_irp_new(); - - if (!irp) - { -@@ -3277,8 +3211,6 @@ static UINT rdpdr_server_drive_read_file_callback(RdpdrServerContext* context, w - RDPDR_IRP* irp, UINT32 deviceId, - UINT32 completionId, UINT32 ioStatus) - { -- UINT32 length = 0; -- char* buffer = nullptr; - WINPR_ASSERT(context); - WINPR_ASSERT(context->priv); - WINPR_ASSERT(irp); -@@ -3292,11 +3224,13 @@ static UINT rdpdr_server_drive_read_file_callback(RdpdrServerContext* context, w - if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 4)) - return ERROR_INVALID_DATA; - -+ UINT32 length = 0; - Stream_Read_UINT32(s, length); /* Length (4 bytes) */ - - if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, length)) - return ERROR_INVALID_DATA; - -+ char* buffer = nullptr; - if (length > 0) - { - buffer = Stream_Pointer(s); -@@ -3319,12 +3253,11 @@ static UINT rdpdr_server_drive_read_file(RdpdrServerContext* context, void* call - UINT32 deviceId, UINT32 fileId, UINT32 length, - UINT32 offset) - { -- RDPDR_IRP* irp = rdpdr_server_irp_new(); - WINPR_ASSERT(context); - WINPR_ASSERT(context->priv); -- WINPR_ASSERT(irp); - - RdpdrServerPrivate* priv = context->priv; -+ RDPDR_IRP* irp = rdpdr_server_irp_new(); - - if (!irp) - { -@@ -3364,7 +3297,6 @@ static UINT rdpdr_server_drive_write_file_callback(RdpdrServerContext* context, - RDPDR_IRP* irp, UINT32 deviceId, - UINT32 completionId, UINT32 ioStatus) - { -- UINT32 length = 0; - WINPR_ASSERT(context); - WINPR_ASSERT(context->priv); - WINPR_ASSERT(irp); -@@ -3378,6 +3310,7 @@ static UINT rdpdr_server_drive_write_file_callback(RdpdrServerContext* context, - if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 5)) - return ERROR_INVALID_DATA; - -+ UINT32 length = 0; - Stream_Read_UINT32(s, length); /* Length (4 bytes) */ - Stream_Seek(s, 1); /* Padding (1 byte) */ - -@@ -3400,12 +3333,11 @@ static UINT rdpdr_server_drive_write_file(RdpdrServerContext* context, void* cal - UINT32 deviceId, UINT32 fileId, const char* buffer, - UINT32 length, UINT32 offset) - { -- RDPDR_IRP* irp = rdpdr_server_irp_new(); - WINPR_ASSERT(context); - WINPR_ASSERT(context->priv); -- WINPR_ASSERT(irp); - - RdpdrServerPrivate* priv = context->priv; -+ RDPDR_IRP* irp = rdpdr_server_irp_new(); - - if (!irp) - { -@@ -3478,12 +3410,11 @@ static UINT rdpdr_server_drive_close_file_callback(RdpdrServerContext* context, - static UINT rdpdr_server_drive_close_file(RdpdrServerContext* context, void* callbackData, - UINT32 deviceId, UINT32 fileId) - { -- RDPDR_IRP* irp = rdpdr_server_irp_new(); - WINPR_ASSERT(context); - WINPR_ASSERT(context->priv); -- WINPR_ASSERT(irp); - - RdpdrServerPrivate* priv = context->priv; -+ RDPDR_IRP* irp = rdpdr_server_irp_new(); - - if (!irp) - { -@@ -3600,12 +3531,11 @@ static UINT rdpdr_server_drive_delete_file_callback1(RdpdrServerContext* context - static UINT rdpdr_server_drive_delete_file(RdpdrServerContext* context, void* callbackData, - UINT32 deviceId, const char* path) - { -- RDPDR_IRP* irp = rdpdr_server_irp_new(); - WINPR_ASSERT(context); - WINPR_ASSERT(context->priv); -- WINPR_ASSERT(irp); - - RdpdrServerPrivate* priv = context->priv; -+ RDPDR_IRP* irp = rdpdr_server_irp_new(); - - if (!irp) - { -@@ -3671,7 +3601,6 @@ static UINT rdpdr_server_drive_rename_file_callback2(RdpdrServerContext* context - RDPDR_IRP* irp, UINT32 deviceId, - UINT32 completionId, UINT32 ioStatus) - { -- UINT32 length = 0; - WINPR_ASSERT(context); - WINPR_ASSERT(context->priv); - WINPR_ASSERT(irp); -@@ -3685,6 +3614,7 @@ static UINT rdpdr_server_drive_rename_file_callback2(RdpdrServerContext* context - if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 5)) - return ERROR_INVALID_DATA; - -+ UINT32 length = 0; - Stream_Read_UINT32(s, length); /* Length (4 bytes) */ - Stream_Seek(s, 1); /* Padding (1 byte) */ - /* Invoke the rename file completion routine. */ - -From d67800b0d1c7ac10f574a56bcfb8d36e3f17bd3f Mon Sep 17 00:00:00 2001 -From: Joan Torres Lopez -Date: Mon, 22 Jun 2026 21:36:20 +0200 -Subject: [PATCH 14/31] [channels,rdpdr] migrate Stream API usage - -- Stream_Read_UINT32/UINT16 to Stream_Get_UINT32/UINT16 -- Stream_Free to Stream_Release -- Stream_Pointer to Stream_PointerAs - -Co-Authored-By: David Fort ---- - channels/rdpdr/server/rdpdr_main.c | 271 +++++++++++------------------ - 1 file changed, 104 insertions(+), 167 deletions(-) - -diff --git a/channels/rdpdr/server/rdpdr_main.c b/channels/rdpdr/server/rdpdr_main.c -index 488efca5bc46..132f0746a17a 100644 ---- a/channels/rdpdr/server/rdpdr_main.c -+++ b/channels/rdpdr/server/rdpdr_main.c -@@ -281,9 +281,10 @@ static UINT rdpdr_seal_send_free_request(RdpdrServerContext* context, wStream* s - - if (length >= RDPDR_HEADER_LENGTH) - { -- RDPDR_HEADER header = WINPR_C_ARRAY_INIT; -- Stream_Read_UINT16(s, header.Component); -- Stream_Read_UINT16(s, header.PacketId); -+ const RDPDR_HEADER header = { -+ .Component = Stream_Get_UINT16(s), -+ .PacketId = Stream_Get_UINT16(s), -+ }; - - WLog_Print(priv->log, WLOG_DEBUG, - "sending message {Component %s[%04" PRIx16 "], PacketId %s[%04" PRIx16 "]", -@@ -294,7 +295,7 @@ static UINT rdpdr_seal_send_free_request(RdpdrServerContext* context, wStream* s - ULONG written = 0; - BOOL status = WTSVirtualChannelWrite(priv->ChannelHandle, Stream_BufferAs(s, char), - (ULONG)length, &written); -- Stream_Free(s, TRUE); -+ Stream_Release(s); - return status ? CHANNEL_RC_OK : ERROR_INTERNAL_ERROR; - } - -@@ -351,12 +352,9 @@ static UINT rdpdr_server_receive_announce_response(RdpdrServerContext* context, - if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 8)) - return ERROR_INVALID_DATA; - -- UINT16 VersionMajor = 0; -- UINT16 VersionMinor = 0; -- UINT32 ClientId = 0; -- Stream_Read_UINT16(s, VersionMajor); /* VersionMajor (2 bytes) */ -- Stream_Read_UINT16(s, VersionMinor); /* VersionMinor (2 bytes) */ -- Stream_Read_UINT32(s, ClientId); /* ClientId (4 bytes) */ -+ const UINT16 VersionMajor = Stream_Get_UINT16(s); /* VersionMajor (2 bytes) */ -+ const UINT16 VersionMinor = Stream_Get_UINT16(s); /* VersionMinor (2 bytes) */ -+ const UINT32 ClientId = Stream_Get_UINT32(s); /* ClientId (4 bytes) */ - WLog_Print(priv->log, WLOG_DEBUG, - "Client Announce Response: VersionMajor: 0x%08" PRIX16 " VersionMinor: 0x%04" PRIX16 - " ClientId: 0x%08" PRIX32 "", -@@ -386,12 +384,9 @@ static UINT rdpdr_server_receive_client_name_request(RdpdrServerContext* context - if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 12)) - return ERROR_INVALID_DATA; - -- UINT32 UnicodeFlag = 0; -- UINT32 CodePage = 0; -- UINT32 ComputerNameLen = 0; -- Stream_Read_UINT32(s, UnicodeFlag); /* UnicodeFlag (4 bytes) */ -- Stream_Read_UINT32(s, CodePage); /* CodePage (4 bytes), MUST be set to zero */ -- Stream_Read_UINT32(s, ComputerNameLen); /* ComputerNameLen (4 bytes) */ -+ UINT32 UnicodeFlag = Stream_Get_UINT32(s); /* UnicodeFlag (4 bytes) */ -+ const UINT32 CodePage = Stream_Get_UINT32(s); /* CodePage (4 bytes) */ -+ const UINT32 ComputerNameLen = Stream_Get_UINT32(s); /* ComputerNameLen (4 bytes) */ - /* UnicodeFlag is either 0 or 1, the other 31 bits must be ignored. - */ - UnicodeFlag = UnicodeFlag & 0x00000001; -@@ -502,18 +497,19 @@ static UINT rdpdr_server_read_general_capability_set(RdpdrServerContext* context - if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 32)) - return ERROR_INVALID_DATA; - -- const UINT32 OsType = Stream_Get_UINT32(s); /* osType (4 bytes), ignored on receipt */ -- const UINT32 OsVersion = -- Stream_Get_UINT32(s); /* osVersion (4 bytes), unused and must be set to zero */ -+ const UINT32 OsType = Stream_Get_UINT32(s); /* osType (4 bytes), -+ ignored on receipt */ -+ const UINT32 OsVersion = Stream_Get_UINT32(s); /* osVersion (4 bytes), -+ unused and must be set to zero */ - const UINT32 VersionMajor = Stream_Get_UINT16(s); /* protocolMajorVersion (2 bytes) */ - const UINT32 VersionMinor = Stream_Get_UINT16(s); /* protocolMinorVersion (2 bytes) */ - const UINT32 IoCode1 = Stream_Get_UINT32(s); /* ioCode1 (4 bytes) */ -- const UINT32 IoCode2 = -- Stream_Get_UINT32(s); /* ioCode2 (4 bytes), must be set to zero, reserved for future use */ -+ const UINT32 IoCode2 = Stream_Get_UINT32(s); /* ioCode2 (4 bytes), -+ must be set to zero, reserved for future use */ - const UINT32 ExtendedPdu = Stream_Get_UINT32(s); /* extendedPdu (4 bytes) */ - const UINT32 ExtraFlags1 = Stream_Get_UINT32(s); /* extraFlags1 (4 bytes) */ -- const UINT32 ExtraFlags2 = Stream_Get_UINT32( -- s); /* extraFlags2 (4 bytes), must be set to zero, reserved for future use */ -+ const UINT32 ExtraFlags2 = Stream_Get_UINT32(s); /* extraFlags2 (4 bytes), -+ must be set to zero, reserved for future use */ - - { - char buffer[1024] = WINPR_C_ARRAY_INIT; -@@ -901,7 +897,7 @@ static UINT rdpdr_server_send_core_capability_request(RdpdrServerContext* contex - - return rdpdr_seal_send_free_request(context, s); - out: -- Stream_Free(s, TRUE); -+ Stream_Release(s); - return error; - } - -@@ -941,9 +937,8 @@ static UINT rdpdr_server_receive_core_capability_response(RdpdrServerContext* co - if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 4)) - return ERROR_INVALID_DATA; - -- UINT16 numCapabilities = 0; -- Stream_Read_UINT16(s, numCapabilities); /* numCapabilities (2 bytes) */ -- Stream_Seek_UINT16(s); /* Padding (2 bytes) */ -+ const UINT16 numCapabilities = Stream_Get_UINT16(s); /* numCapabilities (2 bytes) */ -+ Stream_Seek_UINT16(s); /* Padding (2 bytes) */ - - UINT16 caps = 0; - for (UINT16 i = 0; i < numCapabilities; i++) -@@ -1096,8 +1091,7 @@ static UINT rdpdr_server_receive_device_list_announce_request(RdpdrServerContext - if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 4)) - return ERROR_INVALID_DATA; - -- UINT32 DeviceCount = 0; -- Stream_Read_UINT32(s, DeviceCount); /* DeviceCount (4 bytes) */ -+ const UINT32 DeviceCount = Stream_Get_UINT32(s); /* DeviceCount (4 bytes) */ - WLog_Print(priv->log, WLOG_DEBUG, "DeviceCount: %" PRIu32 "", DeviceCount); - - for (UINT32 i = 0; i < DeviceCount; i++) -@@ -1106,11 +1100,11 @@ static UINT rdpdr_server_receive_device_list_announce_request(RdpdrServerContext - return ERROR_INVALID_DATA; - - RdpdrDevice device = WINPR_C_ARRAY_INIT; -- Stream_Read_UINT32(s, device.DeviceType); /* DeviceType (4 bytes) */ -- Stream_Read_UINT32(s, device.DeviceId); /* DeviceId (4 bytes) */ -+ device.DeviceType = Stream_Get_UINT32(s); /* DeviceType (4 bytes) */ -+ device.DeviceId = Stream_Get_UINT32(s); /* DeviceId (4 bytes) */ - Stream_Read(s, device.PreferredDosName, 8); /* PreferredDosName (8 bytes) */ -- Stream_Read_UINT32(s, device.DeviceDataLength); /* DeviceDataLength (4 bytes) */ -- device.DeviceData = Stream_Pointer(s); -+ device.DeviceDataLength = Stream_Get_UINT32(s); /* DeviceDataLength (4 bytes) */ -+ device.DeviceData = Stream_PointerAs(s, BYTE); - - if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, device.DeviceDataLength)) - return ERROR_INVALID_DATA; -@@ -1210,8 +1204,7 @@ static UINT rdpdr_server_receive_device_list_remove_request(RdpdrServerContext* - if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 4)) - return ERROR_INVALID_DATA; - -- UINT32 DeviceCount = 0; -- Stream_Read_UINT32(s, DeviceCount); /* DeviceCount (4 bytes) */ -+ const UINT32 DeviceCount = Stream_Get_UINT32(s); /* DeviceCount (4 bytes) */ - WLog_Print(priv->log, WLOG_DEBUG, "DeviceCount: %" PRIu32 "", DeviceCount); - - for (UINT32 i = 0; i < DeviceCount; i++) -@@ -1222,8 +1215,7 @@ static UINT rdpdr_server_receive_device_list_remove_request(RdpdrServerContext* - if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 4)) - return ERROR_INVALID_DATA; - -- UINT32 DeviceId = 0; -- Stream_Read_UINT32(s, DeviceId); /* DeviceId (4 bytes) */ -+ const UINT32 DeviceId = Stream_Get_UINT32(s); /* DeviceId (4 bytes) */ - device = rdpdr_get_device_by_id(context->priv, DeviceId); - WLog_Print(priv->log, WLOG_DEBUG, "Device %" PRIu32 " Id: 0x%08" PRIX32 "", i, DeviceId); - UINT32 DeviceType = 0; -@@ -1291,20 +1283,13 @@ static UINT rdpdr_server_receive_io_create_request(RdpdrServerContext* context, - if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 32)) - return ERROR_INVALID_DATA; - -- UINT32 DesiredAccess = 0; -- UINT32 AllocationSize = 0; -- UINT32 FileAttributes = 0; -- UINT32 SharedAccess = 0; -- UINT32 CreateDisposition = 0; -- UINT32 CreateOptions = 0; -- UINT32 PathLength = 0; -- Stream_Read_UINT32(s, DesiredAccess); -- Stream_Read_UINT32(s, AllocationSize); -- Stream_Read_UINT32(s, FileAttributes); -- Stream_Read_UINT32(s, SharedAccess); -- Stream_Read_UINT32(s, CreateDisposition); -- Stream_Read_UINT32(s, CreateOptions); -- Stream_Read_UINT32(s, PathLength); -+ WINPR_ATTR_UNUSED const UINT32 DesiredAccess = Stream_Get_UINT32(s); -+ WINPR_ATTR_UNUSED const UINT32 AllocationSize = Stream_Get_UINT32(s); -+ WINPR_ATTR_UNUSED const UINT32 FileAttributes = Stream_Get_UINT32(s); -+ WINPR_ATTR_UNUSED const UINT32 SharedAccess = Stream_Get_UINT32(s); -+ WINPR_ATTR_UNUSED const UINT32 CreateDisposition = Stream_Get_UINT32(s); -+ WINPR_ATTR_UNUSED const UINT32 CreateOptions = Stream_Get_UINT32(s); -+ const UINT32 PathLength = Stream_Get_UINT32(s); - - const WCHAR* path = rdpdr_read_ustring(priv->log, s, PathLength); - if (!path && (PathLength > 0)) -@@ -1351,10 +1336,8 @@ static UINT rdpdr_server_receive_io_read_request(RdpdrServerContext* context, wS - if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 32)) - return ERROR_INVALID_DATA; - -- UINT32 Length = 0; -- UINT64 Offset = 0; -- Stream_Read_UINT32(s, Length); -- Stream_Read_UINT64(s, Offset); -+ const UINT32 Length = Stream_Get_UINT32(s); -+ const UINT64 Offset = Stream_Get_UINT64(s); - Stream_Seek(s, 20); /* Padding */ - - WLog_Print(priv->log, WLOG_DEBUG, "Got Offset [0x%016" PRIx64 "], Length %" PRIu32, Offset, -@@ -1380,10 +1363,8 @@ static UINT rdpdr_server_receive_io_write_request(RdpdrServerContext* context, w - if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 32)) - return ERROR_INVALID_DATA; - -- UINT32 Length = 0; -- UINT64 Offset = 0; -- Stream_Read_UINT32(s, Length); -- Stream_Read_UINT64(s, Offset); -+ const UINT32 Length = Stream_Get_UINT32(s); -+ const UINT64 Offset = Stream_Get_UINT64(s); - Stream_Seek(s, 20); /* Padding */ - - WLog_Print(priv->log, WLOG_DEBUG, "Got Offset [0x%016" PRIx64 "], Length %" PRIu32, Offset, -@@ -1414,12 +1395,9 @@ static UINT rdpdr_server_receive_io_device_control_request(RdpdrServerContext* c - if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 32)) - return ERROR_INVALID_DATA; - -- UINT32 OutputBufferLength = 0; -- UINT32 InputBufferLength = 0; -- UINT32 IoControlCode = 0; -- Stream_Read_UINT32(s, OutputBufferLength); -- Stream_Read_UINT32(s, InputBufferLength); -- Stream_Read_UINT32(s, IoControlCode); -+ WINPR_ATTR_UNUSED const UINT32 OutputBufferLength = Stream_Get_UINT32(s); -+ WINPR_ATTR_UNUSED const UINT32 InputBufferLength = Stream_Get_UINT32(s); -+ WINPR_ATTR_UNUSED const UINT32 IoControlCode = Stream_Get_UINT32(s); - Stream_Seek(s, 20); /* Padding */ - - const BYTE* InputBuffer = Stream_ConstPointer(s); -@@ -1445,10 +1423,8 @@ static UINT rdpdr_server_receive_io_query_volume_information_request( - if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 32)) - return ERROR_INVALID_DATA; - -- UINT32 FsInformationClass = 0; -- UINT32 Length = 0; -- Stream_Read_UINT32(s, FsInformationClass); -- Stream_Read_UINT32(s, Length); -+ const UINT32 FsInformationClass = Stream_Get_UINT32(s); -+ const UINT32 Length = Stream_Get_UINT32(s); - Stream_Seek(s, 24); /* Padding */ - - WLog_Print(priv->log, WLOG_DEBUG, -@@ -1480,10 +1456,8 @@ static UINT rdpdr_server_receive_io_set_volume_information_request( - if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 32)) - return ERROR_INVALID_DATA; - -- UINT32 FsInformationClass = 0; -- UINT32 Length = 0; -- Stream_Read_UINT32(s, FsInformationClass); -- Stream_Read_UINT32(s, Length); -+ const UINT32 FsInformationClass = Stream_Get_UINT32(s); -+ const UINT32 Length = Stream_Get_UINT32(s); - Stream_Seek(s, 24); /* Padding */ - - WLog_Print(priv->log, WLOG_DEBUG, -@@ -1517,10 +1491,8 @@ static UINT rdpdr_server_receive_io_query_information_request(RdpdrServerContext - if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 32)) - return ERROR_INVALID_DATA; - -- UINT32 FsInformationClass = 0; -- UINT32 Length = 0; -- Stream_Read_UINT32(s, FsInformationClass); -- Stream_Read_UINT32(s, Length); -+ const UINT32 FsInformationClass = Stream_Get_UINT32(s); -+ const UINT32 Length = Stream_Get_UINT32(s); - Stream_Seek(s, 24); /* Padding */ - - WLog_Print(priv->log, WLOG_DEBUG, -@@ -1553,10 +1525,8 @@ static UINT rdpdr_server_receive_io_set_information_request(RdpdrServerContext* - if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 32)) - return ERROR_INVALID_DATA; - -- UINT32 FsInformationClass = 0; -- UINT32 Length = 0; -- Stream_Read_UINT32(s, FsInformationClass); -- Stream_Read_UINT32(s, Length); -+ const UINT32 FsInformationClass = Stream_Get_UINT32(s); -+ const UINT32 Length = Stream_Get_UINT32(s); - Stream_Seek(s, 24); /* Padding */ - - WLog_Print(priv->log, WLOG_DEBUG, -@@ -1589,12 +1559,9 @@ static UINT rdpdr_server_receive_io_query_directory_request(RdpdrServerContext* - if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 32)) - return ERROR_INVALID_DATA; - -- UINT32 FsInformationClass = 0; -- BYTE InitialQuery = 0; -- UINT32 PathLength = 0; -- Stream_Read_UINT32(s, FsInformationClass); -- Stream_Read_UINT8(s, InitialQuery); -- Stream_Read_UINT32(s, PathLength); -+ const UINT32 FsInformationClass = Stream_Get_UINT32(s); -+ const BYTE InitialQuery = Stream_Get_UINT8(s); -+ const UINT32 PathLength = Stream_Get_UINT32(s); - Stream_Seek(s, 23); /* Padding */ - - const WCHAR* wPath = rdpdr_read_ustring(priv->log, s, PathLength); -@@ -1631,10 +1598,8 @@ static UINT rdpdr_server_receive_io_change_directory_request(RdpdrServerContext* - if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 32)) - return ERROR_INVALID_DATA; - -- BYTE WatchTree = 0; -- UINT32 CompletionFilter = 0; -- Stream_Read_UINT8(s, WatchTree); -- Stream_Read_UINT32(s, CompletionFilter); -+ WINPR_ATTR_UNUSED const BYTE WatchTree = Stream_Get_UINT8(s); -+ WINPR_ATTR_UNUSED const UINT32 CompletionFilter = Stream_Get_UINT32(s); - Stream_Seek(s, 27); /* Padding */ - - WLog_Print(priv->log, WLOG_WARN, -@@ -1697,14 +1662,11 @@ static UINT rdpdr_server_receive_io_lock_control_request(RdpdrServerContext* con - - for (UINT32 x = 0; x < NumLocks; x++) - { -- UINT64 Length = 0; -- UINT64 Offset = 0; -- - if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 16)) - return ERROR_INVALID_DATA; - -- Stream_Read_UINT64(s, Length); -- Stream_Read_UINT64(s, Offset); -+ const UINT64 Length = Stream_Get_UINT64(s); -+ const UINT64 Offset = Stream_Get_UINT64(s); - - WLog_Print(priv->log, WLOG_DEBUG, "Locking at Offset=0x%08" PRIx64 " [Length %" PRIu64 "]", - Offset, Length); -@@ -1732,16 +1694,11 @@ static UINT rdpdr_server_receive_device_io_request(RdpdrServerContext* context, - if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 20)) - return ERROR_INVALID_DATA; - -- UINT32 DeviceId = 0; -- UINT32 FileId = 0; -- UINT32 CompletionId = 0; -- UINT32 MajorFunction = 0; -- UINT32 MinorFunction = 0; -- Stream_Read_UINT32(s, DeviceId); -- Stream_Read_UINT32(s, FileId); -- Stream_Read_UINT32(s, CompletionId); -- Stream_Read_UINT32(s, MajorFunction); -- Stream_Read_UINT32(s, MinorFunction); -+ const UINT32 DeviceId = Stream_Get_UINT32(s); -+ const UINT32 FileId = Stream_Get_UINT32(s); -+ const UINT32 CompletionId = Stream_Get_UINT32(s); -+ const UINT32 MajorFunction = Stream_Get_UINT32(s); -+ const UINT32 MinorFunction = Stream_Get_UINT32(s); - if ((MinorFunction != 0) && (MajorFunction != IRP_MJ_DIRECTORY_CONTROL)) - WLog_Print(priv->log, WLOG_WARN, - "[MS-RDPEFS] 2.2.1.4 Device I/O Request (DR_DEVICE_IOREQUEST) MajorFunction=%s, " -@@ -1816,12 +1773,9 @@ static UINT rdpdr_server_receive_device_io_completion(RdpdrServerContext* contex - if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 12)) - return ERROR_INVALID_DATA; - -- UINT32 deviceId = 0; -- UINT32 completionId = 0; -- UINT32 ioStatus = 0; -- Stream_Read_UINT32(s, deviceId); -- Stream_Read_UINT32(s, completionId); -- Stream_Read_UINT32(s, ioStatus); -+ const UINT32 deviceId = Stream_Get_UINT32(s); -+ const UINT32 completionId = Stream_Get_UINT32(s); -+ const UINT32 ioStatus = Stream_Get_UINT32(s); - WLog_Print(priv->log, WLOG_DEBUG, - "deviceId=%" PRIu32 ", completionId=0x%" PRIx32 ", ioStatus=0x%" PRIx32 "", deviceId, - completionId, ioStatus); -@@ -1882,15 +1836,11 @@ static UINT rdpdr_server_receive_prn_cache_add_printer(RdpdrServerContext* conte - return ERROR_INVALID_DATA; - - char PortDosName[9] = WINPR_C_ARRAY_INIT; -- UINT32 PnPNameLen = 0; -- UINT32 DriverNameLen = 0; -- UINT32 PrinterNameLen = 0; -- UINT32 CachedFieldsLen = 0; - Stream_Read(s, PortDosName, 8); -- Stream_Read_UINT32(s, PnPNameLen); -- Stream_Read_UINT32(s, DriverNameLen); -- Stream_Read_UINT32(s, PrinterNameLen); -- Stream_Read_UINT32(s, CachedFieldsLen); -+ const UINT32 PnPNameLen = Stream_Get_UINT32(s); -+ const UINT32 DriverNameLen = Stream_Get_UINT32(s); -+ const UINT32 PrinterNameLen = Stream_Get_UINT32(s); -+ const UINT32 CachedFieldsLen = Stream_Get_UINT32(s); - - const WCHAR* PnPName = rdpdr_read_ustring(priv->log, s, PnPNameLen); - if (!PnPName && (PnPNameLen > 0)) -@@ -1921,10 +1871,8 @@ static UINT rdpdr_server_receive_prn_cache_update_printer(RdpdrServerContext* co - if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 8)) - return ERROR_INVALID_DATA; - -- UINT32 PrinterNameLen = 0; -- UINT32 CachedFieldsLen = 0; -- Stream_Read_UINT32(s, PrinterNameLen); -- Stream_Read_UINT32(s, CachedFieldsLen); -+ const UINT32 PrinterNameLen = Stream_Get_UINT32(s); -+ const UINT32 CachedFieldsLen = Stream_Get_UINT32(s); - - const WCHAR* PrinterName = rdpdr_read_ustring(priv->log, s, PrinterNameLen); - if (!PrinterName && (PrinterNameLen > 0)) -@@ -1952,8 +1900,7 @@ static UINT rdpdr_server_receive_prn_cache_delete_printer(RdpdrServerContext* co - if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 4)) - return ERROR_INVALID_DATA; - -- UINT32 PrinterNameLen = 0; -- Stream_Read_UINT32(s, PrinterNameLen); -+ const UINT32 PrinterNameLen = Stream_Get_UINT32(s); - - const WCHAR* PrinterName = rdpdr_read_ustring(priv->log, s, PrinterNameLen); - if (!PrinterName && (PrinterNameLen > 0)) -@@ -1976,10 +1923,8 @@ static UINT rdpdr_server_receive_prn_cache_rename_cachedata(RdpdrServerContext* - if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 8)) - return ERROR_INVALID_DATA; - -- UINT32 OldPrinterNameLen = 0; -- UINT32 NewPrinterNameLen = 0; -- Stream_Read_UINT32(s, OldPrinterNameLen); -- Stream_Read_UINT32(s, NewPrinterNameLen); -+ const UINT32 OldPrinterNameLen = Stream_Get_UINT32(s); -+ const UINT32 NewPrinterNameLen = Stream_Get_UINT32(s); - - const WCHAR* OldPrinterName = rdpdr_read_ustring(priv->log, s, OldPrinterNameLen); - if (!OldPrinterName && (OldPrinterNameLen > 0)) -@@ -2007,8 +1952,7 @@ rdpdr_server_receive_prn_cache_data_request(RdpdrServerContext* context, wStream - if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 4)) - return ERROR_INVALID_DATA; - -- UINT32 EventId = 0; -- Stream_Read_UINT32(s, EventId); -+ const UINT32 EventId = Stream_Get_UINT32(s); - switch (EventId) - { - case RDPDR_ADD_PRINTER_EVENT: -@@ -2038,10 +1982,8 @@ static UINT rdpdr_server_receive_prn_using_xps_request(RdpdrServerContext* conte - if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 8)) - return ERROR_INVALID_DATA; - -- UINT32 PrinterId = 0; -- UINT32 Flags = 0; -- Stream_Read_UINT32(s, PrinterId); -- Stream_Read_UINT32(s, Flags); -+ const UINT32 PrinterId = Stream_Get_UINT32(s); -+ const UINT32 Flags = Stream_Get_UINT32(s); - - WLog_Print( - priv->log, WLOG_WARN, -@@ -2279,10 +2221,10 @@ static DWORD WINAPI rdpdr_server_thread(LPVOID arg) - - while (Stream_GetRemainingLength(s) >= RDPDR_HEADER_LENGTH) - { -- RDPDR_HEADER header = WINPR_C_ARRAY_INIT; -- -- Stream_Read_UINT16(s, header.Component); /* Component (2 bytes) */ -- Stream_Read_UINT16(s, header.PacketId); /* PacketId (2 bytes) */ -+ const RDPDR_HEADER header = { -+ .Component = Stream_Get_UINT16(s), /* Component (2 bytes) */ -+ .PacketId = Stream_Get_UINT16(s), /* PacketId (2 bytes) */ -+ }; - - if ((error = rdpdr_server_receive_pdu(context, s, &header))) - { -@@ -2295,7 +2237,7 @@ static DWORD WINAPI rdpdr_server_thread(LPVOID arg) - } - - out_stream: -- Stream_Free(s, TRUE); -+ Stream_Release(s); - out: - - if (error && context->rdpcontext) -@@ -2406,17 +2348,16 @@ static UINT rdpdr_server_read_file_directory_information(wLog* log, wStream* s, - if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 64)) - return ERROR_INVALID_DATA; - -- Stream_Read_UINT32(s, fdi->NextEntryOffset); /* NextEntryOffset (4 bytes) */ -- Stream_Read_UINT32(s, fdi->FileIndex); /* FileIndex (4 bytes) */ -- Stream_Read_INT64(s, fdi->CreationTime.QuadPart); /* CreationTime (8 bytes) */ -- Stream_Read_INT64(s, fdi->LastAccessTime.QuadPart); /* LastAccessTime (8 bytes) */ -- Stream_Read_INT64(s, fdi->LastWriteTime.QuadPart); /* LastWriteTime (8 bytes) */ -- Stream_Read_INT64(s, fdi->ChangeTime.QuadPart); /* ChangeTime (8 bytes) */ -- Stream_Read_INT64(s, fdi->EndOfFile.QuadPart); /* EndOfFile (8 bytes) */ -- Stream_Read_INT64(s, fdi->AllocationSize.QuadPart); /* AllocationSize (8 bytes) */ -- Stream_Read_UINT32(s, fdi->FileAttributes); /* FileAttributes (4 bytes) */ -- UINT32 fileNameLength = 0; -- Stream_Read_UINT32(s, fileNameLength); /* FileNameLength (4 bytes) */ -+ fdi->NextEntryOffset = Stream_Get_UINT32(s); /* NextEntryOffset (4 bytes) */ -+ fdi->FileIndex = Stream_Get_UINT32(s); /* FileIndex (4 bytes) */ -+ fdi->CreationTime.QuadPart = Stream_Get_INT64(s); /* CreationTime (8 bytes) */ -+ fdi->LastAccessTime.QuadPart = Stream_Get_INT64(s); /* LastAccessTime (8 bytes) */ -+ fdi->LastWriteTime.QuadPart = Stream_Get_INT64(s); /* LastWriteTime (8 bytes) */ -+ fdi->ChangeTime.QuadPart = Stream_Get_INT64(s); /* ChangeTime (8 bytes) */ -+ fdi->EndOfFile.QuadPart = Stream_Get_INT64(s); /* EndOfFile (8 bytes) */ -+ fdi->AllocationSize.QuadPart = Stream_Get_INT64(s); /* AllocationSize (8 bytes) */ -+ fdi->FileAttributes = Stream_Get_UINT32(s); /* FileAttributes (4 bytes) */ -+ const UINT32 fileNameLength = Stream_Get_UINT32(s); /* FileNameLength (4 bytes) */ - - if (!Stream_CheckAndLogRequiredLengthWLog(log, s, fileNameLength)) - return ERROR_INVALID_DATA; -@@ -2479,7 +2420,7 @@ static UINT rdpdr_server_send_device_create_request(RdpdrServerContext* context, - if (Stream_Write_UTF16_String_From_UTF8(s, pathLength / sizeof(WCHAR), path, - pathLength / sizeof(WCHAR), TRUE) < 0) - { -- Stream_Free(s, TRUE); -+ Stream_Release(s); - return ERROR_INTERNAL_ERROR; - } - return rdpdr_seal_send_free_request(context, s); -@@ -2625,7 +2566,7 @@ static UINT rdpdr_server_send_device_query_directory_request(RdpdrServerContext* - if (Stream_Write_UTF16_String_From_UTF8(s, pathLength / sizeof(WCHAR), path, - pathLength / sizeof(WCHAR), TRUE) < 0) - { -- Stream_Free(s, TRUE); -+ Stream_Release(s); - return ERROR_INTERNAL_ERROR; - } - } -@@ -2678,7 +2619,7 @@ static UINT rdpdr_server_send_device_file_rename_request(RdpdrServerContext* con - if (Stream_Write_UTF16_String_From_UTF8(s, pathLength / sizeof(WCHAR), path, - pathLength / sizeof(WCHAR), TRUE) < 0) - { -- Stream_Free(s, TRUE); -+ Stream_Release(s); - return ERROR_INTERNAL_ERROR; - } - } -@@ -2973,8 +2914,7 @@ static UINT rdpdr_server_drive_query_directory_callback2(RdpdrServerContext* con - if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 4)) - return ERROR_INVALID_DATA; - -- UINT32 length = 0; -- Stream_Read_UINT32(s, length); /* Length (4 bytes) */ -+ const UINT32 length = Stream_Get_UINT32(s); /* Length (4 bytes) */ - - FILE_DIRECTORY_INFORMATION fdi = WINPR_C_ARRAY_INIT; - if (length > 0) -@@ -3224,16 +3164,14 @@ static UINT rdpdr_server_drive_read_file_callback(RdpdrServerContext* context, w - if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 4)) - return ERROR_INVALID_DATA; - -- UINT32 length = 0; -- Stream_Read_UINT32(s, length); /* Length (4 bytes) */ -- -+ const UINT32 length = Stream_Get_UINT32(s); /* Length (4 bytes) */ - if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, length)) - return ERROR_INVALID_DATA; - - char* buffer = nullptr; - if (length > 0) - { -- buffer = Stream_Pointer(s); -+ buffer = Stream_PointerAs(s, char); - Stream_Seek(s, length); - } - -@@ -3310,9 +3248,8 @@ static UINT rdpdr_server_drive_write_file_callback(RdpdrServerContext* context, - if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 5)) - return ERROR_INVALID_DATA; - -- UINT32 length = 0; -- Stream_Read_UINT32(s, length); /* Length (4 bytes) */ -- Stream_Seek(s, 1); /* Padding (1 byte) */ -+ const UINT32 length = Stream_Get_UINT32(s); /* Length (4 bytes) */ -+ Stream_Seek(s, 1); /* Padding (1 byte) */ - - if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, length)) - return ERROR_INVALID_DATA; -@@ -3614,9 +3551,9 @@ static UINT rdpdr_server_drive_rename_file_callback2(RdpdrServerContext* context - if (!Stream_CheckAndLogRequiredLengthWLog(priv->log, s, 5)) - return ERROR_INVALID_DATA; - -- UINT32 length = 0; -- Stream_Read_UINT32(s, length); /* Length (4 bytes) */ -- Stream_Seek(s, 1); /* Padding (1 byte) */ -+ WINPR_ATTR_UNUSED const UINT32 length = Stream_Get_UINT32(s); /* Length (4 bytes) */ -+ Stream_Seek(s, 1); /* Padding (1 byte) */ -+ - /* Invoke the rename file completion routine. */ - context->OnDriveRenameFileComplete(context, irp->CallbackData, ioStatus); - /* Setup the IRP. */ - -From 1c81bb4568234088886378e73d465e3717687271 Mon Sep 17 00:00:00 2001 -From: David Fort -Date: Tue, 23 Jun 2026 20:07:50 +0200 -Subject: [PATCH 15/31] [channels] handle CHANNEL_OPTION_SHOW_PROTOCOL - server-side - -With some static channels like rdpdr or clipdr there's no marking of packet -length so in theory you can't handle packets that you don't know (you don't know -how many bytes to skip) or that are badly encoded (WTSVirtualChannelRead linearizes -the traffic so you can't know which bytes are part of the current PDU and which -bytes are from the next one). To solve that this patch adds server-side the handling -of a CHANNEL_OPTION_SHOW_PROTOCOL with WTSVirtualChannelOpen, when you set that -option you get CHANNEL_PDU_HEADER before the packet payload, and so you can do the -reassembly of a PDU. This allows to skip a PDU when you don't know the type, and -go to the next one correctly if for instance the padding at the end of the PDU is -incorrect (think of some smartcard commands invalidly padded by FreeRDP). - -The patch also provides a ChannelPduTracker component that can do the reassembly -for you. - -Co-Authored-By: Joan Torres Lopez ---- - channels/rdpdr/server/rdpdr_main.c | 131 +++++++++++++---------------- - 1 file changed, 57 insertions(+), 74 deletions(-) - -diff --git a/channels/rdpdr/server/rdpdr_main.c b/channels/rdpdr/server/rdpdr_main.c -index 132f0746a17a..06cd7a025ee4 100644 ---- a/channels/rdpdr/server/rdpdr_main.c -+++ b/channels/rdpdr/server/rdpdr_main.c -@@ -33,6 +33,7 @@ - - #include - #include "rdpdr_main.h" -+#include - - #define RDPDR_ADD_PRINTER_EVENT 0x00000001 - #define RDPDR_UPDATE_PRINTER_EVENT 0x00000002 -@@ -2126,101 +2127,62 @@ static DWORD WINAPI rdpdr_server_thread(LPVOID arg) - WINPR_ASSERT(context->priv); - - UINT error = 0; -+ wStream* s = nullptr; - RdpdrServerPrivate* priv = context->priv; -- DWORD nCount = 0; -+ ChannelPduTracker* tracker = ChannelPduTracker_new(priv->ChannelHandle); -+ if (!tracker) -+ goto out; -+ - void* buffer = nullptr; -- HANDLE events[8] = WINPR_C_ARRAY_INIT; - HANDLE ChannelEvent = nullptr; - DWORD BytesReturned = 0; -- wStream* s = Stream_New(nullptr, 4096); -- -- if (!s) -+ if (!WTSVirtualChannelQuery(priv->ChannelHandle, WTSVirtualEventHandle, &buffer, -+ &BytesReturned)) - { -- WLog_Print(priv->log, WLOG_ERROR, "Stream_New failed!"); -- error = CHANNEL_RC_NO_MEMORY; -+ WLog_Print(priv->log, WLOG_ERROR, "error retrieving WTSVirtualEventHandle"); - goto out; - } - -- if (WTSVirtualChannelQuery(priv->ChannelHandle, WTSVirtualEventHandle, &buffer, -- &BytesReturned) == TRUE) -+ if (BytesReturned != sizeof(HANDLE)) - { -- if (BytesReturned == sizeof(HANDLE)) -- ChannelEvent = *(HANDLE*)buffer; -- -+ WLog_Print(priv->log, WLOG_ERROR, "invalid size for WTSVirtualEventHandle"); - WTSFreeMemory(buffer); -+ goto out; - } - -- nCount = 0; -- events[nCount++] = ChannelEvent; -- events[nCount++] = priv->StopEvent; -+ ChannelEvent = *(HANDLE*)buffer; -+ WTSFreeMemory(buffer); - - if ((error = rdpdr_server_send_announce_request(context))) - { - WLog_Print(priv->log, WLOG_ERROR, - "rdpdr_server_send_announce_request failed with error %" PRIu32 "!", error); -- goto out_stream; -+ goto out; - } - -+ HANDLE events[2] = { priv->StopEvent, ChannelEvent }; -+ - while (1) - { -- size_t capacity = 0; -- BytesReturned = 0; -- DWORD status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE); -- -- if (status == WAIT_FAILED) -- { -- error = GetLastError(); -- WLog_Print(priv->log, WLOG_ERROR, -- "WaitForMultipleObjects failed with error %" PRIu32 "!", error); -- goto out_stream; -- } -- -- status = WaitForSingleObject(priv->StopEvent, 0); -- -- if (status == WAIT_FAILED) -- { -- error = GetLastError(); -- WLog_Print(priv->log, WLOG_ERROR, "WaitForSingleObject failed with error %" PRIu32 "!", -- error); -- goto out_stream; -- } -- -- if (status == WAIT_OBJECT_0) -- break; -- -- if (!WTSVirtualChannelRead(priv->ChannelHandle, 0, nullptr, 0, &BytesReturned)) -- { -- WLog_Print(priv->log, WLOG_ERROR, "WTSVirtualChannelRead failed!"); -- error = ERROR_INTERNAL_ERROR; -- break; -- } -- if (!Stream_EnsureRemainingCapacity(s, BytesReturned)) -- { -- WLog_Print(priv->log, WLOG_ERROR, "Stream_EnsureRemainingCapacity failed!"); -- error = ERROR_INTERNAL_ERROR; -- break; -- } -- -- capacity = MIN(Stream_Capacity(s), UINT32_MAX); -- if (!WTSVirtualChannelRead(priv->ChannelHandle, 0, Stream_BufferAs(s, char), -- (ULONG)capacity, &BytesReturned)) -- { -- WLog_Print(priv->log, WLOG_ERROR, "WTSVirtualChannelRead failed!"); -- error = ERROR_INTERNAL_ERROR; -- break; -- } -+ DWORD status = WaitForMultipleObjects(2, events, FALSE, INFINITE); - -- if (BytesReturned >= RDPDR_HEADER_LENGTH) -+ switch (status) - { -- Stream_ResetPosition(s); -- if (!Stream_SetLength(s, BytesReturned)) -+ case WAIT_OBJECT_0: -+ /* StopEvent */ -+ goto out; -+ case WAIT_OBJECT_0 + 1: - { -- error = ERROR_INTERNAL_ERROR; -- goto out_stream; -- } -+ s = ChannelPduTracker_poll(tracker); -+ if (!s) -+ break; -+ -+ if (Stream_GetRemainingLength(s) < RDPDR_HEADER_LENGTH) -+ { -+ error = ERROR_INTERNAL_ERROR; -+ goto out; -+ } - -- while (Stream_GetRemainingLength(s) >= RDPDR_HEADER_LENGTH) -- { - const RDPDR_HEADER header = { - .Component = Stream_Get_UINT16(s), /* Component (2 bytes) */ - .PacketId = Stream_Get_UINT16(s), /* PacketId (2 bytes) */ -@@ -2230,15 +2192,26 @@ static DWORD WINAPI rdpdr_server_thread(LPVOID arg) - { - WLog_Print(priv->log, WLOG_ERROR, - "rdpdr_server_receive_pdu failed with error %" PRIu32 "!", error); -- goto out_stream; -+ goto out; - } -+ Stream_Release(s); -+ s = nullptr; -+ break; - } -+ case WAIT_FAILED: -+ default: -+ error = GetLastError(); -+ WLog_Print(priv->log, WLOG_ERROR, -+ "WaitForMultipleObjects failed with error %" PRIu32 "!", error); -+ goto out; - } - } - --out_stream: -- Stream_Release(s); - out: -+ ChannelPduTracker_free(tracker); -+ -+ if (s) -+ Stream_Release(s); - - if (error && context->rdpcontext) - setChannelError(context->rdpcontext, error, "rdpdr_server_thread reported an error"); -@@ -2257,9 +2230,19 @@ static UINT rdpdr_server_start(RdpdrServerContext* context) - WINPR_ASSERT(context); - WINPR_ASSERT(context->priv); - -+ PULONG pSessionId = nullptr; -+ DWORD BytesReturned = 0; -+ -+ if (!WTSQuerySessionInformationA(context->vcm, WTS_CURRENT_SESSION, WTSSessionId, -+ (LPSTR*)&pSessionId, &BytesReturned)) -+ return CHANNEL_RC_BAD_CHANNEL; -+ -+ DWORD SessionId = (DWORD)*pSessionId; -+ WTSFreeMemory(pSessionId); -+ - RdpdrServerPrivate* priv = context->priv; - priv->ChannelHandle = -- WTSVirtualChannelOpen(context->vcm, WTS_CURRENT_SESSION, RDPDR_SVC_CHANNEL_NAME); -+ WTSVirtualChannelOpenEx(SessionId, RDPDR_SVC_CHANNEL_NAME, CHANNEL_OPTION_SHOW_PROTOCOL); - - if (!priv->ChannelHandle) - { - -From 7af13f0b5d3b784e00348ebaa46284aa48c70d44 Mon Sep 17 00:00:00 2001 -From: David Fort -Date: Mon, 22 Jun 2026 21:37:34 +0200 -Subject: [PATCH 16/31] [channels,rdpdr] track smartcard device in device - announce - -- add haveSmartcardDevice and smartcardDeviceId to RdpdrServerPrivate -- store smartcard device ID on device announce -- clear smartcard device state on device remove ---- - channels/rdpdr/server/rdpdr_main.c | 22 ++++++++++++++-------- - 1 file changed, 14 insertions(+), 8 deletions(-) - -diff --git a/channels/rdpdr/server/rdpdr_main.c b/channels/rdpdr/server/rdpdr_main.c -index 06cd7a025ee4..e90c287c8a4e 100644 ---- a/channels/rdpdr/server/rdpdr_main.c -+++ b/channels/rdpdr/server/rdpdr_main.c -@@ -64,6 +64,8 @@ struct s_rdpdr_server_private - UINT32 SpecialDeviceTypeCap; - UINT32 IoCode1; - UINT32 ExtendedPDU; -+ BOOL haveSmartcardDevice; -+ UINT32 smartcardDeviceId; - }; - - static const char* fileInformation2str(uint8_t val) -@@ -1156,16 +1158,13 @@ static UINT rdpdr_server_receive_device_list_announce_request(RdpdrServerContext - break; - - case RDPDR_DTYP_SMARTCARD: -- if (device.DeviceDataLength != 0) -+ if ((context->supported & RDPDR_DTYP_SMARTCARD) != 0) - { -- WLog_Print(priv->log, WLOG_WARN, -- "[rdpdr] RDPDR_DTYP_SMARTCARD::DeviceDataLength != 0 [%" PRIu32 "]", -- device.DeviceDataLength); -- error = ERROR_INVALID_DATA; -- } -- else if ((context->supported & RDPDR_DTYP_SMARTCARD) != 0) -+ priv->smartcardDeviceId = device.DeviceId; -+ priv->haveSmartcardDevice = TRUE; - error = -- IFCALLRESULT(CHANNEL_RC_OK, context->OnSmartcardCreate, context, &device); -+ IFCALLRESULT(STATUS_SUCCESS, context->OnSmartcardCreate, context, &device); -+ } - break; - - default: -@@ -1254,6 +1253,11 @@ static UINT rdpdr_server_receive_device_list_remove_request(RdpdrServerContext* - break; - - case RDPDR_DTYP_SMARTCARD: -+ if (priv->haveSmartcardDevice) -+ { -+ priv->haveSmartcardDevice = FALSE; -+ priv->smartcardDeviceId = 0; -+ } - if ((context->supported & RDPDR_DTYP_SMARTCARD) != 0) - error = - IFCALLRESULT(CHANNEL_RC_OK, context->OnSmartcardDelete, context, DeviceId); -@@ -3678,6 +3682,8 @@ static RdpdrServerPrivate* rdpdr_server_private_new(void) - priv->ClientId = g_ClientId++; - priv->UserLoggedOnPdu = TRUE; - priv->NextCompletionId = 1; -+ priv->haveSmartcardDevice = FALSE; -+ priv->smartcardDeviceId = 0; - priv->IrpList = ListDictionary_New(TRUE); - - if (!priv->IrpList) - -From 5a61669cd5bd16643545ad46bb7c2edebe4004bb Mon Sep 17 00:00:00 2001 -From: Joan Torres Lopez -Date: Tue, 23 Jun 2026 20:27:59 +0200 -Subject: [PATCH 17/31] [channels,rdpdr] send DEVICE_REPLY in device announce - -Send PAKID_CORE_DEVICE_REPLY for each announced device. - -Co-Authored-By: David Fort ---- - channels/rdpdr/server/rdpdr_main.c | 36 ++++++++++++++++++++++++++++-- - 1 file changed, 34 insertions(+), 2 deletions(-) - -diff --git a/channels/rdpdr/server/rdpdr_main.c b/channels/rdpdr/server/rdpdr_main.c -index e90c287c8a4e..fd11ad86e37f 100644 ---- a/channels/rdpdr/server/rdpdr_main.c -+++ b/channels/rdpdr/server/rdpdr_main.c -@@ -1075,6 +1075,36 @@ static UINT rdpdr_server_send_client_id_confirm(RdpdrServerContext* context) - return rdpdr_seal_send_free_request(context, s); - } - -+/** -+ * Function description -+ * -+ * @return 0 on success, otherwise a Win32 error code -+ */ -+static UINT rdpdr_server_send_device_reply(RdpdrServerContext* context, UINT32 deviceId, -+ UINT32 resultCode) -+{ -+ WINPR_ASSERT(context); -+ WINPR_ASSERT(context->priv); -+ -+ RdpdrServerPrivate* priv = context->priv; -+ wStream* s = Stream_New(nullptr, RDPDR_HEADER_LENGTH + 8); -+ if (!s) -+ { -+ WLog_Print(priv->log, WLOG_ERROR, "Stream_New failed!"); -+ return CHANNEL_RC_NO_MEMORY; -+ } -+ -+ const RDPDR_HEADER header = { -+ .Component = RDPDR_CTYP_CORE, -+ .PacketId = PAKID_CORE_DEVICE_REPLY, -+ }; -+ Stream_Write_UINT16(s, header.Component); /* Component (2 bytes) */ -+ Stream_Write_UINT16(s, header.PacketId); /* PacketId (2 bytes) */ -+ Stream_Write_UINT32(s, deviceId); /* DeviceId (4 bytes) */ -+ Stream_Write_UINT32(s, resultCode); /* ResultCode (4 bytes) */ -+ return rdpdr_seal_send_free_request(context, s); -+} -+ - /** - * Function description - * -@@ -1119,6 +1149,7 @@ static UINT rdpdr_server_receive_device_list_announce_request(RdpdrServerContext - if (error != CHANNEL_RC_OK) - return error; - -+ error = STATUS_NOT_SUPPORTED; - switch (device.DeviceType) - { - case RDPDR_DTYP_FILESYSTEM: -@@ -1177,10 +1208,11 @@ static UINT rdpdr_server_receive_device_list_announce_request(RdpdrServerContext - break; - } - -+ Stream_Seek(s, device.DeviceDataLength); -+ -+ error = rdpdr_server_send_device_reply(context, device.DeviceId, error); - if (error != CHANNEL_RC_OK) - return error; -- -- Stream_Seek(s, device.DeviceDataLength); - } - - return CHANNEL_RC_OK; - -From c8becfea93ae68bde1dc235e2bbc46a18c443dd2 Mon Sep 17 00:00:00 2001 -From: Joan Torres Lopez -Date: Fri, 19 Jun 2026 12:19:03 +0200 -Subject: [PATCH 18/31] [channels,rdpdr] fix IRP list leak on shutdown - -Set fnObjectFree on IrpList so that pending IRPs are freed when the -dictionary is destroyed during shutdown. ---- - channels/rdpdr/server/rdpdr_main.c | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/channels/rdpdr/server/rdpdr_main.c b/channels/rdpdr/server/rdpdr_main.c -index fd11ad86e37f..5c2df122f1ad 100644 ---- a/channels/rdpdr/server/rdpdr_main.c -+++ b/channels/rdpdr/server/rdpdr_main.c -@@ -3721,6 +3721,8 @@ static RdpdrServerPrivate* rdpdr_server_private_new(void) - if (!priv->IrpList) - goto fail; - -+ ListDictionary_ValueObject(priv->IrpList)->fnObjectFree = (OBJECT_FREE_FN)rdpdr_server_irp_free; -+ - priv->devicelist = HashTable_New(FALSE); - if (!priv->devicelist) - goto fail; - -From 97612e10160c38f1d241025d0fe2af87196ae9f9 Mon Sep 17 00:00:00 2001 -From: Joan Torres Lopez -Date: Tue, 23 Jun 2026 21:30:37 +0200 -Subject: [PATCH 19/31] [channels,rdpdr] add and use prepare_irp helper - -- add prepare_irp to centralize IRP creation, enqueue, and device check -- replace inline IRP creation in all drive operations -- add prepare_smartcard_irp wrapper with smartcard device check and IoControlCode -- add IoControlCode field to RDPDR_IRP - -Co-Authored-By: David Fort ---- - channels/rdpdr/server/rdpdr_main.c | 310 +++++++++++------------------ - channels/rdpdr/server/rdpdr_main.h | 1 + - 2 files changed, 122 insertions(+), 189 deletions(-) - -diff --git a/channels/rdpdr/server/rdpdr_main.c b/channels/rdpdr/server/rdpdr_main.c -index 5c2df122f1ad..af42beb7520f 100644 ---- a/channels/rdpdr/server/rdpdr_main.c -+++ b/channels/rdpdr/server/rdpdr_main.c -@@ -2395,6 +2395,66 @@ static UINT rdpdr_server_read_file_directory_information(wLog* log, wStream* s, - return CHANNEL_RC_OK; - } - -+static UINT prepare_irp(RdpdrServerContext* context, UINT32 deviceId, RDPDR_IRP_Callback callback, -+ void* callbackData, RDPDR_IRP** outIrp) -+{ -+ WINPR_ASSERT(context); -+ WINPR_ASSERT(context->priv); -+ WINPR_ASSERT(callbackData); -+ WINPR_ASSERT(outIrp); -+ -+ RdpdrServerPrivate* priv = context->priv; -+ -+ RDPDR_IRP* irp = rdpdr_server_irp_new(); -+ if (!irp) -+ { -+ WLog_Print(priv->log, WLOG_ERROR, "rdpdr_server_irp_new failed!"); -+ return CHANNEL_RC_NO_MEMORY; -+ } -+ -+ irp->CompletionId = priv->NextCompletionId++; -+ irp->Callback = callback; -+ irp->CallbackData = callbackData; -+ irp->DeviceId = deviceId; -+ -+ if (!rdpdr_server_enqueue_irp(context, irp)) -+ { -+ WLog_Print(priv->log, WLOG_ERROR, "rdpdr_server_enqueue_irp failed!"); -+ rdpdr_server_irp_free(irp); -+ return ERROR_INTERNAL_ERROR; -+ } -+ -+ *outIrp = irp; -+ return CHANNEL_RC_OK; -+} -+ -+static UINT prepare_smartcard_irp(RdpdrServerContext* context, UINT32 ioControlCode, -+ RDPDR_IRP_Callback callback, void* callbackData, -+ RDPDR_IRP** outIrp) -+{ -+ WINPR_ASSERT(context); -+ WINPR_ASSERT(context->priv); -+ WINPR_ASSERT(callbackData); -+ -+ const char* cmd = scard_get_ioctl_string(ioControlCode, FALSE); -+ -+ RdpdrServerPrivate* priv = context->priv; -+ if (!priv->haveSmartcardDevice) -+ { -+ WLog_Print(priv->log, WLOG_ERROR, "%s - no smartcard device registered", cmd); -+ return ERROR_BAD_DEVICE; -+ } -+ -+ RDPDR_IRP* irp = nullptr; -+ UINT error = prepare_irp(context, priv->smartcardDeviceId, callback, callbackData, &irp); -+ if (error != CHANNEL_RC_OK) -+ return error; -+ -+ irp->IoControlCode = ioControlCode; -+ *outIrp = irp; -+ return CHANNEL_RC_OK; -+} -+ - /** - * Function description - * -@@ -2755,32 +2815,18 @@ static UINT rdpdr_server_drive_create_directory(RdpdrServerContext* context, voi - WINPR_ASSERT(callbackData); - WINPR_ASSERT(path); - -- RdpdrServerPrivate* priv = context->priv; -- RDPDR_IRP* irp = rdpdr_server_irp_new(); -+ RDPDR_IRP* irp = nullptr; -+ UINT ret = prepare_irp(context, deviceId, rdpdr_server_drive_create_directory_callback1, -+ callbackData, &irp); -+ if (ret != CHANNEL_RC_OK) -+ return ret; - -- if (!irp) -- { -- WLog_Print(priv->log, WLOG_ERROR, "rdpdr_server_irp_new failed!"); -- return CHANNEL_RC_NO_MEMORY; -- } -- -- irp->CompletionId = priv->NextCompletionId++; -- irp->Callback = rdpdr_server_drive_create_directory_callback1; -- irp->CallbackData = callbackData; -- irp->DeviceId = deviceId; - strncpy(irp->PathName, path, sizeof(irp->PathName) - 1); - rdpdr_server_convert_slashes(irp->PathName, sizeof(irp->PathName)); - -- if (!rdpdr_server_enqueue_irp(context, irp)) -- { -- WLog_Print(priv->log, WLOG_ERROR, "rdpdr_server_enqueue_irp failed!"); -- rdpdr_server_irp_free(irp); -- return ERROR_INTERNAL_ERROR; -- } -- - /* Send a request to open the file. */ - return rdpdr_server_send_device_create_request( -- context, deviceId, irp->CompletionId, irp->PathName, FILE_READ_DATA | SYNCHRONIZE, -+ context, irp->DeviceId, irp->CompletionId, irp->PathName, FILE_READ_DATA | SYNCHRONIZE, - FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT, FILE_CREATE); - } - -@@ -2878,32 +2924,18 @@ static UINT rdpdr_server_drive_delete_directory(RdpdrServerContext* context, voi - WINPR_ASSERT(context); - WINPR_ASSERT(context->priv); - -- RdpdrServerPrivate* priv = context->priv; -- RDPDR_IRP* irp = rdpdr_server_irp_new(); -- -- if (!irp) -- { -- WLog_Print(priv->log, WLOG_ERROR, "rdpdr_server_irp_new failed!"); -- return CHANNEL_RC_NO_MEMORY; -- } -+ RDPDR_IRP* irp = nullptr; -+ UINT ret = prepare_irp(context, deviceId, rdpdr_server_drive_delete_directory_callback1, -+ callbackData, &irp); -+ if (ret != CHANNEL_RC_OK) -+ return ret; - -- irp->CompletionId = priv->NextCompletionId++; -- irp->Callback = rdpdr_server_drive_delete_directory_callback1; -- irp->CallbackData = callbackData; -- irp->DeviceId = deviceId; - strncpy(irp->PathName, path, sizeof(irp->PathName) - 1); - rdpdr_server_convert_slashes(irp->PathName, sizeof(irp->PathName)); - -- if (!rdpdr_server_enqueue_irp(context, irp)) -- { -- WLog_Print(priv->log, WLOG_ERROR, "rdpdr_server_enqueue_irp failed!"); -- rdpdr_server_irp_free(irp); -- return ERROR_INTERNAL_ERROR; -- } -- - /* Send a request to open the file. */ - return rdpdr_server_send_device_create_request( -- context, deviceId, irp->CompletionId, irp->PathName, DELETE | SYNCHRONIZE, -+ context, irp->DeviceId, irp->CompletionId, irp->PathName, DELETE | SYNCHRONIZE, - FILE_DIRECTORY_FILE | FILE_DELETE_ON_CLOSE | FILE_SYNCHRONOUS_IO_NONALERT, FILE_OPEN); - } - -@@ -3049,32 +3081,18 @@ static UINT rdpdr_server_drive_query_directory(RdpdrServerContext* context, void - WINPR_ASSERT(context); - WINPR_ASSERT(context->priv); - -- RdpdrServerPrivate* priv = context->priv; -- RDPDR_IRP* irp = rdpdr_server_irp_new(); -+ RDPDR_IRP* irp = nullptr; -+ UINT ret = prepare_irp(context, deviceId, rdpdr_server_drive_query_directory_callback1, -+ callbackData, &irp); -+ if (ret != CHANNEL_RC_OK) -+ return ret; - -- if (!irp) -- { -- WLog_Print(priv->log, WLOG_ERROR, "rdpdr_server_irp_new failed!"); -- return CHANNEL_RC_NO_MEMORY; -- } -- -- irp->CompletionId = priv->NextCompletionId++; -- irp->Callback = rdpdr_server_drive_query_directory_callback1; -- irp->CallbackData = callbackData; -- irp->DeviceId = deviceId; - strncpy(irp->PathName, path, sizeof(irp->PathName) - 1); - rdpdr_server_convert_slashes(irp->PathName, sizeof(irp->PathName)); - -- if (!rdpdr_server_enqueue_irp(context, irp)) -- { -- WLog_Print(priv->log, WLOG_ERROR, "rdpdr_server_enqueue_irp failed!"); -- rdpdr_server_irp_free(irp); -- return ERROR_INTERNAL_ERROR; -- } -- - /* Send a request to open the directory. */ - return rdpdr_server_send_device_create_request( -- context, deviceId, irp->CompletionId, irp->PathName, FILE_READ_DATA | SYNCHRONIZE, -+ context, irp->DeviceId, irp->CompletionId, irp->PathName, FILE_READ_DATA | SYNCHRONIZE, - FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT, FILE_OPEN); - } - -@@ -3128,31 +3146,17 @@ static UINT rdpdr_server_drive_open_file(RdpdrServerContext* context, void* call - WINPR_ASSERT(context); - WINPR_ASSERT(context->priv); - -- RdpdrServerPrivate* priv = context->priv; -- RDPDR_IRP* irp = rdpdr_server_irp_new(); -- -- if (!irp) -- { -- WLog_Print(priv->log, WLOG_ERROR, "rdpdr_server_irp_new failed!"); -- return CHANNEL_RC_NO_MEMORY; -- } -+ RDPDR_IRP* irp = nullptr; -+ UINT ret = -+ prepare_irp(context, deviceId, rdpdr_server_drive_open_file_callback, callbackData, &irp); -+ if (ret != CHANNEL_RC_OK) -+ return ret; - -- irp->CompletionId = priv->NextCompletionId++; -- irp->Callback = rdpdr_server_drive_open_file_callback; -- irp->CallbackData = callbackData; -- irp->DeviceId = deviceId; - strncpy(irp->PathName, path, sizeof(irp->PathName) - 1); - rdpdr_server_convert_slashes(irp->PathName, sizeof(irp->PathName)); - -- if (!rdpdr_server_enqueue_irp(context, irp)) -- { -- WLog_Print(priv->log, WLOG_ERROR, "rdpdr_server_enqueue_irp failed!"); -- rdpdr_server_irp_free(irp); -- return ERROR_INTERNAL_ERROR; -- } -- - /* Send a request to open the file. */ -- return rdpdr_server_send_device_create_request(context, deviceId, irp->CompletionId, -+ return rdpdr_server_send_device_create_request(context, irp->DeviceId, irp->CompletionId, - irp->PathName, desiredAccess | SYNCHRONIZE, - FILE_SYNCHRONOUS_IO_NONALERT, createDisposition); - } -@@ -3213,32 +3217,17 @@ static UINT rdpdr_server_drive_read_file(RdpdrServerContext* context, void* call - WINPR_ASSERT(context); - WINPR_ASSERT(context->priv); - -- RdpdrServerPrivate* priv = context->priv; -- RDPDR_IRP* irp = rdpdr_server_irp_new(); -+ RDPDR_IRP* irp = nullptr; -+ UINT ret = -+ prepare_irp(context, deviceId, rdpdr_server_drive_read_file_callback, callbackData, &irp); -+ if (ret != CHANNEL_RC_OK) -+ return ret; - -- if (!irp) -- { -- WLog_Print(priv->log, WLOG_ERROR, "rdpdr_server_irp_new failed!"); -- return CHANNEL_RC_NO_MEMORY; -- } -- -- irp->CompletionId = priv->NextCompletionId++; -- irp->Callback = rdpdr_server_drive_read_file_callback; -- irp->CallbackData = callbackData; -- irp->DeviceId = deviceId; - irp->FileId = fileId; - -- if (!rdpdr_server_enqueue_irp(context, irp)) -- { -- WLog_Print(priv->log, WLOG_ERROR, "rdpdr_server_enqueue_irp failed!"); -- rdpdr_server_irp_free(irp); -- return ERROR_INTERNAL_ERROR; -- } -- - /* Send a request to open the directory. */ -- // NOLINTNEXTLINE(clang-analyzer-unix.Malloc): rdpdr_server_enqueue_irp owns irp -- return rdpdr_server_send_device_read_request(context, deviceId, fileId, irp->CompletionId, -- length, offset); -+ return rdpdr_server_send_device_read_request(context, irp->DeviceId, irp->FileId, -+ irp->CompletionId, length, offset); - } - - /************************************************* -@@ -3292,32 +3281,17 @@ static UINT rdpdr_server_drive_write_file(RdpdrServerContext* context, void* cal - WINPR_ASSERT(context); - WINPR_ASSERT(context->priv); - -- RdpdrServerPrivate* priv = context->priv; -- RDPDR_IRP* irp = rdpdr_server_irp_new(); -+ RDPDR_IRP* irp = nullptr; -+ UINT ret = -+ prepare_irp(context, deviceId, rdpdr_server_drive_write_file_callback, callbackData, &irp); -+ if (ret != CHANNEL_RC_OK) -+ return ret; - -- if (!irp) -- { -- WLog_Print(priv->log, WLOG_ERROR, "rdpdr_server_irp_new failed!"); -- return CHANNEL_RC_NO_MEMORY; -- } -- -- irp->CompletionId = priv->NextCompletionId++; -- irp->Callback = rdpdr_server_drive_write_file_callback; -- irp->CallbackData = callbackData; -- irp->DeviceId = deviceId; - irp->FileId = fileId; - -- if (!rdpdr_server_enqueue_irp(context, irp)) -- { -- WLog_Print(priv->log, WLOG_ERROR, "rdpdr_server_enqueue_irp failed!"); -- rdpdr_server_irp_free(irp); -- return ERROR_INTERNAL_ERROR; -- } -- - /* Send a request to open the directory. */ -- // NOLINTNEXTLINE(clang-analyzer-unix.Malloc): rdpdr_server_enqueue_irp owns irp -- return rdpdr_server_send_device_write_request(context, deviceId, fileId, irp->CompletionId, -- buffer, length, offset); -+ return rdpdr_server_send_device_write_request(context, irp->DeviceId, irp->FileId, -+ irp->CompletionId, buffer, length, offset); - } - - /************************************************* -@@ -3369,31 +3343,17 @@ static UINT rdpdr_server_drive_close_file(RdpdrServerContext* context, void* cal - WINPR_ASSERT(context); - WINPR_ASSERT(context->priv); - -- RdpdrServerPrivate* priv = context->priv; -- RDPDR_IRP* irp = rdpdr_server_irp_new(); -+ RDPDR_IRP* irp = nullptr; -+ UINT ret = -+ prepare_irp(context, deviceId, rdpdr_server_drive_close_file_callback, callbackData, &irp); -+ if (ret != CHANNEL_RC_OK) -+ return ret; - -- if (!irp) -- { -- WLog_Print(priv->log, WLOG_ERROR, "rdpdr_server_irp_new failed!"); -- return CHANNEL_RC_NO_MEMORY; -- } -- -- irp->CompletionId = priv->NextCompletionId++; -- irp->Callback = rdpdr_server_drive_close_file_callback; -- irp->CallbackData = callbackData; -- irp->DeviceId = deviceId; - irp->FileId = fileId; - -- if (!rdpdr_server_enqueue_irp(context, irp)) -- { -- WLog_Print(priv->log, WLOG_ERROR, "rdpdr_server_enqueue_irp failed!"); -- rdpdr_server_irp_free(irp); -- return ERROR_INTERNAL_ERROR; -- } -- - /* Send a request to open the directory. */ -- // NOLINTNEXTLINE(clang-analyzer-unix.Malloc): rdpdr_server_enqueue_irp owns irp -- return rdpdr_server_send_device_close_request(context, deviceId, fileId, irp->CompletionId); -+ return rdpdr_server_send_device_close_request(context, irp->DeviceId, irp->FileId, -+ irp->CompletionId); - } - - /************************************************* -@@ -3476,7 +3436,8 @@ static UINT rdpdr_server_drive_delete_file_callback1(RdpdrServerContext* context - } - - /* Send a request to close the file */ -- return rdpdr_server_send_device_close_request(context, deviceId, fileId, irp->CompletionId); -+ return rdpdr_server_send_device_close_request(context, irp->DeviceId, irp->FileId, -+ irp->CompletionId); - } - - /** -@@ -3490,32 +3451,18 @@ static UINT rdpdr_server_drive_delete_file(RdpdrServerContext* context, void* ca - WINPR_ASSERT(context); - WINPR_ASSERT(context->priv); - -- RdpdrServerPrivate* priv = context->priv; -- RDPDR_IRP* irp = rdpdr_server_irp_new(); -+ RDPDR_IRP* irp = nullptr; -+ UINT ret = prepare_irp(context, deviceId, rdpdr_server_drive_delete_file_callback1, -+ callbackData, &irp); -+ if (ret != CHANNEL_RC_OK) -+ return ret; - -- if (!irp) -- { -- WLog_Print(priv->log, WLOG_ERROR, "rdpdr_server_irp_new failed!"); -- return CHANNEL_RC_NO_MEMORY; -- } -- -- irp->CompletionId = priv->NextCompletionId++; -- irp->Callback = rdpdr_server_drive_delete_file_callback1; -- irp->CallbackData = callbackData; -- irp->DeviceId = deviceId; - strncpy(irp->PathName, path, sizeof(irp->PathName) - 1); - rdpdr_server_convert_slashes(irp->PathName, sizeof(irp->PathName)); - -- if (!rdpdr_server_enqueue_irp(context, irp)) -- { -- WLog_Print(priv->log, WLOG_ERROR, "rdpdr_server_enqueue_irp failed!"); -- rdpdr_server_irp_free(irp); -- return ERROR_INTERNAL_ERROR; -- } -- - /* Send a request to open the file. */ - return rdpdr_server_send_device_create_request( -- context, deviceId, irp->CompletionId, irp->PathName, FILE_READ_DATA | SYNCHRONIZE, -+ context, irp->DeviceId, irp->CompletionId, irp->PathName, FILE_READ_DATA | SYNCHRONIZE, - FILE_DELETE_ON_CLOSE | FILE_SYNCHRONOUS_IO_NONALERT, FILE_OPEN); - } - -@@ -3588,7 +3535,7 @@ static UINT rdpdr_server_drive_rename_file_callback2(RdpdrServerContext* context - } - - /* Send a request to close the file */ -- return rdpdr_server_send_device_close_request(context, deviceId, irp->FileId, -+ return rdpdr_server_send_device_close_request(context, irp->DeviceId, irp->FileId, - irp->CompletionId); - } - -@@ -3642,7 +3589,7 @@ static UINT rdpdr_server_drive_rename_file_callback1(RdpdrServerContext* context - } - - /* Send a request to rename the file */ -- return rdpdr_server_send_device_file_rename_request(context, deviceId, fileId, -+ return rdpdr_server_send_device_file_rename_request(context, irp->DeviceId, irp->FileId, - irp->CompletionId, irp->ExtraBuffer); - } - -@@ -3658,34 +3605,19 @@ static UINT rdpdr_server_drive_rename_file(RdpdrServerContext* context, void* ca - WINPR_ASSERT(context); - WINPR_ASSERT(context->priv); - -- RdpdrServerPrivate* priv = context->priv; -- RDPDR_IRP* irp = rdpdr_server_irp_new(); -- -- if (!irp) -- { -- WLog_Print(priv->log, WLOG_ERROR, "rdpdr_server_irp_new failed!"); -- return CHANNEL_RC_NO_MEMORY; -- } -+ RDPDR_IRP* irp = nullptr; -+ UINT ret = prepare_irp(context, deviceId, rdpdr_server_drive_rename_file_callback1, -+ callbackData, &irp); -+ if (ret != CHANNEL_RC_OK) -+ return ret; - -- irp->CompletionId = priv->NextCompletionId++; -- irp->Callback = rdpdr_server_drive_rename_file_callback1; -- irp->CallbackData = callbackData; -- irp->DeviceId = deviceId; - strncpy(irp->PathName, oldPath, sizeof(irp->PathName) - 1); - strncpy(irp->ExtraBuffer, newPath, sizeof(irp->ExtraBuffer) - 1); - rdpdr_server_convert_slashes(irp->PathName, sizeof(irp->PathName)); - rdpdr_server_convert_slashes(irp->ExtraBuffer, sizeof(irp->ExtraBuffer)); - -- if (!rdpdr_server_enqueue_irp(context, irp)) -- { -- WLog_Print(priv->log, WLOG_ERROR, "rdpdr_server_enqueue_irp failed!"); -- rdpdr_server_irp_free(irp); -- return ERROR_INTERNAL_ERROR; -- } -- - /* Send a request to open the file. */ -- // NOLINTNEXTLINE(clang-analyzer-unix.Malloc): rdpdr_server_enqueue_irp owns irp -- return rdpdr_server_send_device_create_request(context, deviceId, irp->CompletionId, -+ return rdpdr_server_send_device_create_request(context, irp->DeviceId, irp->CompletionId, - irp->PathName, FILE_READ_DATA | SYNCHRONIZE, - FILE_SYNCHRONOUS_IO_NONALERT, FILE_OPEN); - } -diff --git a/channels/rdpdr/server/rdpdr_main.h b/channels/rdpdr/server/rdpdr_main.h -index b1d86b148ad7..40327a81313b 100644 ---- a/channels/rdpdr/server/rdpdr_main.h -+++ b/channels/rdpdr/server/rdpdr_main.h -@@ -40,6 +40,7 @@ struct S_RDPDR_IRP - UINT32 CompletionId; - UINT32 DeviceId; - UINT32 FileId; -+ UINT32 IoControlCode; - char PathName[256]; - char ExtraBuffer[256]; - void* CallbackData; - -From 26c63ef8e8591b6fec802c2e04a024f04314f418 Mon Sep 17 00:00:00 2001 -From: Joan Torres Lopez -Date: Wed, 24 Jun 2026 18:19:58 +0200 -Subject: [PATCH 20/31] [channels,rdpdr] normalize indentation in rdpdr.h - -Indent all declarations inside extern "C" block one level. ---- - include/freerdp/server/rdpdr.h | 359 +++++++++++++++++---------------- - 1 file changed, 185 insertions(+), 174 deletions(-) - -diff --git a/include/freerdp/server/rdpdr.h b/include/freerdp/server/rdpdr.h -index f2c33a14ba97..411b33b6d6d7 100644 ---- a/include/freerdp/server/rdpdr.h -+++ b/include/freerdp/server/rdpdr.h -@@ -49,186 +49,197 @@ extern "C" - } RDPDR_HEADER; - - #ifndef __MINGW32__ --typedef struct --{ -- UINT32 NextEntryOffset; -- UINT32 FileIndex; -- LARGE_INTEGER CreationTime; -- LARGE_INTEGER LastAccessTime; -- LARGE_INTEGER LastWriteTime; -- LARGE_INTEGER ChangeTime; -- LARGE_INTEGER EndOfFile; -- LARGE_INTEGER AllocationSize; -- UINT32 FileAttributes; -+ typedef struct -+ { -+ UINT32 NextEntryOffset; -+ UINT32 FileIndex; -+ LARGE_INTEGER CreationTime; -+ LARGE_INTEGER LastAccessTime; -+ LARGE_INTEGER LastWriteTime; -+ LARGE_INTEGER ChangeTime; -+ LARGE_INTEGER EndOfFile; -+ LARGE_INTEGER AllocationSize; -+ UINT32 FileAttributes; - #if defined(WITH_WCHAR_FILE_DIRECTORY_INFORMATION) -- WCHAR FileName[512]; -+ WCHAR FileName[512]; - #else -- char FileName[512]; -+ char FileName[512]; - #endif --} FILE_DIRECTORY_INFORMATION; -+ } FILE_DIRECTORY_INFORMATION; - #endif - --typedef UINT (*psRdpdrStart)(RdpdrServerContext* context); --typedef UINT (*psRdpdrStop)(RdpdrServerContext* context); -- --typedef UINT (*psRdpdrCapablityPDU)(RdpdrServerContext* context, -- const RDPDR_CAPABILITY_HEADER* header, size_t size, -- const BYTE* data); --typedef UINT (*psRdpdrReceivePDU)(RdpdrServerContext* context, const RDPDR_HEADER* header, -- UINT error); --typedef UINT (*psRdpdrReceiveAnnounceResponse)(RdpdrServerContext* context, UINT16 VersionMajor, -- UINT16 VersionMinor, UINT32 ClientId); --typedef UINT (*psRdpdrSendServerAnnounce)(RdpdrServerContext* context); --typedef UINT (*psRdpdrReceiveDeviceAnnounce)(RdpdrServerContext* context, -- const RdpdrDevice* device); --typedef UINT (*psRdpdrReceiveDeviceRemove)(RdpdrServerContext* context, UINT32 deviceId, -- const RdpdrDevice* device); --typedef UINT (*psRdpdrReceiveClientNameRequest)(RdpdrServerContext* context, size_t ComputerNameLen, -- const char* name); -- --typedef UINT (*psRdpdrDriveCreateDirectory)(RdpdrServerContext* context, void* callbackData, -- UINT32 deviceId, const char* path); --typedef UINT (*psRdpdrDriveDeleteDirectory)(RdpdrServerContext* context, void* callbackData, -- UINT32 deviceId, const char* path); --typedef UINT (*psRdpdrDriveQueryDirectory)(RdpdrServerContext* context, void* callbackData, -+ typedef UINT (*psRdpdrStart)(RdpdrServerContext* context); -+ typedef UINT (*psRdpdrStop)(RdpdrServerContext* context); -+ -+ typedef UINT (*psRdpdrCapablityPDU)(RdpdrServerContext* context, -+ const RDPDR_CAPABILITY_HEADER* header, size_t size, -+ const BYTE* data); -+ typedef UINT (*psRdpdrReceivePDU)(RdpdrServerContext* context, const RDPDR_HEADER* header, -+ UINT error); -+ typedef UINT (*psRdpdrReceiveAnnounceResponse)(RdpdrServerContext* context, UINT16 VersionMajor, -+ UINT16 VersionMinor, UINT32 ClientId); -+ typedef UINT (*psRdpdrSendServerAnnounce)(RdpdrServerContext* context); -+ typedef UINT (*psRdpdrReceiveDeviceAnnounce)(RdpdrServerContext* context, -+ const RdpdrDevice* device); -+ typedef UINT (*psRdpdrReceiveDeviceRemove)(RdpdrServerContext* context, UINT32 deviceId, -+ const RdpdrDevice* device); -+ typedef UINT (*psRdpdrReceiveClientNameRequest)(RdpdrServerContext* context, -+ size_t ComputerNameLen, const char* name); -+ -+ typedef UINT (*psRdpdrDriveCreateDirectory)(RdpdrServerContext* context, void* callbackData, -+ UINT32 deviceId, const char* path); -+ typedef UINT (*psRdpdrDriveDeleteDirectory)(RdpdrServerContext* context, void* callbackData, -+ UINT32 deviceId, const char* path); -+ typedef UINT (*psRdpdrDriveQueryDirectory)(RdpdrServerContext* context, void* callbackData, -+ UINT32 deviceId, const char* path); -+ typedef UINT (*psRdpdrDriveOpenFile)(RdpdrServerContext* context, void* callbackData, -+ UINT32 deviceId, const char* path, UINT32 desiredAccess, -+ UINT32 createDisposition); -+ typedef UINT (*psRdpdrDriveReadFile)(RdpdrServerContext* context, void* callbackData, -+ UINT32 deviceId, UINT32 fileId, UINT32 length, -+ UINT32 offset); -+ typedef UINT (*psRdpdrDriveWriteFile)(RdpdrServerContext* context, void* callbackData, -+ UINT32 deviceId, UINT32 fileId, const char* buffer, -+ UINT32 length, UINT32 offset); -+ typedef UINT (*psRdpdrDriveCloseFile)(RdpdrServerContext* context, void* callbackData, -+ UINT32 deviceId, UINT32 fileId); -+ typedef UINT (*psRdpdrDriveDeleteFile)(RdpdrServerContext* context, void* callbackData, - UINT32 deviceId, const char* path); --typedef UINT (*psRdpdrDriveOpenFile)(RdpdrServerContext* context, void* callbackData, -- UINT32 deviceId, const char* path, UINT32 desiredAccess, -- UINT32 createDisposition); --typedef UINT (*psRdpdrDriveReadFile)(RdpdrServerContext* context, void* callbackData, -- UINT32 deviceId, UINT32 fileId, UINT32 length, UINT32 offset); --typedef UINT (*psRdpdrDriveWriteFile)(RdpdrServerContext* context, void* callbackData, -- UINT32 deviceId, UINT32 fileId, const char* buffer, -- UINT32 length, UINT32 offset); --typedef UINT (*psRdpdrDriveCloseFile)(RdpdrServerContext* context, void* callbackData, -- UINT32 deviceId, UINT32 fileId); --typedef UINT (*psRdpdrDriveDeleteFile)(RdpdrServerContext* context, void* callbackData, -- UINT32 deviceId, const char* path); --typedef UINT (*psRdpdrDriveRenameFile)(RdpdrServerContext* context, void* callbackData, -- UINT32 deviceId, const char* oldPath, const char* newPath); -- --typedef void (*psRdpdrOnDriveCreateDirectoryComplete)(RdpdrServerContext* context, -- void* callbackData, UINT32 ioStatus); --typedef void (*psRdpdrOnDriveDeleteDirectoryComplete)(RdpdrServerContext* context, -- void* callbackData, UINT32 ioStatus); --typedef void (*psRdpdrOnDriveQueryDirectoryComplete)(RdpdrServerContext* context, -- void* callbackData, UINT32 ioStatus, -- FILE_DIRECTORY_INFORMATION* fdi); --typedef void (*psRdpdrOnDriveOpenFileComplete)(RdpdrServerContext* context, void* callbackData, -- UINT32 ioStatus, UINT32 deviceId, UINT32 fileId); --typedef void (*psRdpdrOnDriveReadFileComplete)(RdpdrServerContext* context, void* callbackData, -- UINT32 ioStatus, const char* buffer, UINT32 length); --typedef void (*psRdpdrOnDriveWriteFileComplete)(RdpdrServerContext* context, void* callbackData, -- UINT32 ioStatus, UINT32 bytesWritten); --typedef void (*psRdpdrOnDriveCloseFileComplete)(RdpdrServerContext* context, void* callbackData, -- UINT32 ioStatus); --typedef void (*psRdpdrOnDriveDeleteFileComplete)(RdpdrServerContext* context, void* callbackData, -- UINT32 ioStatus); --typedef void (*psRdpdrOnDriveRenameFileComplete)(RdpdrServerContext* context, void* callbackData, -- UINT32 ioStatus); -- --typedef UINT (*psRdpdrOnDeviceCreate)(RdpdrServerContext* context, const RdpdrDevice* device); --typedef UINT (*psRdpdrOnDeviceDelete)(RdpdrServerContext* context, UINT32 deviceId); -- --struct s_rdpdr_server_context --{ -- HANDLE vcm; -- -- WINPR_ATTR_NODISCARD psRdpdrStart Start; -- psRdpdrStop Stop; -- -- RdpdrServerPrivate* priv; -- -- /* Server self-defined pointer. */ -- void* data; -- -- /**< Server supported redirections. -- * initially used to determine which redirections are supported by the -- * server in the server capability, later on updated with what the client -- * actually wants to have supported. -- * -- * Use the \b RDPDR_DTYP_* defines as a mask to check. -- */ -- UINT16 supported; -- -- /*** RDPDR message intercept callbacks */ -- WINPR_ATTR_NODISCARD psRdpdrCapablityPDU -- ReceiveCaps; /**< Called for each received capability */ -- WINPR_ATTR_NODISCARD psRdpdrCapablityPDU SendCaps; /**< Called for each capability to be sent */ -- WINPR_ATTR_NODISCARD psRdpdrReceivePDU -- ReceivePDU; /**< Called after a RDPDR pdu was received and parsed */ -- WINPR_ATTR_NODISCARD psRdpdrSendServerAnnounce -- SendServerAnnounce; /**< Called before the server sends the announce message */ -- WINPR_ATTR_NODISCARD psRdpdrReceiveAnnounceResponse -- ReceiveAnnounceResponse; /**< Called after the client announce response is received */ -- WINPR_ATTR_NODISCARD psRdpdrReceiveClientNameRequest -- ReceiveClientNameRequest; /**< Called after a client name request is received */ -- WINPR_ATTR_NODISCARD psRdpdrReceiveDeviceAnnounce -- ReceiveDeviceAnnounce; /** < Called after a new device request was received but before the -- device is added */ -- WINPR_ATTR_NODISCARD psRdpdrReceiveDeviceRemove -- ReceiveDeviceRemove; /**< Called after a new device request was -- received, but before it is removed */ -- -- /*** Drive APIs called by the server. ***/ -- WINPR_ATTR_NODISCARD psRdpdrDriveCreateDirectory DriveCreateDirectory; -- WINPR_ATTR_NODISCARD psRdpdrDriveDeleteDirectory DriveDeleteDirectory; -- WINPR_ATTR_NODISCARD psRdpdrDriveQueryDirectory DriveQueryDirectory; -- WINPR_ATTR_NODISCARD psRdpdrDriveOpenFile DriveOpenFile; -- WINPR_ATTR_NODISCARD psRdpdrDriveReadFile DriveReadFile; -- WINPR_ATTR_NODISCARD psRdpdrDriveWriteFile DriveWriteFile; -- WINPR_ATTR_NODISCARD psRdpdrDriveCloseFile DriveCloseFile; -- WINPR_ATTR_NODISCARD psRdpdrDriveDeleteFile DriveDeleteFile; -- WINPR_ATTR_NODISCARD psRdpdrDriveRenameFile DriveRenameFile; -- -- /*** Drive callbacks registered by the server. ***/ -- WINPR_ATTR_NODISCARD psRdpdrOnDeviceCreate OnDriveCreate; /**< Called for devices of type \b -- RDPDR_DTYP_FILESYSTEM after \b ReceiveDeviceAnnounce */ -- WINPR_ATTR_NODISCARD psRdpdrOnDeviceDelete OnDriveDelete; /**< Called for devices of type \b -- RDPDR_DTYP_FILESYSTEM after \b ReceiveDeviceRemove */ -- psRdpdrOnDriveCreateDirectoryComplete OnDriveCreateDirectoryComplete; -- psRdpdrOnDriveDeleteDirectoryComplete OnDriveDeleteDirectoryComplete; -- psRdpdrOnDriveQueryDirectoryComplete OnDriveQueryDirectoryComplete; -- psRdpdrOnDriveOpenFileComplete OnDriveOpenFileComplete; -- psRdpdrOnDriveReadFileComplete OnDriveReadFileComplete; -- psRdpdrOnDriveWriteFileComplete OnDriveWriteFileComplete; -- psRdpdrOnDriveCloseFileComplete OnDriveCloseFileComplete; -- psRdpdrOnDriveDeleteFileComplete OnDriveDeleteFileComplete; -- psRdpdrOnDriveRenameFileComplete OnDriveRenameFileComplete; -- -- /*** Serial Port callbacks registered by the server. ***/ -- WINPR_ATTR_NODISCARD psRdpdrOnDeviceCreate OnSerialPortCreate; /**< Called for devices of type -- \b RDPDR_DTYP_SERIAL after \b ReceiveDeviceAnnounce */ -- WINPR_ATTR_NODISCARD psRdpdrOnDeviceDelete OnSerialPortDelete; /**< Called for devices of type -- \b RDPDR_DTYP_SERIAL after \b ReceiveDeviceRemove */ -- -- /*** Parallel Port callbacks registered by the server. ***/ -- WINPR_ATTR_NODISCARD psRdpdrOnDeviceCreate OnParallelPortCreate; /**< Called for devices of type -- \b RDPDR_DTYP_PARALLEL after \b ReceiveDeviceAnnounce */ -- WINPR_ATTR_NODISCARD psRdpdrOnDeviceDelete OnParallelPortDelete; /**< Called for devices of type -- \b RDPDR_DTYP_PARALLEL after \b ReceiveDeviceRemove */ -- -- /*** Printer callbacks registered by the server. ***/ -- WINPR_ATTR_NODISCARD psRdpdrOnDeviceCreate OnPrinterCreate; /**< Called for devices of type -- RDPDR_DTYP_PRINT after \b ReceiveDeviceAnnounce */ -- WINPR_ATTR_NODISCARD psRdpdrOnDeviceDelete OnPrinterDelete; /**< Called for devices of type -- RDPDR_DTYP_PRINT after \b ReceiveDeviceRemove */ -- -- /*** Smartcard callbacks registered by the server. ***/ -- WINPR_ATTR_NODISCARD psRdpdrOnDeviceCreate -- OnSmartcardCreate; /**< Called for devices of type RDPDR_DTYP_SMARTCARD -- after \b ReceiveDeviceAnnounce */ -- WINPR_ATTR_NODISCARD psRdpdrOnDeviceDelete OnSmartcardDelete; /**< Called for devices of type -- RDPDR_DTYP_SMARTCARD after \b ReceiveDeviceRemove */ -- -- rdpContext* rdpcontext; --}; -- --FREERDP_API void rdpdr_server_context_free(RdpdrServerContext* context); -- --WINPR_ATTR_MALLOC(rdpdr_server_context_free, 1) --WINPR_ATTR_NODISCARD --FREERDP_API RdpdrServerContext* rdpdr_server_context_new(HANDLE vcm); -+ typedef UINT (*psRdpdrDriveRenameFile)(RdpdrServerContext* context, void* callbackData, -+ UINT32 deviceId, const char* oldPath, -+ const char* newPath); -+ -+ typedef void (*psRdpdrOnDriveCreateDirectoryComplete)(RdpdrServerContext* context, -+ void* callbackData, UINT32 ioStatus); -+ typedef void (*psRdpdrOnDriveDeleteDirectoryComplete)(RdpdrServerContext* context, -+ void* callbackData, UINT32 ioStatus); -+ typedef void (*psRdpdrOnDriveQueryDirectoryComplete)(RdpdrServerContext* context, -+ void* callbackData, UINT32 ioStatus, -+ FILE_DIRECTORY_INFORMATION* fdi); -+ typedef void (*psRdpdrOnDriveOpenFileComplete)(RdpdrServerContext* context, void* callbackData, -+ UINT32 ioStatus, UINT32 deviceId, UINT32 fileId); -+ typedef void (*psRdpdrOnDriveReadFileComplete)(RdpdrServerContext* context, void* callbackData, -+ UINT32 ioStatus, const char* buffer, -+ UINT32 length); -+ typedef void (*psRdpdrOnDriveWriteFileComplete)(RdpdrServerContext* context, void* callbackData, -+ UINT32 ioStatus, UINT32 bytesWritten); -+ typedef void (*psRdpdrOnDriveCloseFileComplete)(RdpdrServerContext* context, void* callbackData, -+ UINT32 ioStatus); -+ typedef void (*psRdpdrOnDriveDeleteFileComplete)(RdpdrServerContext* context, -+ void* callbackData, UINT32 ioStatus); -+ typedef void (*psRdpdrOnDriveRenameFileComplete)(RdpdrServerContext* context, -+ void* callbackData, UINT32 ioStatus); -+ -+ typedef UINT (*psRdpdrOnDeviceCreate)(RdpdrServerContext* context, const RdpdrDevice* device); -+ typedef UINT (*psRdpdrOnDeviceDelete)(RdpdrServerContext* context, UINT32 deviceId); -+ -+ struct s_rdpdr_server_context -+ { -+ HANDLE vcm; -+ -+ WINPR_ATTR_NODISCARD psRdpdrStart Start; -+ psRdpdrStop Stop; -+ -+ RdpdrServerPrivate* priv; -+ -+ /* Server self-defined pointer. */ -+ void* data; -+ -+ /**< Server supported redirections. -+ * initially used to determine which redirections are supported by the -+ * server in the server capability, later on updated with what the client -+ * actually wants to have supported. -+ * -+ * Use the \b RDPDR_DTYP_* defines as a mask to check. -+ */ -+ UINT16 supported; -+ -+ /*** RDPDR message intercept callbacks */ -+ WINPR_ATTR_NODISCARD psRdpdrCapablityPDU -+ ReceiveCaps; /**< Called for each received capability */ -+ WINPR_ATTR_NODISCARD psRdpdrCapablityPDU -+ SendCaps; /**< Called for each capability to be sent */ -+ WINPR_ATTR_NODISCARD psRdpdrReceivePDU -+ ReceivePDU; /**< Called after a RDPDR pdu was received and parsed */ -+ WINPR_ATTR_NODISCARD psRdpdrSendServerAnnounce -+ SendServerAnnounce; /**< Called before the server sends the announce message */ -+ WINPR_ATTR_NODISCARD psRdpdrReceiveAnnounceResponse -+ ReceiveAnnounceResponse; /**< Called after the client announce response is received */ -+ WINPR_ATTR_NODISCARD psRdpdrReceiveClientNameRequest -+ ReceiveClientNameRequest; /**< Called after a client name request is received */ -+ WINPR_ATTR_NODISCARD psRdpdrReceiveDeviceAnnounce -+ ReceiveDeviceAnnounce; /** < Called after a new device request was received but before -+ the device is added */ -+ WINPR_ATTR_NODISCARD psRdpdrReceiveDeviceRemove -+ ReceiveDeviceRemove; /**< Called after a new device request was -+ received, but before it is removed */ -+ -+ /*** Drive APIs called by the server. ***/ -+ WINPR_ATTR_NODISCARD psRdpdrDriveCreateDirectory DriveCreateDirectory; -+ WINPR_ATTR_NODISCARD psRdpdrDriveDeleteDirectory DriveDeleteDirectory; -+ WINPR_ATTR_NODISCARD psRdpdrDriveQueryDirectory DriveQueryDirectory; -+ WINPR_ATTR_NODISCARD psRdpdrDriveOpenFile DriveOpenFile; -+ WINPR_ATTR_NODISCARD psRdpdrDriveReadFile DriveReadFile; -+ WINPR_ATTR_NODISCARD psRdpdrDriveWriteFile DriveWriteFile; -+ WINPR_ATTR_NODISCARD psRdpdrDriveCloseFile DriveCloseFile; -+ WINPR_ATTR_NODISCARD psRdpdrDriveDeleteFile DriveDeleteFile; -+ WINPR_ATTR_NODISCARD psRdpdrDriveRenameFile DriveRenameFile; -+ -+ /*** Drive callbacks registered by the server. ***/ -+ WINPR_ATTR_NODISCARD psRdpdrOnDeviceCreate -+ OnDriveCreate; /**< Called for devices of type \b -+ RDPDR_DTYP_FILESYSTEM after \b ReceiveDeviceAnnounce */ -+ WINPR_ATTR_NODISCARD psRdpdrOnDeviceDelete -+ OnDriveDelete; /**< Called for devices of type \b -+ RDPDR_DTYP_FILESYSTEM after \b ReceiveDeviceRemove */ -+ psRdpdrOnDriveCreateDirectoryComplete OnDriveCreateDirectoryComplete; -+ psRdpdrOnDriveDeleteDirectoryComplete OnDriveDeleteDirectoryComplete; -+ psRdpdrOnDriveQueryDirectoryComplete OnDriveQueryDirectoryComplete; -+ psRdpdrOnDriveOpenFileComplete OnDriveOpenFileComplete; -+ psRdpdrOnDriveReadFileComplete OnDriveReadFileComplete; -+ psRdpdrOnDriveWriteFileComplete OnDriveWriteFileComplete; -+ psRdpdrOnDriveCloseFileComplete OnDriveCloseFileComplete; -+ psRdpdrOnDriveDeleteFileComplete OnDriveDeleteFileComplete; -+ psRdpdrOnDriveRenameFileComplete OnDriveRenameFileComplete; -+ -+ /*** Serial Port callbacks registered by the server. ***/ -+ WINPR_ATTR_NODISCARD psRdpdrOnDeviceCreate -+ OnSerialPortCreate; /**< Called for devices of type -+ \b RDPDR_DTYP_SERIAL after \b ReceiveDeviceAnnounce */ -+ WINPR_ATTR_NODISCARD psRdpdrOnDeviceDelete -+ OnSerialPortDelete; /**< Called for devices of type -+ \b RDPDR_DTYP_SERIAL after \b ReceiveDeviceRemove */ -+ -+ /*** Parallel Port callbacks registered by the server. ***/ -+ WINPR_ATTR_NODISCARD psRdpdrOnDeviceCreate -+ OnParallelPortCreate; /**< Called for devices of type -+ \b RDPDR_DTYP_PARALLEL after \b ReceiveDeviceAnnounce */ -+ WINPR_ATTR_NODISCARD psRdpdrOnDeviceDelete -+ OnParallelPortDelete; /**< Called for devices of type -+ \b RDPDR_DTYP_PARALLEL after \b ReceiveDeviceRemove */ -+ -+ /*** Printer callbacks registered by the server. ***/ -+ WINPR_ATTR_NODISCARD psRdpdrOnDeviceCreate OnPrinterCreate; /**< Called for devices of type -+ RDPDR_DTYP_PRINT after \b ReceiveDeviceAnnounce */ -+ WINPR_ATTR_NODISCARD psRdpdrOnDeviceDelete OnPrinterDelete; /**< Called for devices of type -+ RDPDR_DTYP_PRINT after \b ReceiveDeviceRemove */ -+ -+ /*** Smartcard callbacks registered by the server. ***/ -+ WINPR_ATTR_NODISCARD psRdpdrOnDeviceCreate -+ OnSmartcardCreate; /**< Called for devices of type RDPDR_DTYP_SMARTCARD -+ after \b ReceiveDeviceAnnounce */ -+ WINPR_ATTR_NODISCARD psRdpdrOnDeviceDelete -+ OnSmartcardDelete; /**< Called for devices of type -+ RDPDR_DTYP_SMARTCARD after \b ReceiveDeviceRemove */ -+ -+ rdpContext* rdpcontext; -+ }; -+ -+ FREERDP_API void rdpdr_server_context_free(RdpdrServerContext* context); -+ -+ WINPR_ATTR_MALLOC(rdpdr_server_context_free, 1) -+ WINPR_ATTR_NODISCARD -+ FREERDP_API RdpdrServerContext* rdpdr_server_context_new(HANDLE vcm); - - #ifdef __cplusplus - } - -From 8064bf9ed77211dea30c1114b5286c5303e1af78 Mon Sep 17 00:00:00 2001 -From: Joan Torres Lopez -Date: Mon, 22 Jun 2026 13:58:54 +0200 -Subject: [PATCH 21/31] [channels,rdpdr] add smartcard server operations - -Add smartcard IOCTL operations to the RDPDR server. Each operation -sends an IRP_MJ_DEVICE_CONTROL request to the client and parses -the response via a completion callback. - -Add rdpdr_server_send_device_control_request for sending -IRP_MJ_DEVICE_CONTROL requests, following the existing drive pattern. - -Add request and completion function pointers to the public -RdpdrServerContext API for all smartcard operations. - -Co-authored-by: David Fort ---- - channels/rdpdr/server/rdpdr_main.c | 1979 ++++++++++++++++- - include/freerdp/server/rdpdr.h | 220 ++ - libfreerdp/utils/test/CMakeLists.txt | 4 +- - .../utils/test/TestSmartcardOperations.c | 1445 ++++++++++++ - 4 files changed, 3614 insertions(+), 34 deletions(-) - create mode 100644 libfreerdp/utils/test/TestSmartcardOperations.c - -diff --git a/channels/rdpdr/server/rdpdr_main.c b/channels/rdpdr/server/rdpdr_main.c -index af42beb7520f..7b9c1d33ff10 100644 ---- a/channels/rdpdr/server/rdpdr_main.c -+++ b/channels/rdpdr/server/rdpdr_main.c -@@ -32,6 +32,8 @@ - #include - - #include -+#include -+#include - #include "rdpdr_main.h" - #include - -@@ -43,6 +45,9 @@ - #define RDPDR_HEADER_LENGTH 4 - #define RDPDR_CAPABILITY_HEADER_LENGTH 8 - -+/* [MS-RDPESC] 3.2.5.1: the output buffer length SHOULD be set to 2048 */ -+#define SCARD_IOCTL_MAX_OUTPUT_BUFFER_LENGTH 2048 -+ - struct s_rdpdr_server_private - { - HANDLE Thread; -@@ -2706,6 +2711,55 @@ static UINT rdpdr_server_send_device_file_rename_request(RdpdrServerContext* con - return rdpdr_seal_send_free_request(context, s); - } - -+static UINT rdpdr_server_send_device_control_request(RdpdrServerContext* context, UINT32 deviceId, -+ UINT32 completionId, UINT32 ioControlCode, -+ UINT32 outputBufferLength, -+ const void* inputBuffer, -+ size_t inputBufferLength) -+{ -+ WINPR_ASSERT(context); -+ WINPR_ASSERT(context->priv); -+ WINPR_ASSERT(inputBuffer || (inputBufferLength == 0)); -+ -+ if (inputBufferLength > UINT32_MAX) -+ { -+ WLog_Print(context->priv->log, WLOG_ERROR, -+ "inputBufferLength %" PRIuz " exceeds UINT32_MAX", inputBufferLength); -+ return ERROR_INVALID_PARAMETER; -+ } -+ -+ RdpdrServerPrivate* priv = context->priv; -+ -+ WLog_Print(priv->log, WLOG_DEBUG, -+ "RdpdrServerSendDeviceControlRequest: deviceId=%" PRIu32 "," -+ " ioControlCode=0x%" PRIx32 ", inputBufferLength=%" PRIuz, -+ deviceId, ioControlCode, inputBufferLength); -+ -+ if (inputBufferLength > 0) -+ winpr_HexLogDump(priv->log, WLOG_DEBUG, inputBuffer, inputBufferLength); -+ -+ wStream* s = -+ Stream_New(nullptr, RDPDR_HEADER_LENGTH + RDPDR_DEVICE_IO_REQUEST_LENGTH + -+ RDPDR_DEVICE_IO_CONTROL_REQ_HDR_LENGTH + inputBufferLength); -+ if (!s) -+ { -+ WLog_Print(priv->log, WLOG_ERROR, "Stream_New failed!"); -+ return CHANNEL_RC_NO_MEMORY; -+ } -+ -+ UINT32 inputLength = WINPR_ASSERTING_INT_CAST(UINT32, inputBufferLength); -+ rdpdr_server_write_device_iorequest(s, deviceId, 0, completionId, IRP_MJ_DEVICE_CONTROL, 0); -+ Stream_Write_UINT32(s, outputBufferLength); /* OutputBufferLength (4 bytes) */ -+ Stream_Write_UINT32(s, inputLength); /* InputBufferLength (4 bytes) */ -+ Stream_Write_UINT32(s, ioControlCode); /* IoControlCode (4 bytes) */ -+ Stream_Zero(s, 20); /* Padding (20 bytes) */ -+ -+ if (inputBufferLength > 0) -+ Stream_Write(s, inputBuffer, inputBufferLength); -+ -+ return rdpdr_seal_send_free_request(context, s); -+} -+ - static void rdpdr_server_convert_slashes(char* path, int size) - { - WINPR_ASSERT(path || (size <= 0)); -@@ -3682,46 +3736,1905 @@ static RdpdrServerPrivate* rdpdr_server_private_new(void) - return nullptr; - } - --RdpdrServerContext* rdpdr_server_context_new(HANDLE vcm) -+static UINT rdpdr_server_smartcard_establish_context_callback(RdpdrServerContext* context, -+ wStream* s, RDPDR_IRP* irp, -+ UINT32 deviceId, UINT32 completionId, -+ UINT32 ioStatus) - { -- RdpdrServerContext* context = (RdpdrServerContext*)calloc(1, sizeof(RdpdrServerContext)); -+ WINPR_ASSERT(context); -+ WINPR_ASSERT(context->priv); -+ WINPR_ASSERT(s); -+ WINPR_ASSERT(irp); - -- if (!context) -- goto fail; -+ UINT result = CHANNEL_RC_OK; -+ RdpdrServerPrivate* priv = context->priv; -+ SMARTCARD_OPERATION op = WINPR_C_ARRAY_INIT; - -- context->vcm = vcm; -- context->Start = rdpdr_server_start; -- context->Stop = rdpdr_server_stop; -- context->DriveCreateDirectory = rdpdr_server_drive_create_directory; -- context->DriveDeleteDirectory = rdpdr_server_drive_delete_directory; -- context->DriveQueryDirectory = rdpdr_server_drive_query_directory; -- context->DriveOpenFile = rdpdr_server_drive_open_file; -- context->DriveReadFile = rdpdr_server_drive_read_file; -- context->DriveWriteFile = rdpdr_server_drive_write_file; -- context->DriveCloseFile = rdpdr_server_drive_close_file; -- context->DriveDeleteFile = rdpdr_server_drive_delete_file; -- context->DriveRenameFile = rdpdr_server_drive_rename_file; -- context->priv = rdpdr_server_private_new(); -- if (!context->priv) -- goto fail; -+ WLog_Print(priv->log, WLOG_DEBUG, -+ "RdpdrServerSmartcardEstablishContextCallback: deviceId=%" PRIu32 -+ ", completionId=%" PRIu32 ", ioStatus=0x%" PRIx32 "", -+ deviceId, completionId, ioStatus); - -- /* By default announce everything, the server application can deactivate that later on */ -- context->supported = UINT16_MAX; -+ if (ioStatus != STATUS_SUCCESS) -+ { -+ if (context->OnSmartcardEstablishContextComplete) -+ context->OnSmartcardEstablishContextComplete(context, irp->CallbackData, ioStatus, -+ SCARD_F_INTERNAL_ERROR, nullptr); -+ goto out; -+ } - -- return context; --fail: -- WINPR_PRAGMA_DIAG_PUSH -- WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC -- rdpdr_server_context_free(context); -- WINPR_PRAGMA_DIAG_POP -- return nullptr; -+ result = smartcard_irp_device_control_decode_response(s, irp->IoControlCode, &op); -+ if (result != SCARD_S_SUCCESS) -+ { -+ result = ERROR_INVALID_DATA; -+ goto out; -+ } -+ -+ if (context->OnSmartcardEstablishContextComplete) -+ context->OnSmartcardEstablishContextComplete(context, irp->CallbackData, ioStatus, -+ op.returnCode, &op.ret.establishContext); -+ -+out: -+ smartcard_operation_free(&op, FALSE); -+ rdpdr_server_irp_free(irp); -+ return result; - } - --void rdpdr_server_context_free(RdpdrServerContext* context) -+static UINT rdpdr_server_smartcard_establish_context(RdpdrServerContext* context, -+ void* callbackData, UINT32 dwScope, -+ UINT32* completionId) - { -- if (!context) -- return; -+ WINPR_ASSERT(context); -+ WINPR_ASSERT(context->priv); -+ WINPR_ASSERT(completionId); - -- rdpdr_server_private_free(context->priv); -- free(context); -+ UINT result = CHANNEL_RC_OK; -+ RdpdrServerPrivate* priv = context->priv; -+ RDPDR_IRP* irp = nullptr; -+ wStream* s = nullptr; -+ -+ switch (dwScope) -+ { -+ case SCARD_SCOPE_USER: -+ case SCARD_SCOPE_TERMINAL: -+ case SCARD_SCOPE_SYSTEM: -+ break; -+ default: -+ WLog_Print(priv->log, WLOG_ERROR, "invalid dwScope=0x%08" PRIx32, dwScope); -+ return ERROR_INVALID_PARAMETER; -+ } -+ -+ result = prepare_smartcard_irp(context, SCARD_IOCTL_ESTABLISHCONTEXT, -+ rdpdr_server_smartcard_establish_context_callback, callbackData, -+ &irp); -+ if (result != CHANNEL_RC_OK) -+ return result; -+ -+ *completionId = irp->CompletionId; -+ -+ const SMARTCARD_OPERATION op = { -+ .ioControlCode = SCARD_IOCTL_ESTABLISHCONTEXT, -+ .call.establishContext.dwScope = dwScope, -+ }; -+ -+ s = Stream_New(nullptr, 64); -+ if (!s) -+ { -+ WLog_Print(priv->log, WLOG_ERROR, "Stream_New failed!"); -+ result = CHANNEL_RC_NO_MEMORY; -+ goto out; -+ } -+ -+ result = smartcard_irp_device_control_encode_request(s, &op); -+ if (result != SCARD_S_SUCCESS) -+ { -+ result = ERROR_INTERNAL_ERROR; -+ goto out; -+ } -+ -+ result = rdpdr_server_send_device_control_request( -+ context, irp->DeviceId, irp->CompletionId, irp->IoControlCode, -+ SCARD_IOCTL_MAX_OUTPUT_BUFFER_LENGTH, Stream_Buffer(s), Stream_Length(s)); -+ -+out: -+ if (result != CHANNEL_RC_OK && irp) -+ rdpdr_server_discard_request(context, irp->CompletionId); -+ if (s) -+ Stream_Release(s); -+ return result; -+} -+ -+/* ReleaseContext */ -+static UINT rdpdr_server_smartcard_release_context_callback(RdpdrServerContext* context, wStream* s, -+ RDPDR_IRP* irp, UINT32 deviceId, -+ UINT32 completionId, UINT32 ioStatus) -+{ -+ WINPR_ASSERT(context); -+ WINPR_ASSERT(context->priv); -+ WINPR_ASSERT(s); -+ WINPR_ASSERT(irp); -+ -+ UINT result = CHANNEL_RC_OK; -+ RdpdrServerPrivate* priv = context->priv; -+ SMARTCARD_OPERATION op = WINPR_C_ARRAY_INIT; -+ -+ WLog_Print(priv->log, WLOG_DEBUG, -+ "SmartcardReleaseContextCallback: deviceId=%" PRIu32 ", completionId=%" PRIu32 -+ ", ioStatus=0x%" PRIx32, -+ deviceId, completionId, ioStatus); -+ -+ if (ioStatus != STATUS_SUCCESS) -+ { -+ if (context->OnSmartcardReleaseContextComplete) -+ context->OnSmartcardReleaseContextComplete(context, irp->CallbackData, ioStatus, -+ SCARD_F_INTERNAL_ERROR); -+ goto out; -+ } -+ -+ result = smartcard_irp_device_control_decode_response(s, irp->IoControlCode, &op); -+ if (result != SCARD_S_SUCCESS) -+ { -+ result = ERROR_INVALID_DATA; -+ goto out; -+ } -+ -+ if (context->OnSmartcardReleaseContextComplete) -+ context->OnSmartcardReleaseContextComplete(context, irp->CallbackData, ioStatus, -+ op.returnCode); -+ -+out: -+ smartcard_operation_free(&op, FALSE); -+ rdpdr_server_irp_free(irp); -+ return result; -+} -+ -+static UINT rdpdr_server_smartcard_release_context(RdpdrServerContext* context, void* callbackData, -+ const REDIR_SCARDCONTEXT* hContext, -+ UINT32* completionId) -+{ -+ WINPR_ASSERT(context); -+ WINPR_ASSERT(context->priv); -+ WINPR_ASSERT(hContext); -+ WINPR_ASSERT(completionId); -+ -+ UINT result = CHANNEL_RC_OK; -+ RdpdrServerPrivate* priv = context->priv; -+ RDPDR_IRP* irp = nullptr; -+ wStream* s = nullptr; -+ -+ result = -+ prepare_smartcard_irp(context, SCARD_IOCTL_RELEASECONTEXT, -+ rdpdr_server_smartcard_release_context_callback, callbackData, &irp); -+ if (result != CHANNEL_RC_OK) -+ return result; -+ -+ *completionId = irp->CompletionId; -+ -+ const SMARTCARD_OPERATION op = { -+ .ioControlCode = SCARD_IOCTL_RELEASECONTEXT, -+ .call.context.handles.hContext = *hContext, -+ }; -+ -+ s = Stream_New(nullptr, 64); -+ if (!s) -+ { -+ WLog_Print(priv->log, WLOG_ERROR, "Stream_New failed!"); -+ result = CHANNEL_RC_NO_MEMORY; -+ goto out; -+ } -+ -+ result = smartcard_irp_device_control_encode_request(s, &op); -+ if (result != SCARD_S_SUCCESS) -+ { -+ result = ERROR_INTERNAL_ERROR; -+ goto out; -+ } -+ -+ result = rdpdr_server_send_device_control_request( -+ context, irp->DeviceId, irp->CompletionId, irp->IoControlCode, -+ SCARD_IOCTL_MAX_OUTPUT_BUFFER_LENGTH, Stream_Buffer(s), Stream_Length(s)); -+ -+out: -+ if (result != CHANNEL_RC_OK && irp) -+ rdpdr_server_discard_request(context, irp->CompletionId); -+ if (s) -+ Stream_Release(s); -+ return result; -+} -+ -+/* IsValidContext */ -+static UINT rdpdr_server_smartcard_is_valid_context_callback(RdpdrServerContext* context, -+ wStream* s, RDPDR_IRP* irp, -+ UINT32 deviceId, UINT32 completionId, -+ UINT32 ioStatus) -+{ -+ WINPR_ASSERT(context); -+ WINPR_ASSERT(context->priv); -+ WINPR_ASSERT(s); -+ WINPR_ASSERT(irp); -+ -+ UINT result = CHANNEL_RC_OK; -+ RdpdrServerPrivate* priv = context->priv; -+ SMARTCARD_OPERATION op = WINPR_C_ARRAY_INIT; -+ -+ WLog_Print(priv->log, WLOG_DEBUG, -+ "SmartcardIsValidContextCallback: deviceId=%" PRIu32 ", completionId=%" PRIu32 -+ ", ioStatus=0x%" PRIx32, -+ deviceId, completionId, ioStatus); -+ -+ if (ioStatus != STATUS_SUCCESS) -+ { -+ if (context->OnSmartcardIsValidContextComplete) -+ context->OnSmartcardIsValidContextComplete(context, irp->CallbackData, ioStatus, -+ SCARD_F_INTERNAL_ERROR); -+ goto out; -+ } -+ -+ result = smartcard_irp_device_control_decode_response(s, irp->IoControlCode, &op); -+ if (result != SCARD_S_SUCCESS) -+ { -+ result = ERROR_INVALID_DATA; -+ goto out; -+ } -+ -+ if (context->OnSmartcardIsValidContextComplete) -+ context->OnSmartcardIsValidContextComplete(context, irp->CallbackData, ioStatus, -+ op.returnCode); -+ -+out: -+ smartcard_operation_free(&op, FALSE); -+ rdpdr_server_irp_free(irp); -+ return result; -+} -+ -+static UINT rdpdr_server_smartcard_is_valid_context(RdpdrServerContext* context, void* callbackData, -+ const REDIR_SCARDCONTEXT* hContext, -+ UINT32* completionId) -+{ -+ WINPR_ASSERT(context); -+ WINPR_ASSERT(context->priv); -+ WINPR_ASSERT(hContext); -+ WINPR_ASSERT(completionId); -+ -+ UINT result = CHANNEL_RC_OK; -+ RdpdrServerPrivate* priv = context->priv; -+ RDPDR_IRP* irp = nullptr; -+ wStream* s = nullptr; -+ -+ result = -+ prepare_smartcard_irp(context, SCARD_IOCTL_ISVALIDCONTEXT, -+ rdpdr_server_smartcard_is_valid_context_callback, callbackData, &irp); -+ if (result != CHANNEL_RC_OK) -+ return result; -+ -+ *completionId = irp->CompletionId; -+ -+ const SMARTCARD_OPERATION op = { -+ .ioControlCode = SCARD_IOCTL_ISVALIDCONTEXT, -+ .call.context.handles.hContext = *hContext, -+ }; -+ -+ s = Stream_New(nullptr, 64); -+ if (!s) -+ { -+ WLog_Print(priv->log, WLOG_ERROR, "Stream_New failed!"); -+ result = CHANNEL_RC_NO_MEMORY; -+ goto out; -+ } -+ -+ result = smartcard_irp_device_control_encode_request(s, &op); -+ if (result != SCARD_S_SUCCESS) -+ { -+ result = ERROR_INTERNAL_ERROR; -+ goto out; -+ } -+ -+ result = rdpdr_server_send_device_control_request( -+ context, irp->DeviceId, irp->CompletionId, irp->IoControlCode, -+ SCARD_IOCTL_MAX_OUTPUT_BUFFER_LENGTH, Stream_Buffer(s), Stream_Length(s)); -+ -+out: -+ if (result != CHANNEL_RC_OK && irp) -+ rdpdr_server_discard_request(context, irp->CompletionId); -+ if (s) -+ Stream_Release(s); -+ return result; -+} -+ -+/* ListReaderGroups */ -+static UINT rdpdr_server_smartcard_list_reader_groups_callback(RdpdrServerContext* context, -+ wStream* s, RDPDR_IRP* irp, -+ UINT32 deviceId, UINT32 completionId, -+ UINT32 ioStatus) -+{ -+ WINPR_ASSERT(context); -+ WINPR_ASSERT(context->priv); -+ WINPR_ASSERT(s); -+ WINPR_ASSERT(irp); -+ -+ UINT result = CHANNEL_RC_OK; -+ RdpdrServerPrivate* priv = context->priv; -+ SMARTCARD_OPERATION op = WINPR_C_ARRAY_INIT; -+ -+ WLog_Print(priv->log, WLOG_DEBUG, -+ "SmartcardListReaderGroupsCallback: deviceId=%" PRIu32 ", completionId=%" PRIu32 -+ ", ioStatus=0x%" PRIx32, -+ deviceId, completionId, ioStatus); -+ -+ if (ioStatus != STATUS_SUCCESS) -+ { -+ if (context->OnSmartcardListReaderGroupsComplete) -+ context->OnSmartcardListReaderGroupsComplete(context, irp->CallbackData, ioStatus, -+ SCARD_F_INTERNAL_ERROR, nullptr); -+ goto out; -+ } -+ -+ result = smartcard_irp_device_control_decode_response(s, irp->IoControlCode, &op); -+ if (result != SCARD_S_SUCCESS) -+ { -+ result = ERROR_INVALID_DATA; -+ goto out; -+ } -+ -+ if (context->OnSmartcardListReaderGroupsComplete) -+ context->OnSmartcardListReaderGroupsComplete(context, irp->CallbackData, ioStatus, -+ op.returnCode, &op.ret.listReaders); -+ -+out: -+ smartcard_operation_free(&op, FALSE); -+ rdpdr_server_irp_free(irp); -+ return result; -+} -+ -+static UINT rdpdr_server_smartcard_list_reader_groups(RdpdrServerContext* context, -+ void* callbackData, UINT32 ioControlCode, -+ const ListReaderGroups_Call* call, -+ UINT32* completionId) -+{ -+ WINPR_ASSERT(context); -+ WINPR_ASSERT(context->priv); -+ WINPR_ASSERT(call); -+ WINPR_ASSERT(completionId); -+ -+ UINT result = CHANNEL_RC_OK; -+ RdpdrServerPrivate* priv = context->priv; -+ RDPDR_IRP* irp = nullptr; -+ wStream* s = nullptr; -+ -+ result = prepare_smartcard_irp(context, ioControlCode, -+ rdpdr_server_smartcard_list_reader_groups_callback, callbackData, -+ &irp); -+ if (result != CHANNEL_RC_OK) -+ return result; -+ -+ *completionId = irp->CompletionId; -+ -+ /* clang-format off */ -+ const SMARTCARD_OPERATION op = { -+ .ioControlCode = ioControlCode, -+ .call.listReaderGroups = { -+ .handles.hContext = call->handles.hContext, -+ .fmszGroupsIsNULL = call->fmszGroupsIsNULL, -+ .cchGroups = call->cchGroups, -+ } -+ }; -+ /* clang-format on */ -+ -+ s = Stream_New(nullptr, 32); -+ if (!s) -+ { -+ WLog_Print(priv->log, WLOG_ERROR, "Stream_New failed!"); -+ result = CHANNEL_RC_NO_MEMORY; -+ goto out; -+ } -+ -+ result = smartcard_irp_device_control_encode_request(s, &op); -+ if (result != SCARD_S_SUCCESS) -+ { -+ result = ERROR_INTERNAL_ERROR; -+ goto out; -+ } -+ -+ result = rdpdr_server_send_device_control_request( -+ context, irp->DeviceId, irp->CompletionId, irp->IoControlCode, -+ SCARD_IOCTL_MAX_OUTPUT_BUFFER_LENGTH, Stream_Buffer(s), Stream_Length(s)); -+ -+out: -+ if (result != CHANNEL_RC_OK && irp) -+ rdpdr_server_discard_request(context, irp->CompletionId); -+ if (s) -+ Stream_Release(s); -+ return result; -+} -+ -+static UINT rdpdr_server_smartcard_list_reader_groupsA(RdpdrServerContext* context, -+ void* callbackData, -+ const ListReaderGroups_Call* call, -+ UINT32* completionId) -+{ -+ return rdpdr_server_smartcard_list_reader_groups( -+ context, callbackData, SCARD_IOCTL_LISTREADERGROUPSA, call, completionId); -+} -+ -+static UINT rdpdr_server_smartcard_list_reader_groupsW(RdpdrServerContext* context, -+ void* callbackData, -+ const ListReaderGroups_Call* call, -+ UINT32* completionId) -+{ -+ return rdpdr_server_smartcard_list_reader_groups( -+ context, callbackData, SCARD_IOCTL_LISTREADERGROUPSW, call, completionId); -+} -+ -+/* ListReaders */ -+static UINT rdpdr_server_smartcard_list_readers_callback(RdpdrServerContext* context, wStream* s, -+ RDPDR_IRP* irp, UINT32 deviceId, -+ UINT32 completionId, UINT32 ioStatus) -+{ -+ WINPR_ASSERT(context); -+ WINPR_ASSERT(context->priv); -+ WINPR_ASSERT(s); -+ WINPR_ASSERT(irp); -+ -+ UINT result = CHANNEL_RC_OK; -+ RdpdrServerPrivate* priv = context->priv; -+ SMARTCARD_OPERATION op = WINPR_C_ARRAY_INIT; -+ -+ WLog_Print(priv->log, WLOG_DEBUG, -+ "SmartcardListReadersCallback: deviceId=%" PRIu32 ", completionId=%" PRIu32 -+ ", ioStatus=0x%" PRIx32, -+ deviceId, completionId, ioStatus); -+ -+ if (ioStatus != STATUS_SUCCESS) -+ { -+ if (context->OnSmartcardListReadersComplete) -+ context->OnSmartcardListReadersComplete(context, irp->CallbackData, ioStatus, -+ SCARD_F_INTERNAL_ERROR, nullptr); -+ goto out; -+ } -+ -+ result = smartcard_irp_device_control_decode_response(s, irp->IoControlCode, &op); -+ if (result != SCARD_S_SUCCESS) -+ { -+ result = ERROR_INVALID_DATA; -+ goto out; -+ } -+ -+ if (context->OnSmartcardListReadersComplete) -+ context->OnSmartcardListReadersComplete(context, irp->CallbackData, ioStatus, op.returnCode, -+ &op.ret.listReaders); -+ -+out: -+ smartcard_operation_free(&op, FALSE); -+ rdpdr_server_irp_free(irp); -+ return result; -+} -+ -+static UINT rdpdr_server_smartcard_list_readers(RdpdrServerContext* context, void* callbackData, -+ UINT32 ioControlCode, const ListReaders_Call* call, -+ UINT32* completionId) -+{ -+ WINPR_ASSERT(context); -+ WINPR_ASSERT(context->priv); -+ WINPR_ASSERT(call); -+ WINPR_ASSERT(completionId); -+ -+ UINT result = CHANNEL_RC_OK; -+ RdpdrServerPrivate* priv = context->priv; -+ RDPDR_IRP* irp = nullptr; -+ wStream* s = nullptr; -+ -+ result = prepare_smartcard_irp( -+ context, ioControlCode, rdpdr_server_smartcard_list_readers_callback, callbackData, &irp); -+ if (result != CHANNEL_RC_OK) -+ return result; -+ -+ *completionId = irp->CompletionId; -+ -+ /* clang-format off */ -+ const SMARTCARD_OPERATION op = { -+ .ioControlCode = ioControlCode, -+ .call.listReaders = { -+ .handles.hContext = call->handles.hContext, -+ .cBytes = call->cBytes, -+ .mszGroups = call->mszGroups, -+ .fmszReadersIsNULL = call->fmszReadersIsNULL, -+ .cchReaders = call->cchReaders, -+ } -+ }; -+ /* clang-format on */ -+ -+ s = Stream_New(nullptr, 256); -+ if (!s) -+ { -+ WLog_Print(priv->log, WLOG_ERROR, "Stream_New failed!"); -+ result = CHANNEL_RC_NO_MEMORY; -+ goto out; -+ } -+ -+ result = smartcard_irp_device_control_encode_request(s, &op); -+ if (result != SCARD_S_SUCCESS) -+ { -+ result = ERROR_INTERNAL_ERROR; -+ goto out; -+ } -+ -+ result = rdpdr_server_send_device_control_request( -+ context, irp->DeviceId, irp->CompletionId, irp->IoControlCode, -+ SCARD_IOCTL_MAX_OUTPUT_BUFFER_LENGTH, Stream_Buffer(s), Stream_Length(s)); -+ -+out: -+ if (result != CHANNEL_RC_OK && irp) -+ rdpdr_server_discard_request(context, irp->CompletionId); -+ if (s) -+ Stream_Release(s); -+ return result; -+} -+ -+static UINT rdpdr_server_smartcard_list_readersA(RdpdrServerContext* context, void* callbackData, -+ const ListReaders_Call* call, UINT32* completionId) -+{ -+ return rdpdr_server_smartcard_list_readers(context, callbackData, SCARD_IOCTL_LISTREADERSA, -+ call, completionId); -+} -+ -+static UINT rdpdr_server_smartcard_list_readersW(RdpdrServerContext* context, void* callbackData, -+ const ListReaders_Call* call, UINT32* completionId) -+{ -+ return rdpdr_server_smartcard_list_readers(context, callbackData, SCARD_IOCTL_LISTREADERSW, -+ call, completionId); -+} -+ -+/* GetStatusChange */ -+static UINT rdpdr_server_smartcard_get_status_change_callback(RdpdrServerContext* context, -+ wStream* s, RDPDR_IRP* irp, -+ UINT32 deviceId, UINT32 completionId, -+ UINT32 ioStatus) -+{ -+ WINPR_ASSERT(context); -+ WINPR_ASSERT(context->priv); -+ WINPR_ASSERT(s); -+ WINPR_ASSERT(irp); -+ -+ UINT result = CHANNEL_RC_OK; -+ RdpdrServerPrivate* priv = context->priv; -+ SMARTCARD_OPERATION op = WINPR_C_ARRAY_INIT; -+ -+ WLog_Print(priv->log, WLOG_DEBUG, -+ "SmartcardGetStatusChangeCallback: deviceId=%" PRIu32 ", completionId=%" PRIu32 -+ ", ioStatus=0x%" PRIx32, -+ deviceId, completionId, ioStatus); -+ -+ if (ioStatus != STATUS_SUCCESS) -+ { -+ if (context->OnSmartcardGetStatusChangeComplete) -+ context->OnSmartcardGetStatusChangeComplete(context, irp->CallbackData, ioStatus, -+ SCARD_F_INTERNAL_ERROR, nullptr); -+ goto out; -+ } -+ -+ result = smartcard_irp_device_control_decode_response(s, irp->IoControlCode, &op); -+ if (result != SCARD_S_SUCCESS) -+ { -+ result = ERROR_INVALID_DATA; -+ goto out; -+ } -+ -+ if (context->OnSmartcardGetStatusChangeComplete) -+ context->OnSmartcardGetStatusChangeComplete(context, irp->CallbackData, ioStatus, -+ op.returnCode, &op.ret.getStatusChange); -+ -+out: -+ smartcard_operation_free(&op, FALSE); -+ rdpdr_server_irp_free(irp); -+ return result; -+} -+ -+static UINT rdpdr_server_smartcard_get_status_change(RdpdrServerContext* context, -+ void* callbackData, UINT32 ioControlCode, -+ const void* call, DWORD cReaders, -+ UINT32* completionId) -+{ -+ WINPR_ASSERT(context); -+ WINPR_ASSERT(context->priv); -+ WINPR_ASSERT(call); -+ WINPR_ASSERT(completionId); -+ -+ UINT result = CHANNEL_RC_OK; -+ RdpdrServerPrivate* priv = context->priv; -+ RDPDR_IRP* irp = nullptr; -+ wStream* s = nullptr; -+ -+ result = prepare_smartcard_irp(context, ioControlCode, -+ rdpdr_server_smartcard_get_status_change_callback, callbackData, -+ &irp); -+ if (result != CHANNEL_RC_OK) -+ return result; -+ -+ *completionId = irp->CompletionId; -+ -+ SMARTCARD_OPERATION op = WINPR_C_ARRAY_INIT; -+ op.ioControlCode = ioControlCode; -+ -+ switch (ioControlCode) -+ { -+ case SCARD_IOCTL_GETSTATUSCHANGEA: -+ op.call.getStatusChangeA = *(const GetStatusChangeA_Call*)call; -+ break; -+ case SCARD_IOCTL_GETSTATUSCHANGEW: -+ op.call.getStatusChangeW = *(const GetStatusChangeW_Call*)call; -+ break; -+ default: -+ WINPR_ASSERT(FALSE); -+ return ERROR_INVALID_PARAMETER; -+ } -+ -+ s = Stream_New(nullptr, 256 + cReaders * 256); -+ if (!s) -+ { -+ WLog_Print(priv->log, WLOG_ERROR, "Stream_New failed!"); -+ result = CHANNEL_RC_NO_MEMORY; -+ goto out; -+ } -+ -+ result = smartcard_irp_device_control_encode_request(s, &op); -+ if (result != SCARD_S_SUCCESS) -+ { -+ result = ERROR_INTERNAL_ERROR; -+ goto out; -+ } -+ -+ result = rdpdr_server_send_device_control_request( -+ context, irp->DeviceId, irp->CompletionId, irp->IoControlCode, -+ SCARD_IOCTL_MAX_OUTPUT_BUFFER_LENGTH, Stream_Buffer(s), Stream_Length(s)); -+ -+out: -+ if (result != CHANNEL_RC_OK && irp) -+ rdpdr_server_discard_request(context, irp->CompletionId); -+ if (s) -+ Stream_Release(s); -+ return result; -+} -+ -+static UINT rdpdr_server_smartcard_get_status_changeA(RdpdrServerContext* context, -+ void* callbackData, -+ const GetStatusChangeA_Call* call, -+ UINT32* completionId) -+{ -+ return rdpdr_server_smartcard_get_status_change( -+ context, callbackData, SCARD_IOCTL_GETSTATUSCHANGEA, call, call->cReaders, completionId); -+} -+ -+static UINT rdpdr_server_smartcard_get_status_changeW(RdpdrServerContext* context, -+ void* callbackData, -+ const GetStatusChangeW_Call* call, -+ UINT32* completionId) -+{ -+ return rdpdr_server_smartcard_get_status_change( -+ context, callbackData, SCARD_IOCTL_GETSTATUSCHANGEW, call, call->cReaders, completionId); -+} -+ -+/* Cancel */ -+static UINT rdpdr_server_smartcard_cancel_callback(RdpdrServerContext* context, wStream* s, -+ RDPDR_IRP* irp, UINT32 deviceId, -+ UINT32 completionId, UINT32 ioStatus) -+{ -+ WINPR_ASSERT(context); -+ WINPR_ASSERT(context->priv); -+ WINPR_ASSERT(s); -+ WINPR_ASSERT(irp); -+ -+ UINT result = CHANNEL_RC_OK; -+ RdpdrServerPrivate* priv = context->priv; -+ SMARTCARD_OPERATION op = WINPR_C_ARRAY_INIT; -+ -+ WLog_Print(priv->log, WLOG_DEBUG, -+ "SmartcardCancelCallback: deviceId=%" PRIu32 ", completionId=%" PRIu32 -+ ", ioStatus=0x%" PRIx32, -+ deviceId, completionId, ioStatus); -+ -+ if (ioStatus != STATUS_SUCCESS) -+ { -+ if (context->OnSmartcardCancelComplete) -+ context->OnSmartcardCancelComplete(context, irp->CallbackData, ioStatus, -+ SCARD_F_INTERNAL_ERROR); -+ goto out; -+ } -+ -+ result = smartcard_irp_device_control_decode_response(s, irp->IoControlCode, &op); -+ if (result != SCARD_S_SUCCESS) -+ { -+ result = ERROR_INVALID_DATA; -+ goto out; -+ } -+ -+ if (context->OnSmartcardCancelComplete) -+ context->OnSmartcardCancelComplete(context, irp->CallbackData, ioStatus, op.returnCode); -+ -+out: -+ smartcard_operation_free(&op, FALSE); -+ rdpdr_server_irp_free(irp); -+ return result; -+} -+ -+static UINT rdpdr_server_smartcard_cancel(RdpdrServerContext* context, void* callbackData, -+ const REDIR_SCARDCONTEXT* hContext, UINT32* completionId) -+{ -+ WINPR_ASSERT(context); -+ WINPR_ASSERT(context->priv); -+ WINPR_ASSERT(hContext); -+ WINPR_ASSERT(completionId); -+ -+ UINT result = CHANNEL_RC_OK; -+ RdpdrServerPrivate* priv = context->priv; -+ RDPDR_IRP* irp = nullptr; -+ wStream* s = nullptr; -+ -+ result = prepare_smartcard_irp(context, SCARD_IOCTL_CANCEL, -+ rdpdr_server_smartcard_cancel_callback, callbackData, &irp); -+ if (result != CHANNEL_RC_OK) -+ return result; -+ -+ *completionId = irp->CompletionId; -+ -+ const SMARTCARD_OPERATION op = { -+ .ioControlCode = SCARD_IOCTL_CANCEL, -+ .call.context.handles.hContext = *hContext, -+ }; -+ -+ s = Stream_New(nullptr, 64); -+ if (!s) -+ { -+ WLog_Print(priv->log, WLOG_ERROR, "Stream_New failed!"); -+ result = CHANNEL_RC_NO_MEMORY; -+ goto out; -+ } -+ -+ result = smartcard_irp_device_control_encode_request(s, &op); -+ if (result != SCARD_S_SUCCESS) -+ { -+ result = ERROR_INTERNAL_ERROR; -+ goto out; -+ } -+ -+ result = rdpdr_server_send_device_control_request( -+ context, irp->DeviceId, irp->CompletionId, irp->IoControlCode, -+ SCARD_IOCTL_MAX_OUTPUT_BUFFER_LENGTH, Stream_Buffer(s), Stream_Length(s)); -+ -+out: -+ if (result != CHANNEL_RC_OK && irp) -+ rdpdr_server_discard_request(context, irp->CompletionId); -+ if (s) -+ Stream_Release(s); -+ return result; -+} -+ -+/* Connect */ -+static UINT rdpdr_server_smartcard_connect_callback(RdpdrServerContext* context, wStream* s, -+ RDPDR_IRP* irp, UINT32 deviceId, -+ UINT32 completionId, UINT32 ioStatus) -+{ -+ WINPR_ASSERT(context); -+ WINPR_ASSERT(context->priv); -+ WINPR_ASSERT(s); -+ WINPR_ASSERT(irp); -+ -+ UINT result = CHANNEL_RC_OK; -+ RdpdrServerPrivate* priv = context->priv; -+ SMARTCARD_OPERATION op = WINPR_C_ARRAY_INIT; -+ -+ WLog_Print(priv->log, WLOG_DEBUG, -+ "SmartcardConnectCallback: deviceId=%" PRIu32 ", completionId=%" PRIu32 -+ ", ioStatus=0x%" PRIx32, -+ deviceId, completionId, ioStatus); -+ -+ if (ioStatus != STATUS_SUCCESS) -+ { -+ if (context->OnSmartcardConnectComplete) -+ context->OnSmartcardConnectComplete(context, irp->CallbackData, ioStatus, -+ SCARD_F_INTERNAL_ERROR, nullptr); -+ goto out; -+ } -+ -+ result = smartcard_irp_device_control_decode_response(s, irp->IoControlCode, &op); -+ if (result != SCARD_S_SUCCESS) -+ { -+ result = ERROR_INVALID_DATA; -+ goto out; -+ } -+ -+ if (context->OnSmartcardConnectComplete) -+ context->OnSmartcardConnectComplete(context, irp->CallbackData, ioStatus, op.returnCode, -+ &op.ret.connect); -+ -+out: -+ smartcard_operation_free(&op, FALSE); -+ rdpdr_server_irp_free(irp); -+ return result; -+} -+ -+static UINT rdpdr_server_smartcard_connect(RdpdrServerContext* context, void* callbackData, -+ UINT32 ioControlCode, const void* call, -+ UINT32* completionId) -+{ -+ WINPR_ASSERT(context); -+ WINPR_ASSERT(context->priv); -+ WINPR_ASSERT(call); -+ WINPR_ASSERT(completionId); -+ -+ UINT result = CHANNEL_RC_OK; -+ RdpdrServerPrivate* priv = context->priv; -+ RDPDR_IRP* irp = nullptr; -+ wStream* s = nullptr; -+ -+ result = prepare_smartcard_irp(context, ioControlCode, rdpdr_server_smartcard_connect_callback, -+ callbackData, &irp); -+ if (result != CHANNEL_RC_OK) -+ return result; -+ -+ *completionId = irp->CompletionId; -+ -+ SMARTCARD_OPERATION op = WINPR_C_ARRAY_INIT; -+ op.ioControlCode = ioControlCode; -+ -+ switch (ioControlCode) -+ { -+ case SCARD_IOCTL_CONNECTA: -+ op.call.connectA = *(const ConnectA_Call*)call; -+ break; -+ case SCARD_IOCTL_CONNECTW: -+ op.call.connectW = *(const ConnectW_Call*)call; -+ break; -+ default: -+ WINPR_ASSERT(FALSE); -+ return ERROR_INVALID_PARAMETER; -+ } -+ -+ s = Stream_New(nullptr, 512); -+ if (!s) -+ { -+ WLog_Print(priv->log, WLOG_ERROR, "Stream_New failed!"); -+ result = CHANNEL_RC_NO_MEMORY; -+ goto out; -+ } -+ -+ result = smartcard_irp_device_control_encode_request(s, &op); -+ if (result != SCARD_S_SUCCESS) -+ { -+ result = ERROR_INTERNAL_ERROR; -+ goto out; -+ } -+ -+ result = rdpdr_server_send_device_control_request( -+ context, irp->DeviceId, irp->CompletionId, irp->IoControlCode, -+ SCARD_IOCTL_MAX_OUTPUT_BUFFER_LENGTH, Stream_Buffer(s), Stream_Length(s)); -+ -+out: -+ if (result != CHANNEL_RC_OK && irp) -+ rdpdr_server_discard_request(context, irp->CompletionId); -+ if (s) -+ Stream_Release(s); -+ return result; -+} -+ -+static UINT rdpdr_server_smartcard_connectA(RdpdrServerContext* context, void* callbackData, -+ const ConnectA_Call* call, UINT32* completionId) -+{ -+ return rdpdr_server_smartcard_connect(context, callbackData, SCARD_IOCTL_CONNECTA, call, -+ completionId); -+} -+ -+static UINT rdpdr_server_smartcard_connectW(RdpdrServerContext* context, void* callbackData, -+ const ConnectW_Call* call, UINT32* completionId) -+{ -+ return rdpdr_server_smartcard_connect(context, callbackData, SCARD_IOCTL_CONNECTW, call, -+ completionId); -+} -+ -+/* Reconnect */ -+static UINT rdpdr_server_smartcard_reconnect_callback(RdpdrServerContext* context, wStream* s, -+ RDPDR_IRP* irp, UINT32 deviceId, -+ UINT32 completionId, UINT32 ioStatus) -+{ -+ WINPR_ASSERT(context); -+ WINPR_ASSERT(context->priv); -+ WINPR_ASSERT(s); -+ WINPR_ASSERT(irp); -+ -+ UINT result = CHANNEL_RC_OK; -+ RdpdrServerPrivate* priv = context->priv; -+ SMARTCARD_OPERATION op = WINPR_C_ARRAY_INIT; -+ -+ WLog_Print(priv->log, WLOG_DEBUG, -+ "SmartcardReconnectCallback: deviceId=%" PRIu32 ", completionId=%" PRIu32 -+ ", ioStatus=0x%" PRIx32, -+ deviceId, completionId, ioStatus); -+ -+ if (ioStatus != STATUS_SUCCESS) -+ { -+ if (context->OnSmartcardReconnectComplete) -+ context->OnSmartcardReconnectComplete(context, irp->CallbackData, ioStatus, -+ SCARD_F_INTERNAL_ERROR, nullptr); -+ goto out; -+ } -+ -+ result = smartcard_irp_device_control_decode_response(s, irp->IoControlCode, &op); -+ if (result != SCARD_S_SUCCESS) -+ { -+ result = ERROR_INVALID_DATA; -+ goto out; -+ } -+ -+ if (context->OnSmartcardReconnectComplete) -+ context->OnSmartcardReconnectComplete(context, irp->CallbackData, ioStatus, op.returnCode, -+ &op.ret.reconnect); -+ -+out: -+ smartcard_operation_free(&op, FALSE); -+ rdpdr_server_irp_free(irp); -+ return result; -+} -+ -+static UINT rdpdr_server_smartcard_reconnect(RdpdrServerContext* context, void* callbackData, -+ const Reconnect_Call* call, UINT32* completionId) -+{ -+ WINPR_ASSERT(context); -+ WINPR_ASSERT(context->priv); -+ WINPR_ASSERT(call); -+ WINPR_ASSERT(completionId); -+ -+ UINT result = CHANNEL_RC_OK; -+ RdpdrServerPrivate* priv = context->priv; -+ RDPDR_IRP* irp = nullptr; -+ wStream* s = nullptr; -+ -+ result = prepare_smartcard_irp(context, SCARD_IOCTL_RECONNECT, -+ rdpdr_server_smartcard_reconnect_callback, callbackData, &irp); -+ if (result != CHANNEL_RC_OK) -+ return result; -+ -+ *completionId = irp->CompletionId; -+ -+ /* clang-format off */ -+ const SMARTCARD_OPERATION op = { -+ .ioControlCode = SCARD_IOCTL_RECONNECT, -+ .call.reconnect = { -+ .handles.hContext = call->handles.hContext, -+ .handles.hCard = call->handles.hCard, -+ .dwShareMode = call->dwShareMode, -+ .dwPreferredProtocols = call->dwPreferredProtocols, -+ .dwInitialization = call->dwInitialization, -+ } -+ }; -+ /* clang-format on */ -+ -+ s = Stream_New(nullptr, 128); -+ if (!s) -+ { -+ WLog_Print(priv->log, WLOG_ERROR, "Stream_New failed!"); -+ result = CHANNEL_RC_NO_MEMORY; -+ goto out; -+ } -+ -+ result = smartcard_irp_device_control_encode_request(s, &op); -+ if (result != SCARD_S_SUCCESS) -+ { -+ result = ERROR_INTERNAL_ERROR; -+ goto out; -+ } -+ -+ result = rdpdr_server_send_device_control_request( -+ context, irp->DeviceId, irp->CompletionId, irp->IoControlCode, -+ SCARD_IOCTL_MAX_OUTPUT_BUFFER_LENGTH, Stream_Buffer(s), Stream_Length(s)); -+ -+out: -+ if (result != CHANNEL_RC_OK && irp) -+ rdpdr_server_discard_request(context, irp->CompletionId); -+ if (s) -+ Stream_Release(s); -+ return result; -+} -+ -+/* Disconnect */ -+static UINT rdpdr_server_smartcard_disconnect_callback(RdpdrServerContext* context, wStream* s, -+ RDPDR_IRP* irp, UINT32 deviceId, -+ UINT32 completionId, UINT32 ioStatus) -+{ -+ WINPR_ASSERT(context); -+ WINPR_ASSERT(context->priv); -+ WINPR_ASSERT(s); -+ WINPR_ASSERT(irp); -+ -+ UINT result = CHANNEL_RC_OK; -+ RdpdrServerPrivate* priv = context->priv; -+ SMARTCARD_OPERATION op = WINPR_C_ARRAY_INIT; -+ -+ WLog_Print(priv->log, WLOG_DEBUG, -+ "SmartcardDisconnectCallback: deviceId=%" PRIu32 ", completionId=%" PRIu32 -+ ", ioStatus=0x%" PRIx32, -+ deviceId, completionId, ioStatus); -+ -+ if (ioStatus != STATUS_SUCCESS) -+ { -+ if (context->OnSmartcardDisconnectComplete) -+ context->OnSmartcardDisconnectComplete(context, irp->CallbackData, ioStatus, -+ SCARD_F_INTERNAL_ERROR); -+ goto out; -+ } -+ -+ result = smartcard_irp_device_control_decode_response(s, irp->IoControlCode, &op); -+ if (result != SCARD_S_SUCCESS) -+ { -+ result = ERROR_INVALID_DATA; -+ goto out; -+ } -+ -+ if (context->OnSmartcardDisconnectComplete) -+ context->OnSmartcardDisconnectComplete(context, irp->CallbackData, ioStatus, op.returnCode); -+ -+out: -+ smartcard_operation_free(&op, FALSE); -+ rdpdr_server_irp_free(irp); -+ return result; -+} -+ -+static UINT rdpdr_server_smartcard_disconnect(RdpdrServerContext* context, void* callbackData, -+ const HCardAndDisposition_Call* call, -+ UINT32* completionId) -+{ -+ WINPR_ASSERT(context); -+ WINPR_ASSERT(context->priv); -+ WINPR_ASSERT(call); -+ WINPR_ASSERT(completionId); -+ -+ UINT result = CHANNEL_RC_OK; -+ RdpdrServerPrivate* priv = context->priv; -+ RDPDR_IRP* irp = nullptr; -+ wStream* s = nullptr; -+ -+ result = prepare_smartcard_irp(context, SCARD_IOCTL_DISCONNECT, -+ rdpdr_server_smartcard_disconnect_callback, callbackData, &irp); -+ if (result != CHANNEL_RC_OK) -+ return result; -+ -+ *completionId = irp->CompletionId; -+ -+ /* clang-format off */ -+ const SMARTCARD_OPERATION op = { -+ .ioControlCode = SCARD_IOCTL_DISCONNECT, -+ .call.hCardAndDisposition = { -+ .handles.hContext = call->handles.hContext, -+ .handles.hCard = call->handles.hCard, -+ .dwDisposition = call->dwDisposition, -+ } -+ }; -+ /* clang-format on */ -+ -+ s = Stream_New(nullptr, 128); -+ if (!s) -+ { -+ WLog_Print(priv->log, WLOG_ERROR, "Stream_New failed!"); -+ result = CHANNEL_RC_NO_MEMORY; -+ goto out; -+ } -+ -+ result = smartcard_irp_device_control_encode_request(s, &op); -+ if (result != SCARD_S_SUCCESS) -+ { -+ result = ERROR_INTERNAL_ERROR; -+ goto out; -+ } -+ -+ result = rdpdr_server_send_device_control_request( -+ context, irp->DeviceId, irp->CompletionId, irp->IoControlCode, -+ SCARD_IOCTL_MAX_OUTPUT_BUFFER_LENGTH, Stream_Buffer(s), Stream_Length(s)); -+ -+out: -+ if (result != CHANNEL_RC_OK && irp) -+ rdpdr_server_discard_request(context, irp->CompletionId); -+ if (s) -+ Stream_Release(s); -+ return result; -+} -+ -+/* BeginTransaction */ -+static UINT rdpdr_server_smartcard_begin_transaction_callback(RdpdrServerContext* context, -+ wStream* s, RDPDR_IRP* irp, -+ UINT32 deviceId, UINT32 completionId, -+ UINT32 ioStatus) -+{ -+ WINPR_ASSERT(context); -+ WINPR_ASSERT(context->priv); -+ WINPR_ASSERT(s); -+ WINPR_ASSERT(irp); -+ -+ UINT result = CHANNEL_RC_OK; -+ RdpdrServerPrivate* priv = context->priv; -+ SMARTCARD_OPERATION op = WINPR_C_ARRAY_INIT; -+ -+ WLog_Print(priv->log, WLOG_DEBUG, -+ "SmartcardBeginTransactionCallback: deviceId=%" PRIu32 ", completionId=%" PRIu32 -+ ", ioStatus=0x%" PRIx32, -+ deviceId, completionId, ioStatus); -+ -+ if (ioStatus != STATUS_SUCCESS) -+ { -+ if (context->OnSmartcardBeginTransactionComplete) -+ context->OnSmartcardBeginTransactionComplete(context, irp->CallbackData, ioStatus, -+ SCARD_F_INTERNAL_ERROR); -+ goto out; -+ } -+ -+ result = smartcard_irp_device_control_decode_response(s, irp->IoControlCode, &op); -+ if (result != SCARD_S_SUCCESS) -+ { -+ result = ERROR_INVALID_DATA; -+ goto out; -+ } -+ -+ if (context->OnSmartcardBeginTransactionComplete) -+ context->OnSmartcardBeginTransactionComplete(context, irp->CallbackData, ioStatus, -+ op.returnCode); -+ -+out: -+ smartcard_operation_free(&op, FALSE); -+ rdpdr_server_irp_free(irp); -+ return result; -+} -+ -+static UINT rdpdr_server_smartcard_begin_transaction(RdpdrServerContext* context, -+ void* callbackData, -+ const HCardAndDisposition_Call* call, -+ UINT32* completionId) -+{ -+ WINPR_ASSERT(context); -+ WINPR_ASSERT(context->priv); -+ WINPR_ASSERT(call); -+ WINPR_ASSERT(completionId); -+ -+ UINT result = CHANNEL_RC_OK; -+ RdpdrServerPrivate* priv = context->priv; -+ RDPDR_IRP* irp = nullptr; -+ wStream* s = nullptr; -+ -+ result = prepare_smartcard_irp(context, SCARD_IOCTL_BEGINTRANSACTION, -+ rdpdr_server_smartcard_begin_transaction_callback, callbackData, -+ &irp); -+ if (result != CHANNEL_RC_OK) -+ return result; -+ -+ *completionId = irp->CompletionId; -+ -+ /* clang-format off */ -+ const SMARTCARD_OPERATION op = { -+ .ioControlCode = SCARD_IOCTL_BEGINTRANSACTION, -+ .call.hCardAndDisposition = { -+ .handles.hContext = call->handles.hContext, -+ .handles.hCard = call->handles.hCard, -+ .dwDisposition = SCARD_LEAVE_CARD, -+ } -+ }; -+ /* clang-format on */ -+ -+ s = Stream_New(nullptr, 128); -+ if (!s) -+ { -+ WLog_Print(priv->log, WLOG_ERROR, "Stream_New failed!"); -+ result = CHANNEL_RC_NO_MEMORY; -+ goto out; -+ } -+ -+ result = smartcard_irp_device_control_encode_request(s, &op); -+ if (result != SCARD_S_SUCCESS) -+ { -+ result = ERROR_INTERNAL_ERROR; -+ goto out; -+ } -+ -+ result = rdpdr_server_send_device_control_request( -+ context, irp->DeviceId, irp->CompletionId, irp->IoControlCode, -+ SCARD_IOCTL_MAX_OUTPUT_BUFFER_LENGTH, Stream_Buffer(s), Stream_Length(s)); -+ -+out: -+ if (result != CHANNEL_RC_OK && irp) -+ rdpdr_server_discard_request(context, irp->CompletionId); -+ if (s) -+ Stream_Release(s); -+ return result; -+} -+ -+/* EndTransaction */ -+static UINT rdpdr_server_smartcard_end_transaction_callback(RdpdrServerContext* context, wStream* s, -+ RDPDR_IRP* irp, UINT32 deviceId, -+ UINT32 completionId, UINT32 ioStatus) -+{ -+ WINPR_ASSERT(context); -+ WINPR_ASSERT(context->priv); -+ WINPR_ASSERT(s); -+ WINPR_ASSERT(irp); -+ -+ UINT result = CHANNEL_RC_OK; -+ RdpdrServerPrivate* priv = context->priv; -+ SMARTCARD_OPERATION op = WINPR_C_ARRAY_INIT; -+ -+ WLog_Print(priv->log, WLOG_DEBUG, -+ "SmartcardEndTransactionCallback: deviceId=%" PRIu32 ", completionId=%" PRIu32 -+ ", ioStatus=0x%" PRIx32, -+ deviceId, completionId, ioStatus); -+ -+ if (ioStatus != STATUS_SUCCESS) -+ { -+ if (context->OnSmartcardEndTransactionComplete) -+ context->OnSmartcardEndTransactionComplete(context, irp->CallbackData, ioStatus, -+ SCARD_F_INTERNAL_ERROR); -+ goto out; -+ } -+ -+ result = smartcard_irp_device_control_decode_response(s, irp->IoControlCode, &op); -+ if (result != SCARD_S_SUCCESS) -+ { -+ result = ERROR_INVALID_DATA; -+ goto out; -+ } -+ -+ if (context->OnSmartcardEndTransactionComplete) -+ context->OnSmartcardEndTransactionComplete(context, irp->CallbackData, ioStatus, -+ op.returnCode); -+ -+out: -+ smartcard_operation_free(&op, FALSE); -+ rdpdr_server_irp_free(irp); -+ return result; -+} -+ -+static UINT rdpdr_server_smartcard_end_transaction(RdpdrServerContext* context, void* callbackData, -+ const HCardAndDisposition_Call* call, -+ UINT32* completionId) -+{ -+ WINPR_ASSERT(context); -+ WINPR_ASSERT(context->priv); -+ WINPR_ASSERT(call); -+ WINPR_ASSERT(completionId); -+ -+ UINT result = CHANNEL_RC_OK; -+ RdpdrServerPrivate* priv = context->priv; -+ RDPDR_IRP* irp = nullptr; -+ wStream* s = nullptr; -+ -+ result = -+ prepare_smartcard_irp(context, SCARD_IOCTL_ENDTRANSACTION, -+ rdpdr_server_smartcard_end_transaction_callback, callbackData, &irp); -+ if (result != CHANNEL_RC_OK) -+ return result; -+ -+ *completionId = irp->CompletionId; -+ -+ /* clang-format off */ -+ const SMARTCARD_OPERATION op = { -+ .ioControlCode = SCARD_IOCTL_ENDTRANSACTION, -+ .call.hCardAndDisposition = { -+ .handles.hContext = call->handles.hContext, -+ .handles.hCard = call->handles.hCard, -+ .dwDisposition = call->dwDisposition, -+ } -+ }; -+ /* clang-format on */ -+ -+ s = Stream_New(nullptr, 128); -+ if (!s) -+ { -+ WLog_Print(priv->log, WLOG_ERROR, "Stream_New failed!"); -+ result = CHANNEL_RC_NO_MEMORY; -+ goto out; -+ } -+ -+ result = smartcard_irp_device_control_encode_request(s, &op); -+ if (result != SCARD_S_SUCCESS) -+ { -+ result = ERROR_INTERNAL_ERROR; -+ goto out; -+ } -+ -+ result = rdpdr_server_send_device_control_request( -+ context, irp->DeviceId, irp->CompletionId, irp->IoControlCode, -+ SCARD_IOCTL_MAX_OUTPUT_BUFFER_LENGTH, Stream_Buffer(s), Stream_Length(s)); -+ -+out: -+ if (result != CHANNEL_RC_OK && irp) -+ rdpdr_server_discard_request(context, irp->CompletionId); -+ if (s) -+ Stream_Release(s); -+ return result; -+} -+ -+/* Status */ -+static UINT rdpdr_server_smartcard_status_callback(RdpdrServerContext* context, wStream* s, -+ RDPDR_IRP* irp, UINT32 deviceId, -+ UINT32 completionId, UINT32 ioStatus) -+{ -+ WINPR_ASSERT(context); -+ WINPR_ASSERT(context->priv); -+ WINPR_ASSERT(s); -+ WINPR_ASSERT(irp); -+ -+ UINT result = CHANNEL_RC_OK; -+ RdpdrServerPrivate* priv = context->priv; -+ SMARTCARD_OPERATION op = WINPR_C_ARRAY_INIT; -+ -+ WLog_Print(priv->log, WLOG_DEBUG, -+ "SmartcardStatusCallback: deviceId=%" PRIu32 ", completionId=%" PRIu32 -+ ", ioStatus=0x%" PRIx32, -+ deviceId, completionId, ioStatus); -+ -+ if (ioStatus != STATUS_SUCCESS) -+ { -+ if (context->OnSmartcardStatusComplete) -+ context->OnSmartcardStatusComplete(context, irp->CallbackData, ioStatus, -+ SCARD_F_INTERNAL_ERROR, nullptr); -+ goto out; -+ } -+ -+ result = smartcard_irp_device_control_decode_response(s, irp->IoControlCode, &op); -+ if (result != SCARD_S_SUCCESS) -+ { -+ result = ERROR_INVALID_DATA; -+ goto out; -+ } -+ -+ if (context->OnSmartcardStatusComplete) -+ context->OnSmartcardStatusComplete(context, irp->CallbackData, ioStatus, op.returnCode, -+ &op.ret.status); -+ -+out: -+ smartcard_operation_free(&op, FALSE); -+ rdpdr_server_irp_free(irp); -+ return result; -+} -+ -+static UINT rdpdr_server_smartcard_status(RdpdrServerContext* context, void* callbackData, -+ UINT32 ioControlCode, const Status_Call* call, -+ UINT32* completionId) -+{ -+ WINPR_ASSERT(context); -+ WINPR_ASSERT(context->priv); -+ WINPR_ASSERT(call); -+ WINPR_ASSERT(completionId); -+ -+ UINT result = CHANNEL_RC_OK; -+ RdpdrServerPrivate* priv = context->priv; -+ RDPDR_IRP* irp = nullptr; -+ wStream* s = nullptr; -+ -+ result = prepare_smartcard_irp(context, ioControlCode, rdpdr_server_smartcard_status_callback, -+ callbackData, &irp); -+ if (result != CHANNEL_RC_OK) -+ return result; -+ -+ *completionId = irp->CompletionId; -+ -+ /* clang-format off */ -+ const SMARTCARD_OPERATION op = { -+ .ioControlCode = ioControlCode, -+ .call.status = { -+ .handles.hContext = call->handles.hContext, -+ .handles.hCard = call->handles.hCard, -+ .fmszReaderNamesIsNULL = call->fmszReaderNamesIsNULL, -+ .cchReaderLen = call->cchReaderLen, -+ .cbAtrLen = call->cbAtrLen, -+ } -+ }; -+ /* clang-format on */ -+ -+ s = Stream_New(nullptr, 128); -+ if (!s) -+ { -+ WLog_Print(priv->log, WLOG_ERROR, "Stream_New failed!"); -+ result = CHANNEL_RC_NO_MEMORY; -+ goto out; -+ } -+ -+ result = smartcard_irp_device_control_encode_request(s, &op); -+ if (result != SCARD_S_SUCCESS) -+ { -+ result = ERROR_INTERNAL_ERROR; -+ goto out; -+ } -+ -+ result = rdpdr_server_send_device_control_request( -+ context, irp->DeviceId, irp->CompletionId, irp->IoControlCode, -+ SCARD_IOCTL_MAX_OUTPUT_BUFFER_LENGTH, Stream_Buffer(s), Stream_Length(s)); -+ -+out: -+ if (result != CHANNEL_RC_OK && irp) -+ rdpdr_server_discard_request(context, irp->CompletionId); -+ if (s) -+ Stream_Release(s); -+ return result; -+} -+ -+static UINT rdpdr_server_smartcard_statusA(RdpdrServerContext* context, void* callbackData, -+ const Status_Call* call, UINT32* completionId) -+{ -+ return rdpdr_server_smartcard_status(context, callbackData, SCARD_IOCTL_STATUSA, call, -+ completionId); -+} -+ -+static UINT rdpdr_server_smartcard_statusW(RdpdrServerContext* context, void* callbackData, -+ const Status_Call* call, UINT32* completionId) -+{ -+ return rdpdr_server_smartcard_status(context, callbackData, SCARD_IOCTL_STATUSW, call, -+ completionId); -+} -+ -+/* Transmit */ -+static UINT rdpdr_server_smartcard_transmit_callback(RdpdrServerContext* context, wStream* s, -+ RDPDR_IRP* irp, UINT32 deviceId, -+ UINT32 completionId, UINT32 ioStatus) -+{ -+ WINPR_ASSERT(context); -+ WINPR_ASSERT(context->priv); -+ WINPR_ASSERT(s); -+ WINPR_ASSERT(irp); -+ -+ UINT result = CHANNEL_RC_OK; -+ RdpdrServerPrivate* priv = context->priv; -+ SMARTCARD_OPERATION op = WINPR_C_ARRAY_INIT; -+ -+ WLog_Print(priv->log, WLOG_DEBUG, -+ "SmartcardTransmitCallback: deviceId=%" PRIu32 ", completionId=%" PRIu32 -+ ", ioStatus=0x%" PRIx32, -+ deviceId, completionId, ioStatus); -+ -+ if (ioStatus != STATUS_SUCCESS) -+ { -+ if (context->OnSmartcardTransmitComplete) -+ context->OnSmartcardTransmitComplete(context, irp->CallbackData, ioStatus, -+ SCARD_F_INTERNAL_ERROR, nullptr); -+ goto out; -+ } -+ -+ result = smartcard_irp_device_control_decode_response(s, irp->IoControlCode, &op); -+ if (result != SCARD_S_SUCCESS) -+ { -+ result = ERROR_INVALID_DATA; -+ goto out; -+ } -+ -+ if (context->OnSmartcardTransmitComplete) -+ context->OnSmartcardTransmitComplete(context, irp->CallbackData, ioStatus, op.returnCode, -+ &op.ret.transmit); -+ -+out: -+ smartcard_operation_free(&op, FALSE); -+ rdpdr_server_irp_free(irp); -+ return result; -+} -+ -+static UINT rdpdr_server_smartcard_transmit(RdpdrServerContext* context, void* callbackData, -+ const Transmit_Call* call, UINT32* completionId) -+{ -+ WINPR_ASSERT(context); -+ WINPR_ASSERT(context->priv); -+ WINPR_ASSERT(call); -+ WINPR_ASSERT(completionId); -+ -+ UINT result = CHANNEL_RC_OK; -+ RdpdrServerPrivate* priv = context->priv; -+ RDPDR_IRP* irp = nullptr; -+ wStream* s = nullptr; -+ -+ result = prepare_smartcard_irp(context, SCARD_IOCTL_TRANSMIT, -+ rdpdr_server_smartcard_transmit_callback, callbackData, &irp); -+ if (result != CHANNEL_RC_OK) -+ return result; -+ -+ *completionId = irp->CompletionId; -+ -+ /* clang-format off */ -+ const SMARTCARD_OPERATION op = { -+ .ioControlCode = SCARD_IOCTL_TRANSMIT, -+ .call.transmit = *call -+ }; -+ /* clang-format on */ -+ -+ s = Stream_New(nullptr, 512 + call->cbSendLength); -+ if (!s) -+ { -+ WLog_Print(priv->log, WLOG_ERROR, "Stream_New failed!"); -+ result = CHANNEL_RC_NO_MEMORY; -+ goto out; -+ } -+ -+ result = smartcard_irp_device_control_encode_request(s, &op); -+ if (result != SCARD_S_SUCCESS) -+ { -+ result = ERROR_INTERNAL_ERROR; -+ goto out; -+ } -+ -+ result = rdpdr_server_send_device_control_request( -+ context, irp->DeviceId, irp->CompletionId, irp->IoControlCode, -+ SCARD_IOCTL_MAX_OUTPUT_BUFFER_LENGTH, Stream_Buffer(s), Stream_Length(s)); -+ -+out: -+ if (result != CHANNEL_RC_OK && irp) -+ rdpdr_server_discard_request(context, irp->CompletionId); -+ if (s) -+ Stream_Release(s); -+ return result; -+} -+ -+/* Control */ -+static UINT rdpdr_server_smartcard_control_callback(RdpdrServerContext* context, wStream* s, -+ RDPDR_IRP* irp, UINT32 deviceId, -+ UINT32 completionId, UINT32 ioStatus) -+{ -+ WINPR_ASSERT(context); -+ WINPR_ASSERT(context->priv); -+ WINPR_ASSERT(s); -+ WINPR_ASSERT(irp); -+ -+ UINT result = CHANNEL_RC_OK; -+ RdpdrServerPrivate* priv = context->priv; -+ SMARTCARD_OPERATION op = WINPR_C_ARRAY_INIT; -+ -+ WLog_Print(priv->log, WLOG_DEBUG, -+ "SmartcardControlCallback: deviceId=%" PRIu32 ", completionId=%" PRIu32 -+ ", ioStatus=0x%" PRIx32, -+ deviceId, completionId, ioStatus); -+ -+ if (ioStatus != STATUS_SUCCESS) -+ { -+ if (context->OnSmartcardControlComplete) -+ context->OnSmartcardControlComplete(context, irp->CallbackData, ioStatus, -+ SCARD_F_INTERNAL_ERROR, nullptr); -+ goto out; -+ } -+ -+ result = smartcard_irp_device_control_decode_response(s, irp->IoControlCode, &op); -+ if (result != SCARD_S_SUCCESS) -+ { -+ result = ERROR_INVALID_DATA; -+ goto out; -+ } -+ -+ if (context->OnSmartcardControlComplete) -+ context->OnSmartcardControlComplete(context, irp->CallbackData, ioStatus, op.returnCode, -+ &op.ret.control); -+ -+out: -+ smartcard_operation_free(&op, FALSE); -+ rdpdr_server_irp_free(irp); -+ return result; -+} -+ -+static UINT rdpdr_server_smartcard_control(RdpdrServerContext* context, void* callbackData, -+ const Control_Call* call, UINT32* completionId) -+{ -+ WINPR_ASSERT(context); -+ WINPR_ASSERT(context->priv); -+ WINPR_ASSERT(call); -+ WINPR_ASSERT(completionId); -+ -+ UINT result = CHANNEL_RC_OK; -+ RdpdrServerPrivate* priv = context->priv; -+ RDPDR_IRP* irp = nullptr; -+ wStream* s = nullptr; -+ -+ result = prepare_smartcard_irp(context, SCARD_IOCTL_CONTROL, -+ rdpdr_server_smartcard_control_callback, callbackData, &irp); -+ if (result != CHANNEL_RC_OK) -+ return result; -+ -+ *completionId = irp->CompletionId; -+ -+ /* clang-format off */ -+ const SMARTCARD_OPERATION op = { -+ .ioControlCode = SCARD_IOCTL_CONTROL, -+ .call.control = { -+ .handles.hContext = call->handles.hContext, -+ .handles.hCard = call->handles.hCard, -+ .dwControlCode = call->dwControlCode, -+ .cbInBufferSize = call->cbInBufferSize, -+ .pvInBuffer = call->pvInBuffer, -+ .fpvOutBufferIsNULL = call->fpvOutBufferIsNULL, -+ .cbOutBufferSize = call->cbOutBufferSize, -+ } -+ }; -+ /* clang-format on */ -+ -+ s = Stream_New(nullptr, 512 + call->cbOutBufferSize); -+ if (!s) -+ { -+ WLog_Print(priv->log, WLOG_ERROR, "Stream_New failed!"); -+ result = CHANNEL_RC_NO_MEMORY; -+ goto out; -+ } -+ -+ result = smartcard_irp_device_control_encode_request(s, &op); -+ if (result != SCARD_S_SUCCESS) -+ { -+ result = ERROR_INTERNAL_ERROR; -+ goto out; -+ } -+ -+ result = rdpdr_server_send_device_control_request( -+ context, irp->DeviceId, irp->CompletionId, irp->IoControlCode, -+ SCARD_IOCTL_MAX_OUTPUT_BUFFER_LENGTH, Stream_Buffer(s), Stream_Length(s)); -+ -+out: -+ if (result != CHANNEL_RC_OK && irp) -+ rdpdr_server_discard_request(context, irp->CompletionId); -+ if (s) -+ Stream_Release(s); -+ return result; -+} -+ -+/* getAttrib */ -+static UINT rdpdr_server_smartcard_get_attrib_callback(RdpdrServerContext* context, wStream* s, -+ RDPDR_IRP* irp, UINT32 deviceId, -+ UINT32 completionId, UINT32 ioStatus) -+{ -+ WINPR_ASSERT(context); -+ WINPR_ASSERT(context->priv); -+ WINPR_ASSERT(s); -+ WINPR_ASSERT(irp); -+ -+ UINT result = CHANNEL_RC_OK; -+ RdpdrServerPrivate* priv = context->priv; -+ SMARTCARD_OPERATION op = WINPR_C_ARRAY_INIT; -+ -+ WLog_Print(priv->log, WLOG_DEBUG, -+ "SmartcardGetAttribCallback: deviceId=%" PRIu32 ", completionId=%" PRIu32 -+ ", ioStatus=0x%" PRIx32, -+ deviceId, completionId, ioStatus); -+ -+ if (ioStatus != STATUS_SUCCESS) -+ { -+ if (context->OnSmartcardGetAttribComplete) -+ context->OnSmartcardGetAttribComplete(context, irp->CallbackData, ioStatus, -+ SCARD_F_INTERNAL_ERROR, nullptr); -+ goto out; -+ } -+ -+ result = smartcard_irp_device_control_decode_response(s, irp->IoControlCode, &op); -+ if (result != SCARD_S_SUCCESS) -+ { -+ result = ERROR_INVALID_DATA; -+ goto out; -+ } -+ -+ if (context->OnSmartcardGetAttribComplete) -+ context->OnSmartcardGetAttribComplete(context, irp->CallbackData, ioStatus, op.returnCode, -+ &op.ret.getAttrib); -+ -+out: -+ smartcard_operation_free(&op, FALSE); -+ rdpdr_server_irp_free(irp); -+ return result; -+} -+ -+UINT rdpdr_server_smartcard_get_attrib(RdpdrServerContext* context, void* callbackData, -+ const GetAttrib_Call* call, UINT32* completionId) -+{ -+ WINPR_ASSERT(context); -+ WINPR_ASSERT(context->priv); -+ WINPR_ASSERT(call); -+ WINPR_ASSERT(completionId); -+ -+ RdpdrServerPrivate* priv = context->priv; -+ -+ RDPDR_IRP* irp = nullptr; -+ UINT ret = -+ prepare_smartcard_irp(context, SCARD_IOCTL_GETATTRIB, -+ rdpdr_server_smartcard_get_attrib_callback, callbackData, &irp); -+ if (ret != CHANNEL_RC_OK) -+ return ret; -+ -+ *completionId = irp->CompletionId; -+ -+ /* clang-format off */ -+ const SMARTCARD_OPERATION op = { -+ .ioControlCode = SCARD_IOCTL_GETATTRIB, -+ .call.getAttrib = *call -+ }; -+ /* clang-format on */ -+ -+ wStream* s = Stream_New(nullptr, 64); -+ if (!s) -+ { -+ WLog_Print(priv->log, WLOG_ERROR, "Stream_New failed!"); -+ return CHANNEL_RC_NO_MEMORY; -+ } -+ -+ LONG status = smartcard_irp_device_control_encode_request(s, &op); -+ if (status != SCARD_S_SUCCESS) -+ { -+ Stream_Release(s); -+ return ERROR_INTERNAL_ERROR; -+ } -+ -+ const UINT error = rdpdr_server_send_device_control_request( -+ context, irp->DeviceId, irp->CompletionId, irp->IoControlCode, -+ SCARD_IOCTL_MAX_OUTPUT_BUFFER_LENGTH, Stream_Buffer(s), Stream_Length(s)); -+ -+ Stream_Release(s); -+ return error; -+} -+ -+/* SetAttrib */ -+static UINT rdpdr_server_smartcard_set_attrib_callback(RdpdrServerContext* context, wStream* s, -+ RDPDR_IRP* irp, UINT32 deviceId, -+ UINT32 completionId, UINT32 ioStatus) -+{ -+ WINPR_ASSERT(context); -+ WINPR_ASSERT(context->priv); -+ WINPR_ASSERT(s); -+ WINPR_ASSERT(irp); -+ -+ UINT result = CHANNEL_RC_OK; -+ RdpdrServerPrivate* priv = context->priv; -+ SMARTCARD_OPERATION op = WINPR_C_ARRAY_INIT; -+ -+ WLog_Print(priv->log, WLOG_DEBUG, -+ "SmartcardSetAttribCallback: deviceId=%" PRIu32 ", completionId=%" PRIu32 -+ ", ioStatus=0x%" PRIx32, -+ deviceId, completionId, ioStatus); -+ -+ if (ioStatus != STATUS_SUCCESS) -+ { -+ if (context->OnSmartcardSetAttribComplete) -+ context->OnSmartcardSetAttribComplete(context, irp->CallbackData, ioStatus, -+ SCARD_F_INTERNAL_ERROR); -+ goto out; -+ } -+ -+ result = smartcard_irp_device_control_decode_response(s, irp->IoControlCode, &op); -+ if (result != SCARD_S_SUCCESS) -+ { -+ result = ERROR_INVALID_DATA; -+ goto out; -+ } -+ -+ if (context->OnSmartcardSetAttribComplete) -+ context->OnSmartcardSetAttribComplete(context, irp->CallbackData, ioStatus, op.returnCode); -+ -+out: -+ smartcard_operation_free(&op, FALSE); -+ rdpdr_server_irp_free(irp); -+ return result; -+} -+ -+static UINT rdpdr_server_smartcard_set_attrib(RdpdrServerContext* context, void* callbackData, -+ const SetAttrib_Call* call, UINT32* completionId) -+{ -+ WINPR_ASSERT(context); -+ WINPR_ASSERT(context->priv); -+ WINPR_ASSERT(call); -+ WINPR_ASSERT(completionId); -+ -+ UINT result = CHANNEL_RC_OK; -+ RdpdrServerPrivate* priv = context->priv; -+ RDPDR_IRP* irp = nullptr; -+ wStream* s = nullptr; -+ -+ result = prepare_smartcard_irp(context, SCARD_IOCTL_SETATTRIB, -+ rdpdr_server_smartcard_set_attrib_callback, callbackData, &irp); -+ if (result != CHANNEL_RC_OK) -+ return result; -+ -+ *completionId = irp->CompletionId; -+ -+ /* clang-format off */ -+ const SMARTCARD_OPERATION op = { -+ .ioControlCode = SCARD_IOCTL_SETATTRIB, -+ .call.setAttrib = { -+ .handles.hContext = call->handles.hContext, -+ .handles.hCard = call->handles.hCard, -+ .dwAttrId = call->dwAttrId, -+ .cbAttrLen = call->cbAttrLen, -+ .pbAttr = call->pbAttr, -+ } -+ }; -+ /* clang-format on */ -+ -+ s = Stream_New(nullptr, 64 + call->cbAttrLen); -+ if (!s) -+ { -+ WLog_Print(priv->log, WLOG_ERROR, "Stream_New failed!"); -+ result = CHANNEL_RC_NO_MEMORY; -+ goto out; -+ } -+ -+ result = smartcard_irp_device_control_encode_request(s, &op); -+ if (result != SCARD_S_SUCCESS) -+ { -+ result = ERROR_INTERNAL_ERROR; -+ goto out; -+ } -+ -+ result = rdpdr_server_send_device_control_request( -+ context, irp->DeviceId, irp->CompletionId, irp->IoControlCode, -+ SCARD_IOCTL_MAX_OUTPUT_BUFFER_LENGTH, Stream_Buffer(s), Stream_Length(s)); -+ -+out: -+ if (result != CHANNEL_RC_OK && irp) -+ rdpdr_server_discard_request(context, irp->CompletionId); -+ if (s) -+ Stream_Release(s); -+ return result; -+} -+ -+RdpdrServerContext* rdpdr_server_context_new(HANDLE vcm) -+{ -+ RdpdrServerContext* context = (RdpdrServerContext*)calloc(1, sizeof(RdpdrServerContext)); -+ -+ if (!context) -+ goto fail; -+ -+ context->vcm = vcm; -+ context->Start = rdpdr_server_start; -+ context->Stop = rdpdr_server_stop; -+ context->DriveCreateDirectory = rdpdr_server_drive_create_directory; -+ context->DriveDeleteDirectory = rdpdr_server_drive_delete_directory; -+ context->DriveQueryDirectory = rdpdr_server_drive_query_directory; -+ context->DriveOpenFile = rdpdr_server_drive_open_file; -+ context->DriveReadFile = rdpdr_server_drive_read_file; -+ context->DriveWriteFile = rdpdr_server_drive_write_file; -+ context->DriveCloseFile = rdpdr_server_drive_close_file; -+ context->DriveDeleteFile = rdpdr_server_drive_delete_file; -+ context->DriveRenameFile = rdpdr_server_drive_rename_file; -+ context->SmartcardEstablishContext = rdpdr_server_smartcard_establish_context; -+ context->SmartcardReleaseContext = rdpdr_server_smartcard_release_context; -+ context->SmartcardIsValidContext = rdpdr_server_smartcard_is_valid_context; -+ context->SmartcardListReaderGroupsA = rdpdr_server_smartcard_list_reader_groupsA; -+ context->SmartcardListReaderGroupsW = rdpdr_server_smartcard_list_reader_groupsW; -+ context->SmartcardListReadersA = rdpdr_server_smartcard_list_readersA; -+ context->SmartcardListReadersW = rdpdr_server_smartcard_list_readersW; -+ context->SmartcardGetStatusChangeA = rdpdr_server_smartcard_get_status_changeA; -+ context->SmartcardGetStatusChangeW = rdpdr_server_smartcard_get_status_changeW; -+ context->SmartcardCancel = rdpdr_server_smartcard_cancel; -+ context->SmartcardConnectA = rdpdr_server_smartcard_connectA; -+ context->SmartcardConnectW = rdpdr_server_smartcard_connectW; -+ context->SmartcardReconnect = rdpdr_server_smartcard_reconnect; -+ context->SmartcardDisconnect = rdpdr_server_smartcard_disconnect; -+ context->SmartcardBeginTransaction = rdpdr_server_smartcard_begin_transaction; -+ context->SmartcardEndTransaction = rdpdr_server_smartcard_end_transaction; -+ context->SmartcardStatusA = rdpdr_server_smartcard_statusA; -+ context->SmartcardStatusW = rdpdr_server_smartcard_statusW; -+ context->SmartcardTransmit = rdpdr_server_smartcard_transmit; -+ context->SmartcardControl = rdpdr_server_smartcard_control; -+ context->SmartcardGetAttrib = rdpdr_server_smartcard_get_attrib; -+ context->SmartcardSetAttrib = rdpdr_server_smartcard_set_attrib; -+ context->priv = rdpdr_server_private_new(); -+ if (!context->priv) -+ goto fail; -+ -+ /* By default announce everything, the server application can deactivate that later on */ -+ context->supported = UINT16_MAX; -+ -+ return context; -+fail: -+ WINPR_PRAGMA_DIAG_PUSH -+ WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC -+ rdpdr_server_context_free(context); -+ WINPR_PRAGMA_DIAG_POP -+ return nullptr; -+} -+ -+void rdpdr_server_context_free(RdpdrServerContext* context) -+{ -+ if (!context) -+ return; -+ -+ rdpdr_server_private_free(context->priv); -+ free(context); -+} -+ -+void rdpdr_server_discard_request(RdpdrServerContext* context, UINT32 completionId) -+{ -+ WINPR_ASSERT(context); -+ -+ RdpdrServerPrivate* priv = context->priv; -+ const uintptr_t key = completionId + 1ull; -+ ListDictionary_Remove(priv->IrpList, (void*)key); - } -diff --git a/include/freerdp/server/rdpdr.h b/include/freerdp/server/rdpdr.h -index 411b33b6d6d7..a44a7e1cef87 100644 ---- a/include/freerdp/server/rdpdr.h -+++ b/include/freerdp/server/rdpdr.h -@@ -28,6 +28,7 @@ - #include - #include - #include -+#include - #include - - #ifdef __cplusplus -@@ -133,6 +134,117 @@ extern "C" - typedef UINT (*psRdpdrOnDeviceCreate)(RdpdrServerContext* context, const RdpdrDevice* device); - typedef UINT (*psRdpdrOnDeviceDelete)(RdpdrServerContext* context, UINT32 deviceId); - -+ typedef UINT (*psRdpdrSmartcardEstablishContext)(RdpdrServerContext* context, -+ void* callbackData, UINT32 dwScope, -+ UINT32* completionId); -+ typedef UINT (*psRdpdrSmartcardReleaseContext)(RdpdrServerContext* context, void* callbackData, -+ const REDIR_SCARDCONTEXT* hContext, -+ UINT32* completionId); -+ typedef UINT (*psRdpdrSmartcardIsValidContext)(RdpdrServerContext* context, void* callbackData, -+ const REDIR_SCARDCONTEXT* hContext, -+ UINT32* completionId); -+ typedef UINT (*psRdpdrSmartcardListReaderGroups)(RdpdrServerContext* context, -+ void* callbackData, -+ const ListReaderGroups_Call* call, -+ UINT32* completionId); -+ typedef UINT (*psRdpdrSmartcardListReaders)(RdpdrServerContext* context, void* callbackData, -+ const ListReaders_Call* call, UINT32* completionId); -+ typedef UINT (*psRdpdrSmartcardGetStatusChangeA)(RdpdrServerContext* context, -+ void* callbackData, -+ const GetStatusChangeA_Call* call, -+ UINT32* completionId); -+ typedef UINT (*psRdpdrSmartcardGetStatusChangeW)(RdpdrServerContext* context, -+ void* callbackData, -+ const GetStatusChangeW_Call* call, -+ UINT32* completionId); -+ typedef UINT (*psRdpdrSmartcardCancel)(RdpdrServerContext* context, void* callbackData, -+ const REDIR_SCARDCONTEXT* hContext, -+ UINT32* completionId); -+ typedef UINT (*psRdpdrSmartcardConnectA)(RdpdrServerContext* context, void* callbackData, -+ const ConnectA_Call* call, UINT32* completionId); -+ typedef UINT (*psRdpdrSmartcardConnectW)(RdpdrServerContext* context, void* callbackData, -+ const ConnectW_Call* call, UINT32* completionId); -+ typedef UINT (*psRdpdrSmartcardReconnect)(RdpdrServerContext* context, void* callbackData, -+ const Reconnect_Call* call, UINT32* completionId); -+ typedef UINT (*psRdpdrSmartcardDisconnect)(RdpdrServerContext* context, void* callbackData, -+ const HCardAndDisposition_Call* call, -+ UINT32* completionId); -+ typedef UINT (*psRdpdrSmartcardBeginTransaction)(RdpdrServerContext* context, -+ void* callbackData, -+ const HCardAndDisposition_Call* call, -+ UINT32* completionId); -+ typedef UINT (*psRdpdrSmartcardEndTransaction)(RdpdrServerContext* context, void* callbackData, -+ const HCardAndDisposition_Call* call, -+ UINT32* completionId); -+ typedef UINT (*psRdpdrSmartcardStatus)(RdpdrServerContext* context, void* callbackData, -+ const Status_Call* call, UINT32* completionId); -+ typedef UINT (*psRdpdrSmartcardTransmit)(RdpdrServerContext* context, void* callbackData, -+ const Transmit_Call* call, UINT32* completionId); -+ typedef UINT (*psRdpdrSmartcardControl)(RdpdrServerContext* context, void* callbackData, -+ const Control_Call* call, UINT32* completionId); -+ typedef UINT (*psRdpdrSmartcardGetAttrib)(RdpdrServerContext* context, void* callbackData, -+ const GetAttrib_Call* call, UINT32* completionId); -+ typedef UINT (*psRdpdrSmartcardSetAttrib)(RdpdrServerContext* context, void* callbackData, -+ const SetAttrib_Call* call, UINT32* completionId); -+ -+ typedef void (*psRdpdrOnSmartcardEstablishContextComplete)(RdpdrServerContext* context, -+ void* callbackData, UINT32 ioStatus, -+ LONG returnCode, -+ const EstablishContext_Return* ret); -+ typedef void (*psRdpdrOnSmartcardReleaseContextComplete)(RdpdrServerContext* context, -+ void* callbackData, UINT32 ioStatus, -+ LONG returnCode); -+ typedef void (*psRdpdrOnSmartcardIsValidContextComplete)(RdpdrServerContext* context, -+ void* callbackData, UINT32 ioStatus, -+ LONG returnCode); -+ typedef void (*psRdpdrOnSmartcardListReaderGroupsComplete)(RdpdrServerContext* context, -+ void* callbackData, UINT32 ioStatus, -+ LONG returnCode, -+ const ListReaderGroups_Return* ret); -+ typedef void (*psRdpdrOnSmartcardListReadersComplete)(RdpdrServerContext* context, -+ void* callbackData, UINT32 ioStatus, -+ LONG returnCode, -+ const ListReaders_Return* ret); -+ typedef void (*psRdpdrOnSmartcardGetStatusChangeComplete)(RdpdrServerContext* context, -+ void* callbackData, UINT32 ioStatus, -+ LONG returnCode, -+ const GetStatusChange_Return* ret); -+ typedef void (*psRdpdrOnSmartcardCancelComplete)(RdpdrServerContext* context, -+ void* callbackData, UINT32 ioStatus, -+ LONG returnCode); -+ typedef void (*psRdpdrOnSmartcardConnectComplete)(RdpdrServerContext* context, -+ void* callbackData, UINT32 ioStatus, -+ LONG returnCode, const Connect_Return* ret); -+ typedef void (*psRdpdrOnSmartcardReconnectComplete)(RdpdrServerContext* context, -+ void* callbackData, UINT32 ioStatus, -+ LONG returnCode, -+ const Reconnect_Return* ret); -+ typedef void (*psRdpdrOnSmartcardDisconnectComplete)(RdpdrServerContext* context, -+ void* callbackData, UINT32 ioStatus, -+ LONG returnCode); -+ typedef void (*psRdpdrOnSmartcardBeginTransactionComplete)(RdpdrServerContext* context, -+ void* callbackData, UINT32 ioStatus, -+ LONG returnCode); -+ typedef void (*psRdpdrOnSmartcardEndTransactionComplete)(RdpdrServerContext* context, -+ void* callbackData, UINT32 ioStatus, -+ LONG returnCode); -+ typedef void (*psRdpdrOnSmartcardStatusComplete)(RdpdrServerContext* context, -+ void* callbackData, UINT32 ioStatus, -+ LONG returnCode, const Status_Return* ret); -+ typedef void (*psRdpdrOnSmartcardTransmitComplete)(RdpdrServerContext* context, -+ void* callbackData, UINT32 ioStatus, -+ LONG returnCode, const Transmit_Return* ret); -+ typedef void (*psRdpdrOnSmartcardControlComplete)(RdpdrServerContext* context, -+ void* callbackData, UINT32 ioStatus, -+ LONG returnCode, const Control_Return* ret); -+ typedef void (*psRdpdrOnSmartcardGetAttribComplete)(RdpdrServerContext* context, -+ void* callbackData, UINT32 ioStatus, -+ LONG returnCode, -+ const GetAttrib_Return* ret); -+ typedef void (*psRdpdrOnSmartcardSetAttribComplete)(RdpdrServerContext* context, -+ void* callbackData, UINT32 ioStatus, -+ LONG returnCode); -+ - struct s_rdpdr_server_context - { - HANDLE vcm; -@@ -233,6 +345,107 @@ extern "C" - RDPDR_DTYP_SMARTCARD after \b ReceiveDeviceRemove */ - - rdpContext* rdpcontext; -+ -+ /*** New Smartcard APIs called by the server. ***/ -+ WINPR_ATTR_NODISCARD psRdpdrSmartcardEstablishContext -+ SmartcardEstablishContext; /**< Send SCardEstablishContext to the client. */ -+ WINPR_ATTR_NODISCARD psRdpdrSmartcardReleaseContext -+ SmartcardReleaseContext; /**< Send SCardReleaseContext to the client. */ -+ WINPR_ATTR_NODISCARD psRdpdrSmartcardIsValidContext -+ SmartcardIsValidContext; /**< Send SCardIsValidContext to the client. */ -+ WINPR_ATTR_NODISCARD psRdpdrSmartcardListReaderGroups -+ SmartcardListReaderGroupsA; /**< Send SCardListReaderGroupsA to the client. */ -+ WINPR_ATTR_NODISCARD psRdpdrSmartcardListReaderGroups -+ SmartcardListReaderGroupsW; /**< Send SCardListReaderGroupsW to the client. */ -+ WINPR_ATTR_NODISCARD psRdpdrSmartcardListReaders -+ SmartcardListReadersA; /**< Send SCardListReadersA to the client. */ -+ WINPR_ATTR_NODISCARD psRdpdrSmartcardListReaders -+ SmartcardListReadersW; /**< Send SCardListReadersW to the client. */ -+ WINPR_ATTR_NODISCARD psRdpdrSmartcardGetStatusChangeA -+ SmartcardGetStatusChangeA; /**< Send SCardGetStatusChangeA to the client. */ -+ WINPR_ATTR_NODISCARD psRdpdrSmartcardGetStatusChangeW -+ SmartcardGetStatusChangeW; /**< Send SCardGetStatusChangeW to the client. */ -+ WINPR_ATTR_NODISCARD psRdpdrSmartcardCancel -+ SmartcardCancel; /**< Send SCardCancel to the client. */ -+ WINPR_ATTR_NODISCARD psRdpdrSmartcardConnectA -+ SmartcardConnectA; /**< Send SCardConnectA to the client. */ -+ WINPR_ATTR_NODISCARD psRdpdrSmartcardConnectW -+ SmartcardConnectW; /**< Send SCardConnectW to the client. */ -+ WINPR_ATTR_NODISCARD psRdpdrSmartcardReconnect -+ SmartcardReconnect; /**< Send SCardReconnect to the client. */ -+ WINPR_ATTR_NODISCARD psRdpdrSmartcardDisconnect -+ SmartcardDisconnect; /**< Send SCardDisconnect to the client. */ -+ WINPR_ATTR_NODISCARD psRdpdrSmartcardBeginTransaction -+ SmartcardBeginTransaction; /**< Send SCardBeginTransaction to the client. */ -+ WINPR_ATTR_NODISCARD psRdpdrSmartcardEndTransaction -+ SmartcardEndTransaction; /**< Send SCardEndTransaction to the client. */ -+ WINPR_ATTR_NODISCARD psRdpdrSmartcardStatus -+ SmartcardStatusA; /**< Send SCardStatusA to the client. */ -+ WINPR_ATTR_NODISCARD psRdpdrSmartcardStatus -+ SmartcardStatusW; /**< Send SCardStatusW to the client. */ -+ WINPR_ATTR_NODISCARD psRdpdrSmartcardTransmit -+ SmartcardTransmit; /**< Send SCardTransmit to the client. */ -+ WINPR_ATTR_NODISCARD psRdpdrSmartcardControl -+ SmartcardControl; /**< Send SCardControl to the client. */ -+ WINPR_ATTR_NODISCARD psRdpdrSmartcardGetAttrib -+ SmartcardGetAttrib; /**< Send SCardGetAttrib to the client. */ -+ WINPR_ATTR_NODISCARD psRdpdrSmartcardSetAttrib -+ SmartcardSetAttrib; /**< Send SCardSetAttrib to the client. */ -+ -+ /*** New Smartcard callbacks registered by the server. ***/ -+ /* clang-format off */ -+ psRdpdrOnSmartcardEstablishContextComplete -+ OnSmartcardEstablishContextComplete; /**< Completion callback for -+ SmartcardEstablishContext. */ -+ psRdpdrOnSmartcardReleaseContextComplete -+ OnSmartcardReleaseContextComplete; /**< Completion callback for -+ SmartcardReleaseContext. */ -+ psRdpdrOnSmartcardIsValidContextComplete -+ OnSmartcardIsValidContextComplete; /**< Completion callback for -+ SmartcardIsValidContext. */ -+ psRdpdrOnSmartcardListReaderGroupsComplete -+ OnSmartcardListReaderGroupsComplete; /**< Completion callback for -+ SmartcardListReaderGroups. */ -+ psRdpdrOnSmartcardListReadersComplete -+ OnSmartcardListReadersComplete; /**< Completion callback for -+ SmartcardListReaders. */ -+ psRdpdrOnSmartcardGetStatusChangeComplete -+ OnSmartcardGetStatusChangeComplete; /**< Completion callback for -+ SmartcardGetStatusChange. */ -+ psRdpdrOnSmartcardCancelComplete -+ OnSmartcardCancelComplete; /**< Completion callback for -+ SmartcardCancel. */ -+ psRdpdrOnSmartcardConnectComplete -+ OnSmartcardConnectComplete; /**< Completion callback for -+ SmartcardConnect. */ -+ psRdpdrOnSmartcardReconnectComplete -+ OnSmartcardReconnectComplete; /**< Completion callback for -+ SmartcardReconnect. */ -+ psRdpdrOnSmartcardDisconnectComplete -+ OnSmartcardDisconnectComplete; /**< Completion callback for -+ SmartcardDisconnect. */ -+ psRdpdrOnSmartcardBeginTransactionComplete -+ OnSmartcardBeginTransactionComplete; /**< Completion callback for -+ SmartcardBeginTransaction. */ -+ psRdpdrOnSmartcardEndTransactionComplete -+ OnSmartcardEndTransactionComplete; /**< Completion callback for -+ SmartcardEndTransaction. */ -+ psRdpdrOnSmartcardStatusComplete -+ OnSmartcardStatusComplete; /**< Completion callback for -+ SmartcardStatus. */ -+ psRdpdrOnSmartcardTransmitComplete -+ OnSmartcardTransmitComplete; /**< Completion callback for -+ SmartcardTransmit. */ -+ psRdpdrOnSmartcardControlComplete -+ OnSmartcardControlComplete; /**< Completion callback for -+ SmartcardControl. */ -+ psRdpdrOnSmartcardGetAttribComplete -+ OnSmartcardGetAttribComplete; /**< Completion callback for -+ SmartcardGetAttrib. */ -+ psRdpdrOnSmartcardSetAttribComplete -+ OnSmartcardSetAttribComplete; /**< Completion callback for -+ SmartcardSetAttrib. */ -+ /* clang-format on */ - }; - - FREERDP_API void rdpdr_server_context_free(RdpdrServerContext* context); -@@ -241,6 +454,13 @@ extern "C" - WINPR_ATTR_NODISCARD - FREERDP_API RdpdrServerContext* rdpdr_server_context_new(HANDLE vcm); - -+ /** -+ * @brief Remove and free a pending IRP request from the context. -+ * @param context The RDPDR server context. -+ * @param completionId The completion ID of the IRP to discard. -+ * @since version 3.28 -+ */ -+ FREERDP_API void rdpdr_server_discard_request(RdpdrServerContext* context, UINT32 completionId); - #ifdef __cplusplus - } - #endif -diff --git a/libfreerdp/utils/test/CMakeLists.txt b/libfreerdp/utils/test/CMakeLists.txt -index 0c2bf8491d7f..eedd7b2599f6 100644 ---- a/libfreerdp/utils/test/CMakeLists.txt -+++ b/libfreerdp/utils/test/CMakeLists.txt -@@ -5,7 +5,9 @@ disable_warnings_for_directory(${CMAKE_CURRENT_BINARY_DIR}) - - set(${MODULE_PREFIX}_DRIVER ${MODULE_NAME}.c) - --set(${MODULE_PREFIX}_TESTS TestRingBuffer.c TestPodArrays.c TestEncodedTypes.c TestSmartcardPack.c) -+set(${MODULE_PREFIX}_TESTS TestRingBuffer.c TestPodArrays.c TestEncodedTypes.c TestSmartcardPack.c -+ TestSmartcardOperations.c -+) - - create_test_sourcelist(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_DRIVER} ${${MODULE_PREFIX}_TESTS}) - -diff --git a/libfreerdp/utils/test/TestSmartcardOperations.c b/libfreerdp/utils/test/TestSmartcardOperations.c -new file mode 100644 -index 000000000000..4c885b13359c ---- /dev/null -+++ b/libfreerdp/utils/test/TestSmartcardOperations.c -@@ -0,0 +1,1445 @@ -+/** -+ * FreeRDP: A Remote Desktop Protocol Implementation -+ * -+ * Copyright 2026 Joan Torres Lopez -+ * -+ * Licensed under the Apache License, Version 2.0 (the "License"); -+ * you may not use this file except in compliance with the License. -+ * You may obtain a copy of the License at -+ * -+ * http://www.apache.org/licenses/LICENSE-2.0 -+ * -+ * Unless required by applicable law or agreed to in writing, software -+ * distributed under the License is distributed on an "AS IS" BASIS, -+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -+ * See the License for the specific language governing permissions and -+ * limitations under the License. -+ */ -+ -+#include -+ -+#include -+#include -+#include -+ -+#include -+#include -+#include -+#include -+#include -+ -+static inline void fill_redir_context(REDIR_SCARDCONTEXT* ctx, SCARDCONTEXT val) -+{ -+ smartcard_scard_context_native_to_redir(ctx, val); -+} -+ -+static inline void fill_redir_handle(REDIR_SCARDHANDLE* handle, SCARDHANDLE val) -+{ -+ smartcard_scard_handle_native_to_redir(handle, val); -+} -+ -+static wStream* build_device_control_request(UINT32 ioControlCode, const void* inputBuffer, -+ size_t inputBufferLength) -+{ -+ const char* name = scard_get_ioctl_string(ioControlCode, TRUE); -+ const size_t totalLength = RDPDR_DEVICE_IO_CONTROL_REQ_HDR_LENGTH + inputBufferLength; -+ -+ wStream* s = Stream_New(NULL, totalLength); -+ if (!s) -+ { -+ (void)fprintf(stderr, "build_device_control_request(%s): Stream_New(%" PRIuz ") failed\n", -+ name, totalLength); -+ return NULL; -+ } -+ -+ UINT32 inputLength = WINPR_ASSERTING_INT_CAST(UINT32, inputBufferLength); -+ Stream_Write_UINT32(s, 2048); /* OutputBufferLength */ -+ Stream_Write_UINT32(s, inputLength); /* InputBufferLength */ -+ Stream_Write_UINT32(s, ioControlCode); /* IoControlCode */ -+ Stream_Zero(s, 20); /* Padding */ -+ -+ if (inputBufferLength > 0) -+ Stream_Write(s, inputBuffer, inputBufferLength); -+ -+ Stream_SealLength(s); -+ if (!Stream_SetPosition(s, 0)) -+ { -+ (void)fprintf(stderr, "build_device_control_request(%s): Stream_SetPosition failed\n", -+ name); -+ Stream_Release(s); -+ return NULL; -+ } -+ -+ return s; -+} -+ -+static BOOL test_request_roundtrip(const SMARTCARD_OPERATION* opIn, SMARTCARD_OPERATION* opOut) -+{ -+ const UINT32 ioControlCode = opIn->ioControlCode; -+ const char* name = scard_get_ioctl_string(ioControlCode, TRUE); -+ -+ wStream* sEnc = Stream_New(NULL, 4096); -+ if (!sEnc) -+ { -+ (void)fprintf(stderr, "%s: Stream_New for encode failed\n", name); -+ return FALSE; -+ } -+ -+ LONG status = smartcard_irp_device_control_encode_request(sEnc, opIn); -+ if (status != SCARD_S_SUCCESS) -+ { -+ (void)fprintf(stderr, "%s: encode_request failed with 0x%08" PRIX32 "\n", name, -+ (UINT32)status); -+ Stream_Release(sEnc); -+ return FALSE; -+ } -+ -+ wStream* sDec = -+ build_device_control_request(ioControlCode, Stream_Buffer(sEnc), Stream_Length(sEnc)); -+ Stream_Release(sEnc); -+ if (!sDec) -+ return FALSE; -+ -+ *opOut = (SMARTCARD_OPERATION)WINPR_C_ARRAY_INIT; -+ status = smartcard_irp_device_control_decode_request(sDec, 1, 0, opOut); -+ Stream_Release(sDec); -+ if (status != SCARD_S_SUCCESS) -+ { -+ (void)fprintf(stderr, "%s: decode_request failed with 0x%08" PRIX32 "\n", name, -+ (UINT32)status); -+ return FALSE; -+ } -+ -+ if (opOut->ioControlCode != ioControlCode) -+ { -+ (void)fprintf(stderr, "%s: ioControlCode mismatch: 0x%08" PRIX32 " != 0x%08" PRIX32 "\n", -+ name, opOut->ioControlCode, ioControlCode); -+ smartcard_operation_free(opOut, FALSE); -+ return FALSE; -+ } -+ -+ return TRUE; -+} -+ -+static inline BOOL check_field(const char* name, const char* field, UINT32 a, UINT32 b) -+{ -+ if (a != b) -+ { -+ (void)fprintf(stderr, "%s: %s mismatch: 0x%" PRIX32 " != 0x%" PRIX32 "\n", name, field, a, -+ b); -+ return FALSE; -+ } -+ return TRUE; -+} -+ -+static inline BOOL check_bytes(const char* name, const char* field, const void* a, const void* b, -+ size_t len) -+{ -+ if (!a || !b || memcmp(a, b, len) != 0) -+ { -+ (void)fprintf(stderr, "%s: %s mismatch (%" PRIuz " bytes)\n", name, field, len); -+ return FALSE; -+ } -+ return TRUE; -+} -+ -+static inline BOOL check_redir_context(const char* name, const REDIR_SCARDCONTEXT* a, -+ const REDIR_SCARDCONTEXT* b) -+{ -+ return check_field(name, "hContext.cbContext", a->cbContext, b->cbContext) && -+ check_bytes(name, "hContext.pbContext", a->pbContext, b->pbContext, a->cbContext); -+} -+ -+static inline BOOL check_redir_handle(const char* name, const REDIR_SCARDHANDLE* a, -+ const REDIR_SCARDHANDLE* b) -+{ -+ return check_field(name, "hCard.cbHandle", a->cbHandle, b->cbHandle) && -+ check_bytes(name, "hCard.pbHandle", a->pbHandle, b->pbHandle, a->cbHandle); -+} -+ -+static BOOL test_establish_context_encode_decode_request(void) -+{ -+ BOOL success = FALSE; -+ SMARTCARD_OPERATION opOut = WINPR_C_ARRAY_INIT; -+ SMARTCARD_OPERATION opIn = WINPR_C_ARRAY_INIT; -+ opIn.ioControlCode = SCARD_IOCTL_ESTABLISHCONTEXT; -+ opIn.call.establishContext.dwScope = SCARD_SCOPE_SYSTEM; -+ -+ if (!test_request_roundtrip(&opIn, &opOut)) -+ goto out; -+ if (!check_field("EstablishContext", "dwScope", opIn.call.establishContext.dwScope, -+ opOut.call.establishContext.dwScope)) -+ goto out; -+ -+ success = TRUE; -+out: -+ smartcard_operation_free(&opIn, FALSE); -+ smartcard_operation_free(&opOut, FALSE); -+ return success; -+} -+ -+static BOOL test_release_context_encode_decode_request(void) -+{ -+ BOOL success = FALSE; -+ SMARTCARD_OPERATION opOut = WINPR_C_ARRAY_INIT; -+ SMARTCARD_OPERATION opIn = WINPR_C_ARRAY_INIT; -+ opIn.ioControlCode = SCARD_IOCTL_RELEASECONTEXT; -+ fill_redir_context(&opIn.call.context.handles.hContext, 0x1234); -+ -+ if (!test_request_roundtrip(&opIn, &opOut)) -+ goto out; -+ if (!check_redir_context("ReleaseContext", &opIn.call.context.handles.hContext, -+ &opOut.call.context.handles.hContext)) -+ goto out; -+ -+ success = TRUE; -+out: -+ smartcard_operation_free(&opIn, FALSE); -+ smartcard_operation_free(&opOut, FALSE); -+ return success; -+} -+ -+static BOOL test_is_valid_context_encode_decode_request(void) -+{ -+ BOOL success = FALSE; -+ SMARTCARD_OPERATION opOut = WINPR_C_ARRAY_INIT; -+ SMARTCARD_OPERATION opIn = WINPR_C_ARRAY_INIT; -+ opIn.ioControlCode = SCARD_IOCTL_ISVALIDCONTEXT; -+ fill_redir_context(&opIn.call.context.handles.hContext, 0x5678); -+ -+ if (!test_request_roundtrip(&opIn, &opOut)) -+ goto out; -+ if (!check_redir_context("IsValidContext", &opIn.call.context.handles.hContext, -+ &opOut.call.context.handles.hContext)) -+ goto out; -+ -+ success = TRUE; -+out: -+ smartcard_operation_free(&opIn, FALSE); -+ smartcard_operation_free(&opOut, FALSE); -+ return success; -+} -+ -+static BOOL test_list_reader_groups_encode_decode_request_impl(UINT32 ioControlCode) -+{ -+ BOOL success = FALSE; -+ const char* n = scard_get_ioctl_string(ioControlCode, TRUE); -+ SMARTCARD_OPERATION opOut = WINPR_C_ARRAY_INIT; -+ SMARTCARD_OPERATION opIn = WINPR_C_ARRAY_INIT; -+ opIn.ioControlCode = ioControlCode; -+ fill_redir_context(&opIn.call.listReaderGroups.handles.hContext, 0x1234); -+ opIn.call.listReaderGroups.fmszGroupsIsNULL = 0; -+ opIn.call.listReaderGroups.cchGroups = SCARD_AUTOALLOCATE; -+ -+ if (!test_request_roundtrip(&opIn, &opOut)) -+ goto out; -+ if (!check_redir_context(n, &opIn.call.listReaderGroups.handles.hContext, -+ &opOut.call.listReaderGroups.handles.hContext)) -+ goto out; -+ if (!check_field(n, "fmszGroupsIsNULL", opIn.call.listReaderGroups.fmszGroupsIsNULL, -+ opOut.call.listReaderGroups.fmszGroupsIsNULL)) -+ goto out; -+ if (!check_field(n, "cchGroups", opIn.call.listReaderGroups.cchGroups, -+ opOut.call.listReaderGroups.cchGroups)) -+ goto out; -+ -+ success = TRUE; -+out: -+ smartcard_operation_free(&opIn, FALSE); -+ smartcard_operation_free(&opOut, FALSE); -+ return success; -+} -+ -+static BOOL test_list_reader_groups_a_encode_decode_request(void) -+{ -+ return test_list_reader_groups_encode_decode_request_impl(SCARD_IOCTL_LISTREADERGROUPSA); -+} -+ -+static BOOL test_list_reader_groups_w_encode_decode_request(void) -+{ -+ return test_list_reader_groups_encode_decode_request_impl(SCARD_IOCTL_LISTREADERGROUPSW); -+} -+ -+static BOOL test_list_readers_encode_decode_request_impl(UINT32 ioControlCode) -+{ -+ BOOL success = FALSE; -+ const char* n = scard_get_ioctl_string(ioControlCode, TRUE); -+ SMARTCARD_OPERATION opOut = WINPR_C_ARRAY_INIT; -+ SMARTCARD_OPERATION opIn = WINPR_C_ARRAY_INIT; -+ opIn.ioControlCode = ioControlCode; -+ fill_redir_context(&opIn.call.listReaders.handles.hContext, 0x1234); -+ opIn.call.listReaders.fmszReadersIsNULL = 0; -+ opIn.call.listReaders.cchReaders = SCARD_AUTOALLOCATE; -+ -+ if (!test_request_roundtrip(&opIn, &opOut)) -+ goto out; -+ if (!check_redir_context(n, &opIn.call.listReaders.handles.hContext, -+ &opOut.call.listReaders.handles.hContext)) -+ goto out; -+ if (!check_field(n, "cchReaders", opIn.call.listReaders.cchReaders, -+ opOut.call.listReaders.cchReaders)) -+ goto out; -+ -+ success = TRUE; -+out: -+ smartcard_operation_free(&opIn, FALSE); -+ smartcard_operation_free(&opOut, FALSE); -+ return success; -+} -+ -+static BOOL test_list_readers_a_encode_decode_request(void) -+{ -+ return test_list_readers_encode_decode_request_impl(SCARD_IOCTL_LISTREADERSA); -+} -+ -+static BOOL test_list_readers_w_encode_decode_request(void) -+{ -+ return test_list_readers_encode_decode_request_impl(SCARD_IOCTL_LISTREADERSW); -+} -+ -+static BOOL test_cancel_encode_decode_request(void) -+{ -+ BOOL success = FALSE; -+ SMARTCARD_OPERATION opOut = WINPR_C_ARRAY_INIT; -+ SMARTCARD_OPERATION opIn = WINPR_C_ARRAY_INIT; -+ opIn.ioControlCode = SCARD_IOCTL_CANCEL; -+ fill_redir_context(&opIn.call.context.handles.hContext, 0xABCD); -+ -+ if (!test_request_roundtrip(&opIn, &opOut)) -+ goto out; -+ if (!check_redir_context("Cancel", &opIn.call.context.handles.hContext, -+ &opOut.call.context.handles.hContext)) -+ goto out; -+ -+ success = TRUE; -+out: -+ smartcard_operation_free(&opIn, FALSE); -+ smartcard_operation_free(&opOut, FALSE); -+ return success; -+} -+ -+static BOOL test_connect_a_encode_decode_request(void) -+{ -+ BOOL success = FALSE; -+ SMARTCARD_OPERATION opOut = WINPR_C_ARRAY_INIT; -+ SMARTCARD_OPERATION opIn = WINPR_C_ARRAY_INIT; -+ opIn.ioControlCode = SCARD_IOCTL_CONNECTA; -+ fill_redir_context(&opIn.call.connectA.Common.handles.hContext, 0x1234); -+ opIn.call.connectA.Common.dwShareMode = SCARD_SHARE_SHARED; -+ opIn.call.connectA.Common.dwPreferredProtocols = SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1; -+ opIn.call.connectA.szReader = _strdup("TestReader"); -+ -+ if (!test_request_roundtrip(&opIn, &opOut)) -+ goto out; -+ if (!check_redir_context("ConnectA", &opIn.call.connectA.Common.handles.hContext, -+ &opOut.call.connectA.Common.handles.hContext)) -+ goto out; -+ if (!check_field("ConnectA", "dwShareMode", opIn.call.connectA.Common.dwShareMode, -+ opOut.call.connectA.Common.dwShareMode)) -+ goto out; -+ if (!check_field("ConnectA", "dwPreferredProtocols", -+ opIn.call.connectA.Common.dwPreferredProtocols, -+ opOut.call.connectA.Common.dwPreferredProtocols)) -+ goto out; -+ if (!check_bytes("ConnectA", "szReader", opIn.call.connectA.szReader, -+ opOut.call.connectA.szReader, strlen(opIn.call.connectA.szReader) + 1)) -+ goto out; -+ -+ success = TRUE; -+out: -+ smartcard_operation_free(&opIn, FALSE); -+ smartcard_operation_free(&opOut, FALSE); -+ return success; -+} -+ -+static BOOL test_connect_w_encode_decode_request(void) -+{ -+ BOOL success = FALSE; -+ SMARTCARD_OPERATION opOut = WINPR_C_ARRAY_INIT; -+ SMARTCARD_OPERATION opIn = WINPR_C_ARRAY_INIT; -+ opIn.ioControlCode = SCARD_IOCTL_CONNECTW; -+ fill_redir_context(&opIn.call.connectW.Common.handles.hContext, 0x1234); -+ opIn.call.connectW.Common.dwShareMode = SCARD_SHARE_SHARED; -+ opIn.call.connectW.Common.dwPreferredProtocols = SCARD_PROTOCOL_T0; -+ opIn.call.connectW.szReader = ConvertUtf8ToWCharAlloc("TestReader", NULL); -+ -+ if (!test_request_roundtrip(&opIn, &opOut)) -+ goto out; -+ if (!check_redir_context("ConnectW", &opIn.call.connectW.Common.handles.hContext, -+ &opOut.call.connectW.Common.handles.hContext)) -+ goto out; -+ if (!check_field("ConnectW", "dwShareMode", opIn.call.connectW.Common.dwShareMode, -+ opOut.call.connectW.Common.dwShareMode)) -+ goto out; -+ if (!check_bytes("ConnectW", "szReader", opIn.call.connectW.szReader, -+ opOut.call.connectW.szReader, -+ (_wcslen(opIn.call.connectW.szReader) + 1) * sizeof(WCHAR))) -+ goto out; -+ -+ success = TRUE; -+out: -+ smartcard_operation_free(&opIn, FALSE); -+ smartcard_operation_free(&opOut, FALSE); -+ return success; -+} -+ -+static BOOL test_reconnect_encode_decode_request(void) -+{ -+ BOOL success = FALSE; -+ const char* n = "Reconnect"; -+ SMARTCARD_OPERATION opOut = WINPR_C_ARRAY_INIT; -+ SMARTCARD_OPERATION opIn = WINPR_C_ARRAY_INIT; -+ opIn.ioControlCode = SCARD_IOCTL_RECONNECT; -+ fill_redir_context(&opIn.call.reconnect.handles.hContext, 0x1234); -+ fill_redir_handle(&opIn.call.reconnect.handles.hCard, 0x5678); -+ opIn.call.reconnect.dwShareMode = SCARD_SHARE_EXCLUSIVE; -+ opIn.call.reconnect.dwPreferredProtocols = SCARD_PROTOCOL_T1; -+ opIn.call.reconnect.dwInitialization = SCARD_LEAVE_CARD; -+ -+ if (!test_request_roundtrip(&opIn, &opOut)) -+ goto out; -+ if (!check_redir_context(n, &opIn.call.reconnect.handles.hContext, -+ &opOut.call.reconnect.handles.hContext)) -+ goto out; -+ if (!check_redir_handle(n, &opIn.call.reconnect.handles.hCard, -+ &opOut.call.reconnect.handles.hCard)) -+ goto out; -+ if (!check_field(n, "dwShareMode", opIn.call.reconnect.dwShareMode, -+ opOut.call.reconnect.dwShareMode)) -+ goto out; -+ if (!check_field(n, "dwPreferredProtocols", opIn.call.reconnect.dwPreferredProtocols, -+ opOut.call.reconnect.dwPreferredProtocols)) -+ goto out; -+ if (!check_field(n, "dwInitialization", opIn.call.reconnect.dwInitialization, -+ opOut.call.reconnect.dwInitialization)) -+ goto out; -+ -+ success = TRUE; -+out: -+ smartcard_operation_free(&opIn, FALSE); -+ smartcard_operation_free(&opOut, FALSE); -+ return success; -+} -+ -+static BOOL test_hcard_and_disposition_encode_decode_request_impl(UINT32 ioControlCode, -+ DWORD dwDisposition) -+{ -+ BOOL success = FALSE; -+ const char* n = scard_get_ioctl_string(ioControlCode, TRUE); -+ SMARTCARD_OPERATION opOut = WINPR_C_ARRAY_INIT; -+ SMARTCARD_OPERATION opIn = WINPR_C_ARRAY_INIT; -+ opIn.ioControlCode = ioControlCode; -+ fill_redir_context(&opIn.call.hCardAndDisposition.handles.hContext, 0x1234); -+ fill_redir_handle(&opIn.call.hCardAndDisposition.handles.hCard, 0x5678); -+ opIn.call.hCardAndDisposition.dwDisposition = dwDisposition; -+ -+ if (!test_request_roundtrip(&opIn, &opOut)) -+ goto out; -+ if (!check_redir_context(n, &opIn.call.hCardAndDisposition.handles.hContext, -+ &opOut.call.hCardAndDisposition.handles.hContext)) -+ goto out; -+ if (!check_redir_handle(n, &opIn.call.hCardAndDisposition.handles.hCard, -+ &opOut.call.hCardAndDisposition.handles.hCard)) -+ goto out; -+ if (!check_field(n, "dwDisposition", opIn.call.hCardAndDisposition.dwDisposition, -+ opOut.call.hCardAndDisposition.dwDisposition)) -+ goto out; -+ -+ success = TRUE; -+out: -+ smartcard_operation_free(&opIn, FALSE); -+ smartcard_operation_free(&opOut, FALSE); -+ return success; -+} -+ -+static BOOL test_disconnect_encode_decode_request(void) -+{ -+ return test_hcard_and_disposition_encode_decode_request_impl(SCARD_IOCTL_DISCONNECT, -+ SCARD_LEAVE_CARD); -+} -+ -+static BOOL test_begin_transaction_encode_decode_request(void) -+{ -+ return test_hcard_and_disposition_encode_decode_request_impl(SCARD_IOCTL_BEGINTRANSACTION, -+ SCARD_LEAVE_CARD); -+} -+ -+static BOOL test_end_transaction_encode_decode_request(void) -+{ -+ return test_hcard_and_disposition_encode_decode_request_impl(SCARD_IOCTL_ENDTRANSACTION, -+ SCARD_RESET_CARD); -+} -+ -+static BOOL test_status_encode_decode_request_impl(UINT32 ioControlCode) -+{ -+ BOOL success = FALSE; -+ const char* n = scard_get_ioctl_string(ioControlCode, TRUE); -+ SMARTCARD_OPERATION opOut = WINPR_C_ARRAY_INIT; -+ SMARTCARD_OPERATION opIn = WINPR_C_ARRAY_INIT; -+ opIn.ioControlCode = ioControlCode; -+ fill_redir_context(&opIn.call.status.handles.hContext, 0x1234); -+ fill_redir_handle(&opIn.call.status.handles.hCard, 0x5678); -+ opIn.call.status.fmszReaderNamesIsNULL = 0; -+ opIn.call.status.cchReaderLen = SCARD_AUTOALLOCATE; -+ opIn.call.status.cbAtrLen = 36; -+ -+ if (!test_request_roundtrip(&opIn, &opOut)) -+ goto out; -+ if (!check_redir_context(n, &opIn.call.status.handles.hContext, -+ &opOut.call.status.handles.hContext)) -+ goto out; -+ if (!check_redir_handle(n, &opIn.call.status.handles.hCard, &opOut.call.status.handles.hCard)) -+ goto out; -+ if (!check_field(n, "fmszReaderNamesIsNULL", opIn.call.status.fmszReaderNamesIsNULL, -+ opOut.call.status.fmszReaderNamesIsNULL)) -+ goto out; -+ if (!check_field(n, "cchReaderLen", opIn.call.status.cchReaderLen, -+ opOut.call.status.cchReaderLen)) -+ goto out; -+ if (!check_field(n, "cbAtrLen", opIn.call.status.cbAtrLen, opOut.call.status.cbAtrLen)) -+ goto out; -+ -+ success = TRUE; -+out: -+ smartcard_operation_free(&opIn, FALSE); -+ smartcard_operation_free(&opOut, FALSE); -+ return success; -+} -+ -+static BOOL test_status_a_encode_decode_request(void) -+{ -+ return test_status_encode_decode_request_impl(SCARD_IOCTL_STATUSA); -+} -+ -+static BOOL test_status_w_encode_decode_request(void) -+{ -+ return test_status_encode_decode_request_impl(SCARD_IOCTL_STATUSW); -+} -+ -+static BOOL test_transmit_encode_decode_request(void) -+{ -+ BOOL success = FALSE; -+ BYTE sendBuf[] = { 0x00, 0xA4, 0x04, 0x00, 0x07 }; -+ SCARD_IO_REQUEST pioSendPci = { .dwProtocol = SCARD_PROTOCOL_T0, .cbPciLength = 8 }; -+ SMARTCARD_OPERATION opIn = WINPR_C_ARRAY_INIT; -+ opIn.ioControlCode = SCARD_IOCTL_TRANSMIT; -+ fill_redir_context(&opIn.call.transmit.handles.hContext, 0x1234); -+ fill_redir_handle(&opIn.call.transmit.handles.hCard, 0x5678); -+ opIn.call.transmit.pioSendPci = &pioSendPci; -+ opIn.call.transmit.cbSendLength = sizeof(sendBuf); -+ opIn.call.transmit.pbSendBuffer = sendBuf; -+ opIn.call.transmit.fpbRecvBufferIsNULL = 0; -+ opIn.call.transmit.cbRecvLength = 256; -+ -+ SMARTCARD_OPERATION opOut = WINPR_C_ARRAY_INIT; -+ if (!test_request_roundtrip(&opIn, &opOut)) -+ goto out; -+ if (!check_redir_context("Transmit", &opIn.call.transmit.handles.hContext, -+ &opOut.call.transmit.handles.hContext)) -+ goto out; -+ if (!check_redir_handle("Transmit", &opIn.call.transmit.handles.hCard, -+ &opOut.call.transmit.handles.hCard)) -+ goto out; -+ if (!check_field("Transmit", "cbSendLength", opIn.call.transmit.cbSendLength, -+ opOut.call.transmit.cbSendLength)) -+ goto out; -+ if (!check_bytes("Transmit", "pbSendBuffer", opIn.call.transmit.pbSendBuffer, -+ opOut.call.transmit.pbSendBuffer, opIn.call.transmit.cbSendLength)) -+ goto out; -+ if (!check_field("Transmit", "fpbRecvBufferIsNULL", -+ (UINT32)opIn.call.transmit.fpbRecvBufferIsNULL, -+ (UINT32)opOut.call.transmit.fpbRecvBufferIsNULL)) -+ goto out; -+ if (!check_field("Transmit", "cbRecvLength", opIn.call.transmit.cbRecvLength, -+ opOut.call.transmit.cbRecvLength)) -+ goto out; -+ if (!check_field("Transmit", "pioSendPci.dwProtocol", opIn.call.transmit.pioSendPci->dwProtocol, -+ opOut.call.transmit.pioSendPci->dwProtocol)) -+ goto out; -+ -+ success = TRUE; -+out: -+ opIn.call.transmit.pioSendPci = NULL; -+ opIn.call.transmit.pbSendBuffer = NULL; -+ smartcard_operation_free(&opIn, FALSE); -+ smartcard_operation_free(&opOut, FALSE); -+ return success; -+} -+ -+static BOOL test_control_encode_decode_request(void) -+{ -+ BOOL success = FALSE; -+ BYTE inBuf[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 }; -+ SMARTCARD_OPERATION opIn = WINPR_C_ARRAY_INIT; -+ opIn.ioControlCode = SCARD_IOCTL_CONTROL; -+ fill_redir_context(&opIn.call.control.handles.hContext, 0x1234); -+ fill_redir_handle(&opIn.call.control.handles.hCard, 0x5678); -+ opIn.call.control.dwControlCode = 0x42000001; -+ opIn.call.control.cbInBufferSize = sizeof(inBuf); -+ opIn.call.control.pvInBuffer = inBuf; -+ opIn.call.control.fpvOutBufferIsNULL = 0; -+ opIn.call.control.cbOutBufferSize = 256; -+ -+ SMARTCARD_OPERATION opOut = WINPR_C_ARRAY_INIT; -+ if (!test_request_roundtrip(&opIn, &opOut)) -+ goto out; -+ if (!check_redir_context("Control", &opIn.call.control.handles.hContext, -+ &opOut.call.control.handles.hContext)) -+ goto out; -+ if (!check_redir_handle("Control", &opIn.call.control.handles.hCard, -+ &opOut.call.control.handles.hCard)) -+ goto out; -+ if (!check_field("Control", "dwControlCode", opIn.call.control.dwControlCode, -+ opOut.call.control.dwControlCode)) -+ goto out; -+ if (!check_field("Control", "cbInBufferSize", opIn.call.control.cbInBufferSize, -+ opOut.call.control.cbInBufferSize)) -+ goto out; -+ if (!check_bytes("Control", "pvInBuffer", opIn.call.control.pvInBuffer, -+ opOut.call.control.pvInBuffer, opIn.call.control.cbInBufferSize)) -+ goto out; -+ if (!check_field("Control", "cbOutBufferSize", opIn.call.control.cbOutBufferSize, -+ opOut.call.control.cbOutBufferSize)) -+ goto out; -+ -+ success = TRUE; -+out: -+ opIn.call.control.pvInBuffer = NULL; -+ smartcard_operation_free(&opIn, FALSE); -+ smartcard_operation_free(&opOut, FALSE); -+ return success; -+} -+ -+static BOOL test_get_attrib_encode_decode_request(void) -+{ -+ BOOL success = FALSE; -+ SMARTCARD_OPERATION opOut = WINPR_C_ARRAY_INIT; -+ SMARTCARD_OPERATION opIn = WINPR_C_ARRAY_INIT; -+ opIn.ioControlCode = SCARD_IOCTL_GETATTRIB; -+ fill_redir_context(&opIn.call.getAttrib.handles.hContext, 0x1234); -+ fill_redir_handle(&opIn.call.getAttrib.handles.hCard, 0x5678); -+ opIn.call.getAttrib.dwAttrId = SCARD_ATTR_ATR_STRING; -+ opIn.call.getAttrib.fpbAttrIsNULL = 0; -+ opIn.call.getAttrib.cbAttrLen = 36; -+ -+ if (!test_request_roundtrip(&opIn, &opOut)) -+ goto out; -+ if (!check_redir_context("GetAttrib", &opIn.call.getAttrib.handles.hContext, -+ &opOut.call.getAttrib.handles.hContext)) -+ goto out; -+ if (!check_redir_handle("GetAttrib", &opIn.call.getAttrib.handles.hCard, -+ &opOut.call.getAttrib.handles.hCard)) -+ goto out; -+ if (!check_field("GetAttrib", "dwAttrId", opIn.call.getAttrib.dwAttrId, -+ opOut.call.getAttrib.dwAttrId)) -+ goto out; -+ if (!check_field("GetAttrib", "cbAttrLen", opIn.call.getAttrib.cbAttrLen, -+ opOut.call.getAttrib.cbAttrLen)) -+ goto out; -+ -+ success = TRUE; -+out: -+ smartcard_operation_free(&opIn, FALSE); -+ smartcard_operation_free(&opOut, FALSE); -+ return success; -+} -+ -+static BOOL test_set_attrib_encode_decode_request(void) -+{ -+ BOOL success = FALSE; -+ BYTE attrBuf[] = { 0x3B, 0x00 }; -+ SMARTCARD_OPERATION opOut = WINPR_C_ARRAY_INIT; -+ SMARTCARD_OPERATION opIn = WINPR_C_ARRAY_INIT; -+ opIn.ioControlCode = SCARD_IOCTL_SETATTRIB; -+ fill_redir_context(&opIn.call.setAttrib.handles.hContext, 0x1234); -+ fill_redir_handle(&opIn.call.setAttrib.handles.hCard, 0x5678); -+ opIn.call.setAttrib.dwAttrId = SCARD_ATTR_ATR_STRING; -+ opIn.call.setAttrib.cbAttrLen = sizeof(attrBuf); -+ opIn.call.setAttrib.pbAttr = attrBuf; -+ -+ if (!test_request_roundtrip(&opIn, &opOut)) -+ goto out; -+ if (!check_redir_context("SetAttrib", &opIn.call.setAttrib.handles.hContext, -+ &opOut.call.setAttrib.handles.hContext)) -+ goto out; -+ if (!check_redir_handle("SetAttrib", &opIn.call.setAttrib.handles.hCard, -+ &opOut.call.setAttrib.handles.hCard)) -+ goto out; -+ if (!check_field("SetAttrib", "dwAttrId", opIn.call.setAttrib.dwAttrId, -+ opOut.call.setAttrib.dwAttrId)) -+ goto out; -+ if (!check_field("SetAttrib", "cbAttrLen", opIn.call.setAttrib.cbAttrLen, -+ opOut.call.setAttrib.cbAttrLen)) -+ goto out; -+ if (!check_bytes("SetAttrib", "pbAttr", opIn.call.setAttrib.pbAttr, opOut.call.setAttrib.pbAttr, -+ opIn.call.setAttrib.cbAttrLen)) -+ goto out; -+ -+ success = TRUE; -+out: -+ opIn.call.setAttrib.pbAttr = NULL; -+ smartcard_operation_free(&opIn, FALSE); -+ smartcard_operation_free(&opOut, FALSE); -+ return success; -+} -+ -+static BOOL test_encode_decode_requests(void) -+{ -+ BOOL success = TRUE; -+ -+ if (!test_establish_context_encode_decode_request()) -+ success = FALSE; -+ if (!test_release_context_encode_decode_request()) -+ success = FALSE; -+ if (!test_is_valid_context_encode_decode_request()) -+ success = FALSE; -+ if (!test_list_reader_groups_a_encode_decode_request()) -+ success = FALSE; -+ if (!test_list_reader_groups_w_encode_decode_request()) -+ success = FALSE; -+ if (!test_list_readers_a_encode_decode_request()) -+ success = FALSE; -+ if (!test_list_readers_w_encode_decode_request()) -+ success = FALSE; -+ if (!test_cancel_encode_decode_request()) -+ success = FALSE; -+ if (!test_connect_a_encode_decode_request()) -+ success = FALSE; -+ if (!test_connect_w_encode_decode_request()) -+ success = FALSE; -+ if (!test_reconnect_encode_decode_request()) -+ success = FALSE; -+ if (!test_disconnect_encode_decode_request()) -+ success = FALSE; -+ if (!test_begin_transaction_encode_decode_request()) -+ success = FALSE; -+ if (!test_end_transaction_encode_decode_request()) -+ success = FALSE; -+ if (!test_status_a_encode_decode_request()) -+ success = FALSE; -+ if (!test_status_w_encode_decode_request()) -+ success = FALSE; -+ if (!test_transmit_encode_decode_request()) -+ success = FALSE; -+ if (!test_control_encode_decode_request()) -+ success = FALSE; -+ if (!test_get_attrib_encode_decode_request()) -+ success = FALSE; -+ if (!test_set_attrib_encode_decode_request()) -+ success = FALSE; -+ -+ return success; -+} -+ -+static LONG encode_response_payload(wStream* s, UINT32 ioControlCode, -+ const SMARTCARD_OPERATION* opIn) -+{ -+ switch (ioControlCode) -+ { -+ case SCARD_IOCTL_ESTABLISHCONTEXT: -+ return smartcard_pack_establish_context_return(s, &opIn->ret.establishContext); -+ case SCARD_IOCTL_RECONNECT: -+ return smartcard_pack_reconnect_return(s, &opIn->ret.reconnect); -+ case SCARD_IOCTL_CONNECTA: -+ case SCARD_IOCTL_CONNECTW: -+ return smartcard_pack_connect_return(s, &opIn->ret.connect); -+ case SCARD_IOCTL_CONTROL: -+ return smartcard_pack_control_return(s, &opIn->ret.control); -+ case SCARD_IOCTL_TRANSMIT: -+ return smartcard_pack_transmit_return(s, &opIn->ret.transmit); -+ case SCARD_IOCTL_GETATTRIB: -+ return smartcard_pack_get_attrib_return(s, &opIn->ret.getAttrib, 0, -+ opIn->ret.getAttrib.cbAttrLen); -+ case SCARD_IOCTL_GETSTATUSCHANGEA: -+ return smartcard_pack_get_status_change_return(s, &opIn->ret.getStatusChange, FALSE); -+ case SCARD_IOCTL_GETSTATUSCHANGEW: -+ return smartcard_pack_get_status_change_return(s, &opIn->ret.getStatusChange, TRUE); -+ case SCARD_IOCTL_LISTREADERGROUPSA: -+ return smartcard_pack_list_reader_groups_return(s, &opIn->ret.listReaders, FALSE); -+ case SCARD_IOCTL_LISTREADERGROUPSW: -+ return smartcard_pack_list_reader_groups_return(s, &opIn->ret.listReaders, TRUE); -+ case SCARD_IOCTL_LISTREADERSA: -+ return smartcard_pack_list_readers_return(s, &opIn->ret.listReaders, FALSE); -+ case SCARD_IOCTL_LISTREADERSW: -+ return smartcard_pack_list_readers_return(s, &opIn->ret.listReaders, TRUE); -+ case SCARD_IOCTL_STATUSA: -+ return smartcard_pack_status_return(s, &opIn->ret.status, FALSE); -+ case SCARD_IOCTL_STATUSW: -+ return smartcard_pack_status_return(s, &opIn->ret.status, TRUE); -+ case SCARD_IOCTL_RELEASECONTEXT: -+ case SCARD_IOCTL_ISVALIDCONTEXT: -+ case SCARD_IOCTL_CANCEL: -+ case SCARD_IOCTL_DISCONNECT: -+ case SCARD_IOCTL_BEGINTRANSACTION: -+ case SCARD_IOCTL_ENDTRANSACTION: -+ case SCARD_IOCTL_SETATTRIB: -+ return SCARD_S_SUCCESS; -+ default: -+ return SCARD_F_INTERNAL_ERROR; -+ } -+} -+ -+static wStream* build_device_control_response(UINT32 ioControlCode, const SMARTCARD_OPERATION* opIn) -+{ -+ const char* name = scard_get_ioctl_string(ioControlCode, TRUE); -+ -+ wStream* payload = Stream_New(NULL, 4096); -+ if (!payload) -+ { -+ (void)fprintf(stderr, "%s: Stream_New for payload failed\n", name); -+ return NULL; -+ } -+ -+ LONG rc = encode_response_payload(payload, ioControlCode, opIn); -+ if (rc != SCARD_S_SUCCESS) -+ { -+ (void)fprintf(stderr, "%s: encode_response_payload failed with 0x%08" PRIX32 "\n", name, -+ (UINT32)rc); -+ Stream_Release(payload); -+ return NULL; -+ } -+ Stream_SealLength(payload); -+ -+ wStream* s = Stream_New(NULL, 256 + Stream_Length(payload)); -+ if (!s) -+ { -+ (void)fprintf(stderr, "%s: Stream_New for response failed\n", name); -+ Stream_Release(payload); -+ return NULL; -+ } -+ -+ Stream_Seek(s, 4); /* Placeholder for outputBufferLength */ -+ const size_t headerPos = Stream_GetPosition(s); -+ Stream_Seek(s, SMARTCARD_COMMON_TYPE_HEADER_LENGTH + -+ SMARTCARD_PRIVATE_TYPE_HEADER_LENGTH); /* Placeholder for headers */ -+ Stream_Write_INT32(s, opIn->returnCode); -+ Stream_Write(s, Stream_Buffer(payload), Stream_Length(payload)); -+ Stream_Release(payload); -+ -+ const size_t payloadSize = Stream_GetPosition(s) - headerPos; -+ const size_t objectBufferLength = -+ payloadSize - SMARTCARD_COMMON_TYPE_HEADER_LENGTH - SMARTCARD_PRIVATE_TYPE_HEADER_LENGTH; -+ -+ WINPR_UNUSED(smartcard_pack_write_size_align(s, payloadSize, 8)); -+ -+ const size_t endPos = Stream_GetPosition(s); -+ const size_t outputBufferLength = endPos - headerPos; -+ -+ Stream_SetPosition(s, 0); -+ UINT32 outputLength = WINPR_ASSERTING_INT_CAST(UINT32, outputBufferLength); -+ UINT32 objectLength = WINPR_ASSERTING_INT_CAST(UINT32, objectBufferLength); -+ Stream_Write_UINT32(s, outputLength); -+ smartcard_pack_common_type_header(s); -+ smartcard_pack_private_type_header(s, objectLength); -+ -+ Stream_SetPosition(s, endPos); -+ Stream_SealLength(s); -+ if (!Stream_SetPosition(s, 0)) -+ { -+ (void)fprintf(stderr, "%s: Stream_SetPosition failed\n", name); -+ Stream_Release(s); -+ return NULL; -+ } -+ return s; -+} -+ -+static BOOL test_response_roundtrip(const SMARTCARD_OPERATION* opIn, SMARTCARD_OPERATION* opOut) -+{ -+ const UINT32 ioControlCode = opIn->ioControlCode; -+ const char* name = scard_get_ioctl_string(ioControlCode, TRUE); -+ -+ wStream* s = build_device_control_response(ioControlCode, opIn); -+ if (!s) -+ return FALSE; -+ -+ *opOut = (SMARTCARD_OPERATION)WINPR_C_ARRAY_INIT; -+ LONG status = smartcard_irp_device_control_decode_response(s, ioControlCode, opOut); -+ Stream_Release(s); -+ -+ if (status != SCARD_S_SUCCESS) -+ { -+ (void)fprintf(stderr, "%s: decode_response failed with 0x%08" PRIX32 "\n", name, -+ (UINT32)status); -+ return FALSE; -+ } -+ -+ return TRUE; -+} -+ -+static BOOL test_establish_context_decode_response(void) -+{ -+ BOOL success = FALSE; -+ SMARTCARD_OPERATION opOut = WINPR_C_ARRAY_INIT; -+ SMARTCARD_OPERATION opIn = WINPR_C_ARRAY_INIT; -+ opIn.ioControlCode = SCARD_IOCTL_ESTABLISHCONTEXT; -+ fill_redir_context(&opIn.ret.establishContext.hContext, 0xABCD); -+ opIn.returnCode = SCARD_S_SUCCESS; -+ -+ if (!test_response_roundtrip(&opIn, &opOut)) -+ goto out; -+ if (!check_redir_context("EstablishContext", &opIn.ret.establishContext.hContext, -+ &opOut.ret.establishContext.hContext)) -+ goto out; -+ if (!check_field("EstablishContext", "returnCode", (UINT32)opIn.returnCode, -+ (UINT32)opOut.returnCode)) -+ goto out; -+ -+ success = TRUE; -+out: -+ smartcard_operation_free(&opIn, FALSE); -+ smartcard_operation_free(&opOut, FALSE); -+ return success; -+} -+ -+static BOOL test_release_context_decode_response(void) -+{ -+ BOOL success = FALSE; -+ SMARTCARD_OPERATION opOut = WINPR_C_ARRAY_INIT; -+ SMARTCARD_OPERATION opIn = WINPR_C_ARRAY_INIT; -+ opIn.ioControlCode = SCARD_IOCTL_RELEASECONTEXT; -+ opIn.returnCode = SCARD_S_SUCCESS; -+ -+ if (!test_response_roundtrip(&opIn, &opOut)) -+ goto out; -+ if (!check_field("ReleaseContext", "returnCode", (UINT32)opIn.returnCode, -+ (UINT32)opOut.returnCode)) -+ goto out; -+ -+ success = TRUE; -+out: -+ smartcard_operation_free(&opIn, FALSE); -+ smartcard_operation_free(&opOut, FALSE); -+ return success; -+} -+ -+static BOOL test_is_valid_context_decode_response(void) -+{ -+ BOOL success = FALSE; -+ SMARTCARD_OPERATION opOut = WINPR_C_ARRAY_INIT; -+ SMARTCARD_OPERATION opIn = WINPR_C_ARRAY_INIT; -+ opIn.ioControlCode = SCARD_IOCTL_ISVALIDCONTEXT; -+ opIn.returnCode = SCARD_S_SUCCESS; -+ -+ if (!test_response_roundtrip(&opIn, &opOut)) -+ goto out; -+ if (!check_field("IsValidContext", "returnCode", (UINT32)opIn.returnCode, -+ (UINT32)opOut.returnCode)) -+ goto out; -+ -+ success = TRUE; -+out: -+ smartcard_operation_free(&opIn, FALSE); -+ smartcard_operation_free(&opOut, FALSE); -+ return success; -+} -+ -+static BOOL test_list_reader_groups_decode_response_impl(UINT32 ioControlCode) -+{ -+ BOOL success = FALSE; -+ const char* n = scard_get_ioctl_string(ioControlCode, TRUE); -+ SMARTCARD_OPERATION opOut = WINPR_C_ARRAY_INIT; -+ SMARTCARD_OPERATION opIn = WINPR_C_ARRAY_INIT; -+ opIn.ioControlCode = ioControlCode; -+ opIn.returnCode = SCARD_S_SUCCESS; -+ BYTE groups[] = { 'G', 'r', 'p', '\0', '\0' }; -+ opIn.ret.listReaders.cBytes = sizeof(groups); -+ opIn.ret.listReaders.msz = groups; -+ -+ if (!test_response_roundtrip(&opIn, &opOut)) -+ goto out; -+ if (!check_field(n, "returnCode", (UINT32)opIn.returnCode, (UINT32)opOut.returnCode)) -+ goto out; -+ if (!check_field(n, "cBytes", opIn.ret.listReaders.cBytes, opOut.ret.listReaders.cBytes)) -+ goto out; -+ if (!check_bytes(n, "msz", opIn.ret.listReaders.msz, opOut.ret.listReaders.msz, -+ opIn.ret.listReaders.cBytes)) -+ goto out; -+ -+ success = TRUE; -+out: -+ opIn.ret.listReaders.msz = NULL; -+ smartcard_operation_free(&opIn, FALSE); -+ smartcard_operation_free(&opOut, FALSE); -+ return success; -+} -+ -+static BOOL test_list_reader_groups_a_decode_response(void) -+{ -+ return test_list_reader_groups_decode_response_impl(SCARD_IOCTL_LISTREADERGROUPSA); -+} -+ -+static BOOL test_list_reader_groups_w_decode_response(void) -+{ -+ return test_list_reader_groups_decode_response_impl(SCARD_IOCTL_LISTREADERGROUPSW); -+} -+ -+static BOOL test_list_readers_decode_response_impl(UINT32 ioControlCode) -+{ -+ BOOL success = FALSE; -+ const char* n = scard_get_ioctl_string(ioControlCode, TRUE); -+ SMARTCARD_OPERATION opOut = WINPR_C_ARRAY_INIT; -+ SMARTCARD_OPERATION opIn = WINPR_C_ARRAY_INIT; -+ opIn.ioControlCode = ioControlCode; -+ opIn.returnCode = SCARD_S_SUCCESS; -+ BYTE readers[] = { 'R', 'd', 'r', '\0', '\0' }; -+ opIn.ret.listReaders.cBytes = sizeof(readers); -+ opIn.ret.listReaders.msz = readers; -+ -+ if (!test_response_roundtrip(&opIn, &opOut)) -+ goto out; -+ if (!check_field(n, "returnCode", (UINT32)opIn.returnCode, (UINT32)opOut.returnCode)) -+ goto out; -+ if (!check_field(n, "cBytes", opIn.ret.listReaders.cBytes, opOut.ret.listReaders.cBytes)) -+ goto out; -+ if (!check_bytes(n, "msz", opIn.ret.listReaders.msz, opOut.ret.listReaders.msz, -+ opIn.ret.listReaders.cBytes)) -+ goto out; -+ -+ success = TRUE; -+out: -+ opIn.ret.listReaders.msz = NULL; -+ smartcard_operation_free(&opIn, FALSE); -+ smartcard_operation_free(&opOut, FALSE); -+ return success; -+} -+ -+static BOOL test_list_readers_a_decode_response(void) -+{ -+ return test_list_readers_decode_response_impl(SCARD_IOCTL_LISTREADERSA); -+} -+ -+static BOOL test_list_readers_w_decode_response(void) -+{ -+ return test_list_readers_decode_response_impl(SCARD_IOCTL_LISTREADERSW); -+} -+ -+static BOOL test_get_status_change_decode_response_impl(UINT32 ioControlCode) -+{ -+ BOOL success = FALSE; -+ const char* n = scard_get_ioctl_string(ioControlCode, TRUE); -+ SMARTCARD_OPERATION opOut = WINPR_C_ARRAY_INIT; -+ SMARTCARD_OPERATION opIn = WINPR_C_ARRAY_INIT; -+ opIn.ioControlCode = ioControlCode; -+ opIn.returnCode = SCARD_S_SUCCESS; -+ ReaderState_Return state = WINPR_C_ARRAY_INIT; -+ state.dwCurrentState = SCARD_STATE_PRESENT; -+ state.dwEventState = SCARD_STATE_CHANGED; -+ state.cbAtr = 2; -+ state.rgbAtr[0] = 0x3B; -+ state.rgbAtr[1] = 0x00; -+ opIn.ret.getStatusChange.cReaders = 1; -+ opIn.ret.getStatusChange.rgReaderStates = &state; -+ -+ if (!test_response_roundtrip(&opIn, &opOut)) -+ goto out; -+ if (!check_field(n, "returnCode", (UINT32)opIn.returnCode, (UINT32)opOut.returnCode)) -+ goto out; -+ if (!check_field(n, "cReaders", opIn.ret.getStatusChange.cReaders, -+ opOut.ret.getStatusChange.cReaders)) -+ goto out; -+ if (!check_field(n, "dwCurrentState", state.dwCurrentState, -+ opOut.ret.getStatusChange.rgReaderStates[0].dwCurrentState)) -+ goto out; -+ if (!check_field(n, "dwEventState", state.dwEventState, -+ opOut.ret.getStatusChange.rgReaderStates[0].dwEventState)) -+ goto out; -+ if (!check_field(n, "cbAtr", state.cbAtr, opOut.ret.getStatusChange.rgReaderStates[0].cbAtr)) -+ goto out; -+ if (!check_bytes(n, "rgbAtr", state.rgbAtr, opOut.ret.getStatusChange.rgReaderStates[0].rgbAtr, -+ sizeof(state.rgbAtr))) -+ goto out; -+ -+ success = TRUE; -+out: -+ opIn.ret.getStatusChange.rgReaderStates = NULL; -+ smartcard_operation_free(&opIn, FALSE); -+ smartcard_operation_free(&opOut, FALSE); -+ return success; -+} -+ -+static BOOL test_get_status_change_a_decode_response(void) -+{ -+ return test_get_status_change_decode_response_impl(SCARD_IOCTL_GETSTATUSCHANGEA); -+} -+ -+static BOOL test_get_status_change_w_decode_response(void) -+{ -+ return test_get_status_change_decode_response_impl(SCARD_IOCTL_GETSTATUSCHANGEW); -+} -+ -+static BOOL test_cancel_decode_response(void) -+{ -+ BOOL success = FALSE; -+ SMARTCARD_OPERATION opOut = WINPR_C_ARRAY_INIT; -+ SMARTCARD_OPERATION opIn = WINPR_C_ARRAY_INIT; -+ opIn.ioControlCode = SCARD_IOCTL_CANCEL; -+ opIn.returnCode = SCARD_S_SUCCESS; -+ -+ if (!test_response_roundtrip(&opIn, &opOut)) -+ goto out; -+ if (!check_field("Cancel", "returnCode", (UINT32)opIn.returnCode, (UINT32)opOut.returnCode)) -+ goto out; -+ -+ success = TRUE; -+out: -+ smartcard_operation_free(&opIn, FALSE); -+ smartcard_operation_free(&opOut, FALSE); -+ return success; -+} -+ -+static BOOL test_connect_decode_response_impl(UINT32 ioControlCode) -+{ -+ BOOL success = FALSE; -+ const char* n = scard_get_ioctl_string(ioControlCode, TRUE); -+ SMARTCARD_OPERATION opOut = WINPR_C_ARRAY_INIT; -+ SMARTCARD_OPERATION opIn = WINPR_C_ARRAY_INIT; -+ opIn.ioControlCode = ioControlCode; -+ opIn.returnCode = SCARD_S_SUCCESS; -+ fill_redir_context(&opIn.ret.connect.hContext, 0x1234); -+ fill_redir_handle(&opIn.ret.connect.hCard, 0x5678); -+ opIn.ret.connect.dwActiveProtocol = SCARD_PROTOCOL_T0; -+ -+ if (!test_response_roundtrip(&opIn, &opOut)) -+ goto out; -+ if (!check_field(n, "returnCode", (UINT32)opIn.returnCode, (UINT32)opOut.returnCode)) -+ goto out; -+ if (!check_redir_context(n, &opIn.ret.connect.hContext, &opOut.ret.connect.hContext)) -+ goto out; -+ if (!check_redir_handle(n, &opIn.ret.connect.hCard, &opOut.ret.connect.hCard)) -+ goto out; -+ if (!check_field(n, "dwActiveProtocol", opIn.ret.connect.dwActiveProtocol, -+ opOut.ret.connect.dwActiveProtocol)) -+ goto out; -+ -+ success = TRUE; -+out: -+ smartcard_operation_free(&opIn, FALSE); -+ smartcard_operation_free(&opOut, FALSE); -+ return success; -+} -+ -+static BOOL test_connect_a_decode_response(void) -+{ -+ return test_connect_decode_response_impl(SCARD_IOCTL_CONNECTA); -+} -+ -+static BOOL test_connect_w_decode_response(void) -+{ -+ return test_connect_decode_response_impl(SCARD_IOCTL_CONNECTW); -+} -+ -+static BOOL test_reconnect_decode_response(void) -+{ -+ BOOL success = FALSE; -+ SMARTCARD_OPERATION opOut = WINPR_C_ARRAY_INIT; -+ SMARTCARD_OPERATION opIn = WINPR_C_ARRAY_INIT; -+ opIn.ioControlCode = SCARD_IOCTL_RECONNECT; -+ opIn.returnCode = SCARD_S_SUCCESS; -+ opIn.ret.reconnect.dwActiveProtocol = SCARD_PROTOCOL_T1; -+ -+ if (!test_response_roundtrip(&opIn, &opOut)) -+ goto out; -+ if (!check_field("Reconnect", "returnCode", (UINT32)opIn.returnCode, (UINT32)opOut.returnCode)) -+ goto out; -+ if (!check_field("Reconnect", "dwActiveProtocol", opIn.ret.reconnect.dwActiveProtocol, -+ opOut.ret.reconnect.dwActiveProtocol)) -+ goto out; -+ -+ success = TRUE; -+out: -+ smartcard_operation_free(&opIn, FALSE); -+ smartcard_operation_free(&opOut, FALSE); -+ return success; -+} -+ -+static BOOL test_disconnect_decode_response(void) -+{ -+ BOOL success = FALSE; -+ SMARTCARD_OPERATION opOut = WINPR_C_ARRAY_INIT; -+ SMARTCARD_OPERATION opIn = WINPR_C_ARRAY_INIT; -+ opIn.ioControlCode = SCARD_IOCTL_DISCONNECT; -+ opIn.returnCode = SCARD_S_SUCCESS; -+ -+ if (!test_response_roundtrip(&opIn, &opOut)) -+ goto out; -+ if (!check_field("Disconnect", "returnCode", (UINT32)opIn.returnCode, (UINT32)opOut.returnCode)) -+ goto out; -+ -+ success = TRUE; -+out: -+ smartcard_operation_free(&opIn, FALSE); -+ smartcard_operation_free(&opOut, FALSE); -+ return success; -+} -+ -+static BOOL test_begin_transaction_decode_response(void) -+{ -+ BOOL success = FALSE; -+ SMARTCARD_OPERATION opOut = WINPR_C_ARRAY_INIT; -+ SMARTCARD_OPERATION opIn = WINPR_C_ARRAY_INIT; -+ opIn.ioControlCode = SCARD_IOCTL_BEGINTRANSACTION; -+ opIn.returnCode = SCARD_S_SUCCESS; -+ -+ if (!test_response_roundtrip(&opIn, &opOut)) -+ goto out; -+ if (!check_field("BeginTransaction", "returnCode", (UINT32)opIn.returnCode, -+ (UINT32)opOut.returnCode)) -+ goto out; -+ -+ success = TRUE; -+out: -+ smartcard_operation_free(&opIn, FALSE); -+ smartcard_operation_free(&opOut, FALSE); -+ return success; -+} -+ -+static BOOL test_end_transaction_decode_response(void) -+{ -+ BOOL success = FALSE; -+ SMARTCARD_OPERATION opOut = WINPR_C_ARRAY_INIT; -+ SMARTCARD_OPERATION opIn = WINPR_C_ARRAY_INIT; -+ opIn.ioControlCode = SCARD_IOCTL_ENDTRANSACTION; -+ opIn.returnCode = SCARD_S_SUCCESS; -+ -+ if (!test_response_roundtrip(&opIn, &opOut)) -+ goto out; -+ if (!check_field("EndTransaction", "returnCode", (UINT32)opIn.returnCode, -+ (UINT32)opOut.returnCode)) -+ goto out; -+ -+ success = TRUE; -+out: -+ smartcard_operation_free(&opIn, FALSE); -+ smartcard_operation_free(&opOut, FALSE); -+ return success; -+} -+ -+static BOOL test_status_decode_response_impl(UINT32 ioControlCode) -+{ -+ BOOL success = FALSE; -+ const char* n = scard_get_ioctl_string(ioControlCode, TRUE); -+ SMARTCARD_OPERATION opOut = WINPR_C_ARRAY_INIT; -+ SMARTCARD_OPERATION opIn = WINPR_C_ARRAY_INIT; -+ opIn.ioControlCode = ioControlCode; -+ opIn.returnCode = SCARD_S_SUCCESS; -+ BYTE readerName[] = { 'R', 'd', 'r', '\0' }; -+ opIn.ret.status.cBytes = sizeof(readerName); -+ opIn.ret.status.mszReaderNames = readerName; -+ opIn.ret.status.dwState = SCARD_SPECIFIC; -+ opIn.ret.status.dwProtocol = SCARD_PROTOCOL_T1; -+ memset(opIn.ret.status.pbAtr, 0x3B, sizeof(opIn.ret.status.pbAtr)); -+ opIn.ret.status.cbAtrLen = 2; -+ -+ if (!test_response_roundtrip(&opIn, &opOut)) -+ goto out; -+ if (!check_field(n, "returnCode", (UINT32)opIn.returnCode, (UINT32)opOut.returnCode)) -+ goto out; -+ if (!check_field(n, "dwState", opIn.ret.status.dwState, opOut.ret.status.dwState)) -+ goto out; -+ if (!check_field(n, "dwProtocol", opIn.ret.status.dwProtocol, opOut.ret.status.dwProtocol)) -+ goto out; -+ if (!check_field(n, "cbAtrLen", opIn.ret.status.cbAtrLen, opOut.ret.status.cbAtrLen)) -+ goto out; -+ if (!check_bytes(n, "pbAtr", opIn.ret.status.pbAtr, opOut.ret.status.pbAtr, -+ sizeof(opIn.ret.status.pbAtr))) -+ goto out; -+ if (!check_field(n, "cBytes", opIn.ret.status.cBytes, opOut.ret.status.cBytes)) -+ goto out; -+ if (!check_bytes(n, "mszReaderNames", opIn.ret.status.mszReaderNames, -+ opOut.ret.status.mszReaderNames, opIn.ret.status.cBytes)) -+ goto out; -+ -+ success = TRUE; -+out: -+ opIn.ret.status.mszReaderNames = NULL; -+ smartcard_operation_free(&opIn, FALSE); -+ smartcard_operation_free(&opOut, FALSE); -+ return success; -+} -+ -+static BOOL test_status_a_decode_response(void) -+{ -+ return test_status_decode_response_impl(SCARD_IOCTL_STATUSA); -+} -+ -+static BOOL test_status_w_decode_response(void) -+{ -+ return test_status_decode_response_impl(SCARD_IOCTL_STATUSW); -+} -+ -+static BOOL test_transmit_decode_response(void) -+{ -+ BOOL success = FALSE; -+ SMARTCARD_OPERATION opOut = WINPR_C_ARRAY_INIT; -+ SMARTCARD_OPERATION opIn = WINPR_C_ARRAY_INIT; -+ opIn.ioControlCode = SCARD_IOCTL_TRANSMIT; -+ opIn.returnCode = SCARD_S_SUCCESS; -+ BYTE recvBuf[] = { 0x90, 0x00 }; -+ opIn.ret.transmit.cbRecvLength = sizeof(recvBuf); -+ opIn.ret.transmit.pbRecvBuffer = recvBuf; -+ opIn.ret.transmit.pioRecvPci = NULL; -+ -+ if (!test_response_roundtrip(&opIn, &opOut)) -+ goto out; -+ if (!check_field("Transmit", "returnCode", (UINT32)opIn.returnCode, (UINT32)opOut.returnCode)) -+ goto out; -+ if (!check_field("Transmit", "cbRecvLength", opIn.ret.transmit.cbRecvLength, -+ opOut.ret.transmit.cbRecvLength)) -+ goto out; -+ if (!check_bytes("Transmit", "pbRecvBuffer", opIn.ret.transmit.pbRecvBuffer, -+ opOut.ret.transmit.pbRecvBuffer, opIn.ret.transmit.cbRecvLength)) -+ goto out; -+ -+ success = TRUE; -+out: -+ opIn.ret.transmit.pbRecvBuffer = NULL; -+ smartcard_operation_free(&opIn, FALSE); -+ smartcard_operation_free(&opOut, FALSE); -+ return success; -+} -+ -+static BOOL test_control_decode_response(void) -+{ -+ BOOL success = FALSE; -+ SMARTCARD_OPERATION opOut = WINPR_C_ARRAY_INIT; -+ SMARTCARD_OPERATION opIn = WINPR_C_ARRAY_INIT; -+ opIn.ioControlCode = SCARD_IOCTL_CONTROL; -+ opIn.returnCode = SCARD_S_SUCCESS; -+ BYTE outBuf[] = { 0xAA, 0xBB, 0xCC }; -+ opIn.ret.control.cbOutBufferSize = sizeof(outBuf); -+ opIn.ret.control.pvOutBuffer = outBuf; -+ -+ if (!test_response_roundtrip(&opIn, &opOut)) -+ goto out; -+ if (!check_field("Control", "returnCode", (UINT32)opIn.returnCode, (UINT32)opOut.returnCode)) -+ goto out; -+ if (!check_field("Control", "cbOutBufferSize", opIn.ret.control.cbOutBufferSize, -+ opOut.ret.control.cbOutBufferSize)) -+ goto out; -+ if (!check_bytes("Control", "pvOutBuffer", opIn.ret.control.pvOutBuffer, -+ opOut.ret.control.pvOutBuffer, opIn.ret.control.cbOutBufferSize)) -+ goto out; -+ -+ success = TRUE; -+out: -+ opIn.ret.control.pvOutBuffer = NULL; -+ smartcard_operation_free(&opIn, FALSE); -+ smartcard_operation_free(&opOut, FALSE); -+ return success; -+} -+ -+static BOOL test_get_attrib_decode_response(void) -+{ -+ BOOL success = FALSE; -+ SMARTCARD_OPERATION opOut = WINPR_C_ARRAY_INIT; -+ SMARTCARD_OPERATION opIn = WINPR_C_ARRAY_INIT; -+ opIn.ioControlCode = SCARD_IOCTL_GETATTRIB; -+ opIn.returnCode = SCARD_S_SUCCESS; -+ BYTE attr[] = { 0x3B, 0x90, 0x00 }; -+ opIn.ret.getAttrib.cbAttrLen = sizeof(attr); -+ opIn.ret.getAttrib.pbAttr = attr; -+ -+ if (!test_response_roundtrip(&opIn, &opOut)) -+ goto out; -+ if (!check_field("GetAttrib", "returnCode", (UINT32)opIn.returnCode, (UINT32)opOut.returnCode)) -+ goto out; -+ if (!check_field("GetAttrib", "cbAttrLen", opIn.ret.getAttrib.cbAttrLen, -+ opOut.ret.getAttrib.cbAttrLen)) -+ goto out; -+ if (!check_bytes("GetAttrib", "pbAttr", opIn.ret.getAttrib.pbAttr, opOut.ret.getAttrib.pbAttr, -+ opIn.ret.getAttrib.cbAttrLen)) -+ goto out; -+ -+ success = TRUE; -+out: -+ opIn.ret.getAttrib.pbAttr = NULL; -+ smartcard_operation_free(&opIn, FALSE); -+ smartcard_operation_free(&opOut, FALSE); -+ return success; -+} -+ -+static BOOL test_set_attrib_decode_response(void) -+{ -+ BOOL success = FALSE; -+ SMARTCARD_OPERATION opOut = WINPR_C_ARRAY_INIT; -+ SMARTCARD_OPERATION opIn = WINPR_C_ARRAY_INIT; -+ opIn.ioControlCode = SCARD_IOCTL_SETATTRIB; -+ opIn.returnCode = SCARD_S_SUCCESS; -+ -+ if (!test_response_roundtrip(&opIn, &opOut)) -+ goto out; -+ if (!check_field("SetAttrib", "returnCode", (UINT32)opIn.returnCode, (UINT32)opOut.returnCode)) -+ goto out; -+ -+ success = TRUE; -+out: -+ smartcard_operation_free(&opIn, FALSE); -+ smartcard_operation_free(&opOut, FALSE); -+ return success; -+} -+ -+static BOOL test_decode_responses(void) -+{ -+ BOOL success = TRUE; -+ -+ if (!test_establish_context_decode_response()) -+ success = FALSE; -+ if (!test_release_context_decode_response()) -+ success = FALSE; -+ if (!test_is_valid_context_decode_response()) -+ success = FALSE; -+ if (!test_list_reader_groups_a_decode_response()) -+ success = FALSE; -+ if (!test_list_reader_groups_w_decode_response()) -+ success = FALSE; -+ if (!test_list_readers_a_decode_response()) -+ success = FALSE; -+ if (!test_list_readers_w_decode_response()) -+ success = FALSE; -+ if (!test_get_status_change_a_decode_response()) -+ success = FALSE; -+ if (!test_get_status_change_w_decode_response()) -+ success = FALSE; -+ if (!test_cancel_decode_response()) -+ success = FALSE; -+ if (!test_connect_a_decode_response()) -+ success = FALSE; -+ if (!test_connect_w_decode_response()) -+ success = FALSE; -+ if (!test_reconnect_decode_response()) -+ success = FALSE; -+ if (!test_disconnect_decode_response()) -+ success = FALSE; -+ if (!test_begin_transaction_decode_response()) -+ success = FALSE; -+ if (!test_end_transaction_decode_response()) -+ success = FALSE; -+ if (!test_status_a_decode_response()) -+ success = FALSE; -+ if (!test_status_w_decode_response()) -+ success = FALSE; -+ if (!test_transmit_decode_response()) -+ success = FALSE; -+ if (!test_control_decode_response()) -+ success = FALSE; -+ if (!test_get_attrib_decode_response()) -+ success = FALSE; -+ if (!test_set_attrib_decode_response()) -+ success = FALSE; -+ -+ return success; -+} -+ -+int TestSmartcardOperations(int argc, char* argv[]) -+{ -+ WINPR_UNUSED(argc); -+ WINPR_UNUSED(argv); -+ -+ if (!test_encode_decode_requests()) -+ return -1; -+ -+ if (!test_decode_responses()) -+ return -1; -+ -+ return 0; -+} - -From 13dd1b439790515be4f6df013b4fb4fc4cbbae69 Mon Sep 17 00:00:00 2001 -From: Joan Torres Lopez -Date: Sat, 27 Jun 2026 01:28:31 +0200 -Subject: [PATCH 22/31] [channels,rdpdr] add doxygen documentation to rdpdr.h - ---- - channels/rdpdr/server/rdpdr_main.h | 17 +++--- - include/freerdp/server/rdpdr.h | 97 ++++++++++++++++++------------ - 2 files changed, 68 insertions(+), 46 deletions(-) - -diff --git a/channels/rdpdr/server/rdpdr_main.h b/channels/rdpdr/server/rdpdr_main.h -index 40327a81313b..bbcb09aea173 100644 ---- a/channels/rdpdr/server/rdpdr_main.h -+++ b/channels/rdpdr/server/rdpdr_main.h -@@ -35,16 +35,17 @@ typedef struct S_RDPDR_IRP RDPDR_IRP; - typedef UINT (*RDPDR_IRP_Callback)(RdpdrServerContext* context, wStream* s, struct S_RDPDR_IRP* irp, - UINT32 deviceId, UINT32 completionId, UINT32 ioStatus); - -+/** IRP request structure */ - struct S_RDPDR_IRP - { -- UINT32 CompletionId; -- UINT32 DeviceId; -- UINT32 FileId; -- UINT32 IoControlCode; -- char PathName[256]; -- char ExtraBuffer[256]; -- void* CallbackData; -- RDPDR_IRP_Callback Callback; -+ UINT32 CompletionId; /**< IRP completion identifier */ -+ UINT32 DeviceId; /**< Target device identifier */ -+ UINT32 FileId; /**< File handle identifier */ -+ UINT32 IoControlCode; /**< I/O control code */ -+ char PathName[256]; /**< File path name */ -+ char ExtraBuffer[256]; /**< Data buffer */ -+ void* CallbackData; /**< User callback data */ -+ RDPDR_IRP_Callback Callback; /**< Completion callback function */ - }; - - #endif /* FREERDP_CHANNEL_RDPDR_SERVER_MAIN_H */ -diff --git a/include/freerdp/server/rdpdr.h b/include/freerdp/server/rdpdr.h -index a44a7e1cef87..9fb1515e1a4e 100644 ---- a/include/freerdp/server/rdpdr.h -+++ b/include/freerdp/server/rdpdr.h -@@ -43,28 +43,30 @@ extern "C" - typedef struct s_rdpdr_server_context RdpdrServerContext; - typedef struct s_rdpdr_server_private RdpdrServerPrivate; - -+ /** RDPDR protocol header */ - typedef struct - { -- UINT16 Component; -- UINT16 PacketId; -+ UINT16 Component; /**< Component identifier */ -+ UINT16 PacketId; /**< Packet identifier */ - } RDPDR_HEADER; - - #ifndef __MINGW32__ -+ /** File directory information structure */ - typedef struct - { -- UINT32 NextEntryOffset; -- UINT32 FileIndex; -- LARGE_INTEGER CreationTime; -- LARGE_INTEGER LastAccessTime; -- LARGE_INTEGER LastWriteTime; -- LARGE_INTEGER ChangeTime; -- LARGE_INTEGER EndOfFile; -- LARGE_INTEGER AllocationSize; -- UINT32 FileAttributes; -+ UINT32 NextEntryOffset; /**< Offset to next entry */ -+ UINT32 FileIndex; /**< File index */ -+ LARGE_INTEGER CreationTime; /**< File creation time */ -+ LARGE_INTEGER LastAccessTime; /**< Last access time */ -+ LARGE_INTEGER LastWriteTime; /**< Last write time */ -+ LARGE_INTEGER ChangeTime; /**< Last change time */ -+ LARGE_INTEGER EndOfFile; /**< End of file position */ -+ LARGE_INTEGER AllocationSize; /**< Allocated size */ -+ UINT32 FileAttributes; /**< File attributes */ - #if defined(WITH_WCHAR_FILE_DIRECTORY_INFORMATION) -- WCHAR FileName[512]; -+ WCHAR FileName[512]; /**< File name (wide char) */ - #else -- char FileName[512]; -+ char FileName[512]; /**< File name */ - #endif - } FILE_DIRECTORY_INFORMATION; - #endif -@@ -247,12 +249,12 @@ extern "C" - - struct s_rdpdr_server_context - { -- HANDLE vcm; -+ HANDLE vcm; /**< Virtual channel manager handle */ - -- WINPR_ATTR_NODISCARD psRdpdrStart Start; -- psRdpdrStop Stop; -+ WINPR_ATTR_NODISCARD psRdpdrStart Start; /**< Start the RDPDR server */ -+ psRdpdrStop Stop; /**< Stop the RDPDR server */ - -- RdpdrServerPrivate* priv; -+ RdpdrServerPrivate* priv; /**< Private server context data */ - - /* Server self-defined pointer. */ - void* data; -@@ -280,22 +282,24 @@ extern "C" - WINPR_ATTR_NODISCARD psRdpdrReceiveClientNameRequest - ReceiveClientNameRequest; /**< Called after a client name request is received */ - WINPR_ATTR_NODISCARD psRdpdrReceiveDeviceAnnounce -- ReceiveDeviceAnnounce; /** < Called after a new device request was received but before -+ ReceiveDeviceAnnounce; /**< Called after a new device request was received but before - the device is added */ - WINPR_ATTR_NODISCARD psRdpdrReceiveDeviceRemove - ReceiveDeviceRemove; /**< Called after a new device request was - received, but before it is removed */ - - /*** Drive APIs called by the server. ***/ -- WINPR_ATTR_NODISCARD psRdpdrDriveCreateDirectory DriveCreateDirectory; -- WINPR_ATTR_NODISCARD psRdpdrDriveDeleteDirectory DriveDeleteDirectory; -- WINPR_ATTR_NODISCARD psRdpdrDriveQueryDirectory DriveQueryDirectory; -- WINPR_ATTR_NODISCARD psRdpdrDriveOpenFile DriveOpenFile; -- WINPR_ATTR_NODISCARD psRdpdrDriveReadFile DriveReadFile; -- WINPR_ATTR_NODISCARD psRdpdrDriveWriteFile DriveWriteFile; -- WINPR_ATTR_NODISCARD psRdpdrDriveCloseFile DriveCloseFile; -- WINPR_ATTR_NODISCARD psRdpdrDriveDeleteFile DriveDeleteFile; -- WINPR_ATTR_NODISCARD psRdpdrDriveRenameFile DriveRenameFile; -+ WINPR_ATTR_NODISCARD psRdpdrDriveCreateDirectory -+ DriveCreateDirectory; /**< Create directory */ -+ WINPR_ATTR_NODISCARD psRdpdrDriveDeleteDirectory -+ DriveDeleteDirectory; /**< Delete directory */ -+ WINPR_ATTR_NODISCARD psRdpdrDriveQueryDirectory DriveQueryDirectory; /**< Query directory */ -+ WINPR_ATTR_NODISCARD psRdpdrDriveOpenFile DriveOpenFile; /**< Open file */ -+ WINPR_ATTR_NODISCARD psRdpdrDriveReadFile DriveReadFile; /**< Read file */ -+ WINPR_ATTR_NODISCARD psRdpdrDriveWriteFile DriveWriteFile; /**< Write file */ -+ WINPR_ATTR_NODISCARD psRdpdrDriveCloseFile DriveCloseFile; /**< Close file */ -+ WINPR_ATTR_NODISCARD psRdpdrDriveDeleteFile DriveDeleteFile; /**< Delete file */ -+ WINPR_ATTR_NODISCARD psRdpdrDriveRenameFile DriveRenameFile; /**< Rename file */ - - /*** Drive callbacks registered by the server. ***/ - WINPR_ATTR_NODISCARD psRdpdrOnDeviceCreate -@@ -304,15 +308,24 @@ extern "C" - WINPR_ATTR_NODISCARD psRdpdrOnDeviceDelete - OnDriveDelete; /**< Called for devices of type \b - RDPDR_DTYP_FILESYSTEM after \b ReceiveDeviceRemove */ -- psRdpdrOnDriveCreateDirectoryComplete OnDriveCreateDirectoryComplete; -- psRdpdrOnDriveDeleteDirectoryComplete OnDriveDeleteDirectoryComplete; -- psRdpdrOnDriveQueryDirectoryComplete OnDriveQueryDirectoryComplete; -- psRdpdrOnDriveOpenFileComplete OnDriveOpenFileComplete; -- psRdpdrOnDriveReadFileComplete OnDriveReadFileComplete; -- psRdpdrOnDriveWriteFileComplete OnDriveWriteFileComplete; -- psRdpdrOnDriveCloseFileComplete OnDriveCloseFileComplete; -- psRdpdrOnDriveDeleteFileComplete OnDriveDeleteFileComplete; -- psRdpdrOnDriveRenameFileComplete OnDriveRenameFileComplete; -+ psRdpdrOnDriveCreateDirectoryComplete -+ OnDriveCreateDirectoryComplete; /**< DriveCreateDirectory completion callback */ -+ psRdpdrOnDriveDeleteDirectoryComplete -+ OnDriveDeleteDirectoryComplete; /**< DriveDeleteDirectory completion callback */ -+ psRdpdrOnDriveQueryDirectoryComplete -+ OnDriveQueryDirectoryComplete; /**< DriveQueryDirectory completion callback */ -+ psRdpdrOnDriveOpenFileComplete -+ OnDriveOpenFileComplete; /**< DriveOpenFile completion callback */ -+ psRdpdrOnDriveReadFileComplete -+ OnDriveReadFileComplete; /**< DriveReadFile completion callback */ -+ psRdpdrOnDriveWriteFileComplete -+ OnDriveWriteFileComplete; /**< DriveWriteFile completion callback */ -+ psRdpdrOnDriveCloseFileComplete -+ OnDriveCloseFileComplete; /**< DriveCloseFile completion callback */ -+ psRdpdrOnDriveDeleteFileComplete -+ OnDriveDeleteFileComplete; /**< DriveDeleteFile completion callback */ -+ psRdpdrOnDriveRenameFileComplete -+ OnDriveRenameFileComplete; /**< DriveRenameFile completion callback */ - - /*** Serial Port callbacks registered by the server. ***/ - WINPR_ATTR_NODISCARD psRdpdrOnDeviceCreate -@@ -344,7 +357,7 @@ extern "C" - OnSmartcardDelete; /**< Called for devices of type - RDPDR_DTYP_SMARTCARD after \b ReceiveDeviceRemove */ - -- rdpContext* rdpcontext; -+ rdpContext* rdpcontext; /**< RDP context */ - - /*** New Smartcard APIs called by the server. ***/ - WINPR_ATTR_NODISCARD psRdpdrSmartcardEstablishContext -@@ -448,10 +461,18 @@ extern "C" - /* clang-format on */ - }; - -+ /** -+ * @brief Free an RDPDR server context. -+ * @param context The RDPDR server context to free. -+ */ - FREERDP_API void rdpdr_server_context_free(RdpdrServerContext* context); - -+ /** -+ * @brief Create a new RDPDR server context. -+ * @param vcm Virtual channel manager handle. -+ * @return Newly allocated RDPDR server context, or NULL on failure. -+ */ - WINPR_ATTR_MALLOC(rdpdr_server_context_free, 1) -- WINPR_ATTR_NODISCARD - FREERDP_API RdpdrServerContext* rdpdr_server_context_new(HANDLE vcm); - - /** - -From 3f911fca8307754edfbc60c3b0994f1cabd52432 Mon Sep 17 00:00:00 2001 -From: Armin Novak -Date: Mon, 29 Jun 2026 19:20:46 +0200 -Subject: [PATCH 23/31] [channels,rdpdr] fix compile warnings - ---- - channels/rdpdr/server/rdpdr_main.c | 150 +++++++++++++++-------------- - 1 file changed, 79 insertions(+), 71 deletions(-) - -diff --git a/channels/rdpdr/server/rdpdr_main.c b/channels/rdpdr/server/rdpdr_main.c -index 7b9c1d33ff10..f5565dcdeb2c 100644 ---- a/channels/rdpdr/server/rdpdr_main.c -+++ b/channels/rdpdr/server/rdpdr_main.c -@@ -254,6 +254,11 @@ static void rdpdr_server_irp_free(RDPDR_IRP* irp) - free(irp); - } - -+static void rdpdr_server_list_free(void* ptr) -+{ -+ RDPDR_IRP* irp = ptr; -+ rdpdr_server_irp_free(irp); -+} - static BOOL rdpdr_server_enqueue_irp(RdpdrServerContext* context, RDPDR_IRP* irp) - { - WINPR_ASSERT(context); -@@ -1154,7 +1159,7 @@ static UINT rdpdr_server_receive_device_list_announce_request(RdpdrServerContext - if (error != CHANNEL_RC_OK) - return error; - -- error = STATUS_NOT_SUPPORTED; -+ error = ERROR_NOT_SUPPORTED; - switch (device.DeviceType) - { - case RDPDR_DTYP_FILESYSTEM: -@@ -2214,7 +2219,10 @@ static DWORD WINAPI rdpdr_server_thread(LPVOID arg) - goto out; - case WAIT_OBJECT_0 + 1: - { -- s = ChannelPduTracker_poll(tracker); -+ BOOL ok = FALSE; -+ s = ChannelPduTracker_poll(tracker, &ok); -+ if (!s && ok) -+ continue; - if (!s) - break; - -@@ -3707,7 +3715,7 @@ static RdpdrServerPrivate* rdpdr_server_private_new(void) - if (!priv->IrpList) - goto fail; - -- ListDictionary_ValueObject(priv->IrpList)->fnObjectFree = (OBJECT_FREE_FN)rdpdr_server_irp_free; -+ ListDictionary_ValueObject(priv->IrpList)->fnObjectFree = rdpdr_server_list_free; - - priv->devicelist = HashTable_New(FALSE); - if (!priv->devicelist) -@@ -3763,8 +3771,8 @@ static UINT rdpdr_server_smartcard_establish_context_callback(RdpdrServerContext - goto out; - } - -- result = smartcard_irp_device_control_decode_response(s, irp->IoControlCode, &op); -- if (result != SCARD_S_SUCCESS) -+ const LONG rc = smartcard_irp_device_control_decode_response(s, irp->IoControlCode, &op); -+ if (rc != SCARD_S_SUCCESS) - { - result = ERROR_INVALID_DATA; - goto out; -@@ -3825,8 +3833,8 @@ static UINT rdpdr_server_smartcard_establish_context(RdpdrServerContext* context - goto out; - } - -- result = smartcard_irp_device_control_encode_request(s, &op); -- if (result != SCARD_S_SUCCESS) -+ const LONG rc = smartcard_irp_device_control_encode_request(s, &op); -+ if (rc != SCARD_S_SUCCESS) - { - result = ERROR_INTERNAL_ERROR; - goto out; -@@ -3871,8 +3879,8 @@ static UINT rdpdr_server_smartcard_release_context_callback(RdpdrServerContext* - goto out; - } - -- result = smartcard_irp_device_control_decode_response(s, irp->IoControlCode, &op); -- if (result != SCARD_S_SUCCESS) -+ const LONG rc = smartcard_irp_device_control_decode_response(s, irp->IoControlCode, &op); -+ if (rc != SCARD_S_SUCCESS) - { - result = ERROR_INVALID_DATA; - goto out; -@@ -3923,8 +3931,8 @@ static UINT rdpdr_server_smartcard_release_context(RdpdrServerContext* context, - goto out; - } - -- result = smartcard_irp_device_control_encode_request(s, &op); -- if (result != SCARD_S_SUCCESS) -+ const LONG rc = smartcard_irp_device_control_encode_request(s, &op); -+ if (rc != SCARD_S_SUCCESS) - { - result = ERROR_INTERNAL_ERROR; - goto out; -@@ -3970,8 +3978,8 @@ static UINT rdpdr_server_smartcard_is_valid_context_callback(RdpdrServerContext* - goto out; - } - -- result = smartcard_irp_device_control_decode_response(s, irp->IoControlCode, &op); -- if (result != SCARD_S_SUCCESS) -+ const LONG rc = smartcard_irp_device_control_decode_response(s, irp->IoControlCode, &op); -+ if (rc != SCARD_S_SUCCESS) - { - result = ERROR_INVALID_DATA; - goto out; -@@ -4022,8 +4030,8 @@ static UINT rdpdr_server_smartcard_is_valid_context(RdpdrServerContext* context, - goto out; - } - -- result = smartcard_irp_device_control_encode_request(s, &op); -- if (result != SCARD_S_SUCCESS) -+ const LONG rc = smartcard_irp_device_control_encode_request(s, &op); -+ if (rc != SCARD_S_SUCCESS) - { - result = ERROR_INTERNAL_ERROR; - goto out; -@@ -4069,8 +4077,8 @@ static UINT rdpdr_server_smartcard_list_reader_groups_callback(RdpdrServerContex - goto out; - } - -- result = smartcard_irp_device_control_decode_response(s, irp->IoControlCode, &op); -- if (result != SCARD_S_SUCCESS) -+ const LONG rc = smartcard_irp_device_control_decode_response(s, irp->IoControlCode, &op); -+ if (rc != SCARD_S_SUCCESS) - { - result = ERROR_INVALID_DATA; - goto out; -@@ -4128,8 +4136,8 @@ static UINT rdpdr_server_smartcard_list_reader_groups(RdpdrServerContext* contex - goto out; - } - -- result = smartcard_irp_device_control_encode_request(s, &op); -- if (result != SCARD_S_SUCCESS) -+ const LONG rc = smartcard_irp_device_control_encode_request(s, &op); -+ if (rc != SCARD_S_SUCCESS) - { - result = ERROR_INTERNAL_ERROR; - goto out; -@@ -4192,8 +4200,8 @@ static UINT rdpdr_server_smartcard_list_readers_callback(RdpdrServerContext* con - goto out; - } - -- result = smartcard_irp_device_control_decode_response(s, irp->IoControlCode, &op); -- if (result != SCARD_S_SUCCESS) -+ const LONG rc = smartcard_irp_device_control_decode_response(s, irp->IoControlCode, &op); -+ if (rc != SCARD_S_SUCCESS) - { - result = ERROR_INVALID_DATA; - goto out; -@@ -4251,8 +4259,8 @@ static UINT rdpdr_server_smartcard_list_readers(RdpdrServerContext* context, voi - goto out; - } - -- result = smartcard_irp_device_control_encode_request(s, &op); -- if (result != SCARD_S_SUCCESS) -+ const LONG rc = smartcard_irp_device_control_encode_request(s, &op); -+ if (rc != SCARD_S_SUCCESS) - { - result = ERROR_INTERNAL_ERROR; - goto out; -@@ -4312,8 +4320,8 @@ static UINT rdpdr_server_smartcard_get_status_change_callback(RdpdrServerContext - goto out; - } - -- result = smartcard_irp_device_control_decode_response(s, irp->IoControlCode, &op); -- if (result != SCARD_S_SUCCESS) -+ const LONG rc = smartcard_irp_device_control_decode_response(s, irp->IoControlCode, &op); -+ if (rc != SCARD_S_SUCCESS) - { - result = ERROR_INVALID_DATA; - goto out; -@@ -4376,8 +4384,8 @@ static UINT rdpdr_server_smartcard_get_status_change(RdpdrServerContext* context - goto out; - } - -- result = smartcard_irp_device_control_encode_request(s, &op); -- if (result != SCARD_S_SUCCESS) -+ const LONG rc = smartcard_irp_device_control_encode_request(s, &op); -+ if (rc != SCARD_S_SUCCESS) - { - result = ERROR_INTERNAL_ERROR; - goto out; -@@ -4440,8 +4448,8 @@ static UINT rdpdr_server_smartcard_cancel_callback(RdpdrServerContext* context, - goto out; - } - -- result = smartcard_irp_device_control_decode_response(s, irp->IoControlCode, &op); -- if (result != SCARD_S_SUCCESS) -+ const LONG rc = smartcard_irp_device_control_decode_response(s, irp->IoControlCode, &op); -+ if (rc != SCARD_S_SUCCESS) - { - result = ERROR_INVALID_DATA; - goto out; -@@ -4489,8 +4497,8 @@ static UINT rdpdr_server_smartcard_cancel(RdpdrServerContext* context, void* cal - goto out; - } - -- result = smartcard_irp_device_control_encode_request(s, &op); -- if (result != SCARD_S_SUCCESS) -+ const LONG rc = smartcard_irp_device_control_encode_request(s, &op); -+ if (rc != SCARD_S_SUCCESS) - { - result = ERROR_INTERNAL_ERROR; - goto out; -@@ -4535,8 +4543,8 @@ static UINT rdpdr_server_smartcard_connect_callback(RdpdrServerContext* context, - goto out; - } - -- result = smartcard_irp_device_control_decode_response(s, irp->IoControlCode, &op); -- if (result != SCARD_S_SUCCESS) -+ const LONG rc = smartcard_irp_device_control_decode_response(s, irp->IoControlCode, &op); -+ if (rc != SCARD_S_SUCCESS) - { - result = ERROR_INVALID_DATA; - goto out; -@@ -4597,8 +4605,8 @@ static UINT rdpdr_server_smartcard_connect(RdpdrServerContext* context, void* ca - goto out; - } - -- result = smartcard_irp_device_control_encode_request(s, &op); -- if (result != SCARD_S_SUCCESS) -+ const LONG rc = smartcard_irp_device_control_encode_request(s, &op); -+ if (rc != SCARD_S_SUCCESS) - { - result = ERROR_INTERNAL_ERROR; - goto out; -@@ -4657,8 +4665,8 @@ static UINT rdpdr_server_smartcard_reconnect_callback(RdpdrServerContext* contex - goto out; - } - -- result = smartcard_irp_device_control_decode_response(s, irp->IoControlCode, &op); -- if (result != SCARD_S_SUCCESS) -+ const LONG rc = smartcard_irp_device_control_decode_response(s, irp->IoControlCode, &op); -+ if (rc != SCARD_S_SUCCESS) - { - result = ERROR_INVALID_DATA; - goto out; -@@ -4715,8 +4723,8 @@ static UINT rdpdr_server_smartcard_reconnect(RdpdrServerContext* context, void* - goto out; - } - -- result = smartcard_irp_device_control_encode_request(s, &op); -- if (result != SCARD_S_SUCCESS) -+ const LONG rc = smartcard_irp_device_control_encode_request(s, &op); -+ if (rc != SCARD_S_SUCCESS) - { - result = ERROR_INTERNAL_ERROR; - goto out; -@@ -4761,8 +4769,8 @@ static UINT rdpdr_server_smartcard_disconnect_callback(RdpdrServerContext* conte - goto out; - } - -- result = smartcard_irp_device_control_decode_response(s, irp->IoControlCode, &op); -- if (result != SCARD_S_SUCCESS) -+ const LONG rc = smartcard_irp_device_control_decode_response(s, irp->IoControlCode, &op); -+ if (rc != SCARD_S_SUCCESS) - { - result = ERROR_INVALID_DATA; - goto out; -@@ -4817,8 +4825,8 @@ static UINT rdpdr_server_smartcard_disconnect(RdpdrServerContext* context, void* - goto out; - } - -- result = smartcard_irp_device_control_encode_request(s, &op); -- if (result != SCARD_S_SUCCESS) -+ const LONG rc = smartcard_irp_device_control_encode_request(s, &op); -+ if (rc != SCARD_S_SUCCESS) - { - result = ERROR_INTERNAL_ERROR; - goto out; -@@ -4864,8 +4872,8 @@ static UINT rdpdr_server_smartcard_begin_transaction_callback(RdpdrServerContext - goto out; - } - -- result = smartcard_irp_device_control_decode_response(s, irp->IoControlCode, &op); -- if (result != SCARD_S_SUCCESS) -+ const LONG rc = smartcard_irp_device_control_decode_response(s, irp->IoControlCode, &op); -+ if (rc != SCARD_S_SUCCESS) - { - result = ERROR_INVALID_DATA; - goto out; -@@ -4923,8 +4931,8 @@ static UINT rdpdr_server_smartcard_begin_transaction(RdpdrServerContext* context - goto out; - } - -- result = smartcard_irp_device_control_encode_request(s, &op); -- if (result != SCARD_S_SUCCESS) -+ const LONG rc = smartcard_irp_device_control_encode_request(s, &op); -+ if (rc != SCARD_S_SUCCESS) - { - result = ERROR_INTERNAL_ERROR; - goto out; -@@ -4969,8 +4977,8 @@ static UINT rdpdr_server_smartcard_end_transaction_callback(RdpdrServerContext* - goto out; - } - -- result = smartcard_irp_device_control_decode_response(s, irp->IoControlCode, &op); -- if (result != SCARD_S_SUCCESS) -+ const LONG rc = smartcard_irp_device_control_decode_response(s, irp->IoControlCode, &op); -+ if (rc != SCARD_S_SUCCESS) - { - result = ERROR_INVALID_DATA; - goto out; -@@ -5027,8 +5035,8 @@ static UINT rdpdr_server_smartcard_end_transaction(RdpdrServerContext* context, - goto out; - } - -- result = smartcard_irp_device_control_encode_request(s, &op); -- if (result != SCARD_S_SUCCESS) -+ const LONG rc = smartcard_irp_device_control_encode_request(s, &op); -+ if (rc != SCARD_S_SUCCESS) - { - result = ERROR_INTERNAL_ERROR; - goto out; -@@ -5073,8 +5081,8 @@ static UINT rdpdr_server_smartcard_status_callback(RdpdrServerContext* context, - goto out; - } - -- result = smartcard_irp_device_control_decode_response(s, irp->IoControlCode, &op); -- if (result != SCARD_S_SUCCESS) -+ const LONG rc = smartcard_irp_device_control_decode_response(s, irp->IoControlCode, &op); -+ if (rc != SCARD_S_SUCCESS) - { - result = ERROR_INVALID_DATA; - goto out; -@@ -5132,8 +5140,8 @@ static UINT rdpdr_server_smartcard_status(RdpdrServerContext* context, void* cal - goto out; - } - -- result = smartcard_irp_device_control_encode_request(s, &op); -- if (result != SCARD_S_SUCCESS) -+ const LONG rc = smartcard_irp_device_control_encode_request(s, &op); -+ if (rc != SCARD_S_SUCCESS) - { - result = ERROR_INTERNAL_ERROR; - goto out; -@@ -5192,8 +5200,8 @@ static UINT rdpdr_server_smartcard_transmit_callback(RdpdrServerContext* context - goto out; - } - -- result = smartcard_irp_device_control_decode_response(s, irp->IoControlCode, &op); -- if (result != SCARD_S_SUCCESS) -+ const LONG rc = smartcard_irp_device_control_decode_response(s, irp->IoControlCode, &op); -+ if (rc != SCARD_S_SUCCESS) - { - result = ERROR_INVALID_DATA; - goto out; -@@ -5244,8 +5252,8 @@ static UINT rdpdr_server_smartcard_transmit(RdpdrServerContext* context, void* c - goto out; - } - -- result = smartcard_irp_device_control_encode_request(s, &op); -- if (result != SCARD_S_SUCCESS) -+ const LONG rc = smartcard_irp_device_control_encode_request(s, &op); -+ if (rc != SCARD_S_SUCCESS) - { - result = ERROR_INTERNAL_ERROR; - goto out; -@@ -5290,8 +5298,8 @@ static UINT rdpdr_server_smartcard_control_callback(RdpdrServerContext* context, - goto out; - } - -- result = smartcard_irp_device_control_decode_response(s, irp->IoControlCode, &op); -- if (result != SCARD_S_SUCCESS) -+ const LONG rc = smartcard_irp_device_control_decode_response(s, irp->IoControlCode, &op); -+ if (rc != SCARD_S_SUCCESS) - { - result = ERROR_INVALID_DATA; - goto out; -@@ -5350,8 +5358,8 @@ static UINT rdpdr_server_smartcard_control(RdpdrServerContext* context, void* ca - goto out; - } - -- result = smartcard_irp_device_control_encode_request(s, &op); -- if (result != SCARD_S_SUCCESS) -+ const LONG rc = smartcard_irp_device_control_encode_request(s, &op); -+ if (rc != SCARD_S_SUCCESS) - { - result = ERROR_INTERNAL_ERROR; - goto out; -@@ -5396,8 +5404,8 @@ static UINT rdpdr_server_smartcard_get_attrib_callback(RdpdrServerContext* conte - goto out; - } - -- result = smartcard_irp_device_control_decode_response(s, irp->IoControlCode, &op); -- if (result != SCARD_S_SUCCESS) -+ const LONG rc = smartcard_irp_device_control_decode_response(s, irp->IoControlCode, &op); -+ if (rc != SCARD_S_SUCCESS) - { - result = ERROR_INVALID_DATA; - goto out; -@@ -5413,8 +5421,8 @@ static UINT rdpdr_server_smartcard_get_attrib_callback(RdpdrServerContext* conte - return result; - } - --UINT rdpdr_server_smartcard_get_attrib(RdpdrServerContext* context, void* callbackData, -- const GetAttrib_Call* call, UINT32* completionId) -+static UINT rdpdr_server_smartcard_get_attrib(RdpdrServerContext* context, void* callbackData, -+ const GetAttrib_Call* call, UINT32* completionId) - { - WINPR_ASSERT(context); - WINPR_ASSERT(context->priv); -@@ -5488,8 +5496,8 @@ static UINT rdpdr_server_smartcard_set_attrib_callback(RdpdrServerContext* conte - goto out; - } - -- result = smartcard_irp_device_control_decode_response(s, irp->IoControlCode, &op); -- if (result != SCARD_S_SUCCESS) -+ const LONG rc = smartcard_irp_device_control_decode_response(s, irp->IoControlCode, &op); -+ if (rc != SCARD_S_SUCCESS) - { - result = ERROR_INVALID_DATA; - goto out; -@@ -5545,8 +5553,8 @@ static UINT rdpdr_server_smartcard_set_attrib(RdpdrServerContext* context, void* - goto out; - } - -- result = smartcard_irp_device_control_encode_request(s, &op); -- if (result != SCARD_S_SUCCESS) -+ const LONG rc = smartcard_irp_device_control_encode_request(s, &op); -+ if (rc != SCARD_S_SUCCESS) - { - result = ERROR_INTERNAL_ERROR; - goto out; - -From 0cf276e1716ba1febd60761f0ab54b02b610e143 Mon Sep 17 00:00:00 2001 -From: Armin Novak -Date: Tue, 30 Jun 2026 08:49:08 +0200 -Subject: [PATCH 24/31] [utils,smartcard] add missing entries in - smartcard_operation_free - ---- - libfreerdp/utils/smartcard_operations.c | 12 ++++++++++++ - 1 file changed, 12 insertions(+) - -diff --git a/libfreerdp/utils/smartcard_operations.c b/libfreerdp/utils/smartcard_operations.c -index a38e0d102487..a92f7222dd7b 100644 ---- a/libfreerdp/utils/smartcard_operations.c -+++ b/libfreerdp/utils/smartcard_operations.c -@@ -1733,6 +1733,18 @@ void smartcard_operation_free(SMARTCARD_OPERATION* op, BOOL allocated) - free(ret->pioRecvPci); - } - break; -+ case SCARD_IOCTL_CONTROL: -+ { -+ Control_Return* call = &op->ret.control; -+ free(call->pvOutBuffer); -+ } -+ break; -+ case SCARD_IOCTL_GETATTRIB: -+ { -+ GetAttrib_Return* ret = &op->ret.getAttrib; -+ free(ret->pbAttr); -+ } -+ break; - default: - break; - } - -From 5793486ae671b43d5b99fc23dfb82a121b7eb9e6 Mon Sep 17 00:00:00 2001 -From: Armin Novak -Date: Tue, 30 Jun 2026 09:04:21 +0200 -Subject: [PATCH 25/31] [server,rdpdr] update doxygen - ---- - include/freerdp/server/rdpdr.h | 207 ++++++++++++++++++++++----------- - 1 file changed, 140 insertions(+), 67 deletions(-) - -diff --git a/include/freerdp/server/rdpdr.h b/include/freerdp/server/rdpdr.h -index 9fb1515e1a4e..a9b38a0dd9ba 100644 ---- a/include/freerdp/server/rdpdr.h -+++ b/include/freerdp/server/rdpdr.h -@@ -359,106 +359,179 @@ extern "C" - - rdpContext* rdpcontext; /**< RDP context */ - -- /*** New Smartcard APIs called by the server. ***/ -+ /*** New Smartcard APIs called by the server. -+ * @since version 3.28.0 -+ */ - WINPR_ATTR_NODISCARD psRdpdrSmartcardEstablishContext -- SmartcardEstablishContext; /**< Send SCardEstablishContext to the client. */ -+ SmartcardEstablishContext; /**< Send SCardEstablishContext to the client. -+ * @since version 3.28.0 -+ */ - WINPR_ATTR_NODISCARD psRdpdrSmartcardReleaseContext -- SmartcardReleaseContext; /**< Send SCardReleaseContext to the client. */ -+ SmartcardReleaseContext; /**< Send SCardReleaseContext to the client. -+ * @since version 3.28.0 -+ */ - WINPR_ATTR_NODISCARD psRdpdrSmartcardIsValidContext -- SmartcardIsValidContext; /**< Send SCardIsValidContext to the client. */ -+ SmartcardIsValidContext; /**< Send SCardIsValidContext to the client. -+ * @since version 3.28.0 -+ */ - WINPR_ATTR_NODISCARD psRdpdrSmartcardListReaderGroups -- SmartcardListReaderGroupsA; /**< Send SCardListReaderGroupsA to the client. */ -+ SmartcardListReaderGroupsA; /**< Send SCardListReaderGroupsA to the client. -+ * @since version 3.28.0 -+ */ - WINPR_ATTR_NODISCARD psRdpdrSmartcardListReaderGroups -- SmartcardListReaderGroupsW; /**< Send SCardListReaderGroupsW to the client. */ -+ SmartcardListReaderGroupsW; /**< Send SCardListReaderGroupsW to the client. -+ * @since version 3.28.0 -+ */ - WINPR_ATTR_NODISCARD psRdpdrSmartcardListReaders -- SmartcardListReadersA; /**< Send SCardListReadersA to the client. */ -+ SmartcardListReadersA; /**< Send SCardListReadersA to the client. -+ * @since version 3.28.0 -+ */ - WINPR_ATTR_NODISCARD psRdpdrSmartcardListReaders -- SmartcardListReadersW; /**< Send SCardListReadersW to the client. */ -+ SmartcardListReadersW; /**< Send SCardListReadersW to the client. -+ * @since version 3.28.0 -+ */ - WINPR_ATTR_NODISCARD psRdpdrSmartcardGetStatusChangeA -- SmartcardGetStatusChangeA; /**< Send SCardGetStatusChangeA to the client. */ -+ SmartcardGetStatusChangeA; /**< Send SCardGetStatusChangeA to the client. -+ * @since version 3.28.0 -+ */ - WINPR_ATTR_NODISCARD psRdpdrSmartcardGetStatusChangeW -- SmartcardGetStatusChangeW; /**< Send SCardGetStatusChangeW to the client. */ -+ SmartcardGetStatusChangeW; /**< Send SCardGetStatusChangeW to the client. -+ * @since version 3.28.0 -+ */ - WINPR_ATTR_NODISCARD psRdpdrSmartcardCancel -- SmartcardCancel; /**< Send SCardCancel to the client. */ -+ SmartcardCancel; /**< Send SCardCancel to the client. -+ * @since version 3.28.0 -+ */ - WINPR_ATTR_NODISCARD psRdpdrSmartcardConnectA -- SmartcardConnectA; /**< Send SCardConnectA to the client. */ -+ SmartcardConnectA; /**< Send SCardConnectA to the client. -+ * @since version 3.28.0 -+ */ - WINPR_ATTR_NODISCARD psRdpdrSmartcardConnectW -- SmartcardConnectW; /**< Send SCardConnectW to the client. */ -+ SmartcardConnectW; /**< Send SCardConnectW to the client. -+ * @since version 3.28.0 -+ */ - WINPR_ATTR_NODISCARD psRdpdrSmartcardReconnect -- SmartcardReconnect; /**< Send SCardReconnect to the client. */ -+ SmartcardReconnect; /**< Send SCardReconnect to the client. -+ * @since version 3.28.0 -+ */ - WINPR_ATTR_NODISCARD psRdpdrSmartcardDisconnect -- SmartcardDisconnect; /**< Send SCardDisconnect to the client. */ -+ SmartcardDisconnect; /**< Send SCardDisconnect to the client. -+ * @since version 3.28.0 -+ */ - WINPR_ATTR_NODISCARD psRdpdrSmartcardBeginTransaction -- SmartcardBeginTransaction; /**< Send SCardBeginTransaction to the client. */ -+ SmartcardBeginTransaction; /**< Send SCardBeginTransaction to the client. -+ * @since version 3.28.0 -+ */ - WINPR_ATTR_NODISCARD psRdpdrSmartcardEndTransaction -- SmartcardEndTransaction; /**< Send SCardEndTransaction to the client. */ -+ SmartcardEndTransaction; /**< Send SCardEndTransaction to the client. -+ * @since version 3.28.0 -+ */ - WINPR_ATTR_NODISCARD psRdpdrSmartcardStatus -- SmartcardStatusA; /**< Send SCardStatusA to the client. */ -+ SmartcardStatusA; /**< Send SCardStatusA to the client. -+ * @since version 3.28.0 -+ */ - WINPR_ATTR_NODISCARD psRdpdrSmartcardStatus -- SmartcardStatusW; /**< Send SCardStatusW to the client. */ -+ SmartcardStatusW; /**< Send SCardStatusW to the client. -+ * @since version 3.28.0 -+ */ - WINPR_ATTR_NODISCARD psRdpdrSmartcardTransmit -- SmartcardTransmit; /**< Send SCardTransmit to the client. */ -+ SmartcardTransmit; /**< Send SCardTransmit to the client. -+ * @since version 3.28.0 -+ */ - WINPR_ATTR_NODISCARD psRdpdrSmartcardControl -- SmartcardControl; /**< Send SCardControl to the client. */ -+ SmartcardControl; /**< Send SCardControl to the client. -+ * @since version 3.28.0 -+ */ - WINPR_ATTR_NODISCARD psRdpdrSmartcardGetAttrib -- SmartcardGetAttrib; /**< Send SCardGetAttrib to the client. */ -+ SmartcardGetAttrib; /**< Send SCardGetAttrib to the client. -+ * @since version 3.28.0 -+ */ - WINPR_ATTR_NODISCARD psRdpdrSmartcardSetAttrib -- SmartcardSetAttrib; /**< Send SCardSetAttrib to the client. */ -+ SmartcardSetAttrib; /**< Send SCardSetAttrib to the client. -+ * @since version 3.28.0 -+ */ - - /*** New Smartcard callbacks registered by the server. ***/ -- /* clang-format off */ - psRdpdrOnSmartcardEstablishContextComplete -- OnSmartcardEstablishContextComplete; /**< Completion callback for -- SmartcardEstablishContext. */ -+ OnSmartcardEstablishContextComplete; /**< -+ * Completion callback for -+ * SmartcardEstablishContext. -+ * @since version 3.28.0 -+ */ - psRdpdrOnSmartcardReleaseContextComplete -- OnSmartcardReleaseContextComplete; /**< Completion callback for -- SmartcardReleaseContext. */ -+ OnSmartcardReleaseContextComplete; /**< Completion -+ * callback for SmartcardReleaseContext. -+ * @since version 3.28.0 -+ */ - psRdpdrOnSmartcardIsValidContextComplete -- OnSmartcardIsValidContextComplete; /**< Completion callback for -- SmartcardIsValidContext. */ -+ OnSmartcardIsValidContextComplete; /**< Completion -+ * callback for SmartcardIsValidContext. -+ * @since version 3.28.0 -+ */ - psRdpdrOnSmartcardListReaderGroupsComplete -- OnSmartcardListReaderGroupsComplete; /**< Completion callback for -- SmartcardListReaderGroups. */ -+ OnSmartcardListReaderGroupsComplete; /**< -+ * Completion callback for -+ * SmartcardListReaderGroups. -+ * @since version 3.28.0 -+ */ - psRdpdrOnSmartcardListReadersComplete -- OnSmartcardListReadersComplete; /**< Completion callback for -- SmartcardListReaders. */ -+ OnSmartcardListReadersComplete; /**< Completion -+ * callback for SmartcardListReaders. -+ * @since version 3.28.0 -+ */ - psRdpdrOnSmartcardGetStatusChangeComplete -- OnSmartcardGetStatusChangeComplete; /**< Completion callback for -- SmartcardGetStatusChange. */ -- psRdpdrOnSmartcardCancelComplete -- OnSmartcardCancelComplete; /**< Completion callback for -- SmartcardCancel. */ -- psRdpdrOnSmartcardConnectComplete -- OnSmartcardConnectComplete; /**< Completion callback for -- SmartcardConnect. */ -- psRdpdrOnSmartcardReconnectComplete -- OnSmartcardReconnectComplete; /**< Completion callback for -- SmartcardReconnect. */ -+ OnSmartcardGetStatusChangeComplete; /**< -+ * Completion callback for SmartcardGetStatusChange. -+ * @since version 3.28.0 -+ */ -+ psRdpdrOnSmartcardCancelComplete OnSmartcardCancelComplete; /**< Completion callback for -+ * SmartcardCancel. -+ * @since version 3.28.0 -+ */ -+ psRdpdrOnSmartcardConnectComplete OnSmartcardConnectComplete; /**< Completion callback for -+ * SmartcardConnect. -+ * @since version 3.28.0 -+ */ -+ psRdpdrOnSmartcardReconnectComplete OnSmartcardReconnectComplete; /**< Completion callback -+ * for SmartcardReconnect. -+ * @since version 3.28.0 -+ */ - psRdpdrOnSmartcardDisconnectComplete -- OnSmartcardDisconnectComplete; /**< Completion callback for -- SmartcardDisconnect. */ -+ OnSmartcardDisconnectComplete; /**< Completion callback -+ * for SmartcardDisconnect. -+ * @since version 3.28.0 -+ */ - psRdpdrOnSmartcardBeginTransactionComplete -- OnSmartcardBeginTransactionComplete; /**< Completion callback for -- SmartcardBeginTransaction. */ -+ OnSmartcardBeginTransactionComplete; /**< -+ * Completion callback for -+ * SmartcardBeginTransaction. -+ * @since version 3.28.0 -+ */ - psRdpdrOnSmartcardEndTransactionComplete -- OnSmartcardEndTransactionComplete; /**< Completion callback for -- SmartcardEndTransaction. */ -- psRdpdrOnSmartcardStatusComplete -- OnSmartcardStatusComplete; /**< Completion callback for -- SmartcardStatus. */ -- psRdpdrOnSmartcardTransmitComplete -- OnSmartcardTransmitComplete; /**< Completion callback for -- SmartcardTransmit. */ -- psRdpdrOnSmartcardControlComplete -- OnSmartcardControlComplete; /**< Completion callback for -- SmartcardControl. */ -- psRdpdrOnSmartcardGetAttribComplete -- OnSmartcardGetAttribComplete; /**< Completion callback for -- SmartcardGetAttrib. */ -- psRdpdrOnSmartcardSetAttribComplete -- OnSmartcardSetAttribComplete; /**< Completion callback for -- SmartcardSetAttrib. */ -- /* clang-format on */ -+ OnSmartcardEndTransactionComplete; /**< Completion -+ * callback for SmartcardEndTransaction. -+ * @since version 3.28.0 -+ */ -+ psRdpdrOnSmartcardStatusComplete OnSmartcardStatusComplete; /**< Completion callback for -+ * SmartcardStatus. -+ * @since version 3.28.0 -+ */ -+ psRdpdrOnSmartcardTransmitComplete OnSmartcardTransmitComplete; /**< Completion callback for -+ * SmartcardTransmit. -+ * @since version 3.28.0 -+ */ -+ psRdpdrOnSmartcardControlComplete OnSmartcardControlComplete; /**< Completion callback for -+ * SmartcardControl. -+ * @since version 3.28.0 -+ */ -+ psRdpdrOnSmartcardGetAttribComplete OnSmartcardGetAttribComplete; /**< Completion callback -+ * for SmartcardGetAttrib. -+ * @since version 3.28.0 -+ */ -+ psRdpdrOnSmartcardSetAttribComplete OnSmartcardSetAttribComplete; /**< Completion callback -+ * for SmartcardSetAttrib. -+ * @since version 3.28.0 -+ */ - }; - - /** - -From 8cb4b9ca8e80c3a8d50a9f5ef9ef3248bccc37fc Mon Sep 17 00:00:00 2001 -From: Armin Novak -Date: Tue, 30 Jun 2026 09:06:32 +0200 -Subject: [PATCH 26/31] [utils,test] replace NULL with nullptr - ---- - libfreerdp/utils/smartcard_pack.c | 4 +- - .../utils/test/TestSmartcardOperations.c | 42 +++++++++---------- - 2 files changed, 23 insertions(+), 23 deletions(-) - -diff --git a/libfreerdp/utils/smartcard_pack.c b/libfreerdp/utils/smartcard_pack.c -index 5aa54590f4fc..a10974f75bfb 100644 ---- a/libfreerdp/utils/smartcard_pack.c -+++ b/libfreerdp/utils/smartcard_pack.c -@@ -4672,7 +4672,7 @@ LONG smartcard_pack_transmit_call(wStream* s, const Transmit_Call* call) - return status; - - UINT32 cbExtraBytes = 0; -- const BYTE* pbExtraBytes = NULL; -+ const BYTE* pbExtraBytes = nullptr; - if (call->pioSendPci) - { - cbExtraBytes = (UINT32)(call->pioSendPci->cbPciLength - sizeof(SCARD_IO_REQUEST)); -@@ -4825,7 +4825,7 @@ LONG smartcard_unpack_get_status_change_return(wStream* s, GetStatusChange_Retur - return status; - } - else -- ret->rgReaderStates = NULL; -+ ret->rgReaderStates = nullptr; - - smartcard_trace_get_status_change_return(log, ret, unicode); - return SCARD_S_SUCCESS; -diff --git a/libfreerdp/utils/test/TestSmartcardOperations.c b/libfreerdp/utils/test/TestSmartcardOperations.c -index 4c885b13359c..590d9cc6fb93 100644 ---- a/libfreerdp/utils/test/TestSmartcardOperations.c -+++ b/libfreerdp/utils/test/TestSmartcardOperations.c -@@ -44,12 +44,12 @@ static wStream* build_device_control_request(UINT32 ioControlCode, const void* i - const char* name = scard_get_ioctl_string(ioControlCode, TRUE); - const size_t totalLength = RDPDR_DEVICE_IO_CONTROL_REQ_HDR_LENGTH + inputBufferLength; - -- wStream* s = Stream_New(NULL, totalLength); -+ wStream* s = Stream_New(nullptr, totalLength); - if (!s) - { - (void)fprintf(stderr, "build_device_control_request(%s): Stream_New(%" PRIuz ") failed\n", - name, totalLength); -- return NULL; -+ return nullptr; - } - - UINT32 inputLength = WINPR_ASSERTING_INT_CAST(UINT32, inputBufferLength); -@@ -67,7 +67,7 @@ static wStream* build_device_control_request(UINT32 ioControlCode, const void* i - (void)fprintf(stderr, "build_device_control_request(%s): Stream_SetPosition failed\n", - name); - Stream_Release(s); -- return NULL; -+ return nullptr; - } - - return s; -@@ -78,7 +78,7 @@ static BOOL test_request_roundtrip(const SMARTCARD_OPERATION* opIn, SMARTCARD_OP - const UINT32 ioControlCode = opIn->ioControlCode; - const char* name = scard_get_ioctl_string(ioControlCode, TRUE); - -- wStream* sEnc = Stream_New(NULL, 4096); -+ wStream* sEnc = Stream_New(nullptr, 4096); - if (!sEnc) - { - (void)fprintf(stderr, "%s: Stream_New for encode failed\n", name); -@@ -361,7 +361,7 @@ static BOOL test_connect_w_encode_decode_request(void) - fill_redir_context(&opIn.call.connectW.Common.handles.hContext, 0x1234); - opIn.call.connectW.Common.dwShareMode = SCARD_SHARE_SHARED; - opIn.call.connectW.Common.dwPreferredProtocols = SCARD_PROTOCOL_T0; -- opIn.call.connectW.szReader = ConvertUtf8ToWCharAlloc("TestReader", NULL); -+ opIn.call.connectW.szReader = ConvertUtf8ToWCharAlloc("TestReader", nullptr); - - if (!test_request_roundtrip(&opIn, &opOut)) - goto out; -@@ -559,8 +559,8 @@ static BOOL test_transmit_encode_decode_request(void) - - success = TRUE; - out: -- opIn.call.transmit.pioSendPci = NULL; -- opIn.call.transmit.pbSendBuffer = NULL; -+ opIn.call.transmit.pioSendPci = nullptr; -+ opIn.call.transmit.pbSendBuffer = nullptr; - smartcard_operation_free(&opIn, FALSE); - smartcard_operation_free(&opOut, FALSE); - return success; -@@ -604,7 +604,7 @@ static BOOL test_control_encode_decode_request(void) - - success = TRUE; - out: -- opIn.call.control.pvInBuffer = NULL; -+ opIn.call.control.pvInBuffer = nullptr; - smartcard_operation_free(&opIn, FALSE); - smartcard_operation_free(&opOut, FALSE); - return success; -@@ -677,7 +677,7 @@ static BOOL test_set_attrib_encode_decode_request(void) - - success = TRUE; - out: -- opIn.call.setAttrib.pbAttr = NULL; -+ opIn.call.setAttrib.pbAttr = nullptr; - smartcard_operation_free(&opIn, FALSE); - smartcard_operation_free(&opOut, FALSE); - return success; -@@ -787,7 +787,7 @@ static wStream* build_device_control_response(UINT32 ioControlCode, const SMARTC - if (!payload) - { - (void)fprintf(stderr, "%s: Stream_New for payload failed\n", name); -- return NULL; -+ return nullptr; - } - - LONG rc = encode_response_payload(payload, ioControlCode, opIn); -@@ -796,7 +796,7 @@ static wStream* build_device_control_response(UINT32 ioControlCode, const SMARTC - (void)fprintf(stderr, "%s: encode_response_payload failed with 0x%08" PRIX32 "\n", name, - (UINT32)rc); - Stream_Release(payload); -- return NULL; -+ return nullptr; - } - Stream_SealLength(payload); - -@@ -805,7 +805,7 @@ static wStream* build_device_control_response(UINT32 ioControlCode, const SMARTC - { - (void)fprintf(stderr, "%s: Stream_New for response failed\n", name); - Stream_Release(payload); -- return NULL; -+ return nullptr; - } - - Stream_Seek(s, 4); /* Placeholder for outputBufferLength */ -@@ -838,7 +838,7 @@ static wStream* build_device_control_response(UINT32 ioControlCode, const SMARTC - { - (void)fprintf(stderr, "%s: Stream_SetPosition failed\n", name); - Stream_Release(s); -- return NULL; -+ return nullptr; - } - return s; - } -@@ -957,7 +957,7 @@ static BOOL test_list_reader_groups_decode_response_impl(UINT32 ioControlCode) - - success = TRUE; - out: -- opIn.ret.listReaders.msz = NULL; -+ opIn.ret.listReaders.msz = nullptr; - smartcard_operation_free(&opIn, FALSE); - smartcard_operation_free(&opOut, FALSE); - return success; -@@ -997,7 +997,7 @@ static BOOL test_list_readers_decode_response_impl(UINT32 ioControlCode) - - success = TRUE; - out: -- opIn.ret.listReaders.msz = NULL; -+ opIn.ret.listReaders.msz = nullptr; - smartcard_operation_free(&opIn, FALSE); - smartcard_operation_free(&opOut, FALSE); - return success; -@@ -1051,7 +1051,7 @@ static BOOL test_get_status_change_decode_response_impl(UINT32 ioControlCode) - - success = TRUE; - out: -- opIn.ret.getStatusChange.rgReaderStates = NULL; -+ opIn.ret.getStatusChange.rgReaderStates = nullptr; - smartcard_operation_free(&opIn, FALSE); - smartcard_operation_free(&opOut, FALSE); - return success; -@@ -1251,7 +1251,7 @@ static BOOL test_status_decode_response_impl(UINT32 ioControlCode) - - success = TRUE; - out: -- opIn.ret.status.mszReaderNames = NULL; -+ opIn.ret.status.mszReaderNames = nullptr; - smartcard_operation_free(&opIn, FALSE); - smartcard_operation_free(&opOut, FALSE); - return success; -@@ -1277,7 +1277,7 @@ static BOOL test_transmit_decode_response(void) - BYTE recvBuf[] = { 0x90, 0x00 }; - opIn.ret.transmit.cbRecvLength = sizeof(recvBuf); - opIn.ret.transmit.pbRecvBuffer = recvBuf; -- opIn.ret.transmit.pioRecvPci = NULL; -+ opIn.ret.transmit.pioRecvPci = nullptr; - - if (!test_response_roundtrip(&opIn, &opOut)) - goto out; -@@ -1292,7 +1292,7 @@ static BOOL test_transmit_decode_response(void) - - success = TRUE; - out: -- opIn.ret.transmit.pbRecvBuffer = NULL; -+ opIn.ret.transmit.pbRecvBuffer = nullptr; - smartcard_operation_free(&opIn, FALSE); - smartcard_operation_free(&opOut, FALSE); - return success; -@@ -1322,7 +1322,7 @@ static BOOL test_control_decode_response(void) - - success = TRUE; - out: -- opIn.ret.control.pvOutBuffer = NULL; -+ opIn.ret.control.pvOutBuffer = nullptr; - smartcard_operation_free(&opIn, FALSE); - smartcard_operation_free(&opOut, FALSE); - return success; -@@ -1352,7 +1352,7 @@ static BOOL test_get_attrib_decode_response(void) - - success = TRUE; - out: -- opIn.ret.getAttrib.pbAttr = NULL; -+ opIn.ret.getAttrib.pbAttr = nullptr; - smartcard_operation_free(&opIn, FALSE); - smartcard_operation_free(&opOut, FALSE); - return success; - -From 5562dec703fc1873ee23e272691872087aeb3158 Mon Sep 17 00:00:00 2001 -From: Armin Novak -Date: Tue, 30 Jun 2026 09:08:01 +0200 -Subject: [PATCH 27/31] [utils,smartcard] make declaration parameters - consistent - ---- - libfreerdp/utils/smartcard_pack.c | 10 +++++----- - 1 file changed, 5 insertions(+), 5 deletions(-) - -diff --git a/libfreerdp/utils/smartcard_pack.c b/libfreerdp/utils/smartcard_pack.c -index a10974f75bfb..a035fcab94d7 100644 ---- a/libfreerdp/utils/smartcard_pack.c -+++ b/libfreerdp/utils/smartcard_pack.c -@@ -4256,12 +4256,12 @@ LONG smartcard_pack_get_reader_icon_return(wStream* s, const GetReaderIcon_Retur - return ret->ReturnCode; - } - --LONG smartcard_pack_get_transmit_count_return(wStream* s, const GetTransmitCount_Return* call) -+LONG smartcard_pack_get_transmit_count_return(wStream* s, const GetTransmitCount_Return* ret) - { -- WINPR_ASSERT(call); -+ WINPR_ASSERT(ret); - wLog* log = scard_log(); - -- smartcard_trace_get_transmit_count_return(log, call); -+ smartcard_trace_get_transmit_count_return(log, ret); - - if (!Stream_EnsureRemainingCapacity(s, 4)) - { -@@ -4269,9 +4269,9 @@ LONG smartcard_pack_get_transmit_count_return(wStream* s, const GetTransmitCount - return SCARD_F_INTERNAL_ERROR; - } - -- Stream_Write_UINT32(s, call->cTransmitCount); /* cBytes (4 cbDataLen) */ -+ Stream_Write_UINT32(s, ret->cTransmitCount); /* cBytes (4 cbDataLen) */ - -- return call->ReturnCode; -+ return ret->ReturnCode; - } - - LONG smartcard_pack_read_cache_return(wStream* s, const ReadCache_Return* ret) - -From c974edcac03ae90b82e6b177cf0875ff10b97a81 Mon Sep 17 00:00:00 2001 -From: Armin Novak -Date: Tue, 30 Jun 2026 09:10:28 +0200 -Subject: [PATCH 28/31] [channel,rdpdr] remove manual code formatting - ---- - channels/rdpdr/server/rdpdr_main.c | 184 +++++++++++------------------ - 1 file changed, 70 insertions(+), 114 deletions(-) - -diff --git a/channels/rdpdr/server/rdpdr_main.c b/channels/rdpdr/server/rdpdr_main.c -index f5565dcdeb2c..f04acffdaafd 100644 ---- a/channels/rdpdr/server/rdpdr_main.c -+++ b/channels/rdpdr/server/rdpdr_main.c -@@ -4117,16 +4117,12 @@ static UINT rdpdr_server_smartcard_list_reader_groups(RdpdrServerContext* contex - - *completionId = irp->CompletionId; - -- /* clang-format off */ -- const SMARTCARD_OPERATION op = { -- .ioControlCode = ioControlCode, -- .call.listReaderGroups = { -- .handles.hContext = call->handles.hContext, -- .fmszGroupsIsNULL = call->fmszGroupsIsNULL, -- .cchGroups = call->cchGroups, -- } -- }; -- /* clang-format on */ -+ const SMARTCARD_OPERATION op = { .ioControlCode = ioControlCode, -+ .call.listReaderGroups = { -+ .handles.hContext = call->handles.hContext, -+ .fmszGroupsIsNULL = call->fmszGroupsIsNULL, -+ .cchGroups = call->cchGroups, -+ } }; - - s = Stream_New(nullptr, 32); - if (!s) -@@ -4238,18 +4234,14 @@ static UINT rdpdr_server_smartcard_list_readers(RdpdrServerContext* context, voi - - *completionId = irp->CompletionId; - -- /* clang-format off */ -- const SMARTCARD_OPERATION op = { -- .ioControlCode = ioControlCode, -- .call.listReaders = { -- .handles.hContext = call->handles.hContext, -- .cBytes = call->cBytes, -- .mszGroups = call->mszGroups, -- .fmszReadersIsNULL = call->fmszReadersIsNULL, -- .cchReaders = call->cchReaders, -- } -- }; -- /* clang-format on */ -+ const SMARTCARD_OPERATION op = { .ioControlCode = ioControlCode, -+ .call.listReaders = { -+ .handles.hContext = call->handles.hContext, -+ .cBytes = call->cBytes, -+ .mszGroups = call->mszGroups, -+ .fmszReadersIsNULL = call->fmszReadersIsNULL, -+ .cchReaders = call->cchReaders, -+ } }; - - s = Stream_New(nullptr, 256); - if (!s) -@@ -4702,18 +4694,14 @@ static UINT rdpdr_server_smartcard_reconnect(RdpdrServerContext* context, void* - - *completionId = irp->CompletionId; - -- /* clang-format off */ -- const SMARTCARD_OPERATION op = { -- .ioControlCode = SCARD_IOCTL_RECONNECT, -- .call.reconnect = { -- .handles.hContext = call->handles.hContext, -- .handles.hCard = call->handles.hCard, -- .dwShareMode = call->dwShareMode, -- .dwPreferredProtocols = call->dwPreferredProtocols, -- .dwInitialization = call->dwInitialization, -- } -- }; -- /* clang-format on */ -+ const SMARTCARD_OPERATION op = { .ioControlCode = SCARD_IOCTL_RECONNECT, -+ .call.reconnect = { -+ .handles.hContext = call->handles.hContext, -+ .handles.hCard = call->handles.hCard, -+ .dwShareMode = call->dwShareMode, -+ .dwPreferredProtocols = call->dwPreferredProtocols, -+ .dwInitialization = call->dwInitialization, -+ } }; - - s = Stream_New(nullptr, 128); - if (!s) -@@ -4806,16 +4794,12 @@ static UINT rdpdr_server_smartcard_disconnect(RdpdrServerContext* context, void* - - *completionId = irp->CompletionId; - -- /* clang-format off */ -- const SMARTCARD_OPERATION op = { -- .ioControlCode = SCARD_IOCTL_DISCONNECT, -- .call.hCardAndDisposition = { -- .handles.hContext = call->handles.hContext, -- .handles.hCard = call->handles.hCard, -- .dwDisposition = call->dwDisposition, -- } -- }; -- /* clang-format on */ -+ const SMARTCARD_OPERATION op = { .ioControlCode = SCARD_IOCTL_DISCONNECT, -+ .call.hCardAndDisposition = { -+ .handles.hContext = call->handles.hContext, -+ .handles.hCard = call->handles.hCard, -+ .dwDisposition = call->dwDisposition, -+ } }; - - s = Stream_New(nullptr, 128); - if (!s) -@@ -4912,16 +4896,12 @@ static UINT rdpdr_server_smartcard_begin_transaction(RdpdrServerContext* context - - *completionId = irp->CompletionId; - -- /* clang-format off */ -- const SMARTCARD_OPERATION op = { -- .ioControlCode = SCARD_IOCTL_BEGINTRANSACTION, -- .call.hCardAndDisposition = { -- .handles.hContext = call->handles.hContext, -- .handles.hCard = call->handles.hCard, -- .dwDisposition = SCARD_LEAVE_CARD, -- } -- }; -- /* clang-format on */ -+ const SMARTCARD_OPERATION op = { .ioControlCode = SCARD_IOCTL_BEGINTRANSACTION, -+ .call.hCardAndDisposition = { -+ .handles.hContext = call->handles.hContext, -+ .handles.hCard = call->handles.hCard, -+ .dwDisposition = SCARD_LEAVE_CARD, -+ } }; - - s = Stream_New(nullptr, 128); - if (!s) -@@ -5016,16 +4996,12 @@ static UINT rdpdr_server_smartcard_end_transaction(RdpdrServerContext* context, - - *completionId = irp->CompletionId; - -- /* clang-format off */ -- const SMARTCARD_OPERATION op = { -- .ioControlCode = SCARD_IOCTL_ENDTRANSACTION, -- .call.hCardAndDisposition = { -- .handles.hContext = call->handles.hContext, -- .handles.hCard = call->handles.hCard, -- .dwDisposition = call->dwDisposition, -- } -- }; -- /* clang-format on */ -+ const SMARTCARD_OPERATION op = { .ioControlCode = SCARD_IOCTL_ENDTRANSACTION, -+ .call.hCardAndDisposition = { -+ .handles.hContext = call->handles.hContext, -+ .handles.hCard = call->handles.hCard, -+ .dwDisposition = call->dwDisposition, -+ } }; - - s = Stream_New(nullptr, 128); - if (!s) -@@ -5119,18 +5095,14 @@ static UINT rdpdr_server_smartcard_status(RdpdrServerContext* context, void* cal - - *completionId = irp->CompletionId; - -- /* clang-format off */ -- const SMARTCARD_OPERATION op = { -- .ioControlCode = ioControlCode, -- .call.status = { -- .handles.hContext = call->handles.hContext, -- .handles.hCard = call->handles.hCard, -- .fmszReaderNamesIsNULL = call->fmszReaderNamesIsNULL, -- .cchReaderLen = call->cchReaderLen, -- .cbAtrLen = call->cbAtrLen, -- } -- }; -- /* clang-format on */ -+ const SMARTCARD_OPERATION op = { .ioControlCode = ioControlCode, -+ .call.status = { -+ .handles.hContext = call->handles.hContext, -+ .handles.hCard = call->handles.hCard, -+ .fmszReaderNamesIsNULL = call->fmszReaderNamesIsNULL, -+ .cchReaderLen = call->cchReaderLen, -+ .cbAtrLen = call->cbAtrLen, -+ } }; - - s = Stream_New(nullptr, 128); - if (!s) -@@ -5237,12 +5209,8 @@ static UINT rdpdr_server_smartcard_transmit(RdpdrServerContext* context, void* c - - *completionId = irp->CompletionId; - -- /* clang-format off */ -- const SMARTCARD_OPERATION op = { -- .ioControlCode = SCARD_IOCTL_TRANSMIT, -- .call.transmit = *call -- }; -- /* clang-format on */ -+ const SMARTCARD_OPERATION op = { .ioControlCode = SCARD_IOCTL_TRANSMIT, -+ .call.transmit = *call }; - - s = Stream_New(nullptr, 512 + call->cbSendLength); - if (!s) -@@ -5335,20 +5303,16 @@ static UINT rdpdr_server_smartcard_control(RdpdrServerContext* context, void* ca - - *completionId = irp->CompletionId; - -- /* clang-format off */ -- const SMARTCARD_OPERATION op = { -- .ioControlCode = SCARD_IOCTL_CONTROL, -- .call.control = { -- .handles.hContext = call->handles.hContext, -- .handles.hCard = call->handles.hCard, -- .dwControlCode = call->dwControlCode, -- .cbInBufferSize = call->cbInBufferSize, -- .pvInBuffer = call->pvInBuffer, -- .fpvOutBufferIsNULL = call->fpvOutBufferIsNULL, -- .cbOutBufferSize = call->cbOutBufferSize, -- } -- }; -- /* clang-format on */ -+ const SMARTCARD_OPERATION op = { .ioControlCode = SCARD_IOCTL_CONTROL, -+ .call.control = { -+ .handles.hContext = call->handles.hContext, -+ .handles.hCard = call->handles.hCard, -+ .dwControlCode = call->dwControlCode, -+ .cbInBufferSize = call->cbInBufferSize, -+ .pvInBuffer = call->pvInBuffer, -+ .fpvOutBufferIsNULL = call->fpvOutBufferIsNULL, -+ .cbOutBufferSize = call->cbOutBufferSize, -+ } }; - - s = Stream_New(nullptr, 512 + call->cbOutBufferSize); - if (!s) -@@ -5440,12 +5404,8 @@ static UINT rdpdr_server_smartcard_get_attrib(RdpdrServerContext* context, void* - - *completionId = irp->CompletionId; - -- /* clang-format off */ -- const SMARTCARD_OPERATION op = { -- .ioControlCode = SCARD_IOCTL_GETATTRIB, -- .call.getAttrib = *call -- }; -- /* clang-format on */ -+ const SMARTCARD_OPERATION op = { .ioControlCode = SCARD_IOCTL_GETATTRIB, -+ .call.getAttrib = *call }; - - wStream* s = Stream_New(nullptr, 64); - if (!s) -@@ -5532,18 +5492,14 @@ static UINT rdpdr_server_smartcard_set_attrib(RdpdrServerContext* context, void* - - *completionId = irp->CompletionId; - -- /* clang-format off */ -- const SMARTCARD_OPERATION op = { -- .ioControlCode = SCARD_IOCTL_SETATTRIB, -- .call.setAttrib = { -- .handles.hContext = call->handles.hContext, -- .handles.hCard = call->handles.hCard, -- .dwAttrId = call->dwAttrId, -- .cbAttrLen = call->cbAttrLen, -- .pbAttr = call->pbAttr, -- } -- }; -- /* clang-format on */ -+ const SMARTCARD_OPERATION op = { .ioControlCode = SCARD_IOCTL_SETATTRIB, -+ .call.setAttrib = { -+ .handles.hContext = call->handles.hContext, -+ .handles.hCard = call->handles.hCard, -+ .dwAttrId = call->dwAttrId, -+ .cbAttrLen = call->cbAttrLen, -+ .pbAttr = call->pbAttr, -+ } }; - - s = Stream_New(nullptr, 64 + call->cbAttrLen); - if (!s) - -From 05fd708bec929581bea630a9d2cb877bdbadb86a Mon Sep 17 00:00:00 2001 -From: Armin Novak -Date: Tue, 30 Jun 2026 09:19:58 +0200 -Subject: [PATCH 29/31] [channels,rdpdr] silence false clang-analyzer warning - -rdpdr_server_discard_request does free up IRP so the -clang-analyzer-unix.Malloc is a false positive and misleading. ---- - channels/rdpdr/server/rdpdr_main.c | 35 ++++++++++++++++++++++++++++-- - 1 file changed, 33 insertions(+), 2 deletions(-) - -diff --git a/channels/rdpdr/server/rdpdr_main.c b/channels/rdpdr/server/rdpdr_main.c -index f04acffdaafd..7588e15d1fc1 100644 ---- a/channels/rdpdr/server/rdpdr_main.c -+++ b/channels/rdpdr/server/rdpdr_main.c -@@ -3845,8 +3845,10 @@ static UINT rdpdr_server_smartcard_establish_context(RdpdrServerContext* context - SCARD_IOCTL_MAX_OUTPUT_BUFFER_LENGTH, Stream_Buffer(s), Stream_Length(s)); - - out: -+ // NOLINTBEGIN(clang-analyzer-unix.Malloc): IRP is removed from context and freed there - if (result != CHANNEL_RC_OK && irp) - rdpdr_server_discard_request(context, irp->CompletionId); -+ // NOLINTEND(clang-analyzer-unix.Malloc): IRP is removed from context and freed there - if (s) - Stream_Release(s); - return result; -@@ -3943,8 +3945,10 @@ static UINT rdpdr_server_smartcard_release_context(RdpdrServerContext* context, - SCARD_IOCTL_MAX_OUTPUT_BUFFER_LENGTH, Stream_Buffer(s), Stream_Length(s)); - - out: -+ // NOLINTBEGIN(clang-analyzer-unix.Malloc): IRP is removed from context and freed there - if (result != CHANNEL_RC_OK && irp) - rdpdr_server_discard_request(context, irp->CompletionId); -+ // NOLINTEND(clang-analyzer-unix.Malloc): IRP is removed from context and freed there - if (s) - Stream_Release(s); - return result; -@@ -4042,8 +4046,10 @@ static UINT rdpdr_server_smartcard_is_valid_context(RdpdrServerContext* context, - SCARD_IOCTL_MAX_OUTPUT_BUFFER_LENGTH, Stream_Buffer(s), Stream_Length(s)); - - out: -+ // NOLINTBEGIN(clang-analyzer-unix.Malloc): IRP is removed from context and freed there - if (result != CHANNEL_RC_OK && irp) - rdpdr_server_discard_request(context, irp->CompletionId); -+ // NOLINTEND(clang-analyzer-unix.Malloc): IRP is removed from context and freed there - if (s) - Stream_Release(s); - return result; -@@ -4144,8 +4150,10 @@ static UINT rdpdr_server_smartcard_list_reader_groups(RdpdrServerContext* contex - SCARD_IOCTL_MAX_OUTPUT_BUFFER_LENGTH, Stream_Buffer(s), Stream_Length(s)); - - out: -+ // NOLINTBEGIN(clang-analyzer-unix.Malloc): IRP is removed from context and freed there - if (result != CHANNEL_RC_OK && irp) - rdpdr_server_discard_request(context, irp->CompletionId); -+ // NOLINTEND(clang-analyzer-unix.Malloc): IRP is removed from context and freed there - if (s) - Stream_Release(s); - return result; -@@ -4263,8 +4271,10 @@ static UINT rdpdr_server_smartcard_list_readers(RdpdrServerContext* context, voi - SCARD_IOCTL_MAX_OUTPUT_BUFFER_LENGTH, Stream_Buffer(s), Stream_Length(s)); - - out: -+ // NOLINTBEGIN(clang-analyzer-unix.Malloc): IRP is removed from context and freed there - if (result != CHANNEL_RC_OK && irp) - rdpdr_server_discard_request(context, irp->CompletionId); -+ // NOLINTEND(clang-analyzer-unix.Malloc): IRP is removed from context and freed there - if (s) - Stream_Release(s); - return result; -@@ -4388,8 +4398,10 @@ static UINT rdpdr_server_smartcard_get_status_change(RdpdrServerContext* context - SCARD_IOCTL_MAX_OUTPUT_BUFFER_LENGTH, Stream_Buffer(s), Stream_Length(s)); - - out: -+ // NOLINTBEGIN(clang-analyzer-unix.Malloc): IRP is removed from context and freed there - if (result != CHANNEL_RC_OK && irp) - rdpdr_server_discard_request(context, irp->CompletionId); -+ // NOLINTEND(clang-analyzer-unix.Malloc): IRP is removed from context and freed there - if (s) - Stream_Release(s); - return result; -@@ -4501,8 +4513,10 @@ static UINT rdpdr_server_smartcard_cancel(RdpdrServerContext* context, void* cal - SCARD_IOCTL_MAX_OUTPUT_BUFFER_LENGTH, Stream_Buffer(s), Stream_Length(s)); - - out: -+ // NOLINTBEGIN(clang-analyzer-unix.Malloc): IRP is removed from context and freed there - if (result != CHANNEL_RC_OK && irp) - rdpdr_server_discard_request(context, irp->CompletionId); -+ // NOLINTEND(clang-analyzer-unix.Malloc): IRP is removed from context and freed there - if (s) - Stream_Release(s); - return result; -@@ -4609,8 +4623,10 @@ static UINT rdpdr_server_smartcard_connect(RdpdrServerContext* context, void* ca - SCARD_IOCTL_MAX_OUTPUT_BUFFER_LENGTH, Stream_Buffer(s), Stream_Length(s)); - - out: -+ // NOLINTBEGIN(clang-analyzer-unix.Malloc): IRP is removed from context and freed there - if (result != CHANNEL_RC_OK && irp) - rdpdr_server_discard_request(context, irp->CompletionId); -+ // NOLINTEND(clang-analyzer-unix.Malloc): IRP is removed from context and freed there - if (s) - Stream_Release(s); - return result; -@@ -4723,8 +4739,10 @@ static UINT rdpdr_server_smartcard_reconnect(RdpdrServerContext* context, void* - SCARD_IOCTL_MAX_OUTPUT_BUFFER_LENGTH, Stream_Buffer(s), Stream_Length(s)); - - out: -+ // NOLINTBEGIN(clang-analyzer-unix.Malloc): IRP is removed from context and freed there - if (result != CHANNEL_RC_OK && irp) - rdpdr_server_discard_request(context, irp->CompletionId); -+ // NOLINTEND(clang-analyzer-unix.Malloc): IRP is removed from context and freed there - if (s) - Stream_Release(s); - return result; -@@ -4821,8 +4839,10 @@ static UINT rdpdr_server_smartcard_disconnect(RdpdrServerContext* context, void* - SCARD_IOCTL_MAX_OUTPUT_BUFFER_LENGTH, Stream_Buffer(s), Stream_Length(s)); - - out: -+ // NOLINTBEGIN(clang-analyzer-unix.Malloc): IRP is removed from context and freed there - if (result != CHANNEL_RC_OK && irp) - rdpdr_server_discard_request(context, irp->CompletionId); -+ // NOLINTEND(clang-analyzer-unix.Malloc): IRP is removed from context and freed there - if (s) - Stream_Release(s); - return result; -@@ -4923,8 +4943,10 @@ static UINT rdpdr_server_smartcard_begin_transaction(RdpdrServerContext* context - SCARD_IOCTL_MAX_OUTPUT_BUFFER_LENGTH, Stream_Buffer(s), Stream_Length(s)); - - out: -+ // NOLINTBEGIN(clang-analyzer-unix.Malloc): IRP is removed from context and freed there - if (result != CHANNEL_RC_OK && irp) - rdpdr_server_discard_request(context, irp->CompletionId); -+ // NOLINTEND(clang-analyzer-unix.Malloc): IRP is removed from context and freed there - if (s) - Stream_Release(s); - return result; -@@ -5023,8 +5045,10 @@ static UINT rdpdr_server_smartcard_end_transaction(RdpdrServerContext* context, - SCARD_IOCTL_MAX_OUTPUT_BUFFER_LENGTH, Stream_Buffer(s), Stream_Length(s)); - - out: -+ // NOLINTBEGIN(clang-analyzer-unix.Malloc): IRP is removed from context and freed there - if (result != CHANNEL_RC_OK && irp) - rdpdr_server_discard_request(context, irp->CompletionId); -+ // NOLINTEND(clang-analyzer-unix.Malloc): IRP is removed from context and freed there - if (s) - Stream_Release(s); - return result; -@@ -5124,8 +5148,10 @@ static UINT rdpdr_server_smartcard_status(RdpdrServerContext* context, void* cal - SCARD_IOCTL_MAX_OUTPUT_BUFFER_LENGTH, Stream_Buffer(s), Stream_Length(s)); - - out: -+ // NOLINTBEGIN(clang-analyzer-unix.Malloc): IRP is removed from context and freed there - if (result != CHANNEL_RC_OK && irp) - rdpdr_server_discard_request(context, irp->CompletionId); -+ // NOLINTEND(clang-analyzer-unix.Malloc): IRP is removed from context and freed there - if (s) - Stream_Release(s); - return result; -@@ -5232,8 +5258,10 @@ static UINT rdpdr_server_smartcard_transmit(RdpdrServerContext* context, void* c - SCARD_IOCTL_MAX_OUTPUT_BUFFER_LENGTH, Stream_Buffer(s), Stream_Length(s)); - - out: -+ // NOLINTBEGIN(clang-analyzer-unix.Malloc): IRP is removed from context and freed there - if (result != CHANNEL_RC_OK && irp) - rdpdr_server_discard_request(context, irp->CompletionId); -+ // NOLINTEND(clang-analyzer-unix.Malloc): IRP is removed from context and freed there - if (s) - Stream_Release(s); - return result; -@@ -5334,8 +5362,10 @@ static UINT rdpdr_server_smartcard_control(RdpdrServerContext* context, void* ca - SCARD_IOCTL_MAX_OUTPUT_BUFFER_LENGTH, Stream_Buffer(s), Stream_Length(s)); - - out: -+ // NOLINTBEGIN(clang-analyzer-unix.Malloc): IRP is removed from context and freed there - if (result != CHANNEL_RC_OK && irp) - rdpdr_server_discard_request(context, irp->CompletionId); -+ // NOLINTEND(clang-analyzer-unix.Malloc): IRP is removed from context and freed there - if (s) - Stream_Release(s); - return result; -@@ -5483,7 +5513,6 @@ static UINT rdpdr_server_smartcard_set_attrib(RdpdrServerContext* context, void* - UINT result = CHANNEL_RC_OK; - RdpdrServerPrivate* priv = context->priv; - RDPDR_IRP* irp = nullptr; -- wStream* s = nullptr; - - result = prepare_smartcard_irp(context, SCARD_IOCTL_SETATTRIB, - rdpdr_server_smartcard_set_attrib_callback, callbackData, &irp); -@@ -5501,7 +5530,7 @@ static UINT rdpdr_server_smartcard_set_attrib(RdpdrServerContext* context, void* - .pbAttr = call->pbAttr, - } }; - -- s = Stream_New(nullptr, 64 + call->cbAttrLen); -+ wStream* s = Stream_New(nullptr, 64 + call->cbAttrLen); - if (!s) - { - WLog_Print(priv->log, WLOG_ERROR, "Stream_New failed!"); -@@ -5521,8 +5550,10 @@ static UINT rdpdr_server_smartcard_set_attrib(RdpdrServerContext* context, void* - SCARD_IOCTL_MAX_OUTPUT_BUFFER_LENGTH, Stream_Buffer(s), Stream_Length(s)); - - out: -+ // NOLINTBEGIN(clang-analyzer-unix.Malloc): IRP is removed from context and freed there - if (result != CHANNEL_RC_OK && irp) - rdpdr_server_discard_request(context, irp->CompletionId); -+ // NOLINTEND(clang-analyzer-unix.Malloc): IRP is removed from context and freed there - if (s) - Stream_Release(s); - return result; - -From e8704c1e11605d902ba077c187fab768e250c04b Mon Sep 17 00:00:00 2001 -From: Armin Novak -Date: Tue, 30 Jun 2026 09:34:30 +0200 -Subject: [PATCH 30/31] [channels,rdpdr] fix clang-analyzer-unix.Malloc - -* Fix false positives with annotations -* Fix actual leaks ---- - channels/rdpdr/server/rdpdr_main.c | 23 +++++++++++++++++------ - 1 file changed, 17 insertions(+), 6 deletions(-) - -diff --git a/channels/rdpdr/server/rdpdr_main.c b/channels/rdpdr/server/rdpdr_main.c -index 7588e15d1fc1..ae230dc1a3d5 100644 ---- a/channels/rdpdr/server/rdpdr_main.c -+++ b/channels/rdpdr/server/rdpdr_main.c -@@ -3352,8 +3352,10 @@ static UINT rdpdr_server_drive_write_file(RdpdrServerContext* context, void* cal - irp->FileId = fileId; - - /* Send a request to open the directory. */ -+ // NOLINTBEGIN(clang-analyzer-unix.Malloc): IRP is removed from context and freed there - return rdpdr_server_send_device_write_request(context, irp->DeviceId, irp->FileId, - irp->CompletionId, buffer, length, offset); -+ // NOLINTEND(clang-analyzer-unix.Malloc): IRP is removed from context and freed there - } - - /************************************************* -@@ -3414,8 +3416,10 @@ static UINT rdpdr_server_drive_close_file(RdpdrServerContext* context, void* cal - irp->FileId = fileId; - - /* Send a request to open the directory. */ -+ // NOLINTBEGIN(clang-analyzer-unix.Malloc): IRP is removed from context and freed there - return rdpdr_server_send_device_close_request(context, irp->DeviceId, irp->FileId, - irp->CompletionId); -+ // NOLINTEND(clang-analyzer-unix.Malloc): IRP is removed from context and freed there - } - - /************************************************* -@@ -5426,7 +5430,7 @@ static UINT rdpdr_server_smartcard_get_attrib(RdpdrServerContext* context, void* - RdpdrServerPrivate* priv = context->priv; - - RDPDR_IRP* irp = nullptr; -- UINT ret = -+ const UINT ret = - prepare_smartcard_irp(context, SCARD_IOCTL_GETATTRIB, - rdpdr_server_smartcard_get_attrib_callback, callbackData, &irp); - if (ret != CHANNEL_RC_OK) -@@ -5437,25 +5441,32 @@ static UINT rdpdr_server_smartcard_get_attrib(RdpdrServerContext* context, void* - const SMARTCARD_OPERATION op = { .ioControlCode = SCARD_IOCTL_GETATTRIB, - .call.getAttrib = *call }; - -+ UINT error = CHANNEL_RC_NO_MEMORY; - wStream* s = Stream_New(nullptr, 64); - if (!s) - { - WLog_Print(priv->log, WLOG_ERROR, "Stream_New failed!"); -- return CHANNEL_RC_NO_MEMORY; -+ goto out; - } - - LONG status = smartcard_irp_device_control_encode_request(s, &op); - if (status != SCARD_S_SUCCESS) - { -- Stream_Release(s); -- return ERROR_INTERNAL_ERROR; -+ error = ERROR_INTERNAL_ERROR; -+ goto out; - } - -- const UINT error = rdpdr_server_send_device_control_request( -+ error = rdpdr_server_send_device_control_request( - context, irp->DeviceId, irp->CompletionId, irp->IoControlCode, - SCARD_IOCTL_MAX_OUTPUT_BUFFER_LENGTH, Stream_Buffer(s), Stream_Length(s)); - -- Stream_Release(s); -+out: -+ // NOLINTBEGIN(clang-analyzer-unix.Malloc): IRP is removed from context and freed there -+ if (error != CHANNEL_RC_OK && irp) -+ rdpdr_server_discard_request(context, irp->CompletionId); -+ // NOLINTEND(clang-analyzer-unix.Malloc): IRP is removed from context and freed there -+ if (s) -+ Stream_Release(s); - return error; - } - - -From 07bee6f35bc236cbe99e9240aa4c8ac2d923b68a Mon Sep 17 00:00:00 2001 -From: Armin Novak -Date: Tue, 30 Jun 2026 09:35:36 +0200 -Subject: [PATCH 31/31] [utils,test] replace NULL with nullptr - ---- - libfreerdp/utils/test/TestSmartcardOperations.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/libfreerdp/utils/test/TestSmartcardOperations.c b/libfreerdp/utils/test/TestSmartcardOperations.c -index 590d9cc6fb93..19969df9794e 100644 ---- a/libfreerdp/utils/test/TestSmartcardOperations.c -+++ b/libfreerdp/utils/test/TestSmartcardOperations.c -@@ -783,7 +783,7 @@ static wStream* build_device_control_response(UINT32 ioControlCode, const SMARTC - { - const char* name = scard_get_ioctl_string(ioControlCode, TRUE); - -- wStream* payload = Stream_New(NULL, 4096); -+ wStream* payload = Stream_New(nullptr, 4096); - if (!payload) - { - (void)fprintf(stderr, "%s: Stream_New for payload failed\n", name); -@@ -800,7 +800,7 @@ static wStream* build_device_control_response(UINT32 ioControlCode, const SMARTC - } - Stream_SealLength(payload); - -- wStream* s = Stream_New(NULL, 256 + Stream_Length(payload)); -+ wStream* s = Stream_New(nullptr, 256 + Stream_Length(payload)); - if (!s) - { - (void)fprintf(stderr, "%s: Stream_New for response failed\n", name); diff --git a/utils-pdu-tracker-clean-up-warnings-fix-poll-return.patch b/utils-pdu-tracker-clean-up-warnings-fix-poll-return.patch deleted file mode 100644 index e8f9e2e..0000000 --- a/utils-pdu-tracker-clean-up-warnings-fix-poll-return.patch +++ /dev/null @@ -1,156 +0,0 @@ -From 1a15128e93705d5680c84b9e6368245d247fe893 Mon Sep 17 00:00:00 2001 -From: Armin Novak -Date: Mon, 29 Jun 2026 10:23:37 +0200 -Subject: [PATCH] [utils,pdu-tracker] clean up warnings, fix poll return - ---- - libfreerdp/utils/channel_pdu_tracker.c | 87 +++++++++++++++----------- - 1 file changed, 52 insertions(+), 35 deletions(-) - -diff --git a/libfreerdp/utils/channel_pdu_tracker.c b/libfreerdp/utils/channel_pdu_tracker.c -index 18e9aab..2b46a98 100644 ---- a/libfreerdp/utils/channel_pdu_tracker.c -+++ b/libfreerdp/utils/channel_pdu_tracker.c -@@ -21,16 +21,18 @@ - - #include - -+#include -+#define TTAG FREERDP_TAG("utils.ChannelPduTracker") -+ - struct ChannelPduTracker - { - HANDLE vc; - wStream* currentPacket; -- BYTE buffer[CHANNEL_PDU_LENGTH]; -- BYTE* writePtr; -+ char buffer[CHANNEL_PDU_LENGTH]; -+ size_t offset; -+ wLog* log; - }; - --#define TAG "ChannelPduTracker" -- - wStream* ChannelPduTracker_poll(ChannelPduTracker* tracker, BOOL* ok) - { - WINPR_ASSERT(tracker); -@@ -38,58 +40,70 @@ wStream* ChannelPduTracker_poll(ChannelPduTracker* tracker, BOOL* ok) - - ULONG sz = 0; - *ok = FALSE; -- const ULONG readSz = -- WINPR_ASSERTING_INT_CAST(ULONG, CHANNEL_PDU_LENGTH - (tracker->writePtr - tracker->buffer)); -- if (!WTSVirtualChannelRead(tracker->vc, INFINITE, (char*)tracker->writePtr, readSz, &sz)) -+ -+ WINPR_ASSERT(tracker->offset <= CHANNEL_PDU_LENGTH); -+ const ULONG readSz = WINPR_ASSERTING_INT_CAST(ULONG, CHANNEL_PDU_LENGTH - tracker->offset); -+ if (!WTSVirtualChannelRead(tracker->vc, INFINITE, &tracker->buffer[tracker->offset], readSz, -+ &sz)) - return nullptr; - -- tracker->writePtr += sz; -- const size_t recvSz = (tracker->writePtr - tracker->buffer); -+ tracker->offset += sz; -+ WINPR_ASSERT(tracker->offset <= CHANNEL_PDU_LENGTH); -+ -+ const size_t recvSz = tracker->offset; - if (recvSz < sizeof(CHANNEL_PDU_HEADER)) - { - *ok = TRUE; - return nullptr; - } - -- CHANNEL_PDU_HEADER* header = (CHANNEL_PDU_HEADER*)tracker->buffer; -+ const CHANNEL_PDU_HEADER* header = (const CHANNEL_PDU_HEADER*)tracker->buffer; - if (header->length > CHANNEL_CHUNK_LENGTH) - { -- WLog_ERR(TAG, "chunk size %" PRIu32 " is too big", header->length); -+ WLog_Print(tracker->log, WLOG_ERROR, "chunk size %" PRIu32 " is too big", header->length); - return nullptr; - } - -- if (recvSz - sizeof(CHANNEL_PDU_HEADER) < header->length) -+ const size_t actual = recvSz - sizeof(CHANNEL_PDU_HEADER); -+ if (actual != header->length) - { -- WLog_ERR(TAG, "chunk size %" PRIu32 " is too big", header->length); -+ WLog_Print(tracker->log, WLOG_ERROR, -+ "Expected chunk size %" PRIu32 " does not match received data size %" PRIuz, -+ header->length, actual); - return nullptr; - } - -- tracker->writePtr = tracker->buffer; -- if (header->flags & CHANNEL_FLAG_FIRST) -+ tracker->offset = 0; -+ if ((header->flags & CHANNEL_FLAG_FIRST) != 0) - Stream_ResetPosition(tracker->currentPacket); - -- if (!Stream_EnsureRemainingCapacity(tracker->currentPacket, header->length)) -+ if (!Stream_CheckAndLogRequiredCapacityWLog(tracker->log, tracker->currentPacket, -+ header->length)) - return nullptr; - -- Stream_Write(tracker->currentPacket, header + 1, header->length); -+ Stream_Write(tracker->currentPacket, &tracker->buffer[sizeof(CHANNEL_PDU_HEADER)], -+ header->length); - -- if (header->flags & CHANNEL_FLAG_LAST) -+ if ((header->flags & CHANNEL_FLAG_LAST) == 0) - { -- Stream_SealLength(tracker->currentPacket); -- Stream_ResetPosition(tracker->currentPacket); -- wStream* ret = tracker->currentPacket; -- -- tracker->currentPacket = Stream_New(nullptr, 4096); -- if (!tracker->currentPacket) -- { -- Stream_Release(ret); -- WLog_ERR(TAG, "error allocating new currentPacket"); -- return nullptr; -- } -+ *ok = TRUE; -+ return nullptr; -+ } -+ -+ Stream_SealLength(tracker->currentPacket); -+ Stream_ResetPosition(tracker->currentPacket); -+ wStream* ret = tracker->currentPacket; -+ -+ tracker->currentPacket = Stream_New(nullptr, 4096); -+ if (!tracker->currentPacket) -+ { -+ Stream_Release(ret); -+ WLog_Print(tracker->log, WLOG_ERROR, "error allocating new currentPacket"); -+ return nullptr; - } - - *ok = TRUE; -- return nullptr; -+ return ret; - } - - void ChannelPduTracker_free(ChannelPduTracker* tracker) -@@ -109,11 +123,14 @@ ChannelPduTracker* ChannelPduTracker_new(HANDLE vc) - - ret->currentPacket = Stream_New(nullptr, 4096); - if (!ret->currentPacket) -- { -- free(ret); -- return nullptr; -- } -+ goto fail; -+ - ret->vc = vc; -- ret->writePtr = ret->buffer; -+ ret->log = WLog_Get(TTAG); -+ if (!ret->log) -+ goto fail; - return ret; -+fail: -+ ChannelPduTracker_free(ret); -+ return nullptr; - } --- -2.54.0 - diff --git a/utils-pdu-tracker-increase-capacity-for-fragmented-P.patch b/utils-pdu-tracker-increase-capacity-for-fragmented-P.patch deleted file mode 100644 index cc20885..0000000 --- a/utils-pdu-tracker-increase-capacity-for-fragmented-P.patch +++ /dev/null @@ -1,26 +0,0 @@ -From a41855e88ea37b92a4d506430bce4b09e76f7d76 Mon Sep 17 00:00:00 2001 -From: Armin Novak -Date: Mon, 29 Jun 2026 15:50:18 +0200 -Subject: [PATCH] [utils,pdu-tracker] increase capacity for fragmented PDU - ---- - libfreerdp/utils/channel_pdu_tracker.c | 3 +-- - 1 file changed, 1 insertion(+), 2 deletions(-) - -diff --git a/libfreerdp/utils/channel_pdu_tracker.c b/libfreerdp/utils/channel_pdu_tracker.c -index 2b46a98..63c112d 100644 ---- a/libfreerdp/utils/channel_pdu_tracker.c -+++ b/libfreerdp/utils/channel_pdu_tracker.c -@@ -77,8 +77,7 @@ wStream* ChannelPduTracker_poll(ChannelPduTracker* tracker, BOOL* ok) - if ((header->flags & CHANNEL_FLAG_FIRST) != 0) - Stream_ResetPosition(tracker->currentPacket); - -- if (!Stream_CheckAndLogRequiredCapacityWLog(tracker->log, tracker->currentPacket, -- header->length)) -+ if (!Stream_EnsureRemainingCapacity(tracker->currentPacket, header->length)) - return nullptr; - - Stream_Write(tracker->currentPacket, &tracker->buffer[sizeof(CHANNEL_PDU_HEADER)], --- -2.54.0 - diff --git a/utils-scard-fix-endianess-issue.patch b/utils-scard-fix-endianess-issue.patch deleted file mode 100644 index 8534a50..0000000 --- a/utils-scard-fix-endianess-issue.patch +++ /dev/null @@ -1,36 +0,0 @@ -From 2a6d532a1d633145ae48e55ae471f2f2d8e56157 Mon Sep 17 00:00:00 2001 -From: Armin Novak -Date: Fri, 19 Jun 2026 20:15:15 +0200 -Subject: [PATCH] [utils,scard] fix endianess issue - ---- - libfreerdp/utils/smartcard_pack.c | 9 +++++---- - 1 file changed, 5 insertions(+), 4 deletions(-) - -diff --git a/libfreerdp/utils/smartcard_pack.c b/libfreerdp/utils/smartcard_pack.c -index bb977c4..83d1fbd 100644 ---- a/libfreerdp/utils/smartcard_pack.c -+++ b/libfreerdp/utils/smartcard_pack.c -@@ -319,14 +319,15 @@ static LONG smartcard_ndr_read_atrmask(wLog* log, wStream* s, LocateCards_ATRMas - /* [MS-RDPESC] 2.2.1.5: cbAtr is range(0..36), the number of valid bytes in the fixed - * rgbAtr/rgbMask arrays. A larger value walks past them when the mask is compared byte - * by byte, so reject it here rather than trusting the wire value. */ -- const LocateCards_ATRMask* masks = *data; -+ LocateCards_ATRMask* masks = *data; - for (size_t x = 0; x < min; x++) - { -- if (masks[x].cbAtr > ARRAYSIZE(masks[x].rgbAtr)) -+ const UINT32 val = winpr_Data_Get_UINT32(&masks[x].cbAtr); -+ if (val > ARRAYSIZE(masks[x].rgbAtr)) - { - WLog_Print(log, WLOG_ERROR, -- "LocateCards_ATRMask[%" PRIuz "]::cbAtr %" PRIu32 " exceeds %" PRIuz, x, -- masks[x].cbAtr, (size_t)ARRAYSIZE(masks[x].rgbAtr)); -+ "LocateCards_ATRMask[%" PRIuz "]::cbAtr %" PRIu32 " exceeds %" PRIuz, x, val, -+ (size_t)ARRAYSIZE(masks[x].rgbAtr)); - free(*data); - *data = nullptr; - return STATUS_DATA_ERROR; --- -2.54.0 - diff --git a/utils-smartcard-validate-cbAtr-against-rgbAtr-size-o.patch b/utils-smartcard-validate-cbAtr-against-rgbAtr-size-o.patch deleted file mode 100644 index 4c1f40a..0000000 --- a/utils-smartcard-validate-cbAtr-against-rgbAtr-size-o.patch +++ /dev/null @@ -1,189 +0,0 @@ -From ececc5cbd0646ef012ca178322e6ef922a11f0c1 Mon Sep 17 00:00:00 2001 -From: metsw24-max -Date: Fri, 19 Jun 2026 12:32:01 +0530 -Subject: [PATCH] [utils,smartcard] validate cbAtr against rgbAtr size on - unpack - ---- - libfreerdp/utils/smartcard_pack.c | 36 ++++++++- - libfreerdp/utils/test/CMakeLists.txt | 2 +- - libfreerdp/utils/test/TestSmartcardPack.c | 93 +++++++++++++++++++++++ - 3 files changed, 129 insertions(+), 2 deletions(-) - create mode 100644 libfreerdp/utils/test/TestSmartcardPack.c - -diff --git a/libfreerdp/utils/smartcard_pack.c b/libfreerdp/utils/smartcard_pack.c -index d8f9cab..bb977c4 100644 ---- a/libfreerdp/utils/smartcard_pack.c -+++ b/libfreerdp/utils/smartcard_pack.c -@@ -312,7 +312,27 @@ static LONG smartcard_ndr_read_atrmask(wLog* log, wStream* s, LocateCards_ATRMas - BYTE** ppv; - } u; - u.ppc = data; -- return smartcard_ndr_read(log, s, u.ppv, min, sizeof(LocateCards_ATRMask), type); -+ const LONG status = smartcard_ndr_read(log, s, u.ppv, min, sizeof(LocateCards_ATRMask), type); -+ if (status != SCARD_S_SUCCESS) -+ return status; -+ -+ /* [MS-RDPESC] 2.2.1.5: cbAtr is range(0..36), the number of valid bytes in the fixed -+ * rgbAtr/rgbMask arrays. A larger value walks past them when the mask is compared byte -+ * by byte, so reject it here rather than trusting the wire value. */ -+ const LocateCards_ATRMask* masks = *data; -+ for (size_t x = 0; x < min; x++) -+ { -+ if (masks[x].cbAtr > ARRAYSIZE(masks[x].rgbAtr)) -+ { -+ WLog_Print(log, WLOG_ERROR, -+ "LocateCards_ATRMask[%" PRIuz "]::cbAtr %" PRIu32 " exceeds %" PRIuz, x, -+ masks[x].cbAtr, (size_t)ARRAYSIZE(masks[x].rgbAtr)); -+ free(*data); -+ *data = nullptr; -+ return STATUS_DATA_ERROR; -+ } -+ } -+ return SCARD_S_SUCCESS; - } - - static LONG smartcard_ndr_read_fixed_string_a(wLog* log, wStream* s, CHAR** data, size_t min, -@@ -2454,6 +2474,13 @@ static LONG smartcard_unpack_reader_state_a(wLog* log, wStream* s, LPSCARD_READE - Stream_Read_UINT32(s, readerState->dwCurrentState); /* dwCurrentState (4 bytes) */ - Stream_Read_UINT32(s, readerState->dwEventState); /* dwEventState (4 bytes) */ - Stream_Read_UINT32(s, readerState->cbAtr); /* cbAtr (4 bytes) */ -+ if (readerState->cbAtr > ARRAYSIZE(readerState->rgbAtr)) -+ { -+ WLog_Print(log, WLOG_ERROR, -+ "SCARD_READERSTATEA[%" PRIu32 "]::cbAtr %" PRIu32 " exceeds %" PRIuz, index, -+ readerState->cbAtr, (size_t)ARRAYSIZE(readerState->rgbAtr)); -+ goto fail; -+ } - Stream_Read(s, readerState->rgbAtr, 36); /* rgbAtr [0..36] (36 bytes) */ - } - -@@ -2528,6 +2555,13 @@ static LONG smartcard_unpack_reader_state_w(wLog* log, wStream* s, LPSCARD_READE - Stream_Read_UINT32(s, readerState->dwCurrentState); /* dwCurrentState (4 bytes) */ - Stream_Read_UINT32(s, readerState->dwEventState); /* dwEventState (4 bytes) */ - Stream_Read_UINT32(s, readerState->cbAtr); /* cbAtr (4 bytes) */ -+ if (readerState->cbAtr > ARRAYSIZE(readerState->rgbAtr)) -+ { -+ WLog_Print(log, WLOG_ERROR, -+ "SCARD_READERSTATEW[%" PRIu32 "]::cbAtr %" PRIu32 " exceeds %" PRIuz, index, -+ readerState->cbAtr, (size_t)ARRAYSIZE(readerState->rgbAtr)); -+ goto fail; -+ } - Stream_Read(s, readerState->rgbAtr, 36); /* rgbAtr [0..36] (36 bytes) */ - } - -diff --git a/libfreerdp/utils/test/CMakeLists.txt b/libfreerdp/utils/test/CMakeLists.txt -index b90c5f4..0c2bf84 100644 ---- a/libfreerdp/utils/test/CMakeLists.txt -+++ b/libfreerdp/utils/test/CMakeLists.txt -@@ -5,7 +5,7 @@ disable_warnings_for_directory(${CMAKE_CURRENT_BINARY_DIR}) - - set(${MODULE_PREFIX}_DRIVER ${MODULE_NAME}.c) - --set(${MODULE_PREFIX}_TESTS TestRingBuffer.c TestPodArrays.c TestEncodedTypes.c) -+set(${MODULE_PREFIX}_TESTS TestRingBuffer.c TestPodArrays.c TestEncodedTypes.c TestSmartcardPack.c) - - create_test_sourcelist(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_DRIVER} ${${MODULE_PREFIX}_TESTS}) - -diff --git a/libfreerdp/utils/test/TestSmartcardPack.c b/libfreerdp/utils/test/TestSmartcardPack.c -new file mode 100644 -index 0000000..8c04600 ---- /dev/null -+++ b/libfreerdp/utils/test/TestSmartcardPack.c -@@ -0,0 +1,93 @@ -+/** -+ * FreeRDP: A Remote Desktop Protocol Implementation -+ * -+ * Licensed under the Apache License, Version 2.0 (the "License"); -+ * you may not use this file except in compliance with the License. -+ * You may obtain a copy of the License at -+ * -+ * http://www.apache.org/licenses/LICENSE-2.0 -+ * -+ * Unless required by applicable law or agreed to in writing, software -+ * distributed under the License is distributed on an "AS IS" BASIS, -+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -+ * See the License for the specific language governing permissions and -+ * limitations under the License. -+ */ -+ -+#include -+#include -+ -+#include -+#include -+#include -+ -+/* Build a LocateCardsByATRA call (cbContext=0, cAtrs=1, cReaders=0) holding a single -+ * LocateCards_ATRMask whose cbAtr is set to the requested value. */ -+static wStream* build_locate_cards_by_atr_a(UINT32 cbAtr) -+{ -+ wStream* s = Stream_New(NULL, 24 + 8 + sizeof(LocateCards_ATRMask)); -+ if (!s) -+ return NULL; -+ -+ Stream_Write_UINT32(s, 0); /* cbContext = 0 */ -+ Stream_Write_UINT32(s, 0); /* pbContextNdrPtr = 0 */ -+ Stream_Write_UINT32(s, 1); /* cAtrs = 1 */ -+ Stream_Write_UINT32(s, 0x00020000); /* rgAtrMasksNdrPtr */ -+ Stream_Write_UINT32(s, 0); /* cReaders = 0 */ -+ Stream_Write_UINT32(s, 0); /* rgReaderStatesNdrPtr = 0 */ -+ Stream_Write_UINT32(s, 1); /* conformant count = cAtrs */ -+ Stream_Write_UINT32(s, cbAtr); /* LocateCards_ATRMask::cbAtr */ -+ Stream_Zero(s, 36); /* rgbAtr[36] */ -+ Stream_Zero(s, 36); /* rgbMask[36] */ -+ -+ Stream_SealLength(s); -+ if (!Stream_SetPosition(s, 0)) -+ { -+ Stream_Free(s, TRUE); -+ return NULL; -+ } -+ return s; -+} -+ -+static BOOL run_case(UINT32 cbAtr, BOOL expectAccept) -+{ -+ wStream* s = build_locate_cards_by_atr_a(cbAtr); -+ if (!s) -+ return FALSE; -+ -+ LocateCardsByATRA_Call call = { 0 }; -+ const LONG status = smartcard_unpack_locate_cards_by_atr_a_call(s, &call); -+ Stream_Free(s, TRUE); -+ -+ const BOOL accepted = (status == SCARD_S_SUCCESS) ? TRUE : FALSE; -+ if (accepted != expectAccept) -+ { -+ printf("cbAtr=%" PRIu32 ": expected %s, unpack returned 0x%08" PRIX32 "\n", cbAtr, -+ expectAccept ? "accept" : "reject", (UINT32)status); -+ free(call.rgAtrMasks); -+ return FALSE; -+ } -+ -+ free(call.rgAtrMasks); -+ return TRUE; -+} -+ -+int TestSmartcardPack(int argc, char* argv[]) -+{ -+ WINPR_UNUSED(argc); -+ WINPR_UNUSED(argv); -+ -+ /* Valid: cbAtr within the fixed 36-byte rgbAtr/rgbMask arrays. */ -+ if (!run_case(0, TRUE)) -+ return -1; -+ if (!run_case(36, TRUE)) -+ return -1; -+ -+ /* Out of range: cbAtr larger than the buffers would later overrun them. */ -+ if (!run_case(37, FALSE)) -+ return -1; -+ if (!run_case(0xFFFFFFFF, FALSE)) -+ return -1; -+ -+ return 0; -+} --- -2.54.0 - diff --git a/utils-test-replace-NULL.patch b/utils-test-replace-NULL.patch deleted file mode 100644 index 0b1ea16..0000000 --- a/utils-test-replace-NULL.patch +++ /dev/null @@ -1,46 +0,0 @@ -From 5cdd46594ec792715a00ecb935dcac7aadde0fc3 Mon Sep 17 00:00:00 2001 -From: Armin Novak -Date: Fri, 19 Jun 2026 20:58:44 +0200 -Subject: [PATCH] [utils,test] replace NULL - ---- - libfreerdp/utils/test/TestSmartcardPack.c | 8 ++++---- - 1 file changed, 4 insertions(+), 4 deletions(-) - -diff --git a/libfreerdp/utils/test/TestSmartcardPack.c b/libfreerdp/utils/test/TestSmartcardPack.c -index 8c04600..4c465f1 100644 ---- a/libfreerdp/utils/test/TestSmartcardPack.c -+++ b/libfreerdp/utils/test/TestSmartcardPack.c -@@ -25,9 +25,9 @@ - * LocateCards_ATRMask whose cbAtr is set to the requested value. */ - static wStream* build_locate_cards_by_atr_a(UINT32 cbAtr) - { -- wStream* s = Stream_New(NULL, 24 + 8 + sizeof(LocateCards_ATRMask)); -+ wStream* s = Stream_New(nullptr, 24 + 8 + sizeof(LocateCards_ATRMask)); - if (!s) -- return NULL; -+ return nullptr; - - Stream_Write_UINT32(s, 0); /* cbContext = 0 */ - Stream_Write_UINT32(s, 0); /* pbContextNdrPtr = 0 */ -@@ -44,7 +44,7 @@ static wStream* build_locate_cards_by_atr_a(UINT32 cbAtr) - if (!Stream_SetPosition(s, 0)) - { - Stream_Free(s, TRUE); -- return NULL; -+ return nullptr; - } - return s; - } -@@ -59,7 +59,7 @@ static BOOL run_case(UINT32 cbAtr, BOOL expectAccept) - const LONG status = smartcard_unpack_locate_cards_by_atr_a_call(s, &call); - Stream_Free(s, TRUE); - -- const BOOL accepted = (status == SCARD_S_SUCCESS) ? TRUE : FALSE; -+ const BOOL accepted = status == SCARD_S_SUCCESS; - if (accepted != expectAccept) - { - printf("cbAtr=%" PRIu32 ": expected %s, unpack returned 0x%08" PRIX32 "\n", cbAtr, --- -2.54.0 -