Added multi filter for smartcard. (based on #4837 by @informatimago)
This commit is contained in:
parent
8740219118
commit
b2ce309b28
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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"
|
||||
|
@ -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;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user