mirror of
https://github.com/reactos/reactos.git
synced 2024-09-06 02:37:06 +00:00
- Remove/deprecate some certain chunks of Cm which are not critical to booting and not even to applications (such as NtSaveKey, which didn't even have NtRestoreKey) and mark them as unimplemented functions.
- This doesn't do much but clean up some of our code to make it easier to see what the critical parts are and reduce bug surface exposure. - Move and slightly reformat (without touching any of the actual code) registry callback/notification code to cmhook.c. svn path=/trunk/; revision=26671
This commit is contained in:
parent
e72d90dbc8
commit
107cb5719e
|
@ -91,20 +91,9 @@ CmImportSystemHive(PCHAR ChunkBase,
|
|||
{
|
||||
*RegistryHive = NULL;
|
||||
|
||||
DPRINT ("CmImportSystemHive() called\n");
|
||||
|
||||
if (strncmp (ChunkBase, "regf", 4))
|
||||
{
|
||||
DPRINT1 ("Found invalid '%.*s' magic\n", 4, ChunkBase);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
DPRINT ("Found '%.*s' magic\n", 4, ChunkBase);
|
||||
|
||||
/* Import the binary system hive (non-volatile, offset-based, permanent) */
|
||||
if (!CmImportBinaryHive (ChunkBase, ChunkSize, 0, RegistryHive))
|
||||
{
|
||||
DPRINT1 ("CmiImportBinaryHive() failed\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
@ -125,123 +114,11 @@ CmImportHardwareHive(PCHAR ChunkBase,
|
|||
ULONG ChunkSize,
|
||||
OUT PEREGISTRY_HIVE *RegistryHive)
|
||||
{
|
||||
OBJECT_ATTRIBUTES ObjectAttributes;
|
||||
UNICODE_STRING KeyName;
|
||||
HANDLE HardwareKey;
|
||||
ULONG Disposition;
|
||||
NTSTATUS Status;
|
||||
*RegistryHive = NULL;
|
||||
|
||||
DPRINT ("CmImportHardwareHive() called\n");
|
||||
|
||||
if (ChunkBase == NULL &&
|
||||
ChunkSize == 0)
|
||||
{
|
||||
/* Create '\Registry\Machine\HARDWARE' key. */
|
||||
RtlInitUnicodeString (&KeyName,
|
||||
REG_HARDWARE_KEY_NAME);
|
||||
InitializeObjectAttributes (&ObjectAttributes,
|
||||
&KeyName,
|
||||
OBJ_CASE_INSENSITIVE,
|
||||
NULL,
|
||||
NULL);
|
||||
Status = ZwCreateKey (&HardwareKey,
|
||||
KEY_ALL_ACCESS,
|
||||
&ObjectAttributes,
|
||||
0,
|
||||
NULL,
|
||||
REG_OPTION_VOLATILE,
|
||||
&Disposition);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT1("NtCreateKey() failed, status: 0x%x\n", Status);
|
||||
return FALSE;
|
||||
}
|
||||
ZwClose (HardwareKey);
|
||||
|
||||
/* Create '\Registry\Machine\HARDWARE\DESCRIPTION' key. */
|
||||
RtlInitUnicodeString(&KeyName,
|
||||
REG_DESCRIPTION_KEY_NAME);
|
||||
InitializeObjectAttributes (&ObjectAttributes,
|
||||
&KeyName,
|
||||
OBJ_CASE_INSENSITIVE,
|
||||
NULL,
|
||||
NULL);
|
||||
Status = ZwCreateKey (&HardwareKey,
|
||||
KEY_ALL_ACCESS,
|
||||
&ObjectAttributes,
|
||||
0,
|
||||
NULL,
|
||||
REG_OPTION_VOLATILE,
|
||||
&Disposition);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT1("NtCreateKey() failed, status: 0x%x\n", Status);
|
||||
return FALSE;
|
||||
}
|
||||
ZwClose (HardwareKey);
|
||||
|
||||
/* Create '\Registry\Machine\HARDWARE\DEVICEMAP' key. */
|
||||
RtlInitUnicodeString (&KeyName,
|
||||
REG_DEVICEMAP_KEY_NAME);
|
||||
InitializeObjectAttributes (&ObjectAttributes,
|
||||
&KeyName,
|
||||
OBJ_CASE_INSENSITIVE,
|
||||
NULL,
|
||||
NULL);
|
||||
Status = ZwCreateKey (&HardwareKey,
|
||||
KEY_ALL_ACCESS,
|
||||
&ObjectAttributes,
|
||||
0,
|
||||
NULL,
|
||||
REG_OPTION_VOLATILE,
|
||||
&Disposition);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT1("NtCreateKey() failed, status: 0x%x\n", Status);
|
||||
return FALSE;
|
||||
}
|
||||
ZwClose (HardwareKey);
|
||||
|
||||
/* Create '\Registry\Machine\HARDWARE\RESOURCEMAP' key. */
|
||||
RtlInitUnicodeString(&KeyName,
|
||||
REG_RESOURCEMAP_KEY_NAME);
|
||||
InitializeObjectAttributes (&ObjectAttributes,
|
||||
&KeyName,
|
||||
OBJ_CASE_INSENSITIVE,
|
||||
NULL,
|
||||
NULL);
|
||||
Status = ZwCreateKey (&HardwareKey,
|
||||
KEY_ALL_ACCESS,
|
||||
&ObjectAttributes,
|
||||
0,
|
||||
NULL,
|
||||
REG_OPTION_VOLATILE,
|
||||
&Disposition);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT1("NtCreateKey() failed, status: 0x%x\n", Status);
|
||||
return FALSE;
|
||||
}
|
||||
ZwClose (HardwareKey);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Check the hive magic */
|
||||
if (strncmp (ChunkBase, "regf", 4))
|
||||
{
|
||||
DPRINT1 ("Found invalid '%.*s' magic\n", 4, ChunkBase);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
DPRINT ("Found '%.*s' magic\n", 4, ChunkBase);
|
||||
DPRINT ("ChunkBase %lx ChunkSize %lu\n", ChunkBase, ChunkSize);
|
||||
|
||||
/* Import the binary system hive (volatile, offset-based, permanent) */
|
||||
if (!CmImportBinaryHive (ChunkBase, ChunkSize, HIVE_NO_FILE, RegistryHive))
|
||||
{
|
||||
DPRINT1 ("CmiImportBinaryHive() failed\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
|
|
@ -29,9 +29,6 @@ extern LIST_ENTRY CmiKeyObjectListHead;
|
|||
|
||||
static BOOLEAN CmiRegistryInitialized = FALSE;
|
||||
|
||||
LIST_ENTRY CmiCallbackHead;
|
||||
FAST_MUTEX CmiCallbackLock;
|
||||
|
||||
/* FUNCTIONS ****************************************************************/
|
||||
|
||||
NTSTATUS
|
||||
|
@ -131,151 +128,6 @@ CmpCreateHandle(PVOID ObjectBody,
|
|||
return STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
/*
|
||||
* @implemented
|
||||
*/
|
||||
NTSTATUS STDCALL
|
||||
CmRegisterCallback(IN PEX_CALLBACK_FUNCTION Function,
|
||||
IN PVOID Context,
|
||||
IN OUT PLARGE_INTEGER Cookie)
|
||||
{
|
||||
PREGISTRY_CALLBACK Callback;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
ASSERT(Function && Cookie);
|
||||
|
||||
Callback = ExAllocatePoolWithTag(PagedPool,
|
||||
sizeof(REGISTRY_CALLBACK),
|
||||
TAG('C', 'M', 'c', 'b'));
|
||||
if(Callback != NULL)
|
||||
{
|
||||
/* initialize the callback */
|
||||
ExInitializeRundownProtection(&Callback->RundownRef);
|
||||
Callback->Function = Function;
|
||||
Callback->Context = Context;
|
||||
Callback->PendingDelete = FALSE;
|
||||
|
||||
/* add it to the callback list and receive a cookie for the callback */
|
||||
ExAcquireFastMutex(&CmiCallbackLock);
|
||||
/* FIXME - to receive a unique cookie we'll just return the pointer to the
|
||||
callback object */
|
||||
Callback->Cookie.QuadPart = (ULONG_PTR)Callback;
|
||||
InsertTailList(&CmiCallbackHead, &Callback->ListEntry);
|
||||
|
||||
ExReleaseFastMutex(&CmiCallbackLock);
|
||||
|
||||
*Cookie = Callback->Cookie;
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* @implemented
|
||||
*/
|
||||
NTSTATUS STDCALL
|
||||
CmUnRegisterCallback(IN LARGE_INTEGER Cookie)
|
||||
{
|
||||
PLIST_ENTRY CurrentEntry;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
ExAcquireFastMutex(&CmiCallbackLock);
|
||||
|
||||
for(CurrentEntry = CmiCallbackHead.Flink;
|
||||
CurrentEntry != &CmiCallbackHead;
|
||||
CurrentEntry = CurrentEntry->Flink)
|
||||
{
|
||||
PREGISTRY_CALLBACK CurrentCallback;
|
||||
|
||||
CurrentCallback = CONTAINING_RECORD(CurrentEntry, REGISTRY_CALLBACK, ListEntry);
|
||||
if(CurrentCallback->Cookie.QuadPart == Cookie.QuadPart)
|
||||
{
|
||||
if(!CurrentCallback->PendingDelete)
|
||||
{
|
||||
/* found the callback, don't unlink it from the list yet so we don't screw
|
||||
the calling loop */
|
||||
CurrentCallback->PendingDelete = TRUE;
|
||||
ExReleaseFastMutex(&CmiCallbackLock);
|
||||
|
||||
/* if the callback is currently executing, wait until it finished */
|
||||
ExWaitForRundownProtectionRelease(&CurrentCallback->RundownRef);
|
||||
|
||||
/* time to unlink it. It's now safe because every attempt to acquire a
|
||||
runtime protection on this callback will fail */
|
||||
ExAcquireFastMutex(&CmiCallbackLock);
|
||||
RemoveEntryList(&CurrentCallback->ListEntry);
|
||||
ExReleaseFastMutex(&CmiCallbackLock);
|
||||
|
||||
/* free the callback */
|
||||
ExFreePool(CurrentCallback);
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* pending delete, pretend like it already is deleted */
|
||||
ExReleaseFastMutex(&CmiCallbackLock);
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ExReleaseFastMutex(&CmiCallbackLock);
|
||||
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
|
||||
NTSTATUS
|
||||
CmiCallRegisteredCallbacks(IN REG_NOTIFY_CLASS Argument1,
|
||||
IN PVOID Argument2)
|
||||
{
|
||||
PLIST_ENTRY CurrentEntry;
|
||||
NTSTATUS Status = STATUS_SUCCESS;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
ExAcquireFastMutex(&CmiCallbackLock);
|
||||
|
||||
for(CurrentEntry = CmiCallbackHead.Flink;
|
||||
CurrentEntry != &CmiCallbackHead;
|
||||
CurrentEntry = CurrentEntry->Flink)
|
||||
{
|
||||
PREGISTRY_CALLBACK CurrentCallback;
|
||||
|
||||
CurrentCallback = CONTAINING_RECORD(CurrentEntry, REGISTRY_CALLBACK, ListEntry);
|
||||
if(!CurrentCallback->PendingDelete &&
|
||||
ExAcquireRundownProtection(&CurrentCallback->RundownRef))
|
||||
{
|
||||
/* don't hold locks during the callbacks! */
|
||||
ExReleaseFastMutex(&CmiCallbackLock);
|
||||
|
||||
Status = CurrentCallback->Function(CurrentCallback->Context,
|
||||
(PVOID)Argument1,
|
||||
Argument2);
|
||||
|
||||
ExAcquireFastMutex(&CmiCallbackLock);
|
||||
/* don't release the rundown protection before holding the callback lock
|
||||
so the pointer to the next callback isn't cleared in case this callback
|
||||
get's deleted */
|
||||
ExReleaseRundownProtection(&CurrentCallback->RundownRef);
|
||||
if(!NT_SUCCESS(Status))
|
||||
{
|
||||
/* one callback returned failure, don't call any more callbacks */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ExReleaseFastMutex(&CmiCallbackLock);
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
|
||||
NTSTATUS STDCALL
|
||||
NtCreateKey(OUT PHANDLE KeyHandle,
|
||||
IN ACCESS_MASK DesiredAccess,
|
||||
|
@ -2219,22 +2071,6 @@ Fail:
|
|||
return Status;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* NOTE:
|
||||
* KeyObjectAttributes->RootDirectory specifies the handle to the parent key and
|
||||
* KeyObjectAttributes->Name specifies the name of the key to load.
|
||||
*/
|
||||
NTSTATUS STDCALL
|
||||
NtLoadKey (IN POBJECT_ATTRIBUTES KeyObjectAttributes,
|
||||
IN POBJECT_ATTRIBUTES FileObjectAttributes)
|
||||
{
|
||||
return NtLoadKey2 (KeyObjectAttributes,
|
||||
FileObjectAttributes,
|
||||
0);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* NOTE:
|
||||
* KeyObjectAttributes->RootDirectory specifies the handle to the parent key and
|
||||
|
@ -2357,52 +2193,6 @@ NtLoadKey2 (IN POBJECT_ATTRIBUTES KeyObjectAttributes,
|
|||
return Status;
|
||||
}
|
||||
|
||||
|
||||
NTSTATUS STDCALL
|
||||
NtNotifyChangeKey (IN HANDLE KeyHandle,
|
||||
IN HANDLE Event,
|
||||
IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
|
||||
IN PVOID ApcContext OPTIONAL,
|
||||
OUT PIO_STATUS_BLOCK IoStatusBlock,
|
||||
IN ULONG CompletionFilter,
|
||||
IN BOOLEAN WatchSubtree,
|
||||
OUT PVOID Buffer,
|
||||
IN ULONG Length,
|
||||
IN BOOLEAN Asynchronous)
|
||||
{
|
||||
UNIMPLEMENTED;
|
||||
return(STATUS_NOT_IMPLEMENTED);
|
||||
}
|
||||
|
||||
#if 0
|
||||
NTSTATUS STDCALL
|
||||
NtNotifyChangeKey (IN HANDLE KeyHandle,
|
||||
IN HANDLE Event,
|
||||
IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
|
||||
IN PVOID ApcContext OPTIONAL,
|
||||
OUT PIO_STATUS_BLOCK IoStatusBlock,
|
||||
IN ULONG CompletionFilter,
|
||||
IN BOOLEAN WatchSubtree,
|
||||
OUT PVOID Buffer,
|
||||
IN ULONG Length,
|
||||
IN BOOLEAN Asynchronous)
|
||||
{
|
||||
return NtNotifyChangeMultipleKeys(KeyHandle,
|
||||
0,
|
||||
NULL,
|
||||
Event,
|
||||
ApcRoutine,
|
||||
ApcContext,
|
||||
IoStatusBlock,
|
||||
CompletionFilter,
|
||||
WatchTree,
|
||||
Buffer,
|
||||
Length,
|
||||
Asynchronous);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
NTSTATUS STDCALL
|
||||
NtQueryMultipleValueKey (IN HANDLE KeyHandle,
|
||||
IN OUT PKEY_VALUE_ENTRY ValueList,
|
||||
|
@ -2542,269 +2332,6 @@ NtQueryMultipleValueKey (IN HANDLE KeyHandle,
|
|||
return Status;
|
||||
}
|
||||
|
||||
|
||||
NTSTATUS STDCALL
|
||||
NtReplaceKey (IN POBJECT_ATTRIBUTES ObjectAttributes,
|
||||
IN HANDLE Key,
|
||||
IN POBJECT_ATTRIBUTES ReplacedObjectAttributes)
|
||||
{
|
||||
UNIMPLEMENTED;
|
||||
return(STATUS_NOT_IMPLEMENTED);
|
||||
}
|
||||
|
||||
|
||||
NTSTATUS STDCALL
|
||||
NtRestoreKey (IN HANDLE KeyHandle,
|
||||
IN HANDLE FileHandle,
|
||||
IN ULONG RestoreFlags)
|
||||
{
|
||||
UNIMPLEMENTED;
|
||||
return(STATUS_NOT_IMPLEMENTED);
|
||||
}
|
||||
|
||||
|
||||
NTSTATUS STDCALL
|
||||
NtSaveKey (IN HANDLE KeyHandle,
|
||||
IN HANDLE FileHandle)
|
||||
{
|
||||
PEREGISTRY_HIVE TempHive;
|
||||
PKEY_OBJECT KeyObject;
|
||||
NTSTATUS Status;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
DPRINT ("NtSaveKey() called\n");
|
||||
|
||||
#if 0
|
||||
if (!SeSinglePrivilegeCheck (SeBackupPrivilege, ExGetPreviousMode ()))
|
||||
return STATUS_PRIVILEGE_NOT_HELD;
|
||||
#endif
|
||||
|
||||
Status = ObReferenceObjectByHandle (KeyHandle,
|
||||
0,
|
||||
CmiKeyType,
|
||||
ExGetPreviousMode(),
|
||||
(PVOID *)&KeyObject,
|
||||
NULL);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT1 ("ObReferenceObjectByHandle() failed (Status %lx)\n", Status);
|
||||
return Status;
|
||||
}
|
||||
|
||||
/* Acquire hive lock exclucively */
|
||||
KeEnterCriticalRegion();
|
||||
ExAcquireResourceExclusiveLite(&CmiRegistryLock, TRUE);
|
||||
|
||||
/* Refuse to save a volatile key */
|
||||
if (KeyObject->KeyCell->Flags & REG_KEY_VOLATILE_CELL)
|
||||
{
|
||||
DPRINT1 ("Cannot save a volatile key\n");
|
||||
ExReleaseResourceLite(&CmiRegistryLock);
|
||||
KeLeaveCriticalRegion();
|
||||
ObDereferenceObject (KeyObject);
|
||||
return STATUS_ACCESS_DENIED;
|
||||
}
|
||||
|
||||
Status = CmiCreateTempHive(&TempHive);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT1 ("CmiCreateTempHive() failed (Status %lx)\n", Status);
|
||||
ExReleaseResourceLite(&CmiRegistryLock);
|
||||
KeLeaveCriticalRegion();
|
||||
ObDereferenceObject (KeyObject);
|
||||
return(Status);
|
||||
}
|
||||
|
||||
Status = CmiCopyKey (TempHive,
|
||||
NULL,
|
||||
KeyObject->RegistryHive,
|
||||
KeyObject->KeyCell);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT1 ("CmiCopyKey() failed (Status %lx)\n", Status);
|
||||
CmiRemoveRegistryHive (TempHive);
|
||||
ExReleaseResourceLite(&CmiRegistryLock);
|
||||
KeLeaveCriticalRegion();
|
||||
ObDereferenceObject (KeyObject);
|
||||
return(Status);
|
||||
}
|
||||
|
||||
Status = CmiSaveTempHive (TempHive,
|
||||
FileHandle);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT1 ("CmiSaveTempHive() failed (Status %lx)\n", Status);
|
||||
}
|
||||
|
||||
CmiRemoveRegistryHive (TempHive);
|
||||
|
||||
/* Release hive lock */
|
||||
ExReleaseResourceLite(&CmiRegistryLock);
|
||||
KeLeaveCriticalRegion();
|
||||
|
||||
ObDereferenceObject (KeyObject);
|
||||
|
||||
DPRINT ("NtSaveKey() done\n");
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* @unimplemented
|
||||
*/
|
||||
NTSTATUS
|
||||
STDCALL
|
||||
NtSaveKeyEx(
|
||||
IN HANDLE KeyHandle,
|
||||
IN HANDLE FileHandle,
|
||||
IN ULONG Flags // REG_STANDARD_FORMAT, etc..
|
||||
)
|
||||
{
|
||||
UNIMPLEMENTED;
|
||||
return STATUS_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
|
||||
NTSTATUS STDCALL
|
||||
NtSetInformationKey (IN HANDLE KeyHandle,
|
||||
IN KEY_SET_INFORMATION_CLASS KeyInformationClass,
|
||||
IN PVOID KeyInformation,
|
||||
IN ULONG KeyInformationLength)
|
||||
{
|
||||
PKEY_OBJECT KeyObject;
|
||||
NTSTATUS Status;
|
||||
REG_SET_INFORMATION_KEY_INFORMATION SetInformationKeyInfo;
|
||||
REG_POST_OPERATION_INFORMATION PostOperationInfo;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
/* Verify that the handle is valid and is a registry key */
|
||||
Status = ObReferenceObjectByHandle (KeyHandle,
|
||||
KEY_SET_VALUE,
|
||||
CmiKeyType,
|
||||
ExGetPreviousMode(),
|
||||
(PVOID *)&KeyObject,
|
||||
NULL);
|
||||
if (!NT_SUCCESS (Status))
|
||||
{
|
||||
DPRINT ("ObReferenceObjectByHandle() failed with status %x\n", Status);
|
||||
return Status;
|
||||
}
|
||||
|
||||
PostOperationInfo.Object = (PVOID)KeyObject;
|
||||
SetInformationKeyInfo.Object = (PVOID)KeyObject;
|
||||
SetInformationKeyInfo.KeySetInformationClass = KeyInformationClass;
|
||||
SetInformationKeyInfo.KeySetInformation = KeyInformation;
|
||||
SetInformationKeyInfo.KeySetInformationLength = KeyInformationLength;
|
||||
|
||||
Status = CmiCallRegisteredCallbacks(RegNtPreSetInformationKey, &SetInformationKeyInfo);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
PostOperationInfo.Status = Status;
|
||||
CmiCallRegisteredCallbacks(RegNtPostSetInformationKey, &PostOperationInfo);
|
||||
ObDereferenceObject (KeyObject);
|
||||
return Status;
|
||||
}
|
||||
|
||||
if (KeyInformationClass != KeyWriteTimeInformation)
|
||||
{
|
||||
Status = STATUS_INVALID_INFO_CLASS;
|
||||
}
|
||||
|
||||
else if (KeyInformationLength != sizeof (KEY_WRITE_TIME_INFORMATION))
|
||||
{
|
||||
Status = STATUS_INFO_LENGTH_MISMATCH;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Acquire hive lock */
|
||||
KeEnterCriticalRegion();
|
||||
ExAcquireResourceExclusiveLite(&CmiRegistryLock, TRUE);
|
||||
|
||||
VERIFY_KEY_OBJECT(KeyObject);
|
||||
|
||||
KeyObject->KeyCell->LastWriteTime.QuadPart =
|
||||
((PKEY_WRITE_TIME_INFORMATION)KeyInformation)->LastWriteTime.QuadPart;
|
||||
|
||||
HvMarkCellDirty (&KeyObject->RegistryHive->Hive,
|
||||
KeyObject->KeyCellOffset);
|
||||
|
||||
/* Release hive lock */
|
||||
ExReleaseResourceLite(&CmiRegistryLock);
|
||||
KeLeaveCriticalRegion();
|
||||
}
|
||||
|
||||
PostOperationInfo.Status = Status;
|
||||
CmiCallRegisteredCallbacks(RegNtPostSetInformationKey, &PostOperationInfo);
|
||||
|
||||
ObDereferenceObject (KeyObject);
|
||||
|
||||
if (NT_SUCCESS(Status))
|
||||
{
|
||||
CmiSyncHives ();
|
||||
}
|
||||
|
||||
DPRINT ("NtSaveKey() done\n");
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* NOTE:
|
||||
* KeyObjectAttributes->RootDirectory specifies the handle to the parent key and
|
||||
* KeyObjectAttributes->Name specifies the name of the key to unload.
|
||||
*/
|
||||
NTSTATUS STDCALL
|
||||
NtUnloadKey (IN POBJECT_ATTRIBUTES KeyObjectAttributes)
|
||||
{
|
||||
PEREGISTRY_HIVE RegistryHive;
|
||||
NTSTATUS Status;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
DPRINT ("NtUnloadKey() called\n");
|
||||
|
||||
#if 0
|
||||
if (!SeSinglePrivilegeCheck (SeRestorePrivilege, ExGetPreviousMode ()))
|
||||
return STATUS_PRIVILEGE_NOT_HELD;
|
||||
#endif
|
||||
|
||||
/* Acquire registry lock exclusively */
|
||||
KeEnterCriticalRegion();
|
||||
ExAcquireResourceExclusiveLite(&CmiRegistryLock, TRUE);
|
||||
|
||||
Status = CmiDisconnectHive (KeyObjectAttributes,
|
||||
&RegistryHive);
|
||||
if (!NT_SUCCESS (Status))
|
||||
{
|
||||
DPRINT1 ("CmiDisconnectHive() failed (Status %lx)\n", Status);
|
||||
ExReleaseResourceLite (&CmiRegistryLock);
|
||||
KeLeaveCriticalRegion();
|
||||
return Status;
|
||||
}
|
||||
|
||||
DPRINT ("RegistryHive %p\n", RegistryHive);
|
||||
|
||||
#if 0
|
||||
/* Flush hive */
|
||||
if (!IsNoFileHive (RegistryHive))
|
||||
CmiFlushRegistryHive (RegistryHive);
|
||||
#endif
|
||||
|
||||
CmiRemoveRegistryHive (RegistryHive);
|
||||
|
||||
/* Release registry lock */
|
||||
ExReleaseResourceLite (&CmiRegistryLock);
|
||||
KeLeaveCriticalRegion();
|
||||
|
||||
DPRINT ("NtUnloadKey() done\n");
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
NTSTATUS STDCALL
|
||||
NtInitializeRegistry (IN BOOLEAN SetUpBoot)
|
||||
{
|
||||
|
@ -2842,6 +2369,14 @@ NtCompressKey(IN HANDLE Key)
|
|||
return STATUS_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
NtLoadKey(IN POBJECT_ATTRIBUTES KeyObjectAttributes,
|
||||
IN POBJECT_ATTRIBUTES FileObjectAttributes)
|
||||
{
|
||||
return NtLoadKey2(KeyObjectAttributes, FileObjectAttributes, 0);
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
NtLoadKeyEx(IN POBJECT_ATTRIBUTES TargetKey,
|
||||
|
@ -2892,6 +2427,33 @@ NtNotifyChangeMultipleKeys(IN HANDLE MasterKeyHandle,
|
|||
return STATUS_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
NtNotifyChangeKey(IN HANDLE KeyHandle,
|
||||
IN HANDLE Event,
|
||||
IN PIO_APC_ROUTINE ApcRoutine OPTIONAL,
|
||||
IN PVOID ApcContext OPTIONAL,
|
||||
OUT PIO_STATUS_BLOCK IoStatusBlock,
|
||||
IN ULONG CompletionFilter,
|
||||
IN BOOLEAN WatchTree,
|
||||
OUT PVOID Buffer,
|
||||
IN ULONG Length,
|
||||
IN BOOLEAN Asynchronous)
|
||||
{
|
||||
return NtNotifyChangeMultipleKeys(KeyHandle,
|
||||
0,
|
||||
NULL,
|
||||
Event,
|
||||
ApcRoutine,
|
||||
ApcContext,
|
||||
IoStatusBlock,
|
||||
CompletionFilter,
|
||||
WatchTree,
|
||||
Buffer,
|
||||
Length,
|
||||
Asynchronous);
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
NtQueryOpenSubKeys(IN POBJECT_ATTRIBUTES TargetKey,
|
||||
|
@ -2912,6 +2474,45 @@ NtQueryOpenSubKeysEx(IN POBJECT_ATTRIBUTES TargetKey,
|
|||
return STATUS_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
NtReplaceKey(IN POBJECT_ATTRIBUTES ObjectAttributes,
|
||||
IN HANDLE Key,
|
||||
IN POBJECT_ATTRIBUTES ReplacedObjectAttributes)
|
||||
{
|
||||
UNIMPLEMENTED;
|
||||
return STATUS_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
NtRestoreKey(IN HANDLE KeyHandle,
|
||||
IN HANDLE FileHandle,
|
||||
IN ULONG RestoreFlags)
|
||||
{
|
||||
UNIMPLEMENTED;
|
||||
return STATUS_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
NtSaveKey(IN HANDLE KeyHandle,
|
||||
IN HANDLE FileHandle)
|
||||
{
|
||||
UNIMPLEMENTED;
|
||||
return STATUS_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
NtSaveKeyEx(IN HANDLE KeyHandle,
|
||||
IN HANDLE FileHandle,
|
||||
IN ULONG Flags)
|
||||
{
|
||||
UNIMPLEMENTED;
|
||||
return STATUS_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
NtSaveMergedKeys(IN HANDLE HighPrecedenceKeyHandle,
|
||||
|
@ -2922,6 +2523,25 @@ NtSaveMergedKeys(IN HANDLE HighPrecedenceKeyHandle,
|
|||
return STATUS_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
NtSetInformationKey(IN HANDLE KeyHandle,
|
||||
IN KEY_SET_INFORMATION_CLASS KeyInformationClass,
|
||||
IN PVOID KeyInformation,
|
||||
IN ULONG KeyInformationLength)
|
||||
{
|
||||
UNIMPLEMENTED;
|
||||
return STATUS_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
NtUnloadKey(IN POBJECT_ATTRIBUTES KeyObjectAttributes)
|
||||
{
|
||||
UNIMPLEMENTED;
|
||||
return STATUS_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
NtUnloadKey2(IN POBJECT_ATTRIBUTES TargetKey,
|
||||
|
|
|
@ -497,13 +497,6 @@ CmInitSystem1(VOID)
|
|||
BaseAddress = CmpRosGetHardwareHive(&Length);
|
||||
if (!CmImportHardwareHive(BaseAddress, Length, &HardwareHive))
|
||||
{
|
||||
/* Create dummy keys if no hardware hive was found */
|
||||
if (!CmImportHardwareHive (NULL, 0, &HardwareHive))
|
||||
{
|
||||
/* Bugcheck */
|
||||
KEBUGCHECKEX(CONFIG_INITIALIZATION_FAILED, 1, 11, Status, 0);
|
||||
}
|
||||
|
||||
/* Don't actually link anything below */
|
||||
Allocate = TRUE;
|
||||
}
|
||||
|
@ -687,108 +680,6 @@ CmiConnectHive(IN POBJECT_ATTRIBUTES KeyObjectAttributes,
|
|||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
NTSTATUS
|
||||
CmiDisconnectHive (IN POBJECT_ATTRIBUTES KeyObjectAttributes,
|
||||
OUT PEREGISTRY_HIVE *RegistryHive)
|
||||
{
|
||||
PKEY_OBJECT KeyObject;
|
||||
PEREGISTRY_HIVE Hive;
|
||||
HANDLE KeyHandle;
|
||||
NTSTATUS Status = STATUS_OBJECT_NAME_NOT_FOUND;
|
||||
PLIST_ENTRY CurrentEntry;
|
||||
PKEY_OBJECT CurrentKey;
|
||||
|
||||
DPRINT("CmiDisconnectHive() called\n");
|
||||
|
||||
*RegistryHive = NULL;
|
||||
|
||||
Status = ObOpenObjectByName (KeyObjectAttributes,
|
||||
CmiKeyType,
|
||||
KernelMode,
|
||||
NULL,
|
||||
STANDARD_RIGHTS_REQUIRED,
|
||||
NULL,
|
||||
&KeyHandle);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT1 ("ObOpenObjectByName() failed (Status %lx)\n", Status);
|
||||
return Status;
|
||||
}
|
||||
|
||||
Status = ObReferenceObjectByHandle (KeyHandle,
|
||||
STANDARD_RIGHTS_REQUIRED,
|
||||
CmiKeyType,
|
||||
KernelMode,
|
||||
(PVOID*)&KeyObject,
|
||||
NULL);
|
||||
ZwClose (KeyHandle);
|
||||
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT1 ("ObReferenceObjectByName() failed (Status %lx)\n", Status);
|
||||
return Status;
|
||||
}
|
||||
DPRINT ("KeyObject %p Hive %p\n", KeyObject, KeyObject->RegistryHive);
|
||||
|
||||
/* Acquire registry lock exclusively */
|
||||
KeEnterCriticalRegion();
|
||||
ExAcquireResourceExclusiveLite(&CmiRegistryLock, TRUE);
|
||||
|
||||
Hive = KeyObject->RegistryHive;
|
||||
|
||||
CurrentEntry = CmiKeyObjectListHead.Flink;
|
||||
while (CurrentEntry != &CmiKeyObjectListHead)
|
||||
{
|
||||
CurrentKey = CONTAINING_RECORD(CurrentEntry, KEY_OBJECT, ListEntry);
|
||||
if (CurrentKey->RegistryHive == Hive &&
|
||||
1 == ObGetObjectPointerCount(CurrentKey) &&
|
||||
!(CurrentKey->Flags & KO_MARKED_FOR_DELETE))
|
||||
{
|
||||
ObDereferenceObject(CurrentKey);
|
||||
CurrentEntry = CmiKeyObjectListHead.Flink;
|
||||
}
|
||||
else
|
||||
{
|
||||
CurrentEntry = CurrentEntry->Flink;
|
||||
}
|
||||
}
|
||||
|
||||
/* FN1 */
|
||||
ObDereferenceObject (KeyObject);
|
||||
|
||||
if (ObGetObjectHandleCount (KeyObject) != 0 ||
|
||||
ObGetObjectPointerCount (KeyObject) != 2)
|
||||
{
|
||||
DPRINT1 ("Hive is still in use (hc %d, rc %d)\n", ObGetObjectHandleCount (KeyObject), ObGetObjectPointerCount (KeyObject));
|
||||
ObDereferenceObject (KeyObject);
|
||||
|
||||
/* Release registry lock */
|
||||
ExReleaseResourceLite (&CmiRegistryLock);
|
||||
KeLeaveCriticalRegion();
|
||||
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
/* Dereference KeyObject twice to delete it */
|
||||
ObDereferenceObject (KeyObject);
|
||||
ObDereferenceObject (KeyObject);
|
||||
|
||||
*RegistryHive = Hive;
|
||||
|
||||
/* Release registry lock */
|
||||
ExReleaseResourceLite (&CmiRegistryLock);
|
||||
KeLeaveCriticalRegion();
|
||||
|
||||
/* Release reference above */
|
||||
ObDereferenceObject (KeyObject);
|
||||
|
||||
DPRINT ("CmiDisconnectHive() done\n");
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
|
||||
static NTSTATUS
|
||||
CmiInitControlSetLink (VOID)
|
||||
{
|
||||
|
|
173
reactos/ntoskrnl/config/cmhook.c
Normal file
173
reactos/ntoskrnl/config/cmhook.c
Normal file
|
@ -0,0 +1,173 @@
|
|||
/*
|
||||
* PROJECT: ReactOS Kernel
|
||||
* LICENSE: GPL - See COPYING in the top level directory
|
||||
* FILE: ntoskrnl/config/cmhook.c
|
||||
* PURPOSE: Configuration Manager - Registry Notifications/Callbacks
|
||||
* PROGRAMMERS: Thomas Weidenmueller (w3seek@reactos.org)
|
||||
*/
|
||||
|
||||
/* INCLUDES ******************************************************************/
|
||||
|
||||
#include "ntoskrnl.h"
|
||||
#include "cm.h"
|
||||
#define NDEBUG
|
||||
#include "debug.h"
|
||||
|
||||
/* GLOBALS *******************************************************************/
|
||||
|
||||
LIST_ENTRY CmiCallbackHead;
|
||||
FAST_MUTEX CmiCallbackLock;
|
||||
|
||||
typedef struct _REGISTRY_CALLBACK
|
||||
{
|
||||
LIST_ENTRY ListEntry;
|
||||
EX_RUNDOWN_REF RundownRef;
|
||||
PEX_CALLBACK_FUNCTION Function;
|
||||
PVOID Context;
|
||||
LARGE_INTEGER Cookie;
|
||||
BOOLEAN PendingDelete;
|
||||
} REGISTRY_CALLBACK, *PREGISTRY_CALLBACK;
|
||||
|
||||
/* PRIVATE FUNCTIONS *********************************************************/
|
||||
|
||||
NTSTATUS
|
||||
CmiCallRegisteredCallbacks(IN REG_NOTIFY_CLASS Argument1,
|
||||
IN PVOID Argument2)
|
||||
{
|
||||
PLIST_ENTRY CurrentEntry;
|
||||
NTSTATUS Status = STATUS_SUCCESS;
|
||||
PREGISTRY_CALLBACK CurrentCallback;
|
||||
PAGED_CODE();
|
||||
|
||||
ExAcquireFastMutex(&CmiCallbackLock);
|
||||
|
||||
for (CurrentEntry = CmiCallbackHead.Flink;
|
||||
CurrentEntry != &CmiCallbackHead;
|
||||
CurrentEntry = CurrentEntry->Flink)
|
||||
{
|
||||
CurrentCallback = CONTAINING_RECORD(CurrentEntry, REGISTRY_CALLBACK, ListEntry);
|
||||
if (!CurrentCallback->PendingDelete &&
|
||||
ExAcquireRundownProtection(&CurrentCallback->RundownRef))
|
||||
{
|
||||
/* don't hold locks during the callbacks! */
|
||||
ExReleaseFastMutex(&CmiCallbackLock);
|
||||
|
||||
Status = CurrentCallback->Function(CurrentCallback->Context,
|
||||
(PVOID)Argument1,
|
||||
Argument2);
|
||||
|
||||
ExAcquireFastMutex(&CmiCallbackLock);
|
||||
|
||||
/* don't release the rundown protection before holding the callback lock
|
||||
so the pointer to the next callback isn't cleared in case this callback
|
||||
get's deleted */
|
||||
ExReleaseRundownProtection(&CurrentCallback->RundownRef);
|
||||
if(!NT_SUCCESS(Status))
|
||||
{
|
||||
/* one callback returned failure, don't call any more callbacks */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ExReleaseFastMutex(&CmiCallbackLock);
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
/* PUBLIC FUNCTIONS **********************************************************/
|
||||
|
||||
/*
|
||||
* @implemented
|
||||
*/
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
CmRegisterCallback(IN PEX_CALLBACK_FUNCTION Function,
|
||||
IN PVOID Context,
|
||||
IN OUT PLARGE_INTEGER Cookie)
|
||||
{
|
||||
PREGISTRY_CALLBACK Callback;
|
||||
PAGED_CODE();
|
||||
ASSERT(Function && Cookie);
|
||||
|
||||
Callback = ExAllocatePoolWithTag(PagedPool,
|
||||
sizeof(REGISTRY_CALLBACK),
|
||||
TAG('C', 'M', 'c', 'b'));
|
||||
if (Callback != NULL)
|
||||
{
|
||||
/* initialize the callback */
|
||||
ExInitializeRundownProtection(&Callback->RundownRef);
|
||||
Callback->Function = Function;
|
||||
Callback->Context = Context;
|
||||
Callback->PendingDelete = FALSE;
|
||||
|
||||
/* add it to the callback list and receive a cookie for the callback */
|
||||
ExAcquireFastMutex(&CmiCallbackLock);
|
||||
|
||||
/* FIXME - to receive a unique cookie we'll just return the pointer to the
|
||||
callback object */
|
||||
Callback->Cookie.QuadPart = (ULONG_PTR)Callback;
|
||||
InsertTailList(&CmiCallbackHead, &Callback->ListEntry);
|
||||
|
||||
ExReleaseFastMutex(&CmiCallbackLock);
|
||||
|
||||
*Cookie = Callback->Cookie;
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
|
||||
/*
|
||||
* @implemented
|
||||
*/
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
CmUnRegisterCallback(IN LARGE_INTEGER Cookie)
|
||||
{
|
||||
PLIST_ENTRY CurrentEntry;
|
||||
PREGISTRY_CALLBACK CurrentCallback;
|
||||
PAGED_CODE();
|
||||
|
||||
ExAcquireFastMutex(&CmiCallbackLock);
|
||||
|
||||
for (CurrentEntry = CmiCallbackHead.Flink;
|
||||
CurrentEntry != &CmiCallbackHead;
|
||||
CurrentEntry = CurrentEntry->Flink)
|
||||
{
|
||||
CurrentCallback = CONTAINING_RECORD(CurrentEntry, REGISTRY_CALLBACK, ListEntry);
|
||||
if (CurrentCallback->Cookie.QuadPart == Cookie.QuadPart)
|
||||
{
|
||||
if (!CurrentCallback->PendingDelete)
|
||||
{
|
||||
/* found the callback, don't unlink it from the list yet so we don't screw
|
||||
the calling loop */
|
||||
CurrentCallback->PendingDelete = TRUE;
|
||||
ExReleaseFastMutex(&CmiCallbackLock);
|
||||
|
||||
/* if the callback is currently executing, wait until it finished */
|
||||
ExWaitForRundownProtectionRelease(&CurrentCallback->RundownRef);
|
||||
|
||||
/* time to unlink it. It's now safe because every attempt to acquire a
|
||||
runtime protection on this callback will fail */
|
||||
ExAcquireFastMutex(&CmiCallbackLock);
|
||||
RemoveEntryList(&CurrentCallback->ListEntry);
|
||||
ExReleaseFastMutex(&CmiCallbackLock);
|
||||
|
||||
/* free the callback */
|
||||
ExFreePool(CurrentCallback);
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* pending delete, pretend like it already is deleted */
|
||||
ExReleaseFastMutex(&CmiCallbackLock);
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ExReleaseFastMutex(&CmiCallbackLock);
|
||||
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
}
|
|
@ -88,6 +88,7 @@
|
|||
<file>cmcontrl.c</file>
|
||||
<file>cmdata.c</file>
|
||||
<file>cmindex.c</file>
|
||||
<file>cmhook.c</file>
|
||||
<file>cmmapvw.c</file>
|
||||
<file>cmname.c</file>
|
||||
<file>cmparse.c</file>
|
||||
|
|
Loading…
Reference in a new issue