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