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 wObject* obj = MessageQueue_Object(pContext->IrpQueue);
200 WINPR_ASSERT(obj);
201 obj->fnObjectFree = smartcard_operation_queue_free;
202
203 pContext->thread = CreateThread(NULL, 0, smartcard_context_thread, pContext, 0, NULL);
204
205 if (!pContext->thread)
206 {
207 WLog_ERR(TAG, "CreateThread failed!");
208 goto fail;
209 }
210
211 return pContext;
212fail:
213 smartcard_context_free(pContext);
214 return NULL;
215}
216
217void smartcard_context_free(void* pCtx)
218{
219 SMARTCARD_CONTEXT* pContext = pCtx;
220
221 if (!pContext)
222 return;
223
224 /* cancel blocking calls like SCardGetStatusChange */
225 WINPR_ASSERT(pContext->smartcard);
226 smartcard_call_cancel_context(pContext->smartcard->callctx, pContext->hContext);
227
228 if (pContext->IrpQueue)
229 {
230 if (MessageQueue_PostQuit(pContext->IrpQueue, 0))
231 {
232 if (WaitForSingleObject(pContext->thread, INFINITE) == WAIT_FAILED)
233 WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "!", GetLastError());
234
235 (void)CloseHandle(pContext->thread);
236 }
237 MessageQueue_Free(pContext->IrpQueue);
238 }
239 smartcard_call_release_context(pContext->smartcard->callctx, pContext->hContext);
240 free(pContext);
241}
242
243static void smartcard_release_all_contexts(SMARTCARD_DEVICE* smartcard)
244{
245 smartcard_call_cancel_all_context(smartcard->callctx);
246}
247
248static UINT smartcard_free_(SMARTCARD_DEVICE* smartcard)
249{
250 if (!smartcard)
251 return CHANNEL_RC_OK;
252
253 if (smartcard->IrpQueue)
254 {
255 MessageQueue_Free(smartcard->IrpQueue);
256 (void)CloseHandle(smartcard->thread);
257 }
258
259 Stream_Free(smartcard->device.data, TRUE);
260 ListDictionary_Free(smartcard->rgOutstandingMessages);
261
262 smartcard_call_context_free(smartcard->callctx);
263
264 free(smartcard);
265 return CHANNEL_RC_OK;
266}
272static UINT smartcard_free(DEVICE* device)
273{
274 SMARTCARD_DEVICE* smartcard = CAST_FROM_DEVICE(device);
275
276 if (!smartcard)
277 return ERROR_INVALID_PARAMETER;
278
283 smartcard_release_all_contexts(smartcard);
284
285 /* Stopping all threads and cancelling all IRPs */
286
287 if (smartcard->IrpQueue)
288 {
289 if (MessageQueue_PostQuit(smartcard->IrpQueue, 0) &&
290 (WaitForSingleObject(smartcard->thread, INFINITE) == WAIT_FAILED))
291 {
292 DWORD error = GetLastError();
293 WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "!", error);
294 return error;
295 }
296 }
297
298 if (sSmartcard == smartcard)
299 sSmartcard = NULL;
300
301 return smartcard_free_(smartcard);
302}
303
314static UINT smartcard_init(DEVICE* device)
315{
316 SMARTCARD_DEVICE* smartcard = CAST_FROM_DEVICE(device);
317
318 if (!smartcard)
319 return ERROR_INVALID_PARAMETER;
320
321 smartcard_release_all_contexts(smartcard);
322 return CHANNEL_RC_OK;
323}
324
330UINT smartcard_complete_irp(SMARTCARD_DEVICE* smartcard, IRP* irp, BOOL* handled)
331{
332 WINPR_ASSERT(smartcard);
333 WINPR_ASSERT(irp);
334 WINPR_ASSERT(handled);
335
336 uintptr_t key = (uintptr_t)irp->CompletionId + 1;
337 ListDictionary_Remove(smartcard->rgOutstandingMessages, (void*)key);
338
339 WINPR_ASSERT(irp->Complete);
340 *handled = TRUE;
341 return irp->Complete(irp);
342}
343
354static UINT smartcard_process_irp(SMARTCARD_DEVICE* smartcard, IRP* irp, BOOL* handled)
355{
356 LONG status = 0;
357 BOOL asyncIrp = FALSE;
358 SMARTCARD_CONTEXT* pContext = NULL;
359
360 WINPR_ASSERT(smartcard);
361 WINPR_ASSERT(handled);
362 WINPR_ASSERT(irp);
363 WINPR_ASSERT(irp->Complete);
364
365 uintptr_t key = (uintptr_t)irp->CompletionId + 1;
366
367 if (!ListDictionary_Add(smartcard->rgOutstandingMessages, (void*)key, irp))
368 {
369 WLog_ERR(TAG, "ListDictionary_Add failed!");
370 return ERROR_INTERNAL_ERROR;
371 }
372
373 if (irp->MajorFunction == IRP_MJ_DEVICE_CONTROL)
374 {
375 scard_irp_queue_element* element = calloc(1, sizeof(scard_irp_queue_element));
376 if (!element)
377 return ERROR_OUTOFMEMORY;
378
379 element->irp = irp;
380 element->operation.completionID = irp->CompletionId;
381
382 status = smartcard_irp_device_control_decode(irp->input, irp->CompletionId, irp->FileId,
383 &element->operation);
384
385 if (status != SCARD_S_SUCCESS)
386 {
387 UINT error = 0;
388
389 smartcard_operation_free(&element->operation, TRUE);
390 irp->IoStatus = STATUS_UNSUCCESSFUL;
391
392 if ((error = smartcard_complete_irp(smartcard, irp, handled)))
393 {
394 WLog_ERR(TAG, "Queue_Enqueue failed!");
395 return error;
396 }
397
398 return CHANNEL_RC_OK;
399 }
400
401 asyncIrp = TRUE;
402
403 switch (element->operation.ioControlCode)
404 {
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:
411 asyncIrp = FALSE;
412 break;
413
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:
456 asyncIrp = TRUE;
457 break;
458 default:
459 break;
460 }
461
462 pContext = smartcard_call_get_context(smartcard->callctx, element->operation.hContext);
463
464 if (!pContext)
465 asyncIrp = FALSE;
466
467 if (!asyncIrp)
468 {
469 UINT error = 0;
470
471 status =
472 smartcard_irp_device_control_call(smartcard->callctx, element->irp->output,
473 &element->irp->IoStatus, &element->operation);
474 smartcard_operation_free(&element->operation, TRUE);
475
476 if (status)
477 {
478 WLog_ERR(TAG, "smartcard_irp_device_control_call failed with error %" PRId32 "!",
479 status);
480 return (UINT32)status;
481 }
482
483 if ((error = smartcard_complete_irp(smartcard, irp, handled)))
484 {
485 WLog_ERR(TAG, "Queue_Enqueue failed!");
486 return error;
487 }
488 }
489 else
490 {
491 if (pContext)
492 {
493 if (!MessageQueue_Post(pContext->IrpQueue, NULL, 0, (void*)element, NULL))
494 {
495 smartcard_operation_free(&element->operation, TRUE);
496 WLog_ERR(TAG, "MessageQueue_Post failed!");
497 return ERROR_INTERNAL_ERROR;
498 }
499 *handled = TRUE;
500 }
501 }
502 }
503 else
504 {
505 UINT ustatus = 0;
506 WLog_ERR(TAG, "Unexpected SmartCard IRP: MajorFunction %s, MinorFunction: 0x%08" PRIX32 "",
507 rdpdr_irp_string(irp->MajorFunction), irp->MinorFunction);
508 irp->IoStatus = STATUS_NOT_SUPPORTED;
509
510 if ((ustatus = smartcard_complete_irp(smartcard, irp, handled)))
511 {
512 WLog_ERR(TAG, "Queue_Enqueue failed!");
513 return ustatus;
514 }
515 }
516
517 return CHANNEL_RC_OK;
518}
519
520static DWORD WINAPI smartcard_thread_func(LPVOID arg)
521{
522 IRP* irp = NULL;
523 DWORD nCount = 0;
524 DWORD status = 0;
525 HANDLE hEvents[1] = { 0 };
526 wMessage message = { 0 };
527 UINT error = CHANNEL_RC_OK;
528 SMARTCARD_DEVICE* smartcard = CAST_FROM_DEVICE(arg);
529
530 if (!smartcard)
531 return ERROR_INVALID_PARAMETER;
532
533 hEvents[nCount++] = MessageQueue_Event(smartcard->IrpQueue);
534
535 while (1)
536 {
537 status = WaitForMultipleObjects(nCount, hEvents, FALSE, INFINITE);
538
539 if (status == WAIT_FAILED)
540 {
541 error = GetLastError();
542 WLog_ERR(TAG, "WaitForMultipleObjects failed with error %" PRIu32 "!", error);
543 break;
544 }
545
546 if (status == WAIT_OBJECT_0)
547 {
548 if (!MessageQueue_Peek(smartcard->IrpQueue, &message, TRUE))
549 {
550 WLog_ERR(TAG, "MessageQueue_Peek failed!");
551 error = ERROR_INTERNAL_ERROR;
552 break;
553 }
554
555 if (message.id == WMQ_QUIT)
556 break;
557
558 irp = (IRP*)message.wParam;
559
560 if (irp)
561 {
562 BOOL handled = FALSE;
563 if ((error = smartcard_process_irp(smartcard, irp, &handled)))
564 {
565 WLog_ERR(TAG, "smartcard_process_irp failed with error %" PRIu32 "!", error);
566 goto out;
567 }
568 if (!handled)
569 {
570 WINPR_ASSERT(irp->Discard);
571 irp->Discard(irp);
572 }
573 }
574 }
575 }
576
577out:
578
579 if (error && smartcard->rdpcontext)
580 setChannelError(smartcard->rdpcontext, error, "smartcard_thread_func reported an error");
581
582 ExitThread(error);
583 return error;
584}
585
591static UINT smartcard_irp_request(DEVICE* device, IRP* irp)
592{
593 SMARTCARD_DEVICE* smartcard = CAST_FROM_DEVICE(device);
594
595 if (!smartcard)
596 return ERROR_INVALID_PARAMETER;
597
598 if (!MessageQueue_Post(smartcard->IrpQueue, NULL, 0, (void*)irp, NULL))
599 {
600 WLog_ERR(TAG, "MessageQueue_Post failed!");
601 return ERROR_INTERNAL_ERROR;
602 }
603
604 return CHANNEL_RC_OK;
605}
606
607static void smartcard_free_irp(void* obj)
608{
609 wMessage* msg = obj;
610 if (!msg)
611 return;
612 if (msg->id != 0)
613 return;
614
615 IRP* irp = (IRP*)msg->wParam;
616 if (!irp)
617 return;
618 WINPR_ASSERT(irp->Discard);
619 irp->Discard(irp);
620}
621
622/* smartcard is always built-in */
623#define DeviceServiceEntry smartcard_DeviceServiceEntry
624
630FREERDP_ENTRY_POINT(UINT VCAPITYPE DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints))
631{
632 SMARTCARD_DEVICE* smartcard = NULL;
633 size_t length = 0;
634 UINT error = CHANNEL_RC_NO_MEMORY;
635
636 if (!sSmartcard)
637 {
638 smartcard = (SMARTCARD_DEVICE*)calloc(1, sizeof(SMARTCARD_DEVICE));
639
640 if (!smartcard)
641 {
642 WLog_ERR(TAG, "calloc failed!");
643 return CHANNEL_RC_NO_MEMORY;
644 }
645
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);
654
655 if (!smartcard->device.data)
656 {
657 WLog_ERR(TAG, "Stream_New failed!");
658 goto fail;
659 }
660
661 Stream_Write(smartcard->device.data, "SCARD", 6);
662 smartcard->IrpQueue = MessageQueue_New(NULL);
663
664 if (!smartcard->IrpQueue)
665 {
666 WLog_ERR(TAG, "MessageQueue_New failed!");
667 goto fail;
668 }
669
670 wObject* obj = MessageQueue_Object(smartcard->IrpQueue);
671 WINPR_ASSERT(obj);
672 obj->fnObjectFree = smartcard_free_irp;
673
674 smartcard->rgOutstandingMessages = ListDictionary_New(TRUE);
675
676 if (!smartcard->rgOutstandingMessages)
677 {
678 WLog_ERR(TAG, "ListDictionary_New failed!");
679 goto fail;
680 }
681
682 smartcard->callctx = smartcard_call_context_new(smartcard->rdpcontext->settings);
683 if (!smartcard->callctx)
684 goto fail;
685
686 if (!smarcard_call_set_callbacks(smartcard->callctx, smartcard, smartcard_context_new,
687 smartcard_context_free))
688 goto fail;
689
690 if ((error = pEntryPoints->RegisterDevice(pEntryPoints->devman, &smartcard->device)))
691 {
692 WLog_ERR(TAG, "RegisterDevice failed!");
693 goto fail;
694 }
695
696 smartcard->thread =
697 CreateThread(NULL, 0, smartcard_thread_func, smartcard, CREATE_SUSPENDED, NULL);
698
699 if (!smartcard->thread)
700 {
701 WLog_ERR(TAG, "ListDictionary_New failed!");
702 error = ERROR_INTERNAL_ERROR;
703 goto fail;
704 }
705
706 ResumeThread(smartcard->thread);
707 }
708 else
709 smartcard = sSmartcard;
710
711 if (pEntryPoints->device->Name)
712 {
713 smartcard_call_context_add(smartcard->callctx, pEntryPoints->device->Name);
714 }
715
716 sSmartcard = smartcard;
717 return CHANNEL_RC_OK;
718fail:
719 smartcard_free_(smartcard);
720 return error;
721}
This struct contains function pointer to initialize/free objects.
Definition collections.h:57