|
|
/*++
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 CreateAdminSecurityDescriptor( IN PSAC_DEVICE_CONTEXT DeviceContext );
NTSTATUS BuildDeviceAcl( OUT PACL *DeviceAcl );
VOID WorkerThreadStartUp( IN PVOID StartContext );
#ifdef ALLOC_PRAGMA
#pragma alloc_text( INIT, InitializeGlobalData)
#pragma alloc_text( INIT, CreateAdminSecurityDescriptor )
#pragma alloc_text( INIT, BuildDeviceAcl )
#endif
//
// Globally defined variables are here.
//
BOOLEAN GlobalDataInitialized = FALSE; UCHAR TmpBuffer[sizeof(PROCESS_PRIORITY_CLASS)]; BOOLEAN IoctlSubmitted; LONG ProcessingType; HANDLE SACEventHandle; PKEVENT SACEvent=NULL; LONG Attempts;
#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; }
Utf8ConversionBuffer = (PUCHAR)ALLOCATE_POOL(MEMORY_INCREMENT, 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; }
GlobalDataInitialized = TRUE; ProcessingType = SAC_NO_OP; IoctlSubmitted = FALSE; Attempts = 0;
//
// 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();
}
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);
FreeMemoryManagement(); 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;
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->AdminSecurityDescriptor = NULL; DeviceContext->UnloadDeferred = FALSE; DeviceContext->Processing = FALSE; KeInitializeTimer(&(DeviceContext->Timer));
KeInitializeDpc(&(DeviceContext->Dpc), &TimerDpcRoutine, DeviceContext);
KeInitializeSpinLock(&(DeviceContext->SpinLock)); KeInitializeEvent(&(DeviceContext->ProcessEvent), SynchronizationEvent, FALSE);
//
// 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 = CreateAdminSecurityDescriptor(DeviceContext);
if (!NT_SUCCESS(Status)) { IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC InitializeDeviceData: Exiting (2) with status FALSE\n"))); Command.Enable = FALSE; HeadlessDispatch(HeadlessCmdEnableTerminal, &Command, sizeof(HEADLESS_CMD_ENABLE_TERMINAL), NULL, NULL ); 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; HeadlessDispatch(HeadlessCmdEnableTerminal, &Command, sizeof(HEADLESS_CMD_ENABLE_TERMINAL), NULL, NULL ); 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->UnloadDeferred = TRUE; KeInitializeEvent(&(DeviceContext->UnloadEvent), SynchronizationEvent, FALSE); KeSetEvent(&(DeviceContext->ProcessEvent), DeviceContext->PriorityBoost, FALSE); Status = KeWaitForSingleObject((PVOID)&(DeviceContext->UnloadEvent), Executive, KernelMode, FALSE, NULL); ASSERT(Status == STATUS_SUCCESS);
Command.Enable = FALSE; HeadlessDispatch(HeadlessCmdEnableTerminal, &Command, sizeof(HEADLESS_CMD_ENABLE_TERMINAL), NULL, NULL ); return FALSE; }
//
// Start our timer
//
Time.QuadPart = Int32x32To64((LONG)100, -1000); // 100ms from now.
KeSetTimerEx(&(DeviceContext->Timer), Time, (LONG)100, &(DeviceContext->Dpc)); // every 100ms
//
// Display the prompt
//
SacPutSimpleMessage( SAC_ENTER ); SacPutSimpleMessage( SAC_INITIALIZED ); SacPutSimpleMessage( SAC_ENTER ); SacPutSimpleMessage( SAC_PROMPT );
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; PVOID MemToFree; 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); DeviceContext->UnloadDeferred = TRUE;
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;
MemToFree = (PVOID)DeviceContext->AdminSecurityDescriptor; DeviceContext->AdminSecurityDescriptor = NULL;
//
// 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; DeviceContext->UnloadDeferred = FALSE;
KeReleaseSpinLock(&(DeviceContext->SpinLock), OldIrql);
if (MemToFree != NULL) { ExFreePool(MemToFree); }
IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC FreeDeviceData: Exiting.\n"))); } // FreeDeviceData
NTSTATUS BuildDeviceAcl( OUT PACL *DeviceAcl )
/*++
Routine Description:
This routine builds an ACL which gives Administrators and LocalSystem principals full access. All other principals have no access.
Arguments:
DeviceAcl - Output pointer to the new ACL.
Return Value:
STATUS_SUCCESS or an appropriate error code.
--*/
{ PGENERIC_MAPPING GenericMapping; PSID AdminsSid; PSID SystemSid; ULONG AclLength; NTSTATUS Status; ACCESS_MASK AccessMask = GENERIC_ALL; PACL NewAcl;
IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC BuildDeviceAcl: Entering.\n"))); //
// Enable access to all the globally defined SIDs
//
GenericMapping = IoGetFileObjectGenericMapping();
RtlMapGenericMask(&AccessMask, GenericMapping);
//SeEnableAccessToExports();
AdminsSid = SeExports->SeAliasAdminsSid; SystemSid = SeExports->SeLocalSystemSid;
AclLength = sizeof(ACL) + (2 * sizeof(ACCESS_ALLOWED_ACE)) + RtlLengthSid(AdminsSid) + RtlLengthSid(SystemSid) - (2 * sizeof(ULONG));
NewAcl = ALLOCATE_POOL(AclLength, SECURITY_POOL_TAG);
if (NewAcl == NULL) { return(STATUS_INSUFFICIENT_RESOURCES); }
Status = RtlCreateAcl(NewAcl, AclLength, ACL_REVISION);
if (!NT_SUCCESS(Status)) { FREE_POOL(&NewAcl); IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC BuildDeviceAcl: Exiting with status 0x%x\n", Status))); return(Status); }
Status = RtlAddAccessAllowedAce(NewAcl, ACL_REVISION2, AccessMask, AdminsSid );
ASSERT(NT_SUCCESS(Status));
Status = RtlAddAccessAllowedAce(NewAcl, ACL_REVISION2, AccessMask, SystemSid );
ASSERT(NT_SUCCESS(Status));
*DeviceAcl = NewAcl;
IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC BuildDeviceAcl: Exiting with status 0x%x\n", STATUS_SUCCESS))); return(STATUS_SUCCESS);
} // BuildDeviceAcl
NTSTATUS CreateAdminSecurityDescriptor( PSAC_DEVICE_CONTEXT DeviceContext )
/*++
Routine Description:
This routine creates a security descriptor which gives access only to Administrtors and LocalSystem. This descriptor is used to access check raw endpoint opens and exclisive access to transport addresses.
Arguments:
DeviceContext - A pointer to the device to work on.
Return Value:
STATUS_SUCCESS or an appropriate error code.
--*/
{ 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 LocalAdminSecurityDescriptor; SECURITY_INFORMATION SecurityInformation = DACL_SECURITY_INFORMATION;
IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC CreateAdminSecDesc: 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 CreateAdminSecDesc: Exiting with status 0x%x\n", Status))); return(Status); }
//
// Build a local security descriptor with an ACL giving only
// administrators and system access.
//
Status = BuildDeviceAcl(&RawAcl);
if (!NT_SUCCESS(Status)) { IF_SAC_DEBUG(SAC_DEBUG_FAILS, KdPrint(("SAC CreateAdminSecDesc: 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);
LocalAdminSecurityDescriptor = ExAllocatePoolWithTag(PagedPool, SecurityDescriptorLength, SECURITY_POOL_TAG );
if (LocalAdminSecurityDescriptor == NULL) { IF_SAC_DEBUG(SAC_DEBUG_FAILS, KdPrint(("SAC CreateAdminSecDesc: couldn't allocate security descriptor\n"))); goto ErrorExit; }
RtlMoveMemory(LocalAdminSecurityDescriptor, SecurityDescriptor, SecurityDescriptorLength );
DeviceContext->AdminSecurityDescriptor = LocalAdminSecurityDescriptor;
//
// Now apply the local descriptor to the raw descriptor.
//
Status = SeSetSecurityDescriptorInfo(NULL, &SecurityInformation, LocalSecurityDescriptor, &(DeviceContext->AdminSecurityDescriptor), NonPagedPool, IoGetFileObjectGenericMapping() );
if (!NT_SUCCESS(Status)) { IF_SAC_DEBUG(SAC_DEBUG_FAILS, KdPrint(("SAC CreateAdminSecDesc: SeSetSecurity failed, %lx\n", Status))); ASSERT(DeviceContext->AdminSecurityDescriptor == LocalAdminSecurityDescriptor); ExFreePool(DeviceContext->AdminSecurityDescriptor); DeviceContext->AdminSecurityDescriptor = NULL; goto ErrorExit; }
if (DeviceContext->AdminSecurityDescriptor != LocalAdminSecurityDescriptor) { ExFreePool(LocalAdminSecurityDescriptor); }
Status = STATUS_SUCCESS;
ErrorExit:
ObReleaseObjectSecurity(SecurityDescriptor, MemoryAllocated);
if (RawAcl != NULL) { FREE_POOL(&RawAcl); }
IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC CreateAdminSecDesc: Exiting with status 0x%x\n", Status)));
return(Status); }
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); }
|