FreeRDP
Loading...
Searching...
No Matches
smartcard_main.c
1
25#include <freerdp/config.h>
26
27#include <winpr/crt.h>
28#include <winpr/smartcard.h>
29#include <winpr/environment.h>
30
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>
37
38#include "smartcard_main.h"
39
40#define CAST_FROM_DEVICE(device) cast_device_from(device, __func__, __FILE__, __LINE__)
41
42typedef struct
43{
44 SMARTCARD_OPERATION operation;
45 IRP* irp;
46} scard_irp_queue_element;
47
48static SMARTCARD_DEVICE* sSmartcard = NULL;
49
50static void smartcard_context_free(void* pCtx);
51
52static UINT smartcard_complete_irp(SMARTCARD_DEVICE* smartcard, IRP* irp, BOOL* handled);
53
54static SMARTCARD_DEVICE* cast_device_from(DEVICE* device, const char* fkt, const char* file,
55 size_t line)
56{
57 if (!device)
58 {
59 WLog_ERR(TAG, "%s [%s:%" PRIuz "] Called smartcard channel with NULL device", fkt, file,
60 line);
61 return NULL;
62 }
63
64 if (device->type != RDPDR_DTYP_SMARTCARD)
65 {
66 WLog_ERR(TAG,
67 "%s [%s:%" PRIuz "] Called smartcard channel with invalid device of type %" PRIx32,
68 fkt, file, line, device->type);
69 return NULL;
70 }
71
72 return (SMARTCARD_DEVICE*)device;
73}
74
75static DWORD WINAPI smartcard_context_thread(LPVOID arg)
76{
77 SMARTCARD_CONTEXT* pContext = (SMARTCARD_CONTEXT*)arg;
78 DWORD nCount = 0;
79 LONG status = 0;
80 DWORD waitStatus = 0;
81 HANDLE hEvents[2] = { 0 };
82 wMessage message = { 0 };
83 SMARTCARD_DEVICE* smartcard = NULL;
84 UINT error = CHANNEL_RC_OK;
85 smartcard = pContext->smartcard;
86
87 hEvents[nCount++] = MessageQueue_Event(pContext->IrpQueue);
88
89 while (1)
90 {
91 waitStatus = WaitForMultipleObjects(nCount, hEvents, FALSE, INFINITE);
92
93 if (waitStatus == WAIT_FAILED)
94 {
95 error = GetLastError();
96 WLog_ERR(TAG, "WaitForMultipleObjects failed with error %" PRIu32 "!", error);
97 break;
98 }
99
100 waitStatus = WaitForSingleObject(MessageQueue_Event(pContext->IrpQueue), 0);
101
102 if (waitStatus == WAIT_FAILED)
103 {
104 error = GetLastError();
105 WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "!", error);
106 break;
107 }
108
109 if (waitStatus == WAIT_OBJECT_0)
110 {
111 scard_irp_queue_element* element = NULL;
112
113 if (!MessageQueue_Peek(pContext->IrpQueue, &message, TRUE))
114 {
115 WLog_ERR(TAG, "MessageQueue_Peek failed!");
116 status = ERROR_INTERNAL_ERROR;
117 break;
118 }
119
120 if (message.id == WMQ_QUIT)
121 break;
122
123 element = (scard_irp_queue_element*)message.wParam;
124
125 if (element)
126 {
127 BOOL handled = FALSE;
128 WINPR_ASSERT(smartcard);
129
130 if ((status = smartcard_irp_device_control_call(
131 smartcard->callctx, element->irp->output, &element->irp->IoStatus,
132 &element->operation)))
133 {
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 "",
137 status);
138 break;
139 }
140
141 error = smartcard_complete_irp(smartcard, element->irp, &handled);
142 if (!handled)
143 element->irp->Discard(element->irp);
144 smartcard_operation_free(&element->operation, TRUE);
145
146 if (error)
147 {
148 WLog_ERR(TAG, "Queue_Enqueue failed!");
149 break;
150 }
151 }
152 }
153 }
154
155 if (status && smartcard->rdpcontext)
156 setChannelError(smartcard->rdpcontext, error, "smartcard_context_thread reported an error");
157
158 ExitThread((uint32_t)status);
159 return error;
160}
161
162static void smartcard_operation_queue_free(void* obj)
163{
164 wMessage* msg = obj;
165 if (!msg)
166 return;
167 if (msg->id != 0)
168 return;
169
170 scard_irp_queue_element* element = (scard_irp_queue_element*)msg->wParam;
171 if (!element)
172 return;
173 WINPR_ASSERT(element->irp);
174 WINPR_ASSERT(element->irp->Discard);
175 element->irp->Discard(element->irp);
176 smartcard_operation_free(&element->operation, TRUE);
177}
178
179static void* smartcard_context_new(void* smartcard, SCARDCONTEXT hContext)
180{
181 SMARTCARD_CONTEXT* pContext = NULL;
182 pContext = (SMARTCARD_CONTEXT*)calloc(1, sizeof(SMARTCARD_CONTEXT));
183
184 if (!pContext)
185 {
186 WLog_ERR(TAG, "calloc failed!");
187 return pContext;
188 }
189
190 pContext->smartcard = smartcard;
191 pContext->hContext = hContext;
192 pContext->IrpQueue = MessageQueue_New(NULL);
193
194 if (!pContext->IrpQueue)
195 {
196 WLog_ERR(TAG, "MessageQueue_New failed!");
197 goto fail;
198 }
199
200 {
201 wObject* obj = MessageQueue_Object(pContext->IrpQueue);
202 WINPR_ASSERT(obj);
203 obj->fnObjectFree = smartcard_operation_queue_free;
204 }
205
206 pContext->thread = CreateThread(NULL, 0, smartcard_context_thread, pContext, 0, NULL);
207
208 if (!pContext->thread)
209 {
210 WLog_ERR(TAG, "CreateThread failed!");
211 goto fail;
212 }
213
214 return pContext;
215fail:
216 smartcard_context_free(pContext);
217 return NULL;
218}
219
220void smartcard_context_free(void* pCtx)
221{
222 SMARTCARD_CONTEXT* pContext = pCtx;
223
224 if (!pContext)
225 return;
226
227 /* cancel blocking calls like SCardGetStatusChange */
228 WINPR_ASSERT(pContext->smartcard);
229 smartcard_call_cancel_context(pContext->smartcard->callctx, pContext->hContext);
230
231 if (pContext->IrpQueue)
232 {
233 if (MessageQueue_PostQuit(pContext->IrpQueue, 0))
234 {
235 if (WaitForSingleObject(pContext->thread, INFINITE) == WAIT_FAILED)
236 WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "!", GetLastError());
237
238 (void)CloseHandle(pContext->thread);
239 }
240 MessageQueue_Free(pContext->IrpQueue);
241 }
242 smartcard_call_release_context(pContext->smartcard->callctx, pContext->hContext);
243 free(pContext);
244}
245
246static void smartcard_release_all_contexts(SMARTCARD_DEVICE* smartcard)
247{
248 smartcard_call_cancel_all_context(smartcard->callctx);
249}
250
251static UINT smartcard_free_(SMARTCARD_DEVICE* smartcard)
252{
253 if (!smartcard)
254 return CHANNEL_RC_OK;
255
256 if (smartcard->IrpQueue)
257 {
258 MessageQueue_Free(smartcard->IrpQueue);
259 (void)CloseHandle(smartcard->thread);
260 }
261
262 Stream_Free(smartcard->device.data, TRUE);
263 ListDictionary_Free(smartcard->rgOutstandingMessages);
264
265 smartcard_call_context_free(smartcard->callctx);
266
267 free(smartcard);
268 return CHANNEL_RC_OK;
269}
275static UINT smartcard_free(DEVICE* device)
276{
277 SMARTCARD_DEVICE* smartcard = CAST_FROM_DEVICE(device);
278
279 if (!smartcard)
280 return ERROR_INVALID_PARAMETER;
281
286 smartcard_release_all_contexts(smartcard);
287
288 /* Stopping all threads and cancelling all IRPs */
289
290 if (smartcard->IrpQueue)
291 {
292 if (MessageQueue_PostQuit(smartcard->IrpQueue, 0) &&
293 (WaitForSingleObject(smartcard->thread, INFINITE) == WAIT_FAILED))
294 {
295 DWORD error = GetLastError();
296 WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "!", error);
297 return error;
298 }
299 }
300
301 if (sSmartcard == smartcard)
302 sSmartcard = NULL;
303
304 return smartcard_free_(smartcard);
305}
306
317static UINT smartcard_init(DEVICE* device)
318{
319 SMARTCARD_DEVICE* smartcard = CAST_FROM_DEVICE(device);
320
321 if (!smartcard)
322 return ERROR_INVALID_PARAMETER;
323
324 smartcard_release_all_contexts(smartcard);
325 return CHANNEL_RC_OK;
326}
327
333UINT smartcard_complete_irp(SMARTCARD_DEVICE* smartcard, IRP* irp, BOOL* handled)
334{
335 WINPR_ASSERT(smartcard);
336 WINPR_ASSERT(irp);
337 WINPR_ASSERT(handled);
338
339 uintptr_t key = (uintptr_t)irp->CompletionId + 1;
340 ListDictionary_Remove(smartcard->rgOutstandingMessages, (void*)key);
341
342 WINPR_ASSERT(irp->Complete);
343 *handled = TRUE;
344 return irp->Complete(irp);
345}
346
357static UINT smartcard_process_irp(SMARTCARD_DEVICE* smartcard, IRP* irp, BOOL* handled)
358{
359 LONG status = 0;
360 BOOL asyncIrp = FALSE;
361 SMARTCARD_CONTEXT* pContext = NULL;
362
363 WINPR_ASSERT(smartcard);
364 WINPR_ASSERT(handled);
365 WINPR_ASSERT(irp);
366 WINPR_ASSERT(irp->Complete);
367
368 uintptr_t key = (uintptr_t)irp->CompletionId + 1;
369
370 if (!ListDictionary_Add(smartcard->rgOutstandingMessages, (void*)key, irp))
371 {
372 WLog_ERR(TAG, "ListDictionary_Add failed!");
373 return ERROR_INTERNAL_ERROR;
374 }
375
376 if (irp->MajorFunction == IRP_MJ_DEVICE_CONTROL)
377 {
378 scard_irp_queue_element* element = calloc(1, sizeof(scard_irp_queue_element));
379 if (!element)
380 return ERROR_OUTOFMEMORY;
381
382 element->irp = irp;
383 element->operation.completionID = irp->CompletionId;
384
385 status = smartcard_irp_device_control_decode(irp->input, irp->CompletionId, irp->FileId,
386 &element->operation);
387
388 if (status != SCARD_S_SUCCESS)
389 {
390 UINT error = 0;
391
392 smartcard_operation_free(&element->operation, TRUE);
393 irp->IoStatus = STATUS_UNSUCCESSFUL;
394
395 if ((error = smartcard_complete_irp(smartcard, irp, handled)))
396 {
397 WLog_ERR(TAG, "Queue_Enqueue failed!");
398 return error;
399 }
400
401 return CHANNEL_RC_OK;
402 }
403
404 asyncIrp = TRUE;
405
406 switch (element->operation.ioControlCode)
407 {
408 case SCARD_IOCTL_ESTABLISHCONTEXT:
409 case SCARD_IOCTL_RELEASECONTEXT:
410 case SCARD_IOCTL_ISVALIDCONTEXT:
411 case SCARD_IOCTL_CANCEL:
412 case SCARD_IOCTL_ACCESSSTARTEDEVENT:
413 case SCARD_IOCTL_RELEASETARTEDEVENT:
414 asyncIrp = FALSE;
415 break;
416
417 case SCARD_IOCTL_LISTREADERGROUPSA:
418 case SCARD_IOCTL_LISTREADERGROUPSW:
419 case SCARD_IOCTL_LISTREADERSA:
420 case SCARD_IOCTL_LISTREADERSW:
421 case SCARD_IOCTL_INTRODUCEREADERGROUPA:
422 case SCARD_IOCTL_INTRODUCEREADERGROUPW:
423 case SCARD_IOCTL_FORGETREADERGROUPA:
424 case SCARD_IOCTL_FORGETREADERGROUPW:
425 case SCARD_IOCTL_INTRODUCEREADERA:
426 case SCARD_IOCTL_INTRODUCEREADERW:
427 case SCARD_IOCTL_FORGETREADERA:
428 case SCARD_IOCTL_FORGETREADERW:
429 case SCARD_IOCTL_ADDREADERTOGROUPA:
430 case SCARD_IOCTL_ADDREADERTOGROUPW:
431 case SCARD_IOCTL_REMOVEREADERFROMGROUPA:
432 case SCARD_IOCTL_REMOVEREADERFROMGROUPW:
433 case SCARD_IOCTL_LOCATECARDSA:
434 case SCARD_IOCTL_LOCATECARDSW:
435 case SCARD_IOCTL_LOCATECARDSBYATRA:
436 case SCARD_IOCTL_LOCATECARDSBYATRW:
437 case SCARD_IOCTL_READCACHEA:
438 case SCARD_IOCTL_READCACHEW:
439 case SCARD_IOCTL_WRITECACHEA:
440 case SCARD_IOCTL_WRITECACHEW:
441 case SCARD_IOCTL_GETREADERICON:
442 case SCARD_IOCTL_GETDEVICETYPEID:
443 case SCARD_IOCTL_GETSTATUSCHANGEA:
444 case SCARD_IOCTL_GETSTATUSCHANGEW:
445 case SCARD_IOCTL_CONNECTA:
446 case SCARD_IOCTL_CONNECTW:
447 case SCARD_IOCTL_RECONNECT:
448 case SCARD_IOCTL_DISCONNECT:
449 case SCARD_IOCTL_BEGINTRANSACTION:
450 case SCARD_IOCTL_ENDTRANSACTION:
451 case SCARD_IOCTL_STATE:
452 case SCARD_IOCTL_STATUSA:
453 case SCARD_IOCTL_STATUSW:
454 case SCARD_IOCTL_TRANSMIT:
455 case SCARD_IOCTL_CONTROL:
456 case SCARD_IOCTL_GETATTRIB:
457 case SCARD_IOCTL_SETATTRIB:
458 case SCARD_IOCTL_GETTRANSMITCOUNT:
459 asyncIrp = TRUE;
460 break;
461 default:
462 break;
463 }
464
465 pContext = smartcard_call_get_context(smartcard->callctx, element->operation.hContext);
466
467 if (!pContext)
468 asyncIrp = FALSE;
469
470 if (!asyncIrp)
471 {
472 UINT error = 0;
473
474 status =
475 smartcard_irp_device_control_call(smartcard->callctx, element->irp->output,
476 &element->irp->IoStatus, &element->operation);
477 smartcard_operation_free(&element->operation, TRUE);
478
479 if (status)
480 {
481 WLog_ERR(TAG, "smartcard_irp_device_control_call failed with error %" PRId32 "!",
482 status);
483 return (UINT32)status;
484 }
485
486 if ((error = smartcard_complete_irp(smartcard, irp, handled)))
487 {
488 WLog_ERR(TAG, "Queue_Enqueue failed!");
489 return error;
490 }
491 }
492 else
493 {
494 if (pContext)
495 {
496 if (!MessageQueue_Post(pContext->IrpQueue, NULL, 0, (void*)element, NULL))
497 {
498 smartcard_operation_free(&element->operation, TRUE);
499 WLog_ERR(TAG, "MessageQueue_Post failed!");
500 return ERROR_INTERNAL_ERROR;
501 }
502 *handled = TRUE;
503 }
504 }
505 }
506 else
507 {
508 UINT ustatus = 0;
509 WLog_ERR(TAG, "Unexpected SmartCard IRP: MajorFunction %s, MinorFunction: 0x%08" PRIX32 "",
510 rdpdr_irp_string(irp->MajorFunction), irp->MinorFunction);
511 irp->IoStatus = STATUS_NOT_SUPPORTED;
512
513 if ((ustatus = smartcard_complete_irp(smartcard, irp, handled)))
514 {
515 WLog_ERR(TAG, "Queue_Enqueue failed!");
516 return ustatus;
517 }
518 }
519
520 return CHANNEL_RC_OK;
521}
522
523static DWORD WINAPI smartcard_thread_func(LPVOID arg)
524{
525 IRP* irp = NULL;
526 DWORD nCount = 0;
527 DWORD status = 0;
528 HANDLE hEvents[1] = { 0 };
529 wMessage message = { 0 };
530 UINT error = CHANNEL_RC_OK;
531 SMARTCARD_DEVICE* smartcard = CAST_FROM_DEVICE(arg);
532
533 if (!smartcard)
534 return ERROR_INVALID_PARAMETER;
535
536 hEvents[nCount++] = MessageQueue_Event(smartcard->IrpQueue);
537
538 while (1)
539 {
540 status = WaitForMultipleObjects(nCount, hEvents, FALSE, INFINITE);
541
542 if (status == WAIT_FAILED)
543 {
544 error = GetLastError();
545 WLog_ERR(TAG, "WaitForMultipleObjects failed with error %" PRIu32 "!", error);
546 break;
547 }
548
549 if (status == WAIT_OBJECT_0)
550 {
551 if (!MessageQueue_Peek(smartcard->IrpQueue, &message, TRUE))
552 {
553 WLog_ERR(TAG, "MessageQueue_Peek failed!");
554 error = ERROR_INTERNAL_ERROR;
555 break;
556 }
557
558 if (message.id == WMQ_QUIT)
559 break;
560
561 irp = (IRP*)message.wParam;
562
563 if (irp)
564 {
565 BOOL handled = FALSE;
566 if ((error = smartcard_process_irp(smartcard, irp, &handled)))
567 {
568 WLog_ERR(TAG, "smartcard_process_irp failed with error %" PRIu32 "!", error);
569 goto out;
570 }
571 if (!handled)
572 {
573 WINPR_ASSERT(irp->Discard);
574 irp->Discard(irp);
575 }
576 }
577 }
578 }
579
580out:
581
582 if (error && smartcard->rdpcontext)
583 setChannelError(smartcard->rdpcontext, error, "smartcard_thread_func reported an error");
584
585 ExitThread(error);
586 return error;
587}
588
594static UINT smartcard_irp_request(DEVICE* device, IRP* irp)
595{
596 SMARTCARD_DEVICE* smartcard = CAST_FROM_DEVICE(device);
597
598 if (!smartcard)
599 return ERROR_INVALID_PARAMETER;
600
601 if (!MessageQueue_Post(smartcard->IrpQueue, NULL, 0, (void*)irp, NULL))
602 {
603 WLog_ERR(TAG, "MessageQueue_Post failed!");
604 return ERROR_INTERNAL_ERROR;
605 }
606
607 return CHANNEL_RC_OK;
608}
609
610static void smartcard_free_irp(void* obj)
611{
612 wMessage* msg = obj;
613 if (!msg)
614 return;
615 if (msg->id != 0)
616 return;
617
618 IRP* irp = (IRP*)msg->wParam;
619 if (!irp)
620 return;
621 WINPR_ASSERT(irp->Discard);
622 irp->Discard(irp);
623}
624
625/* smartcard is always built-in */
626#define DeviceServiceEntry smartcard_DeviceServiceEntry
627
633FREERDP_ENTRY_POINT(UINT VCAPITYPE DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints))
634{
635 SMARTCARD_DEVICE* smartcard = NULL;
636 size_t length = 0;
637 UINT error = CHANNEL_RC_NO_MEMORY;
638
639 if (!sSmartcard)
640 {
641 smartcard = (SMARTCARD_DEVICE*)calloc(1, sizeof(SMARTCARD_DEVICE));
642
643 if (!smartcard)
644 {
645 WLog_ERR(TAG, "calloc failed!");
646 return CHANNEL_RC_NO_MEMORY;
647 }
648
649 smartcard->device.type = RDPDR_DTYP_SMARTCARD;
650 smartcard->device.name = "SCARD";
651 smartcard->device.IRPRequest = smartcard_irp_request;
652 smartcard->device.Init = smartcard_init;
653 smartcard->device.Free = smartcard_free;
654 smartcard->rdpcontext = pEntryPoints->rdpcontext;
655 length = strlen(smartcard->device.name);
656 smartcard->device.data = Stream_New(NULL, length + 1);
657
658 if (!smartcard->device.data)
659 {
660 WLog_ERR(TAG, "Stream_New failed!");
661 goto fail;
662 }
663
664 Stream_Write(smartcard->device.data, "SCARD", 6);
665 smartcard->IrpQueue = MessageQueue_New(NULL);
666
667 if (!smartcard->IrpQueue)
668 {
669 WLog_ERR(TAG, "MessageQueue_New failed!");
670 goto fail;
671 }
672
673 wObject* obj = MessageQueue_Object(smartcard->IrpQueue);
674 WINPR_ASSERT(obj);
675 obj->fnObjectFree = smartcard_free_irp;
676
677 smartcard->rgOutstandingMessages = ListDictionary_New(TRUE);
678
679 if (!smartcard->rgOutstandingMessages)
680 {
681 WLog_ERR(TAG, "ListDictionary_New failed!");
682 goto fail;
683 }
684
685 smartcard->callctx = smartcard_call_context_new(smartcard->rdpcontext->settings);
686 if (!smartcard->callctx)
687 goto fail;
688
689 if (!smarcard_call_set_callbacks(smartcard->callctx, smartcard, smartcard_context_new,
690 smartcard_context_free))
691 goto fail;
692
693 if ((error = pEntryPoints->RegisterDevice(pEntryPoints->devman, &smartcard->device)))
694 {
695 WLog_ERR(TAG, "RegisterDevice failed!");
696 goto fail;
697 }
698
699 smartcard->thread =
700 CreateThread(NULL, 0, smartcard_thread_func, smartcard, CREATE_SUSPENDED, NULL);
701
702 if (!smartcard->thread)
703 {
704 WLog_ERR(TAG, "ListDictionary_New failed!");
705 error = ERROR_INTERNAL_ERROR;
706 goto fail;
707 }
708
709 ResumeThread(smartcard->thread);
710 }
711 else
712 smartcard = sSmartcard;
713
714 if (pEntryPoints->device->Name)
715 {
716 smartcard_call_context_add(smartcard->callctx, pEntryPoints->device->Name);
717 }
718
719 sSmartcard = smartcard;
720 return CHANNEL_RC_OK;
721fail:
722 smartcard_free_(smartcard);
723 return error;
724}
This struct contains function pointer to initialize/free objects.
Definition collections.h:57