/*++ Copyright (c) 2000 Microsoft Corporation Module Name: vfdriver.c Abstract: This module contains the verifier driver filter. Author: Adrian J. Oney (adriao) 12-June-2000 Environment: Kernel mode Revision History: AdriaO 06/12/2000 - Authored --*/ #include "vfdef.h" // Includes vfdef.h #include "vidriver.h" #ifdef ALLOC_PRAGMA #pragma alloc_text(PAGEVRFY, VfDriverInit) #pragma alloc_text(PAGEVRFY, VfDriverAttachFilter) #pragma alloc_text(PAGEVRFY, ViDriverEntry) #pragma alloc_text(PAGEVRFY, ViDriverAddDevice) #pragma alloc_text(PAGEVRFY, ViDriverDispatchPnp) #pragma alloc_text(PAGEVRFY, ViDriverStartCompletionRoutine) #pragma alloc_text(PAGEVRFY, ViDriverDeviceUsageNotificationCompletionRoutine) #pragma alloc_text(PAGEVRFY, ViDriverDispatchPower) #pragma alloc_text(PAGEVRFY, ViDriverDispatchGeneric) #pragma alloc_text(PAGEVRFY, VfDriverIsVerifierFilterObject) #endif PDRIVER_OBJECT VfDriverObject = NULL; #ifdef ALLOC_DATA_PRAGMA #pragma const_seg("PAGEVRFC") #endif WCHAR VerifierDriverName[] = L"\\DRIVER\\VERIFIER"; BOOLEAN VfDriverCreated = FALSE; VOID VfDriverInit( VOID ) /*++ Routine Description: This routine initializes the driver verifier filter code. Arguments: None. Return Value: None. --*/ { } VOID VfDriverAttachFilter( IN PDEVICE_OBJECT PhysicalDeviceObject, IN VF_DEVOBJ_TYPE DeviceObjectType ) /*++ Routine Description: This is the Verifier driver dispatch handler for PnP IRPs. Arguments: PhysicalDeviceObject - Bottom of stack to attach to. DeviceObjectType - Type of filter the device object must simulate. Return Value: None. --*/ { NTSTATUS status; PDEVICE_OBJECT newDeviceObject, lowerDeviceObject; PVERIFIER_EXTENSION verifierExtension; UNICODE_STRING driverString; if (!VfDriverCreated) { RtlInitUnicodeString(&driverString, VerifierDriverName); IoCreateDriver(&driverString, ViDriverEntry); VfDriverCreated = TRUE; } if (VfDriverObject == NULL) { return; } switch(DeviceObjectType) { case VF_DEVOBJ_PDO: // // This makes no sense. We can't impersonate a PDO. // return; case VF_DEVOBJ_BUS_FILTER: // // We don't have the code to impersonate a bus filter yet. // return; case VF_DEVOBJ_LOWER_DEVICE_FILTER: case VF_DEVOBJ_LOWER_CLASS_FILTER: break; case VF_DEVOBJ_FDO: // // This makes no sense. We can't impersonate an FDO. // return; case VF_DEVOBJ_UPPER_DEVICE_FILTER: case VF_DEVOBJ_UPPER_CLASS_FILTER: break; default: // // We don't even know what this is! // ASSERT(0); return; } lowerDeviceObject = IoGetAttachedDevice(PhysicalDeviceObject); if (lowerDeviceObject->DriverObject == VfDriverObject) { // // No need to add another filter. We are immediately below. // return; } // // Create a filter device object. // status = IoCreateDevice( VfDriverObject, sizeof(VERIFIER_EXTENSION), NULL, // No Name FILE_DEVICE_UNKNOWN, FILE_DEVICE_SECURE_OPEN, FALSE, &newDeviceObject ); if (!NT_SUCCESS(status)) { return; } verifierExtension = (PVERIFIER_EXTENSION) newDeviceObject->DeviceExtension; verifierExtension->LowerDeviceObject = IoAttachDeviceToDeviceStack( newDeviceObject, PhysicalDeviceObject ); // // Failure for attachment is an indication of a broken plug & play system. // if (verifierExtension->LowerDeviceObject == NULL) { IoDeleteDevice(newDeviceObject); return; } newDeviceObject->Flags |= verifierExtension->LowerDeviceObject->Flags & (DO_BUFFERED_IO | DO_DIRECT_IO | DO_POWER_PAGABLE | DO_POWER_INRUSH); newDeviceObject->DeviceType = verifierExtension->LowerDeviceObject->DeviceType; newDeviceObject->Characteristics = verifierExtension->LowerDeviceObject->Characteristics; verifierExtension->Self = newDeviceObject; verifierExtension->PhysicalDeviceObject = PhysicalDeviceObject; newDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING; } NTSTATUS ViDriverEntry( IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath ) /*++ Routine Description: This is the callback function when we call IoCreateDriver to create a Verifier Driver Object. In this function, we need to remember the DriverObject. Arguments: DriverObject - Pointer to the driver object created by the system. RegistryPath - is NULL. Return Value: STATUS_SUCCESS --*/ { ULONG i; UNREFERENCED_PARAMETER(RegistryPath); // // File the pointer to our driver object away // VfDriverObject = DriverObject; // // Fill in the driver object // DriverObject->DriverExtension->AddDevice = (PDRIVER_ADD_DEVICE) ViDriverAddDevice; // // Most IRPs are simply pass though // for(i=0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++) { DriverObject->MajorFunction[i] = ViDriverDispatchGeneric; } // // PnP and Power IRPs are of course trickier. // DriverObject->MajorFunction[IRP_MJ_PNP] = ViDriverDispatchPnp; DriverObject->MajorFunction[IRP_MJ_POWER] = ViDriverDispatchPower; return STATUS_SUCCESS; } NTSTATUS ViDriverAddDevice( IN PDRIVER_OBJECT DriverObject, IN PDEVICE_OBJECT PhysicalDeviceObject ) /*++ Routine Description: This is the AddDevice callback function exposed by the verifier driver object. It should never be invoked by the operating system. Arguments: DriverObject - Pointer to the verifier driver object. PhysicalDeviceObject - Stack PnP wishes to attach this driver too. Return Value: NTSTATUS --*/ { UNREFERENCED_PARAMETER(DriverObject); UNREFERENCED_PARAMETER(PhysicalDeviceObject); // // We should never get here! // ASSERT(0); return STATUS_UNSUCCESSFUL; } NTSTATUS ViDriverDispatchPnp( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) /*++ Routine Description: This is the Verifier driver dispatch handler for PnP IRPs. Arguments: DeviceObject - Pointer to the verifier device object. Irp - Pointer to the incoming IRP. Return Value: NTSTATUS --*/ { PVERIFIER_EXTENSION verifierExtension; PIO_STACK_LOCATION irpSp; PDEVICE_OBJECT lowerDeviceObject; NTSTATUS status; verifierExtension = (PVERIFIER_EXTENSION) DeviceObject->DeviceExtension; irpSp = IoGetCurrentIrpStackLocation(Irp); lowerDeviceObject = verifierExtension->LowerDeviceObject; switch(irpSp->MinorFunction) { case IRP_MN_START_DEVICE: IoCopyCurrentIrpStackLocationToNext(Irp); IoSetCompletionRoutine( Irp, ViDriverStartCompletionRoutine, NULL, TRUE, TRUE, TRUE ); return IoCallDriver(lowerDeviceObject, Irp); case IRP_MN_REMOVE_DEVICE: IoCopyCurrentIrpStackLocationToNext(Irp); status = IoCallDriver(lowerDeviceObject, Irp); IoDetachDevice(lowerDeviceObject); IoDeleteDevice(DeviceObject); return status; case IRP_MN_DEVICE_USAGE_NOTIFICATION: // // On the way down, pagable might become set. Mimic the driver // above us. If no one is above us, just set pagable. // if ((DeviceObject->AttachedDevice == NULL) || (DeviceObject->AttachedDevice->Flags & DO_POWER_PAGABLE)) { DeviceObject->Flags |= DO_POWER_PAGABLE; } IoCopyCurrentIrpStackLocationToNext(Irp); IoSetCompletionRoutine( Irp, ViDriverDeviceUsageNotificationCompletionRoutine, NULL, TRUE, TRUE, TRUE ); return IoCallDriver(lowerDeviceObject, Irp); } IoCopyCurrentIrpStackLocationToNext(Irp); return IoCallDriver(lowerDeviceObject, Irp); } NTSTATUS ViDriverStartCompletionRoutine( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context ) { PVERIFIER_EXTENSION verifierExtension; UNREFERENCED_PARAMETER(Context); if (Irp->PendingReturned) { IoMarkIrpPending(Irp); } verifierExtension = (PVERIFIER_EXTENSION) DeviceObject->DeviceExtension; // // Inherit FILE_REMOVABLE_MEDIA during Start. This characteristic didn't // make a clean transition from NT4 to NT5 because it wasn't available // until the driver stack is started! Even worse, drivers *examine* this // characteristic during start as well. // if (verifierExtension->LowerDeviceObject->Characteristics & FILE_REMOVABLE_MEDIA) { DeviceObject->Characteristics |= FILE_REMOVABLE_MEDIA; } return STATUS_SUCCESS; } NTSTATUS ViDriverDeviceUsageNotificationCompletionRoutine( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context ) { PVERIFIER_EXTENSION verifierExtension; UNREFERENCED_PARAMETER(Context); if (Irp->PendingReturned) { IoMarkIrpPending(Irp); } verifierExtension = (PVERIFIER_EXTENSION) DeviceObject->DeviceExtension; // // On the way up, pagable might become clear. Mimic the driver below us. // if (!(verifierExtension->LowerDeviceObject->Flags & DO_POWER_PAGABLE)) { DeviceObject->Flags &= ~DO_POWER_PAGABLE; } return STATUS_SUCCESS; } NTSTATUS ViDriverDispatchPower( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) /*++ Routine Description: This is the Verifier driver dispatch handler for Power IRPs. Arguments: DeviceObject - Pointer to the verifier device object. Irp - Pointer to the incoming IRP. Return Value: NTSTATUS --*/ { PVERIFIER_EXTENSION verifierExtension; verifierExtension = (PVERIFIER_EXTENSION) DeviceObject->DeviceExtension; PoStartNextPowerIrp(Irp); IoCopyCurrentIrpStackLocationToNext(Irp); return PoCallDriver(verifierExtension->LowerDeviceObject, Irp); } NTSTATUS ViDriverDispatchGeneric( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp ) /*++ Routine Description: This is the Verifier driver dispatch handler for generic IRPs. Arguments: DeviceObject - Pointer to the verifier device object. Irp - Pointer to the incoming IRP. Return Value: NTSTATUS --*/ { PVERIFIER_EXTENSION verifierExtension; verifierExtension = (PVERIFIER_EXTENSION) DeviceObject->DeviceExtension; IoCopyCurrentIrpStackLocationToNext(Irp); return IoCallDriver(verifierExtension->LowerDeviceObject, Irp); } BOOLEAN VfDriverIsVerifierFilterObject( IN PDEVICE_OBJECT DeviceObject ) /*++ Routine Description: This determines whether the passed in device object is a verifier DO. Arguments: DeviceObject - Pointer to the device object to check. Return Value: TRUE/FALSE --*/ { return (BOOLEAN) (DeviceObject->DriverObject->MajorFunction[IRP_MJ_PNP] == ViDriverDispatchPnp); }