1093 lines
29 KiB
C
1093 lines
29 KiB
C
/*++
|
||
|
||
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);
|
||
}
|
||
|
||
|