mirror of https://github.com/tongzx/nt5src
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.
982 lines
29 KiB
982 lines
29 KiB
/*++
|
|
|
|
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);
|
|
|
|
}
|