[NTOS:CM] Reuse the saved previous-mode from the ExGetPreviousMode() calls.
[reactos.git] / ntoskrnl / config / ntapi.c
index 95f6116..ee6b57c 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * PROJECT:         ReactOS Kernel
  * LICENSE:         GPL - See COPYING in the top level directory
- * FILE:            ntoskrnl/config/cmapi.c
+ * FILE:            ntoskrnl/config/ntapi.c
  * PURPOSE:         Configuration Manager - Internal Registry APIs
  * PROGRAMMERS:     Alex Ionescu (alex.ionescu@reactos.org)
  *                  Eric Kohl
@@ -15,6 +15,7 @@
 
 BOOLEAN CmBootAcceptFirstTime = TRUE;
 BOOLEAN CmFirstTime = TRUE;
+extern ULONG InitSafeBootMode;
 
 /* FUNCTIONS *****************************************************************/
 
@@ -33,7 +34,13 @@ NtCreateKey(OUT PHANDLE KeyHandle,
     CM_PARSE_CONTEXT ParseContext = {0};
     HANDLE Handle;
     PAGED_CODE();
-    DPRINT("NtCreateKey(OB name %wZ)\n", ObjectAttributes->ObjectName);
+
+    DPRINT("NtCreateKey(Path: %wZ, Root %x, Access: %x, CreateOptions %x)\n",
+            ObjectAttributes->ObjectName, ObjectAttributes->RootDirectory,
+            DesiredAccess, CreateOptions);
+
+    /* Ignore the WOW64 flag, it's not valid in the kernel */
+    DesiredAccess &= ~KEY_WOW64_RES;
 
     /* Check for user-mode caller */
     if (PreviousMode != KernelMode)
@@ -60,7 +67,8 @@ NtCreateKey(OUT PHANDLE KeyHandle,
                          sizeof(OBJECT_ATTRIBUTES),
                          sizeof(ULONG));
 
-            if (Disposition) ProbeForWriteUlong(Disposition);
+            if (Disposition)
+                ProbeForWriteUlong(Disposition);
         }
         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
         {
@@ -101,6 +109,8 @@ NtCreateKey(OUT PHANDLE KeyHandle,
     }
     _SEH2_END;
 
+    DPRINT("Returning handle %x, Status %x.\n", Handle, Status);
+
     /* Return status */
     return Status;
 }
