Fixed smartcard_unpack_reader_state, allow empty names
[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 = SCARD_E_NO_MEMORY;
2377         LPSCARD_READERSTATEA rgReaderStates;
2378         BOOL* states;
2379
2380         if (Stream_GetRemainingLength(s) < 4)
2381                 return status;
2382
2383         Stream_Read_UINT32(s, len);
2384         if (len != cReaders)
2385         {
2386                 WLog_ERR(TAG, "Count mismatch when reading LPSCARD_READERSTATEA");
2387                 return status;
2388         }
2389         rgReaderStates = (LPSCARD_READERSTATEA)calloc(cReaders, sizeof(SCARD_READERSTATEA));
2390         states = calloc(cReaders, sizeof(BOOL));
2391         if (!rgReaderStates || !states)
2392                 goto fail;
2393         status = ERROR_INVALID_DATA;
2394
2395         for (index = 0; index < cReaders; index++)
2396         {
2397                 UINT32 ptr = UINT32_MAX;
2398                 LPSCARD_READERSTATEA readerState = &rgReaderStates[index];
2399
2400                 if (Stream_GetRemainingLength(s) < 52)
2401                 {
2402                         WLog_WARN(TAG, "GetStatusChangeA_Call is too short: %" PRIuz "",
2403                                   Stream_GetRemainingLength(s));
2404                         goto fail;
2405                 }
2406
2407                 if (!smartcard_ndr_pointer_read(s, ptrIndex, &ptr))
2408                 {
2409                         if (ptr != 0)
2410                                 goto fail;
2411                 }
2412                 /* Ignore NULL length strings */
2413                 states[index] = ptr != 0;
2414                 Stream_Read_UINT32(s, readerState->dwCurrentState); /* dwCurrentState (4 bytes) */
2415                 Stream_Read_UINT32(s, readerState->dwEventState);   /* dwEventState (4 bytes) */
2416                 Stream_Read_UINT32(s, readerState->cbAtr);          /* cbAtr (4 bytes) */
2417                 Stream_Read(s, readerState->rgbAtr, 36);            /* rgbAtr [0..36] (36 bytes) */
2418         }
2419
2420         for (index = 0; index < cReaders; index++)
2421         {
2422                 LPSCARD_READERSTATEA readerState = &rgReaderStates[index];
2423
2424                 /* Ignore empty strings */
2425                 if (!states[index])
2426                         continue;
2427                 status = smartcard_ndr_read_a(s, &readerState->szReader, NDR_PTR_FULL);
2428                 if (status != SCARD_S_SUCCESS)
2429                         goto fail;
2430         }
2431
2432         *ppcReaders = rgReaderStates;
2433         free(states);
2434         return SCARD_S_SUCCESS;
2435 fail:
2436         if (rgReaderStates)
2437         {
2438                 for (index = 0; index < cReaders; index++)
2439                 {
2440                         LPSCARD_READERSTATEA readerState = &rgReaderStates[index];
2441                         free(readerState->szReader);
2442                 }
2443         }
2444         free(rgReaderStates);
2445         free(states);
2446         return status;
2447 }
2448
2449 static LONG smartcard_unpack_reader_state_w(wStream* s, LPSCARD_READERSTATEW* ppcReaders,
2450                                             UINT32 cReaders, UINT32* ptrIndex)
2451 {
2452         UINT32 index, len;
2453         LONG status = SCARD_E_NO_MEMORY;
2454         LPSCARD_READERSTATEW rgReaderStates;
2455         BOOL* states;
2456
2457         if (Stream_GetRemainingLength(s) < 4)
2458                 return status;
2459
2460         Stream_Read_UINT32(s, len);
2461         if (len != cReaders)
2462         {
2463                 WLog_ERR(TAG, "Count mismatch when reading LPSCARD_READERSTATEW");
2464                 return status;
2465         }
2466
2467         rgReaderStates = (LPSCARD_READERSTATEW)calloc(cReaders, sizeof(SCARD_READERSTATEW));
2468         states = calloc(cReaders, sizeof(BOOL));
2469
2470         if (!rgReaderStates || !states)
2471                 goto fail;
2472
2473         status = ERROR_INVALID_DATA;
2474         for (index = 0; index < cReaders; index++)
2475         {
2476                 UINT32 ptr = UINT32_MAX;
2477                 LPSCARD_READERSTATEW readerState = &rgReaderStates[index];
2478
2479                 if (Stream_GetRemainingLength(s) < 52)
2480                 {
2481                         WLog_WARN(TAG, "GetStatusChangeA_Call is too short: %" PRIuz "",
2482                                   Stream_GetRemainingLength(s));
2483                         goto fail;
2484                 }
2485
2486                 if (!smartcard_ndr_pointer_read(s, ptrIndex, &ptr))
2487                 {
2488                         if (ptr != 0)
2489                                 goto fail;
2490                 }
2491                 /* Ignore NULL length strings */
2492                 states[index] = ptr != 0;
2493                 Stream_Read_UINT32(s, readerState->dwCurrentState); /* dwCurrentState (4 bytes) */
2494                 Stream_Read_UINT32(s, readerState->dwEventState);   /* dwEventState (4 bytes) */
2495                 Stream_Read_UINT32(s, readerState->cbAtr);          /* cbAtr (4 bytes) */
2496                 Stream_Read(s, readerState->rgbAtr, 36);            /* rgbAtr [0..36] (36 bytes) */
2497         }
2498
2499         for (index = 0; index < cReaders; index++)
2500         {
2501                 LPSCARD_READERSTATEW readerState = &rgReaderStates[index];
2502
2503                 /* Skip NULL pointers */
2504                 if (!states[index])
2505                         continue;
2506
2507                 status = smartcard_ndr_read_w(s, &readerState->szReader, NDR_PTR_FULL);
2508                 if (status != SCARD_S_SUCCESS)
2509                         goto fail;
2510         }
2511
2512         *ppcReaders = rgReaderStates;
2513         free(states);
2514         return SCARD_S_SUCCESS;
2515 fail:
2516         if (rgReaderStates)
2517         {
2518                 for (index = 0; index < cReaders; index++)
2519                 {
2520                         LPSCARD_READERSTATEW readerState = &rgReaderStates[index];
2521                         free(readerState->szReader);
2522                 }
2523         }
2524         free(rgReaderStates);
2525         free(states);
2526         return status;
2527 }
2528
2529 /******************************************************************************/
2530 /************************************* End Trace Functions ********************/
2531 /******************************************************************************/
2532
2533 LONG smartcard_unpack_get_status_change_a_call(SMARTCARD_DEVICE* smartcard, wStream* s,
2534                                                GetStatusChangeA_Call* call)
2535 {
2536         LONG status;
2537         UINT32 ndrPtr;
2538         UINT32 index = 0;
2539         call->rgReaderStates = NULL;
2540
2541         status = smartcard_unpack_redir_scard_context(smartcard, s, &(call->handles.hContext), &index);
2542         if (status != SCARD_S_SUCCESS)
2543                 return status;
2544
2545         if (Stream_GetRemainingLength(s) < 12)
2546         {
2547                 WLog_WARN(TAG, "GetStatusChangeA_Call is too short: %" PRIuz "",
2548                           Stream_GetRemainingLength(s));
2549                 return STATUS_BUFFER_TOO_SMALL;
2550         }
2551
2552         Stream_Read_UINT32(s, call->dwTimeOut); /* dwTimeOut (4 bytes) */
2553         Stream_Read_UINT32(s, call->cReaders);  /* cReaders (4 bytes) */
2554         if (!smartcard_ndr_pointer_read(s, &index, &ndrPtr))
2555                 return ERROR_INVALID_DATA;
2556
2557         if ((status =
2558                  smartcard_unpack_redir_scard_context_ref(smartcard, s, &(call->handles.hContext))))
2559                 return status;
2560
2561         if (ndrPtr)
2562         {
2563                 status = smartcard_unpack_reader_state_a(s, &call->rgReaderStates, call->cReaders, &index);
2564                 if (status != SCARD_S_SUCCESS)
2565                         return status;
2566         }
2567
2568         smartcard_trace_get_status_change_a_call(smartcard, call);
2569         return SCARD_S_SUCCESS;
2570 }
2571
2572 LONG smartcard_unpack_get_status_change_w_call(SMARTCARD_DEVICE* smartcard, wStream* s,
2573                                                GetStatusChangeW_Call* call)
2574 {
2575         UINT32 ndrPtr;
2576         LONG status;
2577         UINT32 index = 0;
2578
2579         call->rgReaderStates = NULL;
2580
2581         status = smartcard_unpack_redir_scard_context(smartcard, s, &(call->handles.hContext), &index);
2582         if (status != SCARD_S_SUCCESS)
2583                 return status;
2584
2585         if (Stream_GetRemainingLength(s) < 12)
2586         {
2587                 WLog_WARN(TAG, "GetStatusChangeW_Call is too short: %" PRIuz "",
2588                           Stream_GetRemainingLength(s));
2589                 return STATUS_BUFFER_TOO_SMALL;
2590         }
2591
2592         Stream_Read_UINT32(s, call->dwTimeOut); /* dwTimeOut (4 bytes) */
2593         Stream_Read_UINT32(s, call->cReaders);  /* cReaders (4 bytes) */
2594         if (!smartcard_ndr_pointer_read(s, &index, &ndrPtr))
2595                 return ERROR_INVALID_DATA;
2596
2597         if ((status =
2598                  smartcard_unpack_redir_scard_context_ref(smartcard, s, &(call->handles.hContext))))
2599                 return status;
2600
2601         if (ndrPtr)
2602         {
2603                 status = smartcard_unpack_reader_state_w(s, &call->rgReaderStates, call->cReaders, &index);
2604                 if (status != SCARD_S_SUCCESS)
2605                         return status;
2606         }
2607
2608         smartcard_trace_get_status_change_w_call(smartcard, call);
2609         return SCARD_S_SUCCESS;
2610 }
2611
2612 LONG smartcard_pack_get_status_change_return(SMARTCARD_DEVICE* smartcard, wStream* s,
2613                                              const GetStatusChange_Return* ret, BOOL unicode)
2614 {
2615         LONG status;
2616         DWORD cReaders = ret->cReaders;
2617         UINT32 index = 0;
2618
2619         smartcard_trace_get_status_change_return(smartcard, ret, unicode);
2620         if (ret->ReturnCode != SCARD_S_SUCCESS)
2621                 cReaders = 0;
2622         if (cReaders == SCARD_AUTOALLOCATE)
2623                 cReaders = 0;
2624
2625         if (!Stream_EnsureRemainingCapacity(s, 4))
2626                 return SCARD_E_NO_MEMORY;
2627
2628         Stream_Write_UINT32(s, cReaders); /* cReaders (4 bytes) */
2629         if (!smartcard_ndr_pointer_write(s, &index, cReaders))
2630                 return SCARD_E_NO_MEMORY;
2631         status = smartcard_ndr_write_state(s, ret->rgReaderStates, cReaders, NDR_PTR_SIMPLE);
2632         if (status != SCARD_S_SUCCESS)
2633                 return status;
2634         return ret->ReturnCode;
2635 }
2636
2637 LONG smartcard_unpack_state_call(SMARTCARD_DEVICE* smartcard, wStream* s, State_Call* call)
2638 {
2639         LONG status;
2640         UINT32 index = 0;
2641
2642         status = smartcard_unpack_redir_scard_context(smartcard, s, &(call->handles.hContext), &index);
2643         if (status != SCARD_S_SUCCESS)
2644                 return status;
2645
2646         status = smartcard_unpack_redir_scard_handle(smartcard, s, &(call->handles.hCard), &index);
2647         if (status != SCARD_S_SUCCESS)
2648                 return status;
2649
2650         if (Stream_GetRemainingLength(s) < 8)
2651         {
2652                 WLog_WARN(TAG, "State_Call is too short: %" PRIuz "", Stream_GetRemainingLength(s));
2653                 return STATUS_BUFFER_TOO_SMALL;
2654         }
2655
2656         Stream_Read_INT32(s, call->fpbAtrIsNULL); /* fpbAtrIsNULL (4 bytes) */
2657         Stream_Read_UINT32(s, call->cbAtrLen);    /* cbAtrLen (4 bytes) */
2658
2659         if ((status =
2660                  smartcard_unpack_redir_scard_context_ref(smartcard, s, &(call->handles.hContext))))
2661                 return status;
2662
2663         if ((status = smartcard_unpack_redir_scard_handle_ref(smartcard, s, &(call->handles.hCard))))
2664                 return status;
2665
2666         return status;
2667 }
2668
2669 LONG smartcard_pack_state_return(SMARTCARD_DEVICE* smartcard, wStream* s, const State_Return* ret)
2670 {
2671         LONG status;
2672         DWORD cbAtrLen = ret->cbAtrLen;
2673         DWORD index = 0;
2674
2675         smartcard_trace_state_return(smartcard, ret);
2676         if (ret->ReturnCode != SCARD_S_SUCCESS)
2677                 cbAtrLen = 0;
2678         if (cbAtrLen == SCARD_AUTOALLOCATE)
2679                 cbAtrLen = 0;
2680
2681         Stream_Write_UINT32(s, ret->dwState);    /* dwState (4 bytes) */
2682         Stream_Write_UINT32(s, ret->dwProtocol); /* dwProtocol (4 bytes) */
2683         Stream_Write_UINT32(s, cbAtrLen);        /* cbAtrLen (4 bytes) */
2684         if (!smartcard_ndr_pointer_write(s, &index, cbAtrLen))
2685                 return SCARD_E_NO_MEMORY;
2686         status = smartcard_ndr_write(s, ret->rgAtr, cbAtrLen, 1, NDR_PTR_SIMPLE);
2687         if (status != SCARD_S_SUCCESS)
2688                 return status;
2689         return ret->ReturnCode;
2690 }
2691
2692 LONG smartcard_unpack_status_call(SMARTCARD_DEVICE* smartcard, wStream* s, Status_Call* call,
2693                                   BOOL unicode)
2694 {
2695         LONG status;
2696         UINT32 index = 0;
2697         status = smartcard_unpack_redir_scard_context(smartcard, s, &(call->handles.hContext), &index);
2698         if (status != SCARD_S_SUCCESS)
2699                 return status;
2700
2701         status = smartcard_unpack_redir_scard_handle(smartcard, s, &(call->handles.hCard), &index);
2702         if (status != SCARD_S_SUCCESS)
2703                 return status;
2704
2705         if (Stream_GetRemainingLength(s) < 12)
2706         {
2707                 WLog_WARN(TAG, "Status_Call is too short: %" PRIuz "", Stream_GetRemainingLength(s));
2708                 return STATUS_BUFFER_TOO_SMALL;
2709         }
2710
2711         Stream_Read_INT32(s, call->fmszReaderNamesIsNULL); /* fmszReaderNamesIsNULL (4 bytes) */
2712         Stream_Read_UINT32(s, call->cchReaderLen);         /* cchReaderLen (4 bytes) */
2713         Stream_Read_UINT32(s, call->cbAtrLen);             /* cbAtrLen (4 bytes) */
2714
2715         if ((status =
2716                  smartcard_unpack_redir_scard_context_ref(smartcard, s, &(call->handles.hContext))))
2717                 return status;
2718
2719         if ((status = smartcard_unpack_redir_scard_handle_ref(smartcard, s, &(call->handles.hCard))))
2720                 return status;
2721
2722         smartcard_trace_status_call(smartcard, call, unicode);
2723         return status;
2724 }
2725
2726 LONG smartcard_pack_status_return(SMARTCARD_DEVICE* smartcard, wStream* s, const Status_Return* ret,
2727                                   BOOL unicode)
2728 {
2729         LONG status;
2730         DWORD index = 0;
2731         DWORD cBytes = ret->cBytes;
2732
2733         smartcard_trace_status_return(smartcard, ret, unicode);
2734         if (ret->ReturnCode != SCARD_S_SUCCESS)
2735                 cBytes = 0;
2736         if (cBytes == SCARD_AUTOALLOCATE)
2737                 cBytes = 0;
2738
2739         if (!Stream_EnsureRemainingCapacity(s, 4))
2740                 return SCARD_F_INTERNAL_ERROR;
2741
2742         Stream_Write_UINT32(s, cBytes); /* cBytes (4 bytes) */
2743         if (!smartcard_ndr_pointer_write(s, &index, cBytes))
2744                 return SCARD_E_NO_MEMORY;
2745
2746         if (!Stream_EnsureRemainingCapacity(s, 44))
2747                 return SCARD_F_INTERNAL_ERROR;
2748
2749         Stream_Write_UINT32(s, ret->dwState);            /* dwState (4 bytes) */
2750         Stream_Write_UINT32(s, ret->dwProtocol);         /* dwProtocol (4 bytes) */
2751         Stream_Write(s, ret->pbAtr, sizeof(ret->pbAtr)); /* pbAtr (32 bytes) */
2752         Stream_Write_UINT32(s, ret->cbAtrLen);           /* cbAtrLen (4 bytes) */
2753         status = smartcard_ndr_write(s, ret->mszReaderNames, cBytes, 1, NDR_PTR_SIMPLE);
2754         if (status != SCARD_S_SUCCESS)
2755                 return status;
2756         return ret->ReturnCode;
2757 }
2758
2759 LONG smartcard_unpack_get_attrib_call(SMARTCARD_DEVICE* smartcard, wStream* s, GetAttrib_Call* call)
2760 {
2761         LONG status;
2762         UINT32 index = 0;
2763
2764         status = smartcard_unpack_redir_scard_context(smartcard, s, &(call->handles.hContext), &index);
2765         if (status != SCARD_S_SUCCESS)
2766                 return status;
2767
2768         status = smartcard_unpack_redir_scard_handle(smartcard, s, &(call->handles.hCard), &index);
2769         if (status != SCARD_S_SUCCESS)
2770                 return status;
2771
2772         if (Stream_GetRemainingLength(s) < 12)
2773         {
2774                 WLog_WARN(TAG, "GetAttrib_Call is too short: %" PRIuz "", Stream_GetRemainingLength(s));
2775                 return STATUS_BUFFER_TOO_SMALL;
2776         }
2777
2778         Stream_Read_UINT32(s, call->dwAttrId);     /* dwAttrId (4 bytes) */
2779         Stream_Read_INT32(s, call->fpbAttrIsNULL); /* fpbAttrIsNULL (4 bytes) */
2780         Stream_Read_UINT32(s, call->cbAttrLen);    /* cbAttrLen (4 bytes) */
2781
2782         if ((status =
2783                  smartcard_unpack_redir_scard_context_ref(smartcard, s, &(call->handles.hContext))))
2784                 return status;
2785
2786         if ((status = smartcard_unpack_redir_scard_handle_ref(smartcard, s, &(call->handles.hCard))))
2787                 return status;
2788
2789         smartcard_trace_get_attrib_call(smartcard, call);
2790         return status;
2791 }
2792
2793 LONG smartcard_pack_get_attrib_return(SMARTCARD_DEVICE* smartcard, wStream* s,
2794                                       const GetAttrib_Return* ret, DWORD dwAttrId)
2795 {
2796         LONG status;
2797         DWORD cbAttrLen;
2798         DWORD index = 0;
2799         smartcard_trace_get_attrib_return(smartcard, ret, dwAttrId);
2800
2801         if (!Stream_EnsureRemainingCapacity(s, 4))
2802                 return SCARD_F_INTERNAL_ERROR;
2803
2804         cbAttrLen = ret->cbAttrLen;
2805         if (cbAttrLen == SCARD_AUTOALLOCATE)
2806                 cbAttrLen = 0;
2807         Stream_Write_UINT32(s, cbAttrLen); /* cbAttrLen (4 bytes) */
2808         if (!smartcard_ndr_pointer_write(s, &index, cbAttrLen))
2809                 return SCARD_E_NO_MEMORY;
2810
2811         status = smartcard_ndr_write(s, ret->pbAttr, cbAttrLen, 1, NDR_PTR_SIMPLE);
2812         if (status != SCARD_S_SUCCESS)
2813                 return status;
2814         return ret->ReturnCode;
2815 }
2816
2817 LONG smartcard_unpack_control_call(SMARTCARD_DEVICE* smartcard, wStream* s, Control_Call* call)
2818 {
2819         LONG status;
2820         UINT32 index = 0;
2821         UINT32 pvInBufferNdrPtr;
2822
2823         call->pvInBuffer = NULL;
2824
2825         status = smartcard_unpack_redir_scard_context(smartcard, s, &(call->handles.hContext), &index);
2826         if (status != SCARD_S_SUCCESS)
2827                 return status;
2828
2829         status = smartcard_unpack_redir_scard_handle(smartcard, s, &(call->handles.hCard), &index);
2830         if (status != SCARD_S_SUCCESS)
2831                 return status;
2832
2833         if (Stream_GetRemainingLength(s) < 20)
2834         {
2835                 WLog_WARN(TAG, "Control_Call is too short: %" PRIuz "", Stream_GetRemainingLength(s));
2836                 return STATUS_BUFFER_TOO_SMALL;
2837         }
2838
2839         Stream_Read_UINT32(s, call->dwControlCode);                    /* dwControlCode (4 bytes) */
2840         Stream_Read_UINT32(s, call->cbInBufferSize);                   /* cbInBufferSize (4 bytes) */
2841         if (!smartcard_ndr_pointer_read(s, &index, &pvInBufferNdrPtr)) /* pvInBufferNdrPtr (4 bytes) */
2842                 return ERROR_INVALID_DATA;
2843         Stream_Read_INT32(s, call->fpvOutBufferIsNULL); /* fpvOutBufferIsNULL (4 bytes) */
2844         Stream_Read_UINT32(s, call->cbOutBufferSize);   /* cbOutBufferSize (4 bytes) */
2845
2846         if ((status =
2847                  smartcard_unpack_redir_scard_context_ref(smartcard, s, &(call->handles.hContext))))
2848                 return status;
2849
2850         if ((status = smartcard_unpack_redir_scard_handle_ref(smartcard, s, &(call->handles.hCard))))
2851                 return status;
2852
2853         if (pvInBufferNdrPtr)
2854         {
2855                 status = smartcard_ndr_read(s, &call->pvInBuffer, call->cbInBufferSize, 1, NDR_PTR_SIMPLE);
2856                 if (status != SCARD_S_SUCCESS)
2857                         return status;
2858         }
2859
2860         smartcard_trace_control_call(smartcard, call);
2861         return SCARD_S_SUCCESS;
2862 }
2863
2864 LONG smartcard_pack_control_return(SMARTCARD_DEVICE* smartcard, wStream* s,
2865                                    const Control_Return* ret)
2866 {
2867         LONG status;
2868         DWORD cbDataLen = ret->cbOutBufferSize;
2869         DWORD index = 0;
2870
2871         smartcard_trace_control_return(smartcard, ret);
2872         if (ret->ReturnCode != SCARD_S_SUCCESS)
2873                 cbDataLen = 0;
2874         if (cbDataLen == SCARD_AUTOALLOCATE)
2875                 cbDataLen = 0;
2876
2877         if (!Stream_EnsureRemainingCapacity(s, 4))
2878                 return SCARD_F_INTERNAL_ERROR;
2879
2880         Stream_Write_UINT32(s, cbDataLen); /* cbOutBufferSize (4 bytes) */
2881         if (!smartcard_ndr_pointer_write(s, &index, cbDataLen))
2882                 return SCARD_E_NO_MEMORY;
2883
2884         status = smartcard_ndr_write(s, ret->pvOutBuffer, cbDataLen, 1, NDR_PTR_SIMPLE);
2885         if (status != SCARD_S_SUCCESS)
2886                 return status;
2887         return ret->ReturnCode;
2888 }
2889
2890 LONG smartcard_unpack_transmit_call(SMARTCARD_DEVICE* smartcard, wStream* s, Transmit_Call* call)
2891 {
2892         LONG status;
2893         UINT32 length;
2894         BYTE* pbExtraBytes;
2895         UINT32 pbExtraBytesNdrPtr;
2896         UINT32 pbSendBufferNdrPtr;
2897         UINT32 pioRecvPciNdrPtr;
2898         SCardIO_Request ioSendPci;
2899         SCardIO_Request ioRecvPci;
2900         UINT32 index = 0;
2901         call->pioSendPci = NULL;
2902         call->pioRecvPci = NULL;
2903         call->pbSendBuffer = NULL;
2904
2905         status = smartcard_unpack_redir_scard_context(smartcard, s, &(call->handles.hContext), &index);
2906         if (status != SCARD_S_SUCCESS)
2907                 return status;
2908
2909         status = smartcard_unpack_redir_scard_handle(smartcard, s, &(call->handles.hCard), &index);
2910         if (status != SCARD_S_SUCCESS)
2911                 return status;
2912
2913         if (Stream_GetRemainingLength(s) < 32)
2914         {
2915                 WLog_WARN(TAG, "Transmit_Call is too short: Actual: %" PRIuz ", Expected: 32",
2916                           Stream_GetRemainingLength(s));
2917                 return STATUS_BUFFER_TOO_SMALL;
2918         }
2919
2920         Stream_Read_UINT32(s, ioSendPci.dwProtocol);   /* dwProtocol (4 bytes) */
2921         Stream_Read_UINT32(s, ioSendPci.cbExtraBytes); /* cbExtraBytes (4 bytes) */
2922         if (!smartcard_ndr_pointer_read(s, &index,
2923                                         &pbExtraBytesNdrPtr)) /* pbExtraBytesNdrPtr (4 bytes) */
2924                 return ERROR_INVALID_DATA;
2925
2926         Stream_Read_UINT32(s, call->cbSendLength); /* cbSendLength (4 bytes) */
2927         if (!smartcard_ndr_pointer_read(s, &index,
2928                                         &pbSendBufferNdrPtr)) /* pbSendBufferNdrPtr (4 bytes) */
2929                 return ERROR_INVALID_DATA;
2930
2931         if (!smartcard_ndr_pointer_read(s, &index, &pioRecvPciNdrPtr)) /* pioRecvPciNdrPtr (4 bytes) */
2932                 return ERROR_INVALID_DATA;
2933
2934         Stream_Read_INT32(s, call->fpbRecvBufferIsNULL); /* fpbRecvBufferIsNULL (4 bytes) */
2935         Stream_Read_UINT32(s, call->cbRecvLength);       /* cbRecvLength (4 bytes) */
2936
2937         if (ioSendPci.cbExtraBytes > 1024)
2938         {
2939                 WLog_WARN(TAG,
2940                           "Transmit_Call ioSendPci.cbExtraBytes is out of bounds: %" PRIu32 " (max: 1024)",
2941                           ioSendPci.cbExtraBytes);
2942                 return STATUS_INVALID_PARAMETER;
2943         }
2944
2945         if (call->cbSendLength > 66560)
2946         {
2947                 WLog_WARN(TAG, "Transmit_Call cbSendLength is out of bounds: %" PRIu32 " (max: 66560)",
2948                           ioSendPci.cbExtraBytes);
2949                 return STATUS_INVALID_PARAMETER;
2950         }
2951
2952         if ((status =
2953                  smartcard_unpack_redir_scard_context_ref(smartcard, s, &(call->handles.hContext))))
2954                 return status;
2955
2956         if ((status = smartcard_unpack_redir_scard_handle_ref(smartcard, s, &(call->handles.hCard))))
2957                 return status;
2958
2959         if (ioSendPci.cbExtraBytes && !pbExtraBytesNdrPtr)
2960         {
2961                 WLog_WARN(
2962                     TAG, "Transmit_Call ioSendPci.cbExtraBytes is non-zero but pbExtraBytesNdrPtr is null");
2963                 return STATUS_INVALID_PARAMETER;
2964         }
2965
2966         if (pbExtraBytesNdrPtr)
2967         {
2968                 // TODO: Use unified pointer reading
2969                 if (Stream_GetRemainingLength(s) < 4)
2970                 {
2971                         WLog_WARN(TAG, "Transmit_Call is too short: %" PRIuz " (ioSendPci.pbExtraBytes)",
2972                                   Stream_GetRemainingLength(s));
2973                         return STATUS_BUFFER_TOO_SMALL;
2974                 }
2975
2976                 Stream_Read_UINT32(s, length); /* Length (4 bytes) */
2977
2978                 if (Stream_GetRemainingLength(s) < ioSendPci.cbExtraBytes)
2979                 {
2980                         WLog_WARN(TAG,
2981                                   "Transmit_Call is too short: Actual: %" PRIuz ", Expected: %" PRIu32
2982                                   " (ioSendPci.cbExtraBytes)",
2983                                   Stream_GetRemainingLength(s), ioSendPci.cbExtraBytes);
2984                         return STATUS_BUFFER_TOO_SMALL;
2985                 }
2986
2987                 ioSendPci.pbExtraBytes = Stream_Pointer(s);
2988                 call->pioSendPci =
2989                     (LPSCARD_IO_REQUEST)malloc(sizeof(SCARD_IO_REQUEST) + ioSendPci.cbExtraBytes);
2990
2991                 if (!call->pioSendPci)
2992                 {
2993                         WLog_WARN(TAG, "Transmit_Call out of memory error (pioSendPci)");
2994                         return STATUS_NO_MEMORY;
2995                 }
2996
2997                 call->pioSendPci->dwProtocol = ioSendPci.dwProtocol;
2998                 call->pioSendPci->cbPciLength = (DWORD)(ioSendPci.cbExtraBytes + sizeof(SCARD_IO_REQUEST));
2999                 pbExtraBytes = &((BYTE*)call->pioSendPci)[sizeof(SCARD_IO_REQUEST)];
3000                 Stream_Read(s, pbExtraBytes, ioSendPci.cbExtraBytes);
3001                 smartcard_unpack_read_size_align(smartcard, s, ioSendPci.cbExtraBytes, 4);
3002         }
3003         else
3004         {
3005                 call->pioSendPci = (LPSCARD_IO_REQUEST)calloc(1, sizeof(SCARD_IO_REQUEST));
3006
3007                 if (!call->pioSendPci)
3008                 {
3009                         WLog_WARN(TAG, "Transmit_Call out of memory error (pioSendPci)");
3010                         return STATUS_NO_MEMORY;
3011                 }
3012
3013                 call->pioSendPci->dwProtocol = ioSendPci.dwProtocol;
3014                 call->pioSendPci->cbPciLength = sizeof(SCARD_IO_REQUEST);
3015         }
3016
3017         if (pbSendBufferNdrPtr)
3018         {
3019                 status = smartcard_ndr_read(s, &call->pbSendBuffer, call->cbSendLength, 1, NDR_PTR_SIMPLE);
3020                 if (status != SCARD_S_SUCCESS)
3021                         return status;
3022         }
3023
3024         if (pioRecvPciNdrPtr)
3025         {
3026                 if (Stream_GetRemainingLength(s) < 12)
3027                 {
3028                         WLog_WARN(TAG, "Transmit_Call is too short: Actual: %" PRIuz ", Expected: 12",
3029                                   Stream_GetRemainingLength(s));
3030                         return STATUS_BUFFER_TOO_SMALL;
3031                 }
3032
3033                 Stream_Read_UINT32(s, ioRecvPci.dwProtocol);   /* dwProtocol (4 bytes) */
3034                 Stream_Read_UINT32(s, ioRecvPci.cbExtraBytes); /* cbExtraBytes (4 bytes) */
3035                 if (!smartcard_ndr_pointer_read(s, &index,
3036                                                 &pbExtraBytesNdrPtr)) /* pbExtraBytesNdrPtr (4 bytes) */
3037                         return ERROR_INVALID_DATA;
3038
3039                 if (ioRecvPci.cbExtraBytes && !pbExtraBytesNdrPtr)
3040                 {
3041                         WLog_WARN(
3042                             TAG,
3043                             "Transmit_Call ioRecvPci.cbExtraBytes is non-zero but pbExtraBytesNdrPtr is null");
3044                         return STATUS_INVALID_PARAMETER;
3045                 }
3046
3047                 if (pbExtraBytesNdrPtr)
3048                 {
3049                         // TODO: Unify ndr pointer reading
3050                         if (Stream_GetRemainingLength(s) < 4)
3051                         {
3052                                 WLog_WARN(TAG, "Transmit_Call is too short: %" PRIuz " (ioRecvPci.pbExtraBytes)",
3053                                           Stream_GetRemainingLength(s));
3054                                 return STATUS_BUFFER_TOO_SMALL;
3055                         }
3056
3057                         Stream_Read_UINT32(s, length); /* Length (4 bytes) */
3058
3059                         if (ioRecvPci.cbExtraBytes > 1024)
3060                         {
3061                                 WLog_WARN(TAG,
3062                                           "Transmit_Call ioRecvPci.cbExtraBytes is out of bounds: %" PRIu32
3063                                           " (max: 1024)",
3064                                           ioRecvPci.cbExtraBytes);
3065                                 return STATUS_INVALID_PARAMETER;
3066                         }
3067
3068                         if (length != ioRecvPci.cbExtraBytes)
3069                         {
3070                                 WLog_WARN(TAG,
3071                                           "Transmit_Call unexpected length: Actual: %" PRIu32 ", Expected: %" PRIu32
3072                                           " (ioRecvPci.cbExtraBytes)",
3073                                           length, ioRecvPci.cbExtraBytes);
3074                                 return STATUS_INVALID_PARAMETER;
3075                         }
3076
3077                         if (Stream_GetRemainingLength(s) < ioRecvPci.cbExtraBytes)
3078                         {
3079                                 WLog_WARN(TAG,
3080                                           "Transmit_Call is too short: Actual: %" PRIuz ", Expected: %" PRIu32
3081                                           " (ioRecvPci.cbExtraBytes)",
3082                                           Stream_GetRemainingLength(s), ioRecvPci.cbExtraBytes);
3083                                 return STATUS_BUFFER_TOO_SMALL;
3084                         }
3085
3086                         ioRecvPci.pbExtraBytes = Stream_Pointer(s);
3087                         call->pioRecvPci =
3088                             (LPSCARD_IO_REQUEST)malloc(sizeof(SCARD_IO_REQUEST) + ioRecvPci.cbExtraBytes);
3089
3090                         if (!call->pioRecvPci)
3091                         {
3092                                 WLog_WARN(TAG, "Transmit_Call out of memory error (pioRecvPci)");
3093                                 return STATUS_NO_MEMORY;
3094                         }
3095
3096                         call->pioRecvPci->dwProtocol = ioRecvPci.dwProtocol;
3097                         call->pioRecvPci->cbPciLength =
3098                             (DWORD)(ioRecvPci.cbExtraBytes + sizeof(SCARD_IO_REQUEST));
3099                         pbExtraBytes = &((BYTE*)call->pioRecvPci)[sizeof(SCARD_IO_REQUEST)];
3100                         Stream_Read(s, pbExtraBytes, ioRecvPci.cbExtraBytes);
3101                         smartcard_unpack_read_size_align(smartcard, s, ioRecvPci.cbExtraBytes, 4);
3102                 }
3103                 else
3104                 {
3105                         call->pioRecvPci = (LPSCARD_IO_REQUEST)calloc(1, sizeof(SCARD_IO_REQUEST));
3106
3107                         if (!call->pioRecvPci)
3108                         {
3109                                 WLog_WARN(TAG, "Transmit_Call out of memory error (pioRecvPci)");
3110                                 return STATUS_NO_MEMORY;
3111                         }
3112
3113                         call->pioRecvPci->dwProtocol = ioRecvPci.dwProtocol;
3114                         call->pioRecvPci->cbPciLength = sizeof(SCARD_IO_REQUEST);
3115                 }
3116         }
3117
3118         smartcard_trace_transmit_call(smartcard, call);
3119         return SCARD_S_SUCCESS;
3120 }
3121
3122 LONG smartcard_pack_transmit_return(SMARTCARD_DEVICE* smartcard, wStream* s,
3123                                     const Transmit_Return* ret)
3124 {
3125         LONG status;
3126         DWORD index = 0;
3127         LONG error;
3128         UINT32 cbRecvLength = ret->cbRecvLength;
3129         UINT32 cbRecvPci = ret->pioRecvPci ? ret->pioRecvPci->cbPciLength : 0;
3130
3131         smartcard_trace_transmit_return(smartcard, ret);
3132
3133         if (!ret->pbRecvBuffer)
3134                 cbRecvLength = 0;
3135
3136         if (!smartcard_ndr_pointer_write(s, &index, cbRecvPci))
3137                 return SCARD_E_NO_MEMORY;
3138         if (!Stream_EnsureRemainingCapacity(s, 4))
3139                 return SCARD_E_NO_MEMORY;
3140         Stream_Write_UINT32(s, cbRecvLength); /* cbRecvLength (4 bytes) */
3141         if (!smartcard_ndr_pointer_write(s, &index, cbRecvLength))
3142                 return SCARD_E_NO_MEMORY;
3143
3144         if (ret->pioRecvPci)
3145         {
3146                 UINT32 cbExtraBytes = (UINT32)(ret->pioRecvPci->cbPciLength - sizeof(SCARD_IO_REQUEST));
3147                 BYTE* pbExtraBytes = &((BYTE*)ret->pioRecvPci)[sizeof(SCARD_IO_REQUEST)];
3148
3149                 if (!Stream_EnsureRemainingCapacity(s, cbExtraBytes + 16))
3150                 {
3151                         WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!");
3152                         return SCARD_F_INTERNAL_ERROR;
3153                 }
3154
3155                 Stream_Write_UINT32(s, ret->pioRecvPci->dwProtocol); /* dwProtocol (4 bytes) */
3156                 Stream_Write_UINT32(s, cbExtraBytes);                /* cbExtraBytes (4 bytes) */
3157                 if (!smartcard_ndr_pointer_write(s, &index, cbExtraBytes))
3158                         return SCARD_E_NO_MEMORY;
3159                 error = smartcard_ndr_write(s, pbExtraBytes, cbExtraBytes, 1, NDR_PTR_SIMPLE);
3160                 if (error)
3161                         return error;
3162         }
3163
3164         status = smartcard_ndr_write(s, ret->pbRecvBuffer, ret->cbRecvLength, 1, NDR_PTR_SIMPLE);
3165         if (status != SCARD_S_SUCCESS)
3166                 return status;
3167         return ret->ReturnCode;
3168 }
3169
3170 LONG smartcard_unpack_locate_cards_by_atr_a_call(SMARTCARD_DEVICE* smartcard, wStream* s,
3171                                                  LocateCardsByATRA_Call* call)
3172 {
3173         LONG status;
3174         UINT32 rgReaderStatesNdrPtr;
3175         UINT32 rgAtrMasksNdrPtr;
3176         UINT32 index = 0;
3177         call->rgReaderStates = NULL;
3178
3179         status = smartcard_unpack_redir_scard_context(smartcard, s, &(call->handles.hContext), &index);
3180         if (status != SCARD_S_SUCCESS)
3181                 return status;
3182
3183         if (Stream_GetRemainingLength(s) < 16)
3184         {
3185                 WLog_WARN(TAG, "LocateCardsByATRA_Call is too short: %" PRIuz "",
3186                           Stream_GetRemainingLength(s));
3187                 return STATUS_BUFFER_TOO_SMALL;
3188         }
3189
3190         Stream_Read_UINT32(s, call->cAtrs);
3191         if (!smartcard_ndr_pointer_read(s, &index, &rgAtrMasksNdrPtr))
3192                 return ERROR_INVALID_DATA;
3193         Stream_Read_UINT32(s, call->cReaders); /* cReaders (4 bytes) */
3194         if (!smartcard_ndr_pointer_read(s, &index, &rgReaderStatesNdrPtr))
3195                 return ERROR_INVALID_DATA;
3196
3197         if ((status =
3198                  smartcard_unpack_redir_scard_context_ref(smartcard, s, &(call->handles.hContext))))
3199                 return status;
3200
3201         if ((rgAtrMasksNdrPtr && !call->cAtrs) || (!rgAtrMasksNdrPtr && call->cAtrs))
3202         {
3203                 WLog_WARN(TAG,
3204                           "LocateCardsByATRA_Call rgAtrMasksNdrPtr (0x%08" PRIX32
3205                           ") and cAtrs (0x%08" PRIX32 ") inconsistency",
3206                           rgAtrMasksNdrPtr, call->cAtrs);
3207                 return STATUS_INVALID_PARAMETER;
3208         }
3209
3210         if (rgAtrMasksNdrPtr)
3211         {
3212                 status = smartcard_ndr_read_atrmask(s, &call->rgAtrMasks, call->cAtrs, NDR_PTR_SIMPLE);
3213                 if (status != SCARD_S_SUCCESS)
3214                         return status;
3215         }
3216
3217         if (rgReaderStatesNdrPtr)
3218         {
3219                 status = smartcard_unpack_reader_state_a(s, &call->rgReaderStates, call->cReaders, &index);
3220                 if (status != SCARD_S_SUCCESS)
3221                         return status;
3222         }
3223
3224         smartcard_trace_locate_cards_by_atr_a_call(smartcard, call);
3225         return SCARD_S_SUCCESS;
3226 }
3227
3228 LONG smartcard_unpack_context_and_two_strings_a_call(SMARTCARD_DEVICE* smartcard, wStream* s,
3229                                                      ContextAndTwoStringA_Call* call)
3230 {
3231         LONG status;
3232         UINT32 sz1NdrPtr, sz2NdrPtr;
3233         UINT32 index = 0;
3234
3235         status = smartcard_unpack_redir_scard_context(smartcard, s, &(call->handles.hContext), &index);
3236         if (status != SCARD_S_SUCCESS)
3237                 return status;
3238
3239         if (!smartcard_ndr_pointer_read(s, &index, &sz1NdrPtr))
3240                 return ERROR_INVALID_DATA;
3241         if (!smartcard_ndr_pointer_read(s, &index, &sz2NdrPtr))
3242                 return ERROR_INVALID_DATA;
3243
3244         status = smartcard_unpack_redir_scard_context_ref(smartcard, s, &call->handles.hContext);
3245         if (status != SCARD_S_SUCCESS)
3246                 return status;
3247
3248         if (sz1NdrPtr)
3249         {
3250                 status = smartcard_ndr_read_a(s, &call->sz1, NDR_PTR_FULL);
3251                 if (status != SCARD_S_SUCCESS)
3252                         return status;
3253         }
3254         if (sz2NdrPtr)
3255         {
3256                 status = smartcard_ndr_read_a(s, &call->sz2, NDR_PTR_FULL);
3257                 if (status != SCARD_S_SUCCESS)
3258                         return status;
3259         }
3260         smartcard_trace_context_and_two_strings_a_call(smartcard, call);
3261         return SCARD_S_SUCCESS;
3262 }
3263
3264 LONG smartcard_unpack_context_and_two_strings_w_call(SMARTCARD_DEVICE* smartcard, wStream* s,
3265                                                      ContextAndTwoStringW_Call* call)
3266 {
3267         LONG status;
3268         UINT32 sz1NdrPtr, sz2NdrPtr;
3269         UINT32 index = 0;
3270         status = smartcard_unpack_redir_scard_context(smartcard, s, &(call->handles.hContext), &index);
3271         if (status != SCARD_S_SUCCESS)
3272                 return status;
3273
3274         if (!smartcard_ndr_pointer_read(s, &index, &sz1NdrPtr))
3275                 return ERROR_INVALID_DATA;
3276         if (!smartcard_ndr_pointer_read(s, &index, &sz2NdrPtr))
3277                 return ERROR_INVALID_DATA;
3278
3279         status = smartcard_unpack_redir_scard_context_ref(smartcard, s, &call->handles.hContext);
3280         if (status != SCARD_S_SUCCESS)
3281                 return status;
3282
3283         if (sz1NdrPtr)
3284         {
3285                 status = smartcard_ndr_read_w(s, &call->sz1, NDR_PTR_FULL);
3286                 if (status != SCARD_S_SUCCESS)
3287                         return status;
3288         }
3289         if (sz2NdrPtr)
3290         {
3291                 status = smartcard_ndr_read_w(s, &call->sz2, NDR_PTR_FULL);
3292                 if (status != SCARD_S_SUCCESS)
3293                         return status;
3294         }
3295         smartcard_trace_context_and_two_strings_w_call(smartcard, call);
3296         return SCARD_S_SUCCESS;
3297 }
3298
3299 LONG smartcard_unpack_locate_cards_a_call(SMARTCARD_DEVICE* smartcard, wStream* s,
3300                                           LocateCardsA_Call* call)
3301 {
3302         LONG status;
3303         UINT32 sz1NdrPtr, sz2NdrPtr;
3304         UINT32 index = 0;
3305         status = smartcard_unpack_redir_scard_context(smartcard, s, &(call->handles.hContext), &index);
3306         if (status != SCARD_S_SUCCESS)
3307                 return status;
3308
3309         if (Stream_GetRemainingLength(s) < 16)
3310         {
3311                 WLog_WARN(TAG, "%s is too short: %" PRIuz "", __FUNCTION__, Stream_GetRemainingLength(s));
3312                 return STATUS_BUFFER_TOO_SMALL;
3313         }
3314         Stream_Read_UINT32(s, call->cBytes);
3315         if (!smartcard_ndr_pointer_read(s, &index, &sz1NdrPtr))
3316                 return ERROR_INVALID_DATA;
3317
3318         Stream_Read_UINT32(s, call->cReaders);
3319         if (!smartcard_ndr_pointer_read(s, &index, &sz2NdrPtr))
3320                 return ERROR_INVALID_DATA;
3321
3322         if (sz1NdrPtr)
3323         {
3324                 status =
3325                     smartcard_ndr_read_fixed_string_a(s, &call->mszCards, call->cBytes, NDR_PTR_SIMPLE);
3326                 if (status != SCARD_S_SUCCESS)
3327                         return status;
3328         }
3329         if (sz2NdrPtr)
3330         {
3331                 status = smartcard_unpack_reader_state_a(s, &call->rgReaderStates, call->cReaders, &index);
3332                 if (status != SCARD_S_SUCCESS)
3333                         return status;
3334         }
3335         smartcard_trace_locate_cards_a_call(smartcard, call);
3336         return SCARD_S_SUCCESS;
3337 }
3338
3339 LONG smartcard_unpack_locate_cards_w_call(SMARTCARD_DEVICE* smartcard, wStream* s,
3340                                           LocateCardsW_Call* call)
3341 {
3342         LONG status;
3343         UINT32 sz1NdrPtr, sz2NdrPtr;
3344         UINT32 index = 0;
3345
3346         status = smartcard_unpack_redir_scard_context(smartcard, s, &(call->handles.hContext), &index);
3347         if (status != SCARD_S_SUCCESS)
3348                 return status;
3349
3350         if (Stream_GetRemainingLength(s) < 16)
3351         {
3352                 WLog_WARN(TAG, "%s is too short: %" PRIuz "", __FUNCTION__, Stream_GetRemainingLength(s));
3353                 return STATUS_BUFFER_TOO_SMALL;
3354         }
3355         Stream_Read_UINT32(s, call->cBytes);
3356         if (!smartcard_ndr_pointer_read(s, &index, &sz1NdrPtr))
3357                 return ERROR_INVALID_DATA;
3358
3359         Stream_Read_UINT32(s, call->cReaders);
3360         if (!smartcard_ndr_pointer_read(s, &index, &sz2NdrPtr))
3361                 return ERROR_INVALID_DATA;
3362
3363         if (sz1NdrPtr)
3364         {
3365                 status =
3366                     smartcard_ndr_read_fixed_string_w(s, &call->mszCards, call->cBytes, NDR_PTR_SIMPLE);
3367                 if (status != SCARD_S_SUCCESS)
3368                         return status;
3369         }
3370         if (sz2NdrPtr)
3371         {
3372                 status = smartcard_unpack_reader_state_w(s, &call->rgReaderStates, call->cReaders, &index);
3373                 if (status != SCARD_S_SUCCESS)
3374                         return status;
3375         }
3376         smartcard_trace_locate_cards_w_call(smartcard, call);
3377         return SCARD_S_SUCCESS;
3378 }
3379
3380 LONG smartcard_unpack_set_attrib_call(SMARTCARD_DEVICE* smartcard, wStream* s, SetAttrib_Call* call)
3381 {
3382         LONG status;
3383         UINT32 index = 0;
3384         UINT32 ndrPtr;
3385
3386         status = smartcard_unpack_redir_scard_context(smartcard, s, &(call->handles.hContext), &index);
3387         if (status != SCARD_S_SUCCESS)
3388                 return status;
3389         status = smartcard_unpack_redir_scard_handle(smartcard, s, &(call->handles.hCard), &index);
3390         if (status != SCARD_S_SUCCESS)
3391                 return status;
3392
3393         if (Stream_GetRemainingLength(s) < 12)
3394                 return STATUS_BUFFER_TOO_SMALL;
3395         Stream_Read_UINT32(s, call->dwAttrId);
3396         Stream_Read_UINT32(s, call->cbAttrLen);
3397
3398         if (!smartcard_ndr_pointer_read(s, &index, &ndrPtr))
3399                 return ERROR_INVALID_DATA;
3400
3401         if ((status =
3402                  smartcard_unpack_redir_scard_context_ref(smartcard, s, &(call->handles.hContext))))
3403                 return status;
3404
3405         if ((status = smartcard_unpack_redir_scard_handle_ref(smartcard, s, &(call->handles.hCard))))
3406                 return status;
3407
3408         if (ndrPtr)
3409         {
3410                 // TODO: call->cbAttrLen was larger than the pointer value.
3411                 // TODO: Maybe need to refine the checks?
3412                 status = smartcard_ndr_read(s, &call->pbAttr, 0, 1, NDR_PTR_SIMPLE);
3413                 if (status != SCARD_S_SUCCESS)
3414                         return status;
3415         }
3416         smartcard_trace_set_attrib_call(smartcard, call);
3417         return SCARD_S_SUCCESS;
3418 }
3419
3420 LONG smartcard_unpack_locate_cards_by_atr_w_call(SMARTCARD_DEVICE* smartcard, wStream* s,
3421                                                  LocateCardsByATRW_Call* call)
3422 {
3423         LONG status;
3424         UINT32 rgReaderStatesNdrPtr;
3425         UINT32 rgAtrMasksNdrPtr;
3426         UINT32 index = 0;
3427         call->rgReaderStates = NULL;
3428
3429         status = smartcard_unpack_redir_scard_context(smartcard, s, &(call->handles.hContext), &index);
3430         if (status != SCARD_S_SUCCESS)
3431                 return status;
3432
3433         if (Stream_GetRemainingLength(s) < 16)
3434         {
3435                 WLog_WARN(TAG, "LocateCardsByATRW_Call is too short: %" PRIuz "",
3436                           Stream_GetRemainingLength(s));
3437                 return STATUS_BUFFER_TOO_SMALL;
3438         }
3439
3440         Stream_Read_UINT32(s, call->cAtrs);
3441         if (!smartcard_ndr_pointer_read(s, &index, &rgAtrMasksNdrPtr))
3442                 return ERROR_INVALID_DATA;
3443
3444         Stream_Read_UINT32(s, call->cReaders); /* cReaders (4 bytes) */
3445         if (!smartcard_ndr_pointer_read(s, &index, &rgReaderStatesNdrPtr))
3446                 return ERROR_INVALID_DATA;
3447
3448         if ((status =
3449                  smartcard_unpack_redir_scard_context_ref(smartcard, s, &(call->handles.hContext))))
3450                 return status;
3451
3452         if ((rgAtrMasksNdrPtr && !call->cAtrs) || (!rgAtrMasksNdrPtr && call->cAtrs))
3453         {
3454                 WLog_WARN(TAG,
3455                           "LocateCardsByATRW_Call rgAtrMasksNdrPtr (0x%08" PRIX32
3456                           ") and cAtrs (0x%08" PRIX32 ") inconsistency",
3457                           rgAtrMasksNdrPtr, call->cAtrs);
3458                 return STATUS_INVALID_PARAMETER;
3459         }
3460
3461         if (rgAtrMasksNdrPtr)
3462         {
3463                 status = smartcard_ndr_read_atrmask(s, &call->rgAtrMasks, call->cAtrs, NDR_PTR_SIMPLE);
3464                 if (status != SCARD_S_SUCCESS)
3465                         return status;
3466         }
3467
3468         if (rgReaderStatesNdrPtr)
3469         {
3470                 status = smartcard_unpack_reader_state_w(s, &call->rgReaderStates, call->cReaders, &index);
3471                 if (status != SCARD_S_SUCCESS)
3472                         return status;
3473         }
3474
3475         smartcard_trace_locate_cards_by_atr_w_call(smartcard, call);
3476         return SCARD_S_SUCCESS;
3477 }
3478
3479 LONG smartcard_unpack_read_cache_a_call(SMARTCARD_DEVICE* smartcard, wStream* s,
3480                                         ReadCacheA_Call* call)
3481 {
3482         LONG status;
3483         UINT32 mszNdrPtr;
3484         UINT32 contextNdrPtr;
3485         UINT32 index = 0;
3486
3487         if (!smartcard_ndr_pointer_read(s, &index, &mszNdrPtr))
3488                 return ERROR_INVALID_DATA;
3489
3490         status = smartcard_unpack_redir_scard_context(smartcard, s, &(call->Common.handles.hContext),
3491                                                       &index);
3492         if (status != SCARD_S_SUCCESS)
3493                 return status;
3494
3495         if (!smartcard_ndr_pointer_read(s, &index, &contextNdrPtr))
3496                 return ERROR_INVALID_DATA;
3497
3498         if (Stream_GetRemainingLength(s) < 12)
3499                 return STATUS_BUFFER_TOO_SMALL;
3500         Stream_Read_UINT32(s, call->Common.FreshnessCounter);
3501         Stream_Read_INT32(s, call->Common.fPbDataIsNULL);
3502         Stream_Read_UINT32(s, call->Common.cbDataLen);
3503
3504         call->szLookupName = NULL;
3505         if (mszNdrPtr)
3506         {
3507                 status = smartcard_ndr_read_a(s, &call->szLookupName, NDR_PTR_FULL);
3508                 if (status != SCARD_S_SUCCESS)
3509                         return status;
3510         }
3511
3512         status = smartcard_unpack_redir_scard_context_ref(smartcard, s, &call->Common.handles.hContext);
3513         if (status != SCARD_S_SUCCESS)
3514                 return status;
3515
3516         if (contextNdrPtr)
3517         {
3518                 status = smartcard_ndr_read_u(s, &call->Common.CardIdentifier);
3519                 if (status != SCARD_S_SUCCESS)
3520                         return status;
3521         }
3522         smartcard_trace_read_cache_a_call(smartcard, call);
3523         return SCARD_S_SUCCESS;
3524 }
3525
3526 LONG smartcard_unpack_read_cache_w_call(SMARTCARD_DEVICE* smartcard, wStream* s,
3527                                         ReadCacheW_Call* call)
3528 {
3529         LONG status;
3530         UINT32 mszNdrPtr;
3531         UINT32 contextNdrPtr;
3532         UINT32 index = 0;
3533
3534         if (!smartcard_ndr_pointer_read(s, &index, &mszNdrPtr))
3535                 return ERROR_INVALID_DATA;
3536
3537         status = smartcard_unpack_redir_scard_context(smartcard, s, &(call->Common.handles.hContext),
3538                                                       &index);
3539         if (status != SCARD_S_SUCCESS)
3540                 return status;
3541
3542         if (!smartcard_ndr_pointer_read(s, &index, &contextNdrPtr))
3543                 return ERROR_INVALID_DATA;
3544
3545         if (Stream_GetRemainingLength(s) < 12)
3546                 return STATUS_BUFFER_TOO_SMALL;
3547         Stream_Read_UINT32(s, call->Common.FreshnessCounter);
3548         Stream_Read_INT32(s, call->Common.fPbDataIsNULL);
3549         Stream_Read_UINT32(s, call->Common.cbDataLen);
3550
3551         call->szLookupName = NULL;
3552         if (mszNdrPtr)
3553         {
3554                 status = smartcard_ndr_read_w(s, &call->szLookupName, NDR_PTR_FULL);
3555                 if (status != SCARD_S_SUCCESS)
3556                         return status;
3557         }
3558
3559         status = smartcard_unpack_redir_scard_context_ref(smartcard, s, &call->Common.handles.hContext);
3560         if (status != SCARD_S_SUCCESS)
3561                 return status;
3562
3563         if (contextNdrPtr)
3564         {
3565                 status = smartcard_ndr_read_u(s, &call->Common.CardIdentifier);
3566                 if (status != SCARD_S_SUCCESS)
3567                         return status;
3568         }
3569         smartcard_trace_read_cache_w_call(smartcard, call);
3570         return SCARD_S_SUCCESS;
3571 }
3572
3573 LONG smartcard_unpack_write_cache_a_call(SMARTCARD_DEVICE* smartcard, wStream* s,
3574                                          WriteCacheA_Call* call)
3575 {
3576         LONG status;
3577         UINT32 mszNdrPtr;
3578         UINT32 contextNdrPtr;
3579         UINT32 pbDataNdrPtr;
3580         UINT32 index = 0;
3581
3582         if (!smartcard_ndr_pointer_read(s, &index, &mszNdrPtr))
3583                 return ERROR_INVALID_DATA;
3584
3585         status = smartcard_unpack_redir_scard_context(smartcard, s, &(call->Common.handles.hContext),
3586                                                       &index);
3587         if (status != SCARD_S_SUCCESS)
3588                 return status;
3589
3590         if (!smartcard_ndr_pointer_read(s, &index, &contextNdrPtr))
3591                 return ERROR_INVALID_DATA;
3592
3593         if (Stream_GetRemainingLength(s) < 8)
3594                 return STATUS_BUFFER_TOO_SMALL;
3595
3596         Stream_Read_UINT32(s, call->Common.FreshnessCounter);
3597         Stream_Read_UINT32(s, call->Common.cbDataLen);
3598
3599         if (!smartcard_ndr_pointer_read(s, &index, &pbDataNdrPtr))
3600                 return ERROR_INVALID_DATA;
3601
3602         call->szLookupName = NULL;
3603         if (mszNdrPtr)
3604         {
3605                 status = smartcard_ndr_read_a(s, &call->szLookupName, NDR_PTR_FULL);
3606                 if (status != SCARD_S_SUCCESS)
3607                         return status;
3608         }
3609
3610         status = smartcard_unpack_redir_scard_context_ref(smartcard, s, &call->Common.handles.hContext);
3611         if (status != SCARD_S_SUCCESS)
3612                 return status;
3613
3614         call->Common.CardIdentifier = NULL;
3615         if (contextNdrPtr)
3616         {
3617                 status = smartcard_ndr_read_u(s, &call->Common.CardIdentifier);
3618                 if (status != SCARD_S_SUCCESS)
3619                         return status;
3620         }
3621
3622         call->Common.pbData = NULL;
3623         if (pbDataNdrPtr)
3624         {
3625                 status =
3626                     smartcard_ndr_read(s, &call->Common.pbData, call->Common.cbDataLen, 1, NDR_PTR_SIMPLE);
3627                 if (status != SCARD_S_SUCCESS)
3628                         return status;
3629         }
3630         smartcard_trace_write_cache_a_call(smartcard, call);
3631         return SCARD_S_SUCCESS;
3632 }
3633
3634 LONG smartcard_unpack_write_cache_w_call(SMARTCARD_DEVICE* smartcard, wStream* s,
3635                                          WriteCacheW_Call* call)
3636 {
3637         LONG status;
3638         UINT32 mszNdrPtr;
3639         UINT32 contextNdrPtr;
3640         UINT32 pbDataNdrPtr;
3641         UINT32 index = 0;
3642
3643         if (!smartcard_ndr_pointer_read(s, &index, &mszNdrPtr))
3644                 return ERROR_INVALID_DATA;
3645
3646         status = smartcard_unpack_redir_scard_context(smartcard, s, &(call->Common.handles.hContext),
3647                                                       &index);
3648         if (status != SCARD_S_SUCCESS)
3649                 return status;
3650
3651         if (!smartcard_ndr_pointer_read(s, &index, &contextNdrPtr))
3652                 return ERROR_INVALID_DATA;
3653
3654         if (Stream_GetRemainingLength(s) < 8)
3655                 return STATUS_BUFFER_TOO_SMALL;
3656         Stream_Read_UINT32(s, call->Common.FreshnessCounter);
3657         Stream_Read_UINT32(s, call->Common.cbDataLen);
3658
3659         if (!smartcard_ndr_pointer_read(s, &index, &pbDataNdrPtr))
3660                 return ERROR_INVALID_DATA;
3661
3662         call->szLookupName = NULL;
3663         if (mszNdrPtr)
3664         {
3665                 status = smartcard_ndr_read_w(s, &call->szLookupName, NDR_PTR_FULL);
3666                 if (status != SCARD_S_SUCCESS)
3667                         return status;
3668         }
3669
3670         status = smartcard_unpack_redir_scard_context_ref(smartcard, s, &call->Common.handles.hContext);
3671         if (status != SCARD_S_SUCCESS)
3672                 return status;
3673
3674         call->Common.CardIdentifier = NULL;
3675         if (contextNdrPtr)
3676         {
3677                 status = smartcard_ndr_read_u(s, &call->Common.CardIdentifier);
3678                 if (status != SCARD_S_SUCCESS)
3679                         return status;
3680         }
3681
3682         call->Common.pbData = NULL;
3683         if (pbDataNdrPtr)
3684         {
3685                 status =
3686                     smartcard_ndr_read(s, &call->Common.pbData, call->Common.cbDataLen, 1, NDR_PTR_SIMPLE);
3687                 if (status != SCARD_S_SUCCESS)
3688                         return status;
3689         }
3690         smartcard_trace_write_cache_w_call(smartcard, call);
3691         return status;
3692 }
3693
3694 LONG smartcard_unpack_get_transmit_count_call(SMARTCARD_DEVICE* smartcard, wStream* s,
3695                                               GetTransmitCount_Call* call)
3696 {
3697         LONG status;
3698         UINT32 index = 0;
3699
3700         status = smartcard_unpack_redir_scard_context(smartcard, s, &(call->handles.hContext), &index);
3701         if (status != SCARD_S_SUCCESS)
3702                 return status;
3703
3704         status = smartcard_unpack_redir_scard_handle(smartcard, s, &(call->handles.hCard), &index);
3705         if (status != SCARD_S_SUCCESS)
3706                 return status;
3707
3708         if ((status =
3709                  smartcard_unpack_redir_scard_context_ref(smartcard, s, &(call->handles.hContext))))
3710         {
3711                 WLog_ERR(TAG, "smartcard_unpack_redir_scard_context_ref failed with error %" PRId32 "",
3712                          status);
3713                 return status;
3714         }
3715
3716         if ((status = smartcard_unpack_redir_scard_handle_ref(smartcard, s, &(call->handles.hCard))))
3717                 WLog_ERR(TAG, "smartcard_unpack_redir_scard_handle_ref failed with error %" PRId32 "",
3718                          status);
3719
3720         smartcard_trace_get_transmit_count_call(smartcard, call);
3721         return status;
3722 }
3723
3724 LONG smartcard_unpack_get_reader_icon_call(SMARTCARD_DEVICE* smartcard, wStream* s,
3725                                            GetReaderIcon_Call* call)
3726 {
3727         return smartcard_unpack_common_context_and_string_w(smartcard, s, &call->handles.hContext,
3728                                                             &call->szReaderName);
3729 }
3730
3731 LONG smartcard_unpack_context_and_string_a_call(SMARTCARD_DEVICE* smartcard, wStream* s,
3732                                                 ContextAndStringA_Call* call)
3733 {
3734         return smartcard_unpack_common_context_and_string_a(smartcard, s, &call->handles.hContext,
3735                                                             &call->sz);
3736 }
3737
3738 LONG smartcard_unpack_context_and_string_w_call(SMARTCARD_DEVICE* smartcard, wStream* s,
3739                                                 ContextAndStringW_Call* call)
3740 {
3741         return smartcard_unpack_common_context_and_string_w(smartcard, s, &call->handles.hContext,
3742                                                             &call->sz);
3743 }
3744
3745 LONG smartcard_unpack_get_device_type_id_call(SMARTCARD_DEVICE* smartcard, wStream* s,
3746                                               GetDeviceTypeId_Call* call)
3747 {
3748         return smartcard_unpack_common_context_and_string_w(smartcard, s, &call->handles.hContext,
3749                                                             &call->szReaderName);
3750 }
3751
3752 LONG smartcard_pack_device_type_id_return(SMARTCARD_DEVICE* smartcard, wStream* s,
3753                                           const GetDeviceTypeId_Return* ret)
3754 {
3755         smartcard_trace_device_type_id_return(smartcard, ret);
3756
3757         if (!Stream_EnsureRemainingCapacity(s, 4))
3758         {
3759                 WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!");
3760                 return SCARD_F_INTERNAL_ERROR;
3761         }
3762
3763         Stream_Write_UINT32(s, ret->dwDeviceId); /* cBytes (4 bytes) */
3764
3765         return ret->ReturnCode;
3766 }
3767
3768 LONG smartcard_pack_locate_cards_return(SMARTCARD_DEVICE* smartcard, wStream* s,
3769                                         const LocateCards_Return* ret)
3770 {
3771         LONG status;
3772         DWORD cbDataLen = ret->cReaders;
3773         DWORD index = 0;
3774
3775         smartcard_trace_locate_cards_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_state(s, ret->rgReaderStates, cbDataLen, NDR_PTR_SIMPLE);
3792         if (status != SCARD_S_SUCCESS)
3793                 return status;
3794         return ret->ReturnCode;
3795 }
3796
3797 LONG smartcard_pack_get_reader_icon_return(SMARTCARD_DEVICE* smartcard, wStream* s,
3798                                            const GetReaderIcon_Return* ret)
3799 {
3800         LONG status;
3801         DWORD index = 0;
3802         DWORD cbDataLen = ret->cbDataLen;
3803         smartcard_trace_get_reader_icon_return(smartcard, ret);
3804         if (ret->ReturnCode != SCARD_S_SUCCESS)
3805                 cbDataLen = 0;
3806         if (cbDataLen == SCARD_AUTOALLOCATE)
3807                 cbDataLen = 0;
3808
3809         if (!Stream_EnsureRemainingCapacity(s, 4))
3810         {
3811                 WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!");
3812                 return SCARD_F_INTERNAL_ERROR;
3813         }
3814
3815         Stream_Write_UINT32(s, cbDataLen); /* cBytes (4 cbDataLen) */
3816         if (!smartcard_ndr_pointer_write(s, &index, cbDataLen))
3817                 return SCARD_E_NO_MEMORY;
3818
3819         status = smartcard_ndr_write(s, ret->pbData, cbDataLen, 1, NDR_PTR_SIMPLE);
3820         if (status != SCARD_S_SUCCESS)
3821                 return status;
3822         return ret->ReturnCode;
3823 }
3824
3825 LONG smartcard_pack_get_transmit_count_return(SMARTCARD_DEVICE* smartcard, wStream* s,
3826                                               const GetTransmitCount_Return* ret)
3827 {
3828         smartcard_trace_get_transmit_count_return(smartcard, ret);
3829
3830         if (!Stream_EnsureRemainingCapacity(s, 4))
3831         {
3832                 WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!");
3833                 return SCARD_F_INTERNAL_ERROR;
3834         }
3835
3836         Stream_Write_UINT32(s, ret->cTransmitCount); /* cBytes (4 cbDataLen) */
3837
3838         return ret->ReturnCode;
3839 }
3840
3841 LONG smartcard_pack_read_cache_return(SMARTCARD_DEVICE* smartcard, wStream* s,
3842                                       const ReadCache_Return* ret)
3843 {
3844         LONG status;
3845         DWORD index = 0;
3846         DWORD cbDataLen = ret->cbDataLen;
3847         smartcard_trace_read_cache_return(smartcard, ret);
3848         if (ret->ReturnCode != SCARD_S_SUCCESS)
3849                 cbDataLen = 0;
3850
3851         if (cbDataLen == SCARD_AUTOALLOCATE)
3852                 cbDataLen = 0;
3853
3854         if (!Stream_EnsureRemainingCapacity(s, 4))
3855         {
3856                 WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!");
3857                 return SCARD_F_INTERNAL_ERROR;
3858         }
3859
3860         Stream_Write_UINT32(s, cbDataLen); /* cBytes (4 cbDataLen) */
3861         if (!smartcard_ndr_pointer_write(s, &index, cbDataLen))
3862                 return SCARD_E_NO_MEMORY;
3863
3864         status = smartcard_ndr_write(s, ret->pbData, cbDataLen, 1, NDR_PTR_SIMPLE);
3865         if (status != SCARD_S_SUCCESS)
3866                 return status;
3867         return ret->ReturnCode;
3868 }