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.cReaders = call->cReaders;
654 ret.rgReaderStates = nullptr;
655
656 if (ret.cReaders > 0)
657 {
658 ret.rgReaderStates = (ReaderState_Return*)calloc(ret.cReaders, sizeof(ReaderState_Return));
659
660 if (!ret.rgReaderStates)
661 return STATUS_NO_MEMORY;
662 }
663
664 for (UINT32 x = 0; x < ret.cReaders; x++)
665 {
666 ret.rgReaderStates[x].dwCurrentState = call->rgReaderStates[x].dwCurrentState;
667 ret.rgReaderStates[x].dwEventState = call->rgReaderStates[x].dwEventState;
668 ret.rgReaderStates[x].cbAtr = call->rgReaderStates[x].cbAtr;
669 CopyMemory(&(ret.rgReaderStates[x].rgbAtr), &(call->rgReaderStates[x].rgbAtr),
670 sizeof(ret.rgReaderStates[x].rgbAtr));
671 }
672
673 status = smartcard_pack_locate_cards_return(out, &ret);
674
675 if (status != SCARD_S_SUCCESS)
676 return status;
677
678 return ret.ReturnCode;
679}
680
681static LONG smartcard_LocateCardsW_Call(scard_call_context* smartcard, wStream* out,
682 SMARTCARD_OPERATION* operation)
683{
684 LONG status = 0;
685 LocateCards_Return ret = WINPR_C_ARRAY_INIT;
686 LocateCardsW_Call* call = nullptr;
687
688 WINPR_ASSERT(smartcard);
689 WINPR_ASSERT(operation);
690
691 call = &operation->call.locateCardsW;
692
693 ret.ReturnCode = wrap(smartcard, SCardLocateCardsW, operation->hContext, call->mszCards,
694 call->rgReaderStates, call->cReaders);
695 scard_log_status_error_wlog(smartcard->log, "SCardLocateCardsW", ret.ReturnCode);
696 ret.cReaders = call->cReaders;
697 ret.rgReaderStates = nullptr;
698
699 if (ret.cReaders > 0)
700 {
701 ret.rgReaderStates = (ReaderState_Return*)calloc(ret.cReaders, sizeof(ReaderState_Return));
702
703 if (!ret.rgReaderStates)
704 return STATUS_NO_MEMORY;
705 }
706
707 for (UINT32 x = 0; x < ret.cReaders; x++)
708 {
709 ret.rgReaderStates[x].dwCurrentState = call->rgReaderStates[x].dwCurrentState;
710 ret.rgReaderStates[x].dwEventState = call->rgReaderStates[x].dwEventState;
711 ret.rgReaderStates[x].cbAtr = call->rgReaderStates[x].cbAtr;
712 CopyMemory(&(ret.rgReaderStates[x].rgbAtr), &(call->rgReaderStates[x].rgbAtr),
713 sizeof(ret.rgReaderStates[x].rgbAtr));
714 }
715
716 status = smartcard_pack_locate_cards_return(out, &ret);
717
718 if (status != SCARD_S_SUCCESS)
719 return status;
720
721 return ret.ReturnCode;
722}
723
724static LONG smartcard_ReadCacheA_Call(scard_call_context* smartcard, wStream* out,
725 SMARTCARD_OPERATION* operation)
726{
727 LONG status = 0;
728 BOOL autoalloc = 0;
729 ReadCache_Return ret = WINPR_C_ARRAY_INIT;
730 ReadCacheA_Call* call = nullptr;
731
732 WINPR_ASSERT(smartcard);
733 WINPR_ASSERT(out);
734 WINPR_ASSERT(operation);
735
736 call = &operation->call.readCacheA;
737 autoalloc = (call->Common.cbDataLen == SCARD_AUTOALLOCATE);
738
739 if (!call->Common.fPbDataIsNULL)
740 {
741 ret.cbDataLen = call->Common.cbDataLen;
742 if (!autoalloc)
743 {
744 ret.pbData = malloc(ret.cbDataLen);
745 if (!ret.pbData)
746 return SCARD_F_INTERNAL_ERROR;
747 }
748 }
749
750 if (autoalloc)
751 ret.ReturnCode = wrap(smartcard, SCardReadCacheA, operation->hContext,
752 call->Common.CardIdentifier, call->Common.FreshnessCounter,
753 call->szLookupName, (BYTE*)&ret.pbData, &ret.cbDataLen);
754 else
755 ret.ReturnCode =
756 wrap(smartcard, SCardReadCacheA, operation->hContext, call->Common.CardIdentifier,
757 call->Common.FreshnessCounter, call->szLookupName, ret.pbData, &ret.cbDataLen);
758
759 WLog_Print(smartcard->log, WLOG_TRACE, "key=%s, length=%" PRIu32, call->szLookupName,
760 ret.cbDataLen);
761
762 if ((ret.ReturnCode != SCARD_W_CACHE_ITEM_NOT_FOUND) &&
763 (ret.ReturnCode != SCARD_W_CACHE_ITEM_STALE))
764 {
765 scard_log_status_error_wlog(smartcard->log, "SCardReadCacheA", ret.ReturnCode);
766 }
767
768 status = smartcard_pack_read_cache_return(out, &ret);
769 if (autoalloc)
770 wrap(smartcard, SCardFreeMemory, operation->hContext, ret.pbData);
771 else
772 free(ret.pbData);
773 if (status != SCARD_S_SUCCESS)
774 return status;
775
776 return ret.ReturnCode;
777}
778
779static LONG smartcard_ReadCacheW_Call(scard_call_context* smartcard, wStream* out,
780 SMARTCARD_OPERATION* operation)
781{
782 LONG status = 0;
783 ReadCache_Return ret = WINPR_C_ARRAY_INIT;
784 ReadCacheW_Call* call = nullptr;
785
786 WINPR_ASSERT(smartcard);
787 WINPR_ASSERT(out);
788 WINPR_ASSERT(operation);
789
790 call = &operation->call.readCacheW;
791
792 if (!call->Common.fPbDataIsNULL)
793 ret.cbDataLen = SCARD_AUTOALLOCATE;
794
795 ret.ReturnCode =
796 wrap(smartcard, SCardReadCacheW, operation->hContext, call->Common.CardIdentifier,
797 call->Common.FreshnessCounter, call->szLookupName, (BYTE*)&ret.pbData, &ret.cbDataLen);
798
799 if (WLog_IsLevelActive(smartcard->log, WLOG_TRACE))
800 {
801 char buffer[128] = WINPR_C_ARRAY_INIT;
802 (void)ConvertWCharToUtf8(call->szLookupName, buffer, sizeof(buffer));
803 WLog_Print(smartcard->log, WLOG_TRACE, "key=%s, length=%" PRIu32, buffer, ret.cbDataLen);
804 }
805 if ((ret.ReturnCode != SCARD_W_CACHE_ITEM_NOT_FOUND) &&
806 (ret.ReturnCode != SCARD_W_CACHE_ITEM_STALE))
807 {
808 scard_log_status_error_wlog(smartcard->log, "SCardReadCacheW", ret.ReturnCode);
809 }
810
811 status = smartcard_pack_read_cache_return(out, &ret);
812
813 wrap(smartcard, SCardFreeMemory, operation->hContext, ret.pbData);
814
815 if (status != SCARD_S_SUCCESS)
816 return status;
817
818 return ret.ReturnCode;
819}
820
821static LONG smartcard_WriteCacheA_Call(scard_call_context* smartcard,
822 WINPR_ATTR_UNUSED wStream* out,
823 SMARTCARD_OPERATION* operation)
824{
825 Long_Return ret = WINPR_C_ARRAY_INIT;
826 WriteCacheA_Call* call = nullptr;
827
828 WINPR_ASSERT(smartcard);
829 WINPR_ASSERT(out);
830 WINPR_ASSERT(operation);
831
832 call = &operation->call.writeCacheA;
833
834 ret.ReturnCode = wrap(smartcard, SCardWriteCacheA, operation->hContext,
835 call->Common.CardIdentifier, call->Common.FreshnessCounter,
836 call->szLookupName, call->Common.pbData, call->Common.cbDataLen);
837 scard_log_status_error_wlog(smartcard->log, "SCardWriteCacheA", ret.ReturnCode);
838 smartcard_trace_long_return_int(smartcard->log, &ret, "SCardWriteCacheA");
839 WLog_Print(smartcard->log, WLOG_TRACE, "key=%s, length=%" PRIu32, call->szLookupName,
840 call->Common.cbDataLen);
841 return ret.ReturnCode;
842}
843
844static LONG smartcard_WriteCacheW_Call(scard_call_context* smartcard,
845 WINPR_ATTR_UNUSED wStream* out,
846 SMARTCARD_OPERATION* operation)
847{
848 Long_Return ret = WINPR_C_ARRAY_INIT;
849 WriteCacheW_Call* call = nullptr;
850
851 WINPR_ASSERT(smartcard);
852 WINPR_ASSERT(out);
853 WINPR_ASSERT(operation);
854
855 call = &operation->call.writeCacheW;
856
857 ret.ReturnCode = wrap(smartcard, SCardWriteCacheW, operation->hContext,
858 call->Common.CardIdentifier, call->Common.FreshnessCounter,
859 call->szLookupName, call->Common.pbData, call->Common.cbDataLen);
860 scard_log_status_error_wlog(smartcard->log, "SCardWriteCacheW", ret.ReturnCode);
861 smartcard_trace_long_return_int(smartcard->log, &ret, "SCardWriteCacheW");
862
863 if (WLog_IsLevelActive(smartcard->log, WLOG_TRACE))
864 {
865 char buffer[128] = WINPR_C_ARRAY_INIT;
866 (void)ConvertWCharToUtf8(call->szLookupName, buffer, sizeof(buffer));
867 WLog_Print(smartcard->log, WLOG_TRACE, "key=%s, length=%" PRIu32, buffer,
868 call->Common.cbDataLen);
869 }
870 return ret.ReturnCode;
871}
872
873static LONG smartcard_GetTransmitCount_Call(scard_call_context* smartcard, wStream* out,
874 SMARTCARD_OPERATION* operation)
875{
876 LONG status = 0;
877 GetTransmitCount_Return ret = WINPR_C_ARRAY_INIT;
878
879 WINPR_ASSERT(smartcard);
880 WINPR_ASSERT(out);
881 WINPR_ASSERT(operation);
882
883 ret.ReturnCode = wrap(smartcard, SCardGetTransmitCount, operation->hCard, &ret.cTransmitCount);
884 scard_log_status_error_wlog(smartcard->log, "SCardGetTransmitCount", ret.ReturnCode);
885 status = smartcard_pack_get_transmit_count_return(out, &ret);
886 if (status != SCARD_S_SUCCESS)
887 return status;
888
889 return ret.ReturnCode;
890}
891
892static LONG smartcard_ReleaseStartedEvent_Call(scard_call_context* smartcard, wStream* out,
893 SMARTCARD_OPERATION* operation)
894{
895 WINPR_UNUSED(smartcard);
896 WINPR_UNUSED(out);
897 WINPR_UNUSED(operation);
898
899 WLog_Print(smartcard->log, WLOG_WARN,
900 "According to [MS-RDPESC] 3.1.4 Message Processing Events and Sequencing Rules "
901 "this is not supported?!?");
902 return SCARD_E_UNSUPPORTED_FEATURE;
903}
904
905static LONG smartcard_GetReaderIcon_Call(scard_call_context* smartcard, wStream* out,
906 SMARTCARD_OPERATION* operation)
907{
908 LONG status = 0;
909 GetReaderIcon_Return ret = WINPR_C_ARRAY_INIT;
910 GetReaderIcon_Call* call = nullptr;
911
912 WINPR_ASSERT(smartcard);
913 WINPR_ASSERT(out);
914 WINPR_ASSERT(operation);
915
916 call = &operation->call.getReaderIcon;
917
918 ret.cbDataLen = SCARD_AUTOALLOCATE;
919 ret.ReturnCode = wrap(smartcard, SCardGetReaderIconW, operation->hContext, call->szReaderName,
920 (LPBYTE)&ret.pbData, &ret.cbDataLen);
921 scard_log_status_error_wlog(smartcard->log, "SCardGetReaderIconW", ret.ReturnCode);
922 if ((ret.ReturnCode == SCARD_S_SUCCESS) && (ret.cbDataLen == SCARD_AUTOALLOCATE))
923 return SCARD_F_UNKNOWN_ERROR;
924
925 status = smartcard_pack_get_reader_icon_return(out, &ret);
926 wrap(smartcard, SCardFreeMemory, operation->hContext, ret.pbData);
927 if (status != SCARD_S_SUCCESS)
928 return status;
929
930 return ret.ReturnCode;
931}
932
933static LONG smartcard_GetDeviceTypeId_Call(scard_call_context* smartcard, wStream* out,
934 SMARTCARD_OPERATION* operation)
935{
936 LONG status = 0;
937 GetDeviceTypeId_Return ret = WINPR_C_ARRAY_INIT;
938 GetDeviceTypeId_Call* call = nullptr;
939
940 WINPR_ASSERT(smartcard);
941 WINPR_ASSERT(out);
942 WINPR_ASSERT(operation);
943
944 call = &operation->call.getDeviceTypeId;
945
946 ret.ReturnCode = wrap(smartcard, SCardGetDeviceTypeIdW, operation->hContext, call->szReaderName,
947 &ret.dwDeviceId);
948 scard_log_status_error_wlog(smartcard->log, "SCardGetDeviceTypeIdW", ret.ReturnCode);
949
950 status = smartcard_pack_device_type_id_return(out, &ret);
951 if (status != SCARD_S_SUCCESS)
952 return status;
953
954 return ret.ReturnCode;
955}
956
957static BOOL smartcard_context_was_aborted(scard_call_context* smartcard)
958{
959 WINPR_ASSERT(smartcard);
960
961 HANDLE handles[] = { smartcard->stopEvent, freerdp_abort_event(smartcard->context) };
962 const DWORD rc = WaitForMultipleObjects(ARRAYSIZE(handles), handles, FALSE, 0);
963 return (rc >= WAIT_OBJECT_0) && (rc <= WAIT_OBJECT_0 + ARRAYSIZE(handles));
964}
965
966static LONG smartcard_GetStatusChangeA_Call(scard_call_context* smartcard, wStream* out,
967 SMARTCARD_OPERATION* operation)
968{
969 LONG status = STATUS_NO_MEMORY;
970 DWORD dwTimeOut = 0;
971 const DWORD dwTimeStep = 100;
972 GetStatusChange_Return ret = WINPR_C_ARRAY_INIT;
973 GetStatusChangeA_Call* call = nullptr;
974 LPSCARD_READERSTATEA rgReaderStates = nullptr;
975
976 WINPR_ASSERT(smartcard);
977 WINPR_ASSERT(out);
978 WINPR_ASSERT(operation);
979
980 call = &operation->call.getStatusChangeA;
981 dwTimeOut = call->dwTimeOut;
982
983 if (call->cReaders > 0)
984 {
985 ret.cReaders = call->cReaders;
986 rgReaderStates = calloc(ret.cReaders, sizeof(SCARD_READERSTATEA));
987 ret.rgReaderStates = (ReaderState_Return*)calloc(ret.cReaders, sizeof(ReaderState_Return));
988 if (!rgReaderStates || !ret.rgReaderStates)
989 goto fail;
990 }
991
992 for (UINT32 x = 0; x < MAX(1, dwTimeOut);)
993 {
994 if (call->cReaders > 0)
995 memcpy(rgReaderStates, call->rgReaderStates,
996 call->cReaders * sizeof(SCARD_READERSTATEA));
997 ret.ReturnCode = wrap(smartcard, SCardGetStatusChangeA, operation->hContext,
998 MIN(dwTimeOut, dwTimeStep), rgReaderStates, call->cReaders);
999 if (ret.ReturnCode != SCARD_E_TIMEOUT)
1000 break;
1001 if (smartcard_context_was_aborted(smartcard))
1002 break;
1003 if (dwTimeOut != INFINITE)
1004 x += dwTimeStep;
1005 }
1006 scard_log_status_error_wlog(smartcard->log, "SCardGetStatusChangeA", ret.ReturnCode);
1007
1008 for (UINT32 index = 0; index < ret.cReaders; index++)
1009 {
1010 const SCARD_READERSTATEA* cur = &rgReaderStates[index];
1011 ReaderState_Return* rout = &ret.rgReaderStates[index];
1012
1013 rout->dwCurrentState = cur->dwCurrentState;
1014 rout->dwEventState = cur->dwEventState;
1015 rout->cbAtr = cur->cbAtr;
1016 CopyMemory(&(rout->rgbAtr), cur->rgbAtr, sizeof(rout->rgbAtr));
1017 }
1018
1019 status = smartcard_pack_get_status_change_return(out, &ret, FALSE);
1020fail:
1021 free(ret.rgReaderStates);
1022 free(rgReaderStates);
1023 if (status != SCARD_S_SUCCESS)
1024 return status;
1025 return ret.ReturnCode;
1026}
1027
1028static LONG smartcard_GetStatusChangeW_Call(scard_call_context* smartcard, wStream* out,
1029 SMARTCARD_OPERATION* operation)
1030{
1031 LONG status = STATUS_NO_MEMORY;
1032 DWORD dwTimeOut = 0;
1033 const DWORD dwTimeStep = 100;
1034 GetStatusChange_Return ret = WINPR_C_ARRAY_INIT;
1035 LPSCARD_READERSTATEW rgReaderStates = nullptr;
1036
1037 WINPR_ASSERT(smartcard);
1038 WINPR_ASSERT(out);
1039 WINPR_ASSERT(operation);
1040
1041 GetStatusChangeW_Call* call = &operation->call.getStatusChangeW;
1042 dwTimeOut = call->dwTimeOut;
1043
1044 if (call->cReaders > 0)
1045 {
1046 ret.cReaders = call->cReaders;
1047 rgReaderStates = calloc(ret.cReaders, sizeof(SCARD_READERSTATEW));
1048 ret.rgReaderStates = (ReaderState_Return*)calloc(ret.cReaders, sizeof(ReaderState_Return));
1049 if (!rgReaderStates || !ret.rgReaderStates)
1050 goto fail;
1051 }
1052
1053 for (UINT32 x = 0; x < MAX(1, dwTimeOut);)
1054 {
1055 if (call->cReaders > 0)
1056 memcpy(rgReaderStates, call->rgReaderStates,
1057 call->cReaders * sizeof(SCARD_READERSTATEW));
1058 {
1059 ret.ReturnCode = wrap(smartcard, SCardGetStatusChangeW, operation->hContext,
1060 MIN(dwTimeOut, dwTimeStep), rgReaderStates, call->cReaders);
1061 }
1062 if (ret.ReturnCode != SCARD_E_TIMEOUT)
1063 break;
1064 if (smartcard_context_was_aborted(smartcard))
1065 break;
1066 if (dwTimeOut != INFINITE)
1067 x += dwTimeStep;
1068 }
1069 scard_log_status_error_wlog(smartcard->log, "SCardGetStatusChangeW", ret.ReturnCode);
1070
1071 for (UINT32 index = 0; index < ret.cReaders; index++)
1072 {
1073 const SCARD_READERSTATEW* cur = &rgReaderStates[index];
1074 ReaderState_Return* rout = &ret.rgReaderStates[index];
1075
1076 rout->dwCurrentState = cur->dwCurrentState;
1077 rout->dwEventState = cur->dwEventState;
1078 rout->cbAtr = cur->cbAtr;
1079 CopyMemory(&(rout->rgbAtr), cur->rgbAtr, sizeof(rout->rgbAtr));
1080 }
1081
1082 status = smartcard_pack_get_status_change_return(out, &ret, TRUE);
1083fail:
1084 free(ret.rgReaderStates);
1085 free(rgReaderStates);
1086 if (status != SCARD_S_SUCCESS)
1087 return status;
1088 return ret.ReturnCode;
1089}
1090
1091static LONG smartcard_Cancel_Call(scard_call_context* smartcard, WINPR_ATTR_UNUSED wStream* out,
1092 SMARTCARD_OPERATION* operation)
1093{
1094 Long_Return ret = WINPR_C_ARRAY_INIT;
1095
1096 WINPR_ASSERT(smartcard);
1097 WINPR_ASSERT(out);
1098 WINPR_ASSERT(operation);
1099
1100 ret.ReturnCode = wrap(smartcard, SCardCancel, operation->hContext);
1101 scard_log_status_error_wlog(smartcard->log, "SCardCancel", ret.ReturnCode);
1102 smartcard_trace_long_return_int(smartcard->log, &ret, "Cancel");
1103 return ret.ReturnCode;
1104}
1105
1106static LONG smartcard_ConnectA_Call(scard_call_context* smartcard, wStream* out,
1107 SMARTCARD_OPERATION* operation)
1108{
1109 LONG status = 0;
1110 SCARDHANDLE hCard = 0;
1111 Connect_Return ret = WINPR_C_ARRAY_INIT;
1112 ConnectA_Call* call = nullptr;
1113
1114 WINPR_ASSERT(smartcard);
1115 WINPR_ASSERT(out);
1116 WINPR_ASSERT(operation);
1117
1118 call = &operation->call.connectA;
1119
1120 if ((call->Common.dwPreferredProtocols == SCARD_PROTOCOL_UNDEFINED) &&
1121 (call->Common.dwShareMode != SCARD_SHARE_DIRECT))
1122 {
1123 call->Common.dwPreferredProtocols = SCARD_PROTOCOL_Tx;
1124 }
1125
1126 ret.ReturnCode = wrap(smartcard, SCardConnectA, operation->hContext, (char*)call->szReader,
1127 call->Common.dwShareMode, call->Common.dwPreferredProtocols, &hCard,
1128 &ret.dwActiveProtocol);
1129 smartcard_scard_context_native_to_redir(&(ret.hContext), operation->hContext);
1130 smartcard_scard_handle_native_to_redir(&(ret.hCard), hCard);
1131
1132 status = smartcard_pack_connect_return(out, &ret);
1133 if (status != SCARD_S_SUCCESS)
1134 goto out_fail;
1135
1136 status = ret.ReturnCode;
1137out_fail:
1138
1139 return status;
1140}
1141
1142static LONG smartcard_ConnectW_Call(scard_call_context* smartcard, wStream* out,
1143 SMARTCARD_OPERATION* operation)
1144{
1145 LONG status = 0;
1146 SCARDHANDLE hCard = 0;
1147 Connect_Return ret = WINPR_C_ARRAY_INIT;
1148 ConnectW_Call* call = nullptr;
1149
1150 WINPR_ASSERT(smartcard);
1151 WINPR_ASSERT(out);
1152 WINPR_ASSERT(operation);
1153
1154 call = &operation->call.connectW;
1155
1156 if ((call->Common.dwPreferredProtocols == SCARD_PROTOCOL_UNDEFINED) &&
1157 (call->Common.dwShareMode != SCARD_SHARE_DIRECT))
1158 {
1159 call->Common.dwPreferredProtocols = SCARD_PROTOCOL_Tx;
1160 }
1161
1162 ret.ReturnCode = wrap(smartcard, SCardConnectW, operation->hContext, (WCHAR*)call->szReader,
1163 call->Common.dwShareMode, call->Common.dwPreferredProtocols, &hCard,
1164 &ret.dwActiveProtocol);
1165 smartcard_scard_context_native_to_redir(&(ret.hContext), operation->hContext);
1166 smartcard_scard_handle_native_to_redir(&(ret.hCard), hCard);
1167
1168 status = smartcard_pack_connect_return(out, &ret);
1169 if (status != SCARD_S_SUCCESS)
1170 goto out_fail;
1171
1172 status = ret.ReturnCode;
1173out_fail:
1174
1175 return status;
1176}
1177
1178static LONG smartcard_Reconnect_Call(scard_call_context* smartcard, wStream* out,
1179 SMARTCARD_OPERATION* operation)
1180{
1181 LONG status = 0;
1182 Reconnect_Return ret = WINPR_C_ARRAY_INIT;
1183 Reconnect_Call* call = nullptr;
1184
1185 WINPR_ASSERT(smartcard);
1186 WINPR_ASSERT(out);
1187 WINPR_ASSERT(operation);
1188
1189 call = &operation->call.reconnect;
1190 ret.ReturnCode =
1191 wrap(smartcard, SCardReconnect, operation->hCard, call->dwShareMode,
1192 call->dwPreferredProtocols, call->dwInitialization, &ret.dwActiveProtocol);
1193 scard_log_status_error_wlog(smartcard->log, "SCardReconnect", ret.ReturnCode);
1194 status = smartcard_pack_reconnect_return(out, &ret);
1195 if (status != SCARD_S_SUCCESS)
1196 return status;
1197
1198 return ret.ReturnCode;
1199}
1200
1201static LONG smartcard_Disconnect_Call(scard_call_context* smartcard, WINPR_ATTR_UNUSED wStream* out,
1202 SMARTCARD_OPERATION* operation)
1203{
1204 Long_Return ret = WINPR_C_ARRAY_INIT;
1205 HCardAndDisposition_Call* call = nullptr;
1206
1207 WINPR_ASSERT(smartcard);
1208 WINPR_ASSERT(out);
1209 WINPR_ASSERT(operation);
1210
1211 call = &operation->call.hCardAndDisposition;
1212
1213 ret.ReturnCode = wrap(smartcard, SCardDisconnect, operation->hCard, call->dwDisposition);
1214 scard_log_status_error_wlog(smartcard->log, "SCardDisconnect", ret.ReturnCode);
1215 smartcard_trace_long_return_int(smartcard->log, &ret, "Disconnect");
1216
1217 return ret.ReturnCode;
1218}
1219
1220static LONG smartcard_BeginTransaction_Call(scard_call_context* smartcard,
1221 WINPR_ATTR_UNUSED wStream* out,
1222 SMARTCARD_OPERATION* operation)
1223{
1224 Long_Return ret = WINPR_C_ARRAY_INIT;
1225
1226 WINPR_ASSERT(smartcard);
1227 WINPR_ASSERT(out);
1228 WINPR_ASSERT(operation);
1229
1230 ret.ReturnCode = wrap(smartcard, SCardBeginTransaction, operation->hCard);
1231 scard_log_status_error_wlog(smartcard->log, "SCardBeginTransaction", ret.ReturnCode);
1232 smartcard_trace_long_return_int(smartcard->log, &ret, "BeginTransaction");
1233 return ret.ReturnCode;
1234}
1235
1236static LONG smartcard_EndTransaction_Call(scard_call_context* smartcard,
1237 WINPR_ATTR_UNUSED wStream* out,
1238 SMARTCARD_OPERATION* operation)
1239{
1240 Long_Return ret = WINPR_C_ARRAY_INIT;
1241 HCardAndDisposition_Call* call = nullptr;
1242
1243 WINPR_ASSERT(smartcard);
1244 WINPR_ASSERT(out);
1245 WINPR_ASSERT(operation);
1246
1247 call = &operation->call.hCardAndDisposition;
1248
1249 ret.ReturnCode = wrap(smartcard, SCardEndTransaction, operation->hCard, call->dwDisposition);
1250 scard_log_status_error_wlog(smartcard->log, "SCardEndTransaction", ret.ReturnCode);
1251 smartcard_trace_long_return_int(smartcard->log, &ret, "EndTransaction");
1252 return ret.ReturnCode;
1253}
1254
1255static LONG smartcard_State_Call(scard_call_context* smartcard, wStream* out,
1256 SMARTCARD_OPERATION* operation)
1257{
1258 LONG status = 0;
1259 State_Return ret = WINPR_C_ARRAY_INIT;
1260
1261 WINPR_ASSERT(smartcard);
1262 WINPR_ASSERT(out);
1263 WINPR_ASSERT(operation);
1264
1265 ret.cbAtrLen = SCARD_ATR_LENGTH;
1266 ret.ReturnCode = wrap(smartcard, SCardState, operation->hCard, &ret.dwState, &ret.dwProtocol,
1267 (BYTE*)&ret.rgAtr, &ret.cbAtrLen);
1268
1269 scard_log_status_error_wlog(smartcard->log, "SCardState", ret.ReturnCode);
1270 status = smartcard_pack_state_return(out, &ret);
1271 if (status != SCARD_S_SUCCESS)
1272 return status;
1273
1274 return ret.ReturnCode;
1275}
1276
1277static LONG smartcard_StatusA_Call(scard_call_context* smartcard, wStream* out,
1278 SMARTCARD_OPERATION* operation)
1279{
1280 LONG status = 0;
1281 Status_Return ret = WINPR_C_ARRAY_INIT;
1282 DWORD cchReaderLen = 0;
1283 DWORD cbAtrLen = 0;
1284 LPSTR mszReaderNames = nullptr;
1285 Status_Call* call = nullptr;
1286
1287 WINPR_ASSERT(smartcard);
1288 WINPR_ASSERT(out);
1289 WINPR_ASSERT(operation);
1290
1291 call = &operation->call.status;
1292
1293 call->cbAtrLen = 32;
1294 cbAtrLen = call->cbAtrLen;
1295
1296 if (call->fmszReaderNamesIsNULL)
1297 cchReaderLen = 0;
1298 else
1299 cchReaderLen = SCARD_AUTOALLOCATE;
1300
1301 status = ret.ReturnCode =
1302 wrap(smartcard, SCardStatusA, operation->hCard,
1303 call->fmszReaderNamesIsNULL ? nullptr : (LPSTR)&mszReaderNames, &cchReaderLen,
1304 &ret.dwState, &ret.dwProtocol, cbAtrLen ? (BYTE*)&ret.pbAtr : nullptr, &cbAtrLen);
1305
1306 scard_log_status_error_wlog(smartcard->log, "SCardStatusA", status);
1307 if ((ret.ReturnCode == SCARD_S_SUCCESS) && (cchReaderLen == SCARD_AUTOALLOCATE))
1308 return SCARD_F_UNKNOWN_ERROR;
1309
1310 if (status == SCARD_S_SUCCESS)
1311 {
1312 if (!call->fmszReaderNamesIsNULL)
1313 ret.mszReaderNames = (BYTE*)mszReaderNames;
1314
1315 ret.cBytes = cchReaderLen;
1316
1317 if (call->cbAtrLen)
1318 ret.cbAtrLen = cbAtrLen;
1319 }
1320
1321 status = smartcard_pack_status_return(out, &ret, FALSE);
1322
1323 if (mszReaderNames)
1324 wrap(smartcard, SCardFreeMemory, operation->hContext, mszReaderNames);
1325
1326 if (status != SCARD_S_SUCCESS)
1327 return status;
1328 return ret.ReturnCode;
1329}
1330
1331static LONG smartcard_StatusW_Call(scard_call_context* smartcard, wStream* out,
1332 SMARTCARD_OPERATION* operation)
1333{
1334 LONG status = 0;
1335 Status_Return ret = WINPR_C_ARRAY_INIT;
1336 LPWSTR mszReaderNames = nullptr;
1337 Status_Call* call = nullptr;
1338 DWORD cbAtrLen = 0;
1339
1340 WINPR_ASSERT(smartcard);
1341 WINPR_ASSERT(out);
1342 WINPR_ASSERT(operation);
1343
1344 call = &operation->call.status;
1345
1350 cbAtrLen = call->cbAtrLen = 32;
1351
1352 if (call->fmszReaderNamesIsNULL)
1353 ret.cBytes = 0;
1354 else
1355 ret.cBytes = SCARD_AUTOALLOCATE;
1356
1357 status = ret.ReturnCode =
1358 wrap(smartcard, SCardStatusW, operation->hCard,
1359 call->fmszReaderNamesIsNULL ? nullptr : (LPWSTR)&mszReaderNames, &ret.cBytes,
1360 &ret.dwState, &ret.dwProtocol, (BYTE*)&ret.pbAtr, &cbAtrLen);
1361 scard_log_status_error_wlog(smartcard->log, "SCardStatusW", status);
1362 if ((ret.ReturnCode == SCARD_S_SUCCESS) && (ret.cBytes == SCARD_AUTOALLOCATE))
1363 return SCARD_F_UNKNOWN_ERROR;
1364
1365 size_t blen = 0;
1366 if (status == SCARD_S_SUCCESS)
1367 {
1368 if (!call->fmszReaderNamesIsNULL)
1369 ret.mszReaderNames = (BYTE*)mszReaderNames;
1370
1371 ret.cbAtrLen = cbAtrLen;
1372 }
1373
1374 if (ret.cBytes != SCARD_AUTOALLOCATE)
1375 {
1376 /* SCardStatusW returns number of characters, we need number of bytes */
1377 WINPR_ASSERT(ret.cBytes < SCARD_AUTOALLOCATE / sizeof(WCHAR));
1378 blen = sizeof(WCHAR) * ret.cBytes;
1379 WINPR_ASSERT(blen <= UINT32_MAX);
1380 ret.cBytes = (UINT32)blen;
1381 }
1382
1383 status = smartcard_pack_status_return(out, &ret, TRUE);
1384 if (status != SCARD_S_SUCCESS)
1385 return status;
1386
1387 if (mszReaderNames)
1388 wrap(smartcard, SCardFreeMemory, operation->hContext, mszReaderNames);
1389
1390 return ret.ReturnCode;
1391}
1392
1393static LONG smartcard_Transmit_Call(scard_call_context* smartcard, wStream* out,
1394 SMARTCARD_OPERATION* operation)
1395{
1396 LONG status = 0;
1397 Transmit_Return ret = WINPR_C_ARRAY_INIT;
1398 Transmit_Call* call = nullptr;
1399
1400 WINPR_ASSERT(smartcard);
1401 WINPR_ASSERT(out);
1402 WINPR_ASSERT(operation);
1403
1404 call = &operation->call.transmit;
1405 ret.cbRecvLength = 0;
1406 ret.pbRecvBuffer = nullptr;
1407
1408 if (call->cbRecvLength && !call->fpbRecvBufferIsNULL)
1409 {
1410 if (call->cbRecvLength >= 66560)
1411 call->cbRecvLength = 66560;
1412
1413 ret.cbRecvLength = call->cbRecvLength;
1414 ret.pbRecvBuffer = (BYTE*)malloc(ret.cbRecvLength);
1415
1416 if (!ret.pbRecvBuffer)
1417 return STATUS_NO_MEMORY;
1418 }
1419
1420 ret.pioRecvPci = call->pioRecvPci;
1421 ret.ReturnCode =
1422 wrap(smartcard, SCardTransmit, operation->hCard, call->pioSendPci, call->pbSendBuffer,
1423 call->cbSendLength, ret.pioRecvPci, ret.pbRecvBuffer, &(ret.cbRecvLength));
1424
1425 scard_log_status_error_wlog(smartcard->log, "SCardTransmit", ret.ReturnCode);
1426
1427 status = smartcard_pack_transmit_return(out, &ret);
1428 free(ret.pbRecvBuffer);
1429
1430 if (status != SCARD_S_SUCCESS)
1431 return status;
1432 return ret.ReturnCode;
1433}
1434
1435static LONG smartcard_Control_Call(scard_call_context* smartcard, wStream* out,
1436 SMARTCARD_OPERATION* operation)
1437{
1438 LONG status = 0;
1439 Control_Return ret = WINPR_C_ARRAY_INIT;
1440 Control_Call* call = nullptr;
1441
1442 WINPR_ASSERT(smartcard);
1443 WINPR_ASSERT(out);
1444 WINPR_ASSERT(operation);
1445
1446 call = &operation->call.control;
1447 ret.cbOutBufferSize = call->cbOutBufferSize;
1448 ret.pvOutBuffer = (BYTE*)malloc(call->cbOutBufferSize);
1449
1450 if (!ret.pvOutBuffer)
1451 return SCARD_E_NO_MEMORY;
1452
1453 ret.ReturnCode =
1454 wrap(smartcard, SCardControl, operation->hCard, call->dwControlCode, call->pvInBuffer,
1455 call->cbInBufferSize, ret.pvOutBuffer, call->cbOutBufferSize, &ret.cbOutBufferSize);
1456 scard_log_status_error_wlog(smartcard->log, "SCardControl", ret.ReturnCode);
1457 status = smartcard_pack_control_return(out, &ret);
1458
1459 free(ret.pvOutBuffer);
1460 if (status != SCARD_S_SUCCESS)
1461 return status;
1462 return ret.ReturnCode;
1463}
1464
1465static LONG smartcard_GetAttrib_Call(scard_call_context* smartcard, wStream* out,
1466 SMARTCARD_OPERATION* operation)
1467{
1468 BOOL autoAllocate = FALSE;
1469 LONG status = 0;
1470 DWORD cbAttrLen = 0;
1471 LPBYTE pbAttr = nullptr;
1472 GetAttrib_Return ret = WINPR_C_ARRAY_INIT;
1473 const GetAttrib_Call* call = nullptr;
1474
1475 WINPR_ASSERT(smartcard);
1476 WINPR_ASSERT(operation);
1477
1478 call = &operation->call.getAttrib;
1479
1480 if (!call->fpbAttrIsNULL)
1481 {
1482 autoAllocate = (call->cbAttrLen == SCARD_AUTOALLOCATE);
1483 cbAttrLen = call->cbAttrLen;
1484 if (cbAttrLen && !autoAllocate)
1485 {
1486 ret.pbAttr = (BYTE*)malloc(cbAttrLen);
1487
1488 if (!ret.pbAttr)
1489 return SCARD_E_NO_MEMORY;
1490 }
1491
1492 pbAttr = autoAllocate ? (LPBYTE) & (ret.pbAttr) : ret.pbAttr;
1493 }
1494
1495 ret.ReturnCode =
1496 wrap(smartcard, SCardGetAttrib, operation->hCard, call->dwAttrId, pbAttr, &cbAttrLen);
1497 scard_log_status_error_wlog(smartcard->log, "SCardGetAttrib", ret.ReturnCode);
1498 if ((ret.ReturnCode == SCARD_S_SUCCESS) && (cbAttrLen == SCARD_AUTOALLOCATE))
1499 return SCARD_F_UNKNOWN_ERROR;
1500
1501 ret.cbAttrLen = cbAttrLen;
1502
1503 status = smartcard_pack_get_attrib_return(out, &ret, call->dwAttrId, call->cbAttrLen);
1504
1505 if (autoAllocate)
1506 wrap(smartcard, SCardFreeMemory, operation->hContext, ret.pbAttr);
1507 else
1508 free(ret.pbAttr);
1509 return status;
1510}
1511
1512static LONG smartcard_SetAttrib_Call(scard_call_context* smartcard, WINPR_ATTR_UNUSED wStream* out,
1513 SMARTCARD_OPERATION* operation)
1514{
1515 Long_Return ret = WINPR_C_ARRAY_INIT;
1516 SetAttrib_Call* call = nullptr;
1517
1518 WINPR_ASSERT(smartcard);
1519 WINPR_ASSERT(out);
1520 WINPR_ASSERT(operation);
1521
1522 call = &operation->call.setAttrib;
1523
1524 ret.ReturnCode = wrap(smartcard, SCardSetAttrib, operation->hCard, call->dwAttrId, call->pbAttr,
1525 call->cbAttrLen);
1526 scard_log_status_error_wlog(smartcard->log, "SCardSetAttrib", ret.ReturnCode);
1527 smartcard_trace_long_return_int(smartcard->log, &ret, "SetAttrib");
1528
1529 return ret.ReturnCode;
1530}
1531
1532static LONG smartcard_AccessStartedEvent_Call(scard_call_context* smartcard,
1533 WINPR_ATTR_UNUSED wStream* out,
1534 SMARTCARD_OPERATION* operation)
1535{
1536 LONG status = SCARD_S_SUCCESS;
1537
1538 WINPR_ASSERT(smartcard);
1539 WINPR_ASSERT(out);
1540 WINPR_UNUSED(operation);
1541
1542 if (!smartcard->StartedEvent)
1543 smartcard->StartedEvent = wrap_ptr(smartcard, SCardAccessStartedEvent);
1544
1545 if (!smartcard->StartedEvent)
1546 status = SCARD_E_NO_SERVICE;
1547
1548 return status;
1549}
1550
1551static LONG smartcard_LocateCardsByATRA_Call(scard_call_context* smartcard, wStream* out,
1552 SMARTCARD_OPERATION* operation)
1553{
1554 LONG status = 0;
1555 GetStatusChange_Return ret = WINPR_C_ARRAY_INIT;
1556 LPSCARD_READERSTATEA states = nullptr;
1557 LocateCardsByATRA_Call* call = nullptr;
1558
1559 WINPR_ASSERT(smartcard);
1560 WINPR_ASSERT(operation);
1561
1562 call = &operation->call.locateCardsByATRA;
1563 states = (LPSCARD_READERSTATEA)calloc(call->cReaders, sizeof(SCARD_READERSTATEA));
1564
1565 if (!states)
1566 return STATUS_NO_MEMORY;
1567
1568 for (UINT32 i = 0; i < call->cReaders; i++)
1569 {
1570 LPSCARD_READERSTATEA state = &states[i];
1571 state->szReader = call->rgReaderStates[i].szReader;
1572 state->dwCurrentState = call->rgReaderStates[i].dwCurrentState;
1573 state->dwEventState = call->rgReaderStates[i].dwEventState;
1574 state->cbAtr = call->rgReaderStates[i].cbAtr;
1575 CopyMemory(&(state->rgbAtr), &(call->rgReaderStates[i].rgbAtr), 36);
1576 }
1577
1578 status = ret.ReturnCode = wrap(smartcard, SCardGetStatusChangeA, operation->hContext,
1579 0x000001F4, states, call->cReaders);
1580
1581 scard_log_status_error_wlog(smartcard->log, "SCardGetStatusChangeA", status);
1582 for (UINT32 i = 0; i < call->cAtrs; i++)
1583 {
1584 for (UINT32 j = 0; j < call->cReaders; j++)
1585 {
1586 for (UINT32 k = 0; k < call->rgAtrMasks[i].cbAtr; k++)
1587 {
1588 if ((call->rgAtrMasks[i].rgbAtr[k] & call->rgAtrMasks[i].rgbMask[k]) !=
1589 (states[j].rgbAtr[k] & call->rgAtrMasks[i].rgbMask[k]))
1590 {
1591 break;
1592 }
1593
1594 states[j].dwEventState |= SCARD_STATE_ATRMATCH;
1595 }
1596 }
1597 }
1598
1599 ret.cReaders = call->cReaders;
1600 ret.rgReaderStates = nullptr;
1601
1602 if (ret.cReaders > 0)
1603 ret.rgReaderStates = (ReaderState_Return*)calloc(ret.cReaders, sizeof(ReaderState_Return));
1604
1605 if (!ret.rgReaderStates)
1606 {
1607 free(states);
1608 return STATUS_NO_MEMORY;
1609 }
1610
1611 for (UINT32 i = 0; i < ret.cReaders; i++)
1612 {
1613 LPSCARD_READERSTATEA state = &states[i];
1614 ret.rgReaderStates[i].dwCurrentState = state->dwCurrentState;
1615 ret.rgReaderStates[i].dwEventState = state->dwEventState;
1616 ret.rgReaderStates[i].cbAtr = state->cbAtr;
1617 CopyMemory(&(ret.rgReaderStates[i].rgbAtr), &(state->rgbAtr),
1618 sizeof(ret.rgReaderStates[i].rgbAtr));
1619 }
1620
1621 free(states);
1622
1623 status = smartcard_pack_get_status_change_return(out, &ret, FALSE);
1624
1625 free(ret.rgReaderStates);
1626 if (status != SCARD_S_SUCCESS)
1627 return status;
1628 return ret.ReturnCode;
1629}
1630
1631LONG smartcard_irp_device_control_call(scard_call_context* ctx, wStream* out, NTSTATUS* pIoStatus,
1632 SMARTCARD_OPERATION* operation)
1633{
1634 LONG result = 0;
1635 UINT32 offset = 0;
1636 size_t objectBufferLength = 0;
1637
1638 WINPR_ASSERT(ctx);
1639 WINPR_ASSERT(out);
1640 WINPR_ASSERT(pIoStatus);
1641 WINPR_ASSERT(operation);
1642
1643 const UINT32 ioControlCode = operation->ioControlCode;
1651 const size_t outMaxLen = MAX(2048, operation->outputBufferLength);
1652 if (!Stream_EnsureRemainingCapacity(out, outMaxLen))
1653 return SCARD_E_NO_MEMORY;
1654
1655 /* Device Control Response */
1656 Stream_Write_UINT32(out, 0); /* OutputBufferLength (4 bytes) */
1657 Stream_Zero(out, SMARTCARD_COMMON_TYPE_HEADER_LENGTH); /* CommonTypeHeader (8 bytes) */
1658 Stream_Zero(out, SMARTCARD_PRIVATE_TYPE_HEADER_LENGTH); /* PrivateTypeHeader (8 bytes) */
1659 Stream_Write_UINT32(out, 0); /* Result (4 bytes) */
1660
1661 /* Call */
1662 switch (ioControlCode)
1663 {
1664 case SCARD_IOCTL_ESTABLISHCONTEXT:
1665 result = smartcard_EstablishContext_Call(ctx, out, operation);
1666 break;
1667
1668 case SCARD_IOCTL_RELEASECONTEXT:
1669 result = smartcard_ReleaseContext_Call(ctx, out, operation);
1670 break;
1671
1672 case SCARD_IOCTL_ISVALIDCONTEXT:
1673 result = smartcard_IsValidContext_Call(ctx, out, operation);
1674 break;
1675
1676 case SCARD_IOCTL_LISTREADERGROUPSA:
1677 result = smartcard_ListReaderGroupsA_Call(ctx, out, operation);
1678 break;
1679
1680 case SCARD_IOCTL_LISTREADERGROUPSW:
1681 result = smartcard_ListReaderGroupsW_Call(ctx, out, operation);
1682 break;
1683
1684 case SCARD_IOCTL_LISTREADERSA:
1685 result = smartcard_ListReadersA_Call(ctx, out, operation);
1686 break;
1687
1688 case SCARD_IOCTL_LISTREADERSW:
1689 result = smartcard_ListReadersW_Call(ctx, out, operation);
1690 break;
1691
1692 case SCARD_IOCTL_INTRODUCEREADERGROUPA:
1693 result = smartcard_IntroduceReaderGroupA_Call(ctx, out, operation);
1694 break;
1695
1696 case SCARD_IOCTL_INTRODUCEREADERGROUPW:
1697 result = smartcard_IntroduceReaderGroupW_Call(ctx, out, operation);
1698 break;
1699
1700 case SCARD_IOCTL_FORGETREADERGROUPA:
1701 result = smartcard_ForgetReaderA_Call(ctx, out, operation);
1702 break;
1703
1704 case SCARD_IOCTL_FORGETREADERGROUPW:
1705 result = smartcard_ForgetReaderW_Call(ctx, out, operation);
1706 break;
1707
1708 case SCARD_IOCTL_INTRODUCEREADERA:
1709 result = smartcard_IntroduceReaderA_Call(ctx, out, operation);
1710 break;
1711
1712 case SCARD_IOCTL_INTRODUCEREADERW:
1713 result = smartcard_IntroduceReaderW_Call(ctx, out, operation);
1714 break;
1715
1716 case SCARD_IOCTL_FORGETREADERA:
1717 result = smartcard_ForgetReaderA_Call(ctx, out, operation);
1718 break;
1719
1720 case SCARD_IOCTL_FORGETREADERW:
1721 result = smartcard_ForgetReaderW_Call(ctx, out, operation);
1722 break;
1723
1724 case SCARD_IOCTL_ADDREADERTOGROUPA:
1725 result = smartcard_AddReaderToGroupA_Call(ctx, out, operation);
1726 break;
1727
1728 case SCARD_IOCTL_ADDREADERTOGROUPW:
1729 result = smartcard_AddReaderToGroupW_Call(ctx, out, operation);
1730 break;
1731
1732 case SCARD_IOCTL_REMOVEREADERFROMGROUPA:
1733 result = smartcard_RemoveReaderFromGroupA_Call(ctx, out, operation);
1734 break;
1735
1736 case SCARD_IOCTL_REMOVEREADERFROMGROUPW:
1737 result = smartcard_RemoveReaderFromGroupW_Call(ctx, out, operation);
1738 break;
1739
1740 case SCARD_IOCTL_LOCATECARDSA:
1741 result = smartcard_LocateCardsA_Call(ctx, out, operation);
1742 break;
1743
1744 case SCARD_IOCTL_LOCATECARDSW:
1745 result = smartcard_LocateCardsW_Call(ctx, out, operation);
1746 break;
1747
1748 case SCARD_IOCTL_GETSTATUSCHANGEA:
1749 result = smartcard_GetStatusChangeA_Call(ctx, out, operation);
1750 break;
1751
1752 case SCARD_IOCTL_GETSTATUSCHANGEW:
1753 result = smartcard_GetStatusChangeW_Call(ctx, out, operation);
1754 break;
1755
1756 case SCARD_IOCTL_CANCEL:
1757 result = smartcard_Cancel_Call(ctx, out, operation);
1758 break;
1759
1760 case SCARD_IOCTL_CONNECTA:
1761 result = smartcard_ConnectA_Call(ctx, out, operation);
1762 break;
1763
1764 case SCARD_IOCTL_CONNECTW:
1765 result = smartcard_ConnectW_Call(ctx, out, operation);
1766 break;
1767
1768 case SCARD_IOCTL_RECONNECT:
1769 result = smartcard_Reconnect_Call(ctx, out, operation);
1770 break;
1771
1772 case SCARD_IOCTL_DISCONNECT:
1773 result = smartcard_Disconnect_Call(ctx, out, operation);
1774 break;
1775
1776 case SCARD_IOCTL_BEGINTRANSACTION:
1777 result = smartcard_BeginTransaction_Call(ctx, out, operation);
1778 break;
1779
1780 case SCARD_IOCTL_ENDTRANSACTION:
1781 result = smartcard_EndTransaction_Call(ctx, out, operation);
1782 break;
1783
1784 case SCARD_IOCTL_STATE:
1785 result = smartcard_State_Call(ctx, out, operation);
1786 break;
1787
1788 case SCARD_IOCTL_STATUSA:
1789 result = smartcard_StatusA_Call(ctx, out, operation);
1790 break;
1791
1792 case SCARD_IOCTL_STATUSW:
1793 result = smartcard_StatusW_Call(ctx, out, operation);
1794 break;
1795
1796 case SCARD_IOCTL_TRANSMIT:
1797 result = smartcard_Transmit_Call(ctx, out, operation);
1798 break;
1799
1800 case SCARD_IOCTL_CONTROL:
1801 result = smartcard_Control_Call(ctx, out, operation);
1802 break;
1803
1804 case SCARD_IOCTL_GETATTRIB:
1805 result = smartcard_GetAttrib_Call(ctx, out, operation);
1806 break;
1807
1808 case SCARD_IOCTL_SETATTRIB:
1809 result = smartcard_SetAttrib_Call(ctx, out, operation);
1810 break;
1811
1812 case SCARD_IOCTL_ACCESSSTARTEDEVENT:
1813 result = smartcard_AccessStartedEvent_Call(ctx, out, operation);
1814 break;
1815
1816 case SCARD_IOCTL_LOCATECARDSBYATRA:
1817 result = smartcard_LocateCardsByATRA_Call(ctx, out, operation);
1818 break;
1819
1820 case SCARD_IOCTL_LOCATECARDSBYATRW:
1821 result = smartcard_LocateCardsW_Call(ctx, out, operation);
1822 break;
1823
1824 case SCARD_IOCTL_READCACHEA:
1825 result = smartcard_ReadCacheA_Call(ctx, out, operation);
1826 break;
1827
1828 case SCARD_IOCTL_READCACHEW:
1829 result = smartcard_ReadCacheW_Call(ctx, out, operation);
1830 break;
1831
1832 case SCARD_IOCTL_WRITECACHEA:
1833 result = smartcard_WriteCacheA_Call(ctx, out, operation);
1834 break;
1835
1836 case SCARD_IOCTL_WRITECACHEW:
1837 result = smartcard_WriteCacheW_Call(ctx, out, operation);
1838 break;
1839
1840 case SCARD_IOCTL_GETTRANSMITCOUNT:
1841 result = smartcard_GetTransmitCount_Call(ctx, out, operation);
1842 break;
1843
1844 case SCARD_IOCTL_RELEASETARTEDEVENT:
1845 result = smartcard_ReleaseStartedEvent_Call(ctx, out, operation);
1846 break;
1847
1848 case SCARD_IOCTL_GETREADERICON:
1849 result = smartcard_GetReaderIcon_Call(ctx, out, operation);
1850 break;
1851
1852 case SCARD_IOCTL_GETDEVICETYPEID:
1853 result = smartcard_GetDeviceTypeId_Call(ctx, out, operation);
1854 break;
1855
1856 default:
1857 result = STATUS_UNSUCCESSFUL;
1858 break;
1859 }
1860
1867 if ((ioControlCode != SCARD_IOCTL_ACCESSSTARTEDEVENT) &&
1868 (ioControlCode != SCARD_IOCTL_RELEASETARTEDEVENT))
1869 {
1870 offset = (RDPDR_DEVICE_IO_RESPONSE_LENGTH + RDPDR_DEVICE_IO_CONTROL_RSP_HDR_LENGTH);
1871 const LONG rc = smartcard_pack_write_size_align(out, Stream_GetPosition(out) - offset, 8);
1872 if (rc != SCARD_S_SUCCESS)
1873 result = rc;
1874 }
1875
1876 if ((result != SCARD_S_SUCCESS) && (result != SCARD_E_TIMEOUT) &&
1877 (result != SCARD_E_NO_READERS_AVAILABLE) && (result != SCARD_E_NO_SERVICE) &&
1878 (result != SCARD_W_CACHE_ITEM_NOT_FOUND) && (result != SCARD_W_CACHE_ITEM_STALE))
1879 {
1880 scard_log_status_error_wlog(ctx->log, "IRP failure: %s (0x%08" PRIX32 ")", result,
1881 scard_get_ioctl_string(ioControlCode, TRUE), ioControlCode);
1882 }
1883
1884 *pIoStatus = STATUS_SUCCESS;
1885
1886 if ((result & 0xC0000000L) == 0xC0000000L)
1887 {
1888 /* NTSTATUS error */
1889 *pIoStatus = result;
1890
1891 scard_log_status_error_wlog(ctx->log, "IRP failure: %s (0x%08" PRIX32 ")", result,
1892 scard_get_ioctl_string(ioControlCode, TRUE), ioControlCode);
1893 }
1894
1895 Stream_SealLength(out);
1896 size_t outputBufferLength = Stream_Length(out);
1897 size_t dataEndPos = outputBufferLength;
1898
1899 WINPR_ASSERT(outputBufferLength >= RDPDR_DEVICE_IO_RESPONSE_LENGTH + 4U);
1900 outputBufferLength -= (RDPDR_DEVICE_IO_RESPONSE_LENGTH + 4U);
1901 WINPR_ASSERT(outputBufferLength >= RDPDR_DEVICE_IO_RESPONSE_LENGTH);
1902 objectBufferLength = outputBufferLength - RDPDR_DEVICE_IO_RESPONSE_LENGTH;
1903 WINPR_ASSERT(outputBufferLength <= UINT32_MAX);
1904 WINPR_ASSERT(objectBufferLength <= UINT32_MAX);
1905 if (!Stream_SetPosition(out, RDPDR_DEVICE_IO_RESPONSE_LENGTH))
1906 return SCARD_E_BAD_SEEK;
1907
1908 /* [MS-RDPESC] 3.2.5.2 Processing Incoming Replies
1909 *
1910 * if the output buffer is too small, reply with STATUS_BUFFER_TOO_SMALL
1911 * and a outputBufferLength of 0.
1912 * The message should then be retransmitted from the server with a doubled
1913 * buffer size.
1914 */
1915 if (outputBufferLength > operation->outputBufferLength)
1916 {
1917 WLog_Print(ctx->log, WLOG_DEBUG,
1918 "IRP warn: expected outputBufferLength %" PRIuz ", but current limit %" PRIu32
1919 ", respond with STATUS_BUFFER_TOO_SMALL for retransmit with larger buffer",
1920 outputBufferLength, operation->outputBufferLength);
1921
1922 *pIoStatus = STATUS_BUFFER_TOO_SMALL;
1923 result = *pIoStatus;
1924 outputBufferLength = 0;
1925 objectBufferLength = 0;
1926 }
1927 else
1928 {
1929 WLog_Print(ctx->log, WLOG_TRACE, "IRP trace: outputBufferLength %" PRIuz ", limit %" PRIu32,
1930 outputBufferLength, operation->outputBufferLength);
1931 }
1932
1933 /* Device Control Response */
1934 Stream_Write_UINT32(out, (UINT32)outputBufferLength); /* OutputBufferLength (4 bytes) */
1935 smartcard_pack_common_type_header(out); /* CommonTypeHeader (8 bytes) */
1936 smartcard_pack_private_type_header(
1937 out, (UINT32)objectBufferLength); /* PrivateTypeHeader (8 bytes) */
1938 Stream_Write_INT32(out, result); /* Result (4 bytes) */
1939 if (result == STATUS_BUFFER_TOO_SMALL)
1940 Stream_SealLength(out);
1941 else if (!Stream_SetPosition(out, dataEndPos))
1942 return SCARD_E_BAD_SEEK;
1943 return SCARD_S_SUCCESS;
1944}
1945
1946void context_free(void* arg)
1947{
1948 struct s_scard_context_element* element = arg;
1949 if (!arg)
1950 return;
1951
1952 if (element->fn_free)
1953 element->fn_free(element->context);
1954 free(element);
1955}
1956
1957#if !defined(WITHOUT_FREERDP_3x_DEPRECATED)
1958scard_call_context* smartcard_call_context_new(const rdpSettings* settings)
1959{
1960 const freerdp* inst = freerdp_settings_get_pointer(settings, FreeRDP_instance);
1961 if (!inst || !inst->context)
1962 return nullptr;
1963 return smartcard_call_context_new_with_context(inst->context);
1964}
1965#endif
1966
1967scard_call_context* smartcard_call_context_new_with_context(rdpContext* context)
1968{
1969 WINPR_ASSERT(context);
1970 scard_call_context* ctx = calloc(1, sizeof(scard_call_context));
1971 if (!ctx)
1972 goto fail;
1973
1974 ctx->context = context;
1975
1976 const rdpSettings* settings = context->settings;
1977 WINPR_ASSERT(settings);
1978
1979 ctx->log = WLog_Get(SCARD_TAG);
1980 WINPR_ASSERT(ctx->log);
1981
1982 ctx->stopEvent = CreateEventA(nullptr, TRUE, FALSE, nullptr);
1983 if (!ctx->stopEvent)
1984 goto fail;
1985
1986 ctx->names = LinkedList_New();
1987 if (!ctx->names)
1988 goto fail;
1989
1990#if defined(WITH_SMARTCARD_EMULATE)
1991 ctx->useEmulatedCard = freerdp_settings_get_bool(settings, FreeRDP_SmartcardEmulation);
1992#endif
1993
1994 if (ctx->useEmulatedCard)
1995 {
1996#if defined(WITH_SMARTCARD_EMULATE)
1997 ctx->emulation = Emulate_New(settings);
1998 if (!ctx->emulation)
1999 goto fail;
2000#else
2001 WLog_Print(ctx->log, WLOG_ERROR, "Smartcard emulation requested, but not supported!");
2002 goto fail;
2003#endif
2004 }
2005 else
2006 {
2007 const char* WinSCardModule = freerdp_settings_get_string(settings, FreeRDP_WinSCardModule);
2008 if (WinSCardModule)
2009 {
2010 ctx->hWinSCardLibrary = LoadLibraryX(WinSCardModule);
2011
2012 if (!ctx->hWinSCardLibrary)
2013 {
2014 WLog_Print(ctx->log, WLOG_ERROR, "Failed to load WinSCard library: '%s'",
2015 WinSCardModule);
2016 goto fail;
2017 }
2018
2019 if (!WinSCard_LoadApiTableFunctions(&ctx->WinSCardApi, ctx->hWinSCardLibrary))
2020 goto fail;
2021 ctx->pWinSCardApi = &ctx->WinSCardApi;
2022 }
2023 else
2024 {
2025 ctx->pWinSCardApi = WinPR_GetSCardApiFunctionTable();
2026 }
2027
2028 if (!ctx->pWinSCardApi)
2029 {
2030 WLog_Print(ctx->log, WLOG_ERROR, "Failed to load WinSCard API!");
2031 goto fail;
2032 }
2033 }
2034
2035 ctx->rgSCardContextList = HashTable_New(FALSE);
2036 if (!ctx->rgSCardContextList)
2037 goto fail;
2038
2039 {
2040 wObject* obj = HashTable_ValueObject(ctx->rgSCardContextList);
2041 WINPR_ASSERT(obj);
2042 obj->fnObjectFree = context_free;
2043 }
2044
2045 return ctx;
2046fail:
2047 WINPR_PRAGMA_DIAG_PUSH
2048 WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
2049 smartcard_call_context_free(ctx);
2050 WINPR_PRAGMA_DIAG_POP
2051 return nullptr;
2052}
2053
2054void smartcard_call_context_free(scard_call_context* ctx)
2055{
2056 if (!ctx)
2057 return;
2058
2059 smartcard_call_context_signal_stop(ctx, FALSE);
2060
2061 LinkedList_Free(ctx->names);
2062 if (ctx->StartedEvent)
2063 {
2064 WINPR_ASSERT(ctx->useEmulatedCard || ctx->pWinSCardApi);
2065 wrap_raw(ctx, SCardReleaseStartedEvent);
2066 }
2067
2068 if (ctx->useEmulatedCard)
2069 {
2070#ifdef WITH_SMARTCARD_EMULATE
2071 if (ctx->emulation)
2072 {
2073 Emulate_Free(ctx->emulation);
2074 ctx->emulation = nullptr;
2075 }
2076#endif
2077 }
2078
2079 if (ctx->hWinSCardLibrary)
2080 {
2081 ZeroMemory(&ctx->WinSCardApi, sizeof(SCardApiFunctionTable));
2082 FreeLibrary(ctx->hWinSCardLibrary);
2083 ctx->hWinSCardLibrary = nullptr;
2084 }
2085
2086 ctx->pWinSCardApi = nullptr;
2087
2088 HashTable_Free(ctx->rgSCardContextList);
2089 (void)CloseHandle(ctx->stopEvent);
2090 free(ctx);
2091}
2092
2093BOOL smartcard_call_context_add(scard_call_context* ctx, const char* name)
2094{
2095 WINPR_ASSERT(ctx);
2096 WINPR_ASSERT(name);
2097 return LinkedList_AddLast(ctx->names, name);
2098}
2099
2100BOOL smartcard_call_cancel_context(scard_call_context* ctx, SCARDCONTEXT hContext)
2101{
2102 WINPR_ASSERT(ctx);
2103 if (wrap(ctx, SCardIsValidContext, hContext) == SCARD_S_SUCCESS)
2104 {
2105 wrap(ctx, SCardCancel, hContext);
2106 }
2107 return TRUE;
2108}
2109
2110BOOL smartcard_call_release_context(scard_call_context* ctx, SCARDCONTEXT hContext)
2111{
2112 WINPR_ASSERT(ctx);
2113 wrap(ctx, SCardReleaseContext, hContext);
2114 return TRUE;
2115}
2116
2117BOOL smartcard_call_cancel_all_context(scard_call_context* ctx)
2118{
2119 if (!ctx)
2120 return FALSE;
2121
2122 HashTable_Clear(ctx->rgSCardContextList);
2123 return TRUE;
2124}
2125
2126BOOL smarcard_call_set_callbacks(scard_call_context* ctx, void* userdata,
2127 void* (*fn_new)(void*, SCARDCONTEXT), void (*fn_free)(void*))
2128{
2129 WINPR_ASSERT(ctx);
2130 ctx->userdata = userdata;
2131 ctx->fn_new = fn_new;
2132 ctx->fn_free = fn_free;
2133 return TRUE;
2134}
2135
2136void* smartcard_call_get_context(scard_call_context* ctx, SCARDCONTEXT hContext)
2137{
2138 struct s_scard_context_element* element = nullptr;
2139
2140 WINPR_ASSERT(ctx);
2141 element = HashTable_GetItemValue(ctx->rgSCardContextList, (void*)hContext);
2142 if (!element)
2143 return nullptr;
2144 return element->context;
2145}
2146
2147BOOL smartcard_call_is_configured(scard_call_context* ctx)
2148{
2149 WINPR_ASSERT(ctx);
2150
2151#if defined(WITH_SMARTCARD_EMULATE)
2152 if (ctx->useEmulatedCard)
2153 return Emulate_IsConfigured(ctx->emulation);
2154#endif
2155
2156 return FALSE;
2157}
2158
2159BOOL smartcard_call_context_signal_stop(scard_call_context* ctx, BOOL reset)
2160{
2161 WINPR_ASSERT(ctx);
2162
2163 if (!ctx->stopEvent)
2164 return TRUE;
2165
2166 if (reset)
2167 return ResetEvent(ctx->stopEvent);
2168 else
2169 return SetEvent(ctx->stopEvent);
2170}
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