@@ -116,7 +126,11 @@ NtOpenKey(OUT PHANDLE KeyHandle,
     NTSTATUS Status;
     KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
     PAGED_CODE();
-    DPRINT("NtOpenKey(OB 0x%wZ)\n", ObjectAttributes->ObjectName);
+    DPRINT("NtOpenKey(Path: %wZ, Root %x, Access: %x)\n",
+            ObjectAttributes->ObjectName, ObjectAttributes->RootDirectory, DesiredAccess);
+
+    /* Ignore the WOW64 flag, it's not valid in the kernel */
+    DesiredAccess &= ~KEY_WOW64_RES;
 
     /* Check for user-mode caller */
     if (PreviousMode != KernelMode)
@@ -144,7 +158,7 @@ NtOpenKey(OUT PHANDLE KeyHandle,
     /* Just let the object manager handle this */
     Status = ObOpenObjectByName(ObjectAttributes,
                                 CmpKeyObjectType,
-                                ExGetPreviousMode(),
+                                PreviousMode,
                                 NULL,
                                 DesiredAccess,
                                 &ParseContext,
@@ -166,6 +180,8 @@ NtOpenKey(OUT PHANDLE KeyHandle,
         _SEH2_END;
     }
 
+    DPRINT("Returning handle %x, Status %x.\n", Handle, Status);
+
     /* Return status */
     return Status;
 }
@@ -235,7 +251,7 @@ NtEnumerateKey(IN HANDLE KeyHandle,
     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",
+    DPRINT("NtEnumerateKey() KH 0x%p, Index 0x%x, KIC %d, Length %lu\n",
            KeyHandle, Index, KeyInformationClass, Length);
 
     /* Reject classes we don't know about */
@@ -251,7 +267,7 @@ NtEnumerateKey(IN HANDLE KeyHandle,
     Status = ObReferenceObjectByHandle(KeyHandle,
                                        KEY_ENUMERATE_SUB_KEYS,
                                        CmpKeyObjectType,
-                                       ExGetPreviousMode(),
+                                       PreviousMode,
                                        (PVOID*)&KeyObject,
                                        NULL);
     if (!NT_SUCCESS(Status)) return Status;
@@ -301,6 +317,7 @@ NtEnumerateKey(IN HANDLE KeyHandle,
 
     /* Dereference and return status */
     ObDereferenceObject(KeyObject);
+    DPRINT("Returning status %x.\n", Status);
     return Status;
 }
 
@@ -319,7 +336,7 @@ NtEnumerateValueKey(IN HANDLE KeyHandle,
     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",
+    DPRINT("NtEnumerateValueKey() KH 0x%p, Index 0x%x, KVIC %d, Length %lu\n",
            KeyHandle, Index, KeyValueInformationClass, Length);
 
     /* Reject classes we don't know about */
@@ -335,7 +352,7 @@ NtEnumerateValueKey(IN HANDLE KeyHandle,
     Status = ObReferenceObjectByHandle(KeyHandle,
                                        KEY_QUERY_VALUE,
                                        CmpKeyObjectType,
-                                       ExGetPreviousMode(),
+                                       PreviousMode,
                                        (PVOID*)&KeyObject,
                                        NULL);
     if (!NT_SUCCESS(Status)) return Status;
@@ -404,7 +421,7 @@ NtQueryKey(IN HANDLE KeyHandle,
     REG_POST_OPERATION_INFORMATION PostOperationInfo;
     OBJECT_HANDLE_INFORMATION HandleInfo;
     PAGED_CODE();
-    DPRINT("NtQueryKey() KH 0x%x, KIC %d, Length %d\n",
+    DPRINT("NtQueryKey() KH 0x%p, KIC %d, Length %lu\n",
            KeyHandle, KeyInformationClass, Length);
 
     /* Reject invalid classes */
@@ -426,7 +443,7 @@ NtQueryKey(IN HANDLE KeyHandle,
         Status = ObReferenceObjectByHandle(KeyHandle,
                                            0,
                                            CmpKeyObjectType,
-                                           ExGetPreviousMode(),
+                                           PreviousMode,
                                            (PVOID*)&KeyObject,
                                            &HandleInfo);
         if (NT_SUCCESS(Status))
@@ -446,7 +463,7 @@ NtQueryKey(IN HANDLE KeyHandle,
         Status = ObReferenceObjectByHandle(KeyHandle,
                                            KEY_QUERY_VALUE,
                                            CmpKeyObjectType,
-                                           ExGetPreviousMode(),
+                                           PreviousMode,
                                            (PVOID*)&KeyObject,
                                            NULL);
     }
@@ -517,14 +534,14 @@ NtQueryValueKey(IN HANDLE KeyHandle,
     REG_POST_OPERATION_INFORMATION PostOperationInfo;
     UNICODE_STRING ValueNameCopy = *ValueName;
     PAGED_CODE();
-    DPRINT("NtQueryValueKey() KH 0x%x, VN '%wZ', KVIC %d, Length %d\n",
+    DPRINT("NtQueryValueKey() KH 0x%p, VN '%wZ', KVIC %d, Length %lu\n",
         KeyHandle, ValueName, KeyValueInformationClass, Length);
 
     /* Verify that the handle is valid and is a registry key */
     Status = ObReferenceObjectByHandle(KeyHandle,
                                        KEY_QUERY_VALUE,
                                        CmpKeyObjectType,
-                                       ExGetPreviousMode(),
+                                       PreviousMode,
                                        (PVOID*)&KeyObject,
                                        NULL);
     if (!NT_SUCCESS(Status)) return Status;
@@ -604,23 +621,62 @@ NtSetValueKey(IN HANDLE KeyHandle,
               IN PVOID Data,
               IN ULONG DataSize)
 {
-    NTSTATUS Status;
-    PCM_KEY_BODY KeyObject;
+    NTSTATUS Status = STATUS_SUCCESS;
+    PCM_KEY_BODY KeyObject = NULL;
     REG_SET_VALUE_KEY_INFORMATION SetValueKeyInfo;
     REG_POST_OPERATION_INFORMATION PostOperationInfo;
-    UNICODE_STRING ValueNameCopy = *ValueName;
+    UNICODE_STRING ValueNameCopy;
+    KPROCESSOR_MODE PreviousMode;
+
     PAGED_CODE();
-    DPRINT("NtSetValueKey() KH 0x%x, VN '%wZ', TI %x, T %d, DS %d\n",
-        KeyHandle, ValueName, TitleIndex, Type, DataSize);
+
+    PreviousMode = ExGetPreviousMode();
+
+    if (!DataSize)
+        Data = NULL;
+
+    /* Probe and copy the data */
+    if ((PreviousMode != KernelMode) && (DataSize != 0))
+    {
+        PVOID DataCopy = ExAllocatePoolWithTag(PagedPool, DataSize, TAG_CM);
+        if (!DataCopy)
+            return STATUS_INSUFFICIENT_RESOURCES;
+        _SEH2_TRY
+        {
+            ProbeForRead(Data, DataSize, 1);
+            RtlCopyMemory(DataCopy, Data, DataSize);
+        }
+        _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+        {
+            Status = _SEH2_GetExceptionCode();
+        }
+        _SEH2_END;
+
+        if (!NT_SUCCESS(Status))
+        {
+            ExFreePoolWithTag(DataCopy, TAG_CM);
+            return Status;
+        }
+        Data = DataCopy;
+    }
+
+    /* Capture the string */
+    Status = ProbeAndCaptureUnicodeString(&ValueNameCopy, PreviousMode, ValueName);
+    if (!NT_SUCCESS(Status))
+        goto end;
+
+    DPRINT("NtSetValueKey() KH 0x%p, VN '%wZ', TI %x, T %lu, DS %lu\n",
+        KeyHandle, &ValueNameCopy, TitleIndex, Type, DataSize);
 
     /* Verify that the handle is valid and is a registry key */
     Status = ObReferenceObjectByHandle(KeyHandle,
                                        KEY_SET_VALUE,
                                        CmpKeyObjectType,
-                                       ExGetPreviousMode(),
+                                       PreviousMode,
                                        (PVOID*)&KeyObject,
                                        NULL);
-    if (!NT_SUCCESS(Status)) return Status;
+    if (!NT_SUCCESS(Status))
+        goto end;
 
     /* Make sure the name is aligned, not too long, and the data under 4GB */
     if ( (ValueNameCopy.Length > 32767) ||
@@ -628,8 +684,8 @@ NtSetValueKey(IN HANDLE KeyHandle,
          (DataSize > 0x80000000))
     {
         /* Fail */
-        ObDereferenceObject(KeyObject);
-        return STATUS_INVALID_PARAMETER;
+        Status = STATUS_INVALID_PARAMETER;
+        goto end;
     }
 
     /* Ignore any null characters at the end */
@@ -644,14 +700,14 @@ NtSetValueKey(IN HANDLE KeyHandle,
     if (KeyObject->KeyControlBlock->ExtFlags & CM_KCB_READ_ONLY_KEY)
     {
         /* Fail */
-        ObDereferenceObject(KeyObject);
-        return STATUS_ACCESS_DENIED;
+        Status = STATUS_ACCESS_DENIED;
+        goto end;
     }
 
     /* Setup callback */
     PostOperationInfo.Object = (PVOID)KeyObject;
     SetValueKeyInfo.Object = (PVOID)KeyObject;
-    SetValueKeyInfo.ValueName = ValueName;
+    SetValueKeyInfo.ValueName = &ValueNameCopy;
     SetValueKeyInfo.TitleIndex = TitleIndex;
     SetValueKeyInfo.Type = Type;
     SetValueKeyInfo.Data = Data;
@@ -673,8 +729,13 @@ NtSetValueKey(IN HANDLE KeyHandle,
     PostOperationInfo.Status = Status;
     CmiCallRegisteredCallbacks(RegNtPostSetValueKey, &PostOperationInfo);
 
+end:
     /* Dereference and return status */
-    ObDereferenceObject(KeyObject);
+    if (KeyObject)
+        ObDereferenceObject(KeyObject);
+    ReleaseCapturedUnicodeString(&ValueNameCopy, PreviousMode);
+    if ((PreviousMode != KernelMode) && Data)
+        ExFreePoolWithTag(Data, TAG_CM);
     return Status;
 }
 
@@ -696,7 +757,7 @@ NtDeleteValueKey(IN HANDLE KeyHandle,
                                        KEY_SET_VALUE,
                                        CmpKeyObjectType,
                                        PreviousMode,
-                                       (PVOID *)&KeyObject,
+                                       (PVOID*)&KeyObject,
                                        NULL);
     if (!NT_SUCCESS(Status)) return Status;
 
@@ -819,7 +880,6 @@ NtLoadKeyEx(IN POBJECT_ATTRIBUTES TargetKey,
     /* Validate privilege */
     if (!SeSinglePrivilegeCheck(SeRestorePrivilege, PreviousMode))
     {
-        /* Fail */
         DPRINT1("Restore Privilege missing!\n");
         return STATUS_PRIVILEGE_NOT_HELD;
     }
@@ -835,7 +895,7 @@ NtLoadKeyEx(IN POBJECT_ATTRIBUTES TargetKey,
                                            0,
                                            CmpKeyObjectType,
                                            PreviousMode,
-                                           (PVOID *)&KeyBody,
+                                           (PVOID*)&KeyBody,
                                            NULL);
     }
 
@@ -893,7 +953,7 @@ NtInitializeRegistry(IN USHORT Flag)
 
     /* Enough of the system has booted by now */
     Ki386PerfEnd();
-            
+
     /* Validate flag */
     if (Flag > CM_BOOT_FLAG_MAX) return STATUS_INVALID_PARAMETER;
 
@@ -962,13 +1022,52 @@ NtCompressKey(IN HANDLE Key)
     return STATUS_NOT_IMPLEMENTED;
 }
 
+// FIXME: different for different windows versions!
+#define PRODUCT_ACTIVATION_VERSION 7749
+
 NTSTATUS
 NTAPI
 NtLockProductActivationKeys(IN PULONG pPrivateVer,
                             IN PULONG pSafeMode)
 {
-    UNIMPLEMENTED;
-    return STATUS_NOT_IMPLEMENTED;
+    KPROCESSOR_MODE PreviousMode;
+
+    PreviousMode = ExGetPreviousMode();
+    _SEH2_TRY
+    {
+        /* Check if the caller asked for the version */
+        if (pPrivateVer != NULL)
+        {
+            /* For user mode, probe it */
+            if (PreviousMode != KernelMode)
+            {
+                ProbeForRead(pPrivateVer, sizeof(ULONG), sizeof(ULONG));
+            }
+
+            /* Return the expected version */
+            *pPrivateVer = PRODUCT_ACTIVATION_VERSION;
+        }
+
+        /* Check if the caller asked for safe mode mode state */
+        if (pSafeMode != NULL)
+        {
+            /* For user mode, probe it */
+            if (PreviousMode != KernelMode)
+            {
+                ProbeForRead(pSafeMode, sizeof(ULONG), sizeof(ULONG));
+            }
+
+            /* Return the safe boot mode state */
+            *pSafeMode = InitSafeBootMode;
+        }
+    }
+    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+    {
+        _SEH2_YIELD(return _SEH2_GetExceptionCode());
+    }
+    _SEH2_END;
+
+    return STATUS_SUCCESS;
 }
 
 NTSTATUS
@@ -994,7 +1093,7 @@ NtNotifyChangeMultipleKeys(IN HANDLE MasterKeyHandle,
                            IN ULONG Length,
                            IN BOOLEAN Asynchronous)
 {
-    UNIMPLEMENTED;
+    UNIMPLEMENTED_ONCE;
     return STATUS_NOT_IMPLEMENTED;
 }
 
@@ -1028,6 +1127,7 @@ NtQueryOpenSubKeys(IN POBJECT_ATTRIBUTES TargetKey,
     /* Get the processor mode */
     PreviousMode = KeGetPreviousMode();
 
+    /* Check for user-mode caller */
     if (PreviousMode != KernelMode)
     {
         /* Prepare to probe parameters */
@@ -1064,7 +1164,7 @@ NtQueryOpenSubKeys(IN POBJECT_ATTRIBUTES TargetKey,
                                            KEY_READ,
                                            CmpKeyObjectType,
                                            PreviousMode,
-                                           (PVOID *)&KeyBody,
+                                           (PVOID*)&KeyBody,
                                            NULL);
 
         /* Close the handle */
@@ -1148,8 +1248,8 @@ NTAPI
 NtSaveKey(IN HANDLE KeyHandle,
           IN HANDLE FileHandle)
 {
-    UNIMPLEMENTED;
-    return STATUS_NOT_IMPLEMENTED;
+    /* Call the extended API */
+    return NtSaveKeyEx(KeyHandle, FileHandle, REG_STANDARD_FORMAT);
 }
 
 NTSTATUS
@@ -1158,8 +1258,43 @@ NtSaveKeyEx(IN HANDLE KeyHandle,
             IN HANDLE FileHandle,
             IN ULONG Flags)
 {
-    UNIMPLEMENTED;
-    return STATUS_NOT_IMPLEMENTED;
+    NTSTATUS Status;
+    PCM_KEY_BODY KeyObject;
+    KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
+
+    PAGED_CODE();
+
+    DPRINT("NtSaveKeyEx(0x%p, 0x%p, %lu)\n", KeyHandle, FileHandle, Flags);
+
+    /* Verify the flags */
+    if ((Flags != REG_STANDARD_FORMAT)
+        && (Flags != REG_LATEST_FORMAT)
+        && (Flags != REG_NO_COMPRESSION))
+    {
+        /* Only one of these values can be specified */
+        return STATUS_INVALID_PARAMETER;
+    }
+
+    /* Validate privilege */
+    if (!SeSinglePrivilegeCheck(SeBackupPrivilege, PreviousMode))
+    {
+        return STATUS_PRIVILEGE_NOT_HELD;
+    }
+
+    /* Verify that the handle is valid and is a registry key */
+    Status = ObReferenceObjectByHandle(KeyHandle,
+                                       KEY_READ,
+                                       CmpKeyObjectType,
+                                       PreviousMode,
+                                       (PVOID*)&KeyObject,
+                                       NULL);
+    if (!NT_SUCCESS(Status)) return Status;
+
+    /* Call the internal API */
+    Status = CmSaveKey(KeyObject->KeyControlBlock, FileHandle, Flags);
+
+    ObDereferenceObject(KeyObject);
+    return Status;
 }
 
 NTSTATUS
@@ -1168,8 +1303,56 @@ NtSaveMergedKeys(IN HANDLE HighPrecedenceKeyHandle,
                  IN HANDLE LowPrecedenceKeyHandle,
                  IN HANDLE FileHandle)
 {
-    UNIMPLEMENTED;
-    return STATUS_NOT_IMPLEMENTED;
+    KPROCESSOR_MODE PreviousMode;
+    PCM_KEY_BODY HighPrecedenceKeyObject = NULL;
+    PCM_KEY_BODY LowPrecedenceKeyObject = NULL;
+    NTSTATUS Status;
+
+    PAGED_CODE();
+
+    DPRINT("NtSaveMergedKeys(0x%p, 0x%p, 0x%p)\n",
+           HighPrecedenceKeyHandle, LowPrecedenceKeyHandle, FileHandle);
+
+    PreviousMode = ExGetPreviousMode();
+
+    /* Validate privilege */
+    if (!SeSinglePrivilegeCheck(SeBackupPrivilege, PreviousMode))
+    {
+        return STATUS_PRIVILEGE_NOT_HELD;
+    }
+
+    /* Verify that the handles are valid and are registry keys */
+    Status = ObReferenceObjectByHandle(HighPrecedenceKeyHandle,
+                                       KEY_READ,
+                                       CmpKeyObjectType,
+                                       PreviousMode,
+                                       (PVOID*)&HighPrecedenceKeyObject,
+                                       NULL);
+    if (!NT_SUCCESS(Status))
+        goto done;
+
+    Status = ObReferenceObjectByHandle(LowPrecedenceKeyHandle,
+                                       KEY_READ,
+                                       CmpKeyObjectType,
+                                       PreviousMode,
+                                       (PVOID*)&LowPrecedenceKeyObject,
+                                       NULL);
+    if (!NT_SUCCESS(Status))
+        goto done;
+
+    /* Call the internal API */
+    Status = CmSaveMergedKeys(HighPrecedenceKeyObject->KeyControlBlock,
+                              LowPrecedenceKeyObject->KeyControlBlock,
+                              FileHandle);
+
+done:
+    if (LowPrecedenceKeyObject)
+        ObDereferenceObject(LowPrecedenceKeyObject);
+
+    if (HighPrecedenceKeyObject)
+        ObDereferenceObject(HighPrecedenceKeyObject);
+
+    return Status;
 }
 
 NTSTATUS
@@ -1195,7 +1378,6 @@ NTAPI
 NtUnloadKey2(IN POBJECT_ATTRIBUTES TargetKey,
              IN ULONG Flags)
 {
-#if 0
     NTSTATUS Status;
     OBJECT_ATTRIBUTES ObjectAttributes;
     UNICODE_STRING ObjectName;
@@ -1204,12 +1386,12 @@ NtUnloadKey2(IN POBJECT_ATTRIBUTES TargetKey,
     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;
     }
@@ -1314,7 +1496,7 @@ NtUnloadKey2(IN POBJECT_ATTRIBUTES TargetKey,
         goto Quickie;
     }
 
-    /* Check if it's a readonly key */
+    /* Check if it's a read-only key */
     if (KeyBody->KeyControlBlock->ExtFlags & CM_KCB_READ_ONLY_KEY)
     {
         /* Return appropriate status */
@@ -1338,11 +1520,11 @@ NtUnloadKey2(IN POBJECT_ATTRIBUTES TargetKey,
     {
         if (Flags != REG_FORCE_UNLOAD)
         {
+            /* Release the KCB locks */
+            CmpReleaseTwoKcbLockByKey(ChildConv, ParentConv);
+
             /* Release the hive loading lock */
             ExReleasePushLockExclusive(&CmpLoadHiveLock);
-
-            /* Release two KCBs lock */
-            CmpReleaseTwoKcbLockByKey(ChildConv, ParentConv);
         }
 
         /* Unlock the registry */
@@ -1355,10 +1537,6 @@ Quickie:
 
     /* Return status */
     return Status;
-#else
-    UNIMPLEMENTED;
-    return STATUS_NOT_IMPLEMENTED;
-#endif
 }
 
 NTSTATUS