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