From b2ce309b28ad90b87800a0ef2b56e52dd62c1ab0 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Tue, 4 Sep 2018 12:58:05 +0200 Subject: [PATCH] Added multi filter for smartcard. (based on #4837 by @informatimago) --- channels/smartcard/client/smartcard_main.c | 274 ++++++++++-------- channels/smartcard/client/smartcard_main.h | 9 +- .../smartcard/client/smartcard_operations.c | 81 +++++- 3 files changed, 242 insertions(+), 122 deletions(-) diff --git a/channels/smartcard/client/smartcard_main.c b/channels/smartcard/client/smartcard_main.c index 37a223e32..04dcb90ab 100644 --- a/channels/smartcard/client/smartcard_main.c +++ b/channels/smartcard/client/smartcard_main.c @@ -34,6 +34,29 @@ #include "smartcard_main.h" +#define CAST_FROM_DEVICE(device) cast_device_from(device, __FUNCTION__, __FILE__, __LINE__) + +static SMARTCARD_DEVICE* sSmartcard = NULL; + +static SMARTCARD_DEVICE* cast_device_from(DEVICE* device, const char* fkt, const char* file, + int line) +{ + if (!device) + { + WLog_ERR(TAG, "%s [%s:%d] Called smartcard channel with NULL device", fkt, file, line); + return NULL; + } + + if (device->type != RDPDR_DTYP_SMARTCARD) + { + WLog_ERR(TAG, "%s [%s:%d] Called smartcard channel with invalid device of type %"PRIx32, + fkt, file, line, device->type); + return NULL; + } + + return (SMARTCARD_DEVICE*)device; +} + static DWORD WINAPI smartcard_context_thread(LPVOID arg) { SMARTCARD_CONTEXT* pContext = (SMARTCARD_CONTEXT*)arg; @@ -152,8 +175,10 @@ error_irpqueue: return NULL; } -void smartcard_context_free(SMARTCARD_CONTEXT* pContext) +void smartcard_context_free(void* pCtx) { + SMARTCARD_CONTEXT* pContext = pCtx; + if (!pContext) return; @@ -169,7 +194,6 @@ void smartcard_context_free(SMARTCARD_CONTEXT* pContext) free(pContext); } - static void smartcard_release_all_contexts(SMARTCARD_DEVICE* smartcard) { int index; @@ -249,7 +273,29 @@ static void smartcard_release_all_contexts(SMARTCARD_DEVICE* smartcard) } } +static UINT smartcard_free_(SMARTCARD_DEVICE* smartcard) +{ + if (!smartcard) + return CHANNEL_RC_OK; + if (smartcard->IrpQueue) + { + MessageQueue_Free(smartcard->IrpQueue); + CloseHandle(smartcard->thread); + } + + Stream_Free(smartcard->device.data, TRUE); + LinkedList_Free(smartcard->names); + ListDictionary_Free(smartcard->rgSCardContextList); + ListDictionary_Free(smartcard->rgOutstandingMessages); + Queue_Free(smartcard->CompletedIrpQueue); + + if (smartcard->StartedEvent) + SCardReleaseStartedEvent(); + + free(smartcard); + return CHANNEL_RC_OK; +} /** * Function description * @@ -258,7 +304,11 @@ static void smartcard_release_all_contexts(SMARTCARD_DEVICE* smartcard) static UINT smartcard_free(DEVICE* device) { UINT error; - SMARTCARD_DEVICE* smartcard = (SMARTCARD_DEVICE*) device; + SMARTCARD_DEVICE* smartcard = CAST_FROM_DEVICE(device); + + if (!smartcard) + return ERROR_INVALID_PARAMETER; + /** * Calling smartcard_release_all_contexts to unblock all operations waiting for transactions * to unlock. @@ -276,31 +326,12 @@ static UINT smartcard_free(DEVICE* device) WLog_ERR(TAG, "WaitForSingleObject failed with error %"PRIu32"!", error); return error; } - - MessageQueue_Free(smartcard->IrpQueue); - smartcard->IrpQueue = NULL; - CloseHandle(smartcard->thread); - smartcard->thread = NULL; } - if (smartcard->device.data) - { - Stream_Free(smartcard->device.data, TRUE); - smartcard->device.data = NULL; - } + if (sSmartcard == smartcard) + sSmartcard = NULL; - ListDictionary_Free(smartcard->rgSCardContextList); - ListDictionary_Free(smartcard->rgOutstandingMessages); - Queue_Free(smartcard->CompletedIrpQueue); - - if (smartcard->StartedEvent) - { - SCardReleaseStartedEvent(); - smartcard->StartedEvent = NULL; - } - - free(device); - return CHANNEL_RC_OK; + return smartcard_free_(smartcard); } /** @@ -315,7 +346,11 @@ static UINT smartcard_free(DEVICE* device) */ static UINT smartcard_init(DEVICE* device) { - SMARTCARD_DEVICE* smartcard = (SMARTCARD_DEVICE*) device; + SMARTCARD_DEVICE* smartcard = CAST_FROM_DEVICE(device); + + if (!smartcard) + return ERROR_INVALID_PARAMETER; + smartcard_release_all_contexts(smartcard); return CHANNEL_RC_OK; } @@ -325,7 +360,7 @@ static UINT smartcard_init(DEVICE* device) * * @return 0 on success, otherwise a Win32 error code */ -UINT smartcard_complete_irp(SMARTCARD_DEVICE* smartcard, IRP* irp) +static UINT smartcard_complete_irp(SMARTCARD_DEVICE* smartcard, IRP* irp) { void* key; key = (void*)(size_t) irp->CompletionId; @@ -343,7 +378,7 @@ UINT smartcard_complete_irp(SMARTCARD_DEVICE* smartcard, IRP* irp) * * @return 0 on success, otherwise a Win32 error code */ -UINT smartcard_process_irp(SMARTCARD_DEVICE* smartcard, IRP* irp) +static UINT smartcard_process_irp(SMARTCARD_DEVICE* smartcard, IRP* irp) { void* key; LONG status; @@ -505,8 +540,12 @@ static DWORD WINAPI smartcard_thread_func(LPVOID arg) DWORD status; HANDLE hEvents[2]; wMessage message; - SMARTCARD_DEVICE* smartcard = (SMARTCARD_DEVICE*) arg; UINT error = CHANNEL_RC_OK; + SMARTCARD_DEVICE* smartcard = CAST_FROM_DEVICE(arg); + + if (!smartcard) + return ERROR_INVALID_PARAMETER; + nCount = 0; hEvents[nCount++] = MessageQueue_Event(smartcard->IrpQueue); hEvents[nCount++] = Queue_Event(smartcard->CompletedIrpQueue); @@ -660,7 +699,10 @@ out: */ static UINT smartcard_irp_request(DEVICE* device, IRP* irp) { - SMARTCARD_DEVICE* smartcard = (SMARTCARD_DEVICE*) device; + SMARTCARD_DEVICE* smartcard = CAST_FROM_DEVICE(device); + + if (!smartcard) + return ERROR_INVALID_PARAMETER; if (!MessageQueue_Post(smartcard->IrpQueue, NULL, 0, (void*) irp, NULL)) { @@ -681,99 +723,99 @@ static UINT smartcard_irp_request(DEVICE* device, IRP* irp) */ UINT DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints) { + SMARTCARD_DEVICE* smartcard = NULL; size_t length; - SMARTCARD_DEVICE* smartcard; UINT error = CHANNEL_RC_NO_MEMORY; - smartcard = (SMARTCARD_DEVICE*) calloc(1, sizeof(SMARTCARD_DEVICE)); - if (!smartcard) + if (!sSmartcard) { - WLog_ERR(TAG, "calloc failed!"); - return CHANNEL_RC_NO_MEMORY; + wObject* obj; + smartcard = (SMARTCARD_DEVICE*) calloc(1, sizeof(SMARTCARD_DEVICE)); + + if (!smartcard) + { + WLog_ERR(TAG, "calloc failed!"); + return CHANNEL_RC_NO_MEMORY; + } + + smartcard->device.type = RDPDR_DTYP_SMARTCARD; + smartcard->device.name = "SCARD"; + smartcard->device.IRPRequest = smartcard_irp_request; + smartcard->device.Init = smartcard_init; + smartcard->device.Free = smartcard_free; + smartcard->names = LinkedList_New(); + smartcard->rdpcontext = pEntryPoints->rdpcontext; + length = strlen(smartcard->device.name); + smartcard->device.data = Stream_New(NULL, length + 1); + + if (!smartcard->device.data || !smartcard->names) + { + WLog_ERR(TAG, "Stream_New failed!"); + goto fail; + } + + Stream_Write(smartcard->device.data, "SCARD", 6); + smartcard->IrpQueue = MessageQueue_New(NULL); + + if (!smartcard->IrpQueue) + { + WLog_ERR(TAG, "MessageQueue_New failed!"); + goto fail; + } + + smartcard->CompletedIrpQueue = Queue_New(TRUE, -1, -1); + + if (!smartcard->CompletedIrpQueue) + { + WLog_ERR(TAG, "Queue_New failed!"); + goto fail; + } + + smartcard->rgSCardContextList = ListDictionary_New(TRUE); + + if (!smartcard->rgSCardContextList) + { + WLog_ERR(TAG, "ListDictionary_New failed!"); + goto fail; + } + + obj = ListDictionary_ValueObject(smartcard->rgSCardContextList); + obj->fnObjectFree = smartcard_context_free; + smartcard->rgOutstandingMessages = ListDictionary_New(TRUE); + + if (!smartcard->rgOutstandingMessages) + { + WLog_ERR(TAG, "ListDictionary_New failed!"); + goto fail; + } + + if ((error = pEntryPoints->RegisterDevice(pEntryPoints->devman, &smartcard->device))) + { + WLog_ERR(TAG, "RegisterDevice failed!"); + goto fail; + } + + smartcard->thread = CreateThread(NULL, 0, + smartcard_thread_func, + smartcard, CREATE_SUSPENDED, NULL); + + if (!smartcard->thread) + { + WLog_ERR(TAG, "ListDictionary_New failed!"); + error = ERROR_INTERNAL_ERROR; + goto fail; + } + + ResumeThread(smartcard->thread); } + else + smartcard = sSmartcard; - smartcard->device.type = RDPDR_DTYP_SMARTCARD; - smartcard->device.name = "SCARD"; - smartcard->device.IRPRequest = smartcard_irp_request; - smartcard->device.Init = smartcard_init; - smartcard->device.Free = smartcard_free; - smartcard->rdpcontext = pEntryPoints->rdpcontext; - length = strlen(smartcard->device.name); - smartcard->device.data = Stream_New(NULL, length + 1); - - if (!smartcard->device.data) - { - WLog_ERR(TAG, "Stream_New failed!"); - goto error_device_data; - } - - Stream_Write(smartcard->device.data, "SCARD", 6); - smartcard->IrpQueue = MessageQueue_New(NULL); - - if (!smartcard->IrpQueue) - { - WLog_ERR(TAG, "MessageQueue_New failed!"); - goto error_irp_queue; - } - - smartcard->CompletedIrpQueue = Queue_New(TRUE, -1, -1); - - if (!smartcard->CompletedIrpQueue) - { - WLog_ERR(TAG, "Queue_New failed!"); - goto error_completed_irp_queue; - } - - smartcard->rgSCardContextList = ListDictionary_New(TRUE); - - if (!smartcard->rgSCardContextList) - { - WLog_ERR(TAG, "ListDictionary_New failed!"); - goto error_context_list; - } - - ListDictionary_ValueObject(smartcard->rgSCardContextList)->fnObjectFree = - (OBJECT_FREE_FN) smartcard_context_free; - smartcard->rgOutstandingMessages = ListDictionary_New(TRUE); - - if (!smartcard->rgOutstandingMessages) - { - WLog_ERR(TAG, "ListDictionary_New failed!"); - goto error_outstanding_messages; - } - - if ((error = pEntryPoints->RegisterDevice(pEntryPoints->devman, - (DEVICE*) smartcard))) - { - WLog_ERR(TAG, "RegisterDevice failed!"); - goto error_outstanding_messages; - } - - smartcard->thread = CreateThread(NULL, 0, - smartcard_thread_func, - smartcard, CREATE_SUSPENDED, NULL); - - if (!smartcard->thread) - { - WLog_ERR(TAG, "ListDictionary_New failed!"); - error = ERROR_INTERNAL_ERROR; - goto error_thread; - } - - ResumeThread(smartcard->thread); + LinkedList_AddLast(smartcard->names, pEntryPoints->device->Name); + sSmartcard = smartcard; return CHANNEL_RC_OK; -error_thread: - ListDictionary_Free(smartcard->rgOutstandingMessages); -error_outstanding_messages: - ListDictionary_Free(smartcard->rgSCardContextList); -error_context_list: - Queue_Free(smartcard->CompletedIrpQueue); -error_completed_irp_queue: - MessageQueue_Free(smartcard->IrpQueue); -error_irp_queue: - Stream_Free(smartcard->device.data, TRUE); -error_device_data: - free(smartcard); +fail: + smartcard_free_(smartcard); return error; } diff --git a/channels/smartcard/client/smartcard_main.h b/channels/smartcard/client/smartcard_main.h index 845123458..a867e69b2 100644 --- a/channels/smartcard/client/smartcard_main.h +++ b/channels/smartcard/client/smartcard_main.h @@ -117,15 +117,14 @@ struct _SMARTCARD_DEVICE wListDictionary* rgSCardContextList; wListDictionary* rgOutstandingMessages; rdpContext* rdpcontext; + wLinkedList* names; }; SMARTCARD_CONTEXT* smartcard_context_new(SMARTCARD_DEVICE* smartcard, SCARDCONTEXT hContext); -void smartcard_context_free(SMARTCARD_CONTEXT* pContext); +void smartcard_context_free(void* pContext); -UINT smartcard_complete_irp(SMARTCARD_DEVICE* smartcard, IRP* irp); -UINT smartcard_process_irp(SMARTCARD_DEVICE* smartcard, IRP* irp); - -LONG smartcard_irp_device_control_decode(SMARTCARD_DEVICE* smartcard, SMARTCARD_OPERATION* operation); +LONG smartcard_irp_device_control_decode(SMARTCARD_DEVICE* smartcard, + SMARTCARD_OPERATION* operation); LONG smartcard_irp_device_control_call(SMARTCARD_DEVICE* smartcard, SMARTCARD_OPERATION* operation); #include "smartcard_pack.h" diff --git a/channels/smartcard/client/smartcard_operations.c b/channels/smartcard/client/smartcard_operations.c index ec979e678..b9b983ce7 100644 --- a/channels/smartcard/client/smartcard_operations.c +++ b/channels/smartcard/client/smartcard_operations.c @@ -432,6 +432,84 @@ static LONG smartcard_ListReaderGroupsW_Call(SMARTCARD_DEVICE* smartcard, return ret.ReturnCode; } +static BOOL filter_match(wLinkedList* list, LPCSTR reader, size_t readerLen) +{ + if (readerLen < 1) + return FALSE; + + LinkedList_Enumerator_Reset(list); + + while (LinkedList_Enumerator_MoveNext(list)) + { + const char* filter = LinkedList_Enumerator_Current(list); + + if (filter) + { + if (strstr(reader, filter) != NULL) + return TRUE; + } + } + + return FALSE; +} + +static DWORD filter_device_by_name_a(wLinkedList* list, LPSTR* mszReaders, DWORD cchReaders) +{ + size_t rpos = 0, wpos = 0; + + if (LinkedList_Count(list) < 1) + return cchReaders; + + do + { + LPCSTR rreader = &(*mszReaders)[rpos]; + LPSTR wreader = &(*mszReaders)[wpos]; + size_t readerLen = strnlen(rreader, cchReaders - rpos); + rpos += readerLen + 1; + + if (filter_match(list, rreader, readerLen)) + { + if (rreader != wreader) + memmove(wreader, rreader, readerLen); + + wpos += readerLen + 1; + } + } + while (rpos < cchReaders); + + /* this string must be double 0 terminated */ + if (rpos != wpos) + { + if (wpos >= cchReaders) + return 0; + + (*mszReaders)[wpos++] = '\0'; + } + + return wpos; +} + +static DWORD filter_device_by_name_w(wLinkedList* list, LPWSTR* mszReaders, DWORD cchReaders) +{ + DWORD rc; + LPSTR readers; + + if (LinkedList_Count(list) < 1) + return cchReaders; + + if (ConvertFromUnicode(CP_UTF8, 0, *mszReaders, cchReaders, &readers, 0, NULL, NULL) != cchReaders) + return 0; + + free(*mszReaders); + rc = filter_device_by_name_a(list, &readers, cchReaders); + + if (ConvertToUnicode(CP_UTF8, 0, &readers, rc, mszReaders, 0) != rc) + rc = 0; + + free(readers); + return rc; +} + static LONG smartcard_ListReadersA_Decode(SMARTCARD_DEVICE* smartcard, SMARTCARD_OPERATION* operation) { @@ -462,6 +540,7 @@ static LONG smartcard_ListReadersA_Call(SMARTCARD_DEVICE* smartcard, SMARTCARD_O cchReaders = SCARD_AUTOALLOCATE; status = ret.ReturnCode = SCardListReadersA(operation->hContext, (LPCSTR) call->mszGroups, (LPSTR) &mszReaders, &cchReaders); + cchReaders = filter_device_by_name_a(smartcard->names, &mszReaders, cchReaders); ret.msz = (BYTE*) mszReaders; ret.cBytes = cchReaders; @@ -524,6 +603,7 @@ static LONG smartcard_ListReadersW_Call(SMARTCARD_DEVICE* smartcard, SMARTCARD_O cchReaders = SCARD_AUTOALLOCATE; status = ret.ReturnCode = SCardListReadersW(operation->hContext, (LPCWSTR) call->mszGroups, (LPWSTR) &mszReaders, &cchReaders); + cchReaders = filter_device_by_name_w(smartcard->names, &mszReaders, cchReaders); ret.msz = (BYTE*) mszReaders; ret.cBytes = cchReaders * 2; @@ -1053,7 +1133,6 @@ static LONG smartcard_StatusA_Call(SMARTCARD_DEVICE* smartcard, SMARTCARD_OPERAT IRP* irp = operation->irp; Status_Call* call = operation->call; ZeroMemory(ret.pbAtr, 32); - call->cbAtrLen = 32; cbAtrLen = call->cbAtrLen;