diff --git a/channels/smartcard/client/smartcard_operations.c b/channels/smartcard/client/smartcard_operations.c index 54f0a7dcc..02c1a3360 100644 --- a/channels/smartcard/client/smartcard_operations.c +++ b/channels/smartcard/client/smartcard_operations.c @@ -145,35 +145,6 @@ const char* smartcard_get_ioctl_string(UINT32 ioControlCode, BOOL funcName) 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) { 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); } -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) { char* p = (char*) msz; @@ -742,7 +707,7 @@ static UINT32 smartcard_State(SMARTCARD_DEVICE* smartcard, IRP* irp) if (status != SCARD_S_SUCCESS) { - status = smartcard_output_return(irp, status); + Stream_Zero(irp->output, 256); goto finish; } @@ -766,18 +731,15 @@ finish: return status; } -static DWORD smartcard_Status(SMARTCARD_DEVICE* smartcard, IRP* irp, BOOL wide) +static DWORD smartcard_StatusA(SMARTCARD_DEVICE* smartcard, IRP* irp) { LONG status; SCARDHANDLE hCard; SCARDCONTEXT hContext; Status_Call call; - DWORD state, protocol; - DWORD readerLen = 0; - char* readerName = NULL; - BYTE *pbAtr = NULL; - UINT32 dataLength = 0; - int pos, poslen1, poslen2; + Status_Return ret; + DWORD cchReaderLen = 0; + LPSTR mszReaderNames = NULL; 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; hContext = (ULONG_PTR) call.hCard.Context.pbContext; - pbAtr = (BYTE*) malloc(call.cbAtrLen); - readerLen = SCARD_AUTOALLOCATE; + if (call.cbAtrLen > 32) + 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) { - status = smartcard_output_return(irp, status); + Stream_Zero(irp->output, 256); goto finish; } - poslen1 = Stream_GetPosition(irp->output); - Stream_Write_UINT32(irp->output, readerLen); - 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); + ret.mszReaderNames = (BYTE*) mszReaderNames; + ret.cBytes = smartcard_multi_string_length_a((char*) ret.mszReaderNames) + 2; - if (call.cbAtrLen < 32) - 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_pack_status_return(smartcard, irp->output, &ret); smartcard_output_alignment(irp, 8); finish: - if (readerName) + if (mszReaderNames) { - SCardFreeMemory(hContext, readerName); + SCardFreeMemory(hContext, mszReaderNames); } - if (pbAtr) - free(pbAtr); + return status; +} + +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; } @@ -993,7 +988,7 @@ static UINT32 smartcard_GetAttrib(SMARTCARD_DEVICE* smartcard, IRP* irp) if (status != SCARD_S_SUCCESS) { - status = smartcard_output_return(irp, status); + Stream_Zero(irp->output, 256); goto finish; } else @@ -1257,11 +1252,11 @@ void smartcard_irp_device_control(SMARTCARD_DEVICE* smartcard, IRP* irp) break; case SCARD_IOCTL_STATUSA: - result = smartcard_Status(smartcard, irp, 0); + result = smartcard_StatusA(smartcard, irp); break; case SCARD_IOCTL_STATUSW: - result = smartcard_Status(smartcard, irp, 1); + result = smartcard_StatusW(smartcard, irp); break; case SCARD_IOCTL_TRANSMIT: diff --git a/channels/smartcard/client/smartcard_pack.c b/channels/smartcard/client/smartcard_pack.c index eedc2e7a3..262c55fd0 100644 --- a/channels/smartcard/client/smartcard_pack.c +++ b/channels/smartcard/client/smartcard_pack.c @@ -913,6 +913,22 @@ UINT32 smartcard_unpack_status_call(SMARTCARD_DEVICE* smartcard, wStream* s, Sta 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 status; diff --git a/channels/smartcard/client/smartcard_pack.h b/channels/smartcard/client/smartcard_pack.h index 99bc48d3c..36321bb78 100644 --- a/channels/smartcard/client/smartcard_pack.h +++ b/channels/smartcard/client/smartcard_pack.h @@ -287,7 +287,7 @@ typedef struct _Status_Return /* [size_is][unique] */ BYTE *mszReaderNames; DWORD dwState; DWORD dwProtocol; - BYTE pbAtr[ 32 ]; + BYTE pbAtr[32]; /* [range] */ DWORD cbAtrLen; } 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_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); diff --git a/winpr/libwinpr/smartcard/smartcard_pcsc.c b/winpr/libwinpr/smartcard/smartcard_pcsc.c index 49193e10d..26a5ee7d4 100644 --- a/winpr/libwinpr/smartcard/smartcard_pcsc.c +++ b/winpr/libwinpr/smartcard/smartcard_pcsc.c @@ -74,6 +74,36 @@ size_t PCSC_MultiStringLengthW(const WCHAR* 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; void PCSC_AddMemoryBlock(SCARDCONTEXT hContext, void* pvMem) @@ -517,6 +547,9 @@ WINSCARDAPI LONG WINAPI PCSC_SCardConnectA(SCARDCONTEXT hContext, status = g_PCSC.pfnSCardConnect(hContext, szReader, dwShareMode, dwPreferredProtocols, phCard, pdwActiveProtocol); status = PCSC_MapErrorCodeToWinSCard(status); + + if (status == SCARD_S_SUCCESS) + PCSC_AddSmartCardHandle(hContext, *phCard); } return status; @@ -540,6 +573,9 @@ WINSCARDAPI LONG WINAPI PCSC_SCardConnectW(SCARDCONTEXT hContext, dwShareMode, dwPreferredProtocols, phCard, pdwActiveProtocol); status = PCSC_MapErrorCodeToWinSCard(status); + if (status == SCARD_S_SUCCESS) + PCSC_AddSmartCardHandle(hContext, *phCard); + free(szReaderA); return status; @@ -571,6 +607,9 @@ WINSCARDAPI LONG WINAPI PCSC_SCardDisconnect(SCARDHANDLE hCard, DWORD dwDisposit { status = g_PCSC.pfnSCardDisconnect(hCard, dwDisposition); status = PCSC_MapErrorCodeToWinSCard(status); + + if (status == SCARD_S_SUCCESS) + PCSC_RemoveSmartCardHandle(hCard); } return status; @@ -637,14 +676,31 @@ WINSCARDAPI LONG WINAPI PCSC_SCardStatusW(SCARDHANDLE hCard, if (g_PCSC.pfnSCardStatus) { - mszReaderNames = NULL; - pcchReaderLen = 0; + UINT32 length; + 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); 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;