changelog
[platform/upstream/freerdp.git] / scripts / test-scard.cpp
1 /**
2  * FreeRDP: A Remote Desktop Protocol Implementation
3  * Smartcard API test program
4  *
5  * This simple program can be used to trigger calls for (almost) the
6  * entire SCARD API.
7  * Compile on windows, connect with FreeRDP via RDP with smartcard
8  * redirection enabled and run this test program on the windows
9  * machine.
10  *
11  * Copyright 2020 Armin Novak <armin.novak@thincast.com>
12  * Copyright 2020 Thincast Technologies GmbH
13  *
14  * Licensed under the Apache License, Version 2.0 (the "License");
15  * you may not use this file except in compliance with the License.
16  * You may obtain a copy of the License at
17  *
18  *     http://www.apache.org/licenses/LICENSE-2.0
19  *
20  * Unless required by applicable law or agreed to in writing, software
21  * distributed under the License is distributed on an "AS IS" BASIS,
22  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
23  * See the License for the specific language governing permissions and
24  * limitations under the License.
25  */
26
27 #include <iostream>
28 #include <string>
29 #include <sstream>
30 #include <locale>
31 #include <codecvt>
32
33 #include <comdef.h>
34 #include <winscard.h>
35
36 static const WCHAR* listW[] = { nullptr, L"SCard$AllReaders\000", L"SCard$DefaultReaders\000",
37                                     L"SCard$LocalReaders\000", L"SCard$SystemReaders\000" };
38 static const char* listA[] = { nullptr, "SCard$AllReaders\000", "SCard$DefaultReaders\000",
39                                    "SCard$LocalReaders\000", "SCard$SystemReaders\000" };
40
41 static std::string scope2str(DWORD scope)
42 {
43         switch (scope)
44         {
45                 case SCARD_SCOPE_USER:
46                         return "SCARD_SCOPE_USER";
47                 case SCARD_SCOPE_TERMINAL:
48                         return "SCARD_SCOPE_TERMINAL";
49                 case SCARD_SCOPE_SYSTEM:
50                         return "SCARD_SCOPE_SYSTEM";
51                 default:
52                         return "UNKNOWN";
53         }
54 }
55
56 static std::string err2str(LONG code)
57 {
58         switch (code)
59         {
60                 case ERROR_BROKEN_PIPE:
61                         return "ERROR_BROKEN_PIPE";
62                 case SCARD_E_BAD_SEEK:
63                         return "SCARD_E_BAD_SEEK";
64                 case SCARD_E_CANCELLED:
65                         return "SCARD_E_CANCELLED";
66                 case SCARD_E_CANT_DISPOSE:
67                         return "SCARD_E_CANT_DISPOSE";
68                 case SCARD_E_CARD_UNSUPPORTED:
69                         return "SCARD_E_CARD_UNSUPPORTED";
70                 case SCARD_E_CERTIFICATE_UNAVAILABLE:
71                         return "SCARD_E_CERTIFICATE_UNAVAILABLE";
72                 case SCARD_E_COMM_DATA_LOST:
73                         return "SCARD_E_COMM_DATA_LOST";
74                 case SCARD_E_DIR_NOT_FOUND:
75                         return "SCARD_E_DIR_NOT_FOUND";
76                 case SCARD_E_DUPLICATE_READER:
77                         return "SCARD_E_DUPLICATE_READER";
78                 case SCARD_E_FILE_NOT_FOUND:
79                         return "SCARD_E_FILE_NOT_FOUND";
80                 case SCARD_E_ICC_CREATEORDER:
81                         return "SCARD_E_ICC_CREATEORDER";
82                 case SCARD_E_ICC_INSTALLATION:
83                         return "SCARD_E_ICC_INSTALLATION";
84                 case SCARD_E_INSUFFICIENT_BUFFER:
85                         return "SCARD_E_INSUFFICIENT_BUFFER";
86                 case SCARD_E_INVALID_ATR:
87                         return "SCARD_E_INVALID_ATR";
88                 case SCARD_E_INVALID_CHV:
89                         return "SCARD_E_INVALID_CHV";
90                 case SCARD_E_INVALID_HANDLE:
91                         return "SCARD_E_INVALID_HANDLE";
92                 case SCARD_E_INVALID_PARAMETER:
93                         return "SCARD_E_INVALID_PARAMETER";
94                 case SCARD_E_INVALID_TARGET:
95                         return "SCARD_E_INVALID_TARGET";
96                 case SCARD_E_INVALID_VALUE:
97                         return "SCARD_E_INVALID_VALUE";
98                 case SCARD_E_NO_ACCESS:
99                         return "SCARD_E_NO_ACCESS";
100                 case SCARD_E_NO_DIR:
101                         return "SCARD_E_NO_DIR";
102                 case SCARD_E_NO_FILE:
103                         return "SCARD_E_NO_FILE";
104                 case SCARD_E_NO_KEY_CONTAINER:
105                         return "SCARD_E_NO_KEY_CONTAINER";
106                 case SCARD_E_NO_MEMORY:
107                         return "SCARD_E_NO_MEMORY";
108                 case SCARD_E_NO_PIN_CACHE:
109                         return "SCARD_E_NO_PIN_CACHE";
110                 case SCARD_E_NO_READERS_AVAILABLE:
111                         return "SCARD_E_NO_READERS_AVAILABLE";
112                 case SCARD_E_NO_SERVICE:
113                         return "SCARD_E_NO_SERVICE";
114                 case SCARD_E_NO_SMARTCARD:
115                         return "SCARD_E_NO_SMARTCARD";
116                 case SCARD_E_NO_SUCH_CERTIFICATE:
117                         return "SCARD_E_NO_SUCH_CERTIFICATE";
118                 case SCARD_E_NOT_READY:
119                         return "SCARD_E_NOT_READY";
120                 case SCARD_E_NOT_TRANSACTED:
121                         return "SCARD_E_NOT_TRANSACTED";
122                 case SCARD_E_PCI_TOO_SMALL:
123                         return "SCARD_E_PCI_TOO_SMALL";
124                 case SCARD_E_PIN_CACHE_EXPIRED:
125                         return "SCARD_E_PIN_CACHE_EXPIRED";
126                 case SCARD_E_PROTO_MISMATCH:
127                         return "SCARD_E_PROTO_MISMATCH";
128                 case SCARD_E_READ_ONLY_CARD:
129                         return "SCARD_E_READ_ONLY_CARD";
130                 case SCARD_E_READER_UNAVAILABLE:
131                         return "SCARD_E_READER_UNAVAILABLE";
132                 case SCARD_E_READER_UNSUPPORTED:
133                         return "SCARD_E_READER_UNSUPPORTED";
134                 case SCARD_E_SERVER_TOO_BUSY:
135                         return "SCARD_E_SERVER_TOO_BUSY";
136                 case SCARD_E_SERVICE_STOPPED:
137                         return "SCARD_E_SERVICE_STOPPED";
138                 case SCARD_E_SHARING_VIOLATION:
139                         return "SCARD_E_SHARING_VIOLATION";
140                 case SCARD_E_SYSTEM_CANCELLED:
141                         return "SCARD_E_SYSTEM_CANCELLED";
142                 case SCARD_E_TIMEOUT:
143                         return "SCARD_E_TIMEOUT";
144                 case SCARD_E_UNEXPECTED:
145                         return "SCARD_E_UNEXPECTED";
146                 case SCARD_E_UNKNOWN_CARD:
147                         return "SCARD_E_UNKNOWN_CARD";
148                 case SCARD_E_UNKNOWN_READER:
149                         return "SCARD_E_UNKNOWN_READER";
150                 case SCARD_E_UNKNOWN_RES_MNG:
151                         return "SCARD_E_UNKNOWN_RES_MNG";
152                 case SCARD_E_UNSUPPORTED_FEATURE:
153                         return "SCARD_E_UNSUPPORTED_FEATURE";
154                 case SCARD_E_WRITE_TOO_MANY:
155                         return "SCARD_E_WRITE_TOO_MANY";
156                 case SCARD_F_COMM_ERROR:
157                         return "SCARD_F_COMM_ERROR";
158                 case SCARD_F_INTERNAL_ERROR:
159                         return "SCARD_F_INTERNAL_ERROR";
160                 case SCARD_F_UNKNOWN_ERROR:
161                         return "SCARD_F_UNKNOWN_ERROR";
162                 case SCARD_F_WAITED_TOO_LONG:
163                         return "SCARD_F_WAITED_TOO_LONG";
164                 case SCARD_P_SHUTDOWN:
165                         return "SCARD_P_SHUTDOWN";
166                 case SCARD_S_SUCCESS:
167                         return "SCARD_S_SUCCESS";
168                 case SCARD_W_CANCELLED_BY_USER:
169                         return "SCARD_W_CANCELLED_BY_USER";
170                 case SCARD_W_CACHE_ITEM_NOT_FOUND:
171                         return "SCARD_W_CACHE_ITEM_NOT_FOUND";
172                 case SCARD_W_CACHE_ITEM_STALE:
173                         return "SCARD_W_CACHE_ITEM_STALE";
174                 case SCARD_W_CACHE_ITEM_TOO_BIG:
175                         return "SCARD_W_CACHE_ITEM_TOO_BIG";
176                 case SCARD_W_CARD_NOT_AUTHENTICATED:
177                         return "SCARD_W_CARD_NOT_AUTHENTICATED";
178                 case SCARD_W_CHV_BLOCKED:
179                         return "SCARD_W_CHV_BLOCKED";
180                 case SCARD_W_EOF:
181                         return "SCARD_W_EOF";
182                 case SCARD_W_REMOVED_CARD:
183                         return "SCARD_W_REMOVED_CARD";
184                 case SCARD_W_RESET_CARD:
185                         return "SCARD_W_RESET_CARD";
186                 case SCARD_W_SECURITY_VIOLATION:
187                         return "SCARD_W_SECURITY_VIOLATION";
188                 case SCARD_W_UNPOWERED_CARD:
189                         return "SCARD_W_UNPOWERED_CARD";
190                 case SCARD_W_UNRESPONSIVE_CARD:
191                         return "SCARD_W_UNRESPONSIVE_CARD";
192                 case SCARD_W_UNSUPPORTED_CARD:
193                         return "SCARD_W_UNSUPPORTED_CARD";
194                 case SCARD_W_WRONG_CHV:
195                         return "SCARD_W_WRONG_CHV";
196                 default:
197                         return "UNKNOWN";
198         }
199 }
200
201 static std::wstring err2wstr(LONG code)
202 {
203         auto str = err2str(code);
204         std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
205         return converter.from_bytes(str);
206 }
207
208 #if 0
209 static bool test_listreadergroups(SCARDCONTEXT hContext) {
210     auto rc = SCardListReaderGroupsA(hContext, &groups, &foobar);
211     rc = SCardListReaderGroupsW(hContext, &groups, &foobar);
212 }
213 #endif
214
215 static bool test_valid(SCARDCONTEXT context)
216 {
217         auto rc = SCardIsValidContext(context);
218         if (rc)
219                 std::cerr << "SCardIsValidContext failed with " << err2str(rc) << std::endl;
220         return true;
221 }
222
223 static bool test_list_readers_a(SCARDCONTEXT context)
224 {
225         for (auto cur : listA)
226         {
227                 LPSTR mszReaders = nullptr;
228                 DWORD chReaders = SCARD_AUTOALLOCATE;
229                 auto rc = SCardListReadersA(context, cur, reinterpret_cast<LPSTR>(&mszReaders), &chReaders);
230                 if (!cur)
231                 {
232                         cur = "NULL";
233                 }
234                 if (rc != SCARD_S_SUCCESS)
235                 {
236                         std::cerr << "SCardListReadersA [" << cur << "] failed with " << err2str(rc)
237                                   << std::endl;
238                 }
239                 else
240                 {
241                         auto start = mszReaders;
242                         auto end = &mszReaders[chReaders];
243
244                         std::cout << "SCardListReadersA [" << cur << "] " << chReaders << " [";
245                         while (start < end)
246                         {
247                                 std::cout << start << ", ";
248                                 start += strnlen(start, chReaders) + 2;
249                         }
250                         std::cout << "]" << std::endl;
251                 }
252                 SCardFreeMemory(context, mszReaders);
253         }
254
255         return true;
256 }
257
258 static bool test_list_readers_w(SCARDCONTEXT context)
259 {
260         for (auto cur : listW)
261         {
262                 LPWSTR mszReaders = nullptr;
263                 DWORD chReaders = SCARD_AUTOALLOCATE;
264                 auto rc =
265                     SCardListReadersW(context, cur, reinterpret_cast<LPWSTR>(&mszReaders), &chReaders);
266                 if (!cur)
267                 {
268                         cur = L"NULL";
269                 }
270                 if (rc != SCARD_S_SUCCESS)
271                 {
272                         std::wcerr << L"SCardListReadersW [" << cur << L"] failed with " << err2wstr(rc)
273                                    << std::endl;
274                 }
275                 else
276                 {
277                         auto start = mszReaders;
278                         auto end = &mszReaders[chReaders];
279
280                         std::wcout << L"SCardListReadersW [" << cur << L"] " << chReaders << L" [";
281                         while (start < end)
282                         {
283                                 std::wcout << start << L", ";
284                                 start += wcsnlen(start, chReaders) + 2;
285                         }
286                         std::wcout << L"]" << std::endl;
287                 }
288                 SCardFreeMemory(context, mszReaders);
289         }
290
291         return true;
292 }
293
294 static bool test_list_reader_groups_a(SCARDCONTEXT context)
295 {
296         LPSTR mszReaders = nullptr;
297         DWORD chReaders = SCARD_AUTOALLOCATE;
298         auto rc = SCardListReaderGroupsA(context, reinterpret_cast<LPSTR>(&mszReaders), &chReaders);
299         if (rc != SCARD_S_SUCCESS)
300         {
301                 std::cerr << "SCardListReaderGroupsA failed with " << err2str(rc) << std::endl;
302         }
303         else
304         {
305                 auto start = mszReaders;
306                 auto end = &mszReaders[chReaders];
307
308                 std::cout << "SCardListReaderGroupsA " << chReaders << " [";
309                 while (start < end)
310                 {
311                         std::cout << start << ", ";
312                         start += strnlen(start, chReaders) + 2;
313                 }
314                 std::cout << "]" << std::endl;
315         }
316         SCardFreeMemory(context, mszReaders);
317
318         return true;
319 }
320
321 static bool test_list_reader_groups_w(SCARDCONTEXT context)
322 {
323         LPWSTR mszReaders = nullptr;
324         DWORD chReaders = SCARD_AUTOALLOCATE;
325         auto rc = SCardListReaderGroupsW(context, reinterpret_cast<LPWSTR>(&mszReaders), &chReaders);
326         if (rc != SCARD_S_SUCCESS)
327         {
328                 std::wcerr << L"SCardListReaderGroupsW failed with " << err2wstr(rc) << std::endl;
329         }
330         else
331         {
332                 auto start = mszReaders;
333                 auto end = &mszReaders[chReaders];
334
335                 std::wcout << L"SCardListReaderGroupsW " << chReaders << L" [";
336                 while (start < end)
337                 {
338                         std::wcout << start << L", ";
339                         start += wcsnlen(start, chReaders) + 2;
340                 }
341                 std::wcout << L"]" << std::endl;
342         }
343         SCardFreeMemory(context, mszReaders);
344
345         return true;
346 }
347
348 static bool test_introduce_forget_reader_groups_a(SCARDCONTEXT context)
349 {
350         LPSTR group = "somefancygroup";
351
352         auto rc = SCardIntroduceReaderGroupA(context, group);
353         if (rc != SCARD_S_SUCCESS)
354         {
355                 std::cerr << "SCardIntroduceReaderGroupA failed with " << err2str(rc) << std::endl;
356                 return false;
357         }
358         else
359         {
360                 rc = SCardForgetReaderGroupA(context, group);
361                 if (rc != SCARD_S_SUCCESS)
362                 {
363                         std::cerr << "SCardForgetReaderGroupA failed with " << err2str(rc) << std::endl;
364                         return false;
365                 }
366                 return true;
367         }
368 }
369
370 static bool test_introduce_forget_reader_groups_w(SCARDCONTEXT context)
371 {
372         LPWSTR group = L"somefancygroup";
373
374         auto rc = SCardIntroduceReaderGroupW(context, group);
375         if (rc != SCARD_S_SUCCESS)
376         {
377                 std::cerr << "SCardIntroduceReaderGroupW failed with " << err2str(rc) << std::endl;
378                 return false;
379         }
380         else
381         {
382                 rc = SCardForgetReaderGroupW(context, group);
383                 if (rc != SCARD_S_SUCCESS)
384                 {
385                         std::cerr << "SCardForgetReaderGroupW failed with " << err2str(rc) << std::endl;
386                         return false;
387                 }
388                 return true;
389         }
390 }
391
392 static bool test_introduce_forget_reader_a(SCARDCONTEXT context)
393 {
394         LPSTR reader = "somefancygroup";
395         LPSTR device = "otherfancy";
396
397         auto rc = SCardIntroduceReaderA(context, reader, device);
398         if (rc != SCARD_S_SUCCESS)
399         {
400                 std::cerr << "SCardIntroduceReaderA failed with " << err2str(rc) << std::endl;
401                 return false;
402         }
403         else
404         {
405                 rc = SCardForgetReaderA(context, reader);
406                 if (rc != SCARD_S_SUCCESS)
407                 {
408                         std::cerr << "SCardForgetReaderA failed with " << err2str(rc) << std::endl;
409                         return false;
410                 }
411                 return true;
412         }
413 }
414
415 static bool test_introduce_forget_reader_w(SCARDCONTEXT context)
416 {
417         LPWSTR reader = L"somefancygroup";
418         LPWSTR device = L"otherfancy";
419
420         auto rc = SCardIntroduceReaderW(context, reader, device);
421         if (rc != SCARD_S_SUCCESS)
422         {
423                 std::cerr << "SCardIntroduceReaderW failed with " << err2str(rc) << std::endl;
424                 return false;
425         }
426         else
427         {
428                 rc = SCardForgetReaderW(context, reader);
429                 if (rc != SCARD_S_SUCCESS)
430                 {
431                         std::cerr << "SCardForgetReaderW failed with " << err2str(rc) << std::endl;
432                         return false;
433                 }
434                 return true;
435         }
436 }
437
438 static bool test_list_cards_a(SCARDCONTEXT context)
439 {
440         DWORD chCards = SCARD_AUTOALLOCATE;
441         LPSTR mszCards = nullptr;
442         auto rc =
443             SCardListCardsA(context, nullptr, nullptr, 0, reinterpret_cast<LPSTR>(&mszCards), &chCards);
444         if (rc != SCARD_S_SUCCESS)
445         {
446                 std::cerr << "SCardListCardsA failed with " << err2str(rc) << std::endl;
447         }
448         else
449         {
450                 auto start = mszCards;
451                 auto end = &mszCards[chCards];
452                 std::cout << "SCardListCardsA " << chCards << " [";
453                 while (start < end)
454                 {
455                         std::cout << start << ", ";
456                         start += strnlen(start, chCards) + 2;
457                 }
458                 std::cout << "]" << std::endl;
459         }
460         return true;
461 }
462
463 static bool test_list_cards_w(SCARDCONTEXT context)
464 {
465         DWORD chCards = SCARD_AUTOALLOCATE;
466         LPWSTR mszCards = nullptr;
467         auto rc = SCardListCardsW(context, nullptr, nullptr, 0, reinterpret_cast<LPWSTR>(&mszCards),
468                                   &chCards);
469         if (rc != SCARD_S_SUCCESS)
470         {
471                 std::cerr << "SCardListCardsW failed with " << err2str(rc) << std::endl;
472         }
473         else
474         {
475                 auto start = mszCards;
476                 auto end = &mszCards[chCards];
477                 std::cout << "SCardListCardsW " << chCards << " [";
478                 while (start < end)
479                 {
480                         std::wcout << start << L", ";
481                         start += wcsnlen(start, chCards) + 2;
482                 }
483                 std::cout << "]" << std::endl;
484         }
485         return true;
486 }
487
488 static bool test_cache_a(SCARDCONTEXT context)
489 {
490         BYTE wdata[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
491         const DWORD wdatalen = sizeof(wdata);
492         BYTE data[32] = {};
493         DWORD datalen = sizeof(data);
494         LPSTR name = "testdata";
495         UUID id = {};
496
497         auto rc = SCardWriteCacheA(context, &id, 0, name, wdata, wdatalen);
498         if (rc != SCARD_S_SUCCESS)
499         {
500                 std::cerr << "SCardWriteCacheA failed with " << err2str(rc) << std::endl;
501                 return false;
502         }
503
504         rc = SCardReadCacheA(context, &id, 0, name, data, &datalen);
505         if (rc != SCARD_S_SUCCESS)
506         {
507                 std::cerr << "SCardReadCacheA failed with " << err2str(rc) << std::endl;
508                 return false;
509         }
510
511         if (wdatalen != datalen)
512         {
513                 std::cerr << "SCardWriteCacheA wrote " << wdatalen << "bytes, SCardReadCacheA read "
514                           << datalen << "bytes" << std::endl;
515                 return false;
516         }
517
518         if (memcmp(wdata, data, wdatalen) != 0)
519         {
520                 std::cerr << "SCardWriteCacheA / SCardReadCacheA data corruption detected" << std::endl;
521                 return false;
522         }
523
524         return true;
525 }
526
527 static bool test_cache_w(SCARDCONTEXT context)
528 {
529         BYTE wdata[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
530         const DWORD wdatalen = sizeof(wdata);
531         BYTE data[32] = {};
532         DWORD datalen = sizeof(data);
533         LPWSTR name = L"testdata";
534         UUID id = {};
535
536         auto rc = SCardWriteCacheW(context, &id, 0, name, wdata, wdatalen);
537         if (rc != SCARD_S_SUCCESS)
538         {
539                 std::cerr << "SCardWriteCacheW failed with " << err2str(rc) << std::endl;
540                 return false;
541         }
542
543         rc = SCardReadCacheW(context, &id, 0, name, data, &datalen);
544         if (rc != SCARD_S_SUCCESS)
545         {
546                 std::cerr << "SCardReadCacheW failed with " << err2str(rc) << std::endl;
547                 return false;
548         }
549
550         if (wdatalen != datalen)
551         {
552                 std::cerr << "SCardReadCacheW wrote " << wdatalen << "bytes, SCardReadCacheW read "
553                           << datalen << "bytes" << std::endl;
554                 return false;
555         }
556
557         if (memcmp(wdata, data, wdatalen) != 0)
558         {
559                 std::cerr << "SCardReadCacheW / SCardReadCacheW data corruption detected" << std::endl;
560                 return false;
561         }
562
563         return true;
564 }
565
566 static bool test_reader_icon_a(SCARDCONTEXT context)
567 {
568         LPSTR name = "Gemalto PC Twin Reader 00 00\0\0";
569         LPBYTE pbIcon = nullptr;
570         DWORD cbIcon = SCARD_AUTOALLOCATE;
571
572         auto rc = SCardGetReaderIconA(context, name, reinterpret_cast<LPBYTE>(&pbIcon), &cbIcon);
573         SCardFreeMemory(context, pbIcon);
574         if (rc != SCARD_S_SUCCESS)
575         {
576                 std::cerr << "SCardGetReaderIconA failed with " << err2str(rc) << std::endl;
577                 return false;
578         }
579
580         return true;
581 }
582
583 static bool test_reader_icon_w(SCARDCONTEXT context)
584 {
585         LPWSTR name = L"Gemalto PC Twin Reader 00 00\0\0";
586         LPBYTE pbIcon = nullptr;
587         DWORD cbIcon = SCARD_AUTOALLOCATE;
588
589         auto rc = SCardGetReaderIconW(context, name, reinterpret_cast<LPBYTE>(&pbIcon), &cbIcon);
590         SCardFreeMemory(context, pbIcon);
591         if (rc != SCARD_S_SUCCESS)
592         {
593                 std::cerr << "SCardGetReaderIconW failed with " << err2str(rc) << std::endl;
594                 return false;
595         }
596
597         return true;
598 }
599
600 static bool test_locate_cards_a(SCARDCONTEXT context)
601 {
602         LPSTR name = "Gemalto PC Twin Reader 00 00\0\0";
603         SCARD_READERSTATEA rgReaderStates[16] = {};
604
605         auto rc = SCardLocateCardsA(context, name, rgReaderStates, ARRAYSIZE(rgReaderStates));
606         if (rc != SCARD_S_SUCCESS)
607         {
608                 std::cerr << "SCardLocateCardsA failed with " << err2str(rc) << std::endl;
609                 return false;
610         }
611
612         return true;
613 }
614
615 static bool test_locate_cards_w(SCARDCONTEXT context)
616 {
617         LPWSTR name = L"Gemalto PC Twin Reader 00 00\0\0";
618         SCARD_READERSTATEW rgReaderStates[16] = {};
619
620         auto rc = SCardLocateCardsW(context, name, rgReaderStates, ARRAYSIZE(rgReaderStates));
621         if (rc != SCARD_S_SUCCESS)
622         {
623                 std::cerr << "SCardLocateCardsW failed with " << err2str(rc) << std::endl;
624                 return false;
625         }
626
627         return true;
628 }
629
630 static bool test_locate_cards_by_atr_a(SCARDCONTEXT context)
631 {
632         SCARD_READERSTATEA rgReaderStates[16] = {};
633         SCARD_ATRMASK rgAtrMasks[16] = {};
634
635         auto rc = SCardLocateCardsByATRA(context, rgAtrMasks, ARRAYSIZE(rgAtrMasks), rgReaderStates,
636                                          ARRAYSIZE(rgReaderStates));
637         if (rc != SCARD_S_SUCCESS)
638         {
639                 std::cerr << "SCardLocateCardsByATRA failed with " << err2str(rc) << std::endl;
640                 return false;
641         }
642
643         return true;
644 }
645
646 static bool test_locate_cards_by_atr_w(SCARDCONTEXT context)
647 {
648         SCARD_READERSTATEW rgReaderStates[16] = {};
649         SCARD_ATRMASK rgAtrMasks[16] = {};
650
651         auto rc = SCardLocateCardsByATRW(context, rgAtrMasks, ARRAYSIZE(rgAtrMasks), rgReaderStates,
652                                          ARRAYSIZE(rgReaderStates));
653         if (rc != SCARD_S_SUCCESS)
654         {
655                 std::cerr << "SCardLocateCardsByATRW failed with " << err2str(rc) << std::endl;
656                 return false;
657         }
658
659         return true;
660 }
661
662 static bool test_devicetype_id_a(SCARDCONTEXT context)
663 {
664         BYTE data[32] = {};
665         LPSTR name = "testdata";
666         DWORD type;
667
668         auto rc = SCardGetDeviceTypeIdA(context, name, &type);
669         if (rc != SCARD_S_SUCCESS)
670         {
671                 std::cerr << "SCardGetDeviceTypeIdA failed with " << err2str(rc) << std::endl;
672                 return false;
673         }
674
675         return true;
676 }
677
678 static bool test_devicetype_id_w(SCARDCONTEXT context)
679 {
680         BYTE data[32] = {};
681         LPWSTR name = L"testdata";
682         DWORD type;
683
684         auto rc = SCardGetDeviceTypeIdW(context, name, &type);
685         if (rc != SCARD_S_SUCCESS)
686         {
687                 std::cerr << "SCardGetDeviceTypeIdW failed with " << err2str(rc) << std::endl;
688                 return false;
689         }
690
691         return true;
692 }
693
694 static bool test_transmitcount(SCARDHANDLE handle)
695 {
696         BYTE data[32] = {};
697         LPWSTR name = L"testdata";
698         DWORD count;
699
700         auto rc = SCardGetTransmitCount(handle, &count);
701         if (rc != SCARD_S_SUCCESS)
702         {
703                 std::cerr << "SCardGetTransmitCount failed with " << err2str(rc) << std::endl;
704                 return false;
705         }
706         std::cout << "SCardGetTransmitCount() " << count << std::endl;
707         return true;
708 }
709
710 static bool test_status_a(SCARDHANDLE handle)
711 {
712         BYTE data[32] = {};
713         LPWSTR name = L"testdata";
714         DWORD count;
715         /*
716             auto rc = SCardStatusA(handle, names, len, &state, &protocol, attr, &attrlen);
717             if (rc != SCARD_S_SUCCESS) {
718                 std::cerr << "SCardGetDeviceTypeIdW failed with " << err2str(rc) << std::endl;
719                 return false;
720             }
721         */
722         return true;
723 }
724
725 static bool test_status_w(SCARDHANDLE handle)
726 {
727         BYTE data[32] = {};
728         LPWSTR name = L"testdata";
729         DWORD count;
730         /*
731         auto rc = SCardStatusA(handle, names, len, &state, &protocol, attr, &attrlen);
732         if (rc != SCARD_S_SUCCESS) {
733             std::cerr << "SCardGetDeviceTypeIdW failed with " << err2str(rc) << std::endl;
734             return false;
735         }
736 */
737         return true;
738 }
739
740 static bool test_get_attrib(SCARDCONTEXT context, SCARDHANDLE handle)
741 {
742         DWORD attrlen = SCARD_AUTOALLOCATE;
743         LPBYTE attr = nullptr;
744
745         auto rc =
746             SCardGetAttrib(handle, SCARD_ATTR_ATR_STRING, reinterpret_cast<LPBYTE>(&attr), &attrlen);
747         if (rc != SCARD_S_SUCCESS)
748         {
749                 std::cerr << "SCardGetAttrib failed with " << err2str(rc) << std::endl;
750                 return false;
751         }
752         std::cout << "SCardGetAttrib [" << attrlen << "]: " << (char*)attr << std::endl;
753         SCardFreeMemory(context, attr);
754
755         return true;
756 }
757
758 static bool test_set_attrib(SCARDCONTEXT context, SCARDHANDLE handle)
759 {
760         DWORD attrlen = SCARD_AUTOALLOCATE;
761         BYTE attr[] = "0123456789";
762
763         auto rc = SCardSetAttrib(handle, SCARD_ATTR_SUPRESS_T1_IFS_REQUEST, attr, ARRAYSIZE(attr));
764         if (rc != SCARD_S_SUCCESS)
765         {
766                 std::cerr << "SCardSetAttrib failed with " << err2str(rc) << std::endl;
767                 return false;
768         }
769         std::cout << "SCardSetAttrib [" << attrlen << "]: " << (char*)attr << std::endl;
770         SCardFreeMemory(context, attr);
771
772         return true;
773 }
774
775 int main()
776 {
777         std::cout << "Hello World!" << std::endl;
778         try
779         {
780                 auto scopes = { SCARD_SCOPE_USER, SCARD_SCOPE_SYSTEM };
781                 for (auto scope : scopes)
782                 {
783                         SCARDCONTEXT context;
784                         auto rc = SCardEstablishContext(scope, nullptr, nullptr, &context);
785                         if (rc != SCARD_S_SUCCESS)
786                         {
787                                 std::cerr << "SCardEstablishContext [" << scope2str(scope) << "] failed with "
788                                           << err2str(rc) << std::endl;
789                         }
790                         else
791                         {
792                                 std::cerr << "SCardEstablishContext [" << scope2str(scope) << "] success"
793                                           << std::endl;
794
795                                 test_valid(context);
796
797                                 test_list_reader_groups_a(context);
798                                 test_list_reader_groups_w(context);
799
800                                 test_list_readers_a(context);
801                                 test_list_readers_w(context);
802
803                                 test_list_cards_a(context);
804                                 test_list_cards_w(context);
805
806                                 test_introduce_forget_reader_groups_a(context);
807                                 test_introduce_forget_reader_groups_w(context);
808
809                                 test_introduce_forget_reader_a(context);
810                                 test_introduce_forget_reader_w(context);
811
812                                 // TODO: Introduce/Remove reader to group
813                                 test_locate_cards_a(context);
814                                 test_locate_cards_w(context);
815
816                                 test_locate_cards_by_atr_a(context);
817                                 test_locate_cards_by_atr_w(context);
818
819                                 test_cache_a(context);
820                                 test_cache_w(context);
821
822                                 test_reader_icon_a(context);
823                                 test_reader_icon_w(context);
824
825                                 test_devicetype_id_a(context);
826                                 test_devicetype_id_w(context);
827
828                                 // TODO: statuschange
829                                 // TODO: begin/end transaction
830                                 // TODO: state
831                                 // TODO: transmit
832                                 // TODO: control
833
834                                 {
835                                         DWORD protocol;
836                                         SCARDHANDLE handle = 0;
837                                         LPSTR mszReaders;
838                                         DWORD chReaders = SCARD_AUTOALLOCATE;
839
840                                         LONG status = SCardListReadersA(
841                                             context, nullptr, reinterpret_cast<LPSTR>(&mszReaders), &chReaders);
842                                         if (status == SCARD_S_SUCCESS)
843                                                 status = SCardConnectA(context, mszReaders, SCARD_SHARE_SHARED,
844                                                                        SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1 |
845                                                                            SCARD_PROTOCOL_Tx | SCARD_PROTOCOL_RAW,
846                                                                        &handle, &protocol);
847                                         SCardFreeMemory(context, mszReaders);
848                                         if (status != SCARD_S_SUCCESS)
849                                         {
850                                                 std::cerr << "SCardConnectA ["
851                                                           << "] failed with " << err2str(status) << std::endl;
852                                         }
853                                         else
854                                         {
855                                                 test_status_a(handle);
856                                                 test_status_w(handle);
857                                                 test_get_attrib(context, handle);
858                                                 test_set_attrib(context, handle);
859                                                 test_transmitcount(handle);
860
861                                                 status = SCardDisconnect(handle, 0);
862                                                 if (status)
863                                                 {
864                                                         std::cerr << "SCardDisconnect ["
865                                                                   << "] failed with " << err2str(status) << std::endl;
866                                                 }
867                                         }
868                                 }
869                                 {
870                                         DWORD protocol;
871                                         SCARDHANDLE handle = 0;
872                                         LPWSTR mszReaders;
873                                         DWORD chReaders = SCARD_AUTOALLOCATE;
874
875                                         LONG status = SCardListReadersW(
876                                             context, nullptr, reinterpret_cast<LPWSTR>(&mszReaders), &chReaders);
877                                         if (status == SCARD_S_SUCCESS)
878                                                 status = SCardConnectW(context, mszReaders, SCARD_SHARE_SHARED,
879                                                                        SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1 |
880                                                                            SCARD_PROTOCOL_Tx | SCARD_PROTOCOL_RAW,
881                                                                        &handle, &protocol);
882                                         SCardFreeMemory(context, mszReaders);
883
884                                         if (status != SCARD_S_SUCCESS)
885                                         {
886                                                 std::cerr << "SCardConnectW ["
887                                                           << "] failed with " << err2str(status) << std::endl;
888                                         }
889                                         else
890                                         {
891                                                 test_status_a(handle);
892                                                 test_status_w(handle);
893                                                 test_get_attrib(context, handle);
894                                                 test_set_attrib(context, handle);
895                                                 test_transmitcount(handle);
896
897                                                 status = SCardDisconnect(handle, 0);
898                                                 if (status)
899                                                 {
900                                                         std::cerr << "SCardDisconnect ["
901                                                                   << "] failed with " << err2str(status) << std::endl;
902                                                 }
903                                         }
904                                 }
905
906                                 rc = SCardReleaseContext(context);
907                                 if (rc != SCARD_S_SUCCESS)
908                                 {
909                                         std::cerr << "SCardReleaseContext [" << scope2str(scope) << "] failed with "
910                                                   << err2str(rc) << std::endl;
911                                 }
912                         }
913                 }
914         }
915         catch (...)
916         {
917                 std::cerr << "exception!!!!" << std::endl;
918         }
919
920         return 0;
921 }