1377 lines
30 KiB
C
1377 lines
30 KiB
C
/*++
|
|
|
|
Copyright (c) 1997 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
smcvxd.c
|
|
|
|
Abstract:
|
|
|
|
This is the Windows 9x specific driver file for the smart card library.
|
|
The smart card library is actually more a library as a driver.
|
|
It contains support functions for smart card driver/reader systems.
|
|
This driver should be loaded through an entry in the registry.
|
|
|
|
Environment:
|
|
|
|
Windows 9x Static VxD
|
|
|
|
Notes:
|
|
|
|
Revision History:
|
|
|
|
- Created June 1997 by Klaus Schutz
|
|
|
|
--*/
|
|
|
|
#define _ISO_TABLES_
|
|
#define WIN40SERVICES
|
|
#include "..\..\inc\smclib.h"
|
|
|
|
#define REGISTRY_PATH_LEN 128
|
|
static PUCHAR DevicePath = "System\\CurrentControlSet\\Services\\VxD\\Smclib\\Devices";
|
|
static BOOLEAN DriverInitialized;
|
|
|
|
#include "errmap.h"
|
|
|
|
DWORD
|
|
_stdcall
|
|
SMCLIB_Init(void)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function will be called by the Windows Kernel upon init of this driver
|
|
|
|
Arguments:
|
|
|
|
-
|
|
|
|
Return Value:
|
|
|
|
VXD_SUCCESS - This driver loaded successfully
|
|
VXD_FAILURE - Load was not successful
|
|
|
|
--*/
|
|
{
|
|
if (DriverInitialized == FALSE) {
|
|
|
|
HANDLE hKey;
|
|
ULONG i;
|
|
|
|
DriverInitialized = TRUE;
|
|
|
|
SmartcardDebug(
|
|
DEBUG_DRIVER,
|
|
("%s(SMCLIB_Init): Enter. %s %s\n",
|
|
DRIVER_NAME,
|
|
__DATE__,
|
|
__TIME__)
|
|
);
|
|
|
|
//
|
|
// Delete old device names
|
|
//
|
|
if(_RegOpenKey(
|
|
HKEY_LOCAL_MACHINE,
|
|
DevicePath,
|
|
&hKey
|
|
) != ERROR_SUCCESS) {
|
|
|
|
SmartcardDebug(
|
|
DEBUG_ERROR,
|
|
("%s(SMCLIB_Init): Unable to open registry key\n",
|
|
DRIVER_NAME)
|
|
);
|
|
|
|
} else {
|
|
|
|
_RegDeleteKey(
|
|
hKey,
|
|
""
|
|
);
|
|
|
|
_RegCloseKey(hKey);
|
|
}
|
|
|
|
//
|
|
// Create new device sub-key
|
|
//
|
|
_RegCreateKey(
|
|
HKEY_LOCAL_MACHINE,
|
|
DevicePath,
|
|
&hKey
|
|
);
|
|
|
|
_RegCloseKey(hKey);
|
|
}
|
|
|
|
return(VXD_SUCCESS);
|
|
}
|
|
|
|
ULONG
|
|
SMCLIB_MapNtStatusToWinError(
|
|
NTSTATUS status
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Maps a NT status code to a Win32 error value
|
|
|
|
Arguments:
|
|
|
|
status - nt status code to map to a Win32 error value
|
|
|
|
Return Value:
|
|
|
|
Win32 error value
|
|
|
|
--*/
|
|
{
|
|
ULONG i;
|
|
|
|
for (i = 0;i < sizeof(CodePairs) / sizeof(CodePairs[0]); i += 2) {
|
|
|
|
if (CodePairs[i] == status) {
|
|
|
|
return CodePairs[i + 1];
|
|
|
|
}
|
|
}
|
|
|
|
SmartcardDebug(
|
|
DEBUG_ERROR,
|
|
("%s(MapNtStatusToWinError): NTSTATUS %lx unknown\n",
|
|
DRIVER_NAME,
|
|
status)
|
|
);
|
|
|
|
//
|
|
// We were unable to map the error code
|
|
//
|
|
return ERROR_GEN_FAILURE;
|
|
}
|
|
|
|
void
|
|
SMCLIB_Assert(
|
|
PVOID FailedAssertion,
|
|
PVOID FileName,
|
|
ULONG LineNumber,
|
|
PCHAR Message
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is a simple assert function that gets called using the ASSERT
|
|
macro. Windows 9x does not offer this functionality
|
|
|
|
Arguments:
|
|
|
|
FailedAssertion - The assertion we tested
|
|
FileName - Yes, this is the name of the source file
|
|
LineNumber - What might this be ?
|
|
Message - An additional message supplied using ASSERTMSG
|
|
|
|
Return Value:
|
|
|
|
-
|
|
|
|
--*/
|
|
{
|
|
#ifdef DEBUG
|
|
|
|
Debug_Printf(
|
|
"Assertion Failed: %s in %s(%ld)",
|
|
FailedAssertion,
|
|
FileName,
|
|
LineNumber
|
|
);
|
|
|
|
if (Message)
|
|
Debug_Printf(" %s",Message);
|
|
|
|
Debug_Printf("\n");
|
|
|
|
#endif
|
|
}
|
|
|
|
//#ifdef _vmm_add_ddb_to_do
|
|
BOOL
|
|
VXDINLINE
|
|
_VMM_Add_DDB(
|
|
struct VxD_Desc_Block *pDeviceDDB
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is used to create a new device instance for a driver
|
|
that supports multiple instances - like a serial based driver that
|
|
supports more than one device -
|
|
|
|
Arguments:
|
|
|
|
pDeviceDDB - The DDB struct that is to be added to the system
|
|
|
|
Return Value:
|
|
|
|
TRUE - Yope, it worked
|
|
FALSE - Out of business (May be the device name already exists)
|
|
|
|
--*/
|
|
{
|
|
_asm mov edi, pDeviceDDB
|
|
VxDCall(VMM_Add_DDB)
|
|
_asm {
|
|
|
|
mov eax, 1
|
|
jnc exit
|
|
mov eax, 0
|
|
exit:
|
|
}
|
|
}
|
|
|
|
BOOL
|
|
VXDINLINE
|
|
_VMM_Remove_DDB(
|
|
struct VxD_Desc_Block *pDeviceDDB
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Removes a DDB (device) that was created using VMM_Add_DDB
|
|
|
|
Arguments:
|
|
|
|
The address of the DDB to remove
|
|
|
|
Return Value:
|
|
|
|
TRUE - OK, DDB removed otherwise FALSE
|
|
|
|
--*/
|
|
{
|
|
_asm mov edi, pDeviceDDB
|
|
VxDCall(VMM_Remove_DDB)
|
|
_asm {
|
|
|
|
mov eax, 1
|
|
jnc exit
|
|
mov eax, 0
|
|
exit:
|
|
}
|
|
}
|
|
//#endif
|
|
|
|
PVMMDDB
|
|
SMCLIB_VxD_CreateDevice(
|
|
char *Device,
|
|
void (*ControlProc)(void)
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Creates a new device. This routine allows a driver to create additional devices.
|
|
|
|
Arguments:
|
|
|
|
Device - Name of the device to be created. At most 8 characters
|
|
ControlProc - Address of the VxD control procedure. (NOT the DeviceIoControl function!)
|
|
|
|
Return Value:
|
|
|
|
The newly created DDB if successful or NULL otherwise
|
|
|
|
--*/
|
|
{
|
|
PVMMDDB pDDB;
|
|
UCHAR DeviceName[9];
|
|
|
|
ASSERT(Device != NULL);
|
|
ASSERT(strlen(Device) <= 8);
|
|
ASSERT(ControlProc != NULL);
|
|
|
|
if (strlen(Device) > 8) {
|
|
|
|
return NULL;
|
|
}
|
|
|
|
_Sprintf(DeviceName, "%-8s", Device);
|
|
|
|
//
|
|
// Allocate space for the VxD description block
|
|
//
|
|
pDDB = (PVMMDDB) _HeapAllocate(
|
|
sizeof(struct VxD_Desc_Block),
|
|
HEAPZEROINIT
|
|
);
|
|
|
|
if (pDDB)
|
|
{
|
|
pDDB->DDB_SDK_Version = DDK_VERSION;
|
|
pDDB->DDB_Req_Device_Number = UNDEFINED_DEVICE_ID;
|
|
pDDB->DDB_Dev_Major_Version = 1;
|
|
pDDB->DDB_Dev_Minor_Version = 0;
|
|
memcpy(pDDB->DDB_Name, DeviceName, 8);
|
|
pDDB->DDB_Init_Order = UNDEFINED_INIT_ORDER;
|
|
pDDB->DDB_Control_Proc = (ULONG) ControlProc;
|
|
pDDB->DDB_Reference_Data = 0;
|
|
pDDB->DDB_Prev = 'Prev';
|
|
pDDB->DDB_Size = sizeof(struct VxD_Desc_Block);
|
|
pDDB->DDB_Reserved1 = 'Rsv1';
|
|
pDDB->DDB_Reserved2 = 'Rsv2';
|
|
pDDB->DDB_Reserved3 = 'Rsv3';
|
|
|
|
//
|
|
// Now create the DDB
|
|
//
|
|
if (!_VMM_Add_DDB(pDDB)) {
|
|
|
|
_HeapFree(pDDB, 0);
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
return pDDB;
|
|
}
|
|
|
|
BOOL
|
|
SMCLIB_VxD_DeleteDevice(
|
|
PVMMDDB pDDB
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Deleted a device. This function can be used to delete
|
|
a device that was created using VxD_CreateDevice
|
|
|
|
Arguments:
|
|
|
|
pDDB - The DDB to be deleted
|
|
|
|
Return Value:
|
|
|
|
TRUE - device successfully deleted
|
|
FALSE - device not deleted
|
|
|
|
--*/
|
|
{
|
|
ASSERT(pDDB != NULL);
|
|
|
|
if(pDDB == NULL || !_VMM_Remove_DDB(pDDB)) {
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
_HeapFree(pDDB, 0);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
DWORD
|
|
_stdcall
|
|
VxD_PageLock(
|
|
DWORD lpMem,
|
|
DWORD cbSize
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function lock the page
|
|
|
|
Arguments:
|
|
|
|
lpMem - pointer to the datablock which has to be locked
|
|
cbSize - length of the datablock
|
|
|
|
Return Value:
|
|
|
|
- pointer to the locked datablock
|
|
|
|
--*/
|
|
{
|
|
DWORD LinPageNum;
|
|
DWORD LinOffset;
|
|
DWORD nPages;
|
|
DWORD dwRet;
|
|
|
|
LinOffset = lpMem & 0xfff; // page offset of memory to map
|
|
LinPageNum = lpMem >> 12; // generate page number
|
|
|
|
// Calculate # of pages to map globally
|
|
nPages = ((lpMem + cbSize) >> 12) - LinPageNum + 1;
|
|
|
|
//
|
|
// Return global mapping of passed in pointer, as this new pointer
|
|
// is how the memory must be accessed out of context.
|
|
//
|
|
dwRet = _LinPageLock(LinPageNum, nPages, PAGEMAPGLOBAL | PAGEMARKDIRTY);
|
|
|
|
ASSERT(dwRet != 0);
|
|
|
|
SmartcardDebug(
|
|
DEBUG_ERROR,
|
|
("%s!VxD_PageLock: LinPageNum = %lx, nPages = %lx, dwRet = %lx\n",
|
|
DRIVER_NAME,
|
|
LinPageNum,
|
|
nPages,
|
|
dwRet)
|
|
);
|
|
|
|
return (dwRet + LinOffset);
|
|
}
|
|
|
|
void
|
|
_stdcall
|
|
VxD_PageUnlock(
|
|
DWORD lpMem,
|
|
DWORD cbSize
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function unlocks a datablock
|
|
|
|
Arguments:
|
|
|
|
lpMem - pointer to the datablock which has to be unlocked
|
|
cbSize - length of the datablock
|
|
|
|
Return Value:
|
|
|
|
-
|
|
|
|
--*/
|
|
{
|
|
DWORD LinPageNum;
|
|
DWORD nPages;
|
|
DWORD dwRet;
|
|
|
|
LinPageNum = lpMem >> 12;
|
|
nPages = ((lpMem + cbSize) >> 12) - LinPageNum + 1;
|
|
|
|
SmartcardDebug(
|
|
DEBUG_ERROR,
|
|
("%s!VxD_PageUnlock: LinPageNum = %lx, nPages = %lx\n",
|
|
DRIVER_NAME,
|
|
LinPageNum,
|
|
nPages)
|
|
);
|
|
|
|
// Free globally mapped memory
|
|
dwRet = _LinPageUnlock(LinPageNum, nPages, PAGEMAPGLOBAL);
|
|
|
|
ASSERT(dwRet != 0);
|
|
}
|
|
|
|
void
|
|
SMCLIB_SmartcardCompleteCardTracking(
|
|
PSMARTCARD_EXTENSION SmartcardExtension
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine calls i/o completion for the pending
|
|
card tracking operation. It also unlocks the previously
|
|
locked memory that was used for the overlapped strucutre
|
|
|
|
Arguments:
|
|
|
|
SmartcardExtension
|
|
|
|
Return Value:
|
|
|
|
-
|
|
|
|
--*/
|
|
{
|
|
if (SmartcardExtension->OsData->NotificationOverlappedData) {
|
|
|
|
DWORD O_Internal = SmartcardExtension->OsData->NotificationOverlappedData->O_Internal;
|
|
|
|
SmartcardDebug(
|
|
DEBUG_ERROR,
|
|
("%s(SmartcardCompleteCardTracking): Completing %lx\n",
|
|
DRIVER_NAME,
|
|
SmartcardExtension->OsData->NotificationOverlappedData)
|
|
);
|
|
|
|
//
|
|
// set number of bytes returned to 0
|
|
//
|
|
SmartcardExtension->OsData->NotificationOverlappedData->O_InternalHigh = 0;
|
|
|
|
_asm mov ebx, O_Internal
|
|
|
|
VxDCall(VWIN32_DIOCCompletionRoutine)
|
|
|
|
_HeapFree(
|
|
SmartcardExtension->OsData->NotificationOverlappedData,
|
|
0
|
|
);
|
|
|
|
SmartcardExtension->OsData->NotificationOverlappedData = NULL;
|
|
}
|
|
}
|
|
|
|
void
|
|
SMCLIB_SmartcardCompleteRequest(
|
|
PSMARTCARD_EXTENSION SmartcardExtension
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine calls i/o completion for a pending
|
|
io operation. It also unlocks the previously
|
|
locked memory that was used for the overlapped structure
|
|
|
|
Arguments:
|
|
|
|
SmartcardExtension
|
|
|
|
Return Value:
|
|
|
|
-
|
|
|
|
--*/
|
|
{
|
|
DWORD O_Internal = SmartcardExtension->OsData->CurrentOverlappedData->O_Internal;
|
|
|
|
_asm mov ebx, O_Internal
|
|
|
|
VxDCall(VWIN32_DIOCCompletionRoutine)
|
|
|
|
VxD_PageUnlock(
|
|
(DWORD) SmartcardExtension->OsData->CurrentOverlappedData,
|
|
sizeof(OVERLAPPED)
|
|
);
|
|
|
|
VxD_PageUnlock(
|
|
(DWORD) SmartcardExtension->IoRequest.RequestBuffer,
|
|
SmartcardExtension->IoRequest.RequestBufferLength
|
|
);
|
|
|
|
VxD_PageUnlock(
|
|
(DWORD) SmartcardExtension->IoRequest.ReplyBuffer,
|
|
SmartcardExtension->IoRequest.ReplyBufferLength
|
|
);
|
|
|
|
SmartcardExtension->OsData->CurrentDiocParams = NULL;
|
|
}
|
|
|
|
NTSTATUS
|
|
SMCLIB_SmartcardCreateLink(
|
|
PUCHAR LinkName,
|
|
PUCHAR DeviceName
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine creates a symbolic link name for the given device name.
|
|
It means it creates a 'STRING-value' in the registry ..VxD\smclib\devices
|
|
like SCReader[0-9] = DeviceName.
|
|
The smart card resource manager uses these entries in order to figure out
|
|
what smart card devices are currently running.
|
|
We do this because we don't have the ability to create a dynamic device
|
|
name like we can do in Windows NT.
|
|
|
|
Arguments:
|
|
|
|
LinkName - receives the created link name
|
|
DeviceName - the device name for which the link should be created
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS
|
|
|
|
--*/
|
|
{
|
|
PUCHAR Value;
|
|
ULONG i;
|
|
HANDLE hKey;
|
|
|
|
if (DriverInitialized == FALSE) {
|
|
|
|
SMCLIB_Init();
|
|
}
|
|
|
|
SmartcardDebug(
|
|
DEBUG_TRACE,
|
|
("%s(SmartcardCreateLink): Enter\n",
|
|
DRIVER_NAME)
|
|
);
|
|
|
|
ASSERT(LinkName != NULL);
|
|
ASSERT(DeviceName != NULL);
|
|
ASSERT(strlen(DeviceName) <= 12);
|
|
|
|
if (LinkName == NULL) {
|
|
|
|
return STATUS_INVALID_PARAMETER_1;
|
|
}
|
|
|
|
if (DeviceName == NULL) {
|
|
|
|
return STATUS_INVALID_PARAMETER_2;
|
|
}
|
|
|
|
//
|
|
// Open the key where the device names are stored
|
|
//
|
|
if(_RegOpenKey(
|
|
HKEY_LOCAL_MACHINE,
|
|
DevicePath,
|
|
&hKey
|
|
) != ERROR_SUCCESS) {
|
|
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
//
|
|
// Allocate a buffer for enumeration of the registry
|
|
//
|
|
Value = (PUCHAR) _HeapAllocate(REGISTRY_PATH_LEN, 0);
|
|
|
|
if (Value == NULL) {
|
|
|
|
SmartcardDebug(
|
|
DEBUG_ERROR,
|
|
("%s(SmartcardCreateLink): Allocation failed\n",
|
|
DRIVER_NAME)
|
|
);
|
|
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
//
|
|
// Now find a free device name
|
|
//
|
|
for (i = 0; i < MAXIMUM_SMARTCARD_READERS ; i++) {
|
|
|
|
_Sprintf(
|
|
Value,
|
|
"SCReader%d",
|
|
i
|
|
);
|
|
|
|
//
|
|
// Check for existence of the key
|
|
//
|
|
|
|
if(_RegQueryValueEx(
|
|
hKey,
|
|
Value,
|
|
NULL,
|
|
NULL,
|
|
NULL,
|
|
NULL
|
|
) != ERROR_SUCCESS) {
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Free the buffer since we don't need it anymore
|
|
//
|
|
_HeapFree(Value, 0);
|
|
|
|
if (i >= MAXIMUM_SMARTCARD_READERS) {
|
|
|
|
SmartcardDebug(
|
|
DEBUG_ERROR,
|
|
("%s(SmartcardCreateLink): Can't create link: Too many readers\n",
|
|
DRIVER_NAME)
|
|
);
|
|
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
//
|
|
// Create the link name...
|
|
//
|
|
_Sprintf(
|
|
LinkName,
|
|
"SCReader%d",
|
|
i
|
|
);
|
|
|
|
//
|
|
// ...and store it in the registry
|
|
//
|
|
_RegSetValueEx(
|
|
hKey,
|
|
LinkName,
|
|
NULL,
|
|
REG_SZ,
|
|
DeviceName,
|
|
strlen(DeviceName)
|
|
);
|
|
|
|
_RegCloseKey(hKey);
|
|
|
|
SmartcardDebug(
|
|
DEBUG_DRIVER,
|
|
("%s(SmartcardCreateLink): Link %s created for Driver %s\n",
|
|
DRIVER_NAME,
|
|
LinkName,
|
|
DeviceName)
|
|
);
|
|
|
|
SmartcardDebug(
|
|
DEBUG_TRACE,
|
|
("%s(SmartcardCreateLink): Exit\n",
|
|
DRIVER_NAME)
|
|
);
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
SMCLIB_SmartcardDeleteLink(
|
|
PUCHAR LinkName
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Deletes the link previously created with SmartcardCreateLink()
|
|
This routine deletes the symbolic link name that is stored in the
|
|
registry. A driver ususally calls this function upon unload.
|
|
|
|
Arguments:
|
|
|
|
LinkName - The link that is to be deleted
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS
|
|
|
|
--*/
|
|
{
|
|
HANDLE hKey;
|
|
NTSTATUS status;
|
|
|
|
SmartcardDebug(
|
|
DEBUG_TRACE,
|
|
("%s(SmartcardDeleteLink): Enter\n",
|
|
DRIVER_NAME)
|
|
);
|
|
|
|
ASSERT(LinkName);
|
|
ASSERT(strlen(LinkName) <= 10);
|
|
|
|
//
|
|
// Open the key where the device names are stored
|
|
//
|
|
if(_RegOpenKey(
|
|
HKEY_LOCAL_MACHINE,
|
|
DevicePath,
|
|
&hKey
|
|
) != ERROR_SUCCESS) {
|
|
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
if(_RegDeleteValue(
|
|
hKey,
|
|
LinkName
|
|
) == ERROR_SUCCESS) {
|
|
|
|
SmartcardDebug(
|
|
DEBUG_DRIVER,
|
|
("%s(SmartcardDeleteLink): Link %s deleted\n",
|
|
DRIVER_NAME,
|
|
LinkName)
|
|
);
|
|
|
|
status = STATUS_SUCCESS;
|
|
|
|
} else {
|
|
|
|
SmartcardDebug(
|
|
DEBUG_ERROR,
|
|
("%s(SmartcardDeleteLink): Can't delete link %s\n",
|
|
DRIVER_NAME,
|
|
LinkName)
|
|
);
|
|
|
|
status = STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
_RegCloseKey(hKey);
|
|
|
|
SmartcardDebug(
|
|
DEBUG_TRACE,
|
|
("%s(SmartcardDeleteLink): Exit",
|
|
DRIVER_NAME)
|
|
);
|
|
|
|
return status;
|
|
}
|
|
|
|
NTSTATUS
|
|
SMCLIB_SmartcardInitialize(
|
|
PSMARTCARD_EXTENSION SmartcardExtension
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function allocated the send and receive buffers for smart card
|
|
data. It also sets the pointer to 2 ISO tables to make them accessible
|
|
to the driver
|
|
|
|
Arguments:
|
|
|
|
SmartcardExtension
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
|
|
SmartcardDebug(
|
|
DEBUG_TRACE,
|
|
("%s(SmartcardInitialize): Enter - Version %lx, %s %s\n",
|
|
DRIVER_NAME,
|
|
SMCLIB_VERSION,
|
|
__DATE__,
|
|
__TIME__)
|
|
);
|
|
|
|
ASSERT(SmartcardExtension != NULL);
|
|
ASSERT(SmartcardExtension->OsData == NULL);
|
|
|
|
if (SmartcardExtension == NULL) {
|
|
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
if (SmartcardExtension->Version < SMCLIB_VERSION_REQUIRED) {
|
|
|
|
SmartcardDebug(
|
|
DEBUG_ERROR,
|
|
("%s(SmartcardInitialize): Invalid Version in SMARTCARD_EXTENSION. Must be %lx\n",
|
|
DRIVER_NAME,
|
|
SMCLIB_VERSION)
|
|
);
|
|
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
if (SmartcardExtension->SmartcardRequest.BufferSize < MIN_BUFFER_SIZE) {
|
|
|
|
SmartcardDebug(
|
|
DEBUG_ERROR,
|
|
("%s(SmartcardInitialize): WARNING: SmartcardRequest.BufferSize (%ld) < MIN_BUFFER_SIZE (%ld)\n",
|
|
DRIVER_NAME,
|
|
SmartcardExtension->SmartcardRequest.BufferSize,
|
|
MIN_BUFFER_SIZE)
|
|
);
|
|
|
|
SmartcardExtension->SmartcardRequest.BufferSize = MIN_BUFFER_SIZE;
|
|
}
|
|
|
|
if (SmartcardExtension->SmartcardReply.BufferSize < MIN_BUFFER_SIZE) {
|
|
|
|
SmartcardDebug(
|
|
DEBUG_ERROR,
|
|
("%s(SmartcardInitialize): WARNING: SmartcardReply.BufferSize (%ld) < MIN_BUFFER_SIZE (%ld)\n",
|
|
DRIVER_NAME,
|
|
SmartcardExtension->SmartcardReply.BufferSize,
|
|
MIN_BUFFER_SIZE)
|
|
);
|
|
|
|
SmartcardExtension->SmartcardReply.BufferSize = MIN_BUFFER_SIZE;
|
|
}
|
|
|
|
SmartcardExtension->SmartcardRequest.Buffer = _HeapAllocate(
|
|
SmartcardExtension->SmartcardRequest.BufferSize,
|
|
0
|
|
);
|
|
|
|
SmartcardExtension->SmartcardReply.Buffer = _HeapAllocate(
|
|
SmartcardExtension->SmartcardReply.BufferSize,
|
|
0
|
|
);
|
|
|
|
SmartcardExtension->OsData = _HeapAllocate(
|
|
sizeof(OS_DEP_DATA),
|
|
0
|
|
);
|
|
|
|
//
|
|
// Check if one of the above allocations failed
|
|
//
|
|
if (SmartcardExtension->SmartcardRequest.Buffer == NULL ||
|
|
SmartcardExtension->SmartcardReply.Buffer == NULL ||
|
|
SmartcardExtension->OsData == NULL) {
|
|
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
if (SmartcardExtension->SmartcardRequest.Buffer) {
|
|
|
|
_HeapFree(SmartcardExtension->SmartcardRequest.Buffer, 0);
|
|
}
|
|
|
|
if (SmartcardExtension->SmartcardReply.Buffer) {
|
|
|
|
_HeapFree(SmartcardExtension->SmartcardReply.Buffer, 0);
|
|
}
|
|
|
|
if (SmartcardExtension->OsData == NULL) {
|
|
|
|
_HeapFree(SmartcardExtension->OsData, 0);
|
|
}
|
|
}
|
|
|
|
if (status != STATUS_SUCCESS) {
|
|
|
|
return status;
|
|
}
|
|
|
|
memset(SmartcardExtension->OsData, 0, sizeof(OS_DEP_DATA));
|
|
|
|
//
|
|
// Create mutex that is used to synch access to the driver
|
|
//
|
|
SmartcardExtension->OsData->Mutex = _CreateMutex(0, 0);
|
|
|
|
//
|
|
// Make the 2 ISO tables accessible to the driver
|
|
//
|
|
SmartcardExtension->CardCapabilities.ClockRateConversion =
|
|
&ClockRateConversion[0];
|
|
|
|
SmartcardExtension->CardCapabilities.BitRateAdjustment =
|
|
&BitRateAdjustment[0];
|
|
|
|
SmartcardDebug(
|
|
DEBUG_TRACE,
|
|
("%s(SmartcardInitialize): Exit\n",
|
|
DRIVER_NAME)
|
|
);
|
|
|
|
return status;
|
|
}
|
|
|
|
VOID
|
|
SMCLIB_SmartcardExit(
|
|
PSMARTCARD_EXTENSION SmartcardExtension
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine frees the send and receive buffer.
|
|
It is usually called when the driver unloads.
|
|
|
|
Arguments:
|
|
|
|
SmartcardExtension
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS
|
|
|
|
--*/
|
|
{
|
|
SmartcardDebug(
|
|
DEBUG_TRACE,
|
|
("%s(SmartcardExit): Enter\n",
|
|
DRIVER_NAME)
|
|
);
|
|
|
|
if (SmartcardExtension->SmartcardRequest.Buffer) {
|
|
|
|
_HeapFree(SmartcardExtension->SmartcardRequest.Buffer, 0);
|
|
}
|
|
|
|
if (SmartcardExtension->SmartcardReply.Buffer) {
|
|
|
|
_HeapFree(SmartcardExtension->SmartcardReply.Buffer, 0);
|
|
}
|
|
|
|
if (SmartcardExtension->OsData) {
|
|
|
|
_HeapFree(SmartcardExtension->OsData, 0);
|
|
}
|
|
|
|
SmartcardDebug(
|
|
DEBUG_TRACE,
|
|
("%s(SmartcardExit): Exit\n",
|
|
DRIVER_NAME)
|
|
);
|
|
}
|
|
|
|
VOID
|
|
SMCLIB_SmartcardLogError(
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine allocates an error log entry, copies the supplied data
|
|
to it, and requests that it be written to the error log file.
|
|
|
|
Arguments:
|
|
Return Value:
|
|
|
|
--*/
|
|
|
|
{
|
|
SmartcardDebug(
|
|
DEBUG_ERROR,
|
|
("%s(SmartcardLogError): Not yet implemented\n",
|
|
DRIVER_NAME)
|
|
);
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
SMCLIB_SmartcardDeviceControl(
|
|
PSMARTCARD_EXTENSION SmartcardExtension,
|
|
DIOCPARAMETERS *lpDiocParams
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
The routine is the general device control dispatch function for VxD drivers.
|
|
|
|
Arguments:
|
|
|
|
SmartcardExtension - The pointer to the smart card datae
|
|
lpDiocParams - struct containing the caller parameter
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
|
|
ASSERT(SmartcardExtension != NULL);
|
|
|
|
if (SmartcardExtension == NULL) {
|
|
|
|
return STATUS_INVALID_PARAMETER_1;
|
|
}
|
|
|
|
ASSERT(lpDiocParams != NULL);
|
|
|
|
if (lpDiocParams == NULL) {
|
|
|
|
return STATUS_INVALID_PARAMETER_2;
|
|
}
|
|
|
|
ASSERT(lpDiocParams->lpoOverlapped != 0);
|
|
|
|
if (lpDiocParams->lpoOverlapped == 0) {
|
|
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
// Check the version that the driver requires
|
|
ASSERT(SmartcardExtension->Version >= SMCLIB_VERSION_REQUIRED);
|
|
|
|
if (SmartcardExtension->Version < SMCLIB_VERSION_REQUIRED) {
|
|
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
// Synchronize access to the driver
|
|
_EnterMutex(
|
|
SmartcardExtension->OsData->Mutex,
|
|
BLOCK_SVC_INTS | BLOCK_THREAD_IDLE
|
|
);
|
|
|
|
if (status == STATUS_SUCCESS) {
|
|
|
|
SmartcardDebug(
|
|
DEBUG_IOCTL,
|
|
("SMCLIB(SmartcardDeviceControl): Ioctl = %s, DIOCP = %lx\n",
|
|
MapIoControlCodeToString(lpDiocParams->dwIoControlCode),
|
|
lpDiocParams)
|
|
);
|
|
|
|
// Return if device is busy
|
|
if (SmartcardExtension->OsData->CurrentDiocParams != NULL) {
|
|
|
|
SmartcardDebug(
|
|
DEBUG_IOCTL,
|
|
("%s(SmartcardDeviceControl): Device is busy\n",
|
|
DRIVER_NAME)
|
|
);
|
|
|
|
status = STATUS_DEVICE_BUSY;
|
|
}
|
|
}
|
|
|
|
if (status == STATUS_SUCCESS) {
|
|
|
|
if (lpDiocParams->lpcbBytesReturned) {
|
|
|
|
// Default number of bytes returned
|
|
*(PULONG) lpDiocParams->lpcbBytesReturned = 0;
|
|
}
|
|
|
|
switch (lpDiocParams->dwIoControlCode) {
|
|
|
|
//
|
|
// We have to check for _IS_ABSENT and _IS_PRESENT first,
|
|
// since these are (the only allowed) asynchronous requests
|
|
//
|
|
case IOCTL_SMARTCARD_IS_ABSENT:
|
|
case IOCTL_SMARTCARD_IS_PRESENT:
|
|
|
|
if (SmartcardExtension->ReaderFunction[RDF_CARD_TRACKING] == NULL) {
|
|
|
|
status = STATUS_NOT_SUPPORTED;
|
|
break;
|
|
}
|
|
|
|
// Now check if the driver is already processing notification
|
|
if (SmartcardExtension->OsData->NotificationOverlappedData != NULL) {
|
|
|
|
status = STATUS_DEVICE_BUSY;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// Lock the overlapped structure that has to be notified
|
|
// about the completion into memory
|
|
//
|
|
SmartcardExtension->OsData->NotificationOverlappedData =
|
|
_HeapAllocate( sizeof(OVERLAPPED), HEAPZEROINIT );
|
|
|
|
if (SmartcardExtension->OsData->NotificationOverlappedData == NULL) {
|
|
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
memcpy(
|
|
SmartcardExtension->OsData->NotificationOverlappedData,
|
|
(PVOID) lpDiocParams->lpoOverlapped,
|
|
sizeof(OVERLAPPED)
|
|
);
|
|
|
|
if (lpDiocParams->dwIoControlCode == IOCTL_SMARTCARD_IS_ABSENT) {
|
|
|
|
//
|
|
// If the card is already (or still) absent, we can return immediatly.
|
|
// Otherwise we must statrt event tracking.
|
|
//
|
|
if (SmartcardExtension->ReaderCapabilities.CurrentState > SCARD_ABSENT) {
|
|
|
|
status = SmartcardExtension->ReaderFunction[RDF_CARD_TRACKING](
|
|
SmartcardExtension
|
|
);
|
|
}
|
|
|
|
} else {
|
|
|
|
//
|
|
// If the card is already (or still) present, we can return immediatly.
|
|
// Otherwise we must statrt event tracking.
|
|
//
|
|
if (SmartcardExtension->ReaderCapabilities.CurrentState <= SCARD_ABSENT) {
|
|
|
|
status = SmartcardExtension->ReaderFunction[RDF_CARD_TRACKING](
|
|
SmartcardExtension
|
|
);
|
|
}
|
|
}
|
|
|
|
if (status != STATUS_PENDING) {
|
|
|
|
//
|
|
// Unlock the overlapped structure again since the driver
|
|
// doesn't need it anymore
|
|
//
|
|
_HeapFree(
|
|
SmartcardExtension->OsData->NotificationOverlappedData,
|
|
0
|
|
);
|
|
|
|
SmartcardExtension->OsData->NotificationOverlappedData = NULL;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
// Check if buffers are properly allocated
|
|
ASSERT(SmartcardExtension->SmartcardRequest.Buffer);
|
|
ASSERT(SmartcardExtension->SmartcardReply.Buffer);
|
|
|
|
SmartcardExtension->OsData->CurrentDiocParams = lpDiocParams;
|
|
|
|
// Get major io control code
|
|
SmartcardExtension->MajorIoControlCode =
|
|
lpDiocParams->dwIoControlCode;
|
|
|
|
if (lpDiocParams->lpvInBuffer) {
|
|
|
|
//
|
|
// Transfer minor io control code, even if it doesn't make sense for
|
|
// this particular major code
|
|
//
|
|
SmartcardExtension->MinorIoControlCode =
|
|
*(PULONG) (lpDiocParams->lpvInBuffer);
|
|
|
|
// Lock memory and save pointer to and length of request buffer
|
|
SmartcardExtension->IoRequest.RequestBuffer = (PUCHAR) VxD_PageLock(
|
|
lpDiocParams->lpvInBuffer,
|
|
lpDiocParams->cbInBuffer
|
|
);
|
|
|
|
SmartcardExtension->IoRequest.RequestBufferLength =
|
|
lpDiocParams->cbInBuffer;
|
|
|
|
} else {
|
|
|
|
SmartcardExtension->IoRequest.RequestBuffer = NULL;
|
|
SmartcardExtension->IoRequest.RequestBufferLength = 0;
|
|
}
|
|
|
|
if (lpDiocParams->lpvOutBuffer) {
|
|
|
|
// Lock memory an save pointer to and length of reply buffer
|
|
SmartcardExtension->IoRequest.ReplyBuffer = (PUCHAR) VxD_PageLock(
|
|
lpDiocParams->lpvOutBuffer,
|
|
lpDiocParams->cbOutBuffer
|
|
);
|
|
|
|
SmartcardExtension->IoRequest.ReplyBufferLength =
|
|
lpDiocParams->cbOutBuffer;
|
|
|
|
} else {
|
|
|
|
SmartcardExtension->IoRequest.ReplyBuffer = NULL;
|
|
SmartcardExtension->IoRequest.ReplyBufferLength = 0;
|
|
}
|
|
|
|
// Lock overlapped struct into memory
|
|
SmartcardExtension->OsData->CurrentOverlappedData =
|
|
(OVERLAPPED *) VxD_PageLock(
|
|
lpDiocParams->lpoOverlapped,
|
|
sizeof(OVERLAPPED)
|
|
);
|
|
|
|
if (SmartcardExtension->OsData->CurrentOverlappedData) {
|
|
|
|
//
|
|
// Pointer to variable that receives the actual number
|
|
// of bytes returned. Since we don't know yet if the
|
|
// driver will return STATUS_PENDING, we use the
|
|
// overlapped data to store the number of bytes returned
|
|
//
|
|
SmartcardExtension->IoRequest.Information =
|
|
&SmartcardExtension->OsData->CurrentOverlappedData->O_InternalHigh;
|
|
|
|
// Set the default number of bytes returned to 0
|
|
*SmartcardExtension->IoRequest.Information = 0;
|
|
|
|
// Process the ioctl-request
|
|
status = SmartcardDeviceIoControl(SmartcardExtension);
|
|
|
|
if (status != STATUS_PENDING) {
|
|
|
|
if(lpDiocParams->lpcbBytesReturned) {
|
|
|
|
*(PULONG) (lpDiocParams->lpcbBytesReturned) =
|
|
*(SmartcardExtension->IoRequest.Information);
|
|
}
|
|
|
|
//
|
|
// The driver satisfied the call immediatly. So we don't use the overlapped
|
|
// data to return information to the caller. We can transfer the 'number
|
|
// of bytes returned' directly
|
|
//
|
|
if (SmartcardExtension->OsData->CurrentOverlappedData) {
|
|
|
|
// Unlock all memory
|
|
VxD_PageUnlock(
|
|
(DWORD) SmartcardExtension->OsData->CurrentOverlappedData,
|
|
sizeof(OVERLAPPED)
|
|
);
|
|
}
|
|
|
|
if (SmartcardExtension->IoRequest.RequestBuffer) {
|
|
|
|
VxD_PageUnlock(
|
|
(DWORD) SmartcardExtension->IoRequest.RequestBuffer,
|
|
SmartcardExtension->IoRequest.RequestBufferLength
|
|
);
|
|
}
|
|
|
|
if (SmartcardExtension->IoRequest.ReplyBuffer) {
|
|
|
|
VxD_PageUnlock(
|
|
(DWORD) SmartcardExtension->IoRequest.ReplyBuffer,
|
|
SmartcardExtension->IoRequest.ReplyBufferLength
|
|
);
|
|
}
|
|
|
|
//
|
|
// If the devcie is not busy, we can set the
|
|
// current parameters back to NULL
|
|
//
|
|
SmartcardExtension->OsData->CurrentDiocParams = NULL;
|
|
}
|
|
|
|
} else {
|
|
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
SmartcardDebug(
|
|
DEBUG_IOCTL,
|
|
("SMCLIB(SmartcardDeviceControl): Exit\n")
|
|
);
|
|
|
|
_LeaveMutex(SmartcardExtension->OsData->Mutex);
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
|
|
DWORD
|
|
_stdcall
|
|
SMCLIB_DeviceIoControl(
|
|
DWORD dwService,
|
|
DWORD dwDDB,
|
|
DWORD hDevice,
|
|
DIOCPARAMETERS *lpDIOCParms
|
|
)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
SMCLIB_Get_Version()
|
|
{
|
|
return SMCLIB_VERSION;
|
|
}
|
|
|