80 static int contextMaxThreadCounter = PCSC_MAX_CONTEXT_THREADS;
81 static int contextMaxCardHandles = PCSC_MAX_CONTEXT_CARD_HANDLES;
101 static LONG MSGCleanupClient(
SCONTEXT *);
103 static void ContextThread(LPVOID pdwIndex);
107 static int contextsListhContext_seeker(
const void *el,
const void *key)
111 if ((el == NULL) || (key == NULL))
113 Log3(PCSC_LOG_CRITICAL,
"called with NULL pointer: el=%p, key=%p",
118 if (currentContext->hContext == *(int32_t *)key)
123 LONG ContextsInitialize(
int customMaxThreadCounter,
124 int customMaxThreadCardHandles)
128 if (customMaxThreadCounter != 0)
129 contextMaxThreadCounter = customMaxThreadCounter;
131 if (customMaxThreadCardHandles != 0)
132 contextMaxCardHandles = customMaxThreadCardHandles;
134 lrv = list_init(&contextsList);
137 Log2(PCSC_LOG_CRITICAL,
"list_init failed with return value: %d", lrv);
140 lrv = list_attributes_seeker(& contextsList, contextsListhContext_seeker);
143 Log2(PCSC_LOG_CRITICAL,
144 "list_attributes_seeker failed with return value: %d", lrv);
153 void ContextsDeinitialize(
void)
156 listSize = list_size(&contextsList);
157 Log2(PCSC_LOG_DEBUG,
"remaining threads: %d", listSize);
160 list_destroy(&contextsList);
183 listSize = list_size(&contextsList);
184 if (listSize >= contextMaxThreadCounter)
186 Log2(PCSC_LOG_CRITICAL,
"Too many context running: %d", listSize);
191 newContext = malloc(
sizeof(*newContext));
192 if (NULL == newContext)
194 Log1(PCSC_LOG_CRITICAL,
"Could not allocate new context");
197 memset(newContext, 0,
sizeof(*newContext));
202 lrv = list_init(&newContext->cardsList);
205 Log2(PCSC_LOG_CRITICAL,
"list_init failed with return value: %d", lrv);
210 list_attributes_copy(&newContext->cardsList, list_meter_int32_t, 1);
217 lrv = list_attributes_comparator(&newContext->cardsList,
218 list_comparator_int32_t);
221 Log2(PCSC_LOG_CRITICAL,
222 "list_attributes_comparator failed with return value: %d", lrv);
223 list_destroy(&newContext->cardsList);
229 lrv = list_append(&contextsList, newContext);
232 Log2(PCSC_LOG_CRITICAL,
"list_append failed with return value: %d",
234 list_destroy(&newContext->cardsList);
238 rv = ThreadCreate(&newContext->
pthThread, THREAD_ATTR_DETACHED,
239 (PCSCLITE_THREAD_FUNCTION( )) ContextThread, (LPVOID) newContext);
244 Log2(PCSC_LOG_CRITICAL,
"ThreadCreate failed: %s", strerror(rv));
245 lrv2 = list_delete(&contextsList, newContext);
247 Log2(PCSC_LOG_CRITICAL,
"list_delete failed with error %d", lrv2);
248 list_destroy(&newContext->cardsList);
265 (void)close(*pdwClientID);
300 "CANCEL_TRANSACTION",
304 "CMD_GET_READERS_STATE",
305 "CMD_WAIT_READER_STATE_CHANGE",
306 "CMD_STOP_WAITING_READER_STATE_CHANGE",
311 #define READ_BODY(v) \
312 if (header.size != sizeof(v)) { goto wrong_length; } \
313 ret = MessageReceive(&v, sizeof(v), filedes); \
314 if (ret != SCARD_S_SUCCESS) { Log2(PCSC_LOG_DEBUG, "Client die: %d", filedes); goto exit; }
316 #define WRITE_BODY(v) \
317 WRITE_BODY_WITH_COMMAND(CommandsText[header.command], v)
318 #define WRITE_BODY_WITH_COMMAND(command, v) \
319 Log4(PCSC_LOG_DEBUG, "%s rv=0x%X for client %d", command, v.rv, filedes); \
320 ret = MessageSend(&v, sizeof(v), filedes);
322 static void ContextThread(LPVOID newContext)
327 if (IsClientAuthorized(filedes,
"access_pcsc", NULL) == 0)
329 Log1(PCSC_LOG_CRITICAL,
"Rejected unauthorized PC/SC client");
334 Log1(PCSC_LOG_DEBUG,
"Authorized PC/SC client");
337 Log3(PCSC_LOG_DEBUG,
"Thread is started: dwClientID=%d, threadContext @%p",
348 Log2(PCSC_LOG_DEBUG,
"Client die: %d", filedes);
353 if ((header.command > CMD_ENUM_FIRST)
354 && (header.command < CMD_ENUM_LAST))
355 Log3(PCSC_LOG_DEBUG,
"Received command: %s from client %d",
356 CommandsText[header.command], filedes);
358 switch (header.command)
367 Log3(PCSC_LOG_DEBUG, "Client is protocol version %d:%d",
376 Log3(PCSC_LOG_CRITICAL,
"Client protocol is %d:%d",
377 veStr.major, veStr.minor);
378 Log3(PCSC_LOG_CRITICAL,
"Server protocol is %d:%d",
398 RFWaitForReaderInit();
402 ret =
MessageSend(readerStates,
sizeof(readerStates), filedes);
413 EHRegisterClientForEvent(filedes);
441 hContext = esStr.hContext;
444 esStr.hContext = hContext;
447 esStr.rv = MSGAddContext(esStr.hContext, threadContext);
462 reStr.rv = MSGRemoveContext(reStr.hContext, threadContext);
472 DWORD dwActiveProtocol;
476 coStr.szReader[sizeof(coStr.szReader)-1] = 0;
478 dwActiveProtocol = coStr.dwActiveProtocol;
480 if (IsClientAuthorized(filedes, "access_card", coStr.szReader) == 0)
482 Log2(PCSC_LOG_CRITICAL,
"Rejected unauthorized client for '%s'", coStr.szReader);
487 Log2(PCSC_LOG_DEBUG,
"Authorized client for '%s'", coStr.szReader);
491 coStr.dwShareMode, coStr.dwPreferredProtocols,
492 &hCard, &dwActiveProtocol);
495 coStr.dwActiveProtocol = dwActiveProtocol;
498 coStr.rv = MSGAddHandle(coStr.hContext, coStr.hCard,
508 DWORD dwActiveProtocol;
512 if (MSGCheckHandleAssociation(rcStr.hCard, threadContext))
516 rcStr.dwPreferredProtocols, rcStr.dwInitialization,
518 rcStr.dwActiveProtocol = dwActiveProtocol;
530 if (MSGCheckHandleAssociation(diStr.hCard, threadContext))
536 diStr.rv = MSGRemoveHandle(diStr.hCard, threadContext);
548 if (MSGCheckHandleAssociation(beStr.hCard, threadContext))
563 if (MSGCheckHandleAssociation(enStr.hCard, threadContext))
567 enStr.dwDisposition);
581 psTargetContext = (
SCONTEXT *) list_seek(&contextsList,
584 if (psTargetContext != NULL)
586 uint32_t fd = psTargetContext->dwClientID;
602 if (MSGCheckHandleAssociation(stStr.hCard, threadContext))
606 stStr.rv =
SCardStatus(stStr.hCard, NULL, NULL, NULL,
624 if (MSGCheckHandleAssociation(trStr.hCard, threadContext))
628 if ((trStr.pcbRecvLength > sizeof(pbRecvBuffer))
629 || (trStr.cbSendLength > sizeof(pbSendBuffer)))
630 goto buffer_overflow;
636 Log2(PCSC_LOG_DEBUG,
"Client die: %d", filedes);
640 ioSendPci.
dwProtocol = trStr.ioSendPciProtocol;
642 ioRecvPci.
dwProtocol = trStr.ioRecvPciProtocol;
644 cbRecvLength = trStr.pcbRecvLength;
647 pbSendBuffer, trStr.cbSendLength, &ioRecvPci,
648 pbRecvBuffer, &cbRecvLength);
650 trStr.ioSendPciProtocol = ioSendPci.
dwProtocol;
652 trStr.ioRecvPciProtocol = ioRecvPci.
dwProtocol;
654 trStr.pcbRecvLength = cbRecvLength;
660 ret =
MessageSend(pbRecvBuffer, cbRecvLength, filedes);
669 DWORD dwBytesReturned;
673 if (MSGCheckHandleAssociation(ctStr.hCard, threadContext))
677 if ((ctStr.cbRecvLength > sizeof(pbRecvBuffer))
678 || (ctStr.cbSendLength > sizeof(pbSendBuffer)))
680 goto buffer_overflow;
687 Log2(PCSC_LOG_DEBUG,
"Client die: %d", filedes);
691 dwBytesReturned = ctStr.dwBytesReturned;
693 ctStr.rv =
SCardControl(ctStr.hCard, ctStr.dwControlCode,
694 pbSendBuffer, ctStr.cbSendLength,
695 pbRecvBuffer, ctStr.cbRecvLength,
698 ctStr.dwBytesReturned = dwBytesReturned;
704 ret =
MessageSend(pbRecvBuffer, dwBytesReturned, filedes);
715 if (MSGCheckHandleAssociation(gsStr.hCard, threadContext))
719 if (gsStr.cbAttrLen > sizeof(gsStr.pbAttr))
720 goto buffer_overflow;
722 cbAttrLen = gsStr.cbAttrLen;
725 gsStr.pbAttr, &cbAttrLen);
727 gsStr.cbAttrLen = cbAttrLen;
739 if (MSGCheckHandleAssociation(gsStr.hCard, threadContext))
743 if (gsStr.cbAttrLen > sizeof(gsStr.pbAttr))
744 goto buffer_overflow;
747 gsStr.pbAttr, gsStr.cbAttrLen);
754 Log2(PCSC_LOG_CRITICAL, "Unknown command: %d", header.command);
762 Log2(PCSC_LOG_DEBUG,
"Client die: %d", filedes);
768 Log2(PCSC_LOG_DEBUG,
"Buffer overflow detected: %d", filedes);
771 Log2(PCSC_LOG_DEBUG,
"Wrong length: %d", filedes);
773 (void)close(filedes);
774 (void)MSGCleanupClient(threadContext);
775 (void)pthread_exit((LPVOID) NULL);
778 LONG MSGSignalClient(uint32_t filedes, LONG rv)
783 Log2(PCSC_LOG_DEBUG,
"Signal client: %d", filedes);
786 WRITE_BODY_WITH_COMMAND(
"SIGNAL", waStr)
793 threadContext->hContext = hContext;
802 if (threadContext->hContext != hContext)
806 while (list_size(&threadContext->cardsList) != 0)
815 ptr = list_get_at(&threadContext->cardsList, 0);
818 Log1(PCSC_LOG_CRITICAL,
"list_get_at failed");
821 hCard = *(int32_t *)ptr;
826 rv = RFReaderInfoById(hCard, &rContext);
836 if (hCard != hLockId)
851 rv =
SCardStatus(hCard, NULL, NULL, NULL, NULL, NULL, NULL);
860 lrv = list_delete_at(&threadContext->cardsList, 0);
862 Log2(PCSC_LOG_CRITICAL,
863 "list_delete_at failed with return value: %d", lrv);
865 UNREF_READER(rContext)
871 threadContext->hContext = 0;
881 if (threadContext->hContext == hContext)
890 listLength = list_size(&threadContext->cardsList);
891 if (listLength >= contextMaxCardHandles)
894 "Too many card handles for thread context @%p: %d (max is %d)"
895 "Restart pcscd with --max-card-handle-per-thread value",
896 threadContext, listLength, contextMaxCardHandles);
903 lrv = list_append(&threadContext->cardsList, &hCard);
906 Log2(PCSC_LOG_CRITICAL,
907 "list_append failed with return value: %d", lrv);
925 lrv = list_delete(&threadContext->cardsList, &hCard);
929 Log2(PCSC_LOG_CRITICAL,
"list_delete failed with error %d", lrv);
937 static LONG MSGCheckHandleAssociation(
SCARDHANDLE hCard,
942 if (0 == threadContext->hContext)
946 Log1(PCSC_LOG_CRITICAL,
"Invalidated handle");
951 list_index = list_locate(&threadContext->cardsList, &hCard);
957 Log1(PCSC_LOG_ERROR,
"Client failed to authenticate");
967 static LONG MSGCleanupClient(
SCONTEXT * threadContext)
972 if (threadContext->hContext != 0)
975 (void)MSGRemoveContext(threadContext->hContext, threadContext);
979 list_destroy(&threadContext->cardsList);
983 "Thread is stopping: dwClientID=%d, threadContext @%p",
989 memset((
void*) threadContext, 0,
sizeof(
SCONTEXT));
990 Log2(PCSC_LOG_DEBUG,
"Freeing SCONTEXT @%p", threadContext);
993 lrv = list_delete(&contextsList, threadContext);
994 listSize = list_size(&contextsList);
997 Log2(PCSC_LOG_CRITICAL,
"list_delete failed with error %x", lrv);
1004 Log2(PCSC_LOG_DEBUG,
"Starting suicide alarm in %d seconds",
1005 TIME_BEFORE_SUICIDE);
1006 alarm(TIME_BEFORE_SUICIDE);
LONG EHUnregisterClientForEvent(int32_t filedes)
Unregister a client and log an error if the client is not found.
used by SCardBeginTransaction()
contained in SCARD_CONNECT Messages.
#define SCARD_E_CANCELLED
The action was cancelled by an SCardCancel request.
wait for a reader state change
contained in SCARD_CANCEL Messages.
contained in SCARD_TRANSMIT Messages.
volatile SCARDHANDLE hLockId
Lock Id.
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()
int32_t minor
IPC minor PROTOCOL_VERSION_MINOR.
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.
This handles abstract system level calls.
#define SCARD_E_NO_SERVICE
The Smart card resource manager is not running.
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.
#define SCARD_E_INVALID_HANDLE
The supplied handle was invalid.
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.
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 reponse from the server or vice-versa.
used by SCardReleaseContext()
LONG SCARDCONTEXT
hContext returned by SCardEstablishContext()
#define SCARD_E_INVALID_VALUE
One or more of the supplied parameters values could not be properly interpreted.
contained in SCARD_STATUS Messages.
contained in SCARD_RECONNECT Messages.
unsigned long dwProtocol
Protocol identifier.
#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.
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 unregisted a client If no client is found then do not log an error.
char AutoExit
Represents an Application Context on the Server side.
This handles card insertion/removal events, updates ATR, protocol, and status information.
#define SCARD_W_REMOVED_CARD
The smart card has been removed, so further communication is not possible.
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 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.
PCSC_API LONG SCardSetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPCBYTE pbAttr, DWORD cbAttrLen)
Set an attribute of the IFD Handler.
#define SCARD_RESET_CARD
Reset on close.
LONG SCARDHANDLE
hCard returned by SCardConnect()
static const char * CommandsText[]
Handles messages received from Clients.
#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 serie of commands in a transaction.
This keeps a list of defines for pcsc-lite.
#define SCARD_W_RESET_CARD
The smart card has been reset, so any shared state information is invalid.
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()
#define SCARD_E_NO_MEMORY
Not enough memory available to complete this command.
contained in SCARD_CONTROL Messages.
This keeps track of a list of currently available reader structures.
int32_t major
IPC major PROTOCOL_VERSION_MAJOR.
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
pthread_mutex_t contextsList_lock
lock for the above list
#define SCARD_S_SUCCESS
error codes from http://msdn.microsoft.com/en-us/library/aa924526.aspx
This handles smart card reader communications.
PCSC_API LONG SCardReleaseContext(SCARDCONTEXT hContext)
Destroys a communication context to the PC/SC Resource Manager.