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