Coverage Report

Created: 2026-04-12 07:03

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/FreeRDP/channels/smartcard/client/smartcard_main.c
Line
Count
Source
1
/**
2
 * FreeRDP: A Remote Desktop Protocol Implementation
3
 * Smartcard Device Service Virtual Channel
4
 *
5
 * Copyright 2011 O.S. Systems Software Ltda.
6
 * Copyright 2011 Eduardo Fiss Beloni <beloni@ossystems.com.br>
7
 * Copyright 2011 Anthony Tong <atong@trustedcs.com>
8
 * Copyright 2015 Thincast Technologies GmbH
9
 * Copyright 2015 DI (FH) Martin Haimberger <martin.haimberger@thincast.com>
10
 * Copyright 2016 David PHAM-VAN <d.phamvan@inuvika.com>
11
 *
12
 * Licensed under the Apache License, Version 2.0 (the "License");
13
 * you may not use this file except in compliance with the License.
14
 * You may obtain a copy of the License at
15
 *
16
 *     http://www.apache.org/licenses/LICENSE-2.0
17
 *
18
 * Unless required by applicable law or agreed to in writing, software
19
 * distributed under the License is distributed on an "AS IS" BASIS,
20
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21
 * See the License for the specific language governing permissions and
22
 * limitations under the License.
23
 */
24
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
0
#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 void smartcard_context_free(void* pCtx);
49
50
static UINT smartcard_complete_irp(SMARTCARD_DEVICE* smartcard, IRP* irp, BOOL* handled);
51
52
static SMARTCARD_DEVICE* cast_device_from(DEVICE* device, const char* fkt, const char* file,
53
                                          size_t line)
54
0
{
55
0
  if (!device)
56
0
  {
57
0
    WLog_ERR(TAG, "%s [%s:%" PRIuz "] Called smartcard channel with nullptr device", fkt, file,
58
0
             line);
59
0
    return nullptr;
60
0
  }
61
62
0
  if (device->type != RDPDR_DTYP_SMARTCARD)
63
0
  {
64
0
    WLog_ERR(TAG,
65
0
             "%s [%s:%" PRIuz "] Called smartcard channel with invalid device of type %" PRIx32,
66
0
             fkt, file, line, device->type);
67
0
    return nullptr;
68
0
  }
69
70
0
  return (SMARTCARD_DEVICE*)device;
71
0
}
72
73
static DWORD WINAPI smartcard_context_thread(LPVOID arg)
74
0
{
75
0
  SMARTCARD_CONTEXT* pContext = (SMARTCARD_CONTEXT*)arg;
76
0
  DWORD nCount = 0;
77
0
  DWORD waitStatus = 0;
78
0
  HANDLE hEvents[2] = WINPR_C_ARRAY_INIT;
79
0
  wMessage message = WINPR_C_ARRAY_INIT;
80
0
  SMARTCARD_DEVICE* smartcard = nullptr;
81
0
  UINT error = CHANNEL_RC_OK;
82
0
  smartcard = pContext->smartcard;
83
84
0
  hEvents[nCount++] = MessageQueue_Event(pContext->IrpQueue);
85
86
0
  while (1)
87
0
  {
88
0
    waitStatus = WaitForMultipleObjects(nCount, hEvents, FALSE, INFINITE);
89
90
0
    if (waitStatus == WAIT_FAILED)
91
0
    {
92
0
      error = GetLastError();
93
0
      WLog_ERR(TAG, "WaitForMultipleObjects failed with error %" PRIu32 "!", error);
94
0
      break;
95
0
    }
96
97
0
    waitStatus = WaitForSingleObject(MessageQueue_Event(pContext->IrpQueue), 0);
98
99
0
    if (waitStatus == WAIT_FAILED)
100
0
    {
101
0
      error = GetLastError();
102
0
      WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "!", error);
103
0
      break;
104
0
    }
105
106
0
    if (waitStatus == WAIT_OBJECT_0)
107
0
    {
108
0
      scard_irp_queue_element* element = nullptr;
109
110
0
      if (!MessageQueue_Peek(pContext->IrpQueue, &message, TRUE))
111
0
      {
112
0
        WLog_ERR(TAG, "MessageQueue_Peek failed!");
113
0
        error = ERROR_INTERNAL_ERROR;
114
0
        break;
115
0
      }
116
117
0
      if (message.id == WMQ_QUIT)
118
0
        break;
119
120
0
      element = (scard_irp_queue_element*)message.wParam;
121
122
0
      if (element)
123
0
      {
124
0
        BOOL handled = FALSE;
125
0
        WINPR_ASSERT(smartcard);
126
127
0
        const LONG status =
128
0
            smartcard_irp_device_control_call(smartcard->callctx, element->irp->output,
129
0
                                              &element->irp->IoStatus, &element->operation);
130
0
        if (status)
131
0
        {
132
0
          element->irp->Discard(element->irp);
133
0
          smartcard_operation_free(&element->operation, TRUE);
134
0
          WLog_ERR(TAG,
135
0
                   "smartcard_irp_device_control_call failed with error %s [%" PRId32 "]",
136
0
                   NtStatus2Tag(status), status);
137
0
          error = (UINT)status;
138
0
          break;
139
0
        }
140
141
0
        error = smartcard_complete_irp(smartcard, element->irp, &handled);
142
0
        if (!handled)
143
0
          element->irp->Discard(element->irp);
144
0
        smartcard_operation_free(&element->operation, TRUE);
145
146
0
        if (error)
147
0
        {
148
0
          WLog_ERR(TAG, "smartcard_complete_irp failed with %s [%" PRIu32 "]",
149
0
                   WTSErrorToString(error), error);
150
0
          break;
151
0
        }
152
0
      }
153
0
    }
154
0
  }
