windows-nt/Source/XPSP1/NT/drivers/sac/driver/data.c
2020-09-26 16:20:57 +08:00

765 lines
21 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
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);
}