76static int contextMaxThreadCounter = PCSC_MAX_CONTEXT_THREADS;
77static int contextMaxCardHandles = PCSC_MAX_CONTEXT_CARD_HANDLES;
92static LONG MSGCheckHandleAssociation(
SCARDHANDLE, SCONTEXT *);
96static LONG MSGRemoveHandle(
SCARDHANDLE, SCONTEXT *);
97static void MSGCleanupClient(SCONTEXT *);
99static void * ContextThread(LPVOID pdwIndex);
101extern int pcsclite_max_reader_context;
102extern READER_CONTEXT ** sReadersContexts;
103extern int16_t ReaderEvents;
105static int contextsListhContext_seeker(
const void *el,
const void *key)
107 const SCONTEXT * currentContext = (SCONTEXT *)el;
109 if ((el == NULL) || (key == NULL))
111 Log3(PCSC_LOG_CRITICAL,
"called with NULL pointer: el=%p, key=%p",
116 if (currentContext->hContext == *(int32_t *)key)
121LONG ContextsInitialize(
int customMaxThreadCounter,
122 int customMaxThreadCardHandles)
126 if (customMaxThreadCounter != 0)
127 contextMaxThreadCounter = customMaxThreadCounter;
129 if (customMaxThreadCardHandles != 0)
130 contextMaxCardHandles = customMaxThreadCardHandles;
135 Log2(PCSC_LOG_CRITICAL,
"list_init failed with return value: %d", lrv);
138 lrv = list_attributes_seeker(&
contextsList, contextsListhContext_seeker);
141 Log2(PCSC_LOG_CRITICAL,
142 "list_attributes_seeker failed with return value: %d", lrv);
151void ContextsDeinitialize(
void)
159 Log2(PCSC_LOG_DEBUG,
"remaining threads: %d", listSize);
164 Log1(PCSC_LOG_ERROR,
"list_iterator_start failed");
170 Log3(PCSC_LOG_DEBUG,
"Cancel dwClientID=%d hContext: %p",
174 Log2(PCSC_LOG_DEBUG,
"Waiting client: %d", elt->
dwClientID);
176 Log2(PCSC_LOG_INFO,
"Client %d terminated", elt->
dwClientID);
198 SCONTEXT * newContext = NULL;
204 if (listSize >= contextMaxThreadCounter)
206 Log2(PCSC_LOG_CRITICAL,
"Too many context running: %d", listSize);
211 newContext = malloc(
sizeof(*newContext));
212 if (NULL == newContext)
214 Log1(PCSC_LOG_CRITICAL,
"Could not allocate new context");
217 memset(newContext, 0,
sizeof(*newContext));
222 lrv = list_init(&newContext->cardsList);
225 Log2(PCSC_LOG_CRITICAL,
"list_init failed with return value: %d", lrv);
230 list_attributes_copy(&newContext->cardsList, list_meter_int32_t, 1);
237 lrv = list_attributes_comparator(&newContext->cardsList,
238 list_comparator_int32_t);
241 Log2(PCSC_LOG_CRITICAL,
242 "list_attributes_comparator failed with return value: %d", lrv);
243 list_destroy(&newContext->cardsList);
252 Log2(PCSC_LOG_CRITICAL,
"list_append failed with return value: %d",
254 list_destroy(&newContext->cardsList);
258 rv = ThreadCreate(&newContext->
pthThread, THREAD_ATTR_DETACHED,
259 (PCSCLITE_THREAD_FUNCTION( )) ContextThread, (LPVOID) newContext);
264 Log2(PCSC_LOG_CRITICAL,
"ThreadCreate failed: %s", strerror(rv));
267 Log2(PCSC_LOG_CRITICAL,
"list_delete failed with error %d", lrv2);
268 list_destroy(&newContext->cardsList);
285 (void)close(*pdwClientID);
320 "CANCEL_TRANSACTION",
324 "CMD_GET_READERS_STATE",
325 "CMD_WAIT_READER_STATE_CHANGE",
326 "CMD_STOP_WAITING_READER_STATE_CHANGE",
327 "CMD_GET_READER_EVENTS",
328 "CMD_GET_READERS_STATE_SIZE",
329 "CMD_GET_READERS_STATE_ARRAY",
334#define READ_BODY(v) \
336 if (header.size != sizeof(v)) \
338 ret = MessageReceive(&v, sizeof(v), filedes); \
339 if (ret != SCARD_S_SUCCESS) { \
340 Log2(PCSC_LOG_DEBUG, "Client die: %d", filedes); \
345#define WRITE_BODY(v) \
346 WRITE_BODY_WITH_COMMAND(CommandsText[header.command], v)
347#define WRITE_BODY_WITH_COMMAND(command, v) \
349 LogRv4(PCSC_LOG_DEBUG, v.rv, "%s for client %d", command, filedes); \
350 ret = MessageSend(&v, sizeof(v), filedes); \
353static void * ContextThread(LPVOID newContext)
355 SCONTEXT * threadContext = (SCONTEXT *) newContext;
357 bool old_reader_state_api =
false;
359 if (IsClientAuthorized(filedes,
"access_pcsc", NULL) == 0)
361 Log1(PCSC_LOG_CRITICAL,
"Rejected unauthorized PC/SC client");
366 Log1(PCSC_LOG_DEBUG,
"Authorized PC/SC client");
369 Log3(PCSC_LOG_DEBUG,
"Thread is started: dwClientID=%d, threadContext @%p",
380 Log2(PCSC_LOG_DEBUG,
"Client die: %d", filedes);
385 if ((header.command > CMD_ENUM_FIRST)
386 && (header.command < CMD_ENUM_LAST))
387 Log3(PCSC_LOG_DEBUG,
"Received command: %s from client %d",
390 switch (header.command)
399 Log3(PCSC_LOG_DEBUG,
"Client is protocol version %d:%d",
400 veStr.major, veStr.minor);
408 Log1(PCSC_LOG_CRITICAL,
409 "Communication protocol mismatch!");
410 Log3(PCSC_LOG_ERROR,
"Client protocol is %d:%d",
411 veStr.major, veStr.minor);
412 Log3(PCSC_LOG_ERROR,
"Server protocol is %d:%d",
421 Log1(PCSC_LOG_INFO,
"Enable backward compatibility");
422 old_reader_state_api =
true;
444 RFWaitForReaderInit();
447 MSGSendReaderStates(filedes,
true);
457 RFWaitForReaderInit();
461 EHRegisterClientForEvent(filedes);
462 if (old_reader_state_api)
463 MSGSendReaderStates(filedes,
true);
495 .readerEvents = ReaderEvents,
499 WRITE_BODY(readerEvents);
503 case CMD_GET_READERS_STATE_SIZE:
506 int32_t array_size = pcsclite_max_reader_context;
508 MessageSend(&array_size,
sizeof(array_size), filedes);
518 RFWaitForReaderInit();
521 MSGSendReaderStates(filedes,
false);
532 hContext = esStr.hContext;
533 esStr.rv = SCardEstablishContext(esStr.dwScope, 0, 0,
535 esStr.hContext = hContext;
538 esStr.rv = MSGAddContext(esStr.hContext, threadContext);
550 reStr.rv = SCardReleaseContext(reStr.hContext);
553 reStr.rv = MSGRemoveContext(reStr.hContext, threadContext);
563 DWORD dwActiveProtocol;
567 coStr.szReader[
sizeof(coStr.szReader)-1] = 0;
569 dwActiveProtocol = coStr.dwActiveProtocol;
571 if (IsClientAuthorized(filedes,
"access_card", coStr.szReader) == 0)
573 Log2(PCSC_LOG_CRITICAL,
"Rejected unauthorized client for '%s'", coStr.szReader);
577 dwActiveProtocol = -1;
581 Log2(PCSC_LOG_DEBUG,
"Authorized client for '%s'", coStr.szReader);
583 coStr.rv = SCardConnect(coStr.hContext, coStr.szReader,
584 coStr.dwShareMode, coStr.dwPreferredProtocols,
585 &hCard, &dwActiveProtocol);
589 coStr.dwActiveProtocol = dwActiveProtocol;
593 coStr.rv = MSGAddHandle(coStr.hContext, coStr.hCard,
612 if (MSGCheckHandleAssociation(rcStr.hCard, threadContext))
615 rcStr.rv = SCardReconnect(rcStr.hCard, rcStr.dwShareMode,
616 rcStr.dwPreferredProtocols, rcStr.dwInitialization,
618 rcStr.dwActiveProtocol = dwActiveProtocol;
630 if (MSGCheckHandleAssociation(diStr.hCard, threadContext))
633 diStr.rv = SCardDisconnect(diStr.hCard, diStr.dwDisposition);
636 diStr.rv = MSGRemoveHandle(diStr.hCard, threadContext);
648 if (MSGCheckHandleAssociation(beStr.hCard, threadContext))
651 beStr.rv = SCardBeginTransaction(beStr.hCard);
663 if (MSGCheckHandleAssociation(enStr.hCard, threadContext))
666 enStr.rv = SCardEndTransaction(enStr.hCard,
667 enStr.dwDisposition);
676 SCONTEXT * psTargetContext = NULL;
689 if (psTargetContext != NULL)
691 uint32_t fd = psTargetContext->dwClientID;
715 if (MSGCheckHandleAssociation(stStr.hCard, threadContext))
719 stStr.rv = SCardStatus(stStr.hCard, NULL, NULL, NULL,
737 if (MSGCheckHandleAssociation(trStr.hCard, threadContext))
741 if (trStr.cbSendLength >
sizeof(pbSendBuffer))
742 goto buffer_overflow;
748 Log2(PCSC_LOG_DEBUG,
"Client die: %d", filedes);
752 ioSendPci.
dwProtocol = trStr.ioSendPciProtocol;
754 ioRecvPci.
dwProtocol = trStr.ioRecvPciProtocol;
756 cbRecvLength =
sizeof pbRecvBuffer;
758 trStr.rv = SCardTransmit(trStr.hCard, &ioSendPci,
759 pbSendBuffer, trStr.cbSendLength, &ioRecvPci,
760 pbRecvBuffer, &cbRecvLength);
762 if (cbRecvLength > trStr.pcbRecvLength)
768 trStr.ioSendPciProtocol = ioSendPci.
dwProtocol;
770 trStr.ioRecvPciProtocol = ioRecvPci.
dwProtocol;
772 trStr.pcbRecvLength = cbRecvLength;
778 ret =
MessageSend(pbRecvBuffer, cbRecvLength, filedes);
787 DWORD dwBytesReturned;
791 if (MSGCheckHandleAssociation(ctStr.hCard, threadContext))
795 if (ctStr.cbSendLength >
sizeof(pbSendBuffer))
797 goto buffer_overflow;
804 Log2(PCSC_LOG_DEBUG,
"Client die: %d", filedes);
808 dwBytesReturned = ctStr.dwBytesReturned;
810 ctStr.rv = SCardControl(ctStr.hCard, ctStr.dwControlCode,
811 pbSendBuffer, ctStr.cbSendLength,
812 pbRecvBuffer,
sizeof pbRecvBuffer,
815 if (dwBytesReturned > ctStr.cbRecvLength)
821 ctStr.dwBytesReturned = dwBytesReturned;
827 ret =
MessageSend(pbRecvBuffer, dwBytesReturned, filedes);
838 if (MSGCheckHandleAssociation(gsStr.hCard, threadContext))
842 if (gsStr.cbAttrLen >
sizeof(gsStr.pbAttr))
843 goto buffer_overflow;
845 cbAttrLen = gsStr.cbAttrLen;
847 gsStr.rv = SCardGetAttrib(gsStr.hCard, gsStr.dwAttrId,
848 gsStr.pbAttr, &cbAttrLen);
850 gsStr.cbAttrLen = cbAttrLen;
862 if (MSGCheckHandleAssociation(gsStr.hCard, threadContext))
866 if (gsStr.cbAttrLen >
sizeof(gsStr.pbAttr))
867 goto buffer_overflow;
869 gsStr.rv = SCardSetAttrib(gsStr.hCard, gsStr.dwAttrId,
870 gsStr.pbAttr, gsStr.cbAttrLen);
877 Log2(PCSC_LOG_CRITICAL,
"Unknown command: %d", header.command);
885 Log2(PCSC_LOG_DEBUG,
"Client die: %d", filedes);
891 Log2(PCSC_LOG_DEBUG,
"Buffer overflow detected: %d", filedes);
894 Log2(PCSC_LOG_DEBUG,
"Wrong length: %d", filedes);
896 (void)close(filedes);
897 MSGCleanupClient(threadContext);
898 (void)pthread_exit((LPVOID) NULL);
901LONG MSGSignalClient(uint32_t filedes, LONG rv)
910 Log2(PCSC_LOG_DEBUG,
"Signal client: %d", filedes);
913 WRITE_BODY_WITH_COMMAND(
"SIGNAL", waStr);
918LONG MSGSendReaderStates(uint32_t filedes,
bool old_api)
922 Log2(PCSC_LOG_DEBUG,
"Send reader states: %d", filedes);
924 int length = pcsclite_max_reader_context;
932 for (
int i=0; i<length; i++)
934 ret =
MessageSend(&sReadersContexts[i]->readerState,
953static LONG MSGAddContext(
SCARDCONTEXT hContext, SCONTEXT * threadContext)
955 threadContext->hContext = hContext;
959static LONG MSGRemoveContext(
SCARDCONTEXT hContext, SCONTEXT * threadContext)
964 if (0 == threadContext->hContext)
966 Log1(PCSC_LOG_ERROR,
"Invalidated handle");
970 if (threadContext->hContext != hContext)
974 while (list_size(&threadContext->cardsList) != 0)
976 READER_CONTEXT * rContext = NULL;
983 ptr = list_get_at(&threadContext->cardsList, 0);
986 Log1(PCSC_LOG_CRITICAL,
"list_get_at failed");
989 hCard = *(int32_t *)ptr;
996 rv = RFReaderInfoById(hCard, &rContext);
1013 if (hCard != rContext->
hLockId)
1032 rv = SCardStatus(hCard, NULL, NULL, NULL, NULL, NULL, NULL);
1043 lrv = list_delete_at(&threadContext->cardsList, 0);
1045 Log2(PCSC_LOG_CRITICAL,
1046 "list_delete_at failed with return value: %d", lrv);
1049 UNREF_READER(rContext)
1056 threadContext->hContext = 0;
1062 SCONTEXT * threadContext)
1066 if (0 == threadContext->hContext)
1068 Log1(PCSC_LOG_ERROR,
"Invalidated handle");
1072 if (threadContext->hContext == hContext)
1081 listLength = list_size(&threadContext->cardsList);
1082 if (listLength >= contextMaxCardHandles)
1084 Log4(PCSC_LOG_DEBUG,
1085 "Too many card handles for thread context @%p: %d (max is %d). "
1086 "Restart pcscd with --max-card-handle-per-thread value",
1087 threadContext, listLength, contextMaxCardHandles);
1094 lrv = list_append(&threadContext->cardsList, &hCard);
1097 Log2(PCSC_LOG_CRITICAL,
1098 "list_append failed with return value: %d", lrv);
1112static LONG MSGRemoveHandle(
SCARDHANDLE hCard, SCONTEXT * threadContext)
1117 lrv = list_delete(&threadContext->cardsList, &hCard);
1121 Log2(PCSC_LOG_CRITICAL,
"list_delete failed with error %d", lrv);
1129static LONG MSGCheckHandleAssociation(
SCARDHANDLE hCard,
1130 SCONTEXT * threadContext)
1134 if (0 == threadContext->hContext)
1138 Log1(PCSC_LOG_CRITICAL,
"Invalidated handle");
1143 list_index = list_locate(&threadContext->cardsList, &hCard);
1145 if (list_index >= 0)
1149 Log1(PCSC_LOG_ERROR,
"Client failed to authenticate");
1159static void MSGCleanupClient(SCONTEXT * threadContext)
1164 if (threadContext->hContext != 0)
1166 (void)SCardReleaseContext(threadContext->hContext);
1167 (void)MSGRemoveContext(threadContext->hContext, threadContext);
1171 list_destroy(&threadContext->cardsList);
1174 Log3(PCSC_LOG_DEBUG,
1175 "Thread is stopping: dwClientID=%d, threadContext @%p",
1181 memset((
void*) threadContext, 0,
sizeof(SCONTEXT));
1182 Log2(PCSC_LOG_DEBUG,
"Freeing SCONTEXT @%p", threadContext);
1189 Log2(PCSC_LOG_CRITICAL,
"list_delete failed with error %x", lrv);
1191 free(threadContext);
1196 Log2(PCSC_LOG_DEBUG,
"Starting exit alarm in %d seconds",
1197 TIME_BEFORE_SUICIDE);
1198 alarm(TIME_BEFORE_SUICIDE);
LONG EHTryToUnregisterClientForEvent(int32_t filedes)
Try to unregister 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_SECURITY_VIOLATION
Access was denied because of a security violation.
#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.
#define SCARD_E_READER_UNAVAILABLE
The specified reader is not currently available for use.
bool AutoExit
Represents an Application Context on the Server side.
#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.
struct pubReaderState READER_STATE
Define an exported public reader state structure so each application gets instant notification of cha...
_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.
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.
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 response from the server or vice-versa.
This defines some structures and #defines to be used over the transport layer.
#define PROTOCOL_VERSION_MINOR_SERVER_BACKWARD
Minor version the server also supports.
#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_GET_READERS_STATE_ARRAY
get the readers state array
@ 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()
@ CMD_GET_READER_EVENTS
get the number of reader events
@ 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
This demarshalls functions over the message queue and keeps track of clients and their handles.