FreeRDP
Loading...
Searching...
No Matches
TestSmartcardOperations.c
1
19#include <stdio.h>
20
21#include <winpr/crt.h>
22#include <winpr/stream.h>
23#include <winpr/smartcard.h>
24
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>
30
31static inline void fill_redir_context(REDIR_SCARDCONTEXT* ctx, SCARDCONTEXT val)
32{
33 smartcard_scard_context_native_to_redir(ctx, val);
34}
35
36static inline void fill_redir_handle(REDIR_SCARDHANDLE* handle, SCARDHANDLE val)
37{
38 smartcard_scard_handle_native_to_redir(handle, val);
39}
40
41static wStream* build_device_control_request(UINT32 ioControlCode, const void* inputBuffer,
42 size_t inputBufferLength)
43{
44 const char* name = scard_get_ioctl_string(ioControlCode, TRUE);
45 const size_t totalLength = RDPDR_DEVICE_IO_CONTROL_REQ_HDR_LENGTH + inputBufferLength;
46
47 wStream* s = Stream_New(nullptr, totalLength);
48 if (!s)
49 {
50 (void)fprintf(stderr, "build_device_control_request(%s): Stream_New(%" PRIuz ") failed\n",
51 name, totalLength);
52 return nullptr;
53 }
54
55 UINT32 inputLength = WINPR_ASSERTING_INT_CAST(UINT32, inputBufferLength);
56 Stream_Write_UINT32(s, 2048); /* OutputBufferLength */
57 Stream_Write_UINT32(s, inputLength); /* InputBufferLength */
58 Stream_Write_UINT32(s, ioControlCode); /* IoControlCode */
59 Stream_Zero(s, 20); /* Padding */
60
61 if (inputBufferLength > 0)
62 Stream_Write(s, inputBuffer, inputBufferLength);
63
64 Stream_SealLength(s);
65 if (!Stream_SetPosition(s, 0))
66 {
67 (void)fprintf(stderr, "build_device_control_request(%s): Stream_SetPosition failed\n",
68 name);
69 Stream_Release(s);
70 return nullptr;
71 }
72
73 return s;
74}
75
76static BOOL test_request_roundtrip(const SMARTCARD_OPERATION* opIn, SMARTCARD_OPERATION* opOut)
77{
78 const UINT32 ioControlCode = opIn->ioControlCode;
79 const char* name = scard_get_ioctl_string(ioControlCode, TRUE);
80
81 wStream* sEnc = Stream_New(nullptr, 4096);
82 if (!sEnc)
83 {
84 (void)fprintf(stderr, "%s: Stream_New for encode failed\n", name);
85 return FALSE;
86 }
87
88 LONG status = smartcard_irp_device_control_encode_request(sEnc, opIn);
89 if (status != SCARD_S_SUCCESS)
90 {
91 (void)fprintf(stderr, "%s: encode_request failed with 0x%08" PRIX32 "\n", name,
92 (UINT32)status);
93 Stream_Release(sEnc);
94 return FALSE;
95 }
96
97 wStream* sDec =
98 build_device_control_request(ioControlCode, Stream_Buffer(sEnc), Stream_Length(sEnc));
99 Stream_Release(sEnc);
100 if (!sDec)
101 return FALSE;
102
103 *opOut = (SMARTCARD_OPERATION)WINPR_C_ARRAY_INIT;
104 status = smartcard_irp_device_control_decode_request(sDec, 1, 0, opOut);
105 Stream_Release(sDec);
106 if (status != SCARD_S_SUCCESS)
107 {
108 (void)fprintf(stderr, "%s: decode_request failed with 0x%08" PRIX32 "\n", name,
109 (UINT32)status);
110 return FALSE;
111 }
112
113 if (opOut->ioControlCode != ioControlCode)
114 {
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);
118 return FALSE;
119 }
120
121 return TRUE;
122}
123
124static inline BOOL check_field(const char* name, const char* field, UINT32 a, UINT32 b)
125{
126 if (a != b)
127 {
128 (void)fprintf(stderr, "%s: %s mismatch: 0x%" PRIX32 " != 0x%" PRIX32 "\n", name, field, a,
129 b);
130 return FALSE;
131 }
132 return TRUE;
133}
134
135static inline BOOL check_bytes(const char* name, const char* field, const void* a, const void* b,
136 size_t len)
137{
138 if (!a || !b || memcmp(a, b, len) != 0)
139 {
140 (void)fprintf(stderr, "%s: %s mismatch (%" PRIuz " bytes)\n", name, field, len);
141 return FALSE;
142 }
143 return TRUE;
144}
145
146static inline BOOL check_redir_context(const char* name, const REDIR_SCARDCONTEXT* a,
147 const REDIR_SCARDCONTEXT* b)
148{
149 return check_field(name, "hContext.cbContext", a->cbContext, b->cbContext) &&
150 check_bytes(name, "hContext.pbContext", a->pbContext, b->pbContext, a->cbContext);
151}
152
153static inline BOOL check_redir_handle(const char* name, const REDIR_SCARDHANDLE* a,
154 const REDIR_SCARDHANDLE* b)
155{
156 return check_field(name, "hCard.cbHandle", a->cbHandle, b->cbHandle) &&
157 check_bytes(name, "hCard.pbHandle", a->pbHandle, b->pbHandle, a->cbHandle);
158}
159
160static BOOL test_establish_context_encode_decode_request(void)
161{
162 BOOL success = FALSE;
163 SMARTCARD_OPERATION opOut = WINPR_C_ARRAY_INIT;
164 SMARTCARD_OPERATION opIn = WINPR_C_ARRAY_INIT;
165 opIn.ioControlCode = SCARD_IOCTL_ESTABLISHCONTEXT;
166 opIn.call.establishContext.dwScope = SCARD_SCOPE_SYSTEM;
167
168 if (!test_request_roundtrip(&opIn, &opOut))
169 goto out;
170 if (!check_field("EstablishContext", "dwScope", opIn.call.establishContext.dwScope,
171 opOut.call.establishContext.dwScope))
172 goto out;
173
174 success = TRUE;
175out:
176 smartcard_operation_free(&opIn, FALSE);
177 smartcard_operation_free(&opOut, FALSE);
178 return success;
179}
180
181static BOOL test_release_context_encode_decode_request(void)
182{
183 BOOL success = FALSE;
184 SMARTCARD_OPERATION opOut = WINPR_C_ARRAY_INIT;
185 SMARTCARD_OPERATION opIn = WINPR_C_ARRAY_INIT;
186 opIn.ioControlCode = SCARD_IOCTL_RELEASECONTEXT;
187 fill_redir_context(&opIn.call.context.handles.hContext, 0x1234);
188
189 if (!test_request_roundtrip(&opIn, &opOut))
190 goto out;
191 if (!check_redir_context("ReleaseContext", &opIn.call.context.handles.hContext,
192 &opOut.call.context.handles.hContext))
193 goto out;
194
195 success = TRUE;
196out:
197 smartcard_operation_free(&opIn, FALSE);
198 smartcard_operation_free(&opOut, FALSE);
199 return success;
200}
201
202static BOOL test_is_valid_context_encode_decode_request(void)
203{
204 BOOL success = FALSE;
205 SMARTCARD_OPERATION opOut = WINPR_C_ARRAY_INIT;
206 SMARTCARD_OPERATION opIn = WINPR_C_ARRAY_INIT;
207 opIn.ioControlCode = SCARD_IOCTL_ISVALIDCONTEXT;
208 fill_redir_context(&opIn.call.context.handles.hContext, 0x5678);
209
210 if (!test_request_roundtrip(&opIn, &opOut))
211 goto out;
212 if (!check_redir_context("IsValidContext", &opIn.call.context.handles.hContext,
213 &opOut.call.context.handles.hContext))
214 goto out;
215
216 success = TRUE;
217out:
218 smartcard_operation_free(&opIn, FALSE);
219 smartcard_operation_free(&opOut, FALSE);
220 return success;
221}
222
223static BOOL test_list_reader_groups_encode_decode_request_impl(UINT32 ioControlCode)
224{
225 BOOL success = FALSE;
226 const char* n = scard_get_ioctl_string(ioControlCode, TRUE);
227 SMARTCARD_OPERATION opOut = WINPR_C_ARRAY_INIT;
228 SMARTCARD_OPERATION opIn = WINPR_C_ARRAY_INIT;
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;
233
234 if (!test_request_roundtrip(&opIn, &opOut))
235 goto out;
236 if (!check_redir_context(n, &opIn.call.listReaderGroups.handles.hContext,
237 &opOut.call.listReaderGroups.handles.hContext))
238 goto out;
239 if (!check_field(n, "fmszGroupsIsNULL", opIn.call.listReaderGroups.fmszGroupsIsNULL,
240 opOut.call.listReaderGroups.fmszGroupsIsNULL))
241 goto out;
242 if (!check_field(n, "cchGroups", opIn.call.listReaderGroups.cchGroups,
243 opOut.call.listReaderGroups.cchGroups))
244 goto out;
245
246 success = TRUE;
247out:
248 smartcard_operation_free(&opIn, FALSE);
249 smartcard_operation_free(&opOut, FALSE);
250 return success;
251}
252
253static BOOL test_list_reader_groups_a_encode_decode_request(void)
254{
255 return test_list_reader_groups_encode_decode_request_impl(SCARD_IOCTL_LISTREADERGROUPSA);
256}
257
258static BOOL test_list_reader_groups_w_encode_decode_request(void)
259{
260 return test_list_reader_groups_encode_decode_request_impl(SCARD_IOCTL_LISTREADERGROUPSW);
261}
262
263static BOOL test_list_readers_encode_decode_request_impl(UINT32 ioControlCode)
264{
265 BOOL success = FALSE;
266 const char* n = scard_get_ioctl_string(ioControlCode, TRUE);
267 SMARTCARD_OPERATION opOut = WINPR_C_ARRAY_INIT;
268 SMARTCARD_OPERATION opIn = WINPR_C_ARRAY_INIT;
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;
273
274 if (!test_request_roundtrip(&opIn, &opOut))
275 goto out;
276 if (!check_redir_context(n, &opIn.call.listReaders.handles.hContext,
277 &opOut.call.listReaders.handles.hContext))
278 goto out;
279 if (!check_field(n, "cchReaders", opIn.call.listReaders.cchReaders,
280 opOut.call.listReaders.cchReaders))
281 goto out;
282
283 success = TRUE;
284out:
285 smartcard_operation_free(&opIn, FALSE);
286 smartcard_operation_free(&opOut, FALSE);
287 return success;
288}
289
290static BOOL test_list_readers_a_encode_decode_request(void)
291{
292 return test_list_readers_encode_decode_request_impl(SCARD_IOCTL_LISTREADERSA);
293}
294
295static BOOL test_list_readers_w_encode_decode_request(void)
296{
297 return test_list_readers_encode_decode_request_impl(SCARD_IOCTL_LISTREADERSW);
298}
299
300static BOOL test_cancel_encode_decode_request(void)
301{
302 BOOL success = FALSE;
303 SMARTCARD_OPERATION opOut = WINPR_C_ARRAY_INIT;
304 SMARTCARD_OPERATION opIn = WINPR_C_ARRAY_INIT;
305 opIn.ioControlCode = SCARD_IOCTL_CANCEL;
306 fill_redir_context(&opIn.call.context.handles.hContext, 0xABCD);
307
308 if (!test_request_roundtrip(&opIn, &opOut))
309 goto out;
310 if (!check_redir_context("Cancel", &opIn.call.context.handles.hContext,
311 &opOut.call.context.handles.hContext))
312 goto out;
313
314 success = TRUE;
315out:
316 smartcard_operation_free(&opIn, FALSE);
317 smartcard_operation_free(&opOut, FALSE);
318 return success;
319}
320
321static BOOL test_connect_a_encode_decode_request(void)
322{
323 BOOL success = FALSE;
324 SMARTCARD_OPERATION opOut = WINPR_C_ARRAY_INIT;
325 SMARTCARD_OPERATION opIn = WINPR_C_ARRAY_INIT;
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");
331
332 if (!test_request_roundtrip(&opIn, &opOut))
333 goto out;
334 if (!check_redir_context("ConnectA", &opIn.call.connectA.Common.handles.hContext,
335 &opOut.call.connectA.Common.handles.hContext))
336 goto out;
337 if (!check_field("ConnectA", "dwShareMode", opIn.call.connectA.Common.dwShareMode,
338 opOut.call.connectA.Common.dwShareMode))
339 goto out;
340 if (!check_field("ConnectA", "dwPreferredProtocols",
341 opIn.call.connectA.Common.dwPreferredProtocols,
342 opOut.call.connectA.Common.dwPreferredProtocols))
343 goto out;
344 if (!check_bytes("ConnectA", "szReader", opIn.call.connectA.szReader,
345 opOut.call.connectA.szReader, strlen(opIn.call.connectA.szReader) + 1))
346 goto out;
347
348 success = TRUE;
349out:
350 smartcard_operation_free(&opIn, FALSE);
351 smartcard_operation_free(&opOut, FALSE);
352 return success;
353}
354
355static BOOL test_connect_w_encode_decode_request(void)
356{
357 BOOL success = FALSE;
358 SMARTCARD_OPERATION opOut = WINPR_C_ARRAY_INIT;
359 SMARTCARD_OPERATION opIn = WINPR_C_ARRAY_INIT;
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);
365
366 if (!test_request_roundtrip(&opIn, &opOut))
367 goto out;
368 if (!check_redir_context("ConnectW", &opIn.call.connectW.Common.handles.hContext,
369 &opOut.call.connectW.Common.handles.hContext))
370 goto out;
371 if (!check_field("ConnectW", "dwShareMode", opIn.call.connectW.Common.dwShareMode,
372 opOut.call.connectW.Common.dwShareMode))
373 goto out;
374 if (!check_bytes("ConnectW", "szReader", opIn.call.connectW.szReader,
375 opOut.call.connectW.szReader,
376 (_wcslen(opIn.call.connectW.szReader) + 1) * sizeof(WCHAR)))
377 goto out;
378
379 success = TRUE;
380out:
381 smartcard_operation_free(&opIn, FALSE);
382 smartcard_operation_free(&opOut, FALSE);
383 return success;
384}
385
386static BOOL test_reconnect_encode_decode_request(void)
387{
388 BOOL success = FALSE;
389 const char* n = "Reconnect";
390 SMARTCARD_OPERATION opOut = WINPR_C_ARRAY_INIT;
391 SMARTCARD_OPERATION opIn = WINPR_C_ARRAY_INIT;
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;
398
399 if (!test_request_roundtrip(&opIn, &opOut))
400 goto out;
401 if (!check_redir_context(n, &opIn.call.reconnect.handles.hContext,
402 &opOut.call.reconnect.handles.hContext))
403 goto out;
404 if (!check_redir_handle(n, &opIn.call.reconnect.handles.hCard,
405 &opOut.call.reconnect.handles.hCard))
406 goto out;
407 if (!check_field(n, "dwShareMode", opIn.call.reconnect.dwShareMode,
408 opOut.call.reconnect.dwShareMode))
409 goto out;
410 if (!check_field(n, "dwPreferredProtocols", opIn.call.reconnect.dwPreferredProtocols,
411 opOut.call.reconnect.dwPreferredProtocols))
412 goto out;
413 if (!check_field(n, "dwInitialization", opIn.call.reconnect.dwInitialization,
414 opOut.call.reconnect.dwInitialization))
415 goto out;
416
417 success = TRUE;
418out:
419 smartcard_operation_free(&opIn, FALSE);
420 smartcard_operation_free(&opOut, FALSE);
421 return success;
422}
423
424static BOOL test_hcard_and_disposition_encode_decode_request_impl(UINT32 ioControlCode,
425 DWORD dwDisposition)
426{
427 BOOL success = FALSE;
428 const char* n = scard_get_ioctl_string(ioControlCode, TRUE);
429 SMARTCARD_OPERATION opOut = WINPR_C_ARRAY_INIT;
430 SMARTCARD_OPERATION opIn = WINPR_C_ARRAY_INIT;
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;
435
436 if (!test_request_roundtrip(&opIn, &opOut))
437 goto out;
438 if (!check_redir_context(n, &opIn.call.hCardAndDisposition.handles.hContext,
439 &opOut.call.hCardAndDisposition.handles.hContext))
440 goto out;
441 if (!check_redir_handle(n, &opIn.call.hCardAndDisposition.handles.hCard,
442 &opOut.call.hCardAndDisposition.handles.hCard))
443 goto out;
444 if (!check_field(n, "dwDisposition", opIn.call.hCardAndDisposition.dwDisposition,
445 opOut.call.hCardAndDisposition.dwDisposition))
446 goto out;
447
448 success = TRUE;
449out:
450 smartcard_operation_free(&opIn, FALSE);
451 smartcard_operation_free(&opOut, FALSE);
452 return success;
453}
454
455static BOOL test_disconnect_encode_decode_request(void)
456{
457 return test_hcard_and_disposition_encode_decode_request_impl(SCARD_IOCTL_DISCONNECT,
458 SCARD_LEAVE_CARD);
459}
460
461static BOOL test_begin_transaction_encode_decode_request(void)
462{
463 return test_hcard_and_disposition_encode_decode_request_impl(SCARD_IOCTL_BEGINTRANSACTION,
464 SCARD_LEAVE_CARD);
465}
466
467static BOOL test_end_transaction_encode_decode_request(void)
468{
469 return test_hcard_and_disposition_encode_decode_request_impl(SCARD_IOCTL_ENDTRANSACTION,
470 SCARD_RESET_CARD);
471}
472
473static BOOL test_status_encode_decode_request_impl(UINT32 ioControlCode)
474{
475 BOOL success = FALSE;
476 const char* n = scard_get_ioctl_string(ioControlCode, TRUE);
477 SMARTCARD_OPERATION opOut = WINPR_C_ARRAY_INIT;
478 SMARTCARD_OPERATION opIn = WINPR_C_ARRAY_INIT;
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;
485
486 if (!test_request_roundtrip(&opIn, &opOut))
487 goto out;
488 if (!check_redir_context(n, &opIn.call.status.handles.hContext,
489 &opOut.call.status.handles.hContext))
490 goto out;
491 if (!check_redir_handle(n, &opIn.call.status.handles.hCard, &opOut.call.status.handles.hCard))
492 goto out;
493 if (!check_field(n, "fmszReaderNamesIsNULL", opIn.call.status.fmszReaderNamesIsNULL,
494 opOut.call.status.fmszReaderNamesIsNULL))
495 goto out;
496 if (!check_field(n, "cchReaderLen", opIn.call.status.cchReaderLen,
497 opOut.call.status.cchReaderLen))
498 goto out;
499 if (!check_field(n, "cbAtrLen", opIn.call.status.cbAtrLen, opOut.call.status.cbAtrLen))
500 goto out;
501
502 success = TRUE;
503out:
504 smartcard_operation_free(&opIn, FALSE);
505 smartcard_operation_free(&opOut, FALSE);
506 return success;
507}
508
509static BOOL test_status_a_encode_decode_request(void)
510{
511 return test_status_encode_decode_request_impl(SCARD_IOCTL_STATUSA);
512}
513
514static BOOL test_status_w_encode_decode_request(void)
515{
516 return test_status_encode_decode_request_impl(SCARD_IOCTL_STATUSW);
517}
518
519static BOOL test_transmit_encode_decode_request(void)
520{
521 BOOL success = FALSE;
522 BYTE sendBuf[] = { 0x00, 0xA4, 0x04, 0x00, 0x07 };
523 SCARD_IO_REQUEST pioSendPci = { .dwProtocol = SCARD_PROTOCOL_T0, .cbPciLength = 8 };
524 SMARTCARD_OPERATION opIn = WINPR_C_ARRAY_INIT;
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;
533
534 SMARTCARD_OPERATION opOut = WINPR_C_ARRAY_INIT;
535 if (!test_request_roundtrip(&opIn, &opOut))
536 goto out;
537 if (!check_redir_context("Transmit", &opIn.call.transmit.handles.hContext,
538 &opOut.call.transmit.handles.hContext))
539 goto out;
540 if (!check_redir_handle("Transmit", &opIn.call.transmit.handles.hCard,
541 &opOut.call.transmit.handles.hCard))
542 goto out;
543 if (!check_field("Transmit", "cbSendLength", opIn.call.transmit.cbSendLength,
544 opOut.call.transmit.cbSendLength))
545 goto out;
546 if (!check_bytes("Transmit", "pbSendBuffer", opIn.call.transmit.pbSendBuffer,
547 opOut.call.transmit.pbSendBuffer, opIn.call.transmit.cbSendLength))
548 goto out;
549 if (!check_field("Transmit", "fpbRecvBufferIsNULL",
550 (UINT32)opIn.call.transmit.fpbRecvBufferIsNULL,
551 (UINT32)opOut.call.transmit.fpbRecvBufferIsNULL))
552 goto out;
553 if (!check_field("Transmit", "cbRecvLength", opIn.call.transmit.cbRecvLength,
554 opOut.call.transmit.cbRecvLength))
555 goto out;
556 if (!check_field("Transmit", "pioSendPci.dwProtocol", opIn.call.transmit.pioSendPci->dwProtocol,
557 opOut.call.transmit.pioSendPci->dwProtocol))
558 goto out;
559
560 success = TRUE;
561out:
562 opIn.call.transmit.pioSendPci = nullptr;
563 opIn.call.transmit.pbSendBuffer = nullptr;
564 smartcard_operation_free(&opIn, FALSE);
565 smartcard_operation_free(&opOut, FALSE);
566 return success;
567}
568
569static BOOL test_control_encode_decode_request(void)
570{
571 BOOL success = FALSE;
572 BYTE inBuf[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 };
573 SMARTCARD_OPERATION opIn = WINPR_C_ARRAY_INIT;
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;
582
583 SMARTCARD_OPERATION opOut = WINPR_C_ARRAY_INIT;
584 if (!test_request_roundtrip(&opIn, &opOut))
585 goto out;
586 if (!check_redir_context("Control", &opIn.call.control.handles.hContext,
587 &opOut.call.control.handles.hContext))
588 goto out;
589 if (!check_redir_handle("Control", &opIn.call.control.handles.hCard,
590 &opOut.call.control.handles.hCard))
591 goto out;
592 if (!check_field("Control", "dwControlCode", opIn.call.control.dwControlCode,
593 opOut.call.control.dwControlCode))
594 goto out;
595 if (!check_field("Control", "cbInBufferSize", opIn.call.control.cbInBufferSize,
596 opOut.call.control.cbInBufferSize))
597 goto out;
598 if (!check_bytes("Control", "pvInBuffer", opIn.call.control.pvInBuffer,
599 opOut.call.control.pvInBuffer, opIn.call.control.cbInBufferSize))
600 goto out;
601 if (!check_field("Control", "cbOutBufferSize", opIn.call.control.cbOutBufferSize,
602 opOut.call.control.cbOutBufferSize))
603 goto out;
604
605 success = TRUE;
606out:
607 opIn.call.control.pvInBuffer = nullptr;
608 smartcard_operation_free(&opIn, FALSE);
609 smartcard_operation_free(&opOut, FALSE);
610 return success;
611}
612
613static BOOL test_get_attrib_encode_decode_request(void)
614{
615 BOOL success = FALSE;
616 SMARTCARD_OPERATION opOut = WINPR_C_ARRAY_INIT;
617 SMARTCARD_OPERATION opIn = WINPR_C_ARRAY_INIT;
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;
624
625 if (!test_request_roundtrip(&opIn, &opOut))
626 goto out;
627 if (!check_redir_context("GetAttrib", &opIn.call.getAttrib.handles.hContext,
628 &opOut.call.getAttrib.handles.hContext))
629 goto out;
630 if (!check_redir_handle("GetAttrib", &opIn.call.getAttrib.handles.hCard,
631 &opOut.call.getAttrib.handles.hCard))
632 goto out;
633 if (!check_field("GetAttrib", "dwAttrId", opIn.call.getAttrib.dwAttrId,
634 opOut.call.getAttrib.dwAttrId))
635 goto out;
636 if (!check_field("GetAttrib", "cbAttrLen", opIn.call.getAttrib.cbAttrLen,
637 opOut.call.getAttrib.cbAttrLen))
638 goto out;
639
640 success = TRUE;
641out:
642 smartcard_operation_free(&opIn, FALSE);
643 smartcard_operation_free(&opOut, FALSE);
644 return success;
645}
646
647static BOOL test_set_attrib_encode_decode_request(void)
648{
649 BOOL success = FALSE;
650 BYTE attrBuf[] = { 0x3B, 0x00 };
651 SMARTCARD_OPERATION opOut = WINPR_C_ARRAY_INIT;
652 SMARTCARD_OPERATION opIn = WINPR_C_ARRAY_INIT;
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;
659
660 if (!test_request_roundtrip(&opIn, &opOut))
661 goto out;
662 if (!check_redir_context("SetAttrib", &opIn.call.setAttrib.handles.hContext,
663 &opOut.call.setAttrib.handles.hContext))
664 goto out;
665 if (!check_redir_handle("SetAttrib", &opIn.call.setAttrib.handles.hCard,
666 &opOut.call.setAttrib.handles.hCard))
667 goto out;
668 if (!check_field("SetAttrib", "dwAttrId", opIn.call.setAttrib.dwAttrId,
669 opOut.call.setAttrib.dwAttrId))
670 goto out;
671 if (!check_field("SetAttrib", "cbAttrLen", opIn.call.setAttrib.cbAttrLen,
672 opOut.call.setAttrib.cbAttrLen))
673 goto out;
674 if (!check_bytes("SetAttrib", "pbAttr", opIn.call.setAttrib.pbAttr, opOut.call.setAttrib.pbAttr,
675 opIn.call.setAttrib.cbAttrLen))
676 goto out;
677
678 success = TRUE;
679out:
680 opIn.call.setAttrib.pbAttr = nullptr;
681 smartcard_operation_free(&opIn, FALSE);
682 smartcard_operation_free(&opOut, FALSE);
683 return success;
684}
685
686static BOOL test_encode_decode_requests(void)
687{
688 BOOL success = TRUE;
689
690 if (!test_establish_context_encode_decode_request())
691 success = FALSE;
692 if (!test_release_context_encode_decode_request())
693 success = FALSE;
694 if (!test_is_valid_context_encode_decode_request())
695 success = FALSE;
696 if (!test_list_reader_groups_a_encode_decode_request())
697 success = FALSE;
698 if (!test_list_reader_groups_w_encode_decode_request())
699 success = FALSE;
700 if (!test_list_readers_a_encode_decode_request())
701 success = FALSE;
702 if (!test_list_readers_w_encode_decode_request())
703 success = FALSE;
704 if (!test_cancel_encode_decode_request())
705 success = FALSE;
706 if (!test_connect_a_encode_decode_request())
707 success = FALSE;
708 if (!test_connect_w_encode_decode_request())
709 success = FALSE;
710 if (!test_reconnect_encode_decode_request())
711 success = FALSE;
712 if (!test_disconnect_encode_decode_request())
713 success = FALSE;
714 if (!test_begin_transaction_encode_decode_request())
715 success = FALSE;
716 if (!test_end_transaction_encode_decode_request())
717 success = FALSE;
718 if (!test_status_a_encode_decode_request())
719 success = FALSE;
720 if (!test_status_w_encode_decode_request())
721 success = FALSE;
722 if (!test_transmit_encode_decode_request())
723 success = FALSE;
724 if (!test_control_encode_decode_request())
725 success = FALSE;
726 if (!test_get_attrib_encode_decode_request())
727 success = FALSE;
728 if (!test_set_attrib_encode_decode_request())
729 success = FALSE;
730
731 return success;
732}
733
734static LONG encode_response_payload(wStream* s, UINT32 ioControlCode,
735 const SMARTCARD_OPERATION* opIn)
736{
737 switch (ioControlCode)
738 {
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;
777 default:
778 return SCARD_F_INTERNAL_ERROR;
779 }
780}
781
782static wStream* build_device_control_response(UINT32 ioControlCode, const SMARTCARD_OPERATION* opIn)
783{
784 const char* name = scard_get_ioctl_string(ioControlCode, TRUE);
785
786 wStream* payload = Stream_New(nullptr, 4096);
787 if (!payload)
788 {
789 (void)fprintf(stderr, "%s: Stream_New for payload failed\n", name);
790 return nullptr;
791 }
792
793 LONG rc = encode_response_payload(payload, ioControlCode, opIn);
794 if (rc != SCARD_S_SUCCESS)
795 {
796 (void)fprintf(stderr, "%s: encode_response_payload failed with 0x%08" PRIX32 "\n", name,
797 (UINT32)rc);
798 Stream_Release(payload);
799 return nullptr;
800 }
801 Stream_SealLength(payload);
802
803 wStream* s = Stream_New(nullptr, 256 + Stream_Length(payload));
804 if (!s)
805 {
806 (void)fprintf(stderr, "%s: Stream_New for response failed\n", name);
807 Stream_Release(payload);
808 return nullptr;
809 }
810
811 Stream_Seek(s, 4); /* Placeholder for outputBufferLength */
812 const size_t headerPos = Stream_GetPosition(s);
813 Stream_Seek(s, SMARTCARD_COMMON_TYPE_HEADER_LENGTH +
814 SMARTCARD_PRIVATE_TYPE_HEADER_LENGTH); /* Placeholder for headers */
815 Stream_Write_INT32(s, opIn->returnCode);
816 Stream_Write(s, Stream_Buffer(payload), Stream_Length(payload));
817 Stream_Release(payload);
818
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;
822
823 WINPR_UNUSED(smartcard_pack_write_size_align(s, payloadSize, 8));
824
825 const size_t endPos = Stream_GetPosition(s);
826 const size_t outputBufferLength = endPos - headerPos;
827
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);
834
835 Stream_SetPosition(s, endPos);
836 Stream_SealLength(s);
837 if (!Stream_SetPosition(s, 0))
838 {
839 (void)fprintf(stderr, "%s: Stream_SetPosition failed\n", name);
840 Stream_Release(s);
841 return nullptr;
842 }
843 return s;
844}
845
846static BOOL test_response_roundtrip(const SMARTCARD_OPERATION* opIn, SMARTCARD_OPERATION* opOut)
847{
848 const UINT32 ioControlCode = opIn->ioControlCode;
849 const char* name = scard_get_ioctl_string(ioControlCode, TRUE);
850
851 wStream* s = build_device_control_response(ioControlCode, opIn);
852 if (!s)
853 return FALSE;
854
855 *opOut = (SMARTCARD_OPERATION)WINPR_C_ARRAY_INIT;
856 LONG status = smartcard_irp_device_control_decode_response(s, ioControlCode, opOut);
857 Stream_Release(s);
858
859 if (status != SCARD_S_SUCCESS)
860 {
861 (void)fprintf(stderr, "%s: decode_response failed with 0x%08" PRIX32 "\n", name,
862 (UINT32)status);
863 return FALSE;
864 }
865
866 return TRUE;
867}
868
869static BOOL test_establish_context_decode_response(void)
870{
871 BOOL success = FALSE;
872 SMARTCARD_OPERATION opOut = WINPR_C_ARRAY_INIT;
873 SMARTCARD_OPERATION opIn = WINPR_C_ARRAY_INIT;
874 opIn.ioControlCode = SCARD_IOCTL_ESTABLISHCONTEXT;
875 fill_redir_context(&opIn.ret.establishContext.hContext, 0xABCD);
876 opIn.returnCode = SCARD_S_SUCCESS;
877
878 if (!test_response_roundtrip(&opIn, &opOut))
879 goto out;
880 if (!check_redir_context("EstablishContext", &opIn.ret.establishContext.hContext,
881 &opOut.ret.establishContext.hContext))
882 goto out;
883 if (!check_field("EstablishContext", "returnCode", (UINT32)opIn.returnCode,
884 (UINT32)opOut.returnCode))
885 goto out;
886
887 success = TRUE;
888out:
889 smartcard_operation_free(&opIn, FALSE);
890 smartcard_operation_free(&opOut, FALSE);
891 return success;
892}
893
894static BOOL test_release_context_decode_response(void)
895{
896 BOOL success = FALSE;
897 SMARTCARD_OPERATION opOut = WINPR_C_ARRAY_INIT;
898 SMARTCARD_OPERATION opIn = WINPR_C_ARRAY_INIT;
899 opIn.ioControlCode = SCARD_IOCTL_RELEASECONTEXT;
900 opIn.returnCode = SCARD_S_SUCCESS;
901
902 if (!test_response_roundtrip(&opIn, &opOut))
903 goto out;
904 if (!check_field("ReleaseContext", "returnCode", (UINT32)opIn.returnCode,
905 (UINT32)opOut.returnCode))
906 goto out;
907
908 success = TRUE;
909out:
910 smartcard_operation_free(&opIn, FALSE);
911 smartcard_operation_free(&opOut, FALSE);
912 return success;
913}
914
915static BOOL test_is_valid_context_decode_response(void)
916{
917 BOOL success = FALSE;
918 SMARTCARD_OPERATION opOut = WINPR_C_ARRAY_INIT;
919 SMARTCARD_OPERATION opIn = WINPR_C_ARRAY_INIT;
920 opIn.ioControlCode = SCARD_IOCTL_ISVALIDCONTEXT;
921 opIn.returnCode = SCARD_S_SUCCESS;
922
923 if (!test_response_roundtrip(&opIn, &opOut))
924 goto out;
925 if (!check_field("IsValidContext", "returnCode", (UINT32)opIn.returnCode,
926 (UINT32)opOut.returnCode))
927 goto out;
928
929 success = TRUE;
930out:
931 smartcard_operation_free(&opIn, FALSE);
932 smartcard_operation_free(&opOut, FALSE);
933 return success;
934}
935
936static BOOL test_list_reader_groups_decode_response_impl(UINT32 ioControlCode)
937{
938 BOOL success = FALSE;
939 const char* n = scard_get_ioctl_string(ioControlCode, TRUE);
940 SMARTCARD_OPERATION opOut = WINPR_C_ARRAY_INIT;
941 SMARTCARD_OPERATION opIn = WINPR_C_ARRAY_INIT;
942 opIn.ioControlCode = ioControlCode;
943 opIn.returnCode = SCARD_S_SUCCESS;
944 BYTE groups[] = { 'G', 'r', 'p', '\0', '\0' };
945 opIn.ret.listReaders.cBytes = sizeof(groups);
946 opIn.ret.listReaders.msz = groups;
947
948 if (!test_response_roundtrip(&opIn, &opOut))
949 goto out;
950 if (!check_field(n, "returnCode", (UINT32)opIn.returnCode, (UINT32)opOut.returnCode))
951 goto out;
952 if (!check_field(n, "cBytes", opIn.ret.listReaders.cBytes, opOut.ret.listReaders.cBytes))
953 goto out;
954 if (!check_bytes(n, "msz", opIn.ret.listReaders.msz, opOut.ret.listReaders.msz,
955 opIn.ret.listReaders.cBytes))
956 goto out;
957
958 success = TRUE;
959out:
960 opIn.ret.listReaders.msz = nullptr;
961 smartcard_operation_free(&opIn, FALSE);
962 smartcard_operation_free(&opOut, FALSE);
963 return success;
964}
965
966static BOOL test_list_reader_groups_a_decode_response(void)
967{
968 return test_list_reader_groups_decode_response_impl(SCARD_IOCTL_LISTREADERGROUPSA);
969}
970
971static BOOL test_list_reader_groups_w_decode_response(void)
972{
973 return test_list_reader_groups_decode_response_impl(SCARD_IOCTL_LISTREADERGROUPSW);
974}
975
976static BOOL test_list_readers_decode_response_impl(UINT32 ioControlCode)
977{
978 BOOL success = FALSE;
979 const char* n = scard_get_ioctl_string(ioControlCode, TRUE);
980 SMARTCARD_OPERATION opOut = WINPR_C_ARRAY_INIT;
981 SMARTCARD_OPERATION opIn = WINPR_C_ARRAY_INIT;
982 opIn.ioControlCode = ioControlCode;
983 opIn.returnCode = SCARD_S_SUCCESS;
984 BYTE readers[] = { 'R', 'd', 'r', '\0', '\0' };
985 opIn.ret.listReaders.cBytes = sizeof(readers);
986 opIn.ret.listReaders.msz = readers;
987
988 if (!test_response_roundtrip(&opIn, &opOut))
989 goto out;
990 if (!check_field(n, "returnCode", (UINT32)opIn.returnCode, (UINT32)opOut.returnCode))
991 goto out;
992 if (!check_field(n, "cBytes", opIn.ret.listReaders.cBytes, opOut.ret.listReaders.cBytes))
993 goto out;
994 if (!check_bytes(n, "msz", opIn.ret.listReaders.msz, opOut.ret.listReaders.msz,
995 opIn.ret.listReaders.cBytes))
996 goto out;
997
998 success = TRUE;
999out:
1000 opIn.ret.listReaders.msz = nullptr;
1001 smartcard_operation_free(&opIn, FALSE);
1002 smartcard_operation_free(&opOut, FALSE);
1003 return success;
1004}
1005
1006static BOOL test_list_readers_a_decode_response(void)
1007{
1008 return test_list_readers_decode_response_impl(SCARD_IOCTL_LISTREADERSA);
1009}
1010
1011static BOOL test_list_readers_w_decode_response(void)
1012{
1013 return test_list_readers_decode_response_impl(SCARD_IOCTL_LISTREADERSW);
1014}
1015
1016static BOOL test_get_status_change_decode_response_impl(UINT32 ioControlCode)
1017{
1018 BOOL success = FALSE;
1019 const char* n = scard_get_ioctl_string(ioControlCode, TRUE);
1020 SMARTCARD_OPERATION opOut = WINPR_C_ARRAY_INIT;
1021 SMARTCARD_OPERATION opIn = WINPR_C_ARRAY_INIT;
1022 opIn.ioControlCode = ioControlCode;
1023 opIn.returnCode = SCARD_S_SUCCESS;
1024 ReaderState_Return state = WINPR_C_ARRAY_INIT;
1025 state.dwCurrentState = SCARD_STATE_PRESENT;
1026 state.dwEventState = SCARD_STATE_CHANGED;
1027 state.cbAtr = 2;
1028 state.rgbAtr[0] = 0x3B;
1029 state.rgbAtr[1] = 0x00;
1030 opIn.ret.getStatusChange.cReaders = 1;
1031 opIn.ret.getStatusChange.rgReaderStates = &state;
1032
1033 if (!test_response_roundtrip(&opIn, &opOut))
1034 goto out;
1035 if (!check_field(n, "returnCode", (UINT32)opIn.returnCode, (UINT32)opOut.returnCode))
1036 goto out;
1037 if (!check_field(n, "cReaders", opIn.ret.getStatusChange.cReaders,
1038 opOut.ret.getStatusChange.cReaders))
1039 goto out;
1040 if (!check_field(n, "dwCurrentState", state.dwCurrentState,
1041 opOut.ret.getStatusChange.rgReaderStates[0].dwCurrentState))
1042 goto out;
1043 if (!check_field(n, "dwEventState", state.dwEventState,
1044 opOut.ret.getStatusChange.rgReaderStates[0].dwEventState))
1045 goto out;
1046 if (!check_field(n, "cbAtr", state.cbAtr, opOut.ret.getStatusChange.rgReaderStates[0].cbAtr))
1047 goto out;
1048 if (!check_bytes(n, "rgbAtr", state.rgbAtr, opOut.ret.getStatusChange.rgReaderStates[0].rgbAtr,
1049 sizeof(state.rgbAtr)))
1050 goto out;
1051
1052 success = TRUE;
1053out:
1054 opIn.ret.getStatusChange.rgReaderStates = nullptr;
1055 smartcard_operation_free(&opIn, FALSE);
1056 smartcard_operation_free(&opOut, FALSE);
1057 return success;
1058}
1059
1060static BOOL test_get_status_change_a_decode_response(void)
1061{
1062 return test_get_status_change_decode_response_impl(SCARD_IOCTL_GETSTATUSCHANGEA);
1063}
1064
1065static BOOL test_get_status_change_w_decode_response(void)
1066{
1067 return test_get_status_change_decode_response_impl(SCARD_IOCTL_GETSTATUSCHANGEW);
1068}
1069
1070static BOOL test_cancel_decode_response(void)
1071{
1072 BOOL success = FALSE;
1073 SMARTCARD_OPERATION opOut = WINPR_C_ARRAY_INIT;
1074 SMARTCARD_OPERATION opIn = WINPR_C_ARRAY_INIT;
1075 opIn.ioControlCode = SCARD_IOCTL_CANCEL;
1076 opIn.returnCode = SCARD_S_SUCCESS;
1077
1078 if (!test_response_roundtrip(&opIn, &opOut))
1079 goto out;
1080 if (!check_field("Cancel", "returnCode", (UINT32)opIn.returnCode, (UINT32)opOut.returnCode))
1081 goto out;
1082
1083 success = TRUE;
1084out:
1085 smartcard_operation_free(&opIn, FALSE);
1086 smartcard_operation_free(&opOut, FALSE);
1087 return success;
1088}
1089
1090static BOOL test_connect_decode_response_impl(UINT32 ioControlCode)
1091{
1092 BOOL success = FALSE;
1093 const char* n = scard_get_ioctl_string(ioControlCode, TRUE);
1094 SMARTCARD_OPERATION opOut = WINPR_C_ARRAY_INIT;
1095 SMARTCARD_OPERATION opIn = WINPR_C_ARRAY_INIT;
1096 opIn.ioControlCode = ioControlCode;
1097 opIn.returnCode = SCARD_S_SUCCESS;
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;
1101
1102 if (!test_response_roundtrip(&opIn, &opOut))
1103 goto out;
1104 if (!check_field(n, "returnCode", (UINT32)opIn.returnCode, (UINT32)opOut.returnCode))
1105 goto out;
1106 if (!check_redir_context(n, &opIn.ret.connect.hContext, &opOut.ret.connect.hContext))
1107 goto out;
1108 if (!check_redir_handle(n, &opIn.ret.connect.hCard, &opOut.ret.connect.hCard))
1109 goto out;
1110 if (!check_field(n, "dwActiveProtocol", opIn.ret.connect.dwActiveProtocol,
1111 opOut.ret.connect.dwActiveProtocol))
1112 goto out;
1113
1114 success = TRUE;
1115out:
1116 smartcard_operation_free(&opIn, FALSE);
1117 smartcard_operation_free(&opOut, FALSE);
1118 return success;
1119}
1120
1121static BOOL test_connect_a_decode_response(void)
1122{
1123 return test_connect_decode_response_impl(SCARD_IOCTL_CONNECTA);
1124}
1125
1126static BOOL test_connect_w_decode_response(void)
1127{
1128 return test_connect_decode_response_impl(SCARD_IOCTL_CONNECTW);
1129}
1130
1131static BOOL test_reconnect_decode_response(void)
1132{
1133 BOOL success = FALSE;
1134 SMARTCARD_OPERATION opOut = WINPR_C_ARRAY_INIT;
1135 SMARTCARD_OPERATION opIn = WINPR_C_ARRAY_INIT;
1136 opIn.ioControlCode = SCARD_IOCTL_RECONNECT;
1137 opIn.returnCode = SCARD_S_SUCCESS;
1138 opIn.ret.reconnect.dwActiveProtocol = SCARD_PROTOCOL_T1;
1139
1140 if (!test_response_roundtrip(&opIn, &opOut))
1141 goto out;
1142 if (!check_field("Reconnect", "returnCode", (UINT32)opIn.returnCode, (UINT32)opOut.returnCode))
1143 goto out;
1144 if (!check_field("Reconnect", "dwActiveProtocol", opIn.ret.reconnect.dwActiveProtocol,
1145 opOut.ret.reconnect.dwActiveProtocol))
1146 goto out;
1147
1148 success = TRUE;
1149out:
1150 smartcard_operation_free(&opIn, FALSE);
1151 smartcard_operation_free(&opOut, FALSE);
1152 return success;
1153}
1154
1155static BOOL test_disconnect_decode_response(void)
1156{
1157 BOOL success = FALSE;
1158 SMARTCARD_OPERATION opOut = WINPR_C_ARRAY_INIT;
1159 SMARTCARD_OPERATION opIn = WINPR_C_ARRAY_INIT;
1160 opIn.ioControlCode = SCARD_IOCTL_DISCONNECT;
1161 opIn.returnCode = SCARD_S_SUCCESS;
1162
1163 if (!test_response_roundtrip(&opIn, &opOut))
1164 goto out;
1165 if (!check_field("Disconnect", "returnCode", (UINT32)opIn.returnCode, (UINT32)opOut.returnCode))
1166 goto out;
1167
1168 success = TRUE;
1169out:
1170 smartcard_operation_free(&opIn, FALSE);
1171 smartcard_operation_free(&opOut, FALSE);
1172 return success;
1173}
1174
1175static BOOL test_begin_transaction_decode_response(void)
1176{
1177 BOOL success = FALSE;
1178 SMARTCARD_OPERATION opOut = WINPR_C_ARRAY_INIT;
1179 SMARTCARD_OPERATION opIn = WINPR_C_ARRAY_INIT;
1180 opIn.ioControlCode = SCARD_IOCTL_BEGINTRANSACTION;
1181 opIn.returnCode = SCARD_S_SUCCESS;
1182
1183 if (!test_response_roundtrip(&opIn, &opOut))
1184 goto out;
1185 if (!check_field("BeginTransaction", "returnCode", (UINT32)opIn.returnCode,
1186 (UINT32)opOut.returnCode))
1187 goto out;
1188
1189 success = TRUE;
1190out:
1191 smartcard_operation_free(&opIn, FALSE);
1192 smartcard_operation_free(&opOut, FALSE);
1193 return success;
1194}
1195
1196static BOOL test_end_transaction_decode_response(void)
1197{
1198 BOOL success = FALSE;
1199 SMARTCARD_OPERATION opOut = WINPR_C_ARRAY_INIT;
1200 SMARTCARD_OPERATION opIn = WINPR_C_ARRAY_INIT;
1201 opIn.ioControlCode = SCARD_IOCTL_ENDTRANSACTION;
1202 opIn.returnCode = SCARD_S_SUCCESS;
1203
1204 if (!test_response_roundtrip(&opIn, &opOut))
1205 goto out;
1206 if (!check_field("EndTransaction", "returnCode", (UINT32)opIn.returnCode,
1207 (UINT32)opOut.returnCode))
1208 goto out;
1209
1210 success = TRUE;
1211out:
1212 smartcard_operation_free(&opIn, FALSE);
1213 smartcard_operation_free(&opOut, FALSE);
1214 return success;
1215}
1216
1217static BOOL test_status_decode_response_impl(UINT32 ioControlCode)
1218{
1219 BOOL success = FALSE;
1220 const char* n = scard_get_ioctl_string(ioControlCode, TRUE);
1221 SMARTCARD_OPERATION opOut = WINPR_C_ARRAY_INIT;
1222 SMARTCARD_OPERATION opIn = WINPR_C_ARRAY_INIT;
1223 opIn.ioControlCode = ioControlCode;
1224 opIn.returnCode = SCARD_S_SUCCESS;
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;
1232
1233 if (!test_response_roundtrip(&opIn, &opOut))
1234 goto out;
1235 if (!check_field(n, "returnCode", (UINT32)opIn.returnCode, (UINT32)opOut.returnCode))
1236 goto out;
1237 if (!check_field(n, "dwState", opIn.ret.status.dwState, opOut.ret.status.dwState))
1238 goto out;
1239 if (!check_field(n, "dwProtocol", opIn.ret.status.dwProtocol, opOut.ret.status.dwProtocol))
1240 goto out;
1241 if (!check_field(n, "cbAtrLen", opIn.ret.status.cbAtrLen, opOut.ret.status.cbAtrLen))
1242 goto out;
1243 if (!check_bytes(n, "pbAtr", opIn.ret.status.pbAtr, opOut.ret.status.pbAtr,
1244 sizeof(opIn.ret.status.pbAtr)))
1245 goto out;
1246 if (!check_field(n, "cBytes", opIn.ret.status.cBytes, opOut.ret.status.cBytes))
1247 goto out;
1248 if (!check_bytes(n, "mszReaderNames", opIn.ret.status.mszReaderNames,
1249 opOut.ret.status.mszReaderNames, opIn.ret.status.cBytes))
1250 goto out;
1251
1252 success = TRUE;
1253out:
1254 opIn.ret.status.mszReaderNames = nullptr;
1255 smartcard_operation_free(&opIn, FALSE);
1256 smartcard_operation_free(&opOut, FALSE);
1257 return success;
1258}
1259
1260static BOOL test_status_a_decode_response(void)
1261{
1262 return test_status_decode_response_impl(SCARD_IOCTL_STATUSA);
1263}
1264
1265static BOOL test_status_w_decode_response(void)
1266{
1267 return test_status_decode_response_impl(SCARD_IOCTL_STATUSW);
1268}
1269
1270static BOOL test_transmit_decode_response(void)
1271{
1272 BOOL success = FALSE;
1273 SMARTCARD_OPERATION opOut = WINPR_C_ARRAY_INIT;
1274 SMARTCARD_OPERATION opIn = WINPR_C_ARRAY_INIT;
1275 opIn.ioControlCode = SCARD_IOCTL_TRANSMIT;
1276 opIn.returnCode = SCARD_S_SUCCESS;
1277 BYTE recvBuf[] = { 0x90, 0x00 };
1278 opIn.ret.transmit.cbRecvLength = sizeof(recvBuf);
1279 opIn.ret.transmit.pbRecvBuffer = recvBuf;
1280 opIn.ret.transmit.pioRecvPci = nullptr;
1281
1282 if (!test_response_roundtrip(&opIn, &opOut))
1283 goto out;
1284 if (!check_field("Transmit", "returnCode", (UINT32)opIn.returnCode, (UINT32)opOut.returnCode))
1285 goto out;
1286 if (!check_field("Transmit", "cbRecvLength", opIn.ret.transmit.cbRecvLength,
1287 opOut.ret.transmit.cbRecvLength))
1288 goto out;
1289 if (!check_bytes("Transmit", "pbRecvBuffer", opIn.ret.transmit.pbRecvBuffer,
1290 opOut.ret.transmit.pbRecvBuffer, opIn.ret.transmit.cbRecvLength))
1291 goto out;
1292
1293 success = TRUE;
1294out:
1295 opIn.ret.transmit.pbRecvBuffer = nullptr;
1296 smartcard_operation_free(&opIn, FALSE);
1297 smartcard_operation_free(&opOut, FALSE);
1298 return success;
1299}
1300
1301static BOOL test_control_decode_response(void)
1302{
1303 BOOL success = FALSE;
1304 SMARTCARD_OPERATION opOut = WINPR_C_ARRAY_INIT;
1305 SMARTCARD_OPERATION opIn = WINPR_C_ARRAY_INIT;
1306 opIn.ioControlCode = SCARD_IOCTL_CONTROL;
1307 opIn.returnCode = SCARD_S_SUCCESS;
1308 BYTE outBuf[] = { 0xAA, 0xBB, 0xCC };
1309 opIn.ret.control.cbOutBufferSize = sizeof(outBuf);
1310 opIn.ret.control.pvOutBuffer = outBuf;
1311
1312 if (!test_response_roundtrip(&opIn, &opOut))
1313 goto out;
1314 if (!check_field("Control", "returnCode", (UINT32)opIn.returnCode, (UINT32)opOut.returnCode))
1315 goto out;
1316 if (!check_field("Control", "cbOutBufferSize", opIn.ret.control.cbOutBufferSize,
1317 opOut.ret.control.cbOutBufferSize))
1318 goto out;
1319 if (!check_bytes("Control", "pvOutBuffer", opIn.ret.control.pvOutBuffer,
1320 opOut.ret.control.pvOutBuffer, opIn.ret.control.cbOutBufferSize))
1321 goto out;
1322
1323 success = TRUE;
1324out:
1325 opIn.ret.control.pvOutBuffer = nullptr;
1326 smartcard_operation_free(&opIn, FALSE);
1327 smartcard_operation_free(&opOut, FALSE);
1328 return success;
1329}
1330
1331static BOOL test_get_attrib_decode_response(void)
1332{
1333 BOOL success = FALSE;
1334 SMARTCARD_OPERATION opOut = WINPR_C_ARRAY_INIT;
1335 SMARTCARD_OPERATION opIn = WINPR_C_ARRAY_INIT;
1336 opIn.ioControlCode = SCARD_IOCTL_GETATTRIB;
1337 opIn.returnCode = SCARD_S_SUCCESS;
1338 BYTE attr[] = { 0x3B, 0x90, 0x00 };
1339 opIn.ret.getAttrib.cbAttrLen = sizeof(attr);
1340 opIn.ret.getAttrib.pbAttr = attr;
1341
1342 if (!test_response_roundtrip(&opIn, &opOut))
1343 goto out;
1344 if (!check_field("GetAttrib", "returnCode", (UINT32)opIn.returnCode, (UINT32)opOut.returnCode))
1345 goto out;
1346 if (!check_field("GetAttrib", "cbAttrLen", opIn.ret.getAttrib.cbAttrLen,
1347 opOut.ret.getAttrib.cbAttrLen))
1348 goto out;
1349 if (!check_bytes("GetAttrib", "pbAttr", opIn.ret.getAttrib.pbAttr, opOut.ret.getAttrib.pbAttr,
1350 opIn.ret.getAttrib.cbAttrLen))
1351 goto out;
1352
1353 success = TRUE;
1354out:
1355 opIn.ret.getAttrib.pbAttr = nullptr;
1356 smartcard_operation_free(&opIn, FALSE);
1357 smartcard_operation_free(&opOut, FALSE);
1358 return success;
1359}
1360
1361static BOOL test_set_attrib_decode_response(void)
1362{
1363 BOOL success = FALSE;
1364 SMARTCARD_OPERATION opOut = WINPR_C_ARRAY_INIT;
1365 SMARTCARD_OPERATION opIn = WINPR_C_ARRAY_INIT;
1366 opIn.ioControlCode = SCARD_IOCTL_SETATTRIB;
1367 opIn.returnCode = SCARD_S_SUCCESS;
1368
1369 if (!test_response_roundtrip(&opIn, &opOut))
1370 goto out;
1371 if (!check_field("SetAttrib", "returnCode", (UINT32)opIn.returnCode, (UINT32)opOut.returnCode))
1372 goto out;
1373
1374 success = TRUE;
1375out:
1376 smartcard_operation_free(&opIn, FALSE);
1377 smartcard_operation_free(&opOut, FALSE);
1378 return success;
1379}
1380
1381static BOOL test_decode_responses(void)
1382{
1383 BOOL success = TRUE;
1384
1385 if (!test_establish_context_decode_response())
1386 success = FALSE;
1387 if (!test_release_context_decode_response())
1388 success = FALSE;
1389 if (!test_is_valid_context_decode_response())
1390 success = FALSE;
1391 if (!test_list_reader_groups_a_decode_response())
1392 success = FALSE;
1393 if (!test_list_reader_groups_w_decode_response())
1394 success = FALSE;
1395 if (!test_list_readers_a_decode_response())
1396 success = FALSE;
1397 if (!test_list_readers_w_decode_response())
1398 success = FALSE;
1399 if (!test_get_status_change_a_decode_response())
1400 success = FALSE;
1401 if (!test_get_status_change_w_decode_response())
1402 success = FALSE;
1403 if (!test_cancel_decode_response())
1404 success = FALSE;
1405 if (!test_connect_a_decode_response())
1406 success = FALSE;
1407 if (!test_connect_w_decode_response())
1408 success = FALSE;
1409 if (!test_reconnect_decode_response())
1410 success = FALSE;
1411 if (!test_disconnect_decode_response())
1412 success = FALSE;
1413 if (!test_begin_transaction_decode_response())
1414 success = FALSE;
1415 if (!test_end_transaction_decode_response())
1416 success = FALSE;
1417 if (!test_status_a_decode_response())
1418 success = FALSE;
1419 if (!test_status_w_decode_response())
1420 success = FALSE;
1421 if (!test_transmit_decode_response())
1422 success = FALSE;
1423 if (!test_control_decode_response())
1424 success = FALSE;
1425 if (!test_get_attrib_decode_response())
1426 success = FALSE;
1427 if (!test_set_attrib_decode_response())
1428 success = FALSE;
1429
1430 return success;
1431}
1432
1433int TestSmartcardOperations(int argc, char* argv[])
1434{
1435 WINPR_UNUSED(argc);
1436 WINPR_UNUSED(argv);
1437
1438 if (!test_encode_decode_requests())
1439 return -1;
1440
1441 if (!test_decode_responses())
1442 return -1;
1443
1444 return 0;
1445}
union SMARTCARD_OPERATION::@30 ret