Merge pull request #5884 from akallabeth/smartcard_ndr_strict

Smartcard tighter input validation
This commit is contained in:
Martin Fleisz 2020-03-31 08:34:04 +02:00 committed by GitHub
commit 99786970a3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 3312 additions and 2303 deletions

View File

@ -73,8 +73,7 @@ static UINT irp_complete(IRP* irp)
error = rdpdr_send(rdpdr, irp->output);
irp->output = NULL;
irp_free(irp);
return error;
return irp_free(irp);
}
IRP* irp_new(DEVMAN* devman, wStream* s, UINT* error)

View File

@ -1471,7 +1471,7 @@ static UINT rdpdr_virtual_channel_event_data_received(rdpdrPlugin* rdpdr, void*
data_in = rdpdr->data_in;
if (!Stream_EnsureRemainingCapacity(data_in, (int)dataLength))
if (!Stream_EnsureRemainingCapacity(data_in, dataLength))
{
WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!");
return ERROR_INVALID_DATA;
@ -1602,6 +1602,12 @@ static DWORD WINAPI rdpdr_virtual_channel_client_thread(LPVOID arg)
return 0;
}
static void queue_free(void* obj)
{
wStream* s = obj;
Stream_Free(s, TRUE);
}
/**
* Function description
*
@ -1630,6 +1636,8 @@ static UINT rdpdr_virtual_channel_event_connected(rdpdrPlugin* rdpdr, LPVOID pDa
return CHANNEL_RC_NO_MEMORY;
}
rdpdr->queue->object.fnObjectFree = queue_free;
if (!(rdpdr->thread =
CreateThread(NULL, 0, rdpdr_virtual_channel_client_thread, (void*)rdpdr, 0, NULL)))
{

View File

@ -211,7 +211,8 @@ static LONG smartcard_EstablishContext_Decode(SMARTCARD_DEVICE* smartcard,
if (!call)
return STATUS_NO_MEMORY;
if ((status = smartcard_unpack_establish_context_call(smartcard, irp->input, call)))
status = smartcard_unpack_establish_context_call(smartcard, irp->input, call);
if (status != SCARD_S_SUCCESS)
{
return log_status_error(TAG, "smartcard_unpack_establish_context_call", status);
}
@ -223,7 +224,7 @@ static LONG smartcard_EstablishContext_Call(SMARTCARD_DEVICE* smartcard,
SMARTCARD_OPERATION* operation)
{
LONG status;
SCARDCONTEXT hContext = -1;
SCARDCONTEXT hContext = { 0 };
EstablishContext_Return ret;
IRP* irp = operation->irp;
EstablishContext_Call* call = operation->call;
@ -255,7 +256,8 @@ static LONG smartcard_EstablishContext_Call(SMARTCARD_DEVICE* smartcard,
smartcard_scard_context_native_to_redir(smartcard, &(ret.hContext), hContext);
if ((status = smartcard_pack_establish_context_return(smartcard, irp->output, &ret)))
status = smartcard_pack_establish_context_return(smartcard, irp->output, &ret);
if (status != SCARD_S_SUCCESS)
{
return log_status_error(TAG, "smartcard_pack_establish_context_return", status);
}
@ -274,7 +276,8 @@ static LONG smartcard_ReleaseContext_Decode(SMARTCARD_DEVICE* smartcard,
if (!call)
return STATUS_NO_MEMORY;
if ((status = smartcard_unpack_context_call(smartcard, irp->input, call, "ReleaseContext")))
status = smartcard_unpack_context_call(smartcard, irp->input, call, "ReleaseContext");
if (status != SCARD_S_SUCCESS)
log_status_error(TAG, "smartcard_unpack_context_call", status);
operation->hContext = smartcard_scard_context_native_from_redir(smartcard, &(call->hContext));
@ -364,7 +367,7 @@ static LONG smartcard_ListReaderGroupsA_Call(SMARTCARD_DEVICE* smartcard,
if (status != SCARD_S_SUCCESS)
return status;
status = smartcard_pack_list_reader_groups_return(smartcard, irp->output, &ret);
status = smartcard_pack_list_reader_groups_return(smartcard, irp->output, &ret, FALSE);
if (status != SCARD_S_SUCCESS)
return status;
@ -409,7 +412,7 @@ static LONG smartcard_ListReaderGroupsW_Call(SMARTCARD_DEVICE* smartcard,
if (status != SCARD_S_SUCCESS)
return status;
status = smartcard_pack_list_reader_groups_return(smartcard, irp->output, &ret);
status = smartcard_pack_list_reader_groups_return(smartcard, irp->output, &ret, TRUE);
if (status != SCARD_S_SUCCESS)
return status;
@ -538,7 +541,7 @@ static LONG smartcard_ListReadersA_Call(SMARTCARD_DEVICE* smartcard, SMARTCARD_O
call->mszGroups = NULL;
}
if (status)
if (status != SCARD_S_SUCCESS)
{
return log_status_error(TAG, "SCardListReadersA", status);
}
@ -547,7 +550,8 @@ static LONG smartcard_ListReadersA_Call(SMARTCARD_DEVICE* smartcard, SMARTCARD_O
ret.msz = (BYTE*)mszReaders;
ret.cBytes = cchReaders;
if ((status = smartcard_pack_list_readers_return(smartcard, irp->output, &ret, FALSE)))
status = smartcard_pack_list_readers_return(smartcard, irp->output, &ret, FALSE);
if (status != SCARD_S_SUCCESS)
{
return log_status_error(TAG, "smartcard_pack_list_readers_return", status);
}
@ -684,7 +688,6 @@ static LONG smartcard_ListReadersW_Call(SMARTCARD_DEVICE* smartcard, SMARTCARD_O
{
LONG status;
ListReaders_Return ret;
LPWSTR mszReaders = NULL;
DWORD cchReaders = 0;
IRP* irp = operation->irp;
ListReaders_Call* call = operation->call;
@ -693,11 +696,17 @@ static LONG smartcard_ListReadersW_Call(SMARTCARD_DEVICE* smartcard, SMARTCARD_O
const char* sz;
const WCHAR* wz;
} string;
union {
WCHAR** ppw;
WCHAR* pw;
CHAR* pc;
BYTE* pb;
} mszReaders;
string.bp = call->mszGroups;
cchReaders = SCARD_AUTOALLOCATE;
status = ret.ReturnCode =
SCardListReadersW(operation->hContext, string.wz, (LPWSTR)&mszReaders, &cchReaders);
SCardListReadersW(operation->hContext, string.wz, (LPWSTR)&mszReaders.pw, &cchReaders);
if (call->mszGroups)
{
@ -708,14 +717,13 @@ static LONG smartcard_ListReadersW_Call(SMARTCARD_DEVICE* smartcard, SMARTCARD_O
if (status != SCARD_S_SUCCESS)
return log_status_error(TAG, "SCardListReadersW", status);
cchReaders = filter_device_by_name_w(smartcard->names, &mszReaders, cchReaders);
ret.msz = (BYTE*)mszReaders;
ret.cBytes = cchReaders * 2;
cchReaders = filter_device_by_name_w(smartcard->names, &mszReaders.pw, cchReaders);
ret.msz = mszReaders.pb;
ret.cBytes = cchReaders;
status = smartcard_pack_list_readers_return(smartcard, irp->output, &ret, TRUE);
if (mszReaders)
SCardFreeMemory(operation->hContext, mszReaders);
if (mszReaders.pb)
SCardFreeMemory(operation->hContext, mszReaders.pb);
if (status != SCARD_S_SUCCESS)
return status;
@ -945,24 +953,36 @@ static LONG smartcard_ReadCacheA_Call(SMARTCARD_DEVICE* smartcard, SMARTCARD_OPE
ReadCache_Return ret = { 0 };
ReadCacheA_Call* call = operation->call;
IRP* irp = operation->irp;
BOOL autoalloc = (call->Common.cbDataLen == SCARD_AUTOALLOCATE);
if (!call->Common.fPbDataIsNULL)
{
ret.cbDataLen = call->Common.cbDataLen;
ret.pbData = malloc(ret.cbDataLen);
if (!ret.pbData)
return SCARD_F_INTERNAL_ERROR;
if (autoalloc)
{
ret.pbData = malloc(ret.cbDataLen);
if (!ret.pbData)
return SCARD_F_INTERNAL_ERROR;
}
}
ret.ReturnCode = SCardReadCacheA(operation->hContext, call->Common.CardIdentifier,
call->Common.FreshnessCounter, call->szLookupName, ret.pbData,
&ret.cbDataLen);
if (autoalloc)
ret.ReturnCode = SCardReadCacheA(operation->hContext, call->Common.CardIdentifier,
call->Common.FreshnessCounter, call->szLookupName,
(BYTE*)&ret.pbData, &ret.cbDataLen);
else
ret.ReturnCode = SCardReadCacheA(operation->hContext, call->Common.CardIdentifier,
call->Common.FreshnessCounter, call->szLookupName,
ret.pbData, &ret.cbDataLen);
log_status_error(TAG, "SCardReadCacheA", ret.ReturnCode);
free(call->szLookupName);
free(call->Common.CardIdentifier);
status = smartcard_pack_read_cache_return(smartcard, irp->output, &ret);
free(ret.pbData);
if (autoalloc)
SCardFreeMemory(operation->hContext, ret.pbData);
else
free(ret.pbData);
if (status != SCARD_S_SUCCESS)
return status;
@ -975,24 +995,35 @@ static LONG smartcard_ReadCacheW_Call(SMARTCARD_DEVICE* smartcard, SMARTCARD_OPE
ReadCache_Return ret = { 0 };
ReadCacheW_Call* call = operation->call;
IRP* irp = operation->irp;
BOOL autoalloc = (call->Common.cbDataLen == SCARD_AUTOALLOCATE);
if (!call->Common.fPbDataIsNULL)
{
ret.cbDataLen = call->Common.cbDataLen;
ret.pbData = malloc(ret.cbDataLen);
if (!ret.pbData)
return SCARD_F_INTERNAL_ERROR;
if (autoalloc)
{
ret.pbData = malloc(ret.cbDataLen);
if (!ret.pbData)
return SCARD_F_INTERNAL_ERROR;
}
}
ret.ReturnCode = SCardReadCacheW(operation->hContext, call->Common.CardIdentifier,
call->Common.FreshnessCounter, call->szLookupName, ret.pbData,
&ret.cbDataLen);
if (autoalloc)
ret.ReturnCode = SCardReadCacheW(operation->hContext, call->Common.CardIdentifier,
call->Common.FreshnessCounter, call->szLookupName,
(BYTE*)&ret.pbData, &ret.cbDataLen);
else
ret.ReturnCode = SCardReadCacheW(operation->hContext, call->Common.CardIdentifier,
call->Common.FreshnessCounter, call->szLookupName,
ret.pbData, &ret.cbDataLen);
log_status_error(TAG, "SCardReadCacheW", ret.ReturnCode);
free(call->szLookupName);
free(call->Common.CardIdentifier);
status = smartcard_pack_read_cache_return(smartcard, irp->output, &ret);
free(ret.pbData);
if (autoalloc)
SCardFreeMemory(operation->hContext, ret.pbData);
else
free(ret.pbData);
if (status != SCARD_S_SUCCESS)
return status;
@ -1042,7 +1073,8 @@ static LONG smartcard_GetTransmitCount_Call(SMARTCARD_DEVICE* smartcard,
ret.ReturnCode = SCardGetTransmitCount(operation->hContext, &ret.cTransmitCount);
log_status_error(TAG, "SCardGetTransmitCount", ret.ReturnCode);
if ((status = smartcard_pack_get_transmit_count_return(smartcard, irp->output, &ret)))
status = smartcard_pack_get_transmit_count_return(smartcard, irp->output, &ret);
if (status != SCARD_S_SUCCESS)
return status;
return ret.ReturnCode;
@ -1074,7 +1106,7 @@ static LONG smartcard_GetReaderIcon_Call(SMARTCARD_DEVICE* smartcard,
free(call->szReaderName);
status = smartcard_pack_get_reader_icon_return(smartcard, irp->output, &ret);
SCardFreeMemory(operation->hContext, ret.pbData);
if (status)
if (status != SCARD_S_SUCCESS)
return status;
return ret.ReturnCode;
@ -1094,7 +1126,7 @@ static LONG smartcard_GetDeviceTypeId_Call(SMARTCARD_DEVICE* smartcard,
free(call->szReaderName);
status = smartcard_pack_device_type_id_return(smartcard, irp->output, &ret);
if (status)
if (status != SCARD_S_SUCCESS)
return status;
return ret.ReturnCode;
@ -1144,7 +1176,8 @@ static LONG smartcard_GetStatusChangeA_Call(SMARTCARD_DEVICE* smartcard,
ret.rgReaderStates[index].dwCurrentState = call->rgReaderStates[index].dwCurrentState;
ret.rgReaderStates[index].dwEventState = call->rgReaderStates[index].dwEventState;
ret.rgReaderStates[index].cbAtr = call->rgReaderStates[index].cbAtr;
CopyMemory(&(ret.rgReaderStates[index].rgbAtr), &(call->rgReaderStates[index].rgbAtr), 32);
CopyMemory(&(ret.rgReaderStates[index].rgbAtr), &(call->rgReaderStates[index].rgbAtr),
sizeof(ret.rgReaderStates[index].rgbAtr));
}
smartcard_pack_get_status_change_return(smartcard, irp->output, &ret, FALSE);
@ -1208,7 +1241,8 @@ static LONG smartcard_GetStatusChangeW_Call(SMARTCARD_DEVICE* smartcard,
ret.rgReaderStates[index].dwCurrentState = call->rgReaderStates[index].dwCurrentState;
ret.rgReaderStates[index].dwEventState = call->rgReaderStates[index].dwEventState;
ret.rgReaderStates[index].cbAtr = call->rgReaderStates[index].cbAtr;
CopyMemory(&(ret.rgReaderStates[index].rgbAtr), &(call->rgReaderStates[index].rgbAtr), 32);
CopyMemory(&(ret.rgReaderStates[index].rgbAtr), &(call->rgReaderStates[index].rgbAtr),
sizeof(ret.rgReaderStates[index].rgbAtr));
}
smartcard_pack_get_status_change_return(smartcard, irp->output, &ret, TRUE);
@ -1290,13 +1324,6 @@ static LONG smartcard_ConnectA_Call(SMARTCARD_DEVICE* smartcard, SMARTCARD_OPERA
call->Common.dwPreferredProtocols, &hCard, &ret.dwActiveProtocol);
smartcard_scard_context_native_to_redir(smartcard, &(ret.hContext), operation->hContext);
smartcard_scard_handle_native_to_redir(smartcard, &(ret.hCard), hCard);
smartcard_trace_connect_return(smartcard, &ret);
if (status)
{
log_status_error(TAG, "SCardConnectA", status);
goto out_fail;
}
status = smartcard_pack_connect_return(smartcard, irp->output, &ret);
if (status != SCARD_S_SUCCESS)
@ -1344,13 +1371,6 @@ static LONG smartcard_ConnectW_Call(SMARTCARD_DEVICE* smartcard, SMARTCARD_OPERA
call->Common.dwPreferredProtocols, &hCard, &ret.dwActiveProtocol);
smartcard_scard_context_native_to_redir(smartcard, &(ret.hContext), operation->hContext);
smartcard_scard_handle_native_to_redir(smartcard, &(ret.hCard), hCard);
smartcard_trace_connect_return(smartcard, &ret);
if (status)
{
log_status_error(TAG, "SCardConnectW", status);
goto out_fail;
}
status = smartcard_pack_connect_return(smartcard, irp->output, &ret);
if (status != SCARD_S_SUCCESS)
@ -1545,7 +1565,7 @@ static LONG smartcard_StatusA_Call(SMARTCARD_DEVICE* smartcard, SMARTCARD_OPERAT
LPSTR mszReaderNames = NULL;
IRP* irp = operation->irp;
Status_Call* call = operation->call;
ZeroMemory(ret.pbAtr, 32);
call->cbAtrLen = 32;
cbAtrLen = call->cbAtrLen;
@ -1601,8 +1621,7 @@ static LONG smartcard_StatusW_Decode(SMARTCARD_DEVICE* smartcard, SMARTCARD_OPER
static LONG smartcard_StatusW_Call(SMARTCARD_DEVICE* smartcard, SMARTCARD_OPERATION* operation)
{
LONG status;
Status_Return ret;
DWORD cchReaderLen = 0;
Status_Return ret = { 0 };
LPWSTR mszReaderNames = NULL;
IRP* irp = operation->irp;
Status_Call* call = operation->call;
@ -1615,28 +1634,19 @@ static LONG smartcard_StatusW_Call(SMARTCARD_DEVICE* smartcard, SMARTCARD_OPERAT
cbAtrLen = call->cbAtrLen = 32;
if (call->fmszReaderNamesIsNULL)
cchReaderLen = 0;
ret.cBytes = 0;
else
cchReaderLen = SCARD_AUTOALLOCATE;
ret.cBytes = SCARD_AUTOALLOCATE;
ZeroMemory(ret.pbAtr, 32);
status = ret.ReturnCode =
SCardStatusW(operation->hCard, call->fmszReaderNamesIsNULL ? NULL : (LPWSTR)&mszReaderNames,
&cchReaderLen, &ret.dwState, &ret.dwProtocol, (BYTE*)&ret.pbAtr, &cbAtrLen);
&ret.cBytes, &ret.dwState, &ret.dwProtocol, (BYTE*)&ret.pbAtr, &cbAtrLen);
log_status_error(TAG, "SCardStatusW", status);
if (status == SCARD_S_SUCCESS)
{
if (!call->fmszReaderNamesIsNULL)
ret.mszReaderNames = (BYTE*)mszReaderNames;
// WinScard returns the number of CHARACTERS whereas pcsc-lite returns the
// number of BYTES.
#ifdef _WIN32
ret.cBytes = cchReaderLen * 2;
#else
ret.cBytes = cchReaderLen;
#endif
ret.cbAtrLen = cbAtrLen;
}
@ -1701,7 +1711,7 @@ static LONG smartcard_Transmit_Call(SMARTCARD_DEVICE* smartcard, SMARTCARD_OPERA
free(call->pioSendPci);
free(call->pioRecvPci);
if (status)
if (status != SCARD_S_SUCCESS)
return status;
return ret.ReturnCode;
}
@ -1811,23 +1821,14 @@ static LONG smartcard_GetAttrib_Call(SMARTCARD_DEVICE* smartcard, SMARTCARD_OPER
autoAllocate ? (LPBYTE) & (ret.pbAttr) : ret.pbAttr, &cbAttrLen);
log_status_error(TAG, "SCardGetAttrib", ret.ReturnCode);
ret.cbAttrLen = cbAttrLen;
free(ret.pbAttr);
if (ret.ReturnCode)
{
WLog_WARN(TAG, "SCardGetAttrib: %s (0x%08" PRIX32 ") cbAttrLen: %" PRIu32 "",
SCardGetAttributeString(call->dwAttrId), call->dwAttrId, call->cbAttrLen);
Stream_Zero(irp->output, 256);
return ret.ReturnCode;
}
status = smartcard_pack_get_attrib_return(smartcard, irp->output, &ret, call->dwAttrId);
if (status != SCARD_S_SUCCESS)
return status;
return ret.ReturnCode;
if (autoAllocate)
SCardFreeMemory(operation->hContext, ret.pbAttr);
else
free(ret.pbAttr);
return status;
}
static LONG smartcard_SetAttrib_Call(SMARTCARD_DEVICE* smartcard, SMARTCARD_OPERATION* operation)
@ -2115,7 +2116,8 @@ static LONG smartcard_LocateCardsByATRA_Call(SMARTCARD_DEVICE* smartcard,
ret.rgReaderStates[i].dwCurrentState = state->dwCurrentState;
ret.rgReaderStates[i].dwEventState = state->dwEventState;
ret.rgReaderStates[i].cbAtr = state->cbAtr;
CopyMemory(&(ret.rgReaderStates[i].rgbAtr), &(state->rgbAtr), 32);
CopyMemory(&(ret.rgReaderStates[i].rgbAtr), &(state->rgbAtr),
sizeof(ret.rgReaderStates[i].rgbAtr));
}
free(states);
@ -2184,10 +2186,12 @@ LONG smartcard_irp_device_control_decode(SMARTCARD_DEVICE* smartcard,
if ((ioControlCode != SCARD_IOCTL_ACCESSSTARTEDEVENT) &&
(ioControlCode != SCARD_IOCTL_RELEASETARTEDEVENT))
{
if ((status = smartcard_unpack_common_type_header(smartcard, irp->input)))
status = smartcard_unpack_common_type_header(smartcard, irp->input);
if (status != SCARD_S_SUCCESS)
return status;
if ((status = smartcard_unpack_private_type_header(smartcard, irp->input)))
status = smartcard_unpack_private_type_header(smartcard, irp->input);
if (status != SCARD_S_SUCCESS)
return status;
}
@ -2451,7 +2455,9 @@ LONG smartcard_irp_device_control_call(SMARTCARD_DEVICE* smartcard, SMARTCARD_OP
* Since it's a SHOULD and not a MUST, we don't care
* about it, but we still reserve at least 2048 bytes.
*/
Stream_EnsureRemainingCapacity(irp->output, 2048);
if (!Stream_EnsureRemainingCapacity(irp->output, 2048))
return SCARD_E_NO_MEMORY;
/* Device Control Response */
Stream_Seek_UINT32(irp->output); /* OutputBufferLength (4 bytes) */
Stream_Seek(irp->output, SMARTCARD_COMMON_TYPE_HEADER_LENGTH); /* CommonTypeHeader (8 bytes) */
@ -2687,7 +2693,7 @@ LONG smartcard_irp_device_control_call(SMARTCARD_DEVICE* smartcard, SMARTCARD_OP
irp->IoStatus = STATUS_SUCCESS;
if ((result & 0xC0000000) == 0xC0000000)
if ((result & 0xC0000000L) == 0xC0000000L)
{
/* NTSTATUS error */
irp->IoStatus = (UINT32)result;
@ -2704,7 +2710,7 @@ LONG smartcard_irp_device_control_call(SMARTCARD_DEVICE* smartcard, SMARTCARD_OP
smartcard_pack_common_type_header(smartcard, irp->output); /* CommonTypeHeader (8 bytes) */
smartcard_pack_private_type_header(smartcard, irp->output,
objectBufferLength); /* PrivateTypeHeader (8 bytes) */
Stream_Write_UINT32(irp->output, result); /* Result (4 bytes) */
Stream_Write_INT32(irp->output, result); /* Result (4 bytes) */
Stream_SetPosition(irp->output, Stream_Length(irp->output));
return SCARD_S_SUCCESS;
}

File diff suppressed because it is too large Load Diff

View File

@ -5,6 +5,8 @@
* Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
* Copyright 2015 Thincast Technologies GmbH
* Copyright 2015 DI (FH) Martin Haimberger <martin.haimberger@thincast.com>
* Copyright 2020 Armin Novak <armin.novak@thincast.com>
* 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.
@ -26,6 +28,8 @@
#include <winpr/stream.h>
#include <winpr/smartcard.h>
#pragma pack(push, 1)
/* interface type_scard_pack */
/* [unique][version][uuid] */
@ -138,7 +142,7 @@ typedef struct _LocateCardsA_Call
{
REDIR_SCARDCONTEXT hContext;
/* [range] */ DWORD cBytes;
/* [size_is] */ char* mszCards;
/* [size_is] */ CHAR* mszCards;
/* [range] */ DWORD cReaders;
/* [size_is] */ LPSCARD_READERSTATEA rgReaderStates;
} LocateCardsA_Call;
@ -228,7 +232,7 @@ typedef struct _Connect_Common
typedef struct _ConnectA_Call
{
/* [string] */ unsigned char* szReader;
/* [string] */ CHAR* szReader;
Connect_Common Common;
} ConnectA_Call;
@ -436,14 +440,16 @@ typedef struct _WriteCacheW_Call
WriteCache_Common Common;
} WriteCacheW_Call;
#pragma pack(pop)
#define SMARTCARD_COMMON_TYPE_HEADER_LENGTH 8
#define SMARTCARD_PRIVATE_TYPE_HEADER_LENGTH 8
#include "smartcard_main.h"
LONG smartcard_pack_write_size_align(SMARTCARD_DEVICE* smartcard, wStream* s, UINT32 size,
LONG smartcard_pack_write_size_align(SMARTCARD_DEVICE* smartcard, wStream* s, size_t size,
UINT32 alignment);
LONG smartcard_unpack_read_size_align(SMARTCARD_DEVICE* smartcard, wStream* s, UINT32 size,
LONG smartcard_unpack_read_size_align(SMARTCARD_DEVICE* smartcard, wStream* s, size_t size,
UINT32 alignment);
SCARDCONTEXT smartcard_scard_context_native_from_redir(SMARTCARD_DEVICE* smartcard,
@ -479,7 +485,7 @@ LONG smartcard_unpack_list_reader_groups_call(SMARTCARD_DEVICE* smartcard, wStre
ListReaderGroups_Call* call, BOOL unicode);
LONG smartcard_pack_list_reader_groups_return(SMARTCARD_DEVICE* smartcard, wStream* s,
const ListReaderGroups_Return* ret);
const ListReaderGroups_Return* ret, BOOL unicode);
LONG smartcard_unpack_list_readers_call(SMARTCARD_DEVICE* smartcard, wStream* s,
ListReaders_Call* call, BOOL unicode);
@ -515,8 +521,8 @@ LONG smartcard_unpack_connect_a_call(SMARTCARD_DEVICE* smartcard, wStream* s, Co
LONG smartcard_unpack_connect_w_call(SMARTCARD_DEVICE* smartcard, wStream* s, ConnectW_Call* call);
LONG smartcard_pack_connect_return(SMARTCARD_DEVICE* smartcard, wStream* s, Connect_Return* ret);
void smartcard_trace_connect_return(SMARTCARD_DEVICE* smartcard, const Connect_Return* ret);
LONG smartcard_pack_connect_return(SMARTCARD_DEVICE* smartcard, wStream* s,
const Connect_Return* ret);
LONG smartcard_unpack_reconnect_call(SMARTCARD_DEVICE* smartcard, wStream* s, Reconnect_Call* call);
@ -553,9 +559,6 @@ LONG smartcard_pack_get_attrib_return(SMARTCARD_DEVICE* smartcard, wStream* s,
LONG smartcard_unpack_set_attrib_call(SMARTCARD_DEVICE* smartcard, wStream* s,
SetAttrib_Call* call);
LONG smartcard_pack_set_attrib_return(SMARTCARD_DEVICE* smartcard, wStream* s,
const GetAttrib_Return* ret);
LONG smartcard_unpack_control_call(SMARTCARD_DEVICE* smartcard, wStream* s, Control_Call* call);
LONG smartcard_pack_control_return(SMARTCARD_DEVICE* smartcard, wStream* s,

921
scripts/test-scard.cpp Normal file
View File

@ -0,0 +1,921 @@
/**
* FreeRDP: A Remote Desktop Protocol Implementation
* Smartcard API test program
*
* This simple program can be used to trigger calls for (almost) the
* entire SCARD API.
* Compile on windows, connect with FreeRDP via RDP with smartcard
* redirection enabled and run this test program on the windows
* machine.
*
* Copyright 2020 Armin Novak <armin.novak@thincast.com>
* 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 <iostream>
#include <string>
#include <sstream>
#include <locale>
#include <codecvt>
#include <comdef.h>
#include <winscard.h>
static const WCHAR* listW[] = { nullptr, L"SCard$AllReaders\000", L"SCard$DefaultReaders\000",
L"SCard$LocalReaders\000", L"SCard$SystemReaders\000" };
static const char* listA[] = { nullptr, "SCard$AllReaders\000", "SCard$DefaultReaders\000",
"SCard$LocalReaders\000", "SCard$SystemReaders\000" };
static std::string scope2str(DWORD scope)
{
switch (scope)
{
case SCARD_SCOPE_USER:
return "SCARD_SCOPE_USER";
case SCARD_SCOPE_TERMINAL:
return "SCARD_SCOPE_TERMINAL";
case SCARD_SCOPE_SYSTEM:
return "SCARD_SCOPE_SYSTEM";
default:
return "UNKNOWN";
}
}
static std::string err2str(LONG code)
{
switch (code)
{
case ERROR_BROKEN_PIPE:
return "ERROR_BROKEN_PIPE";
case SCARD_E_BAD_SEEK:
return "SCARD_E_BAD_SEEK";
case SCARD_E_CANCELLED:
return "SCARD_E_CANCELLED";
case SCARD_E_CANT_DISPOSE:
return "SCARD_E_CANT_DISPOSE";
case SCARD_E_CARD_UNSUPPORTED:
return "SCARD_E_CARD_UNSUPPORTED";
case SCARD_E_CERTIFICATE_UNAVAILABLE:
return "SCARD_E_CERTIFICATE_UNAVAILABLE";
case SCARD_E_COMM_DATA_LOST:
return "SCARD_E_COMM_DATA_LOST";
case SCARD_E_DIR_NOT_FOUND:
return "SCARD_E_DIR_NOT_FOUND";
case SCARD_E_DUPLICATE_READER:
return "SCARD_E_DUPLICATE_READER";
case SCARD_E_FILE_NOT_FOUND:
return "SCARD_E_FILE_NOT_FOUND";
case SCARD_E_ICC_CREATEORDER:
return "SCARD_E_ICC_CREATEORDER";
case SCARD_E_ICC_INSTALLATION:
return "SCARD_E_ICC_INSTALLATION";
case SCARD_E_INSUFFICIENT_BUFFER:
return "SCARD_E_INSUFFICIENT_BUFFER";
case SCARD_E_INVALID_ATR:
return "SCARD_E_INVALID_ATR";
case SCARD_E_INVALID_CHV:
return "SCARD_E_INVALID_CHV";
case SCARD_E_INVALID_HANDLE:
return "SCARD_E_INVALID_HANDLE";
case SCARD_E_INVALID_PARAMETER:
return "SCARD_E_INVALID_PARAMETER";
case SCARD_E_INVALID_TARGET:
return "SCARD_E_INVALID_TARGET";
case SCARD_E_INVALID_VALUE:
return "SCARD_E_INVALID_VALUE";
case SCARD_E_NO_ACCESS:
return "SCARD_E_NO_ACCESS";
case SCARD_E_NO_DIR:
return "SCARD_E_NO_DIR";
case SCARD_E_NO_FILE:
return "SCARD_E_NO_FILE";
case SCARD_E_NO_KEY_CONTAINER:
return "SCARD_E_NO_KEY_CONTAINER";
case SCARD_E_NO_MEMORY:
return "SCARD_E_NO_MEMORY";
case SCARD_E_NO_PIN_CACHE:
return "SCARD_E_NO_PIN_CACHE";
case SCARD_E_NO_READERS_AVAILABLE:
return "SCARD_E_NO_READERS_AVAILABLE";
case SCARD_E_NO_SERVICE:
return "SCARD_E_NO_SERVICE";
case SCARD_E_NO_SMARTCARD:
return "SCARD_E_NO_SMARTCARD";
case SCARD_E_NO_SUCH_CERTIFICATE:
return "SCARD_E_NO_SUCH_CERTIFICATE";
case SCARD_E_NOT_READY:
return "SCARD_E_NOT_READY";
case SCARD_E_NOT_TRANSACTED:
return "SCARD_E_NOT_TRANSACTED";
case SCARD_E_PCI_TOO_SMALL:
return "SCARD_E_PCI_TOO_SMALL";
case SCARD_E_PIN_CACHE_EXPIRED:
return "SCARD_E_PIN_CACHE_EXPIRED";
case SCARD_E_PROTO_MISMATCH:
return "SCARD_E_PROTO_MISMATCH";
case SCARD_E_READ_ONLY_CARD:
return "SCARD_E_READ_ONLY_CARD";
case SCARD_E_READER_UNAVAILABLE:
return "SCARD_E_READER_UNAVAILABLE";
case SCARD_E_READER_UNSUPPORTED:
return "SCARD_E_READER_UNSUPPORTED";
case SCARD_E_SERVER_TOO_BUSY:
return "SCARD_E_SERVER_TOO_BUSY";
case SCARD_E_SERVICE_STOPPED:
return "SCARD_E_SERVICE_STOPPED";
case SCARD_E_SHARING_VIOLATION:
return "SCARD_E_SHARING_VIOLATION";
case SCARD_E_SYSTEM_CANCELLED:
return "SCARD_E_SYSTEM_CANCELLED";
case SCARD_E_TIMEOUT:
return "SCARD_E_TIMEOUT";
case SCARD_E_UNEXPECTED:
return "SCARD_E_UNEXPECTED";
case SCARD_E_UNKNOWN_CARD:
return "SCARD_E_UNKNOWN_CARD";
case SCARD_E_UNKNOWN_READER:
return "SCARD_E_UNKNOWN_READER";
case SCARD_E_UNKNOWN_RES_MNG:
return "SCARD_E_UNKNOWN_RES_MNG";
case SCARD_E_UNSUPPORTED_FEATURE:
return "SCARD_E_UNSUPPORTED_FEATURE";
case SCARD_E_WRITE_TOO_MANY:
return "SCARD_E_WRITE_TOO_MANY";
case SCARD_F_COMM_ERROR:
return "SCARD_F_COMM_ERROR";
case SCARD_F_INTERNAL_ERROR:
return "SCARD_F_INTERNAL_ERROR";
case SCARD_F_UNKNOWN_ERROR:
return "SCARD_F_UNKNOWN_ERROR";
case SCARD_F_WAITED_TOO_LONG:
return "SCARD_F_WAITED_TOO_LONG";
case SCARD_P_SHUTDOWN:
return "SCARD_P_SHUTDOWN";
case SCARD_S_SUCCESS:
return "SCARD_S_SUCCESS";
case SCARD_W_CANCELLED_BY_USER:
return "SCARD_W_CANCELLED_BY_USER";
case SCARD_W_CACHE_ITEM_NOT_FOUND:
return "SCARD_W_CACHE_ITEM_NOT_FOUND";
case SCARD_W_CACHE_ITEM_STALE:
return "SCARD_W_CACHE_ITEM_STALE";
case SCARD_W_CACHE_ITEM_TOO_BIG:
return "SCARD_W_CACHE_ITEM_TOO_BIG";
case SCARD_W_CARD_NOT_AUTHENTICATED:
return "SCARD_W_CARD_NOT_AUTHENTICATED";
case SCARD_W_CHV_BLOCKED:
return "SCARD_W_CHV_BLOCKED";
case SCARD_W_EOF:
return "SCARD_W_EOF";
case SCARD_W_REMOVED_CARD:
return "SCARD_W_REMOVED_CARD";
case SCARD_W_RESET_CARD:
return "SCARD_W_RESET_CARD";
case SCARD_W_SECURITY_VIOLATION:
return "SCARD_W_SECURITY_VIOLATION";
case SCARD_W_UNPOWERED_CARD:
return "SCARD_W_UNPOWERED_CARD";
case SCARD_W_UNRESPONSIVE_CARD:
return "SCARD_W_UNRESPONSIVE_CARD";
case SCARD_W_UNSUPPORTED_CARD:
return "SCARD_W_UNSUPPORTED_CARD";
case SCARD_W_WRONG_CHV:
return "SCARD_W_WRONG_CHV";
default:
return "UNKNOWN";
}
}
static std::wstring err2wstr(LONG code)
{
auto str = err2str(code);
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
return converter.from_bytes(str);
}
#if 0
static bool test_listreadergroups(SCARDCONTEXT hContext) {
auto rc = SCardListReaderGroupsA(hContext, &groups, &foobar);
rc = SCardListReaderGroupsW(hContext, &groups, &foobar);
}
#endif
static bool test_valid(SCARDCONTEXT context)
{
auto rc = SCardIsValidContext(context);
if (rc)
std::cerr << "SCardIsValidContext failed with " << err2str(rc) << std::endl;
return true;
}
static bool test_list_readers_a(SCARDCONTEXT context)
{
for (auto cur : listA)
{
LPSTR mszReaders = nullptr;
DWORD chReaders = SCARD_AUTOALLOCATE;
auto rc = SCardListReadersA(context, cur, reinterpret_cast<LPSTR>(&mszReaders), &chReaders);
if (!cur)
{
cur = "NULL";
}
if (rc != SCARD_S_SUCCESS)
{
std::cerr << "SCardListReadersA [" << cur << "] failed with " << err2str(rc)
<< std::endl;
}
else
{
auto start = mszReaders;
auto end = &mszReaders[chReaders];
std::cout << "SCardListReadersA [" << cur << "] " << chReaders << " [";
while (start < end)
{
std::cout << start << ", ";
start += strnlen(start, chReaders) + 2;
}
std::cout << "]" << std::endl;
}
SCardFreeMemory(context, mszReaders);
}
return true;
}
static bool test_list_readers_w(SCARDCONTEXT context)
{
for (auto cur : listW)
{
LPWSTR mszReaders = nullptr;
DWORD chReaders = SCARD_AUTOALLOCATE;
auto rc =
SCardListReadersW(context, cur, reinterpret_cast<LPWSTR>(&mszReaders), &chReaders);
if (!cur)
{
cur = L"NULL";
}
if (rc != SCARD_S_SUCCESS)
{
std::wcerr << L"SCardListReadersW [" << cur << L"] failed with " << err2wstr(rc)
<< std::endl;
}
else
{
auto start = mszReaders;
auto end = &mszReaders[chReaders];
std::wcout << L"SCardListReadersW [" << cur << L"] " << chReaders << L" [";
while (start < end)
{
std::wcout << start << L", ";
start += wcsnlen(start, chReaders) + 2;
}
std::wcout << L"]" << std::endl;
}
SCardFreeMemory(context, mszReaders);
}
return true;
}
static bool test_list_reader_groups_a(SCARDCONTEXT context)
{
LPSTR mszReaders = nullptr;
DWORD chReaders = SCARD_AUTOALLOCATE;
auto rc = SCardListReaderGroupsA(context, reinterpret_cast<LPSTR>(&mszReaders), &chReaders);
if (rc != SCARD_S_SUCCESS)
{
std::cerr << "SCardListReaderGroupsA failed with " << err2str(rc) << std::endl;
}
else
{
auto start = mszReaders;
auto end = &mszReaders[chReaders];
std::cout << "SCardListReaderGroupsA " << chReaders << " [";
while (start < end)
{
std::cout << start << ", ";
start += strnlen(start, chReaders) + 2;
}
std::cout << "]" << std::endl;
}
SCardFreeMemory(context, mszReaders);
return true;
}
static bool test_list_reader_groups_w(SCARDCONTEXT context)
{
LPWSTR mszReaders = nullptr;
DWORD chReaders = SCARD_AUTOALLOCATE;
auto rc = SCardListReaderGroupsW(context, reinterpret_cast<LPWSTR>(&mszReaders), &chReaders);
if (rc != SCARD_S_SUCCESS)
{
std::wcerr << L"SCardListReaderGroupsW failed with " << err2wstr(rc) << std::endl;
}
else
{
auto start = mszReaders;
auto end = &mszReaders[chReaders];
std::wcout << L"SCardListReaderGroupsW " << chReaders << L" [";
while (start < end)
{
std::wcout << start << L", ";
start += wcsnlen(start, chReaders) + 2;
}
std::wcout << L"]" << std::endl;
}
SCardFreeMemory(context, mszReaders);
return true;
}
static bool test_introduce_forget_reader_groups_a(SCARDCONTEXT context)
{
LPSTR group = "somefancygroup";
auto rc = SCardIntroduceReaderGroupA(context, group);
if (rc != SCARD_S_SUCCESS)
{
std::cerr << "SCardIntroduceReaderGroupA failed with " << err2str(rc) << std::endl;
return false;
}
else
{
rc = SCardForgetReaderGroupA(context, group);
if (rc != SCARD_S_SUCCESS)
{
std::cerr << "SCardForgetReaderGroupA failed with " << err2str(rc) << std::endl;
return false;
}
return true;
}
}
static bool test_introduce_forget_reader_groups_w(SCARDCONTEXT context)
{
LPWSTR group = L"somefancygroup";
auto rc = SCardIntroduceReaderGroupW(context, group);
if (rc != SCARD_S_SUCCESS)
{
std::cerr << "SCardIntroduceReaderGroupW failed with " << err2str(rc) << std::endl;
return false;
}
else
{
rc = SCardForgetReaderGroupW(context, group);
if (rc != SCARD_S_SUCCESS)
{
std::cerr << "SCardForgetReaderGroupW failed with " << err2str(rc) << std::endl;
return false;
}
return true;
}
}
static bool test_introduce_forget_reader_a(SCARDCONTEXT context)
{
LPSTR reader = "somefancygroup";
LPSTR device = "otherfancy";
auto rc = SCardIntroduceReaderA(context, reader, device);
if (rc != SCARD_S_SUCCESS)
{
std::cerr << "SCardIntroduceReaderA failed with " << err2str(rc) << std::endl;
return false;
}
else
{
rc = SCardForgetReaderA(context, reader);
if (rc != SCARD_S_SUCCESS)
{
std::cerr << "SCardForgetReaderA failed with " << err2str(rc) << std::endl;
return false;
}
return true;
}
}
static bool test_introduce_forget_reader_w(SCARDCONTEXT context)
{
LPWSTR reader = L"somefancygroup";
LPWSTR device = L"otherfancy";
auto rc = SCardIntroduceReaderW(context, reader, device);
if (rc != SCARD_S_SUCCESS)
{
std::cerr << "SCardIntroduceReaderW failed with " << err2str(rc) << std::endl;
return false;
}
else
{
rc = SCardForgetReaderW(context, reader);
if (rc != SCARD_S_SUCCESS)
{
std::cerr << "SCardForgetReaderW failed with " << err2str(rc) << std::endl;
return false;
}
return true;
}
}
static bool test_list_cards_a(SCARDCONTEXT context)
{
DWORD chCards = SCARD_AUTOALLOCATE;
LPSTR mszCards = nullptr;
auto rc =
SCardListCardsA(context, nullptr, nullptr, 0, reinterpret_cast<LPSTR>(&mszCards), &chCards);
if (rc != SCARD_S_SUCCESS)
{
std::cerr << "SCardListCardsA failed with " << err2str(rc) << std::endl;
}
else
{
auto start = mszCards;
auto end = &mszCards[chCards];
std::cout << "SCardListCardsA " << chCards << " [";
while (start < end)
{
std::cout << start << ", ";
start += strnlen(start, chCards) + 2;
}
std::cout << "]" << std::endl;
}
return true;
}
static bool test_list_cards_w(SCARDCONTEXT context)
{
DWORD chCards = SCARD_AUTOALLOCATE;
LPWSTR mszCards = nullptr;
auto rc = SCardListCardsW(context, nullptr, nullptr, 0, reinterpret_cast<LPWSTR>(&mszCards),
&chCards);
if (rc != SCARD_S_SUCCESS)
{
std::cerr << "SCardListCardsW failed with " << err2str(rc) << std::endl;
}
else
{
auto start = mszCards;
auto end = &mszCards[chCards];
std::cout << "SCardListCardsW " << chCards << " [";
while (start < end)
{
std::wcout << start << L", ";
start += wcsnlen(start, chCards) + 2;
}
std::cout << "]" << std::endl;
}
return true;
}
static bool test_cache_a(SCARDCONTEXT context)
{
BYTE wdata[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
const DWORD wdatalen = sizeof(wdata);
BYTE data[32] = {};
DWORD datalen = sizeof(data);
LPSTR name = "testdata";
UUID id = {};
auto rc = SCardWriteCacheA(context, &id, 0, name, wdata, wdatalen);
if (rc != SCARD_S_SUCCESS)
{
std::cerr << "SCardWriteCacheA failed with " << err2str(rc) << std::endl;
return false;
}
rc = SCardReadCacheA(context, &id, 0, name, data, &datalen);
if (rc != SCARD_S_SUCCESS)
{
std::cerr << "SCardReadCacheA failed with " << err2str(rc) << std::endl;
return false;
}
if (wdatalen != datalen)
{
std::cerr << "SCardWriteCacheA wrote " << wdatalen << "bytes, SCardReadCacheA read "
<< datalen << "bytes" << std::endl;
return false;
}
if (memcmp(wdata, data, wdatalen) != 0)
{
std::cerr << "SCardWriteCacheA / SCardReadCacheA data corruption detected" << std::endl;
return false;
}
return true;
}
static bool test_cache_w(SCARDCONTEXT context)
{
BYTE wdata[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
const DWORD wdatalen = sizeof(wdata);
BYTE data[32] = {};
DWORD datalen = sizeof(data);
LPWSTR name = L"testdata";
UUID id = {};
auto rc = SCardWriteCacheW(context, &id, 0, name, wdata, wdatalen);
if (rc != SCARD_S_SUCCESS)
{
std::cerr << "SCardWriteCacheW failed with " << err2str(rc) << std::endl;
return false;
}
rc = SCardReadCacheW(context, &id, 0, name, data, &datalen);
if (rc != SCARD_S_SUCCESS)
{
std::cerr << "SCardReadCacheW failed with " << err2str(rc) << std::endl;
return false;
}
if (wdatalen != datalen)
{
std::cerr << "SCardReadCacheW wrote " << wdatalen << "bytes, SCardReadCacheW read "
<< datalen << "bytes" << std::endl;
return false;
}
if (memcmp(wdata, data, wdatalen) != 0)
{
std::cerr << "SCardReadCacheW / SCardReadCacheW data corruption detected" << std::endl;
return false;
}
return true;
}
static bool test_reader_icon_a(SCARDCONTEXT context)
{
LPSTR name = "Gemalto PC Twin Reader 00 00\0\0";
LPBYTE pbIcon = nullptr;
DWORD cbIcon = SCARD_AUTOALLOCATE;
auto rc = SCardGetReaderIconA(context, name, reinterpret_cast<LPBYTE>(&pbIcon), &cbIcon);
SCardFreeMemory(context, pbIcon);
if (rc != SCARD_S_SUCCESS)
{
std::cerr << "SCardGetReaderIconA failed with " << err2str(rc) << std::endl;
return false;
}
return true;
}
static bool test_reader_icon_w(SCARDCONTEXT context)
{
LPWSTR name = L"Gemalto PC Twin Reader 00 00\0\0";
LPBYTE pbIcon = nullptr;
DWORD cbIcon = SCARD_AUTOALLOCATE;
auto rc = SCardGetReaderIconW(context, name, reinterpret_cast<LPBYTE>(&pbIcon), &cbIcon);
SCardFreeMemory(context, pbIcon);
if (rc != SCARD_S_SUCCESS)
{
std::cerr << "SCardGetReaderIconW failed with " << err2str(rc) << std::endl;
return false;
}
return true;
}
static bool test_locate_cards_a(SCARDCONTEXT context)
{
LPSTR name = "Gemalto PC Twin Reader 00 00\0\0";
SCARD_READERSTATEA rgReaderStates[16] = {};
auto rc = SCardLocateCardsA(context, name, rgReaderStates, ARRAYSIZE(rgReaderStates));
if (rc != SCARD_S_SUCCESS)
{
std::cerr << "SCardLocateCardsA failed with " << err2str(rc) << std::endl;
return false;
}
return true;
}
static bool test_locate_cards_w(SCARDCONTEXT context)
{
LPWSTR name = L"Gemalto PC Twin Reader 00 00\0\0";
SCARD_READERSTATEW rgReaderStates[16] = {};
auto rc = SCardLocateCardsW(context, name, rgReaderStates, ARRAYSIZE(rgReaderStates));
if (rc != SCARD_S_SUCCESS)
{
std::cerr << "SCardLocateCardsW failed with " << err2str(rc) << std::endl;
return false;
}
return true;
}
static bool test_locate_cards_by_atr_a(SCARDCONTEXT context)
{
SCARD_READERSTATEA rgReaderStates[16] = {};
SCARD_ATRMASK rgAtrMasks[16] = {};
auto rc = SCardLocateCardsByATRA(context, rgAtrMasks, ARRAYSIZE(rgAtrMasks), rgReaderStates,
ARRAYSIZE(rgReaderStates));
if (rc != SCARD_S_SUCCESS)
{
std::cerr << "SCardLocateCardsByATRA failed with " << err2str(rc) << std::endl;
return false;
}
return true;
}
static bool test_locate_cards_by_atr_w(SCARDCONTEXT context)
{
SCARD_READERSTATEW rgReaderStates[16] = {};
SCARD_ATRMASK rgAtrMasks[16] = {};
auto rc = SCardLocateCardsByATRW(context, rgAtrMasks, ARRAYSIZE(rgAtrMasks), rgReaderStates,
ARRAYSIZE(rgReaderStates));
if (rc != SCARD_S_SUCCESS)
{
std::cerr << "SCardLocateCardsByATRW failed with " << err2str(rc) << std::endl;
return false;
}
return true;
}
static bool test_devicetype_id_a(SCARDCONTEXT context)
{
BYTE data[32] = {};
LPSTR name = "testdata";
DWORD type;
auto rc = SCardGetDeviceTypeIdA(context, name, &type);
if (rc != SCARD_S_SUCCESS)
{
std::cerr << "SCardGetDeviceTypeIdA failed with " << err2str(rc) << std::endl;
return false;
}
return true;
}
static bool test_devicetype_id_w(SCARDCONTEXT context)
{
BYTE data[32] = {};
LPWSTR name = L"testdata";
DWORD type;
auto rc = SCardGetDeviceTypeIdW(context, name, &type);
if (rc != SCARD_S_SUCCESS)
{
std::cerr << "SCardGetDeviceTypeIdW failed with " << err2str(rc) << std::endl;
return false;
}
return true;
}
static bool test_transmitcount(SCARDHANDLE handle)
{
BYTE data[32] = {};
LPWSTR name = L"testdata";
DWORD count;
auto rc = SCardGetTransmitCount(handle, &count);
if (rc != SCARD_S_SUCCESS)
{
std::cerr << "SCardGetTransmitCount failed with " << err2str(rc) << std::endl;
return false;
}
std::cout << "SCardGetTransmitCount() " << count << std::endl;
return true;
}
static bool test_status_a(SCARDHANDLE handle)
{
BYTE data[32] = {};
LPWSTR name = L"testdata";
DWORD count;
/*
auto rc = SCardStatusA(handle, names, len, &state, &protocol, attr, &attrlen);
if (rc != SCARD_S_SUCCESS) {
std::cerr << "SCardGetDeviceTypeIdW failed with " << err2str(rc) << std::endl;
return false;
}
*/
return true;
}
static bool test_status_w(SCARDHANDLE handle)
{
BYTE data[32] = {};
LPWSTR name = L"testdata";
DWORD count;
/*
auto rc = SCardStatusA(handle, names, len, &state, &protocol, attr, &attrlen);
if (rc != SCARD_S_SUCCESS) {
std::cerr << "SCardGetDeviceTypeIdW failed with " << err2str(rc) << std::endl;
return false;
}
*/
return true;
}
static bool test_get_attrib(SCARDCONTEXT context, SCARDHANDLE handle)
{
DWORD attrlen = SCARD_AUTOALLOCATE;
LPBYTE attr = nullptr;
auto rc =
SCardGetAttrib(handle, SCARD_ATTR_ATR_STRING, reinterpret_cast<LPBYTE>(&attr), &attrlen);
if (rc != SCARD_S_SUCCESS)
{
std::cerr << "SCardGetAttrib failed with " << err2str(rc) << std::endl;
return false;
}
std::cout << "SCardGetAttrib [" << attrlen << "]: " << (char*)attr << std::endl;
SCardFreeMemory(context, attr);
return true;
}
static bool test_set_attrib(SCARDCONTEXT context, SCARDHANDLE handle)
{
DWORD attrlen = SCARD_AUTOALLOCATE;
BYTE attr[] = "0123456789";
auto rc = SCardSetAttrib(handle, SCARD_ATTR_SUPRESS_T1_IFS_REQUEST, attr, ARRAYSIZE(attr));
if (rc != SCARD_S_SUCCESS)
{
std::cerr << "SCardSetAttrib failed with " << err2str(rc) << std::endl;
return false;
}
std::cout << "SCardSetAttrib [" << attrlen << "]: " << (char*)attr << std::endl;
SCardFreeMemory(context, attr);
return true;
}
int main()
{
std::cout << "Hello World!" << std::endl;
try
{
auto scopes = { SCARD_SCOPE_USER, SCARD_SCOPE_SYSTEM };
for (auto scope : scopes)
{
SCARDCONTEXT context;
auto rc = SCardEstablishContext(scope, nullptr, nullptr, &context);
if (rc != SCARD_S_SUCCESS)
{
std::cerr << "SCardEstablishContext [" << scope2str(scope) << "] failed with "
<< err2str(rc) << std::endl;
}
else
{
std::cerr << "SCardEstablishContext [" << scope2str(scope) << "] success"
<< std::endl;
test_valid(context);
test_list_reader_groups_a(context);
test_list_reader_groups_w(context);
test_list_readers_a(context);
test_list_readers_w(context);
test_list_cards_a(context);
test_list_cards_w(context);
test_introduce_forget_reader_groups_a(context);
test_introduce_forget_reader_groups_w(context);
test_introduce_forget_reader_a(context);
test_introduce_forget_reader_w(context);
// TODO: Introduce/Remove reader to group
test_locate_cards_a(context);
test_locate_cards_w(context);
test_locate_cards_by_atr_a(context);
test_locate_cards_by_atr_w(context);
test_cache_a(context);
test_cache_w(context);
test_reader_icon_a(context);
test_reader_icon_w(context);
test_devicetype_id_a(context);
test_devicetype_id_w(context);
// TODO: statuschange
// TODO: begin/end transaction
// TODO: state
// TODO: transmit
// TODO: control
{
DWORD protocol;
SCARDHANDLE handle = 0;
LPSTR mszReaders;
DWORD chReaders = SCARD_AUTOALLOCATE;
LONG status = SCardListReadersA(
context, nullptr, reinterpret_cast<LPSTR>(&mszReaders), &chReaders);
if (status == SCARD_S_SUCCESS)
status = SCardConnectA(context, mszReaders, SCARD_SHARE_SHARED,
SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1 |
SCARD_PROTOCOL_Tx | SCARD_PROTOCOL_RAW,
&handle, &protocol);
SCardFreeMemory(context, mszReaders);
if (status != SCARD_S_SUCCESS)
{
std::cerr << "SCardConnectA ["
<< "] failed with " << err2str(status) << std::endl;
}
else
{
test_status_a(handle);
test_status_w(handle);
test_get_attrib(context, handle);
test_set_attrib(context, handle);
test_transmitcount(handle);
status = SCardDisconnect(handle, 0);
if (status)
{
std::cerr << "SCardDisconnect ["
<< "] failed with " << err2str(status) << std::endl;
}
}
}
{
DWORD protocol;
SCARDHANDLE handle = 0;
LPWSTR mszReaders;
DWORD chReaders = SCARD_AUTOALLOCATE;
LONG status = SCardListReadersW(
context, nullptr, reinterpret_cast<LPWSTR>(&mszReaders), &chReaders);
if (status == SCARD_S_SUCCESS)
status = SCardConnectW(context, mszReaders, SCARD_SHARE_SHARED,
SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1 |
SCARD_PROTOCOL_Tx | SCARD_PROTOCOL_RAW,
&handle, &protocol);
SCardFreeMemory(context, mszReaders);
if (status != SCARD_S_SUCCESS)
{
std::cerr << "SCardConnectW ["
<< "] failed with " << err2str(status) << std::endl;
}
else
{
test_status_a(handle);
test_status_w(handle);
test_get_attrib(context, handle);
test_set_attrib(context, handle);
test_transmitcount(handle);
status = SCardDisconnect(handle, 0);
if (status)
{
std::cerr << "SCardDisconnect ["
<< "] failed with " << err2str(status) << std::endl;
}
}
}
rc = SCardReleaseContext(context);
if (rc != SCARD_S_SUCCESS)
{
std::cerr << "SCardReleaseContext [" << scope2str(scope) << "] failed with "
<< err2str(rc) << std::endl;
}
}
}
}
catch (...)
{
std::cerr << "exception!!!!" << std::endl;
}
return 0;
}

View File

@ -3,6 +3,8 @@
* Smart Card API
*
* Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
* Copyright 2020 Armin Novak <armin.novak@thincast.com>
* 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.
@ -106,14 +108,14 @@
#define SCARD_ATR_LENGTH 33
#define SCARD_PROTOCOL_UNDEFINED 0x00000000
#define SCARD_PROTOCOL_T0 0x00000001
#define SCARD_PROTOCOL_T1 0x00000002
#define SCARD_PROTOCOL_RAW 0x00010000
#define SCARD_PROTOCOL_UNDEFINED 0x00000000u
#define SCARD_PROTOCOL_T0 0x00000001u
#define SCARD_PROTOCOL_T1 0x00000002u
#define SCARD_PROTOCOL_RAW 0x00010000u
#define SCARD_PROTOCOL_Tx (SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1)
#define SCARD_PROTOCOL_DEFAULT 0x80000000
#define SCARD_PROTOCOL_OPTIMAL 0x00000000
#define SCARD_PROTOCOL_DEFAULT 0x80000000u
#define SCARD_PROTOCOL_OPTIMAL 0x00000000u
#define SCARD_POWER_DOWN 0
#define SCARD_COLD_RESET 1
@ -681,7 +683,7 @@ extern "C"
WINSCARDAPI LONG WINAPI SCardForgetCardTypeA(SCARDCONTEXT hContext, LPCSTR szCardName);
WINSCARDAPI LONG WINAPI SCardForgetCardTypeW(SCARDCONTEXT hContext, LPCWSTR szCardName);
WINSCARDAPI LONG WINAPI SCardFreeMemory(SCARDCONTEXT hContext, LPCVOID pvMem);
WINSCARDAPI LONG WINAPI SCardFreeMemory(SCARDCONTEXT hContext, LPVOID pvMem);
WINSCARDAPI HANDLE WINAPI SCardAccessStartedEvent(void);
@ -959,7 +961,7 @@ typedef LONG(WINAPI* fnSCardSetCardTypeProviderNameW)(SCARDCONTEXT hContext, LPC
typedef LONG(WINAPI* fnSCardForgetCardTypeA)(SCARDCONTEXT hContext, LPCSTR szCardName);
typedef LONG(WINAPI* fnSCardForgetCardTypeW)(SCARDCONTEXT hContext, LPCWSTR szCardName);
typedef LONG(WINAPI* fnSCardFreeMemory)(SCARDCONTEXT hContext, LPCVOID pvMem);
typedef LONG(WINAPI* fnSCardFreeMemory)(SCARDCONTEXT hContext, LPVOID pvMem);
typedef HANDLE(WINAPI* fnSCardAccessStartedEvent)(void);

View File

@ -3,6 +3,8 @@
* Smart Card API
*
* Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
* Copyright 2020 Armin Novak <armin.novak@thincast.com>
* 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.
@ -34,7 +36,7 @@
#include "smartcard_inspect.h"
static INIT_ONCE g_Initialized = INIT_ONCE_STATIC_INIT;
static PSCardApiFunctionTable g_SCardApi = NULL;
static const SCardApiFunctionTable* g_SCardApi = NULL;
#define TAG WINPR_TAG("smartcard")
@ -296,7 +298,7 @@ WINSCARDAPI LONG WINAPI SCardForgetCardTypeW(SCARDCONTEXT hContext, LPCWSTR szCa
SCARDAPI_STUB_CALL_LONG(SCardForgetCardTypeW, hContext, szCardName);
}
WINSCARDAPI LONG WINAPI SCardFreeMemory(SCARDCONTEXT hContext, LPCVOID pvMem)
WINSCARDAPI LONG WINAPI SCardFreeMemory(SCARDCONTEXT hContext, LPVOID pvMem)
{
SCARDAPI_STUB_CALL_LONG(SCardFreeMemory, hContext, pvMem);
}

File diff suppressed because it is too large Load Diff

View File

@ -3,6 +3,8 @@
* Smart Card API
*
* Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
* Copyright 2020 Armin Novak <armin.novak@thincast.com>
* 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.
@ -23,6 +25,6 @@
#include <winpr/platform.h>
#include <winpr/smartcard.h>
PSCardApiFunctionTable Inspect_RegisterSCardApi(PSCardApiFunctionTable pSCardApi);
const SCardApiFunctionTable* Inspect_RegisterSCardApi(const SCardApiFunctionTable* pSCardApi);
#endif /* WINPR_SMARTCARD_INSPECT_PRIVATE_H */

File diff suppressed because it is too large Load Diff

View File

@ -3,6 +3,8 @@
* Smart Card API
*
* Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
* Copyright 2020 Armin Novak <armin.novak@thincast.com>
* 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.
@ -40,17 +42,68 @@
*/
#ifdef __APPLE__
typedef unsigned int PCSC_DWORD;
typedef PCSC_DWORD *PCSC_PDWORD, *PCSC_LPDWORD;
typedef unsigned int PCSC_ULONG;
#include <stdint.h>
#ifndef BYTE
typedef uint8_t PCSC_BYTE;
#endif
typedef uint8_t PCSC_UCHAR;
typedef PCSC_UCHAR* PCSC_PUCHAR;
typedef uint16_t PCSC_USHORT;
#ifndef __COREFOUNDATION_CFPLUGINCOM__
typedef uint32_t PCSC_ULONG;
typedef void* PCSC_LPVOID;
typedef int16_t PCSC_BOOL;
#endif
typedef PCSC_ULONG* PCSC_PULONG;
typedef int PCSC_LONG;
typedef const void* PCSC_LPCVOID;
typedef uint32_t PCSC_DWORD;
typedef PCSC_DWORD* PCSC_PDWORD;
typedef uint16_t PCSC_WORD;
typedef int32_t PCSC_LONG;
typedef const char* PCSC_LPCSTR;
typedef const PCSC_BYTE* PCSC_LPCBYTE;
typedef PCSC_BYTE* PCSC_LPBYTE;
typedef PCSC_DWORD* PCSC_LPDWORD;
typedef char* PCSC_LPSTR;
#else
typedef unsigned long PCSC_DWORD;
typedef PCSC_DWORD *PCSC_PDWORD, *PCSC_LPDWORD;
#ifndef BYTE
typedef unsigned char PCSC_BYTE;
#endif
typedef unsigned char PCSC_UCHAR;
typedef PCSC_UCHAR* PCSC_PUCHAR;
typedef unsigned short PCSC_USHORT;
#ifndef __COREFOUNDATION_CFPLUGINCOM__
typedef unsigned long PCSC_ULONG;
typedef PCSC_ULONG* PCSC_PULONG;
typedef void* PCSC_LPVOID;
#endif
typedef const void* PCSC_LPCVOID;
typedef unsigned long PCSC_DWORD;
typedef PCSC_DWORD* PCSC_PDWORD;
typedef long PCSC_LONG;
typedef const char* PCSC_LPCSTR;
typedef const PCSC_BYTE* PCSC_LPCBYTE;
typedef PCSC_BYTE* PCSC_LPBYTE;
typedef PCSC_DWORD* PCSC_LPDWORD;
typedef char* PCSC_LPSTR;
/* these types were deprecated but still used by old drivers and
* applications. So just declare and use them. */
typedef PCSC_LPSTR PCSC_LPTSTR;
typedef PCSC_LPCSTR PCSC_LPCTSTR;
/* types unused by pcsc-lite */
typedef short PCSC_BOOL;
typedef unsigned short PCSC_WORD;
typedef PCSC_ULONG* PCSC_PULONG;
#endif
#define PCSC_SCARD_UNKNOWN 0x0001
@ -61,8 +114,8 @@ typedef long PCSC_LONG;
#define PCSC_SCARD_NEGOTIABLE 0x0020
#define PCSC_SCARD_SPECIFIC 0x0040
#define PCSC_SCARD_PROTOCOL_RAW 0x00000004
#define PCSC_SCARD_PROTOCOL_T15 0x00000008
#define PCSC_SCARD_PROTOCOL_RAW 0x00000004u
#define PCSC_SCARD_PROTOCOL_T15 0x00000008u
#define PCSC_MAX_BUFFER_SIZE 264
#define PCSC_MAX_BUFFER_SIZE_EXTENDED (4 + 3 + (1 << 16) + 3 + 2)
@ -71,10 +124,6 @@ typedef long PCSC_LONG;
#define PCSC_SCARD_AUTOALLOCATE (PCSC_DWORD)(-1)
#define PCSC_SCARD_PCI_T0 (&g_PCSC_rgSCardT0Pci)
#define PCSC_SCARD_PCI_T1 (&g_PCSC_rgSCardT1Pci)
#define PCSC_SCARD_PCI_RAW (&g_PCSC_rgSCardRawPci)
#define PCSC_SCARD_CTL_CODE(code) (0x42000000 + (code))
#define PCSC_CM_IOCTL_GET_FEATURE_REQUEST PCSC_SCARD_CTL_CODE(3400)
@ -118,49 +167,8 @@ typedef struct
#pragma pack(pop)
struct _PCSCFunctionTable
{
PCSC_LONG(*pfnSCardEstablishContext)
(PCSC_DWORD dwScope, LPCVOID pvReserved1, LPCVOID pvReserved2, LPSCARDCONTEXT phContext);
PCSC_LONG (*pfnSCardReleaseContext)(SCARDCONTEXT hContext);
PCSC_LONG (*pfnSCardIsValidContext)(SCARDCONTEXT hContext);
PCSC_LONG(*pfnSCardConnect)
(SCARDCONTEXT hContext, LPCSTR szReader, PCSC_DWORD dwShareMode,
PCSC_DWORD dwPreferredProtocols, LPSCARDHANDLE phCard, PCSC_LPDWORD pdwActiveProtocol);
PCSC_LONG(*pfnSCardReconnect)
(SCARDHANDLE hCard, PCSC_DWORD dwShareMode, PCSC_DWORD dwPreferredProtocols,
PCSC_DWORD dwInitialization, PCSC_LPDWORD pdwActiveProtocol);
PCSC_LONG (*pfnSCardDisconnect)(SCARDHANDLE hCard, PCSC_DWORD dwDisposition);
PCSC_LONG (*pfnSCardBeginTransaction)(SCARDHANDLE hCard);
PCSC_LONG (*pfnSCardEndTransaction)(SCARDHANDLE hCard, PCSC_DWORD dwDisposition);
PCSC_LONG(*pfnSCardStatus)
(SCARDHANDLE hCard, LPSTR mszReaderName, PCSC_LPDWORD pcchReaderLen, PCSC_LPDWORD pdwState,
PCSC_LPDWORD pdwProtocol, LPBYTE pbAtr, PCSC_LPDWORD pcbAtrLen);
PCSC_LONG(*pfnSCardGetStatusChange)
(SCARDCONTEXT hContext, PCSC_DWORD dwTimeout, PCSC_SCARD_READERSTATE* rgReaderStates,
PCSC_DWORD cReaders);
PCSC_LONG(*pfnSCardControl)
(SCARDHANDLE hCard, PCSC_DWORD dwControlCode, LPCVOID pbSendBuffer, PCSC_DWORD cbSendLength,
LPVOID pbRecvBuffer, PCSC_DWORD cbRecvLength, PCSC_LPDWORD lpBytesReturned);
PCSC_LONG(*pfnSCardTransmit)
(SCARDHANDLE hCard, const PCSC_SCARD_IO_REQUEST* pioSendPci, LPCBYTE pbSendBuffer,
PCSC_DWORD cbSendLength, PCSC_SCARD_IO_REQUEST* pioRecvPci, LPBYTE pbRecvBuffer,
PCSC_LPDWORD pcbRecvLength);
PCSC_LONG(*pfnSCardListReaderGroups)
(SCARDCONTEXT hContext, LPSTR mszGroups, PCSC_LPDWORD pcchGroups);
PCSC_LONG(*pfnSCardListReaders)
(SCARDCONTEXT hContext, LPCSTR mszGroups, LPSTR mszReaders, PCSC_LPDWORD pcchReaders);
PCSC_LONG (*pfnSCardFreeMemory)(SCARDCONTEXT hContext, LPCVOID pvMem);
PCSC_LONG (*pfnSCardCancel)(SCARDCONTEXT hContext);
PCSC_LONG(*pfnSCardGetAttrib)
(SCARDHANDLE hCard, PCSC_DWORD dwAttrId, LPBYTE pbAttr, PCSC_LPDWORD pcbAttrLen);
PCSC_LONG(*pfnSCardSetAttrib)
(SCARDHANDLE hCard, PCSC_DWORD dwAttrId, LPCBYTE pbAttr, PCSC_DWORD cbAttrLen);
};
typedef struct _PCSCFunctionTable PCSCFunctionTable;
int PCSC_InitializeSCardApi(void);
PSCardApiFunctionTable PCSC_GetSCardApiFunctionTable(void);
const SCardApiFunctionTable* PCSC_GetSCardApiFunctionTable(void);
#endif