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.
1488 lines
42 KiB
1488 lines
42 KiB
|
|
/*++
|
|
|
|
Copyright (c) 1989 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
RxInit.c
|
|
|
|
Abstract:
|
|
|
|
This module implements the DRIVER_INITIALIZATION routine for the RDBSS.
|
|
|
|
Also, the routines for pagingio resource selection/allocation are here; since
|
|
we have to delete the resources when we unload, having them here simply centralizes
|
|
all the pagingio resource stuff.
|
|
|
|
Finally, the routines that are here that implement the wrapper's version of
|
|
network provider order. Basically, the wrapper MUST implement the same concept of
|
|
network provider order as the MUP so that the UI will work as expected. So, we
|
|
read the provider order from the registry at init time and memorize the order. Then,
|
|
we can assign the correct order when minirdrs register. Obviously, provider order is
|
|
not an issue in MONOLITHIC mode.
|
|
|
|
Author:
|
|
|
|
Joe Linn [JoeLinn] 20-jul-1994
|
|
|
|
Revision History:
|
|
|
|
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
#include "ntverp.h"
|
|
#include "NtDdNfs2.h"
|
|
#include "netevent.h"
|
|
|
|
//
|
|
// The local debug trace level
|
|
//
|
|
|
|
#define Dbg (0)
|
|
|
|
ULONG RxBuildNumber = VER_PRODUCTBUILD;
|
|
#ifdef RX_PRIVATE_BUILD
|
|
ULONG RxPrivateBuild = 1;
|
|
#else
|
|
ULONG RxPrivateBuild = 0;
|
|
#endif
|
|
|
|
#ifdef MONOLITHIC_MINIRDR
|
|
RDBSS_DEVICE_OBJECT RxSpaceForTheWrappersDeviceObject;
|
|
#endif
|
|
|
|
#define LANMAN_WORKSTATION_PARAMETERS \
|
|
L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\LanmanWorkStation\\Parameters"
|
|
|
|
BOOLEAN DisableByteRangeLockingOnReadOnlyFiles = FALSE;
|
|
|
|
VOID
|
|
RxReadRegistryParameters (
|
|
VOID
|
|
);
|
|
|
|
NPAGED_LOOKASIDE_LIST RxContextLookasideList;
|
|
|
|
VOID
|
|
RxGetRegistryParameters(
|
|
IN PUNICODE_STRING RegistryPath
|
|
);
|
|
|
|
NTSTATUS
|
|
RxInitializeRegistrationStructures (
|
|
VOID
|
|
);
|
|
VOID
|
|
RxUninitializeRegistrationStructures (
|
|
VOID
|
|
);
|
|
|
|
NTSTATUS
|
|
RxGetStringRegistryParameter (
|
|
HANDLE ParametersHandle,
|
|
PWCHAR ParameterName,
|
|
PUNICODE_STRING ParamString,
|
|
PKEY_VALUE_PARTIAL_INFORMATION Value,
|
|
ULONG ValueSize,
|
|
BOOLEAN LogFailure
|
|
);
|
|
|
|
NTSTATUS
|
|
RxGetUlongRegistryParameter (
|
|
HANDLE ParametersHandle,
|
|
PWCHAR ParameterName,
|
|
PULONG ParamUlong,
|
|
PKEY_VALUE_PARTIAL_INFORMATION Value,
|
|
ULONG ValueSize,
|
|
BOOLEAN LogFailure
|
|
);
|
|
|
|
//
|
|
// this type and variable are used for unwinding the initialization so that stuff doesn't go thru the cracks
|
|
// the way that this works is that stuff is done in the reverse order of the enumeration. that way i can just
|
|
// use a switch-no-break to unwind.
|
|
//
|
|
|
|
typedef enum _RX_INIT_STATES {
|
|
RXINIT_ALL_INITIALIZATION_COMPLETED,
|
|
RXINIT_CONSTRUCTED_PROVIDERORDER,
|
|
RXINIT_CREATED_LOG,
|
|
RXINIT_CREATED_DEVICE_OBJECT,
|
|
RXINIT_CREATED_FIRST_LINK,
|
|
RXINIT_START
|
|
} RX_INIT_STATES;
|
|
|
|
VOID
|
|
RxInitUnwind (
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN RX_INIT_STATES RxInitState
|
|
);
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(INIT, RxDriverEntry)
|
|
#pragma alloc_text(INIT, RxGetRegistryParameters)
|
|
#pragma alloc_text(INIT, RxGetStringRegistryParameter)
|
|
#pragma alloc_text(INIT, RxGetUlongRegistryParameter)
|
|
#pragma alloc_text(PAGE, RxUnload)
|
|
#pragma alloc_text(PAGE, RxInitUnwind)
|
|
#pragma alloc_text(PAGE, RxGetNetworkProviderPriority)
|
|
#pragma alloc_text(PAGE, RxInitializeRegistrationStructures)
|
|
#pragma alloc_text(PAGE, RxUninitializeRegistrationStructures)
|
|
#pragma alloc_text(PAGE, RxInitializeMinirdrDispatchTable)
|
|
#pragma alloc_text(PAGE, __RxFillAndInstallFastIoDispatch)
|
|
#pragma alloc_text(PAGE, RxReadRegistryParameters)
|
|
#endif
|
|
|
|
#define RX_SYMLINK_NAME L"\\??\\fsWrap"
|
|
|
|
BOOLEAN EnableWmiLog = FALSE;
|
|
|
|
NTSTATUS
|
|
RxDriverEntry (
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN PUNICODE_STRING RegistryPath
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the initialization routine for the Rx file system
|
|
device driver. This routine creates the device object for the FileSystem
|
|
device and performs all other driver initialization.
|
|
|
|
Arguments:
|
|
|
|
DriverObject - Pointer to driver object created by the system.
|
|
|
|
Return Value:
|
|
|
|
RXSTATUS - The function value is the final status from the initialization
|
|
operation.
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS Status;
|
|
RX_INIT_STATES RxInitState = 0;
|
|
#ifndef MONOLITHIC_MINIRDR
|
|
UNICODE_STRING UnicodeString,LinkName;
|
|
#endif
|
|
|
|
//
|
|
// this will bugcheck if things are bad
|
|
//
|
|
|
|
RxCheckFcbStructuresForAlignment();
|
|
|
|
//
|
|
// Initialize the global data structures
|
|
//
|
|
|
|
ZeroAndInitializeNodeType( &RxData, RDBSS_NTC_DATA_HEADER, sizeof( RDBSS_DATA ) );
|
|
RxData.DriverObject = DriverObject;
|
|
|
|
ZeroAndInitializeNodeType( &RxDeviceFCB, RDBSS_NTC_DEVICE_FCB, sizeof( FCB ) );
|
|
|
|
KeInitializeSpinLock( &RxStrucSupSpinLock );
|
|
RxExports.pRxStrucSupSpinLock = &RxStrucSupSpinLock;
|
|
|
|
RxInitializeDebugSupport();
|
|
|
|
try {
|
|
|
|
Status = RXINIT_START;
|
|
|
|
#ifndef MONOLITHIC_MINIRDR
|
|
|
|
//
|
|
// Create a symbolic link from \\dosdevices\fswrap to the rdbss device object name
|
|
//
|
|
|
|
RtlInitUnicodeString( &LinkName, RX_SYMLINK_NAME );
|
|
RtlInitUnicodeString( &UnicodeString, DD_NFS2_DEVICE_NAME_U );
|
|
|
|
IoDeleteSymbolicLink( &LinkName );
|
|
|
|
Status = IoCreateSymbolicLink( &LinkName, &UnicodeString );
|
|
if (!NT_SUCCESS( Status )) {
|
|
try_return( Status );
|
|
}
|
|
RxInitState = RXINIT_CREATED_FIRST_LINK;
|
|
|
|
//
|
|
// Create the device object.
|
|
//
|
|
|
|
Status = IoCreateDevice( DriverObject,
|
|
sizeof(RDBSS_DEVICE_OBJECT) - sizeof(DEVICE_OBJECT),
|
|
&UnicodeString,
|
|
FILE_DEVICE_NETWORK_FILE_SYSTEM,
|
|
FILE_REMOTE_DEVICE,
|
|
FALSE,
|
|
(PDEVICE_OBJECT *)(&RxFileSystemDeviceObject) );
|
|
if (!NT_SUCCESS( Status )) {
|
|
try_return( Status );
|
|
}
|
|
RxInitState = RXINIT_CREATED_DEVICE_OBJECT;
|
|
|
|
#else
|
|
|
|
//
|
|
// in monolithic mode, the wrapper doesn't really need a device object but
|
|
// we allocate stuff in the wrapper's device object in order to appropriately throttle
|
|
// thread usage per device object.
|
|
//
|
|
|
|
RxFileSystemDeviceObject = &RxSpaceForTheWrappersDeviceObject;
|
|
RtlZeroMemory( RxFileSystemDeviceObject, sizeof( RxSpaceForTheWrappersDeviceObject ) );
|
|
|
|
#endif
|
|
//
|
|
// Initialize the trace and logging facilities. loginit is a big allocation.
|
|
//
|
|
|
|
RxInitializeDebugTrace();
|
|
|
|
RxInitializeLog();
|
|
|
|
RxInitState = RXINIT_CREATED_LOG;
|
|
|
|
RxGetRegistryParameters( RegistryPath );
|
|
RxDbgTrace( 0, (DEBUG_TRACE_ALWAYS), ("Constants %08lx %08lx\n", RX_CONTEXT_FLAG_WAIT, RX_CONTEXT_CREATE_FLAG_ADDEDBACKSLASH ));
|
|
|
|
RxReadRegistryParameters();
|
|
|
|
//
|
|
// Initialize the minirdr registration facilities.
|
|
//
|
|
|
|
Status = RxInitializeRegistrationStructures();
|
|
if (!NT_SUCCESS( Status )) {
|
|
try_return( Status );
|
|
}
|
|
RxInitState = RXINIT_CONSTRUCTED_PROVIDERORDER;
|
|
|
|
#ifndef MONOLITHIC_MINIRDR
|
|
|
|
//
|
|
// We allocate an IoWorkItem to queue the requests to the FSP in the
|
|
// RxAddToWorkque function. We only do this when the DeviceObject
|
|
// RxFileSystemDeviceObject created to make sure that the RDBSS
|
|
// DeviceObject doesn't get unloaded while a request is being queued
|
|
// to the FSP.
|
|
//
|
|
RxIoWorkItem = IoAllocateWorkItem( (PDEVICE_OBJECT) RxFileSystemDeviceObject );
|
|
if (!NT_SUCCESS( Status )) {
|
|
try_return( Status );
|
|
}
|
|
|
|
#endif
|
|
|
|
try_exit: NOTHING;
|
|
} finally {
|
|
|
|
if (Status != STATUS_SUCCESS) {
|
|
|
|
RxLogFailure ( RxFileSystemDeviceObject, NULL, EVENT_RDR_UNEXPECTED_ERROR, Status );
|
|
RxInitUnwind( DriverObject, RxInitState );
|
|
}
|
|
}
|
|
|
|
if (Status != STATUS_SUCCESS) {
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
//
|
|
//
|
|
//
|
|
// ##### ## # # #### ###### #####
|
|
// # # # # ## # # # # # #
|
|
// # # # # # # # # ##### # #
|
|
// # # ###### # # # # ### # #####
|
|
// # # # # # ## # # # # #
|
|
// ##### # # # # #### ###### # #
|
|
//
|
|
//
|
|
//
|
|
// EVERYTHING FROM HERE DOWN BETTER WORK BECAUSE THERE IS NO MORE UNWINDING!!!
|
|
//
|
|
//
|
|
|
|
|
|
RxInitializeDispatcher();
|
|
RxInitializeBackoffPackage();
|
|
|
|
//
|
|
// Initialize the look aside list for RxContext allocation
|
|
//
|
|
|
|
ExInitializeNPagedLookasideList( &RxContextLookasideList,
|
|
ExAllocatePoolWithTag,
|
|
ExFreePool,
|
|
0,
|
|
sizeof( RX_CONTEXT ),
|
|
RX_IRPC_POOLTAG,
|
|
4 );
|
|
|
|
//
|
|
// Initialize the list of transport Irps to an empty list
|
|
//
|
|
|
|
InitializeListHead( &RxIrpsList );
|
|
KeInitializeSpinLock( &RxIrpsListSpinLock );
|
|
|
|
//
|
|
// Initialize the list of active contexts to an empty list
|
|
//
|
|
|
|
InitializeListHead( &RxActiveContexts );
|
|
|
|
//
|
|
// Initialize the list of srv call downs active
|
|
//
|
|
|
|
InitializeListHead( &RxSrvCalldownList );
|
|
|
|
//
|
|
// a fastmutex is used to serialize access to the Qs that serialize blocking pipe operations
|
|
//
|
|
|
|
ExInitializeFastMutex( &RxContextPerFileSerializationMutex );
|
|
|
|
//
|
|
// and to serialize access to the Qs that serialize some pagingio operations
|
|
//
|
|
|
|
ExInitializeFastMutex( &RxLowIoPagingIoSyncMutex );
|
|
|
|
//
|
|
// Initialize the scavenger mutex
|
|
//
|
|
|
|
KeInitializeMutex( &RxScavengerMutex, 1 );
|
|
|
|
//
|
|
// Initialize the global serialization Mutex.
|
|
//
|
|
|
|
KeInitializeMutex( &RxSerializationMutex, 1 );
|
|
|
|
//
|
|
// Initialize the wrapper's overflow queue
|
|
//
|
|
|
|
{
|
|
PRDBSS_DEVICE_OBJECT MyDo = (PRDBSS_DEVICE_OBJECT)RxFileSystemDeviceObject;
|
|
LONG Index;
|
|
|
|
for (Index = 0; Index < MaximumWorkQueue; Index++) {
|
|
|
|
MyDo->OverflowQueueCount[Index] = 0;
|
|
InitializeListHead( &MyDo->OverflowQueue[Index] );
|
|
MyDo->PostedRequestCount[Index] = 0;
|
|
}
|
|
|
|
KeInitializeSpinLock( &MyDo->OverflowQueueSpinLock );
|
|
}
|
|
|
|
//
|
|
// Initialize dispatch vector for driver object AND ALSO FOR the devicefcb
|
|
//
|
|
|
|
RxInitializeDispatchVectors( DriverObject );
|
|
ExInitializeResourceLite( &RxData.Resource );
|
|
|
|
//
|
|
// Initialize devfcb context2
|
|
//
|
|
|
|
RxDeviceFCB.Context2 = (PVOID) &RxData;
|
|
|
|
//
|
|
// Set up global pointer to our process.
|
|
//
|
|
|
|
RxData.OurProcess = PsGetCurrentProcess();
|
|
|
|
//
|
|
// Put in a bunch of sanity checks about various structures...hey, it's init code!
|
|
//
|
|
|
|
IF_DEBUG {
|
|
ULONG FcbStateBufferingMask = FCB_STATE_BUFFERING_STATE_MASK;
|
|
ULONG MinirdrBufStateCommandMask = MINIRDR_BUFSTATE_COMMAND_MASK;
|
|
USHORT EightBitsPerChar = 8;
|
|
|
|
//
|
|
// we could put in defines for the ULONG/USHORTS here...but they don't change often
|
|
//
|
|
|
|
ASSERT( MRDRBUFSTCMD_MAXXX == (sizeof( ULONG )*EightBitsPerChar) );
|
|
ASSERT( !(FcbStateBufferingMask&MinirdrBufStateCommandMask) );
|
|
|
|
}
|
|
|
|
//
|
|
// Setup the timer subsystem
|
|
//
|
|
|
|
RxInitializeRxTimer();
|
|
|
|
#ifndef MONOLITHIC_MINIRDR
|
|
Status = IoWMIRegistrationControl( (PDEVICE_OBJECT)RxFileSystemDeviceObject, WMIREG_ACTION_REGISTER );
|
|
|
|
if (Status != STATUS_SUCCESS) {
|
|
DbgPrint( "Rdbss fails to register WMI %lx\n", Status );
|
|
} else {
|
|
EnableWmiLog = TRUE;
|
|
}
|
|
#endif
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
//
|
|
// Unload routine
|
|
//
|
|
|
|
VOID
|
|
RxUnload (
|
|
IN PDRIVER_OBJECT DriverObject
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the unload routine for the RDBSS.
|
|
|
|
Arguments:
|
|
|
|
DriverObject - pointer to the driver object for the RDBSS
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
|
|
{
|
|
PAGED_CODE();
|
|
|
|
RxTearDownRxTimer();
|
|
|
|
RxDbgTrace( 0, (DEBUG_TRACE_ALWAYS), ("RxUnload: DriverObject =%08lx\n", DriverObject ) );
|
|
|
|
ExDeleteResourceLite( &RxData.Resource );
|
|
|
|
RxUninitializeBackoffPackage();
|
|
|
|
RxTearDownDispatcher();
|
|
|
|
RxTearDownDebugSupport();
|
|
|
|
ExDeleteNPagedLookasideList( &RxContextLookasideList );
|
|
|
|
RxInitUnwind( DriverObject, RXINIT_ALL_INITIALIZATION_COMPLETED );
|
|
|
|
if (EnableWmiLog) {
|
|
|
|
NTSTATUS Status;
|
|
|
|
Status = IoWMIRegistrationControl( (PDEVICE_OBJECT)RxFileSystemDeviceObject, WMIREG_ACTION_DEREGISTER );
|
|
if (Status != STATUS_SUCCESS) {
|
|
DbgPrint( "Rdbss fails to deregister WMI %lx\n", Status );
|
|
}
|
|
}
|
|
|
|
#ifndef MONOLITHIC_MINIRDR
|
|
|
|
IoFreeWorkItem(RxIoWorkItem);
|
|
|
|
#endif
|
|
|
|
return;
|
|
}
|
|
|
|
#if DBG
|
|
PCHAR RxUnwindFollower = NULL;
|
|
#endif
|
|
|
|
VOID
|
|
RxInitUnwind (
|
|
IN PDRIVER_OBJECT DriverObject,
|
|
IN RX_INIT_STATES RxInitState
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine does the common uninit work for unwinding from a bad driver entry or for unloading.
|
|
|
|
Arguments:
|
|
|
|
RxInitState - tells how far we got into the intialization
|
|
|
|
Return Value:
|
|
|
|
None
|
|
|
|
--*/
|
|
|
|
{
|
|
#ifndef MONOLITHIC_MINIRDR
|
|
UNICODE_STRING LinkName;
|
|
#endif
|
|
|
|
PAGED_CODE();
|
|
|
|
switch (RxInitState) {
|
|
|
|
case RXINIT_ALL_INITIALIZATION_COMPLETED:
|
|
|
|
//
|
|
// Nothing extra to do...this is just so that the constant in RxUnload doesn't change.......
|
|
// lack of break intentional
|
|
//
|
|
|
|
#if DBG
|
|
RxUnwindFollower = "RXINIT_ALL_INITIALIZATION_COMPLETED";
|
|
#endif
|
|
|
|
case RXINIT_CONSTRUCTED_PROVIDERORDER:
|
|
|
|
#if DBG
|
|
RxUnwindFollower = "RXINIT_CONSTRUCTED_PROVIDERORDER";
|
|
#endif
|
|
RxUninitializeRegistrationStructures();
|
|
|
|
//
|
|
// lack of break intentional
|
|
//
|
|
|
|
case RXINIT_CREATED_LOG:
|
|
|
|
#if DBG
|
|
RxUnwindFollower = "RXINIT_CREATED_LOG";
|
|
#endif
|
|
RxUninitializeLog();
|
|
|
|
//
|
|
// lack of break intentional
|
|
//
|
|
|
|
|
|
case RXINIT_CREATED_DEVICE_OBJECT:
|
|
|
|
#if DBG
|
|
RxUnwindFollower = "RXINIT_CREATED_DEVICE_OBJECT";
|
|
#endif
|
|
|
|
#ifndef MONOLITHIC_MINIRDR
|
|
IoDeleteDevice( (PDEVICE_OBJECT)RxFileSystemDeviceObject );
|
|
#endif
|
|
|
|
//
|
|
// lack of break intentional
|
|
//
|
|
|
|
case RXINIT_CREATED_FIRST_LINK:
|
|
|
|
#if DBG
|
|
RxUnwindFollower = "RXINIT_CREATED_FIRST_LINK";
|
|
#endif
|
|
|
|
#ifndef MONOLITHIC_MINIRDR
|
|
RtlInitUnicodeString( &LinkName, L"\\??\\fsWrap" );
|
|
IoDeleteSymbolicLink( &LinkName );
|
|
#endif
|
|
|
|
//
|
|
// lack of break intentional
|
|
//
|
|
|
|
case RXINIT_START:
|
|
|
|
#if DBG
|
|
RxUnwindFollower = "RXINIT_START";
|
|
#endif
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
VOID
|
|
RxGetRegistryParameters (
|
|
PUNICODE_STRING RegistryPath
|
|
)
|
|
{
|
|
ULONG Storage[256];
|
|
UNICODE_STRING UnicodeString;
|
|
HANDLE ConfigHandle;
|
|
HANDLE ParametersHandle;
|
|
NTSTATUS Status;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
PKEY_VALUE_FULL_INFORMATION Value = (PKEY_VALUE_FULL_INFORMATION)Storage;
|
|
|
|
PAGED_CODE();
|
|
|
|
InitializeObjectAttributes( &ObjectAttributes,
|
|
RegistryPath, // name
|
|
OBJ_CASE_INSENSITIVE, // attributes
|
|
NULL, // root
|
|
NULL // security descriptor
|
|
);
|
|
|
|
Status = ZwOpenKey( &ConfigHandle, KEY_READ, &ObjectAttributes );
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
return;
|
|
}
|
|
|
|
RtlInitUnicodeString( &UnicodeString, L"Parameters" );
|
|
|
|
InitializeObjectAttributes( &ObjectAttributes,
|
|
&UnicodeString,
|
|
OBJ_CASE_INSENSITIVE,
|
|
ConfigHandle,
|
|
NULL );
|
|
|
|
|
|
Status = ZwOpenKey( &ParametersHandle, KEY_READ, &ObjectAttributes );
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
|
|
ZwClose(ConfigHandle);
|
|
return;
|
|
}
|
|
|
|
#ifdef RDBSSLOG
|
|
|
|
RxGetStringRegistryParameter( ParametersHandle,
|
|
L"InitialDebugString",
|
|
&UnicodeString,
|
|
(PKEY_VALUE_PARTIAL_INFORMATION) Storage,
|
|
sizeof( Storage ),
|
|
FALSE );
|
|
|
|
|
|
if (UnicodeString.Length && UnicodeString.Length<320) {
|
|
|
|
PWCH u = UnicodeString.Buffer;
|
|
ULONG l;
|
|
PCH p = (PCH)u;
|
|
|
|
for (l=0; l<UnicodeString.Length; l++) {
|
|
|
|
*p++ = (CHAR)*u++;
|
|
*p = 0;
|
|
}
|
|
|
|
DbgPrint( "InitialDebugString From Registry as singlebytestring: <%s>\n", UnicodeString.Buffer );
|
|
RxDebugControlCommand( (PCH)UnicodeString.Buffer );
|
|
}
|
|
#endif // RDBSSLOG
|
|
|
|
ZwClose( ParametersHandle );
|
|
ZwClose( ConfigHandle );
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
RxGetStringRegistryParameter (
|
|
HANDLE ParametersHandle,
|
|
PWCHAR ParameterName,
|
|
PUNICODE_STRING ParamString,
|
|
PKEY_VALUE_PARTIAL_INFORMATION Value,
|
|
ULONG ValueSize,
|
|
BOOLEAN LogFailure
|
|
)
|
|
{
|
|
UNICODE_STRING UnicodeString;
|
|
NTSTATUS Status;
|
|
ULONG BytesRead;
|
|
|
|
PAGED_CODE();
|
|
|
|
RtlInitUnicodeString( &UnicodeString, ParameterName );
|
|
|
|
Status = ZwQueryValueKey( ParametersHandle,
|
|
&UnicodeString,
|
|
KeyValuePartialInformation,
|
|
Value,
|
|
ValueSize,
|
|
&BytesRead );
|
|
|
|
ParamString->Length = 0;
|
|
ParamString->Buffer = NULL;
|
|
|
|
if (NT_SUCCESS(Status)) {
|
|
|
|
ParamString->Buffer = (PWCH)(&Value->Data[0]);
|
|
|
|
//
|
|
// the datalength actually accounts for the trailing null
|
|
//
|
|
|
|
ParamString->Length = ((USHORT)Value->DataLength) - sizeof( WCHAR );
|
|
ParamString->MaximumLength = ParamString->Length;
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
if (!LogFailure) {
|
|
return Status;
|
|
}
|
|
|
|
RxLogFailure ( RxFileSystemDeviceObject, NULL, EVENT_RDR_CANT_READ_REGISTRY, Status );
|
|
return Status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
RxGetUlongRegistryParameter (
|
|
HANDLE ParametersHandle,
|
|
PWCHAR ParameterName,
|
|
PULONG ParamUlong,
|
|
PKEY_VALUE_PARTIAL_INFORMATION Value,
|
|
ULONG ValueSize,
|
|
BOOLEAN LogFailure
|
|
)
|
|
{
|
|
UNICODE_STRING UnicodeString;
|
|
NTSTATUS Status;
|
|
ULONG BytesRead;
|
|
|
|
PAGED_CODE();
|
|
|
|
RtlInitUnicodeString( &UnicodeString, ParameterName );
|
|
|
|
Status = ZwQueryValueKey( ParametersHandle,
|
|
&UnicodeString,
|
|
KeyValuePartialInformation,
|
|
Value,
|
|
ValueSize,
|
|
&BytesRead );
|
|
|
|
|
|
if (NT_SUCCESS(Status)) {
|
|
|
|
if (Value->Type == REG_DWORD) {
|
|
|
|
PULONG ConfigValue = (PULONG)&Value->Data[0];
|
|
*ParamUlong = *((PULONG)ConfigValue);
|
|
DbgPrint( "readRegistryvalue %wZ = %08lx\n", &UnicodeString, *ParamUlong );
|
|
return(STATUS_SUCCESS);
|
|
|
|
} else {
|
|
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
}
|
|
}
|
|
|
|
if (!LogFailure) {
|
|
return Status;
|
|
}
|
|
|
|
RxLogFailureWithBuffer ( RxFileSystemDeviceObject,
|
|
NULL,
|
|
EVENT_RDR_CANT_READ_REGISTRY,
|
|
Status,
|
|
ParameterName,
|
|
(USHORT)(wcslen( ParameterName )* sizeof( WCHAR ) ) );
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
/*-------------------------------
|
|
|
|
This set of routines implements the network provider order in the wrapper.
|
|
The way that this works is somewhat complicated. First, we go to the registry
|
|
to get the provider order; it is stored at key=PROVIDERORDER_REGISTRY_KEY and
|
|
value=L"ProviderOrder". This is a list of service providers whereas what we need
|
|
are the device names. So, for each ServiceProverName, we go to the registry to
|
|
get the device name at key=SERVICE_REGISTRY_KEY, subkey=ServiceProverName,
|
|
subsubkey=NETWORK_PROVIDER_SUBKEY, and value=L"Devicename".
|
|
|
|
We build a linked list of these guys. Later when a minirdr registers, we look
|
|
on this list for the corresponding device name and that gives us the priority.
|
|
|
|
----------------------------------*/
|
|
|
|
#ifndef MONOLITHIC_MINIRDR
|
|
|
|
NTSTATUS
|
|
RxAccrueProviderFromServiceName (
|
|
HANDLE ServicesHandle,
|
|
PUNICODE_STRING ServiceName,
|
|
ULONG Priority,
|
|
PWCHAR ProviderInfoNameBuffer,
|
|
ULONG ProviderInfoNameBufferLength
|
|
);
|
|
|
|
NTSTATUS
|
|
RxConstructProviderOrder (
|
|
VOID
|
|
);
|
|
|
|
VOID
|
|
RxDestructProviderOrder (
|
|
VOID
|
|
);
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(INIT, RxAccrueProviderFromServiceName)
|
|
#pragma alloc_text(INIT, RxConstructProviderOrder)
|
|
#pragma alloc_text(PAGE, RxDestructProviderOrder)
|
|
#endif
|
|
|
|
|
|
#define PROVIDERORDER_REGISTRY_KEY L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\NetworkProvider\\Order"
|
|
#define SERVICE_REGISTRY_KEY L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\"
|
|
#define NETWORK_PROVIDER_SUBKEY L"\\networkprovider"
|
|
|
|
|
|
typedef struct _RX_UNC_PROVIDER_HEADER {
|
|
union {
|
|
LIST_ENTRY;
|
|
LIST_ENTRY Links;
|
|
};
|
|
ULONG Priority;
|
|
union {
|
|
UNICODE_STRING;
|
|
UNICODE_STRING DeviceName;
|
|
};
|
|
} RX_UNC_PROVIDER_HEADER;
|
|
|
|
typedef struct _RX_UNC_PROVIDER {
|
|
RX_UNC_PROVIDER_HEADER;
|
|
KEY_VALUE_PARTIAL_INFORMATION Info;
|
|
} RX_UNC_PROVIDER, *PRX_UNC_PROVIDER;
|
|
|
|
LIST_ENTRY RxUncProviders;
|
|
|
|
ULONG
|
|
RxGetNetworkProviderPriority (
|
|
IN PUNICODE_STRING DeviceName
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called at minirdr registration time to find out the priority
|
|
of the provider with the given DeviceName. It simply looks it up on a list.
|
|
|
|
Arguments:
|
|
|
|
DeviceName - name of the device whose priority is to be found
|
|
|
|
Return Value:
|
|
|
|
the network provider priority that the MUP will use.
|
|
|
|
--*/
|
|
{
|
|
PLIST_ENTRY Entry;
|
|
|
|
PAGED_CODE();
|
|
|
|
RxLog(( "FindUncProvider %wZ \n", DeviceName ));
|
|
RxWmiLog( LOG,
|
|
RxGetNetworkProviderPriority,
|
|
LOGUSTR( *DeviceName ));
|
|
|
|
for (Entry = RxUncProviders.Flink; Entry != &RxUncProviders;) {
|
|
|
|
PRX_UNC_PROVIDER UncProvider = (PRX_UNC_PROVIDER)Entry;
|
|
Entry = Entry->Flink;
|
|
if (RtlEqualUnicodeString( DeviceName, &UncProvider->DeviceName, TRUE )) {
|
|
return UncProvider->Priority;
|
|
}
|
|
}
|
|
|
|
//
|
|
// no corresponding entry was found
|
|
//
|
|
|
|
return 0x7effffff; // got this constant from the MUP........
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
RxAccrueProviderFromServiceName (
|
|
HANDLE ServicesHandle,
|
|
PUNICODE_STRING ServiceName,
|
|
ULONG Priority,
|
|
PWCHAR ProviderInfoNameBuffer,
|
|
ULONG ProviderInfoNameBufferLength
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine has the responsibility to look up the device name corresponding
|
|
to a particular provider name; if successful, the device name and the corresponding
|
|
priority are recorded on the UncProvider List.
|
|
|
|
Arguments:
|
|
|
|
HANDLE ServicesHandle - a handle to the services root in the registry
|
|
PUNICODE_STRING ServiceName - the name of the service relative to the servicehandle
|
|
ULONG Priority, - the priority of this provider
|
|
PWCHAR ProviderInfoNameBuffer, - a buffer that can be used to accrue the subkey name
|
|
ULONG ProviderInfoNameBufferLength - and the length
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS if everything worked elsewise an error status.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
UNICODE_STRING ProviderInfoName,ProviderInfoKey,ParameterDeviceName;
|
|
HANDLE NetworkProviderInfoHandle = INVALID_HANDLE_VALUE;
|
|
KEY_VALUE_PARTIAL_INFORMATION InitialValuePartialInformation;
|
|
ULONG DummyBytesRead,ProviderLength;
|
|
PRX_UNC_PROVIDER UncProvider = NULL;
|
|
|
|
PAGED_CODE();
|
|
|
|
RxLog(( "SvcNm %wZ", ServiceName ));
|
|
RxWmiLog( LOG,
|
|
RxAccrueProviderFromServiceName_1,
|
|
LOGUSTR( *ServiceName ) );
|
|
//
|
|
// Form the correct keyname using the bufferspace provided
|
|
//
|
|
|
|
ProviderInfoName.Buffer = ProviderInfoNameBuffer;
|
|
ProviderInfoName.Length = 0;
|
|
ProviderInfoName.MaximumLength = (USHORT)ProviderInfoNameBufferLength;
|
|
|
|
try {
|
|
|
|
Status = RtlAppendUnicodeStringToString( &ProviderInfoName, ServiceName );
|
|
if (Status != STATUS_SUCCESS) {
|
|
|
|
DbgPrint( "Could append1: %08lx %wZ\n", Status, &ProviderInfoName );
|
|
leave;
|
|
}
|
|
|
|
RtlInitUnicodeString( &ProviderInfoKey, NETWORK_PROVIDER_SUBKEY );
|
|
Status = RtlAppendUnicodeStringToString( &ProviderInfoName, &ProviderInfoKey );
|
|
if (Status != STATUS_SUCCESS) {
|
|
|
|
DbgPrint( "Could append2: %08lx %wZ\n", Status, &ProviderInfoName );
|
|
leave;
|
|
}
|
|
|
|
//
|
|
// Open the key in preparation for reeading the devicename value
|
|
//
|
|
|
|
InitializeObjectAttributes( &ObjectAttributes,
|
|
&ProviderInfoName, // name
|
|
OBJ_CASE_INSENSITIVE, // attributes
|
|
ServicesHandle, // root
|
|
NULL ); // security descriptor
|
|
|
|
|
|
Status = ZwOpenKey( &NetworkProviderInfoHandle, KEY_READ, &ObjectAttributes );
|
|
|
|
if (!NT_SUCCESS(Status )) {
|
|
DbgPrint( "NetWorkProviderInfoFailed: %08lx %wZ\n", Status, &ProviderInfoName );
|
|
leave;
|
|
}
|
|
|
|
//
|
|
// Read the devicename. we do this in two steps. first, we do a partial read to find out
|
|
// how big the name really is. Then, we allocate a UncProviderEntry of the correctsize and make
|
|
// a second call to fill it in.
|
|
//
|
|
|
|
RtlInitUnicodeString( &ParameterDeviceName, L"DeviceName" );
|
|
|
|
Status = ZwQueryValueKey( NetworkProviderInfoHandle,
|
|
&ParameterDeviceName,
|
|
KeyValuePartialInformation,
|
|
&InitialValuePartialInformation,
|
|
sizeof(InitialValuePartialInformation),
|
|
&DummyBytesRead );
|
|
if (Status == STATUS_BUFFER_OVERFLOW) {
|
|
Status = STATUS_SUCCESS;
|
|
}
|
|
if (Status != STATUS_SUCCESS) {
|
|
leave;
|
|
}
|
|
|
|
ProviderLength = sizeof( RX_UNC_PROVIDER) + InitialValuePartialInformation.DataLength;
|
|
UncProvider = RxAllocatePoolWithTag( PagedPool | POOL_COLD_ALLOCATION, ProviderLength, RX_MRX_POOLTAG );
|
|
if (UncProvider == NULL) {
|
|
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
DbgPrint( "UncProviderAllocationFailed: %08lx %wZ\n", Status, &ProviderInfoName );
|
|
leave;
|
|
}
|
|
|
|
Status = ZwQueryValueKey( NetworkProviderInfoHandle,
|
|
&ParameterDeviceName,
|
|
KeyValuePartialInformation,
|
|
&UncProvider->Info,
|
|
ProviderLength,
|
|
&DummyBytesRead );
|
|
if (Status != STATUS_SUCCESS) {
|
|
leave;
|
|
}
|
|
|
|
//
|
|
// Finish filling in the UncProviderEntry and link it in
|
|
//
|
|
|
|
UncProvider->Buffer = (PWCHAR)(&UncProvider->Info.Data[0]);
|
|
UncProvider->Length = (USHORT)(UncProvider->Info.DataLength - sizeof( WCHAR )); // dont include trailing NULL
|
|
UncProvider->MaximumLength = UncProvider->Length;
|
|
UncProvider->Priority = Priority;
|
|
|
|
InsertTailList( &RxUncProviders, &UncProvider->Links );
|
|
|
|
RxLog(( "Dvc p=%lx Nm %wZ",UncProvider->Priority, &UncProvider->DeviceName ));
|
|
RxWmiLog( LOG,
|
|
RxAccrueProviderFromServiceName_2,
|
|
LOGULONG( UncProvider->Priority )
|
|
LOGUSTR( UncProvider->DeviceName ) );
|
|
|
|
UncProvider = NULL;
|
|
|
|
} finally {
|
|
|
|
//
|
|
// if we obtained a handle to ...\\services\<sevicename>\providerinfo then close it
|
|
//
|
|
|
|
if (NetworkProviderInfoHandle != INVALID_HANDLE_VALUE) {
|
|
ZwClose( NetworkProviderInfoHandle );
|
|
}
|
|
|
|
if (UncProvider != NULL) {
|
|
RxFreePool(UncProvider);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
RxConstructProviderOrder (
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine has the responsibility to build the list of network providers
|
|
that is used to look up provider priority at minirdr registration time. It does this
|
|
by first reading the providerorder string fron the registry; then for each provider
|
|
listed in the string, a helper routine is called to lookup the corresponding device
|
|
name and insert an entry on the provider list.
|
|
|
|
Arguments:
|
|
|
|
none.
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS if everything worked elsewise an error status.
|
|
|
|
|
|
--*/
|
|
{
|
|
KEY_VALUE_PARTIAL_INFORMATION InitialValuePartialInformation;
|
|
UNICODE_STRING ProviderOrderValueName;
|
|
ULONG DummyBytesRead;
|
|
PBYTE ProviderOrderStringBuffer;
|
|
PBYTE ServiceNameStringBuffer = NULL;
|
|
ULONG ProviderOrderStringLength,ServiceNameStringLength,AllocationLength;
|
|
|
|
UNICODE_STRING UnicodeString;
|
|
UNICODE_STRING ProviderOrder;
|
|
PWCHAR ScanPtr,FinalScanPtr;
|
|
HANDLE NPOrderHandle = INVALID_HANDLE_VALUE;
|
|
HANDLE ServiceRootHandle = INVALID_HANDLE_VALUE;
|
|
NTSTATUS Status;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
ULONG Priority = 0;
|
|
|
|
PAGED_CODE();
|
|
|
|
RxLog(( "RxConstructProviderOrder" ));
|
|
RxWmiLog( LOG,
|
|
RxConstructProviderOrder_1,
|
|
LOGULONG( Priority ) );
|
|
InitializeListHead( &RxUncProviders );
|
|
|
|
try {
|
|
|
|
//
|
|
// Start by opening the service registry key. This is the root key of all services
|
|
// and is used for relative opens by the helper routine so that string manipulation
|
|
// is reduced.
|
|
//
|
|
|
|
RtlInitUnicodeString( &UnicodeString, SERVICE_REGISTRY_KEY );
|
|
|
|
InitializeObjectAttributes( &ObjectAttributes,
|
|
&UnicodeString, // name
|
|
OBJ_CASE_INSENSITIVE, // attributes
|
|
NULL, // root
|
|
NULL ); // security descriptor
|
|
|
|
Status = ZwOpenKey( &ServiceRootHandle, KEY_READ, &ObjectAttributes );
|
|
|
|
if (!NT_SUCCESS( Status )) {
|
|
DbgPrint( "ServiceRootOpenFailed: %08lx %wZ\n", Status, &UnicodeString );
|
|
leave;
|
|
}
|
|
|
|
//
|
|
// Now open up the key where we find the provider order string
|
|
//
|
|
|
|
RtlInitUnicodeString( &UnicodeString, PROVIDERORDER_REGISTRY_KEY );
|
|
|
|
InitializeObjectAttributes( &ObjectAttributes,
|
|
&UnicodeString, // name
|
|
OBJ_CASE_INSENSITIVE, // attributes
|
|
NULL, // root
|
|
NULL ); // security descriptor
|
|
|
|
|
|
Status = ZwOpenKey( &NPOrderHandle, KEY_READ, &ObjectAttributes );
|
|
|
|
if (!NT_SUCCESS( Status )) {
|
|
|
|
DbgPrint( "NetProviderOpenFailed: %08lx %wZ\n", Status, &UnicodeString );
|
|
leave;
|
|
}
|
|
|
|
//
|
|
// Find out how long the provider order string is
|
|
//
|
|
|
|
RtlInitUnicodeString( &ProviderOrderValueName, L"ProviderOrder" );
|
|
|
|
Status = ZwQueryValueKey( NPOrderHandle,
|
|
&ProviderOrderValueName,
|
|
KeyValuePartialInformation,
|
|
&InitialValuePartialInformation,
|
|
sizeof( InitialValuePartialInformation ),
|
|
&DummyBytesRead );
|
|
|
|
if (Status == STATUS_BUFFER_OVERFLOW) {
|
|
Status = STATUS_SUCCESS;
|
|
}
|
|
if (Status != STATUS_SUCCESS) {
|
|
|
|
DbgPrint( "ProviderOrderStringPartialInfoFailed: %08lx %wZ\n", Status, &ProviderOrderValueName );
|
|
leave;
|
|
}
|
|
|
|
//
|
|
// allocate two buffers: one buffer will hold the provider string -- ProviderOrderStringBuffer.
|
|
// it has to be as long as the providerorder string plus enough extra for the registry
|
|
// structure used in the call. the second buffer is used to hold the servicename key--it has
|
|
// to be as long as any element of the provider string plus enough extra to hold the suffix
|
|
// NETWORK_PROVIDER_SUBKEY. in order to only parse the string once, we just allocate for a complete
|
|
// additional copy of the provider string. we actually combine these into a single allocation.
|
|
//
|
|
|
|
ProviderOrderStringLength = sizeof( KEY_VALUE_PARTIAL_INFORMATION ) + InitialValuePartialInformation.DataLength;
|
|
ProviderOrderStringLength = QuadAlign( ProviderOrderStringLength + 2*sizeof( WCHAR ) ); // chars added below
|
|
|
|
ServiceNameStringLength = sizeof( NETWORK_PROVIDER_SUBKEY ) + InitialValuePartialInformation.DataLength;
|
|
ServiceNameStringLength = QuadAlign( ServiceNameStringLength );
|
|
|
|
AllocationLength = ProviderOrderStringLength + ServiceNameStringLength;
|
|
RxLog(( "prov string=%lx,alloc=%lx\n", InitialValuePartialInformation.DataLength, AllocationLength ));
|
|
RxWmiLog( LOG,
|
|
RxConstructProviderOrder_2,
|
|
LOGULONG( InitialValuePartialInformation.DataLength )
|
|
LOGULONG( AllocationLength ) );
|
|
|
|
ServiceNameStringBuffer = RxAllocatePoolWithTag( PagedPool | POOL_COLD_ALLOCATION, AllocationLength, RX_MRX_POOLTAG );
|
|
if (ServiceNameStringBuffer == NULL) {
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
leave;
|
|
}
|
|
ProviderOrderStringBuffer = ServiceNameStringBuffer+ServiceNameStringLength;
|
|
|
|
//
|
|
// now do the final read to get the providerorder string
|
|
//
|
|
|
|
RxGetStringRegistryParameter( NPOrderHandle,
|
|
L"ProviderOrder",
|
|
&ProviderOrder,
|
|
(PKEY_VALUE_PARTIAL_INFORMATION) ProviderOrderStringBuffer,
|
|
ProviderOrderStringLength,
|
|
FALSE );
|
|
|
|
if (ProviderOrder.Buffer == NULL) {
|
|
Status = STATUS_UNSUCCESSFUL;
|
|
leave;
|
|
}
|
|
|
|
//
|
|
// comma-terminate the string for easier living. then scan down the string
|
|
// looking for comma terminated entries. for each entry found, try to accrue
|
|
// it to the list
|
|
//
|
|
|
|
ProviderOrder.Buffer[ProviderOrder.Length / sizeof( WCHAR )] = L',';
|
|
|
|
ScanPtr = ProviderOrder.Buffer;
|
|
FinalScanPtr = ScanPtr+(ProviderOrder.Length / sizeof( WCHAR ));
|
|
for (;;) {
|
|
|
|
UNICODE_STRING ServiceName;
|
|
|
|
//
|
|
// check for loop termination
|
|
//
|
|
|
|
if (ScanPtr >= FinalScanPtr) { break; }
|
|
if (*ScanPtr==L',') { ScanPtr++; continue; }
|
|
|
|
//
|
|
// parse for a servicename
|
|
//
|
|
|
|
ServiceName.Buffer = ScanPtr;
|
|
for (; *ScanPtr != L','; ScanPtr++) {}
|
|
|
|
ASSERT( *ScanPtr==L',' );
|
|
|
|
ServiceName.Length = (USHORT)(sizeof( WCHAR )* (ScanPtr - ServiceName.Buffer));
|
|
|
|
//
|
|
// accrue it to the list
|
|
//
|
|
|
|
Priority += 1;
|
|
Status = RxAccrueProviderFromServiceName( ServiceRootHandle,
|
|
&ServiceName,
|
|
Priority,
|
|
(PWCHAR)ServiceNameStringBuffer,
|
|
ServiceNameStringLength );
|
|
if (Status == STATUS_INSUFFICIENT_RESOURCES) {
|
|
leave; // a log entry has already been generated
|
|
} else {
|
|
Status = STATUS_SUCCESS;
|
|
}
|
|
}
|
|
} finally {
|
|
|
|
//
|
|
// give back anything that we got in this procedure
|
|
//
|
|
|
|
if (NPOrderHandle != INVALID_HANDLE_VALUE) ZwClose( NPOrderHandle );
|
|
if (ServiceRootHandle != INVALID_HANDLE_VALUE) ZwClose( ServiceRootHandle );
|
|
if (ServiceNameStringBuffer != NULL) RxFreePool( ServiceNameStringBuffer );
|
|
|
|
//
|
|
// if things didn't work, then we won't start....so give back
|
|
// the stuff that we have
|
|
//
|
|
|
|
if (!NT_SUCCESS( Status )) {
|
|
RxDestructProviderOrder();
|
|
}
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
VOID
|
|
RxDestructProviderOrder (
|
|
VOID
|
|
)
|
|
{
|
|
PLIST_ENTRY Entry;
|
|
PAGED_CODE();
|
|
|
|
for (Entry = RxUncProviders.Flink; Entry != &RxUncProviders;) {
|
|
PRX_UNC_PROVIDER UncProvider = (PRX_UNC_PROVIDER)Entry;
|
|
|
|
Entry = Entry->Flink;
|
|
RxFreePool( UncProvider );
|
|
}
|
|
return;
|
|
}
|
|
|
|
#else
|
|
ULONG
|
|
RxGetNetworkProviderPriority (
|
|
PUNICODE_STRING DeviceName
|
|
)
|
|
{
|
|
PAGED_CODE();
|
|
return 1; //this number is irrelevant for monolithic
|
|
}
|
|
#endif //#ifndef MONOLITHIC_MINIRDR
|
|
|
|
NTSTATUS
|
|
RxInitializeRegistrationStructures (
|
|
VOID
|
|
)
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
PAGED_CODE();
|
|
|
|
ExInitializeFastMutex(&RxData.MinirdrRegistrationMutex);
|
|
RxData.NumberOfMinirdrsRegistered = 0;
|
|
RxData.NumberOfMinirdrsStarted = 0;
|
|
InitializeListHead( &RxData.RegisteredMiniRdrs );
|
|
#ifndef MONOLITHIC_MINIRDR
|
|
Status = RxConstructProviderOrder();
|
|
#endif
|
|
return(Status);
|
|
}
|
|
|
|
VOID
|
|
RxUninitializeRegistrationStructures(
|
|
VOID
|
|
)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
#ifndef MONOLITHIC_MINIRDR
|
|
RxDestructProviderOrder();
|
|
#endif
|
|
}
|
|
|
|
|
|
VOID
|
|
RxInitializeMinirdrDispatchTable (
|
|
IN PDRIVER_OBJECT DriverObject
|
|
)
|
|
{
|
|
|
|
#ifndef MONOLITHIC_MINIRDR
|
|
ULONG i;
|
|
|
|
PAGED_CODE();
|
|
|
|
//
|
|
// finally, fill in the dispatch tables for normal guys.........
|
|
//
|
|
|
|
for (i = 0; i < IRP_MJ_MAXIMUM_FUNCTION; i++) {
|
|
DriverObject->MajorFunction[i] = RxData.DriverObject->MajorFunction[i];
|
|
}
|
|
DriverObject->FastIoDispatch = RxData.DriverObject->FastIoDispatch;
|
|
#else
|
|
PAGED_CODE();
|
|
#endif
|
|
}
|
|
|
|
|
|
VOID
|
|
NTAPI
|
|
__RxFillAndInstallFastIoDispatch(
|
|
IN PRDBSS_DEVICE_OBJECT RxDeviceObject,
|
|
IN OUT PFAST_IO_DISPATCH FastIoDispatch,
|
|
IN ULONG FastIoDispatchSize
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine fills out a fastiodispatch vector to be identical with
|
|
that normal one and installs it into the driver object associated with
|
|
the device object passed.
|
|
|
|
Arguments:
|
|
|
|
RxDeviceObject - the device object that is to have its driver's fastiodispatch changed
|
|
FastIoDispatch - the fastiodispatch table to fill in and use
|
|
FastIoDispatchSize - the size of the table passed
|
|
|
|
Return Value:
|
|
|
|
NONE
|
|
|
|
--*/
|
|
{
|
|
ULONG TableSize = min(FastIoDispatchSize, RxFastIoDispatch.SizeOfFastIoDispatch );
|
|
|
|
PAGED_CODE();
|
|
|
|
#ifndef MONOLITHIC_MINIRDR
|
|
RtlCopyMemory( FastIoDispatch, &RxFastIoDispatch, TableSize );
|
|
FastIoDispatch->SizeOfFastIoDispatch = TableSize;
|
|
RxDeviceObject->DriverObject->FastIoDispatch = FastIoDispatch;
|
|
return;
|
|
#endif
|
|
}
|
|
|
|
VOID
|
|
RxReadRegistryParameters(
|
|
VOID
|
|
)
|
|
{
|
|
ULONG Storage[16];
|
|
UNICODE_STRING UnicodeString;
|
|
HANDLE ParametersHandle;
|
|
NTSTATUS Status;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
UNICODE_STRING WorkStationParametersRegistryKeyName;
|
|
PKEY_VALUE_PARTIAL_INFORMATION Value = (PKEY_VALUE_PARTIAL_INFORMATION)Storage;
|
|
ULONG ValueSize;
|
|
ULONG BytesRead;
|
|
|
|
PAGED_CODE();
|
|
|
|
RtlInitUnicodeString( &WorkStationParametersRegistryKeyName, LANMAN_WORKSTATION_PARAMETERS );
|
|
|
|
ValueSize = sizeof( Storage );
|
|
|
|
InitializeObjectAttributes( &ObjectAttributes,
|
|
&WorkStationParametersRegistryKeyName, // name
|
|
OBJ_CASE_INSENSITIVE, // attributes
|
|
NULL, // root
|
|
NULL ); // security descriptor
|
|
|
|
|
|
Status = ZwOpenKey( &ParametersHandle, KEY_READ, &ObjectAttributes );
|
|
|
|
if (!NT_SUCCESS( Status )) {
|
|
return;
|
|
}
|
|
|
|
RtlInitUnicodeString( &UnicodeString, L"DisableByteRangeLockingOnReadOnlyFiles" );
|
|
|
|
Status = ZwQueryValueKey( ParametersHandle,
|
|
&UnicodeString,
|
|
KeyValuePartialInformation,
|
|
Value,
|
|
ValueSize,
|
|
&BytesRead );
|
|
|
|
if (NT_SUCCESS( Status ) && (Value->Type == REG_DWORD)) {
|
|
|
|
PULONG ConfigValue = (PULONG)&Value->Data[0];
|
|
DisableByteRangeLockingOnReadOnlyFiles = (BOOLEAN)(*((PULONG)ConfigValue) != 0);
|
|
}
|
|
|
|
ZwClose( ParametersHandle );
|
|
}
|
|
|