[NTOSKRNL]
[reactos.git] / reactos / ntoskrnl / config / ntapi.c
index e8c455c..0e76f7c 100644 (file)
  * FILE:            ntoskrnl/config/cmapi.c
  * PURPOSE:         Configuration Manager - Internal Registry APIs
  * PROGRAMMERS:     Alex Ionescu (alex.ionescu@reactos.org)
+ *                  Eric Kohl
  */
 
 /* INCLUDES ******************************************************************/
 
 #include "ntoskrnl.h"
-#include "cm.h"
 #define NDEBUG
 #include "debug.h"
 
+BOOLEAN CmBootAcceptFirstTime = TRUE;
+BOOLEAN CmFirstTime = TRUE;
+
 /* FUNCTIONS *****************************************************************/
 
+NTSTATUS
+NTAPI
+NtCreateKey(OUT PHANDLE KeyHandle,
+            IN ACCESS_MASK DesiredAccess,
+            IN POBJECT_ATTRIBUTES ObjectAttributes,
+            IN ULONG TitleIndex,
+            IN PUNICODE_STRING Class OPTIONAL,
+            IN ULONG CreateOptions,
+            OUT PULONG Disposition OPTIONAL)
+{
+    NTSTATUS Status;
+    KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
+    CM_PARSE_CONTEXT ParseContext = {0};
+    HANDLE Handle;
+    PAGED_CODE();
+    DPRINT("NtCreateKey(OB name %wZ)\n", ObjectAttributes->ObjectName);
+
+    /* Check for user-mode caller */
+    if (PreviousMode != KernelMode)
+    {
+        /* Prepare to probe parameters */
+        _SEH2_TRY
+        {
+            /* Check if we have a class */
+            if (Class)
+            {
+                /* Probe it */
+                ParseContext.Class = ProbeForReadUnicodeString(Class);
+                ProbeForRead(ParseContext.Class.Buffer,
+                             ParseContext.Class.Length,
+                             sizeof(WCHAR));
+            }
+
+            /* Probe the key handle */
+            ProbeForWriteHandle(KeyHandle);
+            *KeyHandle = NULL;
+
+            /* Probe object attributes */
+            ProbeForRead(ObjectAttributes,
+                         sizeof(OBJECT_ATTRIBUTES),
+                         sizeof(ULONG));
+
+            if (Disposition) ProbeForWriteUlong(Disposition);
+        }
+        _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+        {
+            /* Return the exception code */
+            _SEH2_YIELD(return _SEH2_GetExceptionCode());
+        }
+        _SEH2_END;
+    }
+    else
+    {
+        /* Save the class directly */
+        if (Class) ParseContext.Class = *Class;
+    }
+
+    /* Setup the parse context */
+    ParseContext.CreateOperation = TRUE;
+    ParseContext.CreateOptions = CreateOptions;
+
+    /* Do the create */
+    Status = ObOpenObjectByName(ObjectAttributes,
+                                CmpKeyObjectType,
+                                PreviousMode,
+                                NULL,
+                                DesiredAccess,
+                                &ParseContext,
+                                &Handle);
+
+    _SEH2_TRY
+    {
+        /* Return data to user */
+        if (NT_SUCCESS(Status)) *KeyHandle = Handle;
+        if (Disposition) *Disposition = ParseContext.Disposition;
+    }
+    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+    {
+        /* Get the status */
+        Status = _SEH2_GetExceptionCode();
+    }
+    _SEH2_END;
+
+    /* Return status */
+    return Status;
+}
+
+NTSTATUS
+NTAPI
+NtOpenKey(OUT PHANDLE KeyHandle,
+          IN ACCESS_MASK DesiredAccess,
+          IN POBJECT_ATTRIBUTES ObjectAttributes)
+{
+    CM_PARSE_CONTEXT ParseContext = {0};
+    HANDLE Handle;
+    NTSTATUS Status;
+    KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
+    PAGED_CODE();
+    DPRINT("NtOpenKey(OB 0x%wZ)\n", ObjectAttributes->ObjectName);
+
+    /* Check for user-mode caller */
+    if (PreviousMode != KernelMode)
+    {
+        /* Prepare to probe parameters */
+        _SEH2_TRY
+        {
+            /* Probe the key handle */
+            ProbeForWriteHandle(KeyHandle);
+            *KeyHandle = NULL;
+
+            /* Probe object attributes */
+            ProbeForRead(ObjectAttributes,
+                         sizeof(OBJECT_ATTRIBUTES),
+                         sizeof(ULONG));
+        }
+        _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+        {
+            /* Return the exception code */
+            _SEH2_YIELD(return _SEH2_GetExceptionCode());
+        }
+        _SEH2_END;
+    }
+
+    /* Just let the object manager handle this */
+    Status = ObOpenObjectByName(ObjectAttributes,
+                                CmpKeyObjectType,
+                                ExGetPreviousMode(),
+                                NULL,
+                                DesiredAccess,
+                                &ParseContext,
+                                &Handle);
+
+    /* Only do this if we succeeded */
+    if (NT_SUCCESS(Status))
+    {
+        _SEH2_TRY
+        {
+            /* Return the handle to caller */
+            *KeyHandle = Handle;
+        }
+        _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+        {
+            /* Get the status */
+            Status = _SEH2_GetExceptionCode();
+        }
+        _SEH2_END;
+    }
+
+    /* Return status */
+    return Status;
+}
+
+
 NTSTATUS
 NTAPI
 NtDeleteKey(IN HANDLE KeyHandle)
 {
-    PKEY_OBJECT KeyObject;
+    PCM_KEY_BODY KeyObject;
     NTSTATUS Status;
     REG_DELETE_KEY_INFORMATION DeleteKeyInfo;
     REG_POST_OPERATION_INFORMATION PostOperationInfo;
     PAGED_CODE();
-
     DPRINT("NtDeleteKey(KH 0x%p)\n", KeyHandle);
 
     /* Verify that the handle is valid and is a registry key */
@@ -32,13 +187,9 @@ NtDeleteKey(IN HANDLE KeyHandle)
                                        DELETE,
                                        CmpKeyObjectType,
                                        ExGetPreviousMode(),
-                                       (PVOID *)&KeyObject,
+                                       (PVOID*)&KeyObject,
                                        NULL);
