Initial commit - from Precise source
[freerdp-ubuntu-pcb-backport.git] / channels / rdpdr / smartcard / scard_operations.c
1 /*
2    FreeRDP: A Remote Desktop Protocol client.
3    Redirected Smart Card Device Service
4
5    Copyright (C) Alexi Volkov <alexi@myrealbox.com> 2006
6    Copyright 2011 O.S. Systems Software Ltda.
7    Copyright 2011 Anthony Tong <atong@trustedcs.com>
8
9    Licensed under the Apache License, Version 2.0 (the "License");
10    you may not use this file except in compliance with the License.
11    You may obtain a copy of the License at
12
13        http://www.apache.org/licenses/LICENSE-2.0
14
15    Unless required by applicable law or agreed to in writing, software
16    distributed under the License is distributed on an "AS IS" BASIS,
17    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18    See the License for the specific language governing permissions and
19    limitations under the License.
20 */
21
22 #include "config.h"
23
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <unistd.h>
28 #include <strings.h>
29 #include <semaphore.h>
30 #include <pthread.h>
31
32 #include <PCSC/pcsclite.h>
33 #include <PCSC/reader.h>
34 #include <PCSC/winscard.h>
35
36 #include <freerdp/freerdp.h>
37 #include <freerdp/utils/hexdump.h>
38 #include <freerdp/utils/memory.h>
39 #include <freerdp/utils/stream.h>
40 #include <freerdp/utils/svc_plugin.h>
41 #include <freerdp/utils/semaphore.h>
42 #include <freerdp/utils/thread.h>
43
44 #include "rdpdr_types.h"
45 #include "rdpdr_constants.h"
46
47 #include "scard_main.h"
48
49 /* [MS-RDPESC] 3.1.4 */
50 #define SCARD_IOCTL_ESTABLISH_CONTEXT        0x00090014 /* EstablishContext */
51 #define SCARD_IOCTL_RELEASE_CONTEXT          0x00090018 /* ReleaseContext */
52 #define SCARD_IOCTL_IS_VALID_CONTEXT         0x0009001C /* IsValidContext */
53 #define SCARD_IOCTL_LIST_READER_GROUPS       0x00090020 /* ListReaderGroups */
54 #define SCARD_IOCTL_LIST_READERS             0x00090028 /* ListReadersA */
55 #define SCARD_IOCTL_INTRODUCE_READER_GROUP   0x00090050 /* IntroduceReaderGroup */
56 #define SCARD_IOCTL_FORGET_READER_GROUP      0x00090058 /* ForgetReader */
57 #define SCARD_IOCTL_INTRODUCE_READER         0x00090060 /* IntroduceReader */
58 #define SCARD_IOCTL_FORGET_READER            0x00090068 /* IntroduceReader */
59 #define SCARD_IOCTL_ADD_READER_TO_GROUP      0x00090070 /* AddReaderToGroup */
60 #define SCARD_IOCTL_REMOVE_READER_FROM_GROUP 0x00090078 /* RemoveReaderFromGroup */
61 #define SCARD_IOCTL_GET_STATUS_CHANGE        0x000900A0 /* GetStatusChangeA */
62 #define SCARD_IOCTL_CANCEL                   0x000900A8 /* Cancel */
63 #define SCARD_IOCTL_CONNECT                  0x000900AC /* ConnectA */
64 #define SCARD_IOCTL_RECONNECT                0x000900B4 /* Reconnect */
65 #define SCARD_IOCTL_DISCONNECT               0x000900B8 /* Disconnect */
66 #define SCARD_IOCTL_BEGIN_TRANSACTION        0x000900BC /* BeginTransaction */
67 #define SCARD_IOCTL_END_TRANSACTION          0x000900C0 /* EndTransaction */
68 #define SCARD_IOCTL_STATE                    0x000900C4 /* State */
69 #define SCARD_IOCTL_STATUS                   0x000900C8 /* StatusA */
70 #define SCARD_IOCTL_TRANSMIT                 0x000900D0 /* Transmit */
71 #define SCARD_IOCTL_CONTROL                  0x000900D4 /* Control */
72 #define SCARD_IOCTL_GETATTRIB                0x000900D8 /* GetAttrib */
73 #define SCARD_IOCTL_SETATTRIB                0x000900DC /* SetAttrib */
74 #define SCARD_IOCTL_ACCESS_STARTED_EVENT     0x000900E0 /* SCardAccessStartedEvent */
75 #define SCARD_IOCTL_LOCATE_CARDS_BY_ATR      0x000900E8 /* LocateCardsByATR */
76
77 #define SCARD_INPUT_LINKED                   0xFFFFFFFF
78
79 /* Decode Win CTL_CODE values */
80 #define WIN_CTL_FUNCTION(ctl_code)      ((ctl_code & 0x3FFC) >> 2)
81 #define WIN_CTL_DEVICE_TYPE(ctl_code)   (ctl_code >> 16)
82
83 #define WIN_FILE_DEVICE_SMARTCARD       0x00000031
84
85
86 static uint32 sc_output_string(IRP* irp, char *src, boolean wide)
87 {
88         uint8* p;
89         uint32 len;
90
91         p = stream_get_tail(irp->output);
92         len = strlen(src) + 1;
93
94         if (wide)
95         {
96                 int i;
97
98                 for (i = 0; i < len; i++ )
99                 {
100                         p[2 * i] = src[i] < 0 ? '?' : src[i];
101                         p[2 * i + 1] = '\0';
102                 }
103
104                 len *= 2;
105         }
106         else
107         {
108                 memcpy(p, src, len);
109         }
110
111         stream_seek(irp->output, len);
112         return len;
113 }
114
115 static void sc_output_alignment(IRP *irp, uint32 seed)
116 {
117         uint32 size = stream_get_length(irp->output) - 20;
118         uint32 add = (seed - (size % seed)) % seed;
119
120         if (add > 0)
121                 stream_write_zero(irp->output, add);
122 }
123
124 static void sc_output_repos(IRP* irp, uint32 written)
125 {
126         uint32 add = (4 - (written % 4)) % 4;
127
128         if (add > 0)
129                 stream_write_zero(irp->output, add);
130 }
131
132 static uint32 sc_output_return(IRP* irp, uint32 rv)
133 {
134         stream_write_zero(irp->output, 256);
135         return rv;
136 }
137
138 static void sc_output_buffer_limit(IRP* irp, char *buffer, unsigned int length, unsigned int highLimit)
139 {
140         int header = (length < 0) ? (0) : ((length > highLimit) ? (highLimit) : (length));
141
142         stream_write_uint32(irp->output, header);
143
144         if (length <= 0)
145         {
146                 stream_write_uint32(irp->output, 0);
147         }
148         else
149         {
150                 if (header < length)
151                         length = header;
152
153                 stream_write(irp->output, buffer, length);
154                 sc_output_repos(irp, length);
155         }
156 }
157
158 static void sc_output_buffer(IRP* irp, char *buffer, unsigned int length)
159 {
160         sc_output_buffer_limit(irp, buffer, length, 0x7FFFFFFF);
161 }
162
163 static void sc_output_buffer_start_limit(IRP *irp, int length, int highLimit)
164 {
165         int header = (length < 0) ? (0) : ((length > highLimit) ? (highLimit) : (length));
166
167         stream_write_uint32(irp->output, header);
168         stream_write_uint32(irp->output, 0x00000001);   /* Magic DWORD - any non zero */
169 }
170
171 static void sc_output_buffer_start(IRP *irp, int length)
172 {
173         sc_output_buffer_start_limit(irp, length, 0x7FFFFFFF);
174 }
175
176 static uint32 sc_input_string(IRP* irp, char **dest, uint32 dataLength, boolean wide)
177 {
178         char *buffer;
179         int bufferSize;
180
181         bufferSize = wide ? (2 * dataLength) : dataLength;
182         buffer = xmalloc(bufferSize + 2); /* reserve 2 bytes for the '\0' */
183
184         stream_read(irp->input, buffer, bufferSize);
185         if (wide)
186         {
187                 int i;
188                 for (i = 0; i < dataLength; i++)
189                 {
190                         if ((buffer[2 * i] < 0) || (buffer[2 * i + 1] != 0))
191                                 buffer[i] = '?';
192                         else
193                                 buffer[i] = buffer[2 * i];
194                 }
195         }
196
197         buffer[dataLength] = '\0';
198         *dest = buffer;
199
200         return bufferSize;
201 }
202
203 static void sc_input_repos(IRP* irp, uint32 read)
204 {
205         uint32 add = 4 - (read % 4);
206
207         if (add < 4 && add > 0)
208                 stream_seek(irp->input, add);
209 }
210
211 static void sc_input_reader_name(IRP* irp, char **dest, boolean wide)
212 {
213         uint32 dataLength;
214
215         stream_seek(irp->input, 8);
216         stream_read_uint32(irp->input, dataLength);
217
218         DEBUG_SCARD("datalength %d", dataLength);
219         sc_input_repos(irp, sc_input_string(irp, dest, dataLength, wide));
220 }
221
222 static void sc_input_skip_linked(IRP* irp)
223 {
224         uint32 len;
225         stream_read_uint32(irp->input, len);
226
227         if (len > 0)
228         {
229                 stream_seek(irp->input, len);
230                 sc_input_repos(irp, len);
231         }
232 }
233
234 static uint32 sc_map_state(uint32 state)
235 {
236         /* is this mapping still needed? */
237
238         if (state & SCARD_SPECIFIC)
239                 state = 0x00000006;
240         else if (state & SCARD_NEGOTIABLE)
241                 state = 0x00000005;
242         else if (state & SCARD_POWERED)
243                 state = 0x00000004;
244         else if (state & SCARD_SWALLOWED)
245                 state = 0x00000003;
246         else if (state & SCARD_PRESENT)
247                 state = 0x00000002;
248         else if (state & SCARD_ABSENT)
249                 state = 0x00000001;
250         else
251                 state = 0x00000000;
252
253         return state;
254 }
255
256 static uint32 handle_EstablishContext(IRP* irp)
257 {
258         uint32 len, rv;
259         uint32 scope;
260         SCARDCONTEXT hContext = -1;
261
262         stream_seek(irp->input, 8);
263         stream_read_uint32(irp->input, len);
264
265         if (len != 8)
266                 return SCARD_F_INTERNAL_ERROR;
267
268         stream_seek_uint32(irp->input);
269         stream_read_uint32(irp->input, scope);
270
271         rv = SCardEstablishContext(scope, NULL, NULL, &hContext);
272
273         stream_write_uint32(irp->output, 4);    // ?
274         stream_write_uint32(irp->output, -1);   // ?
275
276         stream_write_uint32(irp->output, 4);
277         stream_write_uint32(irp->output, hContext);
278
279         /* TODO: store hContext in allowed context list */
280
281         return SCARD_S_SUCCESS;
282 }
283
284 static uint32 handle_ReleaseContext(IRP* irp)
285 {
286         uint32 len, rv;
287         SCARDCONTEXT hContext = -1;
288
289         stream_seek(irp->input, 8);
290         stream_read_uint32(irp->input, len);
291
292         stream_seek(irp->input, 0x10);
293         stream_read_uint32(irp->input, hContext);
294
295         rv = SCardReleaseContext(hContext);
296         if (rv)
297                 DEBUG_SCARD("%s (0x%08x)", pcsc_stringify_error(rv), (unsigned) rv);
298         else
299                 DEBUG_SCARD("success 0x%08lx", hContext);
300
301         return rv;
302 }
303
304 static uint32 handle_IsValidContext(IRP* irp)
305 {
306         uint32 rv;
307         SCARDCONTEXT hContext;
308
309         stream_seek(irp->input, 0x1C);
310         stream_read_uint32(irp->input, hContext);
311
312         rv = SCardIsValidContext(hContext);
313
314         if (rv)
315                 DEBUG_SCARD("Failure: %s (0x%08x)", pcsc_stringify_error(rv), (unsigned) rv);
316         else
317                 DEBUG_SCARD("Success context: 0x%08x", (unsigned) hContext);
318
319         stream_write_uint32(irp->output, rv);
320
321         return rv;
322 }
323
324 static uint32 handle_ListReaders(IRP* irp, boolean wide)
325 {
326         uint32 len, rv;
327         SCARDCONTEXT hContext;
328         DWORD dwReaders;
329         char *readerList = NULL, *walker;
330         int elemLength, dataLength;
331         int pos, poslen1, poslen2;
332
333         stream_seek(irp->input, 8);
334         stream_read_uint32(irp->input, len);
335
336         stream_seek(irp->input, 0x1c);
337         stream_read_uint32(irp->input, len);
338
339         if (len != 4)
340                 return SCARD_F_INTERNAL_ERROR;
341
342         stream_read_uint32(irp->input, hContext);
343
344         /* ignore rest of [MS-RDPESC] 2.2.2.4 ListReaders_Call */
345
346         rv = SCARD_S_SUCCESS;
347 #ifdef SCARD_AUTOALLOCATE
348         dwReaders = SCARD_AUTOALLOCATE;
349         rv = SCardListReaders(hContext, NULL, (LPSTR) &readerList, &dwReaders);
350 #else
351         rv = SCardListReaders(hContext, NULL, NULL, &dwReaders);
352
353         readerList = xmalloc(dwReaders);
354         rv = SCardListReaders(hContext, NULL, readerList, &dwReaders);
355 #endif
356         if (rv != SCARD_S_SUCCESS)
357         {
358                 DEBUG_SCARD("Failure: %s (0x%08x)", pcsc_stringify_error(rv), (unsigned) rv);
359                 return rv;
360         }
361
362 /*      DEBUG_SCARD("Success 0x%08x %d %d", (unsigned) hContext, (unsigned) cchReaders, (int) strlen(readerList));*/
363
364         poslen1 = stream_get_pos(irp->output);
365         stream_seek_uint32(irp->output);
366
367         stream_write_uint32(irp->output, 0x01760650);
368
369         poslen2 = stream_get_pos(irp->output);
370         stream_seek_uint32(irp->output);
371
372         walker = readerList;
373         dataLength = 0;
374
375         while (1)
376         {
377                 elemLength = strlen(walker);
378                 if (elemLength == 0)
379                         break;
380
381                 dataLength += sc_output_string(irp, walker, wide);
382                 walker += elemLength + 1;
383                 elemLength = strlen(walker);
384         }
385
386         dataLength += sc_output_string(irp, "\0", wide);
387
388         pos = stream_get_pos(irp->output);
389
390         stream_set_pos(irp->output, poslen1);
391         stream_write_uint32(irp->output, dataLength);
392         stream_set_pos(irp->output, poslen2);
393         stream_write_uint32(irp->output, dataLength);
394
395         stream_set_pos(irp->output, pos);
396
397         sc_output_repos(irp, dataLength);
398         sc_output_alignment(irp, 8);
399
400 #ifdef SCARD_AUTOALLOCATE
401         SCardFreeMemory(hContext, readerList);
402 #else
403         xfree(readerList);
404 #endif
405
406         return rv;
407 }
408
409 static uint32 handle_GetStatusChange(IRP* irp, boolean wide)
410 {
411         LONG rv;
412         SCARDCONTEXT hContext;
413         DWORD dwTimeout = 0;
414         DWORD readerCount = 0;
415         SCARD_READERSTATE *readerStates, *cur;
416         int i;
417
418         stream_seek(irp->input, 0x18);
419         stream_read_uint32(irp->input, dwTimeout);
420         stream_read_uint32(irp->input, readerCount);
421
422         stream_seek(irp->input, 8);
423
424         stream_read_uint32(irp->input, hContext);
425
426         stream_seek(irp->input, 4);
427
428         DEBUG_SCARD("context: 0x%08x, timeout: 0x%08x, count: %d",
429                      (unsigned) hContext, (unsigned) dwTimeout, (int) readerCount);
430         if (readerCount > 0)
431         {
432                 readerStates = xzalloc(readerCount * sizeof(SCARD_READERSTATE));
433                 if (!readerStates)
434                         return sc_output_return(irp, SCARD_E_NO_MEMORY);
435
436
437                 for (i = 0; i < readerCount; i++)
438                 {
439                         cur = &readerStates[i];
440
441                         stream_seek(irp->input, 4);
442
443                         /*
444                          * TODO: on-wire is little endian; need to either
445                          * convert to host endian or fix the headers to
446                          * request the order we want
447                          */
448                         stream_read_uint32(irp->input, cur->dwCurrentState);
449                         stream_read_uint32(irp->input, cur->dwEventState);
450                         stream_read_uint32(irp->input, cur->cbAtr);
451                         stream_read(irp->input, cur->rgbAtr, 32);
452
453                         stream_seek(irp->input, 4);
454
455                         /* reset high bytes? */
456                         cur->dwCurrentState &= 0x0000FFFF;
457                         cur->dwEventState &= 0x0000FFFF;
458                         cur->dwEventState = 0;
459                 }
460
461                 for (i = 0; i < readerCount; i++)
462                 {
463                         cur = &readerStates[i];
464                         uint32 dataLength;
465
466                         stream_seek(irp->input, 8);
467                         stream_read_uint32(irp->input, dataLength);
468                         sc_input_repos(irp, sc_input_string(irp, (char **) &cur->szReader, dataLength, wide));
469
470                         DEBUG_SCARD("   \"%s\"", cur->szReader ? cur->szReader : "NULL");
471                         DEBUG_SCARD("       user: 0x%08x, state: 0x%08x, event: 0x%08x",
472                                 (unsigned) cur->pvUserData, (unsigned) cur->dwCurrentState,
473                                 (unsigned) cur->dwEventState);
474
475                         if (strcmp(cur->szReader, "\\\\?PnP?\\Notification") == 0)
476                                 cur->dwCurrentState |= SCARD_STATE_IGNORE;
477                 }
478         }
479         else
480         {
481                 readerStates = NULL;
482         }
483
484         rv = SCardGetStatusChange(hContext, (DWORD) dwTimeout, readerStates, (DWORD) readerCount);
485
486         if (rv != SCARD_S_SUCCESS)
487                 DEBUG_SCARD("Failure: %s (0x%08x)", pcsc_stringify_error(rv), (unsigned) rv);
488         else
489                 DEBUG_SCARD("Success");
490
491         stream_write_uint32(irp->output, readerCount);
492         stream_write_uint32(irp->output, 0x00084dd8);
493         stream_write_uint32(irp->output, readerCount);
494
495         for (i = 0; i < readerCount; i++)
496         {
497                 cur = &readerStates[i];
498
499                 DEBUG_SCARD("   \"%s\"", cur->szReader ? cur->szReader : "NULL");
500                 DEBUG_SCARD("       user: 0x%08x, state: 0x%08x, event: 0x%08x\n",
501                         (unsigned) cur->pvUserData, (unsigned) cur->dwCurrentState,
502                         (unsigned) cur->dwEventState);
503
504                 /* TODO: do byte conversions if necessary */
505                 stream_write_uint32(irp->output, cur->dwCurrentState);
506                 stream_write_uint32(irp->output, cur->dwEventState);
507                 stream_write_uint32(irp->output, cur->cbAtr);
508                 stream_write(irp->output, cur->rgbAtr, 32);
509
510                 stream_write_zero(irp->output, 4);
511
512                 xfree((void *)cur->szReader);
513         }
514
515         sc_output_alignment(irp, 8);
516
517         xfree(readerStates);
518         return rv;
519 }
520
521 static uint32 handle_Cancel(IRP *irp)
522 {
523         LONG rv;
524         SCARDCONTEXT hContext;
525
526         stream_seek(irp->input, 0x1C);
527         stream_read_uint32(irp->input, hContext);
528
529         rv = SCardCancel(hContext);
530
531         if (rv != SCARD_S_SUCCESS)
532                 DEBUG_SCARD("Failure: %s (0x%08x)\n", pcsc_stringify_error(rv), (unsigned) rv);
533         else
534                 DEBUG_SCARD("Success context: 0x%08x %s\n", (unsigned) hContext, pcsc_stringify_error(rv));
535
536         sc_output_alignment(irp, 8);
537
538         return rv;
539 }
540
541 static uint32 handle_Connect(IRP* irp, boolean wide)
542 {
543         LONG rv;
544         SCARDCONTEXT hContext;
545         char *readerName = NULL;
546         DWORD dwShareMode = 0;
547         DWORD dwPreferredProtocol = 0;
548         DWORD dwActiveProtocol = 0;
549         SCARDHANDLE hCard;
550
551         stream_seek(irp->input, 0x1c);
552         stream_read_uint32(irp->input, dwShareMode);
553         stream_read_uint32(irp->input, dwPreferredProtocol);
554
555         sc_input_reader_name(irp, &readerName, wide);
556
557         stream_seek(irp->input, 4);
558         stream_read_uint32(irp->input, hContext);
559
560         DEBUG_SCARD("(context: 0x%08x, share: 0x%08x, proto: 0x%08x, reader: \"%s\")",
561                 (unsigned) hContext, (unsigned) dwShareMode,
562                 (unsigned) dwPreferredProtocol, readerName ? readerName : "NULL");
563
564         rv = SCardConnect(hContext, readerName, (DWORD) dwShareMode,
565                 (DWORD) dwPreferredProtocol, &hCard, (DWORD *) &dwActiveProtocol);
566
567         if (rv != SCARD_S_SUCCESS)
568                 DEBUG_SCARD("Failure: %s 0x%08x", pcsc_stringify_error(rv), (unsigned) rv);
569         else
570                 DEBUG_SCARD("Success 0x%08x", (unsigned) hCard);
571
572         stream_write_uint32(irp->output, 0x00000000);
573         stream_write_uint32(irp->output, 0x00000000);
574         stream_write_uint32(irp->output, 0x00000004);
575         stream_write_uint32(irp->output, 0x016Cff34);
576         stream_write_uint32(irp->output, dwActiveProtocol);
577         stream_write_uint32(irp->output, 0x00000004);
578         stream_write_uint32(irp->output, hCard);
579         stream_seek(irp->output, 28);
580
581         sc_output_alignment(irp, 8);
582
583         xfree(readerName);
584         return rv;
585 }
586
587 static uint32 handle_Reconnect(IRP* irp)
588 {
589         LONG rv;
590         SCARDCONTEXT hContext;
591         SCARDHANDLE hCard;
592         DWORD dwShareMode = 0;
593         DWORD dwPreferredProtocol = 0;
594         DWORD dwInitialization = 0;
595         DWORD dwActiveProtocol = 0;
596
597         stream_seek(irp->input, 0x20);
598         stream_read_uint32(irp->input, dwShareMode);
599         stream_read_uint32(irp->input, dwPreferredProtocol);
600         stream_read_uint32(irp->input, dwInitialization);
601
602         stream_seek(irp->input, 0x4);
603         stream_read_uint32(irp->input, hContext);
604         stream_seek(irp->input, 0x4);
605         stream_read_uint32(irp->input, hCard);
606
607         DEBUG_SCARD("(context: 0x%08x, hcard: 0x%08x, share: 0x%08x, proto: 0x%08x, init: 0x%08x)",
608                 (unsigned) hContext, (unsigned) hCard,
609                 (unsigned) dwShareMode, (unsigned) dwPreferredProtocol, (unsigned) dwInitialization);
610
611         rv = SCardReconnect(hCard, (DWORD) dwShareMode, (DWORD) dwPreferredProtocol,
612             (DWORD) dwInitialization, (LPDWORD) &dwActiveProtocol);
613
614         if (rv != SCARD_S_SUCCESS)
615                 DEBUG_SCARD("Failure: %s (0x%08x)", pcsc_stringify_error(rv), (unsigned) rv);
616         else
617                 DEBUG_SCARD("Success (proto: 0x%08x)", (unsigned) dwActiveProtocol);
618
619         sc_output_alignment(irp, 8);
620         stream_write_uint32(irp->output, dwActiveProtocol); /* reversed? */
621
622         return rv;
623 }
624
625 static uint32 handle_Disconnect(IRP* irp)
626 {
627         LONG rv;
628         SCARDCONTEXT hContext;
629         SCARDHANDLE hCard;
630         DWORD dwDisposition = 0;
631
632         stream_seek(irp->input, 0x20);
633         stream_read_uint32(irp->input, dwDisposition);
634         stream_seek(irp->input, 4);
635         stream_read_uint32(irp->input, hContext);
636         stream_seek(irp->input, 4);
637         stream_read_uint32(irp->input, hCard);
638
639         DEBUG_SCARD("(context: 0x%08x, hcard: 0x%08x, disposition: 0x%08x)",
640                 (unsigned) hContext, (unsigned) hCard, (unsigned) dwDisposition);
641
642         rv = SCardDisconnect(hCard, (DWORD) dwDisposition);
643
644         if (rv != SCARD_S_SUCCESS)
645                 DEBUG_SCARD("Failure: %s (0x%08x)", pcsc_stringify_error(rv), (unsigned) rv);
646         else
647                 DEBUG_SCARD("Success");
648
649         sc_output_alignment(irp, 8);
650
651         return rv;
652 }
653
654 static uint32 handle_BeginTransaction(IRP* irp)
655 {
656         LONG rv;
657         SCARDCONTEXT hCard;
658
659         stream_seek(irp->input, 0x30);
660         stream_read_uint32(irp->input, hCard);
661
662         rv = SCardBeginTransaction(hCard);
663
664         if (rv != SCARD_S_SUCCESS)
665                 DEBUG_SCARD("Failure: %s (0x%08x)", pcsc_stringify_error(rv), (unsigned) rv);
666         else
667                 DEBUG_SCARD("Success hcard: 0x%08x", (unsigned) hCard);
668
669         sc_output_alignment(irp, 8);
670
671         return rv;
672 }
673
674 static uint32 handle_EndTransaction(IRP* irp)
675 {
676         LONG rv;
677         SCARDCONTEXT hCard;
678         DWORD dwDisposition = 0;
679
680         stream_seek(irp->input, 0x20);
681         stream_read_uint32(irp->input, dwDisposition);
682
683         stream_seek(irp->input, 0x0C);
684         stream_read_uint32(irp->input, hCard);
685
686         rv = SCardEndTransaction(hCard, dwDisposition);
687
688         if (rv != SCARD_S_SUCCESS)
689                 DEBUG_SCARD("Failure: %s (0x%08x)", pcsc_stringify_error(rv), (unsigned) rv);
690         else
691                 DEBUG_SCARD("Success hcard: 0x%08x", (unsigned) hCard);
692
693         sc_output_alignment(irp, 8);
694
695         return rv;
696 }
697
698 static uint32 handle_State(IRP* irp)
699 {
700         LONG rv;
701         SCARDHANDLE hCard;
702         DWORD state = 0, protocol = 0;
703         DWORD readerLen;
704         DWORD atrLen = MAX_ATR_SIZE;
705         char * readerName;
706         BYTE pbAtr[MAX_ATR_SIZE];
707
708 #ifdef WITH_DEBUG_SCARD
709         int i;
710 #endif
711
712         stream_seek(irp->input, 0x24);
713         stream_seek_uint32(irp->input); /* atrLen */
714
715         stream_seek(irp->input, 0x0c);
716         stream_read_uint32(irp->input, hCard);
717         stream_seek(irp->input, 0x04);
718
719 #ifdef SCARD_AUTOALLOCATE
720         readerLen = SCARD_AUTOALLOCATE;
721
722         rv = SCardStatus(hCard, (LPSTR) &readerName, &readerLen, &state, &protocol, pbAtr, &atrLen);
723 #else
724         readerLen = 256;
725         readerName = xmalloc(readerLen);
726
727         rv = SCardStatus(hCard, (LPSTR) readerName, &readerLen, &state, &protocol, pbAtr, &atrLen);
728 #endif
729
730         if (rv != SCARD_S_SUCCESS)
731         {
732                 DEBUG_SCARD("Failure: %s (0x%08x)", pcsc_stringify_error(rv), (unsigned) rv);
733                 return sc_output_return(irp, rv);
734         }
735
736         DEBUG_SCARD("Success (hcard: 0x%08x len: %d state: 0x%08x, proto: 0x%08x)",
737                 (unsigned) hCard, (int) atrLen, (unsigned) state, (unsigned) protocol);
738
739 #ifdef WITH_DEBUG_SCARD
740         printf("       ATR: ");
741         for (i = 0; i < atrLen; i++)
742                 printf("%02x%c", pbAtr[i], (i == atrLen - 1) ? ' ' : ':');
743         printf("\n");
744 #endif
745
746         state = sc_map_state(state);
747
748         stream_write_uint32(irp->output, state);
749         stream_write_uint32(irp->output, protocol);
750         stream_write_uint32(irp->output, atrLen);
751         stream_write_uint32(irp->output, 0x00000001);
752         stream_write_uint32(irp->output, atrLen);
753         stream_write(irp->output, pbAtr, atrLen);
754
755         sc_output_repos(irp, atrLen);
756         sc_output_alignment(irp, 8);
757
758 #ifdef SCARD_AUTOALLOCATE
759         xfree(readerName);
760 #else
761         xfree(readerName);
762 #endif
763
764         return rv;
765 }
766
767 static DWORD handle_Status(IRP *irp, boolean wide)
768 {
769         LONG rv;
770         SCARDHANDLE hCard;
771         DWORD state, protocol;
772         DWORD readerLen = 0;
773         DWORD atrLen = 0;
774         char * readerName;
775         BYTE pbAtr[MAX_ATR_SIZE];
776         uint32 dataLength;
777         int pos, poslen1, poslen2;
778
779 #ifdef WITH_DEBUG_SCARD
780         int i;
781 #endif
782
783         stream_seek(irp->input, 0x24);
784         stream_read_uint32(irp->input, readerLen);
785         stream_read_uint32(irp->input, atrLen);
786         stream_seek(irp->input, 0x0c);
787         stream_read_uint32(irp->input, hCard);
788         stream_seek(irp->input, 0x4);
789
790         atrLen = MAX_ATR_SIZE;
791
792 #ifdef SCARD_AUTOALLOCATE
793         readerLen = SCARD_AUTOALLOCATE;
794
795         rv = SCardStatus(hCard, (LPSTR) &readerName, &readerLen, &state, &protocol, pbAtr, &atrLen);
796 #else
797         readerLen = 256;
798         readerName = xmalloc(readerLen);
799
800         rv = SCardStatus(hCard, (LPSTR) readerName, &readerLen, &state, &protocol, pbAtr, &atrLen);
801 #endif
802
803         if (rv != SCARD_S_SUCCESS)
804         {
805                 DEBUG_SCARD("Failure: %s (0x%08x)", pcsc_stringify_error(rv), (unsigned) rv);
806                 return sc_output_return(irp, rv);
807         }
808
809         DEBUG_SCARD("Success (state: 0x%08x, proto: 0x%08x)", (unsigned) state, (unsigned) protocol);
810         DEBUG_SCARD("       Reader: \"%s\"", readerName ? readerName : "NULL");
811
812 #ifdef WITH_DEBUG_SCARD
813         printf("       ATR: ");
814         for (i = 0; i < atrLen; i++)
815                 printf("%02x%c", pbAtr[i], (i == atrLen - 1) ? ' ' : ':');
816         printf("\n");
817 #endif
818
819         state = sc_map_state(state);
820
821         poslen1 = stream_get_pos(irp->output);
822         stream_write_uint32(irp->output, readerLen);
823         stream_write_uint32(irp->output, 0x00020000);
824         stream_write_uint32(irp->output, state);
825         stream_write_uint32(irp->output, protocol);
826         stream_write(irp->output, pbAtr, atrLen);
827
828         if (atrLen < 32)
829                 stream_write_zero(irp->output, 32 - atrLen);
830         stream_write_uint32(irp->output, atrLen);
831
832         poslen2 = stream_get_pos(irp->output);
833         stream_write_uint32(irp->output, readerLen);
834
835         dataLength = sc_output_string(irp, readerName, wide);
836         dataLength += sc_output_string(irp, "\0", wide);
837         sc_output_repos(irp, dataLength);
838
839         pos = stream_get_pos(irp->output);
840         stream_set_pos(irp->output, poslen1);
841         stream_write_uint32(irp->output,dataLength);
842         stream_set_pos(irp->output, poslen2);
843         stream_write_uint32(irp->output,dataLength);
844         stream_set_pos(irp->output, pos);
845
846         sc_output_alignment(irp, 8);
847
848 #ifdef SCARD_AUTOALLOCATE
849         /* SCardFreeMemory(NULL, readerName); */
850         free(readerName);
851 #else
852         xfree(readerName);
853 #endif
854
855         return rv;
856 }
857
858 static uint32 handle_Transmit(IRP* irp)
859 {
860         LONG rv;
861         SCARDCONTEXT hCard;
862         uint32 map[7], linkedLen;
863         SCARD_IO_REQUEST pioSendPci, pioRecvPci, *pPioRecvPci;
864         DWORD cbSendLength = 0, cbRecvLength = 0;
865         BYTE *sendBuf = NULL, *recvBuf = NULL;
866
867         stream_seek(irp->input, 0x14);
868         stream_read_uint32(irp->input, map[0]);
869         stream_seek(irp->input, 0x4);
870         stream_read_uint32(irp->input, map[1]);
871
872         stream_read_uint32(irp->input, pioSendPci.dwProtocol);
873         stream_read_uint32(irp->input, pioSendPci.cbPciLength);
874
875         stream_read_uint32(irp->input, map[2]);
876         stream_read_uint32(irp->input, cbSendLength);
877         stream_read_uint32(irp->input, map[3]);
878         stream_read_uint32(irp->input, map[4]);
879         stream_read_uint32(irp->input, map[5]);
880         stream_read_uint32(irp->input, cbRecvLength);
881
882         if (map[0] & SCARD_INPUT_LINKED)
883                 sc_input_skip_linked(irp);
884
885         stream_seek(irp->input, 4);
886         stream_read_uint32(irp->input, hCard);
887
888         if (map[2] & SCARD_INPUT_LINKED)
889         {
890                 /* sendPci */
891                 stream_read_uint32(irp->input, linkedLen);
892
893                 stream_read_uint32(irp->input, pioSendPci.dwProtocol);
894                 stream_seek(irp->input, linkedLen - 4);
895
896                 sc_input_repos(irp, linkedLen);
897         }
898         pioSendPci.cbPciLength = sizeof(SCARD_IO_REQUEST);
899
900         if (map[3] & SCARD_INPUT_LINKED)
901         {
902                 /* send buffer */
903                 stream_read_uint32(irp->input, linkedLen);
904
905                 sendBuf = xmalloc(linkedLen);
906                 stream_read(irp->input, sendBuf, linkedLen);
907                 sc_input_repos(irp, linkedLen);
908         }
909
910         if (cbRecvLength)
911                 recvBuf = xmalloc(cbRecvLength);
912
913         if (map[4] & SCARD_INPUT_LINKED)
914         {
915                 /* recvPci */
916                 stream_read_uint32(irp->input, linkedLen);
917
918                 stream_read_uint32(irp->input, pioRecvPci.dwProtocol);
919                 stream_seek(irp->input, linkedLen - 4);
920
921                 sc_input_repos(irp, linkedLen);
922
923                 stream_read_uint32(irp->input, map[6]);
924                 if (map[6] & SCARD_INPUT_LINKED)
925                 {
926                         /* not sure what this is */
927                         stream_read_uint32(irp->input, linkedLen);
928                         stream_seek(irp->input, linkedLen);
929
930                         sc_input_repos(irp, linkedLen);
931                 }
932                 pioRecvPci.cbPciLength = sizeof(SCARD_IO_REQUEST);
933                 pPioRecvPci = &pioRecvPci;
934         }
935         else
936         {
937                 pPioRecvPci = NULL;
938         }
939         pPioRecvPci = NULL;
940
941         DEBUG_SCARD("SCardTransmit(hcard: 0x%08lx, send: %d bytes, recv: %d bytes)",
942                 (long unsigned) hCard, (int) cbSendLength, (int) cbRecvLength);
943
944         rv = SCardTransmit(hCard, &pioSendPci, sendBuf, cbSendLength,
945                            pPioRecvPci, recvBuf, &cbRecvLength);
946
947         if (rv != SCARD_S_SUCCESS)
948         {
949                 DEBUG_SCARD("Failure: %s (0x%08x)", pcsc_stringify_error(rv), (unsigned) rv);
950         }
951         else
952         {
953                 DEBUG_SCARD("Success (%d bytes)", (int) cbRecvLength);
954
955                 stream_write_uint32(irp->output, 0);    /* pioRecvPci 0x00; */
956
957                 sc_output_buffer_start(irp, cbRecvLength);      /* start of recvBuf output */
958
959                 sc_output_buffer(irp, (char *) recvBuf, cbRecvLength);
960         }
961
962         sc_output_alignment(irp, 8);
963
964         xfree(sendBuf);
965         xfree(recvBuf);
966
967         return rv;
968 }
969
970 static uint32 handle_Control(IRP* irp)
971 {
972         LONG rv;
973         SCARDCONTEXT hContext;
974         SCARDHANDLE hCard;
975         uint32 map[3];
976         uint32 controlCode;
977         uint32 controlFunction;
978         BYTE *recvBuffer = NULL, *sendBuffer = NULL;
979         uint32 recvLength;
980         DWORD nBytesReturned;
981         DWORD outBufferSize;
982
983         stream_seek(irp->input, 0x14);
984         stream_read_uint32(irp->input, map[0]);
985         stream_seek(irp->input, 0x4);
986         stream_read_uint32(irp->input, map[1]);
987         stream_read_uint32(irp->input, controlCode);
988         stream_read_uint32(irp->input, recvLength);
989         stream_read_uint32(irp->input, map[2]);
990         stream_seek(irp->input, 0x4);
991         stream_read_uint32(irp->input, outBufferSize);
992         stream_seek(irp->input, 0x4);
993         stream_read_uint32(irp->input, hContext);
994         stream_seek(irp->input, 0x4);
995         stream_read_uint32(irp->input, hCard);
996
997         /* Translate Windows SCARD_CTL_CODE's to corresponding local code */
998         if (WIN_CTL_DEVICE_TYPE(controlCode) == WIN_FILE_DEVICE_SMARTCARD)
999         {
1000                 controlFunction = WIN_CTL_FUNCTION(controlCode);
1001                 controlCode = SCARD_CTL_CODE(controlFunction);
1002         }
1003         DEBUG_SCARD("controlCode: 0x%08x", (unsigned) controlCode);
1004
1005         if (map[2] & SCARD_INPUT_LINKED)
1006         {
1007                 /* read real input size */
1008                 stream_read_uint32(irp->input, recvLength);
1009
1010                 recvBuffer = xmalloc(recvLength);
1011
1012                 if (!recvBuffer)
1013                         return sc_output_return(irp, SCARD_E_NO_MEMORY);
1014
1015                 stream_read(irp->input, recvBuffer, recvLength);
1016         }
1017
1018         nBytesReturned = outBufferSize;
1019         sendBuffer = xmalloc(outBufferSize);
1020
1021         if (!sendBuffer)
1022                 return sc_output_return(irp, SCARD_E_NO_MEMORY);
1023
1024         rv = SCardControl(hCard, (DWORD) controlCode, recvBuffer, (DWORD) recvLength,
1025                 sendBuffer, (DWORD) outBufferSize, &nBytesReturned);
1026
1027         if (rv != SCARD_S_SUCCESS)
1028                 DEBUG_SCARD("Failure: %s (0x%08x)", pcsc_stringify_error(rv), (unsigned) rv);
1029         else
1030                 DEBUG_SCARD("Success (out: %u bytes)", (unsigned) nBytesReturned);
1031
1032         stream_write_uint32(irp->output, (uint32) nBytesReturned);
1033         stream_write_uint32(irp->output, 0x00000004);
1034         stream_write_uint32(irp->output, nBytesReturned);
1035
1036         if (nBytesReturned > 0)
1037         {
1038                 stream_write(irp->output, sendBuffer, nBytesReturned);
1039                 sc_output_repos(irp, nBytesReturned);
1040         }
1041
1042         sc_output_alignment(irp, 8);
1043
1044         xfree(recvBuffer);
1045         xfree(sendBuffer);
1046
1047         return rv;
1048 }
1049
1050 static uint32 handle_GetAttrib(IRP* irp)
1051 {
1052         LONG rv;
1053         SCARDHANDLE hCard;
1054         DWORD dwAttrId = 0, dwAttrLen = 0;
1055         DWORD attrLen = 0;
1056         uint8* pbAttr = NULL;
1057
1058         stream_seek(irp->input, 0x20);
1059         stream_read_uint32(irp->input, dwAttrId);
1060         stream_seek(irp->input, 0x4);
1061         stream_read_uint32(irp->input, dwAttrLen);
1062         stream_seek(irp->input, 0xC);
1063         stream_read_uint32(irp->input, hCard);
1064
1065         DEBUG_SCARD("hcard: 0x%08x, attrib: 0x%08x (%d bytes)\n",
1066                 (unsigned) hCard, (unsigned) dwAttrId, (int) dwAttrLen);
1067
1068 #ifdef SCARD_AUTOALLOCATE
1069         if(dwAttrLen == 0)
1070         {
1071                 attrLen = 0;
1072         }
1073         else
1074         {
1075                 attrLen = SCARD_AUTOALLOCATE;
1076         }
1077 #endif
1078
1079         rv = SCardGetAttrib(hCard, dwAttrId, attrLen == 0 ? NULL : (uint8*) &pbAttr, &attrLen);
1080         if( rv != SCARD_S_SUCCESS ) {
1081 #ifdef SCARD_AUTOALLOCATE
1082                 if(dwAttrLen == 0)
1083                 {
1084                         attrLen = 0;
1085                 }
1086                 else
1087                 {
1088                         attrLen = SCARD_AUTOALLOCATE;
1089                 }
1090 #endif
1091         }
1092
1093         if(dwAttrId == SCARD_ATTR_DEVICE_FRIENDLY_NAME_A && rv == SCARD_E_UNSUPPORTED_FEATURE)
1094         {
1095                 rv = SCardGetAttrib(hCard, SCARD_ATTR_DEVICE_FRIENDLY_NAME_W,
1096                         attrLen == 0 ? NULL : (uint8*) &pbAttr, &attrLen);
1097                 if( rv != SCARD_S_SUCCESS ) {
1098 #ifdef SCARD_AUTOALLOCATE
1099                         if(dwAttrLen == 0)
1100                         {
1101                                 attrLen = 0;
1102                         }
1103                         else
1104                         {
1105                                 attrLen = SCARD_AUTOALLOCATE;
1106                         }
1107 #endif
1108                 }
1109         }
1110         if(dwAttrId == SCARD_ATTR_DEVICE_FRIENDLY_NAME_W && rv == SCARD_E_UNSUPPORTED_FEATURE)
1111         {
1112                 rv = SCardGetAttrib(hCard, SCARD_ATTR_DEVICE_FRIENDLY_NAME_A,
1113                         attrLen == 0 ? NULL : (uint8*) &pbAttr, &attrLen);
1114                 if( rv != SCARD_S_SUCCESS ) {
1115 #ifdef SCARD_AUTOALLOCATE
1116                         if(dwAttrLen == 0)
1117                         {
1118                                 attrLen = 0;
1119                         }
1120                         else
1121                         {
1122                                 attrLen = SCARD_AUTOALLOCATE;
1123                         }
1124 #endif
1125                 }
1126         }
1127         if(attrLen > dwAttrLen && pbAttr != NULL)
1128         {
1129                 rv = SCARD_E_INSUFFICIENT_BUFFER;
1130         }
1131         dwAttrLen = attrLen;
1132
1133         if (rv != SCARD_S_SUCCESS)
1134         {
1135                 DEBUG_SCARD("Failure: %s (0x%08x)", pcsc_stringify_error(rv), (unsigned int) rv);
1136                 free(pbAttr);
1137                 return sc_output_return(irp, rv);
1138         }
1139         else
1140         {
1141                 DEBUG_SCARD("Success (%d bytes)", (int) dwAttrLen);
1142
1143                 stream_write_uint32(irp->output, dwAttrLen);
1144                 stream_write_uint32(irp->output, 0x00000200);
1145                 stream_write_uint32(irp->output, dwAttrLen);
1146
1147                 if (!pbAttr)
1148                 {
1149                         stream_write_zero(irp->output, dwAttrLen);
1150                 }
1151                 else
1152                 {
1153                         stream_write(irp->output, pbAttr, dwAttrLen);
1154                 }
1155                 sc_output_repos(irp, dwAttrLen);
1156                 /* align to multiple of 4 */
1157                 stream_write_uint32(irp->output, 0);
1158         }
1159         sc_output_alignment(irp, 8);
1160
1161         xfree(pbAttr);
1162
1163         return rv;
1164 }
1165
1166 static uint32 handle_AccessStartedEvent(IRP* irp)
1167 {
1168         stream_write_zero(irp->output, 8);
1169         return SCARD_S_SUCCESS;
1170 }
1171
1172 void scard_error(SCARD_DEVICE* scard, IRP* irp, uint32 ntstatus)
1173 {
1174         /* [MS-RDPESC] 3.1.4.4 */
1175         printf("scard processing error %x\n", ntstatus);
1176
1177         stream_set_pos(irp->output, 0); /* CHECKME */
1178         irp->IoStatus = ntstatus;
1179         irp->Complete(irp);
1180 }
1181
1182 /* http://msdn.microsoft.com/en-gb/library/ms938473.aspx */
1183 typedef struct _SERVER_SCARD_ATRMASK
1184 {
1185         uint32 cbAtr;
1186         uint8 rgbAtr[36];
1187         uint8 rgbMask[36];
1188 }
1189 SERVER_SCARD_ATRMASK;
1190
1191 static uint32 handle_LocateCardsByATR(IRP* irp, boolean wide)
1192 {
1193         LONG rv;
1194         int i, j, k;
1195         SCARDCONTEXT hContext;
1196         uint32 atrMaskCount = 0;
1197         uint32 readerCount = 0;
1198         SCARD_READERSTATE* cur = NULL;
1199         SCARD_READERSTATE* rsCur = NULL;
1200         SCARD_READERSTATE* readerStates = NULL;
1201         SERVER_SCARD_ATRMASK* curAtr = NULL;
1202         SERVER_SCARD_ATRMASK* pAtrMasks = NULL;
1203
1204         stream_seek(irp->input, 0x2C);
1205         stream_read_uint32(irp->input, hContext);
1206         stream_read_uint32(irp->input, atrMaskCount);
1207
1208         pAtrMasks = xmalloc(atrMaskCount * sizeof(SERVER_SCARD_ATRMASK));
1209
1210         if (!pAtrMasks)
1211                 return sc_output_return(irp, SCARD_E_NO_MEMORY);
1212
1213         for (i = 0; i < atrMaskCount; i++)
1214         {
1215                 stream_read_uint32(irp->input, pAtrMasks[i].cbAtr);
1216                 stream_read(irp->input, pAtrMasks[i].rgbAtr, 36);
1217                 stream_read(irp->input, pAtrMasks[i].rgbMask, 36);
1218         }
1219
1220         stream_read_uint32(irp->input, readerCount);
1221
1222         readerStates = xzalloc(readerCount * sizeof(SCARD_READERSTATE));
1223
1224         if (!readerStates)
1225                 return sc_output_return(irp, SCARD_E_NO_MEMORY);
1226
1227         for (i = 0; i < readerCount; i++)
1228         {
1229                 cur = &readerStates[i];
1230
1231                 stream_seek(irp->input, 4);
1232
1233                 /*
1234                  * TODO: on-wire is little endian; need to either
1235                  * convert to host endian or fix the headers to
1236                  * request the order we want
1237                  */
1238                 stream_read_uint32(irp->input, cur->dwCurrentState);
1239                 stream_read_uint32(irp->input, cur->dwEventState);
1240                 stream_read_uint32(irp->input, cur->cbAtr);
1241                 stream_read(irp->input, cur->rgbAtr, 32);
1242
1243                 stream_seek(irp->input, 4);
1244
1245                 /* reset high bytes? */
1246                 cur->dwCurrentState &= 0x0000FFFF;
1247                 cur->dwEventState &= 0x0000FFFF;
1248                 cur->dwEventState = 0;
1249         }
1250
1251         for (i = 0; i < readerCount; i++)
1252         {
1253                 cur = &readerStates[i];
1254                 uint32 dataLength;
1255
1256                 stream_seek(irp->input, 8);
1257                 stream_read_uint32(irp->input, dataLength);
1258                 sc_input_repos(irp, sc_input_string(irp, (char **) &cur->szReader, dataLength, wide));
1259
1260                 DEBUG_SCARD("   \"%s\"", cur->szReader ? cur->szReader : "NULL");
1261                 DEBUG_SCARD("       user: 0x%08x, state: 0x%08x, event: 0x%08x",
1262                                 (unsigned) cur->pvUserData, (unsigned) cur->dwCurrentState,
1263                                 (unsigned) cur->dwEventState);
1264
1265                 if (strcmp(cur->szReader, "\\\\?PnP?\\Notification") == 0)
1266                         cur->dwCurrentState |= SCARD_STATE_IGNORE;
1267         }
1268
1269         rv = SCardGetStatusChange(hContext, 0x00000001, readerStates, readerCount);
1270         if (rv != SCARD_S_SUCCESS)
1271         {
1272                 DEBUG_SCARD("Failure: %s (0x%08x)",
1273                         pcsc_stringify_error(rv), (unsigned) rv);
1274
1275                 return sc_output_return(irp, rv);
1276         }
1277
1278         DEBUG_SCARD("Success");
1279         for (i = 0, curAtr = pAtrMasks; i < atrMaskCount; i++, curAtr++)
1280         {
1281                 for (j = 0, rsCur = readerStates; j < readerCount; j++, rsCur++)
1282                 {
1283                         boolean equal = 1;
1284                         for (k = 0; k < cur->cbAtr; k++)
1285                         {
1286                                 if ((curAtr->rgbAtr[k] & curAtr->rgbMask[k]) !=
1287                                     (rsCur->rgbAtr[k] & curAtr->rgbMask[k]))
1288                                 {
1289                                         equal = 0;
1290                                         break;
1291                                 }
1292                         }
1293                         if (equal)
1294                         {
1295                                 rsCur->dwEventState |= 0x00000040;      /* SCARD_STATE_ATRMATCH 0x00000040 */
1296                         }
1297                 }
1298         }
1299
1300         stream_write_uint32(irp->output, readerCount);
1301         stream_write_uint32(irp->output, 0x00084dd8);
1302         stream_write_uint32(irp->output, readerCount);
1303
1304         for (i = 0, rsCur = readerStates; i < readerCount; i++, rsCur++)
1305         {
1306                 stream_write_uint32(irp->output, cur->dwCurrentState);
1307                 stream_write_uint32(irp->output, cur->dwEventState);
1308                 stream_write_uint32(irp->output, cur->cbAtr);
1309                 stream_write(irp->output, cur->rgbAtr, 32);
1310
1311                 stream_write_zero(irp->output, 4);
1312
1313                 xfree((void*) cur->szReader);
1314         }
1315
1316         sc_output_alignment(irp, 8);
1317
1318         free(readerStates);
1319
1320         return rv;
1321 }
1322
1323 boolean scard_async_op(IRP* irp)
1324 {
1325         uint32 ioctl_code;
1326
1327         /* peek ahead */
1328         stream_seek(irp->input, 8);
1329         stream_read_uint32(irp->input, ioctl_code);
1330         stream_rewind(irp->input, 12);
1331
1332         switch (ioctl_code)
1333         {
1334                 /* non-blocking events */
1335                 case SCARD_IOCTL_ACCESS_STARTED_EVENT:
1336
1337                 case SCARD_IOCTL_ESTABLISH_CONTEXT:
1338                 case SCARD_IOCTL_RELEASE_CONTEXT:
1339                 case SCARD_IOCTL_IS_VALID_CONTEXT:
1340
1341                         return false;
1342                         break;
1343
1344                 /* async events */
1345                 case SCARD_IOCTL_GET_STATUS_CHANGE:
1346                 case SCARD_IOCTL_GET_STATUS_CHANGE + 4:
1347
1348                 case SCARD_IOCTL_TRANSMIT:
1349
1350                 case SCARD_IOCTL_STATUS:
1351                 case SCARD_IOCTL_STATUS + 4:
1352                         return true;
1353                         break;
1354
1355                 default:
1356                         break;
1357         }       
1358
1359         /* default to async */
1360         return true;
1361 }
1362
1363 void scard_device_control(SCARD_DEVICE* scard, IRP* irp)
1364 {
1365         uint32 output_len, input_len, ioctl_code;
1366         uint32 stream_len, result;
1367         uint32 pos, pad_len;
1368         uint32 irp_len;
1369         uint32 irp_result_pos, output_len_pos, result_pos;
1370
1371         stream_read_uint32(irp->input, output_len);
1372         stream_read_uint32(irp->input, input_len);
1373         stream_read_uint32(irp->input, ioctl_code);
1374
1375         stream_seek(irp->input, 20);    /* padding */
1376
1377         // stream_seek(irp->input, 4);  /* TODO: parse len, le, v1 */
1378         // stream_seek(irp->input, 4);  /* 0xcccccccc */
1379         // stream_seek(irp->input, 4);  /* rpce len */
1380
1381         /* [MS-RDPESC] 3.2.5.1 Sending Outgoing Messages */
1382         stream_extend(irp->output, 2048);
1383
1384         irp_result_pos = stream_get_pos(irp->output);
1385
1386         stream_write_uint32(irp->output, 0x00081001); /* len 8, LE, v1 */
1387
1388         /* [MS-RPCE] 2.2.6.1 */
1389         stream_write_uint32(irp->output, 0x00081001); /* len 8, LE, v1 */
1390         stream_write_uint32(irp->output, 0xcccccccc); /* filler */
1391
1392         output_len_pos = stream_get_pos(irp->output);
1393         stream_seek(irp->output, 4);            /* size */
1394
1395         stream_write_uint32(irp->output, 0x0);  /* filler */
1396
1397         result_pos = stream_get_pos(irp->output);
1398         stream_seek(irp->output, 4);            /* result */
1399
1400         /* body */
1401         switch (ioctl_code)
1402         {
1403                 case SCARD_IOCTL_ESTABLISH_CONTEXT:
1404                         result = handle_EstablishContext(irp);
1405                         break;
1406
1407                 case SCARD_IOCTL_IS_VALID_CONTEXT:
1408                         result = handle_IsValidContext(irp);
1409                         break;
1410
1411                 case SCARD_IOCTL_RELEASE_CONTEXT:
1412                         result = handle_ReleaseContext(irp);
1413                         break;
1414
1415                 case SCARD_IOCTL_LIST_READERS:
1416                         result = handle_ListReaders(irp, 0);
1417                         break;
1418                 case SCARD_IOCTL_LIST_READERS + 4:
1419                         result = handle_ListReaders(irp, 1);
1420                         break;
1421
1422                 case SCARD_IOCTL_LIST_READER_GROUPS:
1423                 case SCARD_IOCTL_LIST_READER_GROUPS + 4:
1424                         /* typically not used unless list_readers fail */
1425                         result = SCARD_F_INTERNAL_ERROR;
1426                         break;
1427
1428                 case SCARD_IOCTL_GET_STATUS_CHANGE:
1429                         result = handle_GetStatusChange(irp, 0);
1430                         break;
1431                 case SCARD_IOCTL_GET_STATUS_CHANGE + 4:
1432                         result = handle_GetStatusChange(irp, 1);
1433                         break;
1434
1435                 case SCARD_IOCTL_CANCEL:
1436                         result = handle_Cancel(irp);
1437                         break;
1438
1439                 case SCARD_IOCTL_CONNECT:
1440                         result = handle_Connect(irp, 0);
1441                         break;
1442                 case SCARD_IOCTL_CONNECT + 4:
1443                         result = handle_Connect(irp, 1);
1444                         break;
1445
1446                 case SCARD_IOCTL_RECONNECT:
1447                         result = handle_Reconnect(irp);
1448                         break;
1449
1450                 case SCARD_IOCTL_DISCONNECT:
1451                         result = handle_Disconnect(irp);
1452                         break;
1453
1454                 case SCARD_IOCTL_BEGIN_TRANSACTION:
1455                         result = handle_BeginTransaction(irp);
1456                         break;
1457
1458                 case SCARD_IOCTL_END_TRANSACTION:
1459                         result = handle_EndTransaction(irp);
1460                         break;
1461
1462                 case SCARD_IOCTL_STATE:
1463                         result = handle_State(irp);
1464                         break;
1465
1466                 case SCARD_IOCTL_STATUS:
1467                         result = handle_Status(irp, 0);
1468                         break;
1469                 case SCARD_IOCTL_STATUS + 4:
1470                         result = handle_Status(irp, 1);
1471                         break;
1472
1473                 case SCARD_IOCTL_TRANSMIT:
1474                         result = handle_Transmit(irp);
1475                         break;
1476
1477                 case SCARD_IOCTL_CONTROL:
1478                         result = handle_Control(irp);
1479                         break;
1480
1481                 case SCARD_IOCTL_GETATTRIB:
1482                         result = handle_GetAttrib(irp);
1483                         break;
1484
1485                 case SCARD_IOCTL_ACCESS_STARTED_EVENT:
1486                         result = handle_AccessStartedEvent(irp);
1487                         break;
1488
1489                 case SCARD_IOCTL_LOCATE_CARDS_BY_ATR:
1490                         result = handle_LocateCardsByATR(irp, 0);
1491                         break;
1492                 case SCARD_IOCTL_LOCATE_CARDS_BY_ATR + 4:
1493                         result = handle_LocateCardsByATR(irp, 1);
1494                         break;
1495
1496                 default:
1497                         result = 0xc0000001;
1498                         printf("scard unknown ioctl 0x%x\n", ioctl_code);
1499                         break;
1500         }
1501
1502         /* look for NTSTATUS errors */
1503         if ((result & 0xc0000000) == 0xc0000000)
1504                 return scard_error(scard, irp, result);
1505
1506         /* per Ludovic Rousseau, map different usage of this particular
1507          * error code between pcsc-lite & windows */
1508         if (result == 0x8010001F)
1509                 result = 0x80100022;
1510
1511         /* handle response packet */
1512         pos = stream_get_pos(irp->output);
1513         stream_len = pos - irp_result_pos - 4;
1514
1515         stream_set_pos(irp->output, output_len_pos);
1516         stream_write_uint32(irp->output, stream_len - 24);
1517
1518         stream_set_pos(irp->output, result_pos);
1519         stream_write_uint32(irp->output, result);
1520
1521         stream_set_pos(irp->output, pos);
1522
1523         /* pad stream to 16 byte align */
1524         pad_len = stream_len % 16;
1525         stream_write_zero(irp->output, pad_len);
1526         pos = stream_get_pos(irp->output);
1527         irp_len = stream_len + pad_len;
1528
1529         stream_set_pos(irp->output, irp_result_pos);
1530         stream_write_uint32(irp->output, irp_len);
1531         stream_set_pos(irp->output, pos);
1532
1533 #ifdef WITH_DEBUG_SCARD
1534         freerdp_hexdump(stream_get_data(irp->output), stream_get_length(irp->output));
1535 #endif
1536         irp->IoStatus = 0;
1537
1538         irp->Complete(irp);
1539
1540 }