/*++ Copyright (c) 1989 Microsoft Corporation Module Name: data.c Abstract: This module contains global data for SAC. Author: Sean Selitrennikoff (v-seans) - Jan 11, 1999 Revision History: --*/ #include "sac.h" NTSTATUS CreateDeviceSecurityDescriptor( IN PVOID DeviceOrDriverObject ); NTSTATUS BuildDeviceAcl( OUT PACL *DeviceAcl ); VOID WorkerThreadStartUp( IN PVOID StartContext ); VOID InitializeCmdEventInfo( VOID ); #ifdef ALLOC_PRAGMA #pragma alloc_text( INIT, InitializeGlobalData) #pragma alloc_text( INIT, CreateDeviceSecurityDescriptor ) #pragma alloc_text( INIT, BuildDeviceAcl ) #endif // // Globally defined variables are here. // // // Define the I/O Manager methods. // // The I/O manager is responsible for the behavior layer between // the channels and the serial port. // // Note: currently, the cmd routines are not-multithreadable. // #if 0 IO_MGR_HANDLE_EVENT IoMgrHandleEvent = XmlMgrHandleEvent; IO_MGR_INITITIALIZE IoMgrInitialize = XmlMgrInitialize; IO_MGR_SHUTDOWN IoMgrShutdown = XmlMgrShutdown; IO_MGR_WORKER IoMgrWorkerProcessEvents = XmlMgrWorkerProcessEvents; IO_MGR_IS_CURRENT_CHANNEL IoMgrIsCurrentChannel = XmlMgrIsCurrentChannel; #else IO_MGR_HANDLE_EVENT IoMgrHandleEvent = ConMgrHandleEvent; IO_MGR_INITITIALIZE IoMgrInitialize = ConMgrInitialize; IO_MGR_SHUTDOWN IoMgrShutdown = ConMgrShutdown; IO_MGR_WORKER IoMgrWorkerProcessEvents = ConMgrWorkerProcessEvents; IO_MGR_IS_WRITE_ENABLED IoMgrIsWriteEnabled = ConMgrIsWriteEnabled; IO_MGR_WRITE_DATA IoMgrWriteData = ConMgrWriteData; IO_MGR_FLUSH_DATA IoMgrFlushData = ConMgrFlushData; #endif PMACHINE_INFORMATION MachineInformation = NULL; BOOLEAN GlobalDataInitialized = FALSE; UCHAR TmpBuffer[sizeof(PROCESS_PRIORITY_CLASS)]; BOOLEAN IoctlSubmitted; LONG ProcessingType = SAC_NO_OP; HANDLE SACEventHandle; PKEVENT SACEvent=NULL; #if ENABLE_CMD_SESSION_PERMISSION_CHECKING BOOLEAN CommandConsoleLaunchingEnabled; #endif // // Globals for communicating with the user process responsible // for launching CMD consoles // PVOID RequestSacCmdEventObjectBody = NULL; PVOID RequestSacCmdEventWaitObjectBody = NULL; PVOID RequestSacCmdSuccessEventObjectBody = NULL; PVOID RequestSacCmdSuccessEventWaitObjectBody = NULL; PVOID RequestSacCmdFailureEventObjectBody = NULL; PVOID RequestSacCmdFailureEventWaitObjectBody = NULL; BOOLEAN HaveUserModeServiceCmdEventInfo = FALSE; KMUTEX SACCmdEventInfoMutex; #if ENABLE_SERVICE_FILE_OBJECT_CHECKING // // In order to prevent a rogue process from unregistering the // cmd event info from underneath the service, we only allow // the process that registered to unregister. // PFILE_OBJECT ServiceProcessFileObject = NULL; #endif // // Globals for managing incremental UTF8 encoding for VTUTF8 channels // WCHAR IncomingUnicodeValue; UCHAR IncomingUtf8ConversionBuffer[3]; #if DBG ULONG SACDebug = 0x0; #endif BOOLEAN InitializeGlobalData( IN PUNICODE_STRING RegistryPath, IN PDRIVER_OBJECT DriverObject ) /*++ Routine Description: This routine initializes all the driver components that are shared across devices. Arguments: RegistryPath - A pointer to the location in the registry to read values from. DriverObject - pointer to DriverObject Return Value: TRUE if successful, else FALSE --*/ { NTSTATUS Status; UNICODE_STRING DosName; UNICODE_STRING NtName; UNICODE_STRING UnicodeString; UNREFERENCED_PARAMETER(RegistryPath); PAGED_CODE(); IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC InitializeGlobalData: Entering.\n"))); if (!GlobalDataInitialized) { // // Create a symbolic link from a DosDevice to this device so that a user-mode app can open us. // RtlInitUnicodeString(&DosName, SAC_DOSDEVICE_NAME); RtlInitUnicodeString(&NtName, SAC_DEVICE_NAME); Status = IoCreateSymbolicLink(&DosName, &NtName); if (!NT_SUCCESS(Status)) { return FALSE; } // // Initialize internal memory system // if (!InitializeMemoryManagement()) { IoDeleteSymbolicLink(&DosName); IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC InitializeGlobalData: Exiting with status FALSE\n"))); return FALSE; } Status = PreloadGlobalMessageTable(DriverObject->DriverStart); if (!NT_SUCCESS(Status)) { IoDeleteSymbolicLink(&DosName); IF_SAC_DEBUG(SAC_DEBUG_FAILS, KdPrint(( "SAC DriverEntry: unable to pre-load message table: %X\n", Status ))); return FALSE; } #if ENABLE_CMD_SESSION_PERMISSION_CHECKING // // determine if the SAC driver has permission to launch cmd sessions // Status = GetCommandConsoleLaunchingPermission(&CommandConsoleLaunchingEnabled); if (!NT_SUCCESS(Status)) { IF_SAC_DEBUG( SAC_DEBUG_FAILS, KdPrint(( "SAC DriverEntry: failed GetCommandConsoleLaunchingPermission: %X\n", Status)) ); // // We don't want to fail on this operation // NOTHING; } #if ENABLE_SACSVR_START_TYPE_OVERRIDE else { // // Here we execute the command console service // start type policy. The goal is to provide // a means for the service to automatically start // when the cmd session feature is not explicitly // turned off. // // Here is the state table: // // Command Console Feature Enabled: // // service start type: // // automatic --> NOP // manual --> automatic // disabled --> NOP // // Command Console Feature Disabled: // // service start type: // // automatic --> NOP // manual --> NOP // disabled --> NOP // // service (sacsvr) fails registration // if (IsCommandConsoleLaunchingEnabled()) { // // Modify the service start type if appropriate // Status = ImposeSacCmdServiceStartTypePolicy(); if (!NT_SUCCESS(Status)) { IF_SAC_DEBUG( SAC_DEBUG_FAILS, KdPrint(( "SAC DriverEntry: failed ImposeSacCmdServiceStartTypePolicy: %X\n", Status )) ); // We don't want to fail on this operation // NOTHING; } } else { // // We do nothing here // NOTHING; } } #endif #endif // // // Utf8ConversionBuffer = (PUCHAR)ALLOCATE_POOL( Utf8ConversionBufferSize, GENERAL_POOL_TAG ); if (!Utf8ConversionBuffer) { TearDownGlobalMessageTable(); IoDeleteSymbolicLink(&DosName); IF_SAC_DEBUG(SAC_DEBUG_FAILS, KdPrint(( "SAC DriverEntry: unable to allocate memory for UTF8 translation." ))); return FALSE; } // // initialize the channel manager // Status = ChanMgrInitialize(); if (!NT_SUCCESS(Status)) { FREE_POOL(&Utf8ConversionBuffer); TearDownGlobalMessageTable(); IoDeleteSymbolicLink(&DosName); IF_SAC_DEBUG(SAC_DEBUG_FAILS, KdPrint(( "SAC DriverEntry: Failed to create SAC Channel" ))); return FALSE; } // // Initialize the serial port buffer // SerialPortBuffer = ALLOCATE_POOL(SERIAL_PORT_BUFFER_SIZE, GENERAL_POOL_TAG); if (! SerialPortBuffer) { IF_SAC_DEBUG( SAC_DEBUG_FAILS, KdPrint(("SAC InitializeDeviceData: Failed to allocate Serial Port Buffer\n")) ); return FALSE; } RtlZeroMemory(SerialPortBuffer, SERIAL_PORT_BUFFER_SIZE); // // Initialize the Cmd Console Event information // KeInitializeMutex(&SACCmdEventInfoMutex, 0); InitializeCmdEventInfo(); // // Globals are initialized // GlobalDataInitialized = TRUE; ProcessingType = SAC_NO_OP; IoctlSubmitted = FALSE; // // Setup notification event // RtlInitUnicodeString(&UnicodeString, L"\\SACEvent"); SACEvent = IoCreateSynchronizationEvent(&UnicodeString, &SACEventHandle); if (SACEvent == NULL) { IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC InitializeGlobalData: Exiting with Event NULL\n"))); return FALSE; } // // Retrieve all the machine-specific identification information. // InitializeMachineInformation(); // // Populate the HeadlessDispatch structure with the Machine info // Status = RegisterBlueScreenMachineInformation(); if (! NT_SUCCESS(Status)) { IF_SAC_DEBUG( SAC_DEBUG_FAILS, KdPrint(("SAC InitializeGlobalData: Failed to register blue screen machine info\n")) ); return FALSE; } } IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC InitializeGlobalData: Exiting with status TRUE\n"))); return TRUE; } // InitializeGlobalData VOID FreeGlobalData( VOID ) /*++ Routine Description: This routine frees all shared components. Arguments: None. Return Value: None. --*/ { UNICODE_STRING DosName; IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC FreeGlobalData: Entering.\n"))); if (GlobalDataInitialized) { // // // if(SACEvent != NULL){ ZwClose(SACEventHandle); SACEvent = NULL; } // // // TearDownGlobalMessageTable(); // // // RtlInitUnicodeString(&DosName, SAC_DOSDEVICE_NAME); IoDeleteSymbolicLink(&DosName); // // Shutdown the console manager // // Note: this should be done before shutting down // the channel manager to give the IO manager // a chance to cleanly shut itself down. // IoMgrShutdown(); // // Shutdown the channel manager // ChanMgrShutdown(); // // Release the serial port buffer // SAFE_FREE_POOL(&SerialPortBuffer); // // Release the machine information gathered at driver entry // FreeMachineInformation(); // // Free the internal memory management system // FreeMemoryManagement(); // // Global data is no longer present // GlobalDataInitialized = FALSE; } IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC FreeGlobalData: Exiting.\n"))); } // FreeGlobalData BOOLEAN InitializeDeviceData( PDEVICE_OBJECT DeviceObject ) /*++ Routine Description: This routine initializes all the parts specific for each device. Arguments: DeviceObject - pointer to device object to be initialized. Return Value: TRUE if successful, else FALSE --*/ { NTSTATUS Status; LARGE_INTEGER Time; LONG Priority; HEADLESS_CMD_ENABLE_TERMINAL Command; PSAC_DEVICE_CONTEXT DeviceContext; PWSTR XMLBuffer; PAGED_CODE(); IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC InitializeDeviceData: Entering.\n"))); DeviceContext = (PSAC_DEVICE_CONTEXT)DeviceObject->DeviceExtension; if (!DeviceContext->InitializedAndReady) { DeviceObject->StackSize = DEFAULT_IRP_STACK_SIZE; DeviceObject->Flags |= DO_DIRECT_IO; DeviceContext->DeviceObject = DeviceObject; DeviceContext->PriorityBoost = DEFAULT_PRIORITY_BOOST; DeviceContext->ExitThread = FALSE; DeviceContext->Processing = FALSE; // // // KeInitializeTimer(&(DeviceContext->Timer)); KeInitializeDpc(&(DeviceContext->Dpc), &TimerDpcRoutine, DeviceContext); KeInitializeSpinLock(&(DeviceContext->SpinLock)); KeInitializeEvent(&(DeviceContext->ProcessEvent), SynchronizationEvent, FALSE); InitializeListHead(&(DeviceContext->IrpQueue)); // // Enable the terminal // Command.Enable = TRUE; Status = HeadlessDispatch(HeadlessCmdEnableTerminal, &Command, sizeof(HEADLESS_CMD_ENABLE_TERMINAL), NULL, NULL ); if (!NT_SUCCESS(Status)) { IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC InitializeDeviceData: Exiting (1) with status FALSE\n"))); return FALSE; } // // Remember a pointer to the system process. We'll use this pointer // for KeAttachProcess() calls so that we can open handles in the // context of the system process. // DeviceContext->SystemProcess = (PKPROCESS)IoGetCurrentProcess(); // // Create the security descriptor used for raw access checks. // Status = CreateDeviceSecurityDescriptor(DeviceContext); if (!NT_SUCCESS(Status)) { IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC InitializeDeviceData: Exiting (2) with status FALSE\n"))); Command.Enable = FALSE; Status = HeadlessDispatch( HeadlessCmdEnableTerminal, &Command, sizeof(HEADLESS_CMD_ENABLE_TERMINAL), NULL, NULL ); if (! NT_SUCCESS(Status)) { IF_SAC_DEBUG( SAC_DEBUG_FAILS, KdPrint(("SAC InitializeDeviceData: Failed dispatch\n"))); } return FALSE; } // // Start a thread to handle requests // Status = PsCreateSystemThread(&(DeviceContext->ThreadHandle), PROCESS_ALL_ACCESS, NULL, NULL, NULL, WorkerThreadStartUp, DeviceContext ); if (!NT_SUCCESS(Status)) { IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC InitializeDeviceData: Exiting (3) with status FALSE\n"))); Command.Enable = FALSE; Status = HeadlessDispatch( HeadlessCmdEnableTerminal, &Command, sizeof(HEADLESS_CMD_ENABLE_TERMINAL), NULL, NULL ); if (! NT_SUCCESS(Status)) { IF_SAC_DEBUG( SAC_DEBUG_FAILS, KdPrint(("SAC InitializeDeviceData: Failed dispatch\n"))); } return FALSE; } // // Set this thread to the real-time highest priority so that it will be // responsive. // Priority = HIGH_PRIORITY; Status = NtSetInformationThread(DeviceContext->ThreadHandle, ThreadPriority, &Priority, sizeof(Priority) ); if (!NT_SUCCESS(Status)) { IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC InitializeDeviceData: Exiting (6) with status FALSE\n"))); // // Tell thread to exit. // DeviceContext->ExitThread = TRUE; KeInitializeEvent(&(DeviceContext->ThreadExitEvent), SynchronizationEvent, FALSE); KeSetEvent(&(DeviceContext->ProcessEvent), DeviceContext->PriorityBoost, FALSE); Status = KeWaitForSingleObject((PVOID)&(DeviceContext->ThreadExitEvent), Executive, KernelMode, FALSE, NULL); ASSERT(Status == STATUS_SUCCESS); Command.Enable = FALSE; Status = HeadlessDispatch( HeadlessCmdEnableTerminal, &Command, sizeof(HEADLESS_CMD_ENABLE_TERMINAL), NULL, NULL ); if (! NT_SUCCESS(Status)) { IF_SAC_DEBUG( SAC_DEBUG_FAILS, KdPrint(("SAC InitializeDeviceData: Failed dispatch\n"))); } return FALSE; } // // Send XML machine information to management application // Status = TranslateMachineInformationXML( &XMLBuffer, NULL ); if (NT_SUCCESS(Status)) { UTF8EncodeAndSend(XML_VERSION_HEADER); UTF8EncodeAndSend(XMLBuffer); FREE_POOL(&XMLBuffer); } // // Initialize the console manager // Status = IoMgrInitialize(); if (! NT_SUCCESS(Status)) { return FALSE; } // // Start our timer // Time.QuadPart = Int32x32To64((LONG)4, -1000); KeSetTimerEx(&(DeviceContext->Timer), Time, (LONG)4, &(DeviceContext->Dpc)); DeviceContext->InitializedAndReady = TRUE; } IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC InitializeDeviceData: Exiting with status TRUE\n"))); return TRUE; } // InitializeDeviceData VOID FreeDeviceData( PDEVICE_OBJECT DeviceObject ) /*++ Routine Description: This routine frees all components specific to a device.. Arguments: DeviceContext - The device to work on. Return Value: It will stop and wait, if necessary, for any processing to complete. --*/ { KIRQL OldIrql; NTSTATUS Status; PSAC_DEVICE_CONTEXT DeviceContext; IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC FreeDeviceData: Entering.\n"))); DeviceContext = (PSAC_DEVICE_CONTEXT)DeviceObject->DeviceExtension; if (!GlobalDataInitialized || !DeviceContext->InitializedAndReady) { IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC FreeDeviceData: Exiting.\n"))); return; } // // Wait for all processing to complete // KeAcquireSpinLock(&(DeviceContext->SpinLock), &OldIrql); while (DeviceContext->Processing) { IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC FreeDeviceData: Waiting....\n"))); KeInitializeEvent(&(DeviceContext->UnloadEvent), SynchronizationEvent, FALSE); KeReleaseSpinLock(&(DeviceContext->SpinLock), OldIrql); Status = KeWaitForSingleObject((PVOID)&(DeviceContext->UnloadEvent), Executive, KernelMode, FALSE, NULL); ASSERT(Status == STATUS_SUCCESS); KeAcquireSpinLock(&(DeviceContext->SpinLock), &OldIrql); } DeviceContext->Processing = TRUE; KeReleaseSpinLock(&(DeviceContext->SpinLock), OldIrql); KeCancelTimer(&(DeviceContext->Timer)); KeAcquireSpinLock(&(DeviceContext->SpinLock), &OldIrql); DeviceContext->Processing = FALSE; // // Signal the thread to exit // KeInitializeEvent(&(DeviceContext->UnloadEvent), SynchronizationEvent, FALSE); KeReleaseSpinLock(&(DeviceContext->SpinLock), OldIrql); KeSetEvent(&(DeviceContext->ProcessEvent), DeviceContext->PriorityBoost, FALSE); Status = KeWaitForSingleObject((PVOID)&(DeviceContext->UnloadEvent), Executive, KernelMode, FALSE, NULL); ASSERT(Status == STATUS_SUCCESS); // // Finish up cleaning up. // IoUnregisterShutdownNotification(DeviceObject); KeAcquireSpinLock(&(DeviceContext->SpinLock), &OldIrql); DeviceContext->InitializedAndReady = FALSE; KeReleaseSpinLock(&(DeviceContext->SpinLock), OldIrql); IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC FreeDeviceData: Exiting.\n"))); } // FreeDeviceData VOID WorkerThreadStartUp( IN PVOID StartContext ) /*++ Routine Description: This routine is the start up routine for the worker thread. It justn sends the worker thread to the processing routine. Arguments: StartContext - A pointer to the device to work on. Return Value: None. --*/ { WorkerProcessEvents((PSAC_DEVICE_CONTEXT)StartContext); } NTSTATUS BuildDeviceAcl( OUT PACL *pDAcl ) /*++ Routine Description: This routine builds an ACL which gives System READ/WRITE access. All other principals have no access. Arguments: pDAcl - Output pointer to the new ACL. Return Value: STATUS_SUCCESS or an appropriate error code. --*/ { NTSTATUS status; PACL dacl; SECURITY_DESCRIPTOR securityDescriptor; ULONG length; // // Default: // if( !pDAcl ) { return STATUS_INVALID_PARAMETER; } *pDAcl = NULL; // // Build an appropriate discretionary ACL. // length = (ULONG) sizeof( ACL ) + (ULONG)( 1 * sizeof( ACCESS_ALLOWED_ACE )) + RtlLengthSid( SeExports->SeLocalSystemSid ); dacl = (PACL) ALLOCATE_POOL( length, GENERAL_POOL_TAG ); if (!dacl) { return STATUS_NO_MEMORY; } status = RtlCreateAcl( dacl, length, ACL_REVISION2 ); if (NT_SUCCESS( status )) { status = RtlAddAccessAllowedAce( dacl, ACL_REVISION2, GENERIC_READ | GENERIC_WRITE, SeExports->SeLocalSystemSid ); } if (NT_SUCCESS( status )) { // // Put it in a security descriptor so that it may be applied to // the system partition device. // status = RtlCreateSecurityDescriptor( &securityDescriptor, SECURITY_DESCRIPTOR_REVISION ); } if (NT_SUCCESS( status )) { status = RtlSetDaclSecurityDescriptor( &securityDescriptor, TRUE, dacl, FALSE ); } if (!NT_SUCCESS( status )) { FREE_POOL( &dacl ); } // // Send back the dacl // *pDAcl = dacl; return status; } NTSTATUS CreateDeviceSecurityDescriptor( PSAC_DEVICE_CONTEXT DeviceContext ) /*++ Routine Description: This routine creates a security descriptor which controls access to the SAC device. Arguments: DeviceContext - A pointer to the device to work on. Return Value: STATUS_SUCCESS or an appropriate error code. Security: Currently, only the System user has access (READ/WRITE) to this device. --*/ { PACL RawAcl = NULL; NTSTATUS Status; BOOLEAN MemoryAllocated = FALSE; PSECURITY_DESCRIPTOR SecurityDescriptor; ULONG SecurityDescriptorLength; CHAR Buffer[SECURITY_DESCRIPTOR_MIN_LENGTH]; PSECURITY_DESCRIPTOR LocalSecurityDescriptor = (PSECURITY_DESCRIPTOR) Buffer; PSECURITY_DESCRIPTOR DeviceSecurityDescriptor = NULL; SECURITY_INFORMATION SecurityInformation = DACL_SECURITY_INFORMATION; IF_SAC_DEBUG( SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC CreateDeviceSecurityDescriptor: Entering.\n")) ); // // Get a pointer to the security descriptor from the device object. // Status = ObGetObjectSecurity( DeviceContext->DeviceObject, &SecurityDescriptor, &MemoryAllocated ); if (!NT_SUCCESS(Status)) { IF_SAC_DEBUG( SAC_DEBUG_FAILS, KdPrint(("SAC: Unable to get security descriptor, error: %x\n", Status)) ); ASSERT(MemoryAllocated == FALSE); IF_SAC_DEBUG( SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC CreateDeviceSecurityDescriptor: Exiting with status 0x%x\n", Status)) ); return(Status); } // // Build a local security descriptor // Status = BuildDeviceAcl(&RawAcl); if (!NT_SUCCESS(Status)) { IF_SAC_DEBUG( SAC_DEBUG_FAILS, KdPrint(("SAC CreateDeviceSecurityDescriptor: Unable to create Raw ACL, error: %x\n", Status)) ); goto ErrorExit; } (VOID)RtlCreateSecurityDescriptor( LocalSecurityDescriptor, SECURITY_DESCRIPTOR_REVISION ); (VOID)RtlSetDaclSecurityDescriptor( LocalSecurityDescriptor, TRUE, RawAcl, FALSE ); // // Make a copy of the security descriptor. This copy will be the raw descriptor. // SecurityDescriptorLength = RtlLengthSecurityDescriptor(SecurityDescriptor); DeviceSecurityDescriptor = ExAllocatePoolWithTag( PagedPool, SecurityDescriptorLength, SECURITY_POOL_TAG ); if (DeviceSecurityDescriptor == NULL) { IF_SAC_DEBUG( SAC_DEBUG_FAILS, KdPrint(("SAC CreateDeviceSecurityDescriptor: couldn't allocate security descriptor\n")) ); goto ErrorExit; } RtlMoveMemory( DeviceSecurityDescriptor, SecurityDescriptor, SecurityDescriptorLength ); // // Now apply the local descriptor to the raw descriptor. // Status = SeSetSecurityDescriptorInfo( NULL, &SecurityInformation, LocalSecurityDescriptor, &DeviceSecurityDescriptor, NonPagedPool, IoGetFileObjectGenericMapping() ); if (!NT_SUCCESS(Status)) { IF_SAC_DEBUG( SAC_DEBUG_FAILS, KdPrint(("SAC CreateDeviceSecurityDescriptor: SeSetSecurity failed, %lx\n", Status)) ); goto ErrorExit; } // // Update the driver DACL // Status = ObSetSecurityObjectByPointer( DeviceContext->DeviceObject, SecurityInformation, DeviceSecurityDescriptor ); ErrorExit: ObReleaseObjectSecurity(SecurityDescriptor, MemoryAllocated); if (DeviceSecurityDescriptor) { ExFreePool(DeviceSecurityDescriptor); } SAFE_FREE_POOL(&RawAcl); IF_SAC_DEBUG( SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC CreateDeviceSecurityDescriptor: Exiting with status 0x%x\n", Status)) ); return(Status); }