/*++ 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\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\\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); }