Beispiel #1
0
static uint32 handle_State(IRP* irp)
{
	LONG rv;
	SCARDHANDLE hCard;
	DWORD state = 0, protocol = 0;
	DWORD readerLen;
	DWORD atrLen = MAX_ATR_SIZE;
	char * readerName;
	BYTE pbAtr[MAX_ATR_SIZE];

#ifdef WITH_DEBUG_SCARD
	int i;
#endif

	stream_seek(irp->input, 0x24);
	stream_seek_uint32(irp->input);	/* atrLen */

	stream_seek(irp->input, 0x0c);
	stream_read_uint32(irp->input, hCard);
	stream_seek(irp->input, 0x04);

#ifdef SCARD_AUTOALLOCATE
	readerLen = SCARD_AUTOALLOCATE;

	rv = SCardStatus(hCard, (LPSTR) &readerName, &readerLen, &state, &protocol, pbAtr, &atrLen);
#else
	readerLen = 256;
	readerName = xmalloc(readerLen);

	rv = SCardStatus(hCard, (LPSTR) readerName, &readerLen, &state, &protocol, pbAtr, &atrLen);
#endif

	if (rv != SCARD_S_SUCCESS)
	{
		DEBUG_SCARD("Failure: %s (0x%08x)", pcsc_stringify_error(rv), (unsigned) rv);
		return sc_output_return(irp, rv);
	}

	DEBUG_SCARD("Success (hcard: 0x%08x len: %d state: 0x%08x, proto: 0x%08x)",
		(unsigned) hCard, (int) atrLen, (unsigned) state, (unsigned) protocol);

#ifdef WITH_DEBUG_SCARD
	printf("       ATR: ");
	for (i = 0; i < atrLen; i++)
		printf("%02x%c", pbAtr[i], (i == atrLen - 1) ? ' ' : ':');
	printf("\n");
#endif

	state = sc_map_state(state);

	stream_write_uint32(irp->output, state);
	stream_write_uint32(irp->output, protocol);
	stream_write_uint32(irp->output, atrLen);
	stream_write_uint32(irp->output, 0x00000001);
	stream_write_uint32(irp->output, atrLen);
	stream_write(irp->output, pbAtr, atrLen);

	sc_output_repos(irp, atrLen);
	sc_output_alignment(irp, 8);

#ifdef SCARD_AUTOALLOCATE
	xfree(readerName);
#else
	xfree(readerName);
#endif

	return rv;
}
Beispiel #2
0
static DWORD handle_Status(IRP *irp, boolean wide)
{
	LONG rv;
	SCARDHANDLE hCard;
	DWORD state, protocol;
	DWORD readerLen = 0;
	DWORD atrLen = 0;
	char * readerName;
	BYTE pbAtr[MAX_ATR_SIZE];
	uint32 dataLength;
	int pos, poslen1, poslen2;

#ifdef WITH_DEBUG_SCARD
	int i;
#endif

	stream_seek(irp->input, 0x24);
	stream_read_uint32(irp->input, readerLen);
	stream_read_uint32(irp->input, atrLen);
	stream_seek(irp->input, 0x0c);
	stream_read_uint32(irp->input, hCard);
	stream_seek(irp->input, 0x4);

	atrLen = MAX_ATR_SIZE;

#ifdef SCARD_AUTOALLOCATE
	readerLen = SCARD_AUTOALLOCATE;

	rv = SCardStatus(hCard, (LPSTR) &readerName, &readerLen, &state, &protocol, pbAtr, &atrLen);
#else
	readerLen = 256;
	readerName = xmalloc(readerLen);

	rv = SCardStatus(hCard, (LPSTR) readerName, &readerLen, &state, &protocol, pbAtr, &atrLen);
#endif

	if (rv != SCARD_S_SUCCESS)
	{
		DEBUG_SCARD("Failure: %s (0x%08x)", pcsc_stringify_error(rv), (unsigned) rv);
		return sc_output_return(irp, rv);
	}

	DEBUG_SCARD("Success (state: 0x%08x, proto: 0x%08x)", (unsigned) state, (unsigned) protocol);
	DEBUG_SCARD("       Reader: \"%s\"", readerName ? readerName : "NULL");

#ifdef WITH_DEBUG_SCARD
	printf("       ATR: ");
	for (i = 0; i < atrLen; i++)
		printf("%02x%c", pbAtr[i], (i == atrLen - 1) ? ' ' : ':');
	printf("\n");
#endif

	state = sc_map_state(state);

	poslen1 = stream_get_pos(irp->output);
	stream_write_uint32(irp->output, readerLen);
	stream_write_uint32(irp->output, 0x00020000);
	stream_write_uint32(irp->output, state);
	stream_write_uint32(irp->output, protocol);
	stream_write(irp->output, pbAtr, atrLen);

	if (atrLen < 32)
		stream_write_zero(irp->output, 32 - atrLen);
	stream_write_uint32(irp->output, atrLen);

	poslen2 = stream_get_pos(irp->output);
	stream_write_uint32(irp->output, readerLen);

	dataLength = sc_output_string(irp, readerName, wide);
	dataLength += sc_output_string(irp, "\0", wide);
	sc_output_repos(irp, dataLength);

	pos = stream_get_pos(irp->output);
	stream_set_pos(irp->output, poslen1);
	stream_write_uint32(irp->output,dataLength);
	stream_set_pos(irp->output, poslen2);
	stream_write_uint32(irp->output,dataLength);
	stream_set_pos(irp->output, pos);

	sc_output_alignment(irp, 8);

#ifdef SCARD_AUTOALLOCATE
	/* SCardFreeMemory(NULL, readerName); */
	free(readerName);
#else
	xfree(readerName);
#endif

	return rv;
}
Beispiel #3
0
static uint32 handle_ListReaders(IRP* irp, boolean wide)
{
	uint32 len, rv;
	SCARDCONTEXT hContext;
	DWORD dwReaders;
	char *readerList = NULL, *walker;
	int elemLength, dataLength;
	int pos, poslen1, poslen2;

	stream_seek(irp->input, 8);
	stream_read_uint32(irp->input, len);

	stream_seek(irp->input, 0x1c);
	stream_read_uint32(irp->input, len);

	if (len != 4)
		return SCARD_F_INTERNAL_ERROR;

	stream_read_uint32(irp->input, hContext);

	/* ignore rest of [MS-RDPESC] 2.2.2.4 ListReaders_Call */

	rv = SCARD_S_SUCCESS;
#ifdef SCARD_AUTOALLOCATE
	dwReaders = SCARD_AUTOALLOCATE;
	rv = SCardListReaders(hContext, NULL, (LPSTR) &readerList, &dwReaders);
#else
	rv = SCardListReaders(hContext, NULL, NULL, &dwReaders);

	readerList = xmalloc(dwReaders);
	rv = SCardListReaders(hContext, NULL, readerList, &dwReaders);
#endif
	if (rv != SCARD_S_SUCCESS)
	{
		DEBUG_SCARD("Failure: %s (0x%08x)", pcsc_stringify_error(rv), (unsigned) rv);
		return rv;
	}

/*	DEBUG_SCARD("Success 0x%08x %d %d", (unsigned) hContext, (unsigned) cchReaders, (int) strlen(readerList));*/

	poslen1 = stream_get_pos(irp->output);
	stream_seek_uint32(irp->output);

	stream_write_uint32(irp->output, 0x01760650);

	poslen2 = stream_get_pos(irp->output);
	stream_seek_uint32(irp->output);

	walker = readerList;
	dataLength = 0;

	while (1)
	{
		elemLength = strlen(walker);
		if (elemLength == 0)
			break;

		dataLength += sc_output_string(irp, walker, wide);
		walker += elemLength + 1;
		elemLength = strlen(walker);
	}

	dataLength += sc_output_string(irp, "\0", wide);

	pos = stream_get_pos(irp->output);

	stream_set_pos(irp->output, poslen1);
	stream_write_uint32(irp->output, dataLength);
	stream_set_pos(irp->output, poslen2);
	stream_write_uint32(irp->output, dataLength);

	stream_set_pos(irp->output, pos);

	sc_output_repos(irp, dataLength);
	sc_output_alignment(irp, 8);

#ifdef SCARD_AUTOALLOCATE
	SCardFreeMemory(hContext, readerList);
#else
	xfree(readerList);
#endif

	return rv;
}
Beispiel #4
0
static uint32 handle_GetStatusChange(IRP* irp, boolean wide)
{
	LONG rv;
	SCARDCONTEXT hContext;
	DWORD dwTimeout = 0;
	DWORD readerCount = 0;
	SCARD_READERSTATE *readerStates, *cur;
	int i;

	stream_seek(irp->input, 0x18);
	stream_read_uint32(irp->input, dwTimeout);
	stream_read_uint32(irp->input, readerCount);

	stream_seek(irp->input, 8);

	stream_read_uint32(irp->input, hContext);

	stream_seek(irp->input, 4);

	DEBUG_SCARD("context: 0x%08x, timeout: 0x%08x, count: %d",
		     (unsigned) hContext, (unsigned) dwTimeout, (int) readerCount);
	if (readerCount > 0)
	{
		readerStates = xzalloc(readerCount * sizeof(SCARD_READERSTATE));
		if (!readerStates)
			return sc_output_return(irp, SCARD_E_NO_MEMORY);


		for (i = 0; i < readerCount; i++)
		{
			cur = &readerStates[i];

			stream_seek(irp->input, 4);

			/*
			 * TODO: on-wire is little endian; need to either
			 * convert to host endian or fix the headers to
			 * request the order we want
			 */
			stream_read_uint32(irp->input, cur->dwCurrentState);
			stream_read_uint32(irp->input, cur->dwEventState);
			stream_read_uint32(irp->input, cur->cbAtr);
			stream_read(irp->input, cur->rgbAtr, 32);

			stream_seek(irp->input, 4);

			/* reset high bytes? */
			cur->dwCurrentState &= 0x0000FFFF;
			cur->dwEventState &= 0x0000FFFF;
			cur->dwEventState = 0;
		}

		for (i = 0; i < readerCount; i++)
		{
			cur = &readerStates[i];
			uint32 dataLength;

			stream_seek(irp->input, 8);
			stream_read_uint32(irp->input, dataLength);
			sc_input_repos(irp, sc_input_string(irp, (char **) &cur->szReader, dataLength, wide));

			DEBUG_SCARD("   \"%s\"", cur->szReader ? cur->szReader : "NULL");
			DEBUG_SCARD("       user: 0x%08x, state: 0x%08x, event: 0x%08x",
				(unsigned) cur->pvUserData, (unsigned) cur->dwCurrentState,
				(unsigned) cur->dwEventState);

			if (strcmp(cur->szReader, "\\\\?PnP?\\Notification") == 0)
				cur->dwCurrentState |= SCARD_STATE_IGNORE;
		}
	}
	else
	{
		readerStates = NULL;
	}

	rv = SCardGetStatusChange(hContext, (DWORD) dwTimeout, readerStates, (DWORD) readerCount);

	if (rv != SCARD_S_SUCCESS)
		DEBUG_SCARD("Failure: %s (0x%08x)", pcsc_stringify_error(rv), (unsigned) rv);
	else
		DEBUG_SCARD("Success");

	stream_write_uint32(irp->output, readerCount);
	stream_write_uint32(irp->output, 0x00084dd8);
	stream_write_uint32(irp->output, readerCount);

	for (i = 0; i < readerCount; i++)
	{
		cur = &readerStates[i];

		DEBUG_SCARD("   \"%s\"", cur->szReader ? cur->szReader : "NULL");
		DEBUG_SCARD("       user: 0x%08x, state: 0x%08x, event: 0x%08x\n",
			(unsigned) cur->pvUserData, (unsigned) cur->dwCurrentState,
			(unsigned) cur->dwEventState);

		/* TODO: do byte conversions if necessary */
		stream_write_uint32(irp->output, cur->dwCurrentState);
		stream_write_uint32(irp->output, cur->dwEventState);
		stream_write_uint32(irp->output, cur->cbAtr);
		stream_write(irp->output, cur->rgbAtr, 32);

		stream_write_zero(irp->output, 4);

		xfree((void *)cur->szReader);
	}

	sc_output_alignment(irp, 8);

	xfree(readerStates);
	return rv;
}
Beispiel #5
0
static uint32 handle_GetAttrib(IRP* irp)
{
	LONG rv;
	SCARDHANDLE hCard;
	DWORD dwAttrId = 0, dwAttrLen = 0;
	DWORD attrLen = 0;
	uint8* pbAttr = NULL;

	stream_seek(irp->input, 0x20);
	stream_read_uint32(irp->input, dwAttrId);
	stream_seek(irp->input, 0x4);
	stream_read_uint32(irp->input, dwAttrLen);
	stream_seek(irp->input, 0xC);
	stream_read_uint32(irp->input, hCard);

	DEBUG_SCARD("hcard: 0x%08x, attrib: 0x%08x (%d bytes)\n",
		(unsigned) hCard, (unsigned) dwAttrId, (int) dwAttrLen);

#ifdef SCARD_AUTOALLOCATE
	if(dwAttrLen == 0)
	{
		attrLen = 0;
	}
	else
	{
		attrLen = SCARD_AUTOALLOCATE;
	}
#endif

	rv = SCardGetAttrib(hCard, dwAttrId, attrLen == 0 ? NULL : (uint8*) &pbAttr, &attrLen);

	if(dwAttrId == SCARD_ATTR_DEVICE_FRIENDLY_NAME_A && rv == SCARD_E_UNSUPPORTED_FEATURE)
	{
		rv = SCardGetAttrib(hCard, SCARD_ATTR_DEVICE_FRIENDLY_NAME_W,
			attrLen == 0 ? NULL : (uint8*) &pbAttr, &attrLen);
	}
	if(dwAttrId == SCARD_ATTR_DEVICE_FRIENDLY_NAME_W && rv == SCARD_E_UNSUPPORTED_FEATURE)
	{
		rv = SCardGetAttrib(hCard, SCARD_ATTR_DEVICE_FRIENDLY_NAME_A,
			attrLen == 0 ? NULL : (uint8*) &pbAttr, &attrLen);
	}
	if(attrLen > dwAttrLen && pbAttr != NULL)
	{
		rv = SCARD_E_INSUFFICIENT_BUFFER;
	}
	dwAttrLen = attrLen;

	if (rv != SCARD_S_SUCCESS)
	{
		DEBUG_SCARD("Failure: %s (0x%08x)", pcsc_stringify_error(rv), (unsigned int) rv);
		free(pbAttr);
		return sc_output_return(irp, rv);
	}
	else
	{
		DEBUG_SCARD("Success (%d bytes)", (int) dwAttrLen);

		stream_write_uint32(irp->output, dwAttrLen);
		stream_write_uint32(irp->output, 0x00000200);
		stream_write_uint32(irp->output, dwAttrLen);

		if (!pbAttr)
		{
			stream_write_zero(irp->output, dwAttrLen);
		}
		else
		{
			stream_write(irp->output, pbAttr, dwAttrLen);
		}
		sc_output_repos(irp, dwAttrLen);
		/* align to multiple of 4 */
		stream_write_uint32(irp->output, 0);
	}
	sc_output_alignment(irp, 8);

	xfree(pbAttr);

	return rv;
}
Beispiel #6
0
static uint32 handle_LocateCardsByATR(IRP* irp, boolean wide)
{
	LONG rv;
	int i, j, k;
	SCARDCONTEXT hContext;
	uint32 atrMaskCount = 0;
	uint32 readerCount = 0;
	SCARD_READERSTATE* cur = NULL;
	SCARD_READERSTATE* rsCur = NULL;
	SCARD_READERSTATE* readerStates = NULL;
	SERVER_SCARD_ATRMASK* curAtr = NULL;
	SERVER_SCARD_ATRMASK* pAtrMasks = NULL;

	stream_seek(irp->input, 0x2C);
	stream_read_uint32(irp->input, hContext);
	stream_read_uint32(irp->input, atrMaskCount);

	pAtrMasks = xmalloc(atrMaskCount * sizeof(SERVER_SCARD_ATRMASK));

	if (!pAtrMasks)
		return sc_output_return(irp, SCARD_E_NO_MEMORY);

	for (i = 0; i < atrMaskCount; i++)
	{
		stream_read_uint32(irp->input, pAtrMasks[i].cbAtr);
		stream_read(irp->input, pAtrMasks[i].rgbAtr, 36);
		stream_read(irp->input, pAtrMasks[i].rgbMask, 36);
	}

	stream_read_uint32(irp->input, readerCount);

	readerStates = xzalloc(readerCount * sizeof(SCARD_READERSTATE));

	if (!readerStates)
		return sc_output_return(irp, SCARD_E_NO_MEMORY);

	for (i = 0; i < readerCount; i++)
	{
		cur = &readerStates[i];

		stream_seek(irp->input, 4);

		/*
		 * TODO: on-wire is little endian; need to either
		 * convert to host endian or fix the headers to
		 * request the order we want
		 */
		stream_read_uint32(irp->input, cur->dwCurrentState);
		stream_read_uint32(irp->input, cur->dwEventState);
		stream_read_uint32(irp->input, cur->cbAtr);
		stream_read(irp->input, cur->rgbAtr, 32);

		stream_seek(irp->input, 4);

		/* reset high bytes? */
		cur->dwCurrentState &= 0x0000FFFF;
		cur->dwEventState &= 0x0000FFFF;
		cur->dwEventState = 0;
	}

	for (i = 0; i < readerCount; i++)
	{
		cur = &readerStates[i];
		uint32 dataLength;

		stream_seek(irp->input, 8);
		stream_read_uint32(irp->input, dataLength);
		sc_input_repos(irp, sc_input_string(irp, (char **) &cur->szReader, dataLength, wide));

		DEBUG_SCARD("   \"%s\"", cur->szReader ? cur->szReader : "NULL");
		DEBUG_SCARD("       user: 0x%08x, state: 0x%08x, event: 0x%08x",
				(unsigned) cur->pvUserData, (unsigned) cur->dwCurrentState,
				(unsigned) cur->dwEventState);

		if (strcmp(cur->szReader, "\\\\?PnP?\\Notification") == 0)
			cur->dwCurrentState |= SCARD_STATE_IGNORE;
	}

	rv = SCardGetStatusChange(hContext, 0x00000001, readerStates, readerCount);
	if (rv != SCARD_S_SUCCESS)
	{
		DEBUG_SCARD("Failure: %s (0x%08x)",
			pcsc_stringify_error(rv), (unsigned) rv);

		return sc_output_return(irp, rv);
	}

	DEBUG_SCARD("Success");
	for (i = 0, curAtr = pAtrMasks; i < atrMaskCount; i++, curAtr++)
	{
		for (j = 0, rsCur = readerStates; j < readerCount; j++, rsCur++)
		{
			boolean equal = 1;
			for (k = 0; k < cur->cbAtr; k++)
			{
				if ((curAtr->rgbAtr[k] & curAtr->rgbMask[k]) !=
				    (rsCur->rgbAtr[k] & curAtr->rgbMask[k]))
				{
					equal = 0;
					break;
				}
			}
			if (equal)
			{
				rsCur->dwEventState |= 0x00000040;	/* SCARD_STATE_ATRMATCH 0x00000040 */
			}
		}
	}

	stream_write_uint32(irp->output, readerCount);
	stream_write_uint32(irp->output, 0x00084dd8);
	stream_write_uint32(irp->output, readerCount);

	for (i = 0, rsCur = readerStates; i < readerCount; i++, rsCur++)
	{
		stream_write_uint32(irp->output, cur->dwCurrentState);
		stream_write_uint32(irp->output, cur->dwEventState);
		stream_write_uint32(irp->output, cur->cbAtr);
		stream_write(irp->output, cur->rgbAtr, 32);

		stream_write_zero(irp->output, 4);

		xfree((void*) cur->szReader);
	}

	sc_output_alignment(irp, 8);

	free(readerStates);

	return rv;
}
Beispiel #7
0
void PCSCResourceManager::run()
{
    SCARDCONTEXT context;
    LONG rv;

    while (true)
    {
        rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &context);

        if (rv == SCARD_S_SUCCESS)
        {
            DWORD readerNum = SCARD_AUTOALLOCATE;
            LPSTR readerNames = NULL;

            do
            {
                rv = SCardListReaders(context, NULL, (LPSTR) &readerNames, &readerNum);

                if (rv == SCARD_S_SUCCESS)
                {
                    for (LPCSTR pch = readerNames; *pch != '\0'; pch += strlen(pch) + 1)
                    {
                        int i;
                        for (i = 0; i < m_availabeReaders.size(); i++)
                            if (0 == strcmp(m_availabeReaders[i]->name(), pch))
                                break;

                        if (i == m_availabeReaders.size())
                        {
                                SCardReader *reader = new SCardReader(pch);
                                m_availabeReaders.append(reader);
                                connect(reader, SIGNAL(unavailable(LPCSTR)), SLOT(clearUnavailabeReader(LPCSTR)));
                                reader->start();

                                emit readerPluged(reader);
                        }
                    }

                    (void) SCardFreeMemory(context, readerNames);
                }
                else
                    std::cout << pcsc_stringify_error(rv) << std::endl;

                if (rv == SCARD_S_SUCCESS || rv == SCARD_E_NO_READERS_AVAILABLE)
                {
                    SCARD_READERSTATE readerStates;

                    readerStates.szReader = "\\\\?PnP?\\Notification";
                    readerStates.dwCurrentState = SCARD_STATE_UNAWARE;

                    rv = SCardGetStatusChange(context, INFINITE, &readerStates, 1);

                    if (rv != SCARD_E_TIMEOUT || rv != SCARD_S_SUCCESS)
                    {
                        (void) SCardReleaseContext(context);
                        break;
                    }
                }
                else
                {
                    (void) SCardReleaseContext(context);
                    break;
                }
            } while (true);
        }
        else
        {
            std::cout << pcsc_stringify_error(rv) << std::endl;
            QThread::sleep(PCSC_ERROR_BREAK_TIME);
        }
    }
}
int main(void)
{
	unsigned char cmd1[] = { 0x00, 0xa4, 0x04, 0x00, 0x0a, 0xa0, 0x00, 0x00, 0x00, 0x63, 0x86, 0x53, 0x49, 0x44, 0x01};
	unsigned char cmd2[] = { 0x80, 0x56, 0x00, 0x00, 0x04 };
	unsigned char cmd3[] = { 0x80, 0x48, 0x00, 0x00, 0x04, 0xff, 0xff, 0xff, 0xff };
	unsigned char cmd4[] = { 0x80, 0x44, 0x00, 0x00, 0x05};
	LONG rv;
	SCARDCONTEXT hContext;
	DWORD dwReaders;
	LPSTR mszReaders = NULL;
	char **readers = NULL;
	SCARDHANDLE hCard;
	DWORD dwActiveProtocol;
	unsigned char bRecvBuffer[MAX_BUFFER_SIZE];
	DWORD length;
	SCARD_IO_REQUEST pioRecvPci;
 	SCARD_IO_REQUEST pioSendPci;

	rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext);
	if (rv != SCARD_S_SUCCESS)
	{
		printf("SCardEstablishContext: Cannot Connect to Resource Manager %"LF"X\n", rv);
		return 1;
	}

	/* Retrieve the available readers list */
	rv = SCardListReaders(hContext, NULL, NULL, &dwReaders);
	PCSC_ERROR_EXIT(rv, "SCardListReader");

	if (dwReaders < 4)
	{
		printf("No reader found!\n");
		return -1;
	}

	mszReaders = malloc(sizeof(char)*dwReaders);
	if (mszReaders == NULL)
	{
		printf("malloc: not enough memory\n");
		goto end;
	}

	rv = SCardListReaders(hContext, NULL, mszReaders, &dwReaders);
	PCSC_ERROR_EXIT(rv, "SCardListReader");

	/* connect to the first reader */
	dwActiveProtocol = -1;
	rv = SCardConnect(hContext, mszReaders, SCARD_SHARE_EXCLUSIVE,
		SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, &hCard, &dwActiveProtocol);
	PCSC_ERROR_EXIT(rv, "SCardConnect")

    switch(dwActiveProtocol)
    {
        case SCARD_PROTOCOL_T0:
            pioSendPci = *SCARD_PCI_T0;
            break;
        case SCARD_PROTOCOL_T1:
            pioSendPci = *SCARD_PCI_T1;
            break;
        default:
            printf("Unknown protocol\n");
            return -1;
    }

	/* APDU select applet */
	length = sizeof(bRecvBuffer);
	rv = SCardTransmit(hCard, &pioSendPci, cmd1, sizeof cmd1,
		&pioRecvPci, bRecvBuffer, &length);
	PCSC_ERROR_EXIT(rv, "SCardTransmit")
	if ((length != 2) || (bRecvBuffer[0] != 0x90) || (bRecvBuffer[1] != 0x00))
	{
		printf("cmd1 failed (%"LF"d): %02X%02X\n", length, bRecvBuffer[length-2],
			bRecvBuffer[length-1]);
		goto end;
	}

	/* non ISO APDU */
	length = sizeof(bRecvBuffer);
	rv = SCardTransmit(hCard, &pioSendPci, cmd2, sizeof cmd2,
		&pioRecvPci, bRecvBuffer, &length);
	PCSC_ERROR_EXIT(rv, "SCardTransmit")
	if ((length != 6) || (bRecvBuffer[4] != 0x90) || (bRecvBuffer[5] != 0x00))
	{
		printf("cmd2 failed (%"LF"d) : %02X%02X\n", length,
			bRecvBuffer[length-2], bRecvBuffer[length-1]);
		goto end;
	}

	/* get the argument for cmd3 from result of cmd2 */
	memcpy(cmd3+5, bRecvBuffer, 4);

	/* non ISO APDU */
	length = sizeof(bRecvBuffer);
	rv = SCardTransmit(hCard, &pioSendPci, cmd3, sizeof cmd3,
		&pioRecvPci, bRecvBuffer, &length);
	PCSC_ERROR_EXIT(rv, "SCardTransmit")
	if ((length != 2) || (bRecvBuffer[0] != 0x90) || (bRecvBuffer[1] != 0x00))
	{
		printf("cmd3 failed (%"LF"d): %02X%02X\n", length, bRecvBuffer[length-2],
			bRecvBuffer[length-1]);
		goto end;
	}

	/* non iSO APDU */
	length = sizeof(bRecvBuffer);
	rv = SCardTransmit(hCard, &pioSendPci, cmd4, sizeof cmd4,
		&pioRecvPci, bRecvBuffer, &length);
	PCSC_ERROR_EXIT(rv, "SCardTransmit")
	if ((length != 7) || (bRecvBuffer[5] != 0x90) || (bRecvBuffer[6] != 0x00))
	{
		printf("cmd4 failed (%"LF"d): %02X%02X\n", length, bRecvBuffer[length-2],
			bRecvBuffer[length-1]);
		goto end;
	}

	printf("%02X%02X%02X\n", bRecvBuffer[2], bRecvBuffer[3], bRecvBuffer[4]);