155
156
0
  if (error && smartcard->rdpcontext)
157
0
    setChannelError(smartcard->rdpcontext, error, "smartcard_context_thread reported an error");
158
159
0
  ExitThread(error);
160
0
  return error;
161
0
}
162
163
static void smartcard_operation_queue_free(void* obj)
164
0
{
165
0
  wMessage* msg = obj;
166
0
  if (!msg)
167
0
    return;
168
0
  if (msg->id != 0)
169
0
    return;
170
171
0
  scard_irp_queue_element* element = (scard_irp_queue_element*)msg->wParam;
172
0
  if (!element)
173
0
    return;
174
0
  WINPR_ASSERT(element->irp);
175
0
  WINPR_ASSERT(element->irp->Discard);
176
0
  element->irp->Discard(element->irp);
177
0
  smartcard_operation_free(&element->operation, TRUE);
178
0
}
179
180
static void* smartcard_context_new(void* smartcard, SCARDCONTEXT hContext)
181
0
{
182
0
  SMARTCARD_CONTEXT* pContext = (SMARTCARD_CONTEXT*)calloc(1, sizeof(SMARTCARD_CONTEXT));
183
184
0
  WLog_VRB(TAG, "smartcard context create %p", (const void*)pContext);
185
0
  if (!pContext)
186
0
  {
187
0
    WLog_ERR(TAG, "calloc failed!");
188
0
    return pContext;
189
0
  }
190
191
0
  pContext->smartcard = smartcard;
192
0
  pContext->hContext = hContext;
193
0
  pContext->IrpQueue = MessageQueue_New(nullptr);
194
195
0
  if (!pContext->IrpQueue)
196
0
  {
197
0
    WLog_ERR(TAG, "MessageQueue_New failed!");
198
0
    goto fail;
199
0
  }
200
201
0
  {
202
0
    wObject* obj = MessageQueue_Object(pContext->IrpQueue);
203
0
    WINPR_ASSERT(obj);
204
0
    obj->fnObjectFree = smartcard_operation_queue_free;
205
0
  }
206
207
0
  pContext->thread = CreateThread(nullptr, 0, smartcard_context_thread, pContext, 0, nullptr);
208
209
0
  if (!pContext->thread)
210
0
  {
211
0
    WLog_ERR(TAG, "CreateThread failed!");
212
0
    goto fail;
213
0
  }
214
215
0
  return pContext;
216
0
fail:
217
0
  smartcard_context_free(pContext);
218
0
  return nullptr;
219
0
}
220
221
void smartcard_context_free(void* pCtx)
222
0
{
223
0
  SMARTCARD_CONTEXT* pContext = pCtx;
224
225
0
  WLog_VRB(TAG, "smartcard context destroy %p", pCtx);
226
0
  if (!pContext)
227
0
    return;
228
229
  /* cancel blocking calls like SCardGetStatusChange */
230
0
  WINPR_ASSERT(pContext->smartcard);
231
0
  smartcard_call_cancel_context(pContext->smartcard->callctx, pContext->hContext);
232
233
0
  if (pContext->IrpQueue)
234
0
  {
235
0
    if (MessageQueue_PostQuit(pContext->IrpQueue, 0))
236
0
    {
237
0
      if (WaitForSingleObject(pContext->thread, INFINITE) == WAIT_FAILED)
238
0
        WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "!", GetLastError());
239
240
0
      (void)CloseHandle(pContext->thread);
241
0
    }
242
0
    MessageQueue_Free(pContext->IrpQueue);
243
0
  }
