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