75static int contextMaxThreadCounter = PCSC_MAX_CONTEXT_THREADS;
76static int contextMaxCardHandles = PCSC_MAX_CONTEXT_CARD_HANDLES;
96static void MSGCleanupClient(
SCONTEXT *);
98static void * ContextThread(LPVOID pdwIndex);
102static int contextsListhContext_seeker(
const void *el,
const void *key)
106 if ((el == NULL) || (key == NULL))
108 Log3(PCSC_LOG_CRITICAL,
"called with NULL pointer: el=%p, key=%p",
113 if (currentContext->hContext == *(int32_t *)key)
118LONG ContextsInitialize(
int customMaxThreadCounter,
119 int customMaxThreadCardHandles)
123 if (customMaxThreadCounter != 0)
124 contextMaxThreadCounter = customMaxThreadCounter;
126 if (customMaxThreadCardHandles != 0)
127 contextMaxCardHandles = customMaxThreadCardHandles;
132 Log2(PCSC_LOG_CRITICAL,
"list_init failed with return value: %d", lrv);
135 lrv = list_attributes_seeker(&
contextsList, contextsListhContext_seeker);
138 Log2(PCSC_LOG_CRITICAL,
139 "list_attributes_seeker failed with return value: %d", lrv);
148void ContextsDeinitialize(
void)
155 Log2(PCSC_LOG_DEBUG,
"remaining threads: %d", listSize);
182 if (listSize >= contextMaxThreadCounter)
184 Log2(PCSC_LOG_CRITICAL,
"Too many context running: %d", listSize);
189 newContext = malloc(
sizeof(*newContext));
190 if (NULL == newContext)
192 Log1(PCSC_LOG_CRITICAL,
"Could not allocate new context");
195 memset(newContext, 0,
sizeof(*newContext));
200 lrv = list_init(&newContext->cardsList);
203 Log2(PCSC_LOG_CRITICAL,
"list_init failed with return value: %d", lrv);
208 list_attributes_copy(&newContext->cardsList, list_meter_int32_t, 1);
215 lrv = list_attributes_comparator(&newContext->cardsList,
216 list_comparator_int32_t);
219 Log2(PCSC_LOG_CRITICAL,
220 "list_attributes_comparator failed with return value: %d", lrv);
221 list_destroy(&newContext->cardsList);
230 Log2(PCSC_LOG_CRITICAL,
"list_append failed with return value: %d",
232 list_destroy(&newContext->cardsList);
236 rv = ThreadCreate(&newContext->
pthThread, THREAD_ATTR_DETACHED,
237 (PCSCLITE_THREAD_FUNCTION( )) ContextThread, (LPVOID) newContext);
242 Log2(PCSC_LOG_CRITICAL,
"ThreadCreate failed: %s", strerror(rv));
245 Log2(PCSC_LOG_CRITICAL,
"list_delete failed with error %d", lrv2);
246 list_destroy(&newContext->cardsList);
263 (void)close(*pdwClientID);
298 "CANCEL_TRANSACTION",
302 "CMD_GET_READERS_STATE",
303 "CMD_WAIT_READER_STATE_CHANGE",
304 "CMD_STOP_WAITING_READER_STATE_CHANGE",
309#define READ_BODY(v) \
311 if (header.size != sizeof(v)) \
313 ret = MessageReceive(&v, sizeof(v), filedes); \
314 if (ret != SCARD_S_SUCCESS) { \
315 Log2(PCSC_LOG_DEBUG, "Client die: %d", filedes); \
320#define WRITE_BODY(v) \
321 WRITE_BODY_WITH_COMMAND(CommandsText[header.command], v)
322#define WRITE_BODY_WITH_COMMAND(command, v) \
324 Log4(PCSC_LOG_DEBUG, "%s rv=0x%X for client %d", command, v.rv, filedes); \
325 ret = MessageSend(&v, sizeof(v), filedes); \
328static void * ContextThread(LPVOID newContext)
333 if (IsClientAuthorized(filedes,
"access_pcsc", NULL) == 0)
335 Log1(PCSC_LOG_CRITICAL,
"Rejected unauthorized PC/SC client");
340 Log1(PCSC_LOG_DEBUG,
"Authorized PC/SC client");
343 Log3(PCSC_LOG_DEBUG,
"Thread is started: dwClientID=%d, threadContext @%p",
354 Log2(PCSC_LOG_DEBUG,
"Client die: %d", filedes);
359 if ((header.command > CMD_ENUM_FIRST)
360 && (header.command < CMD_ENUM_LAST))
361 Log3(PCSC_LOG_DEBUG,
"Received command: %s from client %d",
364 switch (header.command)
373 Log3(PCSC_LOG_DEBUG,
"Client is protocol version %d:%d",
374 veStr.major, veStr.minor);
382 Log1(PCSC_LOG_CRITICAL,
383 "Communication protocol mismatch!");
384 Log3(PCSC_LOG_ERROR,
"Client protocol is %d:%d",
385 veStr.major, veStr.minor);
386 Log3(PCSC_LOG_ERROR,
"Server protocol is %d:%d",
406 RFWaitForReaderInit();
410 ret =
MessageSend(readerStates,
sizeof(readerStates), filedes);
420 RFWaitForReaderInit();
424 EHRegisterClientForEvent(filedes);
457 hContext = esStr.hContext;
458 esStr.rv = SCardEstablishContext(esStr.dwScope, 0, 0,
460 esStr.hContext = hContext;
463 esStr.rv = MSGAddContext(esStr.hContext, threadContext);
475 reStr.rv = SCardReleaseContext(reStr.hContext);
478 reStr.rv = MSGRemoveContext(reStr.hContext, threadContext);
488 DWORD dwActiveProtocol;
492 coStr.szReader[
sizeof(coStr.szReader)-1] = 0;
494 dwActiveProtocol = coStr.dwActiveProtocol;
496 if (IsClientAuthorized(filedes,
"access_card", coStr.szReader) == 0)
498 Log2(PCSC_LOG_CRITICAL,
"Rejected unauthorized client for '%s'", coStr.szReader);
503 Log2(PCSC_LOG_DEBUG,
"Authorized client for '%s'", coStr.szReader);
506 coStr.rv = SCardConnect(coStr.hContext, coStr.szReader,
507 coStr.dwShareMode, coStr.dwPreferredProtocols,
508 &hCard, &dwActiveProtocol);
511 coStr.dwActiveProtocol = dwActiveProtocol;
515 coStr.rv = MSGAddHandle(coStr.hContext, coStr.hCard,
534 if (MSGCheckHandleAssociation(rcStr.hCard, threadContext))
537 rcStr.rv = SCardReconnect(rcStr.hCard, rcStr.dwShareMode,
538 rcStr.dwPreferredProtocols, rcStr.dwInitialization,
540 rcStr.dwActiveProtocol = dwActiveProtocol;
552 if (MSGCheckHandleAssociation(diStr.hCard, threadContext))
555 diStr.rv = SCardDisconnect(diStr.hCard, diStr.dwDisposition);
558 diStr.rv = MSGRemoveHandle(diStr.hCard, threadContext);
570 if (MSGCheckHandleAssociation(beStr.hCard, threadContext))
573 beStr.rv = SCardBeginTransaction(beStr.hCard);
585 if (MSGCheckHandleAssociation(enStr.hCard, threadContext))
588 enStr.rv = SCardEndTransaction(enStr.hCard,
589 enStr.dwDisposition);
611 if (psTargetContext != NULL)
613 uint32_t fd = psTargetContext->dwClientID;
635 if (MSGCheckHandleAssociation(stStr.hCard, threadContext))
639 stStr.rv = SCardStatus(stStr.hCard, NULL, NULL, NULL,
657 if (MSGCheckHandleAssociation(trStr.hCard, threadContext))
661 if (trStr.cbSendLength >
sizeof(pbSendBuffer))
662 goto buffer_overflow;
668 Log2(PCSC_LOG_DEBUG,
"Client die: %d", filedes);
672 ioSendPci.
dwProtocol = trStr.ioSendPciProtocol;
674 ioRecvPci.
dwProtocol = trStr.ioRecvPciProtocol;
676 cbRecvLength =
sizeof pbRecvBuffer;
678 trStr.rv = SCardTransmit(trStr.hCard, &ioSendPci,
679 pbSendBuffer, trStr.cbSendLength, &ioRecvPci,
680 pbRecvBuffer, &cbRecvLength);
682 if (cbRecvLength > trStr.pcbRecvLength)
688 trStr.ioSendPciProtocol = ioSendPci.
dwProtocol;
690 trStr.ioRecvPciProtocol = ioRecvPci.
dwProtocol;
692 trStr.pcbRecvLength = cbRecvLength;
698 ret =
MessageSend(pbRecvBuffer, cbRecvLength, filedes);
707 DWORD dwBytesReturned;
711 if (MSGCheckHandleAssociation(ctStr.hCard, threadContext))
715 if (ctStr.cbSendLength >
sizeof(pbSendBuffer))
717 goto buffer_overflow;
724 Log2(PCSC_LOG_DEBUG,
"Client die: %d", filedes);
728 dwBytesReturned = ctStr.dwBytesReturned;
730 ctStr.rv = SCardControl(ctStr.hCard, ctStr.dwControlCode,
731 pbSendBuffer, ctStr.cbSendLength,
732 pbRecvBuffer,
sizeof pbRecvBuffer,
735 if (dwBytesReturned > ctStr.cbRecvLength)
741 ctStr.dwBytesReturned = dwBytesReturned;
747 ret =
MessageSend(pbRecvBuffer, dwBytesReturned, filedes);
758 if (MSGCheckHandleAssociation(gsStr.hCard, threadContext))
762 if (gsStr.cbAttrLen >
sizeof(gsStr.pbAttr))
763 goto buffer_overflow;
765 cbAttrLen = gsStr.cbAttrLen;
767 gsStr.rv = SCardGetAttrib(gsStr.hCard, gsStr.dwAttrId,
768 gsStr.pbAttr, &cbAttrLen);
770 gsStr.cbAttrLen = cbAttrLen;
782 if (MSGCheckHandleAssociation(gsStr.hCard, threadContext))
786 if (gsStr.cbAttrLen >
sizeof(gsStr.pbAttr))
787 goto buffer_overflow;
789 gsStr.rv = SCardSetAttrib(gsStr.hCard, gsStr.dwAttrId,
790 gsStr.pbAttr, gsStr.cbAttrLen);
797 Log2(PCSC_LOG_CRITICAL,
"Unknown command: %d", header.command);
805 Log2(PCSC_LOG_DEBUG,
"Client die: %d", filedes);
811 Log2(PCSC_LOG_DEBUG,
"Buffer overflow detected: %d", filedes);
814 Log2(PCSC_LOG_DEBUG,
"Wrong length: %d", filedes);
816 (void)close(filedes);
817 MSGCleanupClient(threadContext);
818 (void)pthread_exit((LPVOID) NULL);
821LONG MSGSignalClient(uint32_t filedes, LONG rv)
830 Log2(PCSC_LOG_DEBUG,
"Signal client: %d", filedes);
833 WRITE_BODY_WITH_COMMAND(
"SIGNAL", waStr);
838LONG MSGSendReaderStates(uint32_t filedes)
842 Log2(PCSC_LOG_DEBUG,
"Send reader states: %d", filedes);
845 ret =
MessageSend(readerStates,
sizeof(readerStates), filedes);
852 threadContext->hContext = hContext;
861 if (0 == threadContext->hContext)
863 Log1(PCSC_LOG_ERROR,
"Invalidated handle");
867 if (threadContext->hContext != hContext)
871 while (list_size(&threadContext->cardsList) != 0)
880 ptr = list_get_at(&threadContext->cardsList, 0);
883 Log1(PCSC_LOG_CRITICAL,
"list_get_at failed");
886 hCard = *(int32_t *)ptr;
891 rv = RFReaderInfoById(hCard, &rContext);
905 if (hCard != rContext->
hLockId)
924 rv = SCardStatus(hCard, NULL, NULL, NULL, NULL, NULL, NULL);
934 lrv = list_delete_at(&threadContext->cardsList, 0);
936 Log2(PCSC_LOG_CRITICAL,
937 "list_delete_at failed with return value: %d", lrv);
939 UNREF_READER(rContext)
945 threadContext->hContext = 0;
955 if (0 == threadContext->hContext)
957 Log1(PCSC_LOG_ERROR,
"Invalidated handle");
961 if (threadContext->hContext == hContext)
970 listLength = list_size(&threadContext->cardsList);
971 if (listLength >= contextMaxCardHandles)
974 "Too many card handles for thread context @%p: %d (max is %d). "
975 "Restart pcscd with --max-card-handle-per-thread value",
976 threadContext, listLength, contextMaxCardHandles);
983 lrv = list_append(&threadContext->cardsList, &hCard);
986 Log2(PCSC_LOG_CRITICAL,
987 "list_append failed with return value: %d", lrv);
1006 lrv = list_delete(&threadContext->cardsList, &hCard);
1010 Log2(PCSC_LOG_CRITICAL,
"list_delete failed with error %d", lrv);
1018static LONG MSGCheckHandleAssociation(
SCARDHANDLE hCard,
1023 if (0 == threadContext->hContext)
1027 Log1(PCSC_LOG_CRITICAL,
"Invalidated handle");
1032 list_index = list_locate(&threadContext->cardsList, &hCard);
1034 if (list_index >= 0)
1038 Log1(PCSC_LOG_ERROR,
"Client failed to authenticate");
1048static void MSGCleanupClient(
SCONTEXT * threadContext)
1053 if (threadContext->hContext != 0)
1055 (void)SCardReleaseContext(threadContext->hContext);
1056 (void)MSGRemoveContext(threadContext->hContext, threadContext);
1060 list_destroy(&threadContext->cardsList);
1063 Log3(PCSC_LOG_DEBUG,
1064 "Thread is stopping: dwClientID=%d, threadContext @%p",
1070 memset((
void*) threadContext, 0,
sizeof(
SCONTEXT));
1071 Log2(PCSC_LOG_DEBUG,
"Freeing SCONTEXT @%p", threadContext);
1078 Log2(PCSC_LOG_CRITICAL,
"list_delete failed with error %x", lrv);
1080 free(threadContext);
1085 Log2(PCSC_LOG_DEBUG,
"Starting suicide alarm in %d seconds",
1086 TIME_BEFORE_SUICIDE);
1087 alarm(TIME_BEFORE_SUICIDE);
LONG EHTryToUnregisterClientForEvent(int32_t filedes)
Try to unregisted a client If no client is found then do not log an error.
LONG EHUnregisterClientForEvent(int32_t filedes)
Unregister a client and log an error if the client is not found.
This handles card insertion/removal events, updates ATR, protocol, and status information.
#define SCARD_E_INVALID_HANDLE
The supplied handle was invalid.
#define SCARD_F_INTERNAL_ERROR
An internal consistency check failed.
#define SCARD_W_RESET_CARD
The smart card has been reset, so any shared state information is invalid.
#define SCARD_E_SERVICE_STOPPED
The Smart card resource manager has shut down.
#define SCARD_E_CANCELLED
The action was cancelled by an SCardCancel request.
#define SCARD_S_SUCCESS
No error was encountered.
#define SCARD_E_NO_MEMORY
Not enough memory available to complete this command.
#define SCARD_E_INVALID_VALUE
One or more of the supplied parameters values could not be properly interpreted.
#define SCARD_W_REMOVED_CARD
The smart card has been removed, so further communication is not possible.
#define SCARD_E_INSUFFICIENT_BUFFER
The data buffer to receive returned data is too small for the returned data.
This keeps a list of defines for pcsc-lite.
#define SCARD_RESET_CARD
Reset on close.
LONG SCARDCONTEXT
hContext returned by SCardEstablishContext()
#define SCARD_PROTOCOL_UNDEFINED
protocol not set
#define SCARD_LEAVE_CARD
Do nothing on close.
#define MAX_BUFFER_SIZE_EXTENDED
enhanced (64K + APDU + Lc + Le + SW) Tx/Rx Buffer
LONG SCARDHANDLE
hCard returned by SCardConnect()
#define PCSCLITE_MAX_READERS_CONTEXTS
Maximum readers context (a slot is count as a reader)
This keeps track of a list of currently available reader structures.
_Atomic SCARDHANDLE hLockId
Lock Id.
Protocol Control Information (PCI)
unsigned long dwProtocol
Protocol identifier.
unsigned long cbPciLength
Protocol Control Inf Length.
pthread_mutex_t cardsList_lock
lock for the above list
pthread_t pthThread
Event polling thread's ID.
uint32_t dwClientID
Connection ID used to reference the Client.
contained in SCARD_BEGIN_TRANSACTION Messages.
contained in SCARD_CANCEL Messages.
contained in SCARD_CONNECT Messages.
contained in SCARD_CONTROL Messages.
contained in SCARD_DISCONNECT Messages.
contained in SCARD_END_TRANSACTION Messages.
Information contained in SCARD_ESTABLISH_CONTEXT Messages.
contained in SCARD_GET_ATTRIB and Messages.
Define an exported public reader state structure so each application gets instant notification of cha...
contained in SCARD_RECONNECT Messages.
Information contained in SCARD_RELEASE_CONTEXT Messages.
contained in SCARD_STATUS Messages.
contained in SCARD_TRANSMIT Messages.
Information transmitted in CMD_VERSION Messages.
Information contained in CMD_WAIT_READER_STATE_CHANGE Messages.
uint32_t timeOut
timeout in ms
This handles abstract system level calls.
int SYS_Sleep(int)
Makes the current process sleep for some seconds.
This handles smart card reader communications.
INTERNAL LONG MessageSend(void *buffer_void, uint64_t buffer_size, int32_t filedes)
Sends a menssage from client to server or vice-versa.
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.
This defines some structures and #defines to be used over the transport layer.
#define PROTOCOL_VERSION_MAJOR
Major version of the current message protocol.
#define PROTOCOL_VERSION_MINOR
Minor version of the current message protocol.
@ SCARD_DISCONNECT
used by SCardDisconnect()
@ SCARD_SET_ATTRIB
used by SCardSetAttrib()
@ SCARD_RELEASE_CONTEXT
used by SCardReleaseContext()
@ CMD_STOP_WAITING_READER_STATE_CHANGE
stop waiting for a reader state change
@ CMD_GET_READERS_STATE
get the readers state
@ SCARD_CONTROL
used by SCardControl()
@ CMD_VERSION
get the client/server protocol version
@ CMD_WAIT_READER_STATE_CHANGE
wait for a reader state change
@ SCARD_RECONNECT
used by SCardReconnect()
@ SCARD_STATUS
used by SCardStatus()
@ SCARD_GET_ATTRIB
used by SCardGetAttrib()
@ SCARD_BEGIN_TRANSACTION
used by SCardBeginTransaction()
@ SCARD_TRANSMIT
used by SCardTransmit()
@ SCARD_END_TRANSACTION
used by SCardEndTransaction()
@ SCARD_CANCEL
used by SCardCancel()
@ SCARD_CONNECT
used by SCardConnect()
@ SCARD_ESTABLISH_CONTEXT
used by SCardEstablishContext()
LONG CreateContextThread(uint32_t *pdwClientID)
Creates threads to handle messages received from Clients.
static const char * CommandsText[]
Handles messages received from Clients.
static list_t contextsList
Context tracking list.
pthread_mutex_t contextsList_lock
lock for the above list
char AutoExit
Represents an Application Context on the Server side.
This demarshalls functions over the message queue and keeps track of clients and their handles.