108#include <sys/types.h>
137static bool sharing_shall_block =
true;
138static int Protocol_version;
140#define COLOR_RED "\33[01;31m"
141#define COLOR_GREEN "\33[32m"
142#define COLOR_BLUE "\33[34m"
143#define COLOR_MAGENTA "\33[35m"
144#define COLOR_NORMAL "\33[0m"
151static void trace(
const char *func,
const char direction,
const char *fmt, ...)
155 fprintf(stderr, COLOR_GREEN
"%c " COLOR_BLUE
"[%lX] " COLOR_GREEN
"%s ",
156 direction, pthread_self(), func);
158 fprintf(stderr, COLOR_MAGENTA);
160 vfprintf(stderr, fmt, args);
163 fprintf(stderr, COLOR_NORMAL
"\n");
166#define API_TRACE_IN(...) trace(__FUNCTION__, '<', __VA_ARGS__);
167#define API_TRACE_OUT(...) trace(__FUNCTION__, '>', __VA_ARGS__);
169#define API_TRACE_IN(...)
170#define API_TRACE_OUT(...)
175#define PROFILE_FILE "/tmp/pcsc_profile"
181pthread_t threads[MAX_THREADS];
182struct timeval profile_time_start[MAX_THREADS];
186#define PROFILE_START profile_start();
187#define PROFILE_END(rv) profile_end(__FUNCTION__, rv);
189static void profile_start(
void)
191 static bool initialized =
false;
200 sprintf(filename,
"%s-%d", PROFILE_FILE, getuid());
201 profile_fd = fopen(filename,
"a+");
202 if (NULL == profile_fd)
204 fprintf(stderr, COLOR_RED
"Can't open %s: %s" COLOR_NORMAL
"\n",
205 PROFILE_FILE, strerror(errno));
208 fprintf(profile_fd,
"\nStart a new profile\n");
210 if (isatty(fileno(stderr)))
217 for (i=0; i<MAX_THREADS; i++)
218 if (pthread_equal(0, threads[i]))
224 gettimeofday(&profile_time_start[i], NULL);
227static void profile_end(
const char *f, LONG rv)
229 struct timeval profile_time_end;
234 gettimeofday(&profile_time_end, NULL);
237 for (i=0; i<MAX_THREADS; i++)
238 if (pthread_equal(t, threads[i]))
243 fprintf(stderr, COLOR_BLUE
" WARNING: no start info for %s\n", f);
247 d =
time_sub(&profile_time_end, &profile_time_start[i]);
255 COLOR_RED
"RESULT %s " COLOR_MAGENTA
"%ld "
256 COLOR_BLUE
"0x%08lX" COLOR_NORMAL
"\n",
259 fprintf(profile_fd,
"%s %ld\n", f, d);
265#define PROFILE_END(rv)
280static int CHANNEL_MAP_seeker(
const void *el,
const void *key)
282 const CHANNEL_MAP * channelMap = el;
284 if ((el == NULL) || (key == NULL))
286 Log3(PCSC_LOG_CRITICAL,
287 "CHANNEL_MAP_seeker called with NULL pointer: el=%p, key=%p",
318static list_t contextMapList;
321static int SCONTEXTMAP_seeker(
const void *el,
const void *key)
325 if ((el == NULL) || (key == NULL))
327 Log3(PCSC_LOG_CRITICAL,
328 "SCONTEXTMAP_seeker called with NULL pointer: el=%p, key=%p",
343static pthread_once_t init_lib_control = PTHREAD_ONCE_INIT;
355int pcsclite_max_reader_context = 0;
357static pthread_mutex_t readerStatesMutex = PTHREAD_MUTEX_INITIALIZER;
367static LONG SCardGetContextChannelAndLockFromHandle(
SCARDHANDLE,
369static LONG SCardGetContextAndChannelFromHandleTH(
SCARDHANDLE,
373static LONG SCardGetSetAttrib(
SCARDHANDLE hCard,
int command, DWORD dwAttrId,
374 LPBYTE pbAttr, LPDWORD pcbAttrLen);
376static LONG getReaderEvents(
SCONTEXTMAP * currentContextMap,
int *readerEvents);
377static LONG getReaderStates(
SCONTEXTMAP * currentContextMap);
378static LONG getReaderStatesAndRegisterForEvents(
SCONTEXTMAP * currentContextMap);
379static LONG unregisterFromEvents(
SCONTEXTMAP * currentContextMap);
422 return currentContextMap != NULL;
465 LPCVOID pvReserved2, LPSCARDCONTEXT phContext)
469 API_TRACE_IN(
"%ld, %p, %p", dwScope, pvReserved1, pvReserved2)
479 pvReserved2, phContext);
484 API_TRACE_OUT(
"%ld", *phContext)
490DESTRUCTOR
static void destructor(
void)
493 list_destroy(&contextMapList);
504static void init_lib(
void)
511 lrv = list_init(&contextMapList);
514 Log2(PCSC_LOG_CRITICAL,
"list_init failed with return value: %d",
519 lrv = list_attributes_seeker(&contextMapList,
523 Log2(PCSC_LOG_CRITICAL,
524 "list_attributes_seeker failed with return value: %d", lrv);
525 list_destroy(&contextMapList);
531 Log1(PCSC_LOG_INFO,
"Disable shared blocking");
532 sharing_shall_block =
false;
569 LPCVOID pvReserved2, LPSCARDCONTEXT phContext)
573 uint32_t dwClientID = 0;
578 if (phContext == NULL)
583 pthread_once(&init_lib_control, init_lib);
610 Log1(PCSC_LOG_CRITICAL,
611 "Your pcscd is too old and does not support CMD_VERSION");
615 Log3(PCSC_LOG_INFO,
"Server is protocol version %d:%d",
617 Log3(PCSC_LOG_INFO,
"Client is protocol version %d:%d",
629 Log1(PCSC_LOG_INFO,
"Using backward compatibility");
642 Protocol_version = veStr.
major * 1000 + veStr.
minor;
648 scEstablishStruct.dwScope = dwScope;
649 scEstablishStruct.hContext = 0;
653 sizeof(scEstablishStruct), (
void *) &scEstablishStruct);
661 rv =
MessageReceive(&scEstablishStruct,
sizeof(scEstablishStruct),
669 rv = scEstablishStruct.rv;
679 *phContext = scEstablishStruct.hContext;
721 API_TRACE_IN(
"%ld", hContext)
729 if (NULL == currentContextMap)
735 scReleaseStruct.hContext = hContext;
739 currentContextMap->dwClientID,
740 sizeof(scReleaseStruct), (
void *) &scReleaseStruct);
749 currentContextMap->dwClientID);
754 rv = scReleaseStruct.rv;
756 (void)pthread_mutex_unlock(¤tContextMap->mMutex);
828 DWORD dwShareMode, DWORD dwPreferredProtocols, LPSCARDHANDLE phCard,
829 LPDWORD pdwActiveProtocol)
836 API_TRACE_IN(
"%ld %s %ld %ld", hContext, szReader, dwShareMode, dwPreferredProtocols)
841 if (phCard == NULL || pdwActiveProtocol == NULL)
846 if (szReader == NULL)
852 if (strlen(szReader) > MAX_READERNAME)
859 if (NULL == currentContextMap)
862 strncpy(scConnectStruct.szReader, szReader,
sizeof scConnectStruct.szReader -1);
863 scConnectStruct.szReader[
sizeof scConnectStruct.szReader -1] =
'\0';
865 scConnectStruct.hContext = hContext;
866 scConnectStruct.dwShareMode = dwShareMode;
867 scConnectStruct.dwPreferredProtocols = dwPreferredProtocols;
868 scConnectStruct.hCard = 0;
869 scConnectStruct.dwActiveProtocol = 0;
873 sizeof(scConnectStruct), (
void *) &scConnectStruct);
882 currentContextMap->dwClientID);
887 *phCard = scConnectStruct.hCard;
888 *pdwActiveProtocol = scConnectStruct.dwActiveProtocol;
895 rv = SCardAddHandle(*phCard, currentContextMap, szReader);
898 rv = scConnectStruct.rv;
901 (void)pthread_mutex_unlock(¤tContextMap->mMutex);
904 API_TRACE_OUT(
"%d", *pdwActiveProtocol)
982 DWORD dwPreferredProtocols, DWORD dwInitialization,
983 LPDWORD pdwActiveProtocol)
988 CHANNEL_MAP * pChannelMap;
991 API_TRACE_IN(
"%ld %ld %ld", hCard, dwShareMode, dwPreferredProtocols)
993 if (pdwActiveProtocol == NULL)
1002 rv = SCardGetContextChannelAndLockFromHandle(hCard, ¤tContextMap,
1007 scReconnectStruct.hCard = hCard;
1008 scReconnectStruct.dwShareMode = dwShareMode;
1009 scReconnectStruct.dwPreferredProtocols = dwPreferredProtocols;
1010 scReconnectStruct.dwInitialization = dwInitialization;
1011 scReconnectStruct.dwActiveProtocol = *pdwActiveProtocol;
1015 sizeof(scReconnectStruct), (
void *) &scReconnectStruct);
1023 rv =
MessageReceive(&scReconnectStruct,
sizeof(scReconnectStruct),
1024 currentContextMap->dwClientID);
1029 rv = scReconnectStruct.rv;
1033 (void)pthread_mutex_unlock(¤tContextMap->mMutex);
1038 *pdwActiveProtocol = scReconnectStruct.dwActiveProtocol;
1041 (void)pthread_mutex_unlock(¤tContextMap->mMutex);
1044 API_TRACE_OUT(
"%ld", *pdwActiveProtocol)
1085 CHANNEL_MAP * pChannelMap;
1088 API_TRACE_IN(
"%ld %ld", hCard, dwDisposition)
1093 rv = SCardGetContextChannelAndLockFromHandle(hCard, ¤tContextMap,
1101 scDisconnectStruct.hCard = hCard;
1102 scDisconnectStruct.dwDisposition = dwDisposition;
1106 sizeof(scDisconnectStruct), (
void *) &scDisconnectStruct);
1114 rv =
MessageReceive(&scDisconnectStruct,
sizeof(scDisconnectStruct),
1115 currentContextMap->dwClientID);
1121 SCardRemoveHandle(hCard);
1122 rv = scDisconnectStruct.rv;
1125 (void)pthread_mutex_unlock(¤tContextMap->mMutex);
1176 CHANNEL_MAP * pChannelMap;
1179 API_TRACE_IN(
"%ld", hCard)
1191 rv = SCardGetContextChannelAndLockFromHandle(hCard, ¤tContextMap,
1196 scBeginStruct.hCard = hCard;
1200 currentContextMap->dwClientID,
1201 sizeof(scBeginStruct), (
void *) &scBeginStruct);
1210 currentContextMap->dwClientID);
1215 rv = scBeginStruct.rv;
1220 (void)pthread_mutex_unlock(¤tContextMap->mMutex);
1224 (void)pthread_mutex_unlock(¤tContextMap->mMutex);
1276 CHANNEL_MAP * pChannelMap;
1279 API_TRACE_IN(
"%ld", hCard)
1284 rv = SCardGetContextChannelAndLockFromHandle(hCard, ¤tContextMap,
1289 scEndStruct.hCard = hCard;
1290 scEndStruct.dwDisposition = dwDisposition;
1294 currentContextMap->dwClientID,
1295 sizeof(scEndStruct), (
void *) &scEndStruct);
1304 currentContextMap->dwClientID);
1309 rv = scEndStruct.rv;
1312 (void)pthread_mutex_unlock(¤tContextMap->mMutex);
1416 LPDWORD pcchReaderLen, LPDWORD pdwState,
1417 LPDWORD pdwProtocol, LPBYTE pbAtr, LPDWORD pcbAtrLen)
1419 DWORD dwReaderLen, dwAtrLen;
1424 CHANNEL_MAP * pChannelMap;
1426 char *bufReader = NULL;
1427 LPBYTE bufAtr = NULL;
1440 if (pcchReaderLen == NULL)
1441 pcchReaderLen = &dummy;
1443 if (pcbAtrLen == NULL)
1447 dwReaderLen = *pcchReaderLen;
1448 dwAtrLen = *pcbAtrLen;
1459 rv = SCardGetContextChannelAndLockFromHandle(hCard, ¤tContextMap,
1465 (void)pthread_mutex_lock(&readerStatesMutex);
1468 rv = getReaderStates(currentContextMap);
1472 r = pChannelMap->readerName;
1473 for (i = 0; i < pcsclite_max_reader_context; i++)
1476 if (r && strcmp(r, readerStates[i].readerName) == 0)
1480 if (i == pcsclite_max_reader_context)
1487 memset(&scStatusStruct, 0,
sizeof(scStatusStruct));
1488 scStatusStruct.hCard = hCard;
1491 sizeof(scStatusStruct), (
void *) &scStatusStruct);
1500 currentContextMap->dwClientID);
1505 rv = scStatusStruct.rv;
1509 (void)pthread_mutex_unlock(¤tContextMap->mMutex);
1510 (void)pthread_mutex_unlock(&readerStatesMutex);
1527 *pcchReaderLen = strlen(pChannelMap->readerName) + 1;
1528 *pcbAtrLen = readerStates[i].cardAtrLength;
1531 *pdwState = (readerStates[i].eventCounter << 16) + readerStates[i].readerState;
1534 *pdwProtocol = readerStates[i].cardProtocol;
1538 dwReaderLen = *pcchReaderLen;
1539 if (NULL == szReaderName)
1544 bufReader = malloc(dwReaderLen);
1545 if (NULL == bufReader)
1550 *(
char **)szReaderName = bufReader;
1553 bufReader = szReaderName;
1558 if (*pcchReaderLen > dwReaderLen)
1561 strncpy(bufReader, pChannelMap->readerName, dwReaderLen);
1566 dwAtrLen = *pcbAtrLen;
1572 bufAtr = malloc(dwAtrLen);
1578 *(LPBYTE *)pbAtr = bufAtr;
1585 if (*pcbAtrLen > dwAtrLen)
1588 memcpy(bufAtr, readerStates[i].cardAtr, min(*pcbAtrLen, dwAtrLen));
1592 (void)pthread_mutex_unlock(¤tContextMap->mMutex);
1593 (void)pthread_mutex_unlock(&readerStatesMutex);
1717 DWORD dwBreakFlag = 0;
1720 int currentReaderCount = 0;
1722 int pnp_reader = -1;
1725 API_TRACE_IN(
"%ld %ld %d", hContext, dwTimeout, cReaders)
1727 for (j=0; j<cReaders; j++)
1729 API_TRACE_IN(
"[%d] %s %lX %lX (%d)", j, rgReaderStates[j].szReader,
1730 rgReaderStates[j].dwCurrentState, rgReaderStates[j].dwEventState,
1731 rgReaderStates[j].cbAtr)
1735 if (rgReaderStates == NULL && cReaders > 0)
1742 for (j = 0; j < cReaders; j++)
1744 if (rgReaderStates[j].szReader == NULL)
1751 int nbNonIgnoredReaders = cReaders;
1753 for (j=0; j<cReaders; j++)
1755 nbNonIgnoredReaders--;
1757 if (0 == nbNonIgnoredReaders)
1774 if (NULL == currentContextMap)
1781 (void)pthread_mutex_lock(&readerStatesMutex);
1784 rv = getReaderStatesAndRegisterForEvents(currentContextMap);
1788 (void)pthread_mutex_unlock(&readerStatesMutex);
1793 for (j=0; j<cReaders; j++)
1795 const char *readerName;
1798 readerName = rgReaderStates[j].szReader;
1799 for (i = 0; i < pcsclite_max_reader_context; i++)
1801 if (strcmp(readerName, readerStates[i].readerName) == 0)
1806 if (i == pcsclite_max_reader_context)
1809 if (strcasecmp(readerName,
"\\\\?PnP?\\Notification") != 0)
1812 (void)pthread_mutex_unlock(&readerStatesMutex);
1819 (void)pthread_mutex_unlock(&readerStatesMutex);
1822 for (j = 0; j < cReaders; j++)
1823 rgReaderStates[j].dwEventState = 0;
1826 Log2(PCSC_LOG_DEBUG,
"Event Loop Start, dwTimeout: %ld", dwTimeout);
1829 if (pnp_reader >= 0)
1832 currReader = &rgReaderStates[pnp_reader];
1835 if (
SCARD_S_SUCCESS == getReaderEvents(currentContextMap, &readerEvents))
1837 int previousReaderEvents = currReader->dwCurrentState >> 16;
1840 currReader->dwEventState = (currReader->dwEventState & 0xFFFF) + (readerEvents << 16);
1843 (previousReaderEvents != readerEvents)
1846 && previousReaderEvents)
1856 for (
int k=0; k < pcsclite_max_reader_context; k++)
1857 if (readerStates[k].readerName[0] !=
'\0')
1858 currentReaderCount++;
1861 if ((DWORD)-1 == dwTimeout)
1871 currReader = &rgReaderStates[j];
1876 const char *readerName;
1880 (void)pthread_mutex_lock(&readerStatesMutex);
1883 readerName = currReader->szReader;
1884 for (i = 0; i < pcsclite_max_reader_context; i++)
1886 if (strcmp(readerName, readerStates[i].readerName) == 0)
1891 if (i == pcsclite_max_reader_context)
1894 if (strcasecmp(readerName,
"\\\\?PnP?\\Notification") == 0)
1896 int k, newReaderCount = 0;
1898 for (k=0; k < pcsclite_max_reader_context; k++)
1899 if (readerStates[k].readerName[0] !=
'\0')
1902 if (newReaderCount != currentReaderCount)
1906 Log1(PCSC_LOG_INFO,
"Reader list changed");
1907 currentReaderCount = newReaderCount;
1909 if (
SCARD_S_SUCCESS == getReaderEvents(currentContextMap, &readerEvents))
1912 currReader->dwEventState = (currReader->dwEventState & 0xFFFF) + (readerEvents << 16);
1921 currReader->dwEventState =
1937 uint32_t readerState;
1944 Log0(PCSC_LOG_DEBUG);
1949 rContext = &readerStates[i];
1955 if (currReader->dwCurrentState & 0xFFFF0000)
1957 unsigned int currentCounter;
1959 currentCounter = (currReader->dwCurrentState >> 16) & 0xFFFF;
1965 Log0(PCSC_LOG_DEBUG);
1971 currReader->dwEventState = ((currReader->dwEventState & 0xffff )
1983 Log0(PCSC_LOG_DEBUG);
1994 Log0(PCSC_LOG_DEBUG);
2002#ifndef DISABLE_AUTO_POWER_ON
2006 (void)
SYS_USleep(PCSCLITE_STATUS_POLL_RATE + 10);
2010 memcpy(currReader->rgbAtr, rContext->
cardAtr,
2014 currReader->cbAtr = 0;
2033 Log0(PCSC_LOG_DEBUG);
2051 Log0(PCSC_LOG_DEBUG);
2061 Log0(PCSC_LOG_DEBUG);
2071 Log0(PCSC_LOG_DEBUG);
2085 Log0(PCSC_LOG_DEBUG);
2099 Log0(PCSC_LOG_DEBUG);
2112 Log0(PCSC_LOG_DEBUG);
2115 else if (currReader-> dwCurrentState
2119 Log0(PCSC_LOG_DEBUG);
2131 Log0(PCSC_LOG_DEBUG);
2136 (void)pthread_mutex_unlock(&readerStatesMutex);
2149 if (dwBreakFlag == 1)
2155 struct timeval before, after;
2157 gettimeofday(&before, NULL);
2168 &waitStatusStruct,
sizeof(waitStatusStruct),
2179 rv = unregisterFromEvents(currentContextMap);
2188 rv = waitStatusStruct.rv;
2193 (void)pthread_mutex_lock(&readerStatesMutex);
2194 rv = getReaderStatesAndRegisterForEvents(currentContextMap);
2195 (void)pthread_mutex_unlock(&readerStatesMutex);
2203 gettimeofday(&after, NULL);
2205 dwTime -= diff/1000;
2225 Log1(PCSC_LOG_DEBUG,
"Event Loop End");
2230 (void)unregisterFromEvents(currentContextMap);
2232 (void)pthread_mutex_unlock(¤tContextMap->
mMutex);
2237 for (j=0; j<cReaders; j++)
2239 API_TRACE_OUT(
"[%d] %s %lX %lX (%d)", j, rgReaderStates[j].szReader,
2240 rgReaderStates[j].dwCurrentState, rgReaderStates[j].dwEventState,
2241 rgReaderStates[j].cbAtr)
2299 DWORD cbSendLength, LPVOID pbRecvBuffer, DWORD cbRecvLength,
2300 LPDWORD lpBytesReturned)
2305 CHANNEL_MAP * pChannelMap;
2310 if (NULL != lpBytesReturned)
2311 *lpBytesReturned = 0;
2316 rv = SCardGetContextChannelAndLockFromHandle(hCard, ¤tContextMap,
2330 scControlStruct.hCard = hCard;
2331 scControlStruct.dwControlCode = dwControlCode;
2332 scControlStruct.cbSendLength = cbSendLength;
2333 scControlStruct.cbRecvLength = cbRecvLength;
2334 scControlStruct.dwBytesReturned = 0;
2335 scControlStruct.rv = 0;
2338 sizeof(scControlStruct), &scControlStruct);
2344 rv =
MessageSend((
char *)pbSendBuffer, cbSendLength,
2345 currentContextMap->dwClientID);
2354 currentContextMap->dwClientID);
2361 if (scControlStruct.dwBytesReturned > cbRecvLength)
2363 if (NULL != lpBytesReturned)
2364 *lpBytesReturned = scControlStruct.dwBytesReturned;
2370 rv =
MessageReceive(pbRecvBuffer, scControlStruct.dwBytesReturned,
2371 currentContextMap->dwClientID);
2378 if (NULL != lpBytesReturned)
2379 *lpBytesReturned = scControlStruct.dwBytesReturned;
2381 rv = scControlStruct.rv;
2384 (void)pthread_mutex_unlock(¤tContextMap->mMutex);
2513 unsigned char *buf = NULL;
2517 if (NULL == pcbAttrLen)
2529 buf = malloc(*pcbAttrLen);
2536 *(
unsigned char **)pbAttr = buf;
2599 if (NULL == pbAttr || 0 == cbAttrLen)
2610static LONG SCardGetSetAttrib(
SCARDHANDLE hCard,
int command, DWORD dwAttrId,
2611 LPBYTE pbAttr, LPDWORD pcbAttrLen)
2616 CHANNEL_MAP * pChannelMap;
2621 rv = SCardGetContextChannelAndLockFromHandle(hCard, ¤tContextMap,
2632 scGetSetStruct.hCard = hCard;
2633 scGetSetStruct.dwAttrId = dwAttrId;
2635 memset(scGetSetStruct.pbAttr, 0,
sizeof(scGetSetStruct.pbAttr));
2638 memcpy(scGetSetStruct.pbAttr, pbAttr, *pcbAttrLen);
2639 scGetSetStruct.cbAttrLen = *pcbAttrLen;
2643 scGetSetStruct.cbAttrLen =
sizeof scGetSetStruct.pbAttr;
2646 sizeof(scGetSetStruct), &scGetSetStruct);
2655 currentContextMap->dwClientID);
2665 if (*pcbAttrLen < scGetSetStruct.cbAttrLen)
2669 DWORD correct_value = scGetSetStruct.cbAttrLen;
2670 scGetSetStruct.cbAttrLen = *pcbAttrLen;
2671 *pcbAttrLen = correct_value;
2676 *pcbAttrLen = scGetSetStruct.cbAttrLen;
2679 memcpy(pbAttr, scGetSetStruct.pbAttr, scGetSetStruct.cbAttrLen);
2681 memset(scGetSetStruct.pbAttr, 0x00,
sizeof(scGetSetStruct.pbAttr));
2683 rv = scGetSetStruct.rv;
2686 (void)pthread_mutex_unlock(¤tContextMap->mMutex);
2750 LPCBYTE pbSendBuffer, DWORD cbSendLength,
2752 LPDWORD pcbRecvLength)
2756 CHANNEL_MAP * pChannelMap;
2761 if (pbSendBuffer == NULL || pbRecvBuffer == NULL ||
2762 pcbRecvLength == NULL || pioSendPci == NULL)
2771 rv = SCardGetContextChannelAndLockFromHandle(hCard, ¤tContextMap,
2786 scTransmitStruct.hCard = hCard;
2787 scTransmitStruct.cbSendLength = cbSendLength;
2788 scTransmitStruct.pcbRecvLength = *pcbRecvLength;
2789 scTransmitStruct.ioSendPciProtocol = pioSendPci->
dwProtocol;
2790 scTransmitStruct.ioSendPciLength = pioSendPci->
cbPciLength;
2795 scTransmitStruct.ioRecvPciProtocol = pioRecvPci->
dwProtocol;
2796 scTransmitStruct.ioRecvPciLength = pioRecvPci->
cbPciLength;
2805 sizeof(scTransmitStruct), (
void *) &scTransmitStruct);
2811 rv =
MessageSend((
void *)pbSendBuffer, cbSendLength,
2828 if (scTransmitStruct.pcbRecvLength > *pcbRecvLength)
2830 *pcbRecvLength = scTransmitStruct.pcbRecvLength;
2836 rv =
MessageReceive(pbRecvBuffer, scTransmitStruct.pcbRecvLength,
2844 pioRecvPci->
dwProtocol = scTransmitStruct.ioRecvPciProtocol;
2845 pioRecvPci->
cbPciLength = scTransmitStruct.ioRecvPciLength;
2849 rv = scTransmitStruct.rv;
2853 (void)pthread_mutex_unlock(¤tContextMap->
mMutex);
2858 *pcbRecvLength = scTransmitStruct.pcbRecvLength;
2861 (void)pthread_mutex_unlock(¤tContextMap->
mMutex);
2935 LPSTR mszReaders, LPDWORD pcchReaders)
2937 DWORD dwReadersLen = 0;
2945 API_TRACE_IN(
"%ld", hContext)
2950 if (pcchReaders == NULL)
2957 if (NULL == currentContextMap)
2964 (void)pthread_mutex_lock(&readerStatesMutex);
2967 rv = getReaderStates(currentContextMap);
2972 for (i = 0; i < pcsclite_max_reader_context; i++)
2973 if (readerStates[i].readerName[0] !=
'\0')
2974 dwReadersLen += strlen(readerStates[i].readerName) + 1;
2979 if (1 == dwReadersLen)
2987 if (NULL == mszReaders)
2992 buf = malloc(dwReadersLen);
2998 *(
char **)mszReaders = buf;
3005 if ((NULL != mszReaders) && (*pcchReaders < dwReadersLen))
3012 if (mszReaders == NULL)
3015 for (i = 0; i < pcsclite_max_reader_context; i++)
3017 if (readerStates[i].readerName[0] !=
'\0')
3022 strcpy(buf, readerStates[i].readerName);
3023 buf += strlen(readerStates[i].readerName)+1;
3030 *pcchReaders = dwReadersLen;
3032 (void)pthread_mutex_unlock(¤tContextMap->
mMutex);
3033 (void)pthread_mutex_unlock(&readerStatesMutex);
3036 API_TRACE_OUT(
"%d", *pcchReaders)
3066 free((
void *)pvMem);
3134 const char ReaderGroup[] =
"SCard$DefaultReaders\0";
3135 const unsigned int dwGroups =
sizeof(ReaderGroup);
3141 if (NULL == currentContextMap)
3146 if (NULL == mszGroups)
3151 buf = malloc(dwGroups);
3157 *(
char **)mszGroups = buf;
3163 if ((NULL != mszGroups) && (*pcchGroups < dwGroups))
3171 memcpy(buf, ReaderGroup, dwGroups);
3174 *pcchGroups = dwGroups;
3176 (void)pthread_mutex_unlock(¤tContextMap->
mMutex);
3218 uint32_t dwClientID = 0;
3223 API_TRACE_IN(
"%ld", hContext)
3231 if (NULL == currentContextMap)
3253 scCancelStruct.hContext = hContext;
3257 sizeof(scCancelStruct), (
void *) &scCancelStruct);
3265 rv =
MessageReceive(&scCancelStruct,
sizeof(scCancelStruct), dwClientID);
3270 rv = scCancelStruct.rv;
3309 API_TRACE_IN(
"%ld", hContext)
3347 if (NULL == newContextMap)
3350 Log2(PCSC_LOG_DEBUG,
"Allocating new SCONTEXTMAP @%p", newContextMap);
3351 newContextMap->
hContext = hContext;
3355 (void)pthread_mutex_init(&newContextMap->
mMutex, NULL);
3357 lrv = list_init(&newContextMap->channelMapList);
3360 Log2(PCSC_LOG_CRITICAL,
"list_init failed with return value: %d", lrv);
3364 lrv = list_attributes_seeker(&newContextMap->channelMapList,
3365 CHANNEL_MAP_seeker);
3368 Log2(PCSC_LOG_CRITICAL,
3369 "list_attributes_seeker failed with return value: %d", lrv);
3370 list_destroy(&newContextMap->channelMapList);
3375 lrv = list_append(&contextMapList, newContextMap);
3379 Log2(PCSC_LOG_CRITICAL,
"list_append failed with return value: %d",
3381 list_destroy(&newContextMap->channelMapList);
3389 (void)pthread_mutex_destroy(&newContextMap->
mMutex);
3390 free(newContextMap);
3419 if (NULL != currentContextMap)
3420 (void)pthread_mutex_lock(¤tContextMap->
mMutex);
3424 return currentContextMap;
3444 currentContextMap = list_seek(&contextMapList, &hContext);
3447 return currentContextMap;
3461 if (NULL != currentContextMap)
3462 SCardCleanContext(currentContextMap);
3465static void SCardCleanContext(
SCONTEXTMAP * targetContextMap)
3467 int list_index, lrv;
3469 CHANNEL_MAP * currentChannelMap;
3474 (void)pthread_mutex_destroy(&targetContextMap->
mMutex);
3476 listSize = list_size(&targetContextMap->channelMapList);
3477 for (list_index = 0; list_index < listSize; list_index++)
3479 currentChannelMap = list_get_at(&targetContextMap->channelMapList,
3481 if (NULL == currentChannelMap)
3483 Log2(PCSC_LOG_CRITICAL,
"list_get_at failed for index %d",
3489 free(currentChannelMap->readerName);
3490 free(currentChannelMap);
3494 list_destroy(&targetContextMap->channelMapList);
3497 lrv = list_delete(&contextMapList, targetContextMap);
3501 Log2(PCSC_LOG_CRITICAL,
3502 "list_delete failed with return value: %d", lrv);
3505 free(targetContextMap);
3517 CHANNEL_MAP * newChannelMap;
3520 newChannelMap = malloc(
sizeof(CHANNEL_MAP));
3521 if (NULL == newChannelMap)
3524 newChannelMap->hCard = hCard;
3525 newChannelMap->readerName = strdup(readerName);
3527 lrv = list_append(¤tContextMap->channelMapList, newChannelMap);
3530 free(newChannelMap->readerName);
3531 free(newChannelMap);
3532 Log2(PCSC_LOG_CRITICAL,
"list_append failed with return value: %d",
3543 CHANNEL_MAP * currentChannelMap;
3547 rv = SCardGetContextAndChannelFromHandleTH(hCard, ¤tContextMap,
3548 ¤tChannelMap);
3552 free(currentChannelMap->readerName);
3554 lrv = list_delete(¤tContextMap->channelMapList, currentChannelMap);
3557 Log2(PCSC_LOG_CRITICAL,
3558 "list_delete failed with return value: %d", lrv);
3561 free(currentChannelMap);
3566static LONG SCardGetContextChannelAndLockFromHandle(
SCARDHANDLE hCard,
3567 SCONTEXTMAP **targetContextMap, CHANNEL_MAP ** targetChannelMap)
3575 rv = SCardGetContextAndChannelFromHandleTH(hCard, targetContextMap,
3579 (void)pthread_mutex_lock(&(*targetContextMap)->mMutex);
3586static LONG SCardGetContextAndChannelFromHandleTH(
SCARDHANDLE hCard,
3587 SCONTEXTMAP **targetContextMap, CHANNEL_MAP ** targetChannelMap)
3593 CHANNEL_MAP * currentChannelMap;
3596 *targetContextMap = NULL;
3597 *targetChannelMap = NULL;
3600 listSize = list_size(&contextMapList);
3602 for (list_index = 0; list_index < listSize; list_index++)
3604 currentContextMap = list_get_at(&contextMapList, list_index);
3605 if (currentContextMap == NULL)
3607 Log2(PCSC_LOG_CRITICAL,
"list_get_at failed for index %d",
3611 currentChannelMap = list_seek(¤tContextMap->channelMapList,
3613 if (currentChannelMap != NULL)
3615 *targetContextMap = currentContextMap;
3616 *targetChannelMap = currentChannelMap;
3637 struct stat statBuffer;
3640 socketName = getSocketName();
3641 rv = stat(socketName, &statBuffer);
3645 Log3(PCSC_LOG_INFO,
"PCSC Not Running: %s: %s",
3646 socketName, strerror(errno));
3653static LONG getReaderEvents(
SCONTEXTMAP * currentContextMap,
int *readerEvents)
3655 int32_t dwClientID = currentContextMap->
dwClientID;
3660 if (Protocol_version < 4005)
3677static LONG getReaderStates(
SCONTEXTMAP * currentContextMap)
3679 int32_t dwClientID = currentContextMap->
dwClientID;
3683 if (Protocol_version <= 4005)
3693 rv =
MessageReceive(&array_size,
sizeof(array_size), dwClientID);
3702 if (array_size > pcsclite_max_reader_context)
3705 readerStates = realloc(readerStates, array_size *
sizeof(readerStates[0]));
3706 if (NULL == readerStates)
3708 pcsclite_max_reader_context = array_size;
3711 if (array_size != pcsclite_max_reader_context)
3717 if (Protocol_version <= 4005)
3725 rv =
MessageReceive(readerStates, array_size *
sizeof(readerStates[0]), dwClientID);
3732static LONG getReaderStatesAndRegisterForEvents(
SCONTEXTMAP * currentContextMap)
3734 int32_t dwClientID = currentContextMap->
dwClientID;
3743 if (Protocol_version <= 4005)
3752 rv =
MessageReceive(readerStates, pcsclite_max_reader_context *
sizeof(readerStates[0]), dwClientID);
3756 return getReaderStates(currentContextMap);
3759static LONG unregisterFromEvents(
SCONTEXTMAP * currentContextMap)
3761 int32_t dwClientID = currentContextMap->
dwClientID;
3767 dwClientID, 0, NULL);
3784 rv = waitStatusStruct.rv;
This handles card insertion/removal events, updates ATR, protocol, and status information.
#define PCSCLITE_SHARING_EXCLUSIVE_CONTEXT
Reader used in exclusive mode.
#define PCSCLITE_SHARING_NO_CONTEXT
No application is using the reader.
#define PCSCLITE_SHARING_LAST_CONTEXT
One application is using the reader.
LONG SCardFreeMemory(SCARDCONTEXT hContext, LPCVOID pvMem)
Releases memory that has been returned from the resource manager using the SCARD_AUTOALLOCATE length ...
LONG SCardSetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPCBYTE pbAttr, DWORD cbAttrLen)
Set an attribute of the IFD Handler.
LONG SCardGetStatusChange(SCARDCONTEXT hContext, DWORD dwTimeout, SCARD_READERSTATE *rgReaderStates, DWORD cReaders)
Blocks execution until the current availability of the cards in a specific set of readers changes.
LONG SCardDisconnect(SCARDHANDLE hCard, DWORD dwDisposition)
Terminates a connection made through SCardConnect().
LONG SCardConnect(SCARDCONTEXT hContext, LPCSTR szReader, DWORD dwShareMode, DWORD dwPreferredProtocols, LPSCARDHANDLE phCard, LPDWORD pdwActiveProtocol)
Establishes a connection to the reader specified in * szReader.
LONG SCardReleaseContext(SCARDCONTEXT hContext)
Destroys a communication context to the PC/SC Resource Manager.
LONG SCardIsValidContext(SCARDCONTEXT hContext)
Check if a SCARDCONTEXT is valid.
LONG SCardListReaders(SCARDCONTEXT hContext, LPCSTR mszGroups, LPSTR mszReaders, LPDWORD pcchReaders)
Returns a list of currently available readers on the system.
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().
LONG SCardListReaderGroups(SCARDCONTEXT hContext, LPSTR mszGroups, LPDWORD pcchGroups)
Returns a list of currently available reader groups on the system.
LONG SCardEstablishContext(DWORD dwScope, LPCVOID pvReserved1, LPCVOID pvReserved2, LPSCARDCONTEXT phContext)
Creates an Application Context to the PC/SC Resource Manager.
LONG SCardCancel(SCARDCONTEXT hContext)
Cancels a specific blocking SCardGetStatusChange() function.
LONG SCardGetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPBYTE pbAttr, LPDWORD pcbAttrLen)
Get an attribute from the IFD Handler (reader driver).
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.
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().
LONG SCardBeginTransaction(SCARDHANDLE hCard)
Establishes a temporary exclusive access mode for doing a series of commands in a transaction.
LONG SCardStatus(SCARDHANDLE hCard, LPSTR szReaderName, LPDWORD pcchReaderLen, LPDWORD pdwState, LPDWORD pdwProtocol, LPBYTE pbAtr, LPDWORD pcbAtrLen)
Returns the current status of the reader connected to by hCard.
LONG SCardEndTransaction(SCARDHANDLE hCard, DWORD dwDisposition)
Ends a previously begun transaction.
#define SCARD_E_INVALID_HANDLE
The supplied handle was invalid.
#define SCARD_E_UNKNOWN_READER
The specified reader name is not recognized.
#define SCARD_E_SERVICE_STOPPED
The Smart card resource manager has shut down.
#define SCARD_E_INVALID_PARAMETER
One or more of the supplied parameters could not be properly interpreted.
#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_NO_READERS_AVAILABLE
Cannot find a smart card reader.
#define SCARD_E_SHARING_VIOLATION
The smart card cannot be accessed because of other connections outstanding.
#define SCARD_E_INVALID_VALUE
One or more of the supplied parameters values could not be properly interpreted.
#define SCARD_E_TIMEOUT
The user-specified timeout value has expired.
#define SCARD_E_INSUFFICIENT_BUFFER
The data buffer to receive returned data is too small for the returned data.
#define SCARD_E_NO_SERVICE
The Smart card resource manager is not running.
#define SCARD_E_READER_UNAVAILABLE
The specified reader is not currently available for use.
#define SCARD_E_UNSUPPORTED_FEATURE
This smart card does not support the requested feature.
#define SCARD_STATE_IGNORE
Ignore this reader.
#define SCARD_SWALLOWED
Card not powered.
LONG SCARDCONTEXT
hContext returned by SCardEstablishContext()
#define SCARD_PRESENT
Card is present.
#define SCARD_STATE_INUSE
Shared Mode.
#define SCARD_AUTOALLOCATE
see SCardFreeMemory()
#define SCARD_STATE_UNAVAILABLE
Status unavailable.
#define SCARD_STATE_PRESENT
Card inserted.
#define SCARD_ABSENT
Card is absent.
#define SCARD_UNKNOWN
Unknown state.
#define SCARD_STATE_UNKNOWN
Reader unknown.
#define INFINITE
Infinite timeout.
#define SCARD_STATE_EMPTY
Card removed.
#define SCARD_STATE_ATRMATCH
ATR matches card.
#define SCARD_STATE_MUTE
Unresponsive card.
#define SCARD_STATE_CHANGED
State has changed.
#define SCARD_PROTOCOL_ANY
IFD determines prot.
#define MAX_BUFFER_SIZE
Maximum Tx/Rx Buffer for short APDU.
#define MAX_BUFFER_SIZE_EXTENDED
enhanced (64K + APDU + Lc + Le + SW) Tx/Rx Buffer
#define SCARD_STATE_EXCLUSIVE
Exclusive Mode.
#define SCARD_STATE_UNAWARE
App wants status.
LONG SCARDHANDLE
hCard returned by SCardConnect()
#define PCSCLITE_MAX_READERS_CONTEXTS
Maximum readers context (a slot is count as a reader).
struct pubReaderState READER_STATE
Define an exported public reader state structure so each application gets instant notification of cha...
Protocol Control Information (PCI).
unsigned long dwProtocol
Protocol identifier.
unsigned long cbPciLength
Protocol Control Inf Length.
Represents an Application Context Channel.
Represents an Application Context on the Client side.
pthread_mutex_t mMutex
Mutex for this context.
SCARDCONTEXT hContext
Application Context ID.
DWORD dwClientID
Client Connection ID.
bool cancellable
We are in a cancellable call.
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.
_Atomic int32_t readerSharing
PCSCLITE_SHARING_* sharing status.
UCHAR cardAtr[MAX_ATR_SIZE]
ATR.
uint32_t eventCounter
number of card events
_Atomic uint32_t cardAtrLength
ATR length.
uint32_t readerState
SCARD_* bit field.
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.
int32_t major
IPC major PROTOCOL_VERSION_MAJOR.
int32_t minor
IPC minor PROTOCOL_VERSION_MINOR.
Information contained in CMD_WAIT_READER_STATE_CHANGE Messages.
This handles abstract system level calls.
const char * SYS_GetEnv(const char *name)
(More) secure version of getenv(3)
int SYS_USleep(int)
Makes the current process sleep for some microseconds.
long int time_sub(struct timeval *a, struct timeval *b)
return the difference (as long int) in µs between 2 struct timeval r = a - b
This handles smart card reader communications.
static bool isExecuted
Make sure the initialization code is executed only once.
static void SCardLockThread(void)
Locks a mutex so another thread must wait to use this function.
static void SCardRemoveContext(SCARDCONTEXT)
Removes an Application Context from a control vector.
static SCONTEXTMAP * SCardGetAndLockContext(SCARDCONTEXT)
Get the SCONTEXTMAP * from the Application Context vector _psContextMap for the passed context.
static bool SCardGetContextValidity(SCARDCONTEXT hContext)
Tell if a context index from the Application Context vector _psContextMap is valid or not.
static void SCardUnlockThread(void)
Unlocks a mutex so another thread may use the client.
static pthread_mutex_t clientMutex
Ensure that some functions be accessed in thread-safe mode.
pthread_mutex_t contextMapList_lock
lock for the above list
struct _psContextMap SCONTEXTMAP
Represents an Application Context on the Client side.
LONG SCardCheckDaemonAvailability(void)
Checks if the server is running.
static SCONTEXTMAP * SCardGetContextTH(SCARDCONTEXT)
Get the address from the Application Context list _psContextMap for the passed context.
static LONG SCardEstablishContextTH(DWORD, LPCVOID, LPCVOID, LPSCARDCONTEXT)
Creates a communication context to the PC/SC Resource Manager.
static LONG SCardAddContext(SCARDCONTEXT, DWORD)
Functions for managing instances of SCardEstablishContext() These functions keep track of Context han...
INTERNAL int ClientSetupSession(uint32_t *pdwClientID)
Prepares a communication channel for the client to talk to the server.
INTERNAL LONG MessageReceiveTimeout(uint32_t command, void *buffer_void, uint64_t buffer_size, int32_t filedes, long timeOut)
Called by the Client to get the response from the server or vice-versa.
INTERNAL LONG MessageSendWithHeader(uint32_t command, uint32_t dwClientID, uint64_t size, void *data_void)
Wrapper for the MessageSend() function.
INTERNAL LONG MessageSend(void *buffer_void, uint64_t buffer_size, int32_t filedes)
Sends a menssage from client to server or vice-versa.
INTERNAL void ClientCloseSession(uint32_t dwClientID)
Closes the socket used by the client to communicate with the server.
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_MAJOR
Major version of the current message protocol.
#define PROTOCOL_VERSION_MINOR
Minor version of the current message protocol.
#define PROTOCOL_VERSION_MINOR_CLIENT_BACKWARD
Minor version the client also supports.
@ 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()