Fixed SCardTransmit return
[platform/upstream/freerdp.git] / channels / smartcard / client / smartcard_pack.c
1 /**
2  * FreeRDP: A Remote Desktop Protocol Implementation
3  * Smart Card Structure Packing
4  *
5  * Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
6  * Copyright 2015 Thincast Technologies GmbH
7  * Copyright 2015 DI (FH) Martin Haimberger <martin.haimberger@thincast.com>
8  * Copyright 2020 Armin Novak <armin.novak@thincast.com>
9  * Copyright 2020 Thincast Technologies GmbH
10  *
11  * Licensed under the Apache License, Version 2.0 (the "License");
12  * you may not use this file except in compliance with the License.
13  * You may obtain a copy of the License at
14  *
15  *     http://www.apache.org/licenses/LICENSE-2.0
16  *
17  * Unless required by applicable law or agreed to in writing, software
18  * distributed under the License is distributed on an "AS IS" BASIS,
19  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20  * See the License for the specific language governing permissions and
21  * limitations under the License.
22  */
23
24 #ifdef HAVE_CONFIG_H
25 #include "config.h"
26 #endif
27
28 #include <winpr/crt.h>
29 #include <winpr/print.h>
30
31 #include "smartcard_pack.h"
32
33 static const DWORD g_LogLevel = WLOG_DEBUG;
34
35 #define smartcard_unpack_redir_scard_context(smartcard, s, context, index)                \
36         smartcard_unpack_redir_scard_context_((smartcard), (s), (context), (index), __FILE__, \
37                                               __FUNCTION__, __LINE__)
38 #define smartcard_unpack_redir_scard_handle(smartcard, s, context, index)                \
39         smartcard_unpack_redir_scard_handle_((smartcard), (s), (context), (index), __FILE__, \
40                                              __FUNCTION__, __LINE__)
41
42 static LONG smartcard_unpack_redir_scard_context_(SMARTCARD_DEVICE* smartcard, wStream* s,
43                                                   REDIR_SCARDCONTEXT* context, UINT32* index,
44                                                   const char* file, const char* function, int line);
45 static LONG smartcard_pack_redir_scard_context(SMARTCARD_DEVICE* smartcard, wStream* s,
46                                                const REDIR_SCARDCONTEXT* context, DWORD* index);
47 static LONG smartcard_unpack_redir_scard_handle_(SMARTCARD_DEVICE* smartcard, wStream* s,
48                                                  REDIR_SCARDHANDLE* handle, UINT32* index,
49                                                  const char* file, const char* function, int line);
50 static LONG smartcard_pack_redir_scard_handle(SMARTCARD_DEVICE* smartcard, wStream* s,
51                                               const REDIR_SCARDHANDLE* handle, DWORD* index);
52 static LONG smartcard_unpack_redir_scard_context_ref(SMARTCARD_DEVICE* smartcard, wStream* s,
53                                                      REDIR_SCARDCONTEXT* context);
54 static LONG smartcard_pack_redir_scard_context_ref(SMARTCARD_DEVICE* smartcard, wStream* s,
55                                                    const REDIR_SCARDCONTEXT* context);
56
57 static LONG smartcard_unpack_redir_scard_handle_ref(SMARTCARD_DEVICE* smartcard, wStream* s,
58                                                     REDIR_SCARDHANDLE* handle);
59 static LONG smartcard_pack_redir_scard_handle_ref(SMARTCARD_DEVICE* smartcard, wStream* s,
60                                                   const REDIR_SCARDHANDLE* handle);
61
62 typedef enum
63 {
64         NDR_PTR_FULL,
65         NDR_PTR_SIMPLE,
66         NDR_PTR_FIXED
67 } ndr_ptr_t;
68
69 /* Reads a NDR pointer and checks if the value read has the expected relative
70  * addressing */
71 #define smartcard_ndr_pointer_read(s, index, ptr) \
72         smartcard_ndr_pointer_read_((s), (index), (ptr), __FILE__, __FUNCTION__, __LINE__)
73 static BOOL smartcard_ndr_pointer_read_(wStream* s, UINT32* index, UINT32* ptr, const char* file,
74                                         const char* fkt, int line)
75 {
76         const UINT32 expect = 0x20000 + (*index) * 4;
77         UINT32 ndrPtr;
78         WINPR_UNUSED(file);
79         if (!s)
80                 return FALSE;
81         if (Stream_GetRemainingLength(s) < 4)
82                 return FALSE;
83
84         Stream_Read_UINT32(s, ndrPtr); /* mszGroupsNdrPtr (4 bytes) */
85         if (ptr)
86                 *ptr = ndrPtr;
87         if (expect != ndrPtr)
88         {
89                 /* Allow NULL pointer if we read the result */
90                 if (ptr && (ndrPtr == 0))
91                         return TRUE;
92                 WLog_WARN(TAG, "[%s:%d] Read context pointer 0x%08" PRIx32 ", expected 0x%08" PRIx32, fkt,
93                           line, ndrPtr, expect);
94                 return FALSE;
95         }
96
97         (*index) = (*index) + 1;
98         return TRUE;
99 }
100
101 static LONG smartcard_ndr_read(wStream* s, BYTE** data, size_t min, size_t elementSize,
102                                ndr_ptr_t type)
103 {
104         size_t len, offset, len2;
105         void* r;
106         size_t required;
107
108         switch (type)
109         {
110                 case NDR_PTR_FULL:
111                         required = 12;
112                         break;
113                 case NDR_PTR_SIMPLE:
114                         required = 4;
115                         break;
116                 case NDR_PTR_FIXED:
117                         required = min;
118                         break;
119         }
120
121         if (Stream_GetRemainingLength(s) < required)
122         {
123                 WLog_ERR(TAG, "Short data while trying to read NDR pointer, expected 4, got %" PRIu32,
124                          Stream_GetRemainingLength(s));
125                 return STATUS_BUFFER_TOO_SMALL;
126         }
127
128         switch (type)
129         {
130                 case NDR_PTR_FULL:
131                         Stream_Read_UINT32(s, len);
132                         Stream_Read_UINT32(s, offset);
133                         Stream_Read_UINT32(s, len2);
134                         if (len != offset + len2)
135                         {
136                                 WLog_ERR(TAG,
137                                          "Invalid data when reading full NDR pointer: total=%" PRIu32
138                                          ", offset=%" PRIu32 ", remaining=%" PRIu32,
139                                          len, offset, len2);
140                                 return STATUS_BUFFER_TOO_SMALL;
141                         }
142                         break;
143                 case NDR_PTR_SIMPLE:
144                         Stream_Read_UINT32(s, len);
145
146                         if ((len != min) && (min > 0))
147                         {
148                                 WLog_ERR(TAG,
149                                          "Invalid data when reading simple NDR pointer: total=%" PRIu32
150                                          ", expected=%" PRIu32,
151                                          len, min);
152                                 return STATUS_BUFFER_TOO_SMALL;
153                         }
154                         break;
155                 case NDR_PTR_FIXED:
156                         len = (UINT32)min;
157                         break;
158         }
159
160         if (min > len)
161         {
162                 WLog_ERR(TAG, "Invalid length read from NDR pointer, minimum %" PRIu32 ", got %" PRIu32,
163                          min, len);
164                 return STATUS_DATA_ERROR;
165         }
166
167         if (len > SIZE_MAX / 2)
168                 return STATUS_BUFFER_TOO_SMALL;
169
170         if (Stream_GetRemainingLength(s) / elementSize < len)
171         {
172                 WLog_ERR(TAG,
173                          "Short data while trying to read data from NDR pointer, expected %" PRIu32
174                          ", got %" PRIu32,
175                          len, Stream_GetRemainingLength(s));
176                 return STATUS_BUFFER_TOO_SMALL;
177         }
178         len *= elementSize;
179
180         r = calloc(len + 1, sizeof(CHAR));
181         if (!r)
182                 return SCARD_E_NO_MEMORY;
183         Stream_Read(s, r, len);
184         smartcard_unpack_read_size_align(NULL, s, len, 4);
185         *data = r;
186         return STATUS_SUCCESS;
187 }
188
189 static BOOL smartcard_ndr_pointer_write(wStream* s, UINT32* index, DWORD length)
190 {
191         const UINT32 ndrPtr = 0x20000 + (*index) * 4;
192
193         if (!s)
194                 return FALSE;
195         if (!Stream_EnsureRemainingCapacity(s, 4))
196                 return FALSE;
197
198         if (length > 0)
199         {
200                 Stream_Write_UINT32(s, ndrPtr); /* mszGroupsNdrPtr (4 bytes) */
201                 (*index) = (*index) + 1;
202         }
203         else
204                 Stream_Write_UINT32(s, 0);
205         return TRUE;
206 }
207
208 static LONG smartcard_ndr_write(wStream* s, const BYTE* data, UINT32 size, UINT32 elementSize,
209                                 ndr_ptr_t type)
210 {
211         const UINT32 offset = 0;
212         const UINT32 len = size;
213         const UINT32 dataLen = size * elementSize;
214         size_t required;
215
216         if (size == 0)
217                 return SCARD_S_SUCCESS;
218
219         switch (type)
220         {
221                 case NDR_PTR_FULL:
222                         required = 12;
223                         break;
224                 case NDR_PTR_SIMPLE:
225                         required = 4;
226                         break;
227                 case NDR_PTR_FIXED:
228                         required = 0;
229                         break;
230         }
231
232         if (!Stream_EnsureRemainingCapacity(s, required + dataLen + 4))
233                 return STATUS_BUFFER_TOO_SMALL;
234
235         switch (type)
236         {
237                 case NDR_PTR_FULL:
238                         Stream_Write_UINT32(s, len);
239                         Stream_Write_UINT32(s, offset);
240                         Stream_Write_UINT32(s, len);
241                         break;
242                 case NDR_PTR_SIMPLE:
243                         Stream_Write_UINT32(s, len);
244                         break;
245                 case NDR_PTR_FIXED:
246                         break;
247         }
248
249         if (data)
250                 Stream_Write(s, data, dataLen);
251         else
252                 Stream_Zero(s, dataLen);
253         return smartcard_pack_write_size_align(NULL, s, len, 4);
254 }
255
256 static LONG smartcard_ndr_write_state(wStream* s, const ReaderState_Return* data, UINT32 size,
257                                       ndr_ptr_t type)
258 {
259         union
260         {
261                 const ReaderState_Return* reader;
262                 const BYTE* data;
263         } cnv;
264
265         cnv.reader = data;
266         return smartcard_ndr_write(s, cnv.data, size, sizeof(ReaderState_Return), type);
267 }
268
269 static LONG smartcard_ndr_read_atrmask(wStream* s, LocateCards_ATRMask** data, size_t min,
270                                        ndr_ptr_t type)
271 {
272         union
273         {
274                 LocateCards_ATRMask** ppc;
275                 BYTE** ppv;
276         } u;
277         u.ppc = data;
278         return smartcard_ndr_read(s, u.ppv, min, sizeof(LocateCards_ATRMask), type);
279 }
280
281 static LONG smartcard_ndr_read_fixed_string_a(wStream* s, CHAR** data, size_t min, ndr_ptr_t type)
282 {
283         union
284         {
285                 CHAR** ppc;
286                 BYTE** ppv;
287         } u;
288         u.ppc = data;
289         return smartcard_ndr_read(s, u.ppv, min, sizeof(CHAR), type);
290 }
291
292 static LONG smartcard_ndr_read_fixed_string_w(wStream* s, WCHAR** data, size_t min, ndr_ptr_t type)
293 {
294         union
295         {
296                 WCHAR** ppc;
297                 BYTE** ppv;
298         } u;
299         u.ppc = data;
300         return smartcard_ndr_read(s, u.ppv, min, sizeof(WCHAR), type);
301 }
302
303 static LONG smartcard_ndr_read_a(wStream* s, CHAR** data, ndr_ptr_t type)
304 {
305         union
306         {
307                 CHAR** ppc;
308                 BYTE** ppv;
309         } u;
310         u.ppc = data;
311         return smartcard_ndr_read(s, u.ppv, 0, sizeof(CHAR), type);
312 }
313
314 static LONG smartcard_ndr_read_w(wStream* s, WCHAR** data, ndr_ptr_t type)
315 {
316         union
317         {
318                 WCHAR** ppc;
319                 BYTE** ppv;
320         } u;
321         u.ppc = data;
322         return smartcard_ndr_read(s, u.ppv, 0, sizeof(WCHAR), type);
323 }
324
325 static LONG smartcard_ndr_read_u(wStream* s, UUID** data)
326 {
327         union
328         {
329                 UUID** ppc;
330                 BYTE** ppv;
331         } u;
332         u.ppc = data;
333         return smartcard_ndr_read(s, u.ppv, 1, sizeof(UUID), NDR_PTR_FIXED);
334 }
335
336 static char* smartcard_convert_string_list(const void* in, size_t bytes, BOOL unicode)
337 {
338         size_t index, length;
339         union
340         {
341                 const void* pv;
342                 const char* sz;
343                 const WCHAR* wz;
344         } string;
345         char* mszA = NULL;
346
347         string.pv = in;
348
349         if (bytes < 1)
350                 return NULL;
351
352         if (unicode)
353         {
354                 length = (bytes / 2);
355                 if (ConvertFromUnicode(CP_UTF8, 0, string.wz, (int)length, &mszA, 0, NULL, NULL) !=
356                     (int)length)
357                 {
358                         free(mszA);
359                         return NULL;
360                 }
361         }
362         else
363         {
364                 length = bytes;
365                 mszA = (char*)malloc(length);
366                 if (!mszA)
367                         return NULL;
368                 CopyMemory(mszA, string.sz, length);
369         }
370
371         for (index = 0; index < length - 1; index++)
372         {
373                 if (mszA[index] == '\0')
374                         mszA[index] = ',';
375         }
376
377         return mszA;
378 }
379
380 static char* smartcard_msz_dump_a(const char* msz, size_t len, char* buffer, size_t bufferLen)
381 {
382         char* buf = buffer;
383         const char* cur = msz;
384
385         while ((len > 0) && cur && cur[0] != '\0' && (bufferLen > 0))
386         {
387                 size_t clen = strnlen(cur, len);
388                 int rc = _snprintf(buf, bufferLen, "%s", cur);
389                 bufferLen -= (size_t)rc;
390                 buf += rc;
391
392                 cur += clen;
393         }
394
395         return buffer;
396 }
397
398 static char* smartcard_msz_dump_w(const WCHAR* msz, size_t len, char* buffer, size_t bufferLen)
399 {
400         char* sz = NULL;
401         ConvertFromUnicode(CP_UTF8, 0, msz, (int)len, &sz, 0, NULL, NULL);
402         return smartcard_msz_dump_a(sz, len, buffer, bufferLen);
403 }
404
405 static char* smartcard_array_dump(const void* pd, size_t len, char* buffer, size_t bufferLen)
406 {
407         const BYTE* data = pd;
408         size_t x;
409         int rc;
410         char* start = buffer;
411
412         /* Ensure '\0' termination */
413         if (bufferLen > 0)
414         {
415                 buffer[bufferLen - 1] = '\0';
416                 bufferLen--;
417         }
418
419         rc = _snprintf(buffer, bufferLen, "{ ");
420         if ((rc < 0) || ((size_t)rc > bufferLen))
421                 goto fail;
422         buffer += rc;
423         bufferLen -= (size_t)rc;
424
425         for (x = 0; x < len; x++)
426         {
427                 rc = _snprintf(buffer, bufferLen, "%02X", data[x]);
428                 if ((rc < 0) || ((size_t)rc > bufferLen))
429                         goto fail;
430                 buffer += rc;
431                 bufferLen -= (size_t)rc;
432         }
433
434         rc = _snprintf(buffer, bufferLen, " }");
435         if ((rc < 0) || ((size_t)rc > bufferLen))
436                 goto fail;
437         buffer += rc;
438         bufferLen -= (size_t)rc;
439
440 fail:
441         return start;
442 }
443 static void smartcard_log_redir_handle(const char* tag, const REDIR_SCARDHANDLE* pHandle)
444 {
445         char buffer[128];
446
447         WLog_LVL(tag, g_LogLevel, "  hContext: %s",
448                  smartcard_array_dump(pHandle->pbHandle, pHandle->cbHandle, buffer, sizeof(buffer)));
449 }
450
451 static void smartcard_log_context(const char* tag, const REDIR_SCARDCONTEXT* phContext)
452 {
453         char buffer[128];
454         WLog_DBG(
455             tag, "hContext: %s",
456             smartcard_array_dump(phContext->pbContext, phContext->cbContext, buffer, sizeof(buffer)));
457 }
458
459 static void smartcard_trace_context_and_string_call_a(const char* name,
460                                                       const REDIR_SCARDCONTEXT* phContext,
461                                                       const CHAR* sz)
462 {
463         if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel))
464                 return;
465
466         WLog_LVL(TAG, g_LogLevel, "%s {", name);
467         smartcard_log_context(TAG, phContext);
468         WLog_LVL(TAG, g_LogLevel, "  sz=%s", sz);
469
470         WLog_LVL(TAG, g_LogLevel, "}");
471 }
472
473 static void smartcard_trace_context_and_string_call_w(const char* name,
474                                                       const REDIR_SCARDCONTEXT* phContext,
475                                                       const WCHAR* sz)
476 {
477         char* tmp = NULL;
478         if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel))
479                 return;
480
481         WLog_LVL(TAG, g_LogLevel, "%s {", name);
482         smartcard_log_context(TAG, phContext);
483         ConvertFromUnicode(CP_UTF8, 0, sz, -1, &tmp, 0, NULL, NULL);
484         WLog_LVL(TAG, g_LogLevel, "  sz=%s", tmp);
485         free(tmp);
486
487         WLog_LVL(TAG, g_LogLevel, "}");
488 }
489
490 static void smartcard_trace_context_call(SMARTCARD_DEVICE* smartcard, const Context_Call* call,
491                                          const char* name)
492 {
493         WINPR_UNUSED(smartcard);
494
495         if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel))
496                 return;
497
498         WLog_LVL(TAG, g_LogLevel, "%s_Call {", name);
499         smartcard_log_context(TAG, &call->handles.hContext);
500
501         WLog_LVL(TAG, g_LogLevel, "}");
502 }
503
504 static void smartcard_trace_list_reader_groups_call(SMARTCARD_DEVICE* smartcard,
505                                                     const ListReaderGroups_Call* call, BOOL unicode)
506 {
507         WINPR_UNUSED(smartcard);
508
509         if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel))
510                 return;
511
512         WLog_LVL(TAG, g_LogLevel, "ListReaderGroups%S_Call {", unicode ? "W" : "A");
513         smartcard_log_context(TAG, &call->handles.hContext);
514
515         WLog_LVL(TAG, g_LogLevel, "fmszGroupsIsNULL: %" PRId32 " cchGroups: 0x%08" PRIx32,
516                  call->fmszGroupsIsNULL, call->cchGroups);
517         WLog_LVL(TAG, g_LogLevel, "}");
518 }
519
520 static void smartcard_trace_get_status_change_w_call(SMARTCARD_DEVICE* smartcard,
521                                                      const GetStatusChangeW_Call* call)
522 {
523         UINT32 index;
524         char* szEventState;
525         char* szCurrentState;
526         LPSCARD_READERSTATEW readerState;
527         WINPR_UNUSED(smartcard);
528
529         if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel))
530                 return;
531
532         WLog_LVL(TAG, g_LogLevel, "GetStatusChangeW_Call {");
533         smartcard_log_context(TAG, &call->handles.hContext);
534
535         WLog_LVL(TAG, g_LogLevel, "dwTimeOut: 0x%08" PRIX32 " cReaders: %" PRIu32 "", call->dwTimeOut,
536                  call->cReaders);
537
538         for (index = 0; index < call->cReaders; index++)
539         {
540                 char* szReaderA = NULL;
541                 readerState = &call->rgReaderStates[index];
542                 ConvertFromUnicode(CP_UTF8, 0, readerState->szReader, -1, &szReaderA, 0, NULL, NULL);
543                 WLog_LVL(TAG, g_LogLevel, "\t[%" PRIu32 "]: szReader: %s cbAtr: %" PRIu32 "", index,
544                          szReaderA, readerState->cbAtr);
545                 szCurrentState = SCardGetReaderStateString(readerState->dwCurrentState);
546                 szEventState = SCardGetReaderStateString(readerState->dwEventState);
547                 WLog_LVL(TAG, g_LogLevel, "\t[%" PRIu32 "]: dwCurrentState: %s (0x%08" PRIX32 ")", index,
548                          szCurrentState, readerState->dwCurrentState);
549                 WLog_LVL(TAG, g_LogLevel, "\t[%" PRIu32 "]: dwEventState: %s (0x%08" PRIX32 ")", index,
550                          szEventState, readerState->dwEventState);
551                 free(szCurrentState);
552                 free(szEventState);
553                 free(szReaderA);
554         }
555
556         WLog_LVL(TAG, g_LogLevel, "}");
557 }
558
559 static void smartcard_trace_list_reader_groups_return(SMARTCARD_DEVICE* smartcard,
560                                                       const ListReaderGroups_Return* ret,
561                                                       BOOL unicode)
562 {
563         char* mszA = NULL;
564         WINPR_UNUSED(smartcard);
565
566         if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel))
567                 return;
568
569         mszA = smartcard_convert_string_list(ret->msz, ret->cBytes, unicode);
570
571         WLog_LVL(TAG, g_LogLevel, "ListReaderGroups%s_Return {", unicode ? "W" : "A");
572         WLog_LVL(TAG, g_LogLevel, "  ReturnCode: %s (0x%08" PRIx32 ")",
573                  SCardGetErrorString(ret->ReturnCode), ret->ReturnCode);
574         WLog_LVL(TAG, g_LogLevel, "  cBytes: %" PRIu32 " msz: %s", ret->cBytes, mszA);
575         WLog_LVL(TAG, g_LogLevel, "}");
576         free(mszA);
577 }
578
579 static void smartcard_trace_list_readers_call(SMARTCARD_DEVICE* smartcard,
580                                               const ListReaders_Call* call, BOOL unicode)
581 {
582         char* mszGroupsA = NULL;
583         WINPR_UNUSED(smartcard);
584
585         if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel))
586                 return;
587
588         mszGroupsA = smartcard_convert_string_list(call->mszGroups, call->cBytes, unicode);
589
590         WLog_LVL(TAG, g_LogLevel, "ListReaders%s_Call {", unicode ? "W" : "A");
591         smartcard_log_context(TAG, &call->handles.hContext);
592
593         WLog_LVL(TAG, g_LogLevel,
594                  "cBytes: %" PRIu32 " mszGroups: %s fmszReadersIsNULL: %" PRId32
595                  " cchReaders: 0x%08" PRIX32 "",
596                  call->cBytes, mszGroupsA, call->fmszReadersIsNULL, call->cchReaders);
597         WLog_LVL(TAG, g_LogLevel, "}");
598
599         free(mszGroupsA);
600 }
601
602 static void smartcard_trace_locate_cards_by_atr_a_call(SMARTCARD_DEVICE* smartcard,
603                                                        const LocateCardsByATRA_Call* call)
604 {
605         UINT32 index;
606         char* szEventState;
607         char* szCurrentState;
608
609         WINPR_UNUSED(smartcard);
610
611         if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel))
612                 return;
613
614         WLog_LVL(TAG, g_LogLevel, "LocateCardsByATRA_Call {");
615         smartcard_log_context(TAG, &call->handles.hContext);
616
617         for (index = 0; index < call->cReaders; index++)
618         {
619                 char buffer[1024];
620                 const LPSCARD_READERSTATEA readerState = &call->rgReaderStates[index];
621
622                 WLog_LVL(TAG, g_LogLevel, "\t[%" PRIu32 "]: szReader: %s cbAtr: %" PRIu32 "", index,
623                          readerState->szReader, readerState->cbAtr);
624                 szCurrentState = SCardGetReaderStateString(readerState->dwCurrentState);
625                 szEventState = SCardGetReaderStateString(readerState->dwEventState);
626                 WLog_LVL(TAG, g_LogLevel, "\t[%" PRIu32 "]: dwCurrentState: %s (0x%08" PRIX32 ")", index,
627                          szCurrentState, readerState->dwCurrentState);
628                 WLog_LVL(TAG, g_LogLevel, "\t[%" PRIu32 "]: dwEventState: %s (0x%08" PRIX32 ")", index,
629                          szEventState, readerState->dwEventState);
630
631                 WLog_DBG(
632                     TAG, "\t[%" PRIu32 "]: cbAtr: %" PRIu32 " rgbAtr: %s", index, readerState->cbAtr,
633                     smartcard_array_dump(readerState->rgbAtr, readerState->cbAtr, buffer, sizeof(buffer)));
634
635                 free(szCurrentState);
636                 free(szEventState);
637         }
638
639         WLog_LVL(TAG, g_LogLevel, "}");
640 }
641
642 static void smartcard_trace_locate_cards_a_call(SMARTCARD_DEVICE* smartcard,
643                                                 const LocateCardsA_Call* call)
644 {
645         char buffer[8192];
646         WINPR_UNUSED(smartcard);
647
648         if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel))
649                 return;
650
651         WLog_LVL(TAG, g_LogLevel, "LocateCardsA_Call {");
652         smartcard_log_context(TAG, &call->handles.hContext);
653         WLog_LVL(TAG, g_LogLevel, " cBytes=%" PRId32, call->cBytes);
654         WLog_LVL(TAG, g_LogLevel, " mszCards=%s",
655                  smartcard_msz_dump_a(call->mszCards, call->cBytes, buffer, sizeof(buffer)));
656         WLog_LVL(TAG, g_LogLevel, " cReaders=%" PRId32, call->cReaders);
657         // WLog_LVL(TAG, g_LogLevel, " cReaders=%" PRId32, call->rgReaderStates);
658
659         WLog_LVL(TAG, g_LogLevel, "}");
660 }
661
662 static void smartcard_trace_locate_cards_return(SMARTCARD_DEVICE* smartcard,
663                                                 const LocateCards_Return* ret)
664 {
665         WINPR_UNUSED(smartcard);
666         if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel))
667                 return;
668
669         WLog_LVL(TAG, g_LogLevel, "LocateCards_Return {");
670         WLog_LVL(TAG, g_LogLevel, "  ReturnCode: %s (0x%08" PRIX32 ")",
671                  SCardGetErrorString(ret->ReturnCode), ret->ReturnCode);
672
673         if (ret->ReturnCode == SCARD_S_SUCCESS)
674         {
675                 WLog_LVL(TAG, g_LogLevel, "  cReaders=%" PRId32, ret->cReaders);
676         }
677         WLog_LVL(TAG, g_LogLevel, "}");
678 }
679
680 static void smartcard_trace_get_reader_icon_return(SMARTCARD_DEVICE* smartcard,
681                                                    const GetReaderIcon_Return* ret)
682 {
683         WINPR_UNUSED(smartcard);
684         if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel))
685                 return;
686
687         WLog_LVL(TAG, g_LogLevel, "GetReaderIcon_Return {");
688         WLog_LVL(TAG, g_LogLevel, "  ReturnCode: %s (0x%08" PRIX32 ")",
689                  SCardGetErrorString(ret->ReturnCode), ret->ReturnCode);
690
691         if (ret->ReturnCode == SCARD_S_SUCCESS)
692         {
693                 WLog_LVL(TAG, g_LogLevel, "  cbDataLen=%" PRId32, ret->cbDataLen);
694         }
695         WLog_LVL(TAG, g_LogLevel, "}");
696 }
697
698 static void smartcard_trace_get_transmit_count_return(SMARTCARD_DEVICE* smartcard,
699                                                       const GetTransmitCount_Return* ret)
700 {
701         WINPR_UNUSED(smartcard);
702         if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel))
703                 return;
704
705         WLog_LVL(TAG, g_LogLevel, "GetTransmitCount_Return {");
706         WLog_LVL(TAG, g_LogLevel, "  ReturnCode: %s (0x%08" PRIX32 ")",
707                  SCardGetErrorString(ret->ReturnCode), ret->ReturnCode);
708
709         WLog_LVL(TAG, g_LogLevel, "  cTransmitCount=%" PRIu32, ret->cTransmitCount);
710         WLog_LVL(TAG, g_LogLevel, "}");
711 }
712
713 static void smartcard_trace_read_cache_return(SMARTCARD_DEVICE* smartcard,
714                                               const ReadCache_Return* ret)
715 {
716         WINPR_UNUSED(smartcard);
717         if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel))
718                 return;
719
720         WLog_LVL(TAG, g_LogLevel, "ReadCache_Return {");
721         WLog_LVL(TAG, g_LogLevel, "  ReturnCode: %s (0x%08" PRIX32 ")",
722                  SCardGetErrorString(ret->ReturnCode), ret->ReturnCode);
723
724         if (ret->ReturnCode == SCARD_S_SUCCESS)
725         {
726                 char buffer[1024];
727                 WLog_LVL(TAG, g_LogLevel, " cbDataLen=%" PRId32, ret->cbDataLen);
728                 WLog_LVL(TAG, g_LogLevel, "  cbData: %s",
729                          smartcard_array_dump(ret->pbData, ret->cbDataLen, buffer, sizeof(buffer)));
730         }
731         WLog_LVL(TAG, g_LogLevel, "}");
732 }
733
734 static void smartcard_trace_locate_cards_w_call(SMARTCARD_DEVICE* smartcard,
735                                                 const LocateCardsW_Call* call)
736 {
737         char buffer[8192];
738         WINPR_UNUSED(smartcard);
739         if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel))
740                 return;
741
742         WLog_LVL(TAG, g_LogLevel, "LocateCardsW_Call {");
743         smartcard_log_context(TAG, &call->handles.hContext);
744         WLog_LVL(TAG, g_LogLevel, " cBytes=%" PRId32, call->cBytes);
745         WLog_LVL(TAG, g_LogLevel, " sz2=%s",
746                  smartcard_msz_dump_w(call->mszCards, call->cBytes, buffer, sizeof(buffer)));
747         WLog_LVL(TAG, g_LogLevel, " cReaders=%" PRId32, call->cReaders);
748         // WLog_LVL(TAG, g_LogLevel, " sz2=%s", call->rgReaderStates);
749         WLog_LVL(TAG, g_LogLevel, "}");
750 }
751
752 static void smartcard_trace_list_readers_return(SMARTCARD_DEVICE* smartcard,
753                                                 const ListReaders_Return* ret, BOOL unicode)
754 {
755         char* mszA = NULL;
756         WINPR_UNUSED(smartcard);
757
758         if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel))
759                 return;
760
761         WLog_LVL(TAG, g_LogLevel, "ListReaders%s_Return {", unicode ? "W" : "A");
762         WLog_LVL(TAG, g_LogLevel, "  ReturnCode: %s (0x%08" PRIX32 ")",
763                  SCardGetErrorString(ret->ReturnCode), ret->ReturnCode);
764
765         if (ret->ReturnCode != SCARD_S_SUCCESS)
766         {
767                 WLog_LVL(TAG, g_LogLevel, "}");
768                 return;
769         }
770
771         mszA = smartcard_convert_string_list(ret->msz, ret->cBytes, unicode);
772
773         WLog_LVL(TAG, g_LogLevel, "  cBytes: %" PRIu32 " msz: %s", ret->cBytes, mszA);
774         WLog_LVL(TAG, g_LogLevel, "}");
775         free(mszA);
776 }
777
778 static void smartcard_trace_get_status_change_return(SMARTCARD_DEVICE* smartcard,
779                                                      const GetStatusChange_Return* ret,
780                                                      BOOL unicode)
781 {
782         UINT32 index;
783         char* szEventState;
784         char* szCurrentState;
785
786         WINPR_UNUSED(smartcard);
787
788         if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel))
789                 return;
790
791         WLog_LVL(TAG, g_LogLevel, "GetStatusChange%s_Return {", unicode ? "W" : "A");
792         WLog_LVL(TAG, g_LogLevel, "  ReturnCode: %s (0x%08" PRIX32 ")",
793                  SCardGetErrorString(ret->ReturnCode), ret->ReturnCode);
794         WLog_LVL(TAG, g_LogLevel, "  cReaders: %" PRIu32 "", ret->cReaders);
795
796         for (index = 0; index < ret->cReaders; index++)
797         {
798                 char buffer[1024];
799                 const ReaderState_Return* rgReaderState = &(ret->rgReaderStates[index]);
800                 szCurrentState = SCardGetReaderStateString(rgReaderState->dwCurrentState);
801                 szEventState = SCardGetReaderStateString(rgReaderState->dwEventState);
802                 WLog_LVL(TAG, g_LogLevel, "    [%" PRIu32 "]: dwCurrentState: %s (0x%08" PRIX32 ")", index,
803                          szCurrentState, rgReaderState->dwCurrentState);
804                 WLog_LVL(TAG, g_LogLevel, "    [%" PRIu32 "]: dwEventState: %s (0x%08" PRIX32 ")", index,
805                          szEventState, rgReaderState->dwEventState);
806                 WLog_LVL(TAG, g_LogLevel, "    [%" PRIu32 "]: cbAtr: %" PRIu32 " rgbAtr: %s", index,
807                          rgReaderState->cbAtr,
808                          smartcard_array_dump(rgReaderState->rgbAtr, rgReaderState->cbAtr, buffer,
809                                               sizeof(buffer)));
810                 free(szCurrentState);
811                 free(szEventState);
812         }
813
814         WLog_LVL(TAG, g_LogLevel, "}");
815 }
816
817 static void smartcard_trace_context_and_two_strings_a_call(SMARTCARD_DEVICE* smartcard,
818                                                            const ContextAndTwoStringA_Call* call)
819 {
820         WINPR_UNUSED(smartcard);
821         if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel))
822                 return;
823
824         WLog_LVL(TAG, g_LogLevel, "ContextAndTwoStringW_Call {");
825         smartcard_log_context(TAG, &call->handles.hContext);
826         WLog_LVL(TAG, g_LogLevel, " sz1=%s", call->sz1);
827         WLog_LVL(TAG, g_LogLevel, " sz2=%s", call->sz2);
828         WLog_LVL(TAG, g_LogLevel, "}");
829 }
830
831 static void smartcard_trace_context_and_two_strings_w_call(SMARTCARD_DEVICE* smartcard,
832                                                            const ContextAndTwoStringW_Call* call)
833 {
834         CHAR* sz1 = NULL;
835         CHAR* sz2 = NULL;
836
837         WINPR_UNUSED(smartcard);
838         if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel))
839                 return;
840
841         WLog_LVL(TAG, g_LogLevel, "ContextAndTwoStringW_Call {");
842         smartcard_log_context(TAG, &call->handles.hContext);
843         ConvertFromUnicode(CP_UTF8, 0, call->sz1, -1, &sz1, 0, NULL, NULL);
844         ConvertFromUnicode(CP_UTF8, 0, call->sz2, -1, &sz2, 0, NULL, NULL);
845         WLog_LVL(TAG, g_LogLevel, " sz1=%s", sz1);
846         WLog_LVL(TAG, g_LogLevel, " sz2=%s", sz2);
847         free(sz1);
848         free(sz2);
849
850         WLog_LVL(TAG, g_LogLevel, "}");
851 }
852
853 static void smartcard_trace_get_transmit_count_call(SMARTCARD_DEVICE* smartcard,
854                                                     const GetTransmitCount_Call* call)
855 {
856         WINPR_UNUSED(smartcard);
857         if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel))
858                 return;
859
860         WLog_LVL(TAG, g_LogLevel, "GetTransmitCount_Call {");
861         smartcard_log_context(TAG, &call->handles.hContext);
862         smartcard_log_redir_handle(TAG, &call->handles.hCard);
863
864         WLog_LVL(TAG, g_LogLevel, "}");
865 }
866
867 static void smartcard_trace_write_cache_a_call(SMARTCARD_DEVICE* smartcard,
868                                                const WriteCacheA_Call* call)
869 {
870         char buffer[1024];
871         WINPR_UNUSED(smartcard);
872         if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel))
873                 return;
874
875         WLog_LVL(TAG, g_LogLevel, "GetTransmitCount_Call {");
876
877         WLog_LVL(TAG, g_LogLevel, "  szLookupName=%s", call->szLookupName);
878
879         smartcard_log_context(TAG, &call->Common.handles.hContext);
880         WLog_DBG(
881             TAG, "..CardIdentifier=%s",
882             smartcard_array_dump(call->Common.CardIdentifier, sizeof(UUID), buffer, sizeof(buffer)));
883         WLog_LVL(TAG, g_LogLevel, "  FreshnessCounter=%" PRIu32, call->Common.FreshnessCounter);
884         WLog_LVL(TAG, g_LogLevel, "  cbDataLen=%" PRIu32, call->Common.cbDataLen);
885         WLog_DBG(
886             TAG, "  pbData=%s",
887             smartcard_array_dump(call->Common.pbData, call->Common.cbDataLen, buffer, sizeof(buffer)));
888         WLog_LVL(TAG, g_LogLevel, "}");
889 }
890
891 static void smartcard_trace_write_cache_w_call(SMARTCARD_DEVICE* smartcard,
892                                                const WriteCacheW_Call* call)
893 {
894         char* tmp = NULL;
895         char buffer[1024];
896         WINPR_UNUSED(smartcard);
897         if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel))
898                 return;
899
900         WLog_LVL(TAG, g_LogLevel, "GetTransmitCount_Call {");
901
902         ConvertFromUnicode(CP_UTF8, 0, call->szLookupName, -1, &tmp, 0, NULL, NULL);
903         WLog_LVL(TAG, g_LogLevel, "  szLookupName=%s", tmp);
904         free(tmp);
905         smartcard_log_context(TAG, &call->Common.handles.hContext);
906         WLog_DBG(
907             TAG, "..CardIdentifier=%s",
908             smartcard_array_dump(call->Common.CardIdentifier, sizeof(UUID), buffer, sizeof(buffer)));
909         WLog_LVL(TAG, g_LogLevel, "  FreshnessCounter=%" PRIu32, call->Common.FreshnessCounter);
910         WLog_LVL(TAG, g_LogLevel, "  cbDataLen=%" PRIu32, call->Common.cbDataLen);
911         WLog_DBG(
912             TAG, "  pbData=%s",
913             smartcard_array_dump(call->Common.pbData, call->Common.cbDataLen, buffer, sizeof(buffer)));
914         WLog_LVL(TAG, g_LogLevel, "}");
915 }
916
917 static void smartcard_trace_read_cache_a_call(SMARTCARD_DEVICE* smartcard,
918                                               const ReadCacheA_Call* call)
919 {
920         char buffer[1024];
921         WINPR_UNUSED(smartcard);
922         if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel))
923                 return;
924
925         WLog_LVL(TAG, g_LogLevel, "GetTransmitCount_Call {");
926
927         WLog_LVL(TAG, g_LogLevel, "  szLookupName=%s", call->szLookupName);
928         smartcard_log_context(TAG, &call->Common.handles.hContext);
929         WLog_DBG(
930             TAG, "..CardIdentifier=%s",
931             smartcard_array_dump(call->Common.CardIdentifier, sizeof(UUID), buffer, sizeof(buffer)));
932         WLog_LVL(TAG, g_LogLevel, "  FreshnessCounter=%" PRIu32, call->Common.FreshnessCounter);
933         WLog_LVL(TAG, g_LogLevel, "  fPbDataIsNULL=%" PRId32, call->Common.fPbDataIsNULL);
934         WLog_LVL(TAG, g_LogLevel, "  cbDataLen=%" PRIu32, call->Common.cbDataLen);
935
936         WLog_LVL(TAG, g_LogLevel, "}");
937 }
938
939 static void smartcard_trace_read_cache_w_call(SMARTCARD_DEVICE* smartcard,
940                                               const ReadCacheW_Call* call)
941 {
942         char* tmp = NULL;
943         char buffer[1024];
944         WINPR_UNUSED(smartcard);
945         if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel))
946                 return;
947
948         WLog_LVL(TAG, g_LogLevel, "GetTransmitCount_Call {");
949
950         ConvertFromUnicode(CP_UTF8, 0, call->szLookupName, -1, &tmp, 0, NULL, NULL);
951         WLog_LVL(TAG, g_LogLevel, "  szLookupName=%s", tmp);
952         free(tmp);
953         smartcard_log_context(TAG, &call->Common.handles.hContext);
954         WLog_DBG(
955             TAG, "..CardIdentifier=%s",
956             smartcard_array_dump(call->Common.CardIdentifier, sizeof(UUID), buffer, sizeof(buffer)));
957         WLog_LVL(TAG, g_LogLevel, "  FreshnessCounter=%" PRIu32, call->Common.FreshnessCounter);
958         WLog_LVL(TAG, g_LogLevel, "  fPbDataIsNULL=%" PRId32, call->Common.fPbDataIsNULL);
959         WLog_LVL(TAG, g_LogLevel, "  cbDataLen=%" PRIu32, call->Common.cbDataLen);
960
961         WLog_LVL(TAG, g_LogLevel, "}");
962 }
963
964 static void smartcard_trace_transmit_call(SMARTCARD_DEVICE* smartcard, const Transmit_Call* call)
965 {
966         UINT32 cbExtraBytes;
967         BYTE* pbExtraBytes;
968         WINPR_UNUSED(smartcard);
969
970         if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel))
971                 return;
972
973         WLog_LVL(TAG, g_LogLevel, "Transmit_Call {");
974         smartcard_log_context(TAG, &call->handles.hContext);
975         smartcard_log_redir_handle(TAG, &call->handles.hCard);
976
977         if (call->pioSendPci)
978         {
979                 cbExtraBytes = (UINT32)(call->pioSendPci->cbPciLength - sizeof(SCARD_IO_REQUEST));
980                 pbExtraBytes = &((BYTE*)call->pioSendPci)[sizeof(SCARD_IO_REQUEST)];
981                 WLog_LVL(TAG, g_LogLevel, "pioSendPci: dwProtocol: %" PRIu32 " cbExtraBytes: %" PRIu32 "",
982                          call->pioSendPci->dwProtocol, cbExtraBytes);
983
984                 if (cbExtraBytes)
985                 {
986                         char buffer[1024];
987                         WLog_LVL(TAG, g_LogLevel, "pbExtraBytes: %s",
988                                  smartcard_array_dump(pbExtraBytes, cbExtraBytes, buffer, sizeof(buffer)));
989                 }
990         }
991         else
992         {
993                 WLog_LVL(TAG, g_LogLevel, "pioSendPci: null");
994         }
995
996         WLog_LVL(TAG, g_LogLevel, "cbSendLength: %" PRIu32 "", call->cbSendLength);
997
998         if (call->pbSendBuffer)
999         {
1000                 char buffer[1024];
1001                 WLog_DBG(
1002                     TAG, "pbSendBuffer: %s",
1003                     smartcard_array_dump(call->pbSendBuffer, call->cbSendLength, buffer, sizeof(buffer)));
1004         }
1005         else
1006         {
1007                 WLog_LVL(TAG, g_LogLevel, "pbSendBuffer: null");
1008         }
1009
1010         if (call->pioRecvPci)
1011         {
1012                 cbExtraBytes = (UINT32)(call->pioRecvPci->cbPciLength - sizeof(SCARD_IO_REQUEST));
1013                 pbExtraBytes = &((BYTE*)call->pioRecvPci)[sizeof(SCARD_IO_REQUEST)];
1014                 WLog_LVL(TAG, g_LogLevel, "pioRecvPci: dwProtocol: %" PRIu32 " cbExtraBytes: %" PRIu32 "",
1015                          call->pioRecvPci->dwProtocol, cbExtraBytes);
1016
1017                 if (cbExtraBytes)
1018                 {
1019                         char buffer[1024];
1020                         WLog_LVL(TAG, g_LogLevel, "pbExtraBytes: %s",
1021                                  smartcard_array_dump(pbExtraBytes, cbExtraBytes, buffer, sizeof(buffer)));
1022                 }
1023         }
1024         else
1025         {
1026                 WLog_LVL(TAG, g_LogLevel, "pioRecvPci: null");
1027         }
1028
1029         WLog_LVL(TAG, g_LogLevel, "fpbRecvBufferIsNULL: %" PRId32 " cbRecvLength: %" PRIu32 "",
1030                  call->fpbRecvBufferIsNULL, call->cbRecvLength);
1031         WLog_LVL(TAG, g_LogLevel, "}");
1032 }
1033
1034 static void smartcard_trace_locate_cards_by_atr_w_call(SMARTCARD_DEVICE* smartcard,
1035                                                        const LocateCardsByATRW_Call* call)
1036 {
1037         UINT32 index;
1038         char* szEventState;
1039         char* szCurrentState;
1040
1041         WINPR_UNUSED(smartcard);
1042
1043         if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel))
1044                 return;
1045
1046         WLog_LVL(TAG, g_LogLevel, "LocateCardsByATRW_Call {");
1047         smartcard_log_context(TAG, &call->handles.hContext);
1048
1049         for (index = 0; index < call->cReaders; index++)
1050         {
1051                 char buffer[1024];
1052                 char* tmp = NULL;
1053                 const LPSCARD_READERSTATEW readerState =
1054                     (const LPSCARD_READERSTATEW)&call->rgReaderStates[index];
1055
1056                 ConvertFromUnicode(CP_UTF8, 0, readerState->szReader, -1, &tmp, 0, NULL, NULL);
1057                 WLog_LVL(TAG, g_LogLevel, "\t[%" PRIu32 "]: szReader: %s cbAtr: %" PRIu32 "", index, tmp,
1058                          readerState->cbAtr);
1059                 szCurrentState = SCardGetReaderStateString(readerState->dwCurrentState);
1060                 szEventState = SCardGetReaderStateString(readerState->dwEventState);
1061                 WLog_LVL(TAG, g_LogLevel, "\t[%" PRIu32 "]: dwCurrentState: %s (0x%08" PRIX32 ")", index,
1062                          szCurrentState, readerState->dwCurrentState);
1063                 WLog_LVL(TAG, g_LogLevel, "\t[%" PRIu32 "]: dwEventState: %s (0x%08" PRIX32 ")", index,
1064                          szEventState, readerState->dwEventState);
1065
1066                 WLog_DBG(
1067                     TAG, "\t[%" PRIu32 "]: cbAtr: %" PRIu32 " rgbAtr: %s", index, readerState->cbAtr,
1068                     smartcard_array_dump(readerState->rgbAtr, readerState->cbAtr, buffer, sizeof(buffer)));
1069
1070                 free(szCurrentState);
1071                 free(szEventState);
1072                 free(tmp);
1073         }
1074
1075         WLog_LVL(TAG, g_LogLevel, "}");
1076 }
1077
1078 static void smartcard_trace_transmit_return(SMARTCARD_DEVICE* smartcard, const Transmit_Return* ret)
1079 {
1080         UINT32 cbExtraBytes;
1081         BYTE* pbExtraBytes;
1082         WINPR_UNUSED(smartcard);
1083
1084         if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel))
1085                 return;
1086
1087         WLog_LVL(TAG, g_LogLevel, "Transmit_Return {");
1088         WLog_LVL(TAG, g_LogLevel, "  ReturnCode: %s (0x%08" PRIX32 ")",
1089                  SCardGetErrorString(ret->ReturnCode), ret->ReturnCode);
1090
1091         if (ret->pioRecvPci)
1092         {
1093                 cbExtraBytes = (UINT32)(ret->pioRecvPci->cbPciLength - sizeof(SCARD_IO_REQUEST));
1094                 pbExtraBytes = &((BYTE*)ret->pioRecvPci)[sizeof(SCARD_IO_REQUEST)];
1095                 WLog_LVL(TAG, g_LogLevel, "  pioRecvPci: dwProtocol: %" PRIu32 " cbExtraBytes: %" PRIu32 "",
1096                          ret->pioRecvPci->dwProtocol, cbExtraBytes);
1097
1098                 if (cbExtraBytes)
1099                 {
1100                         char buffer[1024];
1101                         WLog_LVL(TAG, g_LogLevel, "  pbExtraBytes: %s",
1102                                  smartcard_array_dump(pbExtraBytes, cbExtraBytes, buffer, sizeof(buffer)));
1103                 }
1104         }
1105         else
1106         {
1107                 WLog_LVL(TAG, g_LogLevel, "  pioRecvPci: null");
1108         }
1109
1110         WLog_LVL(TAG, g_LogLevel, "  cbRecvLength: %" PRIu32 "", ret->cbRecvLength);
1111
1112         if (ret->pbRecvBuffer)
1113         {
1114                 char buffer[1024];
1115                 WLog_DBG(
1116                     TAG, "  pbRecvBuffer: %s",
1117                     smartcard_array_dump(ret->pbRecvBuffer, ret->cbRecvLength, buffer, sizeof(buffer)));
1118         }
1119         else
1120         {
1121                 WLog_LVL(TAG, g_LogLevel, "  pbRecvBuffer: null");
1122         }
1123
1124         WLog_LVL(TAG, g_LogLevel, "}");
1125 }
1126
1127 static void smartcard_trace_control_return(SMARTCARD_DEVICE* smartcard, const Control_Return* ret)
1128 {
1129         WINPR_UNUSED(smartcard);
1130
1131         if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel))
1132                 return;
1133
1134         WLog_LVL(TAG, g_LogLevel, "Control_Return {");
1135         WLog_LVL(TAG, g_LogLevel, "  ReturnCode: %s (0x%08" PRIX32 ")",
1136                  SCardGetErrorString(ret->ReturnCode), ret->ReturnCode);
1137         WLog_LVL(TAG, g_LogLevel, "  cbOutBufferSize: %" PRIu32 "", ret->cbOutBufferSize);
1138
1139         if (ret->pvOutBuffer)
1140         {
1141                 char buffer[1024];
1142                 WLog_DBG(
1143                     TAG, "pvOutBuffer: %s",
1144                     smartcard_array_dump(ret->pvOutBuffer, ret->cbOutBufferSize, buffer, sizeof(buffer)));
1145         }
1146         else
1147         {
1148                 WLog_LVL(TAG, g_LogLevel, "pvOutBuffer: null");
1149         }
1150
1151         WLog_LVL(TAG, g_LogLevel, "}");
1152 }
1153
1154 static void smartcard_trace_control_call(SMARTCARD_DEVICE* smartcard, const Control_Call* call)
1155 {
1156         WINPR_UNUSED(smartcard);
1157
1158         if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel))
1159                 return;
1160
1161         WLog_LVL(TAG, g_LogLevel, "Control_Call {");
1162         smartcard_log_context(TAG, &call->handles.hContext);
1163         smartcard_log_redir_handle(TAG, &call->handles.hCard);
1164
1165         WLog_LVL(TAG, g_LogLevel,
1166                  "dwControlCode: 0x%08" PRIX32 " cbInBufferSize: %" PRIu32
1167                  " fpvOutBufferIsNULL: %" PRId32 " cbOutBufferSize: %" PRIu32 "",
1168                  call->dwControlCode, call->cbInBufferSize, call->fpvOutBufferIsNULL,
1169                  call->cbOutBufferSize);
1170
1171         if (call->pvInBuffer)
1172         {
1173                 char buffer[1024];
1174                 WLog_DBG(
1175                     TAG, "pbInBuffer: %s",
1176                     smartcard_array_dump(call->pvInBuffer, call->cbInBufferSize, buffer, sizeof(buffer)));
1177         }
1178         else
1179         {
1180                 WLog_LVL(TAG, g_LogLevel, "pvInBuffer: null");
1181         }
1182
1183         WLog_LVL(TAG, g_LogLevel, "}");
1184 }
1185
1186 static void smartcard_trace_set_attrib_call(SMARTCARD_DEVICE* smartcard, const SetAttrib_Call* call)
1187 {
1188         char buffer[8192];
1189         WINPR_UNUSED(smartcard);
1190
1191         if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel))
1192                 return;
1193
1194         WLog_LVL(TAG, g_LogLevel, "GetAttrib_Call {");
1195         smartcard_log_context(TAG, &call->handles.hContext);
1196         smartcard_log_redir_handle(TAG, &call->handles.hCard);
1197         WLog_LVL(TAG, g_LogLevel, "dwAttrId: 0x%08" PRIX32, call->dwAttrId);
1198         WLog_LVL(TAG, g_LogLevel, "cbAttrLen: 0x%08" PRId32, call->cbAttrLen);
1199         WLog_LVL(TAG, g_LogLevel, "pbAttr: %s",
1200                  smartcard_array_dump(call->pbAttr, call->cbAttrLen, buffer, sizeof(buffer)));
1201         WLog_LVL(TAG, g_LogLevel, "}");
1202 }
1203
1204 static void smartcard_trace_get_attrib_return(SMARTCARD_DEVICE* smartcard,
1205                                               const GetAttrib_Return* ret, DWORD dwAttrId)
1206 {
1207         WINPR_UNUSED(smartcard);
1208
1209         if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel))
1210                 return;
1211
1212         WLog_LVL(TAG, g_LogLevel, "GetAttrib_Return {");
1213         WLog_LVL(TAG, g_LogLevel, "  ReturnCode: %s (0x%08" PRIX32 ")",
1214                  SCardGetErrorString(ret->ReturnCode), ret->ReturnCode);
1215         WLog_LVL(TAG, g_LogLevel, "  dwAttrId: %s (0x%08" PRIX32 ") cbAttrLen: 0x%08" PRIX32 "",
1216                  SCardGetAttributeString(dwAttrId), dwAttrId, ret->cbAttrLen);
1217
1218         if (dwAttrId == SCARD_ATTR_VENDOR_NAME)
1219         {
1220                 WLog_LVL(TAG, g_LogLevel, "  pbAttr: %.*s", ret->cbAttrLen, (char*)ret->pbAttr);
1221         }
1222         else if (dwAttrId == SCARD_ATTR_CURRENT_PROTOCOL_TYPE)
1223         {
1224                 union
1225                 {
1226                         BYTE* pb;
1227                         DWORD* pd;
1228                 } attr;
1229                 attr.pb = ret->pbAttr;
1230                 WLog_LVL(TAG, g_LogLevel, "  dwProtocolType: %s (0x%08" PRIX32 ")",
1231                          SCardGetProtocolString(*attr.pd), *attr.pd);
1232         }
1233
1234         WLog_LVL(TAG, g_LogLevel, "}");
1235 }
1236
1237 static void smartcard_trace_get_attrib_call(SMARTCARD_DEVICE* smartcard, const GetAttrib_Call* call)
1238 {
1239         WINPR_UNUSED(smartcard);
1240
1241         if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel))
1242                 return;
1243
1244         WLog_LVL(TAG, g_LogLevel, "GetAttrib_Call {");
1245         smartcard_log_context(TAG, &call->handles.hContext);
1246         smartcard_log_redir_handle(TAG, &call->handles.hCard);
1247
1248         WLog_LVL(TAG, g_LogLevel,
1249                  "dwAttrId: %s (0x%08" PRIX32 ") fpbAttrIsNULL: %" PRId32 " cbAttrLen: 0x%08" PRIX32 "",
1250                  SCardGetAttributeString(call->dwAttrId), call->dwAttrId, call->fpbAttrIsNULL,
1251                  call->cbAttrLen);
1252         WLog_LVL(TAG, g_LogLevel, "}");
1253 }
1254
1255 static void smartcard_trace_status_call(SMARTCARD_DEVICE* smartcard, const Status_Call* call,
1256                                         BOOL unicode)
1257 {
1258         WINPR_UNUSED(smartcard);
1259
1260         if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel))
1261                 return;
1262
1263         WLog_LVL(TAG, g_LogLevel, "Status%s_Call {", unicode ? "W" : "A");
1264         smartcard_log_context(TAG, &call->handles.hContext);
1265         smartcard_log_redir_handle(TAG, &call->handles.hCard);
1266
1267         WLog_LVL(TAG, g_LogLevel,
1268                  "fmszReaderNamesIsNULL: %" PRId32 " cchReaderLen: %" PRIu32 " cbAtrLen: %" PRIu32 "",
1269                  call->fmszReaderNamesIsNULL, call->cchReaderLen, call->cbAtrLen);
1270         WLog_LVL(TAG, g_LogLevel, "}");
1271 }
1272
1273 static void smartcard_trace_status_return(SMARTCARD_DEVICE* smartcard, const Status_Return* ret,
1274                                           BOOL unicode)
1275 {
1276         char* mszReaderNamesA = NULL;
1277         char buffer[1024];
1278
1279         WINPR_UNUSED(smartcard);
1280
1281         if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel))
1282                 return;
1283
1284         mszReaderNamesA = smartcard_convert_string_list(ret->mszReaderNames, ret->cBytes, unicode);
1285
1286         WLog_LVL(TAG, g_LogLevel, "Status%s_Return {", unicode ? "W" : "A");
1287         WLog_LVL(TAG, g_LogLevel, "  ReturnCode: %s (0x%08" PRIX32 ")",
1288                  SCardGetErrorString(ret->ReturnCode), ret->ReturnCode);
1289         WLog_LVL(TAG, g_LogLevel, "  dwState: %s (0x%08" PRIX32 ") dwProtocol: %s (0x%08" PRIX32 ")",
1290                  SCardGetCardStateString(ret->dwState), ret->dwState,
1291                  SCardGetProtocolString(ret->dwProtocol), ret->dwProtocol);
1292
1293         WLog_LVL(TAG, g_LogLevel, "  cBytes: %" PRIu32 " mszReaderNames: %s", ret->cBytes,
1294                  mszReaderNamesA);
1295
1296         WLog_LVL(TAG, g_LogLevel, "  cbAtrLen: %" PRIu32 " pbAtr: %s", ret->cbAtrLen,
1297                  smartcard_array_dump(ret->pbAtr, ret->cbAtrLen, buffer, sizeof(buffer)));
1298         WLog_LVL(TAG, g_LogLevel, "}");
1299         free(mszReaderNamesA);
1300 }
1301
1302 static void smartcard_trace_state_return(SMARTCARD_DEVICE* smartcard, const State_Return* ret)
1303 {
1304         char buffer[1024];
1305
1306         WINPR_UNUSED(smartcard);
1307
1308         if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel))
1309                 return;
1310
1311         WLog_LVL(TAG, g_LogLevel, "Reconnect_Return {");
1312         WLog_LVL(TAG, g_LogLevel, "  ReturnCode: %s (0x%08" PRIX32 ")",
1313                  SCardGetErrorString(ret->ReturnCode), ret->ReturnCode);
1314         WLog_LVL(TAG, g_LogLevel, "  dwState:    %s (0x%08" PRIX32 ")", ret->dwState);
1315         WLog_LVL(TAG, g_LogLevel, "  dwProtocol: %s (0x%08" PRIX32 ")", ret->dwProtocol);
1316         WLog_LVL(TAG, g_LogLevel, "  cbAtrLen:   %s (0x%08" PRIX32 ")", ret->cbAtrLen);
1317         WLog_LVL(TAG, g_LogLevel, "  rgAtr:      %s",
1318                  smartcard_array_dump(ret->rgAtr, sizeof(ret->rgAtr), buffer, sizeof(buffer)));
1319         WLog_LVL(TAG, g_LogLevel, "}");
1320 }
1321
1322 static void smartcard_trace_reconnect_return(SMARTCARD_DEVICE* smartcard,
1323                                              const Reconnect_Return* ret)
1324 {
1325         WINPR_UNUSED(smartcard);
1326
1327         if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel))
1328                 return;
1329
1330         WLog_LVL(TAG, g_LogLevel, "Reconnect_Return {");
1331         WLog_LVL(TAG, g_LogLevel, "  ReturnCode: %s (0x%08" PRIX32 ")",
1332                  SCardGetErrorString(ret->ReturnCode), ret->ReturnCode);
1333         WLog_LVL(TAG, g_LogLevel, "  dwActiveProtocol: %s (0x%08" PRIX32 ")",
1334                  SCardGetProtocolString(ret->dwActiveProtocol), ret->dwActiveProtocol);
1335         WLog_LVL(TAG, g_LogLevel, "}");
1336 }
1337
1338 static void smartcard_trace_connect_a_call(SMARTCARD_DEVICE* smartcard, const ConnectA_Call* call)
1339 {
1340         WINPR_UNUSED(smartcard);
1341
1342         if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel))
1343                 return;
1344
1345         WLog_LVL(TAG, g_LogLevel, "ConnectA_Call {");
1346         smartcard_log_context(TAG, &call->Common.handles.hContext);
1347
1348         WLog_LVL(TAG, g_LogLevel,
1349                  "szReader: %s dwShareMode: %s (0x%08" PRIX32 ") dwPreferredProtocols: %s (0x%08" PRIX32
1350                  ")",
1351                  call->szReader, SCardGetShareModeString(call->Common.dwShareMode),
1352                  call->Common.dwShareMode, SCardGetProtocolString(call->Common.dwPreferredProtocols),
1353                  call->Common.dwPreferredProtocols);
1354         WLog_LVL(TAG, g_LogLevel, "}");
1355 }
1356
1357 static void smartcard_trace_connect_w_call(SMARTCARD_DEVICE* smartcard, const ConnectW_Call* call)
1358 {
1359         char* szReaderA = NULL;
1360         WINPR_UNUSED(smartcard);
1361
1362         if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel))
1363                 return;
1364
1365         ConvertFromUnicode(CP_UTF8, 0, call->szReader, -1, &szReaderA, 0, NULL, NULL);
1366         WLog_LVL(TAG, g_LogLevel, "ConnectW_Call {");
1367         smartcard_log_context(TAG, &call->Common.handles.hContext);
1368
1369         WLog_LVL(TAG, g_LogLevel,
1370                  "szReader: %s dwShareMode: %s (0x%08" PRIX32 ") dwPreferredProtocols: %s (0x%08" PRIX32
1371                  ")",
1372                  szReaderA, SCardGetShareModeString(call->Common.dwShareMode), call->Common.dwShareMode,
1373                  SCardGetProtocolString(call->Common.dwPreferredProtocols),
1374                  call->Common.dwPreferredProtocols);
1375         WLog_LVL(TAG, g_LogLevel, "}");
1376         free(szReaderA);
1377 }
1378
1379 static void smartcard_trace_hcard_and_disposition_call(SMARTCARD_DEVICE* smartcard,
1380                                                        const HCardAndDisposition_Call* call,
1381                                                        const char* name)
1382 {
1383         WINPR_UNUSED(smartcard);
1384
1385         if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel))
1386                 return;
1387
1388         WLog_LVL(TAG, g_LogLevel, "%s_Call {", name);
1389         smartcard_log_context(TAG, &call->handles.hContext);
1390         smartcard_log_redir_handle(TAG, &call->handles.hCard);
1391
1392         WLog_LVL(TAG, g_LogLevel, "dwDisposition: %s (0x%08" PRIX32 ")",
1393                  SCardGetDispositionString(call->dwDisposition), call->dwDisposition);
1394         WLog_LVL(TAG, g_LogLevel, "}");
1395 }
1396
1397 static void smartcard_trace_establish_context_call(SMARTCARD_DEVICE* smartcard,
1398                                                    const EstablishContext_Call* call)
1399 {
1400         WINPR_UNUSED(smartcard);
1401
1402         if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel))
1403                 return;
1404
1405         WLog_LVL(TAG, g_LogLevel, "EstablishContext_Call {");
1406         WLog_LVL(TAG, g_LogLevel, "dwScope: %s (0x%08" PRIX32 ")", SCardGetScopeString(call->dwScope),
1407                  call->dwScope);
1408         WLog_LVL(TAG, g_LogLevel, "}");
1409 }
1410
1411 static void smartcard_trace_establish_context_return(SMARTCARD_DEVICE* smartcard,
1412                                                      const EstablishContext_Return* ret)
1413 {
1414         WINPR_UNUSED(smartcard);
1415
1416         if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel))
1417                 return;
1418
1419         WLog_LVL(TAG, g_LogLevel, "EstablishContext_Return {");
1420         WLog_LVL(TAG, g_LogLevel, "  ReturnCode: %s (0x%08" PRIX32 ")",
1421                  SCardGetErrorString(ret->ReturnCode), ret->ReturnCode);
1422         smartcard_log_context(TAG, &ret->hContext);
1423
1424         WLog_LVL(TAG, g_LogLevel, "}");
1425 }
1426
1427 void smartcard_trace_long_return(SMARTCARD_DEVICE* smartcard, const Long_Return* ret,
1428                                  const char* name)
1429 {
1430         WINPR_UNUSED(smartcard);
1431
1432         if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel))
1433                 return;
1434
1435         WLog_LVL(TAG, g_LogLevel, "%s_Return {", name);
1436         WLog_LVL(TAG, g_LogLevel, "  ReturnCode: %s (0x%08" PRIX32 ")",
1437                  SCardGetErrorString(ret->ReturnCode), ret->ReturnCode);
1438         WLog_LVL(TAG, g_LogLevel, "}");
1439 }
1440
1441 static void smartcard_trace_connect_return(SMARTCARD_DEVICE* smartcard, const Connect_Return* ret)
1442 {
1443         WINPR_UNUSED(smartcard);
1444
1445         if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel))
1446                 return;
1447
1448         WLog_LVL(TAG, g_LogLevel, "Connect_Return {");
1449         WLog_LVL(TAG, g_LogLevel, "  ReturnCode: %s (0x%08" PRIX32 ")",
1450                  SCardGetErrorString(ret->ReturnCode), ret->ReturnCode);
1451         smartcard_log_context(TAG, &ret->hContext);
1452         smartcard_log_redir_handle(TAG, &ret->hCard);
1453
1454         WLog_LVL(TAG, g_LogLevel, "  dwActiveProtocol: %s (0x%08" PRIX32 ")",
1455                  SCardGetProtocolString(ret->dwActiveProtocol), ret->dwActiveProtocol);
1456         WLog_LVL(TAG, g_LogLevel, "}");
1457 }
1458
1459 void smartcard_trace_reconnect_call(SMARTCARD_DEVICE* smartcard, const Reconnect_Call* call)
1460 {
1461         WINPR_UNUSED(smartcard);
1462
1463         if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel))
1464                 return;
1465
1466         WLog_LVL(TAG, g_LogLevel, "Reconnect_Call {");
1467         smartcard_log_context(TAG, &call->handles.hContext);
1468         smartcard_log_redir_handle(TAG, &call->handles.hCard);
1469
1470         WLog_LVL(TAG, g_LogLevel,
1471                  "dwShareMode: %s (0x%08" PRIX32 ") dwPreferredProtocols: %s (0x%08" PRIX32
1472                  ") dwInitialization: %s (0x%08" PRIX32 ")",
1473                  SCardGetShareModeString(call->dwShareMode), call->dwShareMode,
1474                  SCardGetProtocolString(call->dwPreferredProtocols), call->dwPreferredProtocols,
1475                  SCardGetDispositionString(call->dwInitialization), call->dwInitialization);
1476         WLog_LVL(TAG, g_LogLevel, "}");
1477 }
1478
1479 static void smartcard_trace_device_type_id_return(SMARTCARD_DEVICE* smartcard,
1480                                                   const GetDeviceTypeId_Return* ret)
1481 {
1482         WINPR_UNUSED(smartcard);
1483
1484         if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel))
1485                 return;
1486
1487         WLog_LVL(TAG, g_LogLevel, "GetDeviceTypeId_Return {");
1488         WLog_LVL(TAG, g_LogLevel, "  ReturnCode: %s (0x%08" PRIX32 ")",
1489                  SCardGetErrorString(ret->ReturnCode), ret->ReturnCode);
1490         WLog_LVL(TAG, g_LogLevel, "  dwDeviceId=%08" PRIx32, ret->dwDeviceId);
1491
1492         WLog_LVL(TAG, g_LogLevel, "}");
1493 }
1494
1495 static LONG smartcard_unpack_common_context_and_string_a(SMARTCARD_DEVICE* smartcard, wStream* s,
1496                                                          REDIR_SCARDCONTEXT* phContext,
1497                                                          CHAR** pszReaderName)
1498 {
1499         LONG status;
1500         UINT32 index = 0;
1501         status = smartcard_unpack_redir_scard_context(smartcard, s, phContext, &index);
1502         if (status != SCARD_S_SUCCESS)
1503                 return status;
1504
1505         if (!smartcard_ndr_pointer_read(s, &index, NULL))
1506                 return ERROR_INVALID_DATA;
1507
1508         status = smartcard_unpack_redir_scard_context_ref(smartcard, s, phContext);
1509         if (status != SCARD_S_SUCCESS)
1510                 return status;
1511
1512         status = smartcard_ndr_read_a(s, pszReaderName, NDR_PTR_FULL);
1513         if (status != SCARD_S_SUCCESS)
1514                 return status;
1515
1516         smartcard_trace_context_and_string_call_a(__FUNCTION__, phContext, *pszReaderName);
1517         return SCARD_S_SUCCESS;
1518 }
1519
1520 static LONG smartcard_unpack_common_context_and_string_w(SMARTCARD_DEVICE* smartcard, wStream* s,
1521                                                          REDIR_SCARDCONTEXT* phContext,
1522                                                          WCHAR** pszReaderName)
1523 {
1524         LONG status;
1525         UINT32 index = 0;
1526
1527         status = smartcard_unpack_redir_scard_context(smartcard, s, phContext, &index);
1528         if (status != SCARD_S_SUCCESS)
1529                 return status;
1530
1531         if (!smartcard_ndr_pointer_read(s, &index, NULL))
1532                 return ERROR_INVALID_DATA;
1533
1534         status = smartcard_unpack_redir_scard_context_ref(smartcard, s, phContext);
1535         if (status != SCARD_S_SUCCESS)
1536                 return status;
1537
1538         status = smartcard_ndr_read_w(s, pszReaderName, NDR_PTR_FULL);
1539         if (status != SCARD_S_SUCCESS)
1540                 return status;
1541
1542         smartcard_trace_context_and_string_call_w(__FUNCTION__, phContext, *pszReaderName);
1543         return SCARD_S_SUCCESS;
1544 }
1545
1546 LONG smartcard_unpack_common_type_header(SMARTCARD_DEVICE* smartcard, wStream* s)
1547 {
1548         UINT8 version;
1549         UINT32 filler;
1550         UINT8 endianness;
1551         UINT16 commonHeaderLength;
1552         WINPR_UNUSED(smartcard);
1553
1554         if (Stream_GetRemainingLength(s) < 8)
1555         {
1556                 WLog_WARN(TAG, "CommonTypeHeader is too short: %" PRIuz "", Stream_GetRemainingLength(s));
1557                 return STATUS_BUFFER_TOO_SMALL;
1558         }
1559
1560         /* Process CommonTypeHeader */
1561         Stream_Read_UINT8(s, version);             /* Version (1 byte) */
1562         Stream_Read_UINT8(s, endianness);          /* Endianness (1 byte) */
1563         Stream_Read_UINT16(s, commonHeaderLength); /* CommonHeaderLength (2 bytes) */
1564         Stream_Read_UINT32(s, filler);             /* Filler (4 bytes), should be 0xCCCCCCCC */
1565
1566         if (version != 1)
1567         {
1568                 WLog_WARN(TAG, "Unsupported CommonTypeHeader Version %" PRIu8 "", version);
1569                 return STATUS_INVALID_PARAMETER;
1570         }
1571
1572         if (endianness != 0x10)
1573         {
1574                 WLog_WARN(TAG, "Unsupported CommonTypeHeader Endianness %" PRIu8 "", endianness);
1575                 return STATUS_INVALID_PARAMETER;
1576         }
1577
1578         if (commonHeaderLength != 8)
1579         {
1580                 WLog_WARN(TAG, "Unsupported CommonTypeHeader CommonHeaderLength %" PRIu16 "",
1581                           commonHeaderLength);
1582                 return STATUS_INVALID_PARAMETER;
1583         }
1584
1585         if (filler != 0xCCCCCCCC)
1586         {
1587                 WLog_WARN(TAG, "Unexpected CommonTypeHeader Filler 0x%08" PRIX32 "", filler);
1588                 return STATUS_INVALID_PARAMETER;
1589         }
1590
1591         return SCARD_S_SUCCESS;
1592 }
1593
1594 void smartcard_pack_common_type_header(SMARTCARD_DEVICE* smartcard, wStream* s)
1595 {
1596         WINPR_UNUSED(smartcard);
1597         Stream_Write_UINT8(s, 1);           /* Version (1 byte) */
1598         Stream_Write_UINT8(s, 0x10);        /* Endianness (1 byte) */
1599         Stream_Write_UINT16(s, 8);          /* CommonHeaderLength (2 bytes) */
1600         Stream_Write_UINT32(s, 0xCCCCCCCC); /* Filler (4 bytes), should be 0xCCCCCCCC */
1601 }
1602
1603 LONG smartcard_unpack_private_type_header(SMARTCARD_DEVICE* smartcard, wStream* s)
1604 {
1605         UINT32 filler;
1606         UINT32 objectBufferLength;
1607         WINPR_UNUSED(smartcard);
1608
1609         if (Stream_GetRemainingLength(s) < 8)
1610         {
1611                 WLog_WARN(TAG, "PrivateTypeHeader is too short: %" PRIuz "", Stream_GetRemainingLength(s));
1612                 return STATUS_BUFFER_TOO_SMALL;
1613         }
1614
1615         Stream_Read_UINT32(s, objectBufferLength); /* ObjectBufferLength (4 bytes) */
1616         Stream_Read_UINT32(s, filler);             /* Filler (4 bytes), should be 0x00000000 */
1617
1618         if (filler != 0x00000000)
1619         {
1620                 WLog_WARN(TAG, "Unexpected PrivateTypeHeader Filler 0x%08" PRIX32 "", filler);
1621                 return STATUS_INVALID_PARAMETER;
1622         }
1623
1624         if (objectBufferLength != Stream_GetRemainingLength(s))
1625         {
1626                 WLog_WARN(TAG,
1627                           "PrivateTypeHeader ObjectBufferLength mismatch: Actual: %" PRIu32
1628                           ", Expected: %" PRIuz "",
1629                           objectBufferLength, Stream_GetRemainingLength(s));
1630                 return STATUS_INVALID_PARAMETER;
1631         }
1632
1633         return SCARD_S_SUCCESS;
1634 }
1635
1636 void smartcard_pack_private_type_header(SMARTCARD_DEVICE* smartcard, wStream* s,
1637                                         UINT32 objectBufferLength)
1638 {
1639         WINPR_UNUSED(smartcard);
1640         Stream_Write_UINT32(s, objectBufferLength); /* ObjectBufferLength (4 bytes) */
1641         Stream_Write_UINT32(s, 0x00000000);         /* Filler (4 bytes), should be 0x00000000 */
1642 }
1643
1644 LONG smartcard_unpack_read_size_align(SMARTCARD_DEVICE* smartcard, wStream* s, size_t size,
1645                                       UINT32 alignment)
1646 {
1647         size_t pad;
1648         WINPR_UNUSED(smartcard);
1649         pad = size;
1650         size = (size + alignment - 1) & ~(alignment - 1);
1651         pad = size - pad;
1652
1653         if (pad)
1654                 Stream_Seek(s, pad);
1655
1656         return (LONG)pad;
1657 }
1658
1659 LONG smartcard_pack_write_size_align(SMARTCARD_DEVICE* smartcard, wStream* s, size_t size,
1660                                      UINT32 alignment)
1661 {
1662         size_t pad;
1663         WINPR_UNUSED(smartcard);
1664         pad = size;
1665         size = (size + alignment - 1) & ~(alignment - 1);
1666         pad = size - pad;
1667
1668         if (pad)
1669         {
1670                 if (!Stream_EnsureRemainingCapacity(s, pad))
1671                 {
1672                         WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!");
1673                         return SCARD_F_INTERNAL_ERROR;
1674                 }
1675
1676                 Stream_Zero(s, pad);
1677         }
1678
1679         return SCARD_S_SUCCESS;
1680 }
1681
1682 SCARDCONTEXT smartcard_scard_context_native_from_redir(SMARTCARD_DEVICE* smartcard,
1683                                                        REDIR_SCARDCONTEXT* context)
1684 {
1685         SCARDCONTEXT hContext = { 0 };
1686         WINPR_UNUSED(smartcard);
1687
1688         if ((context->cbContext != sizeof(ULONG_PTR)) && (context->cbContext != 0))
1689         {
1690                 WLog_WARN(TAG,
1691                           "REDIR_SCARDCONTEXT does not match native size: Actual: %" PRIu32
1692                           ", Expected: %" PRIuz "",
1693                           context->cbContext, sizeof(ULONG_PTR));
1694                 return 0;
1695         }
1696
1697         if (context->cbContext)
1698                 CopyMemory(&hContext, &(context->pbContext), context->cbContext);
1699
1700         return hContext;
1701 }
1702
1703 void smartcard_scard_context_native_to_redir(SMARTCARD_DEVICE* smartcard,
1704                                              REDIR_SCARDCONTEXT* context, SCARDCONTEXT hContext)
1705 {
1706         WINPR_UNUSED(smartcard);
1707         ZeroMemory(context, sizeof(REDIR_SCARDCONTEXT));
1708         context->cbContext = sizeof(ULONG_PTR);
1709         CopyMemory(&(context->pbContext), &hContext, context->cbContext);
1710 }
1711
1712 SCARDHANDLE smartcard_scard_handle_native_from_redir(SMARTCARD_DEVICE* smartcard,
1713                                                      REDIR_SCARDHANDLE* handle)
1714 {
1715         SCARDHANDLE hCard = 0;
1716         WINPR_UNUSED(smartcard);
1717
1718         if (handle->cbHandle == 0)
1719                 return hCard;
1720
1721         if (handle->cbHandle != sizeof(ULONG_PTR))
1722         {
1723                 WLog_WARN(TAG,
1724                           "REDIR_SCARDHANDLE does not match native size: Actual: %" PRIu32
1725                           ", Expected: %" PRIuz "",
1726                           handle->cbHandle, sizeof(ULONG_PTR));
1727                 return 0;
1728         }
1729
1730         if (handle->cbHandle)
1731                 CopyMemory(&hCard, &(handle->pbHandle), handle->cbHandle);
1732
1733         return hCard;
1734 }
1735
1736 void smartcard_scard_handle_native_to_redir(SMARTCARD_DEVICE* smartcard, REDIR_SCARDHANDLE* handle,
1737                                             SCARDHANDLE hCard)
1738 {
1739         WINPR_UNUSED(smartcard);
1740         ZeroMemory(handle, sizeof(REDIR_SCARDHANDLE));
1741         handle->cbHandle = sizeof(ULONG_PTR);
1742         CopyMemory(&(handle->pbHandle), &hCard, handle->cbHandle);
1743 }
1744
1745 LONG smartcard_unpack_redir_scard_context_(SMARTCARD_DEVICE* smartcard, wStream* s,
1746                                            REDIR_SCARDCONTEXT* context, UINT32* index,
1747                                            const char* file, const char* function, int line)
1748 {
1749         UINT32 pbContextNdrPtr;
1750         WINPR_UNUSED(smartcard);
1751         WINPR_UNUSED(file);
1752
1753         ZeroMemory(context, sizeof(REDIR_SCARDCONTEXT));
1754
1755         if (Stream_GetRemainingLength(s) < 4)
1756         {
1757                 WLog_WARN(TAG, "REDIR_SCARDCONTEXT is too short: %" PRIuz "", Stream_GetRemainingLength(s));
1758                 return STATUS_BUFFER_TOO_SMALL;
1759         }
1760
1761         Stream_Read_UINT32(s, context->cbContext); /* cbContext (4 bytes) */
1762
1763         if (Stream_GetRemainingLength(s) < context->cbContext)
1764         {
1765                 WLog_WARN(TAG, "REDIR_SCARDCONTEXT is too short: Actual: %" PRIuz ", Expected: %" PRIu32 "",
1766                           Stream_GetRemainingLength(s), context->cbContext);
1767                 return STATUS_BUFFER_TOO_SMALL;
1768         }
1769
1770         if ((context->cbContext != 0) && (context->cbContext != 4) && (context->cbContext != 8))
1771         {
1772                 WLog_WARN(TAG, "REDIR_SCARDCONTEXT length is not 0, 4 or 8: %" PRIu32 "",
1773                           context->cbContext);
1774                 return STATUS_INVALID_PARAMETER;
1775         }
1776
1777         if (!smartcard_ndr_pointer_read_(s, index, &pbContextNdrPtr, file, function, line))
1778                 return ERROR_INVALID_DATA;
1779
1780         if (((context->cbContext == 0) && pbContextNdrPtr) ||
1781             ((context->cbContext != 0) && !pbContextNdrPtr))
1782         {
1783                 WLog_WARN(TAG,
1784                           "REDIR_SCARDCONTEXT cbContext (%" PRIu32 ") pbContextNdrPtr (%" PRIu32
1785                           ") inconsistency",
1786                           context->cbContext, pbContextNdrPtr);
1787                 return STATUS_INVALID_PARAMETER;
1788         }
1789
1790         if (context->cbContext > Stream_GetRemainingLength(s))
1791         {
1792                 WLog_WARN(TAG, "REDIR_SCARDCONTEXT is too long: Actual: %" PRIuz ", Expected: %" PRIu32 "",
1793                           Stream_GetRemainingLength(s), context->cbContext);
1794                 return STATUS_INVALID_PARAMETER;
1795         }
1796
1797         return SCARD_S_SUCCESS;
1798 }
1799
1800 LONG smartcard_pack_redir_scard_context(SMARTCARD_DEVICE* smartcard, wStream* s,
1801                                         const REDIR_SCARDCONTEXT* context, DWORD* index)
1802 {
1803         const UINT32 pbContextNdrPtr = 0x00020000 + *index * 4;
1804         WINPR_UNUSED(smartcard);
1805
1806         if (context->cbContext != 0)
1807         {
1808                 Stream_Write_UINT32(s, context->cbContext); /* cbContext (4 bytes) */
1809                 Stream_Write_UINT32(s, pbContextNdrPtr);    /* pbContextNdrPtr (4 bytes) */
1810                 *index = *index + 1;
1811         }
1812         else
1813                 Stream_Zero(s, 8);
1814
1815         return SCARD_S_SUCCESS;
1816 }
1817
1818 LONG smartcard_unpack_redir_scard_context_ref(SMARTCARD_DEVICE* smartcard, wStream* s,
1819                                               REDIR_SCARDCONTEXT* context)
1820 {
1821         UINT32 length;
1822         WINPR_UNUSED(smartcard);
1823
1824         if (context->cbContext == 0)
1825                 return SCARD_S_SUCCESS;
1826
1827         if (Stream_GetRemainingLength(s) < 4)
1828         {
1829                 WLog_WARN(TAG, "REDIR_SCARDCONTEXT is too short: Actual: %" PRIuz ", Expected: 4",
1830                           Stream_GetRemainingLength(s));
1831                 return STATUS_BUFFER_TOO_SMALL;
1832         }
1833
1834         Stream_Read_UINT32(s, length); /* Length (4 bytes) */
1835
1836         if (length != context->cbContext)
1837         {
1838                 WLog_WARN(TAG, "REDIR_SCARDCONTEXT length (%" PRIu32 ") cbContext (%" PRIu32 ") mismatch",
1839                           length, context->cbContext);
1840                 return STATUS_INVALID_PARAMETER;
1841         }
1842
1843         if ((context->cbContext != 0) && (context->cbContext != 4) && (context->cbContext != 8))
1844         {
1845                 WLog_WARN(TAG, "REDIR_SCARDCONTEXT length is not 4 or 8: %" PRIu32 "", context->cbContext);
1846                 return STATUS_INVALID_PARAMETER;
1847         }
1848
1849         if (Stream_GetRemainingLength(s) < context->cbContext)
1850         {
1851                 WLog_WARN(TAG, "REDIR_SCARDCONTEXT is too short: Actual: %" PRIuz ", Expected: %" PRIu32 "",
1852                           Stream_GetRemainingLength(s), context->cbContext);
1853                 return STATUS_BUFFER_TOO_SMALL;
1854         }
1855
1856         if (context->cbContext)
1857                 Stream_Read(s, &(context->pbContext), context->cbContext);
1858         else
1859                 ZeroMemory(&(context->pbContext), sizeof(context->pbContext));
1860
1861         return SCARD_S_SUCCESS;
1862 }
1863
1864 LONG smartcard_pack_redir_scard_context_ref(SMARTCARD_DEVICE* smartcard, wStream* s,
1865                                             const REDIR_SCARDCONTEXT* context)
1866 {
1867         WINPR_UNUSED(smartcard);
1868         Stream_Write_UINT32(s, context->cbContext); /* Length (4 bytes) */
1869
1870         if (context->cbContext)
1871         {
1872                 Stream_Write(s, &(context->pbContext), context->cbContext);
1873         }
1874
1875         return SCARD_S_SUCCESS;
1876 }
1877
1878 LONG smartcard_unpack_redir_scard_handle_(SMARTCARD_DEVICE* smartcard, wStream* s,
1879                                           REDIR_SCARDHANDLE* handle, UINT32* index,
1880                                           const char* file, const char* function, int line)
1881 {
1882         WINPR_UNUSED(smartcard);
1883         ZeroMemory(handle, sizeof(REDIR_SCARDHANDLE));
1884
1885         if (Stream_GetRemainingLength(s) < 4)
1886         {
1887                 WLog_WARN(TAG, "SCARDHANDLE is too short: %" PRIuz "", Stream_GetRemainingLength(s));
1888                 return STATUS_BUFFER_TOO_SMALL;
1889         }
1890
1891         Stream_Read_UINT32(s, handle->cbHandle); /* Length (4 bytes) */
1892
1893         if ((Stream_GetRemainingLength(s) < handle->cbHandle) || (!handle->cbHandle))
1894         {
1895                 WLog_WARN(TAG, "SCARDHANDLE is too short: Actual: %" PRIuz ", Expected: %" PRIu32 "",
1896                           Stream_GetRemainingLength(s), handle->cbHandle);
1897                 return STATUS_BUFFER_TOO_SMALL;
1898         }
1899
1900         if (!smartcard_ndr_pointer_read_(s, index, NULL, file, function, line))
1901                 return ERROR_INVALID_DATA;
1902
1903         return SCARD_S_SUCCESS;
1904 }
1905
1906 LONG smartcard_pack_redir_scard_handle(SMARTCARD_DEVICE* smartcard, wStream* s,
1907                                        const REDIR_SCARDHANDLE* handle, DWORD* index)
1908 {
1909         const UINT32 pbContextNdrPtr = 0x00020000 + *index * 4;
1910         WINPR_UNUSED(smartcard);
1911
1912         if (handle->cbHandle != 0)
1913         {
1914                 Stream_Write_UINT32(s, handle->cbHandle); /* cbContext (4 bytes) */
1915                 Stream_Write_UINT32(s, pbContextNdrPtr);  /* pbContextNdrPtr (4 bytes) */
1916                 *index = *index + 1;
1917         }
1918         else
1919                 Stream_Zero(s, 8);
1920         return SCARD_S_SUCCESS;
1921 }
1922
1923 LONG smartcard_unpack_redir_scard_handle_ref(SMARTCARD_DEVICE* smartcard, wStream* s,
1924                                              REDIR_SCARDHANDLE* handle)
1925 {
1926         UINT32 length;
1927         WINPR_UNUSED(smartcard);
1928
1929         if (Stream_GetRemainingLength(s) < 4)
1930         {
1931                 WLog_WARN(TAG, "REDIR_SCARDHANDLE is too short: Actual: %" PRIuz ", Expected: 4",
1932                           Stream_GetRemainingLength(s));
1933                 return STATUS_BUFFER_TOO_SMALL;
1934         }
1935
1936         Stream_Read_UINT32(s, length); /* Length (4 bytes) */
1937
1938         if (length != handle->cbHandle)
1939         {
1940                 WLog_WARN(TAG, "REDIR_SCARDHANDLE length (%" PRIu32 ") cbHandle (%" PRIu32 ") mismatch",
1941                           length, handle->cbHandle);
1942                 return STATUS_INVALID_PARAMETER;
1943         }
1944
1945         if ((handle->cbHandle != 4) && (handle->cbHandle != 8))
1946         {
1947                 WLog_WARN(TAG, "REDIR_SCARDHANDLE length is not 4 or 8: %" PRIu32 "", handle->cbHandle);
1948                 return STATUS_INVALID_PARAMETER;
1949         }
1950
1951         if ((Stream_GetRemainingLength(s) < handle->cbHandle) || (!handle->cbHandle))
1952         {
1953                 WLog_WARN(TAG, "REDIR_SCARDHANDLE is too short: Actual: %" PRIuz ", Expected: %" PRIu32 "",
1954                           Stream_GetRemainingLength(s), handle->cbHandle);
1955                 return STATUS_BUFFER_TOO_SMALL;
1956         }
1957
1958         if (handle->cbHandle)
1959                 Stream_Read(s, &(handle->pbHandle), handle->cbHandle);
1960
1961         return SCARD_S_SUCCESS;
1962 }
1963
1964 LONG smartcard_pack_redir_scard_handle_ref(SMARTCARD_DEVICE* smartcard, wStream* s,
1965                                            const REDIR_SCARDHANDLE* handle)
1966 {
1967         WINPR_UNUSED(smartcard);
1968         Stream_Write_UINT32(s, handle->cbHandle); /* Length (4 bytes) */
1969
1970         if (handle->cbHandle)
1971                 Stream_Write(s, &(handle->pbHandle), handle->cbHandle);
1972
1973         return SCARD_S_SUCCESS;
1974 }
1975
1976 LONG smartcard_unpack_establish_context_call(SMARTCARD_DEVICE* smartcard, wStream* s,
1977                                              EstablishContext_Call* call)
1978 {
1979         WINPR_UNUSED(smartcard);
1980
1981         if (Stream_GetRemainingLength(s) < 4)
1982         {
1983                 WLog_WARN(TAG, "EstablishContext_Call is too short: Actual: %" PRIuz ", Expected: 4",
1984                           Stream_GetRemainingLength(s));
1985                 return STATUS_BUFFER_TOO_SMALL;
1986         }
1987
1988         Stream_Read_UINT32(s, call->dwScope); /* dwScope (4 bytes) */
1989         smartcard_trace_establish_context_call(smartcard, call);
1990         return SCARD_S_SUCCESS;
1991 }
1992
1993 LONG smartcard_pack_establish_context_return(SMARTCARD_DEVICE* smartcard, wStream* s,
1994                                              const EstablishContext_Return* ret)
1995 {
1996         LONG status;
1997         DWORD index = 0;
1998
1999         smartcard_trace_establish_context_return(smartcard, ret);
2000         if (ret->ReturnCode != SCARD_S_SUCCESS)
2001                 return ret->ReturnCode;
2002
2003         if ((status = smartcard_pack_redir_scard_context(smartcard, s, &(ret->hContext), &index)))
2004                 return status;
2005
2006         return smartcard_pack_redir_scard_context_ref(smartcard, s, &(ret->hContext));
2007 }
2008
2009 LONG smartcard_unpack_context_call(SMARTCARD_DEVICE* smartcard, wStream* s, Context_Call* call,
2010                                    const char* name)
2011 {
2012         LONG status;
2013         UINT32 index = 0;
2014
2015         status = smartcard_unpack_redir_scard_context(smartcard, s, &(call->handles.hContext), &index);
2016         if (status != SCARD_S_SUCCESS)
2017                 return status;
2018
2019         if ((status =
2020                  smartcard_unpack_redir_scard_context_ref(smartcard, s, &(call->handles.hContext))))
2021                 WLog_ERR(TAG, "smartcard_unpack_redir_scard_context_ref failed with error %" PRId32 "",
2022                          status);
2023
2024         smartcard_trace_context_call(smartcard, call, name);
2025         return status;
2026 }
2027
2028 LONG smartcard_unpack_list_reader_groups_call(SMARTCARD_DEVICE* smartcard, wStream* s,
2029                                               ListReaderGroups_Call* call, BOOL unicode)
2030 {
2031         LONG status;
2032         UINT32 index = 0;
2033         status = smartcard_unpack_redir_scard_context(smartcard, s, &(call->handles.hContext), &index);
2034
2035         if (status != SCARD_S_SUCCESS)
2036                 return status;
2037
2038         if (Stream_GetRemainingLength(s) < 8)
2039         {
2040                 WLog_WARN(TAG, "ListReaderGroups_Call is too short: %" PRIdz, Stream_GetRemainingLength(s));
2041                 return STATUS_BUFFER_TOO_SMALL;
2042         }
2043
2044         Stream_Read_INT32(s, call->fmszGroupsIsNULL); /* fmszGroupsIsNULL (4 bytes) */
2045         Stream_Read_UINT32(s, call->cchGroups);       /* cchGroups (4 bytes) */
2046         status = smartcard_unpack_redir_scard_context_ref(smartcard, s, &(call->handles.hContext));
2047
2048         if (status != SCARD_S_SUCCESS)
2049                 return status;
2050
2051         smartcard_trace_list_reader_groups_call(smartcard, call, unicode);
2052         return SCARD_S_SUCCESS;
2053 }
2054
2055 LONG smartcard_pack_list_reader_groups_return(SMARTCARD_DEVICE* smartcard, wStream* s,
2056                                               const ListReaderGroups_Return* ret, BOOL unicode)
2057 {
2058         LONG status;
2059         DWORD cBytes = ret->cBytes;
2060         DWORD index = 0;
2061
2062         smartcard_trace_list_reader_groups_return(smartcard, ret, unicode);
2063         if (ret->ReturnCode != SCARD_S_SUCCESS)
2064                 cBytes = 0;
2065         if (cBytes == SCARD_AUTOALLOCATE)
2066                 cBytes = 0;
2067
2068         if (!Stream_EnsureRemainingCapacity(s, 4))
2069                 return SCARD_E_NO_MEMORY;
2070
2071         Stream_Write_UINT32(s, cBytes); /* cBytes (4 bytes) */
2072         if (!smartcard_ndr_pointer_write(s, &index, cBytes))
2073                 return SCARD_E_NO_MEMORY;
2074
2075         status = smartcard_ndr_write(s, ret->msz, cBytes, 1, NDR_PTR_SIMPLE);
2076         if (status != SCARD_S_SUCCESS)
2077                 return status;
2078         return ret->ReturnCode;
2079 }
2080
2081 LONG smartcard_unpack_list_readers_call(SMARTCARD_DEVICE* smartcard, wStream* s,
2082                                         ListReaders_Call* call, BOOL unicode)
2083 {
2084         LONG status;
2085         UINT32 index = 0;
2086         UINT32 mszGroupsNdrPtr;
2087         call->mszGroups = NULL;
2088
2089         status = smartcard_unpack_redir_scard_context(smartcard, s, &(call->handles.hContext), &index);
2090         if (status != SCARD_S_SUCCESS)
2091                 return status;
2092
2093         if (Stream_GetRemainingLength(s) < 16)
2094         {
2095                 WLog_WARN(TAG, "ListReaders_Call is too short: %" PRIuz "", Stream_GetRemainingLength(s));
2096                 return STATUS_BUFFER_TOO_SMALL;
2097         }
2098
2099         Stream_Read_UINT32(s, call->cBytes); /* cBytes (4 bytes) */
2100         if (!smartcard_ndr_pointer_read(s, &index, &mszGroupsNdrPtr))
2101                 return ERROR_INVALID_DATA;
2102         Stream_Read_INT32(s, call->fmszReadersIsNULL); /* fmszReadersIsNULL (4 bytes) */
2103         Stream_Read_UINT32(s, call->cchReaders);       /* cchReaders (4 bytes) */
2104
2105         if ((status =
2106                  smartcard_unpack_redir_scard_context_ref(smartcard, s, &(call->handles.hContext))))
2107                 return status;
2108
2109         if (mszGroupsNdrPtr)
2110         {
2111                 status = smartcard_ndr_read(s, &call->mszGroups, call->cBytes, 1, NDR_PTR_SIMPLE);
2112                 if (status != SCARD_S_SUCCESS)
2113                         return status;
2114         }
2115
2116         smartcard_trace_list_readers_call(smartcard, call, unicode);
2117         return SCARD_S_SUCCESS;
2118 }
2119
2120 LONG smartcard_pack_list_readers_return(SMARTCARD_DEVICE* smartcard, wStream* s,
2121                                         const ListReaders_Return* ret, BOOL unicode)
2122 {
2123         LONG status;
2124         DWORD index = 0;
2125         UINT32 size = unicode ? sizeof(WCHAR) : sizeof(CHAR);
2126
2127         size *= ret->cBytes;
2128
2129         smartcard_trace_list_readers_return(smartcard, ret, unicode);
2130         if (ret->ReturnCode != SCARD_S_SUCCESS)
2131                 size = 0;
2132
2133         if (!Stream_EnsureRemainingCapacity(s, 4))
2134         {
2135                 WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!");
2136                 return SCARD_F_INTERNAL_ERROR;
2137         }
2138
2139         Stream_Write_UINT32(s, size); /* cBytes (4 bytes) */
2140         if (!smartcard_ndr_pointer_write(s, &index, size))
2141                 return SCARD_E_NO_MEMORY;
2142
2143         status = smartcard_ndr_write(s, ret->msz, size, 1, NDR_PTR_SIMPLE);
2144         if (status != SCARD_S_SUCCESS)
2145                 return status;
2146         return ret->ReturnCode;
2147 }
2148
2149 static LONG smartcard_unpack_connect_common(SMARTCARD_DEVICE* smartcard, wStream* s,
2150                                             Connect_Common_Call* common, UINT32* index)
2151 {
2152         LONG status;
2153
2154         status = smartcard_unpack_redir_scard_context(smartcard, s, &(common->handles.hContext), index);
2155         if (status != SCARD_S_SUCCESS)
2156                 return status;
2157
2158         if (Stream_GetRemainingLength(s) < 8)
2159         {
2160                 WLog_WARN(TAG, "Connect_Common is too short: %" PRIuz "", Stream_GetRemainingLength(s));
2161                 return STATUS_BUFFER_TOO_SMALL;
2162         }
2163
2164         Stream_Read_UINT32(s, common->dwShareMode);          /* dwShareMode (4 bytes) */
2165         Stream_Read_UINT32(s, common->dwPreferredProtocols); /* dwPreferredProtocols (4 bytes) */
2166         return SCARD_S_SUCCESS;
2167 }
2168
2169 LONG smartcard_unpack_connect_a_call(SMARTCARD_DEVICE* smartcard, wStream* s, ConnectA_Call* call)
2170 {
2171         LONG status;
2172         UINT32 index = 0;
2173         call->szReader = NULL;
2174
2175         if (!smartcard_ndr_pointer_read(s, &index, NULL))
2176                 return ERROR_INVALID_DATA;
2177
2178         if ((status = smartcard_unpack_connect_common(smartcard, s, &(call->Common), &index)))
2179         {
2180                 WLog_ERR(TAG, "smartcard_unpack_connect_common failed with error %" PRId32 "", status);
2181                 return status;
2182         }
2183
2184         status = smartcard_ndr_read_a(s, &call->szReader, NDR_PTR_FULL);
2185         if (status != SCARD_S_SUCCESS)
2186                 return status;
2187
2188         if ((status = smartcard_unpack_redir_scard_context_ref(smartcard, s,
2189                                                                &(call->Common.handles.hContext))))
2190                 WLog_ERR(TAG, "smartcard_unpack_redir_scard_context_ref failed with error %" PRId32 "",
2191                          status);
2192
2193         smartcard_trace_connect_a_call(smartcard, call);
2194         return status;
2195 }
2196
2197 LONG smartcard_unpack_connect_w_call(SMARTCARD_DEVICE* smartcard, wStream* s, ConnectW_Call* call)
2198 {
2199         LONG status;
2200         UINT32 index = 0;
2201
2202         call->szReader = NULL;
2203
2204         if (!smartcard_ndr_pointer_read(s, &index, NULL))
2205                 return ERROR_INVALID_DATA;
2206
2207         if ((status = smartcard_unpack_connect_common(smartcard, s, &(call->Common), &index)))
2208         {
2209                 WLog_ERR(TAG, "smartcard_unpack_connect_common failed with error %" PRId32 "", status);
2210                 return status;
2211         }
2212
2213         status = smartcard_ndr_read_w(s, &call->szReader, NDR_PTR_FULL);
2214         if (status != SCARD_S_SUCCESS)
2215                 return status;
2216
2217         if ((status = smartcard_unpack_redir_scard_context_ref(smartcard, s,
2218                                                                &(call->Common.handles.hContext))))
2219                 WLog_ERR(TAG, "smartcard_unpack_redir_scard_context_ref failed with error %" PRId32 "",
2220                          status);
2221
2222         smartcard_trace_connect_w_call(smartcard, call);
2223         return status;
2224 }
2225
2226 LONG smartcard_pack_connect_return(SMARTCARD_DEVICE* smartcard, wStream* s,
2227                                    const Connect_Return* ret)
2228 {
2229         LONG status;
2230         DWORD index = 0;
2231
2232         smartcard_trace_connect_return(smartcard, ret);
2233
2234         status = smartcard_pack_redir_scard_context(smartcard, s, &ret->hContext, &index);
2235         if (status != SCARD_S_SUCCESS)
2236                 return status;
2237
2238         status = smartcard_pack_redir_scard_handle(smartcard, s, &ret->hCard, &index);
2239         if (status != SCARD_S_SUCCESS)
2240                 return status;
2241
2242         if (!Stream_EnsureRemainingCapacity(s, 4))
2243                 return SCARD_E_NO_MEMORY;
2244
2245         Stream_Write_UINT32(s, ret->dwActiveProtocol); /* dwActiveProtocol (4 bytes) */
2246         status = smartcard_pack_redir_scard_context_ref(smartcard, s, &ret->hContext);
2247         if (status != SCARD_S_SUCCESS)
2248                 return status;
2249         return smartcard_pack_redir_scard_handle_ref(smartcard, s, &(ret->hCard));
2250 }
2251
2252 LONG smartcard_unpack_reconnect_call(SMARTCARD_DEVICE* smartcard, wStream* s, Reconnect_Call* call)
2253 {
2254         LONG status;
2255         UINT32 index = 0;
2256
2257         status = smartcard_unpack_redir_scard_context(smartcard, s, &(call->handles.hContext), &index);
2258         if (status != SCARD_S_SUCCESS)
2259                 return status;
2260
2261         status = smartcard_unpack_redir_scard_handle(smartcard, s, &(call->handles.hCard), &index);
2262         if (status != SCARD_S_SUCCESS)
2263                 return status;
2264
2265         if (Stream_GetRemainingLength(s) < 12)
2266         {
2267                 WLog_WARN(TAG, "Reconnect_Call is too short: %" PRIuz "", Stream_GetRemainingLength(s));
2268                 return STATUS_BUFFER_TOO_SMALL;
2269         }
2270
2271         Stream_Read_UINT32(s, call->dwShareMode);          /* dwShareMode (4 bytes) */
2272         Stream_Read_UINT32(s, call->dwPreferredProtocols); /* dwPreferredProtocols (4 bytes) */
2273         Stream_Read_UINT32(s, call->dwInitialization);     /* dwInitialization (4 bytes) */
2274
2275         if ((status =
2276                  smartcard_unpack_redir_scard_context_ref(smartcard, s, &(call->handles.hContext))))
2277         {
2278                 WLog_ERR(TAG, "smartcard_unpack_redir_scard_context_ref failed with error %" PRId32 "",
2279                          status);
2280                 return status;
2281         }
2282
2283         if ((status = smartcard_unpack_redir_scard_handle_ref(smartcard, s, &(call->handles.hCard))))
2284                 WLog_ERR(TAG, "smartcard_unpack_redir_scard_handle_ref failed with error %" PRId32 "",
2285                          status);
2286
2287         smartcard_trace_reconnect_call(smartcard, call);
2288         return status;
2289 }
2290
2291 LONG smartcard_pack_reconnect_return(SMARTCARD_DEVICE* smartcard, wStream* s,
2292                                      const Reconnect_Return* ret)
2293 {
2294         smartcard_trace_reconnect_return(smartcard, ret);
2295
2296         if (!Stream_EnsureRemainingCapacity(s, 4))
2297                 return SCARD_E_NO_MEMORY;
2298         Stream_Write_UINT32(s, ret->dwActiveProtocol); /* dwActiveProtocol (4 bytes) */
2299         return ret->ReturnCode;
2300 }
2301
2302 LONG smartcard_unpack_hcard_and_disposition_call(SMARTCARD_DEVICE* smartcard, wStream* s,
2303                                                  HCardAndDisposition_Call* call, const char* name)
2304 {
2305         LONG status;
2306         UINT32 index = 0;
2307
2308         status = smartcard_unpack_redir_scard_context(smartcard, s, &(call->handles.hContext), &index);
2309         if (status != SCARD_S_SUCCESS)
2310                 return status;
2311
2312         status = smartcard_unpack_redir_scard_handle(smartcard, s, &(call->handles.hCard), &index);
2313         if (status != SCARD_S_SUCCESS)
2314                 return status;
2315
2316         if (Stream_GetRemainingLength(s) < 4)
2317         {
2318                 WLog_WARN(TAG, "HCardAndDisposition_Call is too short: %" PRIuz "",
2319                           Stream_GetRemainingLength(s));
2320                 return STATUS_BUFFER_TOO_SMALL;
2321         }
2322
2323         Stream_Read_UINT32(s, call->dwDisposition); /* dwDisposition (4 bytes) */
2324
2325         if ((status =
2326                  smartcard_unpack_redir_scard_context_ref(smartcard, s, &(call->handles.hContext))))
2327                 return status;
2328
2329         if ((status = smartcard_unpack_redir_scard_handle_ref(smartcard, s, &(call->handles.hCard))))
2330                 return status;
2331
2332         smartcard_trace_hcard_and_disposition_call(smartcard, call, name);
2333         return status;
2334 }
2335
2336 static void smartcard_trace_get_status_change_a_call(SMARTCARD_DEVICE* smartcard,
2337                                                      const GetStatusChangeA_Call* call)
2338 {
2339         UINT32 index;
2340         char* szEventState;
2341         char* szCurrentState;
2342         LPSCARD_READERSTATEA readerState;
2343         WINPR_UNUSED(smartcard);
2344
2345         if (!WLog_IsLevelActive(WLog_Get(TAG), g_LogLevel))
2346                 return;
2347
2348         WLog_LVL(TAG, g_LogLevel, "GetStatusChangeA_Call {");
2349         smartcard_log_context(TAG, &call->handles.hContext);
2350
2351         WLog_LVL(TAG, g_LogLevel, "dwTimeOut: 0x%08" PRIX32 " cReaders: %" PRIu32 "", call->dwTimeOut,
2352                  call->cReaders);
2353
2354         for (index = 0; index < call->cReaders; index++)
2355         {
2356                 readerState = &call->rgReaderStates[index];
2357                 WLog_LVL(TAG, g_LogLevel, "\t[%" PRIu32 "]: szReader: %s cbAtr: %" PRIu32 "", index,
2358                          readerState->szReader, readerState->cbAtr);
2359                 szCurrentState = SCardGetReaderStateString(readerState->dwCurrentState);
2360                 szEventState = SCardGetReaderStateString(readerState->dwEventState);
2361                 WLog_LVL(TAG, g_LogLevel, "\t[%" PRIu32 "]: dwCurrentState: %s (0x%08" PRIX32 ")", index,
2362                          szCurrentState, readerState->dwCurrentState);
2363                 WLog_LVL(TAG, g_LogLevel, "\t[%" PRIu32 "]: dwEventState: %s (0x%08" PRIX32 ")", index,
2364                          szEventState, readerState->dwEventState);
2365                 free(szCurrentState);
2366                 free(szEventState);
2367         }
2368
2369         WLog_LVL(TAG, g_LogLevel, "}");
2370 }
2371
2372 static LONG smartcard_unpack_reader_state_a(wStream* s, LPSCARD_READERSTATEA* ppcReaders,
2373                                             UINT32 cReaders, UINT32* ptrIndex)
2374 {
2375         UINT32 index, len;
2376         LONG status = ERROR_INVALID_DATA;
2377         LPSCARD_READERSTATEA rgReaderStates;
2378
2379         if (Stream_GetRemainingLength(s) < 4)
2380                 return status;
2381
2382         Stream_Read_UINT32(s, len);
2383         if (len != cReaders)
2384         {
2385                 WLog_ERR(TAG, "Count mismatch when reading LPSCARD_READERSTATEA");
2386                 return status;
2387         }
2388         rgReaderStates = (LPSCARD_READERSTATEA)calloc(cReaders, sizeof(SCARD_READERSTATEA));
2389
2390         if (!rgReaderStates)
2391                 return STATUS_NO_MEMORY;
2392
2393         for (index = 0; index < cReaders; index++)
2394         {
2395                 LPSCARD_READERSTATEA readerState = &rgReaderStates[index];
2396
2397                 if (Stream_GetRemainingLength(s) < 52)
2398                 {
2399                         WLog_WARN(TAG, "GetStatusChangeA_Call is too short: %" PRIuz "",
2400                                   Stream_GetRemainingLength(s));
2401                         goto fail;
2402                 }
2403
2404                 if (!smartcard_ndr_pointer_read(s, ptrIndex, NULL))
2405                         goto fail;
2406                 Stream_Read_UINT32(s, readerState->dwCurrentState); /* dwCurrentState (4 bytes) */
2407                 Stream_Read_UINT32(s, readerState->dwEventState);   /* dwEventState (4 bytes) */
2408                 Stream_Read_UINT32(s, readerState->cbAtr);          /* cbAtr (4 bytes) */
2409                 Stream_Read(s, readerState->rgbAtr, 36);            /* rgbAtr [0..36] (36 bytes) */
2410         }
2411
2412         for (index = 0; index < cReaders; index++)
2413         {
2414                 LPSCARD_READERSTATEA readerState = &rgReaderStates[index];
2415
2416                 status = smartcard_ndr_read_a(s, &readerState->szReader, NDR_PTR_FULL);
2417                 if (status != SCARD_S_SUCCESS)
2418                         goto fail;
2419         }
2420
2421         *ppcReaders = rgReaderStates;
2422         return SCARD_S_SUCCESS;
2423 fail:
2424         if (rgReaderStates)
2425         {
2426                 for (index = 0; index < cReaders; index++)
2427                 {
2428                         LPSCARD_READERSTATEA readerState = &rgReaderStates[index];
2429                         free(readerState->szReader);
2430                 }
2431         }
2432         free(rgReaderStates);
2433         return status;
2434 }
2435
2436 static LONG smartcard_unpack_reader_state_w(wStream* s, LPSCARD_READERSTATEW* ppcReaders,
2437                                             UINT32 cReaders, UINT32* ptrIndex)
2438 {
2439         UINT32 index, len;
2440         LONG status = ERROR_INVALID_DATA;
2441         LPSCARD_READERSTATEW rgReaderStates;
2442
2443         if (Stream_GetRemainingLength(s) < 4)
2444                 return status;
2445
2446         Stream_Read_UINT32(s, len);
2447         if (len != cReaders)
2448         {
2449                 WLog_ERR(TAG, "Count mismatch when reading LPSCARD_READERSTATEW");
2450                 return status;
2451         }
2452
2453         rgReaderStates = (LPSCARD_READERSTATEW)calloc(cReaders, sizeof(SCARD_READERSTATEW));
2454
2455         if (!rgReaderStates)
2456                 return STATUS_NO_MEMORY;
2457
2458         for (index = 0; index < cReaders; index++)
2459         {
2460                 LPSCARD_READERSTATEW readerState = &rgReaderStates[index];
2461
2462                 if (Stream_GetRemainingLength(s) < 52)
2463                 {
2464                         WLog_WARN(TAG, "GetStatusChangeA_Call is too short: %" PRIuz "",
2465                                   Stream_GetRemainingLength(s));
2466                         goto fail;
2467                 }
2468
2469                 if (!smartcard_ndr_pointer_read(s, ptrIndex, NULL))
2470                         goto fail;
2471                 Stream_Read_UINT32(s, readerState->dwCurrentState); /* dwCurrentState (4 bytes) */
2472                 Stream_Read_UINT32(s, readerState->dwEventState);   /* dwEventState (4 bytes) */
2473                 Stream_Read_UINT32(s, readerState->cbAtr);          /* cbAtr (4 bytes) */
2474                 Stream_Read(s, readerState->rgbAtr, 36);            /* rgbAtr [0..36] (36 bytes) */
2475         }
2476
2477         for (index = 0; index < cReaders; index++)
2478         {
2479                 LPSCARD_READERSTATEW readerState = &rgReaderStates[index];
2480
2481                 status = smartcard_ndr_read_w(s, &readerState->szReader, NDR_PTR_FULL);
2482                 if (status != SCARD_S_SUCCESS)
2483                         goto fail;
2484         }
2485
2486         *ppcReaders = rgReaderStates;
2487         return SCARD_S_SUCCESS;
2488 fail:
2489         if (rgReaderStates)
2490         {
2491                 for (index = 0; index < cReaders; index++)
2492                 {
2493                         LPSCARD_READERSTATEW readerState = &rgReaderStates[index];
2494                         free(readerState->szReader);
2495                 }
2496         }
2497         free(rgReaderStates);
2498         return status;
2499 }
2500
2501 /******************************************************************************/
2502 /************************************* End Trace Functions ********************/
2503 /******************************************************************************/
2504
2505 LONG smartcard_unpack_get_status_change_a_call(SMARTCARD_DEVICE* smartcard, wStream* s,
2506                                                GetStatusChangeA_Call* call)
2507 {
2508         LONG status;
2509         UINT32 ndrPtr;
2510         UINT32 index = 0;
2511         call->rgReaderStates = NULL;
2512
2513         status = smartcard_unpack_redir_scard_context(smartcard, s, &(call->handles.hContext), &index);
2514         if (status != SCARD_S_SUCCESS)
2515                 return status;
2516
2517         if (Stream_GetRemainingLength(s) < 12)
2518         {
2519                 WLog_WARN(TAG, "GetStatusChangeA_Call is too short: %" PRIuz "",
2520                           Stream_GetRemainingLength(s));
2521                 return STATUS_BUFFER_TOO_SMALL;
2522         }
2523
2524         Stream_Read_UINT32(s, call->dwTimeOut); /* dwTimeOut (4 bytes) */
2525         Stream_Read_UINT32(s, call->cReaders);  /* cReaders (4 bytes) */
2526         if (!smartcard_ndr_pointer_read(s, &index, &ndrPtr))
2527                 return ERROR_INVALID_DATA;
2528
2529         if ((status =
2530                  smartcard_unpack_redir_scard_context_ref(smartcard, s, &(call->handles.hContext))))
2531                 return status;
2532
2533         if (ndrPtr)
2534         {
2535                 status = smartcard_unpack_reader_state_a(s, &call->rgReaderStates, call->cReaders, &index);
2536                 if (status != SCARD_S_SUCCESS)
2537                         return status;
2538         }
2539
2540         smartcard_trace_get_status_change_a_call(smartcard, call);
2541         return SCARD_S_SUCCESS;
2542 }
2543
2544 LONG smartcard_unpack_get_status_change_w_call(SMARTCARD_DEVICE* smartcard, wStream* s,
2545                                                GetStatusChangeW_Call* call)
2546 {
2547         UINT32 ndrPtr;
2548         LONG status;
2549         UINT32 index = 0;
2550
2551         call->rgReaderStates = NULL;
2552
2553         status = smartcard_unpack_redir_scard_context(smartcard, s, &(call->handles.hContext), &index);
2554         if (status != SCARD_S_SUCCESS)
2555                 return status;
2556
2557         if (Stream_GetRemainingLength(s) < 12)
2558         {
2559                 WLog_WARN(TAG, "GetStatusChangeW_Call is too short: %" PRIuz "",
2560                           Stream_GetRemainingLength(s));
2561                 return STATUS_BUFFER_TOO_SMALL;
2562         }
2563
2564         Stream_Read_UINT32(s, call->dwTimeOut); /* dwTimeOut (4 bytes) */
2565         Stream_Read_UINT32(s, call->cReaders);  /* cReaders (4 bytes) */
2566         if (!smartcard_ndr_pointer_read(s, &index, &ndrPtr))
2567                 return ERROR_INVALID_DATA;
2568
2569         if ((status =
2570                  smartcard_unpack_redir_scard_context_ref(smartcard, s, &(call->handles.hContext))))
2571                 return status;
2572
2573         if (ndrPtr)
2574         {
2575                 status = smartcard_unpack_reader_state_w(s, &call->rgReaderStates, call->cReaders, &index);
2576                 if (status != SCARD_S_SUCCESS)
2577                         return status;
2578         }
2579
2580         smartcard_trace_get_status_change_w_call(smartcard, call);
2581         return SCARD_S_SUCCESS;
2582 }
2583
2584 LONG smartcard_pack_get_status_change_return(SMARTCARD_DEVICE* smartcard, wStream* s,
2585                                              const GetStatusChange_Return* ret, BOOL unicode)
2586 {
2587         LONG status;
2588         DWORD cReaders = ret->cReaders;
2589         UINT32 index = 0;
2590
2591         smartcard_trace_get_status_change_return(smartcard, ret, unicode);
2592         if (ret->ReturnCode != SCARD_S_SUCCESS)
2593                 cReaders = 0;
2594         if (cReaders == SCARD_AUTOALLOCATE)
2595                 cReaders = 0;
2596
2597         if (!Stream_EnsureRemainingCapacity(s, 4))
2598                 return SCARD_E_NO_MEMORY;
2599
2600         Stream_Write_UINT32(s, cReaders); /* cReaders (4 bytes) */
2601         if (!smartcard_ndr_pointer_write(s, &index, cReaders))
2602                 return SCARD_E_NO_MEMORY;
2603         status = smartcard_ndr_write_state(s, ret->rgReaderStates, cReaders, NDR_PTR_SIMPLE);
2604         if (status != SCARD_S_SUCCESS)
2605                 return status;
2606         return ret->ReturnCode;
2607 }
2608
2609 LONG smartcard_unpack_state_call(SMARTCARD_DEVICE* smartcard, wStream* s, State_Call* call)
2610 {
2611         LONG status;
2612         UINT32 index = 0;
2613
2614         status = smartcard_unpack_redir_scard_context(smartcard, s, &(call->handles.hContext), &index);
2615         if (status != SCARD_S_SUCCESS)
2616                 return status;
2617
2618         status = smartcard_unpack_redir_scard_handle(smartcard, s, &(call->handles.hCard), &index);
2619         if (status != SCARD_S_SUCCESS)
2620                 return status;
2621
2622         if (Stream_GetRemainingLength(s) < 8)
2623         {
2624                 WLog_WARN(TAG, "State_Call is too short: %" PRIuz "", Stream_GetRemainingLength(s));
2625                 return STATUS_BUFFER_TOO_SMALL;
2626         }
2627
2628         Stream_Read_INT32(s, call->fpbAtrIsNULL); /* fpbAtrIsNULL (4 bytes) */
2629         Stream_Read_UINT32(s, call->cbAtrLen);    /* cbAtrLen (4 bytes) */
2630
2631         if ((status =
2632                  smartcard_unpack_redir_scard_context_ref(smartcard, s, &(call->handles.hContext))))
2633                 return status;
2634
2635         if ((status = smartcard_unpack_redir_scard_handle_ref(smartcard, s, &(call->handles.hCard))))
2636                 return status;
2637
2638         return status;
2639 }
2640
2641 LONG smartcard_pack_state_return(SMARTCARD_DEVICE* smartcard, wStream* s, const State_Return* ret)
2642 {
2643         LONG status;
2644         DWORD cbAtrLen = ret->cbAtrLen;
2645         DWORD index = 0;
2646
2647         smartcard_trace_state_return(smartcard, ret);
2648         if (ret->ReturnCode != SCARD_S_SUCCESS)
2649                 cbAtrLen = 0;
2650         if (cbAtrLen == SCARD_AUTOALLOCATE)
2651                 cbAtrLen = 0;
2652
2653         Stream_Write_UINT32(s, ret->dwState);    /* dwState (4 bytes) */
2654         Stream_Write_UINT32(s, ret->dwProtocol); /* dwProtocol (4 bytes) */
2655         Stream_Write_UINT32(s, cbAtrLen);        /* cbAtrLen (4 bytes) */
2656         if (!smartcard_ndr_pointer_write(s, &index, cbAtrLen))
2657                 return SCARD_E_NO_MEMORY;
2658         status = smartcard_ndr_write(s, ret->rgAtr, cbAtrLen, 1, NDR_PTR_SIMPLE);
2659         if (status != SCARD_S_SUCCESS)
2660                 return status;
2661         return ret->ReturnCode;
2662 }
2663
2664 LONG smartcard_unpack_status_call(SMARTCARD_DEVICE* smartcard, wStream* s, Status_Call* call,
2665                                   BOOL unicode)
2666 {
2667         LONG status;
2668         UINT32 index = 0;
2669         status = smartcard_unpack_redir_scard_context(smartcard, s, &(call->handles.hContext), &index);
2670         if (status != SCARD_S_SUCCESS)
2671                 return status;
2672
2673         status = smartcard_unpack_redir_scard_handle(smartcard, s, &(call->handles.hCard), &index);
2674         if (status != SCARD_S_SUCCESS)
2675                 return status;
2676
2677         if (Stream_GetRemainingLength(s) < 12)
2678         {
2679                 WLog_WARN(TAG, "Status_Call is too short: %" PRIuz "", Stream_GetRemainingLength(s));
2680                 return STATUS_BUFFER_TOO_SMALL;
2681         }
2682
2683         Stream_Read_INT32(s, call->fmszReaderNamesIsNULL); /* fmszReaderNamesIsNULL (4 bytes) */
2684         Stream_Read_UINT32(s, call->cchReaderLen);         /* cchReaderLen (4 bytes) */
2685         Stream_Read_UINT32(s, call->cbAtrLen);             /* cbAtrLen (4 bytes) */
2686
2687         if ((status =
2688                  smartcard_unpack_redir_scard_context_ref(smartcard, s, &(call->handles.hContext))))
2689                 return status;
2690
2691         if ((status = smartcard_unpack_redir_scard_handle_ref(smartcard, s, &(call->handles.hCard))))
2692                 return status;
2693
2694         smartcard_trace_status_call(smartcard, call, unicode);
2695         return status;
2696 }
2697
2698 LONG smartcard_pack_status_return(SMARTCARD_DEVICE* smartcard, wStream* s, const Status_Return* ret,
2699                                   BOOL unicode)
2700 {
2701         LONG status;
2702         DWORD index = 0;
2703         DWORD cBytes = ret->cBytes;
2704
2705         smartcard_trace_status_return(smartcard, ret, unicode);
2706         if (ret->ReturnCode != SCARD_S_SUCCESS)
2707                 cBytes = 0;
2708         if (cBytes == SCARD_AUTOALLOCATE)
2709                 cBytes = 0;
2710
2711         if (!Stream_EnsureRemainingCapacity(s, 4))
2712                 return SCARD_F_INTERNAL_ERROR;
2713
2714         Stream_Write_UINT32(s, cBytes); /* cBytes (4 bytes) */
2715         if (!smartcard_ndr_pointer_write(s, &index, cBytes))
2716                 return SCARD_E_NO_MEMORY;
2717
2718         if (!Stream_EnsureRemainingCapacity(s, 44))
2719                 return SCARD_F_INTERNAL_ERROR;
2720
2721         Stream_Write_UINT32(s, ret->dwState);            /* dwState (4 bytes) */
2722         Stream_Write_UINT32(s, ret->dwProtocol);         /* dwProtocol (4 bytes) */
2723         Stream_Write(s, ret->pbAtr, sizeof(ret->pbAtr)); /* pbAtr (32 bytes) */
2724         Stream_Write_UINT32(s, ret->cbAtrLen);           /* cbAtrLen (4 bytes) */
2725         status = smartcard_ndr_write(s, ret->mszReaderNames, cBytes, 1, NDR_PTR_SIMPLE);
2726         if (status != SCARD_S_SUCCESS)
2727                 return status;
2728         return ret->ReturnCode;
2729 }
2730
2731 LONG smartcard_unpack_get_attrib_call(SMARTCARD_DEVICE* smartcard, wStream* s, GetAttrib_Call* call)
2732 {
2733         LONG status;
2734         UINT32 index = 0;
2735
2736         status = smartcard_unpack_redir_scard_context(smartcard, s, &(call->handles.hContext), &index);
2737         if (status != SCARD_S_SUCCESS)
2738                 return status;
2739
2740         status = smartcard_unpack_redir_scard_handle(smartcard, s, &(call->handles.hCard), &index);
2741         if (status != SCARD_S_SUCCESS)
2742                 return status;
2743
2744         if (Stream_GetRemainingLength(s) < 12)
2745         {
2746                 WLog_WARN(TAG, "GetAttrib_Call is too short: %" PRIuz "", Stream_GetRemainingLength(s));
2747                 return STATUS_BUFFER_TOO_SMALL;
2748         }
2749
2750         Stream_Read_UINT32(s, call->dwAttrId);     /* dwAttrId (4 bytes) */
2751         Stream_Read_INT32(s, call->fpbAttrIsNULL); /* fpbAttrIsNULL (4 bytes) */
2752         Stream_Read_UINT32(s, call->cbAttrLen);    /* cbAttrLen (4 bytes) */
2753
2754         if ((status =
2755                  smartcard_unpack_redir_scard_context_ref(smartcard, s, &(call->handles.hContext))))
2756                 return status;
2757
2758         if ((status = smartcard_unpack_redir_scard_handle_ref(smartcard, s, &(call->handles.hCard))))
2759                 return status;
2760
2761         smartcard_trace_get_attrib_call(smartcard, call);
2762         return status;
2763 }
2764
2765 LONG smartcard_pack_get_attrib_return(SMARTCARD_DEVICE* smartcard, wStream* s,
2766                                       const GetAttrib_Return* ret, DWORD dwAttrId)
2767 {
2768         LONG status;
2769         DWORD cbAttrLen;
2770         DWORD index = 0;
2771         smartcard_trace_get_attrib_return(smartcard, ret, dwAttrId);
2772
2773         if (!Stream_EnsureRemainingCapacity(s, 4))
2774                 return SCARD_F_INTERNAL_ERROR;
2775
2776         cbAttrLen = ret->cbAttrLen;
2777         if (cbAttrLen == SCARD_AUTOALLOCATE)
2778                 cbAttrLen = 0;
2779         Stream_Write_UINT32(s, cbAttrLen); /* cbAttrLen (4 bytes) */
2780         if (!smartcard_ndr_pointer_write(s, &index, cbAttrLen))
2781                 return SCARD_E_NO_MEMORY;
2782
2783         status = smartcard_ndr_write(s, ret->pbAttr, cbAttrLen, 1, NDR_PTR_SIMPLE);
2784         if (status != SCARD_S_SUCCESS)
2785                 return status;
2786         return ret->ReturnCode;
2787 }
2788
2789 LONG smartcard_unpack_control_call(SMARTCARD_DEVICE* smartcard, wStream* s, Control_Call* call)
2790 {
2791         LONG status;
2792         UINT32 index = 0;
2793         UINT32 pvInBufferNdrPtr;
2794
2795         call->pvInBuffer = NULL;
2796
2797         status = smartcard_unpack_redir_scard_context(smartcard, s, &(call->handles.hContext), &index);
2798         if (status != SCARD_S_SUCCESS)
2799                 return status;
2800
2801         status = smartcard_unpack_redir_scard_handle(smartcard, s, &(call->handles.hCard), &index);
2802         if (status != SCARD_S_SUCCESS)
2803                 return status;
2804
2805         if (Stream_GetRemainingLength(s) < 20)
2806         {
2807                 WLog_WARN(TAG, "Control_Call is too short: %" PRIuz "", Stream_GetRemainingLength(s));
2808                 return STATUS_BUFFER_TOO_SMALL;
2809         }
2810
2811         Stream_Read_UINT32(s, call->dwControlCode);                    /* dwControlCode (4 bytes) */
2812         Stream_Read_UINT32(s, call->cbInBufferSize);                   /* cbInBufferSize (4 bytes) */
2813         if (!smartcard_ndr_pointer_read(s, &index, &pvInBufferNdrPtr)) /* pvInBufferNdrPtr (4 bytes) */
2814                 return ERROR_INVALID_DATA;
2815         Stream_Read_INT32(s, call->fpvOutBufferIsNULL); /* fpvOutBufferIsNULL (4 bytes) */
2816         Stream_Read_UINT32(s, call->cbOutBufferSize);   /* cbOutBufferSize (4 bytes) */
2817
2818         if ((status =
2819                  smartcard_unpack_redir_scard_context_ref(smartcard, s, &(call->handles.hContext))))
2820                 return status;
2821
2822         if ((status = smartcard_unpack_redir_scard_handle_ref(smartcard, s, &(call->handles.hCard))))
2823                 return status;
2824
2825         if (pvInBufferNdrPtr)
2826         {
2827                 status = smartcard_ndr_read(s, &call->pvInBuffer, call->cbInBufferSize, 1, NDR_PTR_SIMPLE);
2828                 if (status != SCARD_S_SUCCESS)
2829                         return status;
2830         }
2831
2832         smartcard_trace_control_call(smartcard, call);
2833         return SCARD_S_SUCCESS;
2834 }
2835
2836 LONG smartcard_pack_control_return(SMARTCARD_DEVICE* smartcard, wStream* s,
2837                                    const Control_Return* ret)
2838 {
2839         LONG status;
2840         DWORD cbDataLen = ret->cbOutBufferSize;
2841         DWORD index = 0;
2842
2843         smartcard_trace_control_return(smartcard, ret);
2844         if (ret->ReturnCode != SCARD_S_SUCCESS)
2845                 cbDataLen = 0;
2846         if (cbDataLen == SCARD_AUTOALLOCATE)
2847                 cbDataLen = 0;
2848
2849         if (!Stream_EnsureRemainingCapacity(s, 4))
2850                 return SCARD_F_INTERNAL_ERROR;
2851
2852         Stream_Write_UINT32(s, cbDataLen); /* cbOutBufferSize (4 bytes) */
2853         if (!smartcard_ndr_pointer_write(s, &index, cbDataLen))
2854                 return SCARD_E_NO_MEMORY;
2855
2856         status = smartcard_ndr_write(s, ret->pvOutBuffer, cbDataLen, 1, NDR_PTR_SIMPLE);
2857         if (status != SCARD_S_SUCCESS)
2858                 return status;
2859         return ret->ReturnCode;
2860 }
2861
2862 LONG smartcard_unpack_transmit_call(SMARTCARD_DEVICE* smartcard, wStream* s, Transmit_Call* call)
2863 {
2864         LONG status;
2865         UINT32 length;
2866         BYTE* pbExtraBytes;
2867         UINT32 pbExtraBytesNdrPtr;
2868         UINT32 pbSendBufferNdrPtr;
2869         UINT32 pioRecvPciNdrPtr;
2870         SCardIO_Request ioSendPci;
2871         SCardIO_Request ioRecvPci;
2872         UINT32 index = 0;
2873         call->pioSendPci = NULL;
2874         call->pioRecvPci = NULL;
2875         call->pbSendBuffer = NULL;
2876
2877         status = smartcard_unpack_redir_scard_context(smartcard, s, &(call->handles.hContext), &index);
2878         if (status != SCARD_S_SUCCESS)
2879                 return status;
2880
2881         status = smartcard_unpack_redir_scard_handle(smartcard, s, &(call->handles.hCard), &index);
2882         if (status != SCARD_S_SUCCESS)
2883                 return status;
2884
2885         if (Stream_GetRemainingLength(s) < 32)
2886         {
2887                 WLog_WARN(TAG, "Transmit_Call is too short: Actual: %" PRIuz ", Expected: 32",
2888                           Stream_GetRemainingLength(s));
2889                 return STATUS_BUFFER_TOO_SMALL;
2890         }
2891
2892         Stream_Read_UINT32(s, ioSendPci.dwProtocol);   /* dwProtocol (4 bytes) */
2893         Stream_Read_UINT32(s, ioSendPci.cbExtraBytes); /* cbExtraBytes (4 bytes) */
2894         if (!smartcard_ndr_pointer_read(s, &index,
2895                                         &pbExtraBytesNdrPtr)) /* pbExtraBytesNdrPtr (4 bytes) */
2896                 return ERROR_INVALID_DATA;
2897
2898         Stream_Read_UINT32(s, call->cbSendLength); /* cbSendLength (4 bytes) */
2899         if (!smartcard_ndr_pointer_read(s, &index,
2900                                         &pbSendBufferNdrPtr)) /* pbSendBufferNdrPtr (4 bytes) */
2901                 return ERROR_INVALID_DATA;
2902
2903         if (!smartcard_ndr_pointer_read(s, &index, &pioRecvPciNdrPtr)) /* pioRecvPciNdrPtr (4 bytes) */
2904                 return ERROR_INVALID_DATA;
2905
2906         Stream_Read_INT32(s, call->fpbRecvBufferIsNULL); /* fpbRecvBufferIsNULL (4 bytes) */
2907         Stream_Read_UINT32(s, call->cbRecvLength);       /* cbRecvLength (4 bytes) */
2908
2909         if (ioSendPci.cbExtraBytes > 1024)
2910         {
2911                 WLog_WARN(TAG,
2912                           "Transmit_Call ioSendPci.cbExtraBytes is out of bounds: %" PRIu32 " (max: 1024)",
2913                           ioSendPci.cbExtraBytes);
2914                 return STATUS_INVALID_PARAMETER;
2915         }
2916
2917         if (call->cbSendLength > 66560)
2918         {
2919                 WLog_WARN(TAG, "Transmit_Call cbSendLength is out of bounds: %" PRIu32 " (max: 66560)",
2920                           ioSendPci.cbExtraBytes);
2921                 return STATUS_INVALID_PARAMETER;
2922         }
2923
2924         if ((status =
2925                  smartcard_unpack_redir_scard_context_ref(smartcard, s, &(call->handles.hContext))))
2926                 return status;
2927
2928         if ((status = smartcard_unpack_redir_scard_handle_ref(smartcard, s, &(call->handles.hCard))))
2929                 return status;
2930
2931         if (ioSendPci.cbExtraBytes && !pbExtraBytesNdrPtr)
2932         {
2933                 WLog_WARN(
2934                     TAG, "Transmit_Call ioSendPci.cbExtraBytes is non-zero but pbExtraBytesNdrPtr is null");
2935                 return STATUS_INVALID_PARAMETER;
2936         }
2937
2938         if (pbExtraBytesNdrPtr)
2939         {
2940                 // TODO: Use unified pointer reading
2941                 if (Stream_GetRemainingLength(s) < 4)
2942                 {
2943                         WLog_WARN(TAG, "Transmit_Call is too short: %" PRIuz " (ioSendPci.pbExtraBytes)",
2944                                   Stream_GetRemainingLength(s));
2945                         return STATUS_BUFFER_TOO_SMALL;
2946                 }
2947
2948                 Stream_Read_UINT32(s, length); /* Length (4 bytes) */
2949
2950                 if (Stream_GetRemainingLength(s) < ioSendPci.cbExtraBytes)
2951                 {
2952                         WLog_WARN(TAG,
2953                                   "Transmit_Call is too short: Actual: %" PRIuz ", Expected: %" PRIu32
2954                                   " (ioSendPci.cbExtraBytes)",
2955                                   Stream_GetRemainingLength(s), ioSendPci.cbExtraBytes);
2956                         return STATUS_BUFFER_TOO_SMALL;
2957                 }
2958
2959                 ioSendPci.pbExtraBytes = Stream_Pointer(s);
2960                 call->pioSendPci =
2961                     (LPSCARD_IO_REQUEST)malloc(sizeof(SCARD_IO_REQUEST) + ioSendPci.cbExtraBytes);
2962
2963                 if (!call->pioSendPci)
2964                 {
2965                         WLog_WARN(TAG, "Transmit_Call out of memory error (pioSendPci)");
2966                         return STATUS_NO_MEMORY;
2967                 }
2968
2969                 call->pioSendPci->dwProtocol = ioSendPci.dwProtocol;
2970                 call->pioSendPci->cbPciLength = (DWORD)(ioSendPci.cbExtraBytes + sizeof(SCARD_IO_REQUEST));
2971                 pbExtraBytes = &((BYTE*)call->pioSendPci)[sizeof(SCARD_IO_REQUEST)];
2972                 Stream_Read(s, pbExtraBytes, ioSendPci.cbExtraBytes);
2973                 smartcard_unpack_read_size_align(smartcard, s, ioSendPci.cbExtraBytes, 4);
2974         }
2975         else
2976         {
2977                 call->pioSendPci = (LPSCARD_IO_REQUEST)calloc(1, sizeof(SCARD_IO_REQUEST));
2978
2979                 if (!call->pioSendPci)
2980                 {
2981                         WLog_WARN(TAG, "Transmit_Call out of memory error (pioSendPci)");
2982                         return STATUS_NO_MEMORY;
2983                 }
2984
2985                 call->pioSendPci->dwProtocol = ioSendPci.dwProtocol;
2986                 call->pioSendPci->cbPciLength = sizeof(SCARD_IO_REQUEST);
2987         }
2988
2989         if (pbSendBufferNdrPtr)
2990         {
2991                 status = smartcard_ndr_read(s, &call->pbSendBuffer, call->cbSendLength, 1, NDR_PTR_SIMPLE);
2992                 if (status != SCARD_S_SUCCESS)
2993                         return status;
2994         }
2995
2996         if (pioRecvPciNdrPtr)
2997         {
2998                 if (Stream_GetRemainingLength(s) < 12)
2999                 {
3000                         WLog_WARN(TAG, "Transmit_Call is too short: Actual: %" PRIuz ", Expected: 12",
3001                                   Stream_GetRemainingLength(s));
3002                         return STATUS_BUFFER_TOO_SMALL;
3003                 }
3004
3005                 Stream_Read_UINT32(s, ioRecvPci.dwProtocol);   /* dwProtocol (4 bytes) */
3006                 Stream_Read_UINT32(s, ioRecvPci.cbExtraBytes); /* cbExtraBytes (4 bytes) */
3007                 if (!smartcard_ndr_pointer_read(s, &index,
3008                                                 &pbExtraBytesNdrPtr)) /* pbExtraBytesNdrPtr (4 bytes) */
3009                         return ERROR_INVALID_DATA;
3010
3011                 if (ioRecvPci.cbExtraBytes && !pbExtraBytesNdrPtr)
3012                 {
3013                         WLog_WARN(
3014                             TAG,
3015                             "Transmit_Call ioRecvPci.cbExtraBytes is non-zero but pbExtraBytesNdrPtr is null");
3016                         return STATUS_INVALID_PARAMETER;
3017                 }
3018
3019                 if (pbExtraBytesNdrPtr)
3020                 {
3021                         // TODO: Unify ndr pointer reading
3022                         if (Stream_GetRemainingLength(s) < 4)
3023                         {
3024                                 WLog_WARN(TAG, "Transmit_Call is too short: %" PRIuz " (ioRecvPci.pbExtraBytes)",
3025                                           Stream_GetRemainingLength(s));
3026                                 return STATUS_BUFFER_TOO_SMALL;
3027                         }
3028
3029                         Stream_Read_UINT32(s, length); /* Length (4 bytes) */
3030
3031                         if (ioRecvPci.cbExtraBytes > 1024)
3032                         {
3033                                 WLog_WARN(TAG,
3034                                           "Transmit_Call ioRecvPci.cbExtraBytes is out of bounds: %" PRIu32
3035                                           " (max: 1024)",
3036                                           ioRecvPci.cbExtraBytes);
3037                                 return STATUS_INVALID_PARAMETER;
3038                         }
3039
3040                         if (length != ioRecvPci.cbExtraBytes)
3041                         {
3042                                 WLog_WARN(TAG,
3043                                           "Transmit_Call unexpected length: Actual: %" PRIu32 ", Expected: %" PRIu32
3044                                           " (ioRecvPci.cbExtraBytes)",
3045                                           length, ioRecvPci.cbExtraBytes);
3046                                 return STATUS_INVALID_PARAMETER;
3047                         }
3048
3049                         if (Stream_GetRemainingLength(s) < ioRecvPci.cbExtraBytes)
3050                         {
3051                                 WLog_WARN(TAG,
3052                                           "Transmit_Call is too short: Actual: %" PRIuz ", Expected: %" PRIu32
3053                                           " (ioRecvPci.cbExtraBytes)",
3054                                           Stream_GetRemainingLength(s), ioRecvPci.cbExtraBytes);
3055                                 return STATUS_BUFFER_TOO_SMALL;
3056                         }
3057
3058                         ioRecvPci.pbExtraBytes = Stream_Pointer(s);
3059                         call->pioRecvPci =
3060                             (LPSCARD_IO_REQUEST)malloc(sizeof(SCARD_IO_REQUEST) + ioRecvPci.cbExtraBytes);
3061
3062                         if (!call->pioRecvPci)
3063                         {
3064                                 WLog_WARN(TAG, "Transmit_Call out of memory error (pioRecvPci)");
3065                                 return STATUS_NO_MEMORY;
3066                         }
3067
3068                         call->pioRecvPci->dwProtocol = ioRecvPci.dwProtocol;
3069                         call->pioRecvPci->cbPciLength =
3070                             (DWORD)(ioRecvPci.cbExtraBytes + sizeof(SCARD_IO_REQUEST));
3071                         pbExtraBytes = &((BYTE*)call->pioRecvPci)[sizeof(SCARD_IO_REQUEST)];
3072                         Stream_Read(s, pbExtraBytes, ioRecvPci.cbExtraBytes);
3073                         smartcard_unpack_read_size_align(smartcard, s, ioRecvPci.cbExtraBytes, 4);
3074                 }
3075                 else
3076                 {
3077                         call->pioRecvPci = (LPSCARD_IO_REQUEST)calloc(1, sizeof(SCARD_IO_REQUEST));
3078
3079                         if (!call->pioRecvPci)
3080                         {
3081                                 WLog_WARN(TAG, "Transmit_Call out of memory error (pioRecvPci)");
3082                                 return STATUS_NO_MEMORY;
3083                         }
3084
3085                         call->pioRecvPci->dwProtocol = ioRecvPci.dwProtocol;
3086                         call->pioRecvPci->cbPciLength = sizeof(SCARD_IO_REQUEST);
3087                 }
3088         }
3089
3090         smartcard_trace_transmit_call(smartcard, call);
3091         return SCARD_S_SUCCESS;
3092 }
3093
3094 LONG smartcard_pack_transmit_return(SMARTCARD_DEVICE* smartcard, wStream* s,
3095                                     const Transmit_Return* ret)
3096 {
3097         LONG status;
3098         DWORD index = 0;
3099         LONG error;
3100         UINT32 cbRecvLength = ret->cbRecvLength;
3101         UINT32 cbRecvPci = ret->pioRecvPci ? ret->pioRecvPci->cbPciLength : 0;
3102
3103         smartcard_trace_transmit_return(smartcard, ret);
3104
3105         if (!ret->pbRecvBuffer)
3106                 cbRecvLength = 0;
3107
3108         if (!smartcard_ndr_pointer_write(s, &index, cbRecvPci))
3109                 return SCARD_E_NO_MEMORY;
3110         if (!Stream_EnsureRemainingCapacity(s, 4))
3111                 return SCARD_E_NO_MEMORY;
3112         Stream_Write_UINT32(s, cbRecvLength); /* cbRecvLength (4 bytes) */
3113         if (!smartcard_ndr_pointer_write(s, &index, cbRecvLength))
3114                 return SCARD_E_NO_MEMORY;
3115
3116         if (ret->pioRecvPci)
3117         {
3118                 UINT32 cbExtraBytes = (UINT32)(ret->pioRecvPci->cbPciLength - sizeof(SCARD_IO_REQUEST));
3119                 BYTE* pbExtraBytes = &((BYTE*)ret->pioRecvPci)[sizeof(SCARD_IO_REQUEST)];
3120
3121                 if (!Stream_EnsureRemainingCapacity(s, cbExtraBytes + 16))
3122                 {
3123                         WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!");
3124                         return SCARD_F_INTERNAL_ERROR;
3125                 }
3126
3127                 Stream_Write_UINT32(s, ret->pioRecvPci->dwProtocol); /* dwProtocol (4 bytes) */
3128                 Stream_Write_UINT32(s, cbExtraBytes);                /* cbExtraBytes (4 bytes) */
3129                 if (!smartcard_ndr_pointer_write(s, &index, cbExtraBytes))
3130                         return SCARD_E_NO_MEMORY;
3131                 error = smartcard_ndr_write(s, pbExtraBytes, cbExtraBytes, 1, NDR_PTR_SIMPLE);
3132                 if (error)
3133                         return error;
3134         }
3135
3136         status = smartcard_ndr_write(s, ret->pbRecvBuffer, ret->cbRecvLength, 1, NDR_PTR_SIMPLE);
3137         if (status != SCARD_S_SUCCESS)
3138                 return status;
3139         return ret->ReturnCode;
3140 }
3141
3142 LONG smartcard_unpack_locate_cards_by_atr_a_call(SMARTCARD_DEVICE* smartcard, wStream* s,
3143                                                  LocateCardsByATRA_Call* call)
3144 {
3145         LONG status;
3146         UINT32 rgReaderStatesNdrPtr;
3147         UINT32 rgAtrMasksNdrPtr;
3148         UINT32 index = 0;
3149         call->rgReaderStates = NULL;
3150
3151         status = smartcard_unpack_redir_scard_context(smartcard, s, &(call->handles.hContext), &index);
3152         if (status != SCARD_S_SUCCESS)
3153                 return status;
3154
3155         if (Stream_GetRemainingLength(s) < 16)
3156         {
3157                 WLog_WARN(TAG, "LocateCardsByATRA_Call is too short: %" PRIuz "",
3158                           Stream_GetRemainingLength(s));
3159                 return STATUS_BUFFER_TOO_SMALL;
3160         }
3161
3162         Stream_Read_UINT32(s, call->cAtrs);
3163         if (!smartcard_ndr_pointer_read(s, &index, &rgAtrMasksNdrPtr))
3164                 return ERROR_INVALID_DATA;
3165         Stream_Read_UINT32(s, call->cReaders); /* cReaders (4 bytes) */
3166         if (!smartcard_ndr_pointer_read(s, &index, &rgReaderStatesNdrPtr))
3167                 return ERROR_INVALID_DATA;
3168
3169         if ((status =
3170                  smartcard_unpack_redir_scard_context_ref(smartcard, s, &(call->handles.hContext))))
3171                 return status;
3172
3173         if ((rgAtrMasksNdrPtr && !call->cAtrs) || (!rgAtrMasksNdrPtr && call->cAtrs))
3174         {
3175                 WLog_WARN(TAG,
3176                           "LocateCardsByATRA_Call rgAtrMasksNdrPtr (0x%08" PRIX32
3177                           ") and cAtrs (0x%08" PRIX32 ") inconsistency",
3178                           rgAtrMasksNdrPtr, call->cAtrs);
3179                 return STATUS_INVALID_PARAMETER;
3180         }
3181
3182         if (rgAtrMasksNdrPtr)
3183         {
3184                 status = smartcard_ndr_read_atrmask(s, &call->rgAtrMasks, call->cAtrs, NDR_PTR_SIMPLE);
3185                 if (status != SCARD_S_SUCCESS)
3186                         return status;
3187         }
3188
3189         if (rgReaderStatesNdrPtr)
3190         {
3191                 status = smartcard_unpack_reader_state_a(s, &call->rgReaderStates, call->cReaders, &index);
3192                 if (status != SCARD_S_SUCCESS)
3193                         return status;
3194         }
3195
3196         smartcard_trace_locate_cards_by_atr_a_call(smartcard, call);
3197         return SCARD_S_SUCCESS;
3198 }
3199
3200 LONG smartcard_unpack_context_and_two_strings_a_call(SMARTCARD_DEVICE* smartcard, wStream* s,
3201                                                      ContextAndTwoStringA_Call* call)
3202 {
3203         LONG status;
3204         UINT32 sz1NdrPtr, sz2NdrPtr;
3205         UINT32 index = 0;
3206
3207         status = smartcard_unpack_redir_scard_context(smartcard, s, &(call->handles.hContext), &index);
3208         if (status != SCARD_S_SUCCESS)
3209                 return status;
3210
3211         if (!smartcard_ndr_pointer_read(s, &index, &sz1NdrPtr))
3212                 return ERROR_INVALID_DATA;
3213         if (!smartcard_ndr_pointer_read(s, &index, &sz2NdrPtr))
3214                 return ERROR_INVALID_DATA;
3215
3216         status = smartcard_unpack_redir_scard_context_ref(smartcard, s, &call->handles.hContext);
3217         if (status != SCARD_S_SUCCESS)
3218                 return status;
3219
3220         if (sz1NdrPtr)
3221         {
3222                 status = smartcard_ndr_read_a(s, &call->sz1, NDR_PTR_FULL);
3223                 if (status != SCARD_S_SUCCESS)
3224                         return status;
3225         }
3226         if (sz2NdrPtr)
3227         {
3228                 status = smartcard_ndr_read_a(s, &call->sz2, NDR_PTR_FULL);
3229                 if (status != SCARD_S_SUCCESS)
3230                         return status;
3231         }
3232         smartcard_trace_context_and_two_strings_a_call(smartcard, call);
3233         return SCARD_S_SUCCESS;
3234 }
3235
3236 LONG smartcard_unpack_context_and_two_strings_w_call(SMARTCARD_DEVICE* smartcard, wStream* s,
3237                                                      ContextAndTwoStringW_Call* call)
3238 {
3239         LONG status;
3240         UINT32 sz1NdrPtr, sz2NdrPtr;
3241         UINT32 index = 0;
3242         status = smartcard_unpack_redir_scard_context(smartcard, s, &(call->handles.hContext), &index);
3243         if (status != SCARD_S_SUCCESS)
3244                 return status;
3245
3246         if (!smartcard_ndr_pointer_read(s, &index, &sz1NdrPtr))
3247                 return ERROR_INVALID_DATA;
3248         if (!smartcard_ndr_pointer_read(s, &index, &sz2NdrPtr))
3249                 return ERROR_INVALID_DATA;
3250
3251         status = smartcard_unpack_redir_scard_context_ref(smartcard, s, &call->handles.hContext);
3252         if (status != SCARD_S_SUCCESS)
3253                 return status;
3254
3255         if (sz1NdrPtr)
3256         {
3257                 status = smartcard_ndr_read_w(s, &call->sz1, NDR_PTR_FULL);
3258                 if (status != SCARD_S_SUCCESS)
3259                         return status;
3260         }
3261         if (sz2NdrPtr)
3262         {
3263                 status = smartcard_ndr_read_w(s, &call->sz2, NDR_PTR_FULL);
3264                 if (status != SCARD_S_SUCCESS)
3265                         return status;
3266         }
3267         smartcard_trace_context_and_two_strings_w_call(smartcard, call);
3268         return SCARD_S_SUCCESS;
3269 }
3270
3271 LONG smartcard_unpack_locate_cards_a_call(SMARTCARD_DEVICE* smartcard, wStream* s,
3272                                           LocateCardsA_Call* call)
3273 {
3274         LONG status;
3275         UINT32 sz1NdrPtr, sz2NdrPtr;
3276         UINT32 index = 0;
3277         status = smartcard_unpack_redir_scard_context(smartcard, s, &(call->handles.hContext), &index);
3278         if (status != SCARD_S_SUCCESS)
3279                 return status;
3280
3281         if (Stream_GetRemainingLength(s) < 16)
3282         {
3283                 WLog_WARN(TAG, "%s is too short: %" PRIuz "", __FUNCTION__, Stream_GetRemainingLength(s));
3284                 return STATUS_BUFFER_TOO_SMALL;
3285         }
3286         Stream_Read_UINT32(s, call->cBytes);
3287         if (!smartcard_ndr_pointer_read(s, &index, &sz1NdrPtr))
3288                 return ERROR_INVALID_DATA;
3289
3290         Stream_Read_UINT32(s, call->cReaders);
3291         if (!smartcard_ndr_pointer_read(s, &index, &sz2NdrPtr))
3292                 return ERROR_INVALID_DATA;
3293
3294         if (sz1NdrPtr)
3295         {
3296                 status =
3297                     smartcard_ndr_read_fixed_string_a(s, &call->mszCards, call->cBytes, NDR_PTR_SIMPLE);
3298                 if (status != SCARD_S_SUCCESS)
3299                         return status;
3300         }
3301         if (sz2NdrPtr)
3302         {
3303                 status = smartcard_unpack_reader_state_a(s, &call->rgReaderStates, call->cReaders, &index);
3304                 if (status != SCARD_S_SUCCESS)
3305                         return status;
3306         }
3307         smartcard_trace_locate_cards_a_call(smartcard, call);
3308         return SCARD_S_SUCCESS;
3309 }
3310
3311 LONG smartcard_unpack_locate_cards_w_call(SMARTCARD_DEVICE* smartcard, wStream* s,
3312                                           LocateCardsW_Call* call)
3313 {
3314         LONG status;
3315         UINT32 sz1NdrPtr, sz2NdrPtr;
3316         UINT32 index = 0;
3317
3318         status = smartcard_unpack_redir_scard_context(smartcard, s, &(call->handles.hContext), &index);
3319         if (status != SCARD_S_SUCCESS)
3320                 return status;
3321
3322         if (Stream_GetRemainingLength(s) < 16)
3323         {
3324                 WLog_WARN(TAG, "%s is too short: %" PRIuz "", __FUNCTION__, Stream_GetRemainingLength(s));
3325                 return STATUS_BUFFER_TOO_SMALL;
3326         }
3327         Stream_Read_UINT32(s, call->cBytes);
3328         if (!smartcard_ndr_pointer_read(s, &index, &sz1NdrPtr))
3329                 return ERROR_INVALID_DATA;
3330
3331         Stream_Read_UINT32(s, call->cReaders);
3332         if (!smartcard_ndr_pointer_read(s, &index, &sz2NdrPtr))
3333                 return ERROR_INVALID_DATA;
3334
3335         if (sz1NdrPtr)
3336         {
3337                 status =
3338                     smartcard_ndr_read_fixed_string_w(s, &call->mszCards, call->cBytes, NDR_PTR_SIMPLE);
3339                 if (status != SCARD_S_SUCCESS)
3340                         return status;
3341         }
3342         if (sz2NdrPtr)
3343         {
3344                 status = smartcard_unpack_reader_state_w(s, &call->rgReaderStates, call->cReaders, &index);
3345                 if (status != SCARD_S_SUCCESS)
3346                         return status;
3347         }
3348         smartcard_trace_locate_cards_w_call(smartcard, call);
3349         return SCARD_S_SUCCESS;
3350 }
3351
3352 LONG smartcard_unpack_set_attrib_call(SMARTCARD_DEVICE* smartcard, wStream* s, SetAttrib_Call* call)
3353 {
3354         LONG status;
3355         UINT32 index = 0;
3356         UINT32 ndrPtr;
3357
3358         status = smartcard_unpack_redir_scard_context(smartcard, s, &(call->handles.hContext), &index);
3359         if (status != SCARD_S_SUCCESS)
3360                 return status;
3361         status = smartcard_unpack_redir_scard_handle(smartcard, s, &(call->handles.hCard), &index);
3362         if (status != SCARD_S_SUCCESS)
3363                 return status;
3364
3365         if (Stream_GetRemainingLength(s) < 12)
3366                 return STATUS_BUFFER_TOO_SMALL;
3367         Stream_Read_UINT32(s, call->dwAttrId);
3368         Stream_Read_UINT32(s, call->cbAttrLen);
3369
3370         if (!smartcard_ndr_pointer_read(s, &index, &ndrPtr))
3371                 return ERROR_INVALID_DATA;
3372
3373         if ((status =
3374                  smartcard_unpack_redir_scard_context_ref(smartcard, s, &(call->handles.hContext))))
3375                 return status;
3376
3377         if ((status = smartcard_unpack_redir_scard_handle_ref(smartcard, s, &(call->handles.hCard))))
3378                 return status;
3379
3380         if (ndrPtr)
3381         {
3382                 // TODO: call->cbAttrLen was larger than the pointer value.
3383                 // TODO: Maybe need to refine the checks?
3384                 status = smartcard_ndr_read(s, &call->pbAttr, 0, 1, NDR_PTR_SIMPLE);
3385                 if (status != SCARD_S_SUCCESS)
3386                         return status;
3387         }
3388         smartcard_trace_set_attrib_call(smartcard, call);
3389         return SCARD_S_SUCCESS;
3390 }
3391
3392 LONG smartcard_unpack_locate_cards_by_atr_w_call(SMARTCARD_DEVICE* smartcard, wStream* s,
3393                                                  LocateCardsByATRW_Call* call)
3394 {
3395         LONG status;
3396         UINT32 rgReaderStatesNdrPtr;
3397         UINT32 rgAtrMasksNdrPtr;
3398         UINT32 index = 0;
3399         call->rgReaderStates = NULL;
3400
3401         status = smartcard_unpack_redir_scard_context(smartcard, s, &(call->handles.hContext), &index);
3402         if (status != SCARD_S_SUCCESS)
3403                 return status;
3404
3405         if (Stream_GetRemainingLength(s) < 16)
3406         {
3407                 WLog_WARN(TAG, "LocateCardsByATRW_Call is too short: %" PRIuz "",
3408                           Stream_GetRemainingLength(s));
3409                 return STATUS_BUFFER_TOO_SMALL;
3410         }
3411
3412         Stream_Read_UINT32(s, call->cAtrs);
3413         if (!smartcard_ndr_pointer_read(s, &index, &rgAtrMasksNdrPtr))
3414                 return ERROR_INVALID_DATA;
3415
3416         Stream_Read_UINT32(s, call->cReaders); /* cReaders (4 bytes) */
3417         if (!smartcard_ndr_pointer_read(s, &index, &rgReaderStatesNdrPtr))
3418                 return ERROR_INVALID_DATA;
3419
3420         if ((status =
3421                  smartcard_unpack_redir_scard_context_ref(smartcard, s, &(call->handles.hContext))))
3422                 return status;
3423
3424         if ((rgAtrMasksNdrPtr && !call->cAtrs) || (!rgAtrMasksNdrPtr && call->cAtrs))
3425         {
3426                 WLog_WARN(TAG,
3427                           "LocateCardsByATRW_Call rgAtrMasksNdrPtr (0x%08" PRIX32
3428                           ") and cAtrs (0x%08" PRIX32 ") inconsistency",
3429                           rgAtrMasksNdrPtr, call->cAtrs);
3430                 return STATUS_INVALID_PARAMETER;
3431         }
3432
3433         if (rgAtrMasksNdrPtr)
3434         {
3435                 status = smartcard_ndr_read_atrmask(s, &call->rgAtrMasks, call->cAtrs, NDR_PTR_SIMPLE);
3436                 if (status != SCARD_S_SUCCESS)
3437                         return status;
3438         }
3439
3440         if (rgReaderStatesNdrPtr)
3441         {
3442                 status = smartcard_unpack_reader_state_w(s, &call->rgReaderStates, call->cReaders, &index);
3443                 if (status != SCARD_S_SUCCESS)
3444                         return status;
3445         }
3446
3447         smartcard_trace_locate_cards_by_atr_w_call(smartcard, call);
3448         return SCARD_S_SUCCESS;
3449 }
3450
3451 LONG smartcard_unpack_read_cache_a_call(SMARTCARD_DEVICE* smartcard, wStream* s,
3452                                         ReadCacheA_Call* call)
3453 {
3454         LONG status;
3455         UINT32 mszNdrPtr;
3456         UINT32 contextNdrPtr;
3457         UINT32 index = 0;
3458
3459         if (!smartcard_ndr_pointer_read(s, &index, &mszNdrPtr))
3460                 return ERROR_INVALID_DATA;
3461
3462         status = smartcard_unpack_redir_scard_context(smartcard, s, &(call->Common.handles.hContext),
3463                                                       &index);
3464         if (status != SCARD_S_SUCCESS)
3465                 return status;
3466
3467         if (!smartcard_ndr_pointer_read(s, &index, &contextNdrPtr))
3468                 return ERROR_INVALID_DATA;
3469
3470         if (Stream_GetRemainingLength(s) < 12)
3471                 return STATUS_BUFFER_TOO_SMALL;
3472         Stream_Read_UINT32(s, call->Common.FreshnessCounter);
3473         Stream_Read_INT32(s, call->Common.fPbDataIsNULL);
3474         Stream_Read_UINT32(s, call->Common.cbDataLen);
3475
3476         call->szLookupName = NULL;
3477         if (mszNdrPtr)
3478         {
3479                 status = smartcard_ndr_read_a(s, &call->szLookupName, NDR_PTR_FULL);
3480                 if (status != SCARD_S_SUCCESS)
3481                         return status;
3482         }
3483
3484         status = smartcard_unpack_redir_scard_context_ref(smartcard, s, &call->Common.handles.hContext);
3485         if (status != SCARD_S_SUCCESS)
3486                 return status;
3487
3488         if (contextNdrPtr)
3489         {
3490                 status = smartcard_ndr_read_u(s, &call->Common.CardIdentifier);
3491                 if (status != SCARD_S_SUCCESS)
3492                         return status;
3493         }
3494         smartcard_trace_read_cache_a_call(smartcard, call);
3495         return SCARD_S_SUCCESS;
3496 }
3497
3498 LONG smartcard_unpack_read_cache_w_call(SMARTCARD_DEVICE* smartcard, wStream* s,
3499                                         ReadCacheW_Call* call)
3500 {
3501         LONG status;
3502         UINT32 mszNdrPtr;
3503         UINT32 contextNdrPtr;
3504         UINT32 index = 0;
3505
3506         if (!smartcard_ndr_pointer_read(s, &index, &mszNdrPtr))
3507                 return ERROR_INVALID_DATA;
3508
3509         status = smartcard_unpack_redir_scard_context(smartcard, s, &(call->Common.handles.hContext),
3510                                                       &index);
3511         if (status != SCARD_S_SUCCESS)
3512                 return status;
3513
3514         if (!smartcard_ndr_pointer_read(s, &index, &contextNdrPtr))
3515                 return ERROR_INVALID_DATA;
3516
3517         if (Stream_GetRemainingLength(s) < 12)
3518                 return STATUS_BUFFER_TOO_SMALL;
3519         Stream_Read_UINT32(s, call->Common.FreshnessCounter);
3520         Stream_Read_INT32(s, call->Common.fPbDataIsNULL);
3521         Stream_Read_UINT32(s, call->Common.cbDataLen);
3522
3523         call->szLookupName = NULL;
3524         if (mszNdrPtr)
3525         {
3526                 status = smartcard_ndr_read_w(s, &call->szLookupName, NDR_PTR_FULL);
3527                 if (status != SCARD_S_SUCCESS)
3528                         return status;
3529         }
3530
3531         status = smartcard_unpack_redir_scard_context_ref(smartcard, s, &call->Common.handles.hContext);
3532         if (status != SCARD_S_SUCCESS)
3533                 return status;
3534
3535         if (contextNdrPtr)
3536         {
3537                 status = smartcard_ndr_read_u(s, &call->Common.CardIdentifier);
3538                 if (status != SCARD_S_SUCCESS)
3539                         return status;
3540         }
3541         smartcard_trace_read_cache_w_call(smartcard, call);
3542         return SCARD_S_SUCCESS;
3543 }
3544
3545 LONG smartcard_unpack_write_cache_a_call(SMARTCARD_DEVICE* smartcard, wStream* s,
3546                                          WriteCacheA_Call* call)
3547 {
3548         LONG status;
3549         UINT32 mszNdrPtr;
3550         UINT32 contextNdrPtr;
3551         UINT32 pbDataNdrPtr;
3552         UINT32 index = 0;
3553
3554         if (!smartcard_ndr_pointer_read(s, &index, &mszNdrPtr))
3555                 return ERROR_INVALID_DATA;
3556
3557         status = smartcard_unpack_redir_scard_context(smartcard, s, &(call->Common.handles.hContext),
3558                                                       &index);
3559         if (status != SCARD_S_SUCCESS)
3560                 return status;
3561
3562         if (!smartcard_ndr_pointer_read(s, &index, &contextNdrPtr))
3563                 return ERROR_INVALID_DATA;
3564
3565         if (Stream_GetRemainingLength(s) < 8)
3566                 return STATUS_BUFFER_TOO_SMALL;
3567
3568         Stream_Read_UINT32(s, call->Common.FreshnessCounter);
3569         Stream_Read_UINT32(s, call->Common.cbDataLen);
3570
3571         if (!smartcard_ndr_pointer_read(s, &index, &pbDataNdrPtr))
3572                 return ERROR_INVALID_DATA;
3573
3574         call->szLookupName = NULL;
3575         if (mszNdrPtr)
3576         {
3577                 status = smartcard_ndr_read_a(s, &call->szLookupName, NDR_PTR_FULL);
3578                 if (status != SCARD_S_SUCCESS)
3579                         return status;
3580         }
3581
3582         status = smartcard_unpack_redir_scard_context_ref(smartcard, s, &call->Common.handles.hContext);
3583         if (status != SCARD_S_SUCCESS)
3584                 return status;
3585
3586         call->Common.CardIdentifier = NULL;
3587         if (contextNdrPtr)
3588         {
3589                 status = smartcard_ndr_read_u(s, &call->Common.CardIdentifier);
3590                 if (status != SCARD_S_SUCCESS)
3591                         return status;
3592         }
3593
3594         call->Common.pbData = NULL;
3595         if (pbDataNdrPtr)
3596         {
3597                 status =
3598                     smartcard_ndr_read(s, &call->Common.pbData, call->Common.cbDataLen, 1, NDR_PTR_SIMPLE);
3599                 if (status != SCARD_S_SUCCESS)
3600                         return status;
3601         }
3602         smartcard_trace_write_cache_a_call(smartcard, call);
3603         return SCARD_S_SUCCESS;
3604 }
3605
3606 LONG smartcard_unpack_write_cache_w_call(SMARTCARD_DEVICE* smartcard, wStream* s,
3607                                          WriteCacheW_Call* call)
3608 {
3609         LONG status;
3610         UINT32 mszNdrPtr;
3611         UINT32 contextNdrPtr;
3612         UINT32 pbDataNdrPtr;
3613         UINT32 index = 0;
3614
3615         if (!smartcard_ndr_pointer_read(s, &index, &mszNdrPtr))
3616                 return ERROR_INVALID_DATA;
3617
3618         status = smartcard_unpack_redir_scard_context(smartcard, s, &(call->Common.handles.hContext),
3619                                                       &index);
3620         if (status != SCARD_S_SUCCESS)
3621                 return status;
3622
3623         if (!smartcard_ndr_pointer_read(s, &index, &contextNdrPtr))
3624                 return ERROR_INVALID_DATA;
3625
3626         if (Stream_GetRemainingLength(s) < 8)
3627                 return STATUS_BUFFER_TOO_SMALL;
3628         Stream_Read_UINT32(s, call->Common.FreshnessCounter);
3629         Stream_Read_UINT32(s, call->Common.cbDataLen);
3630
3631         if (!smartcard_ndr_pointer_read(s, &index, &pbDataNdrPtr))
3632                 return ERROR_INVALID_DATA;
3633
3634         call->szLookupName = NULL;
3635         if (mszNdrPtr)
3636         {
3637                 status = smartcard_ndr_read_w(s, &call->szLookupName, NDR_PTR_FULL);
3638                 if (status != SCARD_S_SUCCESS)
3639                         return status;
3640         }
3641
3642         status = smartcard_unpack_redir_scard_context_ref(smartcard, s, &call->Common.handles.hContext);
3643         if (status != SCARD_S_SUCCESS)
3644                 return status;
3645
3646         call->Common.CardIdentifier = NULL;
3647         if (contextNdrPtr)
3648         {
3649                 status = smartcard_ndr_read_u(s, &call->Common.CardIdentifier);
3650                 if (status != SCARD_S_SUCCESS)
3651                         return status;
3652         }
3653
3654         call->Common.pbData = NULL;
3655         if (pbDataNdrPtr)
3656         {
3657                 status =
3658                     smartcard_ndr_read(s, &call->Common.pbData, call->Common.cbDataLen, 1, NDR_PTR_SIMPLE);
3659                 if (status != SCARD_S_SUCCESS)
3660                         return status;
3661         }
3662         smartcard_trace_write_cache_w_call(smartcard, call);
3663         return status;
3664 }
3665
3666 LONG smartcard_unpack_get_transmit_count_call(SMARTCARD_DEVICE* smartcard, wStream* s,
3667                                               GetTransmitCount_Call* call)
3668 {
3669         LONG status;
3670         UINT32 index = 0;
3671
3672         status = smartcard_unpack_redir_scard_context(smartcard, s, &(call->handles.hContext), &index);
3673         if (status != SCARD_S_SUCCESS)
3674                 return status;
3675
3676         status = smartcard_unpack_redir_scard_handle(smartcard, s, &(call->handles.hCard), &index);
3677         if (status != SCARD_S_SUCCESS)
3678                 return status;
3679
3680         if ((status =
3681                  smartcard_unpack_redir_scard_context_ref(smartcard, s, &(call->handles.hContext))))
3682         {
3683                 WLog_ERR(TAG, "smartcard_unpack_redir_scard_context_ref failed with error %" PRId32 "",
3684                          status);
3685                 return status;
3686         }
3687
3688         if ((status = smartcard_unpack_redir_scard_handle_ref(smartcard, s, &(call->handles.hCard))))
3689                 WLog_ERR(TAG, "smartcard_unpack_redir_scard_handle_ref failed with error %" PRId32 "",
3690                          status);
3691
3692         smartcard_trace_get_transmit_count_call(smartcard, call);
3693         return status;
3694 }
3695
3696 LONG smartcard_unpack_get_reader_icon_call(SMARTCARD_DEVICE* smartcard, wStream* s,
3697                                            GetReaderIcon_Call* call)
3698 {
3699         return smartcard_unpack_common_context_and_string_w(smartcard, s, &call->handles.hContext,
3700                                                             &call->szReaderName);
3701 }
3702
3703 LONG smartcard_unpack_context_and_string_a_call(SMARTCARD_DEVICE* smartcard, wStream* s,
3704                                                 ContextAndStringA_Call* call)
3705 {
3706         return smartcard_unpack_common_context_and_string_a(smartcard, s, &call->handles.hContext,
3707                                                             &call->sz);
3708 }
3709
3710 LONG smartcard_unpack_context_and_string_w_call(SMARTCARD_DEVICE* smartcard, wStream* s,
3711                                                 ContextAndStringW_Call* call)
3712 {
3713         return smartcard_unpack_common_context_and_string_w(smartcard, s, &call->handles.hContext,
3714                                                             &call->sz);
3715 }
3716
3717 LONG smartcard_unpack_get_device_type_id_call(SMARTCARD_DEVICE* smartcard, wStream* s,
3718                                               GetDeviceTypeId_Call* call)
3719 {
3720         return smartcard_unpack_common_context_and_string_w(smartcard, s, &call->handles.hContext,
3721                                                             &call->szReaderName);
3722 }
3723
3724 LONG smartcard_pack_device_type_id_return(SMARTCARD_DEVICE* smartcard, wStream* s,
3725                                           const GetDeviceTypeId_Return* ret)
3726 {
3727         smartcard_trace_device_type_id_return(smartcard, ret);
3728
3729         if (!Stream_EnsureRemainingCapacity(s, 4))
3730         {
3731                 WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!");
3732                 return SCARD_F_INTERNAL_ERROR;
3733         }
3734
3735         Stream_Write_UINT32(s, ret->dwDeviceId); /* cBytes (4 bytes) */
3736
3737         return ret->ReturnCode;
3738 }
3739
3740 LONG smartcard_pack_locate_cards_return(SMARTCARD_DEVICE* smartcard, wStream* s,
3741                                         const LocateCards_Return* ret)
3742 {
3743         LONG status;
3744         DWORD cbDataLen = ret->cReaders;
3745         DWORD index = 0;
3746
3747         smartcard_trace_locate_cards_return(smartcard, ret);
3748         if (ret->ReturnCode != SCARD_S_SUCCESS)
3749                 cbDataLen = 0;
3750         if (cbDataLen == SCARD_AUTOALLOCATE)
3751                 cbDataLen = 0;
3752
3753         if (!Stream_EnsureRemainingCapacity(s, 4))
3754         {
3755                 WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!");
3756                 return SCARD_F_INTERNAL_ERROR;
3757         }
3758
3759         Stream_Write_UINT32(s, cbDataLen); /* cBytes (4 cbDataLen) */
3760         if (!smartcard_ndr_pointer_write(s, &index, cbDataLen))
3761                 return SCARD_E_NO_MEMORY;
3762
3763         status = smartcard_ndr_write_state(s, ret->rgReaderStates, cbDataLen, NDR_PTR_SIMPLE);
3764         if (status != SCARD_S_SUCCESS)
3765                 return status;
3766         return ret->ReturnCode;
3767 }
3768
3769 LONG smartcard_pack_get_reader_icon_return(SMARTCARD_DEVICE* smartcard, wStream* s,
3770                                            const GetReaderIcon_Return* ret)
3771 {
3772         LONG status;
3773         DWORD index = 0;
3774         DWORD cbDataLen = ret->cbDataLen;
3775         smartcard_trace_get_reader_icon_return(smartcard, ret);
3776         if (ret->ReturnCode != SCARD_S_SUCCESS)
3777                 cbDataLen = 0;
3778         if (cbDataLen == SCARD_AUTOALLOCATE)
3779                 cbDataLen = 0;
3780
3781         if (!Stream_EnsureRemainingCapacity(s, 4))
3782         {
3783                 WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!");
3784                 return SCARD_F_INTERNAL_ERROR;
3785         }
3786
3787         Stream_Write_UINT32(s, cbDataLen); /* cBytes (4 cbDataLen) */
3788         if (!smartcard_ndr_pointer_write(s, &index, cbDataLen))
3789                 return SCARD_E_NO_MEMORY;
3790
3791         status = smartcard_ndr_write(s, ret->pbData, cbDataLen, 1, NDR_PTR_SIMPLE);
3792         if (status != SCARD_S_SUCCESS)
3793                 return status;
3794         return ret->ReturnCode;
3795 }
3796
3797 LONG smartcard_pack_get_transmit_count_return(SMARTCARD_DEVICE* smartcard, wStream* s,
3798                                               const GetTransmitCount_Return* ret)
3799 {
3800         smartcard_trace_get_transmit_count_return(smartcard, ret);
3801
3802         if (!Stream_EnsureRemainingCapacity(s, 4))
3803         {
3804                 WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!");
3805                 return SCARD_F_INTERNAL_ERROR;
3806         }
3807
3808         Stream_Write_UINT32(s, ret->cTransmitCount); /* cBytes (4 cbDataLen) */
3809
3810         return ret->ReturnCode;
3811 }
3812
3813 LONG smartcard_pack_read_cache_return(SMARTCARD_DEVICE* smartcard, wStream* s,
3814                                       const ReadCache_Return* ret)
3815 {
3816         LONG status;
3817         DWORD index = 0;
3818         DWORD cbDataLen = ret->cbDataLen;
3819         smartcard_trace_read_cache_return(smartcard, ret);
3820         if (ret->ReturnCode != SCARD_S_SUCCESS)
3821                 cbDataLen = 0;
3822
3823         if (cbDataLen == SCARD_AUTOALLOCATE)
3824                 cbDataLen = 0;
3825
3826         if (!Stream_EnsureRemainingCapacity(s, 4))
3827         {
3828                 WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!");
3829                 return SCARD_F_INTERNAL_ERROR;
3830         }
3831
3832         Stream_Write_UINT32(s, cbDataLen); /* cBytes (4 cbDataLen) */
3833         if (!smartcard_ndr_pointer_write(s, &index, cbDataLen))
3834                 return SCARD_E_NO_MEMORY;
3835
3836         status = smartcard_ndr_write(s, ret->pbData, cbDataLen, 1, NDR_PTR_SIMPLE);
3837         if (status != SCARD_S_SUCCESS)
3838                 return status;
3839         return ret->ReturnCode;
3840 }