25#include <freerdp/config.h>
28#include <winpr/smartcard.h>
29#include <winpr/environment.h>
31#include <freerdp/freerdp.h>
32#include <freerdp/channels/rdpdr.h>
33#include <freerdp/channels/scard.h>
34#include <freerdp/utils/smartcard_call.h>
35#include <freerdp/utils/smartcard_operations.h>
36#include <freerdp/utils/rdpdr_utils.h>
38#include "smartcard_main.h"
40#define CAST_FROM_DEVICE(device) cast_device_from(device, __func__, __FILE__, __LINE__)
46} scard_irp_queue_element;
48static void smartcard_context_free(
void* pCtx);
50static UINT smartcard_complete_irp(
SMARTCARD_DEVICE* smartcard, IRP* irp, BOOL* handled);
52static SMARTCARD_DEVICE* cast_device_from(DEVICE* device,
const char* fkt,
const char* file,
57 WLog_ERR(TAG,
"%s [%s:%" PRIuz
"] Called smartcard channel with nullptr device", fkt, file,
62 if (device->type != RDPDR_DTYP_SMARTCARD)
65 "%s [%s:%" PRIuz
"] Called smartcard channel with invalid device of type %" PRIx32,
66 fkt, file, line, device->type);
73static DWORD WINAPI smartcard_context_thread(LPVOID arg)
78 HANDLE hEvents[2] = WINPR_C_ARRAY_INIT;
79 wMessage message = WINPR_C_ARRAY_INIT;
81 UINT error = CHANNEL_RC_OK;
82 smartcard = pContext->smartcard;
84 hEvents[nCount++] = MessageQueue_Event(pContext->IrpQueue);
88 waitStatus = WaitForMultipleObjects(nCount, hEvents, FALSE, INFINITE);
90 if (waitStatus == WAIT_FAILED)
92 error = GetLastError();
93 WLog_ERR(TAG,
"WaitForMultipleObjects failed with error %" PRIu32
"!", error);
97 waitStatus = WaitForSingleObject(MessageQueue_Event(pContext->IrpQueue), 0);
99 if (waitStatus == WAIT_FAILED)
101 error = GetLastError();
102 WLog_ERR(TAG,
"WaitForSingleObject failed with error %" PRIu32
"!", error);
106 if (waitStatus == WAIT_OBJECT_0)
108 scard_irp_queue_element* element =
nullptr;
110 if (!MessageQueue_Peek(pContext->IrpQueue, &message, TRUE))
112 WLog_ERR(TAG,
"MessageQueue_Peek failed!");
113 error = ERROR_INTERNAL_ERROR;
117 if (message.id == WMQ_QUIT)
120 element = (scard_irp_queue_element*)message.wParam;
124 BOOL handled = FALSE;
125 WINPR_ASSERT(smartcard);
128 smartcard_irp_device_control_call(smartcard->callctx, element->irp->output,
129 &element->irp->IoStatus, &element->operation);
132 element->irp->Discard(element->irp);
133 smartcard_operation_free(&element->operation, TRUE);
135 "smartcard_irp_device_control_call failed with error %s [%" PRId32
"]",
136 NtStatus2Tag(status), status);
137 error = (UINT)status;
141 error = smartcard_complete_irp(smartcard, element->irp, &handled);
143 element->irp->Discard(element->irp);
144 smartcard_operation_free(&element->operation, TRUE);
148 WLog_ERR(TAG,
"smartcard_complete_irp failed with %s [%" PRIu32
"]",
149 WTSErrorToString(error), error);
156 if (error && smartcard->rdpcontext)
157 setChannelError(smartcard->rdpcontext, error,
"smartcard_context_thread reported an error");
163static void smartcard_operation_queue_free(
void* obj)
171 scard_irp_queue_element* element = (scard_irp_queue_element*)msg->wParam;
174 WINPR_ASSERT(element->irp);
175 WINPR_ASSERT(element->irp->Discard);
176 element->irp->Discard(element->irp);
177 smartcard_operation_free(&element->operation, TRUE);
180static void* smartcard_context_new(
void* smartcard, SCARDCONTEXT hContext)
184 WLog_VRB(TAG,
"smartcard context create %p", (
const void*)pContext);
187 WLog_ERR(TAG,
"calloc failed!");
191 pContext->smartcard = smartcard;
192 pContext->hContext = hContext;
193 pContext->IrpQueue = MessageQueue_New(
nullptr);
195 if (!pContext->IrpQueue)
197 WLog_ERR(TAG,
"MessageQueue_New failed!");
202 wObject* obj = MessageQueue_Object(pContext->IrpQueue);
207 pContext->thread = CreateThread(
nullptr, 0, smartcard_context_thread, pContext, 0,
nullptr);
209 if (!pContext->thread)
211 WLog_ERR(TAG,
"CreateThread failed!");
217 smartcard_context_free(pContext);
221void smartcard_context_free(
void* pCtx)
225 WLog_VRB(TAG,
"smartcard context destroy %p", pCtx);
230 WINPR_ASSERT(pContext->smartcard);
231 smartcard_call_cancel_context(pContext->smartcard->callctx, pContext->hContext);
233 if (pContext->IrpQueue)
235 if (MessageQueue_PostQuit(pContext->IrpQueue, 0))
237 if (WaitForSingleObject(pContext->thread, INFINITE) == WAIT_FAILED)
238 WLog_ERR(TAG,
"WaitForSingleObject failed with error %" PRIu32
"!", GetLastError());
240 (void)CloseHandle(pContext->thread);
242 MessageQueue_Free(pContext->IrpQueue);
244 smartcard_call_release_context(pContext->smartcard->callctx, pContext->hContext);
251 return CHANNEL_RC_OK;
253 if (smartcard->IrpQueue)
255 MessageQueue_Free(smartcard->IrpQueue);
256 (void)CloseHandle(smartcard->thread);
259 Stream_Free(smartcard->device.data, TRUE);
260 ListDictionary_Free(smartcard->rgOutstandingMessages);
262 smartcard_call_context_free(smartcard->callctx);
265 return CHANNEL_RC_OK;
272static UINT smartcard_free(DEVICE* device)
276 WLog_VRB(TAG,
"smartcard device destroy: %p", (
const void*)smartcard);
278 return ERROR_INVALID_PARAMETER;
284 smartcard_call_cancel_all_context(smartcard->callctx);
288 if (smartcard->IrpQueue)
290 if (MessageQueue_PostQuit(smartcard->IrpQueue, 0) &&
291 (WaitForSingleObject(smartcard->thread, INFINITE) == WAIT_FAILED))
293 DWORD error = GetLastError();
294 WLog_ERR(TAG,
"WaitForSingleObject failed with error %" PRIu32
"!", error);
299 return smartcard_free_(smartcard);
312static UINT smartcard_init(DEVICE* device)
316 WLog_VRB(TAG,
"smartcard device init %p", (
const void*)smartcard);
318 return ERROR_INVALID_PARAMETER;
320 return CHANNEL_RC_OK;
328UINT smartcard_complete_irp(
SMARTCARD_DEVICE* smartcard, IRP* irp, BOOL* handled)
330 WINPR_ASSERT(smartcard);
332 WINPR_ASSERT(handled);
334 uintptr_t key = (uintptr_t)irp->CompletionId + 1;
335 ListDictionary_Remove(smartcard->rgOutstandingMessages, (
void*)key);
337 WINPR_ASSERT(irp->Complete);
339 return irp->Complete(irp);
352static UINT smartcard_process_irp(
SMARTCARD_DEVICE* smartcard, IRP* irp, BOOL* handled)
355 BOOL asyncIrp = FALSE;
358 WINPR_ASSERT(smartcard);
359 WINPR_ASSERT(handled);
361 WINPR_ASSERT(irp->Complete);
363 uintptr_t key = (uintptr_t)irp->CompletionId + 1;
365 if (!ListDictionary_Add(smartcard->rgOutstandingMessages, (
void*)key, irp))
367 WLog_ERR(TAG,
"ListDictionary_Add failed!");
368 return ERROR_INTERNAL_ERROR;
371 if (irp->MajorFunction == IRP_MJ_DEVICE_CONTROL)
373 scard_irp_queue_element* element = calloc(1,
sizeof(scard_irp_queue_element));
375 return ERROR_OUTOFMEMORY;
378 element->operation.completionID = irp->CompletionId;
380 status = smartcard_irp_device_control_decode(irp->input, irp->CompletionId, irp->FileId,
381 &element->operation);
383 if (status != SCARD_S_SUCCESS)
387 smartcard_operation_free(&element->operation, TRUE);
388 irp->IoStatus = STATUS_UNSUCCESSFUL;
390 if ((error = smartcard_complete_irp(smartcard, irp, handled)))
392 WLog_ERR(TAG,
"Queue_Enqueue failed!");
396 return CHANNEL_RC_OK;
401 switch (element->operation.ioControlCode)
403 case SCARD_IOCTL_ESTABLISHCONTEXT:
404 case SCARD_IOCTL_RELEASECONTEXT:
405 case SCARD_IOCTL_ISVALIDCONTEXT:
406 case SCARD_IOCTL_CANCEL:
407 case SCARD_IOCTL_ACCESSSTARTEDEVENT:
408 case SCARD_IOCTL_RELEASETARTEDEVENT:
412 case SCARD_IOCTL_LISTREADERGROUPSA:
413 case SCARD_IOCTL_LISTREADERGROUPSW:
414 case SCARD_IOCTL_LISTREADERSA:
415 case SCARD_IOCTL_LISTREADERSW:
416 case SCARD_IOCTL_INTRODUCEREADERGROUPA:
417 case SCARD_IOCTL_INTRODUCEREADERGROUPW:
418 case SCARD_IOCTL_FORGETREADERGROUPA:
419 case SCARD_IOCTL_FORGETREADERGROUPW:
420 case SCARD_IOCTL_INTRODUCEREADERA:
421 case SCARD_IOCTL_INTRODUCEREADERW:
422 case SCARD_IOCTL_FORGETREADERA:
423 case SCARD_IOCTL_FORGETREADERW:
424 case SCARD_IOCTL_ADDREADERTOGROUPA:
425 case SCARD_IOCTL_ADDREADERTOGROUPW:
426 case SCARD_IOCTL_REMOVEREADERFROMGROUPA:
427 case SCARD_IOCTL_REMOVEREADERFROMGROUPW:
428 case SCARD_IOCTL_LOCATECARDSA:
429 case SCARD_IOCTL_LOCATECARDSW:
430 case SCARD_IOCTL_LOCATECARDSBYATRA:
431 case SCARD_IOCTL_LOCATECARDSBYATRW:
432 case SCARD_IOCTL_READCACHEA:
433 case SCARD_IOCTL_READCACHEW:
434 case SCARD_IOCTL_WRITECACHEA:
435 case SCARD_IOCTL_WRITECACHEW:
436 case SCARD_IOCTL_GETREADERICON:
437 case SCARD_IOCTL_GETDEVICETYPEID:
438 case SCARD_IOCTL_GETSTATUSCHANGEA:
439 case SCARD_IOCTL_GETSTATUSCHANGEW:
440 case SCARD_IOCTL_CONNECTA:
441 case SCARD_IOCTL_CONNECTW:
442 case SCARD_IOCTL_RECONNECT:
443 case SCARD_IOCTL_DISCONNECT:
444 case SCARD_IOCTL_BEGINTRANSACTION:
445 case SCARD_IOCTL_ENDTRANSACTION:
446 case SCARD_IOCTL_STATE:
447 case SCARD_IOCTL_STATUSA:
448 case SCARD_IOCTL_STATUSW:
449 case SCARD_IOCTL_TRANSMIT:
450 case SCARD_IOCTL_CONTROL:
451 case SCARD_IOCTL_GETATTRIB:
452 case SCARD_IOCTL_SETATTRIB:
453 case SCARD_IOCTL_GETTRANSMITCOUNT:
460 pContext = smartcard_call_get_context(smartcard->callctx, element->operation.hContext);
470 smartcard_irp_device_control_call(smartcard->callctx, element->irp->output,
471 &element->irp->IoStatus, &element->operation);
472 smartcard_operation_free(&element->operation, TRUE);
476 WLog_ERR(TAG,
"smartcard_irp_device_control_call failed with error %" PRId32
"!",
478 return (UINT32)status;
481 if ((error = smartcard_complete_irp(smartcard, irp, handled)))
483 WLog_ERR(TAG,
"Queue_Enqueue failed!");
491 if (!MessageQueue_Post(pContext->IrpQueue,
nullptr, 0, (
void*)element,
nullptr))
493 smartcard_operation_free(&element->operation, TRUE);
494 WLog_ERR(TAG,
"MessageQueue_Post failed!");
495 return ERROR_INTERNAL_ERROR;
504 WLog_ERR(TAG,
"Unexpected SmartCard IRP: MajorFunction %s, MinorFunction: 0x%08" PRIX32
"",
505 rdpdr_irp_string(irp->MajorFunction), irp->MinorFunction);
506 irp->IoStatus = STATUS_NOT_SUPPORTED;
508 if ((ustatus = smartcard_complete_irp(smartcard, irp, handled)))
510 WLog_ERR(TAG,
"Queue_Enqueue failed!");
515 return CHANNEL_RC_OK;
518static DWORD WINAPI smartcard_thread_func(LPVOID arg)
523 HANDLE hEvents[1] = WINPR_C_ARRAY_INIT;
524 wMessage message = WINPR_C_ARRAY_INIT;
525 UINT error = CHANNEL_RC_OK;
529 return ERROR_INVALID_PARAMETER;
531 hEvents[nCount++] = MessageQueue_Event(smartcard->IrpQueue);
535 status = WaitForMultipleObjects(nCount, hEvents, FALSE, INFINITE);
537 if (status == WAIT_FAILED)
539 error = GetLastError();
540 WLog_ERR(TAG,
"WaitForMultipleObjects failed with error %" PRIu32
"!", error);
544 if (status == WAIT_OBJECT_0)
546 if (!MessageQueue_Peek(smartcard->IrpQueue, &message, TRUE))
548 WLog_ERR(TAG,
"MessageQueue_Peek failed!");
549 error = ERROR_INTERNAL_ERROR;
553 if (message.id == WMQ_QUIT)
556 irp = (IRP*)message.wParam;
560 BOOL handled = FALSE;
561 if ((error = smartcard_process_irp(smartcard, irp, &handled)))
563 WLog_ERR(TAG,
"smartcard_process_irp failed with error %" PRIu32
"!", error);
568 WINPR_ASSERT(irp->Discard);
577 if (error && smartcard->rdpcontext)
578 setChannelError(smartcard->rdpcontext, error,
"smartcard_thread_func reported an error");
589static UINT smartcard_irp_request(DEVICE* device, IRP* irp)
596 return ERROR_INVALID_PARAMETER;
599 if (!MessageQueue_Post(smartcard->IrpQueue,
nullptr, 0, (
void*)irp,
nullptr))
601 WLog_ERR(TAG,
"MessageQueue_Post failed!");
603 return ERROR_INTERNAL_ERROR;
606 return CHANNEL_RC_OK;
609static void smartcard_free_irp(
void* obj)
617 IRP* irp = (IRP*)msg->wParam;
620 WINPR_ASSERT(irp->Discard);
625#define DeviceServiceEntry smartcard_DeviceServiceEntry
635 UINT error = CHANNEL_RC_NO_MEMORY;
638 WLog_VRB(TAG,
"smartcard device create: %p", (
const void*)smartcard);
641 WLog_ERR(TAG,
"calloc failed!");
642 return CHANNEL_RC_NO_MEMORY;
645 smartcard->device.type = RDPDR_DTYP_SMARTCARD;
646 smartcard->device.name =
"SCARD";
647 smartcard->device.IRPRequest = smartcard_irp_request;
648 smartcard->device.Init = smartcard_init;
649 smartcard->device.Free = smartcard_free;
650 smartcard->rdpcontext = pEntryPoints->rdpcontext;
651 length = strlen(smartcard->device.name);
652 smartcard->device.data = Stream_New(
nullptr, length + 1);
654 if (!smartcard->device.data)
656 WLog_ERR(TAG,
"Stream_New failed!");
660 Stream_Write(smartcard->device.data,
"SCARD", 6);
661 smartcard->IrpQueue = MessageQueue_New(
nullptr);
663 if (!smartcard->IrpQueue)
665 WLog_ERR(TAG,
"MessageQueue_New failed!");
669 wObject* obj = MessageQueue_Object(smartcard->IrpQueue);
673 smartcard->rgOutstandingMessages = ListDictionary_New(TRUE);
675 if (!smartcard->rgOutstandingMessages)
677 WLog_ERR(TAG,
"ListDictionary_New failed!");
681 smartcard->callctx = smartcard_call_context_new(smartcard->rdpcontext->settings);
682 if (!smartcard->callctx)
685 if (!smarcard_call_set_callbacks(smartcard->callctx, smartcard, smartcard_context_new,
686 smartcard_context_free))
689 if ((error = pEntryPoints->RegisterDevice(pEntryPoints->devman, &smartcard->device)))
691 WLog_ERR(TAG,
"RegisterDevice failed!");
696 CreateThread(
nullptr, 0, smartcard_thread_func, smartcard, CREATE_SUSPENDED,
nullptr);
698 if (!smartcard->thread)
700 WLog_ERR(TAG,
"CreateThread failed!");
701 error = ERROR_INTERNAL_ERROR;
705 ResumeThread(smartcard->thread);
707 if (pEntryPoints->device->Name)
709 if (!smartcard_call_context_add(smartcard->callctx, pEntryPoints->device->Name))
713 return CHANNEL_RC_OK;
715 smartcard_free_(smartcard);
This struct contains function pointer to initialize/free objects.
OBJECT_FREE_FN fnObjectFree