freerdp/support-rdpdr-device-control-responses.patch
Ondrej Holy b01e0672d5 Add RDP Smart Card Redirection Support
Resolves: RHEL-171999
2026-07-02 10:10:29 +02:00

14827 lines
563 KiB
Diff

From 9088b82c20844abf72d51368a3b14d3e95128937 Mon Sep 17 00:00:00 2001
From: Joan Torres Lopez <joantolo@redhat.com>
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 <joantolo@redhat.com>
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 <joantolo@redhat.com>
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 <joantolo@redhat.com>
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 <joantolo@redhat.com>
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 <joantolo@redhat.com>
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 <noreply@anthropic.com>
---
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 <joantolo@redhat.com>
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 <joantolo@redhat.com>
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 <contact@hardening-consulting.com>
---
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 <joantolo@redhat.com>
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 <joantolo@redhat.com>
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 <contact@hardening-consulting.com>
---
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 <joantolo@redhat.com>
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 <contact@hardening-consulting.com>
---
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 <contact@hardening-consulting.com>
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 <freerdp/settings.h>
#include <freerdp/server/rdpdr.h>
-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 <joantolo@redhat.com>
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 <contact@hardening-consulting.com>
---
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 <joantolo@redhat.com>
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 <contact@hardening-consulting.com>
---
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 <contact@hardening-consulting.com>
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 <joantolo@redhat.com>
---
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 <freerdp/channels/log.h>
#include "rdpdr_main.h"
+#include <freerdp/utils/channel_pdu_tracker.h>
#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 <contact@hardening-consulting.com>
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 <joantolo@redhat.com>
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 <contact@hardening-consulting.com>
---
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 <joantolo@redhat.com>
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 <joantolo@redhat.com>
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 <contact@hardening-consulting.com>
---
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 <joantolo@redhat.com>
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 <joantolo@redhat.com>
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 <contact@hardening-consulting.com>
---
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 <winpr/stream.h>
#include <freerdp/channels/log.h>
+#include <freerdp/channels/scard.h>
+#include <freerdp/utils/smartcard_operations.h>
#include "rdpdr_main.h"
#include <freerdp/utils/channel_pdu_tracker.h>
@@ -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 <freerdp/types.h>
#include <freerdp/channels/wtsvc.h>
#include <freerdp/channels/rdpdr.h>
+#include <freerdp/channels/scard.h>
#include <freerdp/utils/rdpdr_utils.h>
#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 <joantolo@redhat.com>
+ *
+ * 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 <stdio.h>
+
+#include <winpr/crt.h>
+#include <winpr/stream.h>
+#include <winpr/smartcard.h>
+
+#include <freerdp/channels/rdpdr.h>
+#include <freerdp/channels/scard.h>
+#include <freerdp/utils/rdpdr_utils.h>
+#include <freerdp/utils/smartcard_operations.h>
+#include <freerdp/utils/smartcard_pack.h>
+
+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 <joantolo@redhat.com>
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 <armin.novak@thincast.com>
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 <armin.novak@thincast.com>
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 <armin.novak@thincast.com>
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 <armin.novak@thincast.com>
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 <armin.novak@thincast.com>
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 <armin.novak@thincast.com>
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 <armin.novak@thincast.com>
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 <armin.novak@thincast.com>
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 <armin.novak@thincast.com>
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);