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 smartcard_context_queue_loop(
SMARTCARD_CONTEXT* pContext, wMessageQueue* queue)
77 HANDLE hEvents[2] = WINPR_C_ARRAY_INIT;
78 wMessage message = WINPR_C_ARRAY_INIT;
80 UINT error = CHANNEL_RC_OK;
81 smartcard = pContext->smartcard;
83 hEvents[nCount++] = MessageQueue_Event(queue);
87 waitStatus = WaitForMultipleObjects(nCount, hEvents, FALSE, INFINITE);
89 if (waitStatus == WAIT_FAILED)
91 error = GetLastError();
92 WLog_ERR(TAG,
"WaitForMultipleObjects failed with error %" PRIu32
"!", error);
96 waitStatus = WaitForSingleObject(MessageQueue_Event(queue), 0);
98 if (waitStatus == WAIT_FAILED)
100 error = GetLastError();
101 WLog_ERR(TAG,
"WaitForSingleObject failed with error %" PRIu32
"!", error);
105 if (waitStatus == WAIT_OBJECT_0)
107 scard_irp_queue_element* element =
nullptr;
109 if (!MessageQueue_Peek(queue, &message, TRUE))
111 WLog_ERR(TAG,
"MessageQueue_Peek failed!");
112 error = ERROR_INTERNAL_ERROR;
116 if (message.id == WMQ_QUIT)
119 element = (scard_irp_queue_element*)message.wParam;
123 BOOL handled = FALSE;
124 WINPR_ASSERT(smartcard);
127 smartcard_irp_device_control_call(smartcard->callctx, element->irp->output,
128 &element->irp->IoStatus, &element->operation);
131 element->irp->Discard(element->irp);
132 smartcard_operation_free(&element->operation, TRUE);
134 "smartcard_irp_device_control_call failed with error %s [%" PRId32
"]",
135 NtStatus2Tag(status), status);
136 error = (UINT)status;
140 error = smartcard_complete_irp(smartcard, element->irp, &handled);
142 element->irp->Discard(element->irp);
143 smartcard_operation_free(&element->operation, TRUE);
147 WLog_ERR(TAG,
"smartcard_complete_irp failed with %s [%" PRIu32
"]",
148 WTSErrorToString(error), error);
155 if (error && smartcard->rdpcontext)
156 setChannelError(smartcard->rdpcontext, error,
"smartcard_context_thread reported an error");
161static DWORD WINAPI smartcard_context_thread(LPVOID arg)
164 const DWORD error = smartcard_context_queue_loop(pContext, pContext->IrpQueue);
169static DWORD WINAPI smartcard_context_tx_thread(LPVOID arg)
172 const DWORD error = smartcard_context_queue_loop(pContext, pContext->TxQueue);
177static void smartcard_operation_queue_free(
void* obj)
185 scard_irp_queue_element* element = (scard_irp_queue_element*)msg->wParam;
188 WINPR_ASSERT(element->irp);
189 WINPR_ASSERT(element->irp->Discard);
190 element->irp->Discard(element->irp);
191 smartcard_operation_free(&element->operation, TRUE);
194static void* smartcard_context_new(
void* smartcard, SCARDCONTEXT hContext)
198 WLog_VRB(TAG,
"smartcard context create %p", (
const void*)pContext);
201 WLog_ERR(TAG,
"calloc failed!");
205 pContext->smartcard = smartcard;
206 pContext->hContext = hContext;
207 pContext->IrpQueue = MessageQueue_New(
nullptr);
209 if (!pContext->IrpQueue)
211 WLog_ERR(TAG,
"MessageQueue_New failed!");
216 wObject* obj = MessageQueue_Object(pContext->IrpQueue);
221 pContext->thread = CreateThread(
nullptr, 0, smartcard_context_thread, pContext, 0,
nullptr);
223 if (!pContext->thread)
225 WLog_ERR(TAG,
"CreateThread failed!");
229 pContext->TxQueue = MessageQueue_New(
nullptr);
231 if (!pContext->TxQueue)
233 WLog_ERR(TAG,
"MessageQueue_New failed!");
238 wObject* obj = MessageQueue_Object(pContext->TxQueue);
244 CreateThread(
nullptr, 0, smartcard_context_tx_thread, pContext, 0,
nullptr);
246 if (!pContext->txThread)
248 WLog_ERR(TAG,
"CreateThread failed!");
254 smartcard_context_free(pContext);
258void smartcard_context_free(
void* pCtx)
262 WLog_VRB(TAG,
"smartcard context destroy %p", pCtx);
267 WINPR_ASSERT(pContext->smartcard);
268 smartcard_call_cancel_context(pContext->smartcard->callctx, pContext->hContext);
270 if (pContext->IrpQueue)
272 if (MessageQueue_PostQuit(pContext->IrpQueue, 0))
274 if (WaitForSingleObject(pContext->thread, INFINITE) == WAIT_FAILED)
275 WLog_ERR(TAG,
"WaitForSingleObject failed with error %" PRIu32
"!", GetLastError());
277 (void)CloseHandle(pContext->thread);
279 MessageQueue_Free(pContext->IrpQueue);
281 if (pContext->TxQueue)
283 if (pContext->txThread && MessageQueue_PostQuit(pContext->TxQueue, 0))
285 if (WaitForSingleObject(pContext->txThread, INFINITE) == WAIT_FAILED)
286 WLog_ERR(TAG,
"WaitForSingleObject failed with error %" PRIu32
"!", GetLastError());
288 (void)CloseHandle(pContext->txThread);
290 MessageQueue_Free(pContext->TxQueue);
292 smartcard_call_release_context(pContext->smartcard->callctx, pContext->hContext);
299 return CHANNEL_RC_OK;
301 if (smartcard->IrpQueue)
303 MessageQueue_Free(smartcard->IrpQueue);
304 (void)CloseHandle(smartcard->thread);
307 Stream_Free(smartcard->device.data, TRUE);
308 ListDictionary_Free(smartcard->rgOutstandingMessages);
310 smartcard_call_context_free(smartcard->callctx);
313 return CHANNEL_RC_OK;
320static UINT smartcard_free(DEVICE* device)
324 WLog_VRB(TAG,
"smartcard device destroy: %p", (
const void*)smartcard);
326 return ERROR_INVALID_PARAMETER;
332 smartcard_call_cancel_all_context(smartcard->callctx);
336 if (smartcard->IrpQueue)
338 if (MessageQueue_PostQuit(smartcard->IrpQueue, 0) &&
339 (WaitForSingleObject(smartcard->thread, INFINITE) == WAIT_FAILED))
341 DWORD error = GetLastError();
342 WLog_ERR(TAG,
"WaitForSingleObject failed with error %" PRIu32
"!", error);
347 return smartcard_free_(smartcard);
360static UINT smartcard_init(DEVICE* device)
364 WLog_VRB(TAG,
"smartcard device init %p", (
const void*)smartcard);
366 return ERROR_INVALID_PARAMETER;
368 smartcard_call_cancel_all_context(smartcard->callctx);
369 return CHANNEL_RC_OK;
377UINT smartcard_complete_irp(
SMARTCARD_DEVICE* smartcard, IRP* irp, BOOL* handled)
379 WINPR_ASSERT(smartcard);
381 WINPR_ASSERT(handled);
383 uintptr_t key = (uintptr_t)irp->CompletionId + 1;
384 ListDictionary_Remove(smartcard->rgOutstandingMessages, (
void*)key);
386 WINPR_ASSERT(irp->Complete);
388 return irp->Complete(irp);
401static UINT smartcard_process_irp(
SMARTCARD_DEVICE* smartcard, IRP* irp, BOOL* handled)
404 BOOL asyncIrp = FALSE;
407 WINPR_ASSERT(smartcard);
408 WINPR_ASSERT(handled);
410 WINPR_ASSERT(irp->Complete);
412 uintptr_t key = (uintptr_t)irp->CompletionId + 1;
414 if (!ListDictionary_Add(smartcard->rgOutstandingMessages, (
void*)key, irp))
416 WLog_ERR(TAG,
"ListDictionary_Add failed!");
417 return ERROR_INTERNAL_ERROR;
420 if (irp->MajorFunction == IRP_MJ_DEVICE_CONTROL)
422 scard_irp_queue_element* element = calloc(1,
sizeof(scard_irp_queue_element));
424 return ERROR_OUTOFMEMORY;
427 element->operation.completionID = irp->CompletionId;
429 status = smartcard_irp_device_control_decode_request(irp->input, irp->CompletionId,
430 irp->FileId, &element->operation);
432 if (status != SCARD_S_SUCCESS)
436 smartcard_operation_free(&element->operation, TRUE);
437 irp->IoStatus = STATUS_UNSUCCESSFUL;
439 if ((error = smartcard_complete_irp(smartcard, irp, handled)))
441 WLog_ERR(TAG,
"Queue_Enqueue failed!");
445 return CHANNEL_RC_OK;
450 switch (element->operation.ioControlCode)
452 case SCARD_IOCTL_ESTABLISHCONTEXT:
453 case SCARD_IOCTL_RELEASECONTEXT:
454 case SCARD_IOCTL_ISVALIDCONTEXT:
455 case SCARD_IOCTL_CANCEL:
456 case SCARD_IOCTL_ACCESSSTARTEDEVENT:
457 case SCARD_IOCTL_RELEASETARTEDEVENT:
461 case SCARD_IOCTL_LISTREADERGROUPSA:
462 case SCARD_IOCTL_LISTREADERGROUPSW:
463 case SCARD_IOCTL_LISTREADERSA:
464 case SCARD_IOCTL_LISTREADERSW:
465 case SCARD_IOCTL_INTRODUCEREADERGROUPA:
466 case SCARD_IOCTL_INTRODUCEREADERGROUPW:
467 case SCARD_IOCTL_FORGETREADERGROUPA:
468 case SCARD_IOCTL_FORGETREADERGROUPW:
469 case SCARD_IOCTL_INTRODUCEREADERA:
470 case SCARD_IOCTL_INTRODUCEREADERW:
471 case SCARD_IOCTL_FORGETREADERA:
472 case SCARD_IOCTL_FORGETREADERW:
473 case SCARD_IOCTL_ADDREADERTOGROUPA:
474 case SCARD_IOCTL_ADDREADERTOGROUPW:
475 case SCARD_IOCTL_REMOVEREADERFROMGROUPA:
476 case SCARD_IOCTL_REMOVEREADERFROMGROUPW:
477 case SCARD_IOCTL_LOCATECARDSA:
478 case SCARD_IOCTL_LOCATECARDSW:
479 case SCARD_IOCTL_LOCATECARDSBYATRA:
480 case SCARD_IOCTL_LOCATECARDSBYATRW:
481 case SCARD_IOCTL_READCACHEA:
482 case SCARD_IOCTL_READCACHEW:
483 case SCARD_IOCTL_WRITECACHEA:
484 case SCARD_IOCTL_WRITECACHEW:
485 case SCARD_IOCTL_GETREADERICON:
486 case SCARD_IOCTL_GETDEVICETYPEID:
487 case SCARD_IOCTL_GETSTATUSCHANGEA:
488 case SCARD_IOCTL_GETSTATUSCHANGEW:
489 case SCARD_IOCTL_CONNECTA:
490 case SCARD_IOCTL_CONNECTW:
491 case SCARD_IOCTL_RECONNECT:
492 case SCARD_IOCTL_DISCONNECT:
493 case SCARD_IOCTL_BEGINTRANSACTION:
494 case SCARD_IOCTL_ENDTRANSACTION:
495 case SCARD_IOCTL_STATE:
496 case SCARD_IOCTL_STATUSA:
497 case SCARD_IOCTL_STATUSW:
498 case SCARD_IOCTL_TRANSMIT:
499 case SCARD_IOCTL_CONTROL:
500 case SCARD_IOCTL_GETATTRIB:
501 case SCARD_IOCTL_SETATTRIB:
502 case SCARD_IOCTL_GETTRANSMITCOUNT:
509 pContext = smartcard_call_get_context(smartcard->callctx, element->operation.hContext);
519 smartcard_irp_device_control_call(smartcard->callctx, element->irp->output,
520 &element->irp->IoStatus, &element->operation);
521 smartcard_operation_free(&element->operation, TRUE);
525 WLog_ERR(TAG,
"smartcard_irp_device_control_call failed with error %" PRId32
"!",
527 return (UINT32)status;
530 if ((error = smartcard_complete_irp(smartcard, irp, handled)))
532 WLog_ERR(TAG,
"Queue_Enqueue failed!");
540 wMessageQueue* queue = pContext->IrpQueue;
542 switch (element->operation.ioControlCode)
545 case SCARD_IOCTL_BEGINTRANSACTION:
546 case SCARD_IOCTL_CONNECTA:
547 case SCARD_IOCTL_CONNECTW:
548 case SCARD_IOCTL_RECONNECT:
549 queue = pContext->TxQueue;
555 if (!MessageQueue_Post(queue,
nullptr, 0, (
void*)element,
nullptr))
557 smartcard_operation_free(&element->operation, TRUE);
558 WLog_ERR(TAG,
"MessageQueue_Post failed!");
559 return ERROR_INTERNAL_ERROR;
568 WLog_ERR(TAG,
"Unexpected SmartCard IRP: MajorFunction %s, MinorFunction: 0x%08" PRIX32
"",
569 rdpdr_irp_string(irp->MajorFunction), irp->MinorFunction);
570 irp->IoStatus = STATUS_NOT_SUPPORTED;
572 if ((ustatus = smartcard_complete_irp(smartcard, irp, handled)))
574 WLog_ERR(TAG,
"Queue_Enqueue failed!");
579 return CHANNEL_RC_OK;
582static DWORD WINAPI smartcard_thread_func(LPVOID arg)
587 HANDLE hEvents[1] = WINPR_C_ARRAY_INIT;
588 wMessage message = WINPR_C_ARRAY_INIT;
589 UINT error = CHANNEL_RC_OK;
593 return ERROR_INVALID_PARAMETER;
595 hEvents[nCount++] = MessageQueue_Event(smartcard->IrpQueue);
599 status = WaitForMultipleObjects(nCount, hEvents, FALSE, INFINITE);
601 if (status == WAIT_FAILED)
603 error = GetLastError();
604 WLog_ERR(TAG,
"WaitForMultipleObjects failed with error %" PRIu32
"!", error);
608 if (status == WAIT_OBJECT_0)
610 if (!MessageQueue_Peek(smartcard->IrpQueue, &message, TRUE))
612 WLog_ERR(TAG,
"MessageQueue_Peek failed!");
613 error = ERROR_INTERNAL_ERROR;
617 if (message.id == WMQ_QUIT)
620 irp = (IRP*)message.wParam;
624 BOOL handled = FALSE;
625 if ((error = smartcard_process_irp(smartcard, irp, &handled)))
627 WLog_ERR(TAG,
"smartcard_process_irp failed with error %" PRIu32
"!", error);
632 WINPR_ASSERT(irp->Discard);
641 if (error && smartcard->rdpcontext)
642 setChannelError(smartcard->rdpcontext, error,
"smartcard_thread_func reported an error");
653static UINT smartcard_irp_request(DEVICE* device, IRP* irp)
660 return ERROR_INVALID_PARAMETER;
663 if (!MessageQueue_Post(smartcard->IrpQueue,
nullptr, 0, (
void*)irp,
nullptr))
665 WLog_ERR(TAG,
"MessageQueue_Post failed!");
667 return ERROR_INTERNAL_ERROR;
670 return CHANNEL_RC_OK;
673static void smartcard_free_irp(
void* obj)
681 IRP* irp = (IRP*)msg->wParam;
684 WINPR_ASSERT(irp->Discard);
689#define DeviceServiceEntry smartcard_DeviceServiceEntry
698 BOOL registered = FALSE;
699 UINT error = CHANNEL_RC_NO_MEMORY;
702 WLog_VRB(TAG,
"smartcard device create: %p", (
const void*)smartcard);
705 WLog_ERR(TAG,
"calloc failed!");
706 return CHANNEL_RC_NO_MEMORY;
709 smartcard->device.type = RDPDR_DTYP_SMARTCARD;
710 smartcard->device.name =
"SCARD";
711 smartcard->device.IRPRequest = smartcard_irp_request;
712 smartcard->device.Init = smartcard_init;
713 smartcard->device.Free = smartcard_free;
714 smartcard->rdpcontext = pEntryPoints->rdpcontext;
715 smartcard->IrpQueue = MessageQueue_New(
nullptr);
717 if (!smartcard->IrpQueue)
719 WLog_ERR(TAG,
"MessageQueue_New failed!");
723 wObject* obj = MessageQueue_Object(smartcard->IrpQueue);
727 smartcard->rgOutstandingMessages = ListDictionary_New(TRUE);
729 if (!smartcard->rgOutstandingMessages)
731 WLog_ERR(TAG,
"ListDictionary_New failed!");
735 smartcard->callctx = smartcard_call_context_new_with_context(smartcard->rdpcontext);
736 if (!smartcard->callctx)
739 if (!smarcard_call_set_callbacks(smartcard->callctx, smartcard, smartcard_context_new,
740 smartcard_context_free))
743 error = pEntryPoints->RegisterDevice(pEntryPoints->devman, &smartcard->device);
746 WLog_ERR(TAG,
"RegisterDevice failed!");
752 CreateThread(
nullptr, 0, smartcard_thread_func, smartcard, CREATE_SUSPENDED,
nullptr);
754 if (!smartcard->thread)
756 WLog_ERR(TAG,
"CreateThread failed!");
757 error = ERROR_INTERNAL_ERROR;
761 ResumeThread(smartcard->thread);
763 if (pEntryPoints->device->Name)
765 if (!smartcard_call_context_add(smartcard->callctx, pEntryPoints->device->Name))
769 return CHANNEL_RC_OK;
772 smartcard_free_(smartcard);
This struct contains function pointer to initialize/free objects.
OBJECT_FREE_FN fnObjectFree