channels/smartcard: implement clean SCardStatusW

This commit is contained in:
Marc-André Moreau 2014-04-07 00:58:34 -04:00
parent bbfd4fb361
commit c2fb729167
4 changed files with 151 additions and 83 deletions

View File

@ -145,35 +145,6 @@ const char* smartcard_get_ioctl_string(UINT32 ioControlCode, BOOL funcName)
return funcName ? "SCardUnknown" : "SCARD_IOCTL_UNKNOWN"; return funcName ? "SCardUnknown" : "SCARD_IOCTL_UNKNOWN";
} }
static UINT32 smartcard_output_string(IRP* irp, char* src, BOOL wide)
{
BYTE* p;
UINT32 len;
p = Stream_Pointer(irp->output);
len = strlen(src) + 1;
if (wide)
{
UINT32 i;
for (i = 0; i < len; i++ )
{
p[2 * i] = src[i] < 0 ? '?' : src[i];
p[2 * i + 1] = '\0';
}
len *= 2;
}
else
{
memcpy(p, src, len);
}
Stream_Seek(irp->output, len);
return len;
}
static void smartcard_output_alignment(IRP* irp, UINT32 seed) static void smartcard_output_alignment(IRP* irp, UINT32 seed)
{ {
const UINT32 field_lengths = 20;/* Remove the lengths of the fields const UINT32 field_lengths = 20;/* Remove the lengths of the fields
@ -196,12 +167,6 @@ static void smartcard_output_repos(IRP* irp, UINT32 written)
Stream_Zero(irp->output, add); Stream_Zero(irp->output, add);
} }
static UINT32 smartcard_output_return(IRP* irp, UINT32 status)
{
Stream_Zero(irp->output, 256);
return status;
}
size_t smartcard_multi_string_length_a(const char* msz) size_t smartcard_multi_string_length_a(const char* msz)
{ {
char* p = (char*) msz; char* p = (char*) msz;
@ -742,7 +707,7 @@ static UINT32 smartcard_State(SMARTCARD_DEVICE* smartcard, IRP* irp)
if (status != SCARD_S_SUCCESS) if (status != SCARD_S_SUCCESS)
{ {
status = smartcard_output_return(irp, status); Stream_Zero(irp->output, 256);
goto finish; goto finish;
} }
@ -766,18 +731,15 @@ finish:
return status; return status;
} }
static DWORD smartcard_Status(SMARTCARD_DEVICE* smartcard, IRP* irp, BOOL wide) static DWORD smartcard_StatusA(SMARTCARD_DEVICE* smartcard, IRP* irp)
{ {
LONG status; LONG status;
SCARDHANDLE hCard; SCARDHANDLE hCard;
SCARDCONTEXT hContext; SCARDCONTEXT hContext;
Status_Call call; Status_Call call;
DWORD state, protocol; Status_Return ret;
DWORD readerLen = 0; DWORD cchReaderLen = 0;
char* readerName = NULL; LPSTR mszReaderNames = NULL;
BYTE *pbAtr = NULL;
UINT32 dataLength = 0;
int pos, poslen1, poslen2;
status = smartcard_unpack_status_call(smartcard, irp->input, &call); status = smartcard_unpack_status_call(smartcard, irp->input, &call);
@ -787,53 +749,86 @@ static DWORD smartcard_Status(SMARTCARD_DEVICE* smartcard, IRP* irp, BOOL wide)
hCard = (ULONG_PTR) call.hCard.pbHandle; hCard = (ULONG_PTR) call.hCard.pbHandle;
hContext = (ULONG_PTR) call.hCard.Context.pbContext; hContext = (ULONG_PTR) call.hCard.Context.pbContext;
pbAtr = (BYTE*) malloc(call.cbAtrLen); if (call.cbAtrLen > 32)
readerLen = SCARD_AUTOALLOCATE; call.cbAtrLen = 32;
status = SCardStatusA(hCard, (LPSTR) &readerName, &readerLen, &state, &protocol, pbAtr, &call.cbAtrLen); ret.cbAtrLen = call.cbAtrLen;
ZeroMemory(ret.pbAtr, 32);
cchReaderLen = SCARD_AUTOALLOCATE;
status = SCardStatusA(hCard, (LPSTR) &mszReaderNames, &cchReaderLen,
&ret.dwState, &ret.dwProtocol, (BYTE*) &ret.pbAtr, &ret.cbAtrLen);
if (status != SCARD_S_SUCCESS) if (status != SCARD_S_SUCCESS)
{ {
status = smartcard_output_return(irp, status); Stream_Zero(irp->output, 256);
goto finish; goto finish;
} }
poslen1 = Stream_GetPosition(irp->output); ret.mszReaderNames = (BYTE*) mszReaderNames;
Stream_Write_UINT32(irp->output, readerLen); ret.cBytes = smartcard_multi_string_length_a((char*) ret.mszReaderNames) + 2;
Stream_Write_UINT32(irp->output, 0x00020001);
Stream_Write_UINT32(irp->output, state);
Stream_Write_UINT32(irp->output, protocol);
Stream_Write(irp->output, pbAtr, call.cbAtrLen);
if (call.cbAtrLen < 32) smartcard_pack_status_return(smartcard, irp->output, &ret);
Stream_Zero(irp->output, 32 - call.cbAtrLen);
Stream_Write_UINT32(irp->output, call.cbAtrLen);
poslen2 = Stream_GetPosition(irp->output);
Stream_Write_UINT32(irp->output, readerLen);
if (readerName)
dataLength += smartcard_output_string(irp, readerName, wide);
dataLength += smartcard_output_string(irp, "\0", wide);
smartcard_output_repos(irp, dataLength);
pos = Stream_GetPosition(irp->output);
Stream_SetPosition(irp->output, poslen1);
Stream_Write_UINT32(irp->output,dataLength);
Stream_SetPosition(irp->output, poslen2);
Stream_Write_UINT32(irp->output,dataLength);
Stream_SetPosition(irp->output, pos);
smartcard_output_alignment(irp, 8); smartcard_output_alignment(irp, 8);
finish: finish:
if (readerName) if (mszReaderNames)
{ {
SCardFreeMemory(hContext, readerName); SCardFreeMemory(hContext, mszReaderNames);
} }
if (pbAtr) return status;
free(pbAtr); }
static DWORD smartcard_StatusW(SMARTCARD_DEVICE* smartcard, IRP* irp)
{
LONG status;
SCARDHANDLE hCard;
SCARDCONTEXT hContext;
Status_Call call;
Status_Return ret;
DWORD cchReaderLen = 0;
LPWSTR mszReaderNames = NULL;
status = smartcard_unpack_status_call(smartcard, irp->input, &call);
if (status)
goto finish;
hCard = (ULONG_PTR) call.hCard.pbHandle;
hContext = (ULONG_PTR) call.hCard.Context.pbContext;
if (call.cbAtrLen > 32)
call.cbAtrLen = 32;
ret.cbAtrLen = call.cbAtrLen;
ZeroMemory(ret.pbAtr, 32);
cchReaderLen = SCARD_AUTOALLOCATE;
status = SCardStatusW(hCard, (LPWSTR) &mszReaderNames, &cchReaderLen,
&ret.dwState, &ret.dwProtocol, (BYTE*) &ret.pbAtr, &ret.cbAtrLen);
if (status != SCARD_S_SUCCESS)
{
Stream_Zero(irp->output, 256);
goto finish;
}
ret.mszReaderNames = (BYTE*) mszReaderNames;
ret.cBytes = (smartcard_multi_string_length_w((WCHAR*) ret.mszReaderNames) + 2) * 2;
smartcard_pack_status_return(smartcard, irp->output, &ret);
smartcard_output_alignment(irp, 8);
finish:
if (mszReaderNames)
{
SCardFreeMemory(hContext, mszReaderNames);
}
return status; return status;
} }
@ -993,7 +988,7 @@ static UINT32 smartcard_GetAttrib(SMARTCARD_DEVICE* smartcard, IRP* irp)
if (status != SCARD_S_SUCCESS) if (status != SCARD_S_SUCCESS)
{ {
status = smartcard_output_return(irp, status); Stream_Zero(irp->output, 256);
goto finish; goto finish;
} }
else else
@ -1257,11 +1252,11 @@ void smartcard_irp_device_control(SMARTCARD_DEVICE* smartcard, IRP* irp)
break; break;
case SCARD_IOCTL_STATUSA: case SCARD_IOCTL_STATUSA:
result = smartcard_Status(smartcard, irp, 0); result = smartcard_StatusA(smartcard, irp);
break; break;
case SCARD_IOCTL_STATUSW: case SCARD_IOCTL_STATUSW:
result = smartcard_Status(smartcard, irp, 1); result = smartcard_StatusW(smartcard, irp);
break; break;
case SCARD_IOCTL_TRANSMIT: case SCARD_IOCTL_TRANSMIT:

View File

@ -913,6 +913,22 @@ UINT32 smartcard_unpack_status_call(SMARTCARD_DEVICE* smartcard, wStream* s, Sta
return SCARD_S_SUCCESS; return SCARD_S_SUCCESS;
} }
UINT32 smartcard_pack_status_return(SMARTCARD_DEVICE* smartcard, wStream* s, Status_Return* ret)
{
Stream_Write_UINT32(s, ret->cBytes); /* cBytes (4 bytes) */
Stream_Write_UINT32(s, 0x00020010); /* mszReaderNamesNdrPtr (4 bytes) */
Stream_Write_UINT32(s, ret->dwState); /* dwState (4 bytes) */
Stream_Write_UINT32(s, ret->dwProtocol); /* dwProtocol (4 bytes) */
Stream_Write(s, ret->pbAtr, 32); /* pbAtr (32 bytes) */
Stream_Write_UINT32(s, ret->cbAtrLen); /* cbAtrLen (4 bytes) */
Stream_Write_UINT32(s, ret->cBytes); /* mszReaderNamesNdrLen (4 bytes) */
Stream_Write(s, ret->mszReaderNames, ret->cBytes);
smartcard_pack_write_offset_align(smartcard, s, 4);
return SCARD_S_SUCCESS;
}
UINT32 smartcard_unpack_get_attrib_call(SMARTCARD_DEVICE* smartcard, wStream* s, GetAttrib_Call* call) UINT32 smartcard_unpack_get_attrib_call(SMARTCARD_DEVICE* smartcard, wStream* s, GetAttrib_Call* call)
{ {
UINT32 status; UINT32 status;

View File

@ -287,7 +287,7 @@ typedef struct _Status_Return
/* [size_is][unique] */ BYTE *mszReaderNames; /* [size_is][unique] */ BYTE *mszReaderNames;
DWORD dwState; DWORD dwState;
DWORD dwProtocol; DWORD dwProtocol;
BYTE pbAtr[ 32 ]; BYTE pbAtr[32];
/* [range] */ DWORD cbAtrLen; /* [range] */ DWORD cbAtrLen;
} Status_Return; } Status_Return;
@ -465,6 +465,7 @@ UINT32 smartcard_unpack_get_status_change_w_call(SMARTCARD_DEVICE* smartcard, wS
UINT32 smartcard_unpack_state_call(SMARTCARD_DEVICE* smartcard, wStream* s, State_Call* call); UINT32 smartcard_unpack_state_call(SMARTCARD_DEVICE* smartcard, wStream* s, State_Call* call);
UINT32 smartcard_unpack_status_call(SMARTCARD_DEVICE* smartcard, wStream* s, Status_Call* call); UINT32 smartcard_unpack_status_call(SMARTCARD_DEVICE* smartcard, wStream* s, Status_Call* call);
UINT32 smartcard_pack_status_return(SMARTCARD_DEVICE* smartcard, wStream* s, Status_Return* ret);
UINT32 smartcard_unpack_get_attrib_call(SMARTCARD_DEVICE* smartcard, wStream* s, GetAttrib_Call* call); UINT32 smartcard_unpack_get_attrib_call(SMARTCARD_DEVICE* smartcard, wStream* s, GetAttrib_Call* call);

View File

@ -74,6 +74,36 @@ size_t PCSC_MultiStringLengthW(const WCHAR* msz)
return (p - msz); return (p - msz);
} }
static wListDictionary* g_SmartCards = NULL;
void PCSC_AddSmartCardHandle(SCARDCONTEXT hContext, SCARDHANDLE hCard)
{
if (!g_SmartCards)
g_SmartCards = ListDictionary_New(TRUE);
ListDictionary_Add(g_SmartCards, (void*) hCard, (void*) hContext);
}
void* PCSC_RemoveSmartCardHandle(SCARDHANDLE hCard)
{
if (!g_SmartCards)
return NULL;
return ListDictionary_Remove(g_SmartCards, (void*) hCard);
}
SCARDCONTEXT PCSC_GetSmartCardContextFromHandle(SCARDHANDLE hCard)
{
SCARDCONTEXT hContext;
if (!g_SmartCards)
return 0;
hContext = (SCARDCONTEXT) ListDictionary_GetItemValue(g_SmartCards, (void*) hCard);
return hContext;
}
static wListDictionary* g_MemoryBlocks = NULL; static wListDictionary* g_MemoryBlocks = NULL;
void PCSC_AddMemoryBlock(SCARDCONTEXT hContext, void* pvMem) void PCSC_AddMemoryBlock(SCARDCONTEXT hContext, void* pvMem)
@ -517,6 +547,9 @@ WINSCARDAPI LONG WINAPI PCSC_SCardConnectA(SCARDCONTEXT hContext,
status = g_PCSC.pfnSCardConnect(hContext, szReader, status = g_PCSC.pfnSCardConnect(hContext, szReader,
dwShareMode, dwPreferredProtocols, phCard, pdwActiveProtocol); dwShareMode, dwPreferredProtocols, phCard, pdwActiveProtocol);
status = PCSC_MapErrorCodeToWinSCard(status); status = PCSC_MapErrorCodeToWinSCard(status);
if (status == SCARD_S_SUCCESS)
PCSC_AddSmartCardHandle(hContext, *phCard);
} }
return status; return status;
@ -540,6 +573,9 @@ WINSCARDAPI LONG WINAPI PCSC_SCardConnectW(SCARDCONTEXT hContext,
dwShareMode, dwPreferredProtocols, phCard, pdwActiveProtocol); dwShareMode, dwPreferredProtocols, phCard, pdwActiveProtocol);
status = PCSC_MapErrorCodeToWinSCard(status); status = PCSC_MapErrorCodeToWinSCard(status);
if (status == SCARD_S_SUCCESS)
PCSC_AddSmartCardHandle(hContext, *phCard);
free(szReaderA); free(szReaderA);
return status; return status;
@ -571,6 +607,9 @@ WINSCARDAPI LONG WINAPI PCSC_SCardDisconnect(SCARDHANDLE hCard, DWORD dwDisposit
{ {
status = g_PCSC.pfnSCardDisconnect(hCard, dwDisposition); status = g_PCSC.pfnSCardDisconnect(hCard, dwDisposition);
status = PCSC_MapErrorCodeToWinSCard(status); status = PCSC_MapErrorCodeToWinSCard(status);
if (status == SCARD_S_SUCCESS)
PCSC_RemoveSmartCardHandle(hCard);
} }
return status; return status;
@ -637,14 +676,31 @@ WINSCARDAPI LONG WINAPI PCSC_SCardStatusW(SCARDHANDLE hCard,
if (g_PCSC.pfnSCardStatus) if (g_PCSC.pfnSCardStatus)
{ {
mszReaderNames = NULL; UINT32 length;
pcchReaderLen = 0; SCARDCONTEXT hContext = 0;
LPSTR mszReaderNamesA = NULL;
/* FIXME: unicode conversion */ if (!mszReaderNames)
pcchReaderLen = 0;
status = g_PCSC.pfnSCardStatus(hCard, (LPSTR) mszReaderNames, pcchReaderLen, status = g_PCSC.pfnSCardStatus(hCard, (LPSTR) &mszReaderNamesA, pcchReaderLen,
pdwState, pdwProtocol, pbAtr, pcbAtrLen); pdwState, pdwProtocol, pbAtr, pcbAtrLen);
status = PCSC_MapErrorCodeToWinSCard(status); status = PCSC_MapErrorCodeToWinSCard(status);
if (mszReaderNamesA)
{
length = (UINT32) PCSC_MultiStringLengthA(mszReaderNamesA);
ConvertToUnicode(CP_UTF8, 0, mszReaderNamesA, length + 2, (WCHAR**) mszReaderNames, 0);
hContext = PCSC_GetSmartCardContextFromHandle(hCard);
PCSC_AddMemoryBlock(hContext, mszReaderNames);
if (g_PCSC.pfnSCardFreeMemory)
{
g_PCSC.pfnSCardFreeMemory(hContext, mszReaderNamesA);
}
}
} }
return status; return status;