Coverage Report

Created: 2026-09-14 06:32

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/FreeRDP/libfreerdp/utils/smartcard_call.c
Line
Count
Source
1
/**
2
 * FreeRDP: A Remote Desktop Protocol Implementation
3
 * Smartcard Device Service Virtual Channel
4
 *
5
 * Copyright (C) Alexi Volkov <alexi@myrealbox.com> 2006
6
 * Copyright 2011 O.S. Systems Software Ltda.
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 2017 Armin Novak <armin.novak@thincast.com>
11
 * Copyright 2017 Thincast Technologies GmbH
12
 *
13
 * Licensed under the Apache License, Version 2.0 (the "License");
14
 * you may not use this file except in compliance with the License.
15
 * You may obtain a copy of the License at
16
 *
17
 *     http://www.apache.org/licenses/LICENSE-2.0
18
 *
19
 * Unless required by applicable law or agreed to in writing, software
20
 * distributed under the License is distributed on an "AS IS" BASIS,
21
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
22
 * See the License for the specific language governing permissions and
23
 * limitations under the License.
24
 */
25
26
#include <freerdp/config.h>
27
28
#include <winpr/assert.h>
29
30
#include <winpr/crt.h>
31
#include <winpr/print.h>
32
#include <winpr/stream.h>
33
#include <winpr/library.h>
34
#include <winpr/smartcard.h>
35
36
#include <freerdp/freerdp.h>
37
#include <freerdp/channels/rdpdr.h>
38
#include <freerdp/channels/scard.h>
39
40
#include <freerdp/utils/rdpdr_utils.h>
41
#include <freerdp/utils/smartcard_pack.h>
42
#include <freerdp/utils/smartcard_call.h>
43
44
#include "smartcard_pack.h"
45
46
#include <freerdp/log.h>
47
0
#define SCARD_TAG FREERDP_TAG("utils.smartcard.call")
48
49
#if defined(WITH_SMARTCARD_EMULATE)
50
#include <freerdp/emulate/scard/smartcard_emulate.h>
51
52
#define wrap_raw(ctx, fkt, ...)                                         \
53
0
  ctx->useEmulatedCard ? Emulate_##fkt(ctx->emulation, ##__VA_ARGS__) \
54
0
                       : ctx->pWinSCardApi->pfn##fkt(__VA_ARGS__)
55
0
#define wrap_ptr(ctx, fkt, ...) wrap_raw(ctx, fkt, ##__VA_ARGS__)
56
#else
57
#define wrap_raw(ctx, fkt, ...) \
58
  ctx->useEmulatedCard ? SCARD_F_INTERNAL_ERROR : ctx->pWinSCardApi->pfn##fkt(__VA_ARGS__)
59
#define wrap_ptr(ctx, fkt, ...) \
60
  ctx->useEmulatedCard ? nullptr : ctx->pWinSCardApi->pfn##fkt(__VA_ARGS__)
