mirror of https://github.com/tongzx/nt5src
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.
657 lines
13 KiB
657 lines
13 KiB
/*++
|
|
|
|
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
|