Leaked source code of windows server 2003
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.
 
 
 
 
 
 

2469 lines
62 KiB

/*++
Copyright (c) 1997 Microsoft Corporation
Module Name:
sample.c
Abstract:
Sample DDK PnP driver
Environment:
Kernel mode
Revision History:
16-July-1997 : Various changes:
- changed device extension flag names and types
- added SD_IoIncrement and SD_IoDecrement
- added a dispatch function for IRP_MJ_CLOSE
- added an ASSERT in SD_Unload
- added comments about giving up resource when
IRP_MN_STOP_DEVICE is received
25-April-2002 : re-used to test IoCreateDeviceSecure
--*/
#include "wdmsectest.h"
#include "seutil.h"
ULONG PdoSignature = 'SodP';
ULONG g_PdoId = 0;
//
// Globals
//
LONG g_DebugLevel = SAMPLE_DEFAULT_DEBUG_LEVEL;
PDRIVER_OBJECT g_DriverObject;
//
// Private routines (used to manipulate the held IRPs queue)
//
NTSTATUS
pSD_QueueRequest (
IN PSD_FDO_DATA FdoData,
IN PIRP Irp
);
VOID
pSD_ProcessQueuedRequests (
IN PSD_FDO_DATA FdoData
);
VOID
SD_CancelQueued (
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
);
NTSTATUS
pSD_CanStopDevice (
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
);
NTSTATUS
pSD_CanRemoveDevice (
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
);
#ifdef ALLOC_PRAGMA
#pragma alloc_text (INIT, DriverEntry)
#pragma alloc_text (PAGE, SD_AddDevice)
#pragma alloc_text (PAGE, SD_StartDevice)
#pragma alloc_text (PAGE, SD_Unload)
#pragma alloc_text (PAGE, SD_IoIncrement)
#endif
NTSTATUS
DriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
)
/*++
Routine Description:
Installable driver initialization entry point.
This entry point is called directly by the I/O system.
Arguments:
DriverObject - pointer to the driver object
RegistryPath - pointer to a unicode string representing the path,
to driver-specific key in the registry.
Return Value:
STATUS_SUCCESS if successful,
STATUS_UNSUCCESSFUL otherwise
--*/
{
NTSTATUS status = STATUS_SUCCESS;
ULONG ulIndex;
PDRIVER_DISPATCH * dispatch;
UNREFERENCED_PARAMETER (RegistryPath);
SD_KdPrint (2, ("Entered the Driver Entry\n"));
//
// Sace the driver object, we'll need it later
//
g_DriverObject = DriverObject;
//
// Create dispatch points
//
for (ulIndex = 0, dispatch = DriverObject->MajorFunction;
ulIndex <= IRP_MJ_MAXIMUM_FUNCTION;
ulIndex++, dispatch++) {
*dispatch = SD_Pass;
}
DriverObject->MajorFunction[IRP_MJ_PNP] = SD_DispatchPnp;
DriverObject->MajorFunction[IRP_MJ_POWER] = SD_DispatchPower;
DriverObject->MajorFunction[IRP_MJ_CREATE] =
DriverObject->MajorFunction[IRP_MJ_CLOSE] = SD_CreateClose;
DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = SD_Ioctl;
DriverObject->DriverExtension->AddDevice = SD_AddDevice;
DriverObject->DriverUnload = SD_Unload;
return status;
}
NTSTATUS
SD_AddDevice(
IN PDRIVER_OBJECT DriverObject,
IN PDEVICE_OBJECT PhysicalDeviceObject
)
/*++
Routine Description:
The PlugPlay subsystem is handing us a brand new PDO, for which we
(by means of INF registration) have been asked to provide a driver.
We need to determine if we need to be in the driver stack for the device.
Create a functional device object to attach to the stack
Initialize that device object
Return status success.
Remember: we can NOT actually send ANY non pnp IRPS to the given driver
stack, UNTIL we have received an IRP_MN_START_DEVICE.
Arguments:
DeviceObject - pointer to a device object.
PhysicalDeviceObject - pointer to a device object created by the
underlying bus driver.
Return Value:
NT status code.
--*/
{
NTSTATUS status = STATUS_SUCCESS;
NTSTATUS status1 = STATUS_SUCCESS;
PDEVICE_OBJECT deviceObject = NULL;
PSD_FDO_DATA fdoData;
PWSTR pBuf;
ULONG resultLen;
PAGED_CODE ();
SD_KdPrint (2, ("AddDevice\n"));
//
// Remember that you CANNOT send an IRP to the PDO because it has not
// been started as of yet, but you can make PlugPlay queries to find
// out things like hardware, compatible ID's, etc.
//
//
// Create a functional device object.
//
status = IoCreateDevice (DriverObject,
sizeof (SD_FDO_DATA),
NULL, // No Name
FILE_DEVICE_UNKNOWN,
0,
FALSE,
&deviceObject);
if (!NT_SUCCESS (status)) {
//
// returning failure here prevents the entire stack from functioning,
// but most likely the rest of the stack will not be able to create
// device objects either, so it is still OK.
//
return status;
}
//
// Initialize the device extension.
//
fdoData = (PSD_FDO_DATA) deviceObject->DeviceExtension;
//
// Make sure it's zeroed
//
RtlZeroMemory(fdoData, sizeof(PSD_FDO_DATA));
//
// The device is not started yet, but it can queue requests
// BUGBUG - NEED TO CHECK IF THIS CAN BE APPLIED !!!
//
// Also, the device is not removed
//
fdoData->IsStarted = FALSE;
fdoData->IsRemoved = FALSE;
fdoData->IsLegacy = FALSE;
fdoData->HoldNewRequests = TRUE;
fdoData->Self = deviceObject;
fdoData->PDO = PhysicalDeviceObject;
fdoData->NextLowerDriver = NULL;
fdoData->DriverObject = DriverObject;
InitializeListHead(&fdoData->NewRequestsQueue);
KeInitializeEvent(&fdoData->RemoveEvent, SynchronizationEvent, FALSE);
fdoData->OutstandingIO = 1; // biassed to 1. Transition to zero during
// remove device means IO is finished.
//
// 04/20/2002 - Initialize the PDO list as well...
//
InitializeListHead(&fdoData->PdoList);
KeInitializeSpinLock(&fdoData->Lock);
deviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
//
// Attach our driver to the device stack.
// the return value of IoAttachDeviceToDeviceStack is the top of the
// attachment chain. This is where all the IRPs should be routed.
//
// Our driver will send IRPs to the top of the stack and use the PDO
// for all PlugPlay functions.
//
fdoData->NextLowerDriver = IoAttachDeviceToDeviceStack (deviceObject,
PhysicalDeviceObject);
//
// if this attachment fails then top of stack will be null.
// failure for attachment is an indication of a broken plug play system.
//
ASSERT (NULL != fdoData->NextLowerDriver);
status = IoRegisterDeviceInterface (PhysicalDeviceObject,
(LPGUID) &GUID_WDMSECTEST_REPORT_DEVICE,
NULL, // No ref string
&fdoData->DeviceInterfaceName);
if (!NT_SUCCESS (status)) {
SD_KdPrint (0, ("AddDevice: IoRegisterDeviceInterface failed (%x)",
status));
//
// Remember to detach the device object also
//
IoDetachDevice (deviceObject);
IoDeleteDevice (deviceObject);
return status;
}
return STATUS_SUCCESS;
}
NTSTATUS
SD_Pass (
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
Routine Description:
The default dispatch routine. If this driver does not recognize the
IRP, then it should send it down, unmodified.
If the device holds IRPs, this IRP must be queued in the device extension
No completion routine is required.
As we have NO idea which function we are happily passing on, we can make
NO assumptions about whether or not it will be called at raised IRQL.
For this reason, this function must be in put into non-paged pool
(aka the default location).
Arguments:
DeviceObject - pointer to a device object.
Irp - pointer to an I/O Request Packet.
Return Value:
NT status code
--*/
{
PSD_FDO_DATA fdoData;
NTSTATUS status;
PIO_STACK_LOCATION stack;
LONG requestCount;
fdoData = (PSD_FDO_DATA) DeviceObject->DeviceExtension;
//
// Check if it's our test PDO
//
if (fdoData->PdoSignature == PdoSignature) {
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = STATUS_SUCCESS;
IoCompleteRequest (Irp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
stack = IoGetCurrentIrpStackLocation(Irp);
//
// We need to hold the requests that access the device when it is
// stopped. We are currently holding all the IRP except the PnP,
// power and close.
//
//
//
// This IRP was sent to the function driver.
// We need to check if we are currently holding requests
//
// We will count the Irp only when we're going to process
// (dequeue) it. This is because we can't possibly count before
// we queue it (we can receive a surprise remove in between).
// We also know that when we're going to remove the device, we're
// first processing the queue (so we can't fall in the other
// sequencing trap: queue the Irp, but don't count it).
//
if (fdoData->HoldNewRequests) {
//
// We are holding requests only if we are not removed
//
ASSERT(!fdoData->IsRemoved || fdoData->IsLegacy);
status = STATUS_PENDING;
pSD_QueueRequest(fdoData, Irp);
return status;
}
// Since we do not know what to do with the IRP, we should pass
// it on along down the stack.
//
requestCount = SD_IoIncrement (fdoData);
if (fdoData->IsRemoved) {
//
// The device is not active.
// We can get here because a surprise removal was issued,
// but our request arrived after that.
// The request must be failed.
//
requestCount = SD_IoDecrement(fdoData);
status = STATUS_DELETE_PENDING;
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = status;
IoCompleteRequest (Irp, IO_NO_INCREMENT);
} else {
//
// We are the common situation where we send the IRP
// down on the driver stack
//
requestCount = SD_IoDecrement(fdoData);
IoSkipCurrentIrpStackLocation (Irp);
status = IoCallDriver (fdoData->NextLowerDriver, Irp);
}
return status;
}
NTSTATUS
SD_DispatchPnp (
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
Routine Description:
The plug and play dispatch routines.
Most of these these the driver will completely ignore.
In all cases it must pass on the IRP to the lower driver.
Arguments:
DeviceObject - pointer to a device object.
Irp - pointer to an I/O Request Packet.
Return Value:
NT status code
--*/
{
PSD_FDO_DATA fdoData;
PIO_STACK_LOCATION stack;
NTSTATUS status;
PDEVICE_CAPABILITIES deviceCapabilities;
KIRQL oldIrql;
LONG requestCount;
fdoData = (PSD_FDO_DATA) DeviceObject->DeviceExtension;
stack = IoGetCurrentIrpStackLocation (Irp);
requestCount = SD_IoIncrement (fdoData);
if (fdoData->IsRemoved) {
//
// Since the device is stopped, but we don't hold IRPs,
// this is a surprise removal. Just fail it.
//
requestCount = SD_IoDecrement(fdoData);
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = STATUS_DELETE_PENDING;
IoCompleteRequest (Irp, IO_NO_INCREMENT);
return STATUS_DELETE_PENDING;
}
switch (stack->MinorFunction) {
case IRP_MN_START_DEVICE:
//
// The device is starting.
//
// We cannot touch the device (send it any non pnp irps) until a
// start device has been passed down to the lower drivers.
//
SD_KdPrint(1, ("Starting Device...\n"));
IoCopyCurrentIrpStackLocationToNext (Irp);
KeInitializeEvent(&fdoData->StartEvent, NotificationEvent, FALSE);
IoSetCompletionRoutine (Irp,
SD_DispatchPnpComplete,
fdoData,
TRUE,
TRUE,
TRUE);
status = IoCallDriver (fdoData->NextLowerDriver, Irp);
if (STATUS_PENDING == status) {
KeWaitForSingleObject(
&fdoData->StartEvent,
Executive, // Waiting for reason of a driver
KernelMode, // Waiting in kernel mode
FALSE, // No allert
NULL); // No timeout
status = Irp->IoStatus.Status;
}
if (NT_SUCCESS (status)) {
//
// Lower drivers have finished their start operation, so now
// we can finish ours.
//
status = SD_StartDevice (fdoData, Irp);
}
//
// We must now complete the IRP, since we stopped it in the
// completetion routine with MORE_PROCESSING_REQUIRED.
//
Irp->IoStatus.Status = status;
Irp->IoStatus.Information = 0;
IoCompleteRequest (Irp, IO_NO_INCREMENT);
break;
case IRP_MN_QUERY_STOP_DEVICE:
//
// If we can stop the device, we need to set the HoldNewRequests flag,
// so further requests will be queued. We don't care about processing
// some old requests (if there are any), because we expect to be
// started again in the future.
//
ASSERT(fdoData->IsStarted || fdoData->IsLegacy);
//
// We can't be removed at this point
//
ASSERT(!fdoData->IsRemoved || fdoData->IsLegacy);
//
// BUGBUG - check if it is not possible that a query stop
// to be received while the device is already stopped
//
status = pSD_CanStopDevice(DeviceObject, Irp);
Irp->IoStatus.Status = status;
if (NT_SUCCESS(status)) {
fdoData->HoldNewRequests = TRUE;
SD_KdPrint(1, ("Holding requests...\n"));
IoSkipCurrentIrpStackLocation (Irp);
status = IoCallDriver (fdoData->NextLowerDriver, Irp);
} else {
//
// The device can't be stopped, complete the request
//
IoCompleteRequest(Irp, IO_NO_INCREMENT);
}
break;
case IRP_MN_CANCEL_STOP_DEVICE:
//
// We need to flush the held IRPs queue, then to pass the IRP
// to the next driver
//
//
// The device is still active: only after a stop
// we'll mark the device stopped. So assert now that the
// device is not yet stopped.
//
ASSERT(fdoData->IsStarted || fdoData->IsLegacy);
ASSERT(!fdoData->IsRemoved || fdoData->IsLegacy);
fdoData->HoldNewRequests = FALSE;
SD_KdPrint (1,("Cancel stop...\n"));
//
// Process the queued requests
//
pSD_ProcessQueuedRequests(fdoData);
IoSkipCurrentIrpStackLocation (Irp);
status = IoCallDriver (fdoData->NextLowerDriver, Irp);
break;
case IRP_MN_STOP_DEVICE:
//
// After the stop IRP has been sent to the lower driver object, the
// bus may NOT send any more IRPS down that touch the device until
// another START has occured. For this reason we are holding IRPs.
// IRP_MN_STOP_DEVICE doesn't change anything in this behavior
// (we continue to hold IRPs until a IRP_MN_START_DEVICE is issued).
// What ever access is required must be done before the Irp is passed
// on.
//
//
// We don't need a completion routine so fire and forget.
//
// Set the current stack location to the next stack location and
// call the next device object.
//
//
// This is the right place to actually give up all the resources used
// This might include calls to IoDisconnectInterrupt, etc.
//
SD_KdPrint(1, ("Stopping device...\n"));
//
// Mark the guy not started. We don't have race conditions here, since
// it's not possible to receive a start and a stop Irp
// "at the same time".
//
fdoData->IsStarted = FALSE;
IoSkipCurrentIrpStackLocation (Irp);
status = IoCallDriver (fdoData->NextLowerDriver, Irp);
break;
case IRP_MN_QUERY_REMOVE_DEVICE:
//
// If we can stop the device, we need to set the HoldNewRequestsFlag,
// so further requests will be queued.
// The difference from IRP_MN_QUERY_STOP_DFEVICE is that we will
// attempt to process the requests queued before
// (it's likely we won't have another chance to do this, since we
// expect that the device will be removed).
// We then start queueing new IRPs in the event of receiving a
// IRP_MN_CANCEL_STOP_DEVICE
//
//ASSERT(fdoData->IsStarted);
status = pSD_CanRemoveDevice(DeviceObject, Irp);
Irp->IoStatus.Status = status;
if (NT_SUCCESS(status)) {
//
// First, process the old requests
//
SD_KdPrint(2, ("Processing requests\n"));
pSD_ProcessQueuedRequests(fdoData);
//
// Now prepare to hold the new ones (eventually we might
// get a IRP_MN_CANCEL_REMOVE_DEVICE) and we need to
// process the requests then
//
fdoData->HoldNewRequests = TRUE;
SD_KdPrint(2, ("Holding requests...\n"));
IoSkipCurrentIrpStackLocation (Irp);
status = IoCallDriver (fdoData->NextLowerDriver, Irp);
} else {
//
// The device can't be removed, just complete the request.
// The status returned by pSD_CanRemoveDevice is already
// in IoStatus.Status.
//
IoCompleteRequest(Irp, IO_NO_INCREMENT);
}
break;
case IRP_MN_CANCEL_REMOVE_DEVICE:
//
// We need to reset the HoldNewRequests flag, since the device
// resume its normal activities.
//
//
// Since if there was a surprise removal (Active = FALSE,
// HoldNewRequests = FALSE) we couldn't get here, we safely
// assert that we are active.
//
// ???? Is this correct ???
//
ASSERT (fdoData->IsStarted || fdoData->IsLegacy);
fdoData->HoldNewRequests = FALSE;
SD_KdPrint(1, ("Cancel remove...\n"));
//
// Process the queued requests
//
pSD_ProcessQueuedRequests(fdoData);
IoSkipCurrentIrpStackLocation (Irp);
status = IoCallDriver (fdoData->NextLowerDriver, Irp);
break;
case IRP_MN_REMOVE_DEVICE:
//
// The PlugPlay system has dictacted the removal of this device. We
// have no choice but to detach and delete the device object.
// (If we wanted to express an interest in preventing this removal,
// we should have failed the query remove IRP)
//
// Note! we might receive a remove WITHOUT first receiving a stop.
//
// We will no longer receive requests for this device as it has been
// removed.
//
SD_KdPrint(1, ("Removing device...\n"));
//
// We need to mark the fact that we don't hold requests first, since
// we asserted earlier that we are holding requests only if
// we're not removed.
//
fdoData->HoldNewRequests = FALSE;
fdoData->IsStarted = FALSE;
fdoData->IsRemoved = TRUE;
//
// 04/30/02 - remove any PDOs we may have left
//
KeAcquireSpinLock(&fdoData->Lock, &oldIrql);
while (!IsListEmpty(&fdoData->PdoList)) {
PLIST_ENTRY aux;
PPDO_ENTRY pdoEntry;
aux = RemoveHeadList(&fdoData->PdoList);
KeReleaseSpinLock(&fdoData->Lock, oldIrql);
//
// Delete the device and free the memory
//
pdoEntry = CONTAINING_RECORD(aux, PDO_ENTRY, Link);
ASSERT(pdoEntry->Pdo);
IoDeleteDevice(pdoEntry->Pdo);
ExFreePool(aux);
//
// re-acquire the spinlock
//
KeAcquireSpinLock(&fdoData->Lock, &oldIrql);
}
KeReleaseSpinLock(&fdoData->Lock, oldIrql);
//
// Here if we either have completed all the requests in a personal
// queue when IRP_MN_QUERY_REMOVE was received, or will have to
// fail all of them if this is a surprise removal.
// Note that fdoData->IsRemoved is TRUE, so pSD_ProcessQueuedRequests
// will simply delete the queue, completing each IRP with
// STATUS_DELETE_PENDING
//
pSD_ProcessQueuedRequests(fdoData);
//
// Turn off the device interface
//
IoSetDeviceInterfaceState(&fdoData->DeviceInterfaceName, FALSE);
//
// Delete the associated buffer
//
if (fdoData->DeviceInterfaceName.Buffer) {
ExFreePool(fdoData->DeviceInterfaceName.Buffer);
fdoData->DeviceInterfaceName.Buffer = NULL;
}
//
// Update the status
//
Irp->IoStatus.Status = STATUS_SUCCESS;
//
// Send on the remove IRP
//
IoSkipCurrentIrpStackLocation (Irp);
status = IoCallDriver (fdoData->NextLowerDriver, Irp);
//
// We need two decrements here, one for the increment in
// SD_PnpDispatch, the other for the 1-biased value of
// OutstandingIO. Also, we need to wait that all the requests
// are served.
//
requestCount = SD_IoDecrement (fdoData);
//
// The requestCount is a least one here (is 1-biased)
//
ASSERT(requestCount > 0);
requestCount = SD_IoDecrement (fdoData);
KeWaitForSingleObject (
&fdoData->RemoveEvent,
Executive,
KernelMode,
FALSE,
NULL);
//
// Detach the FDO from the device stack
//
IoDetachDevice (fdoData->NextLowerDriver);
//
// Clean up memory
//
IoDeleteDevice (fdoData->Self);
return STATUS_SUCCESS;
case IRP_MN_QUERY_CAPABILITIES:
//
// We will provide here an example of an IRP that is procesed
// both on its way down and on its way up. The driver will wait
// for the lower driver objects (the bus driver among them) to
// process this IRP, then it processes it again
//
//
// We will specifically check for UINumber: even if the bus can't
// support such a convention, we will still supply the value we want.
//
SD_KdPrint(2, ("Query Capabilities, way down...\n"));
deviceCapabilities = stack->Parameters.DeviceCapabilities.Capabilities;
//
// Set some values here...
//
// .......................
//
deviceCapabilities->UINumber = 1;
//
// Prepare to pass the IRP down
//
IoCopyCurrentIrpStackLocationToNext (Irp);
//
// We will re-use the same start event
//
KeInitializeEvent(&fdoData->StartEvent, NotificationEvent, FALSE);
IoSetCompletionRoutine (Irp,
SD_DispatchPnpComplete,
fdoData,
TRUE,
TRUE,
TRUE);
status = IoCallDriver (fdoData->NextLowerDriver, Irp);
if (STATUS_PENDING == status) {
KeWaitForSingleObject(
&fdoData->StartEvent,
Executive, // Waiting for reason of a driver
KernelMode, // Waiting in kernel mode
FALSE, // No allert
NULL); // No timeout
status = Irp->IoStatus.Status;
}
if (NT_SUCCESS (status)) {
//
// Lower drivers have finished their operation, so now
// we can finish ours. We are going to check the UINumber
// we've set on the way down and reset it if necessary.
// This is only an example of processing an IRP both before
// it's sent to the lower drivers and after it was processed
// by them.
//
SD_KdPrint(2, ("Query Capabilities, way up...\n"));
if (deviceCapabilities->UINumber != 1) {
deviceCapabilities->UINumber = 1;
}
}
//
// We must now complete the IRP, since we stopped it in the
// completetion routine with MORE_PROCESSING_REQUIRED.
//
Irp->IoStatus.Status = status;
Irp->IoStatus.Information = 0;
IoCompleteRequest (Irp, IO_NO_INCREMENT);
break;
case IRP_MN_QUERY_DEVICE_RELATIONS:
case IRP_MN_QUERY_INTERFACE:
case IRP_MN_QUERY_RESOURCES:
case IRP_MN_QUERY_RESOURCE_REQUIREMENTS:
case IRP_MN_READ_CONFIG:
case IRP_MN_WRITE_CONFIG:
case IRP_MN_EJECT:
case IRP_MN_SET_LOCK:
case IRP_MN_QUERY_ID:
case IRP_MN_QUERY_PNP_DEVICE_STATE:
default:
//
// Here the driver might modify the behavior of these IRPS
// Please see PlugPlay documentation for use of these IRPs.
//
IoSkipCurrentIrpStackLocation (Irp);
status = IoCallDriver (fdoData->NextLowerDriver, Irp);
break;
}
requestCount = SD_IoDecrement(fdoData);
return status;
}
NTSTATUS
SD_DispatchPnpComplete (
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context
)
/*++
Routine Description:
The pnp IRP was completed by the lower-level drivers.
Signal this to whoever registerd us.
Arguments:
DeviceObject - pointer to a device object.
Irp - pointer to an I/O Request Packet.
Context - pointer to a SD_FDO_DATA structure (contains the event to be
signaled)
Return Value:
NT status code
--*/
{
PIO_STACK_LOCATION stack;
PSD_FDO_DATA fdoData;
NTSTATUS status;
UNREFERENCED_PARAMETER (DeviceObject);
status = STATUS_SUCCESS;
fdoData = (PSD_FDO_DATA) Context;
stack = IoGetCurrentIrpStackLocation (Irp);
if (Irp->PendingReturned) {
IoMarkIrpPending( Irp );
}
switch (stack->MajorFunction) {
case IRP_MJ_PNP:
switch (stack->MinorFunction) {
case IRP_MN_START_DEVICE:
KeSetEvent (&fdoData->StartEvent, 0, FALSE);
//
// Take the IRP back so that we can continue using it during
// the IRP_MN_START_DEVICE dispatch routine.
// NB: The dispatch routine will have to call IoCompleteRequest
//
return STATUS_MORE_PROCESSING_REQUIRED;
case IRP_MN_QUERY_CAPABILITIES:
KeSetEvent (&fdoData->StartEvent, 0, FALSE);
//
// This is basically the same behavior as at IRP_MN_START_DEVICE
//
return STATUS_MORE_PROCESSING_REQUIRED;
default:
break;
}
break;
case IRP_MJ_POWER:
default:
break;
}
return status;
}
NTSTATUS
SD_CreateClose (
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
Routine Description:
The dispatch routine for IRP_MJ_CLOSE and IRP_MJ_CREATE.
Since we use an IOCTL interface, don't pass those down,
just complete them succesfully here.
Arguments:
DeviceObject - pointer to a device object.
Irp - pointer to an I/O Request Packet.
Return Value:
NT status code
--*/
{
PSD_FDO_DATA fdoData;
NTSTATUS status;
PIO_STACK_LOCATION irpStack;
//
// We will just pass this IRP down, no matter what the circumstances...
//
fdoData = (PSD_FDO_DATA) DeviceObject->DeviceExtension;
//
// Check if it's our test PDO
//
if (fdoData->PdoSignature == PdoSignature) {
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = STATUS_SUCCESS;
IoCompleteRequest (Irp, IO_NO_INCREMENT);
return STATUS_SUCCESS;
}
status = STATUS_SUCCESS;
irpStack = IoGetCurrentIrpStackLocation (Irp);
switch (irpStack->MajorFunction) {
case IRP_MJ_CREATE:
SD_KdPrint(2, ("Create \n"));
break;
case IRP_MJ_CLOSE:
SD_KdPrint (2, ("Close \n"));
break;
default :
break;
}
//
// Just complete it
//
Irp->IoStatus.Status = status;
IoCompleteRequest (Irp, IO_NO_INCREMENT);
return status;
}
NTSTATUS
SD_Ioctl (
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
Routine Description:
The dispatch routine for IRP_MJ_DEVICE_CONTROL.
Process the requests the user-mode sends us.
Arguments:
DeviceObject - pointer to a device object.
Irp - pointer to an I/O Request Packet.
Return Value:
NT status code
--*/
{
PIO_STACK_LOCATION irpStack;
NTSTATUS status;
ULONG inlen;
ULONG outlen;
PSD_FDO_DATA fdoData;
PVOID buffer;
LONG requestCount;
KIRQL oldIrql;
PAGED_CODE();
status = STATUS_SUCCESS;
irpStack = IoGetCurrentIrpStackLocation (Irp);
ASSERT (IRP_MJ_DEVICE_CONTROL == irpStack->MajorFunction);
fdoData = (PSD_FDO_DATA) DeviceObject->DeviceExtension;
//
// Count ourselves
//
requestCount = SD_IoIncrement(fdoData);
if (fdoData->IsRemoved) {
//
// Since the device is stopped, but we don't hold IRPs,
// this is a surprise removal. Just fail it.
//
requestCount = SD_IoDecrement(fdoData);
Irp->IoStatus.Information = 0;
Irp->IoStatus.Status = STATUS_DELETE_PENDING;
IoCompleteRequest (Irp, IO_NO_INCREMENT);
return STATUS_DELETE_PENDING;
}
buffer = Irp->AssociatedIrp.SystemBuffer;
inlen = irpStack->Parameters.DeviceIoControl.InputBufferLength;
outlen = irpStack->Parameters.DeviceIoControl.OutputBufferLength;
switch (irpStack->Parameters.DeviceIoControl.IoControlCode) {
case IOCTL_TEST_NAME :
//
// No input parameters, just check we
// get an error for NULL DeviceName
//
status = WdmSecTestName(fdoData);
break;
case IOCTL_TEST_GUID:
if ((inlen == outlen) &&
(sizeof(WST_CREATE_WITH_GUID) <= inlen)
) {
status = WdmSecTestCreateWithGuid(fdoData,
(PWST_CREATE_WITH_GUID)buffer);
Irp->IoStatus.Information = outlen;
} else {
status = STATUS_INVALID_PARAMETER;
}
break;
case IOCTL_TEST_NO_GUID :
if ((inlen == outlen) &&
(sizeof(WST_CREATE_NO_GUID) <= inlen)
) {
status = WdmSecTestCreateNoGuid(fdoData,
(PWST_CREATE_NO_GUID)buffer);
Irp->IoStatus.Information = outlen;
} else {
status = STATUS_INVALID_PARAMETER;
}
break;
case IOCTL_TEST_CREATE_OBJECT :
if ((inlen == outlen) &&
(sizeof(WST_CREATE_OBJECT) <= inlen)
) {
status = WdmSecTestCreateObject(fdoData,
(PWST_CREATE_OBJECT)buffer);
Irp->IoStatus.Information = outlen;
} else {
status = STATUS_INVALID_PARAMETER;
}
break;
case IOCTL_TEST_GET_SECURITY :
if ((inlen == outlen) &&
(sizeof(WST_GET_SECURITY) <= inlen)
) {
status = WdmSecTestGetSecurity(fdoData,
(PWST_GET_SECURITY)buffer);
Irp->IoStatus.Information = outlen;
} else {
status = STATUS_INVALID_PARAMETER;
}
break;
case IOCTL_TEST_DESTROY_OBJECT :
if ((inlen == outlen) &&
(sizeof(WST_DESTROY_OBJECT) <= inlen)
) {
status = WdmSecTestDestroyObject(fdoData,
(PWST_DESTROY_OBJECT)buffer);
Irp->IoStatus.Information = outlen;
} else {
status = STATUS_INVALID_PARAMETER;
}
break;
default:
status = STATUS_INVALID_PARAMETER;
break;
}
requestCount = SD_IoDecrement (fdoData);
Irp->IoStatus.Status = status;
IoCompleteRequest (Irp, IO_NO_INCREMENT);
return status;
}
NTSTATUS
SD_StartDevice (
IN PSD_FDO_DATA FdoData,
IN PIRP Irp
)
/*++
Routine Description:
Performs whatever initialization is needed for a device when it is
started.
Arguments:
DeviceObject - pointer to a device object.
Irp - pointer to an I/O Request Packet.
Context - pointer to a SD_FDO_DATA structure (contains the event to be
signaled)
Return Value:
NT status code
--*/
{
NTSTATUS status = STATUS_SUCCESS;
PAGED_CODE();
//
// We need to check that we haven't received a surprise removal
//
// !!!!!! IS THE SITUATION DESCRIBED ABOVE POSSIBLE ? !!!!!
//
if (FdoData->IsRemoved) {
//
// Some kind of surprise removal arrived. We will fail the IRP
// The dispatch routine that called us will take care of
// completing the IRP.
//
status = STATUS_DELETE_PENDING;
return status;
}
//
// Mark the device as active and not holding IRPs
//
FdoData->IsStarted = TRUE;
FdoData->HoldNewRequests = FALSE;
//
// Do whatever initialization needed when starting the device:
// gather information about it, update the registry, etc.
// At this point, the lower level drivers completed the IRP
//
//
// Turn on the device interafce
//
IoSetDeviceInterfaceState(&FdoData->DeviceInterfaceName, TRUE);
//
// The last thing to do is to process the held IRPs queue.
//
pSD_ProcessQueuedRequests(FdoData);
return status;
}
VOID
SD_Unload(
IN PDRIVER_OBJECT DriverObject
)
/*++
Routine Description:
Free all the allocated resources, etc.
Arguments:
DriverObject - pointer to a driver object.
Return Value:
VOID.
--*/
{
PAGED_CODE ();
//
// The device object(s) should be NULL now
// (since we unload, all the devices objects associated with this
// driver must be deleted.
//
ASSERT(DriverObject->DeviceObject == NULL);
//
// We should not be unloaded until all the devices we control
// have been removed from our queue.
//
SD_KdPrint (1, ("unload\n"));
return;
}
NTSTATUS
pSD_QueueRequest (
IN PSD_FDO_DATA FdoData,
IN PIRP Irp
)
/*++
Routine Description:
Queues the Irp in the device queue. This routine will be called whenever
the device receives IRP_MN_QUERY_STOP_DEVICE or IRP_MN_QUERY_REMOVE_DEVICE
Arguments:
FdoData - pointer to the device's extension.
Irp - the request to be queued.
Return Value:
VOID.
--*/
{
KIRQL oldIrql;
PIO_STACK_LOCATION stack;
stack = IoGetCurrentIrpStackLocation(Irp);
//
// Check if we are allowed to queue requests.
//
ASSERT(FdoData->HoldNewRequests);
//
// Preparing for dealing with cancelling stuff.
//
IoAcquireCancelSpinLock(&oldIrql);
//
// We don't know how long the irp will be in the
// queue. So we need to handle cancel.
//
if (Irp->Cancel) {
//
// Already canceled
//
IoReleaseCancelSpinLock(oldIrql);
Irp->IoStatus.Status = STATUS_CANCELLED;
SD_KdPrint(1, ("Irp not queued because had been cancelled\n"));
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return STATUS_CANCELLED;
} else {
//
// Queue the Irp and set a cancel routine
//
Irp->IoStatus.Status = STATUS_PENDING;
IoMarkIrpPending(Irp);
InsertTailList(&FdoData->NewRequestsQueue,
&Irp->Tail.Overlay.ListEntry);
//
// We need to print some more info about this guy
//
SD_KdPrint(2, ("Irp queued : "));
DbgPrint("Major = 0x%x, Minor = 0x%x\n",
stack->MajorFunction,
stack->MinorFunction);
IoSetCancelRoutine(Irp,
SD_CancelQueued);
IoReleaseCancelSpinLock(oldIrql);
}
return STATUS_SUCCESS;
}
VOID
pSD_ProcessQueuedRequests (
IN PSD_FDO_DATA FdoData
)
/*++
Routine Description:
Removes the entries in the queue and processes them. If this routine is called
when processing IRP_MN_CANCEL_STOP_DEVICE, IRP_MN_CANCEL_REMOVE_DEVICE
or IRP_MN_START_DEVICE, the requests are passed to the next lower driver.
If the routine is called when IRP_MN_REMOVE_DEVICE is received, the IRPs
are completed with STATUS_DELETE_PENDING.
Arguments:
FdoData - pointer to the device's extension (where is the held IRPs queue).
Return Value:
VOID.
--*/
{
KIRQL oldIrql;
PLIST_ENTRY headOfList;
PIRP currentIrp;
PIO_STACK_LOCATION stack;
LONG requestCount;
//
// We need to dequeue all the entries in the queue, to reset the cancel
// routine for each of them and then to process then:
// - if the device is active, we will send them down
// - else we will complete them with STATUS_DELETE_PENDING
// (it is a surprise removal and we need to dispose the queue)
//
while (!IsListEmpty(&FdoData->NewRequestsQueue)) {
IoAcquireCancelSpinLock(&oldIrql);
headOfList = RemoveHeadList(&FdoData->NewRequestsQueue);
currentIrp = CONTAINING_RECORD(headOfList,
IRP,
Tail.Overlay.ListEntry);
IoSetCancelRoutine(currentIrp,
NULL);
IoReleaseCancelSpinLock(oldIrql);
//
// BUGBUG !!!!!!! What of them to be done first ?????
//
stack = IoGetCurrentIrpStackLocation (currentIrp);
requestCount = SD_IoIncrement (FdoData);
if (!FdoData->IsRemoved) {
//
// The device was removed, we need to fail the request
//
currentIrp->IoStatus.Information = 0;
currentIrp->IoStatus.Status = STATUS_DELETE_PENDING;
requestCount = SD_IoDecrement(FdoData);
IoCompleteRequest (currentIrp, IO_NO_INCREMENT);
} else {
requestCount = SD_IoDecrement(FdoData);
IoSkipCurrentIrpStackLocation (currentIrp);
IoCallDriver (FdoData->NextLowerDriver, currentIrp);
}
}
return;
}
VOID
SD_CancelQueued (
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
Routine Description:
The cancel routine. Will remove the IRP from the queue and will complete it.
The cancel spin lock is already acquired when this routine is called.
Arguments:
DeviceObject - pointer to the device object.
Irp - pointer to the IRP to be cancelled.
Return Value:
VOID.
--*/
{
PSD_FDO_DATA fdoData = DeviceObject->DeviceExtension;
PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(Irp);
Irp->IoStatus.Status = STATUS_CANCELLED;
Irp->IoStatus.Information = 0;
RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
IoReleaseCancelSpinLock(Irp->CancelIrql);
SD_KdPrint(2, ("SD_CancelQueued called"));
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return;
}
NTSTATUS
pSD_CanStopDevice (
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
Routine Description:
This routine determines is the device can be safely stopped. In our
particular case, we'll assume we can always stop the device.
Arguments:
DeviceObject - pointer to the device object.
Irp - pointer to the current IRP.
Return Value:
STATUS_SUCCESS if the device can be safely stopped, an appropriate
NT Status if not.
--*/
{
UNREFERENCED_PARAMETER(DeviceObject);
UNREFERENCED_PARAMETER(Irp);
return STATUS_SUCCESS;
}
NTSTATUS
pSD_CanRemoveDevice (
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp
)
/*++
Routine Description:
This routine determines is the device can be safely removed. In our
particular case, we'll assume we can always remove the device.
Arguments:
DeviceObject - pointer to the device object.
Irp - pointer to the current IRP.
Return Value:
STATUS_SUCCESS if the device can be safely removed, an appropriate
NT Status if not.
--*/
{
UNREFERENCED_PARAMETER(DeviceObject);
UNREFERENCED_PARAMETER(Irp);
return STATUS_SUCCESS;
}
LONG
SD_IoIncrement (
IN PSD_FDO_DATA FdoData
)
/*++
Routine Description:
This routine increments the number of requests the device receives
Arguments:
DeviceObject - pointer to the device object.
Return Value:
The value of OutstandingIO field in the device extension.
--*/
{
LONG result;
KIRQL irql;
result = InterlockedIncrement(&FdoData->OutstandingIO);
ASSERT(result > 0);
irql = KeRaiseIrqlToDpcLevel();
KeLowerIrql(irql);
return result;
}
LONG
SD_IoDecrement (
IN PSD_FDO_DATA FdoData
)
/*++
Routine Description:
This routine increments the number of requests the device receives
Arguments:
DeviceObject - pointer to the device object.
Return Value:
The value of OutstandingIO field in the device extension.
--*/
{
LONG result;
result = InterlockedDecrement(&FdoData->OutstandingIO);
ASSERT(result >= 0);
if (result == 0) {
//
// The count is 1-biased, so it cxan be zero only if an
// extra decrement is done when a remove Irp is received
//
ASSERT(FdoData->IsRemoved || FdoData->IsLegacy);
//
// Set the remove event, so the device object can be deleted
//
KeSetEvent (&FdoData->RemoveEvent,
IO_NO_INCREMENT,
FALSE);
}
return result;
}
//
// Test functions
//
NTSTATUS
WdmSecTestName (
IN PSD_FDO_DATA FdoData
)
/*++
Routine Description:
This routine tests if we can call IoCreateDeviceSecure without a
device name or with an autogenerated one (we should not be able to).
Arguments:
FdoData - the device data (we may use it for some purpose)
Return Value:
STATUS_SUCCESS
--*/
{
NTSTATUS status = STATUS_SUCCESS;
PDEVICE_OBJECT newDeviceObject;
UNICODE_STRING deviceName;
RtlInitUnicodeString(&deviceName, DEFAULT_DEVICE_NAME);
//
// Try a NULL name, it should not work
//
status = IoCreateDeviceSecure(
FdoData->DriverObject,
DEFAULT_EXTENSION_SIZE,
NULL,
DEFAULT_DEVICE_TYPE,
DEFAULT_DEVICE_CHARACTERISTICS,
FALSE,
&SDDL_DEVOBJ_SYS_ALL,
NULL,
&newDeviceObject
);
if (status != STATUS_INVALID_PARAMETER) {
//
// This should not happen. Just break
//
SD_KdPrint(0, ("IoCreateDeviceSecure with NULL DeviceName succeeded (DO = %p, status = %x)\n",
newDeviceObject, status));
DbgBreakPoint();
IoDeleteDevice(newDeviceObject);
} else {
SD_KdPrint(1, ("Status %x after IoCreateDeviceSecure with NULL DeviceName\n", status));
}
//
// Autogenerated flag
//
status = IoCreateDeviceSecure(
FdoData->DriverObject,
DEFAULT_EXTENSION_SIZE,
&deviceName,
DEFAULT_DEVICE_TYPE,
(FILE_DEVICE_SECURE_OPEN | FILE_AUTOGENERATED_DEVICE_NAME),
FALSE,
&SDDL_DEVOBJ_SYS_ALL,
NULL,
&newDeviceObject
);
if (status != STATUS_SUCCESS) {
//
// This should not happen. Just break
//
SD_KdPrint(0, ("IoCreateDeviceSecure with autogenerated DeviceName succeeded (DO = %p, status = %x)\n",
newDeviceObject, status));
DbgBreakPoint();
} else {
//
// We need to remember to delete the device object. D'oh !
//
SD_KdPrint(1, ("Status %x after IoCreateDeviceSecure with autogenerated DeviceName\n", status));
IoDeleteDevice(newDeviceObject);
}
return STATUS_SUCCESS;
} // WdmSecTestName
NTSTATUS
WdmSecTestCreateNoGuid (
IN PSD_FDO_DATA FdoData,
IN OUT PWST_CREATE_NO_GUID Create
)
/*++
Routine Description:
This routine calls IoCreateDeviceSecure with a NULL GUID
and a SDDL syting passed from user-mode. It then retrieves
the security descriptor of the newly created device object
and passes back to user-mode for verifying that it's security
matches the SDDL string.
Arguments:
FdoData - the device data
Create - the buffer passed from user-mode describing the SDDL string
and which will receive the SDDL string we got from the newly
created device object.
Return Value:
STATUS_SUCCESS
--*/
{
NTSTATUS status = STATUS_SUCCESS;
PDEVICE_OBJECT newDeviceObject = NULL;
UNICODE_STRING deviceName;
UNICODE_STRING sddlString;
BOOLEAN memoryAllocated = FALSE;
PSECURITY_DESCRIPTOR securityDescriptor = NULL;
SECURITY_INFORMATION securityInformation;
BOOLEAN daclFromDefaultSource;
RtlInitUnicodeString(&deviceName, DEFAULT_DEVICE_NAME);
RtlInitUnicodeString(&sddlString, Create->InSDDL);
//
// Use the sddl string
//
Create->Status = IoCreateDeviceSecure(
FdoData->DriverObject,
DEFAULT_EXTENSION_SIZE,
&deviceName,
DEFAULT_DEVICE_TYPE,
DEFAULT_DEVICE_CHARACTERISTICS,
FALSE,
&sddlString,
NULL,
&newDeviceObject
);
if (NT_SUCCESS(Create->Status)) {
//
// Attempt to get the security descriptor
//
status = ObGetObjectSecurity(newDeviceObject,
&securityDescriptor,
&memoryAllocated);
if (!NT_SUCCESS(status) || (NULL == securityDescriptor)) {
Create->Status = status;
SD_KdPrint(0, ("Failed to get object security for %p, status %x\n",
newDeviceObject, status));
goto Clean0;
}
status = SeUtilSecurityInfoFromSecurityDescriptor(securityDescriptor,
&daclFromDefaultSource,
&securityInformation
);
if (!NT_SUCCESS(status)) {
Create->Status = status;
SD_KdPrint(0, ("Failed to get object security info for %p, status %x\n",
newDeviceObject, status));
goto Clean0;
}
Create->SecInfo = securityInformation;
//
// Set the stage to create the security descriptor
//
Create->SecDescLength = RtlLengthSecurityDescriptor(securityDescriptor);
//
// Just copy the security descriptor
//
if (Create->SecDescLength <= sizeof(Create->SecurityDescriptor)) {
RtlCopyMemory(Create->SecurityDescriptor,
securityDescriptor,
Create->SecDescLength);
} else {
Create->Status = STATUS_BUFFER_TOO_SMALL;
RtlCopyMemory(Create->SecurityDescriptor,
securityDescriptor,
sizeof(Create->SecurityDescriptor));
}
}
Clean0:
ObReleaseObjectSecurity(securityDescriptor, memoryAllocated);
if (newDeviceObject) {
IoDeleteDevice(newDeviceObject);
}
return STATUS_SUCCESS;
} // WdmSecTestCreateNoGuid
NTSTATUS
WdmSecTestCreateWithGuid (
IN PSD_FDO_DATA FdoData,
IN OUT PWST_CREATE_WITH_GUID Create
)
/*++
Routine Description:
This routine calls IoCreateDeviceSecure with a GUID (non-NULL)
and a SDDL syting passed from user-mode. It then retrieves
the security descriptor of the newly created device object
and passes back to user-mode for verifying that it's security
matches the SDDL string or the class override.
Arguments:
FdoData - the device data
Create - the buffer passed from user-mode describing the SDDL string
and which will receive the SDDL string we got from the newly
created device object.
Return Value:
STATUS_SUCCESS
--*/
{
NTSTATUS status = STATUS_SUCCESS;
PDEVICE_OBJECT newDeviceObject = NULL;
UNICODE_STRING deviceName;
UNICODE_STRING sddlString;
BOOLEAN memoryAllocated = FALSE;
PSECURITY_DESCRIPTOR securityDescriptor = NULL;
SECURITY_INFORMATION securityInformation;
BOOLEAN daclFromDefaultSource;
DEVICE_TYPE deviceType;
ULONG deviceCharacteristics;
BOOLEAN exclusivity;
RtlInitUnicodeString(&deviceName, DEFAULT_DEVICE_NAME);
RtlInitUnicodeString(&sddlString, Create->InSDDL);
//
// Check is we have overrides. If we do, we want to
// make sure we're not using the override values
// (so we can actually check that the override has happened).
//
if ((Create->SettingsMask & SET_DEVICE_TYPE) &&
(Create->DeviceType == DEFAULT_DEVICE_TYPE)) {
//
// Just use another one
//
deviceType = FILE_DEVICE_NULL;
} else {
deviceType = DEFAULT_DEVICE_TYPE;
}
if ((Create->SettingsMask & SET_DEVICE_CHARACTERISTICS) &&
(Create->Characteristics == DEFAULT_DEVICE_CHARACTERISTICS)) {
//
// Just use another one
//
deviceCharacteristics = FILE_REMOTE_DEVICE;
} else {
deviceCharacteristics = DEFAULT_DEVICE_CHARACTERISTICS;
}
if (Create->SettingsMask & SET_EXCLUSIVITY) {
//
// That's a boolean, just flip it
//
exclusivity = !Create->Exclusivity;
} else {
exclusivity = FALSE;
}
//
// Use the sddl string
//
Create->Status = IoCreateDeviceSecure(
FdoData->DriverObject,
DEFAULT_EXTENSION_SIZE,
&deviceName,
deviceType,
deviceCharacteristics,
exclusivity,
&sddlString,
&Create->DeviceClassGuid,
&newDeviceObject
);
if (NT_SUCCESS(Create->Status)) {
//
// Attempt to get the security descriptor
//
status = ObGetObjectSecurity(newDeviceObject,
&securityDescriptor,
&memoryAllocated);
if (!NT_SUCCESS(status) || (NULL == securityDescriptor)) {
Create->Status = status;
SD_KdPrint(0, ("Failed to get object security for %p, status %x\n",
newDeviceObject, status));
goto Clean0;
}
status = SeUtilSecurityInfoFromSecurityDescriptor(securityDescriptor,
&daclFromDefaultSource,
&securityInformation
);
if (!NT_SUCCESS(status)) {
Create->Status = status;
SD_KdPrint(0, ("Failed to get object security info for %p, status %x\n",
newDeviceObject, status));
goto Clean0;
}
Create->SecInfo = securityInformation;
//
// Set the stage to create the security descriptor
//
Create->SecDescLength = RtlLengthSecurityDescriptor(securityDescriptor);
//
// Just copy the security descriptor
//
if (Create->SecDescLength <= sizeof(Create->SecurityDescriptor)) {
RtlCopyMemory(Create->SecurityDescriptor,
securityDescriptor,
Create->SecDescLength);
} else {
Create->Status = STATUS_BUFFER_TOO_SMALL;
RtlCopyMemory(Create->SecurityDescriptor,
securityDescriptor,
sizeof(Create->SecurityDescriptor));
}
}
//
// See if we need to copy back the non-security settings
// that we got back
//
if (Create->SettingsMask & SET_DEVICE_TYPE) {
//
// Get it from the device object
//
Create->DeviceType = newDeviceObject->DeviceType;
}
if (Create->SettingsMask & SET_DEVICE_CHARACTERISTICS) {
//
// Just use another one
//
Create->Characteristics = newDeviceObject->Characteristics;
}
if (Create->SettingsMask & SET_EXCLUSIVITY) {
//
// That's a boolean, just flip it
//
Create->Exclusivity = (newDeviceObject->Flags & DO_EXCLUSIVE) ? TRUE : FALSE;
}
Clean0:
ObReleaseObjectSecurity(securityDescriptor, memoryAllocated);
if (newDeviceObject) {
IoDeleteDevice(newDeviceObject);
}
return STATUS_SUCCESS;
} // WdmSecTestCreateWithGuid
NTSTATUS
WdmSecTestCreateObject (
IN PSD_FDO_DATA FdoData,
IN OUT PWST_CREATE_OBJECT Data
)
/*++
Routine Description:
This routine creates a device object (PDO) without a security
descriptor. The user-mode appplication will later set a security
descriptor and we will retrieve it and check that it matches what
we want.
Arguments:
FdoData - the FDO data
Data - data describing the PDO to create
Return Value:
NT Status code.
--*/
{
NTSTATUS status = STATUS_SUCCESS;
PDEVICE_OBJECT newDeviceObject = NULL;
UNICODE_STRING deviceName;
WCHAR fullName[80];
ULONG id;
PPDO_ENTRY pdoEntry;
//
// Build a unique device name
//
id = InterlockedIncrement((PLONG)&g_PdoId);
fullName[sizeof(fullName)/sizeof(fullName[0]) - 1] = 0;
_snwprintf(fullName,
sizeof(fullName)/sizeof(fullName[0]) - 1,
L"%s%d", DEFAULT_DEVICE_NAME, id);
RtlInitUnicodeString(&deviceName, fullName);
status = IoCreateDevice(
FdoData->DriverObject,
DEFAULT_EXTENSION_SIZE,
&deviceName,
DEFAULT_DEVICE_TYPE,
0,
FALSE,
&newDeviceObject
);
if (NT_SUCCESS(status)) {
//
// Set something in the device extension that
// will allow us to distinguish our FDO from the
// test PDOs
//
*((PULONG)newDeviceObject->DeviceExtension) = PdoSignature;
//
// Add it into our PDO list
//
pdoEntry = ExAllocatePoolWithTag(NonPagedPool,
sizeof(PDO_ENTRY),
'TsdW');
if (NULL == pdoEntry) {
//
// Oops, something wrong has happened
//
IoDeleteDevice(newDeviceObject);
return STATUS_INSUFFICIENT_RESOURCES;
}
pdoEntry->Pdo = newDeviceObject;
Data->DevObj = newDeviceObject;
wcsncpy(Data->Name,
fullName,
sizeof(Data->Name)/sizeof(Data->Name[0]) - 1);
ExInterlockedInsertTailList(&FdoData->PdoList,
&pdoEntry->Link,
&FdoData->Lock);
//
// Signal we're done with initializing...
//
newDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
}
return status;
} // WdmSecTestCreateObject
NTSTATUS
WdmSecTestGetSecurity (
IN PSD_FDO_DATA FdoData,
IN OUT PWST_GET_SECURITY Data
)
/*++
Routine Description:
This routine retrieves the security descriptor for
a PDO.
Arguments:
FdoData - the FDO data
Data - data that will receive the security descriptor
Return Value:
NT Status code.
--*/
{
NTSTATUS status = STATUS_SUCCESS;
PPDO_ENTRY pdoEntry = NULL;
KIRQL oldIrql;
PLIST_ENTRY aux;
BOOLEAN found = FALSE;
BOOLEAN memoryAllocated = FALSE;
PSECURITY_DESCRIPTOR securityDescriptor = NULL;
PDEVICE_OBJECT pdo;
//
// Try to find the pdo in the list
//
KeAcquireSpinLock(&FdoData->Lock, &oldIrql);
aux = FdoData->PdoList.Flink;
while (aux != &FdoData->PdoList) {
pdoEntry = CONTAINING_RECORD(aux, PDO_ENTRY, Link);
if (pdoEntry->Pdo == Data->DevObj) {
found = TRUE;
//
// Make sure the device object does not go away
// We're going to take a reference here for this event...
//
pdo = pdoEntry->Pdo;
ObReferenceObject(pdo);
break;
}
}
KeReleaseSpinLock(&FdoData->Lock, oldIrql);
if (FALSE == found) {
SD_KdPrint(0, ("Could not find DO %p in our list\n",
Data->DevObj));
return STATUS_INVALID_PARAMETER;
}
//
// Get the security descriptor for this guy...
//
status = ObGetObjectSecurity(pdo,
&securityDescriptor,
&memoryAllocated);
if (!NT_SUCCESS(status) || (NULL == securityDescriptor)) {
SD_KdPrint(0, ("Failed to get object security for %p, status %x\n",
pdo, status));
goto Clean0;
}
//
// Set the stage to create the security descriptor
//
Data->Length = RtlLengthSecurityDescriptor(securityDescriptor);
//
// Just copy the security descriptor
//
if (Data->Length <= sizeof(Data->SecurityDescriptor)) {
RtlCopyMemory(Data->SecurityDescriptor,
securityDescriptor,
Data->Length);
} else {
RtlCopyMemory(Data->SecurityDescriptor,
securityDescriptor,
sizeof(Data->SecurityDescriptor));
}
Clean0:
//
// remember we referenced the PDO ?
//
ObDereferenceObject(pdo);
ObReleaseObjectSecurity(securityDescriptor, memoryAllocated);
return status;
} // WdmSecTestCreateObject
NTSTATUS
WdmSecTestDestroyObject (
IN PSD_FDO_DATA FdoData,
IN OUT PWST_DESTROY_OBJECT Data
)
/*++
Routine Description:
This routine destroys a device object (PDO) previously created.
Arguments:
FdoData - the FDO data
Data - data describing the PDO to destroy
Return Value:
NT Status code.
--*/
{
NTSTATUS status = STATUS_SUCCESS;
PDEVICE_OBJECT pdo;
PPDO_ENTRY pdoEntry = NULL;
KIRQL oldIrql;
PLIST_ENTRY aux;
BOOLEAN found = FALSE;
//
// Try to find the pdo in the list
//
KeAcquireSpinLock(&FdoData->Lock, &oldIrql);
aux = FdoData->PdoList.Flink;
while (aux != &FdoData->PdoList) {
pdoEntry = CONTAINING_RECORD(aux, PDO_ENTRY, Link);
if (pdoEntry->Pdo == Data->DevObj) {
found = TRUE;
RemoveEntryList(&pdoEntry->Link);
break;
}
}
KeReleaseSpinLock(&FdoData->Lock, oldIrql);
if (FALSE == found) {
SD_KdPrint(0, ("Could not find DO %p in our list\n",
Data->DevObj));
return STATUS_INVALID_PARAMETER;
}
//
// Delete the device and free the memory
//
ASSERT(pdoEntry->Pdo);
IoDeleteDevice(pdoEntry->Pdo);
ExFreePool(pdoEntry);
return status;
} // WdmSecTestDestroyObject