Added multi filter for smartcard. (based on #4837 by @informatimago)

This commit is contained in:
Armin Novak 2018-09-04 12:58:05 +02:00
parent 8740219118
commit b2ce309b28
3 changed files with 242 additions and 122 deletions

View File

@ -34,6 +34,29 @@
#include "smartcard_main.h" #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) static DWORD WINAPI smartcard_context_thread(LPVOID arg)
{ {
SMARTCARD_CONTEXT* pContext = (SMARTCARD_CONTEXT*)arg; SMARTCARD_CONTEXT* pContext = (SMARTCARD_CONTEXT*)arg;
@ -152,8 +175,10 @@ error_irpqueue:
return NULL; return NULL;
} }
void smartcard_context_free(SMARTCARD_CONTEXT* pContext) void smartcard_context_free(void* pCtx)
{ {
SMARTCARD_CONTEXT* pContext = pCtx;
if (!pContext) if (!pContext)
return; return;
@ -169,7 +194,6 @@ void smartcard_context_free(SMARTCARD_CONTEXT* pContext)
free(pContext); free(pContext);
} }
static void smartcard_release_all_contexts(SMARTCARD_DEVICE* smartcard) static void smartcard_release_all_contexts(SMARTCARD_DEVICE* smartcard)
{ {
int index; 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 * Function description
* *
@ -258,7 +304,11 @@ static void smartcard_release_all_contexts(SMARTCARD_DEVICE* smartcard)
static UINT smartcard_free(DEVICE* device) static UINT smartcard_free(DEVICE* device)
{ {
UINT error; 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 * Calling smartcard_release_all_contexts to unblock all operations waiting for transactions
* to unlock. * to unlock.
@ -276,31 +326,12 @@ static UINT smartcard_free(DEVICE* device)
WLog_ERR(TAG, "WaitForSingleObject failed with error %"PRIu32"!", error); WLog_ERR(TAG, "WaitForSingleObject failed with error %"PRIu32"!", error);
return error; return error;
} }
MessageQueue_Free(smartcard->IrpQueue);
smartcard->IrpQueue = NULL;
CloseHandle(smartcard->thread);
smartcard->thread = NULL;
} }
if (smartcard->device.data) if (sSmartcard == smartcard)
{ sSmartcard = NULL;
Stream_Free(smartcard->device.data, TRUE);
smartcard->device.data = NULL;
}
ListDictionary_Free(smartcard->rgSCardContextList); return smartcard_free_(smartcard);
ListDictionary_Free(smartcard->rgOutstandingMessages);
Queue_Free(smartcard->CompletedIrpQueue);
if (smartcard->StartedEvent)
{
SCardReleaseStartedEvent();
smartcard->StartedEvent = NULL;
}
free(device);
return CHANNEL_RC_OK;
} }
/** /**
@ -315,7 +346,11 @@ static UINT smartcard_free(DEVICE* device)
*/ */
static UINT smartcard_init(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); smartcard_release_all_contexts(smartcard);
return CHANNEL_RC_OK; return CHANNEL_RC_OK;
} }
@ -325,7 +360,7 @@ static UINT smartcard_init(DEVICE* device)
* *
* @return 0 on success, otherwise a Win32 error code * @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; void* key;
key = (void*)(size_t) irp->CompletionId; 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 * @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; void* key;
LONG status; LONG status;
@ -505,8 +540,12 @@ static DWORD WINAPI smartcard_thread_func(LPVOID arg)
DWORD status; DWORD status;
HANDLE hEvents[2]; HANDLE hEvents[2];
wMessage message; wMessage message;
SMARTCARD_DEVICE* smartcard = (SMARTCARD_DEVICE*) arg;
UINT error = CHANNEL_RC_OK; UINT error = CHANNEL_RC_OK;
SMARTCARD_DEVICE* smartcard = CAST_FROM_DEVICE(arg);
if (!smartcard)
return ERROR_INVALID_PARAMETER;
nCount = 0; nCount = 0;
hEvents[nCount++] = MessageQueue_Event(smartcard->IrpQueue); hEvents[nCount++] = MessageQueue_Event(smartcard->IrpQueue);
hEvents[nCount++] = Queue_Event(smartcard->CompletedIrpQueue); hEvents[nCount++] = Queue_Event(smartcard->CompletedIrpQueue);
@ -660,7 +699,10 @@ out:
*/ */
static UINT smartcard_irp_request(DEVICE* device, IRP* irp) 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)) 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) UINT DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints)
{ {
SMARTCARD_DEVICE* smartcard = NULL;
size_t length; size_t length;
SMARTCARD_DEVICE* smartcard;
UINT error = CHANNEL_RC_NO_MEMORY; UINT error = CHANNEL_RC_NO_MEMORY;
smartcard = (SMARTCARD_DEVICE*) calloc(1, sizeof(SMARTCARD_DEVICE));
if (!smartcard) if (!sSmartcard)
{ {
WLog_ERR(TAG, "calloc failed!"); wObject* obj;
return CHANNEL_RC_NO_MEMORY; 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; LinkedList_AddLast(smartcard->names, pEntryPoints->device->Name);
smartcard->device.name = "SCARD"; sSmartcard = smartcard;
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);
return CHANNEL_RC_OK; return CHANNEL_RC_OK;
error_thread: fail:
ListDictionary_Free(smartcard->rgOutstandingMessages); smartcard_free_(smartcard);
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);
return error; return error;
} }

