25 #include <freerdp/config.h>
27 #include <winpr/crt.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;
50 static void smartcard_context_free(
void* pCtx);
52 static UINT smartcard_complete_irp(
SMARTCARD_DEVICE* smartcard, IRP* irp, BOOL* handled);
54 static SMARTCARD_DEVICE* cast_device_from(DEVICE* device,
const char* fkt,
const char* file,
59 WLog_ERR(TAG,
"%s [%s:%" PRIuz
"] Called smartcard channel with NULL device", fkt, file,
64 if (device->type != RDPDR_DTYP_SMARTCARD)
67 "%s [%s:%" PRIuz
"] Called smartcard channel with invalid device of type %" PRIx32,
68 fkt, file, line, device->type);
75 static DWORD WINAPI smartcard_context_thread(LPVOID arg)
81 HANDLE hEvents[2] = { 0 };
82 wMessage message = { 0 };
84 UINT error = CHANNEL_RC_OK;
85 smartcard = pContext->smartcard;
87 hEvents[nCount++] = MessageQueue_Event(pContext->IrpQueue);
91 waitStatus = WaitForMultipleObjects(nCount, hEvents, FALSE, INFINITE);
93 if (waitStatus == WAIT_FAILED)
95 error = GetLastError();
96 WLog_ERR(TAG,
"WaitForMultipleObjects failed with error %" PRIu32
"!", error);
100 waitStatus = WaitForSingleObject(MessageQueue_Event(pContext->IrpQueue), 0);
102 if (waitStatus == WAIT_FAILED)
104 error = GetLastError();
105 WLog_ERR(TAG,
"WaitForSingleObject failed with error %" PRIu32
"!", error);
109 if (waitStatus == WAIT_OBJECT_0)
111 scard_irp_queue_element* element = NULL;
113 if (!MessageQueue_Peek(pContext->IrpQueue, &message, TRUE))
115 WLog_ERR(TAG,
"MessageQueue_Peek failed!");
116 status = ERROR_INTERNAL_ERROR;
120 if (message.id == WMQ_QUIT)
123 element = (scard_irp_queue_element*)message.wParam;
127 BOOL handled = FALSE;
128 WINPR_ASSERT(smartcard);
130 if ((status = smartcard_irp_device_control_call(
131 smartcard->callctx, element->irp->output, &element->irp->IoStatus,
132 &element->operation)))
134 element->irp->Discard(element->irp);
135 smartcard_operation_free(&element->operation, TRUE);
136 WLog_ERR(TAG,
"smartcard_irp_device_control_call failed with error %" PRIu32
"",
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,
"Queue_Enqueue failed!");
155 if (status && smartcard->rdpcontext)
156 setChannelError(smartcard->rdpcontext, error,
"smartcard_context_thread reported an error");
162 static void smartcard_operation_queue_free(
void* obj)
170 scard_irp_queue_element* element = (scard_irp_queue_element*)msg->wParam;
173 WINPR_ASSERT(element->irp);
174 WINPR_ASSERT(element->irp->Discard);
175 element->irp->Discard(element->irp);
176 smartcard_operation_free(&element->operation, TRUE);
179 static void* smartcard_context_new(
void* smartcard, SCARDCONTEXT hContext)
186 WLog_ERR(TAG,
"calloc failed!");
190 pContext->smartcard = smartcard;
191 pContext->hContext = hContext;
192 pContext->IrpQueue = MessageQueue_New(NULL);
194 if (!pContext->IrpQueue)
196 WLog_ERR(TAG,
"MessageQueue_New failed!");
199 wObject* obj = MessageQueue_Object(pContext->IrpQueue);
201 obj->fnObjectFree = smartcard_operation_queue_free;
203 pContext->thread = CreateThread(NULL, 0, smartcard_context_thread, pContext, 0, NULL);
205 if (!pContext->thread)
207 WLog_ERR(TAG,
"CreateThread failed!");
213 smartcard_context_free(pContext);
217 void smartcard_context_free(
void* pCtx)
225 WINPR_ASSERT(pContext->smartcard);
226 smartcard_call_cancel_context(pContext->smartcard->callctx, pContext->hContext);
228 if (pContext->IrpQueue)
230 if (MessageQueue_PostQuit(pContext->IrpQueue, 0))
232 if (WaitForSingleObject(pContext->thread, INFINITE) == WAIT_FAILED)
233 WLog_ERR(TAG,
"WaitForSingleObject failed with error %" PRIu32
"!", GetLastError());
235 (void)CloseHandle(pContext->thread);
237 MessageQueue_Free(pContext->IrpQueue);
239 smartcard_call_release_context(pContext->smartcard->callctx, pContext->hContext);
245 smartcard_call_cancel_all_context(smartcard->callctx);
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;
272 static UINT smartcard_free(DEVICE* device)
277 return ERROR_INVALID_PARAMETER;
283 smartcard_release_all_contexts(smartcard);
287 if (smartcard->IrpQueue)
289 if (MessageQueue_PostQuit(smartcard->IrpQueue, 0) &&
290 (WaitForSingleObject(smartcard->thread, INFINITE) == WAIT_FAILED))
292 DWORD error = GetLastError();
293 WLog_ERR(TAG,
"WaitForSingleObject failed with error %" PRIu32
"!", error);
298 if (sSmartcard == smartcard)
301 return smartcard_free_(smartcard);
314 static UINT smartcard_init(DEVICE* device)
319 return ERROR_INVALID_PARAMETER;
321 smartcard_release_all_contexts(smartcard);
322 return CHANNEL_RC_OK;
330 UINT smartcard_complete_irp(
SMARTCARD_DEVICE* smartcard, IRP* irp, BOOL* handled)
332 WINPR_ASSERT(smartcard);
334 WINPR_ASSERT(handled);
336 uintptr_t key = (uintptr_t)irp->CompletionId + 1;
337 ListDictionary_Remove(smartcard->rgOutstandingMessages, (
void*)key);
339 WINPR_ASSERT(irp->Complete);
341 return irp->Complete(irp);
354 static UINT smartcard_process_irp(
SMARTCARD_DEVICE* smartcard, IRP* irp, BOOL* handled)
357 BOOL asyncIrp = FALSE;
360 WINPR_ASSERT(smartcard);
361 WINPR_ASSERT(handled);
363 WINPR_ASSERT(irp->Complete);
365 uintptr_t key = (uintptr_t)irp->CompletionId + 1;
367 if (!ListDictionary_Add(smartcard->rgOutstandingMessages, (
void*)key, irp))
369 WLog_ERR(TAG,
"ListDictionary_Add failed!");
370 return ERROR_INTERNAL_ERROR;
373 if (irp->MajorFunction == IRP_MJ_DEVICE_CONTROL)
375 scard_irp_queue_element* element = calloc(1,
sizeof(scard_irp_queue_element));
377 return ERROR_OUTOFMEMORY;
380 element->operation.completionID = irp->CompletionId;
382 status = smartcard_irp_device_control_decode(irp->input, irp->CompletionId, irp->FileId,
383 &element->operation);
385 if (status != SCARD_S_SUCCESS)
389 smartcard_operation_free(&element->operation, TRUE);
390 irp->IoStatus = (UINT32)STATUS_UNSUCCESSFUL;
392 if ((error = smartcard_complete_irp(smartcard, irp, handled)))
394 WLog_ERR(TAG,
"Queue_Enqueue failed!");
398 return CHANNEL_RC_OK;
403 switch (element->operation.ioControlCode)
405 case SCARD_IOCTL_ESTABLISHCONTEXT:
406 case SCARD_IOCTL_RELEASECONTEXT:
407 case SCARD_IOCTL_ISVALIDCONTEXT:
408 case SCARD_IOCTL_CANCEL:
409 case SCARD_IOCTL_ACCESSSTARTEDEVENT:
410 case SCARD_IOCTL_RELEASETARTEDEVENT:
414 case SCARD_IOCTL_LISTREADERGROUPSA:
415 case SCARD_IOCTL_LISTREADERGROUPSW:
416 case SCARD_IOCTL_LISTREADERSA:
417 case SCARD_IOCTL_LISTREADERSW:
418 case SCARD_IOCTL_INTRODUCEREADERGROUPA:
419 case SCARD_IOCTL_INTRODUCEREADERGROUPW:
420 case SCARD_IOCTL_FORGETREADERGROUPA:
421 case SCARD_IOCTL_FORGETREADERGROUPW:
422 case SCARD_IOCTL_INTRODUCEREADERA:
423 case SCARD_IOCTL_INTRODUCEREADERW:
424 case SCARD_IOCTL_FORGETREADERA:
425 case SCARD_IOCTL_FORGETREADERW:
426 case SCARD_IOCTL_ADDREADERTOGROUPA:
427 case SCARD_IOCTL_ADDREADERTOGROUPW:
428 case SCARD_IOCTL_REMOVEREADERFROMGROUPA:
429 case SCARD_IOCTL_REMOVEREADERFROMGROUPW:
430 case SCARD_IOCTL_LOCATECARDSA:
431 case SCARD_IOCTL_LOCATECARDSW:
432 case SCARD_IOCTL_LOCATECARDSBYATRA:
433 case SCARD_IOCTL_LOCATECARDSBYATRW:
434 case SCARD_IOCTL_READCACHEA:
435 case SCARD_IOCTL_READCACHEW:
436 case SCARD_IOCTL_WRITECACHEA:
437 case SCARD_IOCTL_WRITECACHEW:
438 case SCARD_IOCTL_GETREADERICON:
439 case SCARD_IOCTL_GETDEVICETYPEID:
440 case SCARD_IOCTL_GETSTATUSCHANGEA:
441 case SCARD_IOCTL_GETSTATUSCHANGEW:
442 case SCARD_IOCTL_CONNECTA:
443 case SCARD_IOCTL_CONNECTW:
444 case SCARD_IOCTL_RECONNECT:
445 case SCARD_IOCTL_DISCONNECT:
446 case SCARD_IOCTL_BEGINTRANSACTION:
447 case SCARD_IOCTL_ENDTRANSACTION:
448 case SCARD_IOCTL_STATE:
449 case SCARD_IOCTL_STATUSA:
450 case SCARD_IOCTL_STATUSW:
451 case SCARD_IOCTL_TRANSMIT:
452 case SCARD_IOCTL_CONTROL:
453 case SCARD_IOCTL_GETATTRIB:
454 case SCARD_IOCTL_SETATTRIB:
455 case SCARD_IOCTL_GETTRANSMITCOUNT:
462 pContext = smartcard_call_get_context(smartcard->callctx, element->operation.hContext);
472 smartcard_irp_device_control_call(smartcard->callctx, element->irp->output,
473 &element->irp->IoStatus, &element->operation);
474 smartcard_operation_free(&element->operation, TRUE);
478 WLog_ERR(TAG,
"smartcard_irp_device_control_call failed with error %" PRId32
"!",
480 return (UINT32)status;
483 if ((error = smartcard_complete_irp(smartcard, irp, handled)))
485 WLog_ERR(TAG,
"Queue_Enqueue failed!");
493 if (!MessageQueue_Post(pContext->IrpQueue, NULL, 0, (
void*)element, NULL))
495 smartcard_operation_free(&element->operation, TRUE);
496 WLog_ERR(TAG,
"MessageQueue_Post failed!");
497 return ERROR_INTERNAL_ERROR;
506 WLog_ERR(TAG,
"Unexpected SmartCard IRP: MajorFunction %s, MinorFunction: 0x%08" PRIX32
"",
507 rdpdr_irp_string(irp->MajorFunction), irp->MinorFunction);
508 irp->IoStatus = (UINT32)STATUS_NOT_SUPPORTED;
510 if ((ustatus = smartcard_complete_irp(smartcard, irp, handled)))
512 WLog_ERR(TAG,
"Queue_Enqueue failed!");
517 return CHANNEL_RC_OK;
520 static DWORD WINAPI smartcard_thread_func(LPVOID arg)
525 HANDLE hEvents[1] = { 0 };
526 wMessage message = { 0 };
527 UINT error = CHANNEL_RC_OK;
531 return ERROR_INVALID_PARAMETER;
533 hEvents[nCount++] = MessageQueue_Event(smartcard->IrpQueue);
537 status = WaitForMultipleObjects(nCount, hEvents, FALSE, INFINITE);
539 if (status == WAIT_FAILED)
541 error = GetLastError();
542 WLog_ERR(TAG,
"WaitForMultipleObjects failed with error %" PRIu32
"!", error);
546 if (status == WAIT_OBJECT_0)
548 if (!MessageQueue_Peek(smartcard->IrpQueue, &message, TRUE))
550 WLog_ERR(TAG,
"MessageQueue_Peek failed!");
551 error = ERROR_INTERNAL_ERROR;
555 if (message.id == WMQ_QUIT)
558 irp = (IRP*)message.wParam;
562 BOOL handled = FALSE;
563 if ((error = smartcard_process_irp(smartcard, irp, &handled)))
565 WLog_ERR(TAG,
"smartcard_process_irp failed with error %" PRIu32
"!", error);
570 WINPR_ASSERT(irp->Discard);
579 if (error && smartcard->rdpcontext)
580 setChannelError(smartcard->rdpcontext, error,
"smartcard_thread_func reported an error");
591 static UINT smartcard_irp_request(DEVICE* device, IRP* irp)
596 return ERROR_INVALID_PARAMETER;
598 if (!MessageQueue_Post(smartcard->IrpQueue, NULL, 0, (
void*)irp, NULL))
600 WLog_ERR(TAG,
"MessageQueue_Post failed!");
601 return ERROR_INTERNAL_ERROR;
604 return CHANNEL_RC_OK;
607 static void smartcard_free_irp(
void* obj)
615 IRP* irp = (IRP*)msg->wParam;
618 WINPR_ASSERT(irp->Discard);
623 #define DeviceServiceEntry smartcard_DeviceServiceEntry
634 UINT error = CHANNEL_RC_NO_MEMORY;
642 WLog_ERR(TAG,
"calloc failed!");
643 return CHANNEL_RC_NO_MEMORY;
646 smartcard->device.type = RDPDR_DTYP_SMARTCARD;
647 smartcard->device.name =
"SCARD";
648 smartcard->device.IRPRequest = smartcard_irp_request;
649 smartcard->device.Init = smartcard_init;
650 smartcard->device.Free = smartcard_free;
651 smartcard->rdpcontext = pEntryPoints->rdpcontext;
652 length = strlen(smartcard->device.name);
653 smartcard->device.data = Stream_New(NULL, length + 1);
655 if (!smartcard->device.data)
657 WLog_ERR(TAG,
"Stream_New failed!");
661 Stream_Write(smartcard->device.data,
"SCARD", 6);
662 smartcard->IrpQueue = MessageQueue_New(NULL);
664 if (!smartcard->IrpQueue)
666 WLog_ERR(TAG,
"MessageQueue_New failed!");
670 wObject* obj = MessageQueue_Object(smartcard->IrpQueue);
672 obj->fnObjectFree = smartcard_free_irp;
674 smartcard->rgOutstandingMessages = ListDictionary_New(TRUE);
676 if (!smartcard->rgOutstandingMessages)
678 WLog_ERR(TAG,
"ListDictionary_New failed!");
682 smartcard->callctx = smartcard_call_context_new(smartcard->rdpcontext->settings);
683 if (!smartcard->callctx)
686 if (!smarcard_call_set_callbacks(smartcard->callctx, smartcard, smartcard_context_new,
687 smartcard_context_free))
690 if ((error = pEntryPoints->RegisterDevice(pEntryPoints->devman, &smartcard->device)))
692 WLog_ERR(TAG,
"RegisterDevice failed!");
697 CreateThread(NULL, 0, smartcard_thread_func, smartcard, CREATE_SUSPENDED, NULL);
699 if (!smartcard->thread)
701 WLog_ERR(TAG,
"ListDictionary_New failed!");
702 error = ERROR_INTERNAL_ERROR;
706 ResumeThread(smartcard->thread);
709 smartcard = sSmartcard;
711 if (pEntryPoints->device->Name)
713 smartcard_call_context_add(smartcard->callctx, pEntryPoints->device->Name);
716 sSmartcard = smartcard;
717 return CHANNEL_RC_OK;
719 smartcard_free_(smartcard);
This struct contains function pointer to initialize/free objects.