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]);
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)
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;
320static int SCONTEXTMAP_seeker(
const void *el,
const void *key)
324 if ((el == NULL) || (key == NULL))
326 Log3(PCSC_LOG_CRITICAL,
327 "SCONTEXTMAP_seeker called with NULL pointer: el=%p, key=%p",
342static pthread_once_t init_lib_control = PTHREAD_ONCE_INIT;
355static pthread_mutex_t readerStatesMutex = PTHREAD_MUTEX_INITIALIZER;
365static LONG SCardGetContextChannelAndLockFromHandle(
SCARDHANDLE,
367static LONG SCardGetContextAndChannelFromHandleTH(
SCARDHANDLE,
371static LONG SCardGetSetAttrib(
SCARDHANDLE hCard,
int command, DWORD dwAttrId,
372 LPBYTE pbAttr, LPDWORD pcbAttrLen);
374static LONG getReaderEvents(
SCONTEXTMAP * currentContextMap,
int *readerEvents);
375static LONG getReaderStates(
SCONTEXTMAP * currentContextMap);
376static LONG getReaderStatesAndRegisterForEvents(
SCONTEXTMAP * currentContextMap);
377static LONG unregisterFromEvents(
SCONTEXTMAP * currentContextMap);
420 return currentContextMap != NULL;
462 LPCVOID pvReserved2, LPSCARDCONTEXT phContext)
466 API_TRACE_IN(
"%ld, %p, %p", dwScope, pvReserved1, pvReserved2)
476 pvReserved2, phContext);
481 API_TRACE_OUT(
"%ld", *phContext)
487DESTRUCTOR
static void destructor(
void)
489 list_destroy(&contextMapList);
497static void init_lib(
void)
504 lrv = list_init(&contextMapList);
507 Log2(PCSC_LOG_CRITICAL,
"list_init failed with return value: %d",
512 lrv = list_attributes_seeker(&contextMapList,
516 Log2(PCSC_LOG_CRITICAL,
517 "list_attributes_seeker failed with return value: %d", lrv);
518 list_destroy(&contextMapList);
524 Log1(PCSC_LOG_INFO,
"Disable shared blocking");
525 sharing_shall_block =
false;
560 LPCVOID pvReserved2, LPSCARDCONTEXT phContext)
564 uint32_t dwClientID = 0;
568 if (phContext == NULL)
573 pthread_once(&init_lib_control, init_lib);
599 Log1(PCSC_LOG_CRITICAL,
600 "Your pcscd is too old and does not support CMD_VERSION");
604 Log3(PCSC_LOG_INFO,
"Server is protocol version %d:%d",
618 scEstablishStruct.dwScope = dwScope;
619 scEstablishStruct.hContext = 0;
623 sizeof(scEstablishStruct), (
void *) &scEstablishStruct);
631 rv =
MessageReceive(&scEstablishStruct,
sizeof(scEstablishStruct),
639 rv = scEstablishStruct.rv;
649 *phContext = scEstablishStruct.hContext;
691 API_TRACE_IN(
"%ld", hContext)
699 if (NULL == currentContextMap)
705 scReleaseStruct.hContext = hContext;
709 currentContextMap->dwClientID,
710 sizeof(scReleaseStruct), (
void *) &scReleaseStruct);
719 currentContextMap->dwClientID);
724 rv = scReleaseStruct.rv;
726 (void)pthread_mutex_unlock(¤tContextMap->mMutex);
798 DWORD dwShareMode, DWORD dwPreferredProtocols, LPSCARDHANDLE phCard,
799 LPDWORD pdwActiveProtocol)
806 API_TRACE_IN(
"%ld %s %ld %ld", hContext, szReader, dwShareMode, dwPreferredProtocols)
811 if (phCard == NULL || pdwActiveProtocol == NULL)
816 if (szReader == NULL)
822 if (strlen(szReader) > MAX_READERNAME)
829 if (NULL == currentContextMap)
832 memset(scConnectStruct.szReader, 0,
sizeof scConnectStruct.szReader);
833 strncpy(scConnectStruct.szReader, szReader,
sizeof scConnectStruct.szReader);
834 scConnectStruct.szReader[
sizeof scConnectStruct.szReader -1] =
'\0';
836 scConnectStruct.hContext = hContext;
837 scConnectStruct.dwShareMode = dwShareMode;
838 scConnectStruct.dwPreferredProtocols = dwPreferredProtocols;
839 scConnectStruct.hCard = 0;
840 scConnectStruct.dwActiveProtocol = 0;
844 sizeof(scConnectStruct), (
void *) &scConnectStruct);
853 currentContextMap->dwClientID);
858 *phCard = scConnectStruct.hCard;
859 *pdwActiveProtocol = scConnectStruct.dwActiveProtocol;
866 rv = SCardAddHandle(*phCard, currentContextMap, szReader);
869 rv = scConnectStruct.rv;
872 (void)pthread_mutex_unlock(¤tContextMap->mMutex);
875 API_TRACE_OUT(
"%d", *pdwActiveProtocol)
953 DWORD dwPreferredProtocols, DWORD dwInitialization,
954 LPDWORD pdwActiveProtocol)
962 API_TRACE_IN(
"%ld %ld %ld", hCard, dwShareMode, dwPreferredProtocols)
964 if (pdwActiveProtocol == NULL)
973 rv = SCardGetContextChannelAndLockFromHandle(hCard, ¤tContextMap,
978 scReconnectStruct.hCard = hCard;
979 scReconnectStruct.dwShareMode = dwShareMode;
980 scReconnectStruct.dwPreferredProtocols = dwPreferredProtocols;
981 scReconnectStruct.dwInitialization = dwInitialization;
982 scReconnectStruct.dwActiveProtocol = *pdwActiveProtocol;
986 sizeof(scReconnectStruct), (
void *) &scReconnectStruct);
994 rv =
MessageReceive(&scReconnectStruct,
sizeof(scReconnectStruct),
995 currentContextMap->dwClientID);
1000 rv = scReconnectStruct.rv;
1004 (void)pthread_mutex_unlock(¤tContextMap->mMutex);
1009 *pdwActiveProtocol = scReconnectStruct.dwActiveProtocol;
1012 (void)pthread_mutex_unlock(¤tContextMap->mMutex);
1015 API_TRACE_OUT(
"%ld", *pdwActiveProtocol)
1059 API_TRACE_IN(
"%ld %ld", hCard, dwDisposition)
1064 rv = SCardGetContextChannelAndLockFromHandle(hCard, ¤tContextMap,
1072 scDisconnectStruct.hCard = hCard;
1073 scDisconnectStruct.dwDisposition = dwDisposition;
1077 sizeof(scDisconnectStruct), (
void *) &scDisconnectStruct);
1085 rv =
MessageReceive(&scDisconnectStruct,
sizeof(scDisconnectStruct),
1086 currentContextMap->dwClientID);
1092 SCardRemoveHandle(hCard);
1093 rv = scDisconnectStruct.rv;
1096 (void)pthread_mutex_unlock(¤tContextMap->mMutex);
1150 API_TRACE_IN(
"%ld", hCard)
1162 rv = SCardGetContextChannelAndLockFromHandle(hCard, ¤tContextMap,
1167 scBeginStruct.hCard = hCard;
1171 currentContextMap->dwClientID,
1172 sizeof(scBeginStruct), (
void *) &scBeginStruct);
1181 currentContextMap->dwClientID);
1186 rv = scBeginStruct.rv;
1191 (void)pthread_mutex_unlock(¤tContextMap->mMutex);
1195 (void)pthread_mutex_unlock(¤tContextMap->mMutex);
1250 API_TRACE_IN(
"%ld", hCard)
1255 rv = SCardGetContextChannelAndLockFromHandle(hCard, ¤tContextMap,
1260 scEndStruct.hCard = hCard;
1261 scEndStruct.dwDisposition = dwDisposition;
1265 currentContextMap->dwClientID,
1266 sizeof(scEndStruct), (
void *) &scEndStruct);
1275 currentContextMap->dwClientID);
1280 rv = scEndStruct.rv;
1283 (void)pthread_mutex_unlock(¤tContextMap->mMutex);
1387 LPDWORD pcchReaderLen, LPDWORD pdwState,
1388 LPDWORD pdwProtocol, LPBYTE pbAtr, LPDWORD pcbAtrLen)
1390 DWORD dwReaderLen, dwAtrLen;
1397 char *bufReader = NULL;
1398 LPBYTE bufAtr = NULL;
1411 if (pcchReaderLen == NULL)
1412 pcchReaderLen = &dummy;
1414 if (pcbAtrLen == NULL)
1418 dwReaderLen = *pcchReaderLen;
1419 dwAtrLen = *pcbAtrLen;
1430 rv = SCardGetContextChannelAndLockFromHandle(hCard, ¤tContextMap,
1436 (void)pthread_mutex_lock(&readerStatesMutex);
1439 rv = getReaderStates(currentContextMap);
1443 r = pChannelMap->readerName;
1458 memset(&scStatusStruct, 0,
sizeof(scStatusStruct));
1459 scStatusStruct.hCard = hCard;
1462 sizeof(scStatusStruct), (
void *) &scStatusStruct);
1471 currentContextMap->dwClientID);
1476 rv = scStatusStruct.rv;
1480 (void)pthread_mutex_unlock(¤tContextMap->mMutex);
1481 (void)pthread_mutex_unlock(&readerStatesMutex);
1498 *pcchReaderLen = strlen(pChannelMap->readerName) + 1;
1509 dwReaderLen = *pcchReaderLen;
1510 if (NULL == szReaderName)
1515 bufReader = malloc(dwReaderLen);
1516 if (NULL == bufReader)
1521 *(
char **)szReaderName = bufReader;
1524 bufReader = szReaderName;
1529 if (*pcchReaderLen > dwReaderLen)
1532 strncpy(bufReader, pChannelMap->readerName, dwReaderLen);
1537 dwAtrLen = *pcbAtrLen;
1543 bufAtr = malloc(dwAtrLen);
1549 *(LPBYTE *)pbAtr = bufAtr;
1556 if (*pcbAtrLen > dwAtrLen)
1559 memcpy(bufAtr,
readerStates[i].cardAtr, min(*pcbAtrLen, dwAtrLen));
1563 (void)pthread_mutex_unlock(¤tContextMap->mMutex);
1564 (void)pthread_mutex_unlock(&readerStatesMutex);
1684 DWORD dwBreakFlag = 0;
1687 int currentReaderCount = 0;
1689 int pnp_reader = -1;
1692 API_TRACE_IN(
"%ld %ld %d", hContext, dwTimeout, cReaders)
1694 for (j=0; j<cReaders; j++)
1696 API_TRACE_IN(
"[%d] %s %lX %lX (%d)", j, rgReaderStates[j].szReader,
1697 rgReaderStates[j].dwCurrentState, rgReaderStates[j].dwEventState,
1698 rgReaderStates[j].cbAtr)
1702 if ((rgReaderStates == NULL && cReaders > 0)
1710 for (j = 0; j < cReaders; j++)
1712 if (rgReaderStates[j].szReader == NULL)
1719 int nbNonIgnoredReaders = cReaders;
1721 for (j=0; j<cReaders; j++)
1723 nbNonIgnoredReaders--;
1725 if (0 == nbNonIgnoredReaders)
1742 if (NULL == currentContextMap)
1749 (void)pthread_mutex_lock(&readerStatesMutex);
1752 rv = getReaderStatesAndRegisterForEvents(currentContextMap);
1756 (void)pthread_mutex_unlock(&readerStatesMutex);
1761 for (j=0; j<cReaders; j++)
1763 const char *readerName;
1766 readerName = rgReaderStates[j].szReader;
1769 if (strcmp(readerName,
readerStates[i].readerName) == 0)
1777 if (strcasecmp(readerName,
"\\\\?PnP?\\Notification") != 0)
1780 (void)pthread_mutex_unlock(&readerStatesMutex);
1787 (void)pthread_mutex_unlock(&readerStatesMutex);
1790 for (j = 0; j < cReaders; j++)
1791 rgReaderStates[j].dwEventState = 0;
1794 Log2(PCSC_LOG_DEBUG,
"Event Loop Start, dwTimeout: %ld", dwTimeout);
1797 if (pnp_reader >= 0)
1800 currReader = &rgReaderStates[pnp_reader];
1803 if (
SCARD_S_SUCCESS == getReaderEvents(currentContextMap, &readerEvents))
1805 int previousReaderEvents = currReader->dwCurrentState >> 16;
1808 currReader->dwEventState = (currReader->dwEventState & 0xFFFF) + (readerEvents << 16);
1811 (previousReaderEvents != readerEvents)
1814 && previousReaderEvents)
1826 currentReaderCount++;
1829 if ((DWORD)-1 == dwTimeout)
1839 currReader = &rgReaderStates[j];
1844 const char *readerName;
1848 (void)pthread_mutex_lock(&readerStatesMutex);
1851 readerName = currReader->szReader;
1854 if (strcmp(readerName,
readerStates[i].readerName) == 0)
1862 if (strcasecmp(readerName,
"\\\\?PnP?\\Notification") == 0)
1864 int k, newReaderCount = 0;
1870 if (newReaderCount != currentReaderCount)
1874 Log1(PCSC_LOG_INFO,
"Reader list changed");
1875 currentReaderCount = newReaderCount;
1877 if (
SCARD_S_SUCCESS == getReaderEvents(currentContextMap, &readerEvents))
1880 currReader->dwEventState = (currReader->dwEventState & 0xFFFF) + (readerEvents << 16);
1889 currReader->dwEventState =
1905 uint32_t readerState;
1911 currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
1912 Log0(PCSC_LOG_DEBUG);
1923 if (currReader->dwCurrentState & 0xFFFF0000)
1925 unsigned int currentCounter;
1927 currentCounter = (currReader->dwCurrentState >> 16) & 0xFFFF;
1933 Log0(PCSC_LOG_DEBUG);
1939 currReader->dwEventState = ((currReader->dwEventState & 0xffff )
1951 Log0(PCSC_LOG_DEBUG);
1960 currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE;
1962 Log0(PCSC_LOG_DEBUG);
1970#ifndef DISABLE_AUTO_POWER_ON
1974 (void)
SYS_USleep(PCSCLITE_STATUS_POLL_RATE + 10);
1978 memcpy(currReader->rgbAtr, rContext->
cardAtr,
1982 currReader->cbAtr = 0;
1988 currReader->dwEventState &= ~SCARD_STATE_PRESENT;
1989 currReader->dwEventState &= ~SCARD_STATE_UNAWARE;
1990 currReader->dwEventState &= ~SCARD_STATE_IGNORE;
1991 currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
1992 currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE;
1993 currReader->dwEventState &= ~SCARD_STATE_ATRMATCH;
1994 currReader->dwEventState &= ~SCARD_STATE_MUTE;
1995 currReader->dwEventState &= ~SCARD_STATE_INUSE;
2001 Log0(PCSC_LOG_DEBUG);
2009 currReader->dwEventState &= ~SCARD_STATE_EMPTY;
2010 currReader->dwEventState &= ~SCARD_STATE_UNAWARE;
2011 currReader->dwEventState &= ~SCARD_STATE_IGNORE;
2012 currReader->dwEventState &= ~SCARD_STATE_UNKNOWN;
2013 currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE;
2014 currReader->dwEventState &= ~SCARD_STATE_MUTE;
2019 Log0(PCSC_LOG_DEBUG);
2029 Log0(PCSC_LOG_DEBUG);
2039 Log0(PCSC_LOG_DEBUG);
2049 currReader->dwEventState &= ~SCARD_STATE_INUSE;
2053 Log0(PCSC_LOG_DEBUG);
2063 currReader->dwEventState &= ~SCARD_STATE_EXCLUSIVE;
2067 Log0(PCSC_LOG_DEBUG);
2074 currReader->dwEventState &= ~SCARD_STATE_INUSE;
2075 currReader->dwEventState &= ~SCARD_STATE_EXCLUSIVE;
2080 Log0(PCSC_LOG_DEBUG);
2083 else if (currReader-> dwCurrentState
2087 Log0(PCSC_LOG_DEBUG);
2099 Log0(PCSC_LOG_DEBUG);
2104 (void)pthread_mutex_unlock(&readerStatesMutex);
2117 if (dwBreakFlag == 1)
2123 struct timeval before, after;
2125 gettimeofday(&before, NULL);
2136 &waitStatusStruct,
sizeof(waitStatusStruct),
2147 rv = unregisterFromEvents(currentContextMap);
2156 rv = waitStatusStruct.rv;
2161 (void)pthread_mutex_lock(&readerStatesMutex);
2162 rv = getReaderStatesAndRegisterForEvents(currentContextMap);
2163 (void)pthread_mutex_unlock(&readerStatesMutex);
2171 gettimeofday(&after, NULL);
2173 dwTime -= diff/1000;
2193 Log1(PCSC_LOG_DEBUG,
"Event Loop End");
2198 (void)unregisterFromEvents(currentContextMap);
2200 (void)pthread_mutex_unlock(¤tContextMap->
mMutex);
2205 for (j=0; j<cReaders; j++)
2207 API_TRACE_OUT(
"[%d] %s %lX %lX (%d)", j, rgReaderStates[j].szReader,
2208 rgReaderStates[j].dwCurrentState, rgReaderStates[j].dwEventState,
2209 rgReaderStates[j].cbAtr)
2267 DWORD cbSendLength, LPVOID pbRecvBuffer, DWORD cbRecvLength,
2268 LPDWORD lpBytesReturned)
2278 if (NULL != lpBytesReturned)
2279 *lpBytesReturned = 0;
2284 rv = SCardGetContextChannelAndLockFromHandle(hCard, ¤tContextMap,
2298 scControlStruct.hCard = hCard;
2299 scControlStruct.dwControlCode = dwControlCode;
2300 scControlStruct.cbSendLength = cbSendLength;
2301 scControlStruct.cbRecvLength = cbRecvLength;
2302 scControlStruct.dwBytesReturned = 0;
2303 scControlStruct.rv = 0;
2306 sizeof(scControlStruct), &scControlStruct);
2312 rv =
MessageSend((
char *)pbSendBuffer, cbSendLength,
2313 currentContextMap->dwClientID);
2322 currentContextMap->dwClientID);
2329 if (scControlStruct.dwBytesReturned > cbRecvLength)
2331 if (NULL != lpBytesReturned)
2332 *lpBytesReturned = scControlStruct.dwBytesReturned;
2338 rv =
MessageReceive(pbRecvBuffer, scControlStruct.dwBytesReturned,
2339 currentContextMap->dwClientID);
2346 if (NULL != lpBytesReturned)
2347 *lpBytesReturned = scControlStruct.dwBytesReturned;
2349 rv = scControlStruct.rv;
2352 (void)pthread_mutex_unlock(¤tContextMap->mMutex);
2481 unsigned char *buf = NULL;
2485 if (NULL == pcbAttrLen)
2497 buf = malloc(*pcbAttrLen);
2504 *(
unsigned char **)pbAttr = buf;
2567 if (NULL == pbAttr || 0 == cbAttrLen)
2578static LONG SCardGetSetAttrib(
SCARDHANDLE hCard,
int command, DWORD dwAttrId,
2579 LPBYTE pbAttr, LPDWORD pcbAttrLen)
2589 rv = SCardGetContextChannelAndLockFromHandle(hCard, ¤tContextMap,
2600 scGetSetStruct.hCard = hCard;
2601 scGetSetStruct.dwAttrId = dwAttrId;
2603 memset(scGetSetStruct.pbAttr, 0,
sizeof(scGetSetStruct.pbAttr));
2606 memcpy(scGetSetStruct.pbAttr, pbAttr, *pcbAttrLen);
2607 scGetSetStruct.cbAttrLen = *pcbAttrLen;
2611 scGetSetStruct.cbAttrLen =
sizeof scGetSetStruct.pbAttr;
2614 sizeof(scGetSetStruct), &scGetSetStruct);
2623 currentContextMap->dwClientID);
2633 if (*pcbAttrLen < scGetSetStruct.cbAttrLen)
2637 DWORD correct_value = scGetSetStruct.cbAttrLen;
2638 scGetSetStruct.cbAttrLen = *pcbAttrLen;
2639 *pcbAttrLen = correct_value;
2644 *pcbAttrLen = scGetSetStruct.cbAttrLen;
2647 memcpy(pbAttr, scGetSetStruct.pbAttr, scGetSetStruct.cbAttrLen);
2649 memset(scGetSetStruct.pbAttr, 0x00,
sizeof(scGetSetStruct.pbAttr));
2651 rv = scGetSetStruct.rv;
2654 (void)pthread_mutex_unlock(¤tContextMap->mMutex);
2718 LPCBYTE pbSendBuffer, DWORD cbSendLength,
2720 LPDWORD pcbRecvLength)
2729 if (pbSendBuffer == NULL || pbRecvBuffer == NULL ||
2730 pcbRecvLength == NULL || pioSendPci == NULL)
2739 rv = SCardGetContextChannelAndLockFromHandle(hCard, ¤tContextMap,
2754 scTransmitStruct.hCard = hCard;
2755 scTransmitStruct.cbSendLength = cbSendLength;
2756 scTransmitStruct.pcbRecvLength = *pcbRecvLength;
2757 scTransmitStruct.ioSendPciProtocol = pioSendPci->
dwProtocol;
2758 scTransmitStruct.ioSendPciLength = pioSendPci->
cbPciLength;
2763 scTransmitStruct.ioRecvPciProtocol = pioRecvPci->
dwProtocol;
2764 scTransmitStruct.ioRecvPciLength = pioRecvPci->
cbPciLength;
2773 sizeof(scTransmitStruct), (
void *) &scTransmitStruct);
2779 rv =
MessageSend((
void *)pbSendBuffer, cbSendLength,
2796 if (scTransmitStruct.pcbRecvLength > *pcbRecvLength)
2798 *pcbRecvLength = scTransmitStruct.pcbRecvLength;
2804 rv =
MessageReceive(pbRecvBuffer, scTransmitStruct.pcbRecvLength,
2812 pioRecvPci->
dwProtocol = scTransmitStruct.ioRecvPciProtocol;
2813 pioRecvPci->
cbPciLength = scTransmitStruct.ioRecvPciLength;
2817 rv = scTransmitStruct.rv;
2821 (void)pthread_mutex_unlock(¤tContextMap->
mMutex);
2826 *pcbRecvLength = scTransmitStruct.pcbRecvLength;
2829 (void)pthread_mutex_unlock(¤tContextMap->
mMutex);
2899 LPSTR mszReaders, LPDWORD pcchReaders)
2901 DWORD dwReadersLen = 0;
2909 API_TRACE_IN(
"%ld", hContext)
2914 if (pcchReaders == NULL)
2921 if (NULL == currentContextMap)
2928 (void)pthread_mutex_lock(&readerStatesMutex);
2931 rv = getReaderStates(currentContextMap);
2938 dwReadersLen += strlen(
readerStates[i].readerName) + 1;
2943 if (1 == dwReadersLen)
2951 if (NULL == mszReaders)
2956 buf = malloc(dwReadersLen);
2962 *(
char **)mszReaders = buf;
2969 if ((NULL != mszReaders) && (*pcchReaders < dwReadersLen))
2976 if (mszReaders == NULL)
2994 *pcchReaders = dwReadersLen;
2996 (void)pthread_mutex_unlock(¤tContextMap->
mMutex);
2997 (void)pthread_mutex_unlock(&readerStatesMutex);
3000 API_TRACE_OUT(
"%d", *pcchReaders)
3030 free((
void *)pvMem);
3098 const char ReaderGroup[] =
"SCard$DefaultReaders\0";
3099 const unsigned int dwGroups =
sizeof(ReaderGroup);
3105 if (NULL == currentContextMap)
3110 if (NULL == mszGroups)
3115 buf = malloc(dwGroups);
3121 *(
char **)mszGroups = buf;
3127 if ((NULL != mszGroups) && (*pcchGroups < dwGroups))
3135 memcpy(buf, ReaderGroup, dwGroups);
3138 *pcchGroups = dwGroups;
3140 (void)pthread_mutex_unlock(¤tContextMap->
mMutex);
3182 uint32_t dwClientID = 0;
3187 API_TRACE_IN(
"%ld", hContext)
3195 if (NULL == currentContextMap)
3217 scCancelStruct.hContext = hContext;
3221 sizeof(scCancelStruct), (
void *) &scCancelStruct);
3229 rv =
MessageReceive(&scCancelStruct,
sizeof(scCancelStruct), dwClientID);
3234 rv = scCancelStruct.rv;
3273 API_TRACE_IN(
"%ld", hContext)
3311 if (NULL == newContextMap)
3314 Log2(PCSC_LOG_DEBUG,
"Allocating new SCONTEXTMAP @%p", newContextMap);
3315 newContextMap->
hContext = hContext;
3319 (void)pthread_mutex_init(&newContextMap->
mMutex, NULL);
3321 lrv = list_init(&newContextMap->channelMapList);
3324 Log2(PCSC_LOG_CRITICAL,
"list_init failed with return value: %d", lrv);
3328 lrv = list_attributes_seeker(&newContextMap->channelMapList,
3329 CHANNEL_MAP_seeker);
3332 Log2(PCSC_LOG_CRITICAL,
3333 "list_attributes_seeker failed with return value: %d", lrv);
3334 list_destroy(&newContextMap->channelMapList);
3338 lrv = list_append(&contextMapList, newContextMap);
3341 Log2(PCSC_LOG_CRITICAL,
"list_append failed with return value: %d",
3343 list_destroy(&newContextMap->channelMapList);
3351 (void)pthread_mutex_destroy(&newContextMap->
mMutex);
3352 free(newContextMap);
3381 if (NULL != currentContextMap)
3382 (void)pthread_mutex_lock(¤tContextMap->
mMutex);
3386 return currentContextMap;
3403 return list_seek(&contextMapList, &hContext);
3417 if (NULL != currentContextMap)
3418 SCardCleanContext(currentContextMap);
3421static void SCardCleanContext(
SCONTEXTMAP * targetContextMap)
3423 int list_index, lrv;
3430 (void)pthread_mutex_destroy(&targetContextMap->
mMutex);
3432 listSize = list_size(&targetContextMap->channelMapList);
3433 for (list_index = 0; list_index < listSize; list_index++)
3435 currentChannelMap = list_get_at(&targetContextMap->channelMapList,
3437 if (NULL == currentChannelMap)
3439 Log2(PCSC_LOG_CRITICAL,
"list_get_at failed for index %d",
3445 free(currentChannelMap->readerName);
3446 free(currentChannelMap);
3450 list_destroy(&targetContextMap->channelMapList);
3452 lrv = list_delete(&contextMapList, targetContextMap);
3455 Log2(PCSC_LOG_CRITICAL,
3456 "list_delete failed with return value: %d", lrv);
3459 free(targetContextMap);
3475 if (NULL == newChannelMap)
3478 newChannelMap->hCard = hCard;
3479 newChannelMap->readerName = strdup(readerName);
3481 lrv = list_append(¤tContextMap->channelMapList, newChannelMap);
3484 free(newChannelMap->readerName);
3485 free(newChannelMap);
3486 Log2(PCSC_LOG_CRITICAL,
"list_append failed with return value: %d",
3501 rv = SCardGetContextAndChannelFromHandleTH(hCard, ¤tContextMap,
3502 ¤tChannelMap);
3506 free(currentChannelMap->readerName);
3508 lrv = list_delete(¤tContextMap->channelMapList, currentChannelMap);
3511 Log2(PCSC_LOG_CRITICAL,
3512 "list_delete failed with return value: %d", lrv);
3515 free(currentChannelMap);
3520static LONG SCardGetContextChannelAndLockFromHandle(
SCARDHANDLE hCard,
3529 rv = SCardGetContextAndChannelFromHandleTH(hCard, targetContextMap,
3533 (void)pthread_mutex_lock(&(*targetContextMap)->mMutex);
3540static LONG SCardGetContextAndChannelFromHandleTH(
SCARDHANDLE hCard,
3549 *targetContextMap = NULL;
3550 *targetChannelMap = NULL;
3552 listSize = list_size(&contextMapList);
3554 for (list_index = 0; list_index < listSize; list_index++)
3556 currentContextMap = list_get_at(&contextMapList, list_index);
3557 if (currentContextMap == NULL)
3559 Log2(PCSC_LOG_CRITICAL,
"list_get_at failed for index %d",
3563 currentChannelMap = list_seek(¤tContextMap->channelMapList,
3565 if (currentChannelMap != NULL)
3567 *targetContextMap = currentContextMap;
3568 *targetChannelMap = currentChannelMap;
3586 struct stat statBuffer;
3589 socketName = getSocketName();
3590 rv = stat(socketName, &statBuffer);
3594 Log3(PCSC_LOG_INFO,
"PCSC Not Running: %s: %s",
3595 socketName, strerror(errno));
3602static LONG getReaderEvents(
SCONTEXTMAP * currentContextMap,
int *readerEvents)
3604 int32_t dwClientID = currentContextMap->
dwClientID;
3622static LONG getReaderStates(
SCONTEXTMAP * currentContextMap)
3624 int32_t dwClientID = currentContextMap->
dwClientID;
3639static LONG getReaderStatesAndRegisterForEvents(
SCONTEXTMAP * currentContextMap)
3641 int32_t dwClientID = currentContextMap->
dwClientID;
3655static LONG unregisterFromEvents(
SCONTEXTMAP * currentContextMap)
3657 int32_t dwClientID = currentContextMap->
dwClientID;
3663 dwClientID, 0, NULL);
3680 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_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()
@ 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()