75 static int contextMaxThreadCounter = PCSC_MAX_CONTEXT_THREADS;
76 static int contextMaxCardHandles = PCSC_MAX_CONTEXT_CARD_HANDLES;
96 static LONG MSGCleanupClient(
SCONTEXT *);
98 static void ContextThread(LPVOID pdwIndex);
102 static 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)
118 LONG ContextsInitialize(
int customMaxThreadCounter,
119 int customMaxThreadCardHandles)
123 if (customMaxThreadCounter != 0)
124 contextMaxThreadCounter = customMaxThreadCounter;
126 if (customMaxThreadCardHandles != 0)
127 contextMaxCardHandles = customMaxThreadCardHandles;
129 lrv = list_init(&contextsList);
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);
148 void ContextsDeinitialize(
void)
151 listSize = list_size(&contextsList);
152 Log2(PCSC_LOG_DEBUG,
"remaining threads: %d", listSize);
155 list_destroy(&contextsList);
178 listSize = list_size(&contextsList);
179 if (listSize >= contextMaxThreadCounter)
181 Log2(PCSC_LOG_CRITICAL,
"Too many context running: %d", listSize);
186 newContext = malloc(
sizeof(*newContext));
187 if (NULL == newContext)
189 Log1(PCSC_LOG_CRITICAL,
"Could not allocate new context");
192 memset(newContext, 0,
sizeof(*newContext));
197 lrv = list_init(&newContext->cardsList);
200 Log2(PCSC_LOG_CRITICAL,
"list_init failed with return value: %d", lrv);
205 list_attributes_copy(&newContext->cardsList, list_meter_int32_t, 1);
212 lrv = list_attributes_comparator(&newContext->cardsList,
213 list_comparator_int32_t);
216 Log2(PCSC_LOG_CRITICAL,
217 "list_attributes_comparator failed with return value: %d", lrv);
218 list_destroy(&newContext->cardsList);
224 lrv = list_append(&contextsList, newContext);
227 Log2(PCSC_LOG_CRITICAL,
"list_append failed with return value: %d",
229 list_destroy(&newContext->cardsList);
233 rv = ThreadCreate(&newContext->
pthThread, THREAD_ATTR_DETACHED,
234 (PCSCLITE_THREAD_FUNCTION( )) ContextThread, (LPVOID) newContext);
239 Log2(PCSC_LOG_CRITICAL,
"ThreadCreate failed: %s", strerror(rv));
240 lrv2 = list_delete(&contextsList, newContext);
242 Log2(PCSC_LOG_CRITICAL,
"list_delete failed with error %d", lrv2);
243 list_destroy(&newContext->cardsList);
260 (void)close(*pdwClientID);
295 "CANCEL_TRANSACTION",
299 "CMD_GET_READERS_STATE",
300 "CMD_WAIT_READER_STATE_CHANGE",
301 "CMD_STOP_WAITING_READER_STATE_CHANGE",
306 #define READ_BODY(v) \ 308 if (header.size != sizeof(v)) \ 310 ret = MessageReceive(&v, sizeof(v), filedes); \ 311 if (ret != SCARD_S_SUCCESS) { \ 312 Log2(PCSC_LOG_DEBUG, "Client die: %d", filedes); \ 317 #define WRITE_BODY(v) \ 318 WRITE_BODY_WITH_COMMAND(CommandsText[header.command], v) 319 #define WRITE_BODY_WITH_COMMAND(command, v) \ 321 Log4(PCSC_LOG_DEBUG, "%s rv=0x%X for client %d", command, v.rv, filedes); \ 322 ret = MessageSend(&v, sizeof(v), filedes); \ 325 static void ContextThread(LPVOID newContext)
330 if (IsClientAuthorized(filedes,
"access_pcsc", NULL) == 0)
332 Log1(PCSC_LOG_CRITICAL,
"Rejected unauthorized PC/SC client");
337 Log1(PCSC_LOG_DEBUG,
"Authorized PC/SC client");
340 Log3(PCSC_LOG_DEBUG,
"Thread is started: dwClientID=%d, threadContext @%p",
351 Log2(PCSC_LOG_DEBUG,
"Client die: %d", filedes);
356 if ((header.
command > CMD_ENUM_FIRST)
357 && (header.
command < CMD_ENUM_LAST))
358 Log3(PCSC_LOG_DEBUG,
"Received command: %s from client %d",
359 CommandsText[header.
command], filedes);
370 Log3(PCSC_LOG_DEBUG,
"Client is protocol version %d:%d",
379 Log3(PCSC_LOG_CRITICAL,
"Client protocol is %d:%d",
381 Log3(PCSC_LOG_CRITICAL,
"Server protocol is %d:%d",
401 RFWaitForReaderInit();
405 ret =
MessageSend(readerStates,
sizeof(readerStates), filedes);
416 EHRegisterClientForEvent(filedes);
447 hContext = esStr.hContext;
450 esStr.hContext = hContext;
453 esStr.rv = MSGAddContext(esStr.hContext, threadContext);
468 reStr.rv = MSGRemoveContext(reStr.hContext, threadContext);
478 DWORD dwActiveProtocol;
482 coStr.szReader[
sizeof(coStr.szReader)-1] = 0;
484 dwActiveProtocol = coStr.dwActiveProtocol;
486 if (IsClientAuthorized(filedes,
"access_card", coStr.szReader) == 0)
488 Log2(PCSC_LOG_CRITICAL,
"Rejected unauthorized client for '%s'", coStr.szReader);
493 Log2(PCSC_LOG_DEBUG,
"Authorized client for '%s'", coStr.szReader);
497 coStr.dwShareMode, coStr.dwPreferredProtocols,
498 &hCard, &dwActiveProtocol);
501 coStr.dwActiveProtocol = dwActiveProtocol;
504 coStr.rv = MSGAddHandle(coStr.hContext, coStr.hCard,
514 DWORD dwActiveProtocol;
518 if (MSGCheckHandleAssociation(rcStr.hCard, threadContext))
522 rcStr.dwPreferredProtocols, rcStr.dwInitialization,
524 rcStr.dwActiveProtocol = dwActiveProtocol;
536 if (MSGCheckHandleAssociation(diStr.hCard, threadContext))
542 diStr.rv = MSGRemoveHandle(diStr.hCard, threadContext);
554 if (MSGCheckHandleAssociation(beStr.hCard, threadContext))
569 if (MSGCheckHandleAssociation(enStr.hCard, threadContext))
573 enStr.dwDisposition);
587 psTargetContext = (
SCONTEXT *) list_seek(&contextsList,
590 if (psTargetContext != NULL)
592 uint32_t fd = psTargetContext->dwClientID;
612 if (MSGCheckHandleAssociation(stStr.hCard, threadContext))
616 stStr.rv =
SCardStatus(stStr.hCard, NULL, NULL, NULL,
634 if (MSGCheckHandleAssociation(trStr.hCard, threadContext))
638 if ((trStr.pcbRecvLength >
sizeof(pbRecvBuffer))
639 || (trStr.cbSendLength >
sizeof(pbSendBuffer)))
640 goto buffer_overflow;
646 Log2(PCSC_LOG_DEBUG,
"Client die: %d", filedes);
650 ioSendPci.
dwProtocol = trStr.ioSendPciProtocol;
652 ioRecvPci.
dwProtocol = trStr.ioRecvPciProtocol;
654 cbRecvLength =
sizeof pbRecvBuffer;
657 pbSendBuffer, trStr.cbSendLength, &ioRecvPci,
658 pbRecvBuffer, &cbRecvLength);
660 if (cbRecvLength > trStr.pcbRecvLength)
666 trStr.ioSendPciProtocol = ioSendPci.
dwProtocol;
668 trStr.ioRecvPciProtocol = ioRecvPci.
dwProtocol;
670 trStr.pcbRecvLength = cbRecvLength;
676 ret =
MessageSend(pbRecvBuffer, cbRecvLength, filedes);
685 DWORD dwBytesReturned;
689 if (MSGCheckHandleAssociation(ctStr.hCard, threadContext))
693 if ((ctStr.cbRecvLength >
sizeof(pbRecvBuffer))
694 || (ctStr.cbSendLength >
sizeof(pbSendBuffer)))
696 goto buffer_overflow;
703 Log2(PCSC_LOG_DEBUG,
"Client die: %d", filedes);
707 dwBytesReturned = ctStr.dwBytesReturned;
709 ctStr.rv =
SCardControl(ctStr.hCard, ctStr.dwControlCode,
710 pbSendBuffer, ctStr.cbSendLength,
711 pbRecvBuffer, ctStr.cbRecvLength,
714 ctStr.dwBytesReturned = dwBytesReturned;
720 ret =
MessageSend(pbRecvBuffer, dwBytesReturned, filedes);
731 if (MSGCheckHandleAssociation(gsStr.hCard, threadContext))
735 if (gsStr.cbAttrLen >
sizeof(gsStr.pbAttr))
736 goto buffer_overflow;
738 cbAttrLen = gsStr.cbAttrLen;
741 gsStr.pbAttr, &cbAttrLen);
743 gsStr.cbAttrLen = cbAttrLen;
755 if (MSGCheckHandleAssociation(gsStr.hCard, threadContext))
759 if (gsStr.cbAttrLen >
sizeof(gsStr.pbAttr))
760 goto buffer_overflow;
763 gsStr.pbAttr, gsStr.cbAttrLen);
770 Log2(PCSC_LOG_CRITICAL,
"Unknown command: %d", header.
command);
778 Log2(PCSC_LOG_DEBUG,
"Client die: %d", filedes);
784 Log2(PCSC_LOG_DEBUG,
"Buffer overflow detected: %d", filedes);
787 Log2(PCSC_LOG_DEBUG,
"Wrong length: %d", filedes);
789 (void)close(filedes);
790 (void)MSGCleanupClient(threadContext);
791 (void)pthread_exit((LPVOID) NULL);
794 LONG MSGSignalClient(uint32_t filedes, LONG rv)
799 Log2(PCSC_LOG_DEBUG,
"Signal client: %d", filedes);
802 WRITE_BODY_WITH_COMMAND(
"SIGNAL", waStr);
809 threadContext->hContext = hContext;
818 if (0 == threadContext->hContext)
820 Log1(PCSC_LOG_ERROR,
"Invalidated handle");
824 if (threadContext->hContext != hContext)
828 while (list_size(&threadContext->cardsList) != 0)
837 ptr = list_get_at(&threadContext->cardsList, 0);
840 Log1(PCSC_LOG_CRITICAL,
"list_get_at failed");
843 hCard = *(int32_t *)ptr;
848 rv = RFReaderInfoById(hCard, &rContext);
858 if (hCard != hLockId)
873 rv =
SCardStatus(hCard, NULL, NULL, NULL, NULL, NULL, NULL);
882 lrv = list_delete_at(&threadContext->cardsList, 0);
884 Log2(PCSC_LOG_CRITICAL,
885 "list_delete_at failed with return value: %d", lrv);
887 UNREF_READER(rContext)
893 threadContext->hContext = 0;
903 if (0 == threadContext->hContext)
905 Log1(PCSC_LOG_ERROR,
"Invalidated handle");
909 if (threadContext->hContext == hContext)
918 listLength = list_size(&threadContext->cardsList);
919 if (listLength >= contextMaxCardHandles)
922 "Too many card handles for thread context @%p: %d (max is %d)" 923 "Restart pcscd with --max-card-handle-per-thread value",
924 threadContext, listLength, contextMaxCardHandles);
931 lrv = list_append(&threadContext->cardsList, &hCard);
934 Log2(PCSC_LOG_CRITICAL,
935 "list_append failed with return value: %d", lrv);
954 lrv = list_delete(&threadContext->cardsList, &hCard);
958 Log2(PCSC_LOG_CRITICAL,
"list_delete failed with error %d", lrv);
966 static LONG MSGCheckHandleAssociation(
SCARDHANDLE hCard,
971 if (0 == threadContext->hContext)
975 Log1(PCSC_LOG_CRITICAL,
"Invalidated handle");
980 list_index = list_locate(&threadContext->cardsList, &hCard);
986 Log1(PCSC_LOG_ERROR,
"Client failed to authenticate");
996 static LONG MSGCleanupClient(
SCONTEXT * threadContext)
1001 if (threadContext->hContext != 0)
1004 (void)MSGRemoveContext(threadContext->hContext, threadContext);
1008 list_destroy(&threadContext->cardsList);
1011 Log3(PCSC_LOG_DEBUG,
1012 "Thread is stopping: dwClientID=%d, threadContext @%p",
1018 memset((
void*) threadContext, 0,
sizeof(
SCONTEXT));
1019 Log2(PCSC_LOG_DEBUG,
"Freeing SCONTEXT @%p", threadContext);
1022 lrv = list_delete(&contextsList, threadContext);
1023 listSize = list_size(&contextsList);
1026 Log2(PCSC_LOG_CRITICAL,
"list_delete failed with error %x", lrv);
1028 free(threadContext);
1033 Log2(PCSC_LOG_DEBUG,
"Starting suicide alarm in %d seconds",
1034 TIME_BEFORE_SUICIDE);
1035 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.
volatile SCARDHANDLE hLockId
Lock Id.
#define SCARD_S_SUCCESS
No error was encountered.
contained in SCARD_END_TRANSACTION Messages.
#define SCARD_E_NO_SERVICE
The Smart card resource manager is not running.
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.
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.
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_NO_MEMORY
Not enough memory available to complete this command.
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.
#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 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.
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_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 serie 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.
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_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.