244
0
  smartcard_call_release_context(pContext->smartcard->callctx, pContext->hContext);
245
0
  free(pContext);
246
0
}
247
248
static UINT smartcard_free_(SMARTCARD_DEVICE* smartcard)
249
0
{
250
0
  if (!smartcard)
251
0
    return CHANNEL_RC_OK;
252
253
0
  if (smartcard->IrpQueue)
254
0
  {
255
0
    MessageQueue_Free(smartcard->IrpQueue);
256
0
    (void)CloseHandle(smartcard->thread);
257
0
  }
258
259
0
  Stream_Free(smartcard->device.data, TRUE);
260
0
  ListDictionary_Free(smartcard->rgOutstandingMessages);
261
262
0
  smartcard_call_context_free(smartcard->callctx);
263
264
0
  free(smartcard);
265
0
  return CHANNEL_RC_OK;
266
0
}
267
/**
268
 * Function description
269
 *
270
 * @return 0 on success, otherwise a Win32 error code
271
 */
272
static UINT smartcard_free(DEVICE* device)
273
0
{
274
0
  SMARTCARD_DEVICE* smartcard = CAST_FROM_DEVICE(device);
275
276
0
  WLog_VRB(TAG, "smartcard device destroy: %p", (const void*)smartcard);
277
0
  if (!smartcard)
278
0
    return ERROR_INVALID_PARAMETER;
279
280
  /**
281
   * Calling smartcard_release_all_contexts to unblock all operations waiting for transactions
282
   * to unlock.
283
   */
284
0
  smartcard_call_cancel_all_context(smartcard->callctx);
285
286
  /* Stopping all threads and cancelling all IRPs */
287
288
0
  if (smartcard->IrpQueue)
289
0
  {
290
0
    if (MessageQueue_PostQuit(smartcard->IrpQueue, 0) &&
291
0
        (WaitForSingleObject(smartcard->thread, INFINITE) == WAIT_FAILED))
292
0
    {
293
0
      DWORD error = GetLastError();
294
0
      WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "!", error);
295
0
      return error;
296
0
    }
297
0
  }
298
299
0
  return smartcard_free_(smartcard);
300
0
}
301
302
/**
303
 * Initialization occurs when the protocol server sends a device announce message.
304
 * At that time, we need to cancel all outstanding IRPs.
305
 */
306
307
/**
308
 * Function description
309
 *
310
 * @return 0 on success, otherwise a Win32 error code
311
 */
312
static UINT smartcard_init(DEVICE* device)
313
0
{
314
0
  SMARTCARD_DEVICE* smartcard = CAST_FROM_DEVICE(device);
315
316
0
  WLog_VRB(TAG, "smartcard device init %p", (const void*)smartcard);
317
0
  if (!smartcard)
318
0
    return ERROR_INVALID_PARAMETER;
319
320
0
  smartcard_call_cancel_all_context(smartcard->callctx);
321
0
  return CHANNEL_RC_OK;
322
0
}
323
324
/**
325
 * Function description
326
 *
327
 * @return 0 on success, otherwise a Win32 error code
328
 */
