FreeRDP
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 
42 typedef struct
43 {
44  SMARTCARD_OPERATION operation;
45  IRP* irp;
46 } scard_irp_queue_element;
47 
48 static SMARTCARD_DEVICE* sSmartcard = NULL;
49 
50 static void smartcard_context_free(void* pCtx);
51 
52 static UINT smartcard_complete_irp(SMARTCARD_DEVICE* smartcard, IRP* irp, BOOL* handled);
53 
54 static 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 
75 static 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(status);
159  return error;
160 }
161 
162 static 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 
179 static 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;
212 fail:
213  smartcard_context_free(pContext);
214  return NULL;
215 }
216 
217 void 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 
243 static void smartcard_release_all_contexts(SMARTCARD_DEVICE* smartcard)
244 {
245  smartcard_call_cancel_all_context(smartcard->callctx);
246 }
247 
248 static 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 }
272 static 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 
314 static 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 
330 UINT 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 
354 static 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 = (UINT32)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 = (UINT32)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 
520 static 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 
577 out:
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 
591 static 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 
607 static 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 
630 FREERDP_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;
718 fail:
719  smartcard_free_(smartcard);
720  return error;
721 }
This struct contains function pointer to initialize/free objects.
Definition: collections.h:57