diff --git a/channels/smartcard/client/smartcard_operations.c b/channels/smartcard/client/smartcard_operations.c index 1c3bbbaab..54f0a7dcc 100644 --- a/channels/smartcard/client/smartcard_operations.c +++ b/channels/smartcard/client/smartcard_operations.c @@ -202,6 +202,32 @@ static UINT32 smartcard_output_return(IRP* irp, UINT32 status) return status; } +size_t smartcard_multi_string_length_a(const char* msz) +{ + char* p = (char*) msz; + + if (!p) + return 0; + + while (p[0] || p[1]) + p++; + + return (p - msz); +} + +size_t smartcard_multi_string_length_w(const WCHAR* msz) +{ + WCHAR* p = (WCHAR*) msz; + + if (!p) + return 0; + + while (p[0] || p[1]) + p++; + + return (p - msz); +} + static UINT32 smartcard_EstablishContext(SMARTCARD_DEVICE* smartcard, IRP* irp) { UINT32 status; @@ -270,17 +296,14 @@ static UINT32 smartcard_IsValidContext(SMARTCARD_DEVICE* smartcard, IRP* irp) return status; } -static UINT32 smartcard_ListReaders(SMARTCARD_DEVICE* smartcard, IRP* irp, BOOL wide) +static UINT32 smartcard_ListReadersA(SMARTCARD_DEVICE* smartcard, IRP* irp) { UINT32 status; - DWORD dwReaders; SCARDCONTEXT hContext; ListReaders_Call call; - char *readerList = NULL; - char* walker; - char* walkerEnd; - int elemLength, dataLength; - int pos, poslen1, poslen2; + ListReaders_Return ret; + LPSTR mszReaders = NULL; + DWORD cchReaders = 0; status = smartcard_unpack_list_readers_call(smartcard, irp->input, &call); @@ -289,59 +312,64 @@ static UINT32 smartcard_ListReaders(SMARTCARD_DEVICE* smartcard, IRP* irp, BOOL hContext = (ULONG_PTR) call.Context.pbContext; - dwReaders = SCARD_AUTOALLOCATE; - status = SCardListReadersA(hContext, (LPCSTR) call.mszGroups, (LPSTR) &readerList, &dwReaders); + cchReaders = SCARD_AUTOALLOCATE; + status = SCardListReadersA(hContext, (LPCSTR) call.mszGroups, (LPSTR) &mszReaders, &cchReaders); if (status != SCARD_S_SUCCESS) goto finish; - poslen1 = Stream_GetPosition(irp->output); - Stream_Seek_UINT32(irp->output); + ret.msz = (BYTE*) mszReaders; + ret.cBytes = smartcard_multi_string_length_a((char*) ret.msz) + 2; - Stream_Write_UINT32(irp->output, 0x01760650); + smartcard_pack_list_readers_return(smartcard, irp->output, &ret); - poslen2 = Stream_GetPosition(irp->output); - Stream_Seek_UINT32(irp->output); - - walker = readerList; - walkerEnd = readerList + dwReaders; - dataLength = 0; - - while (1) - { - elemLength = strlen(walker); - - if (!elemLength) - break; - - dataLength += smartcard_output_string(irp, walker, wide); - walker += elemLength + 1; - - if (walker > walkerEnd) - { - status = SCARD_F_INTERNAL_ERROR; - goto finish; - } - } - - dataLength += smartcard_output_string(irp, "\0", wide); - - 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_repos(irp, dataLength); smartcard_output_alignment(irp, 8); finish: - if (readerList) + if (mszReaders) { - SCardFreeMemory(hContext, readerList); + SCardFreeMemory(hContext, mszReaders); + } + + if (call.mszGroups) + free(call.mszGroups); + + return status; +} + +static UINT32 smartcard_ListReadersW(SMARTCARD_DEVICE* smartcard, IRP* irp) +{ + UINT32 status; + SCARDCONTEXT hContext; + ListReaders_Call call; + ListReaders_Return ret; + LPWSTR mszReaders = NULL; + DWORD cchReaders = 0; + + status = smartcard_unpack_list_readers_call(smartcard, irp->input, &call); + + if (status) + goto finish; + + hContext = (ULONG_PTR) call.Context.pbContext; + + cchReaders = SCARD_AUTOALLOCATE; + status = SCardListReadersW(hContext, (LPCWSTR) call.mszGroups, (LPWSTR) &mszReaders, &cchReaders); + + if (status != SCARD_S_SUCCESS) + goto finish; + + ret.msz = (BYTE*) mszReaders; + ret.cBytes = (smartcard_multi_string_length_w((WCHAR*) ret.msz) + 2) * 2; + + smartcard_pack_list_readers_return(smartcard, irp->output, &ret); + + smartcard_output_alignment(irp, 8); + +finish: + if (mszReaders) + { + SCardFreeMemory(hContext, mszReaders); } if (call.mszGroups) @@ -1125,11 +1153,11 @@ void smartcard_irp_device_control(SMARTCARD_DEVICE* smartcard, IRP* irp) break; case SCARD_IOCTL_LISTREADERSA: - result = smartcard_ListReaders(smartcard, irp, 0); + result = smartcard_ListReadersA(smartcard, irp); break; case SCARD_IOCTL_LISTREADERSW: - result = smartcard_ListReaders(smartcard, irp, 1); + result = smartcard_ListReadersW(smartcard, irp); break; case SCARD_IOCTL_INTRODUCEREADERGROUPA: diff --git a/channels/smartcard/client/smartcard_pack.c b/channels/smartcard/client/smartcard_pack.c index 7128bda89..eedc2e7a3 100644 --- a/channels/smartcard/client/smartcard_pack.c +++ b/channels/smartcard/client/smartcard_pack.c @@ -451,6 +451,17 @@ UINT32 smartcard_unpack_list_readers_call(SMARTCARD_DEVICE* smartcard, wStream* return SCARD_S_SUCCESS; } +UINT32 smartcard_pack_list_readers_return(SMARTCARD_DEVICE* smartcard, wStream* s, ListReaders_Return* ret) +{ + Stream_Write_UINT32(s, ret->cBytes); /* cBytes (4 bytes) */ + Stream_Write_UINT32(s, 0x00020008); /* mszNdrPtr (4 bytes) */ + Stream_Write_UINT32(s, ret->cBytes); /* mszNdrLen (4 bytes) */ + Stream_Write(s, ret->msz, ret->cBytes); + smartcard_pack_write_offset_align(smartcard, s, 4); + + return SCARD_S_SUCCESS; +} + UINT32 smartcard_unpack_connect_common(SMARTCARD_DEVICE* smartcard, wStream* s, Connect_Common* common) { UINT32 status; diff --git a/channels/smartcard/client/smartcard_pack.h b/channels/smartcard/client/smartcard_pack.h index 2f3a3af5c..99bc48d3c 100644 --- a/channels/smartcard/client/smartcard_pack.h +++ b/channels/smartcard/client/smartcard_pack.h @@ -447,6 +447,7 @@ UINT32 smartcard_pack_establish_context_return(SMARTCARD_DEVICE* smartcard, wStr UINT32 smartcard_unpack_context_call(SMARTCARD_DEVICE* smartcard, wStream* s, Context_Call* call); UINT32 smartcard_unpack_list_readers_call(SMARTCARD_DEVICE* smartcard, wStream* s, ListReaders_Call* call); +UINT32 smartcard_pack_list_readers_return(SMARTCARD_DEVICE* smartcard, wStream* s, ListReaders_Return* ret); UINT32 smartcard_unpack_connect_a_call(SMARTCARD_DEVICE* smartcard, wStream* s, ConnectA_Call* call); UINT32 smartcard_unpack_connect_w_call(SMARTCARD_DEVICE* smartcard, wStream* s, ConnectW_Call* call); diff --git a/winpr/libwinpr/smartcard/smartcard_pcsc.c b/winpr/libwinpr/smartcard/smartcard_pcsc.c index 2fceda1ae..49193e10d 100644 --- a/winpr/libwinpr/smartcard/smartcard_pcsc.c +++ b/winpr/libwinpr/smartcard/smartcard_pcsc.c @@ -24,6 +24,7 @@ #include #include #include +#include #include "smartcard_pcsc.h" @@ -47,6 +48,64 @@ LONG PCSC_MapErrorCodeToWinSCard(LONG errorCode) return errorCode; } +size_t PCSC_MultiStringLengthA(const char* msz) +{ + char* p = (char*) msz; + + if (!p) + return 0; + + while (p[0] || p[1]) + p++; + + return (p - msz); +} + +size_t PCSC_MultiStringLengthW(const WCHAR* msz) +{ + WCHAR* p = (WCHAR*) msz; + + if (!p) + return 0; + + while (p[0] || p[1]) + p++; + + return (p - msz); +} + +static wListDictionary* g_MemoryBlocks = NULL; + +void PCSC_AddMemoryBlock(SCARDCONTEXT hContext, void* pvMem) +{ + if (!g_MemoryBlocks) + g_MemoryBlocks = ListDictionary_New(TRUE); + + ListDictionary_Add(g_MemoryBlocks, pvMem, (void*) hContext); +} + +void* PCSC_RemoveMemoryBlock(SCARDCONTEXT hContext, void* pvMem) +{ + if (!g_MemoryBlocks) + return NULL; + + return ListDictionary_Remove(g_MemoryBlocks, pvMem); +} + +void* PCSC_SCardAllocMemory(SCARDCONTEXT hContext, size_t size) +{ + void* pvMem; + + pvMem = malloc(size); + + if (!pvMem) + return NULL; + + PCSC_AddMemoryBlock(hContext, pvMem); + + return pvMem; +} + /** * Standard Windows Smart Card API (PCSC) */ @@ -145,7 +204,9 @@ WINSCARDAPI LONG WINAPI PCSC_SCardListReadersW(SCARDCONTEXT hContext, if (g_PCSC.pfnSCardListReaders) { + UINT32 length; LPSTR mszGroupsA = NULL; + LPSTR mszReadersA = NULL; if (mszGroups) ConvertFromUnicode(CP_UTF8, 0, mszGroups, -1, (char**) &mszGroupsA, 0, NULL, NULL); @@ -153,10 +214,20 @@ WINSCARDAPI LONG WINAPI PCSC_SCardListReadersW(SCARDCONTEXT hContext, if (!mszReaders) pcchReaders = 0; - status = g_PCSC.pfnSCardListReaders(hContext, (LPSTR) mszGroupsA, (LPSTR) mszReaders, pcchReaders); + status = g_PCSC.pfnSCardListReaders(hContext, (LPSTR) mszGroupsA, (LPSTR) &mszReadersA, pcchReaders); status = PCSC_MapErrorCodeToWinSCard(status); - /* TODO: unicode conversion */ + if (mszReadersA) + { + length = (UINT32) PCSC_MultiStringLengthA(mszReadersA); + ConvertToUnicode(CP_UTF8, 0, mszReadersA, length + 2, (WCHAR**) mszReaders, 0); + PCSC_AddMemoryBlock(hContext, mszReaders); + + if (g_PCSC.pfnSCardFreeMemory) + { + g_PCSC.pfnSCardFreeMemory(hContext, mszReadersA); + } + } free(mszGroupsA); } @@ -320,8 +391,16 @@ WINSCARDAPI LONG WINAPI PCSC_SCardFreeMemory(SCARDCONTEXT hContext, LPCVOID pvMe if (g_PCSC.pfnSCardFreeMemory) { - status = g_PCSC.pfnSCardFreeMemory(hContext, pvMem); - status = PCSC_MapErrorCodeToWinSCard(status); + if (PCSC_RemoveMemoryBlock(hContext, (void*) pvMem)) + { + free((void*) pvMem); + status = SCARD_S_SUCCESS; + } + else + { + status = g_PCSC.pfnSCardFreeMemory(hContext, pvMem); + status = PCSC_MapErrorCodeToWinSCard(status); + } } return status;