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);
41WINPR_ATTR_MALLOC(Stream_Free, 1)
42static
wStream* build_device_control_request(UINT32 ioControlCode, const
void* inputBuffer,
43 size_t inputBufferLength)
45 const char* name = scard_get_ioctl_string(ioControlCode, TRUE);
48 const size_t totalLength = RDPDR_DEVICE_IO_CONTROL_REQ_HDR_LENGTH + inputBufferLength;
50 wStream* s = Stream_New(
nullptr, totalLength);
53 (void)fprintf(stderr,
"build_device_control_request(%s): Stream_New(%" PRIuz
") failed\n",
58 UINT32 inputLength = WINPR_ASSERTING_INT_CAST(UINT32, inputBufferLength);
59 Stream_Write_UINT32(s, 2048);
60 Stream_Write_UINT32(s, inputLength);
61 Stream_Write_UINT32(s, ioControlCode);
64 if (inputBufferLength > 0)
65 Stream_Write(s, inputBuffer, inputBufferLength);
68 if (!Stream_SetPosition(s, 0))
70 (void)fprintf(stderr,
"build_device_control_request(%s): Stream_SetPosition failed\n",
82 const UINT32 ioControlCode = opIn->ioControlCode;
83 const char* name = scard_get_ioctl_string(ioControlCode, TRUE);
86 wStream* sEnc = Stream_New(
nullptr, 4096);
89 (void)fprintf(stderr,
"%s: Stream_New for encode failed\n", name);
93 LONG status = smartcard_irp_device_control_encode_request(sEnc, opIn);
94 if (status != SCARD_S_SUCCESS)
96 (void)fprintf(stderr,
"%s: encode_request failed with 0x%08" PRIX32
"\n", name,
103 build_device_control_request(ioControlCode, Stream_Buffer(sEnc), Stream_Length(sEnc));
104 Stream_Release(sEnc);
110 status = smartcard_irp_device_control_decode_request(sDec, 1, 0, opOut);
111 Stream_Release(sDec);
112 if (status != SCARD_S_SUCCESS)
114 (void)fprintf(stderr,
"%s: decode_request failed with 0x%08" PRIX32
"\n", name,
119 if (opOut->ioControlCode != ioControlCode)
121 (void)fprintf(stderr,
"%s: ioControlCode mismatch: 0x%08" PRIX32
" != 0x%08" PRIX32
"\n",
122 name, opOut->ioControlCode, ioControlCode);
123 smartcard_operation_free(opOut, FALSE);
131static inline BOOL check_field(
const char* name,
const char* field, UINT32 a, UINT32 b)
135 (void)fprintf(stderr,
"%s: %s mismatch: 0x%" PRIX32
" != 0x%" PRIX32
"\n", name, field, a,
143static inline BOOL check_bytes(
const char* name,
const char* field,
const void* a,
const void* b,
146 if (!a || !b || memcmp(a, b, len) != 0)
148 (void)fprintf(stderr,
"%s: %s mismatch (%" PRIuz
" bytes)\n", name, field, len);
158 return check_field(name,
"hContext.cbContext", a->cbContext, b->cbContext) &&
159 check_bytes(name,
"hContext.pbContext", a->pbContext, b->pbContext, a->cbContext);
163static inline BOOL check_redir_handle(
const char* name,
const REDIR_SCARDHANDLE* a,
166 return check_field(name,
"hCard.cbHandle", a->cbHandle, b->cbHandle) &&
167 check_bytes(name,
"hCard.pbHandle", a->pbHandle, b->pbHandle, a->cbHandle);
171static BOOL test_establish_context_encode_decode_request(
void)
173 BOOL success = FALSE;
176 opIn.ioControlCode = SCARD_IOCTL_ESTABLISHCONTEXT;
177 opIn.call.establishContext.dwScope = SCARD_SCOPE_SYSTEM;
179 if (!test_request_roundtrip(&opIn, &opOut))
181 if (!check_field(
"EstablishContext",
"dwScope", opIn.call.establishContext.dwScope,
182 opOut.call.establishContext.dwScope))
187 smartcard_operation_free(&opIn, FALSE);
188 smartcard_operation_free(&opOut, FALSE);
193static BOOL test_release_context_encode_decode_request(
void)
195 BOOL success = FALSE;
198 opIn.ioControlCode = SCARD_IOCTL_RELEASECONTEXT;
199 fill_redir_context(&opIn.call.context.handles.hContext, 0x1234);
201 if (!test_request_roundtrip(&opIn, &opOut))
203 if (!check_redir_context(
"ReleaseContext", &opIn.call.context.handles.hContext,
204 &opOut.call.context.handles.hContext))
209 smartcard_operation_free(&opIn, FALSE);
210 smartcard_operation_free(&opOut, FALSE);
215static BOOL test_is_valid_context_encode_decode_request(
void)
217 BOOL success = FALSE;
220 opIn.ioControlCode = SCARD_IOCTL_ISVALIDCONTEXT;
221 fill_redir_context(&opIn.call.context.handles.hContext, 0x5678);
223 if (!test_request_roundtrip(&opIn, &opOut))
225 if (!check_redir_context(
"IsValidContext", &opIn.call.context.handles.hContext,
226 &opOut.call.context.handles.hContext))
231 smartcard_operation_free(&opIn, FALSE);
232 smartcard_operation_free(&opOut, FALSE);
237static BOOL test_list_reader_groups_encode_decode_request_impl(UINT32 ioControlCode)
239 BOOL success = FALSE;
240 const char* n = scard_get_ioctl_string(ioControlCode, TRUE);
245 opIn.ioControlCode = ioControlCode;
246 fill_redir_context(&opIn.call.listReaderGroups.handles.hContext, 0x1234);
247 opIn.call.listReaderGroups.fmszGroupsIsNULL = 0;
248 opIn.call.listReaderGroups.cchGroups = SCARD_AUTOALLOCATE;
250 if (!test_request_roundtrip(&opIn, &opOut))
252 if (!check_redir_context(n, &opIn.call.listReaderGroups.handles.hContext,
253 &opOut.call.listReaderGroups.handles.hContext))
255 if (!check_field(n,
"fmszGroupsIsNULL", opIn.call.listReaderGroups.fmszGroupsIsNULL,
256 opOut.call.listReaderGroups.fmszGroupsIsNULL))
258 if (!check_field(n,
"cchGroups", opIn.call.listReaderGroups.cchGroups,
259 opOut.call.listReaderGroups.cchGroups))
264 smartcard_operation_free(&opIn, FALSE);
265 smartcard_operation_free(&opOut, FALSE);
270static BOOL test_list_reader_groups_a_encode_decode_request(
void)
272 return test_list_reader_groups_encode_decode_request_impl(SCARD_IOCTL_LISTREADERGROUPSA);
276static BOOL test_list_reader_groups_w_encode_decode_request(
void)
278 return test_list_reader_groups_encode_decode_request_impl(SCARD_IOCTL_LISTREADERGROUPSW);
282static BOOL test_list_readers_encode_decode_request_impl(UINT32 ioControlCode)
284 BOOL success = FALSE;
285 const char* n = scard_get_ioctl_string(ioControlCode, TRUE);
290 opIn.ioControlCode = ioControlCode;
291 fill_redir_context(&opIn.call.listReaders.handles.hContext, 0x1234);
292 opIn.call.listReaders.fmszReadersIsNULL = 0;
293 opIn.call.listReaders.cchReaders = SCARD_AUTOALLOCATE;
295 if (!test_request_roundtrip(&opIn, &opOut))
297 if (!check_redir_context(n, &opIn.call.listReaders.handles.hContext,
298 &opOut.call.listReaders.handles.hContext))
300 if (!check_field(n,
"cchReaders", opIn.call.listReaders.cchReaders,
301 opOut.call.listReaders.cchReaders))
306 smartcard_operation_free(&opIn, FALSE);
307 smartcard_operation_free(&opOut, FALSE);
312static BOOL test_list_readers_a_encode_decode_request(
void)
314 return test_list_readers_encode_decode_request_impl(SCARD_IOCTL_LISTREADERSA);
318static BOOL test_list_readers_w_encode_decode_request(
void)
320 return test_list_readers_encode_decode_request_impl(SCARD_IOCTL_LISTREADERSW);
324static BOOL test_cancel_encode_decode_request(
void)
326 BOOL success = FALSE;
329 opIn.ioControlCode = SCARD_IOCTL_CANCEL;
330 fill_redir_context(&opIn.call.context.handles.hContext, 0xABCD);
332 if (!test_request_roundtrip(&opIn, &opOut))
334 if (!check_redir_context(
"Cancel", &opIn.call.context.handles.hContext,
335 &opOut.call.context.handles.hContext))
340 smartcard_operation_free(&opIn, FALSE);
341 smartcard_operation_free(&opOut, FALSE);
346static BOOL test_connect_a_encode_decode_request(
void)
348 BOOL success = FALSE;
351 opIn.ioControlCode = SCARD_IOCTL_CONNECTA;
352 fill_redir_context(&opIn.call.connectA.Common.handles.hContext, 0x1234);
353 opIn.call.connectA.Common.dwShareMode = SCARD_SHARE_SHARED;
354 opIn.call.connectA.Common.dwPreferredProtocols = SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1;
355 opIn.call.connectA.szReader = _strdup(
"TestReader");
357 if (!test_request_roundtrip(&opIn, &opOut))
359 if (!check_redir_context(
"ConnectA", &opIn.call.connectA.Common.handles.hContext,
360 &opOut.call.connectA.Common.handles.hContext))
362 if (!check_field(
"ConnectA",
"dwShareMode", opIn.call.connectA.Common.dwShareMode,
363 opOut.call.connectA.Common.dwShareMode))
365 if (!check_field(
"ConnectA",
"dwPreferredProtocols",
366 opIn.call.connectA.Common.dwPreferredProtocols,
367 opOut.call.connectA.Common.dwPreferredProtocols))
369 if (!check_bytes(
"ConnectA",
"szReader", opIn.call.connectA.szReader,
370 opOut.call.connectA.szReader, strlen(opIn.call.connectA.szReader) + 1))
375 smartcard_operation_free(&opIn, FALSE);
376 smartcard_operation_free(&opOut, FALSE);
381static BOOL test_connect_w_encode_decode_request(
void)
383 BOOL success = FALSE;
386 opIn.ioControlCode = SCARD_IOCTL_CONNECTW;
387 fill_redir_context(&opIn.call.connectW.Common.handles.hContext, 0x1234);
388 opIn.call.connectW.Common.dwShareMode = SCARD_SHARE_SHARED;
389 opIn.call.connectW.Common.dwPreferredProtocols = SCARD_PROTOCOL_T0;
390 opIn.call.connectW.szReader = ConvertUtf8ToWCharAlloc(
"TestReader",
nullptr);
392 if (!test_request_roundtrip(&opIn, &opOut))
394 if (!check_redir_context(
"ConnectW", &opIn.call.connectW.Common.handles.hContext,
395 &opOut.call.connectW.Common.handles.hContext))
397 if (!check_field(
"ConnectW",
"dwShareMode", opIn.call.connectW.Common.dwShareMode,
398 opOut.call.connectW.Common.dwShareMode))
400 if (!check_bytes(
"ConnectW",
"szReader", opIn.call.connectW.szReader,
401 opOut.call.connectW.szReader,
402 (_wcslen(opIn.call.connectW.szReader) + 1) *
sizeof(WCHAR)))
407 smartcard_operation_free(&opIn, FALSE);
408 smartcard_operation_free(&opOut, FALSE);
413static BOOL test_reconnect_encode_decode_request(
void)
415 BOOL success = FALSE;
416 const char* n =
"Reconnect";
419 opIn.ioControlCode = SCARD_IOCTL_RECONNECT;
420 fill_redir_context(&opIn.call.reconnect.handles.hContext, 0x1234);
421 fill_redir_handle(&opIn.call.reconnect.handles.hCard, 0x5678);
422 opIn.call.reconnect.dwShareMode = SCARD_SHARE_EXCLUSIVE;
423 opIn.call.reconnect.dwPreferredProtocols = SCARD_PROTOCOL_T1;
424 opIn.call.reconnect.dwInitialization = SCARD_LEAVE_CARD;
426 if (!test_request_roundtrip(&opIn, &opOut))
428 if (!check_redir_context(n, &opIn.call.reconnect.handles.hContext,
429 &opOut.call.reconnect.handles.hContext))
431 if (!check_redir_handle(n, &opIn.call.reconnect.handles.hCard,
432 &opOut.call.reconnect.handles.hCard))
434 if (!check_field(n,
"dwShareMode", opIn.call.reconnect.dwShareMode,
435 opOut.call.reconnect.dwShareMode))
437 if (!check_field(n,
"dwPreferredProtocols", opIn.call.reconnect.dwPreferredProtocols,
438 opOut.call.reconnect.dwPreferredProtocols))
440 if (!check_field(n,
"dwInitialization", opIn.call.reconnect.dwInitialization,
441 opOut.call.reconnect.dwInitialization))
446 smartcard_operation_free(&opIn, FALSE);
447 smartcard_operation_free(&opOut, FALSE);
452static BOOL test_hcard_and_disposition_encode_decode_request_impl(UINT32 ioControlCode,
455 BOOL success = FALSE;
456 const char* n = scard_get_ioctl_string(ioControlCode, TRUE);
461 opIn.ioControlCode = ioControlCode;
462 fill_redir_context(&opIn.call.hCardAndDisposition.handles.hContext, 0x1234);
463 fill_redir_handle(&opIn.call.hCardAndDisposition.handles.hCard, 0x5678);
464 opIn.call.hCardAndDisposition.dwDisposition = dwDisposition;
466 if (!test_request_roundtrip(&opIn, &opOut))
468 if (!check_redir_context(n, &opIn.call.hCardAndDisposition.handles.hContext,
469 &opOut.call.hCardAndDisposition.handles.hContext))
471 if (!check_redir_handle(n, &opIn.call.hCardAndDisposition.handles.hCard,
472 &opOut.call.hCardAndDisposition.handles.hCard))
474 if (!check_field(n,
"dwDisposition", opIn.call.hCardAndDisposition.dwDisposition,
475 opOut.call.hCardAndDisposition.dwDisposition))
480 smartcard_operation_free(&opIn, FALSE);
481 smartcard_operation_free(&opOut, FALSE);
486static BOOL test_disconnect_encode_decode_request(
void)
488 return test_hcard_and_disposition_encode_decode_request_impl(SCARD_IOCTL_DISCONNECT,
493static BOOL test_begin_transaction_encode_decode_request(
void)
495 return test_hcard_and_disposition_encode_decode_request_impl(SCARD_IOCTL_BEGINTRANSACTION,
500static BOOL test_end_transaction_encode_decode_request(
void)
502 return test_hcard_and_disposition_encode_decode_request_impl(SCARD_IOCTL_ENDTRANSACTION,
507static BOOL test_status_encode_decode_request_impl(UINT32 ioControlCode)
509 BOOL success = FALSE;
510 const char* n = scard_get_ioctl_string(ioControlCode, TRUE);
515 opIn.ioControlCode = ioControlCode;
516 fill_redir_context(&opIn.call.status.handles.hContext, 0x1234);
517 fill_redir_handle(&opIn.call.status.handles.hCard, 0x5678);
518 opIn.call.status.fmszReaderNamesIsNULL = 0;
519 opIn.call.status.cchReaderLen = SCARD_AUTOALLOCATE;
520 opIn.call.status.cbAtrLen = 36;
522 if (!test_request_roundtrip(&opIn, &opOut))
524 if (!check_redir_context(n, &opIn.call.status.handles.hContext,
525 &opOut.call.status.handles.hContext))
527 if (!check_redir_handle(n, &opIn.call.status.handles.hCard, &opOut.call.status.handles.hCard))
529 if (!check_field(n,
"fmszReaderNamesIsNULL", opIn.call.status.fmszReaderNamesIsNULL,
530 opOut.call.status.fmszReaderNamesIsNULL))
532 if (!check_field(n,
"cchReaderLen", opIn.call.status.cchReaderLen,
533 opOut.call.status.cchReaderLen))
535 if (!check_field(n,
"cbAtrLen", opIn.call.status.cbAtrLen, opOut.call.status.cbAtrLen))
540 smartcard_operation_free(&opIn, FALSE);
541 smartcard_operation_free(&opOut, FALSE);
546static BOOL test_status_a_encode_decode_request(
void)
548 return test_status_encode_decode_request_impl(SCARD_IOCTL_STATUSA);
552static BOOL test_status_w_encode_decode_request(
void)
554 return test_status_encode_decode_request_impl(SCARD_IOCTL_STATUSW);
558static BOOL test_transmit_encode_decode_request(
void)
560 BOOL success = FALSE;
561 BYTE sendBuf[] = { 0x00, 0xA4, 0x04, 0x00, 0x07 };
562 SCARD_IO_REQUEST pioSendPci = { .dwProtocol = SCARD_PROTOCOL_T0, .cbPciLength = 8 };
564 opIn.ioControlCode = SCARD_IOCTL_TRANSMIT;
565 fill_redir_context(&opIn.call.transmit.handles.hContext, 0x1234);
566 fill_redir_handle(&opIn.call.transmit.handles.hCard, 0x5678);
567 opIn.call.transmit.pioSendPci = &pioSendPci;
568 opIn.call.transmit.cbSendLength =
sizeof(sendBuf);
569 opIn.call.transmit.pbSendBuffer = sendBuf;
570 opIn.call.transmit.fpbRecvBufferIsNULL = 0;
571 opIn.call.transmit.cbRecvLength = 256;
574 if (!test_request_roundtrip(&opIn, &opOut))
576 if (!check_redir_context(
"Transmit", &opIn.call.transmit.handles.hContext,
577 &opOut.call.transmit.handles.hContext))
579 if (!check_redir_handle(
"Transmit", &opIn.call.transmit.handles.hCard,
580 &opOut.call.transmit.handles.hCard))
582 if (!check_field(
"Transmit",
"cbSendLength", opIn.call.transmit.cbSendLength,
583 opOut.call.transmit.cbSendLength))
585 if (!check_bytes(
"Transmit",
"pbSendBuffer", opIn.call.transmit.pbSendBuffer,
586 opOut.call.transmit.pbSendBuffer, opIn.call.transmit.cbSendLength))
588 if (!check_field(
"Transmit",
"fpbRecvBufferIsNULL",
589 (UINT32)opIn.call.transmit.fpbRecvBufferIsNULL,
590 (UINT32)opOut.call.transmit.fpbRecvBufferIsNULL))
592 if (!check_field(
"Transmit",
"cbRecvLength", opIn.call.transmit.cbRecvLength,
593 opOut.call.transmit.cbRecvLength))
595 if (!check_field(
"Transmit",
"pioSendPci.dwProtocol", opIn.call.transmit.pioSendPci->dwProtocol,
596 opOut.call.transmit.pioSendPci->dwProtocol))
601 opIn.call.transmit.pioSendPci =
nullptr;
602 opIn.call.transmit.pbSendBuffer =
nullptr;
603 smartcard_operation_free(&opIn, FALSE);
604 smartcard_operation_free(&opOut, FALSE);
609static BOOL test_control_encode_decode_request(
void)
611 BOOL success = FALSE;
612 BYTE inBuf[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 };
614 opIn.ioControlCode = SCARD_IOCTL_CONTROL;
615 fill_redir_context(&opIn.call.control.handles.hContext, 0x1234);
616 fill_redir_handle(&opIn.call.control.handles.hCard, 0x5678);
617 opIn.call.control.dwControlCode = 0x42000001;
618 opIn.call.control.cbInBufferSize =
sizeof(inBuf);
619 opIn.call.control.pvInBuffer = inBuf;
620 opIn.call.control.fpvOutBufferIsNULL = 0;
621 opIn.call.control.cbOutBufferSize = 256;
624 if (!test_request_roundtrip(&opIn, &opOut))
626 if (!check_redir_context(
"Control", &opIn.call.control.handles.hContext,
627 &opOut.call.control.handles.hContext))
629 if (!check_redir_handle(
"Control", &opIn.call.control.handles.hCard,
630 &opOut.call.control.handles.hCard))
632 if (!check_field(
"Control",
"dwControlCode", opIn.call.control.dwControlCode,
633 opOut.call.control.dwControlCode))
635 if (!check_field(
"Control",
"cbInBufferSize", opIn.call.control.cbInBufferSize,
636 opOut.call.control.cbInBufferSize))
638 if (!check_bytes(
"Control",
"pvInBuffer", opIn.call.control.pvInBuffer,
639 opOut.call.control.pvInBuffer, opIn.call.control.cbInBufferSize))
641 if (!check_field(
"Control",
"cbOutBufferSize", opIn.call.control.cbOutBufferSize,
642 opOut.call.control.cbOutBufferSize))
647 opIn.call.control.pvInBuffer =
nullptr;
648 smartcard_operation_free(&opIn, FALSE);
649 smartcard_operation_free(&opOut, FALSE);
654static BOOL test_get_attrib_encode_decode_request(
void)
656 BOOL success = FALSE;
659 opIn.ioControlCode = SCARD_IOCTL_GETATTRIB;
660 fill_redir_context(&opIn.call.getAttrib.handles.hContext, 0x1234);
661 fill_redir_handle(&opIn.call.getAttrib.handles.hCard, 0x5678);
662 opIn.call.getAttrib.dwAttrId = SCARD_ATTR_ATR_STRING;
663 opIn.call.getAttrib.fpbAttrIsNULL = 0;
664 opIn.call.getAttrib.cbAttrLen = 36;
666 if (!test_request_roundtrip(&opIn, &opOut))
668 if (!check_redir_context(
"GetAttrib", &opIn.call.getAttrib.handles.hContext,
669 &opOut.call.getAttrib.handles.hContext))
671 if (!check_redir_handle(
"GetAttrib", &opIn.call.getAttrib.handles.hCard,
672 &opOut.call.getAttrib.handles.hCard))
674 if (!check_field(
"GetAttrib",
"dwAttrId", opIn.call.getAttrib.dwAttrId,
675 opOut.call.getAttrib.dwAttrId))
677 if (!check_field(
"GetAttrib",
"cbAttrLen", opIn.call.getAttrib.cbAttrLen,
678 opOut.call.getAttrib.cbAttrLen))
683 smartcard_operation_free(&opIn, FALSE);
684 smartcard_operation_free(&opOut, FALSE);
689static BOOL test_set_attrib_encode_decode_request(
void)
691 BOOL success = FALSE;
692 BYTE attrBuf[] = { 0x3B, 0x00 };
695 opIn.ioControlCode = SCARD_IOCTL_SETATTRIB;
696 fill_redir_context(&opIn.call.setAttrib.handles.hContext, 0x1234);
697 fill_redir_handle(&opIn.call.setAttrib.handles.hCard, 0x5678);
698 opIn.call.setAttrib.dwAttrId = SCARD_ATTR_ATR_STRING;
699 opIn.call.setAttrib.cbAttrLen =
sizeof(attrBuf);
700 opIn.call.setAttrib.pbAttr = attrBuf;
702 if (!test_request_roundtrip(&opIn, &opOut))
704 if (!check_redir_context(
"SetAttrib", &opIn.call.setAttrib.handles.hContext,
705 &opOut.call.setAttrib.handles.hContext))
707 if (!check_redir_handle(
"SetAttrib", &opIn.call.setAttrib.handles.hCard,
708 &opOut.call.setAttrib.handles.hCard))
710 if (!check_field(
"SetAttrib",
"dwAttrId", opIn.call.setAttrib.dwAttrId,
711 opOut.call.setAttrib.dwAttrId))
713 if (!check_field(
"SetAttrib",
"cbAttrLen", opIn.call.setAttrib.cbAttrLen,
714 opOut.call.setAttrib.cbAttrLen))
716 if (!check_bytes(
"SetAttrib",
"pbAttr", opIn.call.setAttrib.pbAttr, opOut.call.setAttrib.pbAttr,
717 opIn.call.setAttrib.cbAttrLen))
722 opIn.call.setAttrib.pbAttr =
nullptr;
723 smartcard_operation_free(&opIn, FALSE);
724 smartcard_operation_free(&opOut, FALSE);
729static BOOL test_encode_decode_requests(
void)
733 if (!test_establish_context_encode_decode_request())
735 if (!test_release_context_encode_decode_request())
737 if (!test_is_valid_context_encode_decode_request())
739 if (!test_list_reader_groups_a_encode_decode_request())
741 if (!test_list_reader_groups_w_encode_decode_request())
743 if (!test_list_readers_a_encode_decode_request())
745 if (!test_list_readers_w_encode_decode_request())
747 if (!test_cancel_encode_decode_request())
749 if (!test_connect_a_encode_decode_request())
751 if (!test_connect_w_encode_decode_request())
753 if (!test_reconnect_encode_decode_request())
755 if (!test_disconnect_encode_decode_request())
757 if (!test_begin_transaction_encode_decode_request())
759 if (!test_end_transaction_encode_decode_request())
761 if (!test_status_a_encode_decode_request())
763 if (!test_status_w_encode_decode_request())
765 if (!test_transmit_encode_decode_request())
767 if (!test_control_encode_decode_request())
769 if (!test_get_attrib_encode_decode_request())
771 if (!test_set_attrib_encode_decode_request())
778static LONG encode_response_payload(
wStream* s, UINT32 ioControlCode,
781 switch (ioControlCode)
783 case SCARD_IOCTL_ESTABLISHCONTEXT:
784 return smartcard_pack_establish_context_return(s, &opIn->
ret.establishContext);
785 case SCARD_IOCTL_RECONNECT:
786 return smartcard_pack_reconnect_return(s, &opIn->
ret.reconnect);
787 case SCARD_IOCTL_CONNECTA:
788 case SCARD_IOCTL_CONNECTW:
789 return smartcard_pack_connect_return(s, &opIn->
ret.connect);
790 case SCARD_IOCTL_CONTROL:
791 return smartcard_pack_control_return(s, &opIn->
ret.control);
792 case SCARD_IOCTL_TRANSMIT:
793 return smartcard_pack_transmit_return(s, &opIn->
ret.transmit);
794 case SCARD_IOCTL_GETATTRIB:
795 return smartcard_pack_get_attrib_return(s, &opIn->
ret.getAttrib, 0,
796 opIn->
ret.getAttrib.cbAttrLen);
797 case SCARD_IOCTL_GETSTATUSCHANGEA:
798 return smartcard_pack_get_status_change_return(s, &opIn->
ret.getStatusChange, FALSE);
799 case SCARD_IOCTL_GETSTATUSCHANGEW:
800 return smartcard_pack_get_status_change_return(s, &opIn->
ret.getStatusChange, TRUE);
801 case SCARD_IOCTL_LISTREADERGROUPSA:
802 return smartcard_pack_list_reader_groups_return(s, &opIn->
ret.listReaders, FALSE);
803 case SCARD_IOCTL_LISTREADERGROUPSW:
804 return smartcard_pack_list_reader_groups_return(s, &opIn->
ret.listReaders, TRUE);
805 case SCARD_IOCTL_LISTREADERSA:
806 return smartcard_pack_list_readers_return(s, &opIn->
ret.listReaders, FALSE);
807 case SCARD_IOCTL_LISTREADERSW:
808 return smartcard_pack_list_readers_return(s, &opIn->
ret.listReaders, TRUE);
809 case SCARD_IOCTL_STATUSA:
810 return smartcard_pack_status_return(s, &opIn->
ret.status, FALSE);
811 case SCARD_IOCTL_STATUSW:
812 return smartcard_pack_status_return(s, &opIn->
ret.status, TRUE);
813 case SCARD_IOCTL_RELEASECONTEXT:
814 case SCARD_IOCTL_ISVALIDCONTEXT:
815 case SCARD_IOCTL_CANCEL:
816 case SCARD_IOCTL_DISCONNECT:
817 case SCARD_IOCTL_BEGINTRANSACTION:
818 case SCARD_IOCTL_ENDTRANSACTION:
819 case SCARD_IOCTL_SETATTRIB:
820 return SCARD_S_SUCCESS;
822 return SCARD_F_INTERNAL_ERROR;
826WINPR_ATTR_MALLOC(Stream_Free, 1)
829 const char* name = scard_get_ioctl_string(ioControlCode, TRUE);
832 wStream* payload = Stream_New(
nullptr, 4096);
835 (void)fprintf(stderr,
"%s: Stream_New for payload failed\n", name);
839 LONG rc = encode_response_payload(payload, ioControlCode, opIn);
840 if (rc != SCARD_S_SUCCESS)
842 (void)fprintf(stderr,
"%s: encode_response_payload failed with 0x%08" PRIX32
"\n", name,
844 Stream_Release(payload);
847 Stream_SealLength(payload);
849 wStream* s = Stream_New(
nullptr, 256 + Stream_Length(payload));
852 (void)fprintf(stderr,
"%s: Stream_New for response failed\n", name);
853 Stream_Release(payload);
858 const size_t headerPos = Stream_GetPosition(s);
859 Stream_Seek(s, SMARTCARD_COMMON_TYPE_HEADER_LENGTH +
860 SMARTCARD_PRIVATE_TYPE_HEADER_LENGTH);
861 Stream_Write_INT32(s, opIn->returnCode);
862 Stream_Write(s, Stream_Buffer(payload), Stream_Length(payload));
863 Stream_Release(payload);
865 const size_t payloadSize = Stream_GetPosition(s) - headerPos;
866 const size_t objectBufferLength =
867 payloadSize - SMARTCARD_COMMON_TYPE_HEADER_LENGTH - SMARTCARD_PRIVATE_TYPE_HEADER_LENGTH;
869 WINPR_UNUSED(smartcard_pack_write_size_align(s, payloadSize, 8));
871 const size_t endPos = Stream_GetPosition(s);
872 const size_t outputBufferLength = endPos - headerPos;
874 if (!Stream_SetPosition(s, 0))
876 (void)fprintf(stderr,
"%s: Stream_SetPosition failed\n", name);
880 UINT32 outputLength = WINPR_ASSERTING_INT_CAST(UINT32, outputBufferLength);
881 UINT32 objectLength = WINPR_ASSERTING_INT_CAST(UINT32, objectBufferLength);
882 Stream_Write_UINT32(s, outputLength);
883 smartcard_pack_common_type_header(s);
884 smartcard_pack_private_type_header(s, objectLength);
886 if (!Stream_SetPosition(s, endPos))
888 (void)fprintf(stderr,
"%s: Stream_SetPosition failed\n", name);
892 Stream_SealLength(s);
893 if (!Stream_SetPosition(s, 0))
895 (void)fprintf(stderr,
"%s: Stream_SetPosition failed\n", name);
905 const UINT32 ioControlCode = opIn->ioControlCode;
906 const char* name = scard_get_ioctl_string(ioControlCode, TRUE);
909 wStream* s = build_device_control_response(ioControlCode, opIn);
914 LONG status = smartcard_irp_device_control_decode_response(s, ioControlCode, opOut);
917 if (status != SCARD_S_SUCCESS)
919 (void)fprintf(stderr,
"%s: decode_response failed with 0x%08" PRIX32
"\n", name,
928static BOOL test_establish_context_decode_response(
void)
930 BOOL success = FALSE;
933 opIn.ioControlCode = SCARD_IOCTL_ESTABLISHCONTEXT;
934 fill_redir_context(&opIn.
ret.establishContext.hContext, 0xABCD);
937 if (!test_response_roundtrip(&opIn, &opOut))
939 if (!check_redir_context(
"EstablishContext", &opIn.
ret.establishContext.hContext,
940 &opOut.
ret.establishContext.hContext))
942 if (!check_field(
"EstablishContext",
"returnCode", (UINT32)opIn.
returnCode,
948 smartcard_operation_free(&opIn, FALSE);
949 smartcard_operation_free(&opOut, FALSE);
954static BOOL test_release_context_decode_response(
void)
956 BOOL success = FALSE;
959 opIn.ioControlCode = SCARD_IOCTL_RELEASECONTEXT;
962 if (!test_response_roundtrip(&opIn, &opOut))
964 if (!check_field(
"ReleaseContext",
"returnCode", (UINT32)opIn.
returnCode,
970 smartcard_operation_free(&opIn, FALSE);
971 smartcard_operation_free(&opOut, FALSE);
976static BOOL test_is_valid_context_decode_response(
void)
978 BOOL success = FALSE;
981 opIn.ioControlCode = SCARD_IOCTL_ISVALIDCONTEXT;
984 if (!test_response_roundtrip(&opIn, &opOut))
986 if (!check_field(
"IsValidContext",
"returnCode", (UINT32)opIn.
returnCode,
992 smartcard_operation_free(&opIn, FALSE);
993 smartcard_operation_free(&opOut, FALSE);
998static BOOL test_list_reader_groups_decode_response_impl(UINT32 ioControlCode)
1000 BOOL success = FALSE;
1001 const char* n = scard_get_ioctl_string(ioControlCode, TRUE);
1006 opIn.ioControlCode = ioControlCode;
1008 BYTE groups[] = {
'G',
'r',
'p',
'\0',
'\0' };
1009 opIn.
ret.listReaders.cBytes =
sizeof(groups);
1010 opIn.
ret.listReaders.msz = groups;
1012 if (!test_response_roundtrip(&opIn, &opOut))
1016 if (!check_field(n,
"cBytes", opIn.
ret.listReaders.cBytes, opOut.
ret.listReaders.cBytes))
1018 if (!check_bytes(n,
"msz", opIn.
ret.listReaders.msz, opOut.
ret.listReaders.msz,
1019 opIn.
ret.listReaders.cBytes))
1024 opIn.
ret.listReaders.msz =
nullptr;
1025 smartcard_operation_free(&opIn, FALSE);
1026 smartcard_operation_free(&opOut, FALSE);
1031static BOOL test_list_reader_groups_a_decode_response(
void)
1033 return test_list_reader_groups_decode_response_impl(SCARD_IOCTL_LISTREADERGROUPSA);
1037static BOOL test_list_reader_groups_w_decode_response(
void)
1039 return test_list_reader_groups_decode_response_impl(SCARD_IOCTL_LISTREADERGROUPSW);
1043static BOOL test_list_readers_decode_response_impl(UINT32 ioControlCode)
1045 BOOL success = FALSE;
1046 const char* n = scard_get_ioctl_string(ioControlCode, TRUE);
1051 opIn.ioControlCode = ioControlCode;
1053 BYTE readers[] = {
'R',
'd',
'r',
'\0',
'\0' };
1054 opIn.
ret.listReaders.cBytes =
sizeof(readers);
1055 opIn.
ret.listReaders.msz = readers;
1057 if (!test_response_roundtrip(&opIn, &opOut))
1061 if (!check_field(n,
"cBytes", opIn.
ret.listReaders.cBytes, opOut.
ret.listReaders.cBytes))
1063 if (!check_bytes(n,
"msz", opIn.
ret.listReaders.msz, opOut.
ret.listReaders.msz,
1064 opIn.
ret.listReaders.cBytes))
1069 opIn.
ret.listReaders.msz =
nullptr;
1070 smartcard_operation_free(&opIn, FALSE);
1071 smartcard_operation_free(&opOut, FALSE);
1076static BOOL test_list_readers_a_decode_response(
void)
1078 return test_list_readers_decode_response_impl(SCARD_IOCTL_LISTREADERSA);
1082static BOOL test_list_readers_w_decode_response(
void)
1084 return test_list_readers_decode_response_impl(SCARD_IOCTL_LISTREADERSW);
1088static BOOL test_get_status_change_decode_response_impl(UINT32 ioControlCode)
1090 BOOL success = FALSE;
1091 const char* n = scard_get_ioctl_string(ioControlCode, TRUE);
1096 opIn.ioControlCode = ioControlCode;
1099 .dwEventState = SCARD_STATE_CHANGED,
1102 .rgbAtr[1] = 0x00 };
1103 opIn.
ret.getStatusChange.cReaders = 1;
1104 opIn.
ret.getStatusChange.rgReaderStates = &state;
1106 if (!test_response_roundtrip(&opIn, &opOut))
1110 if (!check_field(n,
"cReaders", opIn.
ret.getStatusChange.cReaders,
1111 opOut.
ret.getStatusChange.cReaders))
1113 if (!check_field(n,
"dwCurrentState", state.dwCurrentState,
1114 opOut.
ret.getStatusChange.rgReaderStates[0].dwCurrentState))
1116 if (!check_field(n,
"dwEventState", state.dwEventState,
1117 opOut.
ret.getStatusChange.rgReaderStates[0].dwEventState))
1119 if (!check_field(n,
"cbAtr", state.cbAtr, opOut.
ret.getStatusChange.rgReaderStates[0].cbAtr))
1121 if (!check_bytes(n,
"rgbAtr", state.rgbAtr, opOut.
ret.getStatusChange.rgReaderStates[0].rgbAtr,
1122 sizeof(state.rgbAtr)))
1127 opIn.
ret.getStatusChange.rgReaderStates =
nullptr;
1128 smartcard_operation_free(&opIn, FALSE);
1129 smartcard_operation_free(&opOut, FALSE);
1134static BOOL test_get_status_change_a_decode_response(
void)
1136 return test_get_status_change_decode_response_impl(SCARD_IOCTL_GETSTATUSCHANGEA);
1140static BOOL test_get_status_change_w_decode_response(
void)
1142 return test_get_status_change_decode_response_impl(SCARD_IOCTL_GETSTATUSCHANGEW);
1146static BOOL test_cancel_decode_response(
void)
1148 BOOL success = FALSE;
1151 opIn.ioControlCode = SCARD_IOCTL_CANCEL;
1154 if (!test_response_roundtrip(&opIn, &opOut))
1161 smartcard_operation_free(&opIn, FALSE);
1162 smartcard_operation_free(&opOut, FALSE);
1167static BOOL test_connect_decode_response_impl(UINT32 ioControlCode)
1169 BOOL success = FALSE;
1170 const char* n = scard_get_ioctl_string(ioControlCode, TRUE);
1175 opIn.ioControlCode = ioControlCode;
1177 fill_redir_context(&opIn.
ret.connect.hContext, 0x1234);
1178 fill_redir_handle(&opIn.
ret.connect.hCard, 0x5678);
1179 opIn.
ret.connect.dwActiveProtocol = SCARD_PROTOCOL_T0;
1181 if (!test_response_roundtrip(&opIn, &opOut))
1185 if (!check_redir_context(n, &opIn.
ret.connect.hContext, &opOut.
ret.connect.hContext))
1187 if (!check_redir_handle(n, &opIn.
ret.connect.hCard, &opOut.
ret.connect.hCard))
1189 if (!check_field(n,
"dwActiveProtocol", opIn.
ret.connect.dwActiveProtocol,
1190 opOut.
ret.connect.dwActiveProtocol))
1195 smartcard_operation_free(&opIn, FALSE);
1196 smartcard_operation_free(&opOut, FALSE);
1201static BOOL test_connect_a_decode_response(
void)
1203 return test_connect_decode_response_impl(SCARD_IOCTL_CONNECTA);
1207static BOOL test_connect_w_decode_response(
void)
1209 return test_connect_decode_response_impl(SCARD_IOCTL_CONNECTW);
1213static BOOL test_reconnect_decode_response(
void)
1215 BOOL success = FALSE;
1218 opIn.ioControlCode = SCARD_IOCTL_RECONNECT;
1220 opIn.
ret.reconnect.dwActiveProtocol = SCARD_PROTOCOL_T1;
1222 if (!test_response_roundtrip(&opIn, &opOut))
1224 if (!check_field(
"Reconnect",
"returnCode", (UINT32)opIn.
returnCode, (UINT32)opOut.
returnCode))
1226 if (!check_field(
"Reconnect",
"dwActiveProtocol", opIn.
ret.reconnect.dwActiveProtocol,
1227 opOut.
ret.reconnect.dwActiveProtocol))
1232 smartcard_operation_free(&opIn, FALSE);
1233 smartcard_operation_free(&opOut, FALSE);
1238static BOOL test_disconnect_decode_response(
void)
1240 BOOL success = FALSE;
1243 opIn.ioControlCode = SCARD_IOCTL_DISCONNECT;
1246 if (!test_response_roundtrip(&opIn, &opOut))
1248 if (!check_field(
"Disconnect",
"returnCode", (UINT32)opIn.
returnCode, (UINT32)opOut.
returnCode))
1253 smartcard_operation_free(&opIn, FALSE);
1254 smartcard_operation_free(&opOut, FALSE);
1259static BOOL test_begin_transaction_decode_response(
void)
1261 BOOL success = FALSE;
1264 opIn.ioControlCode = SCARD_IOCTL_BEGINTRANSACTION;
1267 if (!test_response_roundtrip(&opIn, &opOut))
1269 if (!check_field(
"BeginTransaction",
"returnCode", (UINT32)opIn.
returnCode,
1275 smartcard_operation_free(&opIn, FALSE);
1276 smartcard_operation_free(&opOut, FALSE);
1281static BOOL test_end_transaction_decode_response(
void)
1283 BOOL success = FALSE;
1286 opIn.ioControlCode = SCARD_IOCTL_ENDTRANSACTION;
1289 if (!test_response_roundtrip(&opIn, &opOut))
1291 if (!check_field(
"EndTransaction",
"returnCode", (UINT32)opIn.
returnCode,
1297 smartcard_operation_free(&opIn, FALSE);
1298 smartcard_operation_free(&opOut, FALSE);
1303static BOOL test_status_decode_response_impl(UINT32 ioControlCode)
1305 BOOL success = FALSE;
1306 const char* n = scard_get_ioctl_string(ioControlCode, TRUE);
1311 opIn.ioControlCode = ioControlCode;
1313 BYTE readerName[] = {
'R',
'd',
'r',
'\0' };
1314 opIn.
ret.status.cBytes =
sizeof(readerName);
1315 opIn.
ret.status.mszReaderNames = readerName;
1316 opIn.
ret.status.dwState = SCARD_SPECIFIC;
1317 opIn.
ret.status.dwProtocol = SCARD_PROTOCOL_T1;
1318 memset(opIn.
ret.status.pbAtr, 0x3B,
sizeof(opIn.
ret.status.pbAtr));
1319 opIn.
ret.status.cbAtrLen = 2;
1321 if (!test_response_roundtrip(&opIn, &opOut))
1325 if (!check_field(n,
"dwState", opIn.
ret.status.dwState, opOut.
ret.status.dwState))
1327 if (!check_field(n,
"dwProtocol", opIn.
ret.status.dwProtocol, opOut.
ret.status.dwProtocol))
1329 if (!check_field(n,
"cbAtrLen", opIn.
ret.status.cbAtrLen, opOut.
ret.status.cbAtrLen))
1331 if (!check_bytes(n,
"pbAtr", opIn.
ret.status.pbAtr, opOut.
ret.status.pbAtr,
1332 sizeof(opIn.
ret.status.pbAtr)))
1334 if (!check_field(n,
"cBytes", opIn.
ret.status.cBytes, opOut.
ret.status.cBytes))
1336 if (!check_bytes(n,
"mszReaderNames", opIn.
ret.status.mszReaderNames,
1337 opOut.
ret.status.mszReaderNames, opIn.
ret.status.cBytes))
1342 opIn.
ret.status.mszReaderNames =
nullptr;
1343 smartcard_operation_free(&opIn, FALSE);
1344 smartcard_operation_free(&opOut, FALSE);
1349static BOOL test_status_a_decode_response(
void)
1351 return test_status_decode_response_impl(SCARD_IOCTL_STATUSA);
1355static BOOL test_status_w_decode_response(
void)
1357 return test_status_decode_response_impl(SCARD_IOCTL_STATUSW);
1361static BOOL test_transmit_decode_response(
void)
1363 BOOL success = FALSE;
1366 opIn.ioControlCode = SCARD_IOCTL_TRANSMIT;
1368 BYTE recvBuf[] = { 0x90, 0x00 };
1369 opIn.
ret.transmit.cbRecvLength =
sizeof(recvBuf);
1370 opIn.
ret.transmit.pbRecvBuffer = recvBuf;
1371 opIn.
ret.transmit.pioRecvPci =
nullptr;
1373 if (!test_response_roundtrip(&opIn, &opOut))
1377 if (!check_field(
"Transmit",
"cbRecvLength", opIn.
ret.transmit.cbRecvLength,
1378 opOut.
ret.transmit.cbRecvLength))
1380 if (!check_bytes(
"Transmit",
"pbRecvBuffer", opIn.
ret.transmit.pbRecvBuffer,
1381 opOut.
ret.transmit.pbRecvBuffer, opIn.
ret.transmit.cbRecvLength))
1386 opIn.
ret.transmit.pbRecvBuffer =
nullptr;
1387 smartcard_operation_free(&opIn, FALSE);
1388 smartcard_operation_free(&opOut, FALSE);
1393static BOOL test_control_decode_response(
void)
1395 BOOL success = FALSE;
1398 opIn.ioControlCode = SCARD_IOCTL_CONTROL;
1400 BYTE outBuf[] = { 0xAA, 0xBB, 0xCC };
1401 opIn.
ret.control.cbOutBufferSize =
sizeof(outBuf);
1402 opIn.
ret.control.pvOutBuffer = outBuf;
1404 if (!test_response_roundtrip(&opIn, &opOut))
1408 if (!check_field(
"Control",
"cbOutBufferSize", opIn.
ret.control.cbOutBufferSize,
1409 opOut.
ret.control.cbOutBufferSize))
1411 if (!check_bytes(
"Control",
"pvOutBuffer", opIn.
ret.control.pvOutBuffer,
1412 opOut.
ret.control.pvOutBuffer, opIn.
ret.control.cbOutBufferSize))
1417 opIn.
ret.control.pvOutBuffer =
nullptr;
1418 smartcard_operation_free(&opIn, FALSE);
1419 smartcard_operation_free(&opOut, FALSE);
1424static BOOL test_get_attrib_decode_response(
void)
1426 BOOL success = FALSE;
1429 opIn.ioControlCode = SCARD_IOCTL_GETATTRIB;
1431 BYTE attr[] = { 0x3B, 0x90, 0x00 };
1432 opIn.
ret.getAttrib.cbAttrLen =
sizeof(attr);
1433 opIn.
ret.getAttrib.pbAttr = attr;
1435 if (!test_response_roundtrip(&opIn, &opOut))
1437 if (!check_field(
"GetAttrib",
"returnCode", (UINT32)opIn.
returnCode, (UINT32)opOut.
returnCode))
1439 if (!check_field(
"GetAttrib",
"cbAttrLen", opIn.
ret.getAttrib.cbAttrLen,
1440 opOut.
ret.getAttrib.cbAttrLen))
1442 if (!check_bytes(
"GetAttrib",
"pbAttr", opIn.
ret.getAttrib.pbAttr, opOut.
ret.getAttrib.pbAttr,
1443 opIn.
ret.getAttrib.cbAttrLen))
1448 opIn.
ret.getAttrib.pbAttr =
nullptr;
1449 smartcard_operation_free(&opIn, FALSE);
1450 smartcard_operation_free(&opOut, FALSE);
1455static BOOL test_set_attrib_decode_response(
void)
1457 BOOL success = FALSE;
1460 opIn.ioControlCode = SCARD_IOCTL_SETATTRIB;
1463 if (!test_response_roundtrip(&opIn, &opOut))
1465 if (!check_field(
"SetAttrib",
"returnCode", (UINT32)opIn.
returnCode, (UINT32)opOut.
returnCode))
1470 smartcard_operation_free(&opIn, FALSE);
1471 smartcard_operation_free(&opOut, FALSE);
1476static BOOL test_decode_responses(
void)
1478 BOOL success = TRUE;
1480 if (!test_establish_context_decode_response())
1482 if (!test_release_context_decode_response())
1484 if (!test_is_valid_context_decode_response())
1486 if (!test_list_reader_groups_a_decode_response())
1488 if (!test_list_reader_groups_w_decode_response())
1490 if (!test_list_readers_a_decode_response())
1492 if (!test_list_readers_w_decode_response())
1494 if (!test_get_status_change_a_decode_response())
1496 if (!test_get_status_change_w_decode_response())
1498 if (!test_cancel_decode_response())
1500 if (!test_connect_a_decode_response())
1502 if (!test_connect_w_decode_response())
1504 if (!test_reconnect_decode_response())
1506 if (!test_disconnect_decode_response())
1508 if (!test_begin_transaction_decode_response())
1510 if (!test_end_transaction_decode_response())
1512 if (!test_status_a_decode_response())
1514 if (!test_status_w_decode_response())
1516 if (!test_transmit_decode_response())
1518 if (!test_control_decode_response())
1520 if (!test_get_attrib_decode_response())
1522 if (!test_set_attrib_decode_response())
1528int TestSmartcardOperations(
int argc,
char* argv[])
1533 if (!test_encode_decode_requests())
1536 if (!test_decode_responses())
union SMARTCARD_OPERATION::@35 ret