658 lines
13 KiB
C
658 lines
13 KiB
C
/*++
|
||
|
||
Copyright (c) 1998 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
init.c
|
||
|
||
Abstract:
|
||
|
||
This module performs initialization for the SPUD device driver.
|
||
|
||
Author:
|
||
|
||
John Ballard (jballard) 21-Oct-1996
|
||
|
||
Revision History:
|
||
|
||
Keith Moore (keithmo) 04-Feb-1998
|
||
Cleanup, added much needed comments.
|
||
|
||
--*/
|
||
|
||
|
||
#include "spudp.h"
|
||
|
||
|
||
//
|
||
// Private constants.
|
||
//
|
||
|
||
#define REGISTRY_SPUD_INFORMATION L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\Spud"
|
||
#define REGISTRY_PARAMETERS L"Parameters"
|
||
|
||
#define REGISTRY_DO_NOT_LOAD L"DoNotLoad"
|
||
|
||
#if DBG
|
||
#define REGISTRY_BREAK_ON_STARTUP L"BreakOnStartup"
|
||
#define REGISTRY_USE_PRIVATE_ASSERT L"UsePrivateAssert"
|
||
#endif
|
||
|
||
#if ALLOW_UNLOAD
|
||
#define REGISTRY_ENABLE_UNLOAD L"EnableUnload"
|
||
#endif
|
||
|
||
|
||
//
|
||
// Private globals.
|
||
//
|
||
|
||
BOOLEAN SpudpFailLoad;
|
||
|
||
#if ALLOW_UNLOAD
|
||
BOOLEAN SpudpEnableUnload;
|
||
#endif
|
||
|
||
|
||
//
|
||
// Private prototypes.
|
||
//
|
||
|
||
VOID
|
||
SpudpReadRegistry(
|
||
VOID
|
||
);
|
||
|
||
NTSTATUS
|
||
SpudpOpenRegistry(
|
||
IN PUNICODE_STRING BaseName,
|
||
OUT PHANDLE ParametersHandle
|
||
);
|
||
|
||
ULONG
|
||
SpudpReadSingleParameter(
|
||
IN HANDLE ParametersHandle,
|
||
IN PWCHAR ValueName,
|
||
IN LONG DefaultValue
|
||
);
|
||
|
||
#if ALLOW_UNLOAD
|
||
VOID
|
||
SpudpUnload(
|
||
IN PDRIVER_OBJECT DriverObject
|
||
);
|
||
#endif
|
||
|
||
|
||
#ifdef ALLOC_PRAGMA
|
||
#pragma alloc_text( INIT, DriverEntry )
|
||
#pragma alloc_text( INIT, SpudpReadRegistry )
|
||
#pragma alloc_text( INIT, SpudpOpenRegistry )
|
||
#pragma alloc_text( INIT, SpudpReadSingleParameter )
|
||
#if ALLOW_UNLOAD
|
||
#pragma alloc_text( PAGE, SpudpUnload )
|
||
#endif
|
||
#endif
|
||
|
||
|
||
//
|
||
// Public functions.
|
||
//
|
||
|
||
|
||
NTSTATUS
|
||
DriverEntry(
|
||
IN PDRIVER_OBJECT DriverObject,
|
||
IN PUNICODE_STRING RegistryPath
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This is the initialization routine for the SPUD driver.
|
||
|
||
Arguments:
|
||
|
||
DriverObject - Pointer to driver object created by the system.
|
||
|
||
Return Value:
|
||
|
||
The function value is the final status from the initialization operation.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
NTSTATUS status;
|
||
UNICODE_STRING deviceName;
|
||
|
||
//
|
||
// Sanity check.
|
||
//
|
||
|
||
PAGED_CODE();
|
||
|
||
//
|
||
// Read any configuration information from the registry.
|
||
//
|
||
|
||
SpudpReadRegistry();
|
||
|
||
//
|
||
// If we're configured to fail the load, then bail.
|
||
//
|
||
|
||
if( SpudpFailLoad ) {
|
||
return STATUS_INVALID_DEVICE_REQUEST;
|
||
}
|
||
|
||
//
|
||
// Create and initialize our device object.
|
||
//
|
||
|
||
RtlInitUnicodeString(
|
||
&deviceName,
|
||
SPUD_DEVICE_NAME
|
||
);
|
||
|
||
status = IoCreateDevice(
|
||
DriverObject, // DriverObject
|
||
0, // DeviceExtension
|
||
&deviceName, // DeviceName
|
||
FILE_DEVICE_NAMED_PIPE, // DeviceType
|
||
0, // DeviceCharacteristics
|
||
TRUE, // Exclusive
|
||
&SpudSelfDeviceObject // DeviceObject
|
||
);
|
||
|
||
if( !NT_SUCCESS(status) ) {
|
||
KdPrint(( "SPUD DriverEntry: unable to create device object: %X\n", status ));
|
||
return status;
|
||
}
|
||
|
||
DriverObject->MajorFunction[IRP_MJ_CREATE] = SpudIrpCreate;
|
||
DriverObject->MajorFunction[IRP_MJ_CLOSE] = SpudIrpClose;
|
||
DriverObject->MajorFunction[IRP_MJ_CLEANUP] = SpudIrpCleanup;
|
||
DriverObject->MajorFunction[IRP_MJ_QUERY_INFORMATION] = SpudIrpQuery;
|
||
|
||
#if ALLOW_UNLOAD
|
||
if( SpudpEnableUnload ) {
|
||
DriverObject->DriverUnload = SpudpUnload;
|
||
KdPrint(( "SPUD DriverEntry: unload enabled\n" ));
|
||
}
|
||
#endif
|
||
|
||
//
|
||
// Initialize the context manager.
|
||
//
|
||
|
||
status = SpudInitializeContextManager();
|
||
|
||
if( !NT_SUCCESS(status) ) {
|
||
IoDeleteDevice( SpudSelfDeviceObject );
|
||
return status;
|
||
}
|
||
|
||
//
|
||
// Initialize other global data.
|
||
//
|
||
|
||
status = SpudInitializeData();
|
||
|
||
if( !NT_SUCCESS(status) ) {
|
||
SpudTerminateContextManager();
|
||
IoDeleteDevice( SpudSelfDeviceObject );
|
||
return status;
|
||
}
|
||
|
||
//
|
||
// Add our service table to the system.
|
||
//
|
||
|
||
if( !KeAddSystemServiceTable(
|
||
SpudServiceTable, // Base
|
||
NULL, // Count
|
||
SpudServiceLimit, // Limit
|
||
SpudArgumentTable, // Number
|
||
IIS_SERVICE_INDEX // Index
|
||
) ) {
|
||
SpudTerminateContextManager();
|
||
IoDeleteDevice( SpudSelfDeviceObject );
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
|
||
return status;
|
||
|
||
} // DriverEntry
|
||
|
||
|
||
//
|
||
// Private functions.
|
||
//
|
||
|
||
|
||
VOID
|
||
SpudpReadRegistry(
|
||
VOID
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Reads the SPUD section of the registry. Any values listed in the
|
||
registry override defaults.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
None -- if anything fails, the default value is used.
|
||
|
||
--*/
|
||
{
|
||
|
||
HANDLE parametersHandle;
|
||
NTSTATUS status;
|
||
UNICODE_STRING registryPath;
|
||
CLONG i;
|
||
|
||
//
|
||
// Sanity check.
|
||
//
|
||
|
||
PAGED_CODE();
|
||
|
||
//
|
||
// Open the registry.
|
||
//
|
||
|
||
RtlInitUnicodeString(
|
||
®istryPath,
|
||
REGISTRY_SPUD_INFORMATION
|
||
);
|
||
|
||
status = SpudpOpenRegistry( ®istryPath, ¶metersHandle );
|
||
|
||
if( status != STATUS_SUCCESS ) {
|
||
return;
|
||
}
|
||
|
||
#if DBG
|
||
//
|
||
// Force a breakpoint if so requested.
|
||
//
|
||
|
||
if( SpudpReadSingleParameter(
|
||
parametersHandle,
|
||
REGISTRY_BREAK_ON_STARTUP,
|
||
0 ) != 0 ) {
|
||
DbgBreakPoint();
|
||
}
|
||
|
||
//
|
||
// Enable private assert function if requested. Note that the
|
||
// default value is TRUE for free builds and FALSE for checked
|
||
// builds.
|
||
//
|
||
|
||
SpudUsePrivateAssert = ( *(PULONG)&NtBuildNumber & 0xF0000000 ) == 0xF0000000;
|
||
|
||
SpudUsePrivateAssert = SpudpReadSingleParameter(
|
||
parametersHandle,
|
||
REGISTRY_USE_PRIVATE_ASSERT,
|
||
(LONG)SpudUsePrivateAssert
|
||
) != 0;
|
||
|
||
#endif
|
||
|
||
#if ALLOW_UNLOAD
|
||
//
|
||
// Enable driver unload on checked builds only if the proper
|
||
// value is in the registry. NEVER enable driver unload on free
|
||
// builds.
|
||
//
|
||
|
||
SpudpEnableUnload = SpudpReadSingleParameter(
|
||
parametersHandle,
|
||
REGISTRY_ENABLE_UNLOAD,
|
||
(LONG)SpudpEnableUnload
|
||
) != 0;
|
||
#endif
|
||
|
||
//
|
||
// Fail Load if so requested.
|
||
//
|
||
|
||
if( SpudpReadSingleParameter(
|
||
parametersHandle,
|
||
REGISTRY_DO_NOT_LOAD,
|
||
0 ) != 0 ) {
|
||
SpudpFailLoad = TRUE;
|
||
KdPrint(("Spud.sys load aborted! DoNotLoad is configured in the registry.\n"));
|
||
} else {
|
||
SpudpFailLoad = FALSE;
|
||
KdPrint(("Spud.sys load enabled! DoNotLoad is configured in the registry.\n"));
|
||
}
|
||
|
||
//
|
||
// Cleanup.
|
||
//
|
||
|
||
ZwClose( parametersHandle );
|
||
|
||
} // SpudpReadRegistry
|
||
|
||
|
||
NTSTATUS
|
||
SpudpOpenRegistry(
|
||
IN PUNICODE_STRING BaseName,
|
||
OUT PHANDLE ParametersHandle
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is called by SPUD to open the registry. If the registry
|
||
tree exists, then it opens it and returns STATUS_SUCCESS.
|
||
|
||
Arguments:
|
||
|
||
BaseName - Where in the registry to start looking for the information.
|
||
|
||
LinkageHandle - Returns the handle used to read linkage information.
|
||
|
||
ParametersHandle - Returns the handle used to read other
|
||
parameters.
|
||
|
||
Return Value:
|
||
|
||
The status of the request.
|
||
|
||
--*/
|
||
{
|
||
|
||
HANDLE configHandle;
|
||
NTSTATUS status;
|
||
PWSTR parametersString = REGISTRY_PARAMETERS;
|
||
UNICODE_STRING parametersKeyName;
|
||
OBJECT_ATTRIBUTES objectAttributes;
|
||
ULONG disposition;
|
||
|
||
//
|
||
// Sanity check.
|
||
//
|
||
|
||
PAGED_CODE();
|
||
|
||
//
|
||
// Open the registry for the initial string.
|
||
//
|
||
|
||
InitializeObjectAttributes(
|
||
&objectAttributes,
|
||
BaseName, // name
|
||
OBJ_CASE_INSENSITIVE, // attributes
|
||
NULL, // root
|
||
NULL // security descriptor
|
||
);
|
||
|
||
status = ZwOpenKey(
|
||
&configHandle,
|
||
KEY_READ,
|
||
&objectAttributes
|
||
);
|
||
|
||
if( !NT_SUCCESS(status) ) {
|
||
return STATUS_UNSUCCESSFUL;
|
||
}
|
||
|
||
//
|
||
// Now open the parameters key.
|
||
//
|
||
|
||
RtlInitUnicodeString(
|
||
¶metersKeyName,
|
||
parametersString
|
||
);
|
||
|
||
InitializeObjectAttributes(
|
||
&objectAttributes,
|
||
¶metersKeyName, // name
|
||
OBJ_CASE_INSENSITIVE, // attributes
|
||
configHandle, // root
|
||
NULL // security descriptor
|
||
);
|
||
|
||
status = ZwOpenKey(
|
||
ParametersHandle,
|
||
KEY_READ,
|
||
&objectAttributes
|
||
);
|
||
|
||
if( !NT_SUCCESS(status) ) {
|
||
ZwClose( configHandle );
|
||
return status;
|
||
}
|
||
|
||
//
|
||
// All keys successfully opened.
|
||
//
|
||
|
||
ZwClose( configHandle );
|
||
return STATUS_SUCCESS;
|
||
|
||
} // SpudpOpenRegistry
|
||
|
||
|
||
ULONG
|
||
SpudpReadSingleParameter(
|
||
IN HANDLE ParametersHandle,
|
||
IN PWCHAR ValueName,
|
||
IN LONG DefaultValue
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine is called by SPUD to read a single parameter
|
||
from the registry. If the parameter is found it is stored
|
||
in Data.
|
||
|
||
Arguments:
|
||
|
||
ParametersHandle - A pointer to the open registry.
|
||
|
||
ValueName - The name of the value to search for.
|
||
|
||
DefaultValue - The default value.
|
||
|
||
Return Value:
|
||
|
||
The value to use; will be the default if the value is not
|
||
found or is not in the correct range.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
static ULONG informationBuffer[32]; // declare ULONG to get it aligned
|
||
PKEY_VALUE_FULL_INFORMATION information =
|
||
(PKEY_VALUE_FULL_INFORMATION)informationBuffer;
|
||
UNICODE_STRING valueKeyName;
|
||
ULONG informationLength;
|
||
LONG returnValue;
|
||
NTSTATUS status;
|
||
|
||
//
|
||
// Sanity check.
|
||
//
|
||
|
||
PAGED_CODE();
|
||
|
||
//
|
||
// Read the registry value.
|
||
//
|
||
|
||
RtlInitUnicodeString(
|
||
&valueKeyName,
|
||
ValueName
|
||
);
|
||
|
||
status = ZwQueryValueKey(
|
||
ParametersHandle,
|
||
&valueKeyName,
|
||
KeyValueFullInformation,
|
||
(PVOID)information,
|
||
sizeof (informationBuffer),
|
||
&informationLength
|
||
);
|
||
|
||
if( (status == STATUS_SUCCESS) && (information->DataLength == sizeof(ULONG)) ) {
|
||
|
||
RtlMoveMemory(
|
||
(PVOID)&returnValue,
|
||
((PUCHAR)information) + information->DataOffset,
|
||
sizeof(ULONG)
|
||
);
|
||
|
||
if (returnValue < 0) {
|
||
returnValue = DefaultValue;
|
||
}
|
||
|
||
} else {
|
||
|
||
returnValue = DefaultValue;
|
||
}
|
||
|
||
return returnValue;
|
||
|
||
} // SpudpReadSingleParameter
|
||
|
||
|
||
#if ALLOW_UNLOAD
|
||
|
||
VOID
|
||
SpudpUnload(
|
||
IN PDRIVER_OBJECT DriverObject
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Unload routine.
|
||
|
||
Arguments:
|
||
|
||
DriverObject - Pointer to target driver object.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
PKSERVICE_TABLE_DESCRIPTOR serviceTable;
|
||
ULONG i;
|
||
|
||
//
|
||
// Sanity check.
|
||
//
|
||
|
||
PAGED_CODE();
|
||
UNREFERENCED_PARAMETER( DriverObject );
|
||
|
||
//
|
||
// Yank the system service table. What a hack.
|
||
//
|
||
// Note that this can never be perfectly synchronized, and you
|
||
// risk a blue-screen everytime you unload the driver. Only
|
||
// initiate an unload if you're absolutely sure the server is
|
||
// idle. This is the reason this code is conditionally compiled
|
||
// and will never see the light of day in a public, retail build.
|
||
//
|
||
|
||
serviceTable = *KeServiceDescriptorTable;
|
||
|
||
serviceTable[IIS_SERVICE_INDEX].Base = NULL;
|
||
serviceTable[IIS_SERVICE_INDEX].Count = NULL;
|
||
serviceTable[IIS_SERVICE_INDEX].Limit = 0;
|
||
serviceTable[IIS_SERVICE_INDEX].Number = NULL;
|
||
|
||
try {
|
||
serviceTable += NUMBER_SERVICE_TABLES;
|
||
|
||
for( i = 0 ; i < 1000 ; i++ ) {
|
||
if( serviceTable->Base == SpudServiceTable &&
|
||
serviceTable->Count == NULL &&
|
||
serviceTable->Limit == SpudServiceLimit &&
|
||
serviceTable->Number == SpudArgumentTable
|
||
) {
|
||
serviceTable->Base = NULL;
|
||
serviceTable->Count = NULL;
|
||
serviceTable->Limit = 0;
|
||
serviceTable->Number = NULL;
|
||
break;
|
||
}
|
||
|
||
serviceTable = (PKSERVICE_TABLE_DESCRIPTOR)( (PUCHAR)serviceTable + sizeof(ULONG_PTR) );
|
||
}
|
||
} except( EXCEPTION_EXECUTE_HANDLER ) {
|
||
NOTHING;
|
||
}
|
||
|
||
//
|
||
// Dereference the I/O completion port.
|
||
//
|
||
|
||
if( SpudCompletionPort != NULL ) {
|
||
TRACE_OB_DEREFERENCE( SpudCompletionPort );
|
||
ObDereferenceObject(SpudCompletionPort);
|
||
SpudCompletionPort = NULL;
|
||
}
|
||
|
||
//
|
||
// Destroy the non-paged data.
|
||
//
|
||
|
||
if( SpudNonpagedData != NULL ) {
|
||
|
||
ExDeleteNPagedLookasideList( &SpudNonpagedData->ReqContextList );
|
||
ExDeleteResourceLite( &SpudNonpagedData->ReqHandleTableLock );
|
||
|
||
SPUD_FREE_POOL( SpudNonpagedData );
|
||
SpudNonpagedData = NULL;
|
||
|
||
}
|
||
|
||
//
|
||
// Nuke the device object.
|
||
//
|
||
|
||
IoDeleteDevice( SpudSelfDeviceObject );
|
||
SpudSelfDeviceObject = NULL;
|
||
|
||
//
|
||
// Free the trace log.
|
||
//
|
||
|
||
#if ENABLE_OB_TRACING
|
||
if( SpudTraceLog != NULL ) {
|
||
DestroyRefTraceLog( SpudTraceLog );
|
||
SpudTraceLog = NULL;
|
||
}
|
||
#endif
|
||
|
||
} // SpudpUnload
|
||
|
||
#endif // ALLOW_UNLOAD
|