You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1092 lines
29 KiB
1092 lines
29 KiB
/*++
|
|
|
|
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);
|
|
}
|
|
|
|
|