Windows2003-3790/drivers/sac/driver/data.c
2020-09-30 16:53:55 +02:00

1093 lines
29 KiB
C
Raw Permalink Blame History

This file contains invisible Unicode characters

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

/*++
Copyright (c) 1989 Microsoft Corporation
Module Name:
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);
}