22#include <winpr/stream.h>
23#include <winpr/smartcard.h>
25#include <freerdp/channels/rdpdr.h>
26#include <freerdp/channels/scard.h>
27#include <freerdp/utils/rdpdr_utils.h>
28#include <freerdp/utils/smartcard_operations.h>
29#include <freerdp/utils/smartcard_pack.h>
33 smartcard_scard_context_native_to_redir(ctx, val);
38 smartcard_scard_handle_native_to_redir(handle, val);
41static wStream* build_device_control_request(UINT32 ioControlCode,
const void* inputBuffer,
42 size_t inputBufferLength)
44 const char* name = scard_get_ioctl_string(ioControlCode, TRUE);
45 const size_t totalLength = RDPDR_DEVICE_IO_CONTROL_REQ_HDR_LENGTH + inputBufferLength;
47 wStream* s = Stream_New(
nullptr, totalLength);
50 (void)fprintf(stderr,
"build_device_control_request(%s): Stream_New(%" PRIuz
") failed\n",
55 UINT32 inputLength = WINPR_ASSERTING_INT_CAST(UINT32, inputBufferLength);
56 Stream_Write_UINT32(s, 2048);
57 Stream_Write_UINT32(s, inputLength);
58 Stream_Write_UINT32(s, ioControlCode);
61 if (inputBufferLength > 0)
62 Stream_Write(s, inputBuffer, inputBufferLength);
65 if (!Stream_SetPosition(s, 0))
67 (void)fprintf(stderr,
"build_device_control_request(%s): Stream_SetPosition failed\n",
78 const UINT32 ioControlCode = opIn->ioControlCode;
79 const char* name = scard_get_ioctl_string(ioControlCode, TRUE);
81 wStream* sEnc = Stream_New(
nullptr, 4096);
84 (void)fprintf(stderr,
"%s: Stream_New for encode failed\n", name);
88 LONG status = smartcard_irp_device_control_encode_request(sEnc, opIn);
89 if (status != SCARD_S_SUCCESS)
91 (void)fprintf(stderr,
"%s: encode_request failed with 0x%08" PRIX32
"\n", name,
98 build_device_control_request(ioControlCode, Stream_Buffer(sEnc), Stream_Length(sEnc));
104 status = smartcard_irp_device_control_decode_request(sDec, 1, 0, opOut);
105 Stream_Release(sDec);
106 if (status != SCARD_S_SUCCESS)
108 (void)fprintf(stderr,
"%s: decode_request failed with 0x%08" PRIX32
"\n", name,
113 if (opOut->ioControlCode != ioControlCode)
115 (void)fprintf(stderr,
"%s: ioControlCode mismatch: 0x%08" PRIX32
" != 0x%08" PRIX32
"\n",
116 name, opOut->ioControlCode, ioControlCode);
117 smartcard_operation_free(opOut, FALSE);
124static inline BOOL check_field(
const char* name,
const char* field, UINT32 a, UINT32 b)
128 (void)fprintf(stderr,
"%s: %s mismatch: 0x%" PRIX32
" != 0x%" PRIX32
"\n", name, field, a,
135static inline BOOL check_bytes(
const char* name,
const char* field,
const void* a,
const void* b,
138 if (!a || !b || memcmp(a, b, len) != 0)
140 (void)fprintf(stderr,
"%s: %s mismatch (%" PRIuz
" bytes)\n", name, field, len);
149 return check_field(name,
"hContext.cbContext", a->cbContext, b->cbContext) &&
150 check_bytes(name,
"hContext.pbContext", a->pbContext, b->pbContext, a->cbContext);
153static inline BOOL check_redir_handle(
const char* name,
const REDIR_SCARDHANDLE* a,
156 return check_field(name,
"hCard.cbHandle", a->cbHandle, b->cbHandle) &&
157 check_bytes(name,
"hCard.pbHandle", a->pbHandle, b->pbHandle, a->cbHandle);
160static BOOL test_establish_context_encode_decode_request(
void)
162 BOOL success = FALSE;
165 opIn.ioControlCode = SCARD_IOCTL_ESTABLISHCONTEXT;
166 opIn.call.establishContext.dwScope = SCARD_SCOPE_SYSTEM;
168 if (!test_request_roundtrip(&opIn, &opOut))
170 if (!check_field(
"EstablishContext",
"dwScope", opIn.call.establishContext.dwScope,
171 opOut.call.establishContext.dwScope))
176 smartcard_operation_free(&opIn, FALSE);
177 smartcard_operation_free(&opOut, FALSE);
181static BOOL test_release_context_encode_decode_request(
void)
183 BOOL success = FALSE;
186 opIn.ioControlCode = SCARD_IOCTL_RELEASECONTEXT;
187 fill_redir_context(&opIn.call.context.handles.hContext, 0x1234);
189 if (!test_request_roundtrip(&opIn, &opOut))
191 if (!check_redir_context(
"ReleaseContext", &opIn.call.context.handles.hContext,
192 &opOut.call.context.handles.hContext))
197 smartcard_operation_free(&opIn, FALSE);
198 smartcard_operation_free(&opOut, FALSE);
202static BOOL test_is_valid_context_encode_decode_request(
void)
204 BOOL success = FALSE;
207 opIn.ioControlCode = SCARD_IOCTL_ISVALIDCONTEXT;
208 fill_redir_context(&opIn.call.context.handles.hContext, 0x5678);
210 if (!test_request_roundtrip(&opIn, &opOut))
212 if (!check_redir_context(
"IsValidContext", &opIn.call.context.handles.hContext,
213 &opOut.call.context.handles.hContext))
218 smartcard_operation_free(&opIn, FALSE);
219 smartcard_operation_free(&opOut, FALSE);
223static BOOL test_list_reader_groups_encode_decode_request_impl(UINT32 ioControlCode)
225 BOOL success = FALSE;
226 const char* n = scard_get_ioctl_string(ioControlCode, TRUE);
229 opIn.ioControlCode = ioControlCode;
230 fill_redir_context(&opIn.call.listReaderGroups.handles.hContext, 0x1234);
231 opIn.call.listReaderGroups.fmszGroupsIsNULL = 0;
232 opIn.call.listReaderGroups.cchGroups = SCARD_AUTOALLOCATE;
234 if (!test_request_roundtrip(&opIn, &opOut))
236 if (!check_redir_context(n, &opIn.call.listReaderGroups.handles.hContext,
237 &opOut.call.listReaderGroups.handles.hContext))
239 if (!check_field(n,
"fmszGroupsIsNULL", opIn.call.listReaderGroups.fmszGroupsIsNULL,
240 opOut.call.listReaderGroups.fmszGroupsIsNULL))
242 if (!check_field(n,
"cchGroups", opIn.call.listReaderGroups.cchGroups,
243 opOut.call.listReaderGroups.cchGroups))
248 smartcard_operation_free(&opIn, FALSE);
249 smartcard_operation_free(&opOut, FALSE);
253static BOOL test_list_reader_groups_a_encode_decode_request(
void)
255 return test_list_reader_groups_encode_decode_request_impl(SCARD_IOCTL_LISTREADERGROUPSA);
258static BOOL test_list_reader_groups_w_encode_decode_request(
void)
260 return test_list_reader_groups_encode_decode_request_impl(SCARD_IOCTL_LISTREADERGROUPSW);
263static BOOL test_list_readers_encode_decode_request_impl(UINT32 ioControlCode)
265 BOOL success = FALSE;
266 const char* n = scard_get_ioctl_string(ioControlCode, TRUE);
269 opIn.ioControlCode = ioControlCode;
270 fill_redir_context(&opIn.call.listReaders.handles.hContext, 0x1234);
271 opIn.call.listReaders.fmszReadersIsNULL = 0;
272 opIn.call.listReaders.cchReaders = SCARD_AUTOALLOCATE;
274 if (!test_request_roundtrip(&opIn, &opOut))
276 if (!check_redir_context(n, &opIn.call.listReaders.handles.hContext,
277 &opOut.call.listReaders.handles.hContext))
279 if (!check_field(n,
"cchReaders", opIn.call.listReaders.cchReaders,
280 opOut.call.listReaders.cchReaders))
285 smartcard_operation_free(&opIn, FALSE);
286 smartcard_operation_free(&opOut, FALSE);
290static BOOL test_list_readers_a_encode_decode_request(
void)
292 return test_list_readers_encode_decode_request_impl(SCARD_IOCTL_LISTREADERSA);
295static BOOL test_list_readers_w_encode_decode_request(
void)
297 return test_list_readers_encode_decode_request_impl(SCARD_IOCTL_LISTREADERSW);
300static BOOL test_cancel_encode_decode_request(
void)
302 BOOL success = FALSE;
305 opIn.ioControlCode = SCARD_IOCTL_CANCEL;
306 fill_redir_context(&opIn.call.context.handles.hContext, 0xABCD);
308 if (!test_request_roundtrip(&opIn, &opOut))
310 if (!check_redir_context(
"Cancel", &opIn.call.context.handles.hContext,
311 &opOut.call.context.handles.hContext))
316 smartcard_operation_free(&opIn, FALSE);
317 smartcard_operation_free(&opOut, FALSE);
321static BOOL test_connect_a_encode_decode_request(
void)
323 BOOL success = FALSE;
326 opIn.ioControlCode = SCARD_IOCTL_CONNECTA;
327 fill_redir_context(&opIn.call.connectA.Common.handles.hContext, 0x1234);
328 opIn.call.connectA.Common.dwShareMode = SCARD_SHARE_SHARED;
329 opIn.call.connectA.Common.dwPreferredProtocols = SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1;
330 opIn.call.connectA.szReader = _strdup(
"TestReader");
332 if (!test_request_roundtrip(&opIn, &opOut))
334 if (!check_redir_context(
"ConnectA", &opIn.call.connectA.Common.handles.hContext,
335 &opOut.call.connectA.Common.handles.hContext))
337 if (!check_field(
"ConnectA",
"dwShareMode", opIn.call.connectA.Common.dwShareMode,
338 opOut.call.connectA.Common.dwShareMode))
340 if (!check_field(
"ConnectA",
"dwPreferredProtocols",
341 opIn.call.connectA.Common.dwPreferredProtocols,
342 opOut.call.connectA.Common.dwPreferredProtocols))
344 if (!check_bytes(
"ConnectA",
"szReader", opIn.call.connectA.szReader,
345 opOut.call.connectA.szReader, strlen(opIn.call.connectA.szReader) + 1))
350 smartcard_operation_free(&opIn, FALSE);
351 smartcard_operation_free(&opOut, FALSE);
355static BOOL test_connect_w_encode_decode_request(
void)
357 BOOL success = FALSE;
360 opIn.ioControlCode = SCARD_IOCTL_CONNECTW;
361 fill_redir_context(&opIn.call.connectW.Common.handles.hContext, 0x1234);
362 opIn.call.connectW.Common.dwShareMode = SCARD_SHARE_SHARED;
363 opIn.call.connectW.Common.dwPreferredProtocols = SCARD_PROTOCOL_T0;
364 opIn.call.connectW.szReader = ConvertUtf8ToWCharAlloc(
"TestReader",
nullptr);
366 if (!test_request_roundtrip(&opIn, &opOut))
368 if (!check_redir_context(
"ConnectW", &opIn.call.connectW.Common.handles.hContext,
369 &opOut.call.connectW.Common.handles.hContext))
371 if (!check_field(
"ConnectW",
"dwShareMode", opIn.call.connectW.Common.dwShareMode,
372 opOut.call.connectW.Common.dwShareMode))
374 if (!check_bytes(
"ConnectW",
"szReader", opIn.call.connectW.szReader,
375 opOut.call.connectW.szReader,
376 (_wcslen(opIn.call.connectW.szReader) + 1) *
sizeof(WCHAR)))
381 smartcard_operation_free(&opIn, FALSE);
382 smartcard_operation_free(&opOut, FALSE);
386static BOOL test_reconnect_encode_decode_request(
void)
388 BOOL success = FALSE;
389 const char* n =
"Reconnect";
392 opIn.ioControlCode = SCARD_IOCTL_RECONNECT;
393 fill_redir_context(&opIn.call.reconnect.handles.hContext, 0x1234);
394 fill_redir_handle(&opIn.call.reconnect.handles.hCard, 0x5678);
395 opIn.call.reconnect.dwShareMode = SCARD_SHARE_EXCLUSIVE;
396 opIn.call.reconnect.dwPreferredProtocols = SCARD_PROTOCOL_T1;
397 opIn.call.reconnect.dwInitialization = SCARD_LEAVE_CARD;
399 if (!test_request_roundtrip(&opIn, &opOut))
401 if (!check_redir_context(n, &opIn.call.reconnect.handles.hContext,
402 &opOut.call.reconnect.handles.hContext))
404 if (!check_redir_handle(n, &opIn.call.reconnect.handles.hCard,
405 &opOut.call.reconnect.handles.hCard))
407 if (!check_field(n,
"dwShareMode", opIn.call.reconnect.dwShareMode,
408 opOut.call.reconnect.dwShareMode))
410 if (!check_field(n,
"dwPreferredProtocols", opIn.call.reconnect.dwPreferredProtocols,
411 opOut.call.reconnect.dwPreferredProtocols))
413 if (!check_field(n,
"dwInitialization", opIn.call.reconnect.dwInitialization,
414 opOut.call.reconnect.dwInitialization))
419 smartcard_operation_free(&opIn, FALSE);
420 smartcard_operation_free(&opOut, FALSE);
424static BOOL test_hcard_and_disposition_encode_decode_request_impl(UINT32 ioControlCode,
427 BOOL success = FALSE;
428 const char* n = scard_get_ioctl_string(ioControlCode, TRUE);
431 opIn.ioControlCode = ioControlCode;
432 fill_redir_context(&opIn.call.hCardAndDisposition.handles.hContext, 0x1234);
433 fill_redir_handle(&opIn.call.hCardAndDisposition.handles.hCard, 0x5678);
434 opIn.call.hCardAndDisposition.dwDisposition = dwDisposition;
436 if (!test_request_roundtrip(&opIn, &opOut))
438 if (!check_redir_context(n, &opIn.call.hCardAndDisposition.handles.hContext,
439 &opOut.call.hCardAndDisposition.handles.hContext))
441 if (!check_redir_handle(n, &opIn.call.hCardAndDisposition.handles.hCard,
442 &opOut.call.hCardAndDisposition.handles.hCard))
444 if (!check_field(n,
"dwDisposition", opIn.call.hCardAndDisposition.dwDisposition,
445 opOut.call.hCardAndDisposition.dwDisposition))
450 smartcard_operation_free(&opIn, FALSE);
451 smartcard_operation_free(&opOut, FALSE);
455static BOOL test_disconnect_encode_decode_request(
void)
457 return test_hcard_and_disposition_encode_decode_request_impl(SCARD_IOCTL_DISCONNECT,
461static BOOL test_begin_transaction_encode_decode_request(
void)
463 return test_hcard_and_disposition_encode_decode_request_impl(SCARD_IOCTL_BEGINTRANSACTION,
467static BOOL test_end_transaction_encode_decode_request(
void)
469 return test_hcard_and_disposition_encode_decode_request_impl(SCARD_IOCTL_ENDTRANSACTION,
473static BOOL test_status_encode_decode_request_impl(UINT32 ioControlCode)
475 BOOL success = FALSE;
476 const char* n = scard_get_ioctl_string(ioControlCode, TRUE);
479 opIn.ioControlCode = ioControlCode;
480 fill_redir_context(&opIn.call.status.handles.hContext, 0x1234);
481 fill_redir_handle(&opIn.call.status.handles.hCard, 0x5678);
482 opIn.call.status.fmszReaderNamesIsNULL = 0;
483 opIn.call.status.cchReaderLen = SCARD_AUTOALLOCATE;
484 opIn.call.status.cbAtrLen = 36;
486 if (!test_request_roundtrip(&opIn, &opOut))
488 if (!check_redir_context(n, &opIn.call.status.handles.hContext,
489 &opOut.call.status.handles.hContext))
491 if (!check_redir_handle(n, &opIn.call.status.handles.hCard, &opOut.call.status.handles.hCard))
493 if (!check_field(n,
"fmszReaderNamesIsNULL", opIn.call.status.fmszReaderNamesIsNULL,
494 opOut.call.status.fmszReaderNamesIsNULL))
496 if (!check_field(n,
"cchReaderLen", opIn.call.status.cchReaderLen,
497 opOut.call.status.cchReaderLen))
499 if (!check_field(n,
"cbAtrLen", opIn.call.status.cbAtrLen, opOut.call.status.cbAtrLen))
504 smartcard_operation_free(&opIn, FALSE);
505 smartcard_operation_free(&opOut, FALSE);
509static BOOL test_status_a_encode_decode_request(
void)
511 return test_status_encode_decode_request_impl(SCARD_IOCTL_STATUSA);
514static BOOL test_status_w_encode_decode_request(
void)
516 return test_status_encode_decode_request_impl(SCARD_IOCTL_STATUSW);
519static BOOL test_transmit_encode_decode_request(
void)
521 BOOL success = FALSE;
522 BYTE sendBuf[] = { 0x00, 0xA4, 0x04, 0x00, 0x07 };
523 SCARD_IO_REQUEST pioSendPci = { .dwProtocol = SCARD_PROTOCOL_T0, .cbPciLength = 8 };
525 opIn.ioControlCode = SCARD_IOCTL_TRANSMIT;
526 fill_redir_context(&opIn.call.transmit.handles.hContext, 0x1234);
527 fill_redir_handle(&opIn.call.transmit.handles.hCard, 0x5678);
528 opIn.call.transmit.pioSendPci = &pioSendPci;
529 opIn.call.transmit.cbSendLength =
sizeof(sendBuf);
530 opIn.call.transmit.pbSendBuffer = sendBuf;
531 opIn.call.transmit.fpbRecvBufferIsNULL = 0;
532 opIn.call.transmit.cbRecvLength = 256;
535 if (!test_request_roundtrip(&opIn, &opOut))
537 if (!check_redir_context(
"Transmit", &opIn.call.transmit.handles.hContext,
538 &opOut.call.transmit.handles.hContext))
540 if (!check_redir_handle(
"Transmit", &opIn.call.transmit.handles.hCard,
541 &opOut.call.transmit.handles.hCard))
543 if (!check_field(
"Transmit",
"cbSendLength", opIn.call.transmit.cbSendLength,
544 opOut.call.transmit.cbSendLength))
546 if (!check_bytes(
"Transmit",
"pbSendBuffer", opIn.call.transmit.pbSendBuffer,
547 opOut.call.transmit.pbSendBuffer, opIn.call.transmit.cbSendLength))
549 if (!check_field(
"Transmit",
"fpbRecvBufferIsNULL",
550 (UINT32)opIn.call.transmit.fpbRecvBufferIsNULL,
551 (UINT32)opOut.call.transmit.fpbRecvBufferIsNULL))
553 if (!check_field(
"Transmit",
"cbRecvLength", opIn.call.transmit.cbRecvLength,
554 opOut.call.transmit.cbRecvLength))
556 if (!check_field(
"Transmit",
"pioSendPci.dwProtocol", opIn.call.transmit.pioSendPci->dwProtocol,
557 opOut.call.transmit.pioSendPci->dwProtocol))
562 opIn.call.transmit.pioSendPci =
nullptr;
563 opIn.call.transmit.pbSendBuffer =
nullptr;
564 smartcard_operation_free(&opIn, FALSE);
565 smartcard_operation_free(&opOut, FALSE);
569static BOOL test_control_encode_decode_request(
void)
571 BOOL success = FALSE;
572 BYTE inBuf[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 };
574 opIn.ioControlCode = SCARD_IOCTL_CONTROL;
575 fill_redir_context(&opIn.call.control.handles.hContext, 0x1234);
576 fill_redir_handle(&opIn.call.control.handles.hCard, 0x5678);
577 opIn.call.control.dwControlCode = 0x42000001;
578 opIn.call.control.cbInBufferSize =
sizeof(inBuf);
579 opIn.call.control.pvInBuffer = inBuf;
580 opIn.call.control.fpvOutBufferIsNULL = 0;
581 opIn.call.control.cbOutBufferSize = 256;
584 if (!test_request_roundtrip(&opIn, &opOut))
586 if (!check_redir_context(
"Control", &opIn.call.control.handles.hContext,
587 &opOut.call.control.handles.hContext))
589 if (!check_redir_handle(
"Control", &opIn.call.control.handles.hCard,
590 &opOut.call.control.handles.hCard))
592 if (!check_field(
"Control",
"dwControlCode", opIn.call.control.dwControlCode,
593 opOut.call.control.dwControlCode))
595 if (!check_field(
"Control",
"cbInBufferSize", opIn.call.control.cbInBufferSize,
596 opOut.call.control.cbInBufferSize))
598 if (!check_bytes(
"Control",
"pvInBuffer", opIn.call.control.pvInBuffer,
599 opOut.call.control.pvInBuffer, opIn.call.control.cbInBufferSize))
601 if (!check_field(
"Control",
"cbOutBufferSize", opIn.call.control.cbOutBufferSize,
602 opOut.call.control.cbOutBufferSize))
607 opIn.call.control.pvInBuffer =
nullptr;
608 smartcard_operation_free(&opIn, FALSE);
609 smartcard_operation_free(&opOut, FALSE);
613static BOOL test_get_attrib_encode_decode_request(
void)
615 BOOL success = FALSE;
618 opIn.ioControlCode = SCARD_IOCTL_GETATTRIB;
619 fill_redir_context(&opIn.call.getAttrib.handles.hContext, 0x1234);
620 fill_redir_handle(&opIn.call.getAttrib.handles.hCard, 0x5678);
621 opIn.call.getAttrib.dwAttrId = SCARD_ATTR_ATR_STRING;
622 opIn.call.getAttrib.fpbAttrIsNULL = 0;
623 opIn.call.getAttrib.cbAttrLen = 36;
625 if (!test_request_roundtrip(&opIn, &opOut))
627 if (!check_redir_context(
"GetAttrib", &opIn.call.getAttrib.handles.hContext,
628 &opOut.call.getAttrib.handles.hContext))
630 if (!check_redir_handle(
"GetAttrib", &opIn.call.getAttrib.handles.hCard,
631 &opOut.call.getAttrib.handles.hCard))
633 if (!check_field(
"GetAttrib",
"dwAttrId", opIn.call.getAttrib.dwAttrId,
634 opOut.call.getAttrib.dwAttrId))
636 if (!check_field(
"GetAttrib",
"cbAttrLen", opIn.call.getAttrib.cbAttrLen,
637 opOut.call.getAttrib.cbAttrLen))
642 smartcard_operation_free(&opIn, FALSE);
643 smartcard_operation_free(&opOut, FALSE);
647static BOOL test_set_attrib_encode_decode_request(
void)
649 BOOL success = FALSE;
650 BYTE attrBuf[] = { 0x3B, 0x00 };
653 opIn.ioControlCode = SCARD_IOCTL_SETATTRIB;
654 fill_redir_context(&opIn.call.setAttrib.handles.hContext, 0x1234);
655 fill_redir_handle(&opIn.call.setAttrib.handles.hCard, 0x5678);
656 opIn.call.setAttrib.dwAttrId = SCARD_ATTR_ATR_STRING;
657 opIn.call.setAttrib.cbAttrLen =
sizeof(attrBuf);
658 opIn.call.setAttrib.pbAttr = attrBuf;
660 if (!test_request_roundtrip(&opIn, &opOut))
662 if (!check_redir_context(
"SetAttrib", &opIn.call.setAttrib.handles.hContext,
663 &opOut.call.setAttrib.handles.hContext))
665 if (!check_redir_handle(
"SetAttrib", &opIn.call.setAttrib.handles.hCard,
666 &opOut.call.setAttrib.handles.hCard))
668 if (!check_field(
"SetAttrib",
"dwAttrId", opIn.call.setAttrib.dwAttrId,
669 opOut.call.setAttrib.dwAttrId))
671 if (!check_field(
"SetAttrib",
"cbAttrLen", opIn.call.setAttrib.cbAttrLen,
672 opOut.call.setAttrib.cbAttrLen))
674 if (!check_bytes(
"SetAttrib",
"pbAttr", opIn.call.setAttrib.pbAttr, opOut.call.setAttrib.pbAttr,
675 opIn.call.setAttrib.cbAttrLen))
680 opIn.call.setAttrib.pbAttr =
nullptr;
681 smartcard_operation_free(&opIn, FALSE);
682 smartcard_operation_free(&opOut, FALSE);
686static BOOL test_encode_decode_requests(
void)
690 if (!test_establish_context_encode_decode_request())
692 if (!test_release_context_encode_decode_request())
694 if (!test_is_valid_context_encode_decode_request())
696 if (!test_list_reader_groups_a_encode_decode_request())
698 if (!test_list_reader_groups_w_encode_decode_request())
700 if (!test_list_readers_a_encode_decode_request())
702 if (!test_list_readers_w_encode_decode_request())
704 if (!test_cancel_encode_decode_request())
706 if (!test_connect_a_encode_decode_request())
708 if (!test_connect_w_encode_decode_request())
710 if (!test_reconnect_encode_decode_request())
712 if (!test_disconnect_encode_decode_request())
714 if (!test_begin_transaction_encode_decode_request())
716 if (!test_end_transaction_encode_decode_request())
718 if (!test_status_a_encode_decode_request())
720 if (!test_status_w_encode_decode_request())
722 if (!test_transmit_encode_decode_request())
724 if (!test_control_encode_decode_request())
726 if (!test_get_attrib_encode_decode_request())
728 if (!test_set_attrib_encode_decode_request())
734static LONG encode_response_payload(
wStream* s, UINT32 ioControlCode,
737 switch (ioControlCode)
739 case SCARD_IOCTL_ESTABLISHCONTEXT:
740 return smartcard_pack_establish_context_return(s, &opIn->
ret.establishContext);
741 case SCARD_IOCTL_RECONNECT:
742 return smartcard_pack_reconnect_return(s, &opIn->
ret.reconnect);
743 case SCARD_IOCTL_CONNECTA:
744 case SCARD_IOCTL_CONNECTW:
745 return smartcard_pack_connect_return(s, &opIn->
ret.connect);
746 case SCARD_IOCTL_CONTROL:
747 return smartcard_pack_control_return(s, &opIn->
ret.control);
748 case SCARD_IOCTL_TRANSMIT:
749 return smartcard_pack_transmit_return(s, &opIn->
ret.transmit);
750 case SCARD_IOCTL_GETATTRIB:
751 return smartcard_pack_get_attrib_return(s, &opIn->
ret.getAttrib, 0,
752 opIn->
ret.getAttrib.cbAttrLen);
753 case SCARD_IOCTL_GETSTATUSCHANGEA:
754 return smartcard_pack_get_status_change_return(s, &opIn->
ret.getStatusChange, FALSE);
755 case SCARD_IOCTL_GETSTATUSCHANGEW:
756 return smartcard_pack_get_status_change_return(s, &opIn->
ret.getStatusChange, TRUE);
757 case SCARD_IOCTL_LISTREADERGROUPSA:
758 return smartcard_pack_list_reader_groups_return(s, &opIn->
ret.listReaders, FALSE);
759 case SCARD_IOCTL_LISTREADERGROUPSW:
760 return smartcard_pack_list_reader_groups_return(s, &opIn->
ret.listReaders, TRUE);
761 case SCARD_IOCTL_LISTREADERSA:
762 return smartcard_pack_list_readers_return(s, &opIn->
ret.listReaders, FALSE);
763 case SCARD_IOCTL_LISTREADERSW:
764 return smartcard_pack_list_readers_return(s, &opIn->
ret.listReaders, TRUE);
765 case SCARD_IOCTL_STATUSA:
766 return smartcard_pack_status_return(s, &opIn->
ret.status, FALSE);
767 case SCARD_IOCTL_STATUSW:
768 return smartcard_pack_status_return(s, &opIn->
ret.status, TRUE);
769 case SCARD_IOCTL_RELEASECONTEXT:
770 case SCARD_IOCTL_ISVALIDCONTEXT:
771 case SCARD_IOCTL_CANCEL:
772 case SCARD_IOCTL_DISCONNECT:
773 case SCARD_IOCTL_BEGINTRANSACTION:
774 case SCARD_IOCTL_ENDTRANSACTION:
775 case SCARD_IOCTL_SETATTRIB:
776 return SCARD_S_SUCCESS;
778 return SCARD_F_INTERNAL_ERROR;
784 const char* name = scard_get_ioctl_string(ioControlCode, TRUE);
786 wStream* payload = Stream_New(
nullptr, 4096);
789 (void)fprintf(stderr,
"%s: Stream_New for payload failed\n", name);
793 LONG rc = encode_response_payload(payload, ioControlCode, opIn);
794 if (rc != SCARD_S_SUCCESS)
796 (void)fprintf(stderr,
"%s: encode_response_payload failed with 0x%08" PRIX32
"\n", name,
798 Stream_Release(payload);
801 Stream_SealLength(payload);
803 wStream* s = Stream_New(
nullptr, 256 + Stream_Length(payload));
806 (void)fprintf(stderr,
"%s: Stream_New for response failed\n", name);
807 Stream_Release(payload);
812 const size_t headerPos = Stream_GetPosition(s);
813 Stream_Seek(s, SMARTCARD_COMMON_TYPE_HEADER_LENGTH +
814 SMARTCARD_PRIVATE_TYPE_HEADER_LENGTH);
816 Stream_Write(s, Stream_Buffer(payload), Stream_Length(payload));
817 Stream_Release(payload);
819 const size_t payloadSize = Stream_GetPosition(s) - headerPos;
820 const size_t objectBufferLength =
821 payloadSize - SMARTCARD_COMMON_TYPE_HEADER_LENGTH - SMARTCARD_PRIVATE_TYPE_HEADER_LENGTH;
823 WINPR_UNUSED(smartcard_pack_write_size_align(s, payloadSize, 8));
825 const size_t endPos = Stream_GetPosition(s);
826 const size_t outputBufferLength = endPos - headerPos;
828 Stream_SetPosition(s, 0);
829 UINT32 outputLength = WINPR_ASSERTING_INT_CAST(UINT32, outputBufferLength);
830 UINT32 objectLength = WINPR_ASSERTING_INT_CAST(UINT32, objectBufferLength);
831 Stream_Write_UINT32(s, outputLength);
832 smartcard_pack_common_type_header(s);
833 smartcard_pack_private_type_header(s, objectLength);
835 Stream_SetPosition(s, endPos);
836 Stream_SealLength(s);
837 if (!Stream_SetPosition(s, 0))
839 (void)fprintf(stderr,
"%s: Stream_SetPosition failed\n", name);
848 const UINT32 ioControlCode = opIn->ioControlCode;
849 const char* name = scard_get_ioctl_string(ioControlCode, TRUE);
851 wStream* s = build_device_control_response(ioControlCode, opIn);
856 LONG status = smartcard_irp_device_control_decode_response(s, ioControlCode, opOut);
859 if (status != SCARD_S_SUCCESS)
861 (void)fprintf(stderr,
"%s: decode_response failed with 0x%08" PRIX32
"\n", name,
869static BOOL test_establish_context_decode_response(
void)
871 BOOL success = FALSE;
874 opIn.ioControlCode = SCARD_IOCTL_ESTABLISHCONTEXT;
875 fill_redir_context(&opIn.
ret.establishContext.hContext, 0xABCD);
878 if (!test_response_roundtrip(&opIn, &opOut))
880 if (!check_redir_context(
"EstablishContext", &opIn.
ret.establishContext.hContext,
881 &opOut.
ret.establishContext.hContext))
883 if (!check_field(
"EstablishContext",
"returnCode", (UINT32)opIn.
returnCode,
889 smartcard_operation_free(&opIn, FALSE);
890 smartcard_operation_free(&opOut, FALSE);
894static BOOL test_release_context_decode_response(
void)
896 BOOL success = FALSE;
899 opIn.ioControlCode = SCARD_IOCTL_RELEASECONTEXT;
902 if (!test_response_roundtrip(&opIn, &opOut))
904 if (!check_field(
"ReleaseContext",
"returnCode", (UINT32)opIn.
returnCode,
910 smartcard_operation_free(&opIn, FALSE);
911 smartcard_operation_free(&opOut, FALSE);
915static BOOL test_is_valid_context_decode_response(
void)
917 BOOL success = FALSE;
920 opIn.ioControlCode = SCARD_IOCTL_ISVALIDCONTEXT;
923 if (!test_response_roundtrip(&opIn, &opOut))
925 if (!check_field(
"IsValidContext",
"returnCode", (UINT32)opIn.
returnCode,
931 smartcard_operation_free(&opIn, FALSE);
932 smartcard_operation_free(&opOut, FALSE);
936static BOOL test_list_reader_groups_decode_response_impl(UINT32 ioControlCode)
938 BOOL success = FALSE;
939 const char* n = scard_get_ioctl_string(ioControlCode, TRUE);
942 opIn.ioControlCode = ioControlCode;
944 BYTE groups[] = {
'G',
'r',
'p',
'\0',
'\0' };
945 opIn.
ret.listReaders.cBytes =
sizeof(groups);
946 opIn.
ret.listReaders.msz = groups;
948 if (!test_response_roundtrip(&opIn, &opOut))
952 if (!check_field(n,
"cBytes", opIn.
ret.listReaders.cBytes, opOut.
ret.listReaders.cBytes))
954 if (!check_bytes(n,
"msz", opIn.
ret.listReaders.msz, opOut.
ret.listReaders.msz,
955 opIn.
ret.listReaders.cBytes))
960 opIn.
ret.listReaders.msz =
nullptr;
961 smartcard_operation_free(&opIn, FALSE);
962 smartcard_operation_free(&opOut, FALSE);
966static BOOL test_list_reader_groups_a_decode_response(
void)
968 return test_list_reader_groups_decode_response_impl(SCARD_IOCTL_LISTREADERGROUPSA);
971static BOOL test_list_reader_groups_w_decode_response(
void)
973 return test_list_reader_groups_decode_response_impl(SCARD_IOCTL_LISTREADERGROUPSW);
976static BOOL test_list_readers_decode_response_impl(UINT32 ioControlCode)
978 BOOL success = FALSE;
979 const char* n = scard_get_ioctl_string(ioControlCode, TRUE);
982 opIn.ioControlCode = ioControlCode;
984 BYTE readers[] = {
'R',
'd',
'r',
'\0',
'\0' };
985 opIn.
ret.listReaders.cBytes =
sizeof(readers);
986 opIn.
ret.listReaders.msz = readers;
988 if (!test_response_roundtrip(&opIn, &opOut))
992 if (!check_field(n,
"cBytes", opIn.
ret.listReaders.cBytes, opOut.
ret.listReaders.cBytes))
994 if (!check_bytes(n,
"msz", opIn.
ret.listReaders.msz, opOut.
ret.listReaders.msz,
995 opIn.
ret.listReaders.cBytes))
1000 opIn.
ret.listReaders.msz =
nullptr;
1001 smartcard_operation_free(&opIn, FALSE);
1002 smartcard_operation_free(&opOut, FALSE);
1006static BOOL test_list_readers_a_decode_response(
void)
1008 return test_list_readers_decode_response_impl(SCARD_IOCTL_LISTREADERSA);
1011static BOOL test_list_readers_w_decode_response(
void)
1013 return test_list_readers_decode_response_impl(SCARD_IOCTL_LISTREADERSW);
1016static BOOL test_get_status_change_decode_response_impl(UINT32 ioControlCode)
1018 BOOL success = FALSE;
1019 const char* n = scard_get_ioctl_string(ioControlCode, TRUE);
1022 opIn.ioControlCode = ioControlCode;
1025 state.dwCurrentState = SCARD_STATE_PRESENT;
1026 state.dwEventState = SCARD_STATE_CHANGED;
1028 state.rgbAtr[0] = 0x3B;
1029 state.rgbAtr[1] = 0x00;
1030 opIn.
ret.getStatusChange.cReaders = 1;
1031 opIn.
ret.getStatusChange.rgReaderStates = &state;
1033 if (!test_response_roundtrip(&opIn, &opOut))
1037 if (!check_field(n,
"cReaders", opIn.
ret.getStatusChange.cReaders,
1038 opOut.
ret.getStatusChange.cReaders))
1040 if (!check_field(n,
"dwCurrentState", state.dwCurrentState,
1041 opOut.
ret.getStatusChange.rgReaderStates[0].dwCurrentState))
1043 if (!check_field(n,
"dwEventState", state.dwEventState,
1044 opOut.
ret.getStatusChange.rgReaderStates[0].dwEventState))
1046 if (!check_field(n,
"cbAtr", state.cbAtr, opOut.
ret.getStatusChange.rgReaderStates[0].cbAtr))
1048 if (!check_bytes(n,
"rgbAtr", state.rgbAtr, opOut.
ret.getStatusChange.rgReaderStates[0].rgbAtr,
1049 sizeof(state.rgbAtr)))
1054 opIn.
ret.getStatusChange.rgReaderStates =
nullptr;
1055 smartcard_operation_free(&opIn, FALSE);
1056 smartcard_operation_free(&opOut, FALSE);
1060static BOOL test_get_status_change_a_decode_response(
void)
1062 return test_get_status_change_decode_response_impl(SCARD_IOCTL_GETSTATUSCHANGEA);
1065static BOOL test_get_status_change_w_decode_response(
void)
1067 return test_get_status_change_decode_response_impl(SCARD_IOCTL_GETSTATUSCHANGEW);
1070static BOOL test_cancel_decode_response(
void)
1072 BOOL success = FALSE;
1075 opIn.ioControlCode = SCARD_IOCTL_CANCEL;
1078 if (!test_response_roundtrip(&opIn, &opOut))
1085 smartcard_operation_free(&opIn, FALSE);
1086 smartcard_operation_free(&opOut, FALSE);
1090static BOOL test_connect_decode_response_impl(UINT32 ioControlCode)
1092 BOOL success = FALSE;
1093 const char* n = scard_get_ioctl_string(ioControlCode, TRUE);
1096 opIn.ioControlCode = ioControlCode;
1098 fill_redir_context(&opIn.
ret.connect.hContext, 0x1234);
1099 fill_redir_handle(&opIn.
ret.connect.hCard, 0x5678);
1100 opIn.
ret.connect.dwActiveProtocol = SCARD_PROTOCOL_T0;
1102 if (!test_response_roundtrip(&opIn, &opOut))
1106 if (!check_redir_context(n, &opIn.
ret.connect.hContext, &opOut.
ret.connect.hContext))
1108 if (!check_redir_handle(n, &opIn.
ret.connect.hCard, &opOut.
ret.connect.hCard))
1110 if (!check_field(n,
"dwActiveProtocol", opIn.
ret.connect.dwActiveProtocol,
1111 opOut.
ret.connect.dwActiveProtocol))
1116 smartcard_operation_free(&opIn, FALSE);
1117 smartcard_operation_free(&opOut, FALSE);
1121static BOOL test_connect_a_decode_response(
void)
1123 return test_connect_decode_response_impl(SCARD_IOCTL_CONNECTA);
1126static BOOL test_connect_w_decode_response(
void)
1128 return test_connect_decode_response_impl(SCARD_IOCTL_CONNECTW);
1131static BOOL test_reconnect_decode_response(
void)
1133 BOOL success = FALSE;
1136 opIn.ioControlCode = SCARD_IOCTL_RECONNECT;
1138 opIn.
ret.reconnect.dwActiveProtocol = SCARD_PROTOCOL_T1;
1140 if (!test_response_roundtrip(&opIn, &opOut))
1142 if (!check_field(
"Reconnect",
"returnCode", (UINT32)opIn.
returnCode, (UINT32)opOut.
returnCode))
1144 if (!check_field(
"Reconnect",
"dwActiveProtocol", opIn.
ret.reconnect.dwActiveProtocol,
1145 opOut.
ret.reconnect.dwActiveProtocol))
1150 smartcard_operation_free(&opIn, FALSE);
1151 smartcard_operation_free(&opOut, FALSE);
1155static BOOL test_disconnect_decode_response(
void)
1157 BOOL success = FALSE;
1160 opIn.ioControlCode = SCARD_IOCTL_DISCONNECT;
1163 if (!test_response_roundtrip(&opIn, &opOut))
1165 if (!check_field(
"Disconnect",
"returnCode", (UINT32)opIn.
returnCode, (UINT32)opOut.
returnCode))
1170 smartcard_operation_free(&opIn, FALSE);
1171 smartcard_operation_free(&opOut, FALSE);
1175static BOOL test_begin_transaction_decode_response(
void)
1177 BOOL success = FALSE;
1180 opIn.ioControlCode = SCARD_IOCTL_BEGINTRANSACTION;
1183 if (!test_response_roundtrip(&opIn, &opOut))
1185 if (!check_field(
"BeginTransaction",
"returnCode", (UINT32)opIn.
returnCode,
1191 smartcard_operation_free(&opIn, FALSE);
1192 smartcard_operation_free(&opOut, FALSE);
1196static BOOL test_end_transaction_decode_response(
void)
1198 BOOL success = FALSE;
1201 opIn.ioControlCode = SCARD_IOCTL_ENDTRANSACTION;
1204 if (!test_response_roundtrip(&opIn, &opOut))
1206 if (!check_field(
"EndTransaction",
"returnCode", (UINT32)opIn.
returnCode,
1212 smartcard_operation_free(&opIn, FALSE);
1213 smartcard_operation_free(&opOut, FALSE);
1217static BOOL test_status_decode_response_impl(UINT32 ioControlCode)
1219 BOOL success = FALSE;
1220 const char* n = scard_get_ioctl_string(ioControlCode, TRUE);
1223 opIn.ioControlCode = ioControlCode;
1225 BYTE readerName[] = {
'R',
'd',
'r',
'\0' };
1226 opIn.
ret.status.cBytes =
sizeof(readerName);
1227 opIn.
ret.status.mszReaderNames = readerName;
1228 opIn.
ret.status.dwState = SCARD_SPECIFIC;
1229 opIn.
ret.status.dwProtocol = SCARD_PROTOCOL_T1;
1230 memset(opIn.
ret.status.pbAtr, 0x3B,
sizeof(opIn.
ret.status.pbAtr));
1231 opIn.
ret.status.cbAtrLen = 2;
1233 if (!test_response_roundtrip(&opIn, &opOut))
1237 if (!check_field(n,
"dwState", opIn.
ret.status.dwState, opOut.
ret.status.dwState))
1239 if (!check_field(n,
"dwProtocol", opIn.
ret.status.dwProtocol, opOut.
ret.status.dwProtocol))
1241 if (!check_field(n,
"cbAtrLen", opIn.
ret.status.cbAtrLen, opOut.
ret.status.cbAtrLen))
1243 if (!check_bytes(n,
"pbAtr", opIn.
ret.status.pbAtr, opOut.
ret.status.pbAtr,
1244 sizeof(opIn.
ret.status.pbAtr)))
1246 if (!check_field(n,
"cBytes", opIn.
ret.status.cBytes, opOut.
ret.status.cBytes))
1248 if (!check_bytes(n,
"mszReaderNames", opIn.
ret.status.mszReaderNames,
1249 opOut.
ret.status.mszReaderNames, opIn.
ret.status.cBytes))
1254 opIn.
ret.status.mszReaderNames =
nullptr;
1255 smartcard_operation_free(&opIn, FALSE);
1256 smartcard_operation_free(&opOut, FALSE);
1260static BOOL test_status_a_decode_response(
void)
1262 return test_status_decode_response_impl(SCARD_IOCTL_STATUSA);
1265static BOOL test_status_w_decode_response(
void)
1267 return test_status_decode_response_impl(SCARD_IOCTL_STATUSW);
1270static BOOL test_transmit_decode_response(
void)
1272 BOOL success = FALSE;
1275 opIn.ioControlCode = SCARD_IOCTL_TRANSMIT;
1277 BYTE recvBuf[] = { 0x90, 0x00 };
1278 opIn.
ret.transmit.cbRecvLength =
sizeof(recvBuf);
1279 opIn.
ret.transmit.pbRecvBuffer = recvBuf;
1280 opIn.
ret.transmit.pioRecvPci =
nullptr;
1282 if (!test_response_roundtrip(&opIn, &opOut))
1286 if (!check_field(
"Transmit",
"cbRecvLength", opIn.
ret.transmit.cbRecvLength,
1287 opOut.
ret.transmit.cbRecvLength))
1289 if (!check_bytes(
"Transmit",
"pbRecvBuffer", opIn.
ret.transmit.pbRecvBuffer,
1290 opOut.
ret.transmit.pbRecvBuffer, opIn.
ret.transmit.cbRecvLength))
1295 opIn.
ret.transmit.pbRecvBuffer =
nullptr;
1296 smartcard_operation_free(&opIn, FALSE);
1297 smartcard_operation_free(&opOut, FALSE);
1301static BOOL test_control_decode_response(
void)
1303 BOOL success = FALSE;
1306 opIn.ioControlCode = SCARD_IOCTL_CONTROL;
1308 BYTE outBuf[] = { 0xAA, 0xBB, 0xCC };
1309 opIn.
ret.control.cbOutBufferSize =
sizeof(outBuf);
1310 opIn.
ret.control.pvOutBuffer = outBuf;
1312 if (!test_response_roundtrip(&opIn, &opOut))
1316 if (!check_field(
"Control",
"cbOutBufferSize", opIn.
ret.control.cbOutBufferSize,
1317 opOut.
ret.control.cbOutBufferSize))
1319 if (!check_bytes(
"Control",
"pvOutBuffer", opIn.
ret.control.pvOutBuffer,
1320 opOut.
ret.control.pvOutBuffer, opIn.
ret.control.cbOutBufferSize))
1325 opIn.
ret.control.pvOutBuffer =
nullptr;
1326 smartcard_operation_free(&opIn, FALSE);
1327 smartcard_operation_free(&opOut, FALSE);
1331static BOOL test_get_attrib_decode_response(
void)
1333 BOOL success = FALSE;
1336 opIn.ioControlCode = SCARD_IOCTL_GETATTRIB;
1338 BYTE attr[] = { 0x3B, 0x90, 0x00 };
1339 opIn.
ret.getAttrib.cbAttrLen =
sizeof(attr);
1340 opIn.
ret.getAttrib.pbAttr = attr;
1342 if (!test_response_roundtrip(&opIn, &opOut))
1344 if (!check_field(
"GetAttrib",
"returnCode", (UINT32)opIn.
returnCode, (UINT32)opOut.
returnCode))
1346 if (!check_field(
"GetAttrib",
"cbAttrLen", opIn.
ret.getAttrib.cbAttrLen,
1347 opOut.
ret.getAttrib.cbAttrLen))
1349 if (!check_bytes(
"GetAttrib",
"pbAttr", opIn.
ret.getAttrib.pbAttr, opOut.
ret.getAttrib.pbAttr,
1350 opIn.
ret.getAttrib.cbAttrLen))
1355 opIn.
ret.getAttrib.pbAttr =
nullptr;
1356 smartcard_operation_free(&opIn, FALSE);
1357 smartcard_operation_free(&opOut, FALSE);
1361static BOOL test_set_attrib_decode_response(
void)
1363 BOOL success = FALSE;
1366 opIn.ioControlCode = SCARD_IOCTL_SETATTRIB;
1369 if (!test_response_roundtrip(&opIn, &opOut))
1371 if (!check_field(
"SetAttrib",
"returnCode", (UINT32)opIn.
returnCode, (UINT32)opOut.
returnCode))
1376 smartcard_operation_free(&opIn, FALSE);
1377 smartcard_operation_free(&opOut, FALSE);
1381static BOOL test_decode_responses(
void)
1383 BOOL success = TRUE;
1385 if (!test_establish_context_decode_response())
1387 if (!test_release_context_decode_response())
1389 if (!test_is_valid_context_decode_response())
1391 if (!test_list_reader_groups_a_decode_response())
1393 if (!test_list_reader_groups_w_decode_response())
1395 if (!test_list_readers_a_decode_response())
1397 if (!test_list_readers_w_decode_response())
1399 if (!test_get_status_change_a_decode_response())
1401 if (!test_get_status_change_w_decode_response())
1403 if (!test_cancel_decode_response())
1405 if (!test_connect_a_decode_response())
1407 if (!test_connect_w_decode_response())
1409 if (!test_reconnect_decode_response())
1411 if (!test_disconnect_decode_response())
1413 if (!test_begin_transaction_decode_response())
1415 if (!test_end_transaction_decode_response())
1417 if (!test_status_a_decode_response())
1419 if (!test_status_w_decode_response())
1421 if (!test_transmit_decode_response())
1423 if (!test_control_decode_response())
1425 if (!test_get_attrib_decode_response())
1427 if (!test_set_attrib_decode_response())
1433int TestSmartcardOperations(
int argc,
char* argv[])
1438 if (!test_encode_decode_requests())
1441 if (!test_decode_responses())
union SMARTCARD_OPERATION::@30 ret