mirror of
https://github.com/reactos/reactos.git
synced 2025-08-05 18:23:07 +00:00
Git conversion: Make reactos the root directory, move rosapps, rostests, wallpapers into modules, and delete rossubsys.
This commit is contained in:
parent
b94e2d8ca0
commit
c2c66aff7d
24198 changed files with 0 additions and 37285 deletions
947
boot/environ/lib/misc/bootreg.c
Normal file
947
boot/environ/lib/misc/bootreg.c
Normal file
|
@ -0,0 +1,947 @@
|
|||
/*
|
||||
* COPYRIGHT: See COPYING.ARM in the top level directory
|
||||
* PROJECT: ReactOS UEFI Boot Library
|
||||
* FILE: boot/environ/lib/misc/bootreg.c
|
||||
* PURPOSE: Boot Library Boot Registry Wrapper for CMLIB
|
||||
* PROGRAMMER: Alex Ionescu (alex.ionescu@reactos.org)
|
||||
*/
|
||||
|
||||
/* INCLUDES ******************************************************************/
|
||||
|
||||
#include "bl.h"
|
||||
#include <bcd.h>
|
||||
|
||||
/* DEFINITIONS ***************************************************************/
|
||||
|
||||
#define BI_FLUSH_HIVE 0x01
|
||||
#define BI_HIVE_WRITEABLE 0x02
|
||||
|
||||
/* DATA STRUCTURES ***********************************************************/
|
||||
|
||||
typedef struct _BI_KEY_HIVE
|
||||
{
|
||||
PHBASE_BLOCK BaseBlock;
|
||||
ULONG HiveSize;
|
||||
PBL_FILE_PATH_DESCRIPTOR FilePath;
|
||||
CMHIVE Hive;
|
||||
LONG ReferenceCount;
|
||||
ULONG Flags;
|
||||
PCM_KEY_NODE RootNode;
|
||||
} BI_KEY_HIVE, *PBI_KEY_HIVE;
|
||||
|
||||
typedef struct _BI_KEY_OBJECT
|
||||
{
|
||||
PBI_KEY_HIVE KeyHive;
|
||||
PCM_KEY_NODE KeyNode;
|
||||
HCELL_INDEX KeyCell;
|
||||
PWCHAR KeyName;
|
||||
} BI_KEY_OBJECT, *PBI_KEY_OBJECT;
|
||||
|
||||
/* GLOBALS *******************************************************************/
|
||||
|
||||
BOOLEAN BiHiveHashLibraryInitialized;
|
||||
ULONGLONG HvSymcryptSeed;
|
||||
|
||||
/* FUNCTIONS *****************************************************************/
|
||||
|
||||
BOOLEAN
|
||||
HvIsInPlaceBaseBlockValid (
|
||||
_In_ PHBASE_BLOCK BaseBlock
|
||||
)
|
||||
{
|
||||
ULONG HiveLength, HeaderSum;
|
||||
BOOLEAN Valid;
|
||||
|
||||
/* Assume failure */
|
||||
Valid = FALSE;
|
||||
|
||||
/* Check for incorrect signature, type, version, or format */
|
||||
if ((BaseBlock->Signature == 'fger') &&
|
||||
(BaseBlock->Type == 0) &&
|
||||
(BaseBlock->Major <= 1) &&
|
||||
(BaseBlock->Minor <= 5) &&
|
||||
(BaseBlock->Minor >= 3) &&
|
||||
(BaseBlock->Format == 1))
|
||||
{
|
||||
/* Check for invalid hive size */
|
||||
HiveLength = BaseBlock->Length;
|
||||
if (HiveLength)
|
||||
{
|
||||
/* Check for misaligned or too large hive size */
|
||||
if (!(HiveLength & 0xFFF) && HiveLength <= 0x7FFFE000)
|
||||
{
|
||||
/* Check for invalid header checksum */
|
||||
HeaderSum = HvpHiveHeaderChecksum(BaseBlock);
|
||||
if (HeaderSum == BaseBlock->CheckSum)
|
||||
{
|
||||
/* All good */
|
||||
Valid = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Return validity */
|
||||
return Valid;
|
||||
}
|
||||
|
||||
PVOID
|
||||
NTAPI
|
||||
CmpAllocate (
|
||||
_In_ SIZE_T Size,
|
||||
_In_ BOOLEAN Paged,
|
||||
_In_ ULONG Tag
|
||||
)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(Paged);
|
||||
UNREFERENCED_PARAMETER(Tag);
|
||||
|
||||
/* Call the heap allocator */
|
||||
return BlMmAllocateHeap(Size);
|
||||
}
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
CmpFree (
|
||||
_In_ PVOID Ptr,
|
||||
_In_ ULONG Quota
|
||||
)
|
||||
{
|
||||
UNREFERENCED_PARAMETER(Quota);
|
||||
|
||||
/* Call the heap allocator */
|
||||
BlMmFreeHeap(Ptr);
|
||||
}
|
||||
|
||||
VOID
|
||||
BiDereferenceHive (
|
||||
_In_ HANDLE KeyHandle
|
||||
)
|
||||
{
|
||||
PBI_KEY_OBJECT KeyObject;
|
||||
|
||||
/* Get the key object */
|
||||
KeyObject = (PBI_KEY_OBJECT)KeyHandle;
|
||||
|
||||
/* Drop a reference on the parent hive */
|
||||
--KeyObject->KeyHive->ReferenceCount;
|
||||
}
|
||||
|
||||
VOID
|
||||
BiFlushHive (
|
||||
_In_ HANDLE KeyHandle
|
||||
)
|
||||
{
|
||||
/* Not yet implemented */
|
||||
EfiPrintf(L"NO reg flush\r\n");
|
||||
return;
|
||||
}
|
||||
|
||||
VOID
|
||||
BiCloseKey (
|
||||
_In_ HANDLE KeyHandle
|
||||
)
|
||||
{
|
||||
PBI_KEY_HIVE KeyHive;
|
||||
PBI_KEY_OBJECT KeyObject;
|
||||
|
||||
/* Get the key object and hive */
|
||||
KeyObject = (PBI_KEY_OBJECT)KeyHandle;
|
||||
KeyHive = KeyObject->KeyHive;
|
||||
|
||||
/* Check if we have a hive, or name, or key node */
|
||||
if ((KeyHive) || (KeyObject->KeyNode) || (KeyObject->KeyName))
|
||||
{
|
||||
/* Drop a reference, see if it's the last one */
|
||||
BiDereferenceHive(KeyHandle);
|
||||
if (!KeyHive->ReferenceCount)
|
||||
{
|
||||
/* Check if we should flush it */
|
||||
if (KeyHive->Flags & BI_FLUSH_HIVE)
|
||||
{
|
||||
BiFlushHive(KeyHandle);
|
||||
}
|
||||
|
||||
/* Unmap the hive */
|
||||
MmPapFreePages(KeyHive->BaseBlock, BL_MM_INCLUDE_MAPPED_ALLOCATED);
|
||||
|
||||
/* Free the hive and hive path */
|
||||
BlMmFreeHeap(KeyHive->FilePath);
|
||||
BlMmFreeHeap(KeyHive);
|
||||
}
|
||||
|
||||
/* Check if a key name is present */
|
||||
if (KeyObject->KeyName)
|
||||
{
|
||||
/* Free it */
|
||||
BlMmFreeHeap(KeyObject->KeyName);
|
||||
}
|
||||
}
|
||||
|
||||
/* Free the object */
|
||||
BlMmFreeHeap(KeyObject);
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
BiOpenKey(
|
||||
_In_ HANDLE ParentHandle,
|
||||
_In_ PWCHAR KeyName,
|
||||
_Out_ PHANDLE Handle
|
||||
)
|
||||
{
|
||||
PBI_KEY_OBJECT ParentKey, NewKey;
|
||||
PBI_KEY_HIVE ParentHive;
|
||||
NTSTATUS Status;
|
||||
ULONG NameLength, SubNameLength, NameBytes;
|
||||
PWCHAR NameStart, NameBuffer;
|
||||
UNICODE_STRING KeyString;
|
||||
HCELL_INDEX KeyCell;
|
||||
PHHIVE Hive;
|
||||
PCM_KEY_NODE ParentNode;
|
||||
|
||||
/* Convert from a handle to our key object */
|
||||
ParentKey = (PBI_KEY_OBJECT)ParentHandle;
|
||||
|
||||
/* Extract the hive and node information */
|
||||
ParentHive = ParentKey->KeyHive;
|
||||
ParentNode = ParentKey->KeyNode;
|
||||
Hive = &ParentKey->KeyHive->Hive.Hive;
|
||||
|
||||
/* Initialize variables */
|
||||
KeyCell = HCELL_NIL;
|
||||
Status = STATUS_SUCCESS;
|
||||
NameBuffer = NULL;
|
||||
|
||||
/* Loop as long as there's still portions of the key name in play */
|
||||
NameLength = wcslen(KeyName);
|
||||
while (NameLength)
|
||||
{
|
||||
/* Find the first path separator */
|
||||
NameStart = wcschr(KeyName, OBJ_NAME_PATH_SEPARATOR);
|
||||
if (NameStart)
|
||||
{
|
||||
/* Look only at the key before the separator */
|
||||
SubNameLength = NameStart - KeyName;
|
||||
++NameStart;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* No path separator, this is the final leaf key */
|
||||
SubNameLength = NameLength;
|
||||
}
|
||||
|
||||
/* Free the name buffer from the previous pass if needed */
|
||||
if (NameBuffer)
|
||||
{
|
||||
BlMmFreeHeap(NameBuffer);
|
||||
}
|
||||
|
||||
/* Allocate a buffer to hold the name of this specific subkey only */
|
||||
NameBytes = SubNameLength * sizeof(WCHAR);
|
||||
NameBuffer = BlMmAllocateHeap(NameBytes + sizeof(UNICODE_NULL));
|
||||
if (!NameBuffer)
|
||||
{
|
||||
Status = STATUS_NO_MEMORY;
|
||||
goto Quickie;
|
||||
}
|
||||
|
||||
/* Copy and null-terminate the name of the subkey */
|
||||
RtlCopyMemory(NameBuffer, KeyName, NameBytes);
|
||||
NameBuffer[SubNameLength] = UNICODE_NULL;
|
||||
|
||||
/* Convert it into a UNICODE_STRING and try to find it */
|
||||
RtlInitUnicodeString(&KeyString, NameBuffer);
|
||||
KeyCell = CmpFindSubKeyByName(Hive, ParentNode, &KeyString);
|
||||
if (KeyCell == HCELL_NIL)
|
||||
{
|
||||
Status = STATUS_OBJECT_NAME_NOT_FOUND;
|
||||
goto Quickie;
|
||||
}
|
||||
|
||||
/* We found it -- get the key node out of it */
|
||||
ParentNode = (PCM_KEY_NODE)HvGetCell(Hive, KeyCell);
|
||||
if (!ParentNode)
|
||||
{
|
||||
Status = STATUS_REGISTRY_CORRUPT;
|
||||
goto Quickie;
|
||||
}
|
||||
|
||||
/* Update the key name to the next remaining path element */
|
||||
KeyName = NameStart;
|
||||
if (NameStart)
|
||||
{
|
||||
/* Update the length to the remainder of the path */
|
||||
NameLength += -1 - SubNameLength;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* There's nothing left, this was the leaf key */
|
||||
NameLength = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* Allocate a key object */
|
||||
NewKey = BlMmAllocateHeap(sizeof(*NewKey));
|
||||
if (!NewKey)
|
||||
{
|
||||
/* Bail out if we had no memory for it */
|
||||
Status = STATUS_NO_MEMORY;
|
||||
goto Quickie;
|
||||
}
|
||||
|
||||
/* Fill out the key object data */
|
||||
NewKey->KeyNode = ParentNode;
|
||||
NewKey->KeyHive = ParentHive;
|
||||
NewKey->KeyName = NameBuffer;
|
||||
NewKey->KeyCell = KeyCell;
|
||||
|
||||
/* Add a reference to the hive */
|
||||
++ParentHive->ReferenceCount;
|
||||
|
||||
/* Return the object back to the caller */
|
||||
*Handle = NewKey;
|
||||
|
||||
Quickie:
|
||||
/* If we had a name buffer, free it */
|
||||
if (NameBuffer)
|
||||
{
|
||||
BlMmFreeHeap(NameBuffer);
|
||||
}
|
||||
|
||||
/* Return status of the open operation */
|
||||
return Status;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
BiInitializeAndValidateHive (
|
||||
_In_ PBI_KEY_HIVE Hive
|
||||
)
|
||||
{
|
||||
ULONG HiveSize;
|
||||
NTSTATUS Status;
|
||||
|
||||
/* Make sure the hive is at least the size of a base block */
|
||||
if (Hive->HiveSize < sizeof(HBASE_BLOCK))
|
||||
{
|
||||
return STATUS_REGISTRY_CORRUPT;
|
||||
}
|
||||
|
||||
/* Make sure that the base block accurately describes the size of the hive */
|
||||
HiveSize = Hive->BaseBlock->Length + sizeof(HBASE_BLOCK);
|
||||
if ((HiveSize < sizeof(HBASE_BLOCK)) || (HiveSize > Hive->HiveSize))
|
||||
{
|
||||
return STATUS_REGISTRY_CORRUPT;
|
||||
}
|
||||
|
||||
/* Initialize a flat memory hive */
|
||||
RtlZeroMemory(&Hive->Hive, sizeof(Hive->Hive));
|
||||
Status = HvInitialize(&Hive->Hive.Hive,
|
||||
HINIT_FLAT,
|
||||
0,
|
||||
0,
|
||||
Hive->BaseBlock,
|
||||
CmpAllocate,
|
||||
CmpFree,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
0,
|
||||
NULL);
|
||||
if (NT_SUCCESS(Status))
|
||||
{
|
||||
/* Cleanup volatile/old data */
|
||||
CmPrepareHive(&Hive->Hive.Hive); // CmCheckRegistry
|
||||
Status = STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* Return the final status */
|
||||
return Status;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
BiLoadHive (
|
||||
_In_ PBL_FILE_PATH_DESCRIPTOR FilePath,
|
||||
_Out_ PHANDLE HiveHandle
|
||||
)
|
||||
{
|
||||
ULONG DeviceId;
|
||||
PHBASE_BLOCK BaseBlock, NewBaseBlock;
|
||||
PBI_KEY_OBJECT KeyObject;
|
||||
PBI_KEY_HIVE BcdHive;
|
||||
PBL_DEVICE_DESCRIPTOR BcdDevice;
|
||||
ULONG PathLength, DeviceLength, HiveSize, HiveLength, NewHiveSize;
|
||||
PWCHAR HiveName, LogName;
|
||||
BOOLEAN HaveWriteAccess;
|
||||
NTSTATUS Status;
|
||||
PVOID LogData;
|
||||
PHHIVE Hive;
|
||||
UNICODE_STRING KeyString;
|
||||
PCM_KEY_NODE RootNode;
|
||||
HCELL_INDEX CellIndex;
|
||||
|
||||
/* Initialize variables */
|
||||
DeviceId = -1;
|
||||
BaseBlock = NULL;
|
||||
BcdHive = NULL;
|
||||
KeyObject = NULL;
|
||||
LogData = NULL;
|
||||
LogName = NULL;
|
||||
|
||||
/* Initialize the crypto seed */
|
||||
if (!BiHiveHashLibraryInitialized)
|
||||
{
|
||||
HvSymcryptSeed = 0x82EF4D887A4E55C5;
|
||||
BiHiveHashLibraryInitialized = TRUE;
|
||||
}
|
||||
|
||||
/* Extract and validate the input path */
|
||||
BcdDevice = (PBL_DEVICE_DESCRIPTOR)&FilePath->Path;
|
||||
PathLength = FilePath->Length;
|
||||
DeviceLength = BcdDevice->Size;
|
||||
HiveName = (PWCHAR)((ULONG_PTR)BcdDevice + BcdDevice->Size);
|
||||
if (PathLength <= DeviceLength)
|
||||
{
|
||||
/* Doesn't make sense, bail out */
|
||||
Status = STATUS_INVALID_PARAMETER;
|
||||
goto Quickie;
|
||||
}
|
||||
|
||||
/* Attempt to open the underlying device for RW access */
|
||||
HaveWriteAccess = TRUE;
|
||||
Status = BlpDeviceOpen(BcdDevice,
|
||||
BL_DEVICE_READ_ACCESS | BL_DEVICE_WRITE_ACCESS,
|
||||
0,
|
||||
&DeviceId);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
/* Try for RO access instead */
|
||||
HaveWriteAccess = FALSE;
|
||||
Status = BlpDeviceOpen(BcdDevice, BL_DEVICE_READ_ACCESS, 0, &DeviceId);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
/* No access at all -- bail out */
|
||||
goto Quickie;
|
||||
}
|
||||
}
|
||||
|
||||
/* Now try to load the hive on disk */
|
||||
Status = BlImgLoadImageWithProgress2(DeviceId,
|
||||
BlLoaderRegistry,
|
||||
HiveName,
|
||||
(PVOID*)&BaseBlock,
|
||||
&HiveSize,
|
||||
0,
|
||||
FALSE,
|
||||
NULL,
|
||||
NULL);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
EfiPrintf(L"Hive read failure: % lx\r\n", Status);
|
||||
goto Quickie;
|
||||
}
|
||||
|
||||
/* Allocate a hive structure */
|
||||
BcdHive = BlMmAllocateHeap(sizeof(*BcdHive));
|
||||
if (!BcdHive)
|
||||
{
|
||||
Status = STATUS_NO_MEMORY;
|
||||
goto Quickie;
|
||||
}
|
||||
|
||||
/* Initialize it */
|
||||
RtlZeroMemory(BcdHive, sizeof(*BcdHive));
|
||||
BcdHive->BaseBlock = BaseBlock;
|
||||
BcdHive->HiveSize = HiveSize;
|
||||
if (HaveWriteAccess)
|
||||
{
|
||||
BcdHive->Flags |= BI_HIVE_WRITEABLE;
|
||||
}
|
||||
|
||||
/* Make sure the hive was at least one bin long */
|
||||
if (HiveSize < sizeof(*BaseBlock))
|
||||
{
|
||||
Status = STATUS_REGISTRY_CORRUPT;
|
||||
goto Quickie;
|
||||
}
|
||||
|
||||
/* Make sure the hive contents are at least one bin long */
|
||||
HiveLength = BaseBlock->Length;
|
||||
if (BaseBlock->Length < sizeof(*BaseBlock))
|
||||
{
|
||||
Status = STATUS_REGISTRY_CORRUPT;
|
||||
goto Quickie;
|
||||
}
|
||||
|
||||
/* Validate the initial bin (the base block) */
|
||||
if (!HvIsInPlaceBaseBlockValid(BaseBlock))
|
||||
{
|
||||
EfiPrintf(L"Recovery not implemented\r\n");
|
||||
Status = STATUS_REGISTRY_CORRUPT;
|
||||
goto Quickie;
|
||||
}
|
||||
|
||||
/* Check if there's log recovery that needs to happen */
|
||||
if (BaseBlock->Sequence1 != BaseBlock->Sequence2)
|
||||
{
|
||||
EfiPrintf(L"Log fix not implemented: %lx %lx\r\n");
|
||||
Status = STATUS_REGISTRY_CORRUPT;
|
||||
goto Quickie;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if the whole hive doesn't fit in the buffer.
|
||||
* Note: HiveLength does not include the size of the baseblock itself
|
||||
*/
|
||||
if (HiveSize < (HiveLength + sizeof(*BaseBlock)))
|
||||
{
|
||||
EfiPrintf(L"Need bigger hive buffer path\r\n");
|
||||
|
||||
/* Allocate a slightly bigger buffer */
|
||||
NewHiveSize = HiveLength + sizeof(*BaseBlock);
|
||||
Status = MmPapAllocatePagesInRange((PVOID*)&NewBaseBlock,
|
||||
BlLoaderRegistry,
|
||||
NewHiveSize >> PAGE_SHIFT,
|
||||
0,
|
||||
0,
|
||||
NULL,
|
||||
0);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
goto Quickie;
|
||||
}
|
||||
|
||||
/* Copy the current data in there */
|
||||
RtlCopyMemory(NewBaseBlock, BaseBlock, HiveSize);
|
||||
|
||||
/* Free the old data */
|
||||
MmPapFreePages(BaseBlock, BL_MM_INCLUDE_MAPPED_ALLOCATED);
|
||||
|
||||
/* Update our pointers */
|
||||
BaseBlock = NewBaseBlock;
|
||||
HiveSize = NewHiveSize;
|
||||
BcdHive->BaseBlock = BaseBlock;
|
||||
BcdHive->HiveSize = HiveSize;
|
||||
}
|
||||
|
||||
/* Check if any log stuff needs to happen */
|
||||
if (LogData)
|
||||
{
|
||||
EfiPrintf(L"Log fix not implemented: %lx %lx\r\n");
|
||||
Status = STATUS_REGISTRY_CORRUPT;
|
||||
goto Quickie;
|
||||
}
|
||||
|
||||
/* Call Hv to setup the hive library */
|
||||
Status = BiInitializeAndValidateHive(BcdHive);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
goto Quickie;
|
||||
}
|
||||
|
||||
/* Now get the root node */
|
||||
Hive = &BcdHive->Hive.Hive;
|
||||
RootNode = (PCM_KEY_NODE)HvGetCell(Hive, Hive->BaseBlock->RootCell);
|
||||
if (!RootNode)
|
||||
{
|
||||
Status = STATUS_OBJECT_NAME_NOT_FOUND;
|
||||
goto Quickie;
|
||||
}
|
||||
|
||||
/* Find the Objects subkey under it to see if it's a real BCD hive */
|
||||
RtlInitUnicodeString(&KeyString, L"Objects");
|
||||
CellIndex = CmpFindSubKeyByName(Hive, RootNode, &KeyString);
|
||||
if (CellIndex == HCELL_NIL)
|
||||
{
|
||||
EfiPrintf(L"No OBJECTS subkey found!\r\n");
|
||||
Status = STATUS_OBJECT_NAME_NOT_FOUND;
|
||||
goto Quickie;
|
||||
}
|
||||
|
||||
/* This is a valid BCD hive, store its root node here */
|
||||
BcdHive->RootNode = RootNode;
|
||||
|
||||
/* Allocate a copy of the file path */
|
||||
BcdHive->FilePath = BlMmAllocateHeap(FilePath->Length);
|
||||
if (!BcdHive->FilePath)
|
||||
{
|
||||
Status = STATUS_NO_MEMORY;
|
||||
goto Quickie;
|
||||
}
|
||||
|
||||
/* Make a copy of it */
|
||||
RtlCopyMemory(BcdHive->FilePath, FilePath, FilePath->Length);
|
||||
|
||||
/* Create a key object to describe the rot */
|
||||
KeyObject = BlMmAllocateHeap(sizeof(*KeyObject));
|
||||
if (!KeyObject)
|
||||
{
|
||||
Status = STATUS_NO_MEMORY;
|
||||
goto Quickie;
|
||||
}
|
||||
|
||||
/* Fill out the details */
|
||||
KeyObject->KeyNode = RootNode;
|
||||
KeyObject->KeyHive = BcdHive;
|
||||
KeyObject->KeyName = NULL;
|
||||
KeyObject->KeyCell = Hive->BaseBlock->RootCell;
|
||||
|
||||
/* One reference for the key object, plus one lifetime reference */
|
||||
BcdHive->ReferenceCount = 2;
|
||||
|
||||
/* This is the hive handle */
|
||||
*HiveHandle = KeyObject;
|
||||
|
||||
/* We're all good */
|
||||
Status = STATUS_SUCCESS;
|
||||
|
||||
Quickie:
|
||||
/* If we had a log name, free it */
|
||||
if (LogName)
|
||||
{
|
||||
BlMmFreeHeap(LogName);
|
||||
}
|
||||
|
||||
/* If we had logging data, free it */
|
||||
if (LogData)
|
||||
{
|
||||
MmPapFreePages(LogData, BL_MM_INCLUDE_MAPPED_ALLOCATED);
|
||||
}
|
||||
|
||||
/* Check if this is the failure path */
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
/* If we mapped the hive, free it */
|
||||
if (BaseBlock)
|
||||
{
|
||||
MmPapFreePages(BaseBlock, BL_MM_INCLUDE_MAPPED_ALLOCATED);
|
||||
}
|
||||
|
||||
/* If we opened the device, close it */
|
||||
if (DeviceId != -1)
|
||||
{
|
||||
BlDeviceClose(DeviceId);
|
||||
}
|
||||
|
||||
/* Did we create a hive object? */
|
||||
if (BcdHive)
|
||||
{
|
||||
/* Free the file path if we made a copy of it */
|
||||
if (BcdHive->FilePath)
|
||||
{
|
||||
BlMmFreeHeap(BcdHive->FilePath);
|
||||
}
|
||||
|
||||
/* Free the hive itself */
|
||||
BlMmFreeHeap(BcdHive);
|
||||
}
|
||||
|
||||
/* Finally, free the root key object if we created one */
|
||||
if (KeyObject)
|
||||
{
|
||||
BlMmFreeHeap(KeyObject);
|
||||
}
|
||||
}
|
||||
|
||||
/* Return the final status */
|
||||
return Status;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
BiGetRegistryValue (
|
||||
_In_ HANDLE KeyHandle,
|
||||
_In_ PWCHAR ValueName,
|
||||
_In_ ULONG Type,
|
||||
_Out_ PVOID* Buffer,
|
||||
_Out_ PULONG ValueLength
|
||||
)
|
||||
{
|
||||
PCM_KEY_NODE KeyNode;
|
||||
PHHIVE KeyHive;
|
||||
UNICODE_STRING ValueString;
|
||||
PBI_KEY_OBJECT KeyObject;
|
||||
PCM_KEY_VALUE KeyValue;
|
||||
PVOID ValueCopy;
|
||||
ULONG Size;
|
||||
HCELL_INDEX CellIndex;
|
||||
PCELL_DATA ValueData;
|
||||
|
||||
/* Get the key object, node,and hive */
|
||||
KeyObject = (PBI_KEY_OBJECT)KeyHandle;
|
||||
KeyNode = KeyObject->KeyNode;
|
||||
KeyHive = &KeyObject->KeyHive->Hive.Hive;
|
||||
|
||||
/* Find the value cell index in the list of values */
|
||||
RtlInitUnicodeString(&ValueString, ValueName);
|
||||
CmpFindNameInList(KeyHive,
|
||||
&KeyNode->ValueList,
|
||||
&ValueString,
|
||||
NULL,
|
||||
&CellIndex);
|
||||
if (CellIndex == HCELL_NIL)
|
||||
{
|
||||
return STATUS_OBJECT_NAME_NOT_FOUND;
|
||||
}
|
||||
|
||||
/* Get the cell data for it */
|
||||
KeyValue = (PCM_KEY_VALUE)HvGetCell(KeyHive, CellIndex);
|
||||
if (!KeyValue)
|
||||
{
|
||||
return STATUS_REGISTRY_CORRUPT;
|
||||
}
|
||||
|
||||
/* Make sure the type matches */
|
||||
if (KeyValue->Type != Type)
|
||||
{
|
||||
return STATUS_OBJECT_TYPE_MISMATCH;
|
||||
}
|
||||
|
||||
/* Now get the data cell */
|
||||
ValueData = CmpValueToData(KeyHive, KeyValue, &Size);
|
||||
|
||||
/* Make a copy of it */
|
||||
ValueCopy = BlMmAllocateHeap(Size);
|
||||
if (!ValueCopy)
|
||||
{
|
||||
return STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
/* Copy it in the buffer, and return it and its size */
|
||||
RtlCopyMemory(ValueCopy, ValueData, Size);
|
||||
*Buffer = ValueCopy;
|
||||
*ValueLength = Size;
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
BiEnumerateSubKeys (
|
||||
_In_ HANDLE KeyHandle,
|
||||
_Out_ PWCHAR** SubKeyList,
|
||||
_Out_ PULONG SubKeyCount
|
||||
)
|
||||
{
|
||||
PCM_KEY_NODE KeyNode, Node;
|
||||
PBI_KEY_OBJECT KeyObject;
|
||||
ULONG KeyCount;
|
||||
ULONG NameLength, NewTotalNameLength, FinalLength, TotalNameLength;
|
||||
PHHIVE Hive;
|
||||
PWCHAR KeyName, NameEnd;
|
||||
HCELL_INDEX CellIndex;
|
||||
PWCHAR* SubKeys;
|
||||
NTSTATUS Status;
|
||||
ULONG i;
|
||||
|
||||
/* Get the key object, node, and hive */
|
||||
KeyObject = (PBI_KEY_OBJECT)KeyHandle;
|
||||
KeyNode = KeyObject->KeyNode;
|
||||
Hive = &KeyObject->KeyHive->Hive.Hive;
|
||||
|
||||
/* Assume it's empty */
|
||||
*SubKeyList = 0;
|
||||
*SubKeyCount = 0;
|
||||
|
||||
/* Initialize locals */
|
||||
KeyCount = 0;
|
||||
SubKeys = 0;
|
||||
TotalNameLength = 0;
|
||||
|
||||
/* Find the first subkey cell index */
|
||||
CellIndex = CmpFindSubKeyByNumber(Hive, KeyNode, KeyCount);
|
||||
while (CellIndex != HCELL_NIL)
|
||||
{
|
||||
/* Move to the next one */
|
||||
KeyCount++;
|
||||
|
||||
/* Get the cell data for it */
|
||||
Node = (PCM_KEY_NODE)HvGetCell(Hive, CellIndex);
|
||||
if (!Node)
|
||||
{
|
||||
return STATUS_REGISTRY_CORRUPT;
|
||||
}
|
||||
|
||||
/* Check if the value is compressed */
|
||||
if (Node->Flags & KEY_COMP_NAME)
|
||||
{
|
||||
/* Get the compressed name size */
|
||||
NameLength = CmpCompressedNameSize(Node->Name, Node->NameLength);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Get the real size */
|
||||
NameLength = Node->NameLength;
|
||||
}
|
||||
|
||||
/* Add up the new length, protecting against overflow */
|
||||
NewTotalNameLength = TotalNameLength + NameLength + sizeof(UNICODE_NULL);
|
||||
if (NewTotalNameLength < TotalNameLength)
|
||||
{
|
||||
Status = STATUS_NAME_TOO_LONG;
|
||||
goto Quickie;
|
||||
}
|
||||
|
||||
/* We're good, use the new length */
|
||||
TotalNameLength = NewTotalNameLength;
|
||||
|
||||
/* Find the next subkey cell index */
|
||||
CellIndex = CmpFindSubKeyByNumber(Hive, KeyNode, KeyCount);
|
||||
}
|
||||
|
||||
/* Were there no keys? We're done, if so */
|
||||
if (!KeyCount)
|
||||
{
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* Safely compute the size of the array needed */
|
||||
Status = RtlULongLongToULong(sizeof(PWCHAR) * KeyCount, &FinalLength);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
goto Quickie;
|
||||
}
|
||||
|
||||
/* Safely add that to the name length */
|
||||
Status = RtlULongAdd(TotalNameLength, FinalLength, &FinalLength);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
goto Quickie;
|
||||
}
|
||||
|
||||
/* Allocate an array big enough for the names and pointers */
|
||||
SubKeys = BlMmAllocateHeap(FinalLength);
|
||||
if (!SubKeys)
|
||||
{
|
||||
Status = STATUS_NO_MEMORY;
|
||||
goto Quickie;
|
||||
}
|
||||
|
||||
/* Go over each key again */
|
||||
NameEnd = (PWCHAR)&SubKeys[KeyCount];
|
||||
for (i = 0; i < KeyCount; i++)
|
||||
{
|
||||
/* Get the cell index for this subkey */
|
||||
CellIndex = CmpFindSubKeyByNumber(Hive, KeyNode, i);
|
||||
if (CellIndex == HCELL_NIL)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
/* Get the cell data for it */
|
||||
Node = HvGetCell(Hive, CellIndex);
|
||||
if (!Node)
|
||||
{
|
||||
Status = STATUS_REGISTRY_CORRUPT;
|
||||
goto Quickie;
|
||||
}
|
||||
|
||||
/* Check if the value is compressed */
|
||||
KeyName = Node->Name;
|
||||
if (Node->Flags & KEY_COMP_NAME)
|
||||
{
|
||||
/* Get the compressed name size */
|
||||
NameLength = CmpCompressedNameSize(KeyName, Node->NameLength);
|
||||
CmpCopyCompressedName(NameEnd, NameLength, KeyName, Node->NameLength);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Get the real size */
|
||||
NameLength = Node->NameLength;
|
||||
RtlCopyMemory(NameEnd, KeyName, NameLength);
|
||||
}
|
||||
|
||||
/* Move the name buffer to the next spot, and NULL-terminate */
|
||||
SubKeys[i] = NameEnd;
|
||||
NameEnd += (NameLength / sizeof(WCHAR));
|
||||
*NameEnd = UNICODE_NULL;
|
||||
|
||||
/* Keep going */
|
||||
NameEnd++;
|
||||
}
|
||||
|
||||
/* Check if the subkeys were empty */
|
||||
if (i == 0)
|
||||
{
|
||||
/* They disappeared in the middle of enumeration */
|
||||
Status = STATUS_OBJECT_NAME_NOT_FOUND;
|
||||
goto Quickie;
|
||||
}
|
||||
|
||||
/* Return the count and the array of names */
|
||||
*SubKeyList = SubKeys;
|
||||
*SubKeyCount = i;
|
||||
SubKeys = NULL;
|
||||
Status = STATUS_SUCCESS;
|
||||
|
||||
Quickie:
|
||||
/* On the failure path, free the subkeys if any exist */
|
||||
if (SubKeys)
|
||||
{
|
||||
BlMmFreeHeap(SubKeys);
|
||||
}
|
||||
|
||||
/* All done, return the result */
|
||||
return Status;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
BiDeleteKey (
|
||||
_In_ HANDLE KeyHandle
|
||||
)
|
||||
{
|
||||
NTSTATUS Status;
|
||||
PBI_KEY_OBJECT KeyObject;
|
||||
PHHIVE Hive;
|
||||
ULONG SubKeyCount, i;
|
||||
PWCHAR* SubKeyList;
|
||||
HANDLE SubKeyHandle;
|
||||
|
||||
/* Get the key object and hive */
|
||||
KeyObject = (PBI_KEY_OBJECT)KeyHandle;
|
||||
Hive = &KeyObject->KeyHive->Hive.Hive;
|
||||
|
||||
/* Make sure the hive is writeable */
|
||||
if (!(KeyObject->KeyHive->Flags & BI_HIVE_WRITEABLE))
|
||||
{
|
||||
return STATUS_MEDIA_WRITE_PROTECTED;
|
||||
}
|
||||
|
||||
/* Enumerate all of the subkeys */
|
||||
Status = BiEnumerateSubKeys(KeyHandle, &SubKeyList, &SubKeyCount);
|
||||
if ((NT_SUCCESS(Status)) && (SubKeyCount > 0))
|
||||
{
|
||||
/* Loop through each one */
|
||||
for (i = 0; i < SubKeyCount; i++)
|
||||
{
|
||||
/* Open a handle to it */
|
||||
Status = BiOpenKey(KeyHandle, SubKeyList[i], &SubKeyHandle);
|
||||
if (NT_SUCCESS(Status))
|
||||
{
|
||||
/* Recursively call us to delete it */
|
||||
Status = BiDeleteKey(SubKeyHandle);
|
||||
if (Status != STATUS_SUCCESS)
|
||||
{
|
||||
/* Close the key on failure */
|
||||
BiCloseKey(SubKeyHandle);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Check if we had a list of subkeys */
|
||||
if (SubKeyList)
|
||||
{
|
||||
/* Free it */
|
||||
BlMmFreeHeap(SubKeyList);
|
||||
}
|
||||
|
||||
/* Delete this key cell */
|
||||
Status = CmpFreeKeyByCell(Hive, KeyObject->KeyCell, TRUE);
|
||||
if (NT_SUCCESS(Status))
|
||||
{
|
||||
/* Mark the hive as requiring a flush */
|
||||
KeyObject->KeyHive->Flags |= BI_FLUSH_HIVE;
|
||||
BiCloseKey(KeyHandle);
|
||||
}
|
||||
|
||||
/* All done */
|
||||
return Status;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue