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