This is part of the series: "OS X Yosemite and smart cards: known bugs".
After a
This should not happen since
Apple bug report #19262854 "PC/SC function SCardReconnect does not work as expected". Closed by Apple, 6th January 2015, as a duplicated of #18689292.
No error expected:
Or you can replace the bogus SCardReconnect() by the sequence:
I could not find an elegant way to write a macro to automate the code change. The problem is that
SCardReconnect
SCardReconnect() has a bad side effect on Yosemite.After a
SCardReconnect(..., SCARD_RESET_CARD, ...)
the next SCardTransmit() will fail with the error code 0x80100068
that is SCARD_W_RESET_CARD
.This should not happen since
SCardReconnect()
should reconnect (sic) to the card after the card has been reseted.See also
"[OSX 10.10] After connect and SCardReconnect, SCardTransmit raises card reset" https://smartcardservices.macosforge.org/trac/ticket/136Apple bug report #19262854 "PC/SC function SCardReconnect does not work as expected". Closed by Apple, 6th January 2015, as a duplicated of #18689292.
Sample code
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef __APPLE__
#include <PCSC/winscard.h>
#include <PCSC/wintypes.h>
#else
#include <winscard.h>
#endif
int main(int argc, const char * argv[]) {
SCARDCONTEXT hContext;
LPSTR mszReaders;
DWORD err = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext);
if (err != SCARD_S_SUCCESS) {
printf("ScardEstablishedContext: 0x%08x\n",err);
return -1;
}
DWORD cchReaders = 0;
err = SCardListReaders(hContext, "SCard$AllReaders", NULL, &cchReaders);
if (err != 0) {
printf("ScardListReaders: 0x%08x\n",err);
return -1;
}
mszReaders = calloc(cchReaders, sizeof(char));
if (!mszReaders) {
printf("calloc\n");
return -1;
}
err = SCardListReaders(hContext,"SCard$AllReaders", mszReaders, &cchReaders);
if (err != SCARD_S_SUCCESS) {
printf("ScardListReaders: 0x%08x\n",err);
return -1;
}
printf("Reader: %s\n", mszReaders);
SCARDHANDLE hCard;
DWORD dwActiveProtocol;
err = SCardConnect(hContext, mszReaders, SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, &hCard, &dwActiveProtocol);
if (err != SCARD_S_SUCCESS) {
printf("ScardConnect: 0x%08x\n",err);
return -1;
}
unsigned char cmd[] = {0, 0, 0, 0};
unsigned char resp[255];
DWORD resp_len = sizeof resp;
SCARD_IO_REQUEST * pci;
err = SCardReconnect(hCard, SCARD_SHARE_SHARED, SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, SCARD_RESET_CARD, &dwActiveProtocol);
if (err != SCARD_S_SUCCESS) {
printf("SCardReconnect: 0x%08x\n",err);
}
if (SCARD_PROTOCOL_T0 == dwActiveProtocol)
pci = SCARD_PCI_T0;
else
pci = SCARD_PCI_T1;
err = SCardTransmit(hCard, pci, cmd, sizeof cmd, pci, resp, &resp_len);
if (err != SCARD_S_SUCCESS) {
printf("SCardTransmit: 0x%08x\n",err);
}
SCardDisconnect(hCard, SCARD_LEAVE_CARD);
SCardReleaseContext(hContext);
return 0;
}
Result (on Yosemite)
$ CFLAGS="-framework PCSC" make main
cc -framework PCSC main.c -o main
$ ./main
Reader: Gemalto PC Twin Reader
SCardTransmit: 0x80100068
Expected result (on Debian)
$ CFLAGS=`pkg-config --cflags libpcsclite` LDFLAGS=`pkg-config --libs libpcsclite` make main
cc -pthread -I/usr/include/PCSC -lpcsclite main.c -o main
main.c: In function ‘main’:
main.c:57:7: warning: assignment discards ‘const’ qualifier from pointer target type [enabled by default]
main.c:59:7: warning: assignment discards ‘const’ qualifier from pointer target type [enabled by default]
No error expected:
$ ./main
Reader: Gemalto PC Twin Reader 00 00
Known workaround
You can add an second call toSCardReconnect(..., SCARD_LEAVE_CARD, ...)
after the first one to force a card reconnection.Or you can replace the bogus SCardReconnect() by the sequence:
SCardDisconnect(..., SCARD_RESET_CARD);
SCardConnect(...);
I could not find an elegant way to write a macro to automate the code change. The problem is that
SCardConnect()
needs parameters (PC/SC context and reader name) that are not available from the SCardReconnect()
call.
ConversionConversion EmoticonEmoticon