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