diff options
Diffstat (limited to 'libfreerdp/utils/smartcard_operations.c')
-rw-r--r-- | libfreerdp/utils/smartcard_operations.c | 1048 |
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); +} |