Created
November 11, 2014 17:43
-
-
Save yonran/eda700d8802e209473cd to your computer and use it in GitHub Desktop.
OSX 10.10 Yosemite SCardStatus bug test
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// clang -framework PCSC scardstatus_bug.c -o scardstatus_bug | |
// Tests SCardStatus bug in OSX 10.10 Yosemite. | |
// Connects to a smart card and calls SCardStatus. | |
#include <stdio.h> | |
#include <strings.h> | |
#include <stdlib.h> | |
#include <PCSC/wintypes.h> | |
#include <PCSC/winscard.h> | |
#define TEXT(x) x | |
typedef char TCHAR; | |
static LPCTSTR SCARD_ALL_READERS = TEXT("SCard$AllReaders\000"); | |
void logError(const char *where, DWORD scardError) { | |
fprintf(stderr, "Error at %s: 0x%x\n", where, scardError); | |
exit(1); | |
} | |
int main(int argc, const char * argv[]) { | |
BOOL workaroundSCardStatus = 0; | |
for (int i = 1; i < argc; i++) { | |
if (0 == strcmp("--workaround-scardstatus", argv[i])) { | |
workaroundSCardStatus = 1; | |
} | |
} | |
printf("--workaround-scardstatus is%s specified\n", workaroundSCardStatus?"":" NOT"); | |
SCARDCONTEXT hContext; | |
DWORD err = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext); | |
if (err != 0) { | |
logError("SCardEstablishContext", err); | |
} else { | |
DWORD cchReaders = 0; | |
err = SCardListReaders(hContext, SCARD_ALL_READERS, NULL, &cchReaders); | |
if (err != 0) { | |
logError("SCardListReaders", err); | |
} else { | |
LPTSTR mszReaders = calloc(cchReaders, sizeof(TCHAR)); | |
if (mszReaders == NULL) { | |
perror("calloc for SCardListReaders"); | |
} else { | |
err = SCardListReaders(hContext, SCARD_ALL_READERS, mszReaders, &cchReaders); | |
if (err != 0) { | |
logError("SCardListReaders", err); | |
} else if ('\0' == *mszReaders) { | |
printf("There are no smart card readers. Please plug one in.\n"); | |
} else { | |
DWORD cReaders = 0; | |
for (LPTSTR readerName = mszReaders; *readerName != '\0'; readerName += strlen(readerName) + 1) { | |
printf("Found reader %s\n", readerName); | |
cReaders++; | |
} | |
LPTSTR szChosenReader = mszReaders; | |
SCARD_READERSTATE readerState; | |
memset(&readerState, 0, sizeof(SCARD_READERSTATE)); | |
readerState.szReader = szChosenReader; | |
readerState.dwCurrentState = SCARD_STATE_UNAWARE; | |
err = SCardGetStatusChange(hContext, 0, &readerState, 1); | |
if (err != 0) { | |
logError("SCardGetStatusChange", err); | |
} else if (! (SCARD_STATE_PRESENT & readerState.dwEventState)) { | |
printf("Card is not present in %s. Please insert smart card.\n", szChosenReader); | |
} else { | |
SCARDHANDLE hCard; | |
DWORD dwActiveProtocol; | |
err = SCardConnect(hContext, szChosenReader, SCARD_SHARE_SHARED, SCARD_PROTOCOL_ANY, &hCard, &dwActiveProtocol); | |
if (err != 0) { | |
logError("SCardConnect", err); | |
} else { | |
DWORD chReaderLen; | |
err = SCardStatus(hCard, NULL, &chReaderLen, NULL, NULL, NULL, NULL); | |
if (err != 0) { | |
logError("SCardStatus without buf", err); | |
} else { | |
if (workaroundSCardStatus) | |
chReaderLen++; | |
LPTSTR mszReaderNames = calloc(chReaderLen, sizeof(TCHAR)); | |
if (NULL == mszReaderNames) { | |
perror("calloc for SCardStatus"); | |
} else { | |
DWORD dwState; | |
DWORD dwProtocol; | |
BYTE atr[32]; | |
DWORD cbAtrLen = 32; | |
err = SCardStatus(hCard, mszReaderNames, &chReaderLen, &dwState, &dwProtocol, atr, &cbAtrLen); | |
if (err != 0) { | |
logError("SCardStatus with buf", err); | |
} else { | |
printf("State: %d, protocol: %d, ATR length: %d\n", dwState, dwProtocol, cbAtrLen); | |
BOOL gotMultiStringEnd = 0; | |
for (DWORD i = 0; i < chReaderLen; i += strlen(mszReaderNames + i) + 1) { | |
LPTSTR readerName = mszReaderNames + i; | |
if ('\0' == *readerName) { | |
gotMultiStringEnd = 1; | |
break; | |
} | |
printf("Name of reader: %s\n", readerName); | |
} | |
if (! gotMultiStringEnd) { | |
fprintf(stderr, "SCardStatus reader names multistring did not end with empty string!\n"); | |
} | |
} | |
free(mszReaderNames); | |
} | |
} | |
err = SCardDisconnect(hCard, SCARD_LEAVE_CARD); | |
if (err != 0) { | |
logError("SCardDisconnect", err); | |
} | |
} | |
} | |
} | |
free(mszReaders); | |
} | |
} | |
} | |
err = SCardReleaseContext(hContext); | |
if (err != 0) logError("SCardReleaseContext", err); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I have filed bug 18941693 with bugreport.apple.com. Since there is no external link, here is a copy of my bug report:
Summary:
In the WinSCard API, When supplying pcchReaderLen to SCardStatus, one is supposed to call SCardStatus twice, first to get the length and second to copy the multistring value into szReaderName. In OSX 10.10 Yosemite. there are 2 bugs:
Sample C code that fails:
DWORD namesLength;
SCardStatus(..., NULL, &namesLength, ...);
LPTSTR names = malloc(namesLength);
SCardStatus(..., names, &namesLength, ...); // returns SCARD_E_INSUFFICIENT_BUFFER
This affected my own project, jnasmartcardio: jnasmartcardio/jnasmartcardio#20
Steps to Reproduce:
Expected Results:
Program should connect to card and print information about card. The first cal to SCardStatus should give a buffer size that is appropriate for the second call to SCardStatus. The buffer should be a multistring as described by Raymond Chen here: http://blogs.msdn.com/b/oldnewthing/archive/2009/10/08/9904646.aspx
Actual Results:
3. When allocating a buffer of size specified by first SCardStatus call, the second SCardStatus call fails with SCARD_E_INSUFFICIENT_BUFFER
4. When allocating a buffer that is 1 + size specified by first SCardStatus call, the SCardStatus reader names multistring did not end with empty string