61
#endif
62
63
#if defined(_WIN32)
64
#define wrap(ctx, fkt, ...) wrap_raw(ctx, fkt, ##__VA_ARGS__)
65
#else
66
#define wrap(ctx, fkt, ...)                                               \
67
0
  __extension__({                                                       \
68
0
    LONG defstatus = wrap_raw(ctx, fkt, ##__VA_ARGS__);               \
69
0
    if (defstatus != SCARD_S_SUCCESS)                                 \
70
0
      WLog_Print(ctx->log, WLOG_TRACE, "[" #fkt "] failed with %s", \
71
0
                 SCardGetErrorString(defstatus));                   \
72
0
    defstatus;                                                        \
73
0
  })
74
#endif
75
76
struct s_scard_call_context
77
{
78
  BOOL useEmulatedCard;
79
  HANDLE StartedEvent;
80
  wLinkedList* names;
81
  wHashTable* rgSCardContextList;
82
#if defined(WITH_SMARTCARD_EMULATE)
83
  SmartcardEmulationContext* emulation;
84
#endif
85
  HANDLE hWinSCardLibrary;
86
  SCardApiFunctionTable WinSCardApi;
87
  const SCardApiFunctionTable* pWinSCardApi;
88
  HANDLE stopEvent;
89
  void* userdata;
90
91
  void* (*fn_new)(void*, SCARDCONTEXT);
92
  void (*fn_free)(void*);
93
  wLog* log;
94
  rdpContext* context;
95
};
96
97
struct s_scard_context_element
98
{
99
  void* context;
100
  void (*fn_free)(void*);
101
};
102
103
static void context_free(void* arg);
104
105
WINPR_ATTR_NODISCARD WINPR_ATTR_NODISCARD static LONG
106
smartcard_EstablishContext_Call(scard_call_context* smartcard, wStream* out,
107
                                SMARTCARD_OPERATION* operation)
108
0
{
109
0
  SCARDCONTEXT hContext = WINPR_C_ARRAY_INIT;
110
0
  EstablishContext_Return ret = WINPR_C_ARRAY_INIT;
111
0
  EstablishContext_Call* call = &operation->call.establishContext;
112
0
  LONG status = ret.ReturnCode =
113
0
      wrap(smartcard, SCardEstablishContext, call->dwScope, nullptr, nullptr, &hContext);
114
115
0
  if (ret.ReturnCode == SCARD_S_SUCCESS)
116
0
  {
117
0
    const void* key = (void*)(size_t)hContext;
118
0
    struct s_scard_context_element* pContext =
119
0
        calloc(1, sizeof(struct s_scard_context_element));
120
0
    if (!pContext)
121
0
      return STATUS_NO_MEMORY;
122
123
0
    pContext->fn_free = smartcard->fn_free;
124
125
0
    if (smartcard->fn_new)
126
0
    {
127
0
      pContext->context = smartcard->fn_new(smartcard->userdata, hContext);
128
0
      if (!pContext->context)
129
0
      {
130
0
        free(pContext);
131
0
        return STATUS_NO_MEMORY;
132
0
      }
133
0
    }
134
135
0
    if (!HashTable_Insert(smartcard->rgSCardContextList, key, (void*)pContext))
136
0
    {
137
0
      WLog_Print(smartcard->log, WLOG_ERROR, "HashTable_Insert failed!");
138
0
      context_free(pContext);
139
0
      return STATUS_INTERNAL_ERROR;
140
0
    }
141
0
  }
142
0
  else
143
0
  {
144
0
    return scard_log_status_error_wlog(smartcard->log, "SCardEstablishContext", status);
145
0
  }
146
147
  // NOLINTNEXTLINE(clang-analyzer-unix.Malloc): HashTable_Insert takes ownership of pContext
148
0
  smartcard_scard_context_native_to_redir(&(ret.hContext), hContext);
149
150
0
  status = smartcard_pack_establish_context_return(out, &ret);
151
0
  if (status != SCARD_S_SUCCESS)
152
0
  {
153
0
    return scard_log_status_error_wlog(smartcard->log,
154
0
                                       "smartcard_pack_establish_context_return", status);
155
0
  }
156
157
0
  return ret.ReturnCode;
158
0
}
159
160
WINPR_ATTR_NODISCARD static LONG smartcard_ReleaseContext_Call(scard_call_context* smartcard,
161
                                                               WINPR_ATTR_UNUSED wStream* out,
162
                                                               SMARTCARD_OPERATION* operation)
163
0
{
164
0
  Long_Return ret = WINPR_C_ARRAY_INIT;
165
166
0
  WINPR_ASSERT(smartcard);
167
0
  WINPR_ASSERT(out);
168
0
  WINPR_ASSERT(operation);
169
170
0
  ret.ReturnCode = wrap(smartcard, SCardReleaseContext, operation->hContext);
171
172
0
  if (ret.ReturnCode == SCARD_S_SUCCESS)
173
0
    HashTable_Remove(smartcard->rgSCardContextList, (void*)operation->hContext);
174
0
  else
175
0
  {
176
0
    return scard_log_status_error_wlog(smartcard->log, "SCardReleaseContext", ret.ReturnCode);
177
0
  }
178
179
0
  smartcard_trace_long_return_int(smartcard->log, &ret, "ReleaseContext");
180
0
  return ret.ReturnCode;
181
0
}
182
183
WINPR_ATTR_NODISCARD static LONG smartcard_IsValidContext_Call(scard_call_context* smartcard,
184
                                                               WINPR_ATTR_UNUSED wStream* out,
185
                                                               SMARTCARD_OPERATION* operation)
186
0
{
187
0
  Long_Return ret = WINPR_C_ARRAY_INIT;
188
189
0
  WINPR_ASSERT(smartcard);
190
0
  WINPR_ASSERT(out);
191
0
  WINPR_ASSERT(operation);
192
193
0
  ret.ReturnCode = wrap(smartcard, SCardIsValidContext, operation->hContext);
194
0
  smartcard_trace_long_return_int(smartcard->log, &ret, "IsValidContext");
195
0
  return ret.ReturnCode;
196
0
}
197
198
WINPR_ATTR_NODISCARD static LONG smartcard_ListReaderGroupsA_Call(scard_call_context* smartcard,
199
                                                                  wStream* out,
200
                                                                  SMARTCARD_OPERATION* operation)
201
0
{
202
0
  LONG status = 0;
203
0
  ListReaderGroups_Return ret = WINPR_C_ARRAY_INIT;
204
0
  LPSTR mszGroups = nullptr;
205
0
  DWORD cchGroups = 0;
206
207
0
  WINPR_ASSERT(smartcard);
208
0
  WINPR_ASSERT(out);
209
0
  WINPR_ASSERT(operation);
210
211
0
  cchGroups = SCARD_AUTOALLOCATE;
212
0
  ret.ReturnCode =
213
0
      wrap(smartcard, SCardListReaderGroupsA, operation->hContext, (LPSTR)&mszGroups, &cchGroups);
214
0
  if ((ret.ReturnCode == SCARD_S_SUCCESS) && (cchGroups == SCARD_AUTOALLOCATE))
215
0
    return SCARD_F_UNKNOWN_ERROR;
216
217
0
  ret.msz = (BYTE*)mszGroups;
218
0
  ret.cBytes = cchGroups;
219
220
0
  status = smartcard_pack_list_reader_groups_return(out, &ret, FALSE);
221
222
0
  if (status != SCARD_S_SUCCESS)
223
0
    return status;
224
225
0
  if (mszGroups)
226
0
    wrap(smartcard, SCardFreeMemory, operation->hContext, mszGroups);
227
228
0
  return ret.ReturnCode;
229
0
}
230
231
WINPR_ATTR_NODISCARD static LONG smartcard_ListReaderGroupsW_Call(scard_call_context* smartcard,
232
                                                                  wStream* out,
233
                                                                  SMARTCARD_OPERATION* operation)
234
0
{
235
0
  LONG status = 0;
236
0
  ListReaderGroups_Return ret = WINPR_C_ARRAY_INIT;
237
0
  LPWSTR mszGroups = nullptr;
238
0
  DWORD cchGroups = 0;
239
240
0
  WINPR_ASSERT(smartcard);
241
0
  WINPR_ASSERT(out);
242
0
  WINPR_ASSERT(operation);
243
244
0
  cchGroups = SCARD_AUTOALLOCATE;
245
0
  status = ret.ReturnCode = wrap(smartcard, SCardListReaderGroupsW, operation->hContext,
246
0
                                 (LPWSTR)&mszGroups, &cchGroups);
247
0
  if ((ret.ReturnCode == SCARD_S_SUCCESS) && (cchGroups == SCARD_AUTOALLOCATE))
248
0
    return SCARD_F_UNKNOWN_ERROR;
249
250
0
  ret.msz = (BYTE*)mszGroups;
251
252
0
  WINPR_ASSERT(cchGroups < SCARD_AUTOALLOCATE / sizeof(WCHAR));
253
0
  const size_t blen = sizeof(WCHAR) * cchGroups;
254
0
  WINPR_ASSERT(blen <= UINT32_MAX);
255
0
  ret.cBytes = (UINT32)blen;
256
257
0
  if (status != SCARD_S_SUCCESS)
258
0
    return status;
259
260
0
  status = smartcard_pack_list_reader_groups_return(out, &ret, TRUE);
261
262
0
  if (status != SCARD_S_SUCCESS)
263
0
    return status;
264
265
0
  if (mszGroups)
266
0
    wrap(smartcard, SCardFreeMemory, operation->hContext, mszGroups);
267
268
0
  return ret.ReturnCode;
269
0
}
270
271
WINPR_ATTR_NODISCARD
272
static BOOL filter_match(wLinkedList* list, LPCSTR reader, size_t readerLen)
273
0
{
274
0
  if (readerLen < 1)
275
0
    return FALSE;
276
277
0
  LinkedList_Enumerator_Reset(list);
278
279
0
  while (LinkedList_Enumerator_MoveNext(list))
280
0
  {
281
0
    const char* filter = LinkedList_Enumerator_Current(list);
282
283
0
    if (filter)
284
0
    {
285
0
      if (strstr(reader, filter) != nullptr)
286
0
        return TRUE;
287
0
    }
288
0
  }
289
290
0
  return FALSE;
291
0
}
292
293
WINPR_ATTR_NODISCARD
294
static DWORD filter_device_by_name_a(wLinkedList* list, LPSTR* mszReaders, DWORD cchReaders)
295
0
{
296
0
  size_t rpos = 0;
297
0
  size_t wpos = 0;
298
299
0
  if (*mszReaders == nullptr || LinkedList_Count(list) < 1)
300
0
    return cchReaders;
301
302
0
  do
303
0
  {
304
0
    LPCSTR rreader = &(*mszReaders)[rpos];
305
0
    LPSTR wreader = &(*mszReaders)[wpos];
306
0
    size_t readerLen = strnlen(rreader, cchReaders - rpos);
307
308
0
    rpos += readerLen + 1;
309
310
0
    if (filter_match(list, rreader, readerLen))
311
0
    {
312
0
      if (rreader != wreader)
313
0
        memmove(wreader, rreader, readerLen + 1);
314
315
0
      wpos += readerLen + 1;
316
0
    }
317
0
  } while (rpos < cchReaders);
318
319
  /* this string must be double 0 terminated */
320
0
  if (rpos != wpos)
321
0
  {
322
0
    if (wpos >= cchReaders)
323
0
      return 0;
324
325
0
    (*mszReaders)[wpos++] = '\0';
326
0
  }
327
328
0
  return (DWORD)wpos;
329
0
}
330
331
WINPR_ATTR_NODISCARD
332
static DWORD filter_device_by_name_w(wLinkedList* list, LPWSTR* mszReaders, DWORD cchReaders)
333
0
{
334
0
  DWORD rc = 0;
335
0
  LPSTR readers = nullptr;
336
337
0
  if (LinkedList_Count(list) < 1)
338
0
    return cchReaders;
339
340
0
  readers = ConvertMszWCharNToUtf8Alloc(*mszReaders, cchReaders, nullptr);
341
342
0
  if (!readers)
343
0
  {
344
0
    free(readers);
345
0
    return 0;
346
0
  }
347
348
0
  *mszReaders = nullptr;
349
0
  rc = filter_device_by_name_a(list, &readers, cchReaders);
350
351
0
  *mszReaders = ConvertMszUtf8NToWCharAlloc(readers, rc, nullptr);
352
0
  if (!*mszReaders)
353
0
    rc = 0;
354
355
0
  free(readers);
356
0
  return rc;
357
0
}
358
359
WINPR_ATTR_NODISCARD static LONG smartcard_ListReadersA_Call(scard_call_context* smartcard,
360
                                                             wStream* out,
361
                                                             SMARTCARD_OPERATION* operation)
362
0
{
363
0
  ListReaders_Return ret = WINPR_C_ARRAY_INIT;
364
0
  LPSTR mszReaders = nullptr;
365
366
0
  WINPR_ASSERT(smartcard);
367
0
  WINPR_ASSERT(out);
368
0
  WINPR_ASSERT(operation);
369
370
0
  ListReaders_Call* call = &operation->call.listReaders;
371
0
  DWORD cchReaders = SCARD_AUTOALLOCATE;
372
0
  LONG status = ret.ReturnCode = wrap(smartcard, SCardListReadersA, operation->hContext,
373
0
                                      (LPCSTR)call->mszGroups, (LPSTR)&mszReaders, &cchReaders);
374
0
  if (status == SCARD_S_SUCCESS)
375
0
  {
376
0
    if (cchReaders == SCARD_AUTOALLOCATE)
377
0
      status = SCARD_F_UNKNOWN_ERROR;
378
0
  }
379
380
0
  if (status != SCARD_S_SUCCESS)
381
0
  {
382
0
    (void)scard_log_status_error_wlog(smartcard->log, "SCardListReadersA", status);
383
0
    return smartcard_pack_list_readers_return(out, &ret, FALSE);
384
0
  }
385
386
0
  void* original = mszReaders;
387
0
  cchReaders = filter_device_by_name_a(smartcard->names, &mszReaders, cchReaders);
388
0
  ret.msz = (BYTE*)mszReaders;
389
0
  ret.cBytes = cchReaders;
390
391
0
  status = smartcard_pack_list_readers_return(out, &ret, FALSE);
392
0
  if (original)
393
0
    wrap(smartcard, SCardFreeMemory, operation->hContext, original);
394
395
0
  if (status != SCARD_S_SUCCESS)
396
0
    return scard_log_status_error_wlog(smartcard->log, "smartcard_pack_list_readers_return",
397
0
                                       status);
398
399
0
  return ret.ReturnCode;
400
0
}
401
402
WINPR_ATTR_NODISCARD static LONG smartcard_ListReadersW_Call(scard_call_context* smartcard,
403
                                                             wStream* out,
404
                                                             SMARTCARD_OPERATION* operation)
405
0
{
406
0
  LONG status = 0;
407
0
  ListReaders_Return ret = WINPR_C_ARRAY_INIT;
408
0
  DWORD cchReaders = 0;
409
0
  ListReaders_Call* call = nullptr;
410
0
  union
411
0
  {
412
0
    const BYTE* bp;
413
0
    const char* sz;
414
0
    const WCHAR* wz;
415
0
  } string;
416
0
  union
417
0
  {
418
0
    WCHAR** ppw;
419
0
    WCHAR* pw;
420
0
    CHAR* pc;
421
0
    BYTE* pb;
422
0
  } mszReaders;
423
424
0
  WINPR_ASSERT(smartcard);
425
0
  WINPR_ASSERT(operation);
426
427
0
  call = &operation->call.listReaders;
428
429
0
  string.bp = call->mszGroups;
430
0
  cchReaders = SCARD_AUTOALLOCATE;
431
0
  status = ret.ReturnCode = wrap(smartcard, SCardListReadersW, operation->hContext, string.wz,
432
0
                                 (LPWSTR)&mszReaders.pw, &cchReaders);
433
0
  if (status == SCARD_S_SUCCESS)
434
0
  {
435
0
    if (cchReaders == SCARD_AUTOALLOCATE)
436
0
      status = SCARD_F_UNKNOWN_ERROR;
437
0
  }
438
439
0
  if (status != SCARD_S_SUCCESS)
440
0
  {
441
0
    (void)scard_log_status_error_wlog(smartcard->log, "SCardListReadersW", status);
442
0
    return smartcard_pack_list_readers_return(out, &ret, TRUE);
443
0
  }
444
445
0
  void* original = mszReaders.pb;
446
0
  cchReaders = filter_device_by_name_w(smartcard->names, &mszReaders.pw, cchReaders);
447
0
  ret.msz = mszReaders.pb;
448
0
  ret.cBytes = cchReaders * sizeof(WCHAR);
449
0
  status = smartcard_pack_list_readers_return(out, &ret, TRUE);
450
451
0
  if (original)
452
0
    wrap(smartcard, SCardFreeMemory, operation->hContext, original);
453
454
0
  if (status != SCARD_S_SUCCESS)
455
0
    return status;
456
457
0
  return ret.ReturnCode;
458
0
}
459
460
WINPR_ATTR_NODISCARD static LONG
461
smartcard_IntroduceReaderGroupA_Call(scard_call_context* smartcard, WINPR_ATTR_UNUSED wStream* out,
462
                                     SMARTCARD_OPERATION* operation)
463
0
{
464
0
  Long_Return ret = WINPR_C_ARRAY_INIT;
465
0
  ContextAndStringA_Call* call = nullptr;
466
467
0
  WINPR_ASSERT(smartcard);
468
0
  WINPR_ASSERT(out);
469
0
  WINPR_ASSERT(operation);
470
471
0
  call = &operation->call.contextAndStringA;
472
0
  ret.ReturnCode = wrap(smartcard, SCardIntroduceReaderGroupA, operation->hContext, call->sz);
473
0
  scard_log_status_error_wlog(smartcard->log, "SCardIntroduceReaderGroupA", ret.ReturnCode);
474
0
  smartcard_trace_long_return_int(smartcard->log, &ret, "IntroduceReaderGroupA");
475
0
  return ret.ReturnCode;
476
0
}
477
478
WINPR_ATTR_NODISCARD static LONG
479
smartcard_IntroduceReaderGroupW_Call(scard_call_context* smartcard, WINPR_ATTR_UNUSED wStream* out,
480
                                     SMARTCARD_OPERATION* operation)
481
0
{
482
0
  Long_Return ret = WINPR_C_ARRAY_INIT;
483
0
  ContextAndStringW_Call* call = nullptr;
484
485
0
  WINPR_ASSERT(smartcard);
486
0
  WINPR_ASSERT(out);
487
0
  WINPR_ASSERT(operation);
488
489
0
  call = &operation->call.contextAndStringW;
490
0
  ret.ReturnCode = wrap(smartcard, SCardIntroduceReaderGroupW, operation->hContext, call->sz);
491
0
  scard_log_status_error_wlog(smartcard->log, "SCardIntroduceReaderGroupW", ret.ReturnCode);
492
0
  smartcard_trace_long_return_int(smartcard->log, &ret, "IntroduceReaderGroupW");
493
0
  return ret.ReturnCode;
494
0
}
495
496
WINPR_ATTR_NODISCARD static LONG smartcard_IntroduceReaderA_Call(scard_call_context* smartcard,
497
                                                                 WINPR_ATTR_UNUSED wStream* out,
498
                                                                 SMARTCARD_OPERATION* operation)
499
0
{
500
0
  Long_Return ret = WINPR_C_ARRAY_INIT;
501
0
  ContextAndTwoStringA_Call* call = nullptr;
502
503
0
  WINPR_ASSERT(smartcard);
504
0
  WINPR_ASSERT(out);
505
0
  WINPR_ASSERT(operation);
506
507
0
  call = &operation->call.contextAndTwoStringA;
508
0
  ret.ReturnCode =
509
0
      wrap(smartcard, SCardIntroduceReaderA, operation->hContext, call->sz1, call->sz2);
510
0
  scard_log_status_error_wlog(smartcard->log, "SCardIntroduceReaderA", ret.ReturnCode);
511
0
  smartcard_trace_long_return_int(smartcard->log, &ret, "IntroduceReaderA");
512
0
  return ret.ReturnCode;
513
0
}
514
515
WINPR_ATTR_NODISCARD static LONG smartcard_IntroduceReaderW_Call(scard_call_context* smartcard,
516
                                                                 WINPR_ATTR_UNUSED wStream* out,
517
                                                                 SMARTCARD_OPERATION* operation)
518
0
{
519
0
  Long_Return ret = WINPR_C_ARRAY_INIT;
520
0
  ContextAndTwoStringW_Call* call = nullptr;
521
522
0
  WINPR_ASSERT(smartcard);
523
0
  WINPR_ASSERT(out);
524
0
  WINPR_ASSERT(operation);
525
526
0
  call = &operation->call.contextAndTwoStringW;
527
0
  ret.ReturnCode =
528
0
      wrap(smartcard, SCardIntroduceReaderW, operation->hContext, call->sz1, call->sz2);
529
0
  scard_log_status_error_wlog(smartcard->log, "SCardIntroduceReaderW", ret.ReturnCode);
530
0
  smartcard_trace_long_return_int(smartcard->log, &ret, "IntroduceReaderW");
531
0
  return ret.ReturnCode;
532
0
}
533
534
WINPR_ATTR_NODISCARD static LONG smartcard_ForgetReaderA_Call(scard_call_context* smartcard,
535
                                                              WINPR_ATTR_UNUSED wStream* out,
536
                                                              SMARTCARD_OPERATION* operation)
537
0
{
538
0
  Long_Return ret = WINPR_C_ARRAY_INIT;
539
0
  ContextAndStringA_Call* call = nullptr;
540
541
0
  WINPR_ASSERT(smartcard);
542
0
  WINPR_ASSERT(out);
543
0
  WINPR_ASSERT(operation);
544
545
0
  call = &operation->call.contextAndStringA;
546
0
  ret.ReturnCode = wrap(smartcard, SCardForgetReaderA, operation->hContext, call->sz);
547
0
  scard_log_status_error_wlog(smartcard->log, "SCardForgetReaderA", ret.ReturnCode);
548
0
  smartcard_trace_long_return_int(smartcard->log, &ret, "SCardForgetReaderA");
549
0
  return ret.ReturnCode;
550
0
}
551
552
WINPR_ATTR_NODISCARD static LONG smartcard_ForgetReaderW_Call(scard_call_context* smartcard,
553
                                                              WINPR_ATTR_UNUSED wStream* out,
554
                                                              SMARTCARD_OPERATION* operation)
555
0
{
556
0
  Long_Return ret = WINPR_C_ARRAY_INIT;
557
0
  ContextAndStringW_Call* call = nullptr;
558
559
0
  WINPR_ASSERT(smartcard);
560
0
  WINPR_ASSERT(out);
561
0
  WINPR_ASSERT(operation);
562
563
0
  call = &operation->call.contextAndStringW;
564
0
  ret.ReturnCode = wrap(smartcard, SCardForgetReaderW, operation->hContext, call->sz);
565
0
  scard_log_status_error_wlog(smartcard->log, "SCardForgetReaderW", ret.ReturnCode);
566
0
  smartcard_trace_long_return_int(smartcard->log, &ret, "SCardForgetReaderW");
567
0
  return ret.ReturnCode;
568
0
}
569
570
WINPR_ATTR_NODISCARD static LONG smartcard_AddReaderToGroupA_Call(scard_call_context* smartcard,
571
                                                                  WINPR_ATTR_UNUSED wStream* out,
572
                                                                  SMARTCARD_OPERATION* operation)
573
0
{
574
0
  Long_Return ret = WINPR_C_ARRAY_INIT;
575
0
  ContextAndTwoStringA_Call* call = nullptr;
576
577
0
  WINPR_ASSERT(smartcard);
578
0
  WINPR_ASSERT(out);
579
0
  WINPR_ASSERT(operation);
580
581
0
  call = &operation->call.contextAndTwoStringA;
582
0
  ret.ReturnCode =
583
0
      wrap(smartcard, SCardAddReaderToGroupA, operation->hContext, call->sz1, call->sz2);
584
0
  scard_log_status_error_wlog(smartcard->log, "SCardAddReaderToGroupA", ret.ReturnCode);
585
0
  smartcard_trace_long_return_int(smartcard->log, &ret, "SCardAddReaderToGroupA");
586
0
  return ret.ReturnCode;
587
0
}
588
589
WINPR_ATTR_NODISCARD static LONG smartcard_AddReaderToGroupW_Call(scard_call_context* smartcard,
590
                                                                  WINPR_ATTR_UNUSED wStream* out,
591
                                                                  SMARTCARD_OPERATION* operation)
592
0
{
593
0
  Long_Return ret = WINPR_C_ARRAY_INIT;
594
0
  ContextAndTwoStringW_Call* call = nullptr;
595
596
0
  WINPR_ASSERT(smartcard);
597
0
  WINPR_ASSERT(out);
598
0
  WINPR_ASSERT(operation);
599
600
0
  call = &operation->call.contextAndTwoStringW;
601
0
  ret.ReturnCode =
602
0
      wrap(smartcard, SCardAddReaderToGroupW, operation->hContext, call->sz1, call->sz2);
603
0
  scard_log_status_error_wlog(smartcard->log, "SCardAddReaderToGroupW", ret.ReturnCode);
604
0
  smartcard_trace_long_return_int(smartcard->log, &ret, "SCardAddReaderToGroupA");
605
0
  return ret.ReturnCode;
606
0
}
607
608
WINPR_ATTR_NODISCARD static LONG
609
smartcard_RemoveReaderFromGroupA_Call(scard_call_context* smartcard, WINPR_ATTR_UNUSED wStream* out,
610
                                      SMARTCARD_OPERATION* operation)
611
0
{
612
0
  Long_Return ret = WINPR_C_ARRAY_INIT;
613
0
  ContextAndTwoStringA_Call* call = nullptr;
614
615
0
  WINPR_ASSERT(smartcard);
616
0
  WINPR_ASSERT(out);
617
0
  WINPR_ASSERT(operation);
618
619
0
  call = &operation->call.contextAndTwoStringA;
620
0
  ret.ReturnCode =
621
0
      wrap(smartcard, SCardRemoveReaderFromGroupA, operation->hContext, call->sz1, call->sz2);
622
0
  scard_log_status_error_wlog(smartcard->log, "SCardRemoveReaderFromGroupA", ret.ReturnCode);
623
0
  smartcard_trace_long_return_int(smartcard->log, &ret, "SCardRemoveReaderFromGroupA");
624
0
  return ret.ReturnCode;
625
0
}
626
627
WINPR_ATTR_NODISCARD static LONG
628
smartcard_RemoveReaderFromGroupW_Call(scard_call_context* smartcard, WINPR_ATTR_UNUSED wStream* out,
629
                                      SMARTCARD_OPERATION* operation)
630
0
{
631
0
  Long_Return ret = WINPR_C_ARRAY_INIT;
632
0
  ContextAndTwoStringW_Call* call = nullptr;
633
634
0
  WINPR_ASSERT(smartcard);
635
0
  WINPR_ASSERT(out);
636
0
  WINPR_ASSERT(operation);
637
638
0
  call = &operation->call.contextAndTwoStringW;
639
0
  ret.ReturnCode =
640
0
      wrap(smartcard, SCardRemoveReaderFromGroupW, operation->hContext, call->sz1, call->sz2);
641
0
  scard_log_status_error_wlog(smartcard->log, "SCardRemoveReaderFromGroupW", ret.ReturnCode);
642
0
  smartcard_trace_long_return_int(smartcard->log, &ret, "SCardRemoveReaderFromGroupW");
643
0
  return ret.ReturnCode;
644
0
}
645
646
WINPR_ATTR_NODISCARD static LONG smartcard_LocateCardsA_Call(scard_call_context* smartcard,
647
                                                             wStream* out,
648
                                                             SMARTCARD_OPERATION* operation)
649
0
{
650
0
  LONG status = 0;
651
0
  LocateCards_Return ret = WINPR_C_ARRAY_INIT;
652
0
  LocateCardsA_Call* call = nullptr;
653
654
0
  WINPR_ASSERT(smartcard);
655
0
  WINPR_ASSERT(operation);
656
657
0
  call = &operation->call.locateCardsA;
658
659
0
  ret.ReturnCode = wrap(smartcard, SCardLocateCardsA, operation->hContext, call->mszCards,
660
0
                        call->rgReaderStates, call->cReaders);
661
0
  scard_log_status_error_wlog(smartcard->log, "SCardLocateCardsA", ret.ReturnCode);
662
0
  ret.rgReaderStates = nullptr;
663
664
0
  if (call->cReaders > 0)
665
0
  {
666
0
    ret.rgReaderStates =
667
0
        (ReaderState_Return*)calloc(call->cReaders, sizeof(ReaderState_Return));
668
669
0
    if (!ret.rgReaderStates)
670
0
      return STATUS_NO_MEMORY;
671
0
    ret.cReaders = call->cReaders;
672
0
  }
673
674
0
  for (UINT32 x = 0; x < ret.cReaders; x++)
675
0
  {
676
0
    const LPSCARD_READERSTATEA cstate = &call->rgReaderStates[x];
677
0
    ReaderState_Return* cur = &ret.rgReaderStates[x];
678
679
0
    cur->dwCurrentState = cstate->dwCurrentState;
680
0
    cur->dwEventState = cstate->dwEventState;
681
0
    cur->cbAtr = cstate->cbAtr;
682
0
    CopyMemory(&(cur->rgbAtr), &(cstate->rgbAtr), sizeof(cur->rgbAtr));
683
0
    if (!smartcard_reader_state_return_is_valid(x, cur))
684
0
    {
685
0
      free(ret.rgReaderStates);
686
0
      return SCARD_E_INVALID_ATR;
687
0
    }
688
0
  }
689
690
0
  status = smartcard_pack_locate_cards_return(out, &ret);
691
0
  free(ret.rgReaderStates);
692
693
0
  if (status != SCARD_S_SUCCESS)
694
0
    return status;
695
696
0
  return ret.ReturnCode;
697
0
}
698
699
WINPR_ATTR_NODISCARD static LONG smartcard_LocateCardsW_Call(scard_call_context* smartcard,
700
                                                             wStream* out,
701
                                                             SMARTCARD_OPERATION* operation)
702
0
{
703
0
  LONG status = 0;
704
0
  LocateCards_Return ret = WINPR_C_ARRAY_INIT;
705
706
0
  WINPR_ASSERT(smartcard);
707
0
  WINPR_ASSERT(operation);
708
709
0
  LocateCardsW_Call* call = &operation->call.locateCardsW;
710
711
0
  ret.ReturnCode = wrap(smartcard, SCardLocateCardsW, operation->hContext, call->mszCards,
712
0
                        call->rgReaderStates, call->cReaders);
713
0
  scard_log_status_error_wlog(smartcard->log, "SCardLocateCardsW", ret.ReturnCode);
714
0
  ret.rgReaderStates = nullptr;
715
716
0
  if (call->cReaders > 0)
717
0
  {
718
0
    ret.rgReaderStates =
719
0
        (ReaderState_Return*)calloc(call->cReaders, sizeof(ReaderState_Return));
720
721
0
    if (!ret.rgReaderStates)
722
0
      return STATUS_NO_MEMORY;
723
0
    ret.cReaders = call->cReaders;
724
0
  }
725
726
0
  for (UINT32 x = 0; x < ret.cReaders; x++)
727
0
  {
728
0
    const LPSCARD_READERSTATEW cstate = &call->rgReaderStates[x];
729
0
    ReaderState_Return* cur = &ret.rgReaderStates[x];
730
731
0
    cur->dwCurrentState = cstate->dwCurrentState;
732
0
    cur->dwEventState = cstate->dwEventState;
733
0
    cur->cbAtr = cstate->cbAtr;
734
0
    CopyMemory(&(cur->rgbAtr), &(cstate->rgbAtr), sizeof(cur->rgbAtr));
735
0
    if (!smartcard_reader_state_return_is_valid(x, cur))
736
0
    {
737
0
      free(ret.rgReaderStates);
738
0
      return SCARD_E_INVALID_ATR;
739
0
    }
740
0
  }
741
742
0
  status = smartcard_pack_locate_cards_return(out, &ret);
743
0
  free(ret.rgReaderStates);
744
745
0
  if (status != SCARD_S_SUCCESS)
746
0
    return status;
747
748
0
  return ret.ReturnCode;
749
0
}
750
751
WINPR_ATTR_NODISCARD static LONG smartcard_ReadCacheA_Call(scard_call_context* smartcard,
752
                                                           wStream* out,
753
                                                           SMARTCARD_OPERATION* operation)
754
0
{
755
0
  LONG status = 0;
756
0
  BOOL autoalloc = 0;
757
0
  ReadCache_Return ret = WINPR_C_ARRAY_INIT;
758
0
  ReadCacheA_Call* call = nullptr;
759
760
0
  WINPR_ASSERT(smartcard);
761
0
  WINPR_ASSERT(out);
762
0
  WINPR_ASSERT(operation);
763
764
0
  call = &operation->call.readCacheA;
765
0
  autoalloc = (call->Common.cbDataLen == SCARD_AUTOALLOCATE);
766
767
0
  if (!call->Common.fPbDataIsNULL)
768
0
  {
769
0
    if (!autoalloc)
770
0
    {
771
0
      ret.pbData = malloc(call->Common.cbDataLen);
772
0
      if (!ret.pbData)
773
0
        return SCARD_F_INTERNAL_ERROR;
774
0
    }
775
0
    ret.cbDataLen = call->Common.cbDataLen;
776
0
  }
777
778
0
  if (autoalloc)
779
0
    ret.ReturnCode = wrap(smartcard, SCardReadCacheA, operation->hContext,
780
0
                          call->Common.CardIdentifier, call->Common.FreshnessCounter,
781
0
                          call->szLookupName, (BYTE*)&ret.pbData, &ret.cbDataLen);
782
0
  else
783
0
    ret.ReturnCode =
784
0
        wrap(smartcard, SCardReadCacheA, operation->hContext, call->Common.CardIdentifier,
785
0
             call->Common.FreshnessCounter, call->szLookupName, ret.pbData, &ret.cbDataLen);
786
787
0
  WLog_Print(smartcard->log, WLOG_TRACE, "key=%s, length=%" PRIu32, call->szLookupName,
788
0
             ret.cbDataLen);
789
790
0
  if ((ret.ReturnCode != SCARD_W_CACHE_ITEM_NOT_FOUND) &&
791
0
      (ret.ReturnCode != SCARD_W_CACHE_ITEM_STALE))
792
0
  {
793
0
    scard_log_status_error_wlog(smartcard->log, "SCardReadCacheA", ret.ReturnCode);
794
0
  }
795
796
0
  status = smartcard_pack_read_cache_return(out, &ret);
797
0
  if (autoalloc)
798
0
    wrap(smartcard, SCardFreeMemory, operation->hContext, ret.pbData);
799
0
  else
800
0
    free(ret.pbData);
801
0
  if (status != SCARD_S_SUCCESS)
802
0
    return status;
803
804
0
  return ret.ReturnCode;
805
0
}
806
807
WINPR_ATTR_NODISCARD static LONG smartcard_ReadCacheW_Call(scard_call_context* smartcard,
808
                                                           wStream* out,
809
                                                           SMARTCARD_OPERATION* operation)
810
0
{
811
0
  LONG status = 0;
812
0
  ReadCache_Return ret = WINPR_C_ARRAY_INIT;
813
0
  ReadCacheW_Call* call = nullptr;
814
815
0
  WINPR_ASSERT(smartcard);
816
0
  WINPR_ASSERT(out);
817
0
  WINPR_ASSERT(operation);
818
819
0
  call = &operation->call.readCacheW;
820
821
0
  if (!call->Common.fPbDataIsNULL)
822
0
    ret.cbDataLen = SCARD_AUTOALLOCATE;
823
824
0
  ret.ReturnCode =
825
0
      wrap(smartcard, SCardReadCacheW, operation->hContext, call->Common.CardIdentifier,
826
0
           call->Common.FreshnessCounter, call->szLookupName, (BYTE*)&ret.pbData, &ret.cbDataLen);
827
828
0
  if (WLog_IsLevelActive(smartcard->log, WLOG_TRACE))
829
0
  {
830
0
    char buffer[128] = WINPR_C_ARRAY_INIT;
831
0
    (void)ConvertWCharToUtf8(call->szLookupName, buffer, sizeof(buffer));
832
0
    WLog_Print(smartcard->log, WLOG_TRACE, "key=%s, length=%" PRIu32, buffer, ret.cbDataLen);
833
0
  }
834
0
  if ((ret.ReturnCode != SCARD_W_CACHE_ITEM_NOT_FOUND) &&
835
0
      (ret.ReturnCode != SCARD_W_CACHE_ITEM_STALE))
836
0
  {
837
0
    scard_log_status_error_wlog(smartcard->log, "SCardReadCacheW", ret.ReturnCode);
838
0
  }
839
840
0
  status = smartcard_pack_read_cache_return(out, &ret);
841
842
0
  wrap(smartcard, SCardFreeMemory, operation->hContext, ret.pbData);
843
844
0
  if (status != SCARD_S_SUCCESS)
845
0
    return status;
846
847
0
  return ret.ReturnCode;
848
0
}
849
850
WINPR_ATTR_NODISCARD static LONG smartcard_WriteCacheA_Call(scard_call_context* smartcard,
851
                                                            WINPR_ATTR_UNUSED wStream* out,
852
                                                            SMARTCARD_OPERATION* operation)
853
0
{
854
0
  Long_Return ret = WINPR_C_ARRAY_INIT;
855
0
  WriteCacheA_Call* call = nullptr;
856
857
0
  WINPR_ASSERT(smartcard);
858
0
  WINPR_ASSERT(out);
859
0
  WINPR_ASSERT(operation);
860
861
0
  call = &operation->call.writeCacheA;
862
863
0
  ret.ReturnCode = wrap(smartcard, SCardWriteCacheA, operation->hContext,
864
0
                        call->Common.CardIdentifier, call->Common.FreshnessCounter,
865
0
                        call->szLookupName, call->Common.pbData, call->Common.cbDataLen);
866
0
  scard_log_status_error_wlog(smartcard->log, "SCardWriteCacheA", ret.ReturnCode);
867
0
  smartcard_trace_long_return_int(smartcard->log, &ret, "SCardWriteCacheA");
868
0
  WLog_Print(smartcard->log, WLOG_TRACE, "key=%s, length=%" PRIu32, call->szLookupName,
869
0
             call->Common.cbDataLen);
870
0
  return ret.ReturnCode;
871
0
}
872
873
WINPR_ATTR_NODISCARD static LONG smartcard_WriteCacheW_Call(scard_call_context* smartcard,
874
                                                            WINPR_ATTR_UNUSED wStream* out,
875
                                                            SMARTCARD_OPERATION* operation)
876
0
{
877
0
  Long_Return ret = WINPR_C_ARRAY_INIT;
878
0
  WriteCacheW_Call* call = nullptr;
879
880
0
  WINPR_ASSERT(smartcard);
881
0
  WINPR_ASSERT(out);
882
0
  WINPR_ASSERT(operation);
883
884
0
  call = &operation->call.writeCacheW;
885
886
0
  ret.ReturnCode = wrap(smartcard, SCardWriteCacheW, operation->hContext,
887
0
                        call->Common.CardIdentifier, call->Common.FreshnessCounter,
888
0
                        call->szLookupName, call->Common.pbData, call->Common.cbDataLen);
889
0
  scard_log_status_error_wlog(smartcard->log, "SCardWriteCacheW", ret.ReturnCode);
890
0
  smartcard_trace_long_return_int(smartcard->log, &ret, "SCardWriteCacheW");
891
892
0
  if (WLog_IsLevelActive(smartcard->log, WLOG_TRACE))
893
0
  {
894
0
    char buffer[128] = WINPR_C_ARRAY_INIT;
895
0
    (void)ConvertWCharToUtf8(call->szLookupName, buffer, sizeof(buffer));
896
0
    WLog_Print(smartcard->log, WLOG_TRACE, "key=%s, length=%" PRIu32, buffer,
897
0
               call->Common.cbDataLen);
898
0
  }
899
0
  return ret.ReturnCode;
900
0
}
901
902
WINPR_ATTR_NODISCARD static LONG smartcard_GetTransmitCount_Call(scard_call_context* smartcard,
903
                                                                 wStream* out,
904
                                                                 SMARTCARD_OPERATION* operation)
905
0
{
906
0
  LONG status = 0;
907
0
  GetTransmitCount_Return ret = WINPR_C_ARRAY_INIT;
908
909
0
  WINPR_ASSERT(smartcard);
910
0
  WINPR_ASSERT(out);
911
0
  WINPR_ASSERT(operation);
912
913
0
  ret.ReturnCode = wrap(smartcard, SCardGetTransmitCount, operation->hCard, &ret.cTransmitCount);
914
0
  scard_log_status_error_wlog(smartcard->log, "SCardGetTransmitCount", ret.ReturnCode);
915
0
  status = smartcard_pack_get_transmit_count_return(out, &ret);
916
0
  if (status != SCARD_S_SUCCESS)
917
0
    return status;
918
919
0
  return ret.ReturnCode;
920
0
}
921
922
WINPR_ATTR_NODISCARD static LONG smartcard_ReleaseStartedEvent_Call(scard_call_context* smartcard,
923
                                                                    wStream* out,
924
                                                                    SMARTCARD_OPERATION* operation)
925
0
{
926
0
  WINPR_UNUSED(smartcard);
927
0
  WINPR_UNUSED(out);
928
0
  WINPR_UNUSED(operation);
929
930
0
  WLog_Print(smartcard->log, WLOG_WARN,
931
0
             "According to [MS-RDPESC] 3.1.4 Message Processing Events and Sequencing Rules "
932
0
             "this is not supported?!?");
933
0
  return SCARD_E_UNSUPPORTED_FEATURE;
934
0
}
935
936
WINPR_ATTR_NODISCARD static LONG smartcard_GetReaderIcon_Call(scard_call_context* smartcard,
937
                                                              wStream* out,
938
                                                              SMARTCARD_OPERATION* operation)
939
0
{
940
0
  LONG status = 0;
941
0
  GetReaderIcon_Return ret = WINPR_C_ARRAY_INIT;
942
0
  GetReaderIcon_Call* call = nullptr;
943
944
0
  WINPR_ASSERT(smartcard);
945
0
  WINPR_ASSERT(out);
946
0
  WINPR_ASSERT(operation);
947
948
0
  call = &operation->call.getReaderIcon;
949
950
0
  ret.cbDataLen = SCARD_AUTOALLOCATE;
951
0
  ret.ReturnCode = wrap(smartcard, SCardGetReaderIconW, operation->hContext, call->szReaderName,
952
0
                        (LPBYTE)&ret.pbData, &ret.cbDataLen);
953
0
  scard_log_status_error_wlog(smartcard->log, "SCardGetReaderIconW", ret.ReturnCode);
954
0
  if ((ret.ReturnCode == SCARD_S_SUCCESS) && (ret.cbDataLen == SCARD_AUTOALLOCATE))
955
0
    return SCARD_F_UNKNOWN_ERROR;
956
957
0
  status = smartcard_pack_get_reader_icon_return(out, &ret);
958
0
  wrap(smartcard, SCardFreeMemory, operation->hContext, ret.pbData);
959
0
  if (status != SCARD_S_SUCCESS)
960
0
    return status;
961
962
0
  return ret.ReturnCode;
963
0
}
964
965
WINPR_ATTR_NODISCARD static LONG smartcard_GetDeviceTypeId_Call(scard_call_context* smartcard,
966
                                                                wStream* out,
967
                                                                SMARTCARD_OPERATION* operation)
968
0
{
969
0
  LONG status = 0;
970
0
  GetDeviceTypeId_Return ret = WINPR_C_ARRAY_INIT;
971
0
  GetDeviceTypeId_Call* call = nullptr;
972
973
0
  WINPR_ASSERT(smartcard);
974
0
  WINPR_ASSERT(out);
975
0
  WINPR_ASSERT(operation);
976
977
0
  call = &operation->call.getDeviceTypeId;
978
979
0
  ret.ReturnCode = wrap(smartcard, SCardGetDeviceTypeIdW, operation->hContext, call->szReaderName,
980
0
                        &ret.dwDeviceId);
981
0
  scard_log_status_error_wlog(smartcard->log, "SCardGetDeviceTypeIdW", ret.ReturnCode);
982
983
0
  status = smartcard_pack_device_type_id_return(out, &ret);
984
0
  if (status != SCARD_S_SUCCESS)
985
0
    return status;
986
987
0
  return ret.ReturnCode;
988
0
}
989
990
WINPR_ATTR_NODISCARD
991
static BOOL smartcard_context_was_aborted(scard_call_context* smartcard)
992
0
{
993
0
  WINPR_ASSERT(smartcard);
994
995
0
  HANDLE handles[] = { smartcard->stopEvent, freerdp_abort_event(smartcard->context) };
996
0
  const DWORD rc = WaitForMultipleObjects(ARRAYSIZE(handles), handles, FALSE, 0);
997
0
  return (rc >= WAIT_OBJECT_0) && (rc <= WAIT_OBJECT_0 + ARRAYSIZE(handles));
998
0
}
999
1000
WINPR_ATTR_NODISCARD static LONG smartcard_GetStatusChangeA_Call(scard_call_context* smartcard,
1001
                                                                 wStream* out,
1002
                                                                 SMARTCARD_OPERATION* operation)
1003
0
{
1004
0
  LONG status = STATUS_NO_MEMORY;
1005
0
  DWORD dwTimeOut = 0;
1006
0
  const DWORD dwTimeStep = 100;
1007
0
  GetStatusChange_Return ret = WINPR_C_ARRAY_INIT;
1008
0
  GetStatusChangeA_Call* call = nullptr;
1009
0
  LPSCARD_READERSTATEA rgReaderStates = nullptr;
1010
1011
0
  WINPR_ASSERT(smartcard);
1012
0
  WINPR_ASSERT(out);
1013
0
  WINPR_ASSERT(operation);
1014
1015
0
  call = &operation->call.getStatusChangeA;
1016
0
  dwTimeOut = call->dwTimeOut;
1017
1018
0
  if (call->cReaders > 0)
1019
0
  {
1020
0
    rgReaderStates = calloc(call->cReaders, sizeof(SCARD_READERSTATEA));
1021
0
    ret.rgReaderStates =
1022
0
        (ReaderState_Return*)calloc(call->cReaders, sizeof(ReaderState_Return));
1023
0
    if (!rgReaderStates || !ret.rgReaderStates)
1024
0
      goto fail;
1025
1026
0
    ret.cReaders = call->cReaders;
1027
0
  }
1028
1029
0
  for (UINT32 x = 0; x < MAX(1, dwTimeOut);)
1030
0
  {
1031
0
    if (call->cReaders > 0)
1032
0
      memcpy(rgReaderStates, call->rgReaderStates,
1033
0
             call->cReaders * sizeof(SCARD_READERSTATEA));
1034
0
    ret.ReturnCode = wrap(smartcard, SCardGetStatusChangeA, operation->hContext,
1035
0
                          MIN(dwTimeOut, dwTimeStep), rgReaderStates, call->cReaders);
1036
0
    if (ret.ReturnCode != SCARD_E_TIMEOUT)
1037
0
      break;
1038
0
    if (smartcard_context_was_aborted(smartcard))
1039
0
      break;
1040
0
    if (dwTimeOut != INFINITE)
1041
0
      x += dwTimeStep;
1042
0
  }
1043
0
  scard_log_status_error_wlog(smartcard->log, "SCardGetStatusChangeA", ret.ReturnCode);
1044
1045
0
  status = SCARD_E_INVALID_ATR;
1046
0
  for (UINT32 index = 0; index < ret.cReaders; index++)
1047
0
  {
1048
0
    const SCARD_READERSTATEA* cur = &rgReaderStates[index];
1049
0
    ReaderState_Return* rout = &ret.rgReaderStates[index];
1050
1051
0
    rout->dwCurrentState = cur->dwCurrentState;
1052
0
    rout->dwEventState = cur->dwEventState;
1053
0
    rout->cbAtr = cur->cbAtr;
1054
0
    CopyMemory(&(rout->rgbAtr), cur->rgbAtr, sizeof(rout->rgbAtr));
1055
0
    if (!smartcard_reader_state_return_is_valid(index, rout))
1056
0
      goto fail;
1057
0
  }
1058
1059
0
  status = smartcard_pack_get_status_change_return(out, &ret, FALSE);
1060
0
fail:
1061
0
  free(ret.rgReaderStates);
1062
0
  free(rgReaderStates);
1063
0
  if (status != SCARD_S_SUCCESS)
1064
0
    return status;
1065
0
  return ret.ReturnCode;
1066
0
}
1067
1068
WINPR_ATTR_NODISCARD static LONG smartcard_GetStatusChangeW_Call(scard_call_context* smartcard,
1069
                                                                 wStream* out,
1070
                                                                 SMARTCARD_OPERATION* operation)
1071
0
{
1072
0
  LONG status = STATUS_NO_MEMORY;
1073
0
  DWORD dwTimeOut = 0;
1074
0
  const DWORD dwTimeStep = 100;
1075
0
  GetStatusChange_Return ret = WINPR_C_ARRAY_INIT;
1076
0
  LPSCARD_READERSTATEW rgReaderStates = nullptr;
1077
1078
0
  WINPR_ASSERT(smartcard);
1079
0
  WINPR_ASSERT(out);
1080
0
  WINPR_ASSERT(operation);
1081
1082
0
  GetStatusChangeW_Call* call = &operation->call.getStatusChangeW;
1083
0
  dwTimeOut = call->dwTimeOut;
1084
1085
0
  if (call->cReaders > 0)
1086
0
  {
1087
0
    rgReaderStates = calloc(call->cReaders, sizeof(SCARD_READERSTATEW));
1088
0
    ret.rgReaderStates =
1089
0
        (ReaderState_Return*)calloc(call->cReaders, sizeof(ReaderState_Return));
1090
0
    if (!rgReaderStates || !ret.rgReaderStates)
1091
0
      goto fail;
1092
1093
0
    ret.cReaders = call->cReaders;
1094
0
  }
1095
1096
0
  for (UINT32 x = 0; x < MAX(1, dwTimeOut);)
1097
0
  {
1098
0
    if (call->cReaders > 0)
1099
0
      memcpy(rgReaderStates, call->rgReaderStates,
1100
0
             call->cReaders * sizeof(SCARD_READERSTATEW));
1101
0
    {
1102
0
      ret.ReturnCode = wrap(smartcard, SCardGetStatusChangeW, operation->hContext,
1103
0
                            MIN(dwTimeOut, dwTimeStep), rgReaderStates, call->cReaders);
1104
0
    }
1105
0
    if (ret.ReturnCode != SCARD_E_TIMEOUT)
1106
0
      break;
1107
0
    if (smartcard_context_was_aborted(smartcard))
1108
0
      break;
1109
0
    if (dwTimeOut != INFINITE)
1110
0
      x += dwTimeStep;
1111
0
  }
1112
0
  scard_log_status_error_wlog(smartcard->log, "SCardGetStatusChangeW", ret.ReturnCode);
1113
1114
0
  status = SCARD_E_INVALID_ATR;
1115
0
  for (UINT32 index = 0; index < ret.cReaders; index++)
1116
0
  {
1117
0
    const SCARD_READERSTATEW* cur = &rgReaderStates[index];
1118
0
    ReaderState_Return* rout = &ret.rgReaderStates[index];
1119
1120
0
    rout->dwCurrentState = cur->dwCurrentState;
1121
0
    rout->dwEventState = cur->dwEventState;
1122
0
    rout->cbAtr = cur->cbAtr;
1123
0
    CopyMemory(&(rout->rgbAtr), cur->rgbAtr, sizeof(rout->rgbAtr));
1124
0
    if (!smartcard_reader_state_return_is_valid(index, rout))
1125
0
      goto fail;
1126
0
  }
1127
1128
0
  status = smartcard_pack_get_status_change_return(out, &ret, TRUE);
1129
0
fail:
1130
0
  free(ret.rgReaderStates);
1131
0
  free(rgReaderStates);
1132
0
  if (status != SCARD_S_SUCCESS)
1133
0
    return status;
1134
0
  return ret.ReturnCode;
1135
0
}
1136
1137
WINPR_ATTR_NODISCARD static LONG smartcard_Cancel_Call(scard_call_context* smartcard,
1138
                                                       WINPR_ATTR_UNUSED wStream* out,
1139
                                                       SMARTCARD_OPERATION* operation)
1140
0
{
1141
0
  Long_Return ret = WINPR_C_ARRAY_INIT;
1142
1143
0
  WINPR_ASSERT(smartcard);
1144
0
  WINPR_ASSERT(out);
1145
0
  WINPR_ASSERT(operation);
1146
1147
0
  ret.ReturnCode = wrap(smartcard, SCardCancel, operation->hContext);
1148
0
  scard_log_status_error_wlog(smartcard->log, "SCardCancel", ret.ReturnCode);
1149
0
  smartcard_trace_long_return_int(smartcard->log, &ret, "Cancel");
1150
0
  return ret.ReturnCode;
1151
0
}
1152
1153
WINPR_ATTR_NODISCARD static LONG
1154
smartcard_ConnectA_Call(scard_call_context* smartcard, wStream* out, SMARTCARD_OPERATION* operation)
1155
0
{
1156
0
  LONG status = 0;
1157
0
  SCARDHANDLE hCard = 0;
1158
0
  Connect_Return ret = WINPR_C_ARRAY_INIT;
1159
0
  ConnectA_Call* call = nullptr;
1160
1161
0
  WINPR_ASSERT(smartcard);
1162
0
  WINPR_ASSERT(out);
1163
0
  WINPR_ASSERT(operation);
1164
1165
0
  call = &operation->call.connectA;
1166
1167
0
  if ((call->Common.dwPreferredProtocols == SCARD_PROTOCOL_UNDEFINED) &&
1168
0
      (call->Common.dwShareMode != SCARD_SHARE_DIRECT))
1169
0
  {
1170
0
    call->Common.dwPreferredProtocols = SCARD_PROTOCOL_Tx;
1171
0
  }
1172
1173
0
  ret.ReturnCode = wrap(smartcard, SCardConnectA, operation->hContext, (char*)call->szReader,
1174
0
                        call->Common.dwShareMode, call->Common.dwPreferredProtocols, &hCard,
1175
0
                        &ret.dwActiveProtocol);
1176
0
  smartcard_scard_context_native_to_redir(&(ret.hContext), operation->hContext);
1177
0
  smartcard_scard_handle_native_to_redir(&(ret.hCard), hCard);
1178
1179
0
  status = smartcard_pack_connect_return(out, &ret);
1180
0
  if (status != SCARD_S_SUCCESS)
1181
0
    goto out_fail;
1182
1183
0
  status = ret.ReturnCode;
1184
0
out_fail:
1185
1186
0
  return status;
1187
0
}
1188
1189
WINPR_ATTR_NODISCARD static LONG
1190
smartcard_ConnectW_Call(scard_call_context* smartcard, wStream* out, SMARTCARD_OPERATION* operation)
1191
0
{
1192
0
  LONG status = 0;
1193
0
  SCARDHANDLE hCard = 0;
1194
0
  Connect_Return ret = WINPR_C_ARRAY_INIT;
1195
0
  ConnectW_Call* call = nullptr;
1196
1197
0
  WINPR_ASSERT(smartcard);
1198
0
  WINPR_ASSERT(out);
1199
0
  WINPR_ASSERT(operation);
1200
1201
0
  call = &operation->call.connectW;
1202
1203
0
  if ((call->Common.dwPreferredProtocols == SCARD_PROTOCOL_UNDEFINED) &&
1204
0
      (call->Common.dwShareMode != SCARD_SHARE_DIRECT))
1205
0
  {
1206
0
    call->Common.dwPreferredProtocols = SCARD_PROTOCOL_Tx;
1207
0
  }
1208
1209
0
  ret.ReturnCode = wrap(smartcard, SCardConnectW, operation->hContext, (WCHAR*)call->szReader,
1210
0
                        call->Common.dwShareMode, call->Common.dwPreferredProtocols, &hCard,
1211
0
                        &ret.dwActiveProtocol);
1212
0
  smartcard_scard_context_native_to_redir(&(ret.hContext), operation->hContext);
1213
0
  smartcard_scard_handle_native_to_redir(&(ret.hCard), hCard);
1214
1215
0
  status = smartcard_pack_connect_return(out, &ret);
1216
0
  if (status != SCARD_S_SUCCESS)
1217
0
    goto out_fail;
1218
1219
0
  status = ret.ReturnCode;
1220
0
out_fail:
1221
1222
0
  return status;
1223
0
}
1224
1225
WINPR_ATTR_NODISCARD static LONG smartcard_Reconnect_Call(scard_call_context* smartcard,
1226
                                                          wStream* out,
1227
                                                          SMARTCARD_OPERATION* operation)
1228
0
{
1229
0
  LONG status = 0;
1230
0
  Reconnect_Return ret = WINPR_C_ARRAY_INIT;
1231
0
  Reconnect_Call* call = nullptr;
1232
1233
0
  WINPR_ASSERT(smartcard);
1234
0
  WINPR_ASSERT(out);
1235
0
  WINPR_ASSERT(operation);
1236
1237
0
  call = &operation->call.reconnect;
1238
0
  ret.ReturnCode =
1239
0
      wrap(smartcard, SCardReconnect, operation->hCard, call->dwShareMode,
1240
0
           call->dwPreferredProtocols, call->dwInitialization, &ret.dwActiveProtocol);
1241
0
  scard_log_status_error_wlog(smartcard->log, "SCardReconnect", ret.ReturnCode);
1242
0
  status = smartcard_pack_reconnect_return(out, &ret);
1243
0
  if (status != SCARD_S_SUCCESS)
1244
0
    return status;
1245
1246
0
  return ret.ReturnCode;
1247
0
}
1248
1249
WINPR_ATTR_NODISCARD static LONG smartcard_Disconnect_Call(scard_call_context* smartcard,
1250
                                                           WINPR_ATTR_UNUSED wStream* out,
1251
                                                           SMARTCARD_OPERATION* operation)
1252
0
{
1253
0
  Long_Return ret = WINPR_C_ARRAY_INIT;
1254
0
  HCardAndDisposition_Call* call = nullptr;
1255
1256
0
  WINPR_ASSERT(smartcard);
1257
0
  WINPR_ASSERT(out);
1258
0
  WINPR_ASSERT(operation);
1259
1260
0
  call = &operation->call.hCardAndDisposition;
1261
1262
0
  ret.ReturnCode = wrap(smartcard, SCardDisconnect, operation->hCard, call->dwDisposition);
1263
0
  scard_log_status_error_wlog(smartcard->log, "SCardDisconnect", ret.ReturnCode);
1264
0
  smartcard_trace_long_return_int(smartcard->log, &ret, "Disconnect");
1265
1266
0
  return ret.ReturnCode;
1267
0
}
1268
1269
WINPR_ATTR_NODISCARD static LONG smartcard_BeginTransaction_Call(scard_call_context* smartcard,
1270
                                                                 WINPR_ATTR_UNUSED wStream* out,
1271
                                                                 SMARTCARD_OPERATION* operation)
1272
0
{
1273
0
  Long_Return ret = WINPR_C_ARRAY_INIT;
1274
1275
0
  WINPR_ASSERT(smartcard);
1276
0
  WINPR_ASSERT(out);
1277
0
  WINPR_ASSERT(operation);
1278
1279
0
  ret.ReturnCode = wrap(smartcard, SCardBeginTransaction, operation->hCard);
1280
0
  scard_log_status_error_wlog(smartcard->log, "SCardBeginTransaction", ret.ReturnCode);
1281
0
  smartcard_trace_long_return_int(smartcard->log, &ret, "BeginTransaction");
1282
0
  return ret.ReturnCode;
1283
0
}
1284
1285
WINPR_ATTR_NODISCARD static LONG smartcard_EndTransaction_Call(scard_call_context* smartcard,
1286
                                                               WINPR_ATTR_UNUSED wStream* out,
1287
                                                               SMARTCARD_OPERATION* operation)
1288
0
{
1289
0
  Long_Return ret = WINPR_C_ARRAY_INIT;
1290
0
  HCardAndDisposition_Call* call = nullptr;
1291
1292
0
  WINPR_ASSERT(smartcard);
1293
0
  WINPR_ASSERT(out);
1294
0
  WINPR_ASSERT(operation);
1295
1296
0
  call = &operation->call.hCardAndDisposition;
1297
1298
0
  ret.ReturnCode = wrap(smartcard, SCardEndTransaction, operation->hCard, call->dwDisposition);
1299
0
  scard_log_status_error_wlog(smartcard->log, "SCardEndTransaction", ret.ReturnCode);
1300
0
  smartcard_trace_long_return_int(smartcard->log, &ret, "EndTransaction");
1301
0
  return ret.ReturnCode;
1302
0
}
1303
1304
WINPR_ATTR_NODISCARD static LONG smartcard_State_Call(scard_call_context* smartcard, wStream* out,
1305
                                                      SMARTCARD_OPERATION* operation)
1306
0
{
1307
0
  LONG status = 0;
1308
0
  State_Return ret = WINPR_C_ARRAY_INIT;
1309
1310
0
  WINPR_ASSERT(smartcard);
1311
0
  WINPR_ASSERT(out);
1312
0
  WINPR_ASSERT(operation);
1313
1314
0
  ret.cbAtrLen = SCARD_ATR_LENGTH;
1315
0
  ret.ReturnCode = wrap(smartcard, SCardState, operation->hCard, &ret.dwState, &ret.dwProtocol,
1316
0
                        (BYTE*)&ret.rgAtr, &ret.cbAtrLen);
1317
1318
0
  scard_log_status_error_wlog(smartcard->log, "SCardState", ret.ReturnCode);
1319
0
  status = smartcard_pack_state_return(out, &ret);
1320
0
  if (status != SCARD_S_SUCCESS)
1321
0
    return status;
1322
1323
0
  return ret.ReturnCode;
1324
0
}
1325
1326
WINPR_ATTR_NODISCARD static LONG smartcard_StatusA_Call(scard_call_context* smartcard, wStream* out,
1327
                                                        SMARTCARD_OPERATION* operation)
1328
0
{
1329
0
  LONG status = 0;
1330
0
  Status_Return ret = WINPR_C_ARRAY_INIT;
1331
0
  DWORD cchReaderLen = 0;
1332
0
  DWORD cbAtrLen = 0;
1333
0
  LPSTR mszReaderNames = nullptr;
1334
0
  Status_Call* call = nullptr;
1335
1336
0
  WINPR_ASSERT(smartcard);
1337
0
  WINPR_ASSERT(out);
1338
0
  WINPR_ASSERT(operation);
1339
1340
0
  call = &operation->call.status;
1341
1342
0
  call->cbAtrLen = 32;
1343
0
  cbAtrLen = call->cbAtrLen;
1344
1345
0
  if (call->fmszReaderNamesIsNULL)
1346
0
    cchReaderLen = 0;
1347
0
  else
1348
0
    cchReaderLen = SCARD_AUTOALLOCATE;
1349
1350
0
  status = ret.ReturnCode =
1351
0
      wrap(smartcard, SCardStatusA, operation->hCard,
1352
0
           call->fmszReaderNamesIsNULL ? nullptr : (LPSTR)&mszReaderNames, &cchReaderLen,
1353
0
           &ret.dwState, &ret.dwProtocol, cbAtrLen ? (BYTE*)&ret.pbAtr : nullptr, &cbAtrLen);
1354
1355
0
  scard_log_status_error_wlog(smartcard->log, "SCardStatusA", status);
1356
0
  if ((ret.ReturnCode == SCARD_S_SUCCESS) && (cchReaderLen == SCARD_AUTOALLOCATE))
1357
0
    return SCARD_F_UNKNOWN_ERROR;
1358
1359
0
  if (status == SCARD_S_SUCCESS)
1360
0
  {
1361
0
    if (!call->fmszReaderNamesIsNULL)
1362
0
      ret.mszReaderNames = (BYTE*)mszReaderNames;
1363
1364
0
    ret.cBytes = cchReaderLen;
1365
1366
0
    if (call->cbAtrLen)
1367
0
      ret.cbAtrLen = cbAtrLen;
1368
0
  }
1369
1370
0
  status = smartcard_pack_status_return(out, &ret, FALSE);
1371
1372
0
  if (mszReaderNames)
1373
0
    wrap(smartcard, SCardFreeMemory, operation->hContext, mszReaderNames);
1374
1375
0
  if (status != SCARD_S_SUCCESS)
1376
0
    return status;
1377
0
  return ret.ReturnCode;
1378
0
}
1379
1380
WINPR_ATTR_NODISCARD static LONG smartcard_StatusW_Call(scard_call_context* smartcard, wStream* out,
1381
                                                        SMARTCARD_OPERATION* operation)
1382
0
{
1383
0
  LONG status = 0;
1384
0
  Status_Return ret = WINPR_C_ARRAY_INIT;
1385
0
  LPWSTR mszReaderNames = nullptr;
1386
0
  Status_Call* call = nullptr;
1387
0
  DWORD cbAtrLen = 0;
1388
1389
0
  WINPR_ASSERT(smartcard);
1390
0
  WINPR_ASSERT(out);
1391
0
  WINPR_ASSERT(operation);
1392
1393
0
  call = &operation->call.status;
1394
1395
  /**
1396
   * [MS-RDPESC]
1397
   * According to 2.2.2.18 Status_Call cbAtrLen is unused an must be ignored upon receipt.
1398
   */
1399
0
  cbAtrLen = call->cbAtrLen = 32;
1400
1401
0
  if (call->fmszReaderNamesIsNULL)
1402
0
    ret.cBytes = 0;
1403
0
  else
1404
0
    ret.cBytes = SCARD_AUTOALLOCATE;
1405
1406
0
  status = ret.ReturnCode =
1407
0
      wrap(smartcard, SCardStatusW, operation->hCard,
1408
0
           call->fmszReaderNamesIsNULL ? nullptr : (LPWSTR)&mszReaderNames, &ret.cBytes,
1409
0
           &ret.dwState, &ret.dwProtocol, (BYTE*)&ret.pbAtr, &cbAtrLen);
1410
0
  scard_log_status_error_wlog(smartcard->log, "SCardStatusW", status);
1411
0
  if ((ret.ReturnCode == SCARD_S_SUCCESS) && (ret.cBytes == SCARD_AUTOALLOCATE))
1412
0
    return SCARD_F_UNKNOWN_ERROR;
1413
1414
0
  size_t blen = 0;
1415
0
  if (status == SCARD_S_SUCCESS)
1416
0
  {
1417
0
    if (!call->fmszReaderNamesIsNULL)
1418
0
      ret.mszReaderNames = (BYTE*)mszReaderNames;
1419
1420
0
    ret.cbAtrLen = cbAtrLen;
1421
0
  }
1422
1423
0
  if (ret.cBytes != SCARD_AUTOALLOCATE)
1424
0
  {
1425
    /* SCardStatusW returns number of characters, we need number of bytes */
1426
0
    WINPR_ASSERT(ret.cBytes < SCARD_AUTOALLOCATE / sizeof(WCHAR));
1427
0
    blen = sizeof(WCHAR) * ret.cBytes;
1428
0
    WINPR_ASSERT(blen <= UINT32_MAX);
1429
0
    ret.cBytes = (UINT32)blen;
1430
0
  }
1431
1432
0
  status = smartcard_pack_status_return(out, &ret, TRUE);
1433
0
  if (status != SCARD_S_SUCCESS)
1434
0
    return status;
1435
1436
0
  if (mszReaderNames)
1437
0
    wrap(smartcard, SCardFreeMemory, operation->hContext, mszReaderNames);
1438
1439
0
  return ret.ReturnCode;
1440
0
}
1441
1442
WINPR_ATTR_NODISCARD static LONG
1443
smartcard_Transmit_Call(scard_call_context* smartcard, wStream* out, SMARTCARD_OPERATION* operation)
1444
0
{
1445
0
  LONG status = 0;
1446
0
  Transmit_Return ret = WINPR_C_ARRAY_INIT;
1447
0
  Transmit_Call* call = nullptr;
1448
1449
0
  WINPR_ASSERT(smartcard);
1450
0
  WINPR_ASSERT(out);
1451
0
  WINPR_ASSERT(operation);
1452
1453
0
  call = &operation->call.transmit;
1454
0
  ret.cbRecvLength = 0;
1455
0
  ret.pbRecvBuffer = nullptr;
1456
1457
0
  if (call->cbRecvLength && !call->fpbRecvBufferIsNULL)
1458
0
  {
1459
0
    if (call->cbRecvLength >= 66560)
1460
0
      call->cbRecvLength = 66560;
1461
1462
0
    const UINT32 cbRecvLength = call->cbRecvLength;
1463
0
    ret.pbRecvBuffer = (BYTE*)malloc(cbRecvLength);
1464
1465
0
    if (!ret.pbRecvBuffer)
1466
0
      return STATUS_NO_MEMORY;
1467
0
    ret.cbRecvLength = cbRecvLength;
1468
0
  }
1469
1470
0
  ret.pioRecvPci = call->pioRecvPci;
1471
0
  ret.ReturnCode =
1472
0
      wrap(smartcard, SCardTransmit, operation->hCard, call->pioSendPci, call->pbSendBuffer,
1473
0
           call->cbSendLength, ret.pioRecvPci, ret.pbRecvBuffer, &(ret.cbRecvLength));
1474
1475
0
  scard_log_status_error_wlog(smartcard->log, "SCardTransmit", ret.ReturnCode);
1476
1477
0
  status = smartcard_pack_transmit_return(out, &ret);
1478
0
  free(ret.pbRecvBuffer);
1479
1480
0
  if (status != SCARD_S_SUCCESS)
1481
0
    return status;
1482
0
  return ret.ReturnCode;
1483
0
}
1484
1485
WINPR_ATTR_NODISCARD static LONG smartcard_Control_Call(scard_call_context* smartcard, wStream* out,
1486
                                                        SMARTCARD_OPERATION* operation)
1487
0
{
1488
0
  LONG status = 0;
1489
0
  Control_Return ret = WINPR_C_ARRAY_INIT;
1490
0
  Control_Call* call = nullptr;
1491
1492
0
  WINPR_ASSERT(smartcard);
1493
0
  WINPR_ASSERT(out);
1494
0
  WINPR_ASSERT(operation);
1495
1496
0
  call = &operation->call.control;
1497
0
  ret.pvOutBuffer = (BYTE*)malloc(call->cbOutBufferSize);
1498
1499
0
  if (!ret.pvOutBuffer)
1500
0
    return SCARD_E_NO_MEMORY;
1501
0
  ret.cbOutBufferSize = call->cbOutBufferSize;
1502
1503
0
  ret.ReturnCode =
1504
0
      wrap(smartcard, SCardControl, operation->hCard, call->dwControlCode, call->pvInBuffer,
1505
0
           call->cbInBufferSize, ret.pvOutBuffer, call->cbOutBufferSize, &ret.cbOutBufferSize);
1506
0
  scard_log_status_error_wlog(smartcard->log, "SCardControl", ret.ReturnCode);
1507
0
  status = smartcard_pack_control_return(out, &ret);
1508
1509
0
  free(ret.pvOutBuffer);
1510
0
  if (status != SCARD_S_SUCCESS)
1511
0
    return status;
1512
0
  return ret.ReturnCode;
1513
0
}
1514
1515
WINPR_ATTR_NODISCARD static LONG smartcard_GetAttrib_Call(scard_call_context* smartcard,
1516
                                                          wStream* out,
1517
                                                          SMARTCARD_OPERATION* operation)
1518
0
{
1519
0
  BOOL autoAllocate = FALSE;
1520
0
  LONG status = 0;
1521
0
  DWORD cbAttrLen = 0;
1522
0
  LPBYTE pbAttr = nullptr;
1523
0
  GetAttrib_Return ret = WINPR_C_ARRAY_INIT;
1524
0
  const GetAttrib_Call* call = nullptr;
1525
1526
0
  WINPR_ASSERT(smartcard);
1527
0
  WINPR_ASSERT(operation);
1528
1529
0
  call = &operation->call.getAttrib;
1530
1531
0
  if (!call->fpbAttrIsNULL)
1532
0
  {
1533
0
    autoAllocate = (call->cbAttrLen == SCARD_AUTOALLOCATE);
1534
0
    cbAttrLen = call->cbAttrLen;
1535
0
    if (cbAttrLen && !autoAllocate)
1536
0
    {
1537
0
      ret.pbAttr = (BYTE*)malloc(cbAttrLen);
1538
1539
0
      if (!ret.pbAttr)
1540
0
        return SCARD_E_NO_MEMORY;
1541
0
    }
1542
1543
0
    pbAttr = autoAllocate ? (LPBYTE) & (ret.pbAttr) : ret.pbAttr;
1544
0
  }
1545
1546
0
  ret.ReturnCode =
1547
0
      wrap(smartcard, SCardGetAttrib, operation->hCard, call->dwAttrId, pbAttr, &cbAttrLen);
1548
0
  scard_log_status_error_wlog(smartcard->log, "SCardGetAttrib", ret.ReturnCode);
1549
0
  if ((ret.ReturnCode == SCARD_S_SUCCESS) && (cbAttrLen == SCARD_AUTOALLOCATE))
1550
0
    return SCARD_F_UNKNOWN_ERROR;
1551
1552
0
  ret.cbAttrLen = cbAttrLen;
1553
1554
0
  status = smartcard_pack_get_attrib_return(out, &ret, call->dwAttrId, call->cbAttrLen);
1555
1556
0
  if (autoAllocate)
1557
0
    wrap(smartcard, SCardFreeMemory, operation->hContext, ret.pbAttr);
1558
0
  else
1559
0
    free(ret.pbAttr);
1560
0
  return status;
1561
0
}
1562
1563
WINPR_ATTR_NODISCARD static LONG smartcard_SetAttrib_Call(scard_call_context* smartcard,
1564
                                                          WINPR_ATTR_UNUSED wStream* out,
1565
                                                          SMARTCARD_OPERATION* operation)
1566
0
{
1567
0
  Long_Return ret = WINPR_C_ARRAY_INIT;
1568
0
  SetAttrib_Call* call = nullptr;
1569
1570
0
  WINPR_ASSERT(smartcard);
1571
0
  WINPR_ASSERT(out);
1572
0
  WINPR_ASSERT(operation);
1573
1574
0
  call = &operation->call.setAttrib;
1575
1576
0
  ret.ReturnCode = wrap(smartcard, SCardSetAttrib, operation->hCard, call->dwAttrId, call->pbAttr,
1577
0
                        call->cbAttrLen);
1578
0
  scard_log_status_error_wlog(smartcard->log, "SCardSetAttrib", ret.ReturnCode);
1579
0
  smartcard_trace_long_return_int(smartcard->log, &ret, "SetAttrib");
1580
1581
0
  return ret.ReturnCode;
1582
0
}
1583
1584
WINPR_ATTR_NODISCARD static LONG smartcard_AccessStartedEvent_Call(scard_call_context* smartcard,
1585
                                                                   WINPR_ATTR_UNUSED wStream* out,
1586
                                                                   SMARTCARD_OPERATION* operation)
1587
0
{
1588
0
  LONG status = SCARD_S_SUCCESS;
1589
1590
0
  WINPR_ASSERT(smartcard);
1591
0
  WINPR_ASSERT(out);
1592
0
  WINPR_UNUSED(operation);
1593
1594
0
  if (!smartcard->StartedEvent)
1595
0
    smartcard->StartedEvent = wrap_ptr(smartcard, SCardAccessStartedEvent);
1596
1597
0
  if (!smartcard->StartedEvent)
1598
0
    status = SCARD_E_NO_SERVICE;
1599
1600
0
  return status;
1601
0
}
1602
1603
WINPR_ATTR_NODISCARD static LONG smartcard_LocateCardsByATRA_Call(scard_call_context* smartcard,
1604
                                                                  wStream* out,
1605
                                                                  SMARTCARD_OPERATION* operation)
1606
0
{
1607
0
  LONG status = SCARD_E_INVALID_HANDLE;
1608
0
  GetStatusChange_Return ret = WINPR_C_ARRAY_INIT;
1609
1610
0
  WINPR_ASSERT(smartcard);
1611
0
  WINPR_ASSERT(operation);
1612
1613
0
  LocateCardsByATRA_Call* call = &operation->call.locateCardsByATRA;
1614
0
  LPSCARD_READERSTATEA states =
1615
0
      (LPSCARD_READERSTATEA)calloc(call->cReaders, sizeof(SCARD_READERSTATEA));
1616
1617
0
  if (!states)
1618
0
    return STATUS_NO_MEMORY;
1619
1620
0
  for (UINT32 i = 0; i < call->cReaders; i++)
1621
0
  {
1622
0
    const LPSCARD_READERSTATEA cstate = &call->rgReaderStates[i];
1623
0
    LPSCARD_READERSTATEA state = &states[i];
1624
1625
0
    state->szReader = cstate->szReader;
1626
0
    state->dwCurrentState = cstate->dwCurrentState;
1627
0
    state->dwEventState = cstate->dwEventState;
1628
0
    state->cbAtr = cstate->cbAtr;
1629
1630
0
    if (state->cbAtr > sizeof(state->rgbAtr))
1631
0
    {
1632
0
      WLog_WARN(SCARD_TAG, "[%" PRIu32 "] val->cbAtr=%" PRIu32 ", max=%" PRIuz, i,
1633
0
                state->cbAtr, sizeof(state->rgbAtr));
1634
0
      goto fail;
1635
0
    }
1636
0
    CopyMemory(&(state->rgbAtr), &(cstate->rgbAtr), sizeof(cstate->rgbAtr));
1637
0
  }
1638
1639
0
  status = ret.ReturnCode = wrap(smartcard, SCardGetStatusChangeA, operation->hContext,
1640
0
                                 0x000001F4, states, call->cReaders);
1641
1642
0
  scard_log_status_error_wlog(smartcard->log, "SCardGetStatusChangeA", status);
1643
0
  for (UINT32 i = 0; i < call->cAtrs; i++)
1644
0
  {
1645
0
    for (UINT32 j = 0; j < call->cReaders; j++)
1646
0
    {
1647
0
      const LocateCards_ATRMask* mask = &call->rgAtrMasks[i];
1648
0
      for (UINT32 k = 0; k < mask->cbAtr; k++)
1649
0
      {
1650
0
        if ((mask->rgbAtr[k] & mask->rgbMask[k]) !=
1651
0
            (states[j].rgbAtr[k] & mask->rgbMask[k]))
1652
0
        {
1653
0
          break;
1654
0
        }
1655
1656
0
        states[j].dwEventState |= SCARD_STATE_ATRMATCH;
1657
0
      }
1658
0
    }
1659
0
  }
1660
1661
0
  ret.rgReaderStates = nullptr;
1662
1663
0
  if (call->cReaders > 0)
1664
0
    ret.rgReaderStates =
1665
0
        (ReaderState_Return*)calloc(call->cReaders, sizeof(ReaderState_Return));
1666
1667
0
  if (!ret.rgReaderStates)
1668
0
  {
1669
0
    status = STATUS_NO_MEMORY;
1670
0
    goto fail;
1671
0
  }
1672
1673
0
  ret.cReaders = call->cReaders;
1674
1675
0
  status = SCARD_E_INVALID_ATR;
1676
0
  for (UINT32 i = 0; i < ret.cReaders; i++)
1677
0
  {
1678
0
    const LPSCARD_READERSTATEA state = &states[i];
1679
0
    ReaderState_Return* cur = &ret.rgReaderStates[i];
1680
1681
0
    cur->dwCurrentState = state->dwCurrentState;
1682
0
    cur->dwEventState = state->dwEventState;
1683
0
    cur->cbAtr = state->cbAtr;
1684
0
    CopyMemory(&(cur->rgbAtr), &(state->rgbAtr), sizeof(cur->rgbAtr));
1685
1686
0
    if (!smartcard_reader_state_return_is_valid(i, cur))
1687
0
      goto fail;
1688
0
  }
1689
1690
0
  status = smartcard_pack_get_status_change_return(out, &ret, FALSE);
1691
1692
0
fail:
1693
0
  free(states);
1694
0
  free(ret.rgReaderStates);
1695
0
  if (status != SCARD_S_SUCCESS)
1696
0
    return status;
1697
0
  return ret.ReturnCode;
1698
0
}
1699
1700
WINPR_ATTR_NODISCARD static LONG smartcard_LocateCardsByATRW_Call(scard_call_context* smartcard,
1701
                                                                  wStream* out,
1702
                                                                  SMARTCARD_OPERATION* operation)
1703
0
{
1704
0
  LONG status = SCARD_E_INVALID_HANDLE;
1705
0
  GetStatusChange_Return ret = WINPR_C_ARRAY_INIT;
1706
1707
0
  WINPR_ASSERT(smartcard);
1708
0
  WINPR_ASSERT(operation);
1709
1710
0
  LocateCardsByATRW_Call* call = &operation->call.locateCardsByATRW;
1711
0
  LPSCARD_READERSTATEW states =
1712
0
      (LPSCARD_READERSTATEW)calloc(call->cReaders, sizeof(SCARD_READERSTATEW));
1713
1714
0
  if (!states)
1715
0
    return STATUS_NO_MEMORY;
1716
1717
0
  for (UINT32 i = 0; i < call->cReaders; i++)
1718
0
  {
1719
0
    const LPSCARD_READERSTATEW cstate = &call->rgReaderStates[i];
1720
0
    LPSCARD_READERSTATEW state = &states[i];
1721
1722
0
    state->szReader = cstate->szReader;
1723
0
    state->dwCurrentState = cstate->dwCurrentState;
1724
0
    state->dwEventState = cstate->dwEventState;
1725
0
    state->cbAtr = cstate->cbAtr;
1726
1727
0
    if (state->cbAtr > sizeof(state->rgbAtr))
1728
0
    {
1729
0
      WLog_WARN(SCARD_TAG, "[%" PRIu32 "] val->cbAtr=%" PRIu32 ", max=%" PRIuz, i,
1730
0
                state->cbAtr, sizeof(state->rgbAtr));
1731
0
      goto fail;
1732
0
    }
1733
0
    CopyMemory(&(state->rgbAtr), &(cstate->rgbAtr), sizeof(cstate->rgbAtr));
1734
0
  }
1735
1736
0
  status = ret.ReturnCode = wrap(smartcard, SCardGetStatusChangeW, operation->hContext,
1737
0
                                 0x000001F4, states, call->cReaders);
1738
1739
0
  scard_log_status_error_wlog(smartcard->log, "SCardGetStatusChangeW", status);
1740
0
  for (UINT32 i = 0; i < call->cAtrs; i++)
1741
0
  {
1742
0
    for (UINT32 j = 0; j < call->cReaders; j++)
1743
0
    {
1744
0
      const LocateCards_ATRMask* mask = &call->rgAtrMasks[i];
1745
0
      for (UINT32 k = 0; k < mask->cbAtr; k++)
1746
0
      {
1747
0
        if ((mask->rgbAtr[k] & mask->rgbMask[k]) !=
1748
0
            (states[j].rgbAtr[k] & mask->rgbMask[k]))
1749
0
        {
1750
0
          break;
1751
0
        }
1752
1753
0
        states[j].dwEventState |= SCARD_STATE_ATRMATCH;
1754
0
      }
1755
0
    }
1756
0
  }
1757
1758
0
  ret.rgReaderStates = nullptr;
1759
1760
0
  if (call->cReaders > 0)
1761
0
    ret.rgReaderStates =
1762
0
        (ReaderState_Return*)calloc(call->cReaders, sizeof(ReaderState_Return));
1763
1764
0
  if (!ret.rgReaderStates)
1765
0
  {
1766
0
    status = STATUS_NO_MEMORY;
1767
0
    goto fail;
1768
0
  }
1769
1770
0
  ret.cReaders = call->cReaders;
1771
1772
0
  status = SCARD_E_INVALID_ATR;
1773
0
  for (UINT32 i = 0; i < ret.cReaders; i++)
1774
0
  {
1775
0
    const LPSCARD_READERSTATEW state = &states[i];
1776
0
    ReaderState_Return* cur = &ret.rgReaderStates[i];
1777
1778
0
    cur->dwCurrentState = state->dwCurrentState;
1779
0
    cur->dwEventState = state->dwEventState;
1780
0
    cur->cbAtr = state->cbAtr;
1781
0
    CopyMemory(&(cur->rgbAtr), &(state->rgbAtr), sizeof(cur->rgbAtr));
1782
1783
0
    if (!smartcard_reader_state_return_is_valid(i, cur))
1784
0
      goto fail;
1785
0
  }
1786
1787
0
  status = smartcard_pack_get_status_change_return(out, &ret, FALSE);
1788
1789
0
fail:
1790
0
  free(states);
1791
0
  free(ret.rgReaderStates);
1792
0
  if (status != SCARD_S_SUCCESS)
1793
0
    return status;
1794
0
  return ret.ReturnCode;
1795
0
}
1796
1797
LONG smartcard_irp_device_control_call(scard_call_context* ctx, wStream* out, NTSTATUS* pIoStatus,
1798
                                       SMARTCARD_OPERATION* operation)
1799
0
{
1800
0
  LONG result = 0;
1801
0
  UINT32 offset = 0;
1802
0
  size_t objectBufferLength = 0;
1803
1804
0
  WINPR_ASSERT(ctx);
1805
0
  WINPR_ASSERT(out);
1806
0
  WINPR_ASSERT(pIoStatus);
1807
0
  WINPR_ASSERT(operation);
1808
1809
0
  const UINT32 ioControlCode = operation->ioControlCode;
1810
  /**
1811
   * [MS-RDPESC] 3.2.5.1: Sending Outgoing Messages:
1812
   * the output buffer length SHOULD be set to 2048
1813
   *
1814
   * Since it's a SHOULD and not a MUST, we don't care
1815
   * about it, but we still reserve at least 2048 bytes.
1816
   */
1817
0
  const size_t outMaxLen = MAX(2048, operation->outputBufferLength);
1818
0
  if (!Stream_EnsureRemainingCapacity(out, outMaxLen))
1819
0
    return SCARD_E_NO_MEMORY;
1820
1821
  /* Device Control Response */
1822
0
  Stream_Write_UINT32(out, 0);                            /* OutputBufferLength (4 bytes) */
1823
0
  Stream_Zero(out, SMARTCARD_COMMON_TYPE_HEADER_LENGTH);  /* CommonTypeHeader (8 bytes) */
1824
0
  Stream_Zero(out, SMARTCARD_PRIVATE_TYPE_HEADER_LENGTH); /* PrivateTypeHeader (8 bytes) */
1825
0
  Stream_Write_UINT32(out, 0);                            /* Result (4 bytes) */
1826
1827
  /* Call */
1828
0
  switch (ioControlCode)
1829
0
  {
1830
0
    case SCARD_IOCTL_ESTABLISHCONTEXT:
1831
0
      result = smartcard_EstablishContext_Call(ctx, out, operation);
1832
0
      break;
1833
1834
0
    case SCARD_IOCTL_RELEASECONTEXT:
1835
0
      result = smartcard_ReleaseContext_Call(ctx, out, operation);
1836
0
      break;
1837
1838
0
    case SCARD_IOCTL_ISVALIDCONTEXT:
1839
0
      result = smartcard_IsValidContext_Call(ctx, out, operation);
1840
0
      break;
1841
1842
0
    case SCARD_IOCTL_LISTREADERGROUPSA:
1843
0
      result = smartcard_ListReaderGroupsA_Call(ctx, out, operation);
1844
0
      break;
1845
1846
0
    case SCARD_IOCTL_LISTREADERGROUPSW:
1847
0
      result = smartcard_ListReaderGroupsW_Call(ctx, out, operation);
1848
0
      break;
1849
1850
0
    case SCARD_IOCTL_LISTREADERSA:
1851
0
      result = smartcard_ListReadersA_Call(ctx, out, operation);
1852
0
      break;
1853
1854
0
    case SCARD_IOCTL_LISTREADERSW:
1855
0
      result = smartcard_ListReadersW_Call(ctx, out, operation);
1856
0
      break;
1857
1858
0
    case SCARD_IOCTL_INTRODUCEREADERGROUPA:
1859
0
      result = smartcard_IntroduceReaderGroupA_Call(ctx, out, operation);
1860
0
      break;
1861
1862
0
    case SCARD_IOCTL_INTRODUCEREADERGROUPW:
1863
0
      result = smartcard_IntroduceReaderGroupW_Call(ctx, out, operation);
1864
0
      break;
1865
1866
0
    case SCARD_IOCTL_FORGETREADERGROUPA:
1867
0
      result = smartcard_ForgetReaderA_Call(ctx, out, operation);
1868
0
      break;
1869
1870
0
    case SCARD_IOCTL_FORGETREADERGROUPW:
1871
0
      result = smartcard_ForgetReaderW_Call(ctx, out, operation);
1872
0
      break;
1873
1874
0
    case SCARD_IOCTL_INTRODUCEREADERA:
1875
0
      result = smartcard_IntroduceReaderA_Call(ctx, out, operation);
1876
0
      break;
1877
1878
0
    case SCARD_IOCTL_INTRODUCEREADERW:
1879
0
      result = smartcard_IntroduceReaderW_Call(ctx, out, operation);
1880
0
      break;
1881
1882
0
    case SCARD_IOCTL_FORGETREADERA:
1883
0
      result = smartcard_ForgetReaderA_Call(ctx, out, operation);
1884
0
      break;
1885
1886
0
    case SCARD_IOCTL_FORGETREADERW:
1887
0
      result = smartcard_ForgetReaderW_Call(ctx, out, operation);
1888
0
      break;
1889
1890
0
    case SCARD_IOCTL_ADDREADERTOGROUPA:
1891
0
      result = smartcard_AddReaderToGroupA_Call(ctx, out, operation);
1892
0
      break;
1893
1894
0
    case SCARD_IOCTL_ADDREADERTOGROUPW:
1895
0
      result = smartcard_AddReaderToGroupW_Call(ctx, out, operation);
1896
0
      break;
1897
1898
0
    case SCARD_IOCTL_REMOVEREADERFROMGROUPA:
1899
0
      result = smartcard_RemoveReaderFromGroupA_Call(ctx, out, operation);
1900
0
      break;
1901
1902
0
    case SCARD_IOCTL_REMOVEREADERFROMGROUPW:
1903
0
      result = smartcard_RemoveReaderFromGroupW_Call(ctx, out, operation);
1904
0
      break;
1905
1906
0
    case SCARD_IOCTL_LOCATECARDSA:
1907
0
      result = smartcard_LocateCardsA_Call(ctx, out, operation);
1908
0
      break;
1909
1910
0
    case SCARD_IOCTL_LOCATECARDSW:
1911
0
      result = smartcard_LocateCardsW_Call(ctx, out, operation);
1912
0
      break;
1913
1914
0
    case SCARD_IOCTL_GETSTATUSCHANGEA:
1915
0
      result = smartcard_GetStatusChangeA_Call(ctx, out, operation);
1916
0
      break;
1917
1918
0
    case SCARD_IOCTL_GETSTATUSCHANGEW:
1919
0
      result = smartcard_GetStatusChangeW_Call(ctx, out, operation);
1920
0
      break;
1921
1922
0
    case SCARD_IOCTL_CANCEL:
1923
0
      result = smartcard_Cancel_Call(ctx, out, operation);
1924
0
      break;
1925
1926
0
    case SCARD_IOCTL_CONNECTA:
1927
0
      result = smartcard_ConnectA_Call(ctx, out, operation);
1928
0
      break;
1929
1930
0
    case SCARD_IOCTL_CONNECTW:
1931
0
      result = smartcard_ConnectW_Call(ctx, out, operation);
1932
0
      break;
1933
1934
0
    case SCARD_IOCTL_RECONNECT:
1935
0
      result = smartcard_Reconnect_Call(ctx, out, operation);
1936
0
      break;
1937
1938
0
    case SCARD_IOCTL_DISCONNECT:
1939
0
      result = smartcard_Disconnect_Call(ctx, out, operation);
1940
0
      break;
1941
1942
0
    case SCARD_IOCTL_BEGINTRANSACTION:
1943
0
      result = smartcard_BeginTransaction_Call(ctx, out, operation);
1944
0
      break;
1945
1946
0
    case SCARD_IOCTL_ENDTRANSACTION:
1947
0
      result = smartcard_EndTransaction_Call(ctx, out, operation);
1948
0
      break;
1949
1950
0
    case SCARD_IOCTL_STATE:
1951
0
      result = smartcard_State_Call(ctx, out, operation);
1952
0
      break;
1953
1954
0
    case SCARD_IOCTL_STATUSA:
1955
0
      result = smartcard_StatusA_Call(ctx, out, operation);
1956
0
      break;
1957
1958
0
    case SCARD_IOCTL_STATUSW:
1959
0
      result = smartcard_StatusW_Call(ctx, out, operation);
1960
0
      break;
1961
1962
0
    case SCARD_IOCTL_TRANSMIT:
1963
0
      result = smartcard_Transmit_Call(ctx, out, operation);
1964
0
      break;
1965
1966
0
    case SCARD_IOCTL_CONTROL:
1967
0
      result = smartcard_Control_Call(ctx, out, operation);
1968
0
      break;
1969
1970
0
    case SCARD_IOCTL_GETATTRIB:
1971
0
      result = smartcard_GetAttrib_Call(ctx, out, operation);
1972
0
      break;
1973
1974
0
    case SCARD_IOCTL_SETATTRIB:
1975
0
      result = smartcard_SetAttrib_Call(ctx, out, operation);
1976
0
      break;
1977
1978
0
    case SCARD_IOCTL_ACCESSSTARTEDEVENT:
1979
0
      result = smartcard_AccessStartedEvent_Call(ctx, out, operation);
1980
0
      break;
1981
1982
0
    case SCARD_IOCTL_LOCATECARDSBYATRA:
1983
0
      result = smartcard_LocateCardsByATRA_Call(ctx, out, operation);
1984
0
      break;
1985
1986
0
    case SCARD_IOCTL_LOCATECARDSBYATRW:
1987
0
      result = smartcard_LocateCardsByATRW_Call(ctx, out, operation);
1988
0
      break;
1989
1990
0
    case SCARD_IOCTL_READCACHEA:
1991
0
      result = smartcard_ReadCacheA_Call(ctx, out, operation);
1992
0
      break;
1993
1994
0
    case SCARD_IOCTL_READCACHEW:
1995
0
      result = smartcard_ReadCacheW_Call(ctx, out, operation);
1996
0
      break;
1997
1998
0
    case SCARD_IOCTL_WRITECACHEA:
1999
0
      result = smartcard_WriteCacheA_Call(ctx, out, operation);
2000
0
      break;
2001
2002
0
    case SCARD_IOCTL_WRITECACHEW:
2003
0
      result = smartcard_WriteCacheW_Call(ctx, out, operation);
2004
0
      break;
2005
2006
0
    case SCARD_IOCTL_GETTRANSMITCOUNT:
2007
0
      result = smartcard_GetTransmitCount_Call(ctx, out, operation);
2008
0
      break;
2009
2010
0
    case SCARD_IOCTL_RELEASETARTEDEVENT:
2011
0
      result = smartcard_ReleaseStartedEvent_Call(ctx, out, operation);
2012
0
      break;
2013
2014
0
    case SCARD_IOCTL_GETREADERICON:
2015
0
      result = smartcard_GetReaderIcon_Call(ctx, out, operation);
2016
0
      break;
2017
2018
0
    case SCARD_IOCTL_GETDEVICETYPEID:
2019
0
      result = smartcard_GetDeviceTypeId_Call(ctx, out, operation);
2020
0
      break;
2021
2022
0
    default:
2023
0
      result = STATUS_UNSUCCESSFUL;
2024
0
      break;
2025
0
  }
2026
2027
  /**
2028
   * [MS-RPCE] 2.2.6.3 Primitive Type Serialization
2029
   * The type MUST be aligned on an 8-byte boundary. If the size of the
2030
   * primitive type is not a multiple of 8 bytes, the data MUST be padded.
2031
   */
2032
2033
0
  if ((ioControlCode != SCARD_IOCTL_ACCESSSTARTEDEVENT) &&
2034
0
      (ioControlCode != SCARD_IOCTL_RELEASETARTEDEVENT))
2035
0
  {
2036
0
    offset = (RDPDR_DEVICE_IO_RESPONSE_LENGTH + RDPDR_DEVICE_IO_CONTROL_RSP_HDR_LENGTH);
2037
0
    const LONG rc = smartcard_pack_write_size_align(out, Stream_GetPosition(out) - offset, 8);
2038
0
    if (rc != SCARD_S_SUCCESS)
2039
0
      result = rc;
2040
0
  }
2041
2042
0
  if ((result != SCARD_S_SUCCESS) && (result != SCARD_E_TIMEOUT) &&
2043
0
      (result != SCARD_E_NO_READERS_AVAILABLE) && (result != SCARD_E_NO_SERVICE) &&
2044
0
      (result != SCARD_W_CACHE_ITEM_NOT_FOUND) && (result != SCARD_W_CACHE_ITEM_STALE))
2045
0
  {
2046
0
    scard_log_status_error_wlog(ctx->log, "IRP failure: %s (0x%08" PRIX32 ")", result,
2047
0
                                scard_get_ioctl_string(ioControlCode, TRUE), ioControlCode);
2048
0
  }
2049
2050
0
  *pIoStatus = STATUS_SUCCESS;
2051
2052
0
  if ((result & 0xC0000000L) == 0xC0000000L)
2053
0
  {
2054
    /* NTSTATUS error */
2055
0
    *pIoStatus = result;
2056
2057
0
    scard_log_status_error_wlog(ctx->log, "IRP failure: %s (0x%08" PRIX32 ")", result,
2058
0
                                scard_get_ioctl_string(ioControlCode, TRUE), ioControlCode);
2059
0
  }
2060
2061
0
  Stream_SealLength(out);
2062
0
  size_t outputBufferLength = Stream_Length(out);
2063
0
  size_t dataEndPos = outputBufferLength;
2064
2065
0
  WINPR_ASSERT(outputBufferLength >= RDPDR_DEVICE_IO_RESPONSE_LENGTH + 4U);
2066
0
  outputBufferLength -= (RDPDR_DEVICE_IO_RESPONSE_LENGTH + 4U);
2067
0
  WINPR_ASSERT(outputBufferLength >= RDPDR_DEVICE_IO_RESPONSE_LENGTH);
2068
0
  objectBufferLength = outputBufferLength - RDPDR_DEVICE_IO_RESPONSE_LENGTH;
2069
0
  WINPR_ASSERT(outputBufferLength <= UINT32_MAX);
2070
0
  WINPR_ASSERT(objectBufferLength <= UINT32_MAX);
2071
0
  if (!Stream_SetPosition(out, RDPDR_DEVICE_IO_RESPONSE_LENGTH))
2072
0
    return SCARD_E_BAD_SEEK;
2073
2074
  /* [MS-RDPESC] 3.2.5.2 Processing Incoming Replies
2075
   *
2076
   * if the output buffer is too small, reply with STATUS_BUFFER_TOO_SMALL
2077
   * and a outputBufferLength of 0.
2078
   * The message should then be retransmitted from the server with a doubled
2079
   * buffer size.
2080
   */
2081
0
  if (outputBufferLength > operation->outputBufferLength)
2082
0
  {
2083
0
    WLog_Print(ctx->log, WLOG_DEBUG,
2084
0
               "IRP  warn: expected outputBufferLength %" PRIuz ", but current limit %" PRIu32
2085
0
               ", respond with STATUS_BUFFER_TOO_SMALL for retransmit with larger buffer",
2086
0
               outputBufferLength, operation->outputBufferLength);
2087
2088
0
    *pIoStatus = STATUS_BUFFER_TOO_SMALL;
2089
0
    result = *pIoStatus;
2090
0
    outputBufferLength = 0;
2091
0
    objectBufferLength = 0;
2092
0
  }
2093
0
  else
2094
0
  {
2095
0
    WLog_Print(ctx->log, WLOG_TRACE, "IRP trace: outputBufferLength %" PRIuz ", limit %" PRIu32,
2096
0
               outputBufferLength, operation->outputBufferLength);
2097
0
  }
2098
2099
  /* Device Control Response */
2100
0
  Stream_Write_UINT32(out, (UINT32)outputBufferLength); /* OutputBufferLength (4 bytes) */
2101
0
  smartcard_pack_common_type_header(out);               /* CommonTypeHeader (8 bytes) */
2102
0
  smartcard_pack_private_type_header(
2103
0
      out, (UINT32)objectBufferLength); /* PrivateTypeHeader (8 bytes) */
2104
0
  Stream_Write_INT32(out, result);      /* Result (4 bytes) */
2105
0
  if (result == STATUS_BUFFER_TOO_SMALL)
2106
0
    Stream_SealLength(out);
2107
0
  else if (!Stream_SetPosition(out, dataEndPos))
2108
0
    return SCARD_E_BAD_SEEK;
2109
0
  return SCARD_S_SUCCESS;
2110
0
}
2111
2112
void context_free(void* arg)
2113
0
{
2114
0
  struct s_scard_context_element* element = arg;
2115
0
  if (!arg)
2116
0
    return;
2117
2118
0
  if (element->fn_free)
2119
0
    element->fn_free(element->context);
2120
0
  free(element);
2121
0
}
2122
2123
#if !defined(WITHOUT_FREERDP_3x_DEPRECATED)
2124
scard_call_context* smartcard_call_context_new(const rdpSettings* settings)
2125
0
{
2126
0
  const freerdp* inst = freerdp_settings_get_pointer(settings, FreeRDP_instance);
2127
0
  if (!inst || !inst->context)
2128
0
    return nullptr;
2129
0
  return smartcard_call_context_new_with_context(inst->context);
2130
0
}
2131
#endif
2132
2133
scard_call_context* smartcard_call_context_new_with_context(rdpContext* context)
2134
0
{
2135
0
  WINPR_ASSERT(context);
2136
0
  scard_call_context* ctx = calloc(1, sizeof(scard_call_context));
2137
0
  if (!ctx)
2138
0
    goto fail;
2139
2140
0
  ctx->context = context;
2141
2142
0
  const rdpSettings* settings = context->settings;
2143
0
  WINPR_ASSERT(settings);
2144
2145
0
  ctx->log = WLog_Get(SCARD_TAG);
2146
0
  WINPR_ASSERT(ctx->log);
2147
2148
0
  ctx->stopEvent = CreateEventA(nullptr, TRUE, FALSE, nullptr);
2149
0
  if (!ctx->stopEvent)
2150
0
    goto fail;
2151
2152
0
  ctx->names = LinkedList_New();
2153
0
  if (!ctx->names)
2154
0
    goto fail;
2155
2156
0
#if defined(WITH_SMARTCARD_EMULATE)
2157
0
  ctx->useEmulatedCard = freerdp_settings_get_bool(settings, FreeRDP_SmartcardEmulation);
2158
0
#endif
2159
2160
0
  if (ctx->useEmulatedCard)
2161
0
  {
2162
0
#if defined(WITH_SMARTCARD_EMULATE)
2163
0
    ctx->emulation = Emulate_New(settings);
2164
0
    if (!ctx->emulation)
2165
0
      goto fail;
2166
#else
2167
    WLog_Print(ctx->log, WLOG_ERROR, "Smartcard emulation requested, but not supported!");
2168
    goto fail;
2169
#endif
2170
0
  }
2171
0
  else
2172
0
  {
2173
0
    const char* WinSCardModule = freerdp_settings_get_string(settings, FreeRDP_WinSCardModule);
2174
0
    if (WinSCardModule)
2175
0
    {
2176
0
      ctx->hWinSCardLibrary = LoadLibraryX(WinSCardModule);
2177
2178
0
      if (!ctx->hWinSCardLibrary)
2179
0
      {
2180
0
        WLog_Print(ctx->log, WLOG_ERROR, "Failed to load WinSCard library: '%s'",
2181
0
                   WinSCardModule);
2182
0
        goto fail;
2183
0
      }
2184
2185
0
      if (!WinSCard_LoadApiTableFunctions(&ctx->WinSCardApi, ctx->hWinSCardLibrary))
2186
0
        goto fail;
2187
0
      ctx->pWinSCardApi = &ctx->WinSCardApi;
2188
0
    }
2189
0
    else
2190
0
    {
2191
0
      ctx->pWinSCardApi = WinPR_GetSCardApiFunctionTable();
2192
0
    }
2193
2194
0
    if (!ctx->pWinSCardApi)
2195
0
    {
2196
0
      WLog_Print(ctx->log, WLOG_ERROR, "Failed to load WinSCard API!");
2197
0
      goto fail;
2198
0
    }
2199
0
  }
2200
2201
0
  ctx->rgSCardContextList = HashTable_New(FALSE);
2202
0
  if (!ctx->rgSCardContextList)
2203
0
    goto fail;
2204
2205
0
  {
2206
0
    wObject* obj = HashTable_ValueObject(ctx->rgSCardContextList);
2207
0
    WINPR_ASSERT(obj);
2208
0
    obj->fnObjectFree = context_free;
2209
0
  }
2210
2211
0
  return ctx;
2212
0
fail:
2213
0
  WINPR_PRAGMA_DIAG_PUSH
2214
0
  WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
2215
0
  smartcard_call_context_free(ctx);
2216
0
  WINPR_PRAGMA_DIAG_POP
2217
0
  return nullptr;
2218
0
}
2219
2220
void smartcard_call_context_free(scard_call_context* ctx)
2221
0
{
2222
0
  if (!ctx)
2223
0
    return;
2224
2225
0
  smartcard_call_context_signal_stop(ctx, FALSE);
2226
2227
0
  LinkedList_Free(ctx->names);
2228
0
  if (ctx->StartedEvent)
2229
0
  {
2230
0
    WINPR_ASSERT(ctx->useEmulatedCard || ctx->pWinSCardApi);
2231
0
    wrap_raw(ctx, SCardReleaseStartedEvent);
2232
0
  }
2233
2234
0
  if (ctx->useEmulatedCard)
2235
0
  {
2236
0
#ifdef WITH_SMARTCARD_EMULATE
2237
0
    if (ctx->emulation)
2238
0
    {
2239
0
      Emulate_Free(ctx->emulation);
2240
0
      ctx->emulation = nullptr;
2241
0
    }
2242
0
#endif
2243
0
  }
2244
2245
0
  if (ctx->hWinSCardLibrary)
2246
0
  {
2247
0
    ZeroMemory(&ctx->WinSCardApi, sizeof(SCardApiFunctionTable));
2248
0
    FreeLibrary(ctx->hWinSCardLibrary);
2249
0
    ctx->hWinSCardLibrary = nullptr;
2250
0
  }
2251
2252
0
  ctx->pWinSCardApi = nullptr;
2253
2254
0
  HashTable_Free(ctx->rgSCardContextList);
2255
0
  (void)CloseHandle(ctx->stopEvent);
2256
0
  free(ctx);
2257
0
}
2258
2259
BOOL smartcard_call_context_add(scard_call_context* ctx, const char* name)
2260
0
{
2261
0
  WINPR_ASSERT(ctx);
2262
0
  WINPR_ASSERT(name);
2263
0
  return LinkedList_AddLast(ctx->names, name);
2264
0
}
2265
2266
BOOL smartcard_call_cancel_context(scard_call_context* ctx, SCARDCONTEXT hContext)
2267
0
{
2268
0
  WINPR_ASSERT(ctx);
2269
0
  if (wrap(ctx, SCardIsValidContext, hContext) == SCARD_S_SUCCESS)
2270
0
  {
2271
0
    wrap(ctx, SCardCancel, hContext);
2272
0
  }
2273
0
  return TRUE;
2274
0
}
2275
2276
BOOL smartcard_call_release_context(scard_call_context* ctx, SCARDCONTEXT hContext)
2277
0
{
2278
0
  WINPR_ASSERT(ctx);
2279
0
  wrap(ctx, SCardReleaseContext, hContext);
2280
0
  return TRUE;
2281
0
}
2282
2283
BOOL smartcard_call_cancel_all_context(scard_call_context* ctx)
2284
0
{
2285
0
  if (!ctx)
2286
0
    return FALSE;
2287
2288
0
  HashTable_Clear(ctx->rgSCardContextList);
2289
0
  return TRUE;
2290
0
}
2291
2292
BOOL smarcard_call_set_callbacks(scard_call_context* ctx, void* userdata,
2293
                                 void* (*fn_new)(void*, SCARDCONTEXT), void (*fn_free)(void*))
2294
0
{
2295
0
  WINPR_ASSERT(ctx);
2296
0
  ctx->userdata = userdata;
2297
0
  ctx->fn_new = fn_new;
2298
0
  ctx->fn_free = fn_free;
2299
0
  return TRUE;
2300
0
}
2301
2302
void* smartcard_call_get_context(scard_call_context* ctx, SCARDCONTEXT hContext)
2303
0
{
2304
0
  struct s_scard_context_element* element = nullptr;
2305
2306
0
  WINPR_ASSERT(ctx);
2307
0
  element = HashTable_GetItemValue(ctx->rgSCardContextList, (void*)hContext);
2308
0
  if (!element)
2309
0
    return nullptr;
2310
0
  return element->context;
2311
0
}
2312
2313
BOOL smartcard_call_is_configured(scard_call_context* ctx)
2314
0
{
2315
0
  WINPR_ASSERT(ctx);
2316
2317
0
#if defined(WITH_SMARTCARD_EMULATE)
2318
0
  if (ctx->useEmulatedCard)
2319
0
    return Emulate_IsConfigured(ctx->emulation);
2320
0
#endif
2321
2322
0
  return FALSE;
2323
0
}
2324
2325
BOOL smartcard_call_context_signal_stop(scard_call_context* ctx, BOOL reset)
2326
0
{
2327
0
  WINPR_ASSERT(ctx);
2328
2329
0
  if (!ctx->stopEvent)
2330
0
    return TRUE;
2331
2332
0
  if (reset)
2333
0
    return ResetEvent(ctx->stopEvent);
2334
0
  else
2335
0
    return SetEvent(ctx->stopEvent);
2336
0
}