329
UINT smartcard_complete_irp(SMARTCARD_DEVICE* smartcard, IRP* irp, BOOL* handled)
330
0
{
331
0
  WINPR_ASSERT(smartcard);
332
0
  WINPR_ASSERT(irp);
333
0
  WINPR_ASSERT(handled);
334
335
0
  uintptr_t key = (uintptr_t)irp->CompletionId + 1;
336
0
  ListDictionary_Remove(smartcard->rgOutstandingMessages, (void*)key);
337
338
0
  WINPR_ASSERT(irp->Complete);
339
0
  *handled = TRUE;
340
0
  return irp->Complete(irp);
341
0
}
342
343
/**
344
 * Multiple threads and SCardGetStatusChange:
345
 * http://musclecard.996296.n3.nabble.com/Multiple-threads-and-SCardGetStatusChange-td4430.html
346
 */
347
348
/**
349
 * Function description
350
 *
351
 * @return 0 on success, otherwise a Win32 error code
352
 */
353
static UINT smartcard_process_irp(SMARTCARD_DEVICE* smartcard, IRP* irp, BOOL* handled)
354
0
{
355
0
  LONG status = 0;
356
0
  BOOL asyncIrp = FALSE;
357
0
  SMARTCARD_CONTEXT* pContext = nullptr;
358
359
0
  WINPR_ASSERT(smartcard);
360
0
  WINPR_ASSERT(handled);
361
0
  WINPR_ASSERT(irp);
362
0
  WINPR_ASSERT(irp->Complete);
363
364
0
  uintptr_t key = (uintptr_t)irp->CompletionId + 1;
365
366
0
  if (!ListDictionary_Add(smartcard->rgOutstandingMessages, (void*)key, irp))
367
0
  {
368
0
    WLog_ERR(TAG, "ListDictionary_Add failed!");
369
0
    return ERROR_INTERNAL_ERROR;
370
0
  }
371
372
0
  if (irp->MajorFunction == IRP_MJ_DEVICE_CONTROL)
373
0
  {
374
0
    scard_irp_queue_element* element = calloc(1, sizeof(scard_irp_queue_element));
375
0
    if (!element)
376
0
      return ERROR_OUTOFMEMORY;
377
378
0
    element->irp = irp;
379
0
    element->operation.completionID = irp->CompletionId;
380
381
0
    status = smartcard_irp_device_control_decode(irp->input, irp->CompletionId, irp->FileId,
382
0
                                                 &element->operation);
383
384
0
    if (status != SCARD_S_SUCCESS)
385
0
    {
386
0
      UINT error = 0;
387
388
0
      smartcard_operation_free(&element->operation, TRUE);
389
0
      irp->IoStatus = STATUS_UNSUCCESSFUL;
390
391
0
      if ((error = smartcard_complete_irp(smartcard, irp, handled)))
392
0
      {
393
0
        WLog_ERR(TAG, "Queue_Enqueue failed!");
394
0
        return error;
395
0
      }
396
397
0
      return CHANNEL_RC_OK;
398
0
    }
399
400
0
    asyncIrp = TRUE;
401
402
0
    switch (element->operation.ioControlCode)
403
0
    {
404
0
      case SCARD_IOCTL_ESTABLISHCONTEXT:
405
0
      case SCARD_IOCTL_RELEASECONTEXT:
406
0
      case SCARD_IOCTL_ISVALIDCONTEXT:
407
0
      case SCARD_IOCTL_CANCEL:
408
0
      case SCARD_IOCTL_ACCESSSTARTEDEVENT:
409
0
      case SCARD_IOCTL_RELEASETARTEDEVENT:
410
0
        asyncIrp = FALSE;
411
0
        break;
412
413
0
      case SCARD_IOCTL_LISTREADERGROUPSA:
414
0
      case SCARD_IOCTL_LISTREADERGROUPSW:
415
0
      case SCARD_IOCTL_LISTREADERSA:
416
0
      case SCARD_IOCTL_LISTREADERSW:
417
0
      case SCARD_IOCTL_INTRODUCEREADERGROUPA:
418
0
      case SCARD_IOCTL_INTRODUCEREADERGROUPW:
419
0
      case SCARD_IOCTL_FORGETREADERGROUPA:
420
0
      case SCARD_IOCTL_FORGETREADERGROUPW:
421
0
      case SCARD_IOCTL_INTRODUCEREADERA:
422
0
      case SCARD_IOCTL_INTRODUCEREADERW:
423
0
      case SCARD_IOCTL_FORGETREADERA:
424
0
      case SCARD_IOCTL_FORGETREADERW:
425
0
      case SCARD_IOCTL_ADDREADERTOGROUPA:
426
0
      case SCARD_IOCTL_ADDREADERTOGROUPW:
427
0
      case SCARD_IOCTL_REMOVEREADERFROMGROUPA:
428
0
      case SCARD_IOCTL_REMOVEREADERFROMGROUPW:
429
0
      case SCARD_IOCTL_LOCATECARDSA:
430
0
      case SCARD_IOCTL_LOCATECARDSW:
431
0
      case SCARD_IOCTL_LOCATECARDSBYATRA:
432
0
      case SCARD_IOCTL_LOCATECARDSBYATRW:
433
0
      case SCARD_IOCTL_READCACHEA:
434
0
      case SCARD_IOCTL_READCACHEW:
435
0
      case SCARD_IOCTL_WRITECACHEA:
436
0
      case SCARD_IOCTL_WRITECACHEW:
437
0
      case SCARD_IOCTL_GETREADERICON:
438
0
      case SCARD_IOCTL_GETDEVICETYPEID:
439
0
      case SCARD_IOCTL_GETSTATUSCHANGEA:
440
0
      case SCARD_IOCTL_GETSTATUSCHANGEW:
441
0
      case SCARD_IOCTL_CONNECTA:
442
0
      case SCARD_IOCTL_CONNECTW:
443
0
      case SCARD_IOCTL_RECONNECT:
444
0
      case SCARD_IOCTL_DISCONNECT:
445
0
      case SCARD_IOCTL_BEGINTRANSACTION:
446
0
      case SCARD_IOCTL_ENDTRANSACTION:
447
0
      case SCARD_IOCTL_STATE:
448
0
      case SCARD_IOCTL_STATUSA:
449
0
      case SCARD_IOCTL_STATUSW:
450
0
      case SCARD_IOCTL_TRANSMIT:
451
0
      case SCARD_IOCTL_CONTROL:
452
0
      case SCARD_IOCTL_GETATTRIB:
453
0
      case SCARD_IOCTL_SETATTRIB:
454
0
      case SCARD_IOCTL_GETTRANSMITCOUNT:
455
0
        asyncIrp = TRUE;
456
0
        break;
457
0
      default:
458
0
        break;
459
0
    }
460
461
0
    pContext = smartcard_call_get_context(smartcard->callctx, element->operation.hContext);
462
463
0
    if (!pContext)
464
0
      asyncIrp = FALSE;
465
466
0
    if (!asyncIrp)
467
0
    {
468
0
      UINT error = 0;
469
470
0
      status =
471
0
          smartcard_irp_device_control_call(smartcard->callctx, element->irp->output,
472
0
                                            &element->irp->IoStatus, &element->operation);
473
0
      smartcard_operation_free(&element->operation, TRUE);
474
475
0
      if (status)
476
0
      {
477
0
        WLog_ERR(TAG, "smartcard_irp_device_control_call failed with error %" PRId32 "!",
478
0
                 status);
479
0
        return (UINT32)status;
480
0
      }
481
482
0
      if ((error = smartcard_complete_irp(smartcard, irp, handled)))
483
0
      {
484
0
        WLog_ERR(TAG, "Queue_Enqueue failed!");
485
0
        return error;
486
0
      }
487
0
    }
488
0
    else
489
0
    {
490
0
      if (pContext)
491
0
      {
492
0
        if (!MessageQueue_Post(pContext->IrpQueue, nullptr, 0, (void*)element, nullptr))
493
0
        {
494
0
          smartcard_operation_free(&element->operation, TRUE);
495
0
          WLog_ERR(TAG, "MessageQueue_Post failed!");
496
0
          return ERROR_INTERNAL_ERROR;
497
0
        }
498
0
        *handled = TRUE;
499
0
      }
500
0
    }
501
0
  }
502
0
  else
503
0
  {
504
0
    UINT ustatus = 0;
505
0
    WLog_ERR(TAG, "Unexpected SmartCard IRP: MajorFunction %s, MinorFunction: 0x%08" PRIX32 "",
506
0
             rdpdr_irp_string(irp->MajorFunction), irp->MinorFunction);
507
0
    irp->IoStatus = STATUS_NOT_SUPPORTED;
508
509
0
    if ((ustatus = smartcard_complete_irp(smartcard, irp, handled)))
510
0
    {
511
0
      WLog_ERR(TAG, "Queue_Enqueue failed!");
512
0
      return ustatus;
513
0
    }
514
0
  }
515
516
0
  return CHANNEL_RC_OK;
517
0
}
518
519
static DWORD WINAPI smartcard_thread_func(LPVOID arg)
520
0
{
521
0
  IRP* irp = nullptr;
522
0
  DWORD nCount = 0;
523
0
  DWORD status = 0;
524
0
  HANDLE hEvents[1] = WINPR_C_ARRAY_INIT;
525
0
  wMessage message = WINPR_C_ARRAY_INIT;
526
0
  UINT error = CHANNEL_RC_OK;
527
0
  SMARTCARD_DEVICE* smartcard = CAST_FROM_DEVICE(arg);
528
529
0
  if (!smartcard)
530
0
    return ERROR_INVALID_PARAMETER;
531
532
0
  hEvents[nCount++] = MessageQueue_Event(smartcard->IrpQueue);
533
534
0
  while (1)
535
0
  {
536
0
    status = WaitForMultipleObjects(nCount, hEvents, FALSE, INFINITE);
537
538
0
    if (status == WAIT_FAILED)
539
0
    {
540
0
      error = GetLastError();
541
0
      WLog_ERR(TAG, "WaitForMultipleObjects failed with error %" PRIu32 "!", error);
542
0
      break;
543
0
    }
544
545
0
    if (status == WAIT_OBJECT_0)
546
0
    {
547
0
      if (!MessageQueue_Peek(smartcard->IrpQueue, &message, TRUE))
548
0
      {
549
0
        WLog_ERR(TAG, "MessageQueue_Peek failed!");
550
0
        error = ERROR_INTERNAL_ERROR;
551
0
        break;
552
0
      }
553
554
0
      if (message.id == WMQ_QUIT)
555
0
        break;
556
557
0
      irp = (IRP*)message.wParam;
558
559
0
      if (irp)
560
0
      {
561
0
        BOOL handled = FALSE;
562
0
        if ((error = smartcard_process_irp(smartcard, irp, &handled)))
563
0
        {
564
0
          WLog_ERR(TAG, "smartcard_process_irp failed with error %" PRIu32 "!", error);
565
0
          goto out;
566
0
        }
567
0
        if (!handled)
568
0
        {
569
0
          WINPR_ASSERT(irp->Discard);
570
0
          irp->Discard(irp);
571
0
        }
572
0
      }
573
0
    }
574
0
  }
575
576
0
out:
577
578
0
  if (error && smartcard->rdpcontext)
579
0
    setChannelError(smartcard->rdpcontext, error, "smartcard_thread_func reported an error");
580
581
0
  ExitThread(error);
582
0
  return error;
583
0
}
584
585
/**
586
 * Function description
587
 *
588
 * @return 0 on success, otherwise a Win32 error code
589
 */
