108 #include <sys/types.h>
114 #include <sys/time.h>
116 #include <sys/wait.h>
137 static bool sharing_shall_block =
true;
138 static 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"
151 static 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"
177 #include <sys/time.h>
180 #define MAX_THREADS 5
181 pthread_t threads[MAX_THREADS];
182 struct timeval profile_time_start[MAX_THREADS];
186 #define PROFILE_START profile_start();
187 #define PROFILE_END(rv) profile_end(__FUNCTION__, rv);
189 static 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);
227 static 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);
264 #define PROFILE_START
265 #define PROFILE_END(rv)
280 static 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",
318 static list_t contextMapList;
321 static 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",
343 static pthread_once_t init_lib_control = PTHREAD_ONCE_INIT;
357 static pthread_mutex_t readerStatesMutex = PTHREAD_MUTEX_INITIALIZER;
367 static LONG SCardGetContextChannelAndLockFromHandle(
SCARDHANDLE,
369 static LONG SCardGetContextAndChannelFromHandleTH(
SCARDHANDLE,
373 static LONG SCardGetSetAttrib(
SCARDHANDLE hCard,
int command, DWORD dwAttrId,
374 LPBYTE pbAttr, LPDWORD pcbAttrLen);
376 static LONG getReaderEvents(
SCONTEXTMAP * currentContextMap,
int *readerEvents);
377 static LONG getReaderStates(
SCONTEXTMAP * currentContextMap);
378 static LONG getReaderStatesAndRegisterForEvents(
SCONTEXTMAP * currentContextMap);
379 static LONG unregisterFromEvents(
SCONTEXTMAP * currentContextMap);
392 pthread_mutex_lock(&clientMutex);
402 pthread_mutex_unlock(&clientMutex);
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)
490 DESTRUCTOR
static void destructor(
void)
492 (void)pthread_mutex_lock(&contextMapList_lock);
493 list_destroy(&contextMapList);
494 (void)pthread_mutex_unlock(&contextMapList_lock);
496 (void)pthread_mutex_destroy(&contextMapList_lock);
504 static 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;
535 (void)pthread_mutex_init(&contextMapList_lock, NULL);
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 memset(scConnectStruct.szReader, 0,
sizeof scConnectStruct.szReader);
863 strncpy(scConnectStruct.szReader, szReader,
sizeof scConnectStruct.szReader);
864 scConnectStruct.szReader[
sizeof scConnectStruct.szReader -1] =
'\0';
866 scConnectStruct.hContext = hContext;
867 scConnectStruct.dwShareMode = dwShareMode;
868 scConnectStruct.dwPreferredProtocols = dwPreferredProtocols;
869 scConnectStruct.hCard = 0;
870 scConnectStruct.dwActiveProtocol = 0;
874 sizeof(scConnectStruct), (
void *) &scConnectStruct);
883 currentContextMap->dwClientID);
888 *phCard = scConnectStruct.hCard;
889 *pdwActiveProtocol = scConnectStruct.dwActiveProtocol;
896 rv = SCardAddHandle(*phCard, currentContextMap, szReader);
899 rv = scConnectStruct.rv;
902 (void)pthread_mutex_unlock(¤tContextMap->mMutex);
905 API_TRACE_OUT(
"%d", *pdwActiveProtocol)
983 DWORD dwPreferredProtocols, DWORD dwInitialization,
984 LPDWORD pdwActiveProtocol)
992 API_TRACE_IN(
"%ld %ld %ld", hCard, dwShareMode, dwPreferredProtocols)
994 if (pdwActiveProtocol == NULL)
1003 rv = SCardGetContextChannelAndLockFromHandle(hCard, ¤tContextMap,
1008 scReconnectStruct.hCard = hCard;
1009 scReconnectStruct.dwShareMode = dwShareMode;
1010 scReconnectStruct.dwPreferredProtocols = dwPreferredProtocols;
1011 scReconnectStruct.dwInitialization = dwInitialization;
1012 scReconnectStruct.dwActiveProtocol = *pdwActiveProtocol;
1016 sizeof(scReconnectStruct), (
void *) &scReconnectStruct);
1024 rv =
MessageReceive(&scReconnectStruct,
sizeof(scReconnectStruct),
1025 currentContextMap->dwClientID);
1030 rv = scReconnectStruct.rv;
1034 (void)pthread_mutex_unlock(¤tContextMap->mMutex);
1039 *pdwActiveProtocol = scReconnectStruct.dwActiveProtocol;
1042 (void)pthread_mutex_unlock(¤tContextMap->mMutex);
1045 API_TRACE_OUT(
"%ld", *pdwActiveProtocol)
1089 API_TRACE_IN(
"%ld %ld", hCard, dwDisposition)
1094 rv = SCardGetContextChannelAndLockFromHandle(hCard, ¤tContextMap,
1102 scDisconnectStruct.hCard = hCard;
1103 scDisconnectStruct.dwDisposition = dwDisposition;
1107 sizeof(scDisconnectStruct), (
void *) &scDisconnectStruct);
1115 rv =
MessageReceive(&scDisconnectStruct,
sizeof(scDisconnectStruct),
1116 currentContextMap->dwClientID);
1122 SCardRemoveHandle(hCard);
1123 rv = scDisconnectStruct.rv;
1126 (void)pthread_mutex_unlock(¤tContextMap->mMutex);
1180 API_TRACE_IN(
"%ld", hCard)
1192 rv = SCardGetContextChannelAndLockFromHandle(hCard, ¤tContextMap,
1197 scBeginStruct.hCard = hCard;
1201 currentContextMap->dwClientID,
1202 sizeof(scBeginStruct), (
void *) &scBeginStruct);
1211 currentContextMap->dwClientID);
1216 rv = scBeginStruct.rv;
1221 (void)pthread_mutex_unlock(¤tContextMap->mMutex);
1225 (void)pthread_mutex_unlock(¤tContextMap->mMutex);
1280 API_TRACE_IN(
"%ld", hCard)
1285 rv = SCardGetContextChannelAndLockFromHandle(hCard, ¤tContextMap,
1290 scEndStruct.hCard = hCard;
1291 scEndStruct.dwDisposition = dwDisposition;
1295 currentContextMap->dwClientID,
1296 sizeof(scEndStruct), (
void *) &scEndStruct);
1305 currentContextMap->dwClientID);
1310 rv = scEndStruct.rv;
1313 (void)pthread_mutex_unlock(¤tContextMap->mMutex);
1417 LPDWORD pcchReaderLen, LPDWORD pdwState,
1418 LPDWORD pdwProtocol, LPBYTE pbAtr, LPDWORD pcbAtrLen)
1420 DWORD dwReaderLen, dwAtrLen;
1427 char *bufReader = NULL;
1428 LPBYTE bufAtr = NULL;
1441 if (pcchReaderLen == NULL)
1442 pcchReaderLen = &dummy;
1444 if (pcbAtrLen == NULL)
1448 dwReaderLen = *pcchReaderLen;
1449 dwAtrLen = *pcbAtrLen;
1460 rv = SCardGetContextChannelAndLockFromHandle(hCard, ¤tContextMap,
1466 (void)pthread_mutex_lock(&readerStatesMutex);
1469 rv = getReaderStates(currentContextMap);
1473 r = pChannelMap->readerName;
1477 if (r && strcmp(r, readerStates[i].readerName) == 0)
1481 if (i == pcsclite_max_reader_context)
1488 memset(&scStatusStruct, 0,
sizeof(scStatusStruct));
1489 scStatusStruct.hCard = hCard;
1492 sizeof(scStatusStruct), (
void *) &scStatusStruct);
1501 currentContextMap->dwClientID);
1506 rv = scStatusStruct.rv;
1510 (void)pthread_mutex_unlock(¤tContextMap->mMutex);
1511 (void)pthread_mutex_unlock(&readerStatesMutex);
1528 *pcchReaderLen = strlen(pChannelMap->readerName) + 1;
1532 *pdwState = (readerStates[i].
eventCounter << 16) + readerStates[i].readerState;
1539 dwReaderLen = *pcchReaderLen;
1540 if (NULL == szReaderName)
1545 bufReader = malloc(dwReaderLen);
1546 if (NULL == bufReader)
1551 *(
char **)szReaderName = bufReader;
1554 bufReader = szReaderName;
1559 if (*pcchReaderLen > dwReaderLen)
1562 strncpy(bufReader, pChannelMap->readerName, dwReaderLen);
1567 dwAtrLen = *pcbAtrLen;
1573 bufAtr = malloc(dwAtrLen);
1579 *(LPBYTE *)pbAtr = bufAtr;
1586 if (*pcbAtrLen > dwAtrLen)
1589 memcpy(bufAtr, readerStates[i].cardAtr, min(*pcbAtrLen, dwAtrLen));
1593 (void)pthread_mutex_unlock(¤tContextMap->mMutex);
1594 (void)pthread_mutex_unlock(&readerStatesMutex);
1718 DWORD dwBreakFlag = 0;
1721 int currentReaderCount = 0;
1723 int pnp_reader = -1;
1726 API_TRACE_IN(
"%ld %ld %d", hContext, dwTimeout, cReaders)
1728 for (j=0; j<cReaders; j++)
1730 API_TRACE_IN(
"[%d] %s %lX %lX (%d)", j, rgReaderStates[j].szReader,
1731 rgReaderStates[j].dwCurrentState, rgReaderStates[j].dwEventState,
1732 rgReaderStates[j].cbAtr)
1736 if (rgReaderStates == NULL && cReaders > 0)
1743 for (j = 0; j < cReaders; j++)
1745 if (rgReaderStates[j].szReader == NULL)
1752 int nbNonIgnoredReaders = cReaders;
1754 for (j=0; j<cReaders; j++)
1756 nbNonIgnoredReaders--;
1758 if (0 == nbNonIgnoredReaders)
1775 if (NULL == currentContextMap)
1782 (void)pthread_mutex_lock(&readerStatesMutex);
1785 rv = getReaderStatesAndRegisterForEvents(currentContextMap);
1789 (void)pthread_mutex_unlock(&readerStatesMutex);
1794 for (j=0; j<cReaders; j++)
1796 const char *readerName;
1799 readerName = rgReaderStates[j].szReader;
1802 if (strcmp(readerName, readerStates[i].readerName) == 0)
1807 if (i == pcsclite_max_reader_context)
1810 if (strcasecmp(readerName,
"\\\\?PnP?\\Notification") != 0)
1813 (void)pthread_mutex_unlock(&readerStatesMutex);
1820 (void)pthread_mutex_unlock(&readerStatesMutex);
1823 for (j = 0; j < cReaders; j++)
1824 rgReaderStates[j].dwEventState = 0;
1827 Log2(PCSC_LOG_DEBUG,
"Event Loop Start, dwTimeout: %ld", dwTimeout);
1830 if (pnp_reader >= 0)
1833 currReader = &rgReaderStates[pnp_reader];
1836 if (
SCARD_S_SUCCESS == getReaderEvents(currentContextMap, &readerEvents))
1838 int previousReaderEvents = currReader->dwCurrentState >> 16;
1841 currReader->dwEventState = (currReader->dwEventState & 0xFFFF) + (readerEvents << 16);
1844 (previousReaderEvents != readerEvents)
1847 && previousReaderEvents)
1858 if (readerStates[k].readerName[0] !=
'\0')
1859 currentReaderCount++;
1862 if ((DWORD)-1 == dwTimeout)
1872 currReader = &rgReaderStates[j];
1877 const char *readerName;
1881 (void)pthread_mutex_lock(&readerStatesMutex);
1884 readerName = currReader->szReader;
1887 if (strcmp(readerName, readerStates[i].readerName) == 0)
1892 if (i == pcsclite_max_reader_context)
1895 if (strcasecmp(readerName,
"\\\\?PnP?\\Notification") == 0)
1897 int k, newReaderCount = 0;
1900 if (readerStates[k].readerName[0] !=
'\0')
1903 if (newReaderCount != currentReaderCount)
1907 Log1(PCSC_LOG_INFO,
"Reader list changed");
1908 currentReaderCount = newReaderCount;
1910 if (
SCARD_S_SUCCESS == getReaderEvents(currentContextMap, &readerEvents))
1913 currReader->dwEventState = (currReader->dwEventState & 0xFFFF) + (readerEvents << 16);
1922 currReader->dwEventState =
1938 uint32_t readerState;
1945 Log0(PCSC_LOG_DEBUG);
1950 rContext = &readerStates[i];
1956 if (currReader->dwCurrentState & 0xFFFF0000)
1958 unsigned int currentCounter;
1960 currentCounter = (currReader->dwCurrentState >> 16) & 0xFFFF;
1966 Log0(PCSC_LOG_DEBUG);
1972 currReader->dwEventState = ((currReader->dwEventState & 0xffff )
1984 Log0(PCSC_LOG_DEBUG);
1993 currReader->dwEventState &= ~SCARD_STATE_UNAVAILABLE;
1995 Log0(PCSC_LOG_DEBUG);
2003 #ifndef DISABLE_AUTO_POWER_ON
2007 (void)
SYS_USleep(PCSCLITE_STATUS_POLL_RATE + 10);
2011 memcpy(currReader->rgbAtr, rContext->
cardAtr,
2015 currReader->cbAtr = 0;
2034 Log0(PCSC_LOG_DEBUG);
2039 else if (readerState & SCARD_PRESENT)
2052 Log0(PCSC_LOG_DEBUG);
2062 Log0(PCSC_LOG_DEBUG);
2072 Log0(PCSC_LOG_DEBUG);
2086 Log0(PCSC_LOG_DEBUG);
2093 if (readerState & SCARD_PRESENT)
2100 Log0(PCSC_LOG_DEBUG);
2113 Log0(PCSC_LOG_DEBUG);
2116 else if (currReader-> dwCurrentState
2120 Log0(PCSC_LOG_DEBUG);
2132 Log0(PCSC_LOG_DEBUG);
2137 (void)pthread_mutex_unlock(&readerStatesMutex);
2150 if (dwBreakFlag == 1)
2156 struct timeval before, after;
2158 gettimeofday(&before, NULL);
2169 &waitStatusStruct,
sizeof(waitStatusStruct),
2180 rv = unregisterFromEvents(currentContextMap);
2189 rv = waitStatusStruct.rv;
2194 (void)pthread_mutex_lock(&readerStatesMutex);
2195 rv = getReaderStatesAndRegisterForEvents(currentContextMap);
2196 (void)pthread_mutex_unlock(&readerStatesMutex);
2204 gettimeofday(&after, NULL);
2206 dwTime -= diff/1000;
2226 Log1(PCSC_LOG_DEBUG,
"Event Loop End");
2231 (void)unregisterFromEvents(currentContextMap);
2233 (void)pthread_mutex_unlock(¤tContextMap->
mMutex);
2238 for (j=0; j<cReaders; j++)
2240 API_TRACE_OUT(
"[%d] %s %lX %lX (%d)", j, rgReaderStates[j].szReader,
2241 rgReaderStates[j].dwCurrentState, rgReaderStates[j].dwEventState,
2242 rgReaderStates[j].cbAtr)
2300 DWORD cbSendLength, LPVOID pbRecvBuffer, DWORD cbRecvLength,
2301 LPDWORD lpBytesReturned)
2311 if (NULL != lpBytesReturned)
2312 *lpBytesReturned = 0;
2317 rv = SCardGetContextChannelAndLockFromHandle(hCard, ¤tContextMap,
2331 scControlStruct.hCard = hCard;
2332 scControlStruct.dwControlCode = dwControlCode;
2333 scControlStruct.cbSendLength = cbSendLength;
2334 scControlStruct.cbRecvLength = cbRecvLength;
2335 scControlStruct.dwBytesReturned = 0;
2336 scControlStruct.rv = 0;
2339 sizeof(scControlStruct), &scControlStruct);
2345 rv =
MessageSend((
char *)pbSendBuffer, cbSendLength,
2346 currentContextMap->dwClientID);
2355 currentContextMap->dwClientID);
2362 if (scControlStruct.dwBytesReturned > cbRecvLength)
2364 if (NULL != lpBytesReturned)
2365 *lpBytesReturned = scControlStruct.dwBytesReturned;
2371 rv =
MessageReceive(pbRecvBuffer, scControlStruct.dwBytesReturned,
2372 currentContextMap->dwClientID);
2379 if (NULL != lpBytesReturned)
2380 *lpBytesReturned = scControlStruct.dwBytesReturned;
2382 rv = scControlStruct.rv;
2385 (void)pthread_mutex_unlock(¤tContextMap->mMutex);
2514 unsigned char *buf = NULL;
2518 if (NULL == pcbAttrLen)
2530 buf = malloc(*pcbAttrLen);
2537 *(
unsigned char **)pbAttr = buf;
2600 if (NULL == pbAttr || 0 == cbAttrLen)
2611 static LONG SCardGetSetAttrib(
SCARDHANDLE hCard,
int command, DWORD dwAttrId,
2612 LPBYTE pbAttr, LPDWORD pcbAttrLen)
2622 rv = SCardGetContextChannelAndLockFromHandle(hCard, ¤tContextMap,
2633 scGetSetStruct.hCard = hCard;
2634 scGetSetStruct.dwAttrId = dwAttrId;
2636 memset(scGetSetStruct.pbAttr, 0,
sizeof(scGetSetStruct.pbAttr));
2639 memcpy(scGetSetStruct.pbAttr, pbAttr, *pcbAttrLen);
2640 scGetSetStruct.cbAttrLen = *pcbAttrLen;
2644 scGetSetStruct.cbAttrLen =
sizeof scGetSetStruct.pbAttr;
2647 sizeof(scGetSetStruct), &scGetSetStruct);
2656 currentContextMap->dwClientID);
2666 if (*pcbAttrLen < scGetSetStruct.cbAttrLen)
2670 DWORD correct_value = scGetSetStruct.cbAttrLen;
2671 scGetSetStruct.cbAttrLen = *pcbAttrLen;
2672 *pcbAttrLen = correct_value;
2677 *pcbAttrLen = scGetSetStruct.cbAttrLen;
2680 memcpy(pbAttr, scGetSetStruct.pbAttr, scGetSetStruct.cbAttrLen);
2682 memset(scGetSetStruct.pbAttr, 0x00,
sizeof(scGetSetStruct.pbAttr));
2684 rv = scGetSetStruct.rv;
2687 (void)pthread_mutex_unlock(¤tContextMap->mMutex);
2751 LPCBYTE pbSendBuffer, DWORD cbSendLength,
2753 LPDWORD pcbRecvLength)
2762 if (pbSendBuffer == NULL || pbRecvBuffer == NULL ||
2763 pcbRecvLength == NULL || pioSendPci == NULL)
2772 rv = SCardGetContextChannelAndLockFromHandle(hCard, ¤tContextMap,
2787 scTransmitStruct.hCard = hCard;
2788 scTransmitStruct.cbSendLength = cbSendLength;
2789 scTransmitStruct.pcbRecvLength = *pcbRecvLength;
2790 scTransmitStruct.ioSendPciProtocol = pioSendPci->
dwProtocol;
2791 scTransmitStruct.ioSendPciLength = pioSendPci->
cbPciLength;
2796 scTransmitStruct.ioRecvPciProtocol = pioRecvPci->
dwProtocol;
2797 scTransmitStruct.ioRecvPciLength = pioRecvPci->
cbPciLength;
2806 sizeof(scTransmitStruct), (
void *) &scTransmitStruct);
2812 rv =
MessageSend((
void *)pbSendBuffer, cbSendLength,
2829 if (scTransmitStruct.pcbRecvLength > *pcbRecvLength)
2831 *pcbRecvLength = scTransmitStruct.pcbRecvLength;
2837 rv =
MessageReceive(pbRecvBuffer, scTransmitStruct.pcbRecvLength,
2845 pioRecvPci->
dwProtocol = scTransmitStruct.ioRecvPciProtocol;
2846 pioRecvPci->
cbPciLength = scTransmitStruct.ioRecvPciLength;
2850 rv = scTransmitStruct.rv;
2854 (void)pthread_mutex_unlock(¤tContextMap->
mMutex);
2859 *pcbRecvLength = scTransmitStruct.pcbRecvLength;
2862 (void)pthread_mutex_unlock(¤tContextMap->
mMutex);
2936 LPSTR mszReaders, LPDWORD pcchReaders)
2938 DWORD dwReadersLen = 0;
2946 API_TRACE_IN(
"%ld", hContext)
2951 if (pcchReaders == NULL)
2958 if (NULL == currentContextMap)
2965 (void)pthread_mutex_lock(&readerStatesMutex);
2968 rv = getReaderStates(currentContextMap);
2974 if (readerStates[i].readerName[0] !=
'\0')
2975 dwReadersLen += strlen(readerStates[i].readerName) + 1;
2980 if (1 == dwReadersLen)
2988 if (NULL == mszReaders)
2993 buf = malloc(dwReadersLen);
2999 *(
char **)mszReaders = buf;
3006 if ((NULL != mszReaders) && (*pcchReaders < dwReadersLen))
3013 if (mszReaders == NULL)
3018 if (readerStates[i].readerName[0] !=
'\0')
3023 strcpy(buf, readerStates[i].readerName);
3024 buf += strlen(readerStates[i].readerName)+1;
3031 *pcchReaders = dwReadersLen;
3033 (void)pthread_mutex_unlock(¤tContextMap->
mMutex);
3034 (void)pthread_mutex_unlock(&readerStatesMutex);
3037 API_TRACE_OUT(
"%d", *pcchReaders)
3067 free((
void *)pvMem);
3135 const char ReaderGroup[] =
"SCard$DefaultReaders\0";
3136 const unsigned int dwGroups =
sizeof(ReaderGroup);
3142 if (NULL == currentContextMap)
3147 if (NULL == mszGroups)
3152 buf = malloc(dwGroups);
3158 *(
char **)mszGroups = buf;
3164 if ((NULL != mszGroups) && (*pcchGroups < dwGroups))
3172 memcpy(buf, ReaderGroup, dwGroups);
3175 *pcchGroups = dwGroups;
3177 (void)pthread_mutex_unlock(¤tContextMap->
mMutex);
3219 uint32_t dwClientID = 0;
3224 API_TRACE_IN(
"%ld", hContext)
3232 if (NULL == currentContextMap)
3254 scCancelStruct.hContext = hContext;
3258 sizeof(scCancelStruct), (
void *) &scCancelStruct);
3266 rv =
MessageReceive(&scCancelStruct,
sizeof(scCancelStruct), dwClientID);
3271 rv = scCancelStruct.rv;
3310 API_TRACE_IN(
"%ld", hContext)
3348 if (NULL == newContextMap)
3351 Log2(PCSC_LOG_DEBUG,
"Allocating new SCONTEXTMAP @%p", newContextMap);
3352 newContextMap->
hContext = hContext;
3356 (void)pthread_mutex_init(&newContextMap->
mMutex, NULL);
3358 lrv = list_init(&newContextMap->channelMapList);
3361 Log2(PCSC_LOG_CRITICAL,
"list_init failed with return value: %d", lrv);
3365 lrv = list_attributes_seeker(&newContextMap->channelMapList,
3366 CHANNEL_MAP_seeker);
3369 Log2(PCSC_LOG_CRITICAL,
3370 "list_attributes_seeker failed with return value: %d", lrv);
3371 list_destroy(&newContextMap->channelMapList);
3375 (void)pthread_mutex_lock(&contextMapList_lock);
3376 lrv = list_append(&contextMapList, newContextMap);
3377 (void)pthread_mutex_unlock(&contextMapList_lock);
3380 Log2(PCSC_LOG_CRITICAL,
"list_append failed with return value: %d",
3382 list_destroy(&newContextMap->channelMapList);
3390 (void)pthread_mutex_destroy(&newContextMap->
mMutex);
3391 free(newContextMap);
3420 if (NULL != currentContextMap)
3421 (void)pthread_mutex_lock(¤tContextMap->
mMutex);
3425 return currentContextMap;
3444 (void)pthread_mutex_lock(&contextMapList_lock);
3445 currentContextMap = list_seek(&contextMapList, &hContext);
3446 (void)pthread_mutex_unlock(&contextMapList_lock);
3448 return currentContextMap;
3462 if (NULL != currentContextMap)
3463 SCardCleanContext(currentContextMap);
3466 static void SCardCleanContext(
SCONTEXTMAP * targetContextMap)
3468 int list_index, lrv;
3475 (void)pthread_mutex_destroy(&targetContextMap->
mMutex);
3477 listSize = list_size(&targetContextMap->channelMapList);
3478 for (list_index = 0; list_index < listSize; list_index++)
3480 currentChannelMap = list_get_at(&targetContextMap->channelMapList,
3482 if (NULL == currentChannelMap)
3484 Log2(PCSC_LOG_CRITICAL,
"list_get_at failed for index %d",
3490 free(currentChannelMap->readerName);
3491 free(currentChannelMap);
3495 list_destroy(&targetContextMap->channelMapList);
3497 (void)pthread_mutex_lock(&contextMapList_lock);
3498 lrv = list_delete(&contextMapList, targetContextMap);
3499 (void)pthread_mutex_unlock(&contextMapList_lock);
3502 Log2(PCSC_LOG_CRITICAL,
3503 "list_delete failed with return value: %d", lrv);
3506 free(targetContextMap);
3522 if (NULL == newChannelMap)
3525 newChannelMap->hCard = hCard;
3526 newChannelMap->readerName = strdup(readerName);
3528 lrv = list_append(¤tContextMap->channelMapList, newChannelMap);
3531 free(newChannelMap->readerName);
3532 free(newChannelMap);
3533 Log2(PCSC_LOG_CRITICAL,
"list_append failed with return value: %d",
3548 rv = SCardGetContextAndChannelFromHandleTH(hCard, ¤tContextMap,
3549 ¤tChannelMap);
3553 free(currentChannelMap->readerName);
3555 lrv = list_delete(¤tContextMap->channelMapList, currentChannelMap);
3558 Log2(PCSC_LOG_CRITICAL,
3559 "list_delete failed with return value: %d", lrv);
3562 free(currentChannelMap);
3567 static LONG SCardGetContextChannelAndLockFromHandle(
SCARDHANDLE hCard,
3576 rv = SCardGetContextAndChannelFromHandleTH(hCard, targetContextMap,
3580 (void)pthread_mutex_lock(&(*targetContextMap)->mMutex);
3587 static LONG SCardGetContextAndChannelFromHandleTH(
SCARDHANDLE hCard,
3597 *targetContextMap = NULL;
3598 *targetChannelMap = NULL;
3600 (void)pthread_mutex_lock(&contextMapList_lock);
3601 listSize = list_size(&contextMapList);
3603 for (list_index = 0; list_index < listSize; list_index++)
3605 currentContextMap = list_get_at(&contextMapList, list_index);
3606 if (currentContextMap == NULL)
3608 Log2(PCSC_LOG_CRITICAL,
"list_get_at failed for index %d",
3612 currentChannelMap = list_seek(¤tContextMap->channelMapList,
3614 if (currentChannelMap != NULL)
3616 *targetContextMap = currentContextMap;
3617 *targetChannelMap = currentChannelMap;
3623 (void)pthread_mutex_unlock(&contextMapList_lock);
3638 struct stat statBuffer;
3641 socketName = getSocketName();
3642 rv = stat(socketName, &statBuffer);
3646 Log3(PCSC_LOG_INFO,
"PCSC Not Running: %s: %s",
3647 socketName, strerror(errno));
3654 static LONG getReaderEvents(
SCONTEXTMAP * currentContextMap,
int *readerEvents)
3656 int32_t dwClientID = currentContextMap->
dwClientID;
3661 if (Protocol_version < 4005)
3669 rv =
MessageReceive(&get_reader_events,
sizeof(get_reader_events), dwClientID);
3673 *readerEvents = get_reader_events.readerEvents;
3678 static LONG getReaderStates(
SCONTEXTMAP * currentContextMap)
3680 int32_t dwClientID = currentContextMap->
dwClientID;
3684 if (Protocol_version <= 4005)
3694 rv =
MessageReceive(&array_size,
sizeof(array_size), dwClientID);
3699 if (array_size > pcsclite_max_reader_context)
3702 readerStates = realloc(readerStates, array_size *
sizeof(readerStates[0]));
3703 if (NULL == readerStates)
3705 pcsclite_max_reader_context = array_size;
3708 if (array_size != pcsclite_max_reader_context)
3714 if (Protocol_version <= 4005)
3722 rv =
MessageReceive(readerStates, array_size *
sizeof(readerStates[0]), dwClientID);
3729 static LONG getReaderStatesAndRegisterForEvents(
SCONTEXTMAP * currentContextMap)
3731 int32_t dwClientID = currentContextMap->
dwClientID;
3740 if (Protocol_version <= 4005)
3749 rv =
MessageReceive(readerStates, pcsclite_max_reader_context *
sizeof(readerStates[0]), dwClientID);
3753 return getReaderStates(currentContextMap);
3756 static LONG unregisterFromEvents(
SCONTEXTMAP * currentContextMap)
3758 int32_t dwClientID = currentContextMap->
dwClientID;
3764 dwClientID, 0, NULL);
3781 rv = waitStatusStruct.rv;
#define SCARD_E_INVALID_VALUE
One or more of the supplied parameters values could not be properly interpreted.
used by SCardBeginTransaction()
contained in SCARD_CONNECT Messages.
static void SCardLockThread(void)
Locks a mutex so another thread must wait to use this function.
wait for a reader state change
contained in SCARD_CANCEL Messages.
contained in SCARD_TRANSMIT Messages.
#define SCARD_STATE_UNAVAILABLE
Status unavailable.
LONG SCardListReaders(SCARDCONTEXT hContext, LPCSTR mszGroups, LPSTR mszReaders, LPDWORD pcchReaders)
Returns a list of currently available readers on the system.
#define SCARD_S_SUCCESS
No error was encountered.
contained in SCARD_END_TRANSACTION Messages.
#define PCSCLITE_SHARING_NO_CONTEXT
No application is using the reader.
#define MAX_BUFFER_SIZE
Maximum Tx/Rx Buffer for short APDU.
LONG SCardListReaderGroups(SCARDCONTEXT hContext, LPSTR mszGroups, LPDWORD pcchGroups)
Returns a list of currently available reader groups on the system.
#define SCARD_E_TIMEOUT
The user-specified timeout value has expired.
#define SCARD_STATE_EMPTY
Card removed.
#define SCARD_E_NO_SERVICE
The Smart card resource manager is not running.
UCHAR cardAtr[MAX_ATR_SIZE]
ATR.
get the client/server protocol version
INTERNAL void ClientCloseSession(uint32_t dwClientID)
Closes the socket used by the client to communicate with the server.
static SCONTEXTMAP * SCardGetContextTH(SCARDCONTEXT)
Get the address from the Application Context list _psContextMap for the passed context.
#define SCARD_E_INVALID_PARAMETER
One or more of the supplied parameters could not be properly interpreted.
#define SCARD_STATE_IGNORE
Ignore this reader.
#define SCARD_UNKNOWN
Unknown state.
used by SCardEstablishContext()
#define SCARD_E_NO_READERS_AVAILABLE
Cannot find a smart card reader.
INTERNAL LONG MessageSendWithHeader(uint32_t command, uint32_t dwClientID, uint64_t size, void *data_void)
Wrapper for the MessageSend() function.
int32_t minor
IPC minor PROTOCOL_VERSION_MINOR.
used by SCardEndTransaction()
LONG SCardEstablishContext(DWORD dwScope, LPCVOID pvReserved1, LPCVOID pvReserved2, LPSCARDCONTEXT phContext)
Creates an Application Context to the PC/SC Resource Manager.
unsigned long cbPciLength
Protocol Control Inf Length.
#define SCARD_STATE_CHANGED
State has changed.
This handles abstract system level calls.
const char * SYS_GetEnv(const char *name)
(More) secure version of getenv(3)
#define PROTOCOL_VERSION_MINOR_CLIENT_BACKWARD
Minor version the client also supports.
get the readers state array
#define PROTOCOL_VERSION_MAJOR
Major version of the current message protocol.
contained in SCARD_DISCONNECT Messages.
LONG SCardFreeMemory(SCARDCONTEXT hContext, LPCVOID pvMem)
Releases memory that has been returned from the resource manager using the SCARD_AUTOALLOCATE length ...
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 SCardGetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPBYTE pbAttr, LPDWORD pcbAttrLen)
Get an attribute from the IFD Handler (reader driver).
#define SCARD_PRESENT
Card is present.
Information contained in SCARD_RELEASE_CONTEXT Messages.
LONG SCardDisconnect(SCARDHANDLE hCard, DWORD dwDisposition)
Terminates a connection made through SCardConnect().
LONG SCardCancel(SCARDCONTEXT hContext)
Cancels a specific blocking SCardGetStatusChange() function.
int SYS_USleep(int)
Makes the current process sleep for some microseconds.
contained in SCARD_BEGIN_TRANSACTION Messages.
#define PCSCLITE_SHARING_EXCLUSIVE_CONTEXT
Reader used in exclusive mode.
bool cancellable
We are in a cancellable call.
LONG SCardIsValidContext(SCARDCONTEXT hContext)
Check if a SCARDCONTEXT is valid.
#define INFINITE
Infinite timeout.
#define SCARD_STATE_UNKNOWN
Reader unknown.
Represents an Application Context on the Client side.
Information contained in SCARD_ESTABLISH_CONTEXT Messages.
static void SCardRemoveContext(SCARDCONTEXT)
Removes an Application Context from a control vector.
#define SCARD_AUTOALLOCATE
see SCardFreeMemory()
Information transmitted in CMD_VERSION Messages.
INTERNAL LONG MessageReceive(void *buffer_void, uint64_t buffer_size, int32_t filedes)
Called by the Client to get the response from the server or vice-versa.
used by SCardReleaseContext()
LONG SCARDCONTEXT
hContext returned by SCardEstablishContext()
#define SCARD_E_NO_MEMORY
Not enough memory available to complete this command.
pthread_mutex_t contextMapList_lock
lock for the above list
contained in SCARD_STATUS Messages.
#define SCARD_E_READER_UNAVAILABLE
The specified reader is not currently available for use.
contained in SCARD_RECONNECT Messages.
unsigned long dwProtocol
Protocol identifier.
#define PCSCLITE_MAX_READERS_CONTEXTS
Maximum readers context (a slot is count as a reader)
contained in SCARD_GET_ATTRIB and Messages.
#define SCARD_STATE_PRESENT
Card inserted.
This defines some structures and #defines to be used over the transport layer.
get the number of reader events
Information contained in CMD_WAIT_READER_STATE_CHANGE Messages.
DWORD dwClientID
Client Connection ID.
#define SCARD_STATE_ATRMATCH
ATR matches card.
static SCONTEXTMAP * SCardGetAndLockContext(SCARDCONTEXT)
Get the SCONTEXTMAP * from the Application Context vector _psContextMap for the passed context...
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 int time_sub(struct timeval *a, struct timeval *b)
return the difference (as long int) in µs between 2 struct timeval r = a - b
#define MAX_BUFFER_SIZE_EXTENDED
enhanced (64K + APDU + Lc + Le + SW) Tx/Rx Buffer
Represents an Application Context Channel.
uint32_t cardProtocol
SCARD_PROTOCOL_* value.
This handles card insertion/removal events, updates ATR, protocol, and status information.
SCARDCONTEXT hContext
Application Context ID.
#define SCARD_PROTOCOL_ANY
IFD determines prot.
stop waiting for a reader state change
LONG SCardConnect(SCARDCONTEXT hContext, LPCSTR szReader, DWORD dwShareMode, DWORD dwPreferredProtocols, LPSCARDHANDLE phCard, LPDWORD pdwActiveProtocol)
Establishes a connection to the reader specified in * szReader.
LONG SCardSetAttrib(SCARDHANDLE hCard, DWORD dwAttrId, LPCBYTE pbAttr, DWORD cbAttrLen)
Set an attribute of the IFD Handler.
uint32_t readerState
SCARD_* bit field.
#define SCARD_STATE_EXCLUSIVE
Exclusive Mode.
#define SCARD_SWALLOWED
Card not powered.
static LONG SCardAddContext(SCARDCONTEXT, DWORD)
Functions for managing instances of SCardEstablishContext() These functions keep track of Context han...
LONG SCARDHANDLE
hCard returned by SCardConnect()
#define SCARD_E_INSUFFICIENT_BUFFER
The data buffer to receive returned data is too small for the returned data.
#define SCARD_E_CANCELLED
The action was cancelled by an SCardCancel request.
LONG SCardCheckDaemonAvailability(void)
Checks if the server is running.
INTERNAL int ClientSetupSession(uint32_t *pdwClientID)
Prepares a communication channel for the client to talk to the server.
Define an exported public reader state structure so each application gets instant notification of cha...
#define PROTOCOL_VERSION_MINOR
Minor version of the current message protocol.
static bool isExecuted
Make sure the initialization code is executed only once.
_Atomic uint32_t cardAtrLength
ATR length.
LONG SCardBeginTransaction(SCARDHANDLE hCard)
Establishes a temporary exclusive access mode for doing a series of commands in a transaction...
#define SCARD_STATE_INUSE
Shared Mode.
Protocol Control Information (PCI)
LONG SCardControl(SCARDHANDLE hCard, DWORD dwControlCode, LPCVOID pbSendBuffer, DWORD cbSendLength, LPVOID pbRecvBuffer, DWORD cbRecvLength, LPDWORD lpBytesReturned)
Sends a command directly to the IFD Handler (reader driver) to be processed by the reader...
#define SCARD_ABSENT
Card is absent.
#define SCARD_E_SHARING_VIOLATION
The smart card cannot be accessed because of other connections outstanding.
INTERNAL LONG MessageSend(void *buffer_void, uint64_t buffer_size, int32_t filedes)
Sends a menssage from client to server or vice-versa.
used by SCardDisconnect()
contained in SCARD_CONTROL Messages.
static LONG SCardEstablishContextTH(DWORD, LPCVOID, LPCVOID, LPSCARDCONTEXT)
Creates a communication context to the PC/SC Resource Manager.
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.
pthread_mutex_t mMutex
Mutex for this context.
#define SCARD_E_UNKNOWN_READER
The specified reader name is not recognized.
static pthread_mutex_t clientMutex
Ensure that some functions be accessed in thread-safe mode.
#define PCSCLITE_SHARING_LAST_CONTEXT
One application is using the reader.
int32_t major
IPC major PROTOCOL_VERSION_MAJOR.
static bool SCardGetContextValidity(SCARDCONTEXT hContext)
Tell if a context index from the Application Context vector _psContextMap is valid or not...
LONG SCardEndTransaction(SCARDHANDLE hCard, DWORD dwDisposition)
Ends a previously begun transaction.
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().
_Atomic int32_t readerSharing
PCSCLITE_SHARING_* sharing status.
uint32_t eventCounter
number of card events
#define SCARD_E_UNSUPPORTED_FEATURE
This smart card does not support the requested feature.
#define SCARD_E_SERVICE_STOPPED
The Smart card resource manager has shut down.
#define SCARD_E_INVALID_HANDLE
The supplied handle was invalid.
This handles smart card reader communications.
LONG SCardReleaseContext(SCARDCONTEXT hContext)
Destroys a communication context to the PC/SC Resource Manager.
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.
#define SCARD_STATE_UNAWARE
App wants status.
static void SCardUnlockThread(void)
Unlocks a mutex so another thread may use the client.
int pcsclite_max_reader_context
Area used to read status information about the readers.
#define SCARD_STATE_MUTE
Unresponsive card.