Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

887 lines
18 KiB

//+-------------------------------------------------------------------------
//
// Microsoft Windows
//
// Copyright (C) Microsoft Corporation, 1998 - 1999
//
// File: ifdrdr.cpp
//
//--------------------------------------------------------------------------
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <conio.h>
#include <afx.h>
#include <afxtempl.h>
#include <winioctl.h>
#include <winsmcrd.h>
#include "ifdtest.h"
ULONG CReaderList::m_uRefCount;
ULONG CReaderList::m_uNumReaders;
CReaderList **CReaderList::m_pList;
static CString l_CEmpty("");
void
DumpData(
PCHAR in_pchCaption,
ULONG in_uIndent,
PBYTE in_pbData,
ULONG in_uLength)
{
ULONG l_uIndex, l_uLine, l_uCol;
printf("%s\n%*s%04x: ", in_pchCaption, in_uIndent, "", 0);
for (l_uLine = 0, l_uIndex = 0;
l_uLine < ((in_uLength - 1) / 8) + 1;
l_uLine++) {
for (l_uCol = 0, l_uIndex = l_uLine * 8;
l_uCol < 8; l_uCol++,
l_uIndex++) {
printf(
l_uIndex < in_uLength ? "%02x " : " ",
in_pbData[l_uIndex]
);
}
putchar(' ');
for (l_uCol = 0, l_uIndex = l_uLine * 8;
l_uCol < 8; l_uCol++,
l_uIndex++) {
printf(
l_uIndex < in_uLength ? "%c" : " ",
isprint(in_pbData[l_uIndex]) ? in_pbData[l_uIndex] : '.'
);
}
putchar('\n');
if (l_uIndex < in_uLength) {
printf("%*s%04x: ", in_uIndent, "", l_uIndex + 1);
}
}
}
CReaderList::CReaderList(
CString &in_CDeviceName,
CString &in_CPnPType,
CString &in_CVendorName,
CString &in_CIfdType
)
{
m_CDeviceName += in_CDeviceName;
m_CPnPType += in_CPnPType;
m_CVendorName += in_CVendorName;
m_CIfdType += in_CIfdType;
}
CString &
CReaderList::GetDeviceName(
ULONG in_uIndex
)
/*++
Routine Description:
Retrieves the device name of a reader
Arguments:
in_uIndex - index to reader list
Return Value:
The device name that can be used to open the reader
--*/
{
if (in_uIndex >= m_uNumReaders) {
return l_CEmpty;
}
return m_pList[in_uIndex]->m_CDeviceName;
}
CString &
CReaderList::GetIfdType(
ULONG in_uIndex
)
{
if (in_uIndex >= m_uNumReaders) {
return l_CEmpty;
}
return m_pList[in_uIndex]->m_CIfdType;
}
CString &
CReaderList::GetPnPType(
ULONG in_uIndex
)
{
if (in_uIndex >= m_uNumReaders) {
return l_CEmpty;
}
return m_pList[in_uIndex]->m_CPnPType;
}
CString &
CReaderList::GetVendorName(
ULONG in_uIndex
)
{
if (in_uIndex >= m_uNumReaders) {
return l_CEmpty;
}
return m_pList[in_uIndex]->m_CVendorName;
}
void
CReaderList::AddDevice(
CString in_CDeviceName,
CString in_CPnPType
)
/*++
Routine Description:
This functions tries to open the reader device supplied by
in_pchDeviceName. If the device exists it adds it to the list
of installed readers
Arguments:
in_pchDeviceName - reader device name
in_pchPnPType - type of reader (wdm-pnp, nt, win9x)
--*/
{
CReader l_CReader;
if (l_CReader.Open(in_CDeviceName)) {
if (l_CReader.GetVendorName().IsEmpty()) {
LogMessage(
"VendorName of reader device %s is NULL",
(LPCSTR) in_CDeviceName
);
} else if (l_CReader.GetIfdType().IsEmpty()) {
LogMessage(
"IfdType of reader device %s is NULL",
(LPCSTR) in_CDeviceName
);
} else {
CReaderList *l_CReaderList = new CReaderList(
in_CDeviceName,
in_CPnPType,
l_CReader.GetVendorName(),
l_CReader.GetIfdType()
);
// extend the device list array by one
CReaderList **l_pList =
new CReaderList *[m_uNumReaders + 1];
if (m_pList) {
// copy old list of readers to new list of readers
memcpy(
l_pList,
m_pList,
m_uNumReaders * sizeof(CReaderList *)
);
delete m_pList;
}
m_pList = l_pList;
m_pList[m_uNumReaders++] = l_CReaderList;
}
l_CReader.Close();
}
}
CReaderList::CReaderList()
/*++
Routine Description:
Constructor for CReaderList.
Builds a list of currently installed and running smart card readers.
It first tries to find all WDM PnP drivers. These should be registered
in the registry under the class guid for smart card readers.
Then it looks for all 'old style' reader names like \\.\SCReaderN
And then it looks for all Windows 9x VxD style readers, which are
registered in the registry through smclib.vxd
--*/
{
HKEY l_hKey;
ULONG l_uIndex;
m_uCurrentReader = (ULONG) -1;
if (m_uRefCount++ != 0) {
return;
}
// look up all WDM PnP smart card readers
if (RegOpenKey(
HKEY_LOCAL_MACHINE,
"System\\CurrentControlSet\\Control\\DeviceClasses\\{50DD5230-BA8A-11D1-BF5D-0000F805F530}",
&l_hKey) == ERROR_SUCCESS) {
ULONG l_uStatus, l_uIndex;
for (l_uIndex = 0; ;l_uIndex++) {
HKEY l_hDeviceTypeKey;
UCHAR l_rgchDeviceTypeKey[128];
ULONG l_uDeviceTypeInstance = 0;
// look up 'device type subkey'
l_uStatus = RegEnumKey(
l_hKey,
l_uIndex,
(PCHAR) l_rgchDeviceTypeKey,
sizeof(l_rgchDeviceTypeKey)
);
if (l_uStatus != ERROR_SUCCESS) {
// no smart card device types found
break;
}
// open the found 'device type subkey'
l_uStatus = RegOpenKey(
l_hKey,
(PCHAR) l_rgchDeviceTypeKey,
&l_hDeviceTypeKey
);
if (l_uStatus != ERROR_SUCCESS) {
continue;
}
for (l_uDeviceTypeInstance = 0; ; l_uDeviceTypeInstance++) {
DWORD l_dwKeyType;
HKEY l_hDeviceTypeInstanceKey;
UCHAR l_rgchDeviceName[128];
UCHAR l_rgchDeviceTypeInstanceKey[128];
ULONG l_uDeviceNameLen = sizeof(l_rgchDeviceName);
// look up device instance subkey
l_uStatus = RegEnumKey(
l_hDeviceTypeKey,
l_uDeviceTypeInstance,
(PCHAR) l_rgchDeviceTypeInstanceKey,
sizeof(l_rgchDeviceTypeInstanceKey)
);
if (l_uStatus != ERROR_SUCCESS) {
// no instance of the smart card reader type found
break;
}
// open the found 'device type instance subkey'
l_uStatus = RegOpenKey(
l_hDeviceTypeKey,
(PCHAR) l_rgchDeviceTypeInstanceKey,
&l_hDeviceTypeInstanceKey
);
if (l_uStatus != ERROR_SUCCESS) {
continue;
}
// get the name of the device
if (RegQueryValueEx(
l_hDeviceTypeInstanceKey,
"SymbolicLink",
NULL,
&l_dwKeyType,
l_rgchDeviceName,
&l_uDeviceNameLen) == ERROR_SUCCESS) {
AddDevice(l_rgchDeviceName, READER_TYPE_WDM);
}
}
}
}
// Now look up all non PnP readers
for (l_uIndex = 0; l_uIndex < MAXIMUM_SMARTCARD_READERS; l_uIndex++) {
UCHAR l_rgchDeviceName[128];
sprintf(
(PCHAR) l_rgchDeviceName,
"\\\\.\\SCReader%d",
l_uIndex
);
AddDevice(l_rgchDeviceName, READER_TYPE_NT);
}
// Add all Windows95 type readers to the list
if (RegOpenKey(
HKEY_LOCAL_MACHINE,
"System\\CurrentControlSet\\Services\\VxD\\Smclib\\Devices",
&l_hKey) == ERROR_SUCCESS) {
ULONG l_uIndex;
for (l_uIndex = 0; l_uIndex < MAXIMUM_SMARTCARD_READERS; l_uIndex++) {
UCHAR l_rgchDeviceName[128], l_rgchValueName[128];
DWORD l_dwValueType;
ULONG l_uDeviceNameLen = sizeof(l_rgchDeviceName);
ULONG l_uValueNameLen = sizeof(l_rgchValueName);
if (RegEnumValue(
l_hKey,
l_uIndex,
(PCHAR) l_rgchValueName,
&l_uValueNameLen,
NULL,
&l_dwValueType,
(PUCHAR) l_rgchDeviceName,
&l_uDeviceNameLen) == ERROR_SUCCESS) {
AddDevice(CString("\\\\.\\") + l_rgchDeviceName, READER_TYPE_VXD);
}
}
}
}
CReaderList::~CReaderList()
{
ULONG l_uIndex;
if (--m_uRefCount != 0) {
return;
}
for (l_uIndex = 0; l_uIndex < m_uNumReaders; l_uIndex++) {
delete m_pList[l_uIndex];
}
if (m_pList) {
delete m_pList;
}
}
// ****************************************************************************
// CReader methods
// ****************************************************************************
CReader::CReader(
void
)
{
m_uReplyBufferSize = sizeof(m_rgbReplyBuffer);
m_Ovr.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
ResetEvent(m_Ovr.hEvent);
m_OvrWait.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
ResetEvent(m_OvrWait.hEvent);
m_ScardIoRequest.dwProtocol = 0;
m_ScardIoRequest.cbPciLength = sizeof(m_ScardIoRequest);
m_fDump = FALSE;
}
void
CReader::Close(
void
)
{
#ifndef SIMULATE
CloseHandle(m_hReader);
#endif
}
CString &
CReader::GetIfdType(
void
)
{
ULONG l_uAttr = SCARD_ATTR_VENDOR_IFD_TYPE;
#ifdef SIMULATE
m_CIfdType = "DEBUG IfdType";
#endif
if (m_CIfdType.IsEmpty()) {
BOOL l_bResult = DeviceIoControl(
m_hReader,
IOCTL_SMARTCARD_GET_ATTRIBUTE,
(void *) &l_uAttr,
sizeof(ULONG),
m_rgbReplyBuffer,
sizeof(m_rgbReplyBuffer),
&m_uReplyLength,
&m_Ovr
);
if (l_bResult) {
m_rgbReplyBuffer[m_uReplyLength] = '\0';
m_CIfdType = m_rgbReplyBuffer;
}
}
return m_CIfdType;
}
LONG
CReader::GetState(
PULONG out_puState
)
{
SetLastError(0);
BOOL l_bResult = DeviceIoControl(
m_hReader,
IOCTL_SMARTCARD_GET_STATE,
NULL,
0,
(void *) out_puState,
sizeof(ULONG),
&m_uReplyLength,
&m_Ovr
);
return GetLastError();
}
CString &
CReader::GetVendorName(
void
)
{
ULONG l_uAttr = SCARD_ATTR_VENDOR_NAME;
#ifdef SIMULATE
m_CVendorName = "DEBUG Vendor";
#endif
if (m_CVendorName.IsEmpty()) {
BOOL l_bResult = DeviceIoControl(
m_hReader,
IOCTL_SMARTCARD_GET_ATTRIBUTE,
(void *) &l_uAttr,
sizeof(ULONG),
m_rgbReplyBuffer,
sizeof(m_rgbReplyBuffer),
&m_uReplyLength,
&m_Ovr
);
if (l_bResult) {
m_rgbReplyBuffer[m_uReplyLength] = '\0';
m_CVendorName = m_rgbReplyBuffer;
}
}
return m_CVendorName;
}
ULONG
CReader::GetDeviceUnit(
void
)
{
ULONG l_uAttr = SCARD_ATTR_DEVICE_UNIT;
BOOL l_bResult = DeviceIoControl(
m_hReader,
IOCTL_SMARTCARD_GET_ATTRIBUTE,
(void *) &l_uAttr,
sizeof(ULONG),
m_rgbReplyBuffer,
sizeof(m_rgbReplyBuffer),
&m_uReplyLength,
&m_Ovr
);
return (ULONG) *m_rgbReplyBuffer;
}
BOOL
CReader::Open(
void
)
{
if (m_CDeviceName.IsEmpty()) {
return FALSE;
}
// Try to open the reader.
m_hReader = CreateFile(
(LPCSTR) m_CDeviceName,
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
FILE_FLAG_OVERLAPPED,
NULL
);
if (m_hReader == INVALID_HANDLE_VALUE ) {
return FALSE;
}
return TRUE;
}
BOOL
CReader::Open(
CString & in_CDeviceName
)
{
// save the reader name
m_CDeviceName += in_CDeviceName;
#ifdef SIMULATE
return TRUE;
#endif
return Open();
}
LONG
CReader::PowerCard(
ULONG in_uMinorIoControl
)
/*++
Routine Description:
Cold resets the current card and sets the ATR
of the card in the reader class.
Return Value:
Returns the result of the DeviceIoControl call
--*/
{
BOOL l_bResult;
ULONG l_uReplyLength;
CHAR l_rgbAtr[SCARD_ATR_LENGTH];
SetLastError(0);
l_bResult = DeviceIoControl (
m_hReader,
IOCTL_SMARTCARD_POWER,
&in_uMinorIoControl,
sizeof(in_uMinorIoControl),
l_rgbAtr,
sizeof(l_rgbAtr),
&l_uReplyLength,
&m_Ovr
);
if (l_bResult == FALSE && GetLastError() == ERROR_IO_PENDING) {
SetLastError(0);
l_bResult = GetOverlappedResult(
m_hReader,
&m_Ovr,
&l_uReplyLength,
TRUE
);
}
if (GetLastError() == ERROR_SUCCESS) {
SetAtr((PBYTE) l_rgbAtr, l_uReplyLength);
}
return GetLastError();
}
LONG
CReader::SetProtocol(
const ULONG in_uProtocol
)
{
BOOL l_bResult;
m_ScardIoRequest.dwProtocol = in_uProtocol;
m_ScardIoRequest.cbPciLength = sizeof(SCARD_IO_REQUEST);
SetLastError(0);
l_bResult = DeviceIoControl (
m_hReader,
IOCTL_SMARTCARD_SET_PROTOCOL,
(void *) &in_uProtocol,
sizeof(ULONG),
m_rgbReplyBuffer,
sizeof(m_rgbReplyBuffer),
&m_uReplyLength,
&m_Ovr
);
if (l_bResult == FALSE && GetLastError() == ERROR_IO_PENDING) {
SetLastError(0);
l_bResult = GetOverlappedResult(
m_hReader,
&m_Ovr,
&m_uReplyLength,
TRUE
);
}
return GetLastError();
}
LONG
CReader::Transmit(
PUCHAR in_pchApdu,
ULONG in_uApduLength,
PUCHAR *out_pchReply,
PULONG out_puReplyLength
)
/*++
Routine Description:
Transmits an apdu using the currently connected reader
Arguments:
in_pchApdu - the apdu to send
in_uApduLength - the length of the apdu
out_pchReply - result returned from the reader/card
out_puReplyLength - pointer to store number of bytes returned
Return Value:
The nt-status code returned by the reader
--*/
{
BOOL l_bResult;
ULONG l_uBufferLength = m_ScardIoRequest.cbPciLength + in_uApduLength;
PUCHAR l_pchBuffer = new UCHAR [l_uBufferLength];
// Copy io-request header to request buffer
memcpy(
l_pchBuffer,
&m_ScardIoRequest,
m_ScardIoRequest.cbPciLength
);
// copy io-request header to reply buffer
memcpy(
m_rgbReplyBuffer,
&m_ScardIoRequest,
m_ScardIoRequest.cbPciLength
);
// append apdu to buffer
memcpy(
l_pchBuffer + m_ScardIoRequest.cbPciLength,
in_pchApdu,
in_uApduLength
);
if (m_fDump) {
DumpData(
"\n RequestData:",
3,
l_pchBuffer,
l_uBufferLength
);
}
SetLastError(0);
// send the request to the card
l_bResult = DeviceIoControl (
m_hReader,
IOCTL_SMARTCARD_TRANSMIT,
l_pchBuffer,
l_uBufferLength,
m_rgbReplyBuffer,
m_uReplyBufferSize,
&m_uReplyLength,
&m_Ovr
);
if (l_bResult == FALSE && GetLastError() == ERROR_IO_PENDING) {
// wait for result
SetLastError(0);
l_bResult = GetOverlappedResult(
m_hReader,
&m_Ovr,
&m_uReplyLength,
TRUE
);
}
if (m_fDump) {
printf(" IOCTL returned %lxh\n", GetLastError());
if (l_bResult) {
DumpData(
" ReplyData:",
3,
m_rgbReplyBuffer,
m_uReplyLength
);
}
printf("%*s", 53, "");
}
*out_pchReply = (PUCHAR) m_rgbReplyBuffer + m_ScardIoRequest.cbPciLength;
*out_puReplyLength = m_uReplyLength - m_ScardIoRequest.cbPciLength;
delete l_pchBuffer;
return GetLastError();
}
LONG
CReader::VendorIoctl(
CString &o_Answer
)
{
BOOL l_bResult = DeviceIoControl(
m_hReader,
CTL_CODE(FILE_DEVICE_SMARTCARD, 2048, METHOD_BUFFERED, FILE_ANY_ACCESS),
NULL,
NULL,
m_rgbReplyBuffer,
sizeof(m_rgbReplyBuffer),
&m_uReplyLength,
&m_Ovr
);
if (l_bResult) {
m_rgbReplyBuffer[m_uReplyLength] = '\0';
o_Answer = CString(m_rgbReplyBuffer);
}
return GetLastError();
}
LONG
CReader::WaitForCard(
const ULONG in_uWaitFor
)
{
BOOL l_bResult;
ULONG l_uReplyLength;
SetLastError(0);
l_bResult = DeviceIoControl (
m_hReader,
in_uWaitFor,
NULL,
0,
NULL,
0,
&l_uReplyLength,
&m_Ovr
);
if (l_bResult == FALSE && GetLastError() == ERROR_IO_PENDING) {
SetLastError(0);
l_bResult = GetOverlappedResult(
m_hReader,
&m_Ovr,
&l_uReplyLength,
TRUE
);
}
return GetLastError();
}
LONG
CReader::StartWaitForCard(
const ULONG in_uWaitFor
)
{
BOOL l_bResult;
ULONG l_uReplyLength;
ResetEvent(m_OvrWait.hEvent);
l_bResult = DeviceIoControl (
m_hReader,
in_uWaitFor,
NULL,
0,
NULL,
0,
&l_uReplyLength,
&m_OvrWait
);
return GetLastError();
}
LONG
CReader::FinishWaitForCard(
const BOOL in_bWait
)
{
BOOL l_bResult;
ULONG l_uReplyLength;
SetLastError(0);
l_bResult = GetOverlappedResult(
m_hReader,
&m_OvrWait,
&l_uReplyLength,
in_bWait
);
return GetLastError();
}