590
static UINT smartcard_irp_request(DEVICE* device, IRP* irp)
591
0
{
592
0
  SMARTCARD_DEVICE* smartcard = CAST_FROM_DEVICE(device);
593
594
0
  if (!smartcard)
595
0
  {
596
0
    irp->Discard(irp);
597
0
    return ERROR_INVALID_PARAMETER;
598
0
  }
599
600
0
  if (!MessageQueue_Post(smartcard->IrpQueue, nullptr, 0, (void*)irp, nullptr))
601
0
  {
602
0
    WLog_ERR(TAG, "MessageQueue_Post failed!");
603
0
    irp->Discard(irp);
604
0
    return ERROR_INTERNAL_ERROR;
605
0
  }
606
607
0
  return CHANNEL_RC_OK;
608
0
}
609
610
static void smartcard_free_irp(void* obj)
611
0
{
612
0
  wMessage* msg = obj;
613
0
  if (!msg)
614
0
    return;
615
0
  if (msg->id != 0)
616
0
    return;
617
618
0
  IRP* irp = (IRP*)msg->wParam;
619
0
  if (!irp)
620
0
    return;
621
0
  WINPR_ASSERT(irp->Discard);
622
0
  irp->Discard(irp);
623
0
}
624
625
/* smartcard is always built-in */
626
#define DeviceServiceEntry smartcard_DeviceServiceEntry
627
628
/**
629
 * Function description
630
 *
631
 * @return 0 on success, otherwise a Win32 error code
632
 */
