summaryrefslogtreecommitdiffstats
path: root/libfreerdp/utils/smartcard_operations.c
diff options
context:
space:
mode:
Diffstat (limited to 'libfreerdp/utils/smartcard_operations.c')
-rw-r--r--libfreerdp/utils/smartcard_operations.c1048
1 files changed, 1048 insertions, 0 deletions
diff --git a/libfreerdp/utils/smartcard_operations.c b/libfreerdp/utils/smartcard_operations.c
new file mode 100644
index 0000000..fd7be82
--- /dev/null
+++ b/libfreerdp/utils/smartcard_operations.c
@@ -0,0 +1,1048 @@
+/**
+ * FreeRDP: A Remote Desktop Protocol Implementation
+ * Smartcard Device Service Virtual Channel
+ *
+ * Copyright (C) Alexi Volkov <alexi@myrealbox.com> 2006
+ * Copyright 2011 O.S. Systems Software Ltda.
+ * Copyright 2011 Anthony Tong <atong@trustedcs.com>
+ * Copyright 2015 Thincast Technologies GmbH
+ * Copyright 2015 DI (FH) Martin Haimberger <martin.haimberger@thincast.com>
+ * Copyright 2017 Armin Novak <armin.novak@thincast.com>
+ * Copyright 2017 Thincast Technologies GmbH
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <freerdp/config.h>
+
+#include <winpr/assert.h>
+
+#include <winpr/crt.h>
+#include <winpr/print.h>
+#include <winpr/stream.h>
+#include <winpr/smartcard.h>
+
+#include <freerdp/freerdp.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>
+
+#include <freerdp/log.h>
+#define TAG FREERDP_TAG("utils.smartcard.ops")
+
+static LONG smartcard_call_to_operation_handle(SMARTCARD_OPERATION* operation)
+{
+ WINPR_ASSERT(operation);
+
+ operation->hContext =
+ smartcard_scard_context_native_from_redir(&(operation->call.handles.hContext));
+ operation->hCard = smartcard_scard_handle_native_from_redir(&(operation->call.handles.hCard));
+
+ return SCARD_S_SUCCESS;
+}
+
+static LONG smartcard_EstablishContext_Decode(wStream* s, SMARTCARD_OPERATION* operation)
+{
+ LONG status = 0;
+
+ WINPR_ASSERT(s);
+ WINPR_ASSERT(operation);
+
+ status = smartcard_unpack_establish_context_call(s, &operation->call.establishContext);
+ if (status != SCARD_S_SUCCESS)
+ {
+ return scard_log_status_error(TAG, "smartcard_unpack_establish_context_call", status);
+ }
+
+ return SCARD_S_SUCCESS;
+}
+
+static LONG smartcard_ReleaseContext_Decode(wStream* s, SMARTCARD_OPERATION* operation)
+{
+ LONG status = 0;
+
+ WINPR_ASSERT(s);
+ WINPR_ASSERT(operation);
+
+ status = smartcard_unpack_context_call(s, &operation->call.context, "ReleaseContext");
+ if (status != SCARD_S_SUCCESS)
+ scard_log_status_error(TAG, "smartcard_unpack_context_call", status);
+
+ return status;
+}
+
+static LONG smartcard_IsValidContext_Decode(wStream* s, SMARTCARD_OPERATION* operation)
+{
+ LONG status = 0;
+
+ WINPR_ASSERT(s);
+ WINPR_ASSERT(operation);
+
+ status = smartcard_unpack_context_call(s, &operation->call.context, "IsValidContext");
+
+ return status;
+}
+
+static LONG smartcard_ListReaderGroupsA_Decode(wStream* s, SMARTCARD_OPERATION* operation)
+{
+ LONG status = 0;
+
+ WINPR_ASSERT(s);
+ WINPR_ASSERT(operation);
+
+ status = smartcard_unpack_list_reader_groups_call(s, &operation->call.listReaderGroups, FALSE);
+
+ return status;
+}
+
+static LONG smartcard_ListReaderGroupsW_Decode(wStream* s, SMARTCARD_OPERATION* operation)
+{
+ LONG status = 0;
+
+ WINPR_ASSERT(s);
+ WINPR_ASSERT(operation);
+
+ status = smartcard_unpack_list_reader_groups_call(s, &operation->call.listReaderGroups, TRUE);
+
+ return status;
+}
+
+static LONG smartcard_ListReadersA_Decode(wStream* s, SMARTCARD_OPERATION* operation)
+{
+ LONG status = 0;
+
+ WINPR_ASSERT(s);
+ WINPR_ASSERT(operation);
+
+ status = smartcard_unpack_list_readers_call(s, &operation->call.listReaders, FALSE);
+
+ return status;
+}
+
+static LONG smartcard_ListReadersW_Decode(wStream* s, SMARTCARD_OPERATION* operation)
+{
+ LONG status = 0;
+
+ WINPR_ASSERT(s);
+ WINPR_ASSERT(operation);
+
+ status = smartcard_unpack_list_readers_call(s, &operation->call.listReaders, TRUE);
+
+ return status;
+}
+
+static LONG smartcard_context_and_two_strings_a_Decode(wStream* s, SMARTCARD_OPERATION* operation)
+{
+ LONG status = 0;
+
+ WINPR_ASSERT(s);
+ WINPR_ASSERT(operation);
+
+ status =
+ smartcard_unpack_context_and_two_strings_a_call(s, &operation->call.contextAndTwoStringA);
+
+ return status;
+}
+
+static LONG smartcard_context_and_two_strings_w_Decode(wStream* s, SMARTCARD_OPERATION* operation)
+{
+ LONG status = 0;
+
+ WINPR_ASSERT(s);
+ WINPR_ASSERT(operation);
+
+ status =
+ smartcard_unpack_context_and_two_strings_w_call(s, &operation->call.contextAndTwoStringW);
+
+ return status;
+}
+
+static LONG smartcard_context_and_string_a_Decode(wStream* s, SMARTCARD_OPERATION* operation)
+{
+ LONG status = 0;
+
+ WINPR_ASSERT(s);
+ WINPR_ASSERT(operation);
+
+ status = smartcard_unpack_context_and_string_a_call(s, &operation->call.contextAndStringA);
+
+ return status;
+}
+
+static LONG smartcard_context_and_string_w_Decode(wStream* s, SMARTCARD_OPERATION* operation)
+{
+ LONG status = 0;
+
+ WINPR_ASSERT(s);
+ WINPR_ASSERT(operation);
+
+ status = smartcard_unpack_context_and_string_w_call(s, &operation->call.contextAndStringW);
+
+ return status;
+}
+
+static LONG smartcard_LocateCardsA_Decode(wStream* s, SMARTCARD_OPERATION* operation)
+{
+ LONG status = 0;
+
+ WINPR_ASSERT(s);
+ WINPR_ASSERT(operation);
+
+ status = smartcard_unpack_locate_cards_a_call(s, &operation->call.locateCardsA);
+
+ return status;
+}
+
+static LONG smartcard_LocateCardsW_Decode(wStream* s, SMARTCARD_OPERATION* operation)
+{
+ LONG status = 0;
+
+ WINPR_ASSERT(s);
+ WINPR_ASSERT(operation);
+
+ status = smartcard_unpack_locate_cards_w_call(s, &operation->call.locateCardsW);
+
+ return status;
+}
+
+static LONG smartcard_GetStatusChangeA_Decode(wStream* s, SMARTCARD_OPERATION* operation)
+{
+ LONG status = 0;
+
+ WINPR_ASSERT(s);
+ WINPR_ASSERT(operation);
+
+ status = smartcard_unpack_get_status_change_a_call(s, &operation->call.getStatusChangeA);
+
+ return status;
+}
+
+static LONG smartcard_GetStatusChangeW_Decode(wStream* s, SMARTCARD_OPERATION* operation)
+{
+ LONG status = 0;
+
+ WINPR_ASSERT(s);
+ WINPR_ASSERT(operation);
+
+ status = smartcard_unpack_get_status_change_w_call(s, &operation->call.getStatusChangeW);
+
+ return status;
+}
+
+static LONG smartcard_Cancel_Decode(wStream* s, SMARTCARD_OPERATION* operation)
+{
+ LONG status = 0;
+
+ WINPR_ASSERT(s);
+ WINPR_ASSERT(operation);
+
+ status = smartcard_unpack_context_call(s, &operation->call.context, "Cancel");
+
+ return status;
+}
+
+static LONG smartcard_ConnectA_Decode(wStream* s, SMARTCARD_OPERATION* operation)
+{
+ LONG status = 0;
+
+ WINPR_ASSERT(s);
+ WINPR_ASSERT(operation);
+
+ status = smartcard_unpack_connect_a_call(s, &operation->call.connectA);
+
+ return status;
+}
+
+static LONG smartcard_ConnectW_Decode(wStream* s, SMARTCARD_OPERATION* operation)
+{
+ LONG status = 0;
+
+ WINPR_ASSERT(s);
+ WINPR_ASSERT(operation);
+
+ status = smartcard_unpack_connect_w_call(s, &operation->call.connectW);
+
+ return status;
+}
+
+static LONG smartcard_Reconnect_Decode(wStream* s, SMARTCARD_OPERATION* operation)
+{
+ LONG status = 0;
+
+ WINPR_ASSERT(s);
+ WINPR_ASSERT(operation);
+
+ status = smartcard_unpack_reconnect_call(s, &operation->call.reconnect);
+
+ return status;
+}
+
+static LONG smartcard_Disconnect_Decode(wStream* s, SMARTCARD_OPERATION* operation)
+{
+ LONG status = 0;
+
+ WINPR_ASSERT(s);
+ WINPR_ASSERT(operation);
+
+ status = smartcard_unpack_hcard_and_disposition_call(s, &operation->call.hCardAndDisposition,
+ "Disconnect");
+
+ return status;
+}
+
+static LONG smartcard_BeginTransaction_Decode(wStream* s, SMARTCARD_OPERATION* operation)
+{
+ LONG status = 0;
+
+ WINPR_ASSERT(s);
+ WINPR_ASSERT(operation);
+
+ status = smartcard_unpack_hcard_and_disposition_call(s, &operation->call.hCardAndDisposition,
+ "BeginTransaction");
+
+ return status;
+}
+
+static LONG smartcard_EndTransaction_Decode(wStream* s, SMARTCARD_OPERATION* operation)
+{
+ LONG status = 0;
+
+ WINPR_ASSERT(s);
+ WINPR_ASSERT(operation);
+
+ status = smartcard_unpack_hcard_and_disposition_call(s, &operation->call.hCardAndDisposition,
+ "EndTransaction");
+
+ return status;
+}
+
+static LONG smartcard_State_Decode(wStream* s, SMARTCARD_OPERATION* operation)
+{
+ LONG status = 0;
+
+ WINPR_ASSERT(s);
+ WINPR_ASSERT(operation);
+
+ status = smartcard_unpack_state_call(s, &operation->call.state);
+
+ return status;
+}
+
+static LONG smartcard_StatusA_Decode(wStream* s, SMARTCARD_OPERATION* operation)
+{
+ LONG status = 0;
+
+ WINPR_ASSERT(s);
+ WINPR_ASSERT(operation);
+
+ status = smartcard_unpack_status_call(s, &operation->call.status, FALSE);
+
+ return status;
+}
+
+static LONG smartcard_StatusW_Decode(wStream* s, SMARTCARD_OPERATION* operation)
+{
+ LONG status = 0;
+
+ WINPR_ASSERT(s);
+ WINPR_ASSERT(operation);
+
+ status = smartcard_unpack_status_call(s, &operation->call.status, TRUE);
+
+ return status;
+}
+
+static LONG smartcard_Transmit_Decode(wStream* s, SMARTCARD_OPERATION* operation)
+{
+ LONG status = 0;
+
+ WINPR_ASSERT(s);
+ WINPR_ASSERT(operation);
+
+ status = smartcard_unpack_transmit_call(s, &operation->call.transmit);
+
+ return status;
+}
+
+static LONG smartcard_Control_Decode(wStream* s, SMARTCARD_OPERATION* operation)
+{
+ LONG status = 0;
+
+ WINPR_ASSERT(s);
+ WINPR_ASSERT(operation);
+
+ status = smartcard_unpack_control_call(s, &operation->call.control);
+
+ return status;
+}
+
+static LONG smartcard_GetAttrib_Decode(wStream* s, SMARTCARD_OPERATION* operation)
+{
+ LONG status = 0;
+
+ WINPR_ASSERT(s);
+ WINPR_ASSERT(operation);
+
+ status = smartcard_unpack_get_attrib_call(s, &operation->call.getAttrib);
+
+ return status;
+}
+
+static LONG smartcard_SetAttrib_Decode(wStream* s, SMARTCARD_OPERATION* operation)
+{
+ LONG status = 0;
+
+ WINPR_ASSERT(s);
+ WINPR_ASSERT(operation);
+
+ status = smartcard_unpack_set_attrib_call(s, &operation->call.setAttrib);
+
+ return status;
+}
+
+static LONG smartcard_AccessStartedEvent_Decode(wStream* s, SMARTCARD_OPERATION* operation)
+{
+ WINPR_ASSERT(s);
+ WINPR_ASSERT(operation);
+
+ if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
+ return SCARD_F_INTERNAL_ERROR;
+
+ Stream_Read_INT32(s, operation->call.lng.LongValue); /* Unused (4 bytes) */
+
+ return SCARD_S_SUCCESS;
+}
+
+static LONG smartcard_LocateCardsByATRA_Decode(wStream* s, SMARTCARD_OPERATION* operation)
+{
+ LONG status = 0;
+
+ WINPR_ASSERT(s);
+ WINPR_ASSERT(operation);
+
+ status = smartcard_unpack_locate_cards_by_atr_a_call(s, &operation->call.locateCardsByATRA);
+
+ return status;
+}
+
+static LONG smartcard_LocateCardsByATRW_Decode(wStream* s, SMARTCARD_OPERATION* operation)
+{
+ LONG status = 0;
+
+ WINPR_ASSERT(s);
+ WINPR_ASSERT(operation);
+
+ status = smartcard_unpack_locate_cards_by_atr_w_call(s, &operation->call.locateCardsByATRW);
+
+ return status;
+}
+
+static LONG smartcard_ReadCacheA_Decode(wStream* s, SMARTCARD_OPERATION* operation)
+{
+ LONG status = 0;
+
+ WINPR_ASSERT(s);
+ WINPR_ASSERT(operation);
+
+ status = smartcard_unpack_read_cache_a_call(s, &operation->call.readCacheA);
+
+ return status;
+}
+
+static LONG smartcard_ReadCacheW_Decode(wStream* s, SMARTCARD_OPERATION* operation)
+{
+ LONG status = 0;
+
+ WINPR_ASSERT(s);
+ WINPR_ASSERT(operation);
+
+ status = smartcard_unpack_read_cache_w_call(s, &operation->call.readCacheW);
+
+ return status;
+}
+
+static LONG smartcard_WriteCacheA_Decode(wStream* s, SMARTCARD_OPERATION* operation)
+{
+ LONG status = 0;
+
+ WINPR_ASSERT(s);
+ WINPR_ASSERT(operation);
+
+ status = smartcard_unpack_write_cache_a_call(s, &operation->call.writeCacheA);
+
+ return status;
+}
+
+static LONG smartcard_WriteCacheW_Decode(wStream* s, SMARTCARD_OPERATION* operation)
+{
+ LONG status = 0;
+
+ WINPR_ASSERT(s);
+ WINPR_ASSERT(operation);
+
+ status = smartcard_unpack_write_cache_w_call(s, &operation->call.writeCacheW);
+
+ return status;
+}
+
+static LONG smartcard_GetTransmitCount_Decode(wStream* s, SMARTCARD_OPERATION* operation)
+{
+ LONG status = 0;
+
+ WINPR_ASSERT(s);
+ WINPR_ASSERT(operation);
+
+ status = smartcard_unpack_get_transmit_count_call(s, &operation->call.getTransmitCount);
+
+ return status;
+}
+
+static LONG smartcard_ReleaseStartedEvent_Decode(wStream* s, SMARTCARD_OPERATION* operation)
+{
+ WINPR_UNUSED(s);
+ WINPR_UNUSED(operation);
+ WLog_WARN(TAG, "According to [MS-RDPESC] 3.1.4 Message Processing Events and Sequencing Rules "
+ "SCARD_IOCTL_RELEASETARTEDEVENT is not supported");
+ return SCARD_E_UNSUPPORTED_FEATURE;
+}
+
+static LONG smartcard_GetReaderIcon_Decode(wStream* s, SMARTCARD_OPERATION* operation)
+{
+ LONG status = 0;
+
+ WINPR_ASSERT(s);
+ WINPR_ASSERT(operation);
+
+ status = smartcard_unpack_get_reader_icon_call(s, &operation->call.getReaderIcon);
+
+ return status;
+}
+
+static LONG smartcard_GetDeviceTypeId_Decode(wStream* s, SMARTCARD_OPERATION* operation)
+{
+ LONG status = 0;
+
+ WINPR_ASSERT(s);
+ WINPR_ASSERT(operation);
+
+ status = smartcard_unpack_get_device_type_id_call(s, &operation->call.getDeviceTypeId);
+
+ return status;
+}
+
+LONG smartcard_irp_device_control_decode(wStream* s, UINT32 CompletionId, UINT32 FileId,
+ SMARTCARD_OPERATION* operation)
+{
+ LONG status = 0;
+ UINT32 offset = 0;
+ UINT32 ioControlCode = 0;
+ UINT32 outputBufferLength = 0;
+ UINT32 inputBufferLength = 0;
+
+ WINPR_ASSERT(s);
+ WINPR_ASSERT(operation);
+
+ /* Device Control Request */
+
+ if (!Stream_CheckAndLogRequiredLength(TAG, s, 32))
+ return SCARD_F_INTERNAL_ERROR;
+
+ Stream_Read_UINT32(s, outputBufferLength); /* OutputBufferLength (4 bytes) */
+ Stream_Read_UINT32(s, inputBufferLength); /* InputBufferLength (4 bytes) */
+ Stream_Read_UINT32(s, ioControlCode); /* IoControlCode (4 bytes) */
+ Stream_Seek(s, 20); /* Padding (20 bytes) */
+ operation->ioControlCode = ioControlCode;
+ operation->ioControlCodeName = scard_get_ioctl_string(ioControlCode, FALSE);
+
+ if (Stream_Length(s) != (Stream_GetPosition(s) + inputBufferLength))
+ {
+ WLog_WARN(TAG, "InputBufferLength mismatch: Actual: %" PRIuz " Expected: %" PRIuz "",
+ Stream_Length(s), Stream_GetPosition(s) + inputBufferLength);
+ return SCARD_F_INTERNAL_ERROR;
+ }
+
+ WLog_DBG(TAG, "%s (0x%08" PRIX32 ") FileId: %" PRIu32 " CompletionId: %" PRIu32 "",
+ scard_get_ioctl_string(ioControlCode, TRUE), ioControlCode, FileId, CompletionId);
+
+ if ((ioControlCode != SCARD_IOCTL_ACCESSSTARTEDEVENT) &&
+ (ioControlCode != SCARD_IOCTL_RELEASETARTEDEVENT))
+ {
+ 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;
+ }
+
+ /* Decode */
+ switch (ioControlCode)
+ {
+ case SCARD_IOCTL_ESTABLISHCONTEXT:
+ status = smartcard_EstablishContext_Decode(s, operation);
+ break;
+
+ case SCARD_IOCTL_RELEASECONTEXT:
+ status = smartcard_ReleaseContext_Decode(s, operation);
+ break;
+
+ case SCARD_IOCTL_ISVALIDCONTEXT:
+ status = smartcard_IsValidContext_Decode(s, operation);
+ break;
+
+ case SCARD_IOCTL_LISTREADERGROUPSA:
+ status = smartcard_ListReaderGroupsA_Decode(s, operation);
+ break;
+
+ case SCARD_IOCTL_LISTREADERGROUPSW:
+ status = smartcard_ListReaderGroupsW_Decode(s, operation);
+ break;
+
+ case SCARD_IOCTL_LISTREADERSA:
+ status = smartcard_ListReadersA_Decode(s, operation);
+ break;
+
+ case SCARD_IOCTL_LISTREADERSW:
+ status = smartcard_ListReadersW_Decode(s, operation);
+ break;
+
+ case SCARD_IOCTL_INTRODUCEREADERGROUPA:
+ status = smartcard_context_and_string_a_Decode(s, operation);
+ break;
+
+ case SCARD_IOCTL_INTRODUCEREADERGROUPW:
+ status = smartcard_context_and_string_w_Decode(s, operation);
+ break;
+
+ case SCARD_IOCTL_FORGETREADERGROUPA:
+ status = smartcard_context_and_string_a_Decode(s, operation);
+ break;
+
+ case SCARD_IOCTL_FORGETREADERGROUPW:
+ status = smartcard_context_and_string_w_Decode(s, operation);
+ break;
+
+ case SCARD_IOCTL_INTRODUCEREADERA:
+ status = smartcard_context_and_two_strings_a_Decode(s, operation);
+ break;
+
+ case SCARD_IOCTL_INTRODUCEREADERW:
+ status = smartcard_context_and_two_strings_w_Decode(s, operation);
+ break;
+
+ case SCARD_IOCTL_FORGETREADERA:
+ status = smartcard_context_and_string_a_Decode(s, operation);
+ break;
+
+ case SCARD_IOCTL_FORGETREADERW:
+ status = smartcard_context_and_string_w_Decode(s, operation);
+ break;
+
+ case SCARD_IOCTL_ADDREADERTOGROUPA:
+ status = smartcard_context_and_two_strings_a_Decode(s, operation);
+ break;
+
+ case SCARD_IOCTL_ADDREADERTOGROUPW:
+ status = smartcard_context_and_two_strings_w_Decode(s, operation);
+ break;
+
+ case SCARD_IOCTL_REMOVEREADERFROMGROUPA:
+ status = smartcard_context_and_two_strings_a_Decode(s, operation);
+ break;
+
+ case SCARD_IOCTL_REMOVEREADERFROMGROUPW:
+ status = smartcard_context_and_two_strings_w_Decode(s, operation);
+ break;
+
+ case SCARD_IOCTL_LOCATECARDSA:
+ status = smartcard_LocateCardsA_Decode(s, operation);
+ break;
+
+ case SCARD_IOCTL_LOCATECARDSW:
+ status = smartcard_LocateCardsW_Decode(s, operation);
+ break;
+
+ case SCARD_IOCTL_GETSTATUSCHANGEA:
+ status = smartcard_GetStatusChangeA_Decode(s, operation);
+ break;
+
+ case SCARD_IOCTL_GETSTATUSCHANGEW:
+ status = smartcard_GetStatusChangeW_Decode(s, operation);
+ break;
+
+ case SCARD_IOCTL_CANCEL:
+ status = smartcard_Cancel_Decode(s, operation);
+ break;
+
+ case SCARD_IOCTL_CONNECTA:
+ status = smartcard_ConnectA_Decode(s, operation);
+ break;
+
+ case SCARD_IOCTL_CONNECTW:
+ status = smartcard_ConnectW_Decode(s, operation);
+ break;
+
+ case SCARD_IOCTL_RECONNECT:
+ status = smartcard_Reconnect_Decode(s, operation);
+ break;
+
+ case SCARD_IOCTL_DISCONNECT:
+ status = smartcard_Disconnect_Decode(s, operation);
+ break;
+
+ case SCARD_IOCTL_BEGINTRANSACTION:
+ status = smartcard_BeginTransaction_Decode(s, operation);
+ break;
+
+ case SCARD_IOCTL_ENDTRANSACTION:
+ status = smartcard_EndTransaction_Decode(s, operation);
+ break;
+
+ case SCARD_IOCTL_STATE:
+ status = smartcard_State_Decode(s, operation);
+ break;
+
+ case SCARD_IOCTL_STATUSA:
+ status = smartcard_StatusA_Decode(s, operation);
+ break;
+
+ case SCARD_IOCTL_STATUSW:
+ status = smartcard_StatusW_Decode(s, operation);
+ break;
+
+ case SCARD_IOCTL_TRANSMIT:
+ status = smartcard_Transmit_Decode(s, operation);
+ break;
+
+ case SCARD_IOCTL_CONTROL:
+ status = smartcard_Control_Decode(s, operation);
+ break;
+
+ case SCARD_IOCTL_GETATTRIB:
+ status = smartcard_GetAttrib_Decode(s, operation);
+ break;
+
+ case SCARD_IOCTL_SETATTRIB:
+ status = smartcard_SetAttrib_Decode(s, operation);
+ break;
+
+ case SCARD_IOCTL_ACCESSSTARTEDEVENT:
+ status = smartcard_AccessStartedEvent_Decode(s, operation);
+ break;
+
+ case SCARD_IOCTL_LOCATECARDSBYATRA:
+ status = smartcard_LocateCardsByATRA_Decode(s, operation);
+ break;
+
+ case SCARD_IOCTL_LOCATECARDSBYATRW:
+ status = smartcard_LocateCardsByATRW_Decode(s, operation);
+ break;
+
+ case SCARD_IOCTL_READCACHEA:
+ status = smartcard_ReadCacheA_Decode(s, operation);
+ break;
+
+ case SCARD_IOCTL_READCACHEW:
+ status = smartcard_ReadCacheW_Decode(s, operation);
+ break;
+
+ case SCARD_IOCTL_WRITECACHEA:
+ status = smartcard_WriteCacheA_Decode(s, operation);
+ break;
+
+ case SCARD_IOCTL_WRITECACHEW:
+ status = smartcard_WriteCacheW_Decode(s, operation);
+ break;
+
+ case SCARD_IOCTL_GETTRANSMITCOUNT:
+ status = smartcard_GetTransmitCount_Decode(s, operation);
+ break;
+
+ case SCARD_IOCTL_RELEASETARTEDEVENT:
+ status = smartcard_ReleaseStartedEvent_Decode(s, operation);
+ break;
+
+ case SCARD_IOCTL_GETREADERICON:
+ status = smartcard_GetReaderIcon_Decode(s, operation);
+ break;
+
+ case SCARD_IOCTL_GETDEVICETYPEID:
+ status = smartcard_GetDeviceTypeId_Decode(s, operation);
+ break;
+
+ default:
+ status = SCARD_F_INTERNAL_ERROR;
+ break;
+ }
+
+ smartcard_call_to_operation_handle(operation);
+
+ if ((ioControlCode != SCARD_IOCTL_ACCESSSTARTEDEVENT) &&
+ (ioControlCode != SCARD_IOCTL_RELEASETARTEDEVENT))
+ {
+ offset = (RDPDR_DEVICE_IO_REQUEST_LENGTH + RDPDR_DEVICE_IO_CONTROL_REQ_HDR_LENGTH);
+ smartcard_unpack_read_size_align(s, Stream_GetPosition(s) - offset, 8);
+ }
+
+ if (Stream_GetPosition(s) < Stream_Length(s))
+ {
+ SIZE_T difference = 0;
+ difference = Stream_Length(s) - Stream_GetPosition(s);
+ WLog_WARN(TAG,
+ "IRP was not fully parsed %s (%s [0x%08" PRIX32 "]): Actual: %" PRIuz
+ ", Expected: %" PRIuz ", Difference: %" PRIuz "",
+ scard_get_ioctl_string(ioControlCode, TRUE),
+ scard_get_ioctl_string(ioControlCode, FALSE), ioControlCode,
+ Stream_GetPosition(s), Stream_Length(s), difference);
+ winpr_HexDump(TAG, WLOG_WARN, Stream_ConstPointer(s), difference);
+ }
+
+ if (Stream_GetPosition(s) > Stream_Length(s))
+ {
+ SIZE_T difference = 0;
+ difference = Stream_GetPosition(s) - Stream_Length(s);
+ WLog_WARN(TAG,
+ "IRP was parsed beyond its end %s (0x%08" PRIX32 "): Actual: %" PRIuz
+ ", Expected: %" PRIuz ", Difference: %" PRIuz "",
+ scard_get_ioctl_string(ioControlCode, TRUE), ioControlCode, Stream_GetPosition(s),
+ Stream_Length(s), difference);
+ }
+
+ return status;
+}
+
+static void free_reader_states_a(LPSCARD_READERSTATEA rgReaderStates, UINT32 cReaders)
+{
+ for (UINT32 x = 0; x < cReaders; x++)
+ {
+ SCARD_READERSTATEA* state = &rgReaderStates[x];
+ free(state->szReader);
+ }
+
+ free(rgReaderStates);
+}
+
+static void free_reader_states_w(LPSCARD_READERSTATEW rgReaderStates, UINT32 cReaders)
+{
+ for (UINT32 x = 0; x < cReaders; x++)
+ {
+ SCARD_READERSTATEW* state = &rgReaderStates[x];
+ free(state->szReader);
+ }
+
+ free(rgReaderStates);
+}
+
+void smartcard_operation_free(SMARTCARD_OPERATION* op, BOOL allocated)
+{
+ if (!op)
+ return;
+ switch (op->ioControlCode)
+ {
+ case SCARD_IOCTL_CANCEL:
+ case SCARD_IOCTL_ACCESSSTARTEDEVENT:
+ case SCARD_IOCTL_RELEASETARTEDEVENT:
+ case SCARD_IOCTL_LISTREADERGROUPSA:
+ case SCARD_IOCTL_LISTREADERGROUPSW:
+ case SCARD_IOCTL_RECONNECT:
+ case SCARD_IOCTL_DISCONNECT:
+ case SCARD_IOCTL_BEGINTRANSACTION:
+ case SCARD_IOCTL_ENDTRANSACTION:
+ case SCARD_IOCTL_STATE:
+ case SCARD_IOCTL_STATUSA:
+ case SCARD_IOCTL_STATUSW:
+ case SCARD_IOCTL_ESTABLISHCONTEXT:
+ case SCARD_IOCTL_RELEASECONTEXT:
+ case SCARD_IOCTL_ISVALIDCONTEXT:
+ case SCARD_IOCTL_GETATTRIB:
+ case SCARD_IOCTL_GETTRANSMITCOUNT:
+ break;
+
+ case SCARD_IOCTL_LOCATECARDSA:
+ {
+ LocateCardsA_Call* call = &op->call.locateCardsA;
+ free(call->mszCards);
+
+ free_reader_states_a(call->rgReaderStates, call->cReaders);
+ }
+ break;
+ case SCARD_IOCTL_LOCATECARDSW:
+ {
+ LocateCardsW_Call* call = &op->call.locateCardsW;
+ free(call->mszCards);
+
+ free_reader_states_w(call->rgReaderStates, call->cReaders);
+ }
+ break;
+
+ case SCARD_IOCTL_LOCATECARDSBYATRA:
+ {
+ LocateCardsByATRA_Call* call = &op->call.locateCardsByATRA;
+
+ free_reader_states_a(call->rgReaderStates, call->cReaders);
+ }
+ break;
+ case SCARD_IOCTL_LOCATECARDSBYATRW:
+ {
+ LocateCardsByATRW_Call* call = &op->call.locateCardsByATRW;
+ free_reader_states_w(call->rgReaderStates, call->cReaders);
+ }
+ break;
+ case SCARD_IOCTL_FORGETREADERA:
+ case SCARD_IOCTL_INTRODUCEREADERGROUPA:
+ case SCARD_IOCTL_FORGETREADERGROUPA:
+ {
+ ContextAndStringA_Call* call = &op->call.contextAndStringA;
+ free(call->sz);
+ }
+ break;
+
+ case SCARD_IOCTL_FORGETREADERW:
+ case SCARD_IOCTL_INTRODUCEREADERGROUPW:
+ case SCARD_IOCTL_FORGETREADERGROUPW:
+ {
+ ContextAndStringW_Call* call = &op->call.contextAndStringW;
+ 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:
+ {
+ ListReaders_Call* call = &op->call.listReaders;
+ free(call->mszGroups);
+ }
+ break;
+ case SCARD_IOCTL_GETSTATUSCHANGEA:
+ {
+ GetStatusChangeA_Call* call = &op->call.getStatusChangeA;
+ free_reader_states_a(call->rgReaderStates, call->cReaders);
+ }
+ break;
+
+ case SCARD_IOCTL_GETSTATUSCHANGEW:
+ {
+ GetStatusChangeW_Call* call = &op->call.getStatusChangeW;
+ free_reader_states_w(call->rgReaderStates, call->cReaders);
+ }
+ break;
+ case SCARD_IOCTL_GETREADERICON:
+ {
+ GetReaderIcon_Call* call = &op->call.getReaderIcon;
+ free(call->szReaderName);
+ }
+ break;
+ case SCARD_IOCTL_GETDEVICETYPEID:
+ {
+ GetDeviceTypeId_Call* call = &op->call.getDeviceTypeId;
+ free(call->szReaderName);
+ }
+ break;
+ case SCARD_IOCTL_CONNECTA:
+ {
+ ConnectA_Call* call = &op->call.connectA;
+ free(call->szReader);
+ }
+ break;
+ case SCARD_IOCTL_CONNECTW:
+ {
+ ConnectW_Call* call = &op->call.connectW;
+ free(call->szReader);
+ }
+ break;
+ case SCARD_IOCTL_SETATTRIB:
+ free(op->call.setAttrib.pbAttr);
+ break;
+ case SCARD_IOCTL_TRANSMIT:
+ {
+ Transmit_Call* call = &op->call.transmit;
+ free(call->pbSendBuffer);
+ free(call->pioSendPci);
+ free(call->pioRecvPci);
+ }
+ break;
+ case SCARD_IOCTL_CONTROL:
+ {
+ Control_Call* call = &op->call.control;
+ free(call->pvInBuffer);
+ }
+ break;
+ case SCARD_IOCTL_READCACHEA:
+ {
+ ReadCacheA_Call* call = &op->call.readCacheA;
+ free(call->szLookupName);
+ free(call->Common.CardIdentifier);
+ }
+ break;
+ case SCARD_IOCTL_READCACHEW:
+ {
+ ReadCacheW_Call* call = &op->call.readCacheW;
+ free(call->szLookupName);
+ free(call->Common.CardIdentifier);
+ }
+ break;
+ case SCARD_IOCTL_WRITECACHEA:
+ {
+ WriteCacheA_Call* call = &op->call.writeCacheA;
+ free(call->szLookupName);
+ free(call->Common.CardIdentifier);
+ free(call->Common.pbData);
+ }
+ break;
+ case SCARD_IOCTL_WRITECACHEW:
+ {
+ WriteCacheW_Call* call = &op->call.writeCacheW;
+ free(call->szLookupName);
+ free(call->Common.CardIdentifier);
+ free(call->Common.pbData);
+ }
+ break;
+ default:
+ break;
+ }
+
+ {
+ SMARTCARD_OPERATION empty = { 0 };
+ *op = empty;
+ }
+
+ if (allocated)
+ free(op);
+}