Merge pull request #2195 from Vinche59/master

Implementation of SCARD_IOCTL_LOCATECARDSBYATRA & Modification to make Smartcard reader with PinPad work
This commit is contained in:
Marc-André Moreau 2014-11-11 09:29:45 -05:00
commit b77a3bc1bc
5 changed files with 383 additions and 11 deletions

View File

@ -1032,6 +1032,108 @@ static UINT32 smartcard_AccessStartedEvent_Call(SMARTCARD_DEVICE* smartcard, SMA
return status;
}
static UINT32 smartcard_LocateCardsByATRA_Decode(SMARTCARD_DEVICE* smartcard, SMARTCARD_OPERATION* operation, LocateCardsByATRA_Call* call)
{
LONG status;
IRP* irp = operation->irp;
if (!call)
return STATUS_NO_MEMORY;
status = smartcard_unpack_locate_cards_by_atr_a_call(smartcard, irp->input, call);
smartcard_trace_locate_cards_by_atr_a_call(smartcard, call);
operation->hContext = smartcard_scard_context_native_from_redir(smartcard, &(call->hContext));
return status;
}
static UINT32 smartcard_LocateCardsByATRA_Call(SMARTCARD_DEVICE* smartcard, SMARTCARD_OPERATION* operation, LocateCardsByATRA_Call* call)
{
LONG status;
DWORD index, index2, index3;
BOOL equal;
GetStatusChange_Return ret;
LPSCARD_READERSTATEA rgReaderState2 = NULL;
LPSCARD_READERSTATEA states = NULL;
IRP* irp = operation->irp;
states = calloc(call->cReaders, sizeof(SCARD_READERSTATEA));
for (index = 0; index < call->cReaders; index++)
{
states[index].szReader = (LPCSTR) call->rgReaderStates[index].szReader;
states[index].dwCurrentState = call->rgReaderStates[index].Common.dwCurrentState;
states[index].dwEventState = call->rgReaderStates[index].Common.dwEventState;
states[index].cbAtr = call->rgReaderStates[index].Common.cbAtr;
CopyMemory(&(states[index].rgbAtr), &(call->rgReaderStates[index].Common.rgbAtr), 36);
}
status = ret.ReturnCode = SCardGetStatusChangeA(operation->hContext, 0x000001F4, states, call->cReaders);
if (status && (status != SCARD_E_TIMEOUT) && (status != SCARD_E_CANCELLED))
{
call->cReaders=0;
}
for (index = 0; index < call->cAtrs; index++)
{
for (index2 = 0; index2 < call->cReaders; index2++)
{
equal = TRUE;
for (index3 = 0; index3 < call->rgAtrMasks[index].cbAtr; index3++)
{
if ((call->rgAtrMasks[index].rgbAtr[index3] & call->rgAtrMasks[index].rgbMask[index3]) !=
(states[index2].rgbAtr[index3] & call->rgAtrMasks[index].rgbMask[index3]))
{
equal = FALSE;
break;
}
if (equal)
{
states[index2].dwEventState |= SCARD_STATE_ATRMATCH;
}
}
}
}
ret.cReaders = call->cReaders;
ret.rgReaderStates = (ReaderState_Return*) calloc(ret.cReaders, sizeof(ReaderState_Return));
for (index = 0; index < ret.cReaders; index++)
{
rgReaderState2 = &states[index];
ret.rgReaderStates[index].dwCurrentState = rgReaderState2->dwCurrentState;
ret.rgReaderStates[index].dwEventState = rgReaderState2->dwEventState;
ret.rgReaderStates[index].cbAtr = rgReaderState2->cbAtr;
CopyMemory(&(ret.rgReaderStates[index].rgbAtr), &(rgReaderState2->rgbAtr), 32);
}
free(states);
smartcard_trace_get_status_change_return(smartcard, &ret, FALSE);
status = smartcard_pack_get_status_change_return(smartcard, irp->output, &ret);
if (status)
return status;
if (call->rgReaderStates)
{
for (index = 0; index < call->cReaders; index++)
{
rgReaderState2 = (LPSCARD_READERSTATEA) &call->rgReaderStates[index];
if (rgReaderState2->szReader) {
free((void*) rgReaderState2->szReader);
rgReaderState2->szReader = NULL;
}
}
free(call->rgReaderStates);
call->rgReaderStates = NULL;
}
free(ret.rgReaderStates);
return ret.ReturnCode;
}
UINT32 smartcard_irp_device_control_decode(SMARTCARD_DEVICE* smartcard, SMARTCARD_OPERATION* operation)
{
UINT32 status;
@ -1264,7 +1366,8 @@ UINT32 smartcard_irp_device_control_decode(SMARTCARD_DEVICE* smartcard, SMARTCAR
break;
case SCARD_IOCTL_LOCATECARDSBYATRA:
status = SCARD_F_INTERNAL_ERROR;
call = calloc(1, sizeof(LocateCardsByATRA_Call));
status = smartcard_LocateCardsByATRA_Decode(smartcard, operation, (LocateCardsByATRA_Call*) call);
break;
case SCARD_IOCTL_LOCATECARDSBYATRW:
@ -1530,7 +1633,7 @@ UINT32 smartcard_irp_device_control_call(SMARTCARD_DEVICE* smartcard, SMARTCARD_
break;
case SCARD_IOCTL_LOCATECARDSBYATRA:
result = SCARD_F_INTERNAL_ERROR;
result = smartcard_LocateCardsByATRA_Call(smartcard, operation, (LocateCardsByATRA_Call*) call);
break;
case SCARD_IOCTL_LOCATECARDSBYATRW:

View File

@ -2471,3 +2471,240 @@ void smartcard_trace_transmit_return(SMARTCARD_DEVICE* smartcard, Transmit_Retur
WLog_Print(smartcard->log, WLOG_DEBUG, "}");
}
UINT32 smartcard_unpack_locate_cards_by_atr_a_call(SMARTCARD_DEVICE* smartcard, wStream* s, LocateCardsByATRA_Call* call)
{
UINT32 index;
UINT32 count;
UINT32 status;
UINT32 offset;
UINT32 maxCount;
UINT32 szReaderNdrPtr;
UINT32 rgReaderStatesNdrPtr;
UINT32 rgAtrMasksNdrPtr;
LPSCARD_READERSTATEA readerState;
call->rgReaderStates = NULL;
status = smartcard_unpack_redir_scard_context(smartcard, s, &(call->hContext));
if (status)
return status;
if (Stream_GetRemainingLength(s) < 16)
{
WLog_Print(smartcard->log, WLOG_WARN, "LocateCardsByATRA_Call is too short: %d",
(int) Stream_GetRemainingLength(s));
return STATUS_BUFFER_TOO_SMALL;
}
Stream_Read_UINT32(s, call->cAtrs);
Stream_Read_UINT32(s, rgAtrMasksNdrPtr);
Stream_Read_UINT32(s, call->cReaders); /* cReaders (4 bytes) */
Stream_Read_UINT32(s, rgReaderStatesNdrPtr); /* rgReaderStatesNdrPtr (4 bytes) */
status = smartcard_unpack_redir_scard_context_ref(smartcard, s, &(call->hContext));
if (status)
return status;
if (Stream_GetRemainingLength(s) < 4)
{
WLog_Print(smartcard->log, WLOG_WARN, "LocateCardsByATRA_Call is too short: %d",
(int) Stream_GetRemainingLength(s));
return STATUS_BUFFER_TOO_SMALL;
}
if ((rgAtrMasksNdrPtr && !call->cAtrs) || (!rgAtrMasksNdrPtr && call->cAtrs))
{
WLog_Print(smartcard->log, WLOG_WARN,
"LocateCardsByATRA_Call rgAtrMasksNdrPtr (0x%08X) and cAtrs (0x%08X) inconsistency",
(int) rgAtrMasksNdrPtr, (int) call->cAtrs);
return STATUS_INVALID_PARAMETER;
}
if (rgAtrMasksNdrPtr)
{
Stream_Read_UINT32(s, count);
if (count != call->cAtrs)
{
WLog_Print(smartcard->log, WLOG_WARN,
"LocateCardsByATRA_Call NdrCount (0x%08X) and cAtrs (0x%08X) inconsistency",
(int) count, (int) call->cAtrs);
return STATUS_INVALID_PARAMETER;
}
if (Stream_GetRemainingLength(s) < call->cAtrs)
{
WLog_Print(smartcard->log, WLOG_WARN, "LocateCardsByATRA_Call is too short: Actual: %d, Expected: %d",
(int) Stream_GetRemainingLength(s), call->cAtrs);
return STATUS_BUFFER_TOO_SMALL;
}
call->rgAtrMasks = calloc(call->cAtrs, sizeof(SCARD_ATRMASK));
if (!call->rgAtrMasks)
{
WLog_Print(smartcard->log, WLOG_WARN, "LocateCardsByATRA_Call out of memory error (call->rgAtrMasks)");
return STATUS_NO_MEMORY;
}
for (index = 0; index < call->cAtrs; index++)
{
Stream_Read_UINT32(s, call->rgAtrMasks[index].cbAtr);
Stream_Read(s, call->rgAtrMasks[index].rgbAtr, 36);
Stream_Read(s, call->rgAtrMasks[index].rgbMask, 36);
}
}
Stream_Read_UINT32(s, count);
if (count != call->cReaders)
{
WLog_Print(smartcard->log, WLOG_WARN,
"GetStatusChangeA_Call unexpected reader count: Actual: %d, Expected: %d",
(int) count, call->cReaders);
return STATUS_INVALID_PARAMETER;
}
if (call->cReaders > 0)
{
call->rgReaderStates = calloc(call->cReaders, sizeof(SCARD_READERSTATEA));
if (!call->rgReaderStates)
{
WLog_Print(smartcard->log, WLOG_WARN, "LocateCardsByATRA_Call out of memory error (call->rgReaderStates)");
return STATUS_NO_MEMORY;
}
for (index = 0; index < call->cReaders; index++)
{
readerState = (LPSCARD_READERSTATEA) &call->rgReaderStates[index];
if (Stream_GetRemainingLength(s) < 52)
{
WLog_Print(smartcard->log, WLOG_WARN, "LocateCardsByATRA_Call is too short: %d",
(int) Stream_GetRemainingLength(s));
return STATUS_BUFFER_TOO_SMALL;
}
Stream_Read_UINT32(s, szReaderNdrPtr); /* szReaderNdrPtr (4 bytes) */
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, 32); /* rgbAtr [0..32] (32 bytes) */
Stream_Seek(s, 4); /* rgbAtr [32..36] (4 bytes) */
}
for (index = 0; index < call->cReaders; index++)
{
readerState = (LPSCARD_READERSTATEA) &call->rgReaderStates[index];
if (Stream_GetRemainingLength(s) < 12)
{
WLog_Print(smartcard->log, WLOG_WARN, "GetStatusChangeA_Call is too short: %d",
(int) Stream_GetRemainingLength(s));
return STATUS_BUFFER_TOO_SMALL;
}
Stream_Read_UINT32(s, maxCount); /* NdrMaxCount (4 bytes) */
Stream_Read_UINT32(s, offset); /* NdrOffset (4 bytes) */
Stream_Read_UINT32(s, count); /* NdrActualCount (4 bytes) */
if (Stream_GetRemainingLength(s) < count)
{
WLog_Print(smartcard->log, WLOG_WARN, "GetStatusChangeA_Call is too short: %d",
(int) Stream_GetRemainingLength(s));
return STATUS_BUFFER_TOO_SMALL;
}
readerState->szReader = (LPCSTR) malloc(count + 1);
if (!readerState->szReader)
{
WLog_Print(smartcard->log, WLOG_WARN,
"GetStatusChangeA_Call out of memory error (readerState->szReader)");
return STATUS_NO_MEMORY;
}
Stream_Read(s, (void*) readerState->szReader, count);
smartcard_unpack_read_size_align(smartcard, s, count, 4);
((char*) readerState->szReader)[count] = '\0';
if (!readerState->szReader)
{
WLog_Print(smartcard->log, WLOG_WARN, "GetStatusChangeA_Call null reader name");
return STATUS_INVALID_PARAMETER;
}
}
}
return SCARD_S_SUCCESS;
}
void smartcard_trace_locate_cards_by_atr_a_call(SMARTCARD_DEVICE* smartcard, LocateCardsByATRA_Call* call)
{
BYTE* pb;
UINT32 index;
char* szEventState;
char* szCurrentState;
char* rgbAtr;
LPSCARD_READERSTATEA readerState;
if (!WLog_IsLevelActive(smartcard->log, WLOG_DEBUG))
return;
WLog_Print(smartcard->log, WLOG_DEBUG, "LocateCardsByATRA_Call {");
pb = (BYTE*) &(call->hContext.pbContext);
if (call->hContext.cbContext > 4)
{
WLog_Print(smartcard->log, WLOG_DEBUG, "hContext: 0x%02X%02X%02X%02X%02X%02X%02X%02X (%d)",
pb[0], pb[1], pb[2], pb[3], pb[4], pb[5], pb[6], pb[7], call->hContext.cbContext);
}
else
{
WLog_Print(smartcard->log, WLOG_DEBUG, "hContext: 0x%02X%02X%02X%02X (%d)",
pb[0], pb[1], pb[2], pb[3], call->hContext.cbContext);
}
for (index = 0; index < call->cReaders; index++)
{
readerState = (LPSCARD_READERSTATEA) &call->rgReaderStates[index];
WLog_Print(smartcard->log, WLOG_DEBUG,
"\t[%d]: szReader: %s cbAtr: %d",
index, readerState->szReader, readerState->cbAtr);
szCurrentState = SCardGetReaderStateString(readerState->dwCurrentState);
szEventState = SCardGetReaderStateString(readerState->dwEventState);
rgbAtr = winpr_BinToHexString((BYTE*) &(readerState->rgbAtr), readerState->cbAtr, FALSE);
WLog_Print(smartcard->log, WLOG_DEBUG,
"\t[%d]: dwCurrentState: %s (0x%08X)",
index, szCurrentState, readerState->dwCurrentState);
WLog_Print(smartcard->log, WLOG_DEBUG,
"\t[%d]: dwEventState: %s (0x%08X)",
index, szEventState, readerState->dwEventState);
if (rgbAtr)
{
WLog_Print(smartcard->log, WLOG_DEBUG,
"\t[%d]: cbAtr: %d rgbAtr: %s",
index, readerState->cbAtr, rgbAtr);
}
else
{
WLog_Print(smartcard->log, WLOG_DEBUG,
"\t[%d]: cbAtr: %d rgbAtr: %s",
index, 0, "");
}
free(szCurrentState);
free(szEventState);
free(rgbAtr);
}
WLog_Print(smartcard->log, WLOG_DEBUG, "}");
}

View File

@ -532,4 +532,8 @@ void smartcard_trace_transmit_call(SMARTCARD_DEVICE* smartcard, Transmit_Call* c
UINT32 smartcard_pack_transmit_return(SMARTCARD_DEVICE* smartcard, wStream* s, Transmit_Return* ret);
void smartcard_trace_transmit_return(SMARTCARD_DEVICE* smartcard, Transmit_Return* ret);
UINT32 smartcard_unpack_locate_cards_by_atr_a_call(SMARTCARD_DEVICE* smartcard, wStream* s, LocateCardsByATRA_Call* call);
void smartcard_trace_locate_cards_by_atr_a_call(SMARTCARD_DEVICE* smartcard, LocateCardsByATRA_Call* call);
#endif /* FREERDP_CHANNEL_SMARTCARD_CLIENT_PACK_H */

View File

@ -1382,9 +1382,7 @@ WINSCARDAPI LONG WINAPI PCSC_SCardGetStatusChange_Internal(SCARDCONTEXT hContext
{
int i, j;
int* map;
DWORD dwEventState;
PCSC_DWORD cMappedReaders;
BOOL stateChanged = FALSE;
PCSC_SCARD_READERSTATE* states;
LONG status = SCARD_S_SUCCESS;
PCSC_DWORD pcsc_dwTimeout = (PCSC_DWORD) dwTimeout;
@ -1437,6 +1435,7 @@ WINSCARDAPI LONG WINAPI PCSC_SCardGetStatusChange_Internal(SCARDCONTEXT hContext
states[j].szReader = rgReaderStates[i].szReader;
states[j].dwCurrentState = rgReaderStates[i].dwCurrentState;
states[j].pvUserData = rgReaderStates[i].pvUserData;
states[j].dwEventState = rgReaderStates[i].dwEventState;
states[j].cbAtr = rgReaderStates[i].cbAtr;
CopyMemory(&(states[j].rgbAtr), &(rgReaderStates[i].rgbAtr), PCSC_MAX_ATR_SIZE);
@ -1470,6 +1469,11 @@ WINSCARDAPI LONG WINAPI PCSC_SCardGetStatusChange_Internal(SCARDCONTEXT hContext
rgReaderStates[i].dwCurrentState = states[j].dwCurrentState;
rgReaderStates[i].cbAtr = states[j].cbAtr;
CopyMemory(&(rgReaderStates[i].rgbAtr), &(states[j].rgbAtr), PCSC_MAX_ATR_SIZE);
/**
* Why we should interpret and modify the results of pcsc-lite ScardGetStatusChange ?
* Should not we just act as a pass-through between the client and the remote smartcard subsystem ?
*/
#if 0
/* pcsc-lite puts an event count in the higher bits of dwEventState */
states[j].dwEventState &= 0xFFFF;
dwEventState = states[j].dwEventState & ~SCARD_STATE_CHANGED;
@ -1493,12 +1497,19 @@ WINSCARDAPI LONG WINAPI PCSC_SCardGetStatusChange_Internal(SCARDCONTEXT hContext
if (rgReaderStates[i].dwCurrentState & SCARD_STATE_IGNORE)
rgReaderStates[i].dwEventState = SCARD_STATE_IGNORE;
#endif
rgReaderStates[i].dwEventState = states[j].dwEventState;
}
/**
* Why we should interpret and modify the results of pcsc-lite ScardGetStatusChange ?
* Should not we just act as a pass-through between the client and the remote smartcard subsystem ?
*/
#if 0
if ((status == SCARD_S_SUCCESS) && !stateChanged)
status = SCARD_E_TIMEOUT;
else if ((status == SCARD_E_TIMEOUT) && stateChanged)
return SCARD_S_SUCCESS;
#endif
free(states);
free(map);
@ -1610,7 +1621,15 @@ WINSCARDAPI LONG WINAPI PCSC_SCardConnect_Internal(SCARDCONTEXT hContext,
if (!szReaderPCSC)
szReaderPCSC = (char*) szReader;
pcsc_dwPreferredProtocols = (PCSC_DWORD) PCSC_ConvertProtocolsFromWinSCard(dwPreferredProtocols);
/**
* As stated here : https://pcsclite.alioth.debian.org/api/group__API.html#ga4e515829752e0a8dbc4d630696a8d6a5
* SCARD_PROTOCOL_UNDEFINED is valid for dwPreferredProtocols (only) if dwShareMode == SCARD_SHARE_DIRECT
* and allows to send control commands to the reader (with SCardControl()) even if a card is not present in the reader
*/
if (pcsc_dwShareMode == SCARD_SHARE_DIRECT && dwPreferredProtocols == SCARD_PROTOCOL_UNDEFINED)
pcsc_dwPreferredProtocols = SCARD_PROTOCOL_UNDEFINED;
else
pcsc_dwPreferredProtocols = (PCSC_DWORD) PCSC_ConvertProtocolsFromWinSCard(dwPreferredProtocols);
status = (LONG) g_PCSC.pfnSCardConnect(hPrivateContext, szReaderPCSC,
pcsc_dwShareMode, pcsc_dwPreferredProtocols, phCard, &pcsc_dwActiveProtocol);
status = PCSC_MapErrorCodeToWinSCard(status);
@ -2107,11 +2126,7 @@ WINSCARDAPI LONG WINAPI PCSC_SCardControl(SCARDHANDLE hCard,
{
ioCtlValue = _byteswap_ulong(tlv->value);
ioCtlValue -= 0x42000000; /* inverse of PCSC_SCARD_CTL_CODE() */
IoCtlMethod = METHOD_FROM_CTL_CODE(ioCtlValue);
IoCtlFunction = FUNCTION_FROM_CTL_CODE(ioCtlValue);
IoCtlAccess = ACCESS_FROM_CTL_CODE(ioCtlValue);
IoCtlDeviceType = DEVICE_TYPE_FROM_CTL_CODE(ioCtlValue);
ioCtlValue = SCARD_CTL_CODE(IoCtlFunction);
ioCtlValue = SCARD_CTL_CODE(ioCtlValue);
tlv->value = _byteswap_ulong(ioCtlValue);
}
}

View File

@ -78,7 +78,14 @@ typedef long PCSC_LONG;
#define PCSC_SCARD_CTL_CODE(code) (0x42000000 + (code))
#define PCSC_CM_IOCTL_GET_FEATURE_REQUEST SCARD_CTL_CODE(3400)
/**
* pcsc-lite defines SCARD_READERSTATE, SCARD_IO_REQUEST as packed
* on Mac OS X only and uses default packing everywhere else.
*/
#ifdef __APPLE__
#pragma pack(push, 1)
#endif
typedef struct
{
@ -97,6 +104,12 @@ typedef struct
PCSC_DWORD cbPciLength;
} PCSC_SCARD_IO_REQUEST;
#ifdef __APPLE__
#pragma pack(pop)
#endif
#pragma pack(push, 1)
typedef struct
{
BYTE tag;