end:
	/* We try to leave things as clean as possible */
    rv = SCardReleaseContext(hContext);
    if (rv != SCARD_S_SUCCESS)
        printf("SCardReleaseContext: %s (0x%"LF"X)\n", pcsc_stringify_error(rv),
            rv);

    /* free allocated memory */
    free(mszReaders);
    free(readers);

	return 0;
} /* main */
static unsigned short pcsc_transmit(cardreader_t* cr,
                                    const bytestring_t* command,
                                    bytestring_t* result)
{
    pcsc_data_t* pcsc = cr->extra_data;
    BYTE REC_DAT[MAX_PCSC_READ_LENGTH];
    DWORD REC_LEN=MAX_PCSC_READ_LENGTH;
    unsigned short SW;

    if (cr->protocol==SCARD_PROTOCOL_T0)
    {
        pcsc->status = SCardTransmit(pcsc->hcard,SCARD_PCI_T0,
                bytestring_get_data(command),
                bytestring_get_size(command),
                SCARD_PCI_NULL,
                REC_DAT,&REC_LEN);
    }
    else if (cr->protocol==SCARD_PROTOCOL_T1)
    {
        pcsc->status = SCardTransmit(pcsc->hcard,SCARD_PCI_T1,
                bytestring_get_data(command),
                bytestring_get_size(command),
                SCARD_PCI_NULL,
                REC_DAT,&REC_LEN);

    }
    else
    {
        log_printf(LOG_ERROR,"Unknown smartcard protocol: %i",cr->protocol);
        return CARDPEEK_ERROR_SW;
    }

    if (pcsc->status!=SCARD_S_SUCCESS)
    {
        log_printf(LOG_ERROR,"Failed to transmit command to card: %s (error 0x%08x).",
                pcsc_stringify_error(pcsc->status),
                pcsc->status );
        return CARDPEEK_ERROR_SW;
    }

    if (REC_LEN>=2)
    {
        bytestring_assign_data(result,REC_LEN-2,REC_DAT);
        SW = (REC_DAT[REC_LEN-2]<<8)|REC_DAT[REC_LEN-1];
    }
    else if (REC_LEN==1)
    {
        bytestring_clear(result);
        SW = REC_DAT[0];
    }
    else
    {
        log_printf(LOG_ERROR,"Transmited %i bytes to the card (%s), but recieved a response of length %i, without any status word included.",
                bytestring_get_size(command),
                pcsc_stringify_protocol(cr->protocol),
                REC_LEN);
        return CARDPEEK_ERROR_SW;
    }

    return SW;
}
static int pcsc_connect(cardreader_t *cr, unsigned prefered_protocol)
{
    DWORD attr_maxinput = 0;
    DWORD attr_maxinput_len = sizeof(unsigned int);
    SCARD_READERSTATE reader_state;
    pcsc_data_t* pcsc = cr->extra_data;
    int counter = 0;
    void *progress;

    memset(&reader_state,0,sizeof(reader_state));
    reader_state.szReader = cr->name+7;
    reader_state.dwCurrentState = SCARD_STATE_UNAWARE;
    pcsc->status = SCardGetStatusChange(pcsc->hcontext,INFINITE,&reader_state,1);

    if (pcsc->status != SCARD_S_SUCCESS)
    {
        log_printf(LOG_ERROR,"Failed to query reader status before connecting: %s (error 0x%08x).",
                pcsc_stringify_error(pcsc->status),
                pcsc->status );
        return 0;
    }

    progress = ui_inprogress_new("Connection","Waiting for the reader to connect to a card.");
    while ((reader_state.dwEventState & SCARD_STATE_PRESENT)==0)
    {
        reader_state.dwCurrentState = reader_state.dwEventState;
        if (((counter++)%30)==0)
        {
            log_printf(LOG_INFO,"Waiting for card to be present (current state: %s)...",
                    pcsc_stringify_state(reader_state.dwEventState));
        }

        if (!ui_inprogress_pulse(progress))
        {
            log_printf(LOG_ERROR,"Connection aborted by user");
            ui_inprogress_free(progress);
            pcsc->status = 0x6FFF;
            return 0;	    
        }

        pcsc->status = SCardGetStatusChange(pcsc->hcontext,100,&reader_state,1);
        if ((pcsc->status!=(LONG)SCARD_S_SUCCESS) && (pcsc->status!=(LONG)SCARD_E_TIMEOUT))
        {
            log_printf(LOG_ERROR,"Failed to query reader status change before connecting: %s (error 0x%08x/%08x).",
                    pcsc_stringify_error(pcsc->status),
                    pcsc->status,
                    SCARD_E_TIMEOUT );
            return 0;
        }
    }
    ui_inprogress_free(progress);

    log_printf(LOG_DEBUG,"Attempting to connect to '%s'",cr->name);
    pcsc->status = SCardConnect(pcsc->hcontext,
            cr->name+7,
            /* SCARD_SHARE_EXCLUSIVE, */
            SCARD_SHARE_SHARED,
            prefered_protocol,
            &(pcsc->hcard),
            &(cr->protocol));

    if (pcsc->status!=SCARD_S_SUCCESS)
    {
        log_printf(LOG_ERROR,"Connection failed: %s (error 0x%08x).",
                pcsc_stringify_error(pcsc->status),
                pcsc->status );
        return 0;
    }

    if (SCardGetAttrib(pcsc->hcard,SCARD_ATTR_MAXINPUT,(LPBYTE)&attr_maxinput,(LPDWORD)&attr_maxinput_len)==SCARD_S_SUCCESS)
        log_printf(LOG_INFO,"Reader maximum input length is %u bytes",attr_maxinput);
    else
        log_printf(LOG_DEBUG,"Could not determinate reader maximum input length");

    log_printf(LOG_INFO,"Connection successful, protocol is %s",pcsc_stringify_protocol(cr->protocol));
    cr->connected=1;

    return 1;
}
Beispiel #11
0
int
main(int argc, char *argv[])
{
  LONG rv;
  SCARDCONTEXT hContext;
  SCARDHANDLE hCard;
  char *reader;
  BYTE pbSendBuffer[1 + 1 + sizeof(nfc_connstring)];
  DWORD dwSendLength;
  BYTE pbRecvBuffer[1];
  DWORD dwActiveProtocol, dwRecvLength, dwReaders;
  char* mszReaders = NULL;

  if (argc == 1 ||
      (argc == 2 && (strncmp(argv[1], "yes", strlen("yes")) == 0)))
    pbSendBuffer[0] = IFDNFC_SET_ACTIVE;
  else if (argc == 2 && (strncmp(argv[1], "no", strlen("no")) == 0))
    pbSendBuffer[0] = IFDNFC_SET_INACTIVE;
  else if (argc == 2 && (strncmp(argv[1], "se", strlen("se")) == 0))
    pbSendBuffer[0] = IFDNFC_SET_ACTIVE_SE;
  else if (argc == 2 && (strncmp(argv[1], "status", strlen("status")) == 0))
    pbSendBuffer[0] = IFDNFC_GET_STATUS;
  else {
    printf("Usage: %s [yes|no|status]\n", argv[0]);
    exit(EXIT_FAILURE);
  }


  rv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &hContext);
  if (rv < 0)
    goto pcsc_error;

  dwReaders = 0;
  // Ask how many bytes readers list take
  rv = SCardListReaders(hContext, NULL, NULL, &dwReaders);
  if (rv < 0)
    goto pcsc_error;
  // Then allocate and fill mszReaders
  mszReaders = malloc(dwReaders);
  rv = SCardListReaders(hContext, NULL, mszReaders, &dwReaders);
  if (rv < 0)
    goto pcsc_error;

  int l;
  for (reader = mszReaders;
       dwReaders > 0;
       l = strlen(reader) + 1, dwReaders -= l, reader += l) {
    if (strcmp(IFDNFC_READER_NAME, reader) <= 0)
      break;
  }
  if (dwReaders <= 0) {
    printf("Could not find a reader named: %s\n", IFDNFC_READER_NAME);
    rv = SCARD_E_NO_READERS_AVAILABLE;
    goto pcsc_error;
  }

  // TODO Handle multiple ifdnfc instance for multiple NFC device ?
  rv = SCardConnect(hContext, reader, SCARD_SHARE_DIRECT, 0, &hCard,
                    &dwActiveProtocol);
  if (rv < 0)
    goto pcsc_error;

  if ((pbSendBuffer[0] == IFDNFC_SET_ACTIVE) || (pbSendBuffer[0] == IFDNFC_SET_ACTIVE_SE))  {
    const BYTE command = pbSendBuffer[0];
    // To correctly probe NFC devices, ifdnfc must be disactivated first
    pbSendBuffer[0] = IFDNFC_SET_INACTIVE;
    dwSendLength = 1;
    rv = SCardControl(hCard, IFDNFC_CTRL_ACTIVE, pbSendBuffer,
                      dwSendLength, pbRecvBuffer, sizeof(pbRecvBuffer),
                      &dwRecvLength);
    if (rv < 0) {
      goto pcsc_error;
    }

    pbSendBuffer[0] = command;
    // Initialize libnfc
    nfc_init(NULL);
    // Allocate nfc_connstring array
    nfc_connstring connstrings[MAX_DEVICE_COUNT];
    // List devices
    size_t szDeviceFound = nfc_list_devices(NULL, connstrings, MAX_DEVICE_COUNT);

    int connstring_index = -1;
    switch (szDeviceFound) {
      case 0:
        fprintf(stderr, "Unable to activate ifdnfc: no NFC device found.\n");
        nfc_exit(NULL);
        goto error;
        break;
      case 1:
        // Only one NFC device available, so auto-select it!
        connstring_index = 0;
        break;
      default:
        // More than one available NFC devices, purpose a shell menu:
        printf("%d NFC devices found, please select one:\n", (int)szDeviceFound);
        for (size_t i = 0; i < szDeviceFound; i++) {
          nfc_device *pnd = nfc_open(NULL, connstrings[i]);
          if (pnd != NULL) {
            printf("[%d] %s\t  (%s)\n", (int)i, nfc_device_get_name(pnd), nfc_device_get_connstring(pnd));
            nfc_close(pnd);
          } else {
            fprintf(stderr, "nfc_open failed for %s\n", connstrings[i]);
          }
        }
        // libnfc isn't be needed anymore
        nfc_exit(NULL);
        printf(">> ");
        // Take user's choice
        if (1 != scanf("%d", &connstring_index)) {
          fprintf(stderr, "Value must an integer.\n");
          goto error;
        }
        if ((connstring_index < 0) || (connstring_index >= (int)szDeviceFound)) {
          fprintf(stderr, "Invalid index selection.\n");
          goto error;
        }
        break;
    }
    printf("Activating ifdnfc with \"%s\"...\n", connstrings[connstring_index]);
    // pbSendBuffer = { IFDNFC_SET_ACTIVE (1 byte), length (2 bytes), nfc_connstring (lenght bytes)}
    const uint16_t u16ConnstringLength = strlen(connstrings[connstring_index]) + 1;
    memcpy(pbSendBuffer + 1, &u16ConnstringLength, sizeof(u16ConnstringLength));
    memcpy(pbSendBuffer + 1 + sizeof(u16ConnstringLength), connstrings[connstring_index], u16ConnstringLength);
    dwSendLength = 1 + sizeof(u16ConnstringLength) + u16ConnstringLength;
  } else {
    // pbSendBuffer[0] != IFDNFC_SET_ACTIVE
    dwSendLength = 1;
  }

  rv = SCardControl(hCard, IFDNFC_CTRL_ACTIVE, pbSendBuffer,
                    dwSendLength, pbRecvBuffer, sizeof(pbRecvBuffer),
                    &dwRecvLength);
  if (rv < 0) {
    goto pcsc_error;
  }
  if (dwRecvLength < 1) {
    rv = SCARD_F_INTERNAL_ERROR;
    goto pcsc_error;
  }

  switch (pbRecvBuffer[0]) {
    case IFDNFC_IS_ACTIVE: {
      uint16_t u16ConnstringLength;
      if (dwRecvLength < (1 + sizeof(u16ConnstringLength))) {
        rv = SCARD_F_INTERNAL_ERROR;
        goto pcsc_error;
      }
      memcpy(&u16ConnstringLength, pbRecvBuffer + 1, sizeof(u16ConnstringLength));
      if ((dwRecvLength - (1 + sizeof(u16ConnstringLength))) != u16ConnstringLength) {
        rv = SCARD_F_INTERNAL_ERROR;
        goto pcsc_error;
      }
      nfc_connstring connstring;
      memcpy(connstring, pbRecvBuffer + 1 + sizeof(u16ConnstringLength), u16ConnstringLength);
      printf("%s is active using %s.\n", IFDNFC_READER_NAME, connstring);
    }
    break;
    case IFDNFC_IS_INACTIVE:
      printf("%s is inactive.\n", IFDNFC_READER_NAME);
      break;
    default:
      rv = SCARD_F_INTERNAL_ERROR;
      goto pcsc_error;
  }


  rv = SCardDisconnect(hCard, SCARD_LEAVE_CARD);
  if (rv < 0)
    goto pcsc_error;

  free(mszReaders);

  exit(EXIT_SUCCESS);

