Coverage Report

Created: 2026-01-16 07:10

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