1/*
2 *  Copyright (c) 2000-2007 Apple Inc. All Rights Reserved.
3 *
4 *  @APPLE_LICENSE_HEADER_START@
5 *
6 *  This file contains Original Code and/or Modifications of Original Code
7 *  as defined in and that are subject to the Apple Public Source License
8 *  Version 2.0 (the 'License'). You may not use this file except in
9 *  compliance with the License. Please obtain a copy of the License at
10 *  http://www.opensource.apple.com/apsl/ and read it before using this
11 *  file.
12 *
13 *  The Original Code and all software distributed under the License are
14 *  distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 *  EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 *  INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 *  FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 *  Please see the License for the specific language governing rights and
19 *  limitations under the License.
20 *
21 *  @APPLE_LICENSE_HEADER_END@
22 */
23
24/*
25 *  winscard_clnt.c
26 *  SmartCardServices
27 */
28
29/*
30 * MUSCLE SmartCard Development ( http://www.linuxnet.com )
31 *
32 * Copyright (C) 1999-2004
33 *  David Corcoran <corcoran@linuxnet.com>
34 *  Damien Sauveron <damien.sauveron@labri.fr>
35 *  Ludovic Rousseau <ludovic.rousseau@free.fr>
36 *
37 * $Id: winscard_clnt.c 123 2010-03-27 10:50:42Z ludovic.rousseau@gmail.com $
38 */
39
40/**
41 * @file
42 * @brief This handles smartcard reader communications and
43 * forwarding requests over message queues.
44 *
45 * Here is exposed the API for client applications.
46 */
47
48#include <assert.h>
49#include "config.h"
50#include <stdlib.h>
51#include <string.h>
52#include <sys/types.h>
53#include <fcntl.h>
54#include <unistd.h>
55#include <sys/un.h>
56#include <errno.h>
57#include <sys/socket.h>
58#include <sys/ioctl.h>
59#include <sys/_endian.h>
60
61#include "wintypes.h"
62#include "pcsclite.h"
63#include "pcscexport.h"
64#include "winscard.h"
65#include "debug.h"
66#include "thread_generic.h"
67
68#include "readerfactory.h"
69#include "eventhandler.h"
70#include "sys_generic.h"
71#include "winscard_msg.h"
72#include "readerstate.h"
73
74#include <security_utilities/debugging.h>
75
76/** used for backward compatibility */
77#define SCARD_PROTOCOL_ANY_OLD	0x1000
78
79#ifndef min
80#define min(a,b) (((a) < (b)) ? (a) : (b))
81#endif
82
83#define PROFILE_START
84#define PROFILE_END
85
86/**
87 * Represents an Application Context Channel.
88 * A channel belongs to an Application Context (\c _psContextMap).
89 */
90struct _psChannelMap
91{
92	SCARDHANDLE hCard;
93	LPSTR readerName;
94};
95
96typedef struct _psChannelMap CHANNEL_MAP, *PCHANNEL_MAP;
97
98/**
99 * @brief Represents the an Application Context on the Client side.
100 *
101 * An Application Context contains Channels (\c _psChannelMap).
102 */
103static struct _psContextMap
104{
105	DWORD dwClientID;				/** Client Connection ID */
106	SCARDCONTEXT hContext;			/** Application Context ID */
107	DWORD contextBlockStatus;
108	PCSCLITE_MUTEX_T mMutex;		/** Mutex for this context */
109	CHANNEL_MAP psChannelMap[PCSCLITE_MAX_APPLICATION_CONTEXT_CHANNELS];
110} psContextMap[PCSCLITE_MAX_APPLICATION_CONTEXTS];
111
112/**
113 * Make sure the initialization code is executed only once.
114 */
115static short isExecuted = 0;
116
117/**
118 * Memory mapped address used to read status information about the readers.
119 * Each element in the vector \ref readerStates makes references to a part of
120 * the memory mapped.
121 */
122static int mapAddr = 0;
123
124/**
125 * Ensure that some functions be accessed in thread-safe mode.
126 * These function's names finishes with "TH".
127 */
128static PCSCLITE_MUTEX clientMutex = PTHREAD_MUTEX_INITIALIZER;
129
130/**
131 * Pointers to a memory mapped area used to read status information about the
132 * readers.
133 * Each element in the vector \ref readerStates makes references to a part of
134 * the memory mapped \ref mapAddr.
135 */
136static PREADER_STATE readerStates[PCSCLITE_MAX_READERS_CONTEXTS];
137
138PCSC_API SCARD_IO_REQUEST g_rgSCardT0Pci = { SCARD_PROTOCOL_T0, 8 };
139PCSC_API SCARD_IO_REQUEST g_rgSCardT1Pci = { SCARD_PROTOCOL_T1, 8 };
140PCSC_API SCARD_IO_REQUEST g_rgSCardRawPci = { SCARD_PROTOCOL_RAW, 8 };
141
142
143static LONG SCardAddContext(SCARDCONTEXT, DWORD);
144static LONG SCardGetContextIndice(SCARDCONTEXT);
145static LONG SCardGetContextIndiceTH(SCARDCONTEXT);
146static LONG SCardRemoveContext(SCARDCONTEXT);
147
148static LONG SCardAddHandle(SCARDHANDLE, DWORD, LPSTR);
149static LONG SCardGetIndicesFromHandle(SCARDHANDLE, PDWORD, PDWORD);
150static LONG SCardGetIndicesFromHandleTH(SCARDHANDLE, PDWORD, PDWORD);
151static LONG SCardRemoveHandle(SCARDHANDLE);
152
153static LONG SCardGetSetAttrib(SCARDHANDLE hCard, int command, DWORD dwAttrId,
154	LPBYTE pbAttr, LPDWORD pcbAttrLen);
155
156static LONG SCardCheckDaemonAvailability(void);
157static int SCardInitializeOnce();
158
159static int SHMClientCommunicationTimeout();
160
161/*
162 * Thread safety functions
163 */
164inline static LONG SCardLockThread(void);
165inline static LONG SCardUnlockThread(void);
166
167static LONG SCardEstablishContextTH(DWORD, LPCVOID, LPCVOID, LPSCARDCONTEXT);
168
169/**
170 * @brief Creates an Application Context to the PC/SC Resource Manager.
171
172 * This must be the first function called in a PC/SC application.
173 * This is a thread-safe wrapper to the function SCardEstablishContextTH().
174 *
175 * @param[in] dwScope Scope of the establishment.
176 * This can either be a local or remote connection.
177 * <ul>
178 *   <li>\ref SCARD_SCOPE_USER - Not used.
179 *   <li>\ref SCARD_SCOPE_TERMINAL - Not used.
180 *   <li>\ref SCARD_SCOPE_GLOBAL - Not used.
181 *   <li>\ref SCARD_SCOPE_SYSTEM - Services on the local machine.
182 * </ul>
183 * @param[in] pvReserved1 Reserved for future use. Can be used for remote connection.
184 * @param[in] pvReserved2 Reserved for future use.
185 * @param[out] phContext Returned Application Context.
186 *
187 * @return Connection status.
188 * @retval SCARD_S_SUCCESS Successful (\ref SCARD_S_SUCCESS)
189 * @retval SCARD_E_NO_SERVICE The server is not runing (\ref SCARD_E_NO_SERVICE)
190 * @retval SCARD_E_INVALID_VALUE Invalid scope type passed (\ref SCARD_E_INVALID_VALUE )
191 * @retval SCARD_E_INVALID_PARAMETER phContext is null (\ref SCARD_E_INVALID_PARAMETER)
192 *
193 * @test
194 * @code
195 * SCARDCONTEXT hContext;
196 * LONG rv;
197 * ...
198 * rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext);
199 * @endcode
200 */
201LONG SCardEstablishContext(DWORD dwScope, LPCVOID pvReserved1,
202	LPCVOID pvReserved2, LPSCARDCONTEXT phContext)
203{
204	LONG rv;
205
206	PROFILE_START
207
208	SCardLockThread();
209	rv = SCardEstablishContextTH(dwScope, pvReserved1,
210		pvReserved2, phContext);
211	SCardUnlockThread();
212
213	PROFILE_END
214
215	return rv;
216}
217
218/**
219 * @brief Creates a communication context to the PC/SC Resource
220 * Manager.
221 *
222 * This function shuld not be called directly. Instead, the thread-safe
223 * function SCardEstablishContext() should be called.
224 *
225 * @param[in] dwScope Scope of the establishment.
226 * This can either be a local or remote connection.
227 * <ul>
228 *   <li>\ref SCARD_SCOPE_USER - Not used.
229 *   <li>\ref SCARD_SCOPE_TERMINAL - Not used.
230 *   <li>\ref SCARD_SCOPE_GLOBAL - Not used.
231 *   <li>\ref SCARD_SCOPE_SYSTEM - Services on the local machine.
232 * </ul>
233 * @param[in] pvReserved1 Reserved for future use. Can be used for remote connection.
234 * @param[in] pvReserved2 Reserved for future use.
235 * @param[out] phContext Returned reference to this connection.
236 *
237 * @return Connection status.
238 * @retval SCARD_S_SUCCESS Successful (\ref SCARD_S_SUCCESS)
239 * @retval SCARD_E_NO_SERVICE The server is not runing (\ref SCARD_E_NO_SERVICE)
240 * @retval SCARD_E_INVALID_PARAMETER phContext is null. (\ref SCARD_E_INVALID_PARAMETER)
241 * @retval SCARD_E_INVALID_VALUE Invalid scope type passed (\ref SCARD_E_INVALID_VALUE)
242 */
243static LONG SCardEstablishContextTH(DWORD dwScope, LPCVOID pvReserved1,
244	LPCVOID pvReserved2, LPSCARDCONTEXT phContext)
245{
246	LONG rv;
247	establish_struct scEstablishStruct;
248	sharedSegmentMsg msgStruct;
249	DWORD dwClientID = 0;
250
251	if (phContext == NULL)
252		return SCARD_E_INVALID_PARAMETER;
253	else
254		*phContext = 0;
255
256	/* Check if the server is running */
257	if (SCardCheckDaemonAvailability() != SCARD_S_SUCCESS)
258		return SCARD_E_NO_SERVICE;
259
260	/*
261	 * Do this only once:
262	 * - Initialize debug of need.
263	 * - Set up the memory mapped structures for reader states.
264	 * - Allocate each reader structure.
265	 * - Initialize context struct.
266	 */
267	if (isExecuted == 0)
268	{
269		SCardInitializeOnce();
270		isExecuted = 1;
271	}
272
273	/* Establishes a connection to the server */
274	if (SHMClientSetupSession(&dwClientID) != 0)
275	{
276		SYS_CloseFile(mapAddr);
277		return SCARD_E_NO_SERVICE;
278	}
279
280	{	/* exchange client/server protocol versions */
281		sharedSegmentMsg msgStruct;
282		version_struct *veStr = (version_struct *)&msgStruct.data;
283		veStr->major = PROTOCOL_VERSION_MAJOR;
284		veStr->minor = PROTOCOL_VERSION_MINOR;
285		htonlVersionStruct(veStr);
286
287		if (-1 == WrapSHMWrite(CMD_VERSION, dwClientID, sizeof(version_struct), SHMClientCommunicationTimeout(), veStr))
288			return SCARD_E_NO_SERVICE;
289
290		/*
291		 * Read a message from the server
292		 */
293		if (-1 == SHMClientReadMessage(&msgStruct, dwClientID, sizeof(version_struct), SHMClientCommunicationTimeout()))
294		{
295			Log1(PCSC_LOG_ERROR, "Your pcscd is too old and does not support CMD_VERSION");
296			return SCARD_F_COMM_ERROR;
297		}
298
299		ntohlVersionStruct(veStr);
300		Log3(PCSC_LOG_ERROR, "Server is protocol version %d:%d",
301			veStr->major, veStr->minor);
302
303		if (veStr->rv != SCARD_S_SUCCESS)
304			return veStr->rv;
305	}
306
307	if (dwScope != SCARD_SCOPE_USER && dwScope != SCARD_SCOPE_TERMINAL &&
308		dwScope != SCARD_SCOPE_SYSTEM && dwScope != SCARD_SCOPE_GLOBAL)
309	{
310		return SCARD_E_INVALID_VALUE;
311	}
312
313	/*
314	 * Try to establish an Application Context with the server
315	 */
316	scEstablishStruct.dwScope = dwScope;
317	scEstablishStruct.phContext = 0;
318	scEstablishStruct.rv = 0;
319
320	htonlEstablishStruct(&scEstablishStruct);
321	rv = WrapSHMWrite(SCARD_ESTABLISH_CONTEXT, dwClientID,
322		sizeof(scEstablishStruct), PCSCLITE_MCLIENT_ATTEMPTS,
323		(void *) &scEstablishStruct);
324
325	if (rv == -1)
326		return SCARD_E_NO_SERVICE;
327
328	/*
329	 * Read the response from the server
330	 */
331	rv = SHMClientReadMessage(&msgStruct, dwClientID, sizeof(establish_struct), SHMClientCommunicationTimeout());
332
333	if (rv == -1)
334		return SCARD_F_COMM_ERROR;
335
336	memcpy(&scEstablishStruct, &msgStruct.data, sizeof(scEstablishStruct));
337	ntohlEstablishStruct(&scEstablishStruct);
338
339	if (scEstablishStruct.rv != SCARD_S_SUCCESS)
340		return scEstablishStruct.rv;
341
342	*phContext = scEstablishStruct.phContext;
343
344	/*
345	 * Allocate the new hContext - if allocator full return an error
346	 */
347	rv = SCardAddContext(*phContext, dwClientID);
348
349	return rv;
350}
351
352/**
353 * @brief This function destroys a communication context to the PC/SC Resource
354 * Manager. This must be the last function called in a PC/SC application.
355 *
356 * @param[in] hContext Connection context to be closed.
357 *
358 * @return Connection status.
359 * @retval SCARD_S_SUCCESS Successful (\ref SCARD_S_SUCCESS)
360 *
361 * @test
362 * @code
363 * SCARDCONTEXT hContext;
364 * LONG rv;
365 * ...
366 * rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext);
367 * rv = SCardReleaseContext(hContext);
368 * @endcode
369 */
370LONG SCardReleaseContext(SCARDCONTEXT hContext)
371{
372	LONG rv;
373	release_struct scReleaseStruct;
374	sharedSegmentMsg msgStruct;
375	LONG dwContextIndex;
376
377	PROFILE_START
378
379	if (SCardCheckDaemonAvailability() != SCARD_S_SUCCESS)
380		return SCARD_E_NO_SERVICE;
381
382	/*
383	 * Make sure this context has been opened
384	 */
385	dwContextIndex = SCardGetContextIndice(hContext);
386	if (dwContextIndex == -1)
387		return SCARD_E_INVALID_HANDLE;
388
389	SYS_MutexLock(psContextMap[dwContextIndex].mMutex);
390
391	scReleaseStruct.hContext = hContext;
392	scReleaseStruct.rv = 0;
393	htonlReleaseStruct(&scReleaseStruct);
394
395	rv = WrapSHMWrite(SCARD_RELEASE_CONTEXT, psContextMap[dwContextIndex].dwClientID,
396			  sizeof(scReleaseStruct),
397			  PCSCLITE_MCLIENT_ATTEMPTS, (void *) &scReleaseStruct);
398
399	if (rv == -1)
400	{
401		SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
402		return SCARD_E_NO_SERVICE;
403	}
404
405	/*
406	 * Read a message from the server
407	 */
408	rv = SHMClientReadMessage(&msgStruct, psContextMap[dwContextIndex].dwClientID, sizeof(release_struct), SHMClientCommunicationTimeout());
409	memcpy(&scReleaseStruct, &msgStruct.data, sizeof(scReleaseStruct));
410	ntohlReleaseStruct(&scReleaseStruct);
411
412	if (rv == -1)
413	{
414		SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
415		return SCARD_F_COMM_ERROR;
416	}
417
418	SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
419
420	/*
421	 * Remove the local context from the stack
422	 */
423	SCardLockThread();
424	SCardRemoveContext(hContext);
425	SCardUnlockThread();
426
427	PROFILE_END
428
429	return scReleaseStruct.rv;
430}
431
432/**
433 * @deprecated
434 * This function is not in Microsoft(R) WinSCard API and is deprecated
435 * in pcsc-lite API.
436 * The function does not do anything except returning \ref SCARD_S_SUCCESS.
437 *
438 * @param[in] hContext Connection context to the PC/SC Resource Manager.
439 * @param[in] dwTimeout New timeout value.
440 *
441 * @return Error code.
442 * @retval SCARD_S_SUCCESS Successful (\ref SCARD_S_SUCCESS)
443 */
444LONG SCardSetTimeout(SCARDCONTEXT hContext, DWORD dwTimeout)
445{
446	/*
447	 * Deprecated
448	 */
449
450	return SCARD_S_SUCCESS;
451}
452
453/**
454 * This function establishes a connection to the friendly name of the reader
455 * specified in szReader. The first connection will power up and perform a
456 * reset on the card.
457 *
458 * @param[in] hContext Connection context to the PC/SC Resource Manager.
459 * @param[in] szReader Reader name to connect to.
460 * @param[in] dwShareMode Mode of connection type: exclusive or shared.
461 * <ul>
462 *   <li>\ref SCARD_SHARE_SHARED - This application will allow others to share
463 *   the reader.
464 *   <li>\ref SCARD_SHARE_EXCLUSIVE - This application will NOT allow others to
465 *   share the reader.
466 *   <li>\ref SCARD_SHARE_DIRECT - Direct control of the reader, even without a
467 *   card.  \ref SCARD_SHARE_DIRECT can be used before using SCardControl() to
468 *   send control commands to the reader even if a card is not present in the
469 *   reader.
470 * </ul>
471 * @param[in] dwPreferredProtocols Desired protocol use.
472 * <ul>
473 *   <li>\ref SCARD_PROTOCOL_T0 - Use the T=0 protocol.
474 *   <li>\ref SCARD_PROTOCOL_T1 - Use the T=1 protocol.
475 *   <li>\ref SCARD_PROTOCOL_RAW - Use with memory type cards.
476 * </ul>
477 * dwPreferredProtocols is a bit mask of acceptable protocols for the
478 * connection. You can use (SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1) if you
479 * do not have a preferred protocol.
480 * @param[out] phCard Handle to this connection.
481 * @param[out] pdwActiveProtocol Established protocol to this connection.
482 *
483 * @return Error code.
484 * @retval SCARD_S_SUCCESS Successful (\ref SCARD_S_SUCCESS)
485 * @retval SCARD_E_INVALID_HANDLE Invalid hContext handle (\ref SCARD_E_INVALID_HANDLE)
486 * @retval SCARD_E_INVALID_VALUE Invalid sharing mode, requested protocol, or reader name (\ref SCARD_E_INVALID_VALUE)
487 * @retval SCARD_E_NOT_READY Could not allocate the desired port (\ref SCARD_E_NOT_READY)
488 * @retval SCARD_E_READER_UNAVAILABLE Could not power up the reader or card (\ref SCARD_E_READER_UNAVAILABLE)
489 * @retval SCARD_E_SHARING_VIOLATION Someone else has exclusive rights (\ref SCARD_E_SHARING_VIOLATION)
490 * @retval SCARD_E_UNSUPPORTED_FEATURE Protocol not supported (\ref SCARD_E_UNSUPPORTED_FEATURE)
491 *
492 * @test
493 * @code
494 * SCARDCONTEXT hContext;
495 * SCARDHANDLE hCard;
496 * DWORD dwActiveProtocol;
497 * LONG rv;
498 * ...
499 * rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext);
500 * rv = SCardConnect(hContext, "Reader X", SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0, &hCard, &dwActiveProtocol);
501 * @endcode
502 */
503LONG SCardConnect(SCARDCONTEXT hContext, LPCSTR szReader,
504	DWORD dwShareMode, DWORD dwPreferredProtocols, LPSCARDHANDLE phCard,
505	LPDWORD pdwActiveProtocol)
506{
507	LONG rv;
508	connect_struct scConnectStruct = {0,};
509	sharedSegmentMsg msgStruct = {0,};
510	LONG dwContextIndex;
511
512	PROFILE_START
513
514	/*
515	 * Check for NULL parameters
516	 */
517	if (phCard == NULL || pdwActiveProtocol == NULL)
518		return SCARD_E_INVALID_PARAMETER;
519	else
520		*phCard = 0;
521
522	if (szReader == NULL)
523		return SCARD_E_UNKNOWN_READER;
524
525	/*
526	 * Check for uninitialized strings
527	 */
528	if (strlen(szReader) > MAX_READERNAME)
529		return SCARD_E_INVALID_VALUE;
530
531	if (!(dwPreferredProtocols & SCARD_PROTOCOL_T0) &&
532		!(dwPreferredProtocols & SCARD_PROTOCOL_T1) &&
533		!(dwPreferredProtocols & SCARD_PROTOCOL_RAW) &&
534		!(dwPreferredProtocols & SCARD_PROTOCOL_ANY_OLD))
535	{
536		return SCARD_E_INVALID_VALUE;
537	}
538
539	if (SCardCheckDaemonAvailability() != SCARD_S_SUCCESS)
540		return SCARD_E_NO_SERVICE;
541
542	/*
543	 * Make sure this context has been opened
544	 */
545	dwContextIndex = SCardGetContextIndice(hContext);
546	if (dwContextIndex == -1)
547		return SCARD_E_INVALID_HANDLE;
548
549	SYS_MutexLock(psContextMap[dwContextIndex].mMutex);
550
551	strncpy(scConnectStruct.szReader, szReader, MAX_READERNAME);
552
553	scConnectStruct.hContext = hContext;
554	scConnectStruct.dwShareMode = dwShareMode;
555	scConnectStruct.dwPreferredProtocols = dwPreferredProtocols;
556	scConnectStruct.phCard = *phCard;
557	scConnectStruct.pdwActiveProtocol = *pdwActiveProtocol;
558	htonlConnectStruct(&scConnectStruct);
559
560	rv = WrapSHMWrite(SCARD_CONNECT, psContextMap[dwContextIndex].dwClientID,
561		sizeof(scConnectStruct),
562		SHMClientCommunicationTimeout(), (void *) &scConnectStruct);
563
564	if (rv == -1)
565	{
566		SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
567		return SCARD_E_NO_SERVICE;
568	}
569
570	/*
571	 * Read a message from the server
572	 */
573	rv = SHMClientReadMessage(&msgStruct, psContextMap[dwContextIndex].dwClientID, sizeof(connect_struct), SHMClientCommunicationTimeout());
574
575	memcpy(&scConnectStruct, &msgStruct.data, sizeof(scConnectStruct));
576	ntohlConnectStruct(&scConnectStruct);
577
578	if (rv == -1)
579	{
580		SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
581		return SCARD_F_COMM_ERROR;
582	}
583
584	*phCard = scConnectStruct.phCard;
585	*pdwActiveProtocol = scConnectStruct.pdwActiveProtocol;
586
587	if (scConnectStruct.rv == SCARD_S_SUCCESS)
588	{
589		/*
590		 * Keep track of the handle locally
591		 */
592		rv = SCardAddHandle(*phCard, dwContextIndex, (LPSTR) szReader);
593		SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
594
595		PROFILE_END
596
597		return rv;
598	}
599
600	SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
601
602	PROFILE_END
603
604	return scConnectStruct.rv;
605}
606
607/**
608 * @brief This function reestablishes a connection to a reader that was previously
609 * connected to using SCardConnect().
610 *
611 * In a multi application environment it is possible for an application to reset
612 * the card in shared mode. When this occurs any other application trying to
613 * access certain commands will be returned the value SCARD_W_RESET_CARD. When
614 * this occurs SCardReconnect() must be called in order to acknowledge that
615 * the card was reset and allow it to change it's state accordingly.
616 *
617 * @param[in] hCard Handle to a previous call to connect.
618 * @param[in] dwShareMode Mode of connection type: exclusive/shared.
619 * <ul>
620 *   <li>\ref SCARD_SHARE_SHARED - This application will allow others to share
621 *   the reader.
622 *   <li>\ref SCARD_SHARE_EXCLUSIVE - This application will NOT allow others to
623 *   share the reader.
624 * </ul>
625 * @param[in] dwPreferredProtocols Desired protocol use.
626 * <ul>
627 *   <li>\ref SCARD_PROTOCOL_T0 - Use the T=0 protocol.
628 *   <li>\ref SCARD_PROTOCOL_T1 - Use the T=1 protocol.
629 *   <li>\ref SCARD_PROTOCOL_RAW - Use with memory type cards.
630 * </ul>
631 * \p dwPreferredProtocols is a bit mask of acceptable protocols for
632 * the connection. You can use (SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1)
633 * if you do not have a preferred protocol.
634 * @param[in] dwInitialization Desired action taken on the card/reader.
635 * <ul>
636 *   <li>\ref SCARD_LEAVE_CARD - Do nothing.
637 *   <li>\ref SCARD_RESET_CARD - Reset the card (warm reset).
638 *   <li>\ref SCARD_UNPOWER_CARD - Unpower the card (cold reset).
639 *   <li>\ref SCARD_EJECT_CARD - Eject the card.
640 * </ul>
641 * @param[out] pdwActiveProtocol Established protocol to this connection.
642 *
643 * @return Error code.
644 * @retval SCARD_S_SUCCESS Successful (\ref SCARD_S_SUCCESS)
645 * @retval SCARD_E_INVALID_HANDLE Invalid \p hCard handle (\ref SCARD_E_INVALID_HANDLE)
646 * @retval SCARD_E_NOT_READY Could not allocate the desired port (\ref SCARD_E_NOT_READY)
647 * @retval SCARD_E_INVALID_VALUE Invalid sharing mode, requested protocol, or reader name (\ref SCARD_E_INVALID_VALUE)
648 * @retval SCARD_E_READER_UNAVAILABLE The reader has been removed (\ref SCARD_E_READER_UNAVAILABLE)
649 * @retval SCARD_E_UNSUPPORTED_FEATURE Protocol not supported (\ref SCARD_E_UNSUPPORTED_FEATURE)
650 * @retval SCARD_E_SHARING_VIOLATION Someone else has exclusive rights (\ref SCARD_E_SHARING_VIOLATION)
651 *
652 * @test
653 * @code
654 * SCARDCONTEXT hContext;
655 * SCARDHANDLE hCard;
656 * DWORD dwActiveProtocol, dwSendLength, dwRecvLength;
657 * LONG rv;
658 * BYTE pbRecvBuffer[10];
659 * BYTE pbSendBuffer[] = {0xC0, 0xA4, 0x00, 0x00, 0x02, 0x3F, 0x00};
660 * ...
661 * rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext);
662 * rv = SCardConnect(hContext, "Reader X", SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0, &hCard, &dwActiveProtocol);
663 * ...
664 * dwSendLength = sizeof(pbSendBuffer);
665 * dwRecvLength = sizeof(pbRecvBuffer);
666 * rv = SCardTransmit(hCard, SCARD_PCI_T0, pbSendBuffer, dwSendLength, &pioRecvPci, pbRecvBuffer, &dwRecvLength);
667 * / * Card has been reset by another application * /
668 * if (rv == SCARD_W_RESET_CARD)
669 * {
670 *   rv = SCardReconnect(hCard, SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0, SCARD_RESET_CARD, &dwActiveProtocol);
671 * }
672 * @endcode
673 */
674LONG SCardReconnect(SCARDHANDLE hCard, DWORD dwShareMode,
675	DWORD dwPreferredProtocols, DWORD dwInitialization,
676	LPDWORD pdwActiveProtocol)
677{
678	LONG rv;
679	reconnect_struct scReconnectStruct;
680	sharedSegmentMsg msgStruct;
681	int i;
682	DWORD dwContextIndex, dwChannelIndex;
683
684	PROFILE_START
685
686	if (dwInitialization != SCARD_LEAVE_CARD &&
687		dwInitialization != SCARD_RESET_CARD &&
688		dwInitialization != SCARD_UNPOWER_CARD &&
689		dwInitialization != SCARD_EJECT_CARD)
690	{
691		return SCARD_E_INVALID_VALUE;
692	}
693
694	if (!(dwPreferredProtocols & SCARD_PROTOCOL_T0) &&
695		!(dwPreferredProtocols & SCARD_PROTOCOL_T1) &&
696		!(dwPreferredProtocols & SCARD_PROTOCOL_RAW) &&
697		!(dwPreferredProtocols & SCARD_PROTOCOL_ANY_OLD))
698	{
699		return SCARD_E_INVALID_VALUE;
700	}
701
702	if (pdwActiveProtocol == NULL)
703		return SCARD_E_INVALID_PARAMETER;
704
705	if (SCardCheckDaemonAvailability() != SCARD_S_SUCCESS)
706		return SCARD_E_NO_SERVICE;
707
708	/*
709	 * Make sure this handle has been opened
710	 */
711	rv = SCardGetIndicesFromHandle(hCard, &dwContextIndex, &dwChannelIndex);
712
713	if (rv == -1)
714		return SCARD_E_INVALID_HANDLE;
715
716	SYS_MutexLock(psContextMap[dwContextIndex].mMutex);
717
718
719	for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
720	{
721		char *r = psContextMap[dwContextIndex].psChannelMap[dwChannelIndex].readerName;
722		/* by default r == NULL */
723		if (SharedReaderState_ReaderNameIsEqual(readerStates[i], r))
724			break;
725	}
726
727	if (i == PCSCLITE_MAX_READERS_CONTEXTS)
728	{
729		SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
730		return SCARD_E_READER_UNAVAILABLE;
731	}
732
733	scReconnectStruct.hCard = hCard;
734	scReconnectStruct.dwShareMode = dwShareMode;
735	scReconnectStruct.dwPreferredProtocols = dwPreferredProtocols;
736	scReconnectStruct.dwInitialization = dwInitialization;
737	scReconnectStruct.pdwActiveProtocol = *pdwActiveProtocol;
738	htonlReconnectStruct(&scReconnectStruct);
739
740	rv = WrapSHMWrite(SCARD_RECONNECT, psContextMap[dwContextIndex].dwClientID,
741		sizeof(scReconnectStruct),
742		SHMClientCommunicationTimeout(), (void *) &scReconnectStruct);
743
744	if (rv == -1)
745	{
746		SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
747		return SCARD_E_NO_SERVICE;
748	}
749
750	/*
751	 * Read a message from the server
752	 */
753	rv = SHMClientReadMessage(&msgStruct, psContextMap[dwContextIndex].dwClientID, sizeof(reconnect_struct), SHMClientCommunicationTimeout());
754
755	memcpy(&scReconnectStruct, &msgStruct.data, sizeof(scReconnectStruct));
756	ntohlReconnectStruct(&scReconnectStruct);
757
758	if (rv == -1)
759	{
760		SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
761		return SCARD_F_COMM_ERROR;
762	}
763
764	*pdwActiveProtocol = scReconnectStruct.pdwActiveProtocol;
765
766	SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
767
768	PROFILE_END
769
770	return scReconnectStruct.rv;
771}
772
773/**
774 * This function terminates a connection to the connection made through
775 * SCardConnect(). dwDisposition can have the following values:
776 *
777 * @param[in] hCard Connection made from SCardConnect.
778 * @param[in] dwDisposition Reader function to execute.
779 * <ul>
780 *   <li>\ref SCARD_LEAVE_CARD - Do nothing.
781 *   <li>\ref SCARD_RESET_CARD - Reset the card (warm reset).
782 *   <li>\ref SCARD_UNPOWER_CARD - Unpower the card (cold reset).
783 *   <li>\ref SCARD_EJECT_CARD - Eject the card.
784 * </ul>
785 *
786 * @return Error code.
787 * @retval SCARD_S_SUCCESS Successful(\ref SCARD_S_SUCCESS)
788 * @retval SCARD_E_INVALID_HANDLE Invalid \p hCard handle (\ref SCARD_E_INVALID_HANDLE)
789 * @retval SCARD_E_INVALID_VALUE - Invalid \p dwDisposition (\ref SCARD_E_INVALID_VALUE)
790 *
791 * @test
792 * @code
793 * SCARDCONTEXT hContext;
794 * SCARDHANDLE hCard;
795 * DWORD dwActiveProtocol;
796 * LONG rv;
797 * ...
798 * rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext);
799 * rv = SCardConnect(hContext, "Reader X", SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0, &hCard, &dwActiveProtocol);
800 * rv = SCardDisconnect(hCard, SCARD_UNPOWER_CARD);
801 * @endcode
802 */
803LONG SCardDisconnect(SCARDHANDLE hCard, DWORD dwDisposition)
804{
805	LONG rv;
806	disconnect_struct scDisconnectStruct;
807	sharedSegmentMsg msgStruct;
808	DWORD dwContextIndex, dwChannelIndex;
809
810	PROFILE_START
811
812	if (dwDisposition != SCARD_LEAVE_CARD &&
813		dwDisposition != SCARD_RESET_CARD &&
814		dwDisposition != SCARD_UNPOWER_CARD &&
815		dwDisposition != SCARD_EJECT_CARD)
816	{
817		return SCARD_E_INVALID_VALUE;
818	}
819
820	if (SCardCheckDaemonAvailability() != SCARD_S_SUCCESS)
821		return SCARD_E_NO_SERVICE;
822
823	/*
824	 * Make sure this handle has been opened
825	 */
826	rv = SCardGetIndicesFromHandle(hCard, &dwContextIndex, &dwChannelIndex);
827
828	if (rv == -1)
829		return SCARD_E_INVALID_HANDLE;
830
831	SYS_MutexLock(psContextMap[dwContextIndex].mMutex);
832
833	scDisconnectStruct.hCard = hCard;
834	scDisconnectStruct.dwDisposition = dwDisposition;
835	htonlDisconnectStruct(&scDisconnectStruct);
836
837	rv = WrapSHMWrite(SCARD_DISCONNECT, psContextMap[dwContextIndex].dwClientID,
838		sizeof(scDisconnectStruct),
839		SHMClientCommunicationTimeout(), (void *) &scDisconnectStruct);
840
841	if (rv == -1)
842	{
843		SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
844		return SCARD_E_NO_SERVICE;
845	}
846
847	/*
848	 * Read a message from the server
849	 */
850	rv = SHMClientReadMessage(&msgStruct, psContextMap[dwContextIndex].dwClientID, sizeof(disconnect_struct), SHMClientCommunicationTimeout());
851
852	memcpy(&scDisconnectStruct, &msgStruct.data, sizeof(scDisconnectStruct));
853	ntohlDisconnectStruct(&scDisconnectStruct);
854
855	if (rv == -1)
856	{
857		SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
858		return SCARD_F_COMM_ERROR;
859	}
860
861	SCardRemoveHandle(hCard);
862
863	SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
864
865	PROFILE_END
866
867	return scDisconnectStruct.rv;
868}
869
870/**
871 * @brief This function establishes a temporary exclusive access mode for
872 * doing a series of commands or transaction.
873 *
874 * You might want to use this when you are selecting a few files and then
875 * writing a large file so you can make sure that another application will
876 * not change the current file. If another application has a lock on this
877 * reader or this application is in \ref SCARD_SHARE_EXCLUSIVE there will be no
878 * action taken.
879 *
880 * @param[in] hCard Connection made from SCardConnect.
881 *
882 * @return Error code.
883 * @retval SCARD_S_SUCCESS Successful (\ref SCARD_S_SUCCESS)
884 * @retval SCARD_E_INVALID_HANDLE Invalid hCard handle (\ref SCARD_E_INVALID_HANDLE)
885 * @retval SCARD_E_SHARING_VIOLATION Someone else has exclusive rights (\ref SCARD_E_SHARING_VIOLATION)
886 * @retval SCARD_E_READER_UNAVAILABLE The reader has been removed (\ref SCARD_E_READER_UNAVAILABLE)
887 *
888 * @test
889 * @code
890 * SCARDCONTEXT hContext;
891 * SCARDHANDLE hCard;
892 * DWORD dwActiveProtocol;
893 * LONG rv;
894 * ...
895 * rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext);
896 * rv = SCardConnect(hContext, "Reader X", SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0, &hCard, &dwActiveProtocol);
897 * rv = SCardBeginTransaction(hCard);
898 * ...
899 * / * Do some transmit commands * /
900 * @endcode
901 */
902LONG SCardBeginTransaction(SCARDHANDLE hCard)
903{
904
905	LONG rv;
906	begin_struct txBeginStruct = {0,}, rxBeginStruct = {0,};
907	int i;
908	sharedSegmentMsg msgStruct = {0,};
909	DWORD dwContextIndex, dwChannelIndex;
910
911	PROFILE_START
912
913	secdebug("pcscd", "SCardBeginTransaction: initial request: hCard: 0x%08X", hCard);
914
915	if (SCardCheckDaemonAvailability() != SCARD_S_SUCCESS)
916		return SCARD_E_NO_SERVICE;
917
918	/*
919	 * Make sure this handle has been opened
920	 */
921	rv = SCardGetIndicesFromHandle(hCard, &dwContextIndex, &dwChannelIndex);
922
923	if (rv == -1)
924		return SCARD_E_INVALID_HANDLE;
925
926	SYS_MutexLock(psContextMap[dwContextIndex].mMutex);
927
928	for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
929	{
930		char *r = psContextMap[dwContextIndex].psChannelMap[dwChannelIndex].readerName;
931
932		/* by default r == NULL */
933		if (SharedReaderState_ReaderNameIsEqual(readerStates[i], r))
934			break;
935	}
936
937	if (i == PCSCLITE_MAX_READERS_CONTEXTS)
938	{
939		SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
940		return SCARD_E_READER_UNAVAILABLE;
941	}
942
943	txBeginStruct.hCard = hCard;
944	htonlBeginStruct(&txBeginStruct);
945
946	/*
947	 * Query the server every so often until the sharing violation ends
948	 * and then hold the lock for yourself.
949	 */
950
951	do
952	{
953		rv = WrapSHMWrite(SCARD_BEGIN_TRANSACTION, psContextMap[dwContextIndex].dwClientID,
954			sizeof(txBeginStruct),
955			SHMClientCommunicationTimeout(), (void *) &txBeginStruct);
956
957		if (rv == -1)
958		{
959			SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
960			return SCARD_E_NO_SERVICE;
961		}
962
963		/*
964		 * Read a message from the server
965		 */
966		rv = SHMClientReadMessage(&msgStruct, psContextMap[dwContextIndex].dwClientID, sizeof(begin_struct), SHMClientCommunicationTimeout());
967		memcpy(&rxBeginStruct, &msgStruct.data, sizeof(rxBeginStruct));
968		ntohlBeginStruct(&rxBeginStruct);
969
970		if (rv == -1)
971		{
972			SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
973			return SCARD_F_COMM_ERROR;
974		}
975
976	}
977	while (rxBeginStruct.rv == SCARD_E_SHARING_VIOLATION);
978
979	SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
980
981	PROFILE_END
982	secdebug("pcscd", "SCardBeginTransaction: hCard: 0x%08X, returning: 0x%08X", rxBeginStruct.hCard, rxBeginStruct.rv);
983
984	return rxBeginStruct.rv;
985}
986
987/**
988 * @brief This function ends a previously begun transaction.
989 *
990 * The calling application must be the owner of the previously begun
991 * transaction or an error will occur.
992 *
993 * @param[in] hCard Connection made from SCardConnect.
994 * @param[in] dwDisposition Action to be taken on the reader.
995 * The disposition action is not currently used in this release.
996 * <ul>
997 *   <li>\ref SCARD_LEAVE_CARD - Do nothing.
998 *   <li>\ref SCARD_RESET_CARD - Reset the card.
999 *   <li>\ref SCARD_UNPOWER_CARD - Unpower the card.
1000 *   <li>\ref SCARD_EJECT_CARD - Eject the card.
1001 * </ul>
1002 *
1003 * @return Error code.
1004 * @retval SCARD_S_SUCCESS Successful (\ref SCARD_S_SUCCESS)
1005 * @retval SCARD_E_INVALID_HANDLE Invalid hCard handle (\ref SCARD_E_INVALID_HANDLE)
1006 * @retval SCARD_E_SHARING_VIOLATION Someone else has exclusive rights (\ref SCARD_E_SHARING_VIOLATION)
1007 * @retval SCARD_E_READER_UNAVAILABLE The reader has been removed (\ref SCARD_E_READER_UNAVAILABLE)
1008 *
1009 * @test
1010 * @code
1011 * SCARDCONTEXT hContext;
1012 * SCARDHANDLE hCard;
1013 * DWORD dwActiveProtocol;
1014 * LONG rv;
1015 * ...
1016 * rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext);
1017 * rv = SCardConnect(hContext, "Reader X", SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0, &hCard, &dwActiveProtocol);
1018 * rv = SCardBeginTransaction(hCard);
1019 * ...
1020 * / * Do some transmit commands * /
1021 * ...
1022 * rv = SCardEndTransaction(hCard, SCARD_LEAVE_CARD);
1023 * @endcode
1024 */
1025LONG SCardEndTransaction(SCARDHANDLE hCard, DWORD dwDisposition)
1026{
1027	LONG rv;
1028	end_struct scEndStruct;
1029	sharedSegmentMsg msgStruct;
1030	int randnum, i;
1031	DWORD dwContextIndex, dwChannelIndex;
1032
1033	PROFILE_START
1034
1035	secdebug("pcscd", "SCardEndTransaction: initial request: hCard: 0x%08X, dwDisposition: 0x%04X",
1036			hCard, dwDisposition);
1037	/*
1038	 * Zero out everything
1039	 */
1040	randnum = 0;
1041
1042	if (dwDisposition != SCARD_LEAVE_CARD &&
1043		dwDisposition != SCARD_RESET_CARD &&
1044		dwDisposition != SCARD_UNPOWER_CARD &&
1045		dwDisposition != SCARD_EJECT_CARD)
1046	{
1047		return SCARD_E_INVALID_VALUE;
1048	}
1049
1050	if (SCardCheckDaemonAvailability() != SCARD_S_SUCCESS)
1051		return SCARD_E_NO_SERVICE;
1052
1053	/*
1054	 * Make sure this handle has been opened
1055	 */
1056	rv = SCardGetIndicesFromHandle(hCard, &dwContextIndex, &dwChannelIndex);
1057
1058	if (rv == -1)
1059		return SCARD_E_INVALID_HANDLE;
1060
1061	SYS_MutexLock(psContextMap[dwContextIndex].mMutex);
1062
1063	for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
1064	{
1065		char *r = psContextMap[dwContextIndex].psChannelMap[dwChannelIndex].readerName;
1066
1067		/* by default r == NULL */
1068		if (SharedReaderState_ReaderNameIsEqual(readerStates[i], r))
1069			break;
1070	}
1071
1072	if (i == PCSCLITE_MAX_READERS_CONTEXTS)
1073	{
1074		SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
1075		return SCARD_E_READER_UNAVAILABLE;
1076	}
1077
1078	scEndStruct.hCard = hCard;
1079	scEndStruct.dwDisposition = dwDisposition;
1080	htonlEndStruct(&scEndStruct);
1081
1082	rv = WrapSHMWrite(SCARD_END_TRANSACTION, psContextMap[dwContextIndex].dwClientID,
1083		sizeof(scEndStruct),
1084		SHMClientCommunicationTimeout(), (void *) &scEndStruct);
1085	secdebug("pcscd", "SCardEndTransaction: WrapSHMWrite result: 0x%08X", rv);
1086
1087	if (rv == -1)
1088	{
1089		SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
1090		return SCARD_E_NO_SERVICE;
1091	}
1092
1093	/*
1094	 * Read a message from the server
1095	 */
1096	rv = SHMClientReadMessage(&msgStruct, psContextMap[dwContextIndex].dwClientID, sizeof(end_struct), SHMClientCommunicationTimeout());
1097	secdebug("pcscd", "SCardEndTransaction: SHMClientRead result: 0x%08X", rv);
1098
1099	memcpy(&scEndStruct, &msgStruct.data, sizeof(scEndStruct));
1100	ntohlEndStruct(&scEndStruct);
1101
1102	if (rv == -1)
1103	{
1104		SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
1105		return SCARD_F_COMM_ERROR;
1106	}
1107
1108	/*
1109	 * This helps prevent starvation
1110	 */
1111	randnum = SYS_Random(randnum, 1000.0, 10000.0);
1112	SYS_USleep(randnum);
1113
1114	SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
1115
1116	PROFILE_END
1117
1118	secdebug("pcscd", "SCardEndTransaction: returning: 0x%08X", scEndStruct.rv);
1119	return scEndStruct.rv;
1120}
1121
1122/**
1123 * @deprecated
1124 * This function is not in Microsoft(R) WinSCard API and is deprecated
1125 * in pcsc-lite API.
1126 */
1127LONG SCardCancelTransaction(SCARDHANDLE hCard)
1128{
1129	LONG rv;
1130	cancel_struct scCancelStruct;
1131	sharedSegmentMsg msgStruct;
1132	int i;
1133	DWORD dwContextIndex, dwChannelIndex;
1134
1135	PROFILE_START
1136
1137	if (SCardCheckDaemonAvailability() != SCARD_S_SUCCESS)
1138		return SCARD_E_NO_SERVICE;
1139
1140	/*
1141	 * Make sure this handle has been opened
1142	 */
1143	rv = SCardGetIndicesFromHandle(hCard, &dwContextIndex, &dwChannelIndex);
1144
1145	if (rv == -1)
1146		return SCARD_E_INVALID_HANDLE;
1147
1148	SYS_MutexLock(psContextMap[dwContextIndex].mMutex);
1149
1150	for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
1151	{
1152		char *r = psContextMap[dwContextIndex].psChannelMap[dwChannelIndex].readerName;
1153
1154		/* by default r == NULL */
1155		if (SharedReaderState_ReaderNameIsEqual(readerStates[i], r))
1156			break;
1157	}
1158
1159	if (i == PCSCLITE_MAX_READERS_CONTEXTS)
1160	{
1161		SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
1162		return SCARD_E_READER_UNAVAILABLE;
1163	}
1164
1165	scCancelStruct.hCard = hCard;
1166	htonlCancelStruct(&scCancelStruct);
1167
1168	rv = WrapSHMWrite(SCARD_CANCEL_TRANSACTION, psContextMap[dwContextIndex].dwClientID,
1169		sizeof(scCancelStruct),
1170		SHMClientCommunicationTimeout(), (void *) &scCancelStruct);
1171
1172	if (rv == -1)
1173	{
1174		SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
1175		return SCARD_E_NO_SERVICE;
1176	}
1177
1178	/*
1179	 * Read a message from the server
1180	 */
1181	rv = SHMClientReadMessage(&msgStruct, psContextMap[dwContextIndex].dwClientID, sizeof(cancel_struct), SHMClientCommunicationTimeout());
1182
1183	memcpy(&scCancelStruct, &msgStruct.data, sizeof(scCancelStruct));
1184	ntohlCancelStruct(&scCancelStruct);
1185
1186	if (rv == -1)
1187	{
1188		SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
1189		return SCARD_F_COMM_ERROR;
1190	}
1191
1192	SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
1193
1194	PROFILE_END
1195
1196	return scCancelStruct.rv;
1197}
1198
1199/**
1200 * @brief This function returns the current status of the reader connected to by hCard.
1201 *
1202 * It's friendly name will be stored in szReaderName. pcchReaderLen will be
1203 * the size of the allocated buffer for szReaderName, while pcbAtrLen will
1204 * be the size of the allocated buffer for pbAtr. If either of these is too
1205 * small, the function will return with \ref SCARD_E_INSUFFICIENT_BUFFER and the
1206 * necessary size in pcchReaderLen and pcbAtrLen. The current state, and
1207 * protocol will be stored in pdwState and pdwProtocol respectively.
1208 *
1209 * @param[in] hCard Connection made from SCardConnect.
1210 * @param mszReaderNames [inout] Friendly name of this reader.
1211 * @param pcchReaderLen [inout] Size of the szReaderName multistring.
1212 * @param[out] pdwState Current state of this reader. pdwState
1213 * is a DWORD possibly OR'd with the following values:
1214 * <ul>
1215 *   <li>\ref SCARD_ABSENT - There is no card in the reader.
1216 *   <li>\ref SCARD_PRESENT - There is a card in the reader, but it has not
1217 *       been moved into position for use.
1218 *   <li>\ref SCARD_SWALLOWED - There is a card in the reader in position for
1219 *       use.  The card is not powered.
1220 *   <li>\ref SCARD_POWERED - Power is being provided to the card, but the
1221 *       reader driver is unaware of the mode of the card.
1222 *   <li>\ref SCARD_NEGOTIABLE - The card has been reset and is awaiting PTS
1223 *       negotiation.
1224 *   <li>\ref SCARD_SPECIFIC - The card has been reset and specific
1225 *       communication protocols have been established.
1226 * </ul>
1227 * @param[out] pdwProtocol Current protocol of this reader.
1228 * <ul>
1229 *   <li>\ref SCARD_PROTOCOL_T0 	Use the T=0 protocol.
1230 *   <li>\ref SCARD_PROTOCOL_T1 	Use the T=1 protocol.
1231 * </ul>
1232 * @param[out] pbAtr Current ATR of a card in this reader.
1233 * @param[out] pcbAtrLen Length of ATR.
1234 *
1235 * @return Error code.
1236 * @retval SCARD_S_SUCCESS Successful (\ref SCARD_S_SUCCESS)
1237 * @retval SCARD_E_INVALID_HANDLE Invalid hCard handle (\ref SCARD_E_INVALID_HANDLE)
1238 * @retval SCARD_E_INSUFFICIENT_BUFFER Not enough allocated memory for szReaderName or for pbAtr (\ref SCARD_E_INSUFFICIENT_BUFFER)
1239 * @retval SCARD_E_READER_UNAVAILABLE The reader has been removed (\ref SCARD_E_READER_UNAVAILABLE)
1240 *
1241 * @test
1242 * @code
1243 * SCARDCONTEXT hContext;
1244 * SCARDHANDLE hCard;
1245 * DWORD dwActiveProtocol;
1246 * DWORD dwState, dwProtocol, dwAtrLen, dwReaderLen;
1247 * BYTE pbAtr[MAX_ATR_SIZE];
1248 * ...
1249 * rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext);
1250 * rv = SCardConnect(hContext, "Reader X", SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0, &hCard, &dwActiveProtocol);
1251 * ...
1252 * dwAtrLen = sizeof(pbAtr);
1253 * rv=SCardStatus(hCard, NULL, &dwReaderLen, &dwState, &dwProtocol, pbAtr, &dwAtrLen);
1254 * @endcode
1255 */
1256LONG SCardStatus(SCARDHANDLE hCard, LPSTR mszReaderNames,
1257	LPDWORD pcchReaderLen, LPDWORD pdwState,
1258	LPDWORD pdwProtocol, LPBYTE pbAtr, LPDWORD pcbAtrLen)
1259{
1260	DWORD dwReaderLen, atrOutputBufferSize;
1261	LONG rv;
1262	int i;
1263	status_struct scStatusStruct;
1264	sharedSegmentMsg msgStruct;
1265	DWORD dwContextIndex, dwChannelIndex;
1266	char *r;
1267
1268	PROFILE_START
1269
1270	/*
1271	 * Check for NULL parameters
1272	 */
1273
1274	if (pcchReaderLen == NULL || pcbAtrLen == NULL)
1275		return SCARD_E_INVALID_PARAMETER;
1276
1277	/* length passed from caller */
1278	dwReaderLen = *pcchReaderLen;
1279	atrOutputBufferSize = *pcbAtrLen;
1280
1281	/* default output values */
1282	if (pdwState)
1283		*pdwState = 0;
1284
1285	if (pdwProtocol)
1286		*pdwProtocol = 0;
1287
1288	*pcchReaderLen = 0;
1289	*pcbAtrLen = 0;
1290
1291	if (SCardCheckDaemonAvailability() != SCARD_S_SUCCESS)
1292		return SCARD_E_NO_SERVICE;
1293
1294	/*
1295	 * Make sure this handle has been opened
1296	 */
1297	rv = SCardGetIndicesFromHandle(hCard, &dwContextIndex, &dwChannelIndex);
1298
1299	if (rv == -1)
1300		return SCARD_E_INVALID_HANDLE;
1301
1302	SYS_MutexLock(psContextMap[dwContextIndex].mMutex);
1303
1304	r = psContextMap[dwContextIndex].psChannelMap[dwChannelIndex].readerName;
1305	for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
1306	{
1307		/* by default r == NULL */
1308		if (SharedReaderState_ReaderNameIsEqual(readerStates[i], r))
1309			break;
1310	}
1311
1312	if (i == PCSCLITE_MAX_READERS_CONTEXTS)
1313	{
1314		SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
1315		return SCARD_E_READER_UNAVAILABLE;
1316	}
1317
1318	/* initialise the structure */
1319	memset(&scStatusStruct, 0, sizeof(scStatusStruct));
1320	scStatusStruct.hCard = hCard;
1321
1322	/* those sizes need to be initialised */
1323	scStatusStruct.pcchReaderLen = sizeof(scStatusStruct.mszReaderNames);
1324	scStatusStruct.pcbAtrLen = sizeof(scStatusStruct.pbAtr);
1325	htonlStatusStruct(&scStatusStruct);
1326
1327	rv = WrapSHMWrite(SCARD_STATUS, psContextMap[dwContextIndex].dwClientID,
1328		sizeof(scStatusStruct),
1329		SHMClientCommunicationTimeout(), (void *) &scStatusStruct);
1330
1331	if (rv == -1)
1332	{
1333		SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
1334		return SCARD_E_NO_SERVICE;
1335	}
1336
1337	/*
1338	 * Read a message from the server
1339	 */
1340	rv = SHMClientReadMessage(&msgStruct, psContextMap[dwContextIndex].dwClientID, sizeof(status_struct), SHMClientCommunicationTimeout());
1341
1342	memcpy(&scStatusStruct, &msgStruct.data, sizeof(scStatusStruct));
1343	ntohlStatusStruct(&scStatusStruct);
1344
1345	if (rv == -1)
1346	{
1347		SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
1348		return SCARD_F_COMM_ERROR;
1349	}
1350
1351	rv = scStatusStruct.rv;
1352	if (rv != SCARD_S_SUCCESS && rv != SCARD_E_INSUFFICIENT_BUFFER)
1353	{
1354		/*
1355		 * An event must have occurred
1356		 */
1357		SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
1358		return rv;
1359	}
1360
1361	/*
1362	 * Now continue with the client side SCardStatus
1363	 */
1364
1365	*pcchReaderLen = strlen(psContextMap[dwContextIndex].psChannelMap[dwChannelIndex].readerName) + 1;
1366	*pcbAtrLen = SharedReaderState_CardAtrLength(readerStates[i]);
1367
1368	if (pdwState)
1369		*pdwState = SharedReaderState_State(readerStates[i]);
1370
1371	if (pdwProtocol)
1372		*pdwProtocol = SharedReaderState_Protocol(readerStates[i]);
1373
1374	/* return SCARD_E_INSUFFICIENT_BUFFER only if buffer pointer is non NULL */
1375	if (mszReaderNames)
1376	{
1377		if (*pcchReaderLen > dwReaderLen)
1378			rv = SCARD_E_INSUFFICIENT_BUFFER;
1379
1380		strncpy(mszReaderNames,
1381			psContextMap[dwContextIndex].psChannelMap[dwChannelIndex].readerName,
1382			dwReaderLen);
1383	}
1384
1385	if (pbAtr)
1386	{
1387		if (*pcbAtrLen > atrOutputBufferSize)
1388			rv = SCARD_E_INSUFFICIENT_BUFFER;
1389
1390		memcpy(pbAtr, SharedReaderState_CardAtr(readerStates[i]),
1391			min(*pcbAtrLen, atrOutputBufferSize));
1392	}
1393
1394	SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
1395
1396	PROFILE_END
1397
1398	return rv;
1399}
1400
1401/**
1402 * @brief This function receives a structure or list of structures containing
1403 * reader names. It then blocks for a change in state to occur on any of the
1404 * OR'd values contained in dwCurrentState for a maximum blocking time of
1405 * dwTimeout or forever if INFINITE is used.
1406 *
1407 * The new event state will be contained in dwEventState. A status change might
1408 * be a card insertion or removal event, a change in ATR, etc.
1409 *
1410 * This function will block for reader availability if cReaders is equal to
1411 * zero and rgReaderStates is NULL.
1412 *
1413 * @code
1414 * typedef struct {
1415 *   LPCSTR szReader;          // Reader name
1416 *   LPVOID pvUserData;         // User defined data
1417 *   DWORD dwCurrentState;      // Current state of reader
1418 *   DWORD dwEventState;        // Reader state after a state change
1419 *   DWORD cbAtr;               // ATR Length, usually MAX_ATR_SIZE
1420 *   BYTE rgbAtr[MAX_ATR_SIZE]; // ATR Value
1421 * } SCARD_READERSTATE;
1422 * ...
1423 * typedef SCARD_READERSTATE *PSCARD_READERSTATE, **LPSCARD_READERSTATE;
1424 * ...
1425 * @endcode
1426 *
1427 * Value of dwCurrentState and dwEventState:
1428 * <ul>
1429 *   <li>\ref SCARD_STATE_UNAWARE The application is unaware of the current
1430 *       state, and would like to know. The use of this value results in an
1431 *       immediate return from state transition monitoring services. This is
1432 *       represented by all bits set to zero.
1433 *   <li>\ref SCARD_STATE_IGNORE This reader should be ignored
1434 *   <li>\ref SCARD_STATE_CHANGED There is a difference between the state believed
1435 *       by the application, and the state known by the resource manager.
1436 *       When this bit is set, the application may assume a significant state
1437 *       change has occurred on this reader.
1438 *   <li>\ref SCARD_STATE_UNKNOWN The given reader name is not recognized by the
1439 *       resource manager. If this bit is set, then \ref SCARD_STATE_CHANGED and
1440 *       \ref SCARD_STATE_IGNORE will also be set
1441 *   <li>\ref SCARD_STATE_UNAVAILABLE The actual state of this reader is not
1442 *       available. If this bit is set, then all the following bits are clear.
1443 *   <li>\ref SCARD_STATE_EMPTY There is no card in the reader. If this bit is set,
1444 *       all the following bits will be clear
1445 *   <li>\ref SCARD_STATE_PRESENT There is a card in the reader
1446 *   <li>\ref SCARD_STATE_ATRMATCH There is a card in the reader with an ATR
1447 *       matching one of the target cards. If this bit is set,
1448 *       \ref SCARD_STATE_PRESENT will also be set. This bit is only returned on
1449 *       the SCardLocateCards() function.
1450 *   <li>\ref SCARD_STATE_EXCLUSIVE The card in the reader is allocated for
1451 *       exclusive use by another application. If this bit is set,
1452 *       \ref SCARD_STATE_PRESENT will also be set.
1453 *   <li>\ref SCARD_STATE_INUSE The card in the reader is in use by one or more
1454 *       other applications, but may be connected to in shared mode. If this
1455 *       bit is set, \ref SCARD_STATE_PRESENT will also be set.
1456 *   <li>\ref SCARD_STATE_MUTE There is an unresponsive card in the reader.
1457 * </ul>
1458 *
1459 * @param[in] hContext Connection context to the PC/SC Resource Manager.
1460 * @param[in] dwTimeout Maximum waiting time (in miliseconds) for status
1461 *            change, zero (or INFINITE) for infinite.
1462 * @param rgReaderStates [inout] Structures of readers with current states.
1463 * @param[in] cReaders Number of structures.
1464 *
1465 * @return Error code.
1466 * @retval SCARD_S_SUCCESS Successful (\ref SCARD_S_SUCCESS)
1467 * @retval SCARD_E_INVALID_VALUE Invalid States, reader name, etc (\ref SCARD_E_INVALID_VALUE)
1468 * @retval SCARD_E_INVALID_HANDLE Invalid hContext handle (\ref SCARD_E_INVALID_HANDLE)
1469 * @retval SCARD_E_READER_UNAVAILABLE The reader is unavailable (\ref SCARD_E_READER_UNAVAILABLE)
1470 *
1471 * @test
1472 * @code
1473 * SCARDCONTEXT hContext;
1474 * SCARD_READERSTATE_A rgReaderStates[1];
1475 * LONG rv;
1476 * ...
1477 * rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext);
1478 * ...
1479 * rgReaderStates[0].szReader = "Reader X";
1480 * rgReaderStates[0].dwCurrentState = SCARD_STATE_UNAWARE;
1481 * ...
1482 * rv = SCardGetStatusChange(hContext, INFINITE, rgReaderStates, 1);
1483 * printf("reader state: 0x%04X\n", rgReaderStates[0].dwEventState);
1484 * @endcode
1485 */
1486LONG SCardGetStatusChange(SCARDCONTEXT hContext, DWORD dwTimeout,
1487	LPSCARD_READERSTATE_A rgReaderStates, DWORD cReaders)
1488{
1489	PSCARD_READERSTATE_A currReader;
1490	PREADER_STATE rContext;
1491	DWORD dwTime = 0;
1492	DWORD dwState;
1493	DWORD dwBreakFlag = 0;
1494	int j;
1495	LONG dwContextIndex;
1496	int currentReaderCount = 0;
1497
1498	PROFILE_START
1499
1500	if (rgReaderStates == NULL && cReaders > 0)
1501		return SCARD_E_INVALID_PARAMETER;
1502
1503	if (SCardCheckDaemonAvailability() != SCARD_S_SUCCESS)
1504		return SCARD_E_NO_SERVICE;
1505
1506	/*
1507	 * Make sure this context has been opened
1508	 */
1509
1510	dwContextIndex = SCardGetContextIndice(hContext);
1511	if (dwContextIndex == -1)
1512		return SCARD_E_INVALID_HANDLE;
1513
1514	SYS_MutexLock(psContextMap[dwContextIndex].mMutex);
1515
1516	/*
1517	 * Application is waiting for a reader - return the first available
1518	 * reader
1519	 */
1520
1521	if (cReaders == 0)
1522	{
1523		while (1)
1524		{
1525			int i;
1526
1527			if (SCardCheckDaemonAvailability() != SCARD_S_SUCCESS)
1528			{
1529				SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
1530				return SCARD_E_NO_SERVICE;
1531			}
1532
1533			for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
1534			{
1535				if (SharedReaderState_ReaderID(readerStates[i]) != 0)
1536				{
1537					/*
1538					 * Reader was found
1539					 */
1540					SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
1541
1542					PROFILE_END
1543
1544					return SCARD_S_SUCCESS;
1545				}
1546			}
1547
1548			if (dwTimeout == 0)
1549			{
1550				/*
1551				 * return immediately - no reader available
1552				 */
1553				SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
1554				return SCARD_E_READER_UNAVAILABLE;
1555			}
1556
1557			SYS_USleep(PCSCLITE_STATUS_WAIT);
1558
1559			if (dwTimeout != INFINITE)
1560			{
1561				dwTime += PCSCLITE_STATUS_WAIT;
1562
1563				if (dwTime >= (dwTimeout * 1000))
1564				{
1565					SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
1566
1567					PROFILE_END
1568
1569					return SCARD_E_TIMEOUT;
1570				}
1571			}
1572		}
1573	}
1574	else
1575		if (cReaders >= PCSCLITE_MAX_READERS_CONTEXTS)
1576		{
1577			SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
1578			return SCARD_E_INVALID_VALUE;
1579		}
1580
1581	/*
1582	 * Check the integrity of the reader states structures
1583	 */
1584
1585	for (j = 0; j < cReaders; j++)
1586	{
1587		currReader = &rgReaderStates[j];
1588
1589		if (currReader->szReader == NULL)
1590		{
1591			SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
1592			return SCARD_E_INVALID_VALUE;
1593		}
1594	}
1595
1596	/*
1597	 * End of search for readers
1598	 */
1599
1600	/*
1601	 * Clear the event state for all readers
1602	 */
1603	for (j = 0; j < cReaders; j++)
1604	{
1605		currReader = &rgReaderStates[j];
1606		currReader->dwEventState = 0;
1607	}
1608
1609	/*
1610	 * Now is where we start our event checking loop
1611	 */
1612
1613	Log1(PCSC_LOG_DEBUG, "Event Loop Start");
1614
1615	psContextMap[dwContextIndex].contextBlockStatus = BLOCK_STATUS_BLOCKING;
1616
1617	/* Get the initial reader count on the system */
1618	for (j=0; j < PCSCLITE_MAX_READERS_CONTEXTS; j++)
1619		if (SharedReaderState_ReaderID(readerStates[j]) != 0)
1620			currentReaderCount++;
1621
1622	j = 0;
1623
1624	do
1625	{
1626		int newReaderCount = 0;
1627		char ReaderCountChanged = 0;
1628
1629		if (SCardCheckDaemonAvailability() != SCARD_S_SUCCESS)
1630		{
1631			SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
1632
1633			PROFILE_END
1634
1635			return SCARD_E_NO_SERVICE;
1636		}
1637
1638		if (j == 0)
1639		{
1640			int i;
1641
1642			for (i=0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
1643				if (SharedReaderState_ReaderID(readerStates[i]) != 0)
1644					newReaderCount++;
1645
1646			if (newReaderCount != currentReaderCount)
1647			{
1648				Log1(PCSC_LOG_INFO, "Reader list changed");
1649				ReaderCountChanged = 1;
1650				currentReaderCount = newReaderCount;
1651			}
1652		}
1653		currReader = &rgReaderStates[j];
1654
1655	/************ Look for IGNORED readers ****************************/
1656
1657		if (currReader->dwCurrentState & SCARD_STATE_IGNORE)
1658			currReader->dwEventState = SCARD_STATE_IGNORE;
1659		else
1660		{
1661			LPSTR lpcReaderName;
1662			int i;
1663
1664	  /************ Looks for correct readernames *********************/
1665
1666			lpcReaderName = (char *) currReader->szReader;
1667
1668			for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
1669			{
1670				if (SharedReaderState_ReaderNameIsEqual(readerStates[i], lpcReaderName))
1671					break;
1672			}
1673
1674			/*
1675			 * The requested reader name is not recognized
1676			 */
1677			if (i == PCSCLITE_MAX_READERS_CONTEXTS)
1678			{
1679				if (currReader->dwCurrentState & SCARD_STATE_UNKNOWN)
1680					currReader->dwEventState = SCARD_STATE_UNKNOWN;
1681				else
1682				{
1683					currReader->dwEventState =
1684						SCARD_STATE_UNKNOWN | SCARD_STATE_CHANGED;
1685					/*
1686					 * Spec says use SCARD_STATE_IGNORE but a removed USB
1687					 * reader with eventState fed into currentState will
1688					 * be ignored forever
1689					 */
1690					dwBreakFlag = 1;
1691				}
1692			}
1693			else
1694			{
1695
1696				/*
1697				 * The reader has come back after being away
1698				 */
1699				if (currReader->dwCurrentState & SCARD_STATE_UNKNOWN)
1700				{
1701					currReader->dwEventState |= SCARD_STATE_CHANGED;
1702					currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
1703					dwBreakFlag = 1;
1704				}
1705
1706	/*****************************************************************/
1707
1708				/*
1709				 * Set the reader status structure
1710				 */
1711				rContext = readerStates[i];
1712
1713				/*
1714				 * Now we check all the Reader States
1715				 */
1716				dwState = SharedReaderState_State(rContext);
1717
1718	/*********** Check if the reader is in the correct state ********/
1719				if (dwState & SCARD_UNKNOWN)
1720				{
1721					/*
1722					 * App thinks reader is in bad state and it is
1723					 */
1724					if (currReader-> dwCurrentState & SCARD_STATE_UNAVAILABLE)
1725						currReader->dwEventState = SCARD_STATE_UNAVAILABLE;
1726					else
1727					{
1728						/*
1729						 * App thinks reader is in good state and it is
1730						 * not
1731						 */
1732						currReader->dwEventState = SCARD_STATE_CHANGED |
1733							SCARD_STATE_UNAVAILABLE;
1734						dwBreakFlag = 1;
1735					}
1736				}
1737				else
1738				{
1739					/*
1740					 * App thinks reader in bad state but it is not
1741					 */
1742					if (currReader-> dwCurrentState & SCARD_STATE_UNAVAILABLE)
1743					{
1744						currReader->dwEventState &=
1745							~SCARD_STATE_UNAVAILABLE;
1746						currReader->dwEventState |= SCARD_STATE_CHANGED;
1747						dwBreakFlag = 1;
1748					}
1749				}
1750
1751	/********** Check for card presence in the reader **************/
1752
1753				if (dwState & SCARD_PRESENT)
1754				{
1755					/* card present but not yet powered up */
1756					if (0 == SharedReaderState_CardAtrLength(rContext))
1757						/* Allow the status thread to convey information */
1758						SYS_USleep(PCSCLITE_STATUS_POLL_RATE + 10);
1759
1760					currReader->cbAtr = SharedReaderState_CardAtrLength(rContext);
1761					memcpy(currReader->rgbAtr, SharedReaderState_CardAtr(rContext),
1762						currReader->cbAtr);
1763				}
1764				else
1765					currReader->cbAtr = 0;
1766
1767				/*
1768				 * Card is now absent
1769				 */
1770				if (dwState & SCARD_ABSENT)
1771				{
1772					currReader->dwEventState |= SCARD_STATE_EMPTY;
1773					currReader->dwEventState &= ~SCARD_STATE_PRESENT;
1774					currReader->dwEventState &= ~SCARD_STATE_UNAWARE;
1775					currReader->dwEventState &= ~SCARD_STATE_IGNORE;
1776					currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
1777					currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE;
1778					currReader->dwEventState &= ~SCARD_STATE_ATRMATCH;
1779					currReader->dwEventState &= ~SCARD_STATE_MUTE;
1780					currReader->dwEventState &= ~SCARD_STATE_INUSE;
1781
1782					/*
1783					 * After present the rest are assumed
1784					 */
1785					if (currReader->dwCurrentState & SCARD_STATE_PRESENT
1786						|| currReader->dwCurrentState & SCARD_STATE_ATRMATCH
1787						|| currReader->dwCurrentState & SCARD_STATE_EXCLUSIVE
1788						|| currReader->dwCurrentState & SCARD_STATE_INUSE)
1789					{
1790						currReader->dwEventState |= SCARD_STATE_CHANGED;
1791						dwBreakFlag = 1;
1792					}
1793
1794					/*
1795					 * Card is now present
1796					 */
1797				} else if (dwState & SCARD_PRESENT)
1798				{
1799					currReader->dwEventState |= SCARD_STATE_PRESENT;
1800					currReader->dwEventState &= ~SCARD_STATE_EMPTY;
1801					currReader->dwEventState &= ~SCARD_STATE_UNAWARE;
1802					currReader->dwEventState &= ~SCARD_STATE_IGNORE;
1803					currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
1804					currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE;
1805					currReader->dwEventState &= ~SCARD_STATE_MUTE;
1806
1807					if (currReader->dwCurrentState & SCARD_STATE_EMPTY)
1808					{
1809						currReader->dwEventState |= SCARD_STATE_CHANGED;
1810						dwBreakFlag = 1;
1811					}
1812
1813					if (dwState & SCARD_SWALLOWED)
1814					{
1815						if (currReader->dwCurrentState & SCARD_STATE_MUTE)
1816							currReader->dwEventState |= SCARD_STATE_MUTE;
1817						else
1818						{
1819							currReader->dwEventState |= SCARD_STATE_MUTE;
1820							if (currReader->dwCurrentState
1821								!= SCARD_STATE_UNAWARE)
1822								currReader->dwEventState |= SCARD_STATE_CHANGED;
1823							dwBreakFlag = 1;
1824						}
1825					}
1826					else
1827					{
1828						/*
1829						 * App thinks card is mute but it is not
1830						 */
1831						if (currReader->dwCurrentState & SCARD_STATE_MUTE)
1832						{
1833							currReader->dwEventState |=
1834								SCARD_STATE_CHANGED;
1835							dwBreakFlag = 1;
1836						}
1837					}
1838				}
1839
1840				/*
1841				 * Now figure out sharing modes
1842				 */
1843				DWORD sharing = SharedReaderState_Sharing(rContext);
1844				if (sharing == -1)
1845				{
1846					currReader->dwEventState |= SCARD_STATE_EXCLUSIVE;
1847					currReader->dwEventState &= ~SCARD_STATE_INUSE;
1848					if (currReader->dwCurrentState & SCARD_STATE_INUSE)
1849					{
1850						currReader->dwEventState |= SCARD_STATE_CHANGED;
1851						dwBreakFlag = 1;
1852					}
1853				}
1854				else if (sharing >= 1)
1855				{
1856					/*
1857					 * A card must be inserted for it to be INUSE
1858					 */
1859					if (dwState & SCARD_PRESENT)
1860					{
1861						currReader->dwEventState |= SCARD_STATE_INUSE;
1862						currReader->dwEventState &= ~SCARD_STATE_EXCLUSIVE;
1863						if (currReader-> dwCurrentState & SCARD_STATE_EXCLUSIVE)
1864						{
1865							currReader->dwEventState |= SCARD_STATE_CHANGED;
1866							dwBreakFlag = 1;
1867						}
1868					}
1869				}
1870				else if (sharing == 0)
1871				{
1872					currReader->dwEventState &= ~SCARD_STATE_INUSE;
1873					currReader->dwEventState &= ~SCARD_STATE_EXCLUSIVE;
1874
1875					if (currReader->dwCurrentState & SCARD_STATE_INUSE)
1876					{
1877						currReader->dwEventState |= SCARD_STATE_CHANGED;
1878						dwBreakFlag = 1;
1879					}
1880					else if (currReader-> dwCurrentState
1881						& SCARD_STATE_EXCLUSIVE)
1882					{
1883						currReader->dwEventState |= SCARD_STATE_CHANGED;
1884						dwBreakFlag = 1;
1885					}
1886				}
1887
1888				if (currReader->dwCurrentState == SCARD_STATE_UNAWARE)
1889				{
1890					/*
1891					 * Break out of the while .. loop and return status
1892					 * once all the status's for all readers is met
1893					 */
1894					currReader->dwEventState |= SCARD_STATE_CHANGED;
1895					dwBreakFlag = 1;
1896				}
1897
1898			}	/* End of SCARD_STATE_UNKNOWN */
1899
1900		}	/* End of SCARD_STATE_IGNORE */
1901
1902		/*
1903		 * Counter and resetter
1904		 */
1905		j = j + 1;
1906		if (j == cReaders)
1907		{
1908			if (!dwBreakFlag)
1909			{
1910				/* break if the reader count changed,
1911				 * so that the calling application can update
1912				 * the reader list
1913				 */
1914				if (ReaderCountChanged)
1915					break;
1916			}
1917			j = 0;
1918		}
1919
1920		/*
1921		 * Declare all the break conditions
1922		 */
1923
1924		if (psContextMap[dwContextIndex].contextBlockStatus
1925				== BLOCK_STATUS_RESUME)
1926			break;
1927
1928		/*
1929		 * Break if UNAWARE is set and all readers have been checked
1930		 */
1931		if ((dwBreakFlag == 1) && (j == 0))
1932			break;
1933
1934		/*
1935		 * Timeout has occurred and all readers checked
1936		 */
1937		if ((dwTimeout == 0) && (j == 0))
1938			break;
1939
1940		if (dwTimeout != INFINITE && dwTimeout != 0)
1941		{
1942			/*
1943			 * If time is greater than timeout and all readers have been
1944			 * checked
1945			 */
1946			if ((dwTime >= (dwTimeout * 1000)) && (j == 0))
1947			{
1948				SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
1949				return SCARD_E_TIMEOUT;
1950			}
1951		}
1952
1953		/*
1954		 * Only sleep once for each cycle of reader checks.
1955		 */
1956		if (j == 0)
1957		{
1958			SYS_USleep(PCSCLITE_STATUS_WAIT);
1959			dwTime += PCSCLITE_STATUS_WAIT;
1960		}
1961	}
1962	while (1);
1963
1964	Log1(PCSC_LOG_DEBUG, "Event Loop End");
1965
1966	if (psContextMap[dwContextIndex].contextBlockStatus ==
1967			BLOCK_STATUS_RESUME)
1968	{
1969		SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
1970		return SCARD_E_CANCELLED;
1971	}
1972
1973	SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
1974
1975	PROFILE_END
1976
1977	return SCARD_S_SUCCESS;
1978}
1979
1980#undef SCardControl
1981
1982LONG SCardControl(SCARDHANDLE hCard, const void *pbSendBuffer,
1983	DWORD cbSendLength, void *pbRecvBuffer, LPDWORD pcbRecvLength)
1984{
1985
1986	SCARD_IO_REQUEST pioSendPci, pioRecvPci;
1987
1988	pioSendPci.dwProtocol = SCARD_PROTOCOL_RAW;
1989	pioRecvPci.dwProtocol = SCARD_PROTOCOL_RAW;
1990
1991	return SCardTransmit(hCard, &pioSendPci, pbSendBuffer, cbSendLength,
1992		&pioRecvPci, pbRecvBuffer, pcbRecvLength);
1993}
1994
1995/**
1996 * @brief This function sends a command directly to the IFD Handler to be
1997 * processed by the reader.
1998 *
1999 * This is useful for creating client side reader drivers for functions like
2000 * PIN pads, biometrics, or other extensions to the normal smart card reader
2001 * that are not normally handled by PC/SC.
2002 *
2003 * @note the API of this function changed. In pcsc-lite 1.2.0 and before the
2004 * API was not Windows(R) PC/SC compatible. This has been corrected.
2005 *
2006 * @param[in] hCard Connection made from SCardConnect.
2007 * @param[in] dwControlCode Control code for the operation.\n
2008 * <a href="http://pcsclite.alioth.debian.org/pcsc-lite/node26.html#Some_SCardControl_commands">
2009 * Click here</a> for a list of supported commands by some drivers.
2010 * @param[in] pbSendBuffer Command to send to the reader.
2011 * @param[in] cbSendLength Length of the command.
2012 * @param[out] pbRecvBuffer Response from the reader.
2013 * @param[in] cbRecvLength Length of the response buffer.
2014 * @param[out] lpBytesReturned Length of the response.
2015 *
2016 * @return Error code.
2017 * @retval SCARD_S_SUCCESS Successful (\ref SCARD_S_SUCCESS)
2018 * @retval SCARD_E_NOT_TRANSACTED Data exchange not successful (\ref SCARD_E_NOT_TRANSACTED)
2019 * @retval SCARD_E_INVALID_HANDLE Invalid hCard handle (\ref SCARD_E_INVALID_HANDLE)
2020 * @retval SCARD_E_INVALID_VALUE Invalid value was presented (\ref SCARD_E_INVALID_VALUE)
2021 * @retval SCARD_E_READER_UNAVAILABLE The reader has been removed(\ref SCARD_E_READER_UNAVAILABLE)
2022 * @retval SCARD_W_RESET_CARD The card has been reset by another application (\ref SCARD_W_RESET_CARD)
2023 * @retval SCARD_W_REMOVED_CARD The card has been removed from the reader(\ref SCARD_W_REMOVED_CARD)
2024 *
2025 * @test
2026 * @code
2027 * LONG rv;
2028 * SCARDCONTEXT hContext;
2029 * SCARDHANDLE hCard;
2030 * DWORD dwActiveProtocol, dwSendLength, dwRecvLength;
2031 * BYTE pbRecvBuffer[10];
2032 * BYTE pbSendBuffer[] = { 0x06, 0x00, 0x0A, 0x01, 0x01, 0x10 0x00 };
2033 * ...
2034 * rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext);
2035 * rv = SCardConnect(hContext, "Reader X", SCARD_SHARE_SHARED, SCARD_PROTOCOL_RAW &hCard, &dwActiveProtocol);
2036 * dwSendLength = sizeof(pbSendBuffer);
2037 * dwRecvLength = sizeof(pbRecvBuffer);
2038 * rv = SCardControl(hCard, 0x42000001, pbSendBuffer, dwSendLength, pbRecvBuffer, sizeof(pbRecvBuffer), &dwRecvLength);
2039 * @endcode
2040 */
2041int32_t SCardControl132(SCARDHANDLE hCard, DWORD dwControlCode, LPCVOID pbSendBuffer,
2042	DWORD cbSendLength, LPVOID pbRecvBuffer, DWORD cbRecvLength,
2043	LPDWORD lpBytesReturned)
2044{
2045	// Real implementation to be provided as part of:
2046	//	<rdar://problem/4711576> Support the new SCardControl function
2047	//
2048
2049	LONG rv;
2050	control_struct scControlStruct;
2051	sharedSegmentMsg msgStruct;
2052	int i;
2053	DWORD dwContextIndex, dwChannelIndex;
2054
2055	PROFILE_START
2056
2057	/* 0 bytes received by default */
2058	if (NULL != lpBytesReturned)
2059		*lpBytesReturned = 0;
2060
2061	if (SCardCheckDaemonAvailability() != SCARD_S_SUCCESS)
2062		return SCARD_E_NO_SERVICE;
2063
2064	/*
2065	 * Make sure this handle has been opened
2066	 */
2067	rv = SCardGetIndicesFromHandle(hCard, &dwContextIndex, &dwChannelIndex);
2068
2069	if (rv == -1)
2070		return SCARD_E_INVALID_HANDLE;
2071
2072	SYS_MutexLock(psContextMap[dwContextIndex].mMutex);
2073
2074	for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
2075	{
2076		char *r = psContextMap[dwContextIndex].psChannelMap[dwChannelIndex].readerName;
2077
2078		/* by default r == NULL */
2079		if (SharedReaderState_ReaderNameIsEqual(readerStates[i], r))
2080			break;
2081	}
2082
2083	if (i == PCSCLITE_MAX_READERS_CONTEXTS)
2084	{
2085		SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
2086		return SCARD_E_READER_UNAVAILABLE;
2087	}
2088
2089	if ((cbSendLength > MAX_BUFFER_SIZE_EXTENDED)
2090		|| (cbRecvLength > MAX_BUFFER_SIZE_EXTENDED))
2091	{
2092		SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
2093		return SCARD_E_INSUFFICIENT_BUFFER;
2094	}
2095
2096	if ((cbSendLength > MAX_BUFFER_SIZE) || (cbRecvLength > MAX_BUFFER_SIZE))
2097	{
2098		/* extended control */
2099		unsigned char buffer[sizeof(sharedSegmentMsg) + MAX_BUFFER_SIZE_EXTENDED];
2100		control_struct_extended *scControlStructExtended = (control_struct_extended *)buffer;
2101		sharedSegmentMsg *pmsgStruct = (psharedSegmentMsg)buffer;
2102
2103		scControlStructExtended->hCard = hCard;
2104		scControlStructExtended->dwControlCode = dwControlCode;
2105		scControlStructExtended->cbSendLength = cbSendLength;
2106		scControlStructExtended->cbRecvLength = cbRecvLength;
2107		scControlStructExtended->size = sizeof(*scControlStructExtended) + cbSendLength;
2108		memcpy(scControlStructExtended->data, pbSendBuffer, cbSendLength);
2109
2110		size_t csesize = scControlStructExtended->size;		// remember it from before byte swap
2111		htonlControlStructExtended(scControlStructExtended);
2112		rv = WrapSHMWrite(SCARD_CONTROL_EXTENDED,
2113			psContextMap[dwContextIndex].dwClientID,
2114			csesize,
2115			SHMClientCommunicationTimeout(), buffer);
2116
2117		if (rv == -1)
2118		{
2119			SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
2120			return SCARD_E_NO_SERVICE;
2121		}
2122
2123		/*
2124		 * Read a message from the server
2125		 */
2126		/* read the first block */
2127		rv = SHMClientReadMessage(pmsgStruct, psContextMap[dwContextIndex].dwClientID, 0, SHMClientCommunicationTimeout());
2128		if (rv == -1)
2129		{
2130			SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
2131			return SCARD_F_COMM_ERROR;
2132		}
2133
2134		/* we receive a sharedSegmentMsg and not a control_struct_extended */
2135		scControlStructExtended = (control_struct_extended *)&(pmsgStruct -> data);
2136		ntohlControlStructExtended(scControlStructExtended);
2137
2138		/* a second block is present */
2139		if (scControlStructExtended->size > PCSCLITE_MAX_MESSAGE_SIZE)
2140		{
2141			rv = SHMMessageReceive(buffer + sizeof(sharedSegmentMsg),
2142				scControlStructExtended->size-PCSCLITE_MAX_MESSAGE_SIZE,
2143				psContextMap[dwContextIndex].dwClientID,
2144				SHMClientCommunicationTimeout());
2145			if (rv == -1)
2146			{
2147				SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
2148				return SCARD_F_COMM_ERROR;
2149			}
2150		}
2151
2152		if (scControlStructExtended -> rv == SCARD_S_SUCCESS)
2153		{
2154			/*
2155			 * Copy and zero it so any secret information is not leaked
2156			 */
2157			memcpy(pbRecvBuffer, scControlStructExtended -> data,
2158				scControlStructExtended -> pdwBytesReturned);
2159			memset(scControlStructExtended -> data, 0x00,
2160				scControlStructExtended -> pdwBytesReturned);
2161		}
2162
2163		if (NULL != lpBytesReturned)
2164			*lpBytesReturned = scControlStructExtended -> pdwBytesReturned;
2165
2166		rv = scControlStructExtended -> rv;
2167	}
2168	else
2169	{
2170		scControlStruct.hCard = hCard;
2171		scControlStruct.dwControlCode = dwControlCode;
2172		scControlStruct.cbSendLength = cbSendLength;
2173		scControlStruct.cbRecvLength = cbRecvLength;
2174		memcpy(scControlStruct.pbSendBuffer, pbSendBuffer, cbSendLength);
2175		htonlControlStruct(&scControlStruct);
2176
2177		rv = WrapSHMWrite(SCARD_CONTROL, psContextMap[dwContextIndex].dwClientID,
2178			sizeof(scControlStruct), SHMClientCommunicationTimeout(), &scControlStruct);
2179
2180		if (rv == -1)
2181		{
2182			SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
2183			return SCARD_E_NO_SERVICE;
2184		}
2185
2186		/*
2187		 * Read a message from the server
2188		 */
2189		rv = SHMClientReadMessage(&msgStruct, psContextMap[dwContextIndex].dwClientID, sizeof(control_struct), SHMClientCommunicationTimeout());
2190
2191		if (rv == -1)
2192		{
2193			SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
2194			return SCARD_F_COMM_ERROR;
2195		}
2196
2197		memcpy(&scControlStruct, &msgStruct.data, sizeof(scControlStruct));
2198		ntohlControlStruct(&scControlStruct);
2199
2200		if (NULL != lpBytesReturned)
2201			*lpBytesReturned = scControlStruct.dwBytesReturned;
2202
2203		if (scControlStruct.rv == SCARD_S_SUCCESS)
2204		{
2205			/*
2206			 * Copy and zero it so any secret information is not leaked
2207			 */
2208			memcpy(pbRecvBuffer, scControlStruct.pbRecvBuffer,
2209				scControlStruct.cbRecvLength);
2210			memset(scControlStruct.pbRecvBuffer, 0x00,
2211				sizeof(scControlStruct.pbRecvBuffer));
2212		}
2213
2214		rv = scControlStruct.rv;
2215	}
2216
2217	SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
2218
2219	PROFILE_END
2220
2221	return rv;
2222}
2223
2224/**
2225 * This function get an attribute from the IFD Handler. The list of possible
2226 * attributes is available in the file \c pcsclite.h.
2227 *
2228 * @param[in] hCard Connection made from SCardConnect().
2229 * @param[in] dwAttrId Identifier for the attribute to get.
2230 * <ul>
2231 *   <li>\ref SCARD_ATTR_ASYNC_PROTOCOL_TYPES
2232 *   <li>\ref SCARD_ATTR_ATR_STRING
2233 *   <li>\ref SCARD_ATTR_CHANNEL_ID
2234 *   <li>\ref SCARD_ATTR_CHARACTERISTICS
2235 *   <li>\ref SCARD_ATTR_CURRENT_BWT
2236 *   <li>\ref SCARD_ATTR_CURRENT_CLK
2237 *   <li>\ref SCARD_ATTR_CURRENT_CWT
2238 *   <li>\ref SCARD_ATTR_CURRENT_D
2239 *   <li>\ref SCARD_ATTR_CURRENT_EBC_ENCODING
2240 *   <li>\ref SCARD_ATTR_CURRENT_F
2241 *   <li>\ref SCARD_ATTR_CURRENT_IFSC
2242 *   <li>\ref SCARD_ATTR_CURRENT_IFSD
2243 *   <li>\ref SCARD_ATTR_CURRENT_IO_STATE
2244 *   <li>\ref SCARD_ATTR_CURRENT_N
2245 *   <li>\ref SCARD_ATTR_CURRENT_PROTOCOL_TYPE
2246 *   <li>\ref SCARD_ATTR_CURRENT_W
2247 *   <li>\ref SCARD_ATTR_DEFAULT_CLK
2248 *   <li>\ref SCARD_ATTR_DEFAULT_DATA_RATE
2249 *   <li>\ref SCARD_ATTR_DEVICE_FRIENDLY_NAME_A
2250 *   <li>\ref SCARD_ATTR_DEVICE_FRIENDLY_NAME_W
2251 *   <li>\ref SCARD_ATTR_DEVICE_IN_USE
2252 *   <li>\ref SCARD_ATTR_DEVICE_SYSTEM_NAME_A
2253 *   <li>\ref SCARD_ATTR_DEVICE_SYSTEM_NAME_W
2254 *   <li>\ref SCARD_ATTR_DEVICE_UNIT
2255 *   <li>\ref SCARD_ATTR_ESC_AUTHREQUEST
2256 *   <li>\ref SCARD_ATTR_ESC_CANCEL
2257 *   <li>\ref SCARD_ATTR_ESC_RESET
2258 *   <li>\ref SCARD_ATTR_EXTENDED_BWT
2259 *   <li>\ref SCARD_ATTR_ICC_INTERFACE_STATUS
2260 *   <li>\ref SCARD_ATTR_ICC_PRESENCE
2261 *   <li>\ref SCARD_ATTR_ICC_TYPE_PER_ATR
2262 *   <li>\ref SCARD_ATTR_MAX_CLK
2263 *   <li>\ref SCARD_ATTR_MAX_DATA_RATE
2264 *   <li>\ref SCARD_ATTR_MAX_IFSD
2265 *   <li>\ref SCARD_ATTR_MAXINPUT
2266 *   <li>\ref SCARD_ATTR_POWER_MGMT_SUPPORT
2267 *   <li>\ref SCARD_ATTR_SUPRESS_T1_IFS_REQUEST
2268 *   <li>\ref SCARD_ATTR_SYNC_PROTOCOL_TYPES
2269 *   <li>\ref SCARD_ATTR_USER_AUTH_INPUT_DEVICE
2270 *   <li>\ref SCARD_ATTR_USER_TO_CARD_AUTH_DEVICE
2271 *   <li>\ref SCARD_ATTR_VENDOR_IFD_SERIAL_NO
2272 *   <li>\ref SCARD_ATTR_VENDOR_IFD_TYPE
2273 *   <li>\ref SCARD_ATTR_VENDOR_IFD_VERSION
2274 *   <li>\ref SCARD_ATTR_VENDOR_NAME
2275 * </ul>
2276 *
2277 * Not all the dwAttrId values listed above may be implemented in the IFD
2278 * Handler you are using. And some dwAttrId values not listed here may be
2279 * implemented.
2280 *
2281 * @param[out] pbAttr Pointer to a buffer that receives the attribute.
2282 * @param pcbAttrLen [inout] Length of the \p pbAttr buffer in bytes.
2283 *
2284 * @return Error code.
2285 * @retval SCARD_S_SUCCESS Successful (\ref SCARD_S_SUCCESS)
2286 * @retval SCARD_E_NOT_TRANSACTED Data exchange not successful (\ref SCARD_E_NOT_TRANSACTED)
2287 * @retval SCARD_E_INSUFFICIENT_BUFFER Reader buffer not large enough (\ref SCARD_E_INSUFFICIENT_BUFFER)
2288 *
2289 * @test
2290 * @code
2291 * LONG rv;
2292 * SCARDCONTEXT hContext;
2293 * SCARDHANDLE hCard;
2294 * DWORD dwActiveProtocol;
2295 * unsigned char pbAtr[MAX_ATR_SIZE];
2296 * DWORD dwAtrLen;
2297 * ...
2298 * rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext);
2299 * rv = SCardConnect(hContext, "Reader X", SCARD_SHARE_SHARED,
2300 *                           SCARD_PROTOCOL_RAW &hCard, &dwActiveProtocol);
2301 * rv = SCardGetAttrib(hCard, SCARD_ATTR_ATR_STRING, pbAtr, &dwAtrLen);
2302 * @endcode
2303 */
2304
2305int32_t SCardGetAttrib(SCARDHANDLE hCard, uint32_t dwAttrId, uint8_t * pbAttr,
2306	uint32_t * pcbAttrLen)
2307{
2308	PROFILE_START
2309
2310	if (NULL == pcbAttrLen)
2311		return SCARD_E_INVALID_PARAMETER;
2312
2313	/* if only get the length */
2314	if (NULL == pbAttr)
2315		/* this variable may not be set by the caller. use a reasonable size */
2316		*pcbAttrLen = MAX_BUFFER_SIZE;
2317
2318	PROFILE_END
2319
2320	return SCardGetSetAttrib(hCard, SCARD_GET_ATTRIB, dwAttrId, pbAttr,
2321		pcbAttrLen);
2322}
2323
2324/**
2325 * @brief This function set an attribute of the IFD Handler.
2326 *
2327 * The list of attributes you can set is dependent on the IFD Handler you are
2328 * using.
2329 *
2330 * @param[in] hCard Connection made from SCardConnect().
2331 * @param[in] dwAttrId Identifier for the attribute to set.
2332 * @param[in] pbAttr Pointer to a buffer that receives the attribute.
2333 * @param[in] cbAttrLen Length of the \p pbAttr buffer in bytes.
2334 *
2335 * @return Error code
2336 * @retval SCARD_S_SUCCESS Successful (\ref SCARD_S_SUCCESS)
2337 * @retval SCARD_E_NOT_TRANSACTED Data exchange not successful (\ref SCARD_E_NOT_TRANSACTED)
2338 *
2339 * @test
2340 * @code
2341 * LONG rv;
2342 * SCARDCONTEXT hContext;
2343 * SCARDHANDLE hCard;
2344 * DWORD dwActiveProtocol;
2345 * unsigned char pbAtr[MAX_ATR_SIZE];
2346 * DWORD dwAtrLen;
2347 * ...
2348 * rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext);
2349 * rv = SCardConnect(hContext, "Reader X", SCARD_SHARE_SHARED,
2350 *                   SCARD_PROTOCOL_RAW &hCard, &dwActiveProtocol);
2351 * rv = SCardSetAttrib(hCard, 0x42000001, "\x12\x34\x56", 3);
2352 * @endcode
2353 */
2354
2355int32_t SCardSetAttrib(SCARDHANDLE hCard, uint32_t dwAttrId, const uint8_t *pbAttr,
2356	uint32_t cbAttrLen)
2357{
2358	PROFILE_START
2359
2360	if (NULL == pbAttr || 0 == cbAttrLen)
2361		return SCARD_E_INVALID_PARAMETER;
2362
2363	PROFILE_END
2364
2365	return SCardGetSetAttrib(hCard, SCARD_SET_ATTRIB, dwAttrId, (LPBYTE)pbAttr,
2366		&cbAttrLen);
2367}
2368
2369static LONG SCardGetSetAttrib(SCARDHANDLE hCard, int command, DWORD dwAttrId,
2370	LPBYTE pbAttr, LPDWORD pcbAttrLen)
2371{
2372	PROFILE_START
2373
2374	LONG rv;
2375	getset_struct scGetSetStruct;
2376	sharedSegmentMsg msgStruct;
2377	int i;
2378	DWORD dwContextIndex, dwChannelIndex;
2379
2380	if (SCardCheckDaemonAvailability() != SCARD_S_SUCCESS)
2381		return SCARD_E_NO_SERVICE;
2382
2383	/*
2384	 * Make sure this handle has been opened
2385	 */
2386	rv = SCardGetIndicesFromHandle(hCard, &dwContextIndex, &dwChannelIndex);
2387
2388	if (rv == -1)
2389		return SCARD_E_INVALID_HANDLE;
2390
2391	SYS_MutexLock(psContextMap[dwContextIndex].mMutex);
2392
2393	for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
2394	{
2395		char *r = psContextMap[dwContextIndex].psChannelMap[dwChannelIndex].readerName;
2396
2397		/* by default r == NULL */
2398		if (SharedReaderState_ReaderNameIsEqual(readerStates[i], r))
2399			break;
2400	}
2401
2402	if (i == PCSCLITE_MAX_READERS_CONTEXTS)
2403	{
2404		SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
2405		return SCARD_E_READER_UNAVAILABLE;
2406	}
2407
2408	if (*pcbAttrLen > MAX_BUFFER_SIZE)
2409	{
2410		SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
2411		return SCARD_E_INSUFFICIENT_BUFFER;
2412	}
2413
2414	scGetSetStruct.hCard = hCard;
2415	scGetSetStruct.dwAttrId = dwAttrId;
2416	scGetSetStruct.cbAttrLen = *pcbAttrLen;
2417	scGetSetStruct.rv = SCARD_E_NO_SERVICE;
2418	if (SCARD_SET_ATTRIB == command)
2419		memcpy(scGetSetStruct.pbAttr, pbAttr, *pcbAttrLen);
2420
2421	ntohlGetSetStruct(&scGetSetStruct);
2422	rv = WrapSHMWrite(command,
2423		psContextMap[dwContextIndex].dwClientID, sizeof(scGetSetStruct),
2424		SHMClientCommunicationTimeout(), &scGetSetStruct);
2425
2426	if (rv == -1)
2427	{
2428		SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
2429		return SCARD_E_NO_SERVICE;
2430	}
2431
2432	/*
2433	 * Read a message from the server
2434	 */
2435	rv = SHMClientReadMessage(&msgStruct, psContextMap[dwContextIndex].dwClientID, sizeof(getset_struct), SHMClientCommunicationTimeout());
2436
2437	if (rv == -1)
2438	{
2439		SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
2440		return SCARD_F_COMM_ERROR;
2441	}
2442
2443	memcpy(&scGetSetStruct, &msgStruct.data, sizeof(scGetSetStruct));
2444	ntohlGetSetStruct(&scGetSetStruct);
2445
2446	if ((SCARD_S_SUCCESS == scGetSetStruct.rv) && (SCARD_GET_ATTRIB == command))
2447	{
2448		/*
2449		 * Copy and zero it so any secret information is not leaked
2450		 */
2451		if (*pcbAttrLen < scGetSetStruct.cbAttrLen)
2452		{
2453			scGetSetStruct.cbAttrLen = *pcbAttrLen;
2454			scGetSetStruct.rv = SCARD_E_INSUFFICIENT_BUFFER;
2455		}
2456		else
2457			*pcbAttrLen = scGetSetStruct.cbAttrLen;
2458
2459		if (pbAttr)
2460			memcpy(pbAttr, scGetSetStruct.pbAttr, scGetSetStruct.cbAttrLen);
2461
2462		memset(scGetSetStruct.pbAttr, 0x00, sizeof(scGetSetStruct.pbAttr));
2463	}
2464
2465	SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
2466
2467	PROFILE_END
2468
2469	return scGetSetStruct.rv;
2470}
2471
2472/**
2473 * @brief This function sends an APDU to the smart card contained in the reader
2474 * connected to by SCardConnect().
2475 *
2476 * The card responds from the APDU and stores this response in pbRecvBuffer
2477 * and it's length in SpcbRecvLength.
2478 * SSendPci and SRecvPci are structures containing the following:
2479 * @code
2480 * typedef struct {
2481 *    DWORD dwProtocol;    // SCARD_PROTOCOL_T0 or SCARD_PROTOCOL_T1
2482 *    DWORD cbPciLength;   // Length of this structure - not used
2483 * } SCARD_IO_REQUEST;
2484 * @endcode
2485 *
2486 * @param[in] hCard Connection made from SCardConnect().
2487 * @param pioSendPci [inout] Structure of protocol information.
2488 * <ul>
2489 *   <li>\ref SCARD_PCI_T0 - Pre-defined T=0 PCI structure.
2490 *   <li>\ref SCARD_PCI_T1 - Pre-defined T=1 PCI structure.
2491 * </ul>
2492 * @param[in] pbSendBuffer APDU to send to the card.
2493 * @param[in] cbSendLength Length of the APDU.
2494 * @param pioRecvPci [inout] Structure of protocol information.
2495 * @param[out] pbRecvBuffer Response from the card.
2496 * @param pcbRecvLength [inout] Length of the response.
2497 *
2498 * @return Error code.
2499 * @retval SCARD_S_SUCCESS Successful (\ref SCARD_S_SUCCESS)
2500 * @retval SCARD_E_INVALID_HANDLE Invalid hCard handle (\ref SCARD_E_INVALID_HANDLE)
2501 * @retval SCARD_E_NOT_TRANSACTED APDU exchange not successful (\ref SCARD_E_NOT_TRANSACTED)
2502 * @retval SCARD_E_PROTO_MISMATCH Connect protocol is different than desired (\ref SCARD_E_PROTO_MISMATCH)
2503 * @retval SCARD_E_INVALID_VALUE Invalid Protocol, reader name, etc (\ref SCARD_E_INVALID_VALUE)
2504 * @retval SCARD_E_READER_UNAVAILABLE The reader has been removed (\ref SCARD_E_READER_UNAVAILABLE)
2505 * @retval SCARD_W_RESET_CARD The card has been reset by another application (\ref SCARD_W_RESET_CARD)
2506 * @retval SCARD_W_REMOVED_CARD The card has been removed from the reader (\ref SCARD_W_REMOVED_CARD)
2507 *
2508 * @test
2509 * @code
2510 * LONG rv;
2511 * SCARDCONTEXT hContext;
2512 * SCARDHANDLE hCard;
2513 * DWORD dwActiveProtocol, dwSendLength, dwRecvLength;
2514 * SCARD_IO_REQUEST pioRecvPci;
2515 * BYTE pbRecvBuffer[10];
2516 * BYTE pbSendBuffer[] = { 0xC0, 0xA4, 0x00, 0x00, 0x02, 0x3F, 0x00 };
2517 * ...
2518 * rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext);
2519 * rv = SCardConnect(hContext, "Reader X", SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0, &hCard, &dwActiveProtocol);
2520 * dwSendLength = sizeof(pbSendBuffer);
2521 * dwRecvLength = sizeof(pbRecvBuffer);
2522 * rv = SCardTransmit(hCard, SCARD_PCI_T0, pbSendBuffer, dwSendLength, &pioRecvPci, pbRecvBuffer, &dwRecvLength);
2523 * @endcode
2524 */
2525#include <syslog.h>
2526LONG SCardTransmit(SCARDHANDLE hCard, LPCSCARD_IO_REQUEST pioSendPci,
2527	LPCBYTE pbSendBuffer, DWORD cbSendLength,
2528	LPSCARD_IO_REQUEST pioRecvPci, LPBYTE pbRecvBuffer,
2529	LPDWORD pcbRecvLength)
2530{
2531	LONG rv;
2532	int i;
2533	DWORD dwContextIndex, dwChannelIndex;
2534
2535	PROFILE_START
2536
2537	if (pbSendBuffer == NULL || pbRecvBuffer == NULL ||
2538			pcbRecvLength == NULL || pioSendPci == NULL)
2539		return SCARD_E_INVALID_PARAMETER;
2540
2541	if (SCardCheckDaemonAvailability() != SCARD_S_SUCCESS)
2542		return SCARD_E_NO_SERVICE;
2543
2544	/*
2545	 * Make sure this handle has been opened
2546	 */
2547	rv = SCardGetIndicesFromHandle(hCard, &dwContextIndex, &dwChannelIndex);
2548
2549	if (rv == -1)
2550	{
2551		*pcbRecvLength = 0;
2552		return SCARD_E_INVALID_HANDLE;
2553	}
2554
2555	SYS_MutexLock(psContextMap[dwContextIndex].mMutex);
2556
2557	for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
2558	{
2559		char *r = psContextMap[dwContextIndex].psChannelMap[dwChannelIndex].readerName;
2560
2561		/* by default r == NULL */
2562		if (SharedReaderState_ReaderNameIsEqual(readerStates[i], r))
2563			break;
2564	}
2565
2566	if (i == PCSCLITE_MAX_READERS_CONTEXTS)
2567	{
2568		SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
2569		return SCARD_E_READER_UNAVAILABLE;
2570	}
2571
2572	if ((cbSendLength > MAX_BUFFER_SIZE_EXTENDED)
2573		|| (*pcbRecvLength > MAX_BUFFER_SIZE_EXTENDED))
2574	{
2575		SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
2576		return SCARD_E_INSUFFICIENT_BUFFER;
2577	}
2578
2579	if ((cbSendLength > MAX_BUFFER_SIZE) || (*pcbRecvLength > MAX_BUFFER_SIZE))
2580	{
2581		/* extended APDU */
2582		unsigned char buffer[sizeof(sharedSegmentMsg) + MAX_BUFFER_SIZE_EXTENDED];
2583		const sharedSegmentMsg *pmsgStruct = (psharedSegmentMsg)buffer;
2584		transmit_struct_extended *scTransmitStructExtended = (transmit_struct_extended *)buffer;
2585
2586		scTransmitStructExtended->hCard = hCard;
2587		scTransmitStructExtended->cbSendLength = cbSendLength;
2588		scTransmitStructExtended->pcbRecvLength = *pcbRecvLength;
2589		scTransmitStructExtended->size = sizeof(*scTransmitStructExtended) + cbSendLength;
2590		scTransmitStructExtended->pioSendPciProtocol = pioSendPci->dwProtocol;
2591		scTransmitStructExtended->pioSendPciLength = pioSendPci->cbPciLength;
2592		memcpy(scTransmitStructExtended->data, pbSendBuffer, cbSendLength);
2593		secdebug("pcscd", "Extended APDU: initial request: hCard: 0x%08X, cbSendLength: %d",
2594			hCard, cbSendLength);
2595		secdebug("pcscd", "               pcbRecvLength: %d", *pcbRecvLength);
2596
2597		if (pioRecvPci)
2598		{
2599			scTransmitStructExtended->pioRecvPciProtocol = pioRecvPci->dwProtocol;
2600			scTransmitStructExtended->pioRecvPciLength = pioRecvPci->cbPciLength;
2601		}
2602		else
2603			scTransmitStructExtended->pioRecvPciProtocol = SCARD_PROTOCOL_ANY;
2604
2605		size_t tsesize = scTransmitStructExtended->size;		// remember it before we byte swap
2606		LogXxd(PCSC_LOG_INFO, "Extended APDU: sending: ", pbSendBuffer, cbSendLength);
2607		htonlTransmitStructExtended(scTransmitStructExtended);
2608		rv = WrapSHMWrite(SCARD_TRANSMIT_EXTENDED,
2609			psContextMap[dwContextIndex].dwClientID,
2610			tsesize,
2611			SHMClientCommunicationTimeout(), buffer);
2612		secdebug("pcscd", "Extended APDU: WrapSHMWrite result: %d [0x%08X]", rv, rv);
2613
2614		if (rv == -1)
2615		{
2616			SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
2617			return SCARD_E_NO_SERVICE;
2618		}
2619
2620		/*
2621		 * Read a message from the server
2622		 */
2623		rv = SHMClientReadMessage((psharedSegmentMsg)buffer, psContextMap[dwContextIndex].dwClientID, 0, SHMClientCommunicationTimeout());
2624		if (rv == -1)
2625		{
2626			SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
2627			return SCARD_F_COMM_ERROR;
2628		}
2629
2630		/* we receive a sharedSegmentMsg and not a transmit_struct_extended */
2631		scTransmitStructExtended = (transmit_struct_extended *)pmsgStruct->data;
2632		ntohlTransmitStructExtended(scTransmitStructExtended);
2633		secdebug("pcscd", "Extended APDU: reply received: hCard: 0x%08X, cbSendLength: %d",
2634			hCard, cbSendLength);
2635		secdebug("pcscd", "               reply received: pcbRecvLength: %d, size: %llu",
2636			scTransmitStructExtended->pcbRecvLength, scTransmitStructExtended->size);
2637		secdebug("pcscd", "               reply received: rv %d [0x%08X]",
2638			scTransmitStructExtended -> rv, scTransmitStructExtended -> rv);
2639		LogXxd(PCSC_LOG_INFO, "Extended APDU: received: ", scTransmitStructExtended->data, scTransmitStructExtended->pcbRecvLength);
2640
2641		/* a second block is present */
2642		if (scTransmitStructExtended->size > PCSCLITE_MAX_MESSAGE_SIZE)
2643		{
2644			rv = SHMMessageReceive(buffer + sizeof(sharedSegmentMsg),
2645				scTransmitStructExtended->size-PCSCLITE_MAX_MESSAGE_SIZE,
2646				psContextMap[dwContextIndex].dwClientID,
2647				SHMClientCommunicationTimeout());
2648			if (rv == -1)
2649			{
2650				SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
2651				return SCARD_F_COMM_ERROR;
2652			}
2653			// we don't fix up byte order here since this is in the data portion
2654		}
2655
2656		if (scTransmitStructExtended -> rv == SCARD_S_SUCCESS)
2657		{
2658			/*
2659			 * Copy and zero it so any secret information is not leaked
2660			 */
2661			memcpy(pbRecvBuffer, scTransmitStructExtended -> data,
2662				scTransmitStructExtended -> pcbRecvLength);
2663			memset(scTransmitStructExtended -> data, 0x00,
2664				scTransmitStructExtended -> pcbRecvLength);
2665
2666			if (pioRecvPci)
2667			{
2668				pioRecvPci->dwProtocol = scTransmitStructExtended->pioRecvPciProtocol;
2669				pioRecvPci->cbPciLength = scTransmitStructExtended->pioRecvPciLength;
2670			}
2671		}
2672
2673		*pcbRecvLength = scTransmitStructExtended -> pcbRecvLength;
2674		SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
2675
2676		rv = scTransmitStructExtended -> rv;
2677	}
2678	else
2679	{
2680		/* short APDU */
2681		transmit_struct scTransmitStruct;
2682		sharedSegmentMsg msgStruct;
2683
2684		scTransmitStruct.hCard = hCard;
2685		scTransmitStruct.cbSendLength = cbSendLength;
2686		scTransmitStruct.pcbRecvLength = *pcbRecvLength;
2687		scTransmitStruct.pioSendPciProtocol = pioSendPci->dwProtocol;
2688		scTransmitStruct.pioSendPciLength = pioSendPci->cbPciLength;
2689		memcpy(scTransmitStruct.pbSendBuffer, pbSendBuffer, cbSendLength);
2690
2691		if (pioRecvPci)
2692		{
2693			scTransmitStruct.pioRecvPciProtocol = pioRecvPci->dwProtocol;
2694			scTransmitStruct.pioRecvPciLength = pioRecvPci->cbPciLength;
2695		}
2696		else
2697			scTransmitStruct.pioRecvPciProtocol = SCARD_PROTOCOL_ANY;
2698
2699		htonlTransmitStruct(&scTransmitStruct);
2700		rv = WrapSHMWrite(SCARD_TRANSMIT,
2701			psContextMap[dwContextIndex].dwClientID, sizeof(scTransmitStruct),
2702			SHMClientCommunicationTimeout(), (void *) &scTransmitStruct);
2703
2704		if (rv == -1)
2705		{
2706			SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
2707			return SCARD_E_NO_SERVICE;
2708		}
2709
2710		/*
2711		 * Read a message from the server
2712		 */
2713		rv = SHMClientReadMessage(&msgStruct, psContextMap[dwContextIndex].dwClientID, sizeof(transmit_struct), SHMClientCommunicationTimeout());
2714
2715		memcpy(&scTransmitStruct, &msgStruct.data, sizeof(scTransmitStruct));
2716		ntohlTransmitStruct(&scTransmitStruct);
2717
2718		if (rv == -1)
2719		{
2720			SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
2721			return SCARD_F_COMM_ERROR;
2722		}
2723
2724		/*
2725		 * Zero it and free it so any secret information cannot be leaked
2726		 */
2727		memset(scTransmitStruct.pbSendBuffer, 0x00, cbSendLength);
2728
2729		if (scTransmitStruct.rv == SCARD_S_SUCCESS)
2730		{
2731			/*
2732			 * Copy and zero it so any secret information is not leaked
2733			 */
2734			memcpy(pbRecvBuffer, scTransmitStruct.pbRecvBuffer,
2735				scTransmitStruct.pcbRecvLength);
2736			memset(scTransmitStruct.pbRecvBuffer, 0x00,
2737				scTransmitStruct.pcbRecvLength);
2738
2739			if (pioRecvPci)
2740			{
2741				pioRecvPci->dwProtocol = scTransmitStruct.pioRecvPciProtocol;
2742				pioRecvPci->cbPciLength = scTransmitStruct.pioRecvPciLength;
2743			}
2744		}
2745
2746		*pcbRecvLength = scTransmitStruct.pcbRecvLength;
2747		SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
2748
2749		rv = scTransmitStruct.rv;
2750	}
2751
2752	PROFILE_END
2753
2754	return rv;
2755}
2756
2757/**
2758 * This function returns a list of currently available readers on the system.
2759 * \p mszReaders is a pointer to a character string that is allocated by the application.
2760 * If the application sends mszGroups and mszReaders as NULL then this function will
2761 * return the size of the buffer needed to allocate in pcchReaders.
2762 *
2763 * @param[in] hContext Connection context to the PC/SC Resource Manager.
2764 * @param[in] mszGroups List of groups to list readers (not used).
2765 * @param[out] mszReaders Multi-string with list of readers.
2766 * @param pcchReaders [inout] Size of multi-string buffer including NULL's.
2767 *
2768 * @return Connection status.
2769 * @retval SCARD_S_SUCCESS Successful (\ref SCARD_S_SUCCESS)
2770 * @retval SCARD_E_INVALID_HANDLE Invalid Scope Handle (\ref SCARD_E_INVALID_HANDLE)
2771 * @retval SCARD_E_INSUFFICIENT_BUFFER Reader buffer not large enough (\ref SCARD_E_INSUFFICIENT_BUFFER)
2772 *
2773 * @test
2774 * @code
2775 * SCARDCONTEXT hContext;
2776 * LPSTR mszReaders;
2777 * DWORD dwReaders;
2778 * LONG rv;
2779 * ...
2780 * rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext);
2781 * rv = SCardListReaders(hContext, NULL, NULL, &dwReaders);
2782 * mszReaders = malloc(sizeof(char)*dwReaders);
2783 * rv = SCardListReaders(hContext, NULL, mszReaders, &dwReaders);
2784 * @endcode
2785 */
2786LONG SCardListReaders(SCARDCONTEXT hContext, LPCSTR mszGroups,
2787	LPSTR mszReaders, LPDWORD pcchReaders)
2788{
2789	DWORD dwReadersLen;
2790	int i, lastChrPtr;
2791	LONG dwContextIndex;
2792
2793	PROFILE_START
2794
2795	/*
2796	 * Check for NULL parameters
2797	 */
2798	if (pcchReaders == NULL)
2799		return SCARD_E_INVALID_PARAMETER;
2800
2801	if (SCardCheckDaemonAvailability() != SCARD_S_SUCCESS)
2802		return SCARD_E_NO_SERVICE;
2803
2804	/*
2805	 * Make sure this context has been opened
2806	 */
2807	dwContextIndex = SCardGetContextIndice(hContext);
2808	if (dwContextIndex == -1)
2809		return SCARD_E_INVALID_HANDLE;
2810
2811	SYS_MutexLock(psContextMap[dwContextIndex].mMutex);
2812
2813	dwReadersLen = 0;
2814	for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
2815		if (SharedReaderState_ReaderID(readerStates[i]) != 0)
2816			dwReadersLen += strlen(SharedReaderState_ReaderName(readerStates[i])) + 1;
2817
2818	/* for the last NULL byte */
2819	dwReadersLen += 1;
2820
2821	if ((mszReaders == NULL)	/* text array not allocated */
2822		|| (*pcchReaders == 0))	/* size == 0 */
2823	{
2824		*pcchReaders = dwReadersLen;
2825		SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
2826		return SCARD_S_SUCCESS;
2827	}
2828
2829	if (*pcchReaders < dwReadersLen)
2830	{
2831		*pcchReaders = dwReadersLen;
2832		SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
2833		return SCARD_E_INSUFFICIENT_BUFFER;
2834	}
2835
2836	lastChrPtr = 0;
2837	for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
2838	{
2839		if (SharedReaderState_ReaderID(readerStates[i]) != 0)
2840		{
2841			/*
2842			 * Build the multi-string
2843			 */
2844			strcpy(&mszReaders[lastChrPtr], SharedReaderState_ReaderName(readerStates[i]));
2845			lastChrPtr += strlen(SharedReaderState_ReaderName(readerStates[i]))+1;
2846		}
2847	}
2848	mszReaders[lastChrPtr] = '\0';	/* Add the last null */
2849
2850	*pcchReaders = dwReadersLen;
2851
2852	SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
2853
2854	PROFILE_END
2855
2856	return SCARD_S_SUCCESS;
2857}
2858
2859/**
2860 * @brief This function returns a list of currently available reader groups on the system.
2861 * \p mszGroups is a pointer to a character string that is allocated by the
2862 * application.  If the application sends mszGroups as NULL then this function
2863 * will return the size of the buffer needed to allocate in pcchGroups.
2864 *
2865 * The group names is a multi-string and separated by a nul character ('\\0') and ended by
2866 * a double nul character. "SCard$DefaultReaders\\0Group 2\\0\\0".
2867 *
2868 * @param[in] hContext Connection context to the PC/SC Resource Manager.
2869 * @param[out] mszGroups List of groups to list readers.
2870 * @param pcchGroups [inout] Size of multi-string buffer including NULL's.
2871 *
2872 * @return Error code.
2873 * @retval SCARD_S_SUCCESS Successful (\ref SCARD_S_SUCCESS)
2874 * @retval SCARD_E_INVALID_HANDLE Invalid Scope Handle (\ref SCARD_E_INVALID_HANDLE)
2875 * @retval SCARD_E_INSUFFICIENT_BUFFER Reader buffer not large enough (\ref SCARD_E_INSUFFICIENT_BUFFER)
2876 *
2877 * @test
2878 * @code
2879 * SCARDCONTEXT hContext;
2880 * LPSTR mszGroups;
2881 * DWORD dwGroups;
2882 * LONG rv;
2883 * ...
2884 * rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext);
2885 * rv = SCardListReaderGroups(hContext, NULL, &dwGroups);
2886 * mszGroups = malloc(sizeof(char)*dwGroups);
2887 * rv = SCardListReaderGroups(hContext, mszGroups, &dwGroups);
2888 * @endcode
2889 */
2890LONG SCardListReaderGroups(SCARDCONTEXT hContext, LPSTR mszGroups,
2891	LPDWORD pcchGroups)
2892{
2893	LONG rv = SCARD_S_SUCCESS;
2894	LONG dwContextIndex;
2895
2896	PROFILE_START
2897
2898	const char ReaderGroup[] = "SCard$DefaultReaders";
2899	const int dwGroups = strlen(ReaderGroup) + 2;
2900
2901	if (SCardCheckDaemonAvailability() != SCARD_S_SUCCESS)
2902		return SCARD_E_NO_SERVICE;
2903
2904	/*
2905	 * Make sure this context has been opened
2906	 */
2907	dwContextIndex = SCardGetContextIndice(hContext);
2908	if (dwContextIndex == -1)
2909		return SCARD_E_INVALID_HANDLE;
2910
2911	SYS_MutexLock(psContextMap[dwContextIndex].mMutex);
2912
2913	if (mszGroups)
2914	{
2915
2916		if (*pcchGroups < dwGroups)
2917			rv = SCARD_E_INSUFFICIENT_BUFFER;
2918		else
2919		{
2920			memset(mszGroups, 0, dwGroups);
2921			memcpy(mszGroups, ReaderGroup, strlen(ReaderGroup));
2922		}
2923	}
2924
2925	*pcchGroups = dwGroups;
2926
2927	SYS_MutexUnLock(psContextMap[dwContextIndex].mMutex);
2928
2929	PROFILE_END
2930
2931	return rv;
2932}
2933
2934/**
2935 * This function cancels all pending blocking requests on the
2936 * SCardGetStatusChange() function.
2937 *
2938 * @param[in] hContext Connection context to the PC/SC Resource Manager.
2939 *
2940 * @return Error code.
2941 * @retval SCARD_S_SUCCESS Successful (\ref SCARD_S_SUCCESS)
2942 * @retval SCARD_E_INVALID_HANDLE Invalid \p hContext handle (\ref SCARD_E_INVALID_HANDLE)
2943 *
2944 * @test
2945 * @code
2946 * SCARDCONTEXT hContext;
2947 * DWORD cReaders;
2948 * SCARD_READERSTATE rgReaderStates;
2949 * LONG rv;
2950 * ...
2951 * rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext);
2952 * rgReaderStates.szReader = strdup("Reader X");
2953 * rgReaderStates.dwCurrentState = SCARD_STATE_EMPTY;
2954 * ...
2955 * / * Spawn off thread for following function * /
2956 * ...
2957 * rv = SCardGetStatusChange(hContext, 0, rgReaderStates, cReaders);
2958 * rv = SCardCancel(hContext);
2959 * @endcode
2960 */
2961LONG SCardCancel(SCARDCONTEXT hContext)
2962{
2963	LONG dwContextIndex;
2964
2965	PROFILE_START
2966
2967	dwContextIndex = SCardGetContextIndice(hContext);
2968
2969	if (dwContextIndex == -1)
2970		return SCARD_E_INVALID_HANDLE;
2971
2972	/*
2973	 * Set the block status for this Context so blocking calls will
2974	 * complete
2975	 */
2976	psContextMap[dwContextIndex].contextBlockStatus = BLOCK_STATUS_RESUME;
2977
2978	PROFILE_END
2979
2980	return SCARD_S_SUCCESS;
2981}
2982
2983/**
2984 * @brief check if a \ref SCARDCONTEXT is valid.
2985 *
2986 * Call this function to determine whether a smart card context handle is still
2987 * valid. After a smart card context handle has been set by \ref
2988 * SCardEstablishContext, it may become not valid if the resource manager
2989 * service has been shut down.
2990 *
2991 * @param[in] hContext Connection context to the PC/SC Resource Manager.
2992 *
2993 * @return Error code.
2994 * @retval SCARD_S_SUCCESS Successful (\ref SCARD_S_SUCCESS)
2995 * @retval SCARD_E_INVALID_HANDLE Invalid Handle (\ref SCARD_E_INVALID_HANDLE)
2996 *
2997 * @test
2998 * @code
2999 * SCARDCONTEXT hContext;
3000 * LONG rv;
3001 * ...
3002 * rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext);
3003 * rv = SCardIsValidContext(hContext);
3004 * @endcode
3005 */
3006LONG SCardIsValidContext(SCARDCONTEXT hContext)
3007{
3008	LONG rv;
3009	LONG dwContextIndex;
3010
3011	PROFILE_START
3012
3013	rv = SCARD_S_SUCCESS;
3014
3015	/*
3016	 * Make sure this context has been opened
3017	 */
3018	dwContextIndex = SCardGetContextIndice(hContext);
3019	if (dwContextIndex == -1)
3020		rv = SCARD_E_INVALID_HANDLE;
3021
3022	PROFILE_END
3023
3024	return rv;
3025}
3026
3027/**
3028 * Functions for managing instances of SCardEstablishContext These functions
3029 * keep track of Context handles and associate the blocking
3030 * variable contextBlockStatus to an hContext
3031 */
3032
3033/**
3034 * @brief Adds an Application Context to the vector \c psContextMap.
3035 *
3036 * @param[in] hContext Application Context ID.
3037 * @param[in] dwClientID Client connection ID.
3038 *
3039 * @return Error code.
3040 * @retval SCARD_S_SUCCESS Success (\ref SCARD_S_SUCCESS)
3041 * @retval SCARD_E_NO_MEMORY There is no free slot to store \p hContext (\ref SCARD_E_NO_MEMORY)
3042 */
3043static LONG SCardAddContext(SCARDCONTEXT hContext, DWORD dwClientID)
3044{
3045	int i;
3046
3047	for (i = 0; i < PCSCLITE_MAX_APPLICATION_CONTEXTS; i++)
3048	{
3049		if (psContextMap[i].hContext == 0)
3050		{
3051			psContextMap[i].hContext = hContext;
3052			psContextMap[i].dwClientID = dwClientID;
3053			psContextMap[i].contextBlockStatus = BLOCK_STATUS_RESUME;
3054			psContextMap[i].mMutex = malloc(sizeof(PCSCLITE_MUTEX));
3055			SYS_MutexInit(psContextMap[i].mMutex);
3056			return SCARD_S_SUCCESS;
3057		}
3058	}
3059
3060	return SCARD_E_NO_MEMORY;
3061}
3062
3063/**
3064 * @brief Get the index from the Application Context vector \c psContextMap
3065 * for the passed context.
3066 *
3067 * This function is a thread-safe wrapper to the function
3068 * SCardGetContextIndiceTH().
3069 *
3070 * @param[in] hContext Application Context whose index will be find.
3071 *
3072 * @return Index corresponding to the Application Context or -1 if it is
3073 * not found.
3074 */
3075static LONG SCardGetContextIndice(SCARDCONTEXT hContext)
3076{
3077	LONG rv;
3078
3079	SCardLockThread();
3080	rv = SCardGetContextIndiceTH(hContext);
3081	SCardUnlockThread();
3082
3083	return rv;
3084}
3085
3086/**
3087 * @brief Get the index from the Application Context vector \c psContextMap
3088 * for the passed context.
3089 *
3090 * This functions is not thread-safe and should not be called. Instead, call
3091 * the function SCardGetContextIndice().
3092 *
3093 * @param[in] hContext Application Context whose index will be find.
3094 *
3095 * @return Index corresponding to the Application Context or -1 if it is
3096 * not found.
3097 */
3098static LONG SCardGetContextIndiceTH(SCARDCONTEXT hContext)
3099{
3100	int i;
3101
3102	if (hContext == 0)
3103		return -1;
3104
3105	/*
3106	 * Find this context and return its spot in the array
3107	 */
3108	for (i = 0; i < PCSCLITE_MAX_APPLICATION_CONTEXTS; i++)
3109		if (hContext == psContextMap[i].hContext)
3110			return i;
3111
3112	return -1;
3113}
3114
3115/**
3116 * @brief Removes an Application Context from a control vector.
3117 *
3118 * @param[in] hContext Application Context to be removed.
3119 *
3120 * @return Error code.
3121 * @retval SCARD_S_SUCCESS Success (\ref SCARD_S_SUCCESS)
3122 * @retval SCARD_E_INVALID_HANDLE The context \p hContext was not found (\ref SCARD_E_INVALID_HANDLE)
3123 */
3124static LONG SCardRemoveContext(SCARDCONTEXT hContext)
3125{
3126	LONG  retIndice;
3127
3128	retIndice = SCardGetContextIndiceTH(hContext);
3129
3130	if (retIndice == -1)
3131		return SCARD_E_INVALID_HANDLE;
3132	else
3133	{
3134		int i;
3135
3136		psContextMap[retIndice].hContext = 0;
3137		SHMClientCloseSession(psContextMap[retIndice].dwClientID);
3138		psContextMap[retIndice].dwClientID = 0;
3139		free(psContextMap[retIndice].mMutex);
3140		psContextMap[retIndice].mMutex = NULL;
3141		psContextMap[retIndice].contextBlockStatus = BLOCK_STATUS_RESUME;
3142
3143		for (i = 0; i < PCSCLITE_MAX_APPLICATION_CONTEXT_CHANNELS; i++)
3144		{
3145			/*
3146			 * Reset the \c hCard structs to zero
3147			 */
3148			psContextMap[retIndice].psChannelMap[i].hCard = 0;
3149			free(psContextMap[retIndice].psChannelMap[i].readerName);
3150			psContextMap[retIndice].psChannelMap[i].readerName = NULL;
3151		}
3152
3153		return SCARD_S_SUCCESS;
3154	}
3155}
3156
3157/*
3158 * Functions for managing hCard values returned from SCardConnect.
3159 */
3160
3161static LONG SCardAddHandle(SCARDHANDLE hCard, DWORD dwContextIndex,
3162	LPSTR readerName)
3163{
3164	int i;
3165
3166	for (i = 0; i < PCSCLITE_MAX_APPLICATION_CONTEXT_CHANNELS; i++)
3167	{
3168		if (psContextMap[dwContextIndex].psChannelMap[i].hCard == 0)
3169		{
3170			psContextMap[dwContextIndex].psChannelMap[i].hCard = hCard;
3171			psContextMap[dwContextIndex].psChannelMap[i].readerName = strdup(readerName);
3172			return SCARD_S_SUCCESS;
3173		}
3174	}
3175
3176	return SCARD_E_NO_MEMORY;
3177}
3178
3179static LONG SCardRemoveHandle(SCARDHANDLE hCard)
3180{
3181	DWORD dwContextIndice, dwChannelIndice;
3182	LONG rv;
3183
3184	rv = SCardGetIndicesFromHandle(hCard, &dwContextIndice, &dwChannelIndice);
3185
3186	if (rv == -1)
3187		return SCARD_E_INVALID_HANDLE;
3188	else
3189	{
3190		psContextMap[dwContextIndice].psChannelMap[dwChannelIndice].hCard = 0;
3191		free(psContextMap[dwContextIndice].psChannelMap[dwChannelIndice].readerName);
3192		psContextMap[dwContextIndice].psChannelMap[dwChannelIndice].readerName = NULL;
3193		return SCARD_S_SUCCESS;
3194	}
3195}
3196
3197static LONG SCardGetIndicesFromHandle(SCARDHANDLE hCard, PDWORD pdwContextIndice, PDWORD pdwChannelIndice)
3198{
3199	LONG rv;
3200
3201	if (0 == hCard)
3202		return -1;
3203
3204	SCardLockThread();
3205	rv = SCardGetIndicesFromHandleTH(hCard, pdwContextIndice, pdwChannelIndice);
3206	SCardUnlockThread();
3207
3208	return rv;
3209}
3210
3211static LONG SCardGetIndicesFromHandleTH(SCARDHANDLE hCard, PDWORD pdwContextIndice, PDWORD pdwChannelIndice)
3212{
3213	int i;
3214
3215	for (i = 0; i < PCSCLITE_MAX_APPLICATION_CONTEXTS; i++)
3216	{
3217		if (psContextMap[i].hContext != 0)
3218		{
3219			int j;
3220
3221			for (j = 0; j < PCSCLITE_MAX_APPLICATION_CONTEXT_CHANNELS; j++)
3222			{
3223				if (psContextMap[i].psChannelMap[j].hCard == hCard)
3224				{
3225					*pdwContextIndice = i;
3226					*pdwChannelIndice = j;
3227					return SCARD_S_SUCCESS;
3228				}
3229			}
3230
3231		}
3232	}
3233
3234	return -1;
3235}
3236
3237/**
3238 * @brief This function locks a mutex so another thread must wait to use this
3239 * function.
3240 *
3241 * Wrapper to the function SYS_MutexLock().
3242 */
3243inline static LONG SCardLockThread(void)
3244{
3245	return SYS_MutexLock(&clientMutex);
3246}
3247
3248/**
3249 * @brief This function unlocks a mutex so another thread may use the client.
3250 *
3251 * Wrapper to the function SYS_MutexUnLock().
3252 */
3253inline static LONG SCardUnlockThread(void)
3254{
3255	return SYS_MutexUnLock(&clientMutex);
3256}
3257
3258/**
3259 * @brief Checks if the Server is running.
3260 *
3261 * @return Error code.
3262 * @retval SCARD_S_SUCCESS Server is running (\ref SCARD_S_SUCCESS)
3263 * @retval SCARD_E_NO_SERVICE Server is not running (\ref SCARD_E_NO_SERVICE)
3264 */
3265static LONG SCardCheckDaemonAvailability(void)
3266{
3267	LONG rv;
3268	struct stat statBuffer;
3269
3270	rv = SYS_Stat(PCSCLITE_PUBSHM_FILE, &statBuffer);
3271
3272	if (rv != 0)
3273	{
3274		Log1(PCSC_LOG_ERROR, "PCSC Not Running");
3275		return SCARD_E_NO_SERVICE;
3276	}
3277
3278	return SCARD_S_SUCCESS;
3279}
3280
3281/**
3282 * free resources allocated by the library
3283 * You _shall_ call this function if you use dlopen/dlclose to load/unload the
3284 * library. Otherwise you will exhaust the ressources available.
3285 */
3286#ifdef __SUNPRO_C
3287#pragma fini (SCardUnload)
3288#endif
3289
3290void DESTRUCTOR SCardUnload(void)
3291{
3292	int i;
3293
3294	if (!isExecuted)
3295		return;
3296
3297	/* unmap public shared file from memory */
3298	for (i = 0; i < PCSCLITE_MAX_APPLICATION_CONTEXT_CHANNELS; i++)
3299	{
3300		if (readerStates[i] != NULL)
3301		{
3302			SYS_PublicMemoryUnmap(readerStates[i], sizeof(READER_STATE));
3303			readerStates[i] = NULL;
3304		}
3305	}
3306
3307	SYS_CloseFile(mapAddr);
3308	isExecuted = 0;
3309}
3310
3311static int SCardInitializeOnce()
3312{
3313	int pageSize;
3314	int i;
3315
3316	/*
3317	 * Do any system initilization here
3318	 */
3319	SYS_Initialize();
3320
3321	/*
3322	 * Set up the memory mapped reader stats structures
3323	 */
3324	mapAddr = SYS_OpenFile(PCSCLITE_PUBSHM_FILE, O_RDONLY, 0);
3325	if (mapAddr < 0)
3326	{
3327		Log2(PCSC_LOG_ERROR, "Cannot open public shared file: %s",
3328			PCSCLITE_PUBSHM_FILE);
3329		return SCARD_E_NO_SERVICE;
3330	}
3331
3332	pageSize = SYS_GetPageSize();
3333
3334	/*
3335	 * Allocate each reader structure in the memory map
3336	 */
3337	for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
3338	{
3339		readerStates[i] =
3340			(PREADER_STATE)SYS_PublicMemoryMap(sizeof(READER_STATE),
3341			mapAddr, (i * pageSize));
3342		if (readerStates[i] == NULL)
3343		{
3344			Log1(PCSC_LOG_ERROR, "Cannot public memory map");
3345			SYS_CloseFile(mapAddr);	/* Close the memory map file */
3346			return SCARD_F_INTERNAL_ERROR;
3347		}
3348	}
3349
3350	/*
3351	 * Initializes the application contexts and all channels for each one
3352	 */
3353	for (i = 0; i < PCSCLITE_MAX_APPLICATION_CONTEXTS; i++)
3354	{
3355		int j;
3356
3357		/*
3358		 * Initially set the context struct to zero
3359		 */
3360		psContextMap[i].dwClientID = 0;
3361		psContextMap[i].hContext = 0;
3362		psContextMap[i].contextBlockStatus = BLOCK_STATUS_RESUME;
3363		psContextMap[i].mMutex = NULL;
3364
3365		for (j = 0; j < PCSCLITE_MAX_APPLICATION_CONTEXT_CHANNELS; j++)
3366		{
3367			/*
3368			 * Initially set the hcard structs to zero
3369			 */
3370			psContextMap[i].psChannelMap[j].hCard = 0;
3371			psContextMap[i].psChannelMap[j].readerName = NULL;
3372		}
3373	}
3374
3375	/*
3376	 * Is there a free slot for this connection ?
3377	 */
3378
3379	for (i = 0; i < PCSCLITE_MAX_APPLICATION_CONTEXTS; i++)
3380	{
3381		if (psContextMap[i].dwClientID == 0)
3382			break;
3383	}
3384
3385	if (i == PCSCLITE_MAX_APPLICATION_CONTEXTS)
3386	{
3387		return SCARD_E_NO_MEMORY;
3388	}
3389
3390	return SCARD_S_SUCCESS;
3391}
3392
3393static int SHMClientCommunicationTimeout()
3394{
3395	/*
3396	 This is a param to e.g. SHMClientReadMessage, and is a timeout in milliseconds.
3397	 The constant PCSCLITE_SERVER_ATTEMPTS is very poorly named; it is a time value
3398	 in milliseconds, not the number of attempts. Some values to use:
3399	 5		default if PCSCLITE_ENHANCED_MESSAGING not defined
3400	 200		if PCSCLITE_ENHANCED_MESSAGING is defined
3401	 12000	might be a good value to set while debugging
3402	 */
3403
3404	static int baseTimeout = 12000;//PCSCLITE_CLIENT_ATTEMPTS;
3405	volatile int timeOut = baseTimeout;
3406
3407	return timeOut;
3408}
3409