pcsc_error:
  puts(pcsc_stringify_error(rv));
error:
  if (mszReaders)
    free(mszReaders);

  exit(EXIT_FAILURE);
}
Beispiel #12
0
void SCardReader::run()
{
    SCARDCONTEXT context;
    SCARDHANDLE cardHandle;
    DWORD activeProtocol;
    DWORD oldEventState;
    LONG erv;

    erv = SCardEstablishContext(SCARD_SCOPE_SYSTEM, NULL, NULL, &context);
    if (SCARD_S_SUCCESS == erv)
    {
        LONG crv;

        crv = SCardConnect(context, (LPCSTR) m_name, SCARD_SHARE_SHARED,
                          SCARD_PROTOCOL_T0, &cardHandle, &activeProtocol);
        do
        {
            if (SCARD_S_SUCCESS == crv)
            {
                SCARD_IO_REQUEST ioRecvPci;
                BYTE recvBuffer[32];
                BYTE sendBuffer[] = {0xFF, 0xCA, 0x00, 0x00, 0x00};
                DWORD recvLength = sizeof(recvBuffer);
                LONG trv;

                trv = SCardTransmit(cardHandle, SCARD_PCI_T0, sendBuffer, sizeof(sendBuffer),&ioRecvPci, recvBuffer, &recvLength);
                if (SCARD_S_SUCCESS == trv)
                {
                    if (recvLength == 6 && recvBuffer[4] == 0x90 && recvBuffer[5] == 0x00)
                        m_cardid = (int)recvBuffer[0] | (int)recvBuffer[1] << 8 | (int)recvBuffer[2] << 16 | (int)recvBuffer[3] << 24;

                    std::cout <<  m_cardid  <<  " card inserted." << std::endl;

                    if (m_mode == TallyMode) // m_mode(DriverMode)  初始化为DriverMode
                    {
                        //load authentication key
                        recvLength = sizeof(recvBuffer);
                        BYTE loadKey[] = {0xFF, 0x82, 0x00, 0x00, 0x06, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
                        trv = SCardTransmit(cardHandle, SCARD_PCI_T0, loadKey, sizeof(loadKey), &ioRecvPci, recvBuffer, &recvLength);
                        if (SCARD_S_SUCCESS == trv && recvLength == 2 && recvBuffer[0] == 0x90 && recvBuffer[1] == 0x00)
                        {
                            //authentication key
                            recvLength = sizeof(recvBuffer);
                            BYTE authentication[] = {0xFF, 0x86, 0x00, 0x00, 0x05, 0x01, 0x00, 0x08, 0x60, 0x00};
                            trv = SCardTransmit(cardHandle, SCARD_PCI_T0, authentication, sizeof(authentication), &ioRecvPci, recvBuffer, &recvLength);
                            if (SCARD_S_SUCCESS == trv && recvLength == 2 && recvBuffer[0] == 0x90 && recvBuffer[1] == 0x00)
                            {
                                //read binary
                                recvLength = sizeof(recvBuffer);
                                BYTE read[] = {0xFF, 0xB0, 0x00, 0x08, 0x10};
                                trv = SCardTransmit(cardHandle, SCARD_PCI_T0, read, sizeof(read), &ioRecvPci, recvBuffer, &recvLength);
                                if (SCARD_S_SUCCESS == trv && recvLength == 18 && recvBuffer[16] == 0x90 && recvBuffer[17] == 0x00)
                                {
                                    QByteArray array((const char *)recvBuffer, 16);
                                    emit dataReady(QString::number(m_cardid), array);
                                }
                                else
                                    std::cerr << m_name << " : " << pcsc_stringify_error(trv) << std::endl;
                            }
                            else
                                std::cerr << m_name << " : " << pcsc_stringify_error(trv) << std::endl;
                        }
                        else
                            std::cerr << m_name << " : " << pcsc_stringify_error(trv) << std::endl;
                    }
                    else
                        emit inserted(QString::number(m_cardid));
                }
                else if (SCARD_E_NO_SMARTCARD == trv)
                    std::cerr << m_name << " : " << pcsc_stringify_error(trv) << std::endl;
                else
                {
                    std::cerr << m_name << " : " << pcsc_stringify_error(trv) << std::endl;
                    break;
                }

                (void) SCardDisconnect(cardHandle, SCARD_RESET_CARD);
            }

            if (SCARD_S_SUCCESS == crv || SCARD_E_NO_SMARTCARD == crv)
            {
                SCARD_READERSTATE readerStates;
                LONG grv;

                readerStates.szReader = m_name;
                readerStates.dwCurrentState = SCARD_STATE_UNAWARE;
                grv = SCardGetStatusChange(context, INFINITE, &readerStates, 1);
                oldEventState = readerStates.dwEventState;

                do
                {
                    if (SCARD_S_SUCCESS == grv)
                    {
                        if (readerStates.dwEventState != oldEventState)
                        {
                            //card inserted
                            if  ((SCARD_STATE_CHANGED & readerStates.dwEventState) && (SCARD_STATE_PRESENT & readerStates.dwEventState))
                                break;

                            //card removed
                            if ((SCARD_STATE_CHANGED & readerStates.dwEventState) && (SCARD_STATE_EMPTY & readerStates.dwEventState))
                            {
                                removed(QString::number(m_cardid));
                                std::cout << m_cardid <<  " card removed." << std::endl;
                            }
                        }
                        else
                            QThread::usleep(500);
                    }
                    else if (SCARD_E_TIMEOUT == grv)
                        QThread::sleep(1);
                    else
                        break;

                    oldEventState = readerStates.dwEventState;

                    readerStates.szReader = m_name;
                    readerStates.dwCurrentState = SCARD_STATE_UNAWARE;

                    grv = SCardGetStatusChange(context, INFINITE, &readerStates, 1);

                } while (true);

                //quit if fatal error occurs
                if (SCARD_S_SUCCESS != grv)
                    break;
            }
            else
            {
                std::cerr << m_name << " : " << pcsc_stringify_error(crv) << std::endl;
                break;
            }

            crv = SCardConnect(context, (LPCSTR) m_name, SCARD_SHARE_SHARED,
                              SCARD_PROTOCOL_T0, &cardHandle, &activeProtocol);

        } while(true);
    }
    else
        std::cerr << m_name << " : " << pcsc_stringify_error(erv) << std::endl;

    std::cout << m_name << " deamon thread has exit." << std::endl;
}
int
main (int argc, const char *argv[])
{
   char *pin = 0;
   char *chal = 0;
   char *reader = 0;
   char *amount = 0;
   int getid = 0;
   int getotp = 0;
   int readernum = 0;
   int debug = 0;
   int listreader = 0;
   int hyphen = 0;
   int res;
   char c;
   SCARDCONTEXT ctx;
   SCARDHANDLE card;
   BYTE atr[MAX_ATR_SIZE];
   DWORD atrlen;
   DWORD state;
   DWORD proto;
   DWORD temp;
   SCARD_IO_REQUEST recvpci;
   DWORD buflen;
   BYTE buf[256],
     cmd[256];

   poptContext optCon;          // context for parsing command-line options
   const struct poptOption optionsTable[] = {
      {"id", 'i', POPT_ARG_NONE, &getid, 0, "Report card ID", 0},
      {"pin", 'p', POPT_ARG_STRING, &pin, 0, "PIN", "6 to 12 digits"},
      {"otp", 'o', POPT_ARG_NONE, &getotp, 0, "Get OTP", 0},
      {"reference", 'c', POPT_ARG_STRING, &chal, 0, "Challenge/response or account reference", "Up to 8 digit reference/account"},
      {"amount", 'a', POPT_ARG_STRING, &amount, 0, "", "Amount pounds.pence"},
      {"reader", 'r', POPT_ARG_INT, &readernum, 0, "Which reader to use", "Index number"},
      {"list", 'l', POPT_ARG_NONE, &listreader, 0, "List readers", 0},
      {"hyphen", 'h', POPT_ARG_NONE, &hyphen, 0, "Hyphenate OTP or C/R responses", 0},
      {"debug", 'v', POPT_ARG_NONE, &debug, 0, "Debug output", 0},
      POPT_AUTOHELP {NULL, 0, 0, NULL, 0}
   };

   optCon = poptGetContext (NULL, argc, argv, optionsTable, 0);
   //poptSetOtherOptionHelp (optCon, "");

   /* Now do options processing, get portname */
   if ((c = poptGetNextOpt (optCon)) < -1)
   {
      /* an error occurred during option processing */
      fprintf (stderr, "%s: %s\n", poptBadOption (optCon, POPT_BADOPTION_NOALIAS), poptStrerror (c));
      return 1;
   }
   if (poptPeekArg (optCon))
   {
      poptPrintUsage (optCon, stderr, 0);
      return 2;
   }
   if ((res = SCardEstablishContext (SCARD_SCOPE_SYSTEM, NULL, NULL, &ctx)) != SCARD_S_SUCCESS)
      errx (1, "Can't establish context for reading cards (%s)", pcsc_stringify_error (res));

   {                            // list the readers
      int rn = 0;
      char *r,
       *e;
      if ((res = SCardListReaders (ctx, NULL, NULL, &temp)) != SCARD_S_SUCCESS)
         errx (1, "Cannot get reader list (%s)", pcsc_stringify_error (res));
      if (!(r = malloc (temp)))
         errx (1, "Cannot allocated %d bytes for reader list", (int) temp);
      if ((res = SCardListReaders (ctx, NULL, r, &temp)) != SCARD_S_SUCCESS)
         errx (1, "Cannot list readers (%s)", pcsc_stringify_error (res));
      e = r + temp;
      while (*r && r < e)
      {
         if (rn == readernum)
            reader = r;
         if (listreader)
            printf ("%d: %s\n", rn, r);
         r += strlen (r) + 1;
         rn++;
      }
      // not freed as reader is pointer into r.
   }
   if (!reader)
      errx (1, "Reader %d does not exist", readernum);
   if (debug)
      fprintf (stderr, "Reader: %s\n", reader);

   // connect to card
   if ((res =
        SCardConnect (ctx, reader, SCARD_SHARE_EXCLUSIVE, SCARD_PROTOCOL_T0 | SCARD_PROTOCOL_T1, &card, &proto)) != SCARD_S_SUCCESS)
      errx (1, "Cannot connect to %s (%s)", reader, pcsc_stringify_error (res));
   if (debug)
      fprintf (stderr, "Active protocol %X\n", (int) proto);

   if ((res = SCardBeginTransaction (card)) != SCARD_S_SUCCESS)
      errx (1, "Cannot start transaction (%s)", pcsc_stringify_error (res));

   atrlen = sizeof (atr);
   if ((res = SCardStatus (card, 0, &temp, &state, &proto, atr, &atrlen)) != SCARD_S_SUCCESS)
      errx (1, "Cannot get card status (%s)", pcsc_stringify_error (res));
   if (debug)
      fprintf (stderr, "ATR len %d state %X\n", (int) atrlen, (int) state);

   {                            // get basic data
      BYTE datareq[] = { 0x00, 0xA4, 0x04, 0x00, 0x07, 0xA0, 0x00, 0x00, 0x00, 0x03, 0x80, 0x02 };      // initial data request
      buflen = sizeof (buf);
      if (debug)
         dump ('>', sizeof (datareq), datareq);
      if ((res = SCardTransmit (card, SCARD_PCI_T0, datareq, sizeof (datareq), &recvpci, buf, &buflen)) != SCARD_S_SUCCESS)
         errx (1, "Failed to send initial request for data (%s)", pcsc_stringify_error (res));
      if (debug)
         dump ('<', buflen, buf);
      if (buflen != 2 || buf[0] != 0x61)
         errx (1, "Unexpected response to data request");
   }

   cmd[0] = 0x0;
   cmd[1] = 0xC0;
   cmd[2] = 0;
   cmd[3] = 0;
   cmd[4] = buf[1];
   buflen = sizeof (buf);
   if (debug)
      dump ('>', 5, cmd);
   if ((res = SCardTransmit (card, SCARD_PCI_T0, cmd, 5, &recvpci, buf, &buflen)) != SCARD_S_SUCCESS)
      errx (1, "Failed get initial data (%s)", pcsc_stringify_error (res));
   if (debug)
      dump ('<', buflen, buf);
   if (buflen != cmd[4] + 2)
      errx (1, "Did not get right data length %d!=%d", (int) buflen, cmd[4]);

   cmd[0] = 0x80;
   cmd[1] = 0xA8;
   cmd[2] = 0x00;
   cmd[3] = 0x00;
   cmd[4] = 0x02;
   cmd[5] = 0x83;
   cmd[6] = 0x00;
   buflen = sizeof (buf);
   if (debug)
      dump ('>', 7, cmd);
   if ((res = SCardTransmit (card, SCARD_PCI_T0, cmd, 7, &recvpci, buf, &buflen)) != SCARD_S_SUCCESS)
      errx (1, "Failed get data (%s)", pcsc_stringify_error (res));
   if (debug)
      dump ('<', buflen, buf);
   if (buflen != 2 || buf[0] != 0x61)
      errx (1, "Bad response\n");

   cmd[0] = 0x00;
   cmd[1] = 0xC0;
   cmd[2] = 0x00;
   cmd[3] = 0x00;
   cmd[4] = buf[1];
   buflen = sizeof (buf);
   if (debug)
      dump ('>', 5, cmd);
   if ((res = SCardTransmit (card, SCARD_PCI_T0, cmd, 5, &recvpci, buf, &buflen)) != SCARD_S_SUCCESS)
      errx (1, "Failed to send data (%s)", pcsc_stringify_error (res));
   if (debug)
      dump ('<', buflen, buf);

   if (getid)
   {                            // card number
      int n = 0;
      cmd[0] = 0x00;
      cmd[1] = 0xB2;
      cmd[2] = 0x02;
      cmd[3] = 0x0C;
      cmd[4] = 0x00;
      buflen = sizeof (buf);
      if (debug)
         dump ('>', 5, cmd);
      if ((res = SCardTransmit (card, SCARD_PCI_T0, cmd, 5, &recvpci, buf, &buflen)) != SCARD_S_SUCCESS)
         errx (1, "Failed to send data (%s)", pcsc_stringify_error (res));
      if (debug)
         dump ('<', buflen, buf);
      if (buflen != 2 || buf[0] != 0x6C)
         errx (1, "Unexpected response to data request");
      cmd[4] = buf[1];
      buflen = sizeof (buf);
      if (debug)
         dump ('>', 5, cmd);
      if ((res = SCardTransmit (card, SCARD_PCI_T0, cmd, 5, &recvpci, buf, &buflen)) != SCARD_S_SUCCESS)
         errx (1, "Failed get initial data (%s)", pcsc_stringify_error (res));
      if (debug)
         dump ('<', buflen, buf);
      if (buflen != cmd[4] + 2 || buflen < 12)
         errx (1, "Did not get right data length %d!=%d", (int) buflen, cmd[4]);
      for (n = 4; n < 12; n++)
         printf ("%02X", buf[n]);
      printf ("\n");
   }
   // send PIN if needed
   if (pin && (getotp || chal || amount || debug))
   {                            // send PIN
      char *p = pin;
      int n = 0;
      cmd[0] = 0;
      cmd[1] = 0x20;
      cmd[2] = 0x00;
      cmd[3] = 0x80;
      cmd[4] = 8;
      cmd[5] = 0x24;
      while (*p && n < 14)
      {
         if (isdigit (*p))
         {
            cmd[6 + n / 2] = (cmd[6 + n / 2] << 4) + (*p - '0');
            n++;
         }
         p++;
      }
      while (n < 14)
      {
         cmd[6 + n / 2] = (cmd[6 + n / 2] << 4) + 0xF;
         n++;
      }
      buflen = sizeof (buf);
      if (debug)
         dump ('>', 13, cmd);
      if ((res = SCardTransmit (card, SCARD_PCI_T0, cmd, 13, &recvpci, buf, &buflen)) != SCARD_S_SUCCESS)
         errx (1, "Failed to send PIN (%s)", pcsc_stringify_error (res));
      if (debug)
         dump ('<', buflen, buf);
      if (buflen != 2 || buf[0] != 0x90 || buf[1])
         errx (1, "PIN failed");
   }


   if (getotp || chal || amount)
   {                            // OTP
      unsigned char req[29] = { 0 };
      req[14] = 0x80;
      req[21] = req[22] = req[23] = 1;
      if (chal)
      {
         int n = 0,
            p;
         for (p = 0; chal[p]; p++)
            if (isdigit (chal[p]))
               n++;
         for (p = 0; chal[p] && n; p++)
            if (isdigit (chal[p]))
            {
               n--;
               if (n < 8)
                  req[28 - n / 2] |= ((chal[p] & 0xF) << ((n & 1) ? 4 : 0));
            }
      }
      if (amount)
      {
         int n = 0,
            p;
         for (p = 0; amount[p]; p++)
            if (isdigit (amount[p]))
               n++;
         for (p = 0; amount[p] && n; p++)
            if (isdigit (amount[p]))
            {
               n--;
               if (n < 12)
                  req[5 - n / 2] |= ((amount[p] & 0xF) << ((n & 1) ? 4 : 0));
            }
      }

      buflen = sizeof (buf);
      buf[0] = 0x80;
      buf[1] = 0xAE;
      buf[2] = 0x80;
      buf[3] = 0x00;
      buf[4] = sizeof (req);
      memcpy (buf + 5, req, sizeof (req));
      if (debug)
         dump ('>', sizeof (req) + 5, buf);
      if ((res = SCardTransmit (card, SCARD_PCI_T0, buf, sizeof (req) + 5, &recvpci, buf, &buflen)) != SCARD_S_SUCCESS)
         errx (1, "Failed to send OTP request (%s)", pcsc_stringify_error (res));
      if (debug)
         dump ('<', buflen, buf);
      if (buflen != 2 || buf[0] != 0x61)
         errx (1, "Failed to get OTP");
      cmd[0] = 0x00;
      cmd[1] = 0xC0;
      cmd[2] = 0x00;
      cmd[3] = 0x00;
      cmd[4] = buf[1];
      buflen = sizeof (buf);
      if (debug)
         dump ('>', 5, cmd);
      if ((res = SCardTransmit (card, SCARD_PCI_T0, cmd, 5, &recvpci, buf, &buflen)) != SCARD_S_SUCCESS)
         errx (1, "Failed to send OTP request (%s)", pcsc_stringify_error (res));
      if (debug)
         dump ('<', buflen, buf);
      if (buflen != 22)
         errx (1, "Bad OTP response");
      {
         unsigned long res = ((1 << 25) | (buf[4] << 17) | ((buf[10] & 0x01) << 16) | (buf[11] << 8) | buf[12]);
         printf ("%08lu\n", res);
      }

      // Advance OTP to next number
      buf[0] = 0x80;
      buf[1] = 0xAE;
      buf[2] = 0x00;
      buf[3] = 0x00;
      buf[4] = sizeof (req) + 2;
      buf[5] = 0x5A;
      buf[6] = 0x33;
      memcpy (buf + 7, req, sizeof (req));
      buflen = sizeof (buf);
      if (debug)
         dump ('>', sizeof (req) + 7, buf);
      if ((res = SCardTransmit (card, SCARD_PCI_T0, buf, sizeof (req) + 7, &recvpci, buf, &buflen)) != SCARD_S_SUCCESS)
         errx (1, "Failed to send OTP request (%s)", pcsc_stringify_error (res));
      if (debug)
         dump ('<', buflen, buf);
      if (buflen != 2 || buf[0] != 0x61)
         errx (1, "Failed to get OTP");
      cmd[0] = 0x00;
      cmd[1] = 0xC0;
      cmd[2] = 0x00;
      buflen = sizeof (buf);
      if (debug)
         dump ('>', 5, cmd);
      if ((res = SCardTransmit (card, SCARD_PCI_T0, cmd, 5, &recvpci, buf, &buflen)) != SCARD_S_SUCCESS)
         errx (1, "Failed to send OTP request (%s)", pcsc_stringify_error (res));
      if (debug)
         dump ('<', buflen, buf);
   }
   // Done
   if ((res = SCardEndTransaction (card, SCARD_UNPOWER_CARD)) != SCARD_S_SUCCESS)
      errx (1, "Cannot end transaction (%s)", pcsc_stringify_error (res));

   if ((res = SCardReleaseContext (ctx)) != SCARD_S_SUCCESS)
      errx (1, "Cant release context (%s)", pcsc_stringify_error (res));
   return 0;
}