983 lines
29 KiB
C
983 lines
29 KiB
C
/*++
|
||
|
||
Copyright (c) 1992 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
cminit.c
|
||
|
||
Abstract:
|
||
|
||
This module contains init support for the CM level of the
|
||
config manager/hive.
|
||
|
||
Author:
|
||
|
||
Bryan M. Willman (bryanwi) 2-Apr-1992
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
#include "cmp.h"
|
||
|
||
//
|
||
// Prototypes local to this module
|
||
//
|
||
NTSTATUS
|
||
CmpOpenFileWithExtremePrejudice(
|
||
OUT PHANDLE Primary,
|
||
IN POBJECT_ATTRIBUTES Obja,
|
||
IN ULONG IoFlags,
|
||
IN ULONG AttributeFlags
|
||
);
|
||
|
||
|
||
#ifdef ALLOC_PRAGMA
|
||
#pragma alloc_text(PAGE,CmpOpenHiveFiles)
|
||
#pragma alloc_text(PAGE,CmpInitializeHive)
|
||
#pragma alloc_text(PAGE,CmpDestroyHive)
|
||
#pragma alloc_text(PAGE,CmpOpenFileWithExtremePrejudice)
|
||
#endif
|
||
|
||
extern PCMHIVE CmpMasterHive;
|
||
extern LIST_ENTRY CmpHiveListHead;
|
||
|
||
NTSTATUS
|
||
CmpOpenHiveFiles(
|
||
PUNICODE_STRING BaseName,
|
||
PWSTR Extension OPTIONAL,
|
||
PHANDLE Primary,
|
||
PHANDLE Secondary,
|
||
PULONG PrimaryDisposition,
|
||
PULONG SecondaryDisposition,
|
||
BOOLEAN CreateAllowed,
|
||
BOOLEAN MarkAsSystemHive,
|
||
BOOLEAN NoBuffering,
|
||
OUT OPTIONAL PULONG ClusterSize
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Open/Create Primary, and Log files for Hives.
|
||
|
||
BaseName is some name like "\winnt\system32\config\system".
|
||
Extension is ".alt" or ".log" or NULL.
|
||
|
||
If extension is NULL skip secondary work.
|
||
|
||
If extension is .alt or .log, open/create a secondary file
|
||
(e.g. "\winnt\system32\config\system.alt")
|
||
|
||
If extension is .log, open secondary for buffered I/O, else,
|
||
open for non-buffered I/O. Primary always uses non-buffered I/O.
|
||
|
||
If primary is newly created, supersede secondary. If secondary
|
||
does not exist, simply create (other code will complain if Log
|
||
is needed but does not exist.)
|
||
|
||
WARNING: If Secondary handle is NULL, you have no log
|
||
or alternate!
|
||
|
||
Arguments:
|
||
|
||
BaseName - unicode string of base hive file, must have space for
|
||
extension if that is used.
|
||
|
||
Extension - unicode type extension of secondary file, including
|
||
the leading "."
|
||
|
||
Primary - will get handle to primary file
|
||
|
||
Secondary - will get handle to secondary, or NULL
|
||
|
||
PrimaryDisposition - STATUS_SUCCESS or STATUS_CREATED, of primary file.
|
||
|
||
SecondaryDisposition - STATUS_SUCCESS or STATUS_CREATED, of secondary file.
|
||
|
||
CreateAllowed - if TRUE will create nonexistent primary, if FALSE will
|
||
fail if primary does not exist. no effect on log
|
||
|
||
MarkAsSystemHive - if TRUE will call into file system to mark this
|
||
as a critical system hive.
|
||
|
||
ClusterSize - if not NULL, will compute and return the appropriate
|
||
cluster size for the primary file.
|
||
|
||
Return Value:
|
||
|
||
status - if status is success, Primay succeeded, check Secondary
|
||
value to see if it succeeded.
|
||
|
||
--*/
|
||
{
|
||
IO_STATUS_BLOCK IoStatus;
|
||
IO_STATUS_BLOCK FsctlIoStatus;
|
||
FILE_FS_SIZE_INFORMATION FsSizeInformation;
|
||
ULONG Cluster;
|
||
ULONG CreateDisposition;
|
||
OBJECT_ATTRIBUTES ObjectAttributes;
|
||
NTSTATUS status;
|
||
UNICODE_STRING ExtName;
|
||
UNICODE_STRING WorkName;
|
||
PVOID WorkBuffer;
|
||
USHORT NameSize;
|
||
ULONG IoFlags;
|
||
ULONG AttributeFlags;
|
||
ULONG ShareMode;
|
||
ULONG DesiredAccess;
|
||
USHORT CompressionState;
|
||
HANDLE hEvent;
|
||
PKEVENT pEvent;
|
||
#ifdef CM_RETRY_CREATE_FILE
|
||
ULONG RetryCreateCount = 0;
|
||
#endif //CM_RETRY_CREATE_FILE
|
||
|
||
//
|
||
// Allocate an event to use for our overlapped I/O
|
||
//
|
||
status = CmpCreateEvent(NotificationEvent, &hEvent, &pEvent);
|
||
if (!NT_SUCCESS(status)) {
|
||
return(status);
|
||
}
|
||
|
||
//
|
||
// Allocate a buffer big enough to hold the full name
|
||
//
|
||
WorkName.Length = 0;
|
||
WorkName.MaximumLength = 0;
|
||
WorkName.Buffer = NULL;
|
||
WorkBuffer = NULL;
|
||
|
||
NameSize = BaseName->Length;
|
||
if (ARGUMENT_PRESENT(Extension)) {
|
||
NameSize += (wcslen(Extension)+1) * sizeof(WCHAR);
|
||
WorkBuffer = ExAllocatePool(PagedPool, NameSize);
|
||
WorkName.Buffer = WorkBuffer;
|
||
if (WorkBuffer == NULL) {
|
||
ObDereferenceObject(pEvent);
|
||
ZwClose(hEvent);
|
||
return STATUS_NO_MEMORY;
|
||
}
|
||
WorkName.MaximumLength = NameSize;
|
||
RtlAppendStringToString((PSTRING)&WorkName, (PSTRING)BaseName);
|
||
} else {
|
||
WorkName = *BaseName;
|
||
}
|
||
|
||
|
||
//
|
||
// Open/Create the primary
|
||
//
|
||
InitializeObjectAttributes(
|
||
&ObjectAttributes,
|
||
&WorkName,
|
||
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
|
||
NULL,
|
||
NULL
|
||
);
|
||
|
||
if (CreateAllowed && !CmpShareSystemHives) {
|
||
CreateDisposition = FILE_OPEN_IF;
|
||
} else {
|
||
CreateDisposition = FILE_OPEN;
|
||
}
|
||
|
||
ASSERT_PASSIVE_LEVEL();
|
||
|
||
AttributeFlags = FILE_OPEN_FOR_BACKUP_INTENT | FILE_NO_COMPRESSION | FILE_RANDOM_ACCESS;
|
||
if( NoBuffering == TRUE ) {
|
||
AttributeFlags |= FILE_NO_INTERMEDIATE_BUFFERING;
|
||
}
|
||
#ifdef CM_RETRY_CREATE_FILE
|
||
RetryCreate1:
|
||
#endif //CM_RETRY_CREATE_FILE
|
||
|
||
//
|
||
// Share the file if needed
|
||
//
|
||
if (CmpMiniNTBoot && CmpShareSystemHives) {
|
||
DesiredAccess = FILE_READ_DATA;
|
||
ShareMode = FILE_SHARE_READ;
|
||
} else {
|
||
ShareMode = 0;
|
||
DesiredAccess = FILE_READ_DATA | FILE_WRITE_DATA;
|
||
}
|
||
|
||
status = ZwCreateFile(
|
||
Primary,
|
||
DesiredAccess,
|
||
&ObjectAttributes,
|
||
&IoStatus,
|
||
NULL, // alloc size = none
|
||
FILE_ATTRIBUTE_NORMAL,
|
||
ShareMode, // share nothing
|
||
CreateDisposition,
|
||
////FILE_NO_INTERMEDIATE_BUFFERING |
|
||
//FILE_OPEN_FOR_BACKUP_INTENT |
|
||
//FILE_NO_COMPRESSION,
|
||
AttributeFlags,
|
||
NULL, // eabuffer
|
||
0 // ealength
|
||
);
|
||
#ifdef CM_RETRY_CREATE_FILE
|
||
if( !NT_SUCCESS(status) ) {
|
||
if( RetryCreateCount == 0 ) {
|
||
RetryCreateCount++;
|
||
DbgBreakPoint();
|
||
goto RetryCreate1;
|
||
}
|
||
}
|
||
//
|
||
// reset it for the log
|
||
//
|
||
RetryCreateCount = 0;
|
||
#endif //CM_RETRY_CREATE_FILE
|
||
|
||
if (status == STATUS_ACCESS_DENIED) {
|
||
|
||
//
|
||
// This means some person has put a read-only attribute
|
||
// on one of the critical system hive files. Remove it so they
|
||
// don't hurt themselves.
|
||
//
|
||
|
||
status = CmpOpenFileWithExtremePrejudice(Primary,
|
||
&ObjectAttributes,
|
||
AttributeFlags,
|
||
FILE_ATTRIBUTE_NORMAL);
|
||
}
|
||
|
||
if (!CmpShareSystemHives && (MarkAsSystemHive) &&
|
||
(NT_SUCCESS(status))) {
|
||
|
||
ASSERT_PASSIVE_LEVEL();
|
||
status = ZwFsControlFile(*Primary,
|
||
hEvent,
|
||
NULL,
|
||
NULL,
|
||
&FsctlIoStatus,
|
||
FSCTL_MARK_AS_SYSTEM_HIVE,
|
||
NULL,
|
||
0,
|
||
NULL,
|
||
0);
|
||
if (status == STATUS_PENDING) {
|
||
KeWaitForSingleObject(pEvent,
|
||
Executive,
|
||
KernelMode,
|
||
FALSE,
|
||
NULL);
|
||
status = FsctlIoStatus.Status;
|
||
}
|
||
|
||
//
|
||
// STATUS_INVALID_DEVICE_REQUEST is OK.
|
||
//
|
||
|
||
if (status == STATUS_INVALID_DEVICE_REQUEST) {
|
||
status = STATUS_SUCCESS;
|
||
|
||
} else if (!NT_SUCCESS(status)) {
|
||
ZwClose(*Primary);
|
||
}
|
||
}
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
|
||
CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BUGCHECK,"CMINIT: CmpOpenHiveFile: "));
|
||
CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BUGCHECK,"\tPrimary Open/Create failed for:\n"));
|
||
CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BUGCHECK,"\t%wZ\n", &WorkName));
|
||
CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BUGCHECK,"\tstatus = %08lx\n", status));
|
||
|
||
if (WorkBuffer != NULL) {
|
||
ExFreePool(WorkBuffer);
|
||
}
|
||
ObDereferenceObject(pEvent);
|
||
ZwClose(hEvent);
|
||
return status;
|
||
}
|
||
|
||
//
|
||
// Make sure the file is uncompressed in order to prevent the filesystem
|
||
// from failing our updates due to disk full conditions.
|
||
//
|
||
// Do not fail to open the file if this fails, we don't want to prevent
|
||
// people from booting just because their disk is full. Although they
|
||
// will not be able to update their registry, they will at lease be
|
||
// able to delete some files.
|
||
//
|
||
CompressionState = 0;
|
||
ASSERT_PASSIVE_LEVEL();
|
||
status = ZwFsControlFile(*Primary,
|
||
hEvent,
|
||
NULL,
|
||
NULL,
|
||
&FsctlIoStatus,
|
||
FSCTL_SET_COMPRESSION,
|
||
&CompressionState,
|
||
sizeof(CompressionState),
|
||
NULL,
|
||
0);
|
||
if (status == STATUS_PENDING) {
|
||
KeWaitForSingleObject(pEvent,
|
||
Executive,
|
||
KernelMode,
|
||
FALSE,
|
||
NULL);
|
||
}
|
||
|
||
*PrimaryDisposition = (ULONG) IoStatus.Information;
|
||
|
||
if( *PrimaryDisposition != FILE_CREATED ) {
|
||
//
|
||
// 0-lengthed file case
|
||
//
|
||
FILE_STANDARD_INFORMATION FileInformation;
|
||
NTSTATUS status2;
|
||
|
||
status2 = ZwQueryInformationFile(*Primary,
|
||
&IoStatus,
|
||
(PVOID)&FileInformation,
|
||
sizeof( FileInformation ),
|
||
FileStandardInformation
|
||
);
|
||
if (NT_SUCCESS( status2 )) {
|
||
if(FileInformation.EndOfFile.QuadPart == 0) {
|
||
//
|
||
// treat it as a non-existant one.
|
||
//
|
||
*PrimaryDisposition = FILE_CREATED;
|
||
CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL,"Primary file is zero-lengthed => treat it as non-existant\n"));
|
||
}
|
||
}
|
||
}
|
||
|
||
if (ARGUMENT_PRESENT(ClusterSize)) {
|
||
|
||
ASSERT_PASSIVE_LEVEL();
|
||
status = ZwQueryVolumeInformationFile(*Primary,
|
||
&IoStatus,
|
||
&FsSizeInformation,
|
||
sizeof(FILE_FS_SIZE_INFORMATION),
|
||
FileFsSizeInformation);
|
||
if (!NT_SUCCESS(status)) {
|
||
ObDereferenceObject(pEvent);
|
||
ZwClose(hEvent);
|
||
return(status);
|
||
}
|
||
if (FsSizeInformation.BytesPerSector > HBLOCK_SIZE) {
|
||
CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BUGCHECK,"CmpOpenHiveFiles: sectorsize %lx > HBLOCK_SIZE\n"));
|
||
ObDereferenceObject(pEvent);
|
||
ZwClose(hEvent);
|
||
return(STATUS_CANNOT_LOAD_REGISTRY_FILE);
|
||
}
|
||
|
||
Cluster = FsSizeInformation.BytesPerSector / HSECTOR_SIZE;
|
||
*ClusterSize = (Cluster < 1) ? 1 : Cluster;
|
||
|
||
}
|
||
|
||
if ( ! ARGUMENT_PRESENT(Extension)) {
|
||
if (WorkBuffer != NULL) {
|
||
ExFreePool(WorkBuffer);
|
||
}
|
||
ObDereferenceObject(pEvent);
|
||
ZwClose(hEvent);
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
//
|
||
// Open/Create the secondary
|
||
//
|
||
CreateDisposition = CmpShareSystemHives ? FILE_OPEN : FILE_OPEN_IF;
|
||
|
||
if (*PrimaryDisposition == FILE_CREATED) {
|
||
CreateDisposition = FILE_SUPERSEDE;
|
||
}
|
||
|
||
RtlInitUnicodeString(&ExtName,Extension);
|
||
status = RtlAppendStringToString((PSTRING)&WorkName, (PSTRING)&ExtName);
|
||
|
||
InitializeObjectAttributes(&ObjectAttributes,
|
||
&WorkName,
|
||
OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
|
||
NULL,
|
||
NULL);
|
||
|
||
//
|
||
// non-cached log files (or alternates)
|
||
//
|
||
IoFlags = FILE_NO_COMPRESSION | FILE_NO_INTERMEDIATE_BUFFERING;
|
||
if (_wcsnicmp(Extension, L".log", 4) != 0) {
|
||
AttributeFlags = FILE_ATTRIBUTE_NORMAL;
|
||
} else {
|
||
AttributeFlags = FILE_ATTRIBUTE_NORMAL | FILE_ATTRIBUTE_HIDDEN;
|
||
}
|
||
|
||
#ifdef CM_RETRY_CREATE_FILE
|
||
RetryCreate2:
|
||
#endif //CM_RETRY_CREATE_FILE
|
||
|
||
|
||
ASSERT_PASSIVE_LEVEL();
|
||
status = ZwCreateFile(
|
||
Secondary,
|
||
DesiredAccess,
|
||
&ObjectAttributes,
|
||
&IoStatus,
|
||
NULL, // alloc size = none
|
||
AttributeFlags,
|
||
ShareMode,
|
||
CreateDisposition,
|
||
IoFlags,
|
||
NULL, // eabuffer
|
||
0 // ealength
|
||
);
|
||
#ifdef CM_RETRY_CREATE_FILE
|
||
if( !NT_SUCCESS(status) ) {
|
||
if( RetryCreateCount == 0 ) {
|
||
RetryCreateCount++;
|
||
DbgBreakPoint();
|
||
goto RetryCreate2;
|
||
}
|
||
}
|
||
#endif //CM_RETRY_CREATE_FILE
|
||
|
||
if (status == STATUS_ACCESS_DENIED) {
|
||
|
||
//
|
||
// This means some person has put a read-only attribute
|
||
// on one of the critical system hive files. Remove it so they
|
||
// don't hurt themselves.
|
||
//
|
||
|
||
status = CmpOpenFileWithExtremePrejudice(Secondary,
|
||
&ObjectAttributes,
|
||
IoFlags,
|
||
AttributeFlags);
|
||
}
|
||
|
||
if (!CmpShareSystemHives && (MarkAsSystemHive) &&
|
||
(NT_SUCCESS(status))) {
|
||
|
||
ASSERT_PASSIVE_LEVEL();
|
||
status = ZwFsControlFile(*Secondary,
|
||
hEvent,
|
||
NULL,
|
||
NULL,
|
||
&FsctlIoStatus,
|
||
FSCTL_MARK_AS_SYSTEM_HIVE,
|
||
NULL,
|
||
0,
|
||
NULL,
|
||
0);
|
||
if (status == STATUS_PENDING) {
|
||
KeWaitForSingleObject(pEvent,
|
||
Executive,
|
||
KernelMode,
|
||
FALSE,
|
||
NULL);
|
||
status = FsctlIoStatus.Status;
|
||
}
|
||
//
|
||
// STATUS_INVALID_DEVICE_REQUEST is OK.
|
||
//
|
||
|
||
if (status == STATUS_INVALID_DEVICE_REQUEST) {
|
||
status = STATUS_SUCCESS;
|
||
|
||
} else if (!NT_SUCCESS(status)) {
|
||
|
||
ZwClose(*Secondary);
|
||
}
|
||
}
|
||
|
||
if (!NT_SUCCESS(status)) {
|
||
|
||
CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BUGCHECK,"CMINIT: CmpOpenHiveFile: "));
|
||
CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BUGCHECK,"\tSecondary Open/Create failed for:\n"));
|
||
CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BUGCHECK,"\t%wZ\n", &WorkName));
|
||
CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BUGCHECK,"\tstatus = %08lx\n", status));
|
||
|
||
*Secondary = NULL;
|
||
}
|
||
|
||
*SecondaryDisposition = (ULONG) IoStatus.Information;
|
||
|
||
//
|
||
// Make sure the file is uncompressed in order to prevent the filesystem
|
||
// from failing our updates due to disk full conditions.
|
||
//
|
||
// Do not fail to open the file if this fails, we don't want to prevent
|
||
// people from booting just because their disk is full. Although they
|
||
// will not be able to update their registry, they will at lease be
|
||
// able to delete some files.
|
||
//
|
||
CompressionState = 0;
|
||
|
||
ASSERT_PASSIVE_LEVEL();
|
||
status = ZwFsControlFile(*Secondary,
|
||
hEvent,
|
||
NULL,
|
||
NULL,
|
||
&FsctlIoStatus,
|
||
FSCTL_SET_COMPRESSION,
|
||
&CompressionState,
|
||
sizeof(CompressionState),
|
||
NULL,
|
||
0);
|
||
if (status == STATUS_PENDING) {
|
||
KeWaitForSingleObject(pEvent,
|
||
Executive,
|
||
KernelMode,
|
||
FALSE,
|
||
NULL);
|
||
}
|
||
|
||
if (WorkBuffer != NULL) {
|
||
ExFreePool(WorkBuffer);
|
||
}
|
||
ObDereferenceObject(pEvent);
|
||
ZwClose(hEvent);
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
CmpInitializeHive(
|
||
PCMHIVE *CmHive,
|
||
ULONG OperationType,
|
||
ULONG HiveFlags,
|
||
ULONG FileType,
|
||
PVOID HiveData OPTIONAL,
|
||
HANDLE Primary,
|
||
HANDLE Log,
|
||
HANDLE External,
|
||
PUNICODE_STRING FileName OPTIONAL,
|
||
ULONG CheckFlags
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Initialize a hive.
|
||
|
||
Arguments:
|
||
|
||
CmHive - pointer to a variable to receive a pointer to the CmHive structure
|
||
|
||
OperationType - specifies whether to create a new hive from scratch,
|
||
from a memory image, or by reading a file from disk.
|
||
[HINIT_CREATE | HINIT_MEMORY | HINIT_FILE | HINIT_MAPFILE]
|
||
|
||
HiveFlags - HIVE_VOLATILE - Entire hive is to be volatile, regardless
|
||
of the types of cells allocated
|
||
HIVE_NO_LAZY_FLUSH - Data in this hive is never written
|
||
to disk except by an explicit FlushKey
|
||
|
||
FileType - HFILE_TYPE_*, HFILE_TYPE_LOG set up for logging support
|
||
|
||
HiveData - if present, supplies a pointer to an in memory image of
|
||
from which to init the hive. Only useful when OperationType
|
||
is set to HINIT_MEMORY.
|
||
|
||
Primary - File handle for primary hive file (e.g. SYSTEM)
|
||
|
||
Log - File handle for log hive file (e.g. SOFTWARE.LOG)
|
||
|
||
External - File handle for primary hive file (e.g. BACKUP.REG)
|
||
|
||
FileName - some path like "...\system32\config\system", which will
|
||
be written into the base block as an aid to debugging.
|
||
may be NULL.
|
||
|
||
CheckFlags - Flags to be passed to CmCheckRegistry
|
||
|
||
usually this is CM_CHECK_REGISTRY_CHECK_CLEAN, except for the system hive
|
||
where CM_CHECK_REGISTRY_FORCE_CLEAN is passed
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS
|
||
|
||
--*/
|
||
{
|
||
FILE_FS_SIZE_INFORMATION FsSizeInformation;
|
||
IO_STATUS_BLOCK IoStatusBlock;
|
||
ULONG Cluster;
|
||
NTSTATUS Status;
|
||
PCMHIVE cmhive2;
|
||
ULONG rc;
|
||
|
||
CmKdPrintEx((DPFLTR_CONFIG_ID,CML_INIT,"CmpInitializeHive:\t\n"));
|
||
|
||
//
|
||
// Reject illegal parms
|
||
//
|
||
if ( (External && (Primary || Log)) ||
|
||
(Log && !Primary) ||
|
||
(!CmpShareSystemHives && (HiveFlags & HIVE_VOLATILE) && (Primary || External || Log)) ||
|
||
((OperationType == HINIT_MEMORY) && (!ARGUMENT_PRESENT(HiveData))) ||
|
||
(Log && (FileType != HFILE_TYPE_LOG))
|
||
)
|
||
{
|
||
return (STATUS_INVALID_PARAMETER);
|
||
}
|
||
|
||
//
|
||
// compute control
|
||
//
|
||
if (Primary) {
|
||
|
||
ASSERT_PASSIVE_LEVEL();
|
||
Status = ZwQueryVolumeInformationFile(
|
||
Primary,
|
||
&IoStatusBlock,
|
||
&FsSizeInformation,
|
||
sizeof(FILE_FS_SIZE_INFORMATION),
|
||
FileFsSizeInformation
|
||
);
|
||
if (!NT_SUCCESS(Status)) {
|
||
return (Status);
|
||
}
|
||
if (FsSizeInformation.BytesPerSector > HBLOCK_SIZE) {
|
||
return (STATUS_REGISTRY_IO_FAILED);
|
||
}
|
||
Cluster = FsSizeInformation.BytesPerSector / HSECTOR_SIZE;
|
||
Cluster = (Cluster < 1) ? 1 : Cluster;
|
||
} else {
|
||
Cluster = 1;
|
||
}
|
||
|
||
cmhive2 = CmpAllocate(sizeof(CMHIVE), FALSE,CM_FIND_LEAK_TAG10);
|
||
|
||
if (cmhive2 == NULL) {
|
||
return (STATUS_INSUFFICIENT_RESOURCES);
|
||
}
|
||
|
||
#ifdef NT_UNLOAD_KEY_EX
|
||
cmhive2->UnloadEvent = NULL;
|
||
cmhive2->RootKcb = NULL;
|
||
cmhive2->Frozen = FALSE;
|
||
cmhive2->UnloadWorkItem = NULL;
|
||
#endif //NT_UNLOAD_KEY_EX
|
||
|
||
cmhive2->GrowOnlyMode = FALSE;
|
||
cmhive2->GrowOffset = 0;
|
||
|
||
InitializeListHead(&(cmhive2->KcbConvertListHead));
|
||
InitializeListHead(&(cmhive2->KnodeConvertListHead));
|
||
cmhive2->CellRemapArray = NULL;
|
||
//
|
||
// Allocate the mutex from NonPagedPool so it will not be swapped to the disk
|
||
//
|
||
cmhive2->HiveLock = (PFAST_MUTEX)ExAllocatePoolWithTag(NonPagedPool, sizeof(FAST_MUTEX), CM_POOL_TAG );
|
||
if( cmhive2->HiveLock == NULL ) {
|
||
CmpFree(cmhive2, sizeof(CMHIVE));
|
||
return (STATUS_INSUFFICIENT_RESOURCES);
|
||
}
|
||
|
||
cmhive2->ViewLock = (PFAST_MUTEX)ExAllocatePoolWithTag(NonPagedPool, sizeof(FAST_MUTEX), CM_POOL_TAG );
|
||
if( cmhive2->ViewLock == NULL ) {
|
||
ASSERT( cmhive2->HiveLock );
|
||
ExFreePool(cmhive2->HiveLock);
|
||
CmpFree(cmhive2, sizeof(CMHIVE));
|
||
return (STATUS_INSUFFICIENT_RESOURCES);
|
||
}
|
||
|
||
// need to do this consistently!!!
|
||
cmhive2->FileObject = NULL;
|
||
cmhive2->FileFullPath.Buffer = NULL;
|
||
cmhive2->FileFullPath.Length = 0;
|
||
cmhive2->FileFullPath.MaximumLength = 0;
|
||
|
||
cmhive2->FileUserName.Buffer = NULL;
|
||
cmhive2->FileUserName.Length = 0;
|
||
cmhive2->FileUserName.MaximumLength = 0;
|
||
|
||
//
|
||
// Initialize the Cm hive control block
|
||
//
|
||
//
|
||
ASSERT((HFILE_TYPE_EXTERNAL+1) == HFILE_TYPE_MAX);
|
||
cmhive2->FileHandles[HFILE_TYPE_PRIMARY] = Primary;
|
||
cmhive2->FileHandles[HFILE_TYPE_LOG] = Log;
|
||
cmhive2->FileHandles[HFILE_TYPE_EXTERNAL] = External;
|
||
|
||
cmhive2->NotifyList.Flink = NULL;
|
||
cmhive2->NotifyList.Blink = NULL;
|
||
|
||
ExInitializeFastMutex(cmhive2->HiveLock);
|
||
ExInitializeFastMutex(cmhive2->ViewLock);
|
||
|
||
CmpInitHiveViewList(cmhive2);
|
||
//
|
||
// Initialize the view list
|
||
//
|
||
#if DBG
|
||
if( FileName ) {
|
||
CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_TRACE_LEVEL,"Initializing HiveViewList for hive (%p) (%.*S) \n\n",cmhive2,FileName->Length / sizeof(WCHAR),FileName->Buffer));
|
||
}
|
||
#endif
|
||
|
||
//
|
||
// Initialize the security cache
|
||
//
|
||
CmpInitSecurityCache(cmhive2);
|
||
|
||
//
|
||
// Initialize the Hv hive control block
|
||
//
|
||
Status = HvInitializeHive(
|
||
&(cmhive2->Hive),
|
||
OperationType,
|
||
HiveFlags,
|
||
FileType,
|
||
HiveData,
|
||
CmpAllocate,
|
||
CmpFree,
|
||
CmpFileSetSize,
|
||
CmpFileWrite,
|
||
CmpFileRead,
|
||
CmpFileFlush,
|
||
Cluster,
|
||
FileName
|
||
);
|
||
if (!NT_SUCCESS(Status)) {
|
||
CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BUGCHECK,"CmpInitializeHive: "));
|
||
CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BUGCHECK,"HvInitializeHive failed, Status = %08lx\n", Status));
|
||
|
||
#ifdef DRAGOSS_PRIVATE_DEBUG
|
||
if( OperationType == HINIT_FILE ) DbgBreakPoint();
|
||
#endif //DRAGOSS_PRIVATE_DEBUG
|
||
|
||
ASSERT( cmhive2->HiveLock );
|
||
ExFreePool(cmhive2->HiveLock);
|
||
ASSERT( cmhive2->ViewLock );
|
||
ExFreePool(cmhive2->ViewLock);
|
||
CmpDestroyHiveViewList(cmhive2);
|
||
CmpDestroySecurityCache (cmhive2);
|
||
CmpDropFileObjectForHive(cmhive2);
|
||
|
||
CmpCheckForOrphanedKcbs((PHHIVE)cmhive2);
|
||
|
||
CmpFree(cmhive2, sizeof(CMHIVE));
|
||
return (Status);
|
||
}
|
||
if ( (OperationType == HINIT_FILE) ||
|
||
(OperationType == HINIT_MAPFILE) ||
|
||
(OperationType == HINIT_MEMORY) ||
|
||
(OperationType == HINIT_MEMORY_INPLACE))
|
||
{
|
||
|
||
rc = CmCheckRegistry(cmhive2, CheckFlags);
|
||
if (rc != 0) {
|
||
PCM_VIEW_OF_FILE CmView;
|
||
|
||
CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BUGCHECK,"CmpInitializeHive: "));
|
||
CmKdPrintEx((DPFLTR_CONFIG_ID,CML_BUGCHECK,"CmCheckRegistry failed, rc = %08lx\n",rc));
|
||
//
|
||
// we have dirtied some cells (by clearing the volatile information)
|
||
// we need first to unpin all the views
|
||
|
||
#ifdef DRAGOSS_PRIVATE_DEBUG
|
||
if( OperationType == HINIT_FILE ) DbgBreakPoint();
|
||
#endif //DRAGOSS_PRIVATE_DEBUG
|
||
|
||
//
|
||
// in theory we should do this for MEMORY and MEMORY_INPLACE
|
||
// as well, but they're only used at init time.
|
||
//
|
||
CmpDestroyHiveViewList(cmhive2);
|
||
CmpDestroySecurityCache(cmhive2);
|
||
CmpDropFileObjectForHive(cmhive2);
|
||
|
||
if (OperationType == HINIT_FILE) {
|
||
HvFreeHive((PHHIVE)cmhive2);
|
||
} else {
|
||
CmpCheckForOrphanedKcbs((PHHIVE)cmhive2);
|
||
}
|
||
ASSERT( cmhive2->HiveLock );
|
||
ExFreePool(cmhive2->HiveLock);
|
||
ASSERT( cmhive2->ViewLock );
|
||
ExFreePool(cmhive2->ViewLock);
|
||
|
||
CmpFree(cmhive2, sizeof(CMHIVE));
|
||
return(STATUS_REGISTRY_CORRUPT);
|
||
}
|
||
}
|
||
|
||
LOCK_HIVE_LIST();
|
||
InsertHeadList(&CmpHiveListHead, &(cmhive2->HiveList));
|
||
UNLOCK_HIVE_LIST();
|
||
*CmHive = cmhive2;
|
||
return (STATUS_SUCCESS);
|
||
}
|
||
|
||
|
||
BOOLEAN
|
||
CmpDestroyHive(
|
||
IN PHHIVE Hive,
|
||
IN HCELL_INDEX Cell
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine tears down a cmhive.
|
||
|
||
Arguments:
|
||
|
||
Hive - Supplies a pointer to the hive to be freed.
|
||
|
||
Cell - Supplies index of the hive's root cell.
|
||
|
||
Return Value:
|
||
|
||
TRUE if successful
|
||
FALSE if some failure occurred
|
||
|
||
--*/
|
||
|
||
{
|
||
PCELL_DATA CellData;
|
||
HCELL_INDEX LinkCell;
|
||
NTSTATUS Status;
|
||
|
||
//
|
||
// First find the link cell.
|
||
//
|
||
CellData = HvGetCell(Hive, Cell);
|
||
if( CellData == NULL ) {
|
||
//
|
||
// we couldn't map the bin containing this cell
|
||
//
|
||
return FALSE;
|
||
}
|
||
LinkCell = CellData->u.KeyNode.Parent;
|
||
HvReleaseCell(Hive, Cell);
|
||
|
||
//
|
||
// Now delete the link cell.
|
||
//
|
||
ASSERT(FIELD_OFFSET(CMHIVE, Hive) == 0);
|
||
Status = CmpFreeKeyByCell((PHHIVE)CmpMasterHive, LinkCell, TRUE);
|
||
|
||
if (NT_SUCCESS(Status)) {
|
||
//
|
||
// Take the hive out of the hive list
|
||
//
|
||
LOCK_HIVE_LIST();
|
||
CmpRemoveEntryList(&( ((PCMHIVE)Hive)->HiveList));
|
||
UNLOCK_HIVE_LIST();
|
||
return(TRUE);
|
||
} else {
|
||
return(FALSE);
|
||
}
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
CmpOpenFileWithExtremePrejudice(
|
||
OUT PHANDLE Primary,
|
||
IN POBJECT_ATTRIBUTES Obja,
|
||
IN ULONG IoFlags,
|
||
IN ULONG AttributeFlags
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine opens a hive file that some person has put a
|
||
read-only attribute on. It is used to prevent people from hurting
|
||
themselves by making the critical system hive files read-only.
|
||
|
||
Arguments:
|
||
|
||
Primary - Returns handle to file
|
||
|
||
Obja - Supplies Object Attributes of file.
|
||
|
||
IoFlags - Supplies flags to pass to ZwCreateFile
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status;
|
||
HANDLE Handle;
|
||
IO_STATUS_BLOCK IoStatusBlock;
|
||
FILE_BASIC_INFORMATION FileInfo;
|
||
|
||
RtlZeroMemory(&FileInfo, sizeof(FileInfo));
|
||
//
|
||
// Get the current file attributes
|
||
//
|
||
ASSERT_PASSIVE_LEVEL();
|
||
Status = ZwQueryAttributesFile(Obja, &FileInfo);
|
||
if (!NT_SUCCESS(Status)) {
|
||
CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"ZwQueryAttributesFile failed with IO status %lx\n",Status));
|
||
return(Status);
|
||
}
|
||
|
||
//
|
||
// Clear the readonly bit.
|
||
//
|
||
FileInfo.FileAttributes &= ~FILE_ATTRIBUTE_READONLY;
|
||
|
||
//
|
||
// Open the file
|
||
//
|
||
Status = ZwOpenFile(&Handle,
|
||
FILE_WRITE_ATTRIBUTES,
|
||
Obja,
|
||
&IoStatusBlock,
|
||
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
||
FILE_OPEN_FOR_BACKUP_INTENT);
|
||
if (!NT_SUCCESS(Status)) {
|
||
return(Status);
|
||
}
|
||
|
||
//
|
||
// Set the new attributes
|
||
//
|
||
Status = ZwSetInformationFile(Handle,
|
||
&IoStatusBlock,
|
||
&FileInfo,
|
||
sizeof(FileInfo),
|
||
FileBasicInformation);
|
||
ZwClose(Handle);
|
||
if (NT_SUCCESS(Status)) {
|
||
//
|
||
// Reopen the file with the access that we really need.
|
||
//
|
||
Status = ZwCreateFile(Primary,
|
||
FILE_READ_DATA | FILE_WRITE_DATA,
|
||
Obja,
|
||
&IoStatusBlock,
|
||
NULL,
|
||
AttributeFlags,
|
||
0,
|
||
FILE_OPEN,
|
||
IoFlags,
|
||
NULL,
|
||
0);
|
||
}
|
||
#if DBG
|
||
else {
|
||
CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"ZwSetInformationFile failed with IO status %lx\n",Status));
|
||
}
|
||
CmKdPrintEx((DPFLTR_CONFIG_ID,DPFLTR_ERROR_LEVEL,"CmpOpenFileWithExtremePrejudice returns with IO status %lx\n",Status));
|
||
#endif
|
||
|
||
return(Status);
|
||
|
||
}
|