windows-nt/Source/XPSP1/NT/base/fs/rdr2/rdbss/ntinit.c
2020-09-26 16:20:57 +08:00

1443 lines
39 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
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();
NPAGED_LOOKASIDE_LIST RxContextLookasideList;
VOID
RxGetRegistryParameters(
IN PUNICODE_STRING RegistryPath
);
NTSTATUS
RxInitializeRegistrationStructures(
void
);
VOID
RxUninitializeRegistrationStructures(
void
);
VOID
RxAbbreviatedWriteLogEntry__ (
IN NTSTATUS Status,
IN ULONG OneExtraUlong
);
#define RxAbbreviatedWriteLogEntry(STATUS__) RxAbbreviatedWriteLogEntry__(STATUS__,__LINE__)
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(INIT, RxAbbreviatedWriteLogEntry__)
#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
//Structure checks
RxCheckFcbStructuresForAlignment(); //this will bugcheck if things are bad
//
// 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;
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 );
//
// 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
--*/
{
//UNICODE_STRING LinkName;
PAGED_CODE();
RxTearDownRxTimer();
//remember this
// RdrUnloadSecurity();
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);
}
}
}
#if DBG
PCHAR RxUnwindFollower = NULL;
#define UNWIND_CASE(x) case x: RxUnwindFollower = #x;
#else
#define UNWIND_CASE(x) case x:
#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) {
UNWIND_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
UNWIND_CASE(RXINIT_CONSTRUCTED_PROVIDERORDER)
RxUninitializeRegistrationStructures();
//lack of break intentional
UNWIND_CASE(RXINIT_CREATED_LOG)
RxUninitializeLog();
//lack of break intentional
#ifndef MONOLITHIC_MINIRDR
UNWIND_CASE(RXINIT_CREATED_DEVICE_OBJECT)
IoDeleteDevice((PDEVICE_OBJECT)RxFileSystemDeviceObject);
//lack of break intentional
UNWIND_CASE(RXINIT_CREATED_FIRST_LINK)
RtlInitUnicodeString(&LinkName, RX_SYMLINK_NAME);
IoDeleteSymbolicLink(&LinkName);
// lack of break intentional
#endif
UNWIND_CASE(RXINIT_START)
//RdrUninitializeDiscardableCode();
//DbgBreakPoint();
break;
}
}
VOID
RxAbbreviatedWriteLogEntry__ (
IN NTSTATUS Status,
IN ULONG OneExtraUlong
)
/*++
Routine Description:
This routine write a log entry with most of the fields set to fixed values.
Arguments:
Status - the status to be stored in the log record
OneExtraUlong - a key for finding out what happened
Return Value:
none.
--*/
{
//RxLogFailureWithBuffer (
// RxFileSystemDeviceObject,
// NULL,
// EVENT_RDR_CANT_READ_REGISTRY,
// Status,
// &OneExtraUlong,
// sizeof(ULONG)
// );
}
VOID
RxGetRegistryParameters(
PUNICODE_STRING RegistryPath
)
{
ULONG Storage[256];
UNICODE_STRING UnicodeString;
HANDLE ConfigHandle;
HANDLE ParametersHandle;
NTSTATUS Status;
//ULONG BytesRead;
OBJECT_ATTRIBUTES ObjectAttributes;
PKEY_VALUE_FULL_INFORMATION Value = (PKEY_VALUE_FULL_INFORMATION)Storage;
PAGED_CODE(); //INIT
InitializeObjectAttributes(
&ObjectAttributes,
RegistryPath, // name
OBJ_CASE_INSENSITIVE, // attributes
NULL, // root
NULL // security descriptor
);
Status = ZwOpenKey (&ConfigHandle, KEY_READ, &ObjectAttributes);
if (!NT_SUCCESS(Status)) {
//RxLogFailure (
// RxFileSystemDeviceObject,
// NULL,
// EVENT_RDR_CANT_READ_REGISTRY,
// Status);
return;
}
RtlInitUnicodeString(&UnicodeString, L"Parameters");
InitializeObjectAttributes(
&ObjectAttributes,
&UnicodeString,
OBJ_CASE_INSENSITIVE,
ConfigHandle,
NULL
);
Status = ZwOpenKey (&ParametersHandle, KEY_READ, &ObjectAttributes);
if (!NT_SUCCESS(Status)) {
//RxLogFailure (
// RxFileSystemDeviceObject,
// NULL,
// EVENT_RDR_CANT_READ_REGISTRY,
// Status);
ZwClose(ConfigHandle);
return;
}
#ifdef RDBSSLOG
RxGetStringRegistryParameter(ParametersHandle,
L"InitialDebugString",
&UnicodeString,
(PKEY_VALUE_PARTIAL_INFORMATION) Storage,
sizeof(Storage),
FALSE
);
//DbgPrint("String From Registry %wZ, buffer = %08lx\n",&UnicodeString,UnicodeString.Buffer);
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(); //INIT
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(); //INIT
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.
simple? i think NOT.
----------------------------------*/
#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;
Status = RtlAppendUnicodeStringToString(&ProviderInfoName,ServiceName);
if (Status != STATUS_SUCCESS) {
DbgPrint("Could append1: %08lx %wZ\n",Status,&ProviderInfoName);
//RxAbbreviatedWriteLogEntry(Status);
goto FINALLY;
}
RtlInitUnicodeString(&ProviderInfoKey, NETWORK_PROVIDER_SUBKEY);
Status = RtlAppendUnicodeStringToString(&ProviderInfoName,&ProviderInfoKey);
if (Status != STATUS_SUCCESS) {
DbgPrint("Could append2: %08lx %wZ\n",Status,&ProviderInfoName);
RxAbbreviatedWriteLogEntry(Status);
goto FINALLY;
}
//
// Open the key in preparation for reeading the devicename value
//DbgPrint("RxAccrueProviderFromServiceName providerinfoname %wZ\n",&ProviderInfoName);
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);
RxAbbreviatedWriteLogEntry(Status);
goto FINALLY;
}
//
// 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.
//DbgPrint("RxAccrueProviderFromServiceName ServiceName %wZ; worked\n",ServiceName);
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) {
RxAbbreviatedWriteLogEntry(Status);
goto FINALLY;
}
//DbgPrint("RxAccrueProviderFromServiceName ServiceName %wZ; worked; devicenamesize=%08lx\n",
// ServiceName,InitialValuePartialInformation.DataLength);
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);
RxAbbreviatedWriteLogEntry(Status);
goto FINALLY;
}
Status = ZwQueryValueKey(NetworkProviderInfoHandle,
&ParameterDeviceName,
KeyValuePartialInformation,
&UncProvider->Info,
ProviderLength,
&DummyBytesRead);
if (Status!=STATUS_SUCCESS) {
RxAbbreviatedWriteLogEntry(Status);
goto FINALLY;
}
//
// 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);
//
// 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);
RxAbbreviatedWriteLogEntry(Status);
goto FINALLY;
}
//
// 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);
RxAbbreviatedWriteLogEntry(Status);
goto FINALLY;
}
//
//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);
RxAbbreviatedWriteLogEntry(Status);
goto FINALLY;
}
//
// 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;
RxAbbreviatedWriteLogEntry(Status);
goto FINALLY;
}
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;
RxAbbreviatedWriteLogEntry(Status);
goto FINALLY;
}
//
// 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++) {
//DbgPrint("Considering %c\n",*ScanPtr);
}
ASSERT(*ScanPtr==L',');
ServiceName.Length = (USHORT)(sizeof(WCHAR)*(ScanPtr - ServiceName.Buffer));
//DbgPrint("Length %08lx\n",ServiceName.Length);
//DbgPrint("ServiceName %wZ\n",&ServiceName);
// accrue it to the list
Priority++;
Status = RxAccrueProviderFromServiceName(ServiceRootHandle,
&ServiceName,
Priority,
(PWCHAR)ServiceNameStringBuffer,
ServiceNameStringLength );
if (Status == STATUS_INSUFFICIENT_RESOURCES) {
goto FINALLY; //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();
//DbgPrint("RxDestructProviderOrder \n");
for (Entry = RxUncProviders.Flink;
Entry != &RxUncProviders;
) {
PRX_UNC_PROVIDER UncProvider = (PRX_UNC_PROVIDER)Entry;
Entry = Entry->Flink;
//DbgPrint("RxDO UncP %wZ p=%x\n",&UncProvider->DeviceName,UncProvider->Priority);
RxFreePool(UncProvider);
}
return;
}
#else
ULONG
RxGetNetworkProviderPriority(
PUNICODE_STRING DeviceName
)
{
PAGED_CODE(); //DUPLICATE
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
)
{
PAGED_CODE();
#ifndef MONOLITHIC_MINIRDR
{ULONG i;
//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;
#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(); //INIT
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)) {
//RxLogFailure (
// RxFileSystemDeviceObject,
// NULL,
// EVENT_RDR_CANT_READ_REGISTRY,
// Status);
return;
}
RtlInitUnicodeString(&UnicodeString, L"DisableByteRangeLockingOnReadOnlyFiles");
Status = ZwQueryValueKey(ParametersHandle,
&UnicodeString,
KeyValuePartialInformation,
Value,
ValueSize,
&BytesRead);
if (NT_SUCCESS(Status)) {
if (Value->Type == REG_DWORD) {
PULONG ConfigValue = (PULONG)&Value->Data[0];
DisableByteRangeLockingOnReadOnlyFiles =
(BOOLEAN) (*((PULONG)ConfigValue) != 0);
}
}
ZwClose(ParametersHandle);
}