76 static int contextMaxThreadCounter = PCSC_MAX_CONTEXT_THREADS;
77 static int contextMaxCardHandles = PCSC_MAX_CONTEXT_CARD_HANDLES;
97 static void MSGCleanupClient(
SCONTEXT *);
99 static void * ContextThread(LPVOID pdwIndex);
103 static int contextsListhContext_seeker(
const void *el,
const void *key)
107 if ((el == NULL) || (key == NULL))
109 Log3(PCSC_LOG_CRITICAL,
"called with NULL pointer: el=%p, key=%p",
114 if (currentContext->hContext == *(int32_t *)key)
119 LONG ContextsInitialize(
int customMaxThreadCounter,
120 int customMaxThreadCardHandles)
124 if (customMaxThreadCounter != 0)
125 contextMaxThreadCounter = customMaxThreadCounter;
127 if (customMaxThreadCardHandles != 0)
128 contextMaxCardHandles = customMaxThreadCardHandles;
130 lrv = list_init(&contextsList);
133 Log2(PCSC_LOG_CRITICAL,
"list_init failed with return value: %d", lrv);
136 lrv = list_attributes_seeker(& contextsList, contextsListhContext_seeker);
139 Log2(PCSC_LOG_CRITICAL,
140 "list_attributes_seeker failed with return value: %d", lrv);
149 void ContextsDeinitialize(
void)
153 listSize = list_size(&contextsList);
157 Log2(PCSC_LOG_DEBUG,
"remaining threads: %d", listSize);
160 int rv = list_iterator_start(&contextsList);
162 Log1(PCSC_LOG_ERROR,
"list_iterator_start failed");
165 while (list_iterator_hasnext(&contextsList))
167 SCONTEXT * elt = list_iterator_next(&contextsList);
168 Log3(PCSC_LOG_DEBUG,
"Cancel dwClientID=%d hContext: %p",
172 Log2(PCSC_LOG_DEBUG,
"Waiting client: %d", elt->
dwClientID);
174 Log2(PCSC_LOG_INFO,
"Client %d terminated", elt->
dwClientID);
177 list_destroy(&contextsList);
201 listSize = list_size(&contextsList);
202 if (listSize >= contextMaxThreadCounter)
204 Log2(PCSC_LOG_CRITICAL,
"Too many context running: %d", listSize);
209 newContext = malloc(
sizeof(*newContext));
210 if (NULL == newContext)
212 Log1(PCSC_LOG_CRITICAL,
"Could not allocate new context");
215 memset(newContext, 0,
sizeof(*newContext));
220 lrv = list_init(&newContext->cardsList);
223 Log2(PCSC_LOG_CRITICAL,
"list_init failed with return value: %d", lrv);
228 list_attributes_copy(&newContext->cardsList, list_meter_int32_t, 1);
235 lrv = list_attributes_comparator(&newContext->cardsList,
236 list_comparator_int32_t);
239 Log2(PCSC_LOG_CRITICAL,
240 "list_attributes_comparator failed with return value: %d", lrv);
241 list_destroy(&newContext->cardsList);
247 lrv = list_append(&contextsList, newContext);
250 Log2(PCSC_LOG_CRITICAL,
"list_append failed with return value: %d",
252 list_destroy(&newContext->cardsList);
256 rv = ThreadCreate(&newContext->
pthThread, THREAD_ATTR_DETACHED,
257 (PCSCLITE_THREAD_FUNCTION( )) ContextThread, (LPVOID) newContext);
262 Log2(PCSC_LOG_CRITICAL,
"ThreadCreate failed: %s", strerror(rv));
263 lrv2 = list_delete(&contextsList, newContext);
265 Log2(PCSC_LOG_CRITICAL,
"list_delete failed with error %d", lrv2);
266 list_destroy(&newContext->cardsList);
283 (void)close(*pdwClientID);
318 "CANCEL_TRANSACTION",
322 "CMD_GET_READERS_STATE",
323 "CMD_WAIT_READER_STATE_CHANGE",
324 "CMD_STOP_WAITING_READER_STATE_CHANGE",
329 #define READ_BODY(v) \
331 if (header.size != sizeof(v)) \
333 ret = MessageReceive(&v, sizeof(v), filedes); \
334 if (ret != SCARD_S_SUCCESS) { \
335 Log2(PCSC_LOG_DEBUG, "Client die: %d", filedes); \
340 #define WRITE_BODY(v) \
341 WRITE_BODY_WITH_COMMAND(CommandsText[header.command], v)
342 #define WRITE_BODY_WITH_COMMAND(command, v) \
344 LogRv4(PCSC_LOG_DEBUG, v.rv, "%s for client %d", command, filedes); \
345 ret = MessageSend(&v, sizeof(v), filedes); \
348 static void * ContextThread(LPVOID newContext)
353 if (IsClientAuthorized(filedes,
"access_pcsc", NULL) == 0)
355 Log1(PCSC_LOG_CRITICAL,
"Rejected unauthorized PC/SC client");
360 Log1(PCSC_LOG_DEBUG,
"Authorized PC/SC client");
363 Log3(PCSC_LOG_DEBUG,
"Thread is started: dwClientID=%d, threadContext @%p",
374 Log2(PCSC_LOG_DEBUG,
"Client die: %d", filedes);
379 if ((header.command > CMD_ENUM_FIRST)
380 && (header.command < CMD_ENUM_LAST))
381 Log3(PCSC_LOG_DEBUG,
"Received command: %s from client %d",
382 CommandsText[header.command], filedes);
384 switch (header.command)
393 Log3(PCSC_LOG_DEBUG,
"Client is protocol version %d:%d",
394 veStr.major, veStr.minor);
402 Log1(PCSC_LOG_CRITICAL,
403 "Communication protocol mismatch!");
404 Log3(PCSC_LOG_ERROR,
"Client protocol is %d:%d",
405 veStr.major, veStr.minor);
406 Log3(PCSC_LOG_ERROR,
"Server protocol is %d:%d",
426 RFWaitForReaderInit();
430 ret =
MessageSend(readerStates,
sizeof(readerStates), filedes);
440 RFWaitForReaderInit();
444 EHRegisterClientForEvent(filedes);
477 hContext = esStr.hContext;
480 esStr.hContext = hContext;
483 esStr.rv = MSGAddContext(esStr.hContext, threadContext);
498 reStr.rv = MSGRemoveContext(reStr.hContext, threadContext);
508 DWORD dwActiveProtocol;
512 coStr.szReader[
sizeof(coStr.szReader)-1] = 0;
514 dwActiveProtocol = coStr.dwActiveProtocol;
516 if (IsClientAuthorized(filedes,
"access_card", coStr.szReader) == 0)
518 Log2(PCSC_LOG_CRITICAL,
"Rejected unauthorized client for '%s'", coStr.szReader);
522 dwActiveProtocol = -1;
526 Log2(PCSC_LOG_DEBUG,
"Authorized client for '%s'", coStr.szReader);
529 coStr.dwShareMode, coStr.dwPreferredProtocols,
530 &hCard, &dwActiveProtocol);
534 coStr.dwActiveProtocol = dwActiveProtocol;
538 coStr.rv = MSGAddHandle(coStr.hContext, coStr.hCard,
557 if (MSGCheckHandleAssociation(rcStr.hCard, threadContext))
561 rcStr.dwPreferredProtocols, rcStr.dwInitialization,
563 rcStr.dwActiveProtocol = dwActiveProtocol;
575 if (MSGCheckHandleAssociation(diStr.hCard, threadContext))
581 diStr.rv = MSGRemoveHandle(diStr.hCard, threadContext);
593 if (MSGCheckHandleAssociation(beStr.hCard, threadContext))
608 if (MSGCheckHandleAssociation(enStr.hCard, threadContext))
612 enStr.dwDisposition);
627 psTargetContext = (
SCONTEXT *) list_seek(&contextsList,
634 if (psTargetContext != NULL)
636 uint32_t fd = psTargetContext->dwClientID;
660 if (MSGCheckHandleAssociation(stStr.hCard, threadContext))
664 stStr.rv =
SCardStatus(stStr.hCard, NULL, NULL, NULL,
682 if (MSGCheckHandleAssociation(trStr.hCard, threadContext))
686 if (trStr.cbSendLength >
sizeof(pbSendBuffer))
687 goto buffer_overflow;
693 Log2(PCSC_LOG_DEBUG,
"Client die: %d", filedes);
697 ioSendPci.
dwProtocol = trStr.ioSendPciProtocol;
699 ioRecvPci.
dwProtocol = trStr.ioRecvPciProtocol;
701 cbRecvLength =
sizeof pbRecvBuffer;
704 pbSendBuffer, trStr.cbSendLength, &ioRecvPci,
705 pbRecvBuffer, &cbRecvLength);
707 if (cbRecvLength > trStr.pcbRecvLength)
713 trStr.ioSendPciProtocol = ioSendPci.
dwProtocol;
715 trStr.ioRecvPciProtocol = ioRecvPci.
dwProtocol;
717 trStr.pcbRecvLength = cbRecvLength;
723 ret =
MessageSend(pbRecvBuffer, cbRecvLength, filedes);
732 DWORD dwBytesReturned;
736 if (MSGCheckHandleAssociation(ctStr.hCard, threadContext))
740 if (ctStr.cbSendLength >
sizeof(pbSendBuffer))
742 goto buffer_overflow;
749 Log2(PCSC_LOG_DEBUG,
"Client die: %d", filedes);
753 dwBytesReturned = ctStr.dwBytesReturned;
755 ctStr.rv =
SCardControl(ctStr.hCard, ctStr.dwControlCode,
756 pbSendBuffer, ctStr.cbSendLength,
757 pbRecvBuffer,
sizeof pbRecvBuffer,
760 if (dwBytesReturned > ctStr.cbRecvLength)
766 ctStr.dwBytesReturned = dwBytesReturned;
772 ret =
MessageSend(pbRecvBuffer, dwBytesReturned, filedes);
783 if (MSGCheckHandleAssociation(gsStr.hCard, threadContext))
787 if (gsStr.cbAttrLen >
sizeof(gsStr.pbAttr))
788 goto buffer_overflow;
790 cbAttrLen = gsStr.cbAttrLen;
793 gsStr.pbAttr, &cbAttrLen);
795 gsStr.cbAttrLen = cbAttrLen;
807 if (MSGCheckHandleAssociation(gsStr.hCard, threadContext))
811 if (gsStr.cbAttrLen >
sizeof(gsStr.pbAttr))
812 goto buffer_overflow;
815 gsStr.pbAttr, gsStr.cbAttrLen);
822 Log2(PCSC_LOG_CRITICAL,
"Unknown command: %d", header.command);
830 Log2(PCSC_LOG_DEBUG,
"Client die: %d", filedes);
836 Log2(PCSC_LOG_DEBUG,
"Buffer overflow detected: %d", filedes);
839 Log2(PCSC_LOG_DEBUG,
"Wrong length: %d", filedes);
841 (void)close(filedes);
842 MSGCleanupClient(threadContext);
843 (void)pthread_exit((LPVOID) NULL);
846 LONG MSGSignalClient(uint32_t filedes, LONG rv)
855 Log2(PCSC_LOG_DEBUG,
"Signal client: %d", filedes);
858 WRITE_BODY_WITH_COMMAND(
"SIGNAL", waStr);
863 LONG MSGSendReaderStates(uint32_t filedes)
867 Log2(PCSC_LOG_DEBUG,
"Send reader states: %d", filedes);
870 ret =
MessageSend(readerStates,
sizeof(readerStates), filedes);
877 threadContext->hContext = hContext;
886 if (0 == threadContext->hContext)
888 Log1(PCSC_LOG_ERROR,
"Invalidated handle");
892 if (threadContext->hContext != hContext)
896 while (list_size(&threadContext->cardsList) != 0)
905 ptr = list_get_at(&threadContext->cardsList, 0);
908 Log1(PCSC_LOG_CRITICAL,
"list_get_at failed");
911 hCard = *(int32_t *)ptr;
918 rv = RFReaderInfoById(hCard, &rContext);
935 if (hCard != rContext->
hLockId)
954 rv =
SCardStatus(hCard, NULL, NULL, NULL, NULL, NULL, NULL);
965 lrv = list_delete_at(&threadContext->cardsList, 0);
967 Log2(PCSC_LOG_CRITICAL,
968 "list_delete_at failed with return value: %d", lrv);
971 UNREF_READER(rContext)
978 threadContext->hContext = 0;
988 if (0 == threadContext->hContext)
990 Log1(PCSC_LOG_ERROR,
"Invalidated handle");
994 if (threadContext->hContext == hContext)
1003 listLength = list_size(&threadContext->cardsList);
1004 if (listLength >= contextMaxCardHandles)
1006 Log4(PCSC_LOG_DEBUG,
1007 "Too many card handles for thread context @%p: %d (max is %d). "
1008 "Restart pcscd with --max-card-handle-per-thread value",
1009 threadContext, listLength, contextMaxCardHandles);
1016 lrv = list_append(&threadContext->cardsList, &hCard);
1019 Log2(PCSC_LOG_CRITICAL,
1020 "list_append failed with return value: %d", lrv);
1039 lrv = list_delete(&threadContext->cardsList, &hCard);
1043 Log2(PCSC_LOG_CRITICAL,
"list_delete failed with error %d", lrv);
1051 static LONG MSGCheckHandleAssociation(
SCARDHANDLE hCard,
1056 if (0 == threadContext->hContext)
1060 Log1(PCSC_LOG_CRITICAL,
"Invalidated handle");
1065 list_index = list_locate(&threadContext->cardsList, &hCard);
1067 if (list_index >= 0)
1071 Log1(PCSC_LOG_ERROR,
"Client failed to authenticate");
1081 static void MSGCleanupClient(
SCONTEXT * threadContext)
1086 if (threadContext->hContext != 0)
1089 (void)MSGRemoveContext(threadContext->hContext, threadContext);
1093 list_destroy(&threadContext->cardsList);
1096 Log3(PCSC_LOG_DEBUG,
1097 "Thread is stopping: dwClientID=%d, threadContext @%p",
1103 memset((
void*) threadContext, 0,
sizeof(
SCONTEXT));
1104 Log2(PCSC_LOG_DEBUG,
"Freeing SCONTEXT @%p", threadContext);
1107 lrv = list_delete(&contextsList, threadContext);
1108 listSize = list_size(&contextsList);
1111 Log2(PCSC_LOG_CRITICAL,
"list_delete failed with error %x", lrv);
1113 free(threadContext);
1118 Log2(PCSC_LOG_DEBUG,
"Starting suicide alarm in %d seconds",
1119 TIME_BEFORE_SUICIDE);
1120 alarm(TIME_BEFORE_SUICIDE);
LONG EHUnregisterClientForEvent(int32_t filedes)
Unregister a client and log an error if the client is not found.
#define SCARD_E_INVALID_VALUE
One or more of the supplied parameters values could not be properly interpreted.
used by SCardBeginTransaction()
contained in SCARD_CONNECT Messages.
wait for a reader state change
contained in SCARD_CANCEL Messages.
contained in SCARD_TRANSMIT Messages.
#define SCARD_S_SUCCESS
No error was encountered.
contained in SCARD_END_TRANSACTION Messages.
get the client/server protocol version
LONG CreateContextThread(uint32_t *pdwClientID)
Creates threads to handle messages received from Clients.
pthread_t pthThread
Event polling thread's ID.
used by SCardEstablishContext()
used by SCardEndTransaction()
PCSC_API LONG SCardEstablishContext(DWORD dwScope, LPCVOID pvReserved1, LPCVOID pvReserved2, LPSCARDCONTEXT phContext)
Creates an Application Context to the PC/SC Resource Manager.
unsigned long cbPciLength
Protocol Control Inf Length.
#define SCARD_LEAVE_CARD
Do nothing on close.
#define SCARD_W_SECURITY_VIOLATION
Access was denied because of a security violation.
This handles abstract system level calls.
int SYS_Sleep(int)
Makes the current process sleep for some seconds.
uint32_t dwClientID
Connection ID used to reference the Client.
This demarshalls functions over the message queue and keeps track of clients and their handles...
#define PROTOCOL_VERSION_MAJOR
Major version of the current message protocol.
contained in SCARD_DISCONNECT Messages.
static list_t contextsList
Context tracking list.
bool AutoExit
Represents an Application Context on the Server side.
PCSC_API LONG SCardGetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPBYTE pbAttr, LPDWORD pcbAttrLen)
Get an attribute from the IFD Handler (reader driver).
Information contained in SCARD_RELEASE_CONTEXT Messages.
PCSC_API LONG SCardDisconnect(SCARDHANDLE hCard, DWORD dwDisposition)
Terminates a connection made through SCardConnect().
contained in SCARD_BEGIN_TRANSACTION Messages.
Information contained in SCARD_ESTABLISH_CONTEXT Messages.
_Atomic SCARDHANDLE hLockId
Lock Id.
Information transmitted in CMD_VERSION Messages.
INTERNAL LONG MessageReceive(void *buffer_void, uint64_t buffer_size, int32_t filedes)
Called by the Client to get the response from the server or vice-versa.
used by SCardReleaseContext()
LONG SCARDCONTEXT
hContext returned by SCardEstablishContext()
#define SCARD_E_NO_MEMORY
Not enough memory available to complete this command.
contained in SCARD_STATUS Messages.
#define SCARD_E_READER_UNAVAILABLE
The specified reader is not currently available for use.
contained in SCARD_RECONNECT Messages.
unsigned long dwProtocol
Protocol identifier.
uint32_t timeOut
timeout in ms
#define PCSCLITE_MAX_READERS_CONTEXTS
Maximum readers context (a slot is count as a reader)
contained in SCARD_GET_ATTRIB and Messages.
This defines some structures and #defines to be used over the transport layer.
Information contained in CMD_WAIT_READER_STATE_CHANGE Messages.
#define SCARD_W_RESET_CARD
The smart card has been reset, so any shared state information is invalid.
PCSC_API LONG SCardReconnect(SCARDHANDLE hCard, DWORD dwShareMode, DWORD dwPreferredProtocols, DWORD dwInitialization, LPDWORD pdwActiveProtocol)
Reestablishes a connection to a reader that was previously connected to using SCardConnect().
#define MAX_BUFFER_SIZE_EXTENDED
enhanced (64K + APDU + Lc + Le + SW) Tx/Rx Buffer
static READER_STATE readerStates[PCSCLITE_MAX_READERS_CONTEXTS]
Area used to read status information about the readers.
LONG EHTryToUnregisterClientForEvent(int32_t filedes)
Try to unregister a client If no client is found then do not log an error.
This handles card insertion/removal events, updates ATR, protocol, and status information.
PCSC_API LONG SCardConnect(SCARDCONTEXT hContext, LPCSTR szReader, DWORD dwShareMode, DWORD dwPreferredProtocols, LPSCARDHANDLE phCard, LPDWORD pdwActiveProtocol)
Establishes a connection to the reader specified in * szReader.
stop waiting for a reader state change
PCSC_API LONG SCardSetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPCBYTE pbAttr, DWORD cbAttrLen)
Set an attribute of the IFD Handler.
#define SCARD_W_REMOVED_CARD
The smart card has been removed, so further communication is not possible.
#define SCARD_PROTOCOL_UNDEFINED
protocol not set
#define SCARD_RESET_CARD
Reset on close.
LONG SCARDHANDLE
hCard returned by SCardConnect()
#define SCARD_E_INSUFFICIENT_BUFFER
The data buffer to receive returned data is too small for the returned data.
static const char * CommandsText[]
Handles messages received from Clients.
#define SCARD_E_CANCELLED
The action was cancelled by an SCardCancel request.
#define PROTOCOL_VERSION_MINOR
Minor version of the current message protocol.
PCSC_API LONG SCardBeginTransaction(SCARDHANDLE hCard)
Establishes a temporary exclusive access mode for doing a series of commands in a transaction...
This keeps a list of defines for pcsc-lite.
Protocol Control Information (PCI)
PCSC_API LONG SCardControl(SCARDHANDLE hCard, DWORD dwControlCode, LPCVOID pbSendBuffer, DWORD cbSendLength, LPVOID pbRecvBuffer, DWORD cbRecvLength, LPDWORD lpBytesReturned)
Sends a command directly to the IFD Handler (reader driver) to be processed by the reader...
Define an exported public reader state structure so each application gets instant notification of cha...
INTERNAL LONG MessageSend(void *buffer_void, uint64_t buffer_size, int32_t filedes)
Sends a menssage from client to server or vice-versa.
used by SCardDisconnect()
contained in SCARD_CONTROL Messages.
This keeps track of a list of currently available reader structures.
PCSC_API LONG SCardStatus(SCARDHANDLE hCard, LPSTR mszReaderName, LPDWORD pcchReaderLen, LPDWORD pdwState, LPDWORD pdwProtocol, LPBYTE pbAtr, LPDWORD pcbAtrLen)
Returns the current status of the reader connected to by hCard.
#define SCARD_F_INTERNAL_ERROR
An internal consistency check failed.
PCSC_API LONG SCardEndTransaction(SCARDHANDLE hCard, DWORD dwDisposition)
Ends a previously begun transaction.
PCSC_API LONG SCardTransmit(SCARDHANDLE hCard, const SCARD_IO_REQUEST *pioSendPci, LPCBYTE pbSendBuffer, DWORD cbSendLength, SCARD_IO_REQUEST *pioRecvPci, LPBYTE pbRecvBuffer, LPDWORD pcbRecvLength)
Sends an APDU to the smart card contained in the reader connected to by SCardConnect().
pthread_mutex_t cardsList_lock
lock for the above list
#define SCARD_E_SERVICE_STOPPED
The Smart card resource manager has shut down.
pthread_mutex_t contextsList_lock
lock for the above list
#define SCARD_E_INVALID_HANDLE
The supplied handle was invalid.
This handles smart card reader communications.
PCSC_API LONG SCardReleaseContext(SCARDCONTEXT hContext)
Destroys a communication context to the PC/SC Resource Manager.