-    if (!NT_SUCCESS(Status))
-    {
-        DPRINT("ObReferenceObjectByHandle() failed with Status = 0x%08X\n");
-        return Status;
-    }
+    if (!NT_SUCCESS(Status)) return Status;
 
     /* Setup the callback */
     PostOperationInfo.Object = (PVOID)KeyObject;
@@ -46,16 +197,17 @@ NtDeleteKey(IN HANDLE KeyHandle)
     Status = CmiCallRegisteredCallbacks(RegNtPreDeleteKey, &DeleteKeyInfo);
     if (NT_SUCCESS(Status))
     {
-        /* Call the internal API */
-        Status = CmDeleteKey(KeyObject->KeyControlBlock);
-
-        /* Remove the keep-alive reference */
-        ObDereferenceObject(KeyObject);
-        if (KeyObject->KeyControlBlock->KeyHive !=
-            KeyObject->KeyControlBlock->ParentKcb->KeyHive)
+        /* Check if we are read-only */
+        if ((KeyObject->KeyControlBlock->ExtFlags & CM_KCB_READ_ONLY_KEY) ||
+            (KeyObject->KeyControlBlock->ParentKcb->ExtFlags & CM_KCB_READ_ONLY_KEY))
         {
-            /* Dereference again */
-            ObDereferenceObject(KeyObject);
+            /* Fail */
+            Status = STATUS_ACCESS_DENIED;
+        }
+        else
+        {
+            /* Call the internal API */
+            Status = CmDeleteKey(KeyObject);
         }
 
         /* Do post callback */
@@ -77,26 +229,49 @@ NtEnumerateKey(IN HANDLE KeyHandle,
                IN ULONG Length,
                OUT PULONG ResultLength)
 {
+    KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
     NTSTATUS Status;
-    PKEY_OBJECT KeyObject;
+    PCM_KEY_BODY KeyObject;
     REG_ENUMERATE_KEY_INFORMATION EnumerateKeyInfo;
     REG_POST_OPERATION_INFORMATION PostOperationInfo;
     PAGED_CODE();
-
     DPRINT("NtEnumerateKey() KH 0x%x, Index 0x%x, KIC %d, Length %d\n",
-        KeyHandle, Index, KeyInformationClass, Length);
+           KeyHandle, Index, KeyInformationClass, Length);
+
+    /* Reject classes we don't know about */
+    if ((KeyInformationClass != KeyBasicInformation) &&
+        (KeyInformationClass != KeyNodeInformation)  &&
+        (KeyInformationClass != KeyFullInformation))
+    {
+        /* Fail */
+        return STATUS_INVALID_PARAMETER;
+    }
 
     /* Verify that the handle is valid and is a registry key */
     Status = ObReferenceObjectByHandle(KeyHandle,
                                        KEY_ENUMERATE_SUB_KEYS,
                                        CmpKeyObjectType,
                                        ExGetPreviousMode(),
-                                       (PVOID *)&KeyObject,
+                                       (PVOID*)&KeyObject,
                                        NULL);
-    if (!NT_SUCCESS(Status))
+    if (!NT_SUCCESS(Status)) return Status;
+
+    if (PreviousMode != KernelMode)
     {
-        DPRINT("ObReferenceObjectByHandle() failed with Status = 0x%08X\n");
-        return Status;
+        _SEH2_TRY
+        {
+            ProbeForWriteUlong(ResultLength);
+            ProbeForWrite(KeyInformation,
+                          Length,
+                          sizeof(ULONG));
+        }
+        _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+        {
+            /* Dereference and return status */
+            ObDereferenceObject(KeyObject);
+            _SEH2_YIELD(return _SEH2_GetExceptionCode());
+        }
+        _SEH2_END;
     }
 
     /* Setup the callback */
@@ -138,26 +313,49 @@ NtEnumerateValueKey(IN HANDLE KeyHandle,
                     IN ULONG Length,
                     OUT PULONG ResultLength)
 {
+    KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
     NTSTATUS Status;
-    PKEY_OBJECT KeyObject;
+    PCM_KEY_BODY KeyObject;
     REG_ENUMERATE_VALUE_KEY_INFORMATION EnumerateValueKeyInfo;
     REG_POST_OPERATION_INFORMATION PostOperationInfo;
     PAGED_CODE();
-
     DPRINT("NtEnumerateValueKey() KH 0x%x, Index 0x%x, KVIC %d, Length %d\n",
-        KeyHandle, Index, KeyValueInformationClass, Length);
+           KeyHandle, Index, KeyValueInformationClass, Length);
+
+    /* Reject classes we don't know about */
+    if ((KeyValueInformationClass != KeyValueBasicInformation) &&
+        (KeyValueInformationClass != KeyValueFullInformation)  &&
+        (KeyValueInformationClass != KeyValuePartialInformation))
+    {
+        /* Fail */
+        return STATUS_INVALID_PARAMETER;
+    }
 
     /* Verify that the handle is valid and is a registry key */
     Status = ObReferenceObjectByHandle(KeyHandle,
                                        KEY_QUERY_VALUE,
                                        CmpKeyObjectType,
                                        ExGetPreviousMode(),
-                                       (PVOID *)&KeyObject,
+                                       (PVOID*)&KeyObject,
                                        NULL);
-    if (!NT_SUCCESS(Status))
+    if (!NT_SUCCESS(Status)) return Status;
+
+    if (PreviousMode != KernelMode)
     {
-        DPRINT("ObReferenceObjectByHandle() failed with Status = 0x%08X\n");
-        return Status;
+        _SEH2_TRY
+        {
+            ProbeForWriteUlong(ResultLength);
+            ProbeForWrite(KeyValueInformation,
+                          Length,
+                          sizeof(ULONG));
+        }
+        _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+        {
+            /* Dereference and return status */
+            ObDereferenceObject(KeyObject);
+            _SEH2_YIELD(return _SEH2_GetExceptionCode());
+        }
+        _SEH2_END;
     }
 
     /* Setup the callback */
@@ -199,28 +397,79 @@ NtQueryKey(IN HANDLE KeyHandle,
            IN ULONG Length,
            OUT PULONG ResultLength)
 {
+    KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
     NTSTATUS Status;
-    PKEY_OBJECT KeyObject;
+    PCM_KEY_BODY KeyObject;
     REG_QUERY_KEY_INFORMATION QueryKeyInfo;
     REG_POST_OPERATION_INFORMATION PostOperationInfo;
+    OBJECT_HANDLE_INFORMATION HandleInfo;
     PAGED_CODE();
-
     DPRINT("NtQueryKey() KH 0x%x, KIC %d, Length %d\n",
-        KeyHandle, KeyInformationClass, Length);
+           KeyHandle, KeyInformationClass, Length);
+
+    /* Reject invalid classes */
+    if ((KeyInformationClass != KeyBasicInformation) &&
+        (KeyInformationClass != KeyNodeInformation)  &&
+        (KeyInformationClass != KeyFullInformation)  &&
+        (KeyInformationClass != KeyNameInformation) &&
+        (KeyInformationClass != KeyCachedInformation) &&
+        (KeyInformationClass != KeyFlagsInformation))
+    {
+        /* Fail */
+        return STATUS_INVALID_PARAMETER;
+    }
 
-    /* Verify that the handle is valid and is a registry key */
-    Status = ObReferenceObjectByHandle(KeyHandle,
-                                       (KeyInformationClass !=
-                                        KeyNameInformation) ?
-                                       KEY_QUERY_VALUE : 0,
-                                       CmpKeyObjectType,
-                                       ExGetPreviousMode(),
-                                       (PVOID *)&KeyObject,
-                                       NULL);
-    if (!NT_SUCCESS(Status))
+    /* Check if just the name is required */
+    if (KeyInformationClass == KeyNameInformation)
     {
-        DPRINT("ObReferenceObjectByHandle() failed with Status = 0x%08X\n");
-        return Status;
+        /* Ignore access level */
+        Status = ObReferenceObjectByHandle(KeyHandle,
+                                           0,
+                                           CmpKeyObjectType,
+                                           ExGetPreviousMode(),
+                                           (PVOID*)&KeyObject,
+                                           &HandleInfo);
+        if (NT_SUCCESS(Status))
+        {
+            /* At least a single bit of access is required */
+            if (!HandleInfo.GrantedAccess)
+            {
+                /* No such luck */
+                ObDereferenceObject(KeyObject);
+                Status = STATUS_ACCESS_DENIED;
+            }
+        }
+    }
+    else
+    {
+        /* Get a reference */
+        Status = ObReferenceObjectByHandle(KeyHandle,
+                                           KEY_QUERY_VALUE,
+                                           CmpKeyObjectType,
+                                           ExGetPreviousMode(),
+                                           (PVOID*)&KeyObject,
+                                           NULL);
+    }
+
+    /* Quit on failure */
+    if (!NT_SUCCESS(Status)) return Status;
+
+    if (PreviousMode != KernelMode)
+    {
+        _SEH2_TRY
+        {
+            ProbeForWriteUlong(ResultLength);
+            ProbeForWrite(KeyInformation,
+                          Length,
+                          sizeof(ULONG));
+        }
+        _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+        {
+            /* Dereference and return status */
+            ObDereferenceObject(KeyObject);
+            _SEH2_YIELD(return _SEH2_GetExceptionCode());
+        }
+        _SEH2_END;
     }
 
     /* Setup the callback */
@@ -261,12 +510,13 @@ NtQueryValueKey(IN HANDLE KeyHandle,
                 IN ULONG Length,
                 OUT PULONG ResultLength)
 {
+    KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
     NTSTATUS Status;
-    PKEY_OBJECT KeyObject;
+    PCM_KEY_BODY KeyObject;
     REG_QUERY_VALUE_KEY_INFORMATION QueryValueKeyInfo;
     REG_POST_OPERATION_INFORMATION PostOperationInfo;
+    UNICODE_STRING ValueNameCopy = *ValueName;
     PAGED_CODE();
-
     DPRINT("NtQueryValueKey() KH 0x%x, VN '%wZ', KVIC %d, Length %d\n",
         KeyHandle, ValueName, KeyValueInformationClass, Length);
 
@@ -275,18 +525,50 @@ NtQueryValueKey(IN HANDLE KeyHandle,
                                        KEY_QUERY_VALUE,
                                        CmpKeyObjectType,
                                        ExGetPreviousMode(),
-                                       (PVOID *)&KeyObject,
+                                       (PVOID*)&KeyObject,
                                        NULL);
-    if (!NT_SUCCESS(Status))
+    if (!NT_SUCCESS(Status)) return Status;
+
+    if (PreviousMode != KernelMode)
     {
-        DPRINT("ObReferenceObjectByHandle() failed with Status = 0x%08X\n");
-        return Status;
+        _SEH2_TRY
+        {
+            ProbeForWriteUlong(ResultLength);
+            ProbeForWrite(KeyValueInformation,
+                          Length,
+                          sizeof(ULONG));
+        }
+        _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+        {
+            /* Dereference and return status */
+            ObDereferenceObject(KeyObject);
+            _SEH2_YIELD(return _SEH2_GetExceptionCode());
+        }
+        _SEH2_END;
+    }
+
+    /* Make sure the name is aligned properly */
+    if ((ValueNameCopy.Length & (sizeof(WCHAR) - 1)))
+    {
+        /* It isn't, so we'll fail */
+        ObDereferenceObject(KeyObject);
+        return STATUS_INVALID_PARAMETER;
+    }
+    else
+    {
+        /* Ignore any null characters at the end */
+        while ((ValueNameCopy.Length) &&
+               !(ValueNameCopy.Buffer[ValueNameCopy.Length / sizeof(WCHAR) - 1]))
+        {
+            /* Skip it */
+            ValueNameCopy.Length -= sizeof(WCHAR);
+        }
     }
 
     /* Setup the callback */
     PostOperationInfo.Object = (PVOID)KeyObject;
     QueryValueKeyInfo.Object = (PVOID)KeyObject;
-    QueryValueKeyInfo.ValueName = ValueName;
+    QueryValueKeyInfo.ValueName = &ValueNameCopy;
     QueryValueKeyInfo.KeyValueInformationClass = KeyValueInformationClass;
     QueryValueKeyInfo.Length = Length;
     QueryValueKeyInfo.ResultLength = ResultLength;
@@ -297,7 +579,7 @@ NtQueryValueKey(IN HANDLE KeyHandle,
     {
         /* Call the internal API */
         Status = CmQueryValueKey(KeyObject->KeyControlBlock,
-                                 *ValueName,
+                                 ValueNameCopy,
                                  KeyValueInformationClass,
                                  KeyValueInformation,
                                  Length,
@@ -308,8 +590,6 @@ NtQueryValueKey(IN HANDLE KeyHandle,
         CmiCallRegisteredCallbacks(RegNtPostQueryValueKey, &PostOperationInfo);
     }
 
-    DPRINT("NtQueryValueKey() returning 0x%08X\n", Status);
-
     /* Dereference and return status */
     ObDereferenceObject(KeyObject);
     return Status;
@@ -325,11 +605,11 @@ NtSetValueKey(IN HANDLE KeyHandle,
               IN ULONG DataSize)
 {
     NTSTATUS Status;
-    PKEY_OBJECT KeyObject;
+    PCM_KEY_BODY KeyObject;
     REG_SET_VALUE_KEY_INFORMATION SetValueKeyInfo;
     REG_POST_OPERATION_INFORMATION PostOperationInfo;
+    UNICODE_STRING ValueNameCopy = *ValueName;
     PAGED_CODE();
-
     DPRINT("NtSetValueKey() KH 0x%x, VN '%wZ', TI %x, T %d, DS %d\n",
         KeyHandle, ValueName, TitleIndex, Type, DataSize);
 
@@ -338,12 +618,34 @@ NtSetValueKey(IN HANDLE KeyHandle,
                                        KEY_SET_VALUE,
                                        CmpKeyObjectType,
                                        ExGetPreviousMode(),
-                                       (PVOID *)&KeyObject,
+                                       (PVOID*)&KeyObject,
                                        NULL);
-    if (!NT_SUCCESS(Status))
+    if (!NT_SUCCESS(Status)) return Status;
+
+    /* Make sure the name is aligned, not too long, and the data under 4GB */
+    if ( (ValueNameCopy.Length > 32767) ||
+         ((ValueNameCopy.Length & (sizeof(WCHAR) - 1))) ||
+         (DataSize > 0x80000000))
     {
-        DPRINT1("ObReferenceObjectByHandle() failed with Status = 0x%08X\n", Status);
-        return Status;
+        /* Fail */
+        ObDereferenceObject(KeyObject);
+        return STATUS_INVALID_PARAMETER;
+    }
+
+    /* Ignore any null characters at the end */
+    while ((ValueNameCopy.Length) &&
+           !(ValueNameCopy.Buffer[ValueNameCopy.Length / sizeof(WCHAR) - 1]))
+    {
+        /* Skip it */
+        ValueNameCopy.Length -= sizeof(WCHAR);
+    }
+
+    /* Don't touch read-only keys */
+    if (KeyObject->KeyControlBlock->ExtFlags & CM_KCB_READ_ONLY_KEY)
+    {
+        /* Fail */
+        ObDereferenceObject(KeyObject);
+        return STATUS_ACCESS_DENIED;
     }
 
     /* Setup callback */
@@ -358,22 +660,21 @@ NtSetValueKey(IN HANDLE KeyHandle,
     /* Do the callback */
     Status = CmiCallRegisteredCallbacks(RegNtPreSetValueKey, &SetValueKeyInfo);
     if (NT_SUCCESS(Status))
-    {        
+    {
         /* Call the internal API */
         Status = CmSetValueKey(KeyObject->KeyControlBlock,
-                               ValueName,
+                               &ValueNameCopy,
                                Type,
                                Data,
                                DataSize);
     }
 
-    /* Do the post-callback and de-reference the key object */
+    /* Do the post-callback */
     PostOperationInfo.Status = Status;
     CmiCallRegisteredCallbacks(RegNtPostSetValueKey, &PostOperationInfo);
-    ObDereferenceObject(KeyObject);
 
-    /* Synchronize the hives and return */
-    CmpLazyFlush();
+    /* Dereference and return status */
+    ObDereferenceObject(KeyObject);
     return Status;
 }
 
@@ -382,11 +683,12 @@ NTAPI
 NtDeleteValueKey(IN HANDLE KeyHandle,
                  IN PUNICODE_STRING ValueName)
 {
-    PKEY_OBJECT KeyObject;
+    PCM_KEY_BODY KeyObject;
     NTSTATUS Status;
     REG_DELETE_VALUE_KEY_INFORMATION DeleteValueKeyInfo;
     REG_POST_OPERATION_INFORMATION PostOperationInfo;
     KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
+    UNICODE_STRING ValueNameCopy = *ValueName;
     PAGED_CODE();
 
     /* Verify that the handle is valid and is a registry key */
@@ -396,10 +698,22 @@ NtDeleteValueKey(IN HANDLE KeyHandle,
                                        PreviousMode,
                                        (PVOID *)&KeyObject,
                                        NULL);
-    if (!NT_SUCCESS(Status))
+    if (!NT_SUCCESS(Status)) return Status;
+
+    /* Don't touch read-only keys */
+    if (KeyObject->KeyControlBlock->ExtFlags & CM_KCB_READ_ONLY_KEY)
     {
-        DPRINT("ObReferenceObjectByHandle() failed with Status = 0x%08X\n");
-        return Status;
+        /* Fail */
+        ObDereferenceObject(KeyObject);
+        return STATUS_ACCESS_DENIED;
+    }
+
+    /* Make sure the name is aligned properly */
+    if ((ValueNameCopy.Length & (sizeof(WCHAR) - 1)))
+    {
+        /* It isn't, so we'll fail */
+        ObDereferenceObject(KeyObject);
+        return STATUS_INVALID_PARAMETER;
     }
 
     /* Do the callback */
@@ -410,7 +724,7 @@ NtDeleteValueKey(IN HANDLE KeyHandle,
     if (NT_SUCCESS(Status))
     {
         /* Call the internal API */
-        Status = CmDeleteValueKey(KeyObject->KeyControlBlock, *ValueName);
+        Status = CmDeleteValueKey(KeyObject->KeyControlBlock, ValueNameCopy);
 
         /* Do the post callback */
         PostOperationInfo.Object = (PVOID)KeyObject;
@@ -419,9 +733,8 @@ NtDeleteValueKey(IN HANDLE KeyHandle,
                                    &PostOperationInfo);
     }
 
-    /* Dereference the key body and synchronize the hives */
+    /* Dereference the key body */
     ObDereferenceObject(KeyObject);
-    CmpLazyFlush();
     return Status;
 }
 
@@ -430,9 +743,9 @@ NTAPI
 NtFlushKey(IN HANDLE KeyHandle)
 {
     NTSTATUS Status;
-    PKEY_OBJECT KeyObject;
+    PCM_KEY_BODY KeyObject;
     PAGED_CODE();
-    
+
     /* Get the key object */
     Status = ObReferenceObjectByHandle(KeyHandle,
                                        0,
@@ -441,11 +754,13 @@ NtFlushKey(IN HANDLE KeyHandle)
                                        (PVOID*)&KeyObject,
                                        NULL);
     if (!NT_SUCCESS(Status)) return Status;
-    
+
     /* Lock the registry */
-    KeEnterCriticalRegion();
-    ExAcquireResourceExclusiveLite(&CmpRegistryLock, TRUE);
-    
+    CmpLockRegistry();
+
+    /* Lock the KCB */
+    CmpAcquireKcbLockShared(KeyObject->KeyControlBlock);
+
     /* Make sure KCB isn't deleted */
     if (KeyObject->KeyControlBlock->Delete)
     {
@@ -457,39 +772,23 @@ NtFlushKey(IN HANDLE KeyHandle)
         /* Call the internal API */
         Status = CmFlushKey(KeyObject->KeyControlBlock, FALSE);
     }
-    
-    /* Release the lock */
-    ExReleaseResourceLite(&CmpRegistryLock);
-    KeLeaveCriticalRegion();
-    
+
+    /* Release the locks */
+    CmpReleaseKcbLock(KeyObject->KeyControlBlock);
+    CmpUnlockRegistry();
+
     /* Dereference the object and return status */
     ObDereferenceObject(KeyObject);
     return Status;
 }
 
-NTSTATUS
-NTAPI
-NtCompactKeys(IN ULONG Count,
-              IN PHANDLE KeyArray)
-{
-    UNIMPLEMENTED;
-    return STATUS_NOT_IMPLEMENTED;
-}
-
-NTSTATUS
-NTAPI
-NtCompressKey(IN HANDLE Key)
-{
-    UNIMPLEMENTED;
-    return STATUS_NOT_IMPLEMENTED;
-}
-
 NTSTATUS
 NTAPI
 NtLoadKey(IN POBJECT_ATTRIBUTES KeyObjectAttributes,
           IN POBJECT_ATTRIBUTES FileObjectAttributes)
 {
-    return NtLoadKey2(KeyObjectAttributes, FileObjectAttributes, 0);
+    /* Call the newer API */
+    return NtLoadKeyEx(KeyObjectAttributes, FileObjectAttributes, 0, NULL);
 }
 
 NTSTATUS
@@ -498,16 +797,10 @@ NtLoadKey2(IN POBJECT_ATTRIBUTES KeyObjectAttributes,
            IN POBJECT_ATTRIBUTES FileObjectAttributes,
            IN ULONG Flags)
 {
+    /* Call the newer API */
     return NtLoadKeyEx(KeyObjectAttributes, FileObjectAttributes, Flags, NULL);
 }
 
-NTSTATUS
-NTAPI
-CmLoadKey(IN POBJECT_ATTRIBUTES TargetKey,
-          IN POBJECT_ATTRIBUTES SourceFile,
-          IN ULONG Flags,
-          IN PKEY_OBJECT KeyBody);
-
 NTSTATUS
 NTAPI
 NtLoadKeyEx(IN POBJECT_ATTRIBUTES TargetKey,
@@ -517,23 +810,23 @@ NtLoadKeyEx(IN POBJECT_ATTRIBUTES TargetKey,
 {
     NTSTATUS Status;
     KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
-    PKEY_OBJECT KeyBody = NULL;
+    PCM_KEY_BODY KeyBody = NULL;
     PAGED_CODE();
 
     /* Validate flags */
     if (Flags & ~REG_NO_LAZY_FLUSH) return STATUS_INVALID_PARAMETER;
-    
+
     /* Validate privilege */
     if (!SeSinglePrivilegeCheck(SeRestorePrivilege, PreviousMode))
     {
         /* Fail */
         DPRINT1("Restore Privilege missing!\n");
-        //return STATUS_PRIVILEGE_NOT_HELD;
+        return STATUS_PRIVILEGE_NOT_HELD;
     }
-    
+
     /* Block APCs */
     KeEnterCriticalRegion();
-    
+
     /* Check if we have a trust class */
     if (TrustClassKey)
     {
@@ -545,20 +838,130 @@ NtLoadKeyEx(IN POBJECT_ATTRIBUTES TargetKey,
                                            (PVOID *)&KeyBody,
                                            NULL);
     }
-    
+
     /* Call the internal API */
     Status = CmLoadKey(TargetKey, SourceFile, Flags, KeyBody);
-    
+
     /* Dereference the trust key, if any */
     if (KeyBody) ObDereferenceObject(KeyBody);
-    
+
     /* Bring back APCs */
     KeLeaveCriticalRegion();
-    
+
     /* Return status */
     return Status;
 }
 
+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)
+{
+    /* Call the newer API */
+    return NtNotifyChangeMultipleKeys(KeyHandle,
+                                      0,
+                                      NULL,
+                                      Event,
+                                      ApcRoutine,
+                                      ApcContext,
+                                      IoStatusBlock,
+                                      CompletionFilter,
+                                      WatchTree,
+                                      Buffer,
+                                      Length,
+                                      Asynchronous);
+}
+
+NTSTATUS
+NTAPI
+NtInitializeRegistry(IN USHORT Flag)
+{
+    BOOLEAN SetupBoot;
+    NTSTATUS Status = STATUS_SUCCESS;
+    PAGED_CODE();
+
+    /* Always do this as kernel mode */
+    if (KeGetPreviousMode() == UserMode) return ZwInitializeRegistry(Flag);
+
+    /* Enough of the system has booted by now */
+    Ki386PerfEnd();
+            
+    /* Validate flag */
+    if (Flag > CM_BOOT_FLAG_MAX) return STATUS_INVALID_PARAMETER;
+
+    /* Check if boot was accepted */
+    if ((Flag >= CM_BOOT_FLAG_ACCEPTED) && (Flag <= CM_BOOT_FLAG_MAX))
+    {
+        /* Only allow once */
+        if (!CmBootAcceptFirstTime) return STATUS_ACCESS_DENIED;
+        CmBootAcceptFirstTime = FALSE;
+
+        /* Get the control set accepted */
+        Flag -= CM_BOOT_FLAG_ACCEPTED;
+        if (Flag)
+        {
+            /* FIXME: Save the last known good boot */
+            //Status = CmpSaveBootControlSet(Flag);
+
+            /* Notify HAL */
+            HalEndOfBoot();
+
+            /* Enable lazy flush */
+            CmpHoldLazyFlush = FALSE;
+            CmpLazyFlush();
+            return Status;
+        }
+
+        /* Otherwise, invalid boot */
+        return STATUS_INVALID_PARAMETER;
+    }
+
+    /* Check if this was a setup boot */
+    SetupBoot = (Flag == CM_BOOT_FLAG_SETUP ? TRUE : FALSE);
+
+    /* Make sure we're only called once */
+    if (!CmFirstTime) return STATUS_ACCESS_DENIED;
+    CmFirstTime = FALSE;
+
+    /* Acquire registry lock */
+    //CmpLockRegistryExclusive();
+
+    /* Initialize the hives and lazy flusher */
+    CmpCmdInit(SetupBoot);
+
+    /* FIXME: Save version data */
+    //CmpSetVersionData();
+
+    /* Release the registry lock */
+    //CmpUnlockRegistry();
+    return STATUS_SUCCESS;
+}
+
+NTSTATUS
+NTAPI
+NtCompactKeys(IN ULONG Count,
+              IN PHANDLE KeyArray)
+{
+    UNIMPLEMENTED;
+    return STATUS_NOT_IMPLEMENTED;
+}
+
+NTSTATUS
+NTAPI
+NtCompressKey(IN HANDLE Key)
+{
+    UNIMPLEMENTED;
+    return STATUS_NOT_IMPLEMENTED;
+}
+
 NTSTATUS
 NTAPI
 NtLockProductActivationKeys(IN PULONG pPrivateVer,
@@ -595,33 +998,6 @@ 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
 NtQueryMultipleValueKey(IN HANDLE KeyHandle,
@@ -638,10 +1014,93 @@ NtQueryMultipleValueKey(IN HANDLE KeyHandle,
 NTSTATUS
 NTAPI
 NtQueryOpenSubKeys(IN POBJECT_ATTRIBUTES TargetKey,
-                   IN ULONG HandleCount)
+                   OUT PULONG HandleCount)
 {
-    UNIMPLEMENTED;
-    return STATUS_NOT_IMPLEMENTED;
+    KPROCESSOR_MODE PreviousMode;
+    PCM_KEY_BODY KeyBody = NULL;
+    HANDLE KeyHandle;
+    NTSTATUS Status;
+
+    DPRINT("NtQueryOpenSubKeys()\n");
+
+    PAGED_CODE();
+
+    /* Get the processor mode */
+    PreviousMode = KeGetPreviousMode();
+
+    if (PreviousMode != KernelMode)
+    {
+        /* Prepare to probe parameters */
+        _SEH2_TRY
+        {
+            /* Probe target key */
+            ProbeForRead(TargetKey,
+                         sizeof(OBJECT_ATTRIBUTES),
+                         sizeof(ULONG));
+
+            /* Probe handle count */
+            ProbeForWriteUlong(HandleCount);
+        }
+        _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+        {
+            /* Return the exception code */
+            _SEH2_YIELD(return _SEH2_GetExceptionCode());
+        }
+        _SEH2_END;
+    }
+
+    /* Open a handle to the key */
+    Status = ObOpenObjectByName(TargetKey,
+                                CmpKeyObjectType,
+                                PreviousMode,
+                                NULL,
+                                KEY_READ,
+                                NULL,
+                                &KeyHandle);
+    if (NT_SUCCESS(Status))
+    {
+        /* Reference the key object */
+        Status = ObReferenceObjectByHandle(KeyHandle,
+                                           KEY_READ,
+                                           CmpKeyObjectType,
+                                           PreviousMode,
+                                           (PVOID *)&KeyBody,
+                                           NULL);
+
+        /* Close the handle */
+        NtClose(KeyHandle);
+    }
+
+    /* Fail, if the key object could not be referenced */
+    if (!NT_SUCCESS(Status))
+        return Status;
+
+    /* Lock the registry exclusively */
+    CmpLockRegistryExclusive();
+
+    /* Fail, if we did not open a hive root key */
+    if (KeyBody->KeyControlBlock->KeyCell !=
+        KeyBody->KeyControlBlock->KeyHive->BaseBlock->RootCell)
+    {
+        DPRINT("Error: Key is not a hive root key!\n");
+        CmpUnlockRegistry();
+        ObDereferenceObject(KeyBody);
+        return STATUS_INVALID_PARAMETER;
+    }
+
+    /* Call the internal API */
+    *HandleCount = CmCountOpenSubKeys(KeyBody->KeyControlBlock,
+                                      FALSE);
+
+    /* Unlock the registry */
+    CmpUnlockRegistry();
+
+    /* Dereference the key object */
+    ObDereferenceObject(KeyBody);
+
+    DPRINT("Done.\n");
+
+    return Status;
 }
 
 NTSTATUS
@@ -655,6 +1114,15 @@ NtQueryOpenSubKeysEx(IN POBJECT_ATTRIBUTES TargetKey,
     return STATUS_NOT_IMPLEMENTED;
 }
 
+NTSTATUS
+NTAPI
+NtRenameKey(IN HANDLE KeyHandle,
+            IN PUNICODE_STRING ReplacementName)
+{
+    UNIMPLEMENTED;
+    return STATUS_NOT_IMPLEMENTED;
+}
+
 NTSTATUS
 NTAPI
 NtReplaceKey(IN POBJECT_ATTRIBUTES ObjectAttributes,
@@ -719,8 +1187,7 @@ NTSTATUS
 NTAPI
 NtUnloadKey(IN POBJECT_ATTRIBUTES KeyObjectAttributes)
 {
-    UNIMPLEMENTED;
-    return STATUS_NOT_IMPLEMENTED;
+    return NtUnloadKey2(KeyObjectAttributes, 0);
 }
 
 NTSTATUS
@@ -728,8 +1195,170 @@ NTAPI
 NtUnloadKey2(IN POBJECT_ATTRIBUTES TargetKey,
              IN ULONG Flags)
 {
+#if 0
+    NTSTATUS Status;
+    OBJECT_ATTRIBUTES ObjectAttributes;
+    UNICODE_STRING ObjectName;
+    CM_PARSE_CONTEXT ParseContext = {0};
+    KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
+    PCM_KEY_BODY KeyBody = NULL;
+    ULONG ParentConv = 0, ChildConv = 0;
+    HANDLE Handle;
+    PAGED_CODE();
+
+    /* Validate privilege */
+    if (!SeSinglePrivilegeCheck(SeRestorePrivilege, PreviousMode))
+    {
+        /* Fail */
+        DPRINT1("Restore Privilege missing!\n");
+        return STATUS_PRIVILEGE_NOT_HELD;
+    }
+
+    /* Check for user-mode caller */
+    if (PreviousMode != KernelMode)
+    {
+        /* Prepare to probe parameters */
+        _SEH2_TRY
+        {
+            /* Probe object attributes */
+            ProbeForRead(TargetKey,
+                         sizeof(OBJECT_ATTRIBUTES),
+                         sizeof(ULONG));
+
+            ObjectAttributes = *TargetKey;
+
+            /* Probe the string */
+            ProbeForReadUnicodeString(&TargetKey->ObjectName);
+
+            ObjectName = *TargetKey->ObjectName;
+
+            ProbeForRead(ObjectName.Buffer,
+                         ObjectName.Length,
+                         sizeof(WCHAR));
+
+            ObjectAttributes.ObjectName = &ObjectName;
+        }
+        _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+        {
+            /* Return the exception code */
+            _SEH2_YIELD(return _SEH2_GetExceptionCode());
+        }
+        _SEH2_END;
+    }
+    else
+    {
+        /* Save the target attributes directly */
+        ObjectAttributes = *TargetKey;
+    }
+
+    /* Setup the parse context */
+    ParseContext.CreateOperation = TRUE;
+    ParseContext.CreateOptions = REG_OPTION_BACKUP_RESTORE;
+
+    /* Do the create */
+    Status = ObOpenObjectByName(&ObjectAttributes,
+                                CmpKeyObjectType,
+                                KernelMode,
+                                NULL,
+                                KEY_WRITE,
+                                &ParseContext,
+                                &Handle);
+
+    /* Return if failure encountered */
+    if (!NT_SUCCESS(Status)) return Status;
+
+    /* Reference it */
+    Status = ObReferenceObjectByHandle(Handle,
+                                       KEY_WRITE,
+                                       CmpKeyObjectType,
+                                       KernelMode,
+                                       (PVOID *)&KeyBody,
+                                       NULL);
+
+    /* Close the handle */
+    ZwClose(Handle);
+
+    /* Return if failure encountered */
+    if (!NT_SUCCESS(Status)) return Status;
+
+    /* Acquire the lock depending on flags */
+    if (Flags == REG_FORCE_UNLOAD)
+    {
+        /* Lock registry exclusively */
+        CmpLockRegistryExclusive();
+    }
+    else
+    {
+        /* Lock registry */
+        CmpLockRegistry();
+
+        /* Acquire the hive loading lock */
+        ExAcquirePushLockExclusive(&CmpLoadHiveLock);
+
+        /* Lock parent and child */
+        if (KeyBody->KeyControlBlock->ParentKcb)
+            ParentConv = KeyBody->KeyControlBlock->ParentKcb->ConvKey;
+        else
+            ParentConv = KeyBody->KeyControlBlock->ConvKey;
+
+        ChildConv = KeyBody->KeyControlBlock->ConvKey;
+
+        CmpAcquireTwoKcbLocksExclusiveByKey(ChildConv, ParentConv);
+    }
+
+    /* Check if it's being deleted already */
+    if (KeyBody->KeyControlBlock->Delete)
+    {
+        /* Return appropriate status */
+        Status = STATUS_KEY_DELETED;
+        goto Quickie;
+    }
+
+    /* Check if it's a readonly key */
+    if (KeyBody->KeyControlBlock->ExtFlags & CM_KCB_READ_ONLY_KEY)
+    {
+        /* Return appropriate status */
+        Status = STATUS_ACCESS_DENIED;
+        goto Quickie;
+    }
+
+    /* Call the internal API */
+    Status = CmUnloadKey(KeyBody->KeyControlBlock,
+                         Flags);
+
+    /* Check if we failed, but really need to succeed */
+    if ((Status == STATUS_CANNOT_DELETE) && (Flags == REG_FORCE_UNLOAD))
+    {
+        /* TODO: We should perform another attempt here */
+        ASSERT(FALSE);
+    }
+
+    /* If CmUnloadKey failed we need to unlock registry ourselves */
+    if (!NT_SUCCESS(Status))
+    {
+        if (Flags != REG_FORCE_UNLOAD)
+        {
+            /* Release the hive loading lock */
+            ExReleasePushLockExclusive(&CmpLoadHiveLock);
+
+            /* Release two KCBs lock */
+            CmpReleaseTwoKcbLockByKey(ChildConv, ParentConv);
+        }
+
+        /* Unlock the registry */
+        CmpUnlockRegistry();
+    }
+
+Quickie:
+    /* Dereference the key */
+    ObDereferenceObject(KeyBody);
+
+    /* Return status */
+    return Status;
+#else
     UNIMPLEMENTED;
     return STATUS_NOT_IMPLEMENTED;
+#endif
 }
 
 NTSTATUS