/*++ Copyright (c) 1998-2001 Microsoft Corporation Module Name: init.cxx Abstract: This module performs initialization for the UL device driver. Author: Keith Moore (keithmo) 10-Jun-1998 Revision History: --*/ #include "precomp.h" // // Private constants. // #define DEFAULT_THREAD_AFFINITY_MASK ((1ui64 << KeNumberProcessors) - 1) // // Private types. // typedef struct _SID_MASK_PAIR { PSID pSid; ACCESS_MASK AccessMask; } SID_MASK_PAIR, *PSID_MASK_PAIR; #ifdef __cplusplus extern "C" { #endif // __cplusplus // // Private prototypes. // NTSTATUS UlpApplySecurityToDeviceObjects( VOID ); NTSTATUS UlpCreateSecurityDescriptor( OUT PSECURITY_DESCRIPTOR pSecurityDescriptor, IN PSID_MASK_PAIR pSidMaskPairs, IN ULONG NumSidMaskPairs ); VOID UlpCleanupSecurityDescriptor( IN PSECURITY_DESCRIPTOR pSecurityDescriptor ); NTSTATUS UlpSetDeviceObjectSecurity( IN PDEVICE_OBJECT pDeviceObject, IN SECURITY_INFORMATION SecurityInformation, IN PSECURITY_DESCRIPTOR pSecurityDescriptor ); VOID UlpReadRegistry ( IN PUL_CONFIG pConfig ); VOID UlpTerminateModules( VOID ); #if ALLOW_UNLOAD VOID UlpUnload ( IN PDRIVER_OBJECT DriverObject ); #endif // ALLOW_UNLOAD #ifdef __cplusplus }; // extern "C" #endif // __cplusplus // // Private globals. // #if DBG ULONG g_UlpForceInitFailure = 0; #endif // DBG #ifdef ALLOC_PRAGMA #pragma alloc_text( INIT, DriverEntry ) #pragma alloc_text( INIT, UlpApplySecurityToDeviceObjects ) #pragma alloc_text( INIT, UlpCreateSecurityDescriptor ) #pragma alloc_text( INIT, UlpCleanupSecurityDescriptor ) #pragma alloc_text( INIT, UlpSetDeviceObjectSecurity ) #pragma alloc_text( INIT, UlpReadRegistry ) #if ALLOW_UNLOAD #pragma alloc_text( PAGE, UlpUnload ) #pragma alloc_text( PAGE, UlpTerminateModules ) #endif // ALLOW_UNLOAD // // Note that UlpTerminateModules() must be "page" if driver unloading // is enabled (it's called from UlpUnload), but can be "init" otherwise // (it's only called after initialization failure). // #if ALLOW_UNLOAD #pragma alloc_text( PAGE, UlpTerminateModules ) #else #pragma alloc_text( INIT, UlpTerminateModules ) #endif // ALLOW_UNLOAD #endif // ALLOC_PRAGMA // // Public functions. // /***************************************************************************++ Routine Description: This is the initialization routine for the UL device driver. Arguments: DriverObject - Supplies a pointer to driver object created by the system. RegistryPath - Supplies the name of the driver's configuration registry tree. Return Value: NTSTATUS - Completion status. --***************************************************************************/ NTSTATUS DriverEntry( IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath ) { NTSTATUS status; UNICODE_STRING deviceName; OBJECT_ATTRIBUTES objectAttributes; CLONG i; UL_CONFIG config; // // Sanity check. // PAGED_CODE(); // // Grab the number of processors in the system. // g_UlNumberOfProcessors = KeNumberProcessors; g_UlThreadAffinityMask = DEFAULT_THREAD_AFFINITY_MASK; // // Grab the largest cache line size in the system // g_UlCacheLineSize = KeGetRecommendedSharedDataAlignment(); for (g_UlCacheLineBits = 0; (1U << g_UlCacheLineBits) < g_UlCacheLineSize; ++g_UlCacheLineBits) {} ASSERT(g_UlCacheLineSize <= (1U << g_UlCacheLineBits)); // // Snag a pointer to the system process. // g_pUlSystemProcess = (PKPROCESS)IoGetCurrentProcess(); // // Read registry information. // UlpReadRegistry( &config ); #if DBG // // Give anyone using the kernel debugger a chance to abort // initialization. // if (g_UlpForceInitFailure != 0) { status = STATUS_UNSUCCESSFUL; goto fatal; } #endif // DBG // // Initialize the global trace logs. // UlInitializeOwnerRefTraceLog(); CREATE_REF_TRACE_LOG( g_pMondoGlobalTraceLog, 16384 - REF_TRACE_OVERHEAD, 0 ); CREATE_REF_TRACE_LOG( g_pTdiTraceLog, 32768 - REF_TRACE_OVERHEAD, 0 ); CREATE_REF_TRACE_LOG( g_pHttpRequestTraceLog, 2048 - REF_TRACE_OVERHEAD, 0 ); CREATE_REF_TRACE_LOG( g_pHttpConnectionTraceLog, 2048 - REF_TRACE_OVERHEAD, 0 ); CREATE_REF_TRACE_LOG( g_pHttpResponseTraceLog, 2048 - REF_TRACE_OVERHEAD, 0 ); CREATE_REF_TRACE_LOG( g_pAppPoolTraceLog, 2048 - REF_TRACE_OVERHEAD, 0 ); CREATE_REF_TRACE_LOG( g_pConfigGroupTraceLog, 2048 - REF_TRACE_OVERHEAD, 0 ); CREATE_REF_TRACE_LOG( g_pThreadTraceLog, 2048 - REF_TRACE_OVERHEAD, 0 ); CREATE_REF_TRACE_LOG( g_pMdlTraceLog, 2048 - REF_TRACE_OVERHEAD, 0 ); CREATE_REF_TRACE_LOG( g_pFilterTraceLog, 2048 - REF_TRACE_OVERHEAD, 0 ); CREATE_IRP_TRACE_LOG( g_pIrpTraceLog, 32768 - REF_TRACE_OVERHEAD, 0 ); CREATE_TIME_TRACE_LOG( g_pTimeTraceLog, 32768 - REF_TRACE_OVERHEAD, 0 ); CREATE_REPLENISH_TRACE_LOG( g_pReplenishTraceLog, 32768 - REF_TRACE_OVERHEAD, 0 ); CREATE_FILTQ_TRACE_LOG( g_pFilterQueueTraceLog, 2048 - REF_TRACE_OVERHEAD, 0 ); CREATE_REF_TRACE_LOG( g_pSiteCounterTraceLog, 2048 - REF_TRACE_OVERHEAD, 0 ); CREATE_REF_TRACE_LOG( g_pConnectionCountTraceLog, 2048 - REF_TRACE_OVERHEAD, 0 ); CREATE_REF_TRACE_LOG( g_pConfigGroupInfoTraceLog, 2048 - REF_TRACE_OVERHEAD, 0 ); CREATE_REF_TRACE_LOG( g_pChunkTrackerTraceLog, 2048 - REF_TRACE_OVERHEAD, 0 ); CREATE_REF_TRACE_LOG( g_pWorkItemTraceLog, 32768 - REF_TRACE_OVERHEAD, 0 ); // // Create an object directory to contain our device objects. // RtlInitUnicodeString( &deviceName, HTTP_DIRECTORY_NAME ); InitializeObjectAttributes( &objectAttributes, // ObjectAttributes &deviceName, // ObjectName OBJ_CASE_INSENSITIVE | // Attributes UL_KERNEL_HANDLE, NULL, // RootDirectory NULL // SecurityDescriptor ); UlAttachToSystemProcess(); status = ZwCreateDirectoryObject( &g_UlDirectoryObject, // DirectoryHandle DIRECTORY_ALL_ACCESS, // AccessMask &objectAttributes // ObjectAttributes ); UlDetachFromSystemProcess(); if (!NT_SUCCESS(status)) { goto fatal; } // // Create the control channel device object. // RtlInitUnicodeString( &deviceName, HTTP_CONTROL_DEVICE_NAME ); status = IoCreateDevice( DriverObject, // DriverObject 0, // DeviceExtension &deviceName, // DeviceName FILE_DEVICE_NETWORK, // DeviceType 0, // DeviceCharacteristics TRUE, // Exclusive &g_pUlControlDeviceObject // DeviceObject ); if (!NT_SUCCESS(status)) { goto fatal; } // // Create the filter device object. // RtlInitUnicodeString( &deviceName, HTTP_FILTER_DEVICE_NAME ); status = IoCreateDevice( DriverObject, // DriverObject 0, // DeviceExtension &deviceName, // DeviceName FILE_DEVICE_NETWORK, // DeviceType 0, // DeviceCharacteristics FALSE, // Exclusive &g_pUlFilterDeviceObject // DeviceObject ); if (!NT_SUCCESS(status)) { goto fatal; } g_pUlFilterDeviceObject->StackSize = g_UlIrpStackSize; // // Create the app pool device object. // RtlInitUnicodeString( &deviceName, HTTP_APP_POOL_DEVICE_NAME ); status = IoCreateDevice( DriverObject, // DriverObject 0, // DeviceExtension &deviceName, // DeviceName FILE_DEVICE_NETWORK, // DeviceType 0, // DeviceCharacteristics FALSE, // Exclusive &g_pUlAppPoolDeviceObject // DeviceObject ); if (!NT_SUCCESS(status)) { goto fatal; } g_pUlAppPoolDeviceObject->StackSize = g_UlIrpStackSize; // // If so requested, apply security to the device objects. // // CODEWORK: REMOVE THIS CONFIGURATION PARAMETER! // if (config.EnableSecurity) { status = UlpApplySecurityToDeviceObjects(); if (!NT_SUCCESS(status)) { goto fatal; } } else { KdPrint(( "UL: security disabled\n" )); } // // Initialize the driver object with this driver's entrypoints. // DriverObject->MajorFunction[IRP_MJ_CREATE] = &UlCreate; DriverObject->MajorFunction[IRP_MJ_CLOSE] = &UlClose; DriverObject->MajorFunction[IRP_MJ_CLEANUP] = &UlCleanup; DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = &UlDeviceControl; DriverObject->FastIoDispatch = &UlFastIoDispatch; DriverObject->DriverUnload = NULL; #if ALLOW_UNLOAD if( config.EnableUnload ) { KdPrint(( "UL: DriverUnload enabled\n" )); DriverObject->DriverUnload = &UlpUnload; } #endif // ALLOW_UNLOAD // // Initialize global data. // status = UlInitializeData(&config); if (!NT_SUCCESS(status)) { goto fatal; } // // Create the thread pool. // status = UlInitializeThreadPool(config.ThreadsPerCpu); if (!NT_SUCCESS(status)) { goto fatal; } // // Initialize common TDI. // status = UxInitializeTdi(); if (!NT_SUCCESS(status)) { goto fatal; } // // Initialize server connection code. // status = UlInitializeTdi(); if (!NT_SUCCESS(status)) { goto fatal; } // // Initialize temporary test code. // // status = UlInitializeTdiTest(); // if (!NT_SUCCESS(status)) // { // goto fatal; // } // // Initialize George. // status = UlLargeMemInitialize(&config); ASSERT( NT_SUCCESS(status) ); // // Initialize Keith. // status = UlInitializeControlChannel(); ASSERT( NT_SUCCESS(status) ); // // Initialize Henry. // status = InitializeHttpUtil(); ASSERT( NT_SUCCESS(status) ); status = InitializeParser(); ASSERT( NT_SUCCESS(status) ); status = UlInitializeOpaqueIdTable(); ASSERT( NT_SUCCESS(status) ); status = InitializeFileCache(); ASSERT( NT_SUCCESS(status) ); // // Initialize Michael. // status = UlInitializeFilterChannel(); ASSERT( NT_SUCCESS(status) ); // // Initialize Alex. // status = UlInitializeUriCache(&config); if ( !NT_SUCCESS(status) ) { goto fatal; } status = UlInitializeDateCache(); ASSERT( NT_SUCCESS(status) ); // // Initialize Paul. // status = UlInitializeCG(); ASSERT( NT_SUCCESS(status) ); status = UlInitializeAP(); ASSERT( NT_SUCCESS(status) ); // // Initialize Ali // status = UlInitializeLogs(); ASSERT( NT_SUCCESS(status) ); // TC Init may fail if PSched // is not installed. UlTcInitialize(); #if 0 status = UlTcInitialize(); ASSERT( NT_SUCCESS(status)); #endif status = UlInitGlobalConnectionLimits(); ASSERT( NT_SUCCESS(status) ); // // Initialize Eric. // status = UlInitializeHttpRcv(); ASSERT( NT_SUCCESS(status) ); status = UlInitializeCounters(); ASSERT( NT_SUCCESS(status) ); UlInitializeTimeoutMonitor(); #if DBG // // Give anyone using the kernel debugger one final chance to abort // initialization. // if (g_UlpForceInitFailure != 0) { status = STATUS_UNSUCCESSFUL; goto fatal; } #endif // DBG return STATUS_SUCCESS; // // Fatal error handlers. // fatal: UlpTerminateModules(); ASSERT( !NT_SUCCESS(status) ); return status; } // DriverEntry // // Private functions. // /***************************************************************************++ Routine Description: Applies the appropriate security descriptors to the global device objects created at initialization time. Return Value: NTSTATUS - Completion status. --***************************************************************************/ NTSTATUS UlpApplySecurityToDeviceObjects( VOID ) { NTSTATUS status; SECURITY_DESCRIPTOR securityDescriptor; PGENERIC_MAPPING pFileObjectGenericMapping; ACCESS_MASK fileRead; ACCESS_MASK fileAll; HANDLE handle; SID_MASK_PAIR sidMaskPairs[3]; // // Sanity check. // PAGED_CODE(); ASSERT( IS_VALID_DEVICE_OBJECT( g_pUlControlDeviceObject ) ); ASSERT( IS_VALID_DEVICE_OBJECT( g_pUlFilterDeviceObject ) ); ASSERT( IS_VALID_DEVICE_OBJECT( g_pUlAppPoolDeviceObject ) ); // // Gain access to the predefined SIDs and other security-related // goodies exported by the kernel. // //SeEnableAccessToExports(); // // Map a couple of generic file access types to their corresponding // object-specific rights. // pFileObjectGenericMapping = IoGetFileObjectGenericMapping(); ASSERT( pFileObjectGenericMapping != NULL ); fileRead = GENERIC_READ; RtlMapGenericMask( &fileRead, pFileObjectGenericMapping ); fileAll = GENERIC_ALL; RtlMapGenericMask( &fileAll, pFileObjectGenericMapping ); // // Build a restrictive security descriptor for the control device // object: // // Full access for NT AUTHORITY\SYSTEM // Full access for BUILTIN\Administrators // sidMaskPairs[0].pSid = SeExports->SeLocalSystemSid; sidMaskPairs[0].AccessMask = fileAll; sidMaskPairs[1].pSid = SeExports->SeAliasAdminsSid; sidMaskPairs[1].AccessMask = fileAll; status = UlpCreateSecurityDescriptor( &securityDescriptor, // pSecurityDescriptor &sidMaskPairs[0], // pSidMaskPairs 2 // NumSidMaskPairs ); if (!NT_SUCCESS(status)) { goto complete; } status = UlpSetDeviceObjectSecurity( g_pUlControlDeviceObject, DACL_SECURITY_INFORMATION, &securityDescriptor ); UlpCleanupSecurityDescriptor( &securityDescriptor ); if (!NT_SUCCESS(status)) { goto complete; } // // Build a restrictive security descriptor for the filter device // object: // // Full access for NT AUTHORITY\SYSTEM // Full access for BUILTIN\Administrators // sidMaskPairs[0].pSid = SeExports->SeLocalSystemSid; sidMaskPairs[0].AccessMask = fileAll; sidMaskPairs[1].pSid = SeExports->SeAliasAdminsSid; sidMaskPairs[1].AccessMask = fileAll; status = UlpCreateSecurityDescriptor( &securityDescriptor, // pSecurityDescriptor &sidMaskPairs[0], // pSidMaskPairs 2 // NumSidMaskPairs ); if (!NT_SUCCESS(status)) { goto complete; } status = UlpSetDeviceObjectSecurity( g_pUlFilterDeviceObject, DACL_SECURITY_INFORMATION, &securityDescriptor ); UlpCleanupSecurityDescriptor( &securityDescriptor ); if (!NT_SUCCESS(status)) { goto complete; } // // Build a slightly less restrictive security descriptor for the // app pool device object: // // Full access for NT AUTHORITY\SYSTEM // Full access for BUILTIN\Administrators // Read access for Everyone // sidMaskPairs[0].pSid = SeExports->SeLocalSystemSid; sidMaskPairs[0].AccessMask = fileAll; sidMaskPairs[1].pSid = SeExports->SeAliasAdminsSid; sidMaskPairs[1].AccessMask = fileAll; sidMaskPairs[2].pSid = SeExports->SeWorldSid; sidMaskPairs[2].AccessMask = fileRead; status = UlpCreateSecurityDescriptor( &securityDescriptor, // pSecurityDescriptor &sidMaskPairs[0], // pSidMaskPairs 3 // NumSidMaskPairs ); if (!NT_SUCCESS(status)) { goto complete; } status = UlpSetDeviceObjectSecurity( g_pUlAppPoolDeviceObject, DACL_SECURITY_INFORMATION, &securityDescriptor ); UlpCleanupSecurityDescriptor( &securityDescriptor ); if (!NT_SUCCESS(status)) { goto complete; } complete: return status; } // UlpApplySecurityToDeviceObjects /***************************************************************************++ Routine Description: Allocates and initializes a security descriptor with the specified attributes. Arguments: pSecurityDescriptor - Supplies a pointer to the security descriptor to initialize. pSidMaskPairs - Supplies an array of SID/ACCESS_MASK pairs. NumSidMaskPairs - Supplies the number of SID/ACESS_MASK pairs. Return Value: NTSTATUS - Completion status. --***************************************************************************/ NTSTATUS UlpCreateSecurityDescriptor( OUT PSECURITY_DESCRIPTOR pSecurityDescriptor, IN PSID_MASK_PAIR pSidMaskPairs, IN ULONG NumSidMaskPairs ) { NTSTATUS status; PACL pDacl; ULONG daclLength; ULONG i; // // Sanity check. // PAGED_CODE(); ASSERT( pSecurityDescriptor != NULL ); ASSERT( pSidMaskPairs != NULL ); ASSERT( NumSidMaskPairs > 0 ); // // Setup locals so we know how to cleanup on exit. // pDacl = NULL; // // Initialize the security descriptor. // status = RtlCreateSecurityDescriptor( pSecurityDescriptor, // SecurityDescriptor SECURITY_DESCRIPTOR_REVISION // Revision ); if (!NT_SUCCESS(status)) { goto cleanup; } // // Calculate the DACL length. // daclLength = sizeof(ACL); for (i = 0 ; i < NumSidMaskPairs ; i++) { daclLength += sizeof(ACCESS_ALLOWED_ACE); daclLength += RtlLengthSid( pSidMaskPairs[i].pSid ); } // // Allocate & initialize the DACL. // pDacl = (PACL) UL_ALLOCATE_POOL( PagedPool, daclLength, UL_SECURITY_DATA_POOL_TAG ); if (pDacl == NULL) { status = STATUS_INSUFFICIENT_RESOURCES; goto cleanup; } status = RtlCreateAcl( pDacl, // Acl daclLength, // AclLength ACL_REVISION // AclRevision ); if (!NT_SUCCESS(status)) { goto cleanup; } // // Add the necessary access-allowed ACEs to the DACL. // for (i = 0 ; i < NumSidMaskPairs ; i++) { status = RtlAddAccessAllowedAce( pDacl, // Acl ACL_REVISION, // AceRevision pSidMaskPairs[i].AccessMask, // AccessMask pSidMaskPairs[i].pSid // Sid ); if (!NT_SUCCESS(status)) { goto cleanup; } } // // Attach the DACL to the security descriptor. // status = RtlSetDaclSecurityDescriptor( pSecurityDescriptor, // SecurityDescriptor TRUE, // DaclPresent pDacl, // Dacl FALSE // DaclDefaulted ); if (!NT_SUCCESS(status)) { goto cleanup; } // // Success! // ASSERT( NT_SUCCESS(status) ); return STATUS_SUCCESS; cleanup: ASSERT( !NT_SUCCESS(status) ); if (pDacl != NULL) { UL_FREE_POOL( pDacl, UL_SECURITY_DATA_POOL_TAG ); } return status; } // UlpCreateSecurityDescriptor /***************************************************************************++ Routine Description: Frees any resources associated with the security descriptor created by UlpCreateSecurityDescriptor(). Arguments: pSecurityDescriptor - Supplies the security descriptor to cleanup. --***************************************************************************/ VOID UlpCleanupSecurityDescriptor( IN PSECURITY_DESCRIPTOR pSecurityDescriptor ) { NTSTATUS status; PACL pDacl; BOOLEAN daclPresent; BOOLEAN daclDefaulted; // // Sanity check. // PAGED_CODE(); ASSERT( RtlValidSecurityDescriptor( pSecurityDescriptor ) ); // // Try to retrieve the DACL from the security descriptor. // status = RtlGetDaclSecurityDescriptor( pSecurityDescriptor, // SecurityDescriptor &daclPresent, // DaclPresent &pDacl, // Dacl &daclDefaulted // DaclDefaulted ); if (NT_SUCCESS(status)) { if (daclPresent && (pDacl != NULL)) { UL_FREE_POOL( pDacl, UL_SECURITY_DATA_POOL_TAG ); } } } // UlpCleanupSecurityDescriptor /***************************************************************************++ Routine Description: Applies the specified security descriptor to the specified device object. Arguments: pDeviceObject - Supplies the device object to manipulate. SecurityInformation - Supplies the level of information to change. pSecurityDescriptor - Supplies the new security descriptor for the device object. Return Value: NTSTATUS - Completion status. --***************************************************************************/ NTSTATUS UlpSetDeviceObjectSecurity( IN PDEVICE_OBJECT pDeviceObject, IN SECURITY_INFORMATION SecurityInformation, IN PSECURITY_DESCRIPTOR pSecurityDescriptor ) { NTSTATUS status; HANDLE handle; // // Sanity check. // PAGED_CODE(); ASSERT( IS_VALID_DEVICE_OBJECT( pDeviceObject ) ); ASSERT( RtlValidSecurityDescriptor( pSecurityDescriptor ) ); // // Open a handle to the device object. // UlAttachToSystemProcess(); status = ObOpenObjectByPointer( pDeviceObject, // Object OBJ_CASE_INSENSITIVE | // HandleAttributes UL_KERNEL_HANDLE, NULL, // PassedAccessState MAXIMUM_ALLOWED, // DesiredAccess NULL, // ObjectType KernelMode, // AccessMode &handle // Handle ); if (NT_SUCCESS(status)) { status = NtSetSecurityObject( handle, // Handle SecurityInformation, // SecurityInformation pSecurityDescriptor // SecurityDescriptor ); ZwClose( handle ); } UlDetachFromSystemProcess(); return status; } // UlpSetDeviceObjectSecurity /***************************************************************************++ Routine Description: Reads the UL section of the registry. Any values contained in the registry override defaults. Arguments: pConfig - Supplies a pointer to a UL_CONFIG structure that receives init-time configuration parameters. These are basically parameters that do not need to persist in the driver once initialization is complete. --***************************************************************************/ VOID UlpReadRegistry( IN PUL_CONFIG pConfig ) { HANDLE parametersHandle; NTSTATUS status; LONG tmp; LONGLONG tmp64; UNICODE_STRING registryPath; // // Sanity check. // PAGED_CODE(); // // Establish defaults. // pConfig->ThreadsPerCpu = DEFAULT_THREADS_PER_CPU; pConfig->IrpContextLookasideDepth = DEFAULT_IRP_CONTEXT_LOOKASIDE_DEPTH; pConfig->ReceiveBufferLookasideDepth = DEFAULT_RCV_BUFFER_LOOKASIDE_DEPTH; pConfig->ResourceLookasideDepth = DEFAULT_RESOURCE_LOOKASIDE_DEPTH; pConfig->RequestBufferLookasideDepth = DEFAULT_REQ_BUFFER_LOOKASIDE_DEPTH; pConfig->InternalRequestLookasideDepth = DEFAULT_INT_REQUEST_LOOKASIDE_DEPTH; pConfig->ResponseBufferLookasideDepth = DEFAULT_RESP_BUFFER_LOOKASIDE_DEPTH; pConfig->SendTrackerLookasideDepth = DEFAULT_SEND_TRACKER_LOOKASIDE_DEPTH; pConfig->LogBufferLookasideDepth = DEFAULT_LOG_BUFFER_LOOKASIDE_DEPTH; pConfig->EnableUnload = DEFAULT_ENABLE_UNLOAD; pConfig->EnableSecurity = DEFAULT_ENABLE_SECURITY; pConfig->UriConfig.EnableCache = DEFAULT_CACHE_ENABLED; pConfig->UriConfig.MaxCacheUriCount = DEFAULT_MAX_CACHE_URI_COUNT; pConfig->UriConfig.MaxCacheMegabyteCount = DEFAULT_MAX_CACHE_MEGABYTE_COUNT; pConfig->UriConfig.MaxUriBytes = DEFAULT_MAX_URI_BYTES; pConfig->UriConfig.ScavengerPeriod = DEFAULT_CACHE_SCAVENGER_PERIOD; pConfig->LargeMemMegabytes = DEFAULT_LARGE_MEM_MEGABYTES; // // Open the registry. // RtlInitUnicodeString( ®istryPath, REGISTRY_UL_INFORMATION ); status = UlOpenRegistry( ®istryPath, ¶metersHandle ); if (status != STATUS_SUCCESS) { return; } #if DBG // // Read the debug flags. // g_UlDebug = (ULONG)UlReadLongParameter( parametersHandle, REGISTRY_DEBUG_FLAGS, g_UlDebug ); // // Force a breakpoint if so requested. // if (UlReadLongParameter( parametersHandle, REGISTRY_BREAK_ON_STARTUP, DEFAULT_BREAK_ON_STARTUP) != 0 ) { DbgBreakPoint(); } // // Read the break-on-error flags. // g_UlBreakOnError = (ULONG)UlReadLongParameter( parametersHandle, REGISTRY_BREAK_ON_ERROR, g_UlBreakOnError ); g_UlVerboseErrors = (ULONG)UlReadLongParameter( parametersHandle, REGISTRY_VERBOSE_ERRORS, g_UlVerboseErrors ); // // Break-on-error implies verbose-errors. // if (g_UlBreakOnError) { g_UlVerboseErrors = TRUE; } #endif // DBG #if ALLOW_UNLOAD // // Enable driver unload if requested. // pConfig->EnableUnload = UlReadLongParameter( parametersHandle, REGISTRY_ENABLE_UNLOAD, (LONG)pConfig->EnableUnload ) != 0; #endif // ALLOW_UNLOAD // // Enable driver security if requested. // pConfig->EnableSecurity = UlReadLongParameter( parametersHandle, REGISTRY_ENABLE_SECURITY, (LONG)pConfig->EnableSecurity ) != 0; // // Read the stack size and priority boost values from the registry. // tmp = UlReadLongParameter( parametersHandle, REGISTRY_IRP_STACK_SIZE, (LONG)g_UlIrpStackSize ); // // Enforce reasonable minimum/maximum values for the IRP stack size. // if (tmp < 2) { tmp = 2; } else if (tmp > 64) { tmp = 64; } g_UlIrpStackSize = (CCHAR)tmp; tmp = UlReadLongParameter( parametersHandle, REGISTRY_PRIORITY_BOOST, (LONG)g_UlPriorityBoost ); if (tmp > 16 || tmp <= 0) { tmp = DEFAULT_PRIORITY_BOOST; } g_UlPriorityBoost = (CCHAR)tmp; // // Read the thread pool parameters. // tmp = UlReadLongParameter( parametersHandle, REGISTRY_THREADS_PER_CPU, (LONG)pConfig->ThreadsPerCpu ); if (tmp > 0xFFFF || tmp <= 0) { tmp = DEFAULT_THREADS_PER_CPU; } pConfig->ThreadsPerCpu = (USHORT)tmp; // // Other configuration parameters. // tmp = UlReadLongParameter( parametersHandle, REGISTRY_MIN_IDLE_CONNECTIONS, (LONG)g_UlMinIdleConnections ); if (tmp > 0xFFFF || tmp <= 1) { tmp = DEFAULT_MIN_IDLE_CONNECTIONS; } g_UlMinIdleConnections = (USHORT)tmp; tmp = UlReadLongParameter( parametersHandle, REGISTRY_MAX_IDLE_CONNECTIONS, (LONG)g_UlMaxIdleConnections ); if (tmp > 0xFFFF || tmp <= 0) { tmp = DEFAULT_MAX_IDLE_CONNECTIONS; } g_UlMaxIdleConnections = (USHORT)tmp; tmp = UlReadLongParameter( parametersHandle, REGISTRY_IRP_CONTEXT_LOOKASIDE_DEPTH, (LONG)pConfig->IrpContextLookasideDepth ); if (tmp > 0xFFFF || tmp <= 0) { tmp = DEFAULT_IRP_CONTEXT_LOOKASIDE_DEPTH; } pConfig->IrpContextLookasideDepth = (USHORT)tmp; tmp = UlReadLongParameter( parametersHandle, REGISTRY_RCV_BUFFER_LOOKASIDE_DEPTH, (LONG)pConfig->ReceiveBufferLookasideDepth ); if (tmp > 0xFFFF || tmp <= 0) { tmp = DEFAULT_RCV_BUFFER_LOOKASIDE_DEPTH; } pConfig->ReceiveBufferLookasideDepth = (USHORT)tmp; tmp = UlReadLongParameter( parametersHandle, REGISTRY_REQ_BUFFER_LOOKASIDE_DEPTH, (LONG)pConfig->RequestBufferLookasideDepth ); if (tmp > 0xFFFF || tmp <= 0) { tmp = DEFAULT_REQ_BUFFER_LOOKASIDE_DEPTH; } pConfig->RequestBufferLookasideDepth = (USHORT)tmp; tmp = UlReadLongParameter( parametersHandle, REGISTRY_INT_REQUEST_LOOKASIDE_DEPTH, (LONG)pConfig->InternalRequestLookasideDepth ); if (tmp > 0xFFFF || tmp <= 0) { tmp = DEFAULT_INT_REQUEST_LOOKASIDE_DEPTH; } pConfig->InternalRequestLookasideDepth = (USHORT)tmp; tmp = UlReadLongParameter( parametersHandle, REGISTRY_RESP_BUFFER_LOOKASIDE_DEPTH, (LONG)pConfig->ResponseBufferLookasideDepth ); if (tmp > 0xFFFF || tmp <= 0) { tmp = DEFAULT_RESP_BUFFER_LOOKASIDE_DEPTH; } pConfig->ResponseBufferLookasideDepth = (USHORT)tmp; tmp = UlReadLongParameter( parametersHandle, REGISTRY_SEND_TRACKER_LOOKASIDE_DEPTH, (LONG)pConfig->SendTrackerLookasideDepth ); if (tmp > 0xFFFF || tmp <= 0) { tmp = DEFAULT_SEND_TRACKER_LOOKASIDE_DEPTH; } pConfig->SendTrackerLookasideDepth = (USHORT)tmp; tmp = UlReadLongParameter( parametersHandle, REGISTRY_LOG_BUFFER_LOOKASIDE_DEPTH, (LONG)pConfig->LogBufferLookasideDepth ); if (tmp > 0xFFFF || tmp <= 0) { tmp = DEFAULT_LOG_BUFFER_LOOKASIDE_DEPTH; } pConfig->LogBufferLookasideDepth = (USHORT)tmp; g_UlEnableConnectionReuse = UlReadLongParameter( parametersHandle, REGISTRY_ENABLE_CONNECTION_REUSE, (LONG)g_UlEnableConnectionReuse ) != 0; g_UlEnableNagling = UlReadLongParameter( parametersHandle, REGISTRY_ENABLE_NAGLING, (LONG)g_UlEnableNagling ) != 0; g_UlEnableThreadAffinity = UlReadLongParameter( parametersHandle, REGISTRY_ENABLE_THREAD_AFFINITY, (LONG)g_UlEnableThreadAffinity ) != 0; tmp64 = UlReadLongLongParameter( parametersHandle, REGISTRY_THREAD_AFFINITY_MASK, g_UlThreadAffinityMask ); if ((ULONGLONG)tmp64 > DEFAULT_THREAD_AFFINITY_MASK || (ULONGLONG)tmp64 == 0) { tmp64 = DEFAULT_THREAD_AFFINITY_MASK; } g_UlThreadAffinityMask = (ULONGLONG)tmp64; tmp = UlReadLongParameter( parametersHandle, REGISTRY_MAX_WORK_QUEUE_DEPTH, (LONG)g_UlMaxWorkQueueDepth ); if (tmp > 0xFFFF || tmp < 0) { tmp = DEFAULT_MAX_WORK_QUEUE_DEPTH; } g_UlMaxWorkQueueDepth = (USHORT)tmp; tmp = UlReadLongParameter( parametersHandle, REGISTRY_MIN_WORK_DEQUEUE_DEPTH, (LONG)g_UlMinWorkDequeueDepth ); if (tmp > 0xFFFF || tmp < 0) { tmp = DEFAULT_MIN_WORK_DEQUEUE_DEPTH; } g_UlMinWorkDequeueDepth = (USHORT)tmp; tmp = UlReadLongParameter( parametersHandle, REGISTRY_OPAQUE_ID_TABLE_SIZE, (LONG)g_UlOpaqueIdTableSize ); if (tmp > 0xFFFF || tmp <= 0) { tmp = DEFAULT_OPAQUE_ID_TABLE_SIZE; } g_UlOpaqueIdTableSize = tmp; // // MAX url setting // tmp = UlReadLongParameter( parametersHandle, REGISTRY_MAX_URL_LENGTH, (LONG)g_UlMaxUrlLength ); if (tmp > 0xFFFF || tmp <= 0) { tmp = DEFAULT_MAX_URL_LENGTH; } g_UlMaxUrlLength = (USHORT)tmp; // // MAX allowed field length in HTTP requests // tmp = UlReadLongParameter( parametersHandle, REGISTRY_MAX_FIELD_LENGTH, (LONG)g_UlMaxFieldLength ); if (tmp > 0xFFFFFF || tmp <= 0) { tmp = DEFAULT_MAX_FIELD_LENGTH; } g_UlMaxFieldLength = tmp; // // If defined this will overwrite the default // log timer cycle period of 1 hour and make // the testing of the log recycling easier. // The value is interpreted in seconds. // tmp = UlReadLongParameter( parametersHandle, REGISTRY_DEBUG_LOGTIMER_CYCLE, (LONG)g_UlDebugLogTimerCycle ); if (tmp > 0xFFFF || tmp <= 0) { tmp = DEFAULT_DEBUG_LOGTIMER_CYCLE; } g_UlDebugLogTimerCycle = (USHORT)tmp; tmp = UlReadLongParameter( parametersHandle, REGISTRY_DEBUG_LOG_BUFFER_PERIOD, (LONG)g_UlDebugLogBufferPeriod ); if (tmp > 0xFFFF || tmp <= 0) { tmp = DEFAULT_DEBUG_LOG_BUFFER_PERIOD; } g_UlDebugLogBufferPeriod = (USHORT)tmp; tmp = UlReadLongParameter( parametersHandle, REGISTRY_LOG_BUFFER_SIZE, (LONG)g_UlLogBufferSize ); if (tmp > MAXIMUM_ALLOWED_LOG_BUFFER_SIZE || tmp < MINIMUM_ALLOWED_LOG_BUFFER_SIZE ) { // Basically this value will be discarted by the logging code // instead systems granularity size (64K) will be used. tmp = DEFAULT_LOG_BUFFER_SIZE; } tmp -= tmp % 4096; // Align down to 4k g_UlLogBufferSize = (ULONG) tmp; // // read the resource lookaside config // tmp = UlReadLongParameter( parametersHandle, REGISTRY_RESOURCE_LOOKASIDE_DEPTH, (LONG)pConfig->ResourceLookasideDepth ); if (tmp > 0xFFFF || tmp <= 0) { tmp = DEFAULT_RESOURCE_LOOKASIDE_DEPTH; } pConfig->ResourceLookasideDepth = (USHORT)tmp; tmp = UlReadLongParameter( parametersHandle, REGISTRY_MAX_REQUEST_BYTES, g_UlMaxRequestBytes ); if (tmp > 0xFFFFFF || tmp <= 0) { tmp = DEFAULT_MAX_REQUEST_BYTES; } g_UlMaxRequestBytes = ALIGN_DOWN( tmp, PVOID ); tmp = UlReadLongParameter( parametersHandle, REGISTRY_RCV_BUFFER_SIZE, g_UlReceiveBufferSize ); if (tmp > 0xFFFFFF || tmp <= 0) { tmp = DEFAULT_RCV_BUFFER_SIZE; } g_UlReceiveBufferSize = ALIGN_DOWN( tmp, PVOID ); tmp = UlReadLongParameter( parametersHandle, REGISTRY_RESP_BUFFER_SIZE, g_UlResponseBufferSize ); if (tmp > 0xFFFFFF || tmp <= 0) { tmp = DEFAULT_RESP_BUFFER_SIZE; } g_UlResponseBufferSize = ALIGN_DOWN( tmp, PVOID ); // // Read URL processing parameters. // BUGBUG: read legacy IIS value? // g_UlEnableNonUTF8 = UlReadLongParameter( parametersHandle, REGISTRY_ENABLE_NON_UTF8_URL, DEFAULT_ENABLE_NON_UTF8_URL ) != 0; if (g_UlEnableNonUTF8) { g_UlEnableDBCS = UlReadLongParameter( parametersHandle, REGISTRY_ENABLE_DBCS_URL, DEFAULT_ENABLE_DBCS_URL ) != 0; } else { // // We can't do DBCS if we only accept UTF-8. // g_UlEnableDBCS = FALSE; } if (g_UlEnableDBCS) { g_UlFavorDBCS = UlReadLongParameter( parametersHandle, REGISTRY_FAVOR_DBCS_URL, DEFAULT_FAVOR_DBCS_URL ) != 0; } else { // // We can't favor DBCS if we don't allow DBCS. // g_UlFavorDBCS = FALSE; } tmp = UlReadLongParameter( parametersHandle, REGISTRY_MAX_INTERNAL_URL_LENGTH, g_UlMaxInternalUrlLength ); if (tmp > 0xFFFFFF || tmp <= 0) { tmp = DEFAULT_MAX_INTERNAL_URL_LENGTH; } g_UlMaxInternalUrlLength = (USHORT)tmp; // // Read URI Cache parameters // pConfig->UriConfig.EnableCache = UlReadLongParameter( parametersHandle, REGISTRY_CACHE_ENABLED, DEFAULT_CACHE_ENABLED ) != 0; pConfig->UriConfig.MaxCacheUriCount = UlReadLongParameter( parametersHandle, REGISTRY_MAX_CACHE_URI_COUNT, DEFAULT_MAX_CACHE_URI_COUNT ); pConfig->UriConfig.MaxCacheMegabyteCount = UlReadLongParameter( parametersHandle, REGISTRY_MAX_CACHE_MEGABYTE_COUNT, DEFAULT_MAX_CACHE_MEGABYTE_COUNT ); pConfig->UriConfig.MaxUriBytes = UlReadLongParameter( parametersHandle, REGISTRY_MAX_URI_BYTES, DEFAULT_MAX_URI_BYTES ); pConfig->UriConfig.ScavengerPeriod = UlReadLongParameter( parametersHandle, REGISTRY_CACHE_SCAVENGER_PERIOD, DEFAULT_CACHE_SCAVENGER_PERIOD ); pConfig->UriConfig.HashTableBits = UlReadLongParameter( parametersHandle, REGISTRY_HASH_TABLE_BITS, DEFAULT_HASH_TABLE_BITS ); pConfig->LargeMemMegabytes = UlReadLongParameter( parametersHandle, REGISTRY_LARGE_MEM_MEGABYTES, DEFAULT_LARGE_MEM_MEGABYTES ); // // Make sure we can always buffer enough bytes for an entire request // header. // g_UlMaxBufferedBytes = MAX(g_UlMaxBufferedBytes, g_UlMaxRequestBytes); // // Dump configuration on checked builds. // #if DBG DbgPrint( "UL Configuration:\n" ); #if DBG DbgPrint( " g_UlDebug = %08lx\n", g_UlDebug ); DbgPrint( " g_UlBreakOnError = %lu\n", g_UlBreakOnError ); DbgPrint( " g_UlVerboseErrors = %lu\n", g_UlVerboseErrors ); #endif // DBG DbgPrint( " g_UlIrpStackSize = %lu\n", g_UlIrpStackSize ); DbgPrint( " g_UlPriorityBoost = %lu\n", g_UlPriorityBoost ); DbgPrint( " g_UlMinIdleConnections = %lu\n", g_UlMinIdleConnections ); DbgPrint( " g_UlMaxIdleConnections = %lu\n", g_UlMaxIdleConnections ); DbgPrint( " g_UlEnableConnectionReuse = %lu\n", g_UlEnableConnectionReuse ); DbgPrint( " g_UlEnableNagling = %lu\n", g_UlEnableNagling ); DbgPrint( " g_UlEnableThreadAffinity = %lu\n", g_UlEnableThreadAffinity ); DbgPrint( " g_UlThreadAffinityMask = %I64x\n", g_UlThreadAffinityMask ); DbgPrint( " g_UlMaxWorkQueueDepth = %lu\n", g_UlMaxWorkQueueDepth ); DbgPrint( " g_UlMinWorkDequeueDepth = %lu\n", g_UlMinWorkDequeueDepth ); DbgPrint( " g_UlOpaqueIdTableSize = %lu\n", g_UlOpaqueIdTableSize ); DbgPrint( " g_UlMaxRequestBytes = %lu\n", g_UlMaxRequestBytes ); DbgPrint( " g_UlReceiveBufferSize = %lu\n", g_UlReceiveBufferSize ); DbgPrint( " g_UlResponseBufferSize = %lu\n", g_UlResponseBufferSize ); DbgPrint( " g_UlMaxUrlLength = %lu\n", g_UlMaxUrlLength ); DbgPrint( " g_UlMaxFieldLength = %lu\n", g_UlMaxFieldLength ); DbgPrint( " g_UlDebugLogTimerCycle = %lu\n", g_UlDebugLogTimerCycle ); DbgPrint( " g_UlDebugLogBufferPeriod = %lu\n", g_UlDebugLogBufferPeriod ); DbgPrint( " g_UlLogBufferSize = %lu\n", g_UlLogBufferSize ); DbgPrint( " g_UlEnableNonUTF8 = %lu\n", g_UlEnableNonUTF8 ); DbgPrint( " g_UlEnableDBCS = %lu\n", g_UlEnableDBCS ); DbgPrint( " g_UlFavorDBCS = %lu\n", g_UlFavorDBCS ); DbgPrint( " g_UlMaxInternalUrlLength = %lu\n", g_UlMaxInternalUrlLength ); #if ALLOW_UNLOAD DbgPrint( " EnableUnload = %lu\n", pConfig->EnableUnload ); #endif // ALLOW_UNLOAD DbgPrint( " EnableSecurity = %lu\n", pConfig->EnableSecurity ); DbgPrint( " ThreadsPerCpu = %lx\n", pConfig->ThreadsPerCpu ); DbgPrint( " IrpContextLookasideDepth = %lu\n", pConfig->IrpContextLookasideDepth ); DbgPrint( " ReceiveBufferLookasideDepth = %lu\n", pConfig->ReceiveBufferLookasideDepth ); DbgPrint( " ResourceLookasideDepth = %lu\n", pConfig->ResourceLookasideDepth ); DbgPrint( " RequestBufferLookasideDepth = %lu\n", pConfig->RequestBufferLookasideDepth ); DbgPrint( " IntlRequestLookasideDepth = %lu\n", pConfig->InternalRequestLookasideDepth ); DbgPrint( " ResponseBufferLookasideDepth = %lu\n", pConfig->ResponseBufferLookasideDepth ); DbgPrint( " SendTrackerLookasideDepth = %lu\n", pConfig->SendTrackerLookasideDepth ); DbgPrint( " LogBufferLookasideDepth = %lu\n", pConfig->LogBufferLookasideDepth ); DbgPrint( " EnableCache = %lu\n", pConfig->UriConfig.EnableCache ); DbgPrint( " MaxCacheUriCount = %lu\n", pConfig->UriConfig.MaxCacheUriCount ); DbgPrint( " MaxCacheMegabyteCount = %lu\n", pConfig->UriConfig.MaxCacheMegabyteCount ); DbgPrint( " ScavengerPeriod = %lu\n", pConfig->UriConfig.ScavengerPeriod ); DbgPrint( " HashTableBits = %ld\n", pConfig->UriConfig.HashTableBits); DbgPrint( " MaxUriBytes = %lu\n", pConfig->UriConfig.MaxUriBytes ); DbgPrint( " LargeMemMegabytes = %ld\n", pConfig->LargeMemMegabytes ); #endif // DBG // // Cleanup. // UlCloseSystemHandle( parametersHandle ); } // UlpReadRegistry #if ALLOW_UNLOAD /***************************************************************************++ Routine Description: Unload routine called by the IO subsystem when UL is getting unloaded. --***************************************************************************/ VOID UlpUnload( IN PDRIVER_OBJECT DriverObject ) { // // Sanity check. // PAGED_CODE(); UL_ENTER_DRIVER("UlpUnload", NULL); #if DBG KdPrint(( "UlpUnload called.\n" )); #endif // DBG // // Terminate the UL modules. // UlpTerminateModules(); UL_LEAVE_DRIVER("UlpUnload"); #if DBG // // Terminate any debug-specific data after UL_LEAVE_DRIVER // UlDbgTerminateDebugData( ); #endif // DBG } // UlpUnload #endif // ALLOW_UNLOAD /***************************************************************************++ Routine Description: Terminates the various UL modules in the correct order. --***************************************************************************/ VOID UlpTerminateModules( VOID ) { // // Sanity check. // PAGED_CODE(); // // Wait for endpoints to go away, so we're sure all I/O is done. // UlWaitForEndpointDrain(); // // Kill Michael. // UlTerminateDateCache(); UlTerminateUriCache(); UlTerminateFilterChannel(); // // Kill Henry. // TerminateFileCache(); // // Kill Paul. // UlTerminateCG(); UlTerminateAP(); // // Kill Keith. // UlTerminateControlChannel(); // // TerminateLogs Blocks until all Io To Be Complete // // Note:CG should be terminated before Logs. // Otherwise we won't stop issuing the buffer writes. // ThreadPool should be terminated after Logs. // Otherwise our Completion APCs won't be completed back. // // // Kill Ali // UlTerminateLogs(); UlTcTerminate(); // // Kill Eric. // UlTerminateHttpRcv(); UlTerminateCounters(); UlTerminateTimeoutMonitor(); // // Kill George. // UlLargeMemTerminate(); // // Kill TDI. // UxTerminateTdi(); UlTerminateTdi(); // // Kill the thread pool. // UlTerminateThreadPool(); // // Kill the opaque Ids // UlTerminateOpaqueIdTable(); // // Kill any global data. // UlTerminateData(); // // Delete our device objects. // if (g_pUlAppPoolDeviceObject != NULL) { IoDeleteDevice( g_pUlAppPoolDeviceObject ); } if (g_pUlFilterDeviceObject != NULL) { IoDeleteDevice( g_pUlFilterDeviceObject ); } if (g_pUlControlDeviceObject != NULL) { IoDeleteDevice( g_pUlControlDeviceObject ); } // // Delete the directory container. // if (g_UlDirectoryObject != NULL) { UlCloseSystemHandle( g_UlDirectoryObject ); } // // Delete the global trace logs. // DESTROY_REF_TRACE_LOG( g_pTdiTraceLog ); DESTROY_REF_TRACE_LOG( g_pHttpRequestTraceLog ); DESTROY_REF_TRACE_LOG( g_pHttpConnectionTraceLog ); DESTROY_REF_TRACE_LOG( g_pHttpResponseTraceLog ); DESTROY_REF_TRACE_LOG( g_pAppPoolTraceLog ); DESTROY_REF_TRACE_LOG( g_pConfigGroupTraceLog ); DESTROY_REF_TRACE_LOG( g_pThreadTraceLog ); DESTROY_REF_TRACE_LOG( g_pMdlTraceLog ); DESTROY_REF_TRACE_LOG( g_pFilterTraceLog ); DESTROY_REF_TRACE_LOG( g_pMondoGlobalTraceLog ); DESTROY_IRP_TRACE_LOG( g_pIrpTraceLog ); DESTROY_TIME_TRACE_LOG( g_pTimeTraceLog ); DESTROY_REPLENISH_TRACE_LOG( g_pReplenishTraceLog ); DESTROY_FILTQ_TRACE_LOG( g_pFilterQueueTraceLog ); DESTROY_REF_TRACE_LOG( g_pSiteCounterTraceLog ); DESTROY_REF_TRACE_LOG( g_pConnectionCountTraceLog ); DESTROY_REF_TRACE_LOG( g_pConfigGroupInfoTraceLog ); DESTROY_REF_TRACE_LOG( g_pChunkTrackerTraceLog ); DESTROY_REF_TRACE_LOG( g_pWorkItemTraceLog ); UlTerminateOwnerRefTraceLog(); } // UlpTerminateModules