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 = { .dwCurrentState = SCARD_STATE_PRESENT,
1025 .dwEventState = SCARD_STATE_CHANGED,
1026 .cbAtr = 2,
1027 .rgbAtr[0] = 0x3B,
1028 .rgbAtr[1] = 0x00 };
1029 opIn.ret.getStatusChange.cReaders = 1;
1030 opIn.ret.getStatusChange.rgReaderStates = &state;
1031
1032 if (!test_response_roundtrip(&opIn, &opOut))
1033 goto out;
1034 if (!check_field(n, "returnCode", (UINT32)opIn.returnCode, (UINT32)opOut.returnCode))
1035 goto out;
1036 if (!check_field(n, "cReaders", opIn.ret.getStatusChange.cReaders,
1037 opOut.ret.getStatusChange.cReaders))
1038 goto out;
1039 if (!check_field(n, "dwCurrentState", state.dwCurrentState,
1040 opOut.ret.getStatusChange.rgReaderStates[0].dwCurrentState))
1041 goto out;
1042 if (!check_field(n, "dwEventState", state.dwEventState,
1043 opOut.ret.getStatusChange.rgReaderStates[0].dwEventState))
1044 goto out;
1045 if (!check_field(n, "cbAtr", state.cbAtr, opOut.ret.getStatusChange.rgReaderStates[0].cbAtr))
1046 goto out;
1047 if (!check_bytes(n, "rgbAtr", state.rgbAtr, opOut.ret.getStatusChange.rgReaderStates[0].rgbAtr,
1048 sizeof(state.rgbAtr)))
1049 goto out;
1050
1051 success = TRUE;
1052out:
1053 opIn.ret.getStatusChange.rgReaderStates = nullptr;
1054 smartcard_operation_free(&opIn, FALSE);
1055 smartcard_operation_free(&opOut, FALSE);
1056 return success;
1057}
1058
1059static BOOL test_get_status_change_a_decode_response(void)
1060{
1061 return test_get_status_change_decode_response_impl(SCARD_IOCTL_GETSTATUSCHANGEA);
1062}
1063
1064static BOOL test_get_status_change_w_decode_response(void)
1065{
1066 return test_get_status_change_decode_response_impl(SCARD_IOCTL_GETSTATUSCHANGEW);
1067}
1068
1069static BOOL test_cancel_decode_response(void)
1070{
1071 BOOL success = FALSE;
1072 SMARTCARD_OPERATION opOut = WINPR_C_ARRAY_INIT;
1073 SMARTCARD_OPERATION opIn = WINPR_C_ARRAY_INIT;
1074 opIn.ioControlCode = SCARD_IOCTL_CANCEL;
1075 opIn.returnCode = SCARD_S_SUCCESS;
1076
1077 if (!test_response_roundtrip(&opIn, &opOut))
1078 goto out;
1079 if (!check_field("Cancel", "returnCode", (UINT32)opIn.returnCode, (UINT32)opOut.returnCode))
1080 goto out;
1081
1082 success = TRUE;
1083out:
1084 smartcard_operation_free(&opIn, FALSE);
1085 smartcard_operation_free(&opOut, FALSE);
1086 return success;
1087}
1088
1089static BOOL test_connect_decode_response_impl(UINT32 ioControlCode)
1090{
1091 BOOL success = FALSE;
1092 const char* n = scard_get_ioctl_string(ioControlCode, TRUE);
1093 SMARTCARD_OPERATION opOut = WINPR_C_ARRAY_INIT;
1094 SMARTCARD_OPERATION opIn = WINPR_C_ARRAY_INIT;
1095 opIn.ioControlCode = ioControlCode;
1096 opIn.returnCode = SCARD_S_SUCCESS;
1097 fill_redir_context(&opIn.ret.connect.hContext, 0x1234);
1098 fill_redir_handle(&opIn.ret.connect.hCard, 0x5678);
1099 opIn.ret.connect.dwActiveProtocol = SCARD_PROTOCOL_T0;
1100
1101 if (!test_response_roundtrip(&opIn, &opOut))
1102 goto out;
1103 if (!check_field(n, "returnCode", (UINT32)opIn.returnCode, (UINT32)opOut.returnCode))
1104 goto out;
1105 if (!check_redir_context(n, &opIn.ret.connect.hContext, &opOut.ret.connect.hContext))
1106 goto out;
1107 if (!check_redir_handle(n, &opIn.ret.connect.hCard, &opOut.ret.connect.hCard))
1108 goto out;
1109 if (!check_field(n, "dwActiveProtocol", opIn.ret.connect.dwActiveProtocol,
1110 opOut.ret.connect.dwActiveProtocol))
1111 goto out;
1112
1113 success = TRUE;
1114out:
1115 smartcard_operation_free(&opIn, FALSE);
1116 smartcard_operation_free(&opOut, FALSE);
1117 return success;
1118}
1119
1120static BOOL test_connect_a_decode_response(void)
1121{
1122 return test_connect_decode_response_impl(SCARD_IOCTL_CONNECTA);
1123}
1124
1125static BOOL test_connect_w_decode_response(void)
1126{
1127 return test_connect_decode_response_impl(SCARD_IOCTL_CONNECTW);
1128}
1129
1130static BOOL test_reconnect_decode_response(void)
1131{
1132 BOOL success = FALSE;
1133 SMARTCARD_OPERATION opOut = WINPR_C_ARRAY_INIT;
1134 SMARTCARD_OPERATION opIn = WINPR_C_ARRAY_INIT;
1135 opIn.ioControlCode = SCARD_IOCTL_RECONNECT;
1136 opIn.returnCode = SCARD_S_SUCCESS;
1137 opIn.ret.reconnect.dwActiveProtocol = SCARD_PROTOCOL_T1;
1138
1139 if (!test_response_roundtrip(&opIn, &opOut))
1140 goto out;
1141 if (!check_field("Reconnect", "returnCode", (UINT32)opIn.returnCode, (UINT32)opOut.returnCode))
1142 goto out;
1143 if (!check_field("Reconnect", "dwActiveProtocol", opIn.ret.reconnect.dwActiveProtocol,
1144 opOut.ret.reconnect.dwActiveProtocol))
1145 goto out;
1146
1147 success = TRUE;
1148out:
1149 smartcard_operation_free(&opIn, FALSE);
1150 smartcard_operation_free(&opOut, FALSE);
1151 return success;
1152}
1153
1154static BOOL test_disconnect_decode_response(void)
1155{
1156 BOOL success = FALSE;
1157 SMARTCARD_OPERATION opOut = WINPR_C_ARRAY_INIT;
1158 SMARTCARD_OPERATION opIn = WINPR_C_ARRAY_INIT;
1159 opIn.ioControlCode = SCARD_IOCTL_DISCONNECT;
1160 opIn.returnCode = SCARD_S_SUCCESS;
1161
1162 if (!test_response_roundtrip(&opIn, &opOut))
1163 goto out;
1164 if (!check_field("Disconnect", "returnCode", (UINT32)opIn.returnCode, (UINT32)opOut.returnCode))
1165 goto out;
1166
1167 success = TRUE;
1168out:
1169 smartcard_operation_free(&opIn, FALSE);
1170 smartcard_operation_free(&opOut, FALSE);
1171 return success;
1172}
1173
1174static BOOL test_begin_transaction_decode_response(void)
1175{
1176 BOOL success = FALSE;
1177 SMARTCARD_OPERATION opOut = WINPR_C_ARRAY_INIT;
1178 SMARTCARD_OPERATION opIn = WINPR_C_ARRAY_INIT;
1179 opIn.ioControlCode = SCARD_IOCTL_BEGINTRANSACTION;
1180 opIn.returnCode = SCARD_S_SUCCESS;
1181
1182 if (!test_response_roundtrip(&opIn, &opOut))
1183 goto out;
1184 if (!check_field("BeginTransaction", "returnCode", (UINT32)opIn.returnCode,
1185 (UINT32)opOut.returnCode))
1186 goto out;
1187
1188 success = TRUE;
1189out:
1190 smartcard_operation_free(&opIn, FALSE);
1191 smartcard_operation_free(&opOut, FALSE);
1192 return success;
1193}
1194
1195static BOOL test_end_transaction_decode_response(void)
1196{
1197 BOOL success = FALSE;
1198 SMARTCARD_OPERATION opOut = WINPR_C_ARRAY_INIT;
1199 SMARTCARD_OPERATION opIn = WINPR_C_ARRAY_INIT;
1200 opIn.ioControlCode = SCARD_IOCTL_ENDTRANSACTION;
1201 opIn.returnCode = SCARD_S_SUCCESS;
1202
1203 if (!test_response_roundtrip(&opIn, &opOut))
1204 goto out;
1205 if (!check_field("EndTransaction", "returnCode", (UINT32)opIn.returnCode,
1206 (UINT32)opOut.returnCode))
1207 goto out;
1208
1209 success = TRUE;
1210out:
1211 smartcard_operation_free(&opIn, FALSE);
1212 smartcard_operation_free(&opOut, FALSE);
1213 return success;
1214}
1215
1216static BOOL test_status_decode_response_impl(UINT32 ioControlCode)
1217{
1218 BOOL success = FALSE;
1219 const char* n = scard_get_ioctl_string(ioControlCode, TRUE);
1220 SMARTCARD_OPERATION opOut = WINPR_C_ARRAY_INIT;
1221 SMARTCARD_OPERATION opIn = WINPR_C_ARRAY_INIT;
1222 opIn.ioControlCode = ioControlCode;
1223 opIn.returnCode = SCARD_S_SUCCESS;
1224 BYTE readerName[] = { 'R', 'd', 'r', '\0' };
1225 opIn.ret.status.cBytes = sizeof(readerName);
1226 opIn.ret.status.mszReaderNames = readerName;
1227 opIn.ret.status.dwState = SCARD_SPECIFIC;
1228 opIn.ret.status.dwProtocol = SCARD_PROTOCOL_T1;
1229 memset(opIn.ret.status.pbAtr, 0x3B, sizeof(opIn.ret.status.pbAtr));
1230 opIn.ret.status.cbAtrLen = 2;
1231
1232 if (!test_response_roundtrip(&opIn, &opOut))
1233 goto out;
1234 if (!check_field(n, "returnCode", (UINT32)opIn.returnCode, (UINT32)opOut.returnCode))
1235 goto out;
1236 if (!check_field(n, "dwState", opIn.ret.status.dwState, opOut.ret.status.dwState))
1237 goto out;
1238 if (!check_field(n, "dwProtocol", opIn.ret.status.dwProtocol, opOut.ret.status.dwProtocol))
1239 goto out;
1240 if (!check_field(n, "cbAtrLen", opIn.ret.status.cbAtrLen, opOut.ret.status.cbAtrLen))
1241 goto out;
1242 if (!check_bytes(n, "pbAtr", opIn.ret.status.pbAtr, opOut.ret.status.pbAtr,
1243 sizeof(opIn.ret.status.pbAtr)))
1244 goto out;
1245 if (!check_field(n, "cBytes", opIn.ret.status.cBytes, opOut.ret.status.cBytes))
1246 goto out;
1247 if (!check_bytes(n, "mszReaderNames", opIn.ret.status.mszReaderNames,
1248 opOut.ret.status.mszReaderNames, opIn.ret.status.cBytes))
1249 goto out;
1250
1251 success = TRUE;
1252out:
1253 opIn.ret.status.mszReaderNames = nullptr;
1254 smartcard_operation_free(&opIn, FALSE);
1255 smartcard_operation_free(&opOut, FALSE);
1256 return success;
1257}
1258
1259static BOOL test_status_a_decode_response(void)
1260{
1261 return test_status_decode_response_impl(SCARD_IOCTL_STATUSA);
1262}
1263
1264static BOOL test_status_w_decode_response(void)
1265{
1266 return test_status_decode_response_impl(SCARD_IOCTL_STATUSW);
1267}
1268
1269static BOOL test_transmit_decode_response(void)
1270{
1271 BOOL success = FALSE;
1272 SMARTCARD_OPERATION opOut = WINPR_C_ARRAY_INIT;
1273 SMARTCARD_OPERATION opIn = WINPR_C_ARRAY_INIT;
1274 opIn.ioControlCode = SCARD_IOCTL_TRANSMIT;
1275 opIn.returnCode = SCARD_S_SUCCESS;
1276 BYTE recvBuf[] = { 0x90, 0x00 };
1277 opIn.ret.transmit.cbRecvLength = sizeof(recvBuf);
1278 opIn.ret.transmit.pbRecvBuffer = recvBuf;
1279 opIn.ret.transmit.pioRecvPci = nullptr;
1280
1281 if (!test_response_roundtrip(&opIn, &opOut))
1282 goto out;
1283 if (!check_field("Transmit", "returnCode", (UINT32)opIn.returnCode, (UINT32)opOut.returnCode))
1284 goto out;
1285 if (!check_field("Transmit", "cbRecvLength", opIn.ret.transmit.cbRecvLength,
1286 opOut.ret.transmit.cbRecvLength))
1287 goto out;
1288 if (!check_bytes("Transmit", "pbRecvBuffer", opIn.ret.transmit.pbRecvBuffer,
1289 opOut.ret.transmit.pbRecvBuffer, opIn.ret.transmit.cbRecvLength))
1290 goto out;
1291
1292 success = TRUE;
1293out:
1294 opIn.ret.transmit.pbRecvBuffer = nullptr;
1295 smartcard_operation_free(&opIn, FALSE);
1296 smartcard_operation_free(&opOut, FALSE);
1297 return success;
1298}
1299
1300static BOOL test_control_decode_response(void)
1301{
1302 BOOL success = FALSE;
1303 SMARTCARD_OPERATION opOut = WINPR_C_ARRAY_INIT;
1304 SMARTCARD_OPERATION opIn = WINPR_C_ARRAY_INIT;
1305 opIn.ioControlCode = SCARD_IOCTL_CONTROL;
1306 opIn.returnCode = SCARD_S_SUCCESS;
1307 BYTE outBuf[] = { 0xAA, 0xBB, 0xCC };
1308 opIn.ret.control.cbOutBufferSize = sizeof(outBuf);
1309 opIn.ret.control.pvOutBuffer = outBuf;
1310
1311 if (!test_response_roundtrip(&opIn, &opOut))
1312 goto out;
1313 if (!check_field("Control", "returnCode", (UINT32)opIn.returnCode, (UINT32)opOut.returnCode))
1314 goto out;
1315 if (!check_field("Control", "cbOutBufferSize", opIn.ret.control.cbOutBufferSize,
1316 opOut.ret.control.cbOutBufferSize))
1317 goto out;
1318 if (!check_bytes("Control", "pvOutBuffer", opIn.ret.control.pvOutBuffer,
1319 opOut.ret.control.pvOutBuffer, opIn.ret.control.cbOutBufferSize))
1320 goto out;
1321
1322 success = TRUE;
1323out:
1324 opIn.ret.control.pvOutBuffer = nullptr;
1325 smartcard_operation_free(&opIn, FALSE);
1326 smartcard_operation_free(&opOut, FALSE);
1327 return success;
1328}
1329
1330static BOOL test_get_attrib_decode_response(void)
1331{
1332 BOOL success = FALSE;
1333 SMARTCARD_OPERATION opOut = WINPR_C_ARRAY_INIT;
1334 SMARTCARD_OPERATION opIn = WINPR_C_ARRAY_INIT;
1335 opIn.ioControlCode = SCARD_IOCTL_GETATTRIB;
1336 opIn.returnCode = SCARD_S_SUCCESS;
1337 BYTE attr[] = { 0x3B, 0x90, 0x00 };
1338 opIn.ret.getAttrib.cbAttrLen = sizeof(attr);
1339 opIn.ret.getAttrib.pbAttr = attr;
1340
1341 if (!test_response_roundtrip(&opIn, &opOut))
1342 goto out;
1343 if (!check_field("GetAttrib", "returnCode", (UINT32)opIn.returnCode, (UINT32)opOut.returnCode))
1344 goto out;
1345 if (!check_field("GetAttrib", "cbAttrLen", opIn.ret.getAttrib.cbAttrLen,
1346 opOut.ret.getAttrib.cbAttrLen))
1347 goto out;
1348 if (!check_bytes("GetAttrib", "pbAttr", opIn.ret.getAttrib.pbAttr, opOut.ret.getAttrib.pbAttr,
1349 opIn.ret.getAttrib.cbAttrLen))
1350 goto out;
1351
1352 success = TRUE;
1353out:
1354 opIn.ret.getAttrib.pbAttr = nullptr;
1355 smartcard_operation_free(&opIn, FALSE);
1356 smartcard_operation_free(&opOut, FALSE);
1357 return success;
1358}
1359
1360static BOOL test_set_attrib_decode_response(void)
1361{
1362 BOOL success = FALSE;
1363 SMARTCARD_OPERATION opOut = WINPR_C_ARRAY_INIT;
1364 SMARTCARD_OPERATION opIn = WINPR_C_ARRAY_INIT;
1365 opIn.ioControlCode = SCARD_IOCTL_SETATTRIB;
1366 opIn.returnCode = SCARD_S_SUCCESS;
1367
1368 if (!test_response_roundtrip(&opIn, &opOut))
1369 goto out;
1370 if (!check_field("SetAttrib", "returnCode", (UINT32)opIn.returnCode, (UINT32)opOut.returnCode))
1371 goto out;
1372
1373 success = TRUE;
1374out:
1375 smartcard_operation_free(&opIn, FALSE);
1376 smartcard_operation_free(&opOut, FALSE);
1377 return success;
1378}
1379
1380static BOOL test_decode_responses(void)
1381{
1382 BOOL success = TRUE;
1383
1384 if (!test_establish_context_decode_response())
1385 success = FALSE;
1386 if (!test_release_context_decode_response())
1387 success = FALSE;
1388 if (!test_is_valid_context_decode_response())
1389 success = FALSE;
1390 if (!test_list_reader_groups_a_decode_response())
1391 success = FALSE;
1392 if (!test_list_reader_groups_w_decode_response())
1393 success = FALSE;
1394 if (!test_list_readers_a_decode_response())
1395 success = FALSE;
1396 if (!test_list_readers_w_decode_response())
1397 success = FALSE;
1398 if (!test_get_status_change_a_decode_response())
1399 success = FALSE;
1400 if (!test_get_status_change_w_decode_response())
1401 success = FALSE;
1402 if (!test_cancel_decode_response())
1403 success = FALSE;
1404 if (!test_connect_a_decode_response())
1405 success = FALSE;
1406 if (!test_connect_w_decode_response())
1407 success = FALSE;
1408 if (!test_reconnect_decode_response())
1409 success = FALSE;
1410 if (!test_disconnect_decode_response())
1411 success = FALSE;
1412 if (!test_begin_transaction_decode_response())
1413 success = FALSE;
1414 if (!test_end_transaction_decode_response())
1415 success = FALSE;
1416 if (!test_status_a_decode_response())
1417 success = FALSE;
1418 if (!test_status_w_decode_response())
1419 success = FALSE;
1420 if (!test_transmit_decode_response())
1421 success = FALSE;
1422 if (!test_control_decode_response())
1423 success = FALSE;
1424 if (!test_get_attrib_decode_response())
1425 success = FALSE;
1426 if (!test_set_attrib_decode_response())
1427 success = FALSE;
1428
1429 return success;
1430}
1431
1432int TestSmartcardOperations(int argc, char* argv[])
1433{
1434 WINPR_UNUSED(argc);
1435 WINPR_UNUSED(argv);
1436
1437 if (!test_encode_decode_requests())
1438 return -1;
1439
1440 if (!test_decode_responses())
1441 return -1;
1442
1443 return 0;
1444}
union SMARTCARD_OPERATION::@33 ret