/** * FreeRDP: A Remote Desktop Protocol Implementation * Smart Card Structure Packing * * Copyright 2014 Marc-Andre Moreau * Copyright 2015 Thincast Technologies GmbH * Copyright 2015 DI (FH) Martin Haimberger * Copyright 2020 Armin Novak * Copyright 2020 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 #include #include #include #include #include "smartcard_pack.h" #include #define SCARD_TAG FREERDP_TAG("scard.pack") static const DWORD g_LogLevel = WLOG_DEBUG; static wLog* scard_log(void) { static wLog* log = nullptr; if (!log) log = WLog_Get(SCARD_TAG); return log; } #define smartcard_unpack_redir_scard_context(log, s, context, index, ndr) \ smartcard_unpack_redir_scard_context_((log), (s), (context), (index), (ndr), __FILE__, \ __func__, __LINE__) #define smartcard_unpack_redir_scard_handle(log, s, context, index) \ smartcard_unpack_redir_scard_handle_((log), (s), (context), (index), __FILE__, __func__, \ __LINE__) static LONG smartcard_unpack_redir_scard_context_(wLog* log, wStream* s, REDIR_SCARDCONTEXT* context, UINT32* index, UINT32* ppbContextNdrPtr, const char* file, const char* function, size_t line); static LONG smartcard_pack_redir_scard_context(wLog* log, wStream* s, const REDIR_SCARDCONTEXT* context, DWORD* index); static LONG smartcard_unpack_redir_scard_handle_(wLog* log, wStream* s, REDIR_SCARDHANDLE* handle, UINT32* index, const char* file, const char* function, size_t line); static LONG smartcard_pack_redir_scard_handle(wLog* log, wStream* s, const REDIR_SCARDHANDLE* handle, DWORD* index); static LONG smartcard_unpack_redir_scard_context_ref(wLog* log, wStream* s, UINT32 pbContextNdrPtr, REDIR_SCARDCONTEXT* context); static LONG smartcard_pack_redir_scard_context_ref(wLog* log, wStream* s, const REDIR_SCARDCONTEXT* context); static LONG smartcard_unpack_redir_scard_handle_ref(wLog* log, wStream* s, REDIR_SCARDHANDLE* handle); static LONG smartcard_pack_redir_scard_handle_ref(wLog* log, wStream* s, const REDIR_SCARDHANDLE* handle); typedef enum { NDR_PTR_FULL, NDR_PTR_SIMPLE, NDR_PTR_FIXED } ndr_ptr_t; /* Reads a NDR pointer and checks if the value read has the expected relative * addressing */ #define smartcard_ndr_pointer_read(log, s, index, ptr) \ smartcard_ndr_pointer_read_((log), (s), (index), (ptr), __FILE__, __func__, __LINE__) static BOOL smartcard_ndr_pointer_read_(wLog* log, wStream* s, UINT32* index, UINT32* ptr, const char* file, const char* fkt, size_t line) { const UINT32 expect = 0x20000 + (*index) * 4; UINT32 ndrPtr = 0; WINPR_UNUSED(file); if (!s) return FALSE; if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4)) return FALSE; Stream_Read_UINT32(s, ndrPtr); /* mszGroupsNdrPtr (4 bytes) */ if (ptr) *ptr = ndrPtr; if (expect != ndrPtr) { /* Allow nullptr pointer if we read the result */ if (ptr && (ndrPtr == 0)) return TRUE; WLog_Print(log, WLOG_WARN, "[%s:%" PRIuz "] Read context pointer 0x%08" PRIx32 ", expected 0x%08" PRIx32, fkt, line, ndrPtr, expect); return FALSE; } (*index) = (*index) + 1; return TRUE; } static LONG smartcard_ndr_read_ex(wLog* log, wStream* s, BYTE** data, size_t min, size_t elementSize, ndr_ptr_t type, size_t* plen) { size_t len = 0; size_t offset = 0; size_t len2 = 0; void* r = nullptr; size_t required = 0; *data = nullptr; if (plen) *plen = 0; switch (type) { case NDR_PTR_FULL: required = 12; break; case NDR_PTR_SIMPLE: required = 4; break; case NDR_PTR_FIXED: required = min; break; default: return STATUS_INVALID_PARAMETER; } if (!Stream_CheckAndLogRequiredLengthWLog(log, s, required)) return STATUS_BUFFER_TOO_SMALL; switch (type) { case NDR_PTR_FULL: Stream_Read_UINT32(s, len); Stream_Read_UINT32(s, offset); Stream_Read_UINT32(s, len2); if (len != offset + len2) { WLog_Print(log, WLOG_ERROR, "Invalid data when reading full NDR pointer: total=%" PRIuz ", offset=%" PRIuz ", remaining=%" PRIuz, len, offset, len2); return STATUS_BUFFER_TOO_SMALL; } break; case NDR_PTR_SIMPLE: Stream_Read_UINT32(s, len); if ((len != min) && (min > 0)) { WLog_Print(log, WLOG_ERROR, "Invalid data when reading simple NDR pointer: total=%" PRIuz ", expected=%" PRIuz, len, min); return STATUS_BUFFER_TOO_SMALL; } break; case NDR_PTR_FIXED: len = (UINT32)min; break; default: return STATUS_INVALID_PARAMETER; } if (min > len) { WLog_Print(log, WLOG_ERROR, "Invalid length read from NDR pointer, minimum %" PRIuz ", got %" PRIuz, min, len); return STATUS_DATA_ERROR; } if (len > SIZE_MAX / 2) return STATUS_BUFFER_TOO_SMALL; if (!Stream_CheckAndLogRequiredLengthOfSizeWLog(log, s, len, elementSize)) return STATUS_BUFFER_TOO_SMALL; len *= elementSize; /* Ensure proper '\0' termination for all kinds of unicode strings * as we do not know if the data from the wire contains one. */ r = calloc(len + sizeof(WCHAR), sizeof(CHAR)); if (!r) return SCARD_E_NO_MEMORY; Stream_Read(s, r, len); const LONG pad = smartcard_unpack_read_size_align(s, len, 4); if (pad < 0) { free(r); return STATUS_INVALID_PARAMETER; } len += (size_t)pad; *data = r; if (plen) *plen = len; return STATUS_SUCCESS; } static LONG smartcard_ndr_read(wLog* log, wStream* s, BYTE** data, size_t min, size_t elementSize, ndr_ptr_t type) { return smartcard_ndr_read_ex(log, s, data, min, elementSize, type, nullptr); } static BOOL smartcard_ndr_pointer_write(wStream* s, UINT32* index, DWORD length) { const UINT32 ndrPtr = 0x20000 + (*index) * 4; if (!s) return FALSE; if (!Stream_EnsureRemainingCapacity(s, 4)) return FALSE; if (length > 0) { Stream_Write_UINT32(s, ndrPtr); /* mszGroupsNdrPtr (4 bytes) */ (*index) = (*index) + 1; } else Stream_Write_UINT32(s, 0); return TRUE; } static LONG smartcard_ndr_write(wStream* s, const BYTE* data, UINT32 size, UINT32 elementSize, ndr_ptr_t type) { const UINT32 offset = 0; const UINT32 len = size; const UINT32 dataLen = size * elementSize; size_t required = 0; if (size == 0) return SCARD_S_SUCCESS; switch (type) { case NDR_PTR_FULL: required = 12; break; case NDR_PTR_SIMPLE: required = 4; break; case NDR_PTR_FIXED: required = 0; break; default: return SCARD_E_INVALID_PARAMETER; } if (!Stream_EnsureRemainingCapacity(s, required + dataLen + 4)) return STATUS_BUFFER_TOO_SMALL; switch (type) { case NDR_PTR_FULL: Stream_Write_UINT32(s, len); Stream_Write_UINT32(s, offset); Stream_Write_UINT32(s, len); break; case NDR_PTR_SIMPLE: Stream_Write_UINT32(s, len); break; case NDR_PTR_FIXED: break; default: return SCARD_E_INVALID_PARAMETER; } if (data) Stream_Write(s, data, dataLen); else Stream_Zero(s, dataLen); return smartcard_pack_write_size_align(s, len, 4); } static LONG smartcard_ndr_write_state(wStream* s, const ReaderState_Return* data, UINT32 size, ndr_ptr_t type) { union { const ReaderState_Return* reader; const BYTE* data; } cnv; WINPR_ASSERT(data || (size == 0)); cnv.reader = data; return smartcard_ndr_write(s, cnv.data, size, sizeof(ReaderState_Return), type); } static LONG smartcard_ndr_read_atrmask(wLog* log, wStream* s, LocateCards_ATRMask** data, size_t min, ndr_ptr_t type) { union { LocateCards_ATRMask** ppc; BYTE** ppv; } u; u.ppc = data; return smartcard_ndr_read(log, s, u.ppv, min, sizeof(LocateCards_ATRMask), type); } static LONG smartcard_ndr_read_fixed_string_a(wLog* log, wStream* s, CHAR** data, size_t min, ndr_ptr_t type) { union { CHAR** ppc; BYTE** ppv; } u; u.ppc = data; return smartcard_ndr_read(log, s, u.ppv, min, sizeof(CHAR), type); } static LONG smartcard_ndr_read_fixed_string_w(wLog* log, wStream* s, WCHAR** data, size_t min, ndr_ptr_t type) { union { WCHAR** ppc; BYTE** ppv; } u; u.ppc = data; return smartcard_ndr_read(log, s, u.ppv, min, sizeof(WCHAR), type); } static LONG smartcard_ndr_read_a(wLog* log, wStream* s, CHAR** data, ndr_ptr_t type) { union { CHAR** ppc; BYTE** ppv; } u; u.ppc = data; return smartcard_ndr_read(log, s, u.ppv, 0, sizeof(CHAR), type); } static LONG smartcard_ndr_read_w(wLog* log, wStream* s, WCHAR** data, ndr_ptr_t type) { union { WCHAR** ppc; BYTE** ppv; } u; u.ppc = data; return smartcard_ndr_read(log, s, u.ppv, 0, sizeof(WCHAR), type); } static LONG smartcard_ndr_read_u(wLog* log, wStream* s, UUID** data) { union { UUID** ppc; BYTE** ppv; } u; u.ppc = data; return smartcard_ndr_read(log, s, u.ppv, 1, sizeof(UUID), NDR_PTR_FIXED); } static char* smartcard_convert_string_list(const void* in, size_t bytes, BOOL unicode) { size_t length = 0; union { const void* pv; const char* sz; const WCHAR* wz; } string; char* mszA = nullptr; string.pv = in; if (bytes < 1) return nullptr; if (in == nullptr) return nullptr; if (unicode) { mszA = ConvertMszWCharNToUtf8Alloc(string.wz, bytes / sizeof(WCHAR), &length); if (!mszA) return nullptr; } else { mszA = (char*)calloc(bytes, sizeof(char)); if (!mszA) return nullptr; CopyMemory(mszA, string.sz, bytes - 1); length = bytes; } if (length < 1) { free(mszA); return nullptr; } for (size_t index = 0; index < length - 1; index++) { if (mszA[index] == '\0') mszA[index] = ','; } return mszA; } static char* smartcard_msz_dump_a(const char* msz, size_t len, char* buffer, size_t bufferLen) { char* buf = buffer; const char* cur = msz; while ((len > 0) && cur && cur[0] != '\0' && (bufferLen > 0)) { size_t clen = strnlen(cur, len); int rc = _snprintf(buf, bufferLen, "%s", cur); bufferLen -= (size_t)rc; buf += rc; cur += clen; } return buffer; } static char* smartcard_msz_dump_w(const WCHAR* msz, size_t len, char* buffer, size_t bufferLen) { size_t szlen = 0; if (!msz) return nullptr; char* sz = ConvertMszWCharNToUtf8Alloc(msz, len, &szlen); if (!sz) return nullptr; smartcard_msz_dump_a(sz, szlen, buffer, bufferLen); free(sz); return buffer; } static char* smartcard_array_dump(const void* pd, size_t len, char* buffer, size_t bufferLen) { const BYTE* data = pd; int rc = 0; char* start = buffer; WINPR_ASSERT(buffer || (bufferLen == 0)); if (!data && (len > 0)) { (void)_snprintf(buffer, bufferLen, "{ nullptr [%" PRIuz "] }", len); goto fail; } rc = _snprintf(buffer, bufferLen, "{ "); if ((rc < 0) || ((size_t)rc >= bufferLen)) goto fail; buffer += rc; bufferLen -= (size_t)rc; for (size_t x = 0; x < len; x++) { rc = _snprintf(buffer, bufferLen, "%02X", data[x]); if ((rc < 0) || ((size_t)rc >= bufferLen)) goto fail; buffer += rc; bufferLen -= (size_t)rc; } rc = _snprintf(buffer, bufferLen, " }"); if ((rc < 0) || ((size_t)rc >= bufferLen)) goto fail; fail: return start; } static void smartcard_log_redir_handle(wLog* log, const REDIR_SCARDHANDLE* pHandle) { char buffer[128] = WINPR_C_ARRAY_INIT; WINPR_ASSERT(pHandle); WLog_Print(log, g_LogLevel, " hContext: %s", smartcard_array_dump(pHandle->pbHandle, pHandle->cbHandle, buffer, sizeof(buffer))); } static void smartcard_log_context(wLog* log, const REDIR_SCARDCONTEXT* phContext) { char buffer[128] = WINPR_C_ARRAY_INIT; WINPR_ASSERT(phContext); WLog_Print( log, g_LogLevel, "hContext: %s", smartcard_array_dump(phContext->pbContext, phContext->cbContext, buffer, sizeof(buffer))); } static void smartcard_trace_context_and_string_call_a(wLog* log, const char* name, const REDIR_SCARDCONTEXT* phContext, const CHAR* sz) { if (!WLog_IsLevelActive(log, g_LogLevel)) return; WLog_Print(log, g_LogLevel, "%s {", name); smartcard_log_context(log, phContext); WLog_Print(log, g_LogLevel, " sz=%s", sz); WLog_Print(log, g_LogLevel, "}"); } static void smartcard_trace_context_and_string_call_w(wLog* log, const char* name, const REDIR_SCARDCONTEXT* phContext, const WCHAR* sz) { char tmp[1024] = WINPR_C_ARRAY_INIT; if (!WLog_IsLevelActive(log, g_LogLevel)) return; if (sz) (void)ConvertWCharToUtf8(sz, tmp, ARRAYSIZE(tmp)); WLog_Print(log, g_LogLevel, "%s {", name); smartcard_log_context(log, phContext); WLog_Print(log, g_LogLevel, " sz=%s", tmp); WLog_Print(log, g_LogLevel, "}"); } static void smartcard_trace_context_call(wLog* log, const Context_Call* call, const char* name) { WINPR_ASSERT(call); if (!WLog_IsLevelActive(log, g_LogLevel)) return; WLog_Print(log, g_LogLevel, "%s_Call {", name); smartcard_log_context(log, &call->handles.hContext); WLog_Print(log, g_LogLevel, "}"); } static void smartcard_trace_list_reader_groups_call(wLog* log, const ListReaderGroups_Call* call, BOOL unicode) { WINPR_ASSERT(call); if (!WLog_IsLevelActive(log, g_LogLevel)) return; WLog_Print(log, g_LogLevel, "ListReaderGroups%s_Call {", unicode ? "W" : "A"); smartcard_log_context(log, &call->handles.hContext); WLog_Print(log, g_LogLevel, "fmszGroupsIsNULL: %" PRId32 " cchGroups: 0x%08" PRIx32, call->fmszGroupsIsNULL, call->cchGroups); WLog_Print(log, g_LogLevel, "}"); } static void dump_reader_states_return(wLog* log, const ReaderState_Return* rgReaderStates, UINT32 cReaders) { WINPR_ASSERT(rgReaderStates || (cReaders == 0)); for (UINT32 index = 0; index < cReaders; index++) { char buffer[1024] = WINPR_C_ARRAY_INIT; const ReaderState_Return* readerState = &rgReaderStates[index]; char* szCurrentState = SCardGetReaderStateString(readerState->dwCurrentState); char* szEventState = SCardGetReaderStateString(readerState->dwEventState); WLog_Print(log, g_LogLevel, "\t[%" PRIu32 "]: dwCurrentState: %s (0x%08" PRIX32 ")", index, szCurrentState, readerState->dwCurrentState); WLog_Print(log, g_LogLevel, "\t[%" PRIu32 "]: dwEventState: %s (0x%08" PRIX32 ")", index, szEventState, readerState->dwEventState); free(szCurrentState); free(szEventState); WLog_Print( log, g_LogLevel, "\t[%" PRIu32 "]: cbAttr: %" PRIu32 " { %s }", index, readerState->cbAtr, smartcard_array_dump(readerState->rgbAtr, readerState->cbAtr, buffer, sizeof(buffer))); } } static void dump_reader_states_a(wLog* log, const SCARD_READERSTATEA* rgReaderStates, UINT32 cReaders) { WINPR_ASSERT(rgReaderStates || (cReaders == 0)); for (UINT32 index = 0; index < cReaders; index++) { char buffer[1024] = WINPR_C_ARRAY_INIT; const SCARD_READERSTATEA* readerState = &rgReaderStates[index]; WLog_Print(log, g_LogLevel, "\t[%" PRIu32 "]: szReader: %s cbAtr: %" PRIu32 "", index, readerState->szReader, readerState->cbAtr); char* szCurrentState = SCardGetReaderStateString(readerState->dwCurrentState); char* szEventState = SCardGetReaderStateString(readerState->dwEventState); WLog_Print(log, g_LogLevel, "\t[%" PRIu32 "]: dwCurrentState: %s (0x%08" PRIX32 ")", index, szCurrentState, readerState->dwCurrentState); WLog_Print(log, g_LogLevel, "\t[%" PRIu32 "]: dwEventState: %s (0x%08" PRIX32 ")", index, szEventState, readerState->dwEventState); free(szCurrentState); free(szEventState); WLog_Print( log, g_LogLevel, "\t[%" PRIu32 "]: cbAttr: %" PRIu32 " { %s }", index, readerState->cbAtr, smartcard_array_dump(readerState->rgbAtr, readerState->cbAtr, buffer, sizeof(buffer))); } } static void dump_reader_states_w(wLog* log, const SCARD_READERSTATEW* rgReaderStates, UINT32 cReaders) { WINPR_ASSERT(rgReaderStates || (cReaders == 0)); for (UINT32 index = 0; index < cReaders; index++) { char buffer[1024] = WINPR_C_ARRAY_INIT; const SCARD_READERSTATEW* readerState = &rgReaderStates[index]; (void)ConvertWCharToUtf8(readerState->szReader, buffer, sizeof(buffer)); WLog_Print(log, g_LogLevel, "\t[%" PRIu32 "]: szReader: %s cbAtr: %" PRIu32 "", index, buffer, readerState->cbAtr); char* szCurrentState = SCardGetReaderStateString(readerState->dwCurrentState); char* szEventState = SCardGetReaderStateString(readerState->dwEventState); WLog_Print(log, g_LogLevel, "\t[%" PRIu32 "]: dwCurrentState: %s (0x%08" PRIX32 ")", index, szCurrentState, readerState->dwCurrentState); WLog_Print(log, g_LogLevel, "\t[%" PRIu32 "]: dwEventState: %s (0x%08" PRIX32 ")", index, szEventState, readerState->dwEventState); free(szCurrentState); free(szEventState); WLog_Print( log, g_LogLevel, "\t[%" PRIu32 "]: cbAttr: %" PRIu32 " { %s }", index, readerState->cbAtr, smartcard_array_dump(readerState->rgbAtr, readerState->cbAtr, buffer, sizeof(buffer))); } } static void smartcard_trace_get_status_change_w_call(wLog* log, const GetStatusChangeW_Call* call) { WINPR_ASSERT(call); if (!WLog_IsLevelActive(log, g_LogLevel)) return; WLog_Print(log, g_LogLevel, "GetStatusChangeW_Call {"); smartcard_log_context(log, &call->handles.hContext); WLog_Print(log, g_LogLevel, "dwTimeOut: 0x%08" PRIX32 " cReaders: %" PRIu32 "", call->dwTimeOut, call->cReaders); dump_reader_states_w(log, call->rgReaderStates, call->cReaders); WLog_Print(log, g_LogLevel, "}"); } static void smartcard_trace_list_reader_groups_return(wLog* log, const ListReaderGroups_Return* ret, BOOL unicode) { WINPR_ASSERT(ret); if (!WLog_IsLevelActive(log, g_LogLevel)) return; char* mszA = smartcard_convert_string_list(ret->msz, ret->cBytes, unicode); WLog_Print(log, g_LogLevel, "ListReaderGroups%s_Return {", unicode ? "W" : "A"); WLog_Print(log, g_LogLevel, " ReturnCode: %s (0x%08" PRIx32 ")", SCardGetErrorString(ret->ReturnCode), WINPR_CXX_COMPAT_CAST(UINT32, ret->ReturnCode)); WLog_Print(log, g_LogLevel, " cBytes: %" PRIu32 " msz: %s", ret->cBytes, mszA); WLog_Print(log, g_LogLevel, "}"); free(mszA); } static void smartcard_trace_list_readers_call(wLog* log, const ListReaders_Call* call, BOOL unicode) { WINPR_ASSERT(call); if (!WLog_IsLevelActive(log, g_LogLevel)) return; char* mszGroupsA = smartcard_convert_string_list(call->mszGroups, call->cBytes, unicode); WLog_Print(log, g_LogLevel, "ListReaders%s_Call {", unicode ? "W" : "A"); smartcard_log_context(log, &call->handles.hContext); WLog_Print(log, g_LogLevel, "cBytes: %" PRIu32 " mszGroups: %s fmszReadersIsNULL: %" PRId32 " cchReaders: 0x%08" PRIX32 "", call->cBytes, mszGroupsA, call->fmszReadersIsNULL, call->cchReaders); WLog_Print(log, g_LogLevel, "}"); free(mszGroupsA); } static void smartcard_trace_locate_cards_by_atr_a_call(wLog* log, const LocateCardsByATRA_Call* call) { WINPR_ASSERT(call); if (!WLog_IsLevelActive(log, g_LogLevel)) return; WLog_Print(log, g_LogLevel, "LocateCardsByATRA_Call {"); smartcard_log_context(log, &call->handles.hContext); dump_reader_states_a(log, call->rgReaderStates, call->cReaders); WLog_Print(log, g_LogLevel, "}"); } static void smartcard_trace_locate_cards_a_call(wLog* log, const LocateCardsA_Call* call) { char buffer[8192] = WINPR_C_ARRAY_INIT; WINPR_ASSERT(call); if (!WLog_IsLevelActive(log, g_LogLevel)) return; WLog_Print(log, g_LogLevel, "LocateCardsA_Call {"); smartcard_log_context(log, &call->handles.hContext); WLog_Print(log, g_LogLevel, " cBytes=%" PRIu32, call->cBytes); WLog_Print(log, g_LogLevel, " mszCards=%s", smartcard_msz_dump_a(call->mszCards, call->cBytes, buffer, sizeof(buffer))); WLog_Print(log, g_LogLevel, " cReaders=%" PRIu32, call->cReaders); dump_reader_states_a(log, call->rgReaderStates, call->cReaders); WLog_Print(log, g_LogLevel, "}"); } static void smartcard_trace_locate_cards_return(wLog* log, const LocateCards_Return* ret) { WINPR_ASSERT(ret); if (!WLog_IsLevelActive(log, g_LogLevel)) return; WLog_Print(log, g_LogLevel, "LocateCards_Return {"); WLog_Print(log, g_LogLevel, " ReturnCode: %s (0x%08" PRIX32 ")", SCardGetErrorString(ret->ReturnCode), WINPR_CXX_COMPAT_CAST(UINT32, ret->ReturnCode)); if (ret->ReturnCode == SCARD_S_SUCCESS) { WLog_Print(log, g_LogLevel, " cReaders=%" PRIu32, ret->cReaders); } WLog_Print(log, g_LogLevel, "}"); } static void smartcard_trace_get_reader_icon_return(wLog* log, const GetReaderIcon_Return* ret) { WINPR_ASSERT(ret); if (!WLog_IsLevelActive(log, g_LogLevel)) return; WLog_Print(log, g_LogLevel, "GetReaderIcon_Return {"); WLog_Print(log, g_LogLevel, " ReturnCode: %s (0x%08" PRIX32 ")", SCardGetErrorString(ret->ReturnCode), WINPR_CXX_COMPAT_CAST(UINT32, ret->ReturnCode)); if (ret->ReturnCode == SCARD_S_SUCCESS) { WLog_Print(log, g_LogLevel, " cbDataLen=%" PRIu32, ret->cbDataLen); } WLog_Print(log, g_LogLevel, "}"); } static void smartcard_trace_get_transmit_count_return(wLog* log, const GetTransmitCount_Return* ret) { WINPR_ASSERT(ret); if (!WLog_IsLevelActive(log, g_LogLevel)) return; WLog_Print(log, g_LogLevel, "GetTransmitCount_Return {"); WLog_Print(log, g_LogLevel, " ReturnCode: %s (0x%08" PRIX32 ")", SCardGetErrorString(ret->ReturnCode), WINPR_CXX_COMPAT_CAST(UINT32, ret->ReturnCode)); WLog_Print(log, g_LogLevel, " cTransmitCount=%" PRIu32, ret->cTransmitCount); WLog_Print(log, g_LogLevel, "}"); } static void smartcard_trace_read_cache_return(wLog* log, const ReadCache_Return* ret) { WINPR_ASSERT(ret); if (!WLog_IsLevelActive(log, g_LogLevel)) return; WLog_Print(log, g_LogLevel, "ReadCache_Return {"); WLog_Print(log, g_LogLevel, " ReturnCode: %s (0x%08" PRIX32 ")", SCardGetErrorString(ret->ReturnCode), WINPR_CXX_COMPAT_CAST(UINT32, ret->ReturnCode)); if (ret->ReturnCode == SCARD_S_SUCCESS) { char buffer[1024] = WINPR_C_ARRAY_INIT; WLog_Print(log, g_LogLevel, " cbDataLen=%" PRIu32, ret->cbDataLen); WLog_Print(log, g_LogLevel, " cbData: %s", smartcard_array_dump(ret->pbData, ret->cbDataLen, buffer, sizeof(buffer))); } WLog_Print(log, g_LogLevel, "}"); } static void smartcard_trace_locate_cards_w_call(wLog* log, const LocateCardsW_Call* call) { WINPR_ASSERT(call); char buffer[8192] = WINPR_C_ARRAY_INIT; if (!WLog_IsLevelActive(log, g_LogLevel)) return; WLog_Print(log, g_LogLevel, "LocateCardsW_Call {"); smartcard_log_context(log, &call->handles.hContext); WLog_Print(log, g_LogLevel, " cBytes=%" PRIu32, call->cBytes); WLog_Print(log, g_LogLevel, " sz2=%s", smartcard_msz_dump_w(call->mszCards, call->cBytes, buffer, sizeof(buffer))); WLog_Print(log, g_LogLevel, " cReaders=%" PRIu32, call->cReaders); dump_reader_states_w(log, call->rgReaderStates, call->cReaders); WLog_Print(log, g_LogLevel, "}"); } static void smartcard_trace_list_readers_return(wLog* log, const ListReaders_Return* ret, BOOL unicode) { WINPR_ASSERT(ret); if (!WLog_IsLevelActive(log, g_LogLevel)) return; WLog_Print(log, g_LogLevel, "ListReaders%s_Return {", unicode ? "W" : "A"); WLog_Print(log, g_LogLevel, " ReturnCode: %s (0x%08" PRIX32 ")", SCardGetErrorString(ret->ReturnCode), WINPR_CXX_COMPAT_CAST(UINT32, ret->ReturnCode)); if (ret->ReturnCode != SCARD_S_SUCCESS) { WLog_Print(log, g_LogLevel, "}"); return; } char* mszA = smartcard_convert_string_list(ret->msz, ret->cBytes, unicode); WLog_Print(log, g_LogLevel, " cBytes: %" PRIu32 " msz: %s", ret->cBytes, mszA); WLog_Print(log, g_LogLevel, "}"); free(mszA); } static void smartcard_trace_get_status_change_return(wLog* log, const GetStatusChange_Return* ret, BOOL unicode) { WINPR_ASSERT(ret); if (!WLog_IsLevelActive(log, g_LogLevel)) return; WLog_Print(log, g_LogLevel, "GetStatusChange%s_Return {", unicode ? "W" : "A"); WLog_Print(log, g_LogLevel, " ReturnCode: %s (0x%08" PRIX32 ")", SCardGetErrorString(ret->ReturnCode), WINPR_CXX_COMPAT_CAST(UINT32, ret->ReturnCode)); WLog_Print(log, g_LogLevel, " cReaders: %" PRIu32 "", ret->cReaders); dump_reader_states_return(log, ret->rgReaderStates, ret->cReaders); if (!ret->rgReaderStates && (ret->cReaders > 0)) { WLog_Print(log, g_LogLevel, " [INVALID STATE] rgReaderStates=nullptr, cReaders=%" PRIu32, ret->cReaders); } else if (ret->ReturnCode != SCARD_S_SUCCESS) { WLog_Print(log, g_LogLevel, " [INVALID RETURN] rgReaderStates, cReaders=%" PRIu32, ret->cReaders); } else { for (UINT32 index = 0; index < ret->cReaders; index++) { char buffer[1024] = WINPR_C_ARRAY_INIT; const ReaderState_Return* rgReaderState = &(ret->rgReaderStates[index]); char* szCurrentState = SCardGetReaderStateString(rgReaderState->dwCurrentState); char* szEventState = SCardGetReaderStateString(rgReaderState->dwEventState); WLog_Print(log, g_LogLevel, " [%" PRIu32 "]: dwCurrentState: %s (0x%08" PRIX32 ")", index, szCurrentState, rgReaderState->dwCurrentState); WLog_Print(log, g_LogLevel, " [%" PRIu32 "]: dwEventState: %s (0x%08" PRIX32 ")", index, szEventState, rgReaderState->dwEventState); WLog_Print(log, g_LogLevel, " [%" PRIu32 "]: cbAtr: %" PRIu32 " rgbAtr: %s", index, rgReaderState->cbAtr, smartcard_array_dump(rgReaderState->rgbAtr, rgReaderState->cbAtr, buffer, sizeof(buffer))); free(szCurrentState); free(szEventState); } } WLog_Print(log, g_LogLevel, "}"); } static void smartcard_trace_context_and_two_strings_a_call(wLog* log, const ContextAndTwoStringA_Call* call) { WINPR_ASSERT(call); if (!WLog_IsLevelActive(log, g_LogLevel)) return; WLog_Print(log, g_LogLevel, "ContextAndTwoStringW_Call {"); smartcard_log_context(log, &call->handles.hContext); WLog_Print(log, g_LogLevel, " sz1=%s", call->sz1); WLog_Print(log, g_LogLevel, " sz2=%s", call->sz2); WLog_Print(log, g_LogLevel, "}"); } static void smartcard_trace_context_and_two_strings_w_call(wLog* log, const ContextAndTwoStringW_Call* call) { WINPR_ASSERT(call); char sz1[1024] = WINPR_C_ARRAY_INIT; char sz2[1024] = WINPR_C_ARRAY_INIT; if (!WLog_IsLevelActive(log, g_LogLevel)) return; if (call->sz1) (void)ConvertWCharToUtf8(call->sz1, sz1, ARRAYSIZE(sz1)); if (call->sz2) (void)ConvertWCharToUtf8(call->sz2, sz2, ARRAYSIZE(sz2)); WLog_Print(log, g_LogLevel, "ContextAndTwoStringW_Call {"); smartcard_log_context(log, &call->handles.hContext); WLog_Print(log, g_LogLevel, " sz1=%s", sz1); WLog_Print(log, g_LogLevel, " sz2=%s", sz2); WLog_Print(log, g_LogLevel, "}"); } static void smartcard_trace_get_transmit_count_call(wLog* log, const GetTransmitCount_Call* call) { WINPR_ASSERT(call); if (!WLog_IsLevelActive(log, g_LogLevel)) return; WLog_Print(log, g_LogLevel, "GetTransmitCount_Call {"); smartcard_log_context(log, &call->handles.hContext); smartcard_log_redir_handle(log, &call->handles.hCard); WLog_Print(log, g_LogLevel, "}"); } static void smartcard_trace_write_cache_a_call(wLog* log, const WriteCacheA_Call* call) { WINPR_ASSERT(call); char buffer[1024] = WINPR_C_ARRAY_INIT; if (!WLog_IsLevelActive(log, g_LogLevel)) return; WLog_Print(log, g_LogLevel, "WriteCacheA_Call {"); WLog_Print(log, g_LogLevel, " szLookupName=%s", call->szLookupName); smartcard_log_context(log, &call->Common.handles.hContext); WLog_Print( log, g_LogLevel, "..CardIdentifier=%s", smartcard_array_dump(call->Common.CardIdentifier, sizeof(UUID), buffer, sizeof(buffer))); WLog_Print(log, g_LogLevel, " FreshnessCounter=%" PRIu32, call->Common.FreshnessCounter); WLog_Print(log, g_LogLevel, " cbDataLen=%" PRIu32, call->Common.cbDataLen); WLog_Print( log, g_LogLevel, " pbData=%s", smartcard_array_dump(call->Common.pbData, call->Common.cbDataLen, buffer, sizeof(buffer))); WLog_Print(log, g_LogLevel, "}"); } static void smartcard_trace_write_cache_w_call(wLog* log, const WriteCacheW_Call* call) { WINPR_ASSERT(call); char tmp[1024] = WINPR_C_ARRAY_INIT; char buffer[1024] = WINPR_C_ARRAY_INIT; if (!WLog_IsLevelActive(log, g_LogLevel)) return; WLog_Print(log, g_LogLevel, "WriteCacheW_Call {"); if (call->szLookupName) (void)ConvertWCharToUtf8(call->szLookupName, tmp, ARRAYSIZE(tmp)); WLog_Print(log, g_LogLevel, " szLookupName=%s", tmp); smartcard_log_context(log, &call->Common.handles.hContext); WLog_Print( log, g_LogLevel, "..CardIdentifier=%s", smartcard_array_dump(call->Common.CardIdentifier, sizeof(UUID), buffer, sizeof(buffer))); WLog_Print(log, g_LogLevel, " FreshnessCounter=%" PRIu32, call->Common.FreshnessCounter); WLog_Print(log, g_LogLevel, " cbDataLen=%" PRIu32, call->Common.cbDataLen); WLog_Print( log, g_LogLevel, " pbData=%s", smartcard_array_dump(call->Common.pbData, call->Common.cbDataLen, buffer, sizeof(buffer))); WLog_Print(log, g_LogLevel, "}"); } static void smartcard_trace_read_cache_a_call(wLog* log, const ReadCacheA_Call* call) { WINPR_ASSERT(call); char buffer[1024] = WINPR_C_ARRAY_INIT; if (!WLog_IsLevelActive(log, g_LogLevel)) return; WLog_Print(log, g_LogLevel, "ReadCacheA_Call {"); WLog_Print(log, g_LogLevel, " szLookupName=%s", call->szLookupName); smartcard_log_context(log, &call->Common.handles.hContext); WLog_Print( log, g_LogLevel, "..CardIdentifier=%s", smartcard_array_dump(call->Common.CardIdentifier, sizeof(UUID), buffer, sizeof(buffer))); WLog_Print(log, g_LogLevel, " FreshnessCounter=%" PRIu32, call->Common.FreshnessCounter); WLog_Print(log, g_LogLevel, " fPbDataIsNULL=%" PRId32, call->Common.fPbDataIsNULL); WLog_Print(log, g_LogLevel, " cbDataLen=%" PRIu32, call->Common.cbDataLen); WLog_Print(log, g_LogLevel, "}"); } static void smartcard_trace_read_cache_w_call(wLog* log, const ReadCacheW_Call* call) { WINPR_ASSERT(call); char tmp[1024] = WINPR_C_ARRAY_INIT; char buffer[1024] = WINPR_C_ARRAY_INIT; if (!WLog_IsLevelActive(log, g_LogLevel)) return; WLog_Print(log, g_LogLevel, "ReadCacheW_Call {"); if (call->szLookupName) (void)ConvertWCharToUtf8(call->szLookupName, tmp, ARRAYSIZE(tmp)); WLog_Print(log, g_LogLevel, " szLookupName=%s", tmp); smartcard_log_context(log, &call->Common.handles.hContext); WLog_Print( log, g_LogLevel, "..CardIdentifier=%s", smartcard_array_dump(call->Common.CardIdentifier, sizeof(UUID), buffer, sizeof(buffer))); WLog_Print(log, g_LogLevel, " FreshnessCounter=%" PRIu32, call->Common.FreshnessCounter); WLog_Print(log, g_LogLevel, " fPbDataIsNULL=%" PRId32, call->Common.fPbDataIsNULL); WLog_Print(log, g_LogLevel, " cbDataLen=%" PRIu32, call->Common.cbDataLen); WLog_Print(log, g_LogLevel, "}"); } static void smartcard_trace_transmit_call(wLog* log, const Transmit_Call* call) { WINPR_ASSERT(call); UINT32 cbExtraBytes = 0; BYTE* pbExtraBytes = nullptr; if (!WLog_IsLevelActive(log, g_LogLevel)) return; WLog_Print(log, g_LogLevel, "Transmit_Call {"); smartcard_log_context(log, &call->handles.hContext); smartcard_log_redir_handle(log, &call->handles.hCard); if (call->pioSendPci) { cbExtraBytes = (UINT32)(call->pioSendPci->cbPciLength - sizeof(SCARD_IO_REQUEST)); pbExtraBytes = &((BYTE*)call->pioSendPci)[sizeof(SCARD_IO_REQUEST)]; WLog_Print(log, g_LogLevel, "pioSendPci: dwProtocol: %" PRIu32 " cbExtraBytes: %" PRIu32 "", call->pioSendPci->dwProtocol, cbExtraBytes); if (cbExtraBytes) { char buffer[1024] = WINPR_C_ARRAY_INIT; WLog_Print(log, g_LogLevel, "pbExtraBytes: %s", smartcard_array_dump(pbExtraBytes, cbExtraBytes, buffer, sizeof(buffer))); } } else { WLog_Print(log, g_LogLevel, "pioSendPci: null"); } WLog_Print(log, g_LogLevel, "cbSendLength: %" PRIu32 "", call->cbSendLength); if (call->pbSendBuffer) { char buffer[1024] = WINPR_C_ARRAY_INIT; WLog_Print( log, g_LogLevel, "pbSendBuffer: %s", smartcard_array_dump(call->pbSendBuffer, call->cbSendLength, buffer, sizeof(buffer))); } else { WLog_Print(log, g_LogLevel, "pbSendBuffer: null"); } if (call->pioRecvPci) { cbExtraBytes = (UINT32)(call->pioRecvPci->cbPciLength - sizeof(SCARD_IO_REQUEST)); pbExtraBytes = &((BYTE*)call->pioRecvPci)[sizeof(SCARD_IO_REQUEST)]; WLog_Print(log, g_LogLevel, "pioRecvPci: dwProtocol: %" PRIu32 " cbExtraBytes: %" PRIu32 "", call->pioRecvPci->dwProtocol, cbExtraBytes); if (cbExtraBytes) { char buffer[1024] = WINPR_C_ARRAY_INIT; WLog_Print(log, g_LogLevel, "pbExtraBytes: %s", smartcard_array_dump(pbExtraBytes, cbExtraBytes, buffer, sizeof(buffer))); } } else { WLog_Print(log, g_LogLevel, "pioRecvPci: null"); } WLog_Print(log, g_LogLevel, "fpbRecvBufferIsNULL: %" PRId32 " cbRecvLength: %" PRIu32 "", call->fpbRecvBufferIsNULL, call->cbRecvLength); WLog_Print(log, g_LogLevel, "}"); } static void smartcard_trace_locate_cards_by_atr_w_call(wLog* log, const LocateCardsByATRW_Call* call) { WINPR_ASSERT(call); if (!WLog_IsLevelActive(log, g_LogLevel)) return; WLog_Print(log, g_LogLevel, "LocateCardsByATRW_Call {"); smartcard_log_context(log, &call->handles.hContext); dump_reader_states_w(log, call->rgReaderStates, call->cReaders); WLog_Print(log, g_LogLevel, "}"); } static void smartcard_trace_transmit_return(wLog* log, const Transmit_Return* ret) { WINPR_ASSERT(ret); UINT32 cbExtraBytes = 0; BYTE* pbExtraBytes = nullptr; if (!WLog_IsLevelActive(log, g_LogLevel)) return; WLog_Print(log, g_LogLevel, "Transmit_Return {"); WLog_Print(log, g_LogLevel, " ReturnCode: %s (0x%08" PRIX32 ")", SCardGetErrorString(ret->ReturnCode), WINPR_CXX_COMPAT_CAST(UINT32, ret->ReturnCode)); if (ret->pioRecvPci) { cbExtraBytes = (UINT32)(ret->pioRecvPci->cbPciLength - sizeof(SCARD_IO_REQUEST)); pbExtraBytes = &((BYTE*)ret->pioRecvPci)[sizeof(SCARD_IO_REQUEST)]; WLog_Print(log, g_LogLevel, " pioRecvPci: dwProtocol: %" PRIu32 " cbExtraBytes: %" PRIu32 "", ret->pioRecvPci->dwProtocol, cbExtraBytes); if (cbExtraBytes) { char buffer[1024] = WINPR_C_ARRAY_INIT; WLog_Print(log, g_LogLevel, " pbExtraBytes: %s", smartcard_array_dump(pbExtraBytes, cbExtraBytes, buffer, sizeof(buffer))); } } else { WLog_Print(log, g_LogLevel, " pioRecvPci: null"); } WLog_Print(log, g_LogLevel, " cbRecvLength: %" PRIu32 "", ret->cbRecvLength); if (ret->pbRecvBuffer) { char buffer[1024] = WINPR_C_ARRAY_INIT; WLog_Print( log, g_LogLevel, " pbRecvBuffer: %s", smartcard_array_dump(ret->pbRecvBuffer, ret->cbRecvLength, buffer, sizeof(buffer))); } else { WLog_Print(log, g_LogLevel, " pbRecvBuffer: null"); } WLog_Print(log, g_LogLevel, "}"); } static void smartcard_trace_control_return(wLog* log, const Control_Return* ret) { WINPR_ASSERT(ret); if (!WLog_IsLevelActive(log, g_LogLevel)) return; WLog_Print(log, g_LogLevel, "Control_Return {"); WLog_Print(log, g_LogLevel, " ReturnCode: %s (0x%08" PRIX32 ")", SCardGetErrorString(ret->ReturnCode), WINPR_CXX_COMPAT_CAST(UINT32, ret->ReturnCode)); WLog_Print(log, g_LogLevel, " cbOutBufferSize: %" PRIu32 "", ret->cbOutBufferSize); if (ret->pvOutBuffer) { char buffer[1024] = WINPR_C_ARRAY_INIT; WLog_Print( log, g_LogLevel, "pvOutBuffer: %s", smartcard_array_dump(ret->pvOutBuffer, ret->cbOutBufferSize, buffer, sizeof(buffer))); } else { WLog_Print(log, g_LogLevel, "pvOutBuffer: null"); } WLog_Print(log, g_LogLevel, "}"); } static void smartcard_trace_control_call(wLog* log, const Control_Call* call) { WINPR_ASSERT(call); if (!WLog_IsLevelActive(log, g_LogLevel)) return; WLog_Print(log, g_LogLevel, "Control_Call {"); smartcard_log_context(log, &call->handles.hContext); smartcard_log_redir_handle(log, &call->handles.hCard); WLog_Print(log, g_LogLevel, "dwControlCode: 0x%08" PRIX32 " cbInBufferSize: %" PRIu32 " fpvOutBufferIsNULL: %" PRId32 " cbOutBufferSize: %" PRIu32 "", call->dwControlCode, call->cbInBufferSize, call->fpvOutBufferIsNULL, call->cbOutBufferSize); if (call->pvInBuffer) { char buffer[1024] = WINPR_C_ARRAY_INIT; WLog_Print( log, WLOG_DEBUG, "pbInBuffer: %s", smartcard_array_dump(call->pvInBuffer, call->cbInBufferSize, buffer, sizeof(buffer))); } else { WLog_Print(log, g_LogLevel, "pvInBuffer: null"); } WLog_Print(log, g_LogLevel, "}"); } static void smartcard_trace_set_attrib_call(wLog* log, const SetAttrib_Call* call) { WINPR_ASSERT(call); char buffer[8192] = WINPR_C_ARRAY_INIT; if (!WLog_IsLevelActive(log, g_LogLevel)) return; WLog_Print(log, g_LogLevel, "GetAttrib_Call {"); smartcard_log_context(log, &call->handles.hContext); smartcard_log_redir_handle(log, &call->handles.hCard); WLog_Print(log, g_LogLevel, "dwAttrId: 0x%08" PRIX32, call->dwAttrId); WLog_Print(log, g_LogLevel, "cbAttrLen: 0x%08" PRIx32, call->cbAttrLen); WLog_Print(log, g_LogLevel, "pbAttr: %s", smartcard_array_dump(call->pbAttr, call->cbAttrLen, buffer, sizeof(buffer))); WLog_Print(log, g_LogLevel, "}"); } static void smartcard_trace_get_attrib_return(wLog* log, const GetAttrib_Return* ret, DWORD dwAttrId) { WINPR_ASSERT(ret); char buffer[1024] = WINPR_C_ARRAY_INIT; if (!WLog_IsLevelActive(log, g_LogLevel)) return; WLog_Print(log, g_LogLevel, "GetAttrib_Return {"); WLog_Print(log, g_LogLevel, " ReturnCode: %s (0x%08" PRIX32 ")", SCardGetErrorString(ret->ReturnCode), WINPR_CXX_COMPAT_CAST(UINT32, ret->ReturnCode)); WLog_Print(log, g_LogLevel, " dwAttrId: %s (0x%08" PRIX32 ") cbAttrLen: 0x%08" PRIX32 "", SCardGetAttributeString(dwAttrId), dwAttrId, ret->cbAttrLen); WLog_Print(log, g_LogLevel, " %s", smartcard_array_dump(ret->pbAttr, ret->cbAttrLen, buffer, sizeof(buffer))); WLog_Print(log, g_LogLevel, "}"); } static void smartcard_trace_get_attrib_call(wLog* log, const GetAttrib_Call* call) { WINPR_ASSERT(call); if (!WLog_IsLevelActive(log, g_LogLevel)) return; WLog_Print(log, g_LogLevel, "GetAttrib_Call {"); smartcard_log_context(log, &call->handles.hContext); smartcard_log_redir_handle(log, &call->handles.hCard); WLog_Print(log, g_LogLevel, "dwAttrId: %s (0x%08" PRIX32 ") fpbAttrIsNULL: %" PRId32 " cbAttrLen: 0x%08" PRIX32 "", SCardGetAttributeString(call->dwAttrId), call->dwAttrId, call->fpbAttrIsNULL, call->cbAttrLen); WLog_Print(log, g_LogLevel, "}"); } static void smartcard_trace_status_call(wLog* log, const Status_Call* call, BOOL unicode) { WINPR_ASSERT(call); if (!WLog_IsLevelActive(log, g_LogLevel)) return; WLog_Print(log, g_LogLevel, "Status%s_Call {", unicode ? "W" : "A"); smartcard_log_context(log, &call->handles.hContext); smartcard_log_redir_handle(log, &call->handles.hCard); WLog_Print(log, g_LogLevel, "fmszReaderNamesIsNULL: %" PRId32 " cchReaderLen: %" PRIu32 " cbAtrLen: %" PRIu32 "", call->fmszReaderNamesIsNULL, call->cchReaderLen, call->cbAtrLen); WLog_Print(log, g_LogLevel, "}"); } static void smartcard_trace_status_return(wLog* log, const Status_Return* ret, BOOL unicode) { WINPR_ASSERT(ret); char* mszReaderNamesA = nullptr; char buffer[1024] = WINPR_C_ARRAY_INIT; DWORD cBytes = 0; if (!WLog_IsLevelActive(log, g_LogLevel)) return; cBytes = ret->cBytes; if (ret->ReturnCode != SCARD_S_SUCCESS) cBytes = 0; if (cBytes == SCARD_AUTOALLOCATE) cBytes = 0; mszReaderNamesA = smartcard_convert_string_list(ret->mszReaderNames, cBytes, unicode); WLog_Print(log, g_LogLevel, "Status%s_Return {", unicode ? "W" : "A"); WLog_Print(log, g_LogLevel, " ReturnCode: %s (0x%08" PRIX32 ")", SCardGetErrorString(ret->ReturnCode), WINPR_CXX_COMPAT_CAST(UINT32, ret->ReturnCode)); WLog_Print(log, g_LogLevel, " dwState: %s (0x%08" PRIX32 ") dwProtocol: %s (0x%08" PRIX32 ")", SCardGetCardStateString(ret->dwState), ret->dwState, SCardGetProtocolString(ret->dwProtocol), ret->dwProtocol); WLog_Print(log, g_LogLevel, " cBytes: %" PRIu32 " mszReaderNames: %s", ret->cBytes, mszReaderNamesA); WLog_Print(log, g_LogLevel, " cbAtrLen: %" PRIu32 " pbAtr: %s", ret->cbAtrLen, smartcard_array_dump(ret->pbAtr, ret->cbAtrLen, buffer, sizeof(buffer))); WLog_Print(log, g_LogLevel, "}"); free(mszReaderNamesA); } static void smartcard_trace_state_return(wLog* log, const State_Return* ret) { WINPR_ASSERT(ret); char buffer[1024] = WINPR_C_ARRAY_INIT; char* state = nullptr; if (!WLog_IsLevelActive(log, g_LogLevel)) return; state = SCardGetReaderStateString(ret->dwState); WLog_Print(log, g_LogLevel, "Reconnect_Return {"); WLog_Print(log, g_LogLevel, " ReturnCode: %s (0x%08" PRIX32 ")", SCardGetErrorString(ret->ReturnCode), WINPR_CXX_COMPAT_CAST(UINT32, ret->ReturnCode)); WLog_Print(log, g_LogLevel, " dwState: %s (0x%08" PRIX32 ")", state, ret->dwState); WLog_Print(log, g_LogLevel, " dwProtocol: %s (0x%08" PRIX32 ")", SCardGetProtocolString(ret->dwProtocol), ret->dwProtocol); WLog_Print(log, g_LogLevel, " cbAtrLen: (0x%08" PRIX32 ")", ret->cbAtrLen); WLog_Print(log, g_LogLevel, " rgAtr: %s", smartcard_array_dump(ret->rgAtr, sizeof(ret->rgAtr), buffer, sizeof(buffer))); WLog_Print(log, g_LogLevel, "}"); free(state); } static void smartcard_trace_reconnect_return(wLog* log, const Reconnect_Return* ret) { WINPR_ASSERT(ret); if (!WLog_IsLevelActive(log, g_LogLevel)) return; WLog_Print(log, g_LogLevel, "Reconnect_Return {"); WLog_Print(log, g_LogLevel, " ReturnCode: %s (0x%08" PRIX32 ")", SCardGetErrorString(ret->ReturnCode), WINPR_CXX_COMPAT_CAST(UINT32, ret->ReturnCode)); WLog_Print(log, g_LogLevel, " dwActiveProtocol: %s (0x%08" PRIX32 ")", SCardGetProtocolString(ret->dwActiveProtocol), ret->dwActiveProtocol); WLog_Print(log, g_LogLevel, "}"); } static void smartcard_trace_connect_a_call(wLog* log, const ConnectA_Call* call) { WINPR_ASSERT(call); if (!WLog_IsLevelActive(log, g_LogLevel)) return; WLog_Print(log, g_LogLevel, "ConnectA_Call {"); smartcard_log_context(log, &call->Common.handles.hContext); WLog_Print(log, g_LogLevel, "szReader: %s dwShareMode: %s (0x%08" PRIX32 ") dwPreferredProtocols: %s (0x%08" PRIX32 ")", call->szReader, SCardGetShareModeString(call->Common.dwShareMode), call->Common.dwShareMode, SCardGetProtocolString(call->Common.dwPreferredProtocols), call->Common.dwPreferredProtocols); WLog_Print(log, g_LogLevel, "}"); } static void smartcard_trace_connect_w_call(wLog* log, const ConnectW_Call* call) { WINPR_ASSERT(call); char szReaderA[1024] = WINPR_C_ARRAY_INIT; if (!WLog_IsLevelActive(log, g_LogLevel)) return; if (call->szReader) (void)ConvertWCharToUtf8(call->szReader, szReaderA, ARRAYSIZE(szReaderA)); WLog_Print(log, g_LogLevel, "ConnectW_Call {"); smartcard_log_context(log, &call->Common.handles.hContext); WLog_Print(log, g_LogLevel, "szReader: %s dwShareMode: %s (0x%08" PRIX32 ") dwPreferredProtocols: %s (0x%08" PRIX32 ")", szReaderA, SCardGetShareModeString(call->Common.dwShareMode), call->Common.dwShareMode, SCardGetProtocolString(call->Common.dwPreferredProtocols), call->Common.dwPreferredProtocols); WLog_Print(log, g_LogLevel, "}"); } static void smartcard_trace_hcard_and_disposition_call(wLog* log, const HCardAndDisposition_Call* call, const char* name) { WINPR_ASSERT(call); if (!WLog_IsLevelActive(log, g_LogLevel)) return; WLog_Print(log, g_LogLevel, "%s_Call {", name); smartcard_log_context(log, &call->handles.hContext); smartcard_log_redir_handle(log, &call->handles.hCard); WLog_Print(log, g_LogLevel, "dwDisposition: %s (0x%08" PRIX32 ")", SCardGetDispositionString(call->dwDisposition), call->dwDisposition); WLog_Print(log, g_LogLevel, "}"); } static void smartcard_trace_establish_context_call(wLog* log, const EstablishContext_Call* call) { WINPR_ASSERT(call); if (!WLog_IsLevelActive(log, g_LogLevel)) return; WLog_Print(log, g_LogLevel, "EstablishContext_Call {"); WLog_Print(log, g_LogLevel, "dwScope: %s (0x%08" PRIX32 ")", SCardGetScopeString(call->dwScope), call->dwScope); WLog_Print(log, g_LogLevel, "}"); } static void smartcard_trace_establish_context_return(wLog* log, const EstablishContext_Return* ret) { WINPR_ASSERT(ret); if (!WLog_IsLevelActive(log, g_LogLevel)) return; WLog_Print(log, g_LogLevel, "EstablishContext_Return {"); WLog_Print(log, g_LogLevel, " ReturnCode: %s (0x%08" PRIX32 ")", SCardGetErrorString(ret->ReturnCode), WINPR_CXX_COMPAT_CAST(UINT32, ret->ReturnCode)); smartcard_log_context(log, &ret->hContext); WLog_Print(log, g_LogLevel, "}"); } void smartcard_trace_long_return(const Long_Return* ret, const char* name) { wLog* log = scard_log(); smartcard_trace_long_return_int(log, ret, name); } void smartcard_trace_long_return_int(wLog* log, const Long_Return* ret, const char* name) { WINPR_ASSERT(ret); if (!WLog_IsLevelActive(log, g_LogLevel)) return; WLog_Print(log, g_LogLevel, "%s_Return {", name); WLog_Print(log, g_LogLevel, " ReturnCode: %s (0x%08" PRIX32 ")", SCardGetErrorString(ret->ReturnCode), WINPR_CXX_COMPAT_CAST(UINT32, ret->ReturnCode)); WLog_Print(log, g_LogLevel, "}"); } static void smartcard_trace_connect_return(wLog* log, const Connect_Return* ret) { WINPR_ASSERT(ret); if (!WLog_IsLevelActive(log, g_LogLevel)) return; WLog_Print(log, g_LogLevel, "Connect_Return {"); WLog_Print(log, g_LogLevel, " ReturnCode: %s (0x%08" PRIX32 ")", SCardGetErrorString(ret->ReturnCode), WINPR_CXX_COMPAT_CAST(UINT32, ret->ReturnCode)); smartcard_log_context(log, &ret->hContext); smartcard_log_redir_handle(log, &ret->hCard); WLog_Print(log, g_LogLevel, " dwActiveProtocol: %s (0x%08" PRIX32 ")", SCardGetProtocolString(ret->dwActiveProtocol), ret->dwActiveProtocol); WLog_Print(log, g_LogLevel, "}"); } static void smartcard_trace_reconnect_call(wLog* log, const Reconnect_Call* call) { WINPR_ASSERT(call); if (!WLog_IsLevelActive(log, g_LogLevel)) return; WLog_Print(log, g_LogLevel, "Reconnect_Call {"); smartcard_log_context(log, &call->handles.hContext); smartcard_log_redir_handle(log, &call->handles.hCard); WLog_Print(log, g_LogLevel, "dwShareMode: %s (0x%08" PRIX32 ") dwPreferredProtocols: %s (0x%08" PRIX32 ") dwInitialization: %s (0x%08" PRIX32 ")", SCardGetShareModeString(call->dwShareMode), call->dwShareMode, SCardGetProtocolString(call->dwPreferredProtocols), call->dwPreferredProtocols, SCardGetDispositionString(call->dwInitialization), call->dwInitialization); WLog_Print(log, g_LogLevel, "}"); } static void smartcard_trace_device_type_id_return(wLog* log, const GetDeviceTypeId_Return* ret) { WINPR_ASSERT(ret); if (!WLog_IsLevelActive(log, g_LogLevel)) return; WLog_Print(log, g_LogLevel, "GetDeviceTypeId_Return {"); WLog_Print(log, g_LogLevel, " ReturnCode: %s (0x%08" PRIX32 ")", SCardGetErrorString(ret->ReturnCode), WINPR_CXX_COMPAT_CAST(UINT32, ret->ReturnCode)); WLog_Print(log, g_LogLevel, " dwDeviceId=%08" PRIx32, ret->dwDeviceId); WLog_Print(log, g_LogLevel, "}"); } static LONG smartcard_unpack_common_context_and_string_a(wLog* log, wStream* s, REDIR_SCARDCONTEXT* phContext, CHAR** pszReaderName) { UINT32 index = 0; UINT32 pbContextNdrPtr = 0; LONG status = smartcard_unpack_redir_scard_context(log, s, phContext, &index, &pbContextNdrPtr); if (status != SCARD_S_SUCCESS) return status; if (!smartcard_ndr_pointer_read(log, s, &index, nullptr)) return ERROR_INVALID_DATA; status = smartcard_unpack_redir_scard_context_ref(log, s, pbContextNdrPtr, phContext); if (status != SCARD_S_SUCCESS) return status; status = smartcard_ndr_read_a(log, s, pszReaderName, NDR_PTR_FULL); if (status != SCARD_S_SUCCESS) return status; smartcard_trace_context_and_string_call_a(log, __func__, phContext, *pszReaderName); return SCARD_S_SUCCESS; } static LONG smartcard_unpack_common_context_and_string_w(wLog* log, wStream* s, REDIR_SCARDCONTEXT* phContext, WCHAR** pszReaderName) { UINT32 index = 0; UINT32 pbContextNdrPtr = 0; LONG status = smartcard_unpack_redir_scard_context(log, s, phContext, &index, &pbContextNdrPtr); if (status != SCARD_S_SUCCESS) return status; if (!smartcard_ndr_pointer_read(log, s, &index, nullptr)) return ERROR_INVALID_DATA; status = smartcard_unpack_redir_scard_context_ref(log, s, pbContextNdrPtr, phContext); if (status != SCARD_S_SUCCESS) return status; status = smartcard_ndr_read_w(log, s, pszReaderName, NDR_PTR_FULL); if (status != SCARD_S_SUCCESS) return status; smartcard_trace_context_and_string_call_w(log, __func__, phContext, *pszReaderName); return SCARD_S_SUCCESS; } LONG smartcard_unpack_common_type_header(wStream* s) { wLog* log = scard_log(); UINT8 version = 0; UINT32 filler = 0; UINT8 endianness = 0; UINT16 commonHeaderLength = 0; if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 8)) return STATUS_BUFFER_TOO_SMALL; /* Process CommonTypeHeader */ Stream_Read_UINT8(s, version); /* Version (1 byte) */ Stream_Read_UINT8(s, endianness); /* Endianness (1 byte) */ Stream_Read_UINT16(s, commonHeaderLength); /* CommonHeaderLength (2 bytes) */ Stream_Read_UINT32(s, filler); /* Filler (4 bytes), should be 0xCCCCCCCC */ if (version != 1) { WLog_Print(log, WLOG_WARN, "Unsupported CommonTypeHeader Version %" PRIu8 "", version); return STATUS_INVALID_PARAMETER; } if (endianness != 0x10) { WLog_Print(log, WLOG_WARN, "Unsupported CommonTypeHeader Endianness %" PRIu8 "", endianness); return STATUS_INVALID_PARAMETER; } if (commonHeaderLength != 8) { WLog_Print(log, WLOG_WARN, "Unsupported CommonTypeHeader CommonHeaderLength %" PRIu16 "", commonHeaderLength); return STATUS_INVALID_PARAMETER; } if (filler != 0xCCCCCCCC) { WLog_Print(log, WLOG_WARN, "Unexpected CommonTypeHeader Filler 0x%08" PRIX32 "", filler); return STATUS_INVALID_PARAMETER; } return SCARD_S_SUCCESS; } void smartcard_pack_common_type_header(wStream* s) { Stream_Write_UINT8(s, 1); /* Version (1 byte) */ Stream_Write_UINT8(s, 0x10); /* Endianness (1 byte) */ Stream_Write_UINT16(s, 8); /* CommonHeaderLength (2 bytes) */ Stream_Write_UINT32(s, 0xCCCCCCCC); /* Filler (4 bytes), should be 0xCCCCCCCC */ } LONG smartcard_unpack_private_type_header(wStream* s) { wLog* log = scard_log(); UINT32 filler = 0; UINT32 objectBufferLength = 0; if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 8)) return STATUS_BUFFER_TOO_SMALL; Stream_Read_UINT32(s, objectBufferLength); /* ObjectBufferLength (4 bytes) */ Stream_Read_UINT32(s, filler); /* Filler (4 bytes), should be 0x00000000 */ if (filler != 0x00000000) { WLog_Print(log, WLOG_WARN, "Unexpected PrivateTypeHeader Filler 0x%08" PRIX32 "", filler); return STATUS_INVALID_PARAMETER; } if (!Stream_CheckAndLogRequiredLengthWLog(log, s, objectBufferLength)) return STATUS_INVALID_PARAMETER; return SCARD_S_SUCCESS; } void smartcard_pack_private_type_header(wStream* s, UINT32 objectBufferLength) { Stream_Write_UINT32(s, objectBufferLength); /* ObjectBufferLength (4 bytes) */ Stream_Write_UINT32(s, 0x00000000); /* Filler (4 bytes), should be 0x00000000 */ } LONG smartcard_unpack_read_size_align(wStream* s, size_t size, UINT32 alignment) { const size_t padsize = (size + alignment - 1) & ~(alignment - 1); const size_t pad = padsize - size; if (pad > 0) { if (!Stream_SafeSeek(s, pad)) return -1; } return (LONG)pad; } LONG smartcard_pack_write_size_align(wStream* s, size_t size, UINT32 alignment) { const size_t padsize = (size + alignment - 1) & ~(alignment - 1); const size_t pad = padsize - size; if (pad) { if (!Stream_EnsureRemainingCapacity(s, pad)) { wLog* log = scard_log(); WLog_Print(log, WLOG_ERROR, "Stream_EnsureRemainingCapacity failed!"); return SCARD_F_INTERNAL_ERROR; } Stream_Zero(s, pad); } return SCARD_S_SUCCESS; } SCARDCONTEXT smartcard_scard_context_native_from_redir(REDIR_SCARDCONTEXT* context) { SCARDCONTEXT hContext = WINPR_C_ARRAY_INIT; WINPR_ASSERT(context); if ((context->cbContext != sizeof(ULONG_PTR)) && (context->cbContext != 0)) { wLog* log = scard_log(); WLog_Print(log, WLOG_WARN, "REDIR_SCARDCONTEXT does not match native size: Actual: %" PRIu32 ", Expected: %" PRIuz "", context->cbContext, sizeof(ULONG_PTR)); return 0; } if (context->cbContext) CopyMemory(&hContext, &(context->pbContext), context->cbContext); return hContext; } void smartcard_scard_context_native_to_redir(REDIR_SCARDCONTEXT* context, SCARDCONTEXT hContext) { WINPR_ASSERT(context); ZeroMemory(context, sizeof(REDIR_SCARDCONTEXT)); context->cbContext = sizeof(ULONG_PTR); CopyMemory(&(context->pbContext), &hContext, context->cbContext); } SCARDHANDLE smartcard_scard_handle_native_from_redir(REDIR_SCARDHANDLE* handle) { SCARDHANDLE hCard = 0; WINPR_ASSERT(handle); if (handle->cbHandle == 0) return hCard; if (handle->cbHandle != sizeof(ULONG_PTR)) { wLog* log = scard_log(); WLog_Print(log, WLOG_WARN, "REDIR_SCARDHANDLE does not match native size: Actual: %" PRIu32 ", Expected: %" PRIuz "", handle->cbHandle, sizeof(ULONG_PTR)); return 0; } if (handle->cbHandle) CopyMemory(&hCard, &(handle->pbHandle), handle->cbHandle); return hCard; } void smartcard_scard_handle_native_to_redir(REDIR_SCARDHANDLE* handle, SCARDHANDLE hCard) { WINPR_ASSERT(handle); ZeroMemory(handle, sizeof(REDIR_SCARDHANDLE)); handle->cbHandle = sizeof(ULONG_PTR); CopyMemory(&(handle->pbHandle), &hCard, handle->cbHandle); } #define smartcard_context_supported(log, size) \ smartcard_context_supported_((log), (size), __FILE__, __func__, __LINE__) static LONG smartcard_context_supported_(wLog* log, uint32_t size, const char* file, const char* fkt, size_t line) { switch (size) { case 0: case 4: case 8: return SCARD_S_SUCCESS; default: { const uint32_t level = WLOG_WARN; if (WLog_IsLevelActive(log, level)) { WLog_PrintTextMessage(log, level, line, file, fkt, "REDIR_SCARDCONTEXT length is not 0, 4 or 8: %" PRIu32 "", size); } return STATUS_INVALID_PARAMETER; } } } LONG smartcard_unpack_redir_scard_context_(wLog* log, wStream* s, REDIR_SCARDCONTEXT* context, UINT32* index, UINT32* ppbContextNdrPtr, const char* file, const char* function, size_t line) { UINT32 pbContextNdrPtr = 0; WINPR_UNUSED(file); WINPR_ASSERT(context); ZeroMemory(context, sizeof(REDIR_SCARDCONTEXT)); if (!Stream_CheckAndLogRequiredLengthWLogEx(log, WLOG_WARN, s, 4, 1, "%s(%s:%" PRIuz ")", file, function, line)) return STATUS_BUFFER_TOO_SMALL; const LONG status = smartcard_context_supported_(log, context->cbContext, file, function, line); if (status != SCARD_S_SUCCESS) return status; Stream_Read_UINT32(s, context->cbContext); /* cbContext (4 bytes) */ if (!smartcard_ndr_pointer_read_(log, s, index, &pbContextNdrPtr, file, function, line)) return ERROR_INVALID_DATA; if (((context->cbContext == 0) && pbContextNdrPtr) || ((context->cbContext != 0) && !pbContextNdrPtr)) { WLog_Print(log, WLOG_WARN, "REDIR_SCARDCONTEXT cbContext (%" PRIu32 ") pbContextNdrPtr (%" PRIu32 ") inconsistency", context->cbContext, pbContextNdrPtr); return STATUS_INVALID_PARAMETER; } if (!Stream_CheckAndLogRequiredLengthWLogEx(log, WLOG_WARN, s, context->cbContext, 1, "%s(%s:%" PRIuz ")", file, function, line)) return STATUS_INVALID_PARAMETER; *ppbContextNdrPtr = pbContextNdrPtr; return SCARD_S_SUCCESS; } LONG smartcard_pack_redir_scard_context(WINPR_ATTR_UNUSED wLog* log, wStream* s, const REDIR_SCARDCONTEXT* context, DWORD* index) { const UINT32 pbContextNdrPtr = 0x00020000 + *index * 4; WINPR_ASSERT(context); if (context->cbContext != 0) { Stream_Write_UINT32(s, context->cbContext); /* cbContext (4 bytes) */ Stream_Write_UINT32(s, pbContextNdrPtr); /* pbContextNdrPtr (4 bytes) */ *index = *index + 1; } else Stream_Zero(s, 8); return SCARD_S_SUCCESS; } LONG smartcard_unpack_redir_scard_context_ref(wLog* log, wStream* s, WINPR_ATTR_UNUSED UINT32 pbContextNdrPtr, REDIR_SCARDCONTEXT* context) { UINT32 length = 0; WINPR_ASSERT(context); if (context->cbContext == 0) return SCARD_S_SUCCESS; if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4)) return STATUS_BUFFER_TOO_SMALL; Stream_Read_UINT32(s, length); /* Length (4 bytes) */ if (length != context->cbContext) { WLog_Print(log, WLOG_WARN, "REDIR_SCARDCONTEXT length (%" PRIu32 ") cbContext (%" PRIu32 ") mismatch", length, context->cbContext); return STATUS_INVALID_PARAMETER; } const LONG status = smartcard_context_supported(log, context->cbContext); if (status != SCARD_S_SUCCESS) return status; if (!Stream_CheckAndLogRequiredLengthWLog(log, s, context->cbContext)) return STATUS_BUFFER_TOO_SMALL; if (context->cbContext) Stream_Read(s, &(context->pbContext), context->cbContext); else ZeroMemory(&(context->pbContext), sizeof(context->pbContext)); return SCARD_S_SUCCESS; } LONG smartcard_pack_redir_scard_context_ref(WINPR_ATTR_UNUSED wLog* log, wStream* s, const REDIR_SCARDCONTEXT* context) { WINPR_ASSERT(context); Stream_Write_UINT32(s, context->cbContext); /* Length (4 bytes) */ if (context->cbContext) { Stream_Write(s, &(context->pbContext), context->cbContext); } return SCARD_S_SUCCESS; } LONG smartcard_unpack_redir_scard_handle_(wLog* log, wStream* s, REDIR_SCARDHANDLE* handle, UINT32* index, const char* file, const char* function, size_t line) { WINPR_ASSERT(handle); ZeroMemory(handle, sizeof(REDIR_SCARDHANDLE)); if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4)) return STATUS_BUFFER_TOO_SMALL; Stream_Read_UINT32(s, handle->cbHandle); /* Length (4 bytes) */ if (!Stream_CheckAndLogRequiredLengthWLog(log, s, handle->cbHandle)) return STATUS_BUFFER_TOO_SMALL; if (!smartcard_ndr_pointer_read_(log, s, index, nullptr, file, function, line)) return ERROR_INVALID_DATA; return SCARD_S_SUCCESS; } LONG smartcard_pack_redir_scard_handle(WINPR_ATTR_UNUSED wLog* log, wStream* s, const REDIR_SCARDHANDLE* handle, DWORD* index) { const UINT32 pbContextNdrPtr = 0x00020000 + *index * 4; WINPR_ASSERT(handle); if (handle->cbHandle != 0) { Stream_Write_UINT32(s, handle->cbHandle); /* cbContext (4 bytes) */ Stream_Write_UINT32(s, pbContextNdrPtr); /* pbContextNdrPtr (4 bytes) */ *index = *index + 1; } else Stream_Zero(s, 8); return SCARD_S_SUCCESS; } LONG smartcard_unpack_redir_scard_handle_ref(wLog* log, wStream* s, REDIR_SCARDHANDLE* handle) { UINT32 length = 0; WINPR_ASSERT(handle); if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4)) return STATUS_BUFFER_TOO_SMALL; Stream_Read_UINT32(s, length); /* Length (4 bytes) */ if (length != handle->cbHandle) { WLog_Print(log, WLOG_WARN, "REDIR_SCARDHANDLE length (%" PRIu32 ") cbHandle (%" PRIu32 ") mismatch", length, handle->cbHandle); return STATUS_INVALID_PARAMETER; } if ((handle->cbHandle != 4) && (handle->cbHandle != 8)) { WLog_Print(log, WLOG_WARN, "REDIR_SCARDHANDLE length is not 4 or 8: %" PRIu32 "", handle->cbHandle); return STATUS_INVALID_PARAMETER; } if (!Stream_CheckAndLogRequiredLengthWLog(log, s, handle->cbHandle)) return STATUS_BUFFER_TOO_SMALL; if (handle->cbHandle) Stream_Read(s, &(handle->pbHandle), handle->cbHandle); return SCARD_S_SUCCESS; } LONG smartcard_pack_redir_scard_handle_ref(WINPR_ATTR_UNUSED wLog* log, wStream* s, const REDIR_SCARDHANDLE* handle) { WINPR_ASSERT(handle); Stream_Write_UINT32(s, handle->cbHandle); /* Length (4 bytes) */ if (handle->cbHandle) Stream_Write(s, &(handle->pbHandle), handle->cbHandle); return SCARD_S_SUCCESS; } LONG smartcard_unpack_establish_context_call(wStream* s, EstablishContext_Call* call) { WINPR_ASSERT(call); wLog* log = scard_log(); if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4)) return STATUS_BUFFER_TOO_SMALL; Stream_Read_UINT32(s, call->dwScope); /* dwScope (4 bytes) */ smartcard_trace_establish_context_call(log, call); return SCARD_S_SUCCESS; } LONG smartcard_pack_establish_context_return(wStream* s, const EstablishContext_Return* ret) { WINPR_ASSERT(ret); wLog* log = scard_log(); LONG status = 0; DWORD index = 0; smartcard_trace_establish_context_return(log, ret); if (ret->ReturnCode != SCARD_S_SUCCESS) return ret->ReturnCode; status = smartcard_pack_redir_scard_context(log, s, &(ret->hContext), &index); if (status != SCARD_S_SUCCESS) return status; return smartcard_pack_redir_scard_context_ref(log, s, &(ret->hContext)); } LONG smartcard_unpack_context_call(wStream* s, Context_Call* call, const char* name) { UINT32 index = 0; UINT32 pbContextNdrPtr = 0; wLog* log = scard_log(); WINPR_ASSERT(call); LONG status = smartcard_unpack_redir_scard_context(log, s, &(call->handles.hContext), &index, &pbContextNdrPtr); if (status != SCARD_S_SUCCESS) return status; status = smartcard_unpack_redir_scard_context_ref(log, s, pbContextNdrPtr, &(call->handles.hContext)); if (status != SCARD_S_SUCCESS) WLog_Print(log, WLOG_ERROR, "smartcard_unpack_redir_scard_context_ref failed with error %" PRId32 "", status); smartcard_trace_context_call(log, call, name); return status; } LONG smartcard_unpack_list_reader_groups_call(wStream* s, ListReaderGroups_Call* call, BOOL unicode) { UINT32 index = 0; UINT32 pbContextNdrPtr = 0; wLog* log = scard_log(); WINPR_ASSERT(call); LONG status = smartcard_unpack_redir_scard_context(log, s, &(call->handles.hContext), &index, &pbContextNdrPtr); if (status != SCARD_S_SUCCESS) return status; if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 8)) return STATUS_BUFFER_TOO_SMALL; Stream_Read_INT32(s, call->fmszGroupsIsNULL); /* fmszGroupsIsNULL (4 bytes) */ Stream_Read_UINT32(s, call->cchGroups); /* cchGroups (4 bytes) */ status = smartcard_unpack_redir_scard_context_ref(log, s, pbContextNdrPtr, &(call->handles.hContext)); if (status != SCARD_S_SUCCESS) return status; smartcard_trace_list_reader_groups_call(log, call, unicode); return SCARD_S_SUCCESS; } LONG smartcard_pack_list_reader_groups_return(wStream* s, const ListReaderGroups_Return* ret, BOOL unicode) { WINPR_ASSERT(ret); wLog* log = scard_log(); LONG status = 0; DWORD cBytes = ret->cBytes; UINT32 index = 0; smartcard_trace_list_reader_groups_return(log, ret, unicode); if (ret->ReturnCode != SCARD_S_SUCCESS) cBytes = 0; if (cBytes == SCARD_AUTOALLOCATE) cBytes = 0; if (!Stream_EnsureRemainingCapacity(s, 4)) return SCARD_E_NO_MEMORY; Stream_Write_UINT32(s, cBytes); /* cBytes (4 bytes) */ if (!smartcard_ndr_pointer_write(s, &index, cBytes)) return SCARD_E_NO_MEMORY; status = smartcard_ndr_write(s, ret->msz, cBytes, 1, NDR_PTR_SIMPLE); if (status != SCARD_S_SUCCESS) return status; return ret->ReturnCode; } LONG smartcard_unpack_list_readers_call(wStream* s, ListReaders_Call* call, BOOL unicode) { UINT32 index = 0; UINT32 mszGroupsNdrPtr = 0; UINT32 pbContextNdrPtr = 0; wLog* log = scard_log(); WINPR_ASSERT(call); call->mszGroups = nullptr; LONG status = smartcard_unpack_redir_scard_context(log, s, &(call->handles.hContext), &index, &pbContextNdrPtr); if (status != SCARD_S_SUCCESS) return status; if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4)) return STATUS_BUFFER_TOO_SMALL; Stream_Read_UINT32(s, call->cBytes); /* cBytes (4 bytes) */ if (!smartcard_ndr_pointer_read(log, s, &index, &mszGroupsNdrPtr)) return ERROR_INVALID_DATA; if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 8)) return STATUS_BUFFER_TOO_SMALL; Stream_Read_INT32(s, call->fmszReadersIsNULL); /* fmszReadersIsNULL (4 bytes) */ Stream_Read_UINT32(s, call->cchReaders); /* cchReaders (4 bytes) */ status = smartcard_unpack_redir_scard_context_ref(log, s, pbContextNdrPtr, &(call->handles.hContext)); if (status != SCARD_S_SUCCESS) return status; if (mszGroupsNdrPtr) { status = smartcard_ndr_read(log, s, &call->mszGroups, call->cBytes, 1, NDR_PTR_SIMPLE); if (status != SCARD_S_SUCCESS) return status; } smartcard_trace_list_readers_call(log, call, unicode); return SCARD_S_SUCCESS; } LONG smartcard_pack_list_readers_return(wStream* s, const ListReaders_Return* ret, BOOL unicode) { WINPR_ASSERT(ret); wLog* log = scard_log(); LONG status = 0; UINT32 index = 0; UINT32 size = ret->cBytes; smartcard_trace_list_readers_return(log, ret, unicode); if (ret->ReturnCode != SCARD_S_SUCCESS) size = 0; if (!Stream_EnsureRemainingCapacity(s, 4)) { WLog_Print(log, WLOG_ERROR, "Stream_EnsureRemainingCapacity failed!"); return SCARD_F_INTERNAL_ERROR; } Stream_Write_UINT32(s, size); /* cBytes (4 bytes) */ if (!smartcard_ndr_pointer_write(s, &index, size)) return SCARD_E_NO_MEMORY; status = smartcard_ndr_write(s, ret->msz, size, 1, NDR_PTR_SIMPLE); if (status != SCARD_S_SUCCESS) return status; return ret->ReturnCode; } static LONG smartcard_unpack_connect_common(wLog* log, wStream* s, Connect_Common_Call* common, UINT32* index, UINT32* ppbContextNdrPtr) { WINPR_ASSERT(common); LONG status = smartcard_unpack_redir_scard_context(log, s, &(common->handles.hContext), index, ppbContextNdrPtr); if (status != SCARD_S_SUCCESS) return status; if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 8)) return STATUS_BUFFER_TOO_SMALL; Stream_Read_UINT32(s, common->dwShareMode); /* dwShareMode (4 bytes) */ Stream_Read_UINT32(s, common->dwPreferredProtocols); /* dwPreferredProtocols (4 bytes) */ return SCARD_S_SUCCESS; } LONG smartcard_unpack_connect_a_call(wStream* s, ConnectA_Call* call) { LONG status = 0; UINT32 index = 0; UINT32 pbContextNdrPtr = 0; WINPR_ASSERT(call); wLog* log = scard_log(); call->szReader = nullptr; if (!smartcard_ndr_pointer_read(log, s, &index, nullptr)) return ERROR_INVALID_DATA; status = smartcard_unpack_connect_common(log, s, &(call->Common), &index, &pbContextNdrPtr); if (status != SCARD_S_SUCCESS) { WLog_Print(log, WLOG_ERROR, "smartcard_unpack_connect_common failed with error %" PRId32 "", status); return status; } status = smartcard_ndr_read_a(log, s, &call->szReader, NDR_PTR_FULL); if (status != SCARD_S_SUCCESS) return status; status = smartcard_unpack_redir_scard_context_ref(log, s, pbContextNdrPtr, &(call->Common.handles.hContext)); if (status != SCARD_S_SUCCESS) WLog_Print(log, WLOG_ERROR, "smartcard_unpack_redir_scard_context_ref failed with error %" PRId32 "", status); smartcard_trace_connect_a_call(log, call); return status; } LONG smartcard_unpack_connect_w_call(wStream* s, ConnectW_Call* call) { LONG status = 0; UINT32 index = 0; UINT32 pbContextNdrPtr = 0; WINPR_ASSERT(call); wLog* log = scard_log(); call->szReader = nullptr; if (!smartcard_ndr_pointer_read(log, s, &index, nullptr)) return ERROR_INVALID_DATA; status = smartcard_unpack_connect_common(log, s, &(call->Common), &index, &pbContextNdrPtr); if (status != SCARD_S_SUCCESS) { WLog_Print(log, WLOG_ERROR, "smartcard_unpack_connect_common failed with error %" PRId32 "", status); return status; } status = smartcard_ndr_read_w(log, s, &call->szReader, NDR_PTR_FULL); if (status != SCARD_S_SUCCESS) return status; status = smartcard_unpack_redir_scard_context_ref(log, s, pbContextNdrPtr, &(call->Common.handles.hContext)); if (status != SCARD_S_SUCCESS) WLog_Print(log, WLOG_ERROR, "smartcard_unpack_redir_scard_context_ref failed with error %" PRId32 "", status); smartcard_trace_connect_w_call(log, call); return status; } LONG smartcard_pack_connect_return(wStream* s, const Connect_Return* ret) { LONG status = 0; DWORD index = 0; WINPR_ASSERT(ret); wLog* log = scard_log(); smartcard_trace_connect_return(log, ret); status = smartcard_pack_redir_scard_context(log, s, &ret->hContext, &index); if (status != SCARD_S_SUCCESS) return status; status = smartcard_pack_redir_scard_handle(log, s, &ret->hCard, &index); if (status != SCARD_S_SUCCESS) return status; if (!Stream_EnsureRemainingCapacity(s, 4)) return SCARD_E_NO_MEMORY; Stream_Write_UINT32(s, ret->dwActiveProtocol); /* dwActiveProtocol (4 bytes) */ status = smartcard_pack_redir_scard_context_ref(log, s, &ret->hContext); if (status != SCARD_S_SUCCESS) return status; return smartcard_pack_redir_scard_handle_ref(log, s, &(ret->hCard)); } LONG smartcard_unpack_reconnect_call(wStream* s, Reconnect_Call* call) { UINT32 index = 0; UINT32 pbContextNdrPtr = 0; WINPR_ASSERT(call); wLog* log = scard_log(); LONG status = smartcard_unpack_redir_scard_context(log, s, &(call->handles.hContext), &index, &pbContextNdrPtr); if (status != SCARD_S_SUCCESS) return status; status = smartcard_unpack_redir_scard_handle(log, s, &(call->handles.hCard), &index); if (status != SCARD_S_SUCCESS) return status; if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 12)) return STATUS_BUFFER_TOO_SMALL; Stream_Read_UINT32(s, call->dwShareMode); /* dwShareMode (4 bytes) */ Stream_Read_UINT32(s, call->dwPreferredProtocols); /* dwPreferredProtocols (4 bytes) */ Stream_Read_UINT32(s, call->dwInitialization); /* dwInitialization (4 bytes) */ status = smartcard_unpack_redir_scard_context_ref(log, s, pbContextNdrPtr, &(call->handles.hContext)); if (status != SCARD_S_SUCCESS) { WLog_Print(log, WLOG_ERROR, "smartcard_unpack_redir_scard_context_ref failed with error %" PRId32 "", status); return status; } status = smartcard_unpack_redir_scard_handle_ref(log, s, &(call->handles.hCard)); if (status != SCARD_S_SUCCESS) WLog_Print(log, WLOG_ERROR, "smartcard_unpack_redir_scard_handle_ref failed with error %" PRId32 "", status); smartcard_trace_reconnect_call(log, call); return status; } LONG smartcard_pack_reconnect_return(wStream* s, const Reconnect_Return* ret) { WINPR_ASSERT(ret); wLog* log = scard_log(); smartcard_trace_reconnect_return(log, ret); if (!Stream_EnsureRemainingCapacity(s, 4)) return SCARD_E_NO_MEMORY; Stream_Write_UINT32(s, ret->dwActiveProtocol); /* dwActiveProtocol (4 bytes) */ return ret->ReturnCode; } LONG smartcard_unpack_hcard_and_disposition_call(wStream* s, HCardAndDisposition_Call* call, const char* name) { UINT32 index = 0; UINT32 pbContextNdrPtr = 0; WINPR_ASSERT(call); wLog* log = scard_log(); LONG status = smartcard_unpack_redir_scard_context(log, s, &(call->handles.hContext), &index, &pbContextNdrPtr); if (status != SCARD_S_SUCCESS) return status; status = smartcard_unpack_redir_scard_handle(log, s, &(call->handles.hCard), &index); if (status != SCARD_S_SUCCESS) return status; if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4)) return STATUS_BUFFER_TOO_SMALL; Stream_Read_UINT32(s, call->dwDisposition); /* dwDisposition (4 bytes) */ status = smartcard_unpack_redir_scard_context_ref(log, s, pbContextNdrPtr, &(call->handles.hContext)); if (status != SCARD_S_SUCCESS) return status; status = smartcard_unpack_redir_scard_handle_ref(log, s, &(call->handles.hCard)); if (status != SCARD_S_SUCCESS) return status; smartcard_trace_hcard_and_disposition_call(log, call, name); return status; } static void smartcard_trace_get_status_change_a_call(wLog* log, const GetStatusChangeA_Call* call) { WINPR_ASSERT(call); if (!WLog_IsLevelActive(log, g_LogLevel)) return; WLog_Print(log, g_LogLevel, "GetStatusChangeA_Call {"); smartcard_log_context(log, &call->handles.hContext); WLog_Print(log, g_LogLevel, "dwTimeOut: 0x%08" PRIX32 " cReaders: %" PRIu32 "", call->dwTimeOut, call->cReaders); dump_reader_states_a(log, call->rgReaderStates, call->cReaders); WLog_Print(log, g_LogLevel, "}"); } static LONG smartcard_unpack_reader_state_a(wLog* log, wStream* s, LPSCARD_READERSTATEA* ppcReaders, UINT32 cReaders, UINT32* ptrIndex) { LONG status = SCARD_E_NO_MEMORY; WINPR_ASSERT(ppcReaders || (cReaders == 0)); if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4)) return status; const UINT32 len = Stream_Get_UINT32(s); if (len != cReaders) { WLog_Print(log, WLOG_ERROR, "Count mismatch when reading LPSCARD_READERSTATEA"); return status; } LPSCARD_READERSTATEA rgReaderStates = (LPSCARD_READERSTATEA)calloc(cReaders, sizeof(SCARD_READERSTATEA)); BOOL* states = calloc(cReaders, sizeof(BOOL)); if (!rgReaderStates || !states) goto fail; status = ERROR_INVALID_DATA; for (UINT32 index = 0; index < cReaders; index++) { UINT32 ptr = UINT32_MAX; LPSCARD_READERSTATEA readerState = &rgReaderStates[index]; if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 52)) goto fail; if (!smartcard_ndr_pointer_read(log, s, ptrIndex, &ptr)) { if (ptr != 0) goto fail; } /* Ignore nullptr length strings */ states[index] = ptr != 0; Stream_Read_UINT32(s, readerState->dwCurrentState); /* dwCurrentState (4 bytes) */ Stream_Read_UINT32(s, readerState->dwEventState); /* dwEventState (4 bytes) */ Stream_Read_UINT32(s, readerState->cbAtr); /* cbAtr (4 bytes) */ Stream_Read(s, readerState->rgbAtr, 36); /* rgbAtr [0..36] (36 bytes) */ } for (UINT32 index = 0; index < cReaders; index++) { LPSCARD_READERSTATEA readerState = &rgReaderStates[index]; /* Ignore empty strings */ if (!states[index]) continue; status = smartcard_ndr_read_a(log, s, &readerState->szReader, NDR_PTR_FULL); if (status != SCARD_S_SUCCESS) goto fail; } *ppcReaders = rgReaderStates; free(states); return SCARD_S_SUCCESS; fail: if (rgReaderStates) { for (UINT32 index = 0; index < cReaders; index++) { LPSCARD_READERSTATEA readerState = &rgReaderStates[index]; free(readerState->szReader); } } free(rgReaderStates); free(states); return status; } static LONG smartcard_unpack_reader_state_w(wLog* log, wStream* s, LPSCARD_READERSTATEW* ppcReaders, UINT32 cReaders, UINT32* ptrIndex) { LONG status = SCARD_E_NO_MEMORY; WINPR_ASSERT(ppcReaders || (cReaders == 0)); if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4)) return status; const UINT32 len = Stream_Get_UINT32(s); if (len != cReaders) { WLog_Print(log, WLOG_ERROR, "Count mismatch when reading LPSCARD_READERSTATEW"); return status; } LPSCARD_READERSTATEW rgReaderStates = (LPSCARD_READERSTATEW)calloc(cReaders, sizeof(SCARD_READERSTATEW)); BOOL* states = calloc(cReaders, sizeof(BOOL)); if (!rgReaderStates || !states) goto fail; status = ERROR_INVALID_DATA; for (UINT32 index = 0; index < cReaders; index++) { UINT32 ptr = UINT32_MAX; LPSCARD_READERSTATEW readerState = &rgReaderStates[index]; if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 52)) goto fail; if (!smartcard_ndr_pointer_read(log, s, ptrIndex, &ptr)) { if (ptr != 0) goto fail; } /* Ignore nullptr length strings */ states[index] = ptr != 0; Stream_Read_UINT32(s, readerState->dwCurrentState); /* dwCurrentState (4 bytes) */ Stream_Read_UINT32(s, readerState->dwEventState); /* dwEventState (4 bytes) */ Stream_Read_UINT32(s, readerState->cbAtr); /* cbAtr (4 bytes) */ Stream_Read(s, readerState->rgbAtr, 36); /* rgbAtr [0..36] (36 bytes) */ } for (UINT32 index = 0; index < cReaders; index++) { LPSCARD_READERSTATEW readerState = &rgReaderStates[index]; /* Skip nullptr pointers */ if (!states[index]) continue; status = smartcard_ndr_read_w(log, s, &readerState->szReader, NDR_PTR_FULL); if (status != SCARD_S_SUCCESS) goto fail; } *ppcReaders = rgReaderStates; free(states); return SCARD_S_SUCCESS; fail: if (rgReaderStates) { for (UINT32 index = 0; index < cReaders; index++) { LPSCARD_READERSTATEW readerState = &rgReaderStates[index]; free(readerState->szReader); } } free(rgReaderStates); free(states); return status; } /******************************************************************************/ /************************************* End Trace Functions ********************/ /******************************************************************************/ LONG smartcard_unpack_get_status_change_a_call(wStream* s, GetStatusChangeA_Call* call) { UINT32 ndrPtr = 0; UINT32 index = 0; UINT32 pbContextNdrPtr = 0; WINPR_ASSERT(call); wLog* log = scard_log(); call->rgReaderStates = nullptr; LONG status = smartcard_unpack_redir_scard_context(log, s, &(call->handles.hContext), &index, &pbContextNdrPtr); if (status != SCARD_S_SUCCESS) return status; if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 8)) return STATUS_BUFFER_TOO_SMALL; Stream_Read_UINT32(s, call->dwTimeOut); /* dwTimeOut (4 bytes) */ Stream_Read_UINT32(s, call->cReaders); /* cReaders (4 bytes) */ if (!smartcard_ndr_pointer_read(log, s, &index, &ndrPtr)) return ERROR_INVALID_DATA; status = smartcard_unpack_redir_scard_context_ref(log, s, pbContextNdrPtr, &(call->handles.hContext)); if (status != SCARD_S_SUCCESS) return status; if (ndrPtr) { status = smartcard_unpack_reader_state_a(log, s, &call->rgReaderStates, call->cReaders, &index); if (status != SCARD_S_SUCCESS) return status; } else { WLog_Print(log, WLOG_WARN, "ndrPtr=0x%08" PRIx32 ", can not read rgReaderStates", ndrPtr); return SCARD_E_UNEXPECTED; } smartcard_trace_get_status_change_a_call(log, call); return SCARD_S_SUCCESS; } LONG smartcard_unpack_get_status_change_w_call(wStream* s, GetStatusChangeW_Call* call) { UINT32 ndrPtr = 0; UINT32 index = 0; UINT32 pbContextNdrPtr = 0; WINPR_ASSERT(call); wLog* log = scard_log(); call->rgReaderStates = nullptr; LONG status = smartcard_unpack_redir_scard_context(log, s, &(call->handles.hContext), &index, &pbContextNdrPtr); if (status != SCARD_S_SUCCESS) return status; if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 8)) return STATUS_BUFFER_TOO_SMALL; Stream_Read_UINT32(s, call->dwTimeOut); /* dwTimeOut (4 bytes) */ Stream_Read_UINT32(s, call->cReaders); /* cReaders (4 bytes) */ if (!smartcard_ndr_pointer_read(log, s, &index, &ndrPtr)) return ERROR_INVALID_DATA; status = smartcard_unpack_redir_scard_context_ref(log, s, pbContextNdrPtr, &(call->handles.hContext)); if (status != SCARD_S_SUCCESS) return status; if (ndrPtr) { status = smartcard_unpack_reader_state_w(log, s, &call->rgReaderStates, call->cReaders, &index); if (status != SCARD_S_SUCCESS) return status; } else { WLog_Print(log, WLOG_WARN, "ndrPtr=0x%08" PRIx32 ", can not read rgReaderStates", ndrPtr); return SCARD_E_UNEXPECTED; } smartcard_trace_get_status_change_w_call(log, call); return SCARD_S_SUCCESS; } LONG smartcard_pack_get_status_change_return(wStream* s, const GetStatusChange_Return* ret, BOOL unicode) { WINPR_ASSERT(ret); wLog* log = scard_log(); LONG status = 0; DWORD cReaders = ret->cReaders; UINT32 index = 0; smartcard_trace_get_status_change_return(log, ret, unicode); if (ret->ReturnCode != SCARD_S_SUCCESS) cReaders = 0; if (cReaders == SCARD_AUTOALLOCATE) cReaders = 0; if (!Stream_EnsureRemainingCapacity(s, 4)) return SCARD_E_NO_MEMORY; Stream_Write_UINT32(s, cReaders); /* cReaders (4 bytes) */ if (!smartcard_ndr_pointer_write(s, &index, cReaders)) return SCARD_E_NO_MEMORY; status = smartcard_ndr_write_state(s, ret->rgReaderStates, cReaders, NDR_PTR_SIMPLE); if (status != SCARD_S_SUCCESS) return status; return ret->ReturnCode; } LONG smartcard_unpack_state_call(wStream* s, State_Call* call) { UINT32 index = 0; UINT32 pbContextNdrPtr = 0; wLog* log = scard_log(); WINPR_ASSERT(call); LONG status = smartcard_unpack_redir_scard_context(log, s, &(call->handles.hContext), &index, &pbContextNdrPtr); if (status != SCARD_S_SUCCESS) return status; status = smartcard_unpack_redir_scard_handle(log, s, &(call->handles.hCard), &index); if (status != SCARD_S_SUCCESS) return status; if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 8)) return STATUS_BUFFER_TOO_SMALL; Stream_Read_INT32(s, call->fpbAtrIsNULL); /* fpbAtrIsNULL (4 bytes) */ Stream_Read_UINT32(s, call->cbAtrLen); /* cbAtrLen (4 bytes) */ status = smartcard_unpack_redir_scard_context_ref(log, s, pbContextNdrPtr, &(call->handles.hContext)); if (status != SCARD_S_SUCCESS) return status; status = smartcard_unpack_redir_scard_handle_ref(log, s, &(call->handles.hCard)); if (status != SCARD_S_SUCCESS) return status; return status; } LONG smartcard_pack_state_return(wStream* s, const State_Return* ret) { WINPR_ASSERT(ret); wLog* log = scard_log(); LONG status = 0; DWORD cbAtrLen = ret->cbAtrLen; UINT32 index = 0; smartcard_trace_state_return(log, ret); if (ret->ReturnCode != SCARD_S_SUCCESS) cbAtrLen = 0; if (cbAtrLen == SCARD_AUTOALLOCATE) cbAtrLen = 0; Stream_Write_UINT32(s, ret->dwState); /* dwState (4 bytes) */ Stream_Write_UINT32(s, ret->dwProtocol); /* dwProtocol (4 bytes) */ Stream_Write_UINT32(s, cbAtrLen); /* cbAtrLen (4 bytes) */ if (!smartcard_ndr_pointer_write(s, &index, cbAtrLen)) return SCARD_E_NO_MEMORY; status = smartcard_ndr_write(s, ret->rgAtr, cbAtrLen, 1, NDR_PTR_SIMPLE); if (status != SCARD_S_SUCCESS) return status; return ret->ReturnCode; } LONG smartcard_unpack_status_call(wStream* s, Status_Call* call, BOOL unicode) { UINT32 index = 0; UINT32 pbContextNdrPtr = 0; WINPR_ASSERT(call); wLog* log = scard_log(); LONG status = smartcard_unpack_redir_scard_context(log, s, &(call->handles.hContext), &index, &pbContextNdrPtr); if (status != SCARD_S_SUCCESS) return status; status = smartcard_unpack_redir_scard_handle(log, s, &(call->handles.hCard), &index); if (status != SCARD_S_SUCCESS) return status; if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 12)) return STATUS_BUFFER_TOO_SMALL; Stream_Read_INT32(s, call->fmszReaderNamesIsNULL); /* fmszReaderNamesIsNULL (4 bytes) */ Stream_Read_UINT32(s, call->cchReaderLen); /* cchReaderLen (4 bytes) */ Stream_Read_UINT32(s, call->cbAtrLen); /* cbAtrLen (4 bytes) */ status = smartcard_unpack_redir_scard_context_ref(log, s, pbContextNdrPtr, &(call->handles.hContext)); if (status != SCARD_S_SUCCESS) return status; status = smartcard_unpack_redir_scard_handle_ref(log, s, &(call->handles.hCard)); if (status != SCARD_S_SUCCESS) return status; smartcard_trace_status_call(log, call, unicode); return status; } LONG smartcard_pack_status_return(wStream* s, const Status_Return* ret, BOOL unicode) { WINPR_ASSERT(ret); wLog* log = scard_log(); LONG status = 0; UINT32 index = 0; DWORD cBytes = ret->cBytes; smartcard_trace_status_return(log, ret, unicode); if (ret->ReturnCode != SCARD_S_SUCCESS) cBytes = 0; if (cBytes == SCARD_AUTOALLOCATE) cBytes = 0; if (!Stream_EnsureRemainingCapacity(s, 4)) return SCARD_F_INTERNAL_ERROR; Stream_Write_UINT32(s, cBytes); /* cBytes (4 bytes) */ if (!smartcard_ndr_pointer_write(s, &index, cBytes)) return SCARD_E_NO_MEMORY; if (!Stream_EnsureRemainingCapacity(s, 44)) return SCARD_F_INTERNAL_ERROR; Stream_Write_UINT32(s, ret->dwState); /* dwState (4 bytes) */ Stream_Write_UINT32(s, ret->dwProtocol); /* dwProtocol (4 bytes) */ Stream_Write(s, ret->pbAtr, sizeof(ret->pbAtr)); /* pbAtr (32 bytes) */ Stream_Write_UINT32(s, ret->cbAtrLen); /* cbAtrLen (4 bytes) */ status = smartcard_ndr_write(s, ret->mszReaderNames, cBytes, 1, NDR_PTR_SIMPLE); if (status != SCARD_S_SUCCESS) return status; return ret->ReturnCode; } LONG smartcard_unpack_get_attrib_call(wStream* s, GetAttrib_Call* call) { WINPR_ASSERT(call); wLog* log = scard_log(); UINT32 index = 0; UINT32 pbContextNdrPtr = 0; LONG status = smartcard_unpack_redir_scard_context(log, s, &(call->handles.hContext), &index, &pbContextNdrPtr); if (status != SCARD_S_SUCCESS) return status; status = smartcard_unpack_redir_scard_handle(log, s, &(call->handles.hCard), &index); if (status != SCARD_S_SUCCESS) return status; if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 12)) return STATUS_BUFFER_TOO_SMALL; Stream_Read_UINT32(s, call->dwAttrId); /* dwAttrId (4 bytes) */ Stream_Read_INT32(s, call->fpbAttrIsNULL); /* fpbAttrIsNULL (4 bytes) */ Stream_Read_UINT32(s, call->cbAttrLen); /* cbAttrLen (4 bytes) */ status = smartcard_unpack_redir_scard_context_ref(log, s, pbContextNdrPtr, &(call->handles.hContext)); if (status != SCARD_S_SUCCESS) return status; status = smartcard_unpack_redir_scard_handle_ref(log, s, &(call->handles.hCard)); if (status != SCARD_S_SUCCESS) return status; smartcard_trace_get_attrib_call(log, call); return status; } LONG smartcard_pack_get_attrib_return(wStream* s, const GetAttrib_Return* ret, DWORD dwAttrId, DWORD cbAttrCallLen) { WINPR_ASSERT(ret); wLog* log = scard_log(); LONG status = 0; DWORD cbAttrLen = 0; UINT32 index = 0; smartcard_trace_get_attrib_return(log, ret, dwAttrId); if (!Stream_EnsureRemainingCapacity(s, 4)) return SCARD_F_INTERNAL_ERROR; cbAttrLen = ret->cbAttrLen; if (ret->ReturnCode != SCARD_S_SUCCESS) cbAttrLen = 0; if (cbAttrLen == SCARD_AUTOALLOCATE) cbAttrLen = 0; if (ret->pbAttr) { if (cbAttrCallLen < cbAttrLen) cbAttrLen = cbAttrCallLen; } Stream_Write_UINT32(s, cbAttrLen); /* cbAttrLen (4 bytes) */ if (!smartcard_ndr_pointer_write(s, &index, cbAttrLen)) return SCARD_E_NO_MEMORY; status = smartcard_ndr_write(s, ret->pbAttr, cbAttrLen, 1, NDR_PTR_SIMPLE); if (status != SCARD_S_SUCCESS) return status; return ret->ReturnCode; } LONG smartcard_unpack_control_call(wStream* s, Control_Call* call) { WINPR_ASSERT(call); wLog* log = scard_log(); UINT32 index = 0; UINT32 pvInBufferNdrPtr = 0; UINT32 pbContextNdrPtr = 0; call->pvInBuffer = nullptr; LONG status = smartcard_unpack_redir_scard_context(log, s, &(call->handles.hContext), &index, &pbContextNdrPtr); if (status != SCARD_S_SUCCESS) return status; status = smartcard_unpack_redir_scard_handle(log, s, &(call->handles.hCard), &index); if (status != SCARD_S_SUCCESS) return status; if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 20)) return STATUS_BUFFER_TOO_SMALL; Stream_Read_UINT32(s, call->dwControlCode); /* dwControlCode (4 bytes) */ Stream_Read_UINT32(s, call->cbInBufferSize); /* cbInBufferSize (4 bytes) */ if (!smartcard_ndr_pointer_read(log, s, &index, &pvInBufferNdrPtr)) /* pvInBufferNdrPtr (4 bytes) */ return ERROR_INVALID_DATA; Stream_Read_INT32(s, call->fpvOutBufferIsNULL); /* fpvOutBufferIsNULL (4 bytes) */ Stream_Read_UINT32(s, call->cbOutBufferSize); /* cbOutBufferSize (4 bytes) */ status = smartcard_unpack_redir_scard_context_ref(log, s, pbContextNdrPtr, &(call->handles.hContext)); if (status != SCARD_S_SUCCESS) return status; status = smartcard_unpack_redir_scard_handle_ref(log, s, &(call->handles.hCard)); if (status != SCARD_S_SUCCESS) return status; if (pvInBufferNdrPtr) { status = smartcard_ndr_read(log, s, &call->pvInBuffer, call->cbInBufferSize, 1, NDR_PTR_SIMPLE); if (status != SCARD_S_SUCCESS) return status; } smartcard_trace_control_call(log, call); return SCARD_S_SUCCESS; } LONG smartcard_pack_control_return(wStream* s, const Control_Return* ret) { WINPR_ASSERT(ret); wLog* log = scard_log(); LONG status = 0; DWORD cbDataLen = ret->cbOutBufferSize; UINT32 index = 0; smartcard_trace_control_return(log, ret); if (ret->ReturnCode != SCARD_S_SUCCESS) cbDataLen = 0; if (cbDataLen == SCARD_AUTOALLOCATE) cbDataLen = 0; if (!Stream_EnsureRemainingCapacity(s, 4)) return SCARD_F_INTERNAL_ERROR; Stream_Write_UINT32(s, cbDataLen); /* cbOutBufferSize (4 bytes) */ if (!smartcard_ndr_pointer_write(s, &index, cbDataLen)) return SCARD_E_NO_MEMORY; status = smartcard_ndr_write(s, ret->pvOutBuffer, cbDataLen, 1, NDR_PTR_SIMPLE); if (status != SCARD_S_SUCCESS) return status; return ret->ReturnCode; } LONG smartcard_unpack_transmit_call(wStream* s, Transmit_Call* call) { UINT32 length = 0; BYTE* pbExtraBytes = nullptr; UINT32 pbExtraBytesNdrPtr = 0; UINT32 pbSendBufferNdrPtr = 0; UINT32 pioRecvPciNdrPtr = 0; SCardIO_Request ioSendPci; SCardIO_Request ioRecvPci; UINT32 index = 0; UINT32 pbContextNdrPtr = 0; WINPR_ASSERT(call); wLog* log = scard_log(); call->pioSendPci = nullptr; call->pioRecvPci = nullptr; call->pbSendBuffer = nullptr; LONG status = smartcard_unpack_redir_scard_context(log, s, &(call->handles.hContext), &index, &pbContextNdrPtr); if (status != SCARD_S_SUCCESS) return status; status = smartcard_unpack_redir_scard_handle(log, s, &(call->handles.hCard), &index); if (status != SCARD_S_SUCCESS) return status; if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 32)) return STATUS_BUFFER_TOO_SMALL; Stream_Read_UINT32(s, ioSendPci.dwProtocol); /* dwProtocol (4 bytes) */ Stream_Read_UINT32(s, ioSendPci.cbExtraBytes); /* cbExtraBytes (4 bytes) */ if (!smartcard_ndr_pointer_read(log, s, &index, &pbExtraBytesNdrPtr)) /* pbExtraBytesNdrPtr (4 bytes) */ return ERROR_INVALID_DATA; Stream_Read_UINT32(s, call->cbSendLength); /* cbSendLength (4 bytes) */ if (!smartcard_ndr_pointer_read(log, s, &index, &pbSendBufferNdrPtr)) /* pbSendBufferNdrPtr (4 bytes) */ return ERROR_INVALID_DATA; if (!smartcard_ndr_pointer_read(log, s, &index, &pioRecvPciNdrPtr)) /* pioRecvPciNdrPtr (4 bytes) */ return ERROR_INVALID_DATA; Stream_Read_INT32(s, call->fpbRecvBufferIsNULL); /* fpbRecvBufferIsNULL (4 bytes) */ Stream_Read_UINT32(s, call->cbRecvLength); /* cbRecvLength (4 bytes) */ if (ioSendPci.cbExtraBytes > 1024) { WLog_Print(log, WLOG_WARN, "Transmit_Call ioSendPci.cbExtraBytes is out of bounds: %" PRIu32 " (max: 1024)", ioSendPci.cbExtraBytes); return STATUS_INVALID_PARAMETER; } if (call->cbSendLength > 66560) { WLog_Print(log, WLOG_WARN, "Transmit_Call cbSendLength is out of bounds: %" PRIu32 " (max: 66560)", ioSendPci.cbExtraBytes); return STATUS_INVALID_PARAMETER; } status = smartcard_unpack_redir_scard_context_ref(log, s, pbContextNdrPtr, &(call->handles.hContext)); if (status != SCARD_S_SUCCESS) return status; status = smartcard_unpack_redir_scard_handle_ref(log, s, &(call->handles.hCard)); if (status != SCARD_S_SUCCESS) return status; if (ioSendPci.cbExtraBytes && !pbExtraBytesNdrPtr) { WLog_Print( log, WLOG_WARN, "Transmit_Call ioSendPci.cbExtraBytes is non-zero but pbExtraBytesNdrPtr is null"); return STATUS_INVALID_PARAMETER; } if (pbExtraBytesNdrPtr) { // TODO: Use unified pointer reading if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4)) return STATUS_BUFFER_TOO_SMALL; Stream_Read_UINT32(s, length); /* Length (4 bytes) */ if (!Stream_CheckAndLogRequiredLengthWLog(log, s, ioSendPci.cbExtraBytes)) return STATUS_BUFFER_TOO_SMALL; ioSendPci.pbExtraBytes = Stream_Pointer(s); call->pioSendPci = (LPSCARD_IO_REQUEST)malloc(sizeof(SCARD_IO_REQUEST) + ioSendPci.cbExtraBytes); if (!call->pioSendPci) { WLog_Print(log, WLOG_WARN, "Transmit_Call out of memory error (pioSendPci)"); return STATUS_NO_MEMORY; } call->pioSendPci->dwProtocol = ioSendPci.dwProtocol; call->pioSendPci->cbPciLength = (DWORD)(ioSendPci.cbExtraBytes + sizeof(SCARD_IO_REQUEST)); pbExtraBytes = &((BYTE*)call->pioSendPci)[sizeof(SCARD_IO_REQUEST)]; Stream_Read(s, pbExtraBytes, ioSendPci.cbExtraBytes); if (smartcard_unpack_read_size_align(s, ioSendPci.cbExtraBytes, 4) < 0) return STATUS_INVALID_PARAMETER; } else { call->pioSendPci = (LPSCARD_IO_REQUEST)calloc(1, sizeof(SCARD_IO_REQUEST)); if (!call->pioSendPci) { WLog_Print(log, WLOG_WARN, "Transmit_Call out of memory error (pioSendPci)"); return STATUS_NO_MEMORY; } call->pioSendPci->dwProtocol = ioSendPci.dwProtocol; call->pioSendPci->cbPciLength = sizeof(SCARD_IO_REQUEST); } if (pbSendBufferNdrPtr) { status = smartcard_ndr_read(log, s, &call->pbSendBuffer, call->cbSendLength, 1, NDR_PTR_SIMPLE); if (status != SCARD_S_SUCCESS) return status; } if (pioRecvPciNdrPtr) { if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 12)) return STATUS_BUFFER_TOO_SMALL; Stream_Read_UINT32(s, ioRecvPci.dwProtocol); /* dwProtocol (4 bytes) */ Stream_Read_UINT32(s, ioRecvPci.cbExtraBytes); /* cbExtraBytes (4 bytes) */ if (!smartcard_ndr_pointer_read(log, s, &index, &pbExtraBytesNdrPtr)) /* pbExtraBytesNdrPtr (4 bytes) */ return ERROR_INVALID_DATA; if (ioRecvPci.cbExtraBytes && !pbExtraBytesNdrPtr) { WLog_Print( log, WLOG_WARN, "Transmit_Call ioRecvPci.cbExtraBytes is non-zero but pbExtraBytesNdrPtr is null"); return STATUS_INVALID_PARAMETER; } if (pbExtraBytesNdrPtr) { // TODO: Unify ndr pointer reading if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 4)) return STATUS_BUFFER_TOO_SMALL; Stream_Read_UINT32(s, length); /* Length (4 bytes) */ if (ioRecvPci.cbExtraBytes > 1024) { WLog_Print(log, WLOG_WARN, "Transmit_Call ioRecvPci.cbExtraBytes is out of bounds: %" PRIu32 " (max: 1024)", ioRecvPci.cbExtraBytes); return STATUS_INVALID_PARAMETER; } if (length != ioRecvPci.cbExtraBytes) { WLog_Print(log, WLOG_WARN, "Transmit_Call unexpected length: Actual: %" PRIu32 ", Expected: %" PRIu32 " (ioRecvPci.cbExtraBytes)", length, ioRecvPci.cbExtraBytes); return STATUS_INVALID_PARAMETER; } if (!Stream_CheckAndLogRequiredLengthWLog(log, s, ioRecvPci.cbExtraBytes)) return STATUS_BUFFER_TOO_SMALL; ioRecvPci.pbExtraBytes = Stream_Pointer(s); call->pioRecvPci = (LPSCARD_IO_REQUEST)malloc(sizeof(SCARD_IO_REQUEST) + ioRecvPci.cbExtraBytes); if (!call->pioRecvPci) { WLog_Print(log, WLOG_WARN, "Transmit_Call out of memory error (pioRecvPci)"); return STATUS_NO_MEMORY; } call->pioRecvPci->dwProtocol = ioRecvPci.dwProtocol; call->pioRecvPci->cbPciLength = (DWORD)(ioRecvPci.cbExtraBytes + sizeof(SCARD_IO_REQUEST)); pbExtraBytes = &((BYTE*)call->pioRecvPci)[sizeof(SCARD_IO_REQUEST)]; Stream_Read(s, pbExtraBytes, ioRecvPci.cbExtraBytes); if (smartcard_unpack_read_size_align(s, ioRecvPci.cbExtraBytes, 4) < 0) return STATUS_INVALID_PARAMETER; } else { call->pioRecvPci = (LPSCARD_IO_REQUEST)calloc(1, sizeof(SCARD_IO_REQUEST)); if (!call->pioRecvPci) { WLog_Print(log, WLOG_WARN, "Transmit_Call out of memory error (pioRecvPci)"); return STATUS_NO_MEMORY; } call->pioRecvPci->dwProtocol = ioRecvPci.dwProtocol; call->pioRecvPci->cbPciLength = sizeof(SCARD_IO_REQUEST); } } smartcard_trace_transmit_call(log, call); return SCARD_S_SUCCESS; } LONG smartcard_pack_transmit_return(wStream* s, const Transmit_Return* ret) { WINPR_ASSERT(ret); wLog* log = scard_log(); LONG status = 0; UINT32 index = 0; LONG error = 0; UINT32 cbRecvLength = ret->cbRecvLength; UINT32 cbRecvPci = ret->pioRecvPci ? ret->pioRecvPci->cbPciLength : 0; smartcard_trace_transmit_return(log, ret); if (!ret->pbRecvBuffer) cbRecvLength = 0; if (!smartcard_ndr_pointer_write(s, &index, cbRecvPci)) return SCARD_E_NO_MEMORY; if (!Stream_EnsureRemainingCapacity(s, 4)) return SCARD_E_NO_MEMORY; Stream_Write_UINT32(s, cbRecvLength); /* cbRecvLength (4 bytes) */ if (!smartcard_ndr_pointer_write(s, &index, cbRecvLength)) return SCARD_E_NO_MEMORY; if (ret->pioRecvPci) { UINT32 cbExtraBytes = (UINT32)(ret->pioRecvPci->cbPciLength - sizeof(SCARD_IO_REQUEST)); BYTE* pbExtraBytes = &((BYTE*)ret->pioRecvPci)[sizeof(SCARD_IO_REQUEST)]; if (!Stream_EnsureRemainingCapacity(s, cbExtraBytes + 16)) { WLog_Print(log, WLOG_ERROR, "Stream_EnsureRemainingCapacity failed!"); return SCARD_F_INTERNAL_ERROR; } Stream_Write_UINT32(s, ret->pioRecvPci->dwProtocol); /* dwProtocol (4 bytes) */ Stream_Write_UINT32(s, cbExtraBytes); /* cbExtraBytes (4 bytes) */ if (!smartcard_ndr_pointer_write(s, &index, cbExtraBytes)) return SCARD_E_NO_MEMORY; error = smartcard_ndr_write(s, pbExtraBytes, cbExtraBytes, 1, NDR_PTR_SIMPLE); if (error) return error; } status = smartcard_ndr_write(s, ret->pbRecvBuffer, ret->cbRecvLength, 1, NDR_PTR_SIMPLE); if (status != SCARD_S_SUCCESS) return status; return ret->ReturnCode; } LONG smartcard_unpack_locate_cards_by_atr_a_call(wStream* s, LocateCardsByATRA_Call* call) { UINT32 rgReaderStatesNdrPtr = 0; UINT32 rgAtrMasksNdrPtr = 0; UINT32 index = 0; UINT32 pbContextNdrPtr = 0; WINPR_ASSERT(call); wLog* log = scard_log(); call->rgReaderStates = nullptr; LONG status = smartcard_unpack_redir_scard_context(log, s, &(call->handles.hContext), &index, &pbContextNdrPtr); if (status != SCARD_S_SUCCESS) return status; if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 16)) return STATUS_BUFFER_TOO_SMALL; Stream_Read_UINT32(s, call->cAtrs); if (!smartcard_ndr_pointer_read(log, s, &index, &rgAtrMasksNdrPtr)) return ERROR_INVALID_DATA; Stream_Read_UINT32(s, call->cReaders); /* cReaders (4 bytes) */ if (!smartcard_ndr_pointer_read(log, s, &index, &rgReaderStatesNdrPtr)) return ERROR_INVALID_DATA; status = smartcard_unpack_redir_scard_context_ref(log, s, pbContextNdrPtr, &(call->handles.hContext)); if (status != SCARD_S_SUCCESS) return status; if ((rgAtrMasksNdrPtr && !call->cAtrs) || (!rgAtrMasksNdrPtr && call->cAtrs)) { WLog_Print(log, WLOG_WARN, "LocateCardsByATRA_Call rgAtrMasksNdrPtr (0x%08" PRIX32 ") and cAtrs (0x%08" PRIX32 ") inconsistency", rgAtrMasksNdrPtr, call->cAtrs); return STATUS_INVALID_PARAMETER; } if (rgAtrMasksNdrPtr) { status = smartcard_ndr_read_atrmask(log, s, &call->rgAtrMasks, call->cAtrs, NDR_PTR_SIMPLE); if (status != SCARD_S_SUCCESS) return status; } if (rgReaderStatesNdrPtr) { status = smartcard_unpack_reader_state_a(log, s, &call->rgReaderStates, call->cReaders, &index); if (status != SCARD_S_SUCCESS) return status; } smartcard_trace_locate_cards_by_atr_a_call(log, call); return SCARD_S_SUCCESS; } LONG smartcard_unpack_context_and_two_strings_a_call(wStream* s, ContextAndTwoStringA_Call* call) { UINT32 sz1NdrPtr = 0; UINT32 sz2NdrPtr = 0; UINT32 index = 0; UINT32 pbContextNdrPtr = 0; WINPR_ASSERT(call); wLog* log = scard_log(); LONG status = smartcard_unpack_redir_scard_context(log, s, &(call->handles.hContext), &index, &pbContextNdrPtr); if (status != SCARD_S_SUCCESS) return status; if (!smartcard_ndr_pointer_read(log, s, &index, &sz1NdrPtr)) return ERROR_INVALID_DATA; if (!smartcard_ndr_pointer_read(log, s, &index, &sz2NdrPtr)) return ERROR_INVALID_DATA; status = smartcard_unpack_redir_scard_context_ref(log, s, pbContextNdrPtr, &call->handles.hContext); if (status != SCARD_S_SUCCESS) return status; if (sz1NdrPtr) { status = smartcard_ndr_read_a(log, s, &call->sz1, NDR_PTR_FULL); if (status != SCARD_S_SUCCESS) return status; } if (sz2NdrPtr) { status = smartcard_ndr_read_a(log, s, &call->sz2, NDR_PTR_FULL); if (status != SCARD_S_SUCCESS) return status; } smartcard_trace_context_and_two_strings_a_call(log, call); return SCARD_S_SUCCESS; } LONG smartcard_unpack_context_and_two_strings_w_call(wStream* s, ContextAndTwoStringW_Call* call) { UINT32 sz1NdrPtr = 0; UINT32 sz2NdrPtr = 0; UINT32 index = 0; UINT32 pbContextNdrPtr = 0; WINPR_ASSERT(call); wLog* log = scard_log(); LONG status = smartcard_unpack_redir_scard_context(log, s, &(call->handles.hContext), &index, &pbContextNdrPtr); if (status != SCARD_S_SUCCESS) return status; if (!smartcard_ndr_pointer_read(log, s, &index, &sz1NdrPtr)) return ERROR_INVALID_DATA; if (!smartcard_ndr_pointer_read(log, s, &index, &sz2NdrPtr)) return ERROR_INVALID_DATA; status = smartcard_unpack_redir_scard_context_ref(log, s, pbContextNdrPtr, &call->handles.hContext); if (status != SCARD_S_SUCCESS) return status; if (sz1NdrPtr) { status = smartcard_ndr_read_w(log, s, &call->sz1, NDR_PTR_FULL); if (status != SCARD_S_SUCCESS) return status; } if (sz2NdrPtr) { status = smartcard_ndr_read_w(log, s, &call->sz2, NDR_PTR_FULL); if (status != SCARD_S_SUCCESS) return status; } smartcard_trace_context_and_two_strings_w_call(log, call); return SCARD_S_SUCCESS; } LONG smartcard_unpack_locate_cards_a_call(wStream* s, LocateCardsA_Call* call) { UINT32 sz1NdrPtr = 0; UINT32 sz2NdrPtr = 0; UINT32 index = 0; UINT32 pbContextNdrPtr = 0; WINPR_ASSERT(call); wLog* log = scard_log(); LONG status = smartcard_unpack_redir_scard_context(log, s, &(call->handles.hContext), &index, &pbContextNdrPtr); if (status != SCARD_S_SUCCESS) return status; if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 16)) return STATUS_BUFFER_TOO_SMALL; Stream_Read_UINT32(s, call->cBytes); if (!smartcard_ndr_pointer_read(log, s, &index, &sz1NdrPtr)) return ERROR_INVALID_DATA; Stream_Read_UINT32(s, call->cReaders); if (!smartcard_ndr_pointer_read(log, s, &index, &sz2NdrPtr)) return ERROR_INVALID_DATA; status = smartcard_unpack_redir_scard_context_ref(log, s, pbContextNdrPtr, &(call->handles.hContext)); if (status != SCARD_S_SUCCESS) return status; if (sz1NdrPtr) { status = smartcard_ndr_read_fixed_string_a(log, s, &call->mszCards, call->cBytes, NDR_PTR_SIMPLE); if (status != SCARD_S_SUCCESS) return status; } if (sz2NdrPtr) { status = smartcard_unpack_reader_state_a(log, s, &call->rgReaderStates, call->cReaders, &index); if (status != SCARD_S_SUCCESS) return status; } smartcard_trace_locate_cards_a_call(log, call); return SCARD_S_SUCCESS; } LONG smartcard_unpack_locate_cards_w_call(wStream* s, LocateCardsW_Call* call) { UINT32 sz1NdrPtr = 0; UINT32 sz2NdrPtr = 0; UINT32 index = 0; UINT32 pbContextNdrPtr = 0; WINPR_ASSERT(call); wLog* log = scard_log(); LONG status = smartcard_unpack_redir_scard_context(log, s, &(call->handles.hContext), &index, &pbContextNdrPtr); if (status != SCARD_S_SUCCESS) return status; if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 16)) return STATUS_BUFFER_TOO_SMALL; Stream_Read_UINT32(s, call->cBytes); if (!smartcard_ndr_pointer_read(log, s, &index, &sz1NdrPtr)) return ERROR_INVALID_DATA; Stream_Read_UINT32(s, call->cReaders); if (!smartcard_ndr_pointer_read(log, s, &index, &sz2NdrPtr)) return ERROR_INVALID_DATA; status = smartcard_unpack_redir_scard_context_ref(log, s, pbContextNdrPtr, &(call->handles.hContext)); if (status != SCARD_S_SUCCESS) return status; if (sz1NdrPtr) { status = smartcard_ndr_read_fixed_string_w(log, s, &call->mszCards, call->cBytes, NDR_PTR_SIMPLE); if (status != SCARD_S_SUCCESS) return status; } if (sz2NdrPtr) { status = smartcard_unpack_reader_state_w(log, s, &call->rgReaderStates, call->cReaders, &index); if (status != SCARD_S_SUCCESS) return status; } smartcard_trace_locate_cards_w_call(log, call); return SCARD_S_SUCCESS; } LONG smartcard_unpack_set_attrib_call(wStream* s, SetAttrib_Call* call) { UINT32 index = 0; UINT32 ndrPtr = 0; UINT32 pbContextNdrPtr = 0; WINPR_ASSERT(call); wLog* log = scard_log(); LONG status = smartcard_unpack_redir_scard_context(log, s, &(call->handles.hContext), &index, &pbContextNdrPtr); if (status != SCARD_S_SUCCESS) return status; status = smartcard_unpack_redir_scard_handle(log, s, &(call->handles.hCard), &index); if (status != SCARD_S_SUCCESS) return status; if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 12)) return STATUS_BUFFER_TOO_SMALL; Stream_Read_UINT32(s, call->dwAttrId); Stream_Read_UINT32(s, call->cbAttrLen); if (!smartcard_ndr_pointer_read(log, s, &index, &ndrPtr)) return ERROR_INVALID_DATA; status = smartcard_unpack_redir_scard_context_ref(log, s, pbContextNdrPtr, &(call->handles.hContext)); if (status != SCARD_S_SUCCESS) return status; status = smartcard_unpack_redir_scard_handle_ref(log, s, &(call->handles.hCard)); if (status != SCARD_S_SUCCESS) return status; if (ndrPtr) { size_t len = 0; status = smartcard_ndr_read_ex(log, s, &call->pbAttr, 0, 1, NDR_PTR_SIMPLE, &len); if (status != SCARD_S_SUCCESS) return status; if (call->cbAttrLen > len) call->cbAttrLen = WINPR_ASSERTING_INT_CAST(DWORD, len); } else call->cbAttrLen = 0; smartcard_trace_set_attrib_call(log, call); return SCARD_S_SUCCESS; } LONG smartcard_unpack_locate_cards_by_atr_w_call(wStream* s, LocateCardsByATRW_Call* call) { UINT32 rgReaderStatesNdrPtr = 0; UINT32 rgAtrMasksNdrPtr = 0; UINT32 index = 0; UINT32 pbContextNdrPtr = 0; WINPR_ASSERT(call); wLog* log = scard_log(); call->rgReaderStates = nullptr; LONG status = smartcard_unpack_redir_scard_context(log, s, &(call->handles.hContext), &index, &pbContextNdrPtr); if (status != SCARD_S_SUCCESS) return status; if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 16)) return STATUS_BUFFER_TOO_SMALL; Stream_Read_UINT32(s, call->cAtrs); if (!smartcard_ndr_pointer_read(log, s, &index, &rgAtrMasksNdrPtr)) return ERROR_INVALID_DATA; Stream_Read_UINT32(s, call->cReaders); /* cReaders (4 bytes) */ if (!smartcard_ndr_pointer_read(log, s, &index, &rgReaderStatesNdrPtr)) return ERROR_INVALID_DATA; status = smartcard_unpack_redir_scard_context_ref(log, s, pbContextNdrPtr, &(call->handles.hContext)); if (status != SCARD_S_SUCCESS) return status; if ((rgAtrMasksNdrPtr && !call->cAtrs) || (!rgAtrMasksNdrPtr && call->cAtrs)) { WLog_Print(log, WLOG_WARN, "LocateCardsByATRW_Call rgAtrMasksNdrPtr (0x%08" PRIX32 ") and cAtrs (0x%08" PRIX32 ") inconsistency", rgAtrMasksNdrPtr, call->cAtrs); return STATUS_INVALID_PARAMETER; } if (rgAtrMasksNdrPtr) { status = smartcard_ndr_read_atrmask(log, s, &call->rgAtrMasks, call->cAtrs, NDR_PTR_SIMPLE); if (status != SCARD_S_SUCCESS) return status; } if (rgReaderStatesNdrPtr) { status = smartcard_unpack_reader_state_w(log, s, &call->rgReaderStates, call->cReaders, &index); if (status != SCARD_S_SUCCESS) return status; } smartcard_trace_locate_cards_by_atr_w_call(log, call); return SCARD_S_SUCCESS; } LONG smartcard_unpack_read_cache_a_call(wStream* s, ReadCacheA_Call* call) { UINT32 mszNdrPtr = 0; UINT32 contextNdrPtr = 0; UINT32 index = 0; UINT32 pbContextNdrPtr = 0; WINPR_ASSERT(call); wLog* log = scard_log(); if (!smartcard_ndr_pointer_read(log, s, &index, &mszNdrPtr)) return ERROR_INVALID_DATA; LONG status = smartcard_unpack_redir_scard_context(log, s, &(call->Common.handles.hContext), &index, &pbContextNdrPtr); if (status != SCARD_S_SUCCESS) return status; if (!smartcard_ndr_pointer_read(log, s, &index, &contextNdrPtr)) return ERROR_INVALID_DATA; if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 12)) return STATUS_BUFFER_TOO_SMALL; Stream_Read_UINT32(s, call->Common.FreshnessCounter); Stream_Read_INT32(s, call->Common.fPbDataIsNULL); Stream_Read_UINT32(s, call->Common.cbDataLen); call->szLookupName = nullptr; if (mszNdrPtr) { status = smartcard_ndr_read_a(log, s, &call->szLookupName, NDR_PTR_FULL); if (status != SCARD_S_SUCCESS) return status; } status = smartcard_unpack_redir_scard_context_ref(log, s, pbContextNdrPtr, &call->Common.handles.hContext); if (status != SCARD_S_SUCCESS) return status; if (contextNdrPtr) { status = smartcard_ndr_read_u(log, s, &call->Common.CardIdentifier); if (status != SCARD_S_SUCCESS) return status; } smartcard_trace_read_cache_a_call(log, call); return SCARD_S_SUCCESS; } LONG smartcard_unpack_read_cache_w_call(wStream* s, ReadCacheW_Call* call) { UINT32 mszNdrPtr = 0; UINT32 contextNdrPtr = 0; UINT32 index = 0; UINT32 pbContextNdrPtr = 0; WINPR_ASSERT(call); wLog* log = scard_log(); if (!smartcard_ndr_pointer_read(log, s, &index, &mszNdrPtr)) return ERROR_INVALID_DATA; LONG status = smartcard_unpack_redir_scard_context(log, s, &(call->Common.handles.hContext), &index, &pbContextNdrPtr); if (status != SCARD_S_SUCCESS) return status; if (!smartcard_ndr_pointer_read(log, s, &index, &contextNdrPtr)) return ERROR_INVALID_DATA; if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 12)) return STATUS_BUFFER_TOO_SMALL; Stream_Read_UINT32(s, call->Common.FreshnessCounter); Stream_Read_INT32(s, call->Common.fPbDataIsNULL); Stream_Read_UINT32(s, call->Common.cbDataLen); call->szLookupName = nullptr; if (mszNdrPtr) { status = smartcard_ndr_read_w(log, s, &call->szLookupName, NDR_PTR_FULL); if (status != SCARD_S_SUCCESS) return status; } status = smartcard_unpack_redir_scard_context_ref(log, s, pbContextNdrPtr, &call->Common.handles.hContext); if (status != SCARD_S_SUCCESS) return status; if (contextNdrPtr) { status = smartcard_ndr_read_u(log, s, &call->Common.CardIdentifier); if (status != SCARD_S_SUCCESS) return status; } smartcard_trace_read_cache_w_call(log, call); return SCARD_S_SUCCESS; } LONG smartcard_unpack_write_cache_a_call(wStream* s, WriteCacheA_Call* call) { UINT32 mszNdrPtr = 0; UINT32 contextNdrPtr = 0; UINT32 pbDataNdrPtr = 0; UINT32 index = 0; UINT32 pbContextNdrPtr = 0; WINPR_ASSERT(call); wLog* log = scard_log(); if (!smartcard_ndr_pointer_read(log, s, &index, &mszNdrPtr)) return ERROR_INVALID_DATA; LONG status = smartcard_unpack_redir_scard_context(log, s, &(call->Common.handles.hContext), &index, &pbContextNdrPtr); if (status != SCARD_S_SUCCESS) return status; if (!smartcard_ndr_pointer_read(log, s, &index, &contextNdrPtr)) return ERROR_INVALID_DATA; if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 8)) return STATUS_BUFFER_TOO_SMALL; Stream_Read_UINT32(s, call->Common.FreshnessCounter); Stream_Read_UINT32(s, call->Common.cbDataLen); if (!smartcard_ndr_pointer_read(log, s, &index, &pbDataNdrPtr)) return ERROR_INVALID_DATA; call->szLookupName = nullptr; if (mszNdrPtr) { status = smartcard_ndr_read_a(log, s, &call->szLookupName, NDR_PTR_FULL); if (status != SCARD_S_SUCCESS) return status; } status = smartcard_unpack_redir_scard_context_ref(log, s, pbContextNdrPtr, &call->Common.handles.hContext); if (status != SCARD_S_SUCCESS) return status; call->Common.CardIdentifier = nullptr; if (contextNdrPtr) { status = smartcard_ndr_read_u(log, s, &call->Common.CardIdentifier); if (status != SCARD_S_SUCCESS) return status; } call->Common.pbData = nullptr; if (pbDataNdrPtr) { status = smartcard_ndr_read(log, s, &call->Common.pbData, call->Common.cbDataLen, 1, NDR_PTR_SIMPLE); if (status != SCARD_S_SUCCESS) return status; } smartcard_trace_write_cache_a_call(log, call); return SCARD_S_SUCCESS; } LONG smartcard_unpack_write_cache_w_call(wStream* s, WriteCacheW_Call* call) { UINT32 mszNdrPtr = 0; UINT32 contextNdrPtr = 0; UINT32 pbDataNdrPtr = 0; UINT32 index = 0; UINT32 pbContextNdrPtr = 0; WINPR_ASSERT(call); wLog* log = scard_log(); if (!smartcard_ndr_pointer_read(log, s, &index, &mszNdrPtr)) return ERROR_INVALID_DATA; LONG status = smartcard_unpack_redir_scard_context(log, s, &(call->Common.handles.hContext), &index, &pbContextNdrPtr); if (status != SCARD_S_SUCCESS) return status; if (!smartcard_ndr_pointer_read(log, s, &index, &contextNdrPtr)) return ERROR_INVALID_DATA; if (!Stream_CheckAndLogRequiredLengthWLog(log, s, 8)) return STATUS_BUFFER_TOO_SMALL; Stream_Read_UINT32(s, call->Common.FreshnessCounter); Stream_Read_UINT32(s, call->Common.cbDataLen); if (!smartcard_ndr_pointer_read(log, s, &index, &pbDataNdrPtr)) return ERROR_INVALID_DATA; call->szLookupName = nullptr; if (mszNdrPtr) { status = smartcard_ndr_read_w(log, s, &call->szLookupName, NDR_PTR_FULL); if (status != SCARD_S_SUCCESS) return status; } status = smartcard_unpack_redir_scard_context_ref(log, s, pbContextNdrPtr, &call->Common.handles.hContext); if (status != SCARD_S_SUCCESS) return status; call->Common.CardIdentifier = nullptr; if (contextNdrPtr) { status = smartcard_ndr_read_u(log, s, &call->Common.CardIdentifier); if (status != SCARD_S_SUCCESS) return status; } call->Common.pbData = nullptr; if (pbDataNdrPtr) { status = smartcard_ndr_read(log, s, &call->Common.pbData, call->Common.cbDataLen, 1, NDR_PTR_SIMPLE); if (status != SCARD_S_SUCCESS) return status; } smartcard_trace_write_cache_w_call(log, call); return status; } LONG smartcard_unpack_get_transmit_count_call(wStream* s, GetTransmitCount_Call* call) { WINPR_ASSERT(call); wLog* log = scard_log(); UINT32 index = 0; UINT32 pbContextNdrPtr = 0; LONG status = smartcard_unpack_redir_scard_context(log, s, &(call->handles.hContext), &index, &pbContextNdrPtr); if (status != SCARD_S_SUCCESS) return status; status = smartcard_unpack_redir_scard_handle(log, s, &(call->handles.hCard), &index); if (status != SCARD_S_SUCCESS) return status; status = smartcard_unpack_redir_scard_context_ref(log, s, pbContextNdrPtr, &(call->handles.hContext)); if (status != SCARD_S_SUCCESS) { WLog_Print(log, WLOG_ERROR, "smartcard_unpack_redir_scard_context_ref failed with error %" PRId32 "", status); return status; } status = smartcard_unpack_redir_scard_handle_ref(log, s, &(call->handles.hCard)); if (status != SCARD_S_SUCCESS) WLog_Print(log, WLOG_ERROR, "smartcard_unpack_redir_scard_handle_ref failed with error %" PRId32 "", status); smartcard_trace_get_transmit_count_call(log, call); return status; } LONG smartcard_unpack_get_reader_icon_call(wStream* s, GetReaderIcon_Call* call) { WINPR_ASSERT(call); wLog* log = scard_log(); return smartcard_unpack_common_context_and_string_w(log, s, &call->handles.hContext, &call->szReaderName); } LONG smartcard_unpack_context_and_string_a_call(wStream* s, ContextAndStringA_Call* call) { WINPR_ASSERT(call); wLog* log = scard_log(); return smartcard_unpack_common_context_and_string_a(log, s, &call->handles.hContext, &call->sz); } LONG smartcard_unpack_context_and_string_w_call(wStream* s, ContextAndStringW_Call* call) { WINPR_ASSERT(call); wLog* log = scard_log(); return smartcard_unpack_common_context_and_string_w(log, s, &call->handles.hContext, &call->sz); } LONG smartcard_unpack_get_device_type_id_call(wStream* s, GetDeviceTypeId_Call* call) { WINPR_ASSERT(call); wLog* log = scard_log(); return smartcard_unpack_common_context_and_string_w(log, s, &call->handles.hContext, &call->szReaderName); } LONG smartcard_pack_device_type_id_return(wStream* s, const GetDeviceTypeId_Return* ret) { WINPR_ASSERT(ret); wLog* log = scard_log(); smartcard_trace_device_type_id_return(log, ret); if (!Stream_EnsureRemainingCapacity(s, 4)) { WLog_Print(log, WLOG_ERROR, "Stream_EnsureRemainingCapacity failed!"); return SCARD_F_INTERNAL_ERROR; } Stream_Write_UINT32(s, ret->dwDeviceId); /* cBytes (4 bytes) */ return ret->ReturnCode; } LONG smartcard_pack_locate_cards_return(wStream* s, const LocateCards_Return* ret) { WINPR_ASSERT(ret); wLog* log = scard_log(); LONG status = 0; DWORD cbDataLen = ret->cReaders; UINT32 index = 0; smartcard_trace_locate_cards_return(log, ret); if (ret->ReturnCode != SCARD_S_SUCCESS) cbDataLen = 0; if (cbDataLen == SCARD_AUTOALLOCATE) cbDataLen = 0; if (!Stream_EnsureRemainingCapacity(s, 4)) { WLog_Print(log, WLOG_ERROR, "Stream_EnsureRemainingCapacity failed!"); return SCARD_F_INTERNAL_ERROR; } Stream_Write_UINT32(s, cbDataLen); /* cBytes (4 cbDataLen) */ if (!smartcard_ndr_pointer_write(s, &index, cbDataLen)) return SCARD_E_NO_MEMORY; status = smartcard_ndr_write_state(s, ret->rgReaderStates, cbDataLen, NDR_PTR_SIMPLE); if (status != SCARD_S_SUCCESS) return status; return ret->ReturnCode; } LONG smartcard_pack_get_reader_icon_return(wStream* s, const GetReaderIcon_Return* ret) { WINPR_ASSERT(ret); wLog* log = scard_log(); LONG status = 0; UINT32 index = 0; DWORD cbDataLen = ret->cbDataLen; smartcard_trace_get_reader_icon_return(log, ret); if (ret->ReturnCode != SCARD_S_SUCCESS) cbDataLen = 0; if (cbDataLen == SCARD_AUTOALLOCATE) cbDataLen = 0; if (!Stream_EnsureRemainingCapacity(s, 4)) { WLog_Print(log, WLOG_ERROR, "Stream_EnsureRemainingCapacity failed!"); return SCARD_F_INTERNAL_ERROR; } Stream_Write_UINT32(s, cbDataLen); /* cBytes (4 cbDataLen) */ if (!smartcard_ndr_pointer_write(s, &index, cbDataLen)) return SCARD_E_NO_MEMORY; status = smartcard_ndr_write(s, ret->pbData, cbDataLen, 1, NDR_PTR_SIMPLE); if (status != SCARD_S_SUCCESS) return status; return ret->ReturnCode; } LONG smartcard_pack_get_transmit_count_return(wStream* s, const GetTransmitCount_Return* call) { WINPR_ASSERT(call); wLog* log = scard_log(); smartcard_trace_get_transmit_count_return(log, call); if (!Stream_EnsureRemainingCapacity(s, 4)) { WLog_Print(log, WLOG_ERROR, "Stream_EnsureRemainingCapacity failed!"); return SCARD_F_INTERNAL_ERROR; } Stream_Write_UINT32(s, call->cTransmitCount); /* cBytes (4 cbDataLen) */ return call->ReturnCode; } LONG smartcard_pack_read_cache_return(wStream* s, const ReadCache_Return* ret) { WINPR_ASSERT(ret); wLog* log = scard_log(); LONG status = 0; UINT32 index = 0; DWORD cbDataLen = ret->cbDataLen; smartcard_trace_read_cache_return(log, ret); if (ret->ReturnCode != SCARD_S_SUCCESS) cbDataLen = 0; if (cbDataLen == SCARD_AUTOALLOCATE) cbDataLen = 0; if (!Stream_EnsureRemainingCapacity(s, 4)) { WLog_Print(log, WLOG_ERROR, "Stream_EnsureRemainingCapacity failed!"); return SCARD_F_INTERNAL_ERROR; } Stream_Write_UINT32(s, cbDataLen); /* cBytes (4 cbDataLen) */ if (!smartcard_ndr_pointer_write(s, &index, cbDataLen)) return SCARD_E_NO_MEMORY; status = smartcard_ndr_write(s, ret->pbData, cbDataLen, 1, NDR_PTR_SIMPLE); if (status != SCARD_S_SUCCESS) return status; return ret->ReturnCode; }