108#include <sys/types.h>
138static bool sharing_shall_block =
true;
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]);
256 COLOR_RED
"RESULT %s " COLOR_MAGENTA
"%ld "
257 COLOR_BLUE
"0x%08lX %s" COLOR_NORMAL
"\n",
260 fprintf(stderr, COLOR_RED
"RESULT %s " COLOR_MAGENTA
"%ld"
261 COLOR_NORMAL
"\n", f, d);
263 fprintf(profile_fd,
"%s %ld\n", f, d);
269#define PROFILE_END(rv)
284static int CHANNEL_MAP_seeker(
const void *el,
const void *key)
288 if ((el == NULL) || (key == NULL))
290 Log3(PCSC_LOG_CRITICAL,
291 "CHANNEL_MAP_seeker called with NULL pointer: el=%p, key=%p",
322static list_t contextMapList;
324static int SCONTEXTMAP_seeker(
const void *el,
const void *key)
328 if ((el == NULL) || (key == NULL))
330 Log3(PCSC_LOG_CRITICAL,
331 "SCONTEXTMAP_seeker called with NULL pointer: el=%p, key=%p",
346static pthread_once_t init_lib_control = PTHREAD_ONCE_INIT;
359static pthread_mutex_t readerStatesMutex = PTHREAD_MUTEX_INITIALIZER;
369static LONG SCardGetContextChannelAndLockFromHandle(
SCARDHANDLE,
371static LONG SCardGetContextAndChannelFromHandleTH(
SCARDHANDLE,
375static LONG SCardGetSetAttrib(
SCARDHANDLE hCard,
int command, DWORD dwAttrId,
376 LPBYTE pbAttr, LPDWORD pcbAttrLen);
378static LONG getReaderStates(
SCONTEXTMAP * currentContextMap);
379static LONG getReaderStatesAndRegisterForEvents(
SCONTEXTMAP * currentContextMap);
380static LONG unregisterFromEvents(
SCONTEXTMAP * currentContextMap);
423 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)
492 list_destroy(&contextMapList);
500static void init_lib(
void)
507 lrv = list_init(&contextMapList);
510 Log2(PCSC_LOG_CRITICAL,
"list_init failed with return value: %d",
515 lrv = list_attributes_seeker(&contextMapList,
519 Log2(PCSC_LOG_CRITICAL,
520 "list_attributes_seeker failed with return value: %d", lrv);
521 list_destroy(&contextMapList);
527 Log1(PCSC_LOG_INFO,
"Disable shared blocking");
528 sharing_shall_block =
false;
563 LPCVOID pvReserved2, LPSCARDCONTEXT phContext)
567 uint32_t dwClientID = 0;
571 if (phContext == NULL)
576 pthread_once(&init_lib_control, init_lib);
602 Log1(PCSC_LOG_CRITICAL,
603 "Your pcscd is too old and does not support CMD_VERSION");
607 Log3(PCSC_LOG_INFO,
"Server is protocol version %d:%d",
621 scEstablishStruct.dwScope = dwScope;
622 scEstablishStruct.hContext = 0;
626 sizeof(scEstablishStruct), (
void *) &scEstablishStruct);
634 rv =
MessageReceive(&scEstablishStruct,
sizeof(scEstablishStruct),
642 rv = scEstablishStruct.rv;
652 *phContext = scEstablishStruct.hContext;
694 API_TRACE_IN(
"%ld", hContext)
702 if (NULL == currentContextMap)
708 scReleaseStruct.hContext = hContext;
712 currentContextMap->dwClientID,
713 sizeof(scReleaseStruct), (
void *) &scReleaseStruct);
722 currentContextMap->dwClientID);
727 rv = scReleaseStruct.rv;
729 (void)pthread_mutex_unlock(¤tContextMap->mMutex);
801 DWORD dwShareMode, DWORD dwPreferredProtocols, LPSCARDHANDLE phCard,
802 LPDWORD pdwActiveProtocol)
809 API_TRACE_IN(
"%ld %s %ld %ld", hContext, szReader, dwShareMode, dwPreferredProtocols)
814 if (phCard == NULL || pdwActiveProtocol == NULL)
819 if (szReader == NULL)
825 if (strlen(szReader) > MAX_READERNAME)
832 if (NULL == currentContextMap)
835 memset(scConnectStruct.szReader, 0,
sizeof scConnectStruct.szReader);
836 strncpy(scConnectStruct.szReader, szReader,
sizeof scConnectStruct.szReader);
837 scConnectStruct.szReader[
sizeof scConnectStruct.szReader -1] =
'\0';
839 scConnectStruct.hContext = hContext;
840 scConnectStruct.dwShareMode = dwShareMode;
841 scConnectStruct.dwPreferredProtocols = dwPreferredProtocols;
842 scConnectStruct.hCard = 0;
843 scConnectStruct.dwActiveProtocol = 0;
847 sizeof(scConnectStruct), (
void *) &scConnectStruct);
856 currentContextMap->dwClientID);
861 *phCard = scConnectStruct.hCard;
862 *pdwActiveProtocol = scConnectStruct.dwActiveProtocol;
869 rv = SCardAddHandle(*phCard, currentContextMap, szReader);
872 rv = scConnectStruct.rv;
875 (void)pthread_mutex_unlock(¤tContextMap->mMutex);
878 API_TRACE_OUT(
"%d", *pdwActiveProtocol)
956 DWORD dwPreferredProtocols, DWORD dwInitialization,
957 LPDWORD pdwActiveProtocol)
965 API_TRACE_IN(
"%ld %ld %ld", hCard, dwShareMode, dwPreferredProtocols)
967 if (pdwActiveProtocol == NULL)
976 rv = SCardGetContextChannelAndLockFromHandle(hCard, ¤tContextMap,
981 scReconnectStruct.hCard = hCard;
982 scReconnectStruct.dwShareMode = dwShareMode;
983 scReconnectStruct.dwPreferredProtocols = dwPreferredProtocols;
984 scReconnectStruct.dwInitialization = dwInitialization;
985 scReconnectStruct.dwActiveProtocol = *pdwActiveProtocol;
989 sizeof(scReconnectStruct), (
void *) &scReconnectStruct);
997 rv =
MessageReceive(&scReconnectStruct,
sizeof(scReconnectStruct),
998 currentContextMap->dwClientID);
1003 rv = scReconnectStruct.rv;
1007 (void)pthread_mutex_unlock(¤tContextMap->mMutex);
1012 *pdwActiveProtocol = scReconnectStruct.dwActiveProtocol;
1015 (void)pthread_mutex_unlock(¤tContextMap->mMutex);
1018 API_TRACE_OUT(
"%ld", *pdwActiveProtocol)
1062 API_TRACE_IN(
"%ld %ld", hCard, dwDisposition)
1067 rv = SCardGetContextChannelAndLockFromHandle(hCard, ¤tContextMap,
1075 scDisconnectStruct.hCard = hCard;
1076 scDisconnectStruct.dwDisposition = dwDisposition;
1080 sizeof(scDisconnectStruct), (
void *) &scDisconnectStruct);
1088 rv =
MessageReceive(&scDisconnectStruct,
sizeof(scDisconnectStruct),
1089 currentContextMap->dwClientID);
1095 SCardRemoveHandle(hCard);
1096 rv = scDisconnectStruct.rv;
1099 (void)pthread_mutex_unlock(¤tContextMap->mMutex);
1153 API_TRACE_IN(
"%ld", hCard)
1165 rv = SCardGetContextChannelAndLockFromHandle(hCard, ¤tContextMap,
1170 scBeginStruct.hCard = hCard;
1174 currentContextMap->dwClientID,
1175 sizeof(scBeginStruct), (
void *) &scBeginStruct);
1184 currentContextMap->dwClientID);
1189 rv = scBeginStruct.rv;
1194 (void)pthread_mutex_unlock(¤tContextMap->mMutex);
1198 (void)pthread_mutex_unlock(¤tContextMap->mMutex);
1253 API_TRACE_IN(
"%ld", hCard)
1258 rv = SCardGetContextChannelAndLockFromHandle(hCard, ¤tContextMap,
1263 scEndStruct.hCard = hCard;
1264 scEndStruct.dwDisposition = dwDisposition;
1268 currentContextMap->dwClientID,
1269 sizeof(scEndStruct), (
void *) &scEndStruct);
1278 currentContextMap->dwClientID);
1283 rv = scEndStruct.rv;
1286 (void)pthread_mutex_unlock(¤tContextMap->mMutex);
1390 LPDWORD pcchReaderLen, LPDWORD pdwState,
1391 LPDWORD pdwProtocol, LPBYTE pbAtr, LPDWORD pcbAtrLen)
1393 DWORD dwReaderLen, dwAtrLen;
1400 char *bufReader = NULL;
1401 LPBYTE bufAtr = NULL;
1414 if (pcchReaderLen == NULL)
1415 pcchReaderLen = &dummy;
1417 if (pcbAtrLen == NULL)
1421 dwReaderLen = *pcchReaderLen;
1422 dwAtrLen = *pcbAtrLen;
1433 rv = SCardGetContextChannelAndLockFromHandle(hCard, ¤tContextMap,
1439 (void)pthread_mutex_lock(&readerStatesMutex);
1442 rv = getReaderStates(currentContextMap);
1446 r = pChannelMap->readerName;
1461 memset(&scStatusStruct, 0,
sizeof(scStatusStruct));
1462 scStatusStruct.hCard = hCard;
1465 sizeof(scStatusStruct), (
void *) &scStatusStruct);
1474 currentContextMap->dwClientID);
1479 rv = scStatusStruct.rv;
1483 (void)pthread_mutex_unlock(¤tContextMap->mMutex);
1484 (void)pthread_mutex_unlock(&readerStatesMutex);
1501 *pcchReaderLen = strlen(pChannelMap->readerName) + 1;
1512 dwReaderLen = *pcchReaderLen;
1513 if (NULL == szReaderName)
1518 bufReader = malloc(dwReaderLen);
1519 if (NULL == bufReader)
1524 *(
char **)szReaderName = bufReader;
1527 bufReader = szReaderName;
1532 if (*pcchReaderLen > dwReaderLen)
1535 strncpy(bufReader, pChannelMap->readerName, dwReaderLen);
1540 dwAtrLen = *pcbAtrLen;
1546 bufAtr = malloc(dwAtrLen);
1552 *(LPBYTE *)pbAtr = bufAtr;
1559 if (*pcbAtrLen > dwAtrLen)
1562 memcpy(bufAtr,
readerStates[i].cardAtr, min(*pcbAtrLen, dwAtrLen));
1566 (void)pthread_mutex_unlock(¤tContextMap->mMutex);
1567 (void)pthread_mutex_unlock(&readerStatesMutex);
1687 DWORD dwBreakFlag = 0;
1690 int currentReaderCount = 0;
1694 API_TRACE_IN(
"%ld %ld %d", hContext, dwTimeout, cReaders)
1696 for (j=0; j<cReaders; j++)
1698 API_TRACE_IN(
"[%d] %s %lX %lX", j, rgReaderStates[j].szReader,
1699 rgReaderStates[j].dwCurrentState, rgReaderStates[j].dwEventState)
1703 if ((rgReaderStates == NULL && cReaders > 0)
1711 for (j = 0; j < cReaders; j++)
1713 if (rgReaderStates[j].szReader == NULL)
1720 int nbNonIgnoredReaders = cReaders;
1722 for (j=0; j<cReaders; j++)
1724 nbNonIgnoredReaders--;
1726 if (0 == nbNonIgnoredReaders)
1743 if (NULL == currentContextMap)
1750 (void)pthread_mutex_lock(&readerStatesMutex);
1753 rv = getReaderStatesAndRegisterForEvents(currentContextMap);
1757 (void)pthread_mutex_unlock(&readerStatesMutex);
1762 for (j=0; j<cReaders; j++)
1764 const char *readerName;
1767 readerName = rgReaderStates[j].szReader;
1770 if (strcmp(readerName,
readerStates[i].readerName) == 0)
1778 if (strcasecmp(readerName,
"\\\\?PnP?\\Notification") != 0)
1781 (void)pthread_mutex_unlock(&readerStatesMutex);
1786 (void)pthread_mutex_unlock(&readerStatesMutex);
1789 for (j = 0; j < cReaders; j++)
1790 rgReaderStates[j].dwEventState = 0;
1793 Log2(PCSC_LOG_DEBUG,
"Event Loop Start, dwTimeout: %ld", dwTimeout);
1798 currentReaderCount++;
1801 if ((DWORD)-1 == dwTimeout)
1811 currReader = &rgReaderStates[j];
1816 const char *readerName;
1820 (void)pthread_mutex_lock(&readerStatesMutex);
1823 readerName = currReader->szReader;
1826 if (strcmp(readerName,
readerStates[i].readerName) == 0)
1834 if (strcasecmp(readerName,
"\\\\?PnP?\\Notification") == 0)
1836 int k, newReaderCount = 0;
1842 if (newReaderCount != currentReaderCount)
1844 Log1(PCSC_LOG_INFO,
"Reader list changed");
1845 currentReaderCount = newReaderCount;
1853 currReader->dwEventState =
1869 uint32_t readerState;
1875 currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
1876 Log0(PCSC_LOG_DEBUG);
1887 if (currReader->dwCurrentState & 0xFFFF0000)
1889 unsigned int currentCounter;
1891 currentCounter = (currReader->dwCurrentState >> 16) & 0xFFFF;
1897 Log0(PCSC_LOG_DEBUG);
1903 currReader->dwEventState = ((currReader->dwEventState & 0xffff )
1915 Log0(PCSC_LOG_DEBUG);
1924 currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE;
1926 Log0(PCSC_LOG_DEBUG);
1934#ifndef DISABLE_AUTO_POWER_ON
1938 (void)
SYS_USleep(PCSCLITE_STATUS_POLL_RATE + 10);
1942 memcpy(currReader->rgbAtr, rContext->
cardAtr,
1946 currReader->cbAtr = 0;
1952 currReader->dwEventState &= ~SCARD_STATE_PRESENT;
1953 currReader->dwEventState &= ~SCARD_STATE_UNAWARE;
1954 currReader->dwEventState &= ~SCARD_STATE_IGNORE;
1955 currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
1956 currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE;
1957 currReader->dwEventState &= ~SCARD_STATE_ATRMATCH;
1958 currReader->dwEventState &= ~SCARD_STATE_MUTE;
1959 currReader->dwEventState &= ~SCARD_STATE_INUSE;
1965 Log0(PCSC_LOG_DEBUG);
1973 currReader->dwEventState &= ~SCARD_STATE_EMPTY;
1974 currReader->dwEventState &= ~SCARD_STATE_UNAWARE;
1975 currReader->dwEventState &= ~SCARD_STATE_IGNORE;
1976 currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
1977 currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE;
1978 currReader->dwEventState &= ~SCARD_STATE_MUTE;
1983 Log0(PCSC_LOG_DEBUG);
1993 Log0(PCSC_LOG_DEBUG);
2003 Log0(PCSC_LOG_DEBUG);
2013 currReader->dwEventState &= ~SCARD_STATE_INUSE;
2017 Log0(PCSC_LOG_DEBUG);
2027 currReader->dwEventState &= ~SCARD_STATE_EXCLUSIVE;
2031 Log0(PCSC_LOG_DEBUG);
2038 currReader->dwEventState &= ~SCARD_STATE_INUSE;
2039 currReader->dwEventState &= ~SCARD_STATE_EXCLUSIVE;
2044 Log0(PCSC_LOG_DEBUG);
2047 else if (currReader-> dwCurrentState
2051 Log0(PCSC_LOG_DEBUG);
2063 Log0(PCSC_LOG_DEBUG);
2068 (void)pthread_mutex_unlock(&readerStatesMutex);
2081 if (dwBreakFlag == 1)
2087 struct timeval before, after;
2089 gettimeofday(&before, NULL);
2100 &waitStatusStruct,
sizeof(waitStatusStruct),
2111 rv = unregisterFromEvents(currentContextMap);
2120 rv = waitStatusStruct.rv;
2125 (void)pthread_mutex_lock(&readerStatesMutex);
2126 rv = getReaderStatesAndRegisterForEvents(currentContextMap);
2127 (void)pthread_mutex_unlock(&readerStatesMutex);
2135 gettimeofday(&after, NULL);
2137 dwTime -= diff/1000;
2157 Log1(PCSC_LOG_DEBUG,
"Event Loop End");
2162 (void)unregisterFromEvents(currentContextMap);
2164 (void)pthread_mutex_unlock(¤tContextMap->
mMutex);
2169 for (j=0; j<cReaders; j++)
2171 API_TRACE_OUT(
"[%d] %s %X %X", j, rgReaderStates[j].szReader,
2172 rgReaderStates[j].dwCurrentState, rgReaderStates[j].dwEventState)
2230 DWORD cbSendLength, LPVOID pbRecvBuffer, DWORD cbRecvLength,
2231 LPDWORD lpBytesReturned)
2241 if (NULL != lpBytesReturned)
2242 *lpBytesReturned = 0;
2247 rv = SCardGetContextChannelAndLockFromHandle(hCard, ¤tContextMap,
2261 scControlStruct.hCard = hCard;
2262 scControlStruct.dwControlCode = dwControlCode;
2263 scControlStruct.cbSendLength = cbSendLength;
2264 scControlStruct.cbRecvLength = cbRecvLength;
2265 scControlStruct.dwBytesReturned = 0;
2266 scControlStruct.rv = 0;
2269 sizeof(scControlStruct), &scControlStruct);
2275 rv =
MessageSend((
char *)pbSendBuffer, cbSendLength,
2276 currentContextMap->dwClientID);
2285 currentContextMap->dwClientID);
2292 if (scControlStruct.dwBytesReturned > cbRecvLength)
2294 if (NULL != lpBytesReturned)
2295 *lpBytesReturned = scControlStruct.dwBytesReturned;
2301 rv =
MessageReceive(pbRecvBuffer, scControlStruct.dwBytesReturned,
2302 currentContextMap->dwClientID);
2309 if (NULL != lpBytesReturned)
2310 *lpBytesReturned = scControlStruct.dwBytesReturned;
2312 rv = scControlStruct.rv;
2315 (void)pthread_mutex_unlock(¤tContextMap->mMutex);
2444 unsigned char *buf = NULL;
2448 if (NULL == pcbAttrLen)
2460 buf = malloc(*pcbAttrLen);
2467 *(
unsigned char **)pbAttr = buf;
2530 if (NULL == pbAttr || 0 == cbAttrLen)
2541static LONG SCardGetSetAttrib(
SCARDHANDLE hCard,
int command, DWORD dwAttrId,
2542 LPBYTE pbAttr, LPDWORD pcbAttrLen)
2552 rv = SCardGetContextChannelAndLockFromHandle(hCard, ¤tContextMap,
2563 scGetSetStruct.hCard = hCard;
2564 scGetSetStruct.dwAttrId = dwAttrId;
2566 memset(scGetSetStruct.pbAttr, 0,
sizeof(scGetSetStruct.pbAttr));
2569 memcpy(scGetSetStruct.pbAttr, pbAttr, *pcbAttrLen);
2570 scGetSetStruct.cbAttrLen = *pcbAttrLen;
2574 scGetSetStruct.cbAttrLen =
sizeof scGetSetStruct.pbAttr;
2577 sizeof(scGetSetStruct), &scGetSetStruct);
2586 currentContextMap->dwClientID);
2596 if (*pcbAttrLen < scGetSetStruct.cbAttrLen)
2600 DWORD correct_value = scGetSetStruct.cbAttrLen;
2601 scGetSetStruct.cbAttrLen = *pcbAttrLen;
2602 *pcbAttrLen = correct_value;
2607 *pcbAttrLen = scGetSetStruct.cbAttrLen;
2610 memcpy(pbAttr, scGetSetStruct.pbAttr, scGetSetStruct.cbAttrLen);
2612 memset(scGetSetStruct.pbAttr, 0x00,
sizeof(scGetSetStruct.pbAttr));
2614 rv = scGetSetStruct.rv;
2617 (void)pthread_mutex_unlock(¤tContextMap->mMutex);
2681 LPCBYTE pbSendBuffer, DWORD cbSendLength,
2683 LPDWORD pcbRecvLength)
2692 if (pbSendBuffer == NULL || pbRecvBuffer == NULL ||
2693 pcbRecvLength == NULL || pioSendPci == NULL)
2702 rv = SCardGetContextChannelAndLockFromHandle(hCard, ¤tContextMap,
2717 scTransmitStruct.hCard = hCard;
2718 scTransmitStruct.cbSendLength = cbSendLength;
2719 scTransmitStruct.pcbRecvLength = *pcbRecvLength;
2720 scTransmitStruct.ioSendPciProtocol = pioSendPci->
dwProtocol;
2721 scTransmitStruct.ioSendPciLength = pioSendPci->
cbPciLength;
2726 scTransmitStruct.ioRecvPciProtocol = pioRecvPci->
dwProtocol;
2727 scTransmitStruct.ioRecvPciLength = pioRecvPci->
cbPciLength;
2736 sizeof(scTransmitStruct), (
void *) &scTransmitStruct);
2742 rv =
MessageSend((
void *)pbSendBuffer, cbSendLength,
2759 if (scTransmitStruct.pcbRecvLength > *pcbRecvLength)
2761 *pcbRecvLength = scTransmitStruct.pcbRecvLength;
2767 rv =
MessageReceive(pbRecvBuffer, scTransmitStruct.pcbRecvLength,
2775 pioRecvPci->
dwProtocol = scTransmitStruct.ioRecvPciProtocol;
2776 pioRecvPci->
cbPciLength = scTransmitStruct.ioRecvPciLength;
2780 rv = scTransmitStruct.rv;
2784 (void)pthread_mutex_unlock(¤tContextMap->
mMutex);
2789 *pcbRecvLength = scTransmitStruct.pcbRecvLength;
2792 (void)pthread_mutex_unlock(¤tContextMap->
mMutex);
2862 LPSTR mszReaders, LPDWORD pcchReaders)
2864 DWORD dwReadersLen = 0;
2872 API_TRACE_IN(
"%ld", hContext)
2877 if (pcchReaders == NULL)
2884 if (NULL == currentContextMap)
2891 (void)pthread_mutex_lock(&readerStatesMutex);
2894 rv = getReaderStates(currentContextMap);
2901 dwReadersLen += strlen(
readerStates[i].readerName) + 1;
2906 if (1 == dwReadersLen)
2914 if (NULL == mszReaders)
2919 buf = malloc(dwReadersLen);
2925 *(
char **)mszReaders = buf;
2932 if ((NULL != mszReaders) && (*pcchReaders < dwReadersLen))
2939 if (mszReaders == NULL)
2957 *pcchReaders = dwReadersLen;
2959 (void)pthread_mutex_unlock(¤tContextMap->
mMutex);
2960 (void)pthread_mutex_unlock(&readerStatesMutex);
2963 API_TRACE_OUT(
"%d", *pcchReaders)
2993 free((
void *)pvMem);
3061 const char ReaderGroup[] =
"SCard$DefaultReaders\0";
3062 const unsigned int dwGroups =
sizeof(ReaderGroup);
3068 if (NULL == currentContextMap)
3073 if (NULL == mszGroups)
3078 buf = malloc(dwGroups);
3084 *(
char **)mszGroups = buf;
3090 if ((NULL != mszGroups) && (*pcchGroups < dwGroups))
3098 memcpy(buf, ReaderGroup, dwGroups);
3101 *pcchGroups = dwGroups;
3103 (void)pthread_mutex_unlock(¤tContextMap->
mMutex);
3145 uint32_t dwClientID = 0;
3150 API_TRACE_IN(
"%ld", hContext)
3158 if (NULL == currentContextMap)
3180 scCancelStruct.hContext = hContext;
3184 sizeof(scCancelStruct), (
void *) &scCancelStruct);
3192 rv =
MessageReceive(&scCancelStruct,
sizeof(scCancelStruct), dwClientID);
3197 rv = scCancelStruct.rv;
3236 API_TRACE_IN(
"%ld", hContext)
3274 if (NULL == newContextMap)
3277 Log2(PCSC_LOG_DEBUG,
"Allocating new SCONTEXTMAP @%p", newContextMap);
3278 newContextMap->
hContext = hContext;
3282 (void)pthread_mutex_init(&newContextMap->
mMutex, NULL);
3284 lrv = list_init(&newContextMap->channelMapList);
3287 Log2(PCSC_LOG_CRITICAL,
"list_init failed with return value: %d", lrv);
3291 lrv = list_attributes_seeker(&newContextMap->channelMapList,
3292 CHANNEL_MAP_seeker);
3295 Log2(PCSC_LOG_CRITICAL,
3296 "list_attributes_seeker failed with return value: %d", lrv);
3297 list_destroy(&newContextMap->channelMapList);
3301 lrv = list_append(&contextMapList, newContextMap);
3304 Log2(PCSC_LOG_CRITICAL,
"list_append failed with return value: %d",
3306 list_destroy(&newContextMap->channelMapList);
3314 (void)pthread_mutex_destroy(&newContextMap->
mMutex);
3315 free(newContextMap);
3344 if (NULL != currentContextMap)
3345 (void)pthread_mutex_lock(¤tContextMap->
mMutex);
3349 return currentContextMap;
3366 return list_seek(&contextMapList, &hContext);
3380 if (NULL != currentContextMap)
3381 SCardCleanContext(currentContextMap);
3384static void SCardCleanContext(
SCONTEXTMAP * targetContextMap)
3386 int list_index, lrv;
3393 (void)pthread_mutex_destroy(&targetContextMap->
mMutex);
3395 listSize = list_size(&targetContextMap->channelMapList);
3396 for (list_index = 0; list_index < listSize; list_index++)
3398 currentChannelMap = list_get_at(&targetContextMap->channelMapList,
3400 if (NULL == currentChannelMap)
3402 Log2(PCSC_LOG_CRITICAL,
"list_get_at failed for index %d",
3408 free(currentChannelMap->readerName);
3409 free(currentChannelMap);
3413 list_destroy(&targetContextMap->channelMapList);
3415 lrv = list_delete(&contextMapList, targetContextMap);
3418 Log2(PCSC_LOG_CRITICAL,
3419 "list_delete failed with return value: %d", lrv);
3422 free(targetContextMap);
3438 if (NULL == newChannelMap)
3441 newChannelMap->hCard = hCard;
3442 newChannelMap->readerName = strdup(readerName);
3444 lrv = list_append(¤tContextMap->channelMapList, newChannelMap);
3447 free(newChannelMap->readerName);
3448 free(newChannelMap);
3449 Log2(PCSC_LOG_CRITICAL,
"list_append failed with return value: %d",
3464 rv = SCardGetContextAndChannelFromHandleTH(hCard, ¤tContextMap,
3465 ¤tChannelMap);
3469 free(currentChannelMap->readerName);
3471 lrv = list_delete(¤tContextMap->channelMapList, currentChannelMap);
3474 Log2(PCSC_LOG_CRITICAL,
3475 "list_delete failed with return value: %d", lrv);
3478 free(currentChannelMap);
3483static LONG SCardGetContextChannelAndLockFromHandle(
SCARDHANDLE hCard,
3492 rv = SCardGetContextAndChannelFromHandleTH(hCard, targetContextMap,
3496 (void)pthread_mutex_lock(&(*targetContextMap)->mMutex);
3503static LONG SCardGetContextAndChannelFromHandleTH(
SCARDHANDLE hCard,
3512 *targetContextMap = NULL;
3513 *targetChannelMap = NULL;
3515 listSize = list_size(&contextMapList);
3517 for (list_index = 0; list_index < listSize; list_index++)
3519 currentContextMap = list_get_at(&contextMapList, list_index);
3520 if (currentContextMap == NULL)
3522 Log2(PCSC_LOG_CRITICAL,
"list_get_at failed for index %d",
3526 currentChannelMap = list_seek(¤tContextMap->channelMapList,
3528 if (currentChannelMap != NULL)
3530 *targetContextMap = currentContextMap;
3531 *targetChannelMap = currentChannelMap;
3549 struct stat statBuffer;
3552 socketName = getSocketName();
3553 rv = stat(socketName, &statBuffer);
3557 Log3(PCSC_LOG_INFO,
"PCSC Not Running: %s: %s",
3558 socketName, strerror(errno));
3565static LONG getReaderStates(
SCONTEXTMAP * currentContextMap)
3567 int32_t dwClientID = currentContextMap->
dwClientID;
3582static LONG getReaderStatesAndRegisterForEvents(
SCONTEXTMAP * currentContextMap)
3584 int32_t dwClientID = currentContextMap->
dwClientID;
3598static LONG unregisterFromEvents(
SCONTEXTMAP * currentContextMap)
3600 int32_t dwClientID = currentContextMap->
dwClientID;
3606 dwClientID, 0, NULL);
3623 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.
PCSC_API const char * pcsc_stringify_error(const LONG pcscError)
Returns a human readable text for the given PC/SC error code.
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_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_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_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)
This keeps track of a list of currently available reader structures.
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.
Define an exported public reader state structure so each application gets instant notification of cha...
_Atomic int32_t readerSharing
PCSCLITE_SHARING_* sharing status.
uint32_t cardProtocol
SCARD_PROTOCOL_* value.
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.
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...
static READER_STATE readerStates[PCSCLITE_MAX_READERS_CONTEXTS]
Area used to read status information about the readers.
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.
@ 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()