/*++ Copyright (c) 1992 Microsoft Corporation Module Name: NwInit.c Abstract: This module implements the DRIVER_INITIALIZATION routine for NetWare Author: Colin Watson [ColinW] 15-Dec-1992 Revision History: --*/ #include "Procs.h" #include "wdmsec.h" #define Dbg (DEBUG_TRACE_LOAD) // // Private declaration because ZwQueryDefaultLocale isn't in any header. // NTSYSAPI NTSTATUS NTAPI ZwQueryDefaultLocale( IN BOOLEAN UserProfile, OUT PLCID DefaultLocaleId ); NTSTATUS DriverEntry( IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath ); VOID UnloadDriver( IN PDRIVER_OBJECT DriverObject ); VOID GetConfigurationInformation( PUNICODE_STRING RegistryPath ); VOID ReadValue( HANDLE ParametersHandle, PLONG pVar, PWCHAR Name ); #ifdef ALLOC_PRAGMA #pragma alloc_text( PAGE, DriverEntry ) #pragma alloc_text( PAGE, GetConfigurationInformation ) #pragma alloc_text( PAGE, ReadValue ) #endif #if 0 // Not pageable UnloadDriver #endif #ifdef _PNP_POWER_ extern HANDLE TdiBindingHandle; #endif static ULONG IrpStackSize; NTSTATUS DriverEntry( IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath ) /*++ Routine Description: This is the initialization routine for the Nw 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: NTSTATUS - The function value is the final status from the initialization operation. --*/ { NTSTATUS Status; UNICODE_STRING UnicodeString; UNICODE_STRING SddlString; PAGED_CODE(); //DbgBreakPoint(); InitializeAttach( ); NwInitializeData(); //NwInitializePidTable(); // Terminal Server code merge - // NwInitalizePidTable in the NwAllocateAndInitScb // Pid table is per SCB base. // // Create the device object. // RtlInitUnicodeString( &UnicodeString, DD_NWFS_DEVICE_NAME_U ); RtlInitUnicodeString( &SddlString, L"D:P(A;;GX;;;WD)(A;;GA;;;SY)(A;;GA;;;BA)(A;;GA;;;LS)(A;;GA;;;NS)(A;;GX;;;RC)" ); Status = IoCreateDeviceSecure( DriverObject, 0, &UnicodeString, FILE_DEVICE_NETWORK_FILE_SYSTEM, FILE_REMOTE_DEVICE, FALSE, &SddlString, NULL, &FileSystemDeviceObject ); if (!NT_SUCCESS( Status )) { Error(EVENT_NWRDR_CANT_CREATE_DEVICE, Status, NULL, 0, 0); return Status; } // // Initialize parameters to the defaults. // IrpStackSize = NWRDR_IO_STACKSIZE; // // Attempt to read config information from the registry // GetConfigurationInformation( RegistryPath ); // // Set the stack size. // FileSystemDeviceObject->StackSize = (CCHAR)IrpStackSize; // // Initialize the driver object with this driver's entry points. // DriverObject->MajorFunction[IRP_MJ_CREATE] = (PDRIVER_DISPATCH)NwFsdCreate; DriverObject->MajorFunction[IRP_MJ_CLEANUP] = (PDRIVER_DISPATCH)NwFsdCleanup; DriverObject->MajorFunction[IRP_MJ_CLOSE] = (PDRIVER_DISPATCH)NwFsdClose; DriverObject->MajorFunction[IRP_MJ_FILE_SYSTEM_CONTROL] = (PDRIVER_DISPATCH)NwFsdFileSystemControl; DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = (PDRIVER_DISPATCH)NwFsdDeviceIoControl; DriverObject->MajorFunction[IRP_MJ_QUERY_INFORMATION] = (PDRIVER_DISPATCH)NwFsdQueryInformation; DriverObject->MajorFunction[IRP_MJ_QUERY_VOLUME_INFORMATION] = (PDRIVER_DISPATCH)NwFsdQueryVolumeInformation; DriverObject->MajorFunction[IRP_MJ_SET_VOLUME_INFORMATION] = (PDRIVER_DISPATCH)NwFsdSetVolumeInformation; DriverObject->MajorFunction[IRP_MJ_DIRECTORY_CONTROL] = (PDRIVER_DISPATCH)NwFsdDirectoryControl; DriverObject->MajorFunction[IRP_MJ_READ] = (PDRIVER_DISPATCH)NwFsdRead; DriverObject->MajorFunction[IRP_MJ_WRITE] = (PDRIVER_DISPATCH)NwFsdWrite; DriverObject->MajorFunction[IRP_MJ_SET_INFORMATION] = (PDRIVER_DISPATCH)NwFsdSetInformation; DriverObject->MajorFunction[IRP_MJ_LOCK_CONTROL] = (PDRIVER_DISPATCH)NwFsdLockControl; DriverObject->MajorFunction[IRP_MJ_FLUSH_BUFFERS] = (PDRIVER_DISPATCH)NwFsdFlushBuffers; #ifdef _PNP_POWER_ DriverObject->MajorFunction[IRP_MJ_PNP] = (PDRIVER_DISPATCH)NwFsdProcessPnpIrp; #endif /* DriverObject->MajorFunction[IRP_MJ_QUERY_EA] = (PDRIVER_DISPATCH)NwFsdQueryEa; DriverObject->MajorFunction[IRP_MJ_SET_EA] = (PDRIVER_DISPATCH)NwFsdSetEa; DriverObject->MajorFunction[IRP_MJ_SHUTDOWN] = (PDRIVER_DISPATCH)NwFsdShutdown; */ DriverObject->DriverUnload = UnloadDriver; #if NWFASTIO DriverObject->FastIoDispatch = &NwFastIoDispatch; NwFastIoDispatch.SizeOfFastIoDispatch = sizeof(FAST_IO_DISPATCH); NwFastIoDispatch.FastIoCheckIfPossible = NULL; NwFastIoDispatch.FastIoRead = NwFastRead; NwFastIoDispatch.FastIoWrite = NwFastWrite; NwFastIoDispatch.FastIoQueryBasicInfo = NwFastQueryBasicInfo; NwFastIoDispatch.FastIoQueryStandardInfo = NwFastQueryStandardInfo; NwFastIoDispatch.FastIoLock = NULL; NwFastIoDispatch.FastIoUnlockSingle = NULL; NwFastIoDispatch.FastIoUnlockAll = NULL; NwFastIoDispatch.FastIoUnlockAllByKey = NULL; NwFastIoDispatch.FastIoDeviceControl = NULL; #endif NwInitializeRcb( &NwRcb ); InitializeIrpContext( ); NwPermanentNpScb.State = SCB_STATE_DISCONNECTING; // // Do a kludge here so that we get to the "real" global variables. // //NlsLeadByteInfo = *(PUSHORT *)NlsLeadByteInfo; //NlsMbCodePageTag = *(*(PBOOLEAN *)&NlsMbCodePageTag); #ifndef IFS FsRtlLegalAnsiCharacterArray = *(PUCHAR *)FsRtlLegalAnsiCharacterArray; #endif // // Register as a file system, notifies filters // IoRegisterFileSystem(FileSystemDeviceObject); DebugTrace(0, Dbg, "NetWare redirector loaded\n", 0); // // And return to our caller // return( STATUS_SUCCESS ); } VOID UnloadDriver( IN PDRIVER_OBJECT DriverObject ) /*++ Routine Description: This is the unload routine for the NetWare redirector filesystem. Arguments: DriverObject - pointer to the driver object for the redirector Return Value: None --*/ { KIRQL OldIrql; NTSTATUS status; // // Lock down code // DebugTrace(0, Dbg, "UnloadDriver called\n", 0); // // Unregister as a file system, notifies filters // IoUnregisterFileSystem(FileSystemDeviceObject); // // tommye - MS bug 33463 // // Clean up our cached credentials - this fixes a // memory leak when we shut down. // { LARGE_INTEGER Unused; KeQuerySystemTime( &Unused ); CleanupSupplementalCredentials(Unused, TRUE); } NwReferenceUnlockableCodeSection (); TerminateWorkerThread(); #ifdef _PNP_POWER_ // // Unregister the bind handler with tdi. // if ( TdiBindingHandle != NULL ) { status = TdiDeregisterPnPHandlers( TdiBindingHandle ); TdiBindingHandle = NULL; DebugTrace(0, Dbg,"TDI binding handle deregistered\n",0); } #endif IpxClose(); IPX_Close_Socket( &NwPermanentNpScb.Server ); KeAcquireSpinLock( &ScbSpinLock, &OldIrql ); RemoveEntryList( &NwPermanentNpScb.ScbLinks ); KeReleaseSpinLock( &ScbSpinLock, OldIrql ); DestroyAllScb(); UninitializeIrpContext(); NwDereferenceUnlockableCodeSection (); NwUnlockCodeSections(FALSE); StopTimer(); if (IpxTransportName.Buffer != NULL) { FREE_POOL(IpxTransportName.Buffer); } if ( NwProviderName.Buffer != NULL ) { FREE_POOL( NwProviderName.Buffer ); } //NwUninitializePidTable(); //Terminal Server code merge - //NwUninitializePidTable is called in //NwDeleteScb. Pid table is per SCB base. ASSERT( IsListEmpty( &NwPagedPoolList ) ); ASSERT( IsListEmpty( &NwNonpagedPoolList ) ); ASSERT( MdlCount == 0 ); ASSERT( IrpCount == 0 ); NwDeleteRcb( &NwRcb ); #ifdef NWDBG ExDeleteResourceLite( &NwDebugResource ); #endif ExDeleteResourceLite( &NwOpenResource ); ExDeleteResourceLite( &NwUnlockableCodeResource ); IoDeleteDevice(FileSystemDeviceObject); DebugTrace(0, Dbg, "NetWare redirector unloaded\n\n", 0); } VOID GetConfigurationInformation( PUNICODE_STRING RegistryPath ) /*++ Routine Description: This routine read redirector configuration information from the registry. Arguments: RegistryPath - A pointer the a path to the Return Value: None --*/ { UNICODE_STRING UnicodeString; HANDLE ConfigHandle; HANDLE ParametersHandle; NTSTATUS Status; OBJECT_ATTRIBUTES ObjectAttributes; ULONG TimeOutEventinMins = 0L; LCID lcid; PAGED_CODE(); Japan = FALSE; Korean = FALSE; ZwQueryDefaultLocale( FALSE, &lcid ); if (PRIMARYLANGID(lcid) == LANG_JAPANESE || PRIMARYLANGID(lcid) == LANG_KOREAN || PRIMARYLANGID(lcid) == LANG_CHINESE) { Japan = TRUE; if (PRIMARYLANGID(lcid) == LANG_KOREAN){ Korean = TRUE; } } 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; } ReadValue( ParametersHandle, &IrpStackSize, L"IrpStackSize" ); ReadValue( ParametersHandle, &MaxSendDelay, L"MaxSendDelay" ); ReadValue( ParametersHandle, &MaxReceiveDelay, L"MaxReceiveDelay" ); ReadValue( ParametersHandle, &MinSendDelay, L"MinSendDelay" ); ReadValue( ParametersHandle, &MinReceiveDelay, L"MinReceiveDelay" ); ReadValue( ParametersHandle, &BurstSuccessCount, L"BurstSuccessCount" ); ReadValue( ParametersHandle, &BurstSuccessCount2, L"BurstSuccessCount2" ); ReadValue( ParametersHandle, &MaxReadTimeout, L"MaxReadTimeout" ); ReadValue( ParametersHandle, &MaxWriteTimeout, L"MaxWriteTimeout" ); ReadValue( ParametersHandle, &ReadTimeoutMultiplier, L"ReadTimeoutMultiplier" ); ReadValue( ParametersHandle, &WriteTimeoutMultiplier, L"WriteTimeoutMultiplier" ); ReadValue( ParametersHandle, &AllowGrowth, L"AllowGrowth" ); ReadValue( ParametersHandle, &DontShrink, L"DontShrink" ); ReadValue( ParametersHandle, &SendExtraNcp, L"SendExtraNcp" ); ReadValue( ParametersHandle, &DefaultMaxPacketSize, L"DefaultMaxPacketSize" ); ReadValue( ParametersHandle, &PacketThreshold, L"PacketThreshold" ); ReadValue( ParametersHandle, &LargePacketAdjustment, L"LargePacketAdjustment" ); ReadValue( ParametersHandle, &LipPacketAdjustment, L"LipPacketAdjustment" ); ReadValue( ParametersHandle, &LipAccuracy, L"LipAccuracy" ); ReadValue( ParametersHandle, &DisableReadCache, L"DisableReadCache" ); ReadValue( ParametersHandle, &DisableWriteCache, L"DisableWriteCache" ); ReadValue( ParametersHandle, &FavourLongNames, L"FavourLongNames" ); ReadValue( ParametersHandle, &LongNameFlags, L"LongNameFlags" ); ReadValue( ParametersHandle, &DirCacheEntries, L"DirectoryCacheSize" ); if( DirCacheEntries == 0 ) { DirCacheEntries = 1; } if( DirCacheEntries > MAX_DIR_CACHE_ENTRIES ) { DirCacheEntries = MAX_DIR_CACHE_ENTRIES; } ReadValue( ParametersHandle, &LockTimeoutThreshold, L"LockTimeout" ); ReadValue( ParametersHandle, &TimeOutEventinMins, L"TimeOutEventinMins"); ReadValue( ParametersHandle, &EnableMultipleConnects, L"EnableMultipleConnects"); ReadValue( ParametersHandle, &AllowSeedServerRedirection, L"AllowSeedServerRedirection"); ReadValue( ParametersHandle, &ReadExecOnlyFiles, L"ReadExecOnlyFiles"); ReadValue( ParametersHandle, &DisableAltFileName, L"DisableAltFileName"); ReadValue( ParametersHandle, &NwAbsoluteTotalWaitTime, L"AbsoluteTotalWaitTime"); ReadValue( ParametersHandle, &NdsObjectCacheSize, L"NdsObjectCacheSize" ); ReadValue( ParametersHandle, &NdsObjectCacheTimeout, L"NdsObjectCacheTimeout" ); ReadValue ( ParametersHandle, &PreferNDSBrowsing, L"PreferNDSBrowsing" ); // // Make sure the object cache values are within bounds. // // NOTE: If the timeout is set to zero, then the cache is // effectively disabled. NdsObjectCacheSize is set // to zero to accomplish this. // if( NdsObjectCacheSize > MAX_NDS_OBJECT_CACHE_SIZE ) { NdsObjectCacheSize = MAX_NDS_OBJECT_CACHE_SIZE; } if( NdsObjectCacheTimeout > MAX_NDS_OBJECT_CACHE_TIMEOUT ) { NdsObjectCacheTimeout = MAX_NDS_OBJECT_CACHE_TIMEOUT; } else if( NdsObjectCacheTimeout == 0 ) { NdsObjectCacheSize = 0; } if (!TimeOutEventinMins) { // // If for some reason, the registry has set the TimeOutEventInterval // to zero, reset to the default value to avoid divide-by-zero // TimeOutEventinMins = DEFAULT_TIMEOUT_EVENT_INTERVAL; } TimeOutEventInterval.QuadPart = TimeOutEventinMins * 60 * SECONDS; // // tommye - MS bug 2743 we now get the RetryCount from the registry, providing // a default of DEFAULT_RETRY_COUNT. // { LONG TempRetryCount; TempRetryCount = DEFAULT_RETRY_COUNT; ReadValue( ParametersHandle, &TempRetryCount, L"DefaultRetryCount"); DefaultRetryCount = (SHORT) TempRetryCount & 0xFFFF; } ZwClose( ParametersHandle ); ZwClose( ConfigHandle ); } VOID ReadValue( HANDLE ParametersHandle, PLONG pVar, PWCHAR Name ) /*++ Routine Description: This routine reads a single redirector configuration value from the registry. Arguments: Parameters - Supplies where to look for values. pVar - Address of the variable to receive the new value if the name exists. Name - Name whose value is to be loaded. Return Value: None --*/ { WCHAR Storage[256]; UNICODE_STRING UnicodeString; NTSTATUS Status; ULONG BytesRead; PKEY_VALUE_FULL_INFORMATION Value = (PKEY_VALUE_FULL_INFORMATION)Storage; PAGED_CODE(); UnicodeString.Buffer = Storage; RtlInitUnicodeString(&UnicodeString, Name ); Status = ZwQueryValueKey( ParametersHandle, &UnicodeString, KeyValueFullInformation, Value, sizeof(Storage), &BytesRead ); if ( NT_SUCCESS( Status ) ) { if ( Value->DataLength >= sizeof(ULONG) ) { *pVar = *(LONG UNALIGNED *)( (PCHAR)Value + Value->DataOffset ); } } }