View File

@ -117,15 +117,14 @@ struct _SMARTCARD_DEVICE
wListDictionary* rgSCardContextList; wListDictionary* rgSCardContextList;
wListDictionary* rgOutstandingMessages; wListDictionary* rgOutstandingMessages;
rdpContext* rdpcontext; rdpContext* rdpcontext;
wLinkedList* names;
}; };
SMARTCARD_CONTEXT* smartcard_context_new(SMARTCARD_DEVICE* smartcard, SCARDCONTEXT hContext); 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); LONG smartcard_irp_device_control_decode(SMARTCARD_DEVICE* smartcard,
UINT smartcard_process_irp(SMARTCARD_DEVICE* smartcard, IRP* irp); 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); LONG smartcard_irp_device_control_call(SMARTCARD_DEVICE* smartcard, SMARTCARD_OPERATION* operation);
#include "smartcard_pack.h" #include "smartcard_pack.h"

View File

@ -432,6 +432,84 @@ static LONG smartcard_ListReaderGroupsW_Call(SMARTCARD_DEVICE* smartcard,
return ret.ReturnCode; 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, static LONG smartcard_ListReadersA_Decode(SMARTCARD_DEVICE* smartcard,
SMARTCARD_OPERATION* operation) SMARTCARD_OPERATION* operation)
{ {
@ -462,6 +540,7 @@ static LONG smartcard_ListReadersA_Call(SMARTCARD_DEVICE* smartcard, SMARTCARD_O
cchReaders = SCARD_AUTOALLOCATE; cchReaders = SCARD_AUTOALLOCATE;
status = ret.ReturnCode = SCardListReadersA(operation->hContext, (LPCSTR) call->mszGroups, status = ret.ReturnCode = SCardListReadersA(operation->hContext, (LPCSTR) call->mszGroups,
(LPSTR) &mszReaders, &cchReaders); (LPSTR) &mszReaders, &cchReaders);
cchReaders = filter_device_by_name_a(smartcard->names, &mszReaders, cchReaders);
ret.msz = (BYTE*) mszReaders; ret.msz = (BYTE*) mszReaders;
ret.cBytes = cchReaders; ret.cBytes = cchReaders;
@ -524,6 +603,7 @@ static LONG smartcard_ListReadersW_Call(SMARTCARD_DEVICE* smartcard, SMARTCARD_O
cchReaders = SCARD_AUTOALLOCATE; cchReaders = SCARD_AUTOALLOCATE;
status = ret.ReturnCode = SCardListReadersW(operation->hContext, status = ret.ReturnCode = SCardListReadersW(operation->hContext,
(LPCWSTR) call->mszGroups, (LPWSTR) &mszReaders, &cchReaders); (LPCWSTR) call->mszGroups, (LPWSTR) &mszReaders, &cchReaders);
cchReaders = filter_device_by_name_w(smartcard->names, &mszReaders, cchReaders);
ret.msz = (BYTE*) mszReaders; ret.msz = (BYTE*) mszReaders;
ret.cBytes = cchReaders * 2; ret.cBytes = cchReaders * 2;
@ -1053,7 +1133,6 @@ static LONG smartcard_StatusA_Call(SMARTCARD_DEVICE* smartcard, SMARTCARD_OPERAT
IRP* irp = operation->irp; IRP* irp = operation->irp;
Status_Call* call = operation->call; Status_Call* call = operation->call;
ZeroMemory(ret.pbAtr, 32); ZeroMemory(ret.pbAtr, 32);
call->cbAtrLen = 32; call->cbAtrLen = 32;
cbAtrLen = call->cbAtrLen; cbAtrLen = call->cbAtrLen;