633
FREERDP_ENTRY_POINT(UINT VCAPITYPE DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints))
634
0
{
635
0
  size_t length = 0;
636
0
  UINT error = CHANNEL_RC_NO_MEMORY;
637
638
0
  SMARTCARD_DEVICE* smartcard = (SMARTCARD_DEVICE*)calloc(1, sizeof(SMARTCARD_DEVICE));
639
0
  WLog_VRB(TAG, "smartcard device create: %p", (const void*)smartcard);
640
0
  if (!smartcard)
641
0
  {
642
0
    WLog_ERR(TAG, "calloc failed!");
643
0
    return CHANNEL_RC_NO_MEMORY;
644
0
  }
645
646
0
  smartcard->device.type = RDPDR_DTYP_SMARTCARD;
647
0
  smartcard->device.name = "SCARD";
648
0
  smartcard->device.IRPRequest = smartcard_irp_request;
649
0
  smartcard->device.Init = smartcard_init;
650
0
  smartcard->device.Free = smartcard_free;
651
0
  smartcard->rdpcontext = pEntryPoints->rdpcontext;
652
0
  length = strlen(smartcard->device.name);
653
0
  smartcard->device.data = Stream_New(nullptr, length + 1);
654
655
0
  if (!smartcard->device.data)
656
0
  {
657
0
    WLog_ERR(TAG, "Stream_New failed!");
658
0
    goto fail;
659
0
  }
660
661
0
  Stream_Write(smartcard->device.data, "SCARD", 6);
662
0
  smartcard->IrpQueue = MessageQueue_New(nullptr);
663
664
0
  if (!smartcard->IrpQueue)
665
0
  {
666
0
    WLog_ERR(TAG, "MessageQueue_New failed!");
667
0
    goto fail;
668
0
  }
669
670
0
  wObject* obj = MessageQueue_Object(smartcard->IrpQueue);
671
0
  WINPR_ASSERT(obj);
672
0
  obj->fnObjectFree = smartcard_free_irp;
673
674
0
  smartcard->rgOutstandingMessages = ListDictionary_New(TRUE);
675
676
0
  if (!smartcard->rgOutstandingMessages)
677
0
  {
678
0
    WLog_ERR(TAG, "ListDictionary_New failed!");
679
0
    goto fail;
680
0
  }
681
682
0
  smartcard->callctx = smartcard_call_context_new_with_context(smartcard->rdpcontext);
683
0
  if (!smartcard->callctx)
684
0
    goto fail;
685
686
0
  if (!smarcard_call_set_callbacks(smartcard->callctx, smartcard, smartcard_context_new,
687
0
                                   smartcard_context_free))
688
0
    goto fail;
689
690
0
  if ((error = pEntryPoints->RegisterDevice(pEntryPoints->devman, &smartcard->device)))
691
0
  {
692
0
    WLog_ERR(TAG, "RegisterDevice failed!");
693
0
    goto fail;
694
0
  }
695
696
0
  smartcard->thread =
697
0
      CreateThread(nullptr, 0, smartcard_thread_func, smartcard, CREATE_SUSPENDED, nullptr);
698
699
0
  if (!smartcard->thread)
700
0
  {
701
0
    WLog_ERR(TAG, "CreateThread failed!");
702
0
    error = ERROR_INTERNAL_ERROR;
703
0
    goto fail;
704
0
  }
705
706
0
  ResumeThread(smartcard->thread);
707
708
0
  if (pEntryPoints->device->Name)
709
0
  {
710
0
    if (!smartcard_call_context_add(smartcard->callctx, pEntryPoints->device->Name))
711
0
      goto fail;
712
0
  }
713
714
0
  return CHANNEL_RC_OK;
715
0
fail:
716
0
  smartcard_free_(smartcard);
717
0
  return error;
718
0
}