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