2012-08-14 17:09:01 -04:00
|
|
|
/**
|
2012-10-08 23:02:04 -04:00
|
|
|
* FreeRDP: A Remote Desktop Protocol Implementation
|
2012-08-14 17:09:01 -04:00
|
|
|
* Smartcard Device Service Virtual Channel
|
|
|
|
|
*
|
|
|
|
|
* Copyright 2011 O.S. Systems Software Ltda.
|
|
|
|
|
* Copyright 2011 Eduardo Fiss Beloni <beloni@ossystems.com.br>
|
|
|
|
|
* Copyright 2011 Anthony Tong <atong@trustedcs.com>
|
2015-07-03 04:09:03 -07:00
|
|
|
* Copyright 2015 Thincast Technologies GmbH
|
|
|
|
|
* Copyright 2015 DI (FH) Martin Haimberger <martin.haimberger@thincast.com>
|
2016-09-01 11:34:38 -07:00
|
|
|
* Copyright 2016 David PHAM-VAN <d.phamvan@inuvika.com>
|
2012-08-14 17:09:01 -04:00
|
|
|
*
|
|
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
|
* you may not use this file except in compliance with the License.
|
|
|
|
|
* You may obtain a copy of the License at
|
|
|
|
|
*
|
|
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
*
|
|
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
|
* See the License for the specific language governing permissions and
|
|
|
|
|
* limitations under the License.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
2011-10-15 10:30:10 -05:00
|
|
|
#include "config.h"
|
2012-08-14 17:09:01 -04:00
|
|
|
#endif
|
2011-10-15 10:30:10 -05:00
|
|
|
|
2012-11-21 11:56:40 -05:00
|
|
|
#include <winpr/crt.h>
|
2014-04-03 15:27:55 -04:00
|
|
|
#include <winpr/smartcard.h>
|
2014-05-03 13:49:50 -04:00
|
|
|
#include <winpr/environment.h>
|
2012-11-21 11:56:40 -05:00
|
|
|
|
2012-10-08 21:00:07 -04:00
|
|
|
#include <freerdp/channels/rdpdr.h>
|
2011-10-15 10:30:10 -05:00
|
|
|
|
2012-11-21 11:56:40 -05:00
|
|
|
#include "smartcard_main.h"
|
2011-10-15 10:30:10 -05:00
|
|
|
|
2018-09-04 12:58:05 +02:00
|
|
|
#define CAST_FROM_DEVICE(device) cast_device_from(device, __FUNCTION__, __FILE__, __LINE__)
|
|
|
|
|
|
2021-11-05 13:09:42 +01:00
|
|
|
#if defined(WITH_SMARTCARD_EMULATE)
|
|
|
|
|
#include <freerdp/emulate/scard/smartcard_emulate.h>
|
|
|
|
|
#define str(x) #x
|
|
|
|
|
#define wrap(smartcard, fkt, ...) Emulate_##fkt(smartcard->emulation, ##__VA_ARGS__)
|
|
|
|
|
#else
|
|
|
|
|
#define wrap(smartcard, fkt, ...) fkt(__VA_ARGS__)
|
|
|
|
|
#endif
|
|
|
|
|
|
2018-09-04 12:58:05 +02:00
|
|
|
static SMARTCARD_DEVICE* sSmartcard = NULL;
|
|
|
|
|
|
|
|
|
|
static SMARTCARD_DEVICE* cast_device_from(DEVICE* device, const char* fkt, const char* file,
|
2019-11-06 15:24:51 +01:00
|
|
|
int line)
|
2018-09-04 12:58:05 +02:00
|
|
|
{
|
|
|
|
|
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)
|
|
|
|
|
{
|
2019-11-06 15:24:51 +01:00
|
|
|
WLog_ERR(TAG, "%s [%s:%d] Called smartcard channel with invalid device of type %" PRIx32,
|
2018-09-04 12:58:05 +02:00
|
|
|
fkt, file, line, device->type);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (SMARTCARD_DEVICE*)device;
|
|
|
|
|
}
|
|
|
|
|
|
2018-03-07 12:03:10 +01:00
|
|
|
static DWORD WINAPI smartcard_context_thread(LPVOID arg)
|
2014-05-12 11:28:20 -04:00
|
|
|
{
|
2018-03-07 12:03:10 +01:00
|
|
|
SMARTCARD_CONTEXT* pContext = (SMARTCARD_CONTEXT*)arg;
|
2014-05-12 11:28:20 -04:00
|
|
|
DWORD nCount;
|
2015-09-01 12:27:54 +02:00
|
|
|
LONG status = 0;
|
|
|
|
|
DWORD waitStatus;
|
2014-05-12 11:28:20 -04:00
|
|
|
HANDLE hEvents[2];
|
|
|
|
|
wMessage message;
|
|
|
|
|
SMARTCARD_DEVICE* smartcard;
|
2014-05-12 17:05:20 -04:00
|
|
|
SMARTCARD_OPERATION* operation;
|
2015-08-27 05:25:09 -07:00
|
|
|
UINT error = CHANNEL_RC_OK;
|
2014-05-12 11:28:20 -04:00
|
|
|
smartcard = pContext->smartcard;
|
|
|
|
|
nCount = 0;
|
|
|
|
|
hEvents[nCount++] = MessageQueue_Event(pContext->IrpQueue);
|
|
|
|
|
|
|
|
|
|
while (1)
|
|
|
|
|
{
|
2015-09-01 12:27:54 +02:00
|
|
|
waitStatus = WaitForMultipleObjects(nCount, hEvents, FALSE, INFINITE);
|
2015-07-30 06:49:21 -07:00
|
|
|
|
2015-09-01 12:27:54 +02:00
|
|
|
if (waitStatus == WAIT_FAILED)
|
|
|
|
|
{
|
|
|
|
|
error = GetLastError();
|
2019-11-06 15:24:51 +01:00
|
|
|
WLog_ERR(TAG, "WaitForMultipleObjects failed with error %" PRIu32 "!", error);
|
2015-09-01 12:27:54 +02:00
|
|
|
break;
|
|
|
|
|
}
|
2015-07-30 06:49:21 -07:00
|
|
|
|
2015-09-01 12:27:54 +02:00
|
|
|
waitStatus = WaitForSingleObject(MessageQueue_Event(pContext->IrpQueue), 0);
|
2014-05-12 11:28:20 -04:00
|
|
|
|
2015-09-01 12:27:54 +02:00
|
|
|
if (waitStatus == WAIT_FAILED)
|
|
|
|
|
{
|
|
|
|
|
error = GetLastError();
|
2019-11-06 15:24:51 +01:00
|
|
|
WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "!", error);
|
2015-09-01 12:27:54 +02:00
|
|
|
break;
|
|
|
|
|
}
|
2015-07-30 06:49:21 -07:00
|
|
|
|
|
|
|
|
if (waitStatus == WAIT_OBJECT_0)
|
2014-05-12 11:28:20 -04:00
|
|
|
{
|
|
|
|
|
if (!MessageQueue_Peek(pContext->IrpQueue, &message, TRUE))
|
2015-07-15 00:50:35 -07:00
|
|
|
{
|
|
|
|
|
WLog_ERR(TAG, "MessageQueue_Peek failed!");
|
|
|
|
|
status = ERROR_INTERNAL_ERROR;
|
2014-05-12 11:28:20 -04:00
|
|
|
break;
|
2015-07-15 00:50:35 -07:00
|
|
|
}
|
|
|
|
|
|
2014-05-12 11:28:20 -04:00
|
|
|
if (message.id == WMQ_QUIT)
|
|
|
|
|
break;
|
|
|
|
|
|
2019-11-06 15:24:51 +01:00
|
|
|
operation = (SMARTCARD_OPERATION*)message.wParam;
|
2014-05-12 11:28:20 -04:00
|
|
|
|
2014-05-12 17:05:20 -04:00
|
|
|
if (operation)
|
2014-05-12 11:28:20 -04:00
|
|
|
{
|
2015-07-03 04:09:03 -07:00
|
|
|
if ((status = smartcard_irp_device_control_call(smartcard, operation)))
|
|
|
|
|
{
|
2019-11-06 15:24:51 +01:00
|
|
|
WLog_ERR(TAG, "smartcard_irp_device_control_call failed with error %" PRIu32 "",
|
2016-09-26 12:12:37 +02:00
|
|
|
status);
|
2015-07-03 04:09:03 -07:00
|
|
|
break;
|
|
|
|
|
}
|
2014-05-12 17:05:20 -04:00
|
|
|
|
2019-11-06 15:24:51 +01:00
|
|
|
if (!Queue_Enqueue(smartcard->CompletedIrpQueue, (void*)operation->irp))
|
2015-07-15 00:50:35 -07:00
|
|
|
{
|
|
|
|
|
WLog_ERR(TAG, "Queue_Enqueue failed!");
|
|
|
|
|
status = ERROR_INTERNAL_ERROR;
|
|
|
|
|
break;
|
|
|
|
|
}
|
2014-05-12 17:05:20 -04:00
|
|
|
|
|
|
|
|
free(operation);
|
2014-05-12 11:28:20 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-07-15 00:50:35 -07:00
|
|
|
if (status && smartcard->rdpcontext)
|
2019-11-06 15:24:51 +01:00
|
|
|
setChannelError(smartcard->rdpcontext, error, "smartcard_context_thread reported an error");
|
2015-07-15 00:50:35 -07:00
|
|
|
|
2018-03-07 12:03:10 +01:00
|
|
|
ExitThread(status);
|
|
|
|
|
return error;
|
2014-05-12 11:28:20 -04:00
|
|
|
}
|
|
|
|
|
|
2019-11-06 15:24:51 +01:00
|
|
|
SMARTCARD_CONTEXT* smartcard_context_new(SMARTCARD_DEVICE* smartcard, SCARDCONTEXT hContext)
|
2014-05-12 11:28:20 -04:00
|
|
|
{
|
|
|
|
|
SMARTCARD_CONTEXT* pContext;
|
2019-11-06 15:24:51 +01:00
|
|
|
pContext = (SMARTCARD_CONTEXT*)calloc(1, sizeof(SMARTCARD_CONTEXT));
|
2016-09-26 12:12:37 +02:00
|
|
|
|
2014-05-12 11:28:20 -04:00
|
|
|
if (!pContext)
|
2015-07-15 00:50:35 -07:00
|
|
|
{
|
|
|
|
|
WLog_ERR(TAG, "calloc failed!");
|
2014-05-12 11:28:20 -04:00
|
|
|
return pContext;
|
2015-07-15 00:50:35 -07:00
|
|
|
}
|
2014-05-12 11:28:20 -04:00
|
|
|
|
2014-05-12 17:05:20 -04:00
|
|
|
pContext->smartcard = smartcard;
|
2014-05-12 11:28:20 -04:00
|
|
|
pContext->hContext = hContext;
|
|
|
|
|
pContext->IrpQueue = MessageQueue_New(NULL);
|
2016-09-26 12:12:37 +02:00
|
|
|
|
2015-05-18 11:28:00 +02:00
|
|
|
if (!pContext->IrpQueue)
|
2015-07-15 00:50:35 -07:00
|
|
|
{
|
|
|
|
|
WLog_ERR(TAG, "MessageQueue_New failed!");
|
2021-11-05 13:09:42 +01:00
|
|
|
goto fail;
|
2015-07-15 00:50:35 -07:00
|
|
|
}
|
2014-05-12 11:28:20 -04:00
|
|
|
|
2019-11-06 15:24:51 +01:00
|
|
|
pContext->thread = CreateThread(NULL, 0, smartcard_context_thread, pContext, 0, NULL);
|
2016-09-26 12:12:37 +02:00
|
|
|
|
2015-05-18 11:28:00 +02:00
|
|
|
if (!pContext->thread)
|
2015-07-15 00:50:35 -07:00
|
|
|
{
|
|
|
|
|
WLog_ERR(TAG, "CreateThread failed!");
|
2021-11-05 13:09:42 +01:00
|
|
|
goto fail;
|
2015-07-15 00:50:35 -07:00
|
|
|
}
|
|
|
|
|
|
2014-05-12 11:28:20 -04:00
|
|
|
return pContext;
|
2021-11-05 13:09:42 +01:00
|
|
|
fail:
|
|
|
|
|
smartcard_context_free(pContext);
|
2015-05-18 11:28:00 +02:00
|
|
|
return NULL;
|
2014-05-12 11:28:20 -04:00
|
|
|
}
|
|
|
|
|
|
2018-09-04 12:58:05 +02:00
|
|
|
void smartcard_context_free(void* pCtx)
|
2014-05-12 11:28:20 -04:00
|
|
|
{
|
2018-09-04 12:58:05 +02:00
|
|
|
SMARTCARD_CONTEXT* pContext = pCtx;
|
|
|
|
|
|
2014-05-12 11:28:20 -04:00
|
|
|
if (!pContext)
|
|
|
|
|
return;
|
|
|
|
|
|
2014-12-28 14:56:13 -05:00
|
|
|
/* cancel blocking calls like SCardGetStatusChange */
|
2021-11-05 13:09:42 +01:00
|
|
|
wrap(pContext->smartcard, SCardCancel, pContext->hContext);
|
2016-09-26 12:12:37 +02:00
|
|
|
|
2021-11-05 13:09:42 +01:00
|
|
|
if (pContext->IrpQueue)
|
|
|
|
|
{
|
|
|
|
|
if (MessageQueue_PostQuit(pContext->IrpQueue, 0))
|
|
|
|
|
{
|
|
|
|
|
if (WaitForSingleObject(pContext->thread, INFINITE) == WAIT_FAILED)
|
|
|
|
|
WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "!", GetLastError());
|
2014-12-28 14:56:13 -05:00
|
|
|
|
2021-11-05 13:09:42 +01:00
|
|
|
CloseHandle(pContext->thread);
|
|
|
|
|
}
|
|
|
|
|
MessageQueue_Free(pContext->IrpQueue);
|
|
|
|
|
}
|
|
|
|
|
wrap(pContext->smartcard, SCardReleaseContext, pContext->hContext);
|
2014-05-12 11:28:20 -04:00
|
|
|
free(pContext);
|
|
|
|
|
}
|
|
|
|
|
|
2016-09-26 12:12:37 +02:00
|
|
|
static void smartcard_release_all_contexts(SMARTCARD_DEVICE* smartcard)
|
|
|
|
|
{
|
2014-04-05 17:15:17 -04:00
|
|
|
int index;
|
|
|
|
|
int keyCount;
|
|
|
|
|
ULONG_PTR* pKeys;
|
2014-05-06 17:42:10 -04:00
|
|
|
SCARDCONTEXT hContext;
|
2014-05-12 11:28:20 -04:00
|
|
|
SMARTCARD_CONTEXT* pContext;
|
2014-04-05 16:57:31 -04:00
|
|
|
|
2014-05-06 17:42:10 -04:00
|
|
|
/**
|
|
|
|
|
* On protocol termination, the following actions are performed:
|
2019-11-06 15:24:51 +01:00
|
|
|
* For each context in rgSCardContextList, SCardCancel is called causing all
|
|
|
|
|
* SCardGetStatusChange calls to be processed. After that, SCardReleaseContext is called on each
|
|
|
|
|
* context and the context MUST be removed from rgSCardContextList.
|
2014-05-06 17:42:10 -04:00
|
|
|
*/
|
|
|
|
|
|
2014-05-07 17:41:53 -04:00
|
|
|
/**
|
2015-07-17 16:37:44 +03:00
|
|
|
* Call SCardCancel on existing contexts, unblocking all outstanding SCardGetStatusChange calls.
|
2014-05-07 17:41:53 -04:00
|
|
|
*/
|
|
|
|
|
|
2021-01-21 10:10:44 +01:00
|
|
|
ListDictionary_Lock(smartcard->rgSCardContextList);
|
2014-05-06 17:42:10 -04:00
|
|
|
if (ListDictionary_Count(smartcard->rgSCardContextList) > 0)
|
|
|
|
|
{
|
|
|
|
|
pKeys = NULL;
|
|
|
|
|
keyCount = ListDictionary_GetKeys(smartcard->rgSCardContextList, &pKeys);
|
|
|
|
|
|
|
|
|
|
for (index = 0; index < keyCount; index++)
|
|
|
|
|
{
|
2019-11-06 15:24:51 +01:00
|
|
|
pContext = (SMARTCARD_CONTEXT*)ListDictionary_GetItemValue(
|
|
|
|
|
smartcard->rgSCardContextList, (void*)pKeys[index]);
|
2014-05-12 11:28:20 -04:00
|
|
|
|
|
|
|
|
if (!pContext)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
hContext = pContext->hContext;
|
2014-05-06 17:42:10 -04:00
|
|
|
|
2021-11-05 13:09:42 +01:00
|
|
|
if (wrap(smartcard, SCardIsValidContext, hContext) == SCARD_S_SUCCESS)
|
2014-05-07 17:41:53 -04:00
|
|
|
{
|
2021-11-05 13:09:42 +01:00
|
|
|
wrap(smartcard, SCardCancel, hContext);
|
2014-05-07 17:41:53 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
free(pKeys);
|
|
|
|
|
}
|
2021-01-21 10:10:44 +01:00
|
|
|
ListDictionary_Unlock(smartcard->rgSCardContextList);
|
|
|
|
|
|
|
|
|
|
/* Put thread to sleep so that PC/SC can process the cancel requests. This fixes a race
|
|
|
|
|
* condition that sometimes caused the pc/sc daemon to crash on MacOS (_xpc_api_misuse) */
|
2021-03-12 08:56:23 +01:00
|
|
|
SleepEx(100, FALSE);
|
2014-05-07 17:41:53 -04:00
|
|
|
|
|
|
|
|
/**
|
2014-05-08 15:24:33 -04:00
|
|
|
* Call SCardReleaseContext on remaining contexts and remove them from rgSCardContextList.
|
2014-05-07 17:41:53 -04:00
|
|
|
*/
|
|
|
|
|
|
2021-01-21 10:10:44 +01:00
|
|
|
ListDictionary_Lock(smartcard->rgSCardContextList);
|
2014-05-07 17:41:53 -04:00
|
|
|
if (ListDictionary_Count(smartcard->rgSCardContextList) > 0)
|
|
|
|
|
{
|
|
|
|
|
pKeys = NULL;
|
|
|
|
|
keyCount = ListDictionary_GetKeys(smartcard->rgSCardContextList, &pKeys);
|
|
|
|
|
|
|
|
|
|
for (index = 0; index < keyCount; index++)
|
|
|
|
|
{
|
2021-03-12 08:56:23 +01:00
|
|
|
ListDictionary_SetItemValue(smartcard->rgSCardContextList, (void*)pKeys[index], NULL);
|
2014-05-07 17:41:53 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
free(pKeys);
|
|
|
|
|
}
|
2021-01-21 10:10:44 +01:00
|
|
|
ListDictionary_Unlock(smartcard->rgSCardContextList);
|
2015-07-17 16:37:44 +03:00
|
|
|
}
|
|
|
|
|
|
2018-09-04 12:58:05 +02:00
|
|
|
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)
|
2021-11-05 13:09:42 +01:00
|
|
|
wrap(smartcard, SCardReleaseStartedEvent);
|
2015-07-30 07:29:12 -07:00
|
|
|
|
2021-11-05 13:09:42 +01:00
|
|
|
#if defined(WITH_SMARTCARD_EMULATE)
|
|
|
|
|
Emulate_Free(smartcard->emulation);
|
|
|
|
|
#endif
|
2018-09-04 12:58:05 +02:00
|
|
|
free(smartcard);
|
|
|
|
|
return CHANNEL_RC_OK;
|
|
|
|
|
}
|
2015-08-27 05:25:09 -07:00
|
|
|
/**
|
|
|
|
|
* Function description
|
|
|
|
|
*
|
|
|
|
|
* @return 0 on success, otherwise a Win32 error code
|
|
|
|
|
*/
|
|
|
|
|
static UINT smartcard_free(DEVICE* device)
|
2015-07-17 16:37:44 +03:00
|
|
|
{
|
2018-09-04 12:58:05 +02:00
|
|
|
SMARTCARD_DEVICE* smartcard = CAST_FROM_DEVICE(device);
|
|
|
|
|
|
|
|
|
|
if (!smartcard)
|
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
|
|
2015-07-17 16:37:44 +03:00
|
|
|
/**
|
|
|
|
|
* Calling smartcard_release_all_contexts to unblock all operations waiting for transactions
|
|
|
|
|
* to unlock.
|
|
|
|
|
*/
|
|
|
|
|
smartcard_release_all_contexts(smartcard);
|
|
|
|
|
|
|
|
|
|
/* Stopping all threads and cancelling all IRPs */
|
|
|
|
|
|
|
|
|
|
if (smartcard->IrpQueue)
|
|
|
|
|
{
|
2019-11-06 15:24:51 +01:00
|
|
|
if (MessageQueue_PostQuit(smartcard->IrpQueue, 0) &&
|
|
|
|
|
(WaitForSingleObject(smartcard->thread, INFINITE) == WAIT_FAILED))
|
2015-07-30 07:29:12 -07:00
|
|
|
{
|
2021-11-05 13:09:42 +01:00
|
|
|
DWORD error = GetLastError();
|
2019-11-06 15:24:51 +01:00
|
|
|
WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "!", error);
|
2015-07-30 07:29:12 -07:00
|
|
|
return error;
|
|
|
|
|
}
|
2015-07-17 16:37:44 +03:00
|
|
|
}
|
|
|
|
|
|
2018-09-04 12:58:05 +02:00
|
|
|
if (sSmartcard == smartcard)
|
|
|
|
|
sSmartcard = NULL;
|
2015-07-17 16:37:44 +03:00
|
|
|
|
2018-09-04 12:58:05 +02:00
|
|
|
return smartcard_free_(smartcard);
|
2015-07-17 16:37:44 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Initialization occurs when the protocol server sends a device announce message.
|
|
|
|
|
* At that time, we need to cancel all outstanding IRPs.
|
|
|
|
|
*/
|
|
|
|
|
|
2015-08-27 05:25:09 -07:00
|
|
|
/**
|
|
|
|
|
* Function description
|
|
|
|
|
*
|
|
|
|
|
* @return 0 on success, otherwise a Win32 error code
|
|
|
|
|
*/
|
|
|
|
|
static UINT smartcard_init(DEVICE* device)
|
2015-07-17 16:37:44 +03:00
|
|
|
{
|
2018-09-04 12:58:05 +02:00
|
|
|
SMARTCARD_DEVICE* smartcard = CAST_FROM_DEVICE(device);
|
|
|
|
|
|
|
|
|
|
if (!smartcard)
|
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
|
|
2015-07-17 16:37:44 +03:00
|
|
|
smartcard_release_all_contexts(smartcard);
|
2015-06-12 03:26:15 -07:00
|
|
|
return CHANNEL_RC_OK;
|
2014-04-05 16:57:31 -04:00
|
|
|
}
|
|
|
|
|
|
2015-08-27 05:25:09 -07:00
|
|
|
/**
|
|
|
|
|
* Function description
|
|
|
|
|
*
|
|
|
|
|
* @return 0 on success, otherwise a Win32 error code
|
|
|
|
|
*/
|
2018-09-04 12:58:05 +02:00
|
|
|
static UINT smartcard_complete_irp(SMARTCARD_DEVICE* smartcard, IRP* irp)
|
2014-04-05 16:57:31 -04:00
|
|
|
{
|
|
|
|
|
void* key;
|
2019-11-06 15:24:51 +01:00
|
|
|
key = (void*)(size_t)irp->CompletionId;
|
2014-05-06 17:42:10 -04:00
|
|
|
ListDictionary_Remove(smartcard->rgOutstandingMessages, key);
|
2015-07-03 04:09:03 -07:00
|
|
|
return irp->Complete(irp);
|
2014-04-05 16:57:31 -04:00
|
|
|
}
|
|
|
|
|
|
2014-04-05 16:06:46 -04:00
|
|
|
/**
|
|
|
|
|
* Multiple threads and SCardGetStatusChange:
|
|
|
|
|
* http://musclecard.996296.n3.nabble.com/Multiple-threads-and-SCardGetStatusChange-td4430.html
|
|
|
|
|
*/
|
|
|
|
|
|
2015-08-27 05:25:09 -07:00
|
|
|
/**
|
|
|
|
|
* Function description
|
|
|
|
|
*
|
|
|
|
|
* @return 0 on success, otherwise a Win32 error code
|
|
|
|
|
*/
|
2018-09-04 12:58:05 +02:00
|
|
|
static UINT smartcard_process_irp(SMARTCARD_DEVICE* smartcard, IRP* irp)
|
2014-04-05 17:51:13 -04:00
|
|
|
{
|
|
|
|
|
void* key;
|
2015-07-03 04:09:03 -07:00
|
|
|
LONG status;
|
2014-04-05 17:51:13 -04:00
|
|
|
BOOL asyncIrp = FALSE;
|
2014-05-12 17:05:20 -04:00
|
|
|
SMARTCARD_CONTEXT* pContext = NULL;
|
2014-05-12 15:47:49 -04:00
|
|
|
SMARTCARD_OPERATION* operation = NULL;
|
2019-11-06 15:24:51 +01:00
|
|
|
key = (void*)(size_t)irp->CompletionId;
|
2014-04-05 17:51:13 -04:00
|
|
|
|
2015-07-03 04:09:03 -07:00
|
|
|
if (!ListDictionary_Add(smartcard->rgOutstandingMessages, key, irp))
|
|
|
|
|
{
|
|
|
|
|
WLog_ERR(TAG, "ListDictionary_Add failed!");
|
|
|
|
|
return ERROR_INTERNAL_ERROR;
|
|
|
|
|
}
|
2014-04-05 17:51:13 -04:00
|
|
|
|
|
|
|
|
if (irp->MajorFunction == IRP_MJ_DEVICE_CONTROL)
|
|
|
|
|
{
|
2019-11-06 15:24:51 +01:00
|
|
|
operation = (SMARTCARD_OPERATION*)calloc(1, sizeof(SMARTCARD_OPERATION));
|
2014-05-12 15:47:49 -04:00
|
|
|
|
|
|
|
|
if (!operation)
|
2015-07-03 04:09:03 -07:00
|
|
|
{
|
|
|
|
|
WLog_ERR(TAG, "calloc failed!");
|
|
|
|
|
return CHANNEL_RC_NO_MEMORY;
|
|
|
|
|
}
|
2014-05-12 15:47:49 -04:00
|
|
|
|
|
|
|
|
operation->irp = irp;
|
|
|
|
|
status = smartcard_irp_device_control_decode(smartcard, operation);
|
|
|
|
|
|
|
|
|
|
if (status != SCARD_S_SUCCESS)
|
|
|
|
|
{
|
2015-07-03 04:09:03 -07:00
|
|
|
irp->IoStatus = (UINT32)STATUS_UNSUCCESSFUL;
|
2014-05-12 15:47:49 -04:00
|
|
|
|
2019-11-06 15:24:51 +01:00
|
|
|
if (!Queue_Enqueue(smartcard->CompletedIrpQueue, (void*)irp))
|
2015-07-03 04:09:03 -07:00
|
|
|
{
|
2018-08-17 14:19:19 +02:00
|
|
|
free(operation);
|
2015-07-03 04:09:03 -07:00
|
|
|
WLog_ERR(TAG, "Queue_Enqueue failed!");
|
|
|
|
|
return ERROR_INTERNAL_ERROR;
|
|
|
|
|
}
|
2014-04-05 17:51:13 -04:00
|
|
|
|
2018-08-17 14:19:19 +02:00
|
|
|
free(operation);
|
2015-07-03 04:09:03 -07:00
|
|
|
return CHANNEL_RC_OK;
|
2014-05-12 15:47:49 -04:00
|
|
|
}
|
2014-04-05 17:51:13 -04:00
|
|
|
|
2014-05-07 21:16:05 -04:00
|
|
|
asyncIrp = TRUE;
|
2014-05-03 13:49:50 -04:00
|
|
|
|
2014-05-12 15:47:49 -04:00
|
|
|
switch (operation->ioControlCode)
|
2014-05-07 21:16:05 -04:00
|
|
|
{
|
|
|
|
|
case SCARD_IOCTL_ESTABLISHCONTEXT:
|
|
|
|
|
case SCARD_IOCTL_RELEASECONTEXT:
|
|
|
|
|
case SCARD_IOCTL_ISVALIDCONTEXT:
|
2017-12-04 15:22:07 +01:00
|
|
|
case SCARD_IOCTL_CANCEL:
|
|
|
|
|
case SCARD_IOCTL_ACCESSSTARTEDEVENT:
|
2020-01-13 10:51:22 +01:00
|
|
|
case SCARD_IOCTL_RELEASETARTEDEVENT:
|
2017-12-04 15:22:07 +01:00
|
|
|
asyncIrp = FALSE;
|
|
|
|
|
break;
|
|
|
|
|
|
2014-05-07 21:16:05 -04:00
|
|
|
case SCARD_IOCTL_LISTREADERGROUPSA:
|
|
|
|
|
case SCARD_IOCTL_LISTREADERGROUPSW:
|
|
|
|
|
case SCARD_IOCTL_LISTREADERSA:
|
|
|
|
|
case SCARD_IOCTL_LISTREADERSW:
|
|
|
|
|
case SCARD_IOCTL_INTRODUCEREADERGROUPA:
|
|
|
|
|
case SCARD_IOCTL_INTRODUCEREADERGROUPW:
|
|
|
|
|
case SCARD_IOCTL_FORGETREADERGROUPA:
|
|
|
|
|
case SCARD_IOCTL_FORGETREADERGROUPW:
|
|
|
|
|
case SCARD_IOCTL_INTRODUCEREADERA:
|
|
|
|
|
case SCARD_IOCTL_INTRODUCEREADERW:
|
|
|
|
|
case SCARD_IOCTL_FORGETREADERA:
|
|
|
|
|
case SCARD_IOCTL_FORGETREADERW:
|
|
|
|
|
case SCARD_IOCTL_ADDREADERTOGROUPA:
|
|
|
|
|
case SCARD_IOCTL_ADDREADERTOGROUPW:
|
|
|
|
|
case SCARD_IOCTL_REMOVEREADERFROMGROUPA:
|
|
|
|
|
case SCARD_IOCTL_REMOVEREADERFROMGROUPW:
|
|
|
|
|
case SCARD_IOCTL_LOCATECARDSA:
|
|
|
|
|
case SCARD_IOCTL_LOCATECARDSW:
|
|
|
|
|
case SCARD_IOCTL_LOCATECARDSBYATRA:
|
|
|
|
|
case SCARD_IOCTL_LOCATECARDSBYATRW:
|
|
|
|
|
case SCARD_IOCTL_READCACHEA:
|
|
|
|
|
case SCARD_IOCTL_READCACHEW:
|
|
|
|
|
case SCARD_IOCTL_WRITECACHEA:
|
|
|
|
|
case SCARD_IOCTL_WRITECACHEW:
|
|
|
|
|
case SCARD_IOCTL_GETREADERICON:
|
|
|
|
|
case SCARD_IOCTL_GETDEVICETYPEID:
|
|
|
|
|
case SCARD_IOCTL_GETSTATUSCHANGEA:
|
|
|
|
|
case SCARD_IOCTL_GETSTATUSCHANGEW:
|
|
|
|
|
case SCARD_IOCTL_CONNECTA:
|
|
|
|
|
case SCARD_IOCTL_CONNECTW:
|
|
|
|
|
case SCARD_IOCTL_RECONNECT:
|
|
|
|
|
case SCARD_IOCTL_DISCONNECT:
|
|
|
|
|
case SCARD_IOCTL_BEGINTRANSACTION:
|
|
|
|
|
case SCARD_IOCTL_ENDTRANSACTION:
|
|
|
|
|
case SCARD_IOCTL_STATE:
|
|
|
|
|
case SCARD_IOCTL_STATUSA:
|
|
|
|
|
case SCARD_IOCTL_STATUSW:
|
|
|
|
|
case SCARD_IOCTL_TRANSMIT:
|
|
|
|
|
case SCARD_IOCTL_CONTROL:
|
|
|
|
|
case SCARD_IOCTL_GETATTRIB:
|
|
|
|
|
case SCARD_IOCTL_SETATTRIB:
|
|
|
|
|
case SCARD_IOCTL_GETTRANSMITCOUNT:
|
|
|
|
|
asyncIrp = TRUE;
|
|
|
|
|
break;
|
2014-04-05 17:51:13 -04:00
|
|
|
}
|
|
|
|
|
|
2019-11-06 15:24:51 +01:00
|
|
|
pContext =
|
|
|
|
|
ListDictionary_GetItemValue(smartcard->rgSCardContextList, (void*)operation->hContext);
|
2014-05-12 17:05:20 -04:00
|
|
|
|
|
|
|
|
if (!pContext)
|
|
|
|
|
asyncIrp = FALSE;
|
|
|
|
|
|
2014-05-12 15:32:02 -04:00
|
|
|
if (!asyncIrp)
|
|
|
|
|
{
|
2015-07-03 04:09:03 -07:00
|
|
|
if ((status = smartcard_irp_device_control_call(smartcard, operation)))
|
|
|
|
|
{
|
2021-04-27 10:04:47 +02:00
|
|
|
free(operation);
|
2019-11-06 15:24:51 +01:00
|
|
|
WLog_ERR(TAG, "smartcard_irp_device_control_call failed with error %" PRId32 "!",
|
2016-09-26 12:12:37 +02:00
|
|
|
status);
|
2015-07-03 04:09:03 -07:00
|
|
|
return (UINT32)status;
|
|
|
|
|
}
|
2016-09-26 12:12:37 +02:00
|
|
|
|
2019-11-06 15:24:51 +01:00
|
|
|
if (!Queue_Enqueue(smartcard->CompletedIrpQueue, (void*)irp))
|
2015-07-03 04:09:03 -07:00
|
|
|
{
|
2018-08-17 14:19:19 +02:00
|
|
|
free(operation);
|
2015-07-03 04:09:03 -07:00
|
|
|
WLog_ERR(TAG, "Queue_Enqueue failed!");
|
|
|
|
|
return ERROR_INTERNAL_ERROR;
|
|
|
|
|
}
|
2016-09-26 12:12:37 +02:00
|
|
|
|
2014-05-12 15:47:49 -04:00
|
|
|
free(operation);
|
2014-04-05 17:51:13 -04:00
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2014-05-12 17:05:20 -04:00
|
|
|
if (pContext)
|
|
|
|
|
{
|
2019-11-06 15:24:51 +01:00
|
|
|
if (!MessageQueue_Post(pContext->IrpQueue, NULL, 0, (void*)operation, NULL))
|
2015-07-03 04:09:03 -07:00
|
|
|
{
|
|
|
|
|
WLog_ERR(TAG, "MessageQueue_Post failed!");
|
|
|
|
|
return ERROR_INTERNAL_ERROR;
|
|
|
|
|
}
|
2014-05-12 17:05:20 -04:00
|
|
|
}
|
2014-04-05 17:51:13 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2016-09-26 12:12:37 +02:00
|
|
|
WLog_ERR(TAG,
|
2019-11-06 15:24:51 +01:00
|
|
|
"Unexpected SmartCard IRP: MajorFunction 0x%08" PRIX32
|
|
|
|
|
" MinorFunction: 0x%08" PRIX32 "",
|
2016-09-26 12:12:37 +02:00
|
|
|
irp->MajorFunction, irp->MinorFunction);
|
2015-07-03 04:09:03 -07:00
|
|
|
irp->IoStatus = (UINT32)STATUS_NOT_SUPPORTED;
|
2014-05-07 17:41:53 -04:00
|
|
|
|
2019-11-06 15:24:51 +01:00
|
|
|
if (!Queue_Enqueue(smartcard->CompletedIrpQueue, (void*)irp))
|
2015-07-03 04:09:03 -07:00
|
|
|
{
|
|
|
|
|
WLog_ERR(TAG, "Queue_Enqueue failed!");
|
|
|
|
|
return ERROR_INTERNAL_ERROR;
|
|
|
|
|
}
|
2014-04-05 17:51:13 -04:00
|
|
|
}
|
2016-09-26 12:12:37 +02:00
|
|
|
|
2015-07-03 04:09:03 -07:00
|
|
|
return CHANNEL_RC_OK;
|
2014-04-05 17:51:13 -04:00
|
|
|
}
|
|
|
|
|
|
2018-03-07 12:03:10 +01:00
|
|
|
static DWORD WINAPI smartcard_thread_func(LPVOID arg)
|
2011-10-15 10:30:10 -05:00
|
|
|
{
|
2012-09-23 13:54:14 -04:00
|
|
|
IRP* irp;
|
2014-05-07 17:41:53 -04:00
|
|
|
DWORD nCount;
|
|
|
|
|
DWORD status;
|
|
|
|
|
HANDLE hEvents[2];
|
2013-11-03 20:46:40 -05:00
|
|
|
wMessage message;
|
2015-08-27 05:25:09 -07:00
|
|
|
UINT error = CHANNEL_RC_OK;
|
2018-09-04 12:58:05 +02:00
|
|
|
SMARTCARD_DEVICE* smartcard = CAST_FROM_DEVICE(arg);
|
|
|
|
|
|
|
|
|
|
if (!smartcard)
|
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
|
|
2014-05-07 17:41:53 -04:00
|
|
|
nCount = 0;
|
|
|
|
|
hEvents[nCount++] = MessageQueue_Event(smartcard->IrpQueue);
|
|
|
|
|
hEvents[nCount++] = Queue_Event(smartcard->CompletedIrpQueue);
|
|
|
|
|
|
2012-11-21 12:53:54 -05:00
|
|
|
while (1)
|
2011-10-15 10:30:10 -05:00
|
|
|
{
|
2014-05-07 17:41:53 -04:00
|
|
|
status = WaitForMultipleObjects(nCount, hEvents, FALSE, INFINITE);
|
2012-11-21 12:53:54 -05:00
|
|
|
|
2015-09-01 12:27:54 +02:00
|
|
|
if (status == WAIT_FAILED)
|
|
|
|
|
{
|
|
|
|
|
error = GetLastError();
|
2019-11-06 15:24:51 +01:00
|
|
|
WLog_ERR(TAG, "WaitForMultipleObjects failed with error %" PRIu32 "!", error);
|
2015-09-01 12:27:54 +02:00
|
|
|
break;
|
|
|
|
|
}
|
2015-07-30 06:49:21 -07:00
|
|
|
|
2015-09-01 12:27:54 +02:00
|
|
|
status = WaitForSingleObject(MessageQueue_Event(smartcard->IrpQueue), 0);
|
2015-07-30 06:49:21 -07:00
|
|
|
|
2015-09-01 12:27:54 +02:00
|
|
|
if (status == WAIT_FAILED)
|
|
|
|
|
{
|
|
|
|
|
error = GetLastError();
|
2019-11-06 15:24:51 +01:00
|
|
|
WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "!", error);
|
2015-09-01 12:27:54 +02:00
|
|
|
break;
|
|
|
|
|
}
|
2015-07-30 06:49:21 -07:00
|
|
|
|
2015-09-01 12:27:54 +02:00
|
|
|
if (status == WAIT_OBJECT_0)
|
2014-05-07 17:41:53 -04:00
|
|
|
{
|
|
|
|
|
if (!MessageQueue_Peek(smartcard->IrpQueue, &message, TRUE))
|
2015-07-15 00:50:35 -07:00
|
|
|
{
|
|
|
|
|
WLog_ERR(TAG, "MessageQueue_Peek failed!");
|
|
|
|
|
error = ERROR_INTERNAL_ERROR;
|
2014-05-07 17:41:53 -04:00
|
|
|
break;
|
2015-07-15 00:50:35 -07:00
|
|
|
}
|
|
|
|
|
|
2014-05-07 17:41:53 -04:00
|
|
|
if (message.id == WMQ_QUIT)
|
2014-05-08 15:24:33 -04:00
|
|
|
{
|
2015-07-30 06:49:21 -07:00
|
|
|
while (1)
|
2014-05-08 15:24:33 -04:00
|
|
|
{
|
2015-09-01 12:27:54 +02:00
|
|
|
status = WaitForSingleObject(Queue_Event(smartcard->CompletedIrpQueue), 0);
|
2015-07-30 06:49:21 -07:00
|
|
|
|
2015-09-01 12:27:54 +02:00
|
|
|
if (status == WAIT_FAILED)
|
|
|
|
|
{
|
|
|
|
|
error = GetLastError();
|
2019-11-06 15:24:51 +01:00
|
|
|
WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "!", error);
|
2015-09-01 12:27:54 +02:00
|
|
|
goto out;
|
|
|
|
|
}
|
2015-07-30 06:49:21 -07:00
|
|
|
|
2015-09-01 12:27:54 +02:00
|
|
|
if (status == WAIT_TIMEOUT)
|
|
|
|
|
break;
|
2015-07-30 06:49:21 -07:00
|
|
|
|
2019-11-06 15:24:51 +01:00
|
|
|
irp = (IRP*)Queue_Dequeue(smartcard->CompletedIrpQueue);
|
2014-05-08 15:24:33 -04:00
|
|
|
|
|
|
|
|
if (irp)
|
|
|
|
|
{
|
|
|
|
|
if (irp->thread)
|
|
|
|
|
{
|
2015-07-30 06:49:21 -07:00
|
|
|
status = WaitForSingleObject(irp->thread, INFINITE);
|
|
|
|
|
|
2015-09-01 12:27:54 +02:00
|
|
|
if (status == WAIT_FAILED)
|
|
|
|
|
{
|
|
|
|
|
error = GetLastError();
|
2019-11-06 15:24:51 +01:00
|
|
|
WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "!",
|
|
|
|
|
error);
|
2015-09-01 12:27:54 +02:00
|
|
|
goto out;
|
|
|
|
|
}
|
2015-07-30 06:49:21 -07:00
|
|
|
|
2014-05-08 15:24:33 -04:00
|
|
|
CloseHandle(irp->thread);
|
2014-12-28 14:56:13 -05:00
|
|
|
irp->thread = NULL;
|
2014-05-08 15:24:33 -04:00
|
|
|
}
|
|
|
|
|
|
2015-07-03 04:09:03 -07:00
|
|
|
if ((error = smartcard_complete_irp(smartcard, irp)))
|
|
|
|
|
{
|
2019-11-06 15:24:51 +01:00
|
|
|
WLog_ERR(TAG, "smartcard_complete_irp failed with error %" PRIu32 "!",
|
|
|
|
|
error);
|
2015-07-03 04:09:03 -07:00
|
|
|
goto out;
|
|
|
|
|
}
|
2014-05-08 15:24:33 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-05-07 17:41:53 -04:00
|
|
|
break;
|
2014-05-08 15:24:33 -04:00
|
|
|
}
|
2012-11-21 11:56:40 -05:00
|
|
|
|
2019-11-06 15:24:51 +01:00
|
|
|
irp = (IRP*)message.wParam;
|
2012-08-01 17:05:45 -05:00
|
|
|
|
2014-05-07 17:41:53 -04:00
|
|
|
if (irp)
|
|
|
|
|
{
|
2015-07-03 04:09:03 -07:00
|
|
|
if ((error = smartcard_process_irp(smartcard, irp)))
|
|
|
|
|
{
|
2019-11-06 15:24:51 +01:00
|
|
|
WLog_ERR(TAG, "smartcard_process_irp failed with error %" PRIu32 "!", error);
|
2015-07-03 04:09:03 -07:00
|
|
|
goto out;
|
|
|
|
|
}
|
2014-05-07 17:41:53 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-09-01 12:27:54 +02:00
|
|
|
status = WaitForSingleObject(Queue_Event(smartcard->CompletedIrpQueue), 0);
|
2015-07-30 06:49:21 -07:00
|
|
|
|
2015-09-01 12:27:54 +02:00
|
|
|
if (status == WAIT_FAILED)
|
|
|
|
|
{
|
|
|
|
|
error = GetLastError();
|
2019-11-06 15:24:51 +01:00
|
|
|
WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "!", error);
|
2015-09-01 12:27:54 +02:00
|
|
|
break;
|
|
|
|
|
}
|
2015-07-30 06:49:21 -07:00
|
|
|
|
2015-09-01 12:27:54 +02:00
|
|
|
if (status == WAIT_OBJECT_0)
|
|
|
|
|
{
|
2019-11-06 15:24:51 +01:00
|
|
|
irp = (IRP*)Queue_Dequeue(smartcard->CompletedIrpQueue);
|
2014-05-07 17:41:53 -04:00
|
|
|
|
|
|
|
|
if (irp)
|
|
|
|
|
{
|
|
|
|
|
if (irp->thread)
|
|
|
|
|
{
|
2015-07-30 06:49:21 -07:00
|
|
|
status = WaitForSingleObject(irp->thread, INFINITE);
|
|
|
|
|
|
2015-09-01 12:27:54 +02:00
|
|
|
if (status == WAIT_FAILED)
|
|
|
|
|
{
|
|
|
|
|
error = GetLastError();
|
2019-11-06 15:24:51 +01:00
|
|
|
WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "!", error);
|
2015-09-01 12:27:54 +02:00
|
|
|
break;
|
|
|
|
|
}
|
2015-07-30 06:49:21 -07:00
|
|
|
|
2014-05-07 17:41:53 -04:00
|
|
|
CloseHandle(irp->thread);
|
2014-12-28 14:56:13 -05:00
|
|
|
irp->thread = NULL;
|
2014-05-07 17:41:53 -04:00
|
|
|
}
|
|
|
|
|
|
2015-07-03 04:09:03 -07:00
|
|
|
if ((error = smartcard_complete_irp(smartcard, irp)))
|
|
|
|
|
{
|
2016-09-01 11:34:38 -07:00
|
|
|
if (error == CHANNEL_RC_NOT_CONNECTED)
|
|
|
|
|
{
|
|
|
|
|
error = CHANNEL_RC_OK;
|
|
|
|
|
goto out;
|
|
|
|
|
}
|
2016-10-04 09:00:00 +02:00
|
|
|
|
2019-11-06 15:24:51 +01:00
|
|
|
WLog_ERR(TAG, "smartcard_complete_irp failed with error %" PRIu32 "!", error);
|
2015-07-03 04:09:03 -07:00
|
|
|
goto out;
|
|
|
|
|
}
|
2014-05-07 17:41:53 -04:00
|
|
|
}
|
|
|
|
|
}
|
2012-08-01 17:05:45 -05:00
|
|
|
}
|
2016-09-26 12:12:37 +02:00
|
|
|
|
2015-07-03 04:09:03 -07:00
|
|
|
out:
|
2016-09-26 12:12:37 +02:00
|
|
|
|
2015-07-15 00:50:35 -07:00
|
|
|
if (error && smartcard->rdpcontext)
|
2019-11-06 15:24:51 +01:00
|
|
|
setChannelError(smartcard->rdpcontext, error, "smartcard_thread_func reported an error");
|
2015-07-15 00:50:35 -07:00
|
|
|
|
2018-03-07 12:03:10 +01:00
|
|
|
ExitThread(error);
|
|
|
|
|
return error;
|
2012-08-01 17:05:45 -05:00
|
|
|
}
|
|
|
|
|
|
2015-08-27 05:25:09 -07:00
|
|
|
/**
|
|
|
|
|
* Function description
|
|
|
|
|
*
|
|
|
|
|
* @return 0 on success, otherwise a Win32 error code
|
|
|
|
|
*/
|
|
|
|
|
static UINT smartcard_irp_request(DEVICE* device, IRP* irp)
|
2011-10-15 10:30:10 -05:00
|
|
|
{
|
2018-09-04 12:58:05 +02:00
|
|
|
SMARTCARD_DEVICE* smartcard = CAST_FROM_DEVICE(device);
|
|
|
|
|
|
|
|
|
|
if (!smartcard)
|
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
2016-09-26 12:12:37 +02:00
|
|
|
|
2019-11-06 15:24:51 +01:00
|
|
|
if (!MessageQueue_Post(smartcard->IrpQueue, NULL, 0, (void*)irp, NULL))
|
2015-07-15 00:50:35 -07:00
|
|
|
{
|
|
|
|
|
WLog_ERR(TAG, "MessageQueue_Post failed!");
|
|
|
|
|
return ERROR_INTERNAL_ERROR;
|
|
|
|
|
}
|
2016-09-26 12:12:37 +02:00
|
|
|
|
2015-06-12 03:26:15 -07:00
|
|
|
return CHANNEL_RC_OK;
|
2011-10-15 10:30:10 -05:00
|
|
|
}
|
|
|
|
|
|
2014-04-05 20:05:51 -04:00
|
|
|
/* smartcard is always built-in */
|
2019-11-06 15:24:51 +01:00
|
|
|
#define DeviceServiceEntry smartcard_DeviceServiceEntry
|
2012-10-14 02:38:58 -04:00
|
|
|
|
2015-08-27 05:25:09 -07:00
|
|
|
/**
|
|
|
|
|
* Function description
|
|
|
|
|
*
|
|
|
|
|
* @return 0 on success, otherwise a Win32 error code
|
|
|
|
|
*/
|
2021-06-18 11:15:28 +02:00
|
|
|
extern UINT DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints);
|
2015-08-27 05:25:09 -07:00
|
|
|
UINT DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints)
|
2011-10-15 10:30:10 -05:00
|
|
|
{
|
2018-09-04 12:58:05 +02:00
|
|
|
SMARTCARD_DEVICE* smartcard = NULL;
|
2015-07-03 04:09:03 -07:00
|
|
|
size_t length;
|
2015-08-27 05:25:09 -07:00
|
|
|
UINT error = CHANNEL_RC_NO_MEMORY;
|
2016-09-26 12:12:37 +02:00
|
|
|
|
2018-09-04 12:58:05 +02:00
|
|
|
if (!sSmartcard)
|
2015-07-03 04:09:03 -07:00
|
|
|
{
|
2018-09-04 12:58:05 +02:00
|
|
|
wObject* obj;
|
2019-11-06 15:24:51 +01:00
|
|
|
smartcard = (SMARTCARD_DEVICE*)calloc(1, sizeof(SMARTCARD_DEVICE));
|
2011-10-15 10:30:10 -05:00
|
|
|
|
2018-09-04 12:58:05 +02:00
|
|
|
if (!smartcard)
|
|
|
|
|
{
|
|
|
|
|
WLog_ERR(TAG, "calloc failed!");
|
|
|
|
|
return CHANNEL_RC_NO_MEMORY;
|
|
|
|
|
}
|
2016-09-26 12:12:37 +02:00
|
|
|
|
2018-09-04 12:58:05 +02:00
|
|
|
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;
|
|
|
|
|
}
|
2011-10-15 10:30:10 -05:00
|
|
|
|
2018-09-04 12:58:05 +02:00
|
|
|
Stream_Write(smartcard->device.data, "SCARD", 6);
|
|
|
|
|
smartcard->IrpQueue = MessageQueue_New(NULL);
|
2016-09-26 12:12:37 +02:00
|
|
|
|
2018-09-04 12:58:05 +02:00
|
|
|
if (!smartcard->IrpQueue)
|
|
|
|
|
{
|
|
|
|
|
WLog_ERR(TAG, "MessageQueue_New failed!");
|
|
|
|
|
goto fail;
|
|
|
|
|
}
|
2015-07-03 04:09:03 -07:00
|
|
|
|
2018-09-04 12:58:05 +02:00
|
|
|
smartcard->CompletedIrpQueue = Queue_New(TRUE, -1, -1);
|
2016-09-26 12:12:37 +02:00
|
|
|
|
2018-09-04 12:58:05 +02:00
|
|
|
if (!smartcard->CompletedIrpQueue)
|
|
|
|
|
{
|
|
|
|
|
WLog_ERR(TAG, "Queue_New failed!");
|
|
|
|
|
goto fail;
|
|
|
|
|
}
|
2014-12-28 14:56:13 -05:00
|
|
|
|
2018-09-04 12:58:05 +02:00
|
|
|
smartcard->rgSCardContextList = ListDictionary_New(TRUE);
|
2016-09-26 12:12:37 +02:00
|
|
|
|
2018-09-04 12:58:05 +02:00
|
|
|
if (!smartcard->rgSCardContextList)
|
|
|
|
|
{
|
|
|
|
|
WLog_ERR(TAG, "ListDictionary_New failed!");
|
|
|
|
|
goto fail;
|
|
|
|
|
}
|
2014-12-28 14:56:13 -05:00
|
|
|
|
2018-09-04 12:58:05 +02:00
|
|
|
obj = ListDictionary_ValueObject(smartcard->rgSCardContextList);
|
|
|
|
|
obj->fnObjectFree = smartcard_context_free;
|
|
|
|
|
smartcard->rgOutstandingMessages = ListDictionary_New(TRUE);
|
2016-09-26 12:12:37 +02:00
|
|
|
|
2018-09-04 12:58:05 +02:00
|
|
|
if (!smartcard->rgOutstandingMessages)
|
|
|
|
|
{
|
|
|
|
|
WLog_ERR(TAG, "ListDictionary_New failed!");
|
|
|
|
|
goto fail;
|
|
|
|
|
}
|
2015-07-03 04:09:03 -07:00
|
|
|
|
2021-11-05 13:09:42 +01:00
|
|
|
#if defined(WITH_SMARTCARD_EMULATE)
|
|
|
|
|
smartcard->emulation = Emulate_New(smartcard->rdpcontext->settings);
|
|
|
|
|
if (!smartcard->emulation)
|
|
|
|
|
goto fail;
|
|
|
|
|
#endif
|
2018-09-04 12:58:05 +02:00
|
|
|
if ((error = pEntryPoints->RegisterDevice(pEntryPoints->devman, &smartcard->device)))
|
|
|
|
|
{
|
|
|
|
|
WLog_ERR(TAG, "RegisterDevice failed!");
|
|
|
|
|
goto fail;
|
|
|
|
|
}
|
2015-07-03 04:09:03 -07:00
|
|
|
|
2019-11-06 15:24:51 +01:00
|
|
|
smartcard->thread =
|
|
|
|
|
CreateThread(NULL, 0, smartcard_thread_func, smartcard, CREATE_SUSPENDED, NULL);
|
2014-04-05 16:57:31 -04:00
|
|
|
|
2018-09-04 12:58:05 +02:00
|
|
|
if (!smartcard->thread)
|
|
|
|
|
{
|
|
|
|
|
WLog_ERR(TAG, "ListDictionary_New failed!");
|
|
|
|
|
error = ERROR_INTERNAL_ERROR;
|
|
|
|
|
goto fail;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ResumeThread(smartcard->thread);
|
2015-07-03 04:09:03 -07:00
|
|
|
}
|
2018-09-04 12:58:05 +02:00
|
|
|
else
|
|
|
|
|
smartcard = sSmartcard;
|
2011-10-15 10:30:10 -05:00
|
|
|
|
2018-09-19 11:13:02 +02:00
|
|
|
if (pEntryPoints->device->Name)
|
|
|
|
|
LinkedList_AddLast(smartcard->names, pEntryPoints->device->Name);
|
|
|
|
|
|
2018-09-04 12:58:05 +02:00
|
|
|
sSmartcard = smartcard;
|
2015-07-03 04:09:03 -07:00
|
|
|
return CHANNEL_RC_OK;
|
2018-09-04 12:58:05 +02:00
|
|
|
fail:
|
|
|
|
|
smartcard_free_(smartcard);
|
2015-07-03 04:09:03 -07:00
|
|
|
return error;
|
2011-10-15 10:30:10 -05:00
|
|
|
}
|