- Fix prototype of NtLoadKeyEx.
authorAleksey Bragin <aleksey@reactos.org>
Thu, 22 Nov 2007 18:38:32 +0000 (18:38 +0000)
committerAleksey Bragin <aleksey@reactos.org>
Thu, 22 Nov 2007 18:38:32 +0000 (18:38 +0000)
- Refactor CmiLoadHives using new config routines instead of deprecated cm routines.
- Stop using deprecated CmiScanKeyForValue (delete regfile.c as a result).
- Add code for parallel hive loading to speed up boot process, but don't yet fully use it due to changes required in linking hives.
- Add code for new hive linking process (CmpCreateLinkNode/CmpDoOpen). Not yet used to avoid too many changes in one patch.
- Add new code in CmiLoadHives to deal with updated linking process when it becomes used.
- Implement NtLoadKey2 to cal NtLoadKeyEx.
- Implement NtLoadKeyEx as a new config routine, using CmLoadKey, move out of Cm.
- Add some more code in CmpInitializeSystemHive to deal with SYSTEM hive creation during setup, once hive linking is refactored.
- Implement a new command except for flushing -- open: CmpCmdHiveOpen. Used by CmLoadKey.
- Add support for impersonating the SYSTEM account if the hive can't be open in the current client security context.
- Fill out CmpMachineHiveList, to be used in parallel hive loading.

svn path=/trunk/; revision=30680

14 files changed:
reactos/include/ndk/cmfuncs.h
reactos/ntoskrnl/cm/ntfunc.c
reactos/ntoskrnl/cm/regfile.c [deleted file]
reactos/ntoskrnl/cm/registry.c
reactos/ntoskrnl/cm/regobj.c
reactos/ntoskrnl/config/cm.h
reactos/ntoskrnl/config/cmapi.c
reactos/ntoskrnl/config/cmdata.c
reactos/ntoskrnl/config/cmlazy.c
reactos/ntoskrnl/config/cmparse.c
reactos/ntoskrnl/config/cmsysini.c
reactos/ntoskrnl/config/ntapi.c
reactos/ntoskrnl/ntoskrnl.rbuild
reactos/ntoskrnl/sysfuncs.lst

index 2232292..be88bc6 100644 (file)
@@ -139,10 +139,7 @@ NtLoadKeyEx(
     IN POBJECT_ATTRIBUTES TargetKey,
     IN POBJECT_ATTRIBUTES SourceFile,
     IN ULONG Flags,
-    IN HANDLE TrustClassKey,
-    IN HANDLE Event,
-    IN ACCESS_MASK DesiredAccess,
-    OUT PHANDLE RootHandle
+    IN HANDLE TrustClassKey
 );
 
 NTSTATUS
index a6049dd..23f9d87 100644 (file)
@@ -578,65 +578,25 @@ openkey_cleanup:
     return Status;
 }
 
-/*
- * NOTE:
- * KeyObjectAttributes->RootDirectory specifies the handle to the parent key and
- * KeyObjectAttributes->Name specifies the name of the key to load.
- * Flags can be 0 or REG_NO_LAZY_FLUSH.
- */
-NTSTATUS
-NTAPI
-NtLoadKey2 (IN POBJECT_ATTRIBUTES KeyObjectAttributes,
-            IN POBJECT_ATTRIBUTES FileObjectAttributes,
-            IN ULONG Flags)
-{
-    NTSTATUS Status;
-    PAGED_CODE();
-    DPRINT ("NtLoadKey2() called\n");
-
-#if 0
-    if (!SeSinglePrivilegeCheck (SeRestorePrivilege, ExGetPreviousMode ()))
-        return STATUS_PRIVILEGE_NOT_HELD;
-#endif
-
-    /* Acquire hive lock */
-    KeEnterCriticalRegion();
-    ExAcquireResourceExclusiveLite(&CmpRegistryLock, TRUE);
-
-    Status = CmiLoadHive (KeyObjectAttributes,
-                          FileObjectAttributes->ObjectName,
-                          Flags);
-    if (!NT_SUCCESS (Status))
-    {
-        DPRINT1 ("CmiLoadHive() failed (Status %lx)\n", Status);
-    }
-
-    /* Release hive lock */
-    ExReleaseResourceLite(&CmpRegistryLock);
-    KeLeaveCriticalRegion();
-
-    return Status;
-}
-
 NTSTATUS
 NTAPI
 NtInitializeRegistry (IN USHORT Flag)
 {
     NTSTATUS Status;
-
+    
     PAGED_CODE();
-
+    
     if (CmiRegistryInitialized == TRUE)
         return STATUS_ACCESS_DENIED;
     
     /* Save boot log file */
     IopSaveBootLogToFile();
-
+    
     Status = CmiInitHives (Flag);
-
+    
     CmpCmdInit(Flag);
     CmiRegistryInitialized = TRUE;
-
+    
     return Status;
 }
 
diff --git a/reactos/ntoskrnl/cm/regfile.c b/reactos/ntoskrnl/cm/regfile.c
deleted file mode 100644 (file)
index d9260a5..0000000
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * PROJECT:         ReactOS Kernel
- * COPYRIGHT:       GPL - See COPYING in the top level directory
- * FILE:            ntoskrnl/cm/regfile.c
- * PURPOSE:         Registry file manipulation routines
- *
- * PROGRAMMERS:     Casper Hornstrup
- *                  Eric Kohl
- *                  Filip Navara
- */
-
-#include <ntoskrnl.h>
-#define NDEBUG
-#include <internal/debug.h>
-#include "cm.h"
-
-/* LOCAL MACROS *************************************************************/
-
-#define ABS_VALUE(V) (((V) < 0) ? -(V) : (V))
-#define REG_DATA_SIZE_MASK                 0x7FFFFFFF
-#define REG_DATA_IN_OFFSET                 0x80000000
-
-/* FUNCTIONS ****************************************************************/
-
-NTSTATUS
-CmiLoadHive(IN POBJECT_ATTRIBUTES KeyObjectAttributes,
-            IN PCUNICODE_STRING FileName,
-            IN ULONG Flags)
-{
-    PCMHIVE Hive = NULL;
-    NTSTATUS Status;
-    BOOLEAN Allocate = TRUE;
-
-    DPRINT ("CmiLoadHive(Filename %wZ)\n", FileName);
-
-    if (Flags & ~REG_NO_LAZY_FLUSH) return STATUS_INVALID_PARAMETER;
-
-    Status = CmpInitHiveFromFile(FileName,
-                                 (Flags & REG_NO_LAZY_FLUSH) ? HIVE_NOLAZYFLUSH : 0,
-                                 &Hive,
-                                 &Allocate,
-                                 0);
-    if (!NT_SUCCESS(Status))
-    {
-        DPRINT1("CmpInitHiveFromFile() failed (Status %lx)\n", Status);
-        if (Hive) ExFreePool(Hive);
-        return Status;
-    }
-
-    Status = CmiConnectHive(KeyObjectAttributes, Hive);
-    if (!NT_SUCCESS(Status))
-    {
-        DPRINT1 ("CmiConnectHive() failed (Status %lx)\n", Status);
-        //      CmiRemoveRegistryHive (Hive);
-    }
-
-    DPRINT ("CmiLoadHive() done\n");
-    return Status;
-}
-
-NTSTATUS
-CmiScanKeyForValue(IN PCMHIVE RegistryHive,
-                   IN PCM_KEY_NODE KeyCell,
-                   IN PUNICODE_STRING ValueName,
-                   OUT PCM_KEY_VALUE *ValueCell,
-                   OUT HCELL_INDEX *ValueCellOffset)
-{
-    HCELL_INDEX CellIndex;
-
-    /* Assume failure */
-    *ValueCell = NULL;
-    if (ValueCellOffset) *ValueCellOffset = HCELL_NIL;
-
-    /* Call newer Cm API */
-    CellIndex = CmpFindValueByName(&RegistryHive->Hive, KeyCell, ValueName);
-    if (CellIndex == HCELL_NIL) return STATUS_OBJECT_NAME_NOT_FOUND;
-
-    /* Otherwise, get the cell data back too */
-    if (ValueCellOffset) *ValueCellOffset = CellIndex;
-    *ValueCell = (PCM_KEY_VALUE)HvGetCell(&RegistryHive->Hive, CellIndex);
-    return STATUS_SUCCESS;
-}
-
-/* EOF */
index 8282036..654c4db 100644 (file)
@@ -328,6 +328,8 @@ CmiInitHives(BOOLEAN SetupBoot)
     ULONG BufferSize;
     ULONG ResultSize;
     PWSTR EndPtr;
+    PCMHIVE CmHive;
+    BOOLEAN Allocate = TRUE;
 
     DPRINT("CmiInitHives() called\n");
 
@@ -379,138 +381,172 @@ CmiInitHives(BOOLEAN SetupBoot)
         wcscpy(ConfigPath, L"\\SystemRoot");
     }
     wcscat(ConfigPath, L"\\system32\\config");
-
     DPRINT("ConfigPath: %S\n", ConfigPath);
-
     EndPtr = ConfigPath + wcslen(ConfigPath);
 
-    /* FIXME: Save boot log */
+    /* Setup the file name for the SECURITY hive */
+    wcscpy(EndPtr, REG_SEC_FILE_NAME);
+    RtlInitUnicodeString(&FileName, ConfigPath);
+    DPRINT ("ConfigPath: %S\n", ConfigPath);
+    
+    /* Load the hive */
+    Status = CmpInitHiveFromFile(&FileName,
+                                 0,
+                                 &CmHive,
+                                 &Allocate,
+                                 0);
+    
+    /* Setup the key name for the SECURITY hive */
+    RtlInitUnicodeString(&KeyName, REG_SEC_KEY_NAME);
+    
+    Status = CmpLinkHiveToMaster(&KeyName,
+                                 NULL,
+                                 CmHive,
+                                 FALSE,
+                                 NULL);
+    
+    /* Connect the SOFTWARE hive */
+    wcscpy(EndPtr, REG_SOFTWARE_FILE_NAME);
+    RtlInitUnicodeString(&FileName, ConfigPath);
+    DPRINT ("ConfigPath: %S\n", ConfigPath);
 
+    /* Load the hive */
+    Status = CmpInitHiveFromFile(&FileName,
+                                 0,
+                                 &CmHive,
+                                 &Allocate,
+                                 0);
+    
+    /* Setup the key name for the SECURITY hive */
+    RtlInitUnicodeString (&KeyName, REG_SOFTWARE_KEY_NAME);
+    
+    Status = CmpLinkHiveToMaster(&KeyName,
+                                 NULL,
+                                 CmHive,
+                                 FALSE,
+                                 NULL);
+    
     /* Connect the SYSTEM hive only if it has been created */
     if (SetupBoot == TRUE)
     {
         wcscpy(EndPtr, REG_SYSTEM_FILE_NAME);
+        RtlInitUnicodeString(&FileName, ConfigPath);
         DPRINT ("ConfigPath: %S\n", ConfigPath);
-
-        RtlInitUnicodeString (&KeyName,
-                              REG_SYSTEM_KEY_NAME);
-        InitializeObjectAttributes(&ObjectAttributes,
-                                   &KeyName,
-                                   OBJ_CASE_INSENSITIVE,
-                                   NULL,
-                                   NULL);
-
-        RtlInitUnicodeString (&FileName,
-                              ConfigPath);
-        Status = CmiLoadHive (&ObjectAttributes,
-                              &FileName,
-                              0);
-        if (!NT_SUCCESS(Status))
+#if 0
+        HANDLE PrimaryHandle, LogHandle;
+        ULONG PrimaryDisposition, SecondaryDisposition;
+        ULONG ClusterSize, Length;
+        
+        /* Build the file name */
+        wcscpy(EndPtr, REG_SYSTEM_FILE_NAME);
+        RtlInitUnicodeString(&FileName, ConfigPath);
+        DPRINT ("ConfigPath: %S\n", ConfigPath);
+        
+        /* Hive already exists */
+        CmHive = CmpMachineHiveList[3].CmHive;
+        
+        /* Open the hive file and log */
+        Status = CmpOpenHiveFiles(&FileName,
+                                  L".LOG",
+                                  &PrimaryHandle,
+                                  &LogHandle,
+                                  &PrimaryDisposition,
+                                  &SecondaryDisposition,
+                                  TRUE,
+                                  TRUE,
+                                  FALSE,
+                                  &ClusterSize);
+        if (!(NT_SUCCESS(Status)) || !(LogHandle))
         {
-            DPRINT1 ("CmiLoadHive() failed (Status %lx)\n", Status);
-            return Status;
+            /* Bugcheck */
+            KeBugCheck(BAD_SYSTEM_CONFIG_INFO);
         }
-
-        Status = CmiInitControlSetLink ();
-        if (!NT_SUCCESS(Status))
+        
+        /* Save the file handles */
+        CmHive->FileHandles[HFILE_TYPE_LOG] = LogHandle;
+        CmHive->FileHandles[HFILE_TYPE_PRIMARY] = PrimaryHandle;
+        
+        /* Allow lazy flushing since the handles are there */
+        ASSERT(CmHive->Hive.HiveFlags & HIVE_NOLAZYFLUSH);
+        CmHive->Hive.HiveFlags &= ~HIVE_NOLAZYFLUSH;
+        
+        /* Get the real size of the hive */
+        Length = CmHive->Hive.Storage[Stable].Length + HBLOCK_SIZE;
+        
+        /* Check if the cluster size doesn't match */
+        if (CmHive->Hive.Cluster != ClusterSize) ASSERT(FALSE);
+        
+        /* Set the file size */
+        if (!CmpFileSetSize((PHHIVE)CmHive, HFILE_TYPE_PRIMARY, Length, Length))
         {
-            DPRINT1("CmiInitControlSetLink() failed (Status %lx)\n", Status);
-            return(Status);
+            /* This shouldn't fail */
+            ASSERT(FALSE);
         }
-    }
-
-    /* Connect the SOFTWARE hive */
-    wcscpy(EndPtr, REG_SOFTWARE_FILE_NAME);
-    RtlInitUnicodeString (&FileName,
-                          ConfigPath);
-    DPRINT ("ConfigPath: %S\n", ConfigPath);
-
-    RtlInitUnicodeString (&KeyName,
-                          REG_SOFTWARE_KEY_NAME);
-    InitializeObjectAttributes(&ObjectAttributes,
-                               &KeyName,
-                               OBJ_CASE_INSENSITIVE,
-                               NULL,
-                               NULL);
-
-    Status = CmiLoadHive (&ObjectAttributes,
-                          &FileName,
-                          0);
-    if (!NT_SUCCESS(Status))
-    {
-        DPRINT1("CmiInitializeHive() failed (Status %lx)\n", Status);
-        return(Status);
-    }
-
-    /* Connect the SAM hive */
-    wcscpy(EndPtr, REG_SAM_FILE_NAME);
-    RtlInitUnicodeString (&FileName,
-                          ConfigPath);
-    DPRINT ("ConfigPath: %S\n", ConfigPath);
-
-    RtlInitUnicodeString (&KeyName,
-                          REG_SAM_KEY_NAME);
-    InitializeObjectAttributes(&ObjectAttributes,
-                               &KeyName,
-                               OBJ_CASE_INSENSITIVE,
-                               NULL,
-                               NULL);
-    Status = CmiLoadHive (&ObjectAttributes,
-                          &FileName,
-                          0);
-    if (!NT_SUCCESS(Status))
-    {
-        DPRINT1("CmiInitializeHive() failed (Status %lx)\n", Status);
-        return(Status);
-    }
-
-    /* Connect the SECURITY hive */
-    wcscpy(EndPtr, REG_SEC_FILE_NAME);
-    RtlInitUnicodeString (&FileName,
-                          ConfigPath);
-    DPRINT ("ConfigPath: %S\n", ConfigPath);
+        
+        /* Setup the key name for the SECURITY hive */
+        RtlInitUnicodeString (&KeyName, REG_SYSTEM_KEY_NAME);
+#else
+        /* Load the hive */
+        Status = CmpInitHiveFromFile(&FileName,
+                                     0,
+                                     &CmHive,
+                                     &Allocate,
+                                     0);
+        
+        /* Setup the key name for the SECURITY hive */
+        RtlInitUnicodeString (&KeyName, REG_SYSTEM_KEY_NAME);
+        
+        Status = CmpLinkHiveToMaster(&KeyName,
+                                     NULL,
+                                     CmHive,
+                                     FALSE,
+                                     NULL);
 
-    RtlInitUnicodeString (&KeyName,
-                          REG_SEC_KEY_NAME);
-    InitializeObjectAttributes(&ObjectAttributes,
-                               &KeyName,
-                               OBJ_CASE_INSENSITIVE,
-                               NULL,
-                               NULL);
-    Status = CmiLoadHive (&ObjectAttributes,
-                          &FileName,
-                          0);
-    if (!NT_SUCCESS(Status))
-    {
-        DPRINT1("CmiInitializeHive() failed (Status %lx)\n", Status);
-        return(Status);
+        Status = CmiInitControlSetLink ();
+#endif
     }
 
     /* Connect the DEFAULT hive */
     wcscpy(EndPtr, REG_DEFAULT_USER_FILE_NAME);
-    RtlInitUnicodeString (&FileName,
-                          ConfigPath);
+    RtlInitUnicodeString(&FileName, ConfigPath);
     DPRINT ("ConfigPath: %S\n", ConfigPath);
 
-    RtlInitUnicodeString (&KeyName,
-                          REG_DEFAULT_USER_KEY_NAME);
-    InitializeObjectAttributes(&ObjectAttributes,
-                               &KeyName,
-                               OBJ_CASE_INSENSITIVE,
-                               NULL,
-                               NULL);
-    Status = CmiLoadHive (&ObjectAttributes,
-                          &FileName,
-                          0);
-    if (!NT_SUCCESS(Status))
-    {
-        DPRINT1("CmiInitializeHive() failed (Status %lx)\n", Status);
-        return(Status);
-    }
-
-    DPRINT("CmiInitHives() done\n");
+    /* Load the hive */
+    Status = CmpInitHiveFromFile(&FileName,
+                                 0,
+                                 &CmHive,
+                                 &Allocate,
+                                 0);
+
+    /* Setup the key name for the SECURITY hive */
+    RtlInitUnicodeString (&KeyName, REG_DEFAULT_USER_KEY_NAME);
+    
+    Status = CmpLinkHiveToMaster(&KeyName,
+                                 NULL,
+                                 CmHive,
+                                 FALSE,
+                                 NULL);
 
-    return(STATUS_SUCCESS);
+    /* Connect the SAM hive */
+    wcscpy(EndPtr, REG_SAM_FILE_NAME);
+    RtlInitUnicodeString(&FileName, ConfigPath);
+    DPRINT ("ConfigPath: %S\n", ConfigPath);
+    
+    /* Load the hive */
+    Status = CmpInitHiveFromFile(&FileName,
+                                 0,
+                                 &CmHive,
+                                 &Allocate,
+                                 0);
+    
+    /* Setup the key name for the SECURITY hive */
+    RtlInitUnicodeString(&KeyName, REG_SAM_KEY_NAME);
+    Status = CmpLinkHiveToMaster(&KeyName,
+                                 NULL,
+                                 CmHive,
+                                 FALSE,
+                                 NULL);
+    return Status;
 }
 
 VOID
index 3d108a9..ad0035b 100644 (file)
@@ -838,22 +838,20 @@ CmiGetLinkTarget(PCMHIVE RegistryHive,
     UNICODE_STRING LinkName = RTL_CONSTANT_STRING(L"SymbolicLinkValue");
     PCM_KEY_VALUE ValueCell;
     PVOID DataCell;
-    NTSTATUS Status;
+    HCELL_INDEX Cell;
 
     DPRINT("CmiGetLinkTarget() called\n");
 
-    /* Get Value block of interest */
-    Status = CmiScanKeyForValue(RegistryHive,
-                                KeyCell,
-                                &LinkName,
-                                &ValueCell,
-                                NULL);
-    if (!NT_SUCCESS(Status))
+    /* Find the cell */
+    Cell = CmpFindValueByName(&RegistryHive->Hive, KeyCell, &LinkName);
+    if (Cell == HCELL_NIL)
     {
-        DPRINT1("CmiScanKeyForValue() failed (Status %lx)\n", Status);
-        return(Status);
+        DPRINT1("CmiScanKeyForValue() failed\n");
+        return STATUS_OBJECT_NAME_NOT_FOUND;
     }
-
+    
+    /* Get the cell data */
+    ValueCell = (PCM_KEY_VALUE)HvGetCell(&RegistryHive->Hive, Cell);
     if (ValueCell->Type != REG_LINK)
     {
         DPRINT1("Type != REG_LINK\n!");
index 8c58b56..40dfa8e 100644 (file)
 //
 #define MAXIMUM_CACHED_DATA                             2 * PAGE_SIZE
 
+//
+// Hives to load on startup
+//
+#define CM_NUMBER_OF_MACHINE_HIVES                      6
+
 //
 // Number of items that can fit inside an Allocation Page
 //
 #define CM_KCBS_PER_PAGE                                \
     PAGE_SIZE / sizeof(CM_KEY_CONTROL_BLOCK)
-#define CM_DELAYS_PER_PAGE                       \
+#define CM_DELAYS_PER_PAGE                              \
     PAGE_SIZE / sizeof(CM_DELAYED_CLOSE_ENTRY)
 
 //
@@ -429,9 +434,8 @@ typedef struct _CM_CACHED_VALUE
 //
 typedef struct _HIVE_LIST_ENTRY
 {
-    PWCHAR FileName;
-    PWCHAR BaseName;
-    PWCHAR RegRootName;
+    PWSTR Name;
+    PWSTR BaseName;
     PCMHIVE CmHive;
     ULONG HHiveFlags;
     ULONG CmHiveFlags;
@@ -439,7 +443,6 @@ typedef struct _HIVE_LIST_ENTRY
     BOOLEAN ThreadFinished;
     BOOLEAN ThreadStarted;
     BOOLEAN Allocate;
-    BOOLEAN WinPERequired;
 } HIVE_LIST_ENTRY, *PHIVE_LIST_ENTRY;
 
 //
@@ -759,6 +762,12 @@ CmpInitHiveFromFile(
     IN ULONG CheckFlags
 );
 
+VOID
+NTAPI
+CmpInitializeHiveList(
+    IN USHORT Flag
+);
+
 //
 // Registry Utility Functions
 //
@@ -956,7 +965,7 @@ CmpGetNextName(
 );
 
 //
-// Flush Routines
+// Command Routines (Flush, Open, Close, Init);
 //
 BOOLEAN
 NTAPI
@@ -976,6 +985,16 @@ CmpCmdInit(
     IN BOOLEAN SetupBoot
 );
 
+NTSTATUS
+NTAPI
+CmpCmdHiveOpen(
+    IN POBJECT_ATTRIBUTES FileAttributes,
+    IN PSECURITY_CLIENT_CONTEXT ImpersonationContext,
+    IN OUT PBOOLEAN Allocate,
+    OUT PCMHIVE *NewHive,
+    IN ULONG CheckFlags
+);
+
 VOID
 NTAPI
 CmpLazyFlush(
@@ -1351,7 +1370,7 @@ extern CM_SYSTEM_CONTROL_VECTOR CmControlVector[];
 extern ULONG CmpConfigurationAreaSize;
 extern PCM_FULL_RESOURCE_DESCRIPTOR CmpConfigurationData;
 extern UNICODE_STRING CmTypeName[];
-extern HIVE_LIST_ENTRY CmpMachineHiveList[5];
+extern HIVE_LIST_ENTRY CmpMachineHiveList[];
 extern UNICODE_STRING CmSymbolicLinkValueName;
 extern UNICODE_STRING CmpSystemStartOptions;
 extern UNICODE_STRING CmpLoadOptions;
index 075064d..d56ce62 100644 (file)
@@ -13,9 +13,6 @@
 #define NDEBUG
 #include "debug.h"
 
-NTSTATUS
-CmiFlushRegistryHive(PCMHIVE RegistryHive);
-
 /* FUNCTIONS *****************************************************************/
 
 BOOLEAN
@@ -892,7 +889,7 @@ CmpQueryKeyData(IN PHHIVE Hive,
             Info->KeyFullInformation.MaxNameLen = Node->MaxNameLen;
             Info->KeyFullInformation.MaxClassLen = Node->MaxClassLen;
             Info->KeyFullInformation.MaxValueNameLen = Node->MaxValueNameLen;
-            Info->KeyFullInformation.MaxValueDataLen = Node->MaxValueDataLen;            
+            Info->KeyFullInformation.MaxValueDataLen = Node->MaxValueDataLen;
 
             /* Check if we have a class */
             if (Node->ClassLength > 0)
@@ -1202,3 +1199,121 @@ CmFlushKey(IN PCM_KEY_CONTROL_BLOCK Kcb,
     /* Return the status */
     return Status;
 }
+
+NTSTATUS
+NTAPI
+CmLoadKey(IN POBJECT_ATTRIBUTES TargetKey,
+          IN POBJECT_ATTRIBUTES SourceFile,
+          IN ULONG Flags,
+          IN PKEY_OBJECT KeyBody)
+{
+    SECURITY_QUALITY_OF_SERVICE ServiceQos;
+    SECURITY_CLIENT_CONTEXT ClientSecurityContext;
+    HANDLE KeyHandle;
+    BOOLEAN Allocate = TRUE;
+    PCMHIVE CmHive;
+    NTSTATUS Status;
+    
+    /* Check if we have a trust key */
+    if (KeyBody)
+    {
+        /* Fail */
+        DPRINT1("Trusted classes not yet supported\n");
+        return STATUS_NOT_IMPLEMENTED;
+    }
+    
+    /* Build a service QoS for a security context */
+    ServiceQos.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
+    ServiceQos.ImpersonationLevel = SecurityImpersonation;
+    ServiceQos.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
+    ServiceQos.EffectiveOnly = TRUE;
+    Status = SeCreateClientSecurity(PsGetCurrentThread(),
+                                    &ServiceQos,
+                                    FALSE,
+                                    &ClientSecurityContext);
+    if (!NT_SUCCESS(Status))
+    {
+        /* Fail */
+        DPRINT1("Security context failed\n");
+        return Status;
+    }
+    
+    /* Open the target key */
+    Status = ZwOpenKey(&KeyHandle, KEY_READ, TargetKey);
+    if (!NT_SUCCESS(Status)) KeyHandle = NULL;
+    
+    /* Open the hive */
+    Status = CmpCmdHiveOpen(SourceFile,
+                            &ClientSecurityContext,
+                            &Allocate,
+                            &CmHive,
+                            0);
+
+    /* Get rid of the security context */
+    SeDeleteClientSecurity(&ClientSecurityContext);
+
+    /* See if we failed */
+    if (!NT_SUCCESS(Status))
+    {
+        /* See if the target already existed */
+        if (KeyHandle)
+        {
+            /* Lock the registry */
+            CmpLockRegistryExclusive();
+            
+            /* FIXME: Check if we are already loaded */
+            
+            /* Release the registry */
+            CmpUnlockRegistry();
+        }
+        
+        /* Close the key handle if we had one */
+        if (KeyHandle) ZwClose(KeyHandle);
+        DPRINT1("Failed: %lx\n", Status);
+        return Status;
+    }
+    
+    /* Lock the registry shared */
+    //CmpLockRegistry();
+    
+    /* Lock the hive to this thread */
+    CmHive->Hive.HiveFlags |= HIVE_IS_UNLOADING;
+    CmHive->CreatorOwner = KeGetCurrentThread();
+    
+    /* Set flag */
+    if (Flags & REG_NO_LAZY_FLUSH) CmHive->Hive.HiveFlags |= HIVE_NOLAZYFLUSH;
+    
+    /* Link the hive */
+    Status = CmpLinkHiveToMaster(TargetKey->ObjectName,
+                                 TargetKey->RootDirectory,
+                                 CmHive,
+                                 FALSE,
+                                 TargetKey->SecurityDescriptor);
+    if (NT_SUCCESS(Status))
+    {
+        /* FIXME: Add to HiveList key */
+        
+        /* Sync the hive if necessary */
+        if (Allocate)
+        {
+            /* Sync it */
+            HvSyncHive(&CmHive->Hive);
+        }
+        
+        /* Release the hive */
+        CmHive->Hive.HiveFlags &= ~HIVE_IS_UNLOADING;
+        CmHive->CreatorOwner = NULL;
+    }
+    else
+    {
+        /* FIXME: TODO */
+        
+    }
+    
+    /* Unlock the registry */
+    //CmpUnlockRegistry();
+    
+    /* Close handle and return */
+    if (KeyHandle) ZwClose(KeyHandle);
+    return Status;
+}
index d7c36e9..b5f029a 100644 (file)
@@ -38,7 +38,16 @@ PCM_FULL_RESOURCE_DESCRIPTOR CmpConfigurationData;
 \r
 EX_PUSH_LOCK CmpHiveListHeadLock, CmpLoadHiveLock;\r
 \r
-HIVE_LIST_ENTRY CmpMachineHiveList[5];\r
+HIVE_LIST_ENTRY CmpMachineHiveList[] =\r
+{\r
+    { L"HARDWARE", L"MACHINE\\", NULL, HIVE_VOLATILE    , 0                         ,   NULL,   FALSE,  FALSE,  FALSE},\r
+    { L"SECURITY", L"MACHINE\\", NULL, 0                , 0                         ,   NULL,   FALSE,  FALSE,  FALSE},\r
+    { L"SOFTWARE", L"MACHINE\\", NULL, 0                , 0                         ,   NULL,   FALSE,  FALSE,  FALSE},\r
+    { L"SYSTEM",   L"MACHINE\\", NULL, 0                , 0                         ,   NULL,   FALSE,  FALSE,  FALSE},\r
+    { L"DEFAULT",  L"USER\\.DEFAULT", NULL, 0           , 0   ,   NULL,   FALSE,  FALSE,  FALSE},\r
+    { L"SAM",      L"MACHINE\\", NULL, HIVE_NOLAZYFLUSH , 0                         ,   NULL,   FALSE,  FALSE,  FALSE},\r
+    { NULL,        NULL,         0, 0                   , 0                         ,   NULL,   FALSE,  FALSE,  FALSE}\r
+};\r
 \r
 UNICODE_STRING CmSymbolicLinkValueName =\r
     RTL_CONSTANT_STRING(L"SymbolicLinkValue");\r
index bffe6f5..7b79e85 100644 (file)
@@ -238,6 +238,56 @@ CmpCmdInit(IN BOOLEAN SetupBoot)
     
     /* Testing: Force Lazy Flushing */
     CmpHoldLazyFlush = FALSE;
+    
+    /* Setup the hive list */
+    CmpInitializeHiveList(SetupBoot);
+}
+
+NTSTATUS
+NTAPI
+CmpCmdHiveOpen(IN POBJECT_ATTRIBUTES FileAttributes,
+               IN PSECURITY_CLIENT_CONTEXT ImpersonationContext,
+               IN OUT PBOOLEAN Allocate,
+               OUT PCMHIVE *NewHive,
+               IN ULONG CheckFlags)
+{
+    PUNICODE_STRING FileName;
+    NTSTATUS Status;
+    PAGED_CODE();
+
+    /* Open the file in the current security context */
+    FileName = FileAttributes->ObjectName;
+    Status = CmpInitHiveFromFile(FileName,
+                                 0,
+                                 NewHive,
+                                 Allocate,
+                                                                CheckFlags);
+    if (((Status == STATUS_ACCESS_DENIED) ||
+         (Status == STATUS_NO_SUCH_USER) ||
+         (Status == STATUS_WRONG_PASSWORD) ||
+         (Status == STATUS_ACCOUNT_EXPIRED) ||
+         (Status == STATUS_ACCOUNT_DISABLED) ||
+         (Status == STATUS_ACCOUNT_RESTRICTION)) &&
+        (ImpersonationContext))
+    {
+        /* We failed due to an account/security error, impersonate SYSTEM */
+        Status = SeImpersonateClientEx(ImpersonationContext, NULL);
+        if (NT_SUCCESS(Status))
+        {
+            /* Now try again */
+            Status = CmpInitHiveFromFile(FileName,
+                                         0,
+                                         NewHive,
+                                         Allocate,
+                                                                                CheckFlags);
+            
+            /* Restore impersonation token */
+            PsRevertToSelf();
+        }
+    }
+
+    /* Return status of open attempt */
+    return Status;
 }
 
 VOID
index 53e8571..15aaa4e 100644 (file)
@@ -416,3 +416,299 @@ Exit:
     ExReleasePushLock((PVOID)&((PCMHIVE)Hive)->FlusherLock);\r
     return Status;\r
 }\r
+\r
+NTSTATUS\r
+NTAPI\r
+CmpDoOpen(IN PHHIVE Hive,\r
+          IN HCELL_INDEX Cell,\r
+          IN PCM_KEY_NODE Node,\r
+          IN PACCESS_STATE AccessState,\r
+          IN KPROCESSOR_MODE AccessMode,\r
+          IN ULONG Attributes,\r
+          IN PCM_PARSE_CONTEXT Context OPTIONAL,\r
+          IN ULONG ControlFlags,\r
+          IN OUT PCM_KEY_CONTROL_BLOCK *CachedKcb,\r
+          IN PUNICODE_STRING KeyName,\r
+          OUT PVOID *Object)\r
+{\r
+    NTSTATUS Status;\r
+    PKEY_OBJECT KeyBody = NULL;\r
+    PCM_KEY_CONTROL_BLOCK Kcb = NULL;\r
+\r
+    /* Make sure the hive isn't locked */\r
+    if ((Hive->HiveFlags & HIVE_IS_UNLOADING) &&\r
+        (((PCMHIVE)Hive)->CreatorOwner != KeGetCurrentThread()))\r
+    {\r
+        /* It is, don't touch it */\r
+        return STATUS_OBJECT_NAME_NOT_FOUND;\r
+    }\r
+\r
+    /* If we have a KCB, make sure it's locked */\r
+    ASSERT(CmpIsKcbLockedExclusive(*CachedKcb));\r
+\r
+    /* Create the KCB */\r
+    Kcb = CmpCreateKeyControlBlock(Hive, Cell, Node, *CachedKcb, 0, KeyName);\r
+    if (!Kcb) return STATUS_INSUFFICIENT_RESOURCES;\r
+\r
+    /* Make sure it's also locked, and set the pointer */\r
+    ASSERT(CmpIsKcbLockedExclusive(Kcb));\r
+    *CachedKcb = Kcb;\r
+\r
+    /* Allocate the key object */\r
+    Status = ObCreateObject(AccessMode,\r
+                            CmpKeyObjectType,\r
+                            NULL,\r
+                            AccessMode,\r
+                            NULL,\r
+                            sizeof(KEY_OBJECT),\r
+                            0,\r
+                            0,\r
+                            Object);\r
+    if (NT_SUCCESS(Status))\r
+    {\r
+        /* Get the key body and fill it out */\r
+        KeyBody = (PKEY_OBJECT)(*Object);       \r
+        KeyBody->KeyControlBlock = Kcb;\r
+        KeyBody->SubKeyCounts = 0;\r
+        KeyBody->SubKeys = NULL;\r
+        KeyBody->SizeOfSubKeys = 0;\r
+        InsertTailList(&CmiKeyObjectListHead, &KeyBody->KeyBodyList);\r
+    }\r
+    else\r
+    {\r
+        /* Failed, dereference the KCB */\r
+        CmpDereferenceKeyControlBlockWithLock(Kcb, FALSE);\r
+    }\r
+\r
+    /* Return status */\r
+    return Status;\r
+}\r
+\r
+/* Remove calls to CmCreateRootNode once this is used! */\r
+NTSTATUS\r
+NTAPI\r
+CmpCreateLinkNode(IN PHHIVE Hive,\r
+                  IN HCELL_INDEX Cell,\r
+                  IN PACCESS_STATE AccessState,\r
+                  IN UNICODE_STRING Name,\r
+                  IN KPROCESSOR_MODE AccessMode,\r
+                  IN ULONG CreateOptions,\r
+                  IN PCM_PARSE_CONTEXT Context,\r
+                  IN PCM_KEY_CONTROL_BLOCK ParentKcb,\r
+                  OUT PVOID *Object)\r
+{\r
+    NTSTATUS Status;\r
+    HCELL_INDEX KeyCell, LinkCell, ChildCell;\r
+    PKEY_OBJECT KeyBody;\r
+    LARGE_INTEGER TimeStamp;\r
+    PCM_KEY_NODE KeyNode;\r
+    PCM_KEY_CONTROL_BLOCK Kcb = ParentKcb;\r
+    \r
+    /* Link nodes only allowed on the master */\r
+    if (Hive != &CmiVolatileHive->Hive)\r
+    {\r
+        /* Fail */\r
+        DPRINT1("Invalid link node attempt\n");\r
+        return STATUS_ACCESS_DENIED;\r
+    }\r
+    \r
+    /* Acquire the flusher locks */\r
+    ExAcquirePushLockShared((PVOID)&((PCMHIVE)Hive)->FlusherLock);\r
+    ExAcquirePushLockShared((PVOID)&((PCMHIVE)Context->ChildHive.KeyHive)->FlusherLock);\r
+\r
+    /* Check if the parent is being deleted */\r
+    if (ParentKcb->Delete)\r
+    {\r
+        /* It is, quit */\r
+        ASSERT(FALSE);\r
+        Status = STATUS_OBJECT_NAME_NOT_FOUND;\r
+        goto Exit;\r
+    }\r
+    \r
+    /* Allocate a link node */\r
+    LinkCell = HvAllocateCell(Hive,\r
+                              FIELD_OFFSET(CM_KEY_NODE, Name) +\r
+                              CmpNameSize(Hive, &Name),\r
+                              Stable,\r
+                              HCELL_NIL);\r
+    if (LinkCell == HCELL_NIL)\r
+    {\r
+        /* Fail */\r
+        Status = STATUS_INSUFFICIENT_RESOURCES;\r
+        goto Exit;\r
+    }\r
+    \r
+    /* Get the key cell */\r
+    KeyCell = Context->ChildHive.KeyCell;\r
+    if (KeyCell != HCELL_NIL)\r
+    {\r
+        /* Hive exists! */\r
+        ChildCell = KeyCell;\r
+        \r
+        /* Get the node data */\r
+        KeyNode = (PCM_KEY_NODE)HvGetCell(Context->ChildHive.KeyHive, ChildCell);\r
+        if (!KeyNode)\r
+        {\r
+            /* Fail */\r
+            ASSERT(FALSE);\r
+            Status = STATUS_INSUFFICIENT_RESOURCES;\r
+            goto Exit;\r
+        }\r
+        \r
+        /* Fill out the data */\r
+        KeyNode->Parent = LinkCell;\r
+        KeyNode->Flags |= KEY_HIVE_ENTRY | KEY_NO_DELETE;\r
+        HvReleaseCell(Context->ChildHive.KeyHive, ChildCell);\r
+        \r
+        /* Now open the key cell */\r
+        KeyNode = (PCM_KEY_NODE)HvGetCell(Context->ChildHive.KeyHive, KeyCell);\r
+        if (!KeyNode)\r
+        {\r
+            /* Fail */\r
+            ASSERT(FALSE);\r
+            Status = STATUS_INSUFFICIENT_RESOURCES;\r
+            goto Exit;\r
+        }\r
+        \r
+        /* Open the parent */\r
+        Status = CmpDoOpen(Context->ChildHive.KeyHive,\r
+                           KeyCell,\r
+                           KeyNode,\r
+                           AccessState,\r
+                           AccessMode,\r
+                           CreateOptions,\r
+                           NULL,\r
+                           0,\r
+                           &Kcb,\r
+                           &Name,\r
+                           Object);\r
+        HvReleaseCell(Context->ChildHive.KeyHive, KeyCell);\r
+    }\r
+    else\r
+    {\r
+        /* Do the actual create operation */\r
+        Status = CmpDoCreateChild(Context->ChildHive.KeyHive,\r
+                                  Cell,\r
+                                  NULL,\r
+                                  AccessState,\r
+                                  &Name,\r
+                                  AccessMode,\r
+                                  &Context->Class,\r
+                                  ParentKcb,\r
+                                  KEY_HIVE_ENTRY | KEY_NO_DELETE,\r
+                                  &ChildCell,\r
+                                  Object);\r
+        if (NT_SUCCESS(Status))\r
+        {\r
+            /* Setup root pointer */\r
+            Context->ChildHive.KeyHive->BaseBlock->RootCell = ChildCell;\r
+        }\r
+    }\r
+    \r
+    /* Check if open or create suceeded */\r
+    if (NT_SUCCESS(Status))\r
+    {\r
+        /* Mark the cell dirty */\r
+        HvMarkCellDirty(Context->ChildHive.KeyHive, ChildCell, FALSE);\r
+        \r
+        /* Get the key node */\r
+        KeyNode = HvGetCell(Context->ChildHive.KeyHive, ChildCell);\r
+        if (!KeyNode)\r
+        {\r
+            /* Fail */\r
+            ASSERT(FALSE);\r
+            Status = STATUS_INSUFFICIENT_RESOURCES;\r
+            goto Exit;\r
+        }\r
+        \r
+        /* Release it */\r
+        HvReleaseCell(Context->ChildHive.KeyHive, ChildCell);\r
+        \r
+        /* Set the parent adn flags */\r
+        KeyNode->Parent = LinkCell;\r
+        KeyNode->Flags |= KEY_HIVE_ENTRY | KEY_NO_DELETE;\r
+        \r
+        /* Get the link node */\r
+        KeyNode = HvGetCell(Hive, LinkCell);\r
+        if (!KeyNode)\r
+        {\r
+            /* Fail */\r
+            ASSERT(FALSE);\r
+            Status = STATUS_INSUFFICIENT_RESOURCES;\r
+            goto Exit;\r
+        }\r
+        \r
+        /* Set it up */\r
+        KeyNode->Signature = CM_LINK_NODE_SIGNATURE;\r
+        KeyNode->Flags = KEY_HIVE_EXIT | KEY_NO_DELETE;\r
+        KeyNode->Parent = Cell;\r
+        KeyNode->NameLength = CmpCopyName(Hive, KeyNode->Name, &Name);\r
+        if (KeyNode->NameLength < Name.Length) KeyNode->Flags |= KEY_COMP_NAME;\r
+        KeQuerySystemTime(&TimeStamp);\r
+        KeyNode->LastWriteTime = TimeStamp;\r
+        \r
+        /* Clear out the rest */\r
+        KeyNode->SubKeyCounts[Stable] = 0;\r
+        KeyNode->SubKeyCounts[Volatile] = 0;\r
+        KeyNode->SubKeyLists[Stable] = HCELL_NIL;\r
+        KeyNode->SubKeyLists[Volatile] = HCELL_NIL;\r
+        KeyNode->ValueList.Count = 0;\r
+        KeyNode->ValueList.List = HCELL_NIL;\r
+        KeyNode->ClassLength = 0;\r
+        \r
+        /* Reference the root node */\r
+        //KeyNode->ChildHiveReference.KeyHive = Context->ChildHive.KeyHive;\r
+        //KeyNode->ChildHiveReference.KeyCell = ChildCell;\r
+        HvReleaseCell(Hive, LinkCell);\r
+        \r
+        /* Get the parent node */\r
+        KeyNode = HvGetCell(Hive, Cell);\r
+        if (!KeyNode)\r
+        {\r
+            /* Fail */\r
+            ASSERT(FALSE);\r
+            Status = STATUS_INSUFFICIENT_RESOURCES;\r
+            goto Exit;  \r
+        }\r
+        \r
+        /* Now add the subkey */\r
+        if (!CmpAddSubKey(Hive, Cell, LinkCell))\r
+        {\r
+            /* Failure! We don't handle this yet! */\r
+            ASSERT(FALSE);\r
+        }\r
+        \r
+        /* Get the key body */\r
+        KeyBody = (PKEY_OBJECT)*Object;\r
+\r
+        /* Sanity checks */\r
+        ASSERT(KeyBody->KeyControlBlock->ParentKcb->KeyCell == Cell);\r
+        ASSERT(KeyBody->KeyControlBlock->ParentKcb->KeyHive == Hive);\r
+        //ASSERT(KeyBody->KeyControlBlock->ParentKcb->KcbMaxNameLen == KeyNode->MaxNameLen);\r
+        \r
+        /* Update the timestamp */\r
+        KeQuerySystemTime(&TimeStamp);\r
+        KeyNode->LastWriteTime = TimeStamp;\r
+        \r
+        /* Check if we need to update name maximum */\r
+        if (KeyNode->MaxNameLen < Name.Length)\r
+        {\r
+            /* Do it */\r
+            KeyNode->MaxNameLen = Name.Length;\r
+            KeyBody->KeyControlBlock->ParentKcb->KcbMaxNameLen = Name.Length;\r
+        }\r
+        \r
+        /* Check if we need toupdate class length maximum */\r
+        if (KeyNode->MaxClassLen < Context->Class.Length)\r
+        {\r
+            /* Update it */\r
+            KeyNode->MaxClassLen = Context->Class.Length;\r
+        }\r
+    }\r
+    \r
+Exit:\r
+    /* Release the flusher locks and return status */\r
+    ExReleasePushLock((PVOID)&((PCMHIVE)Context->ChildHive.KeyHive)->FlusherLock);\r
+    ExReleasePushLock((PVOID)&((PCMHIVE)Hive)->FlusherLock);\r
+    return Status;\r
+}\r
index 9a7434b..605c2fc 100644 (file)
@@ -15,6 +15,8 @@
 \r
 KGUARDED_MUTEX CmpSelfHealQueueLock;\r
 LIST_ENTRY CmpSelfHealQueueListHead;\r
+KEVENT CmpLoadWorkerEvent;\r
+LONG CmpLoadWorkerIncrement;\r
 PEPROCESS CmpSystemProcess;\r
 BOOLEAN HvShutdownComplete;\r
 PVOID CmpRegistryLockCallerCaller, CmpRegistryLockCaller;\r
@@ -496,11 +498,11 @@ CmpInitializeSystemHive(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
     }\r
     else\r
     {\r
-#if 0\r
         /* Create it */\r
-        Status = CmpInitializeHive((PCMHIVE*)&SystemHive,\r
+#if 0\r
+        Status = CmpInitializeHive(&SystemHive,\r
                                    HINIT_CREATE,\r
-                                   HIVE_NOLAZYFLUSH,\r
+                                   0, //HIVE_NOLAZYFLUSH,\r
                                    HFILE_TYPE_LOG,\r
                                    NULL,\r
                                    NULL,\r
@@ -509,8 +511,10 @@ CmpInitializeSystemHive(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
                                    &HiveName,\r
                                    0);\r
         if (!NT_SUCCESS(Status)) return FALSE;\r
+        \r
+        /* Set the hive filename */\r
+        RtlCreateUnicodeString(&SystemHive->FileFullPath, SYSTEM_REG_FILE);\r
 #endif\r
-\r
         /* Tell CmpLinkHiveToMaster to allocate a hive */\r
         Allocate = TRUE;\r
     }\r
@@ -746,6 +750,314 @@ CmpCreateRegistryRoot(VOID)
     return TRUE;\r
 }\r
 \r
+VOID\r
+NTAPI\r
+CmpLoadHiveThread(IN PVOID StartContext)\r
+{\r
+    WCHAR FileBuffer[MAX_PATH], RegBuffer[MAX_PATH];\r
+    UNICODE_STRING TempName, FileName, RegName;\r
+    ULONG FileStart, RegStart, i, ErrorResponse, ClusterSize, WorkerCount;\r
+    ULONG PrimaryDisposition, SecondaryDisposition, Length;\r
+    PCMHIVE CmHive;\r
+    HANDLE PrimaryHandle, LogHandle;\r
+    NTSTATUS Status = STATUS_SUCCESS;\r
+    PVOID ErrorParameters;\r
+    PAGED_CODE();\r
+    \r
+    /* Get the hive index, make sure it makes sense */\r
+    i = (ULONG)StartContext;\r
+    ASSERT(CmpMachineHiveList[i].Name != NULL);\r
+    DPRINT1("[HiveLoad] Parallel Thread: %d\n", i);\r
+    \r
+    /* We were started */\r
+    CmpMachineHiveList[i].ThreadStarted = TRUE;\r
+    \r
+    /* Build the file name and registry name strings */\r
+    RtlInitEmptyUnicodeString(&FileName, FileBuffer, MAX_PATH);\r
+    RtlInitEmptyUnicodeString(&RegName, RegBuffer, MAX_PATH);\r
+    \r
+    /* Now build the system root path */\r
+    RtlInitUnicodeString(&TempName, L"\\SystemRoot\\System32\\Config\\");\r
+    RtlAppendStringToString((PSTRING)&FileName, (PSTRING)&TempName);\r
+    FileStart = FileName.Length;\r
+    \r
+    /* And build the registry root path */\r
+    RtlInitUnicodeString(&TempName, L"\\REGISTRY\\");\r
+    RtlAppendStringToString((PSTRING)&RegName, (PSTRING)&TempName);\r
+    RegStart = RegName.Length;\r
+    \r
+    /* Build the base name */\r
+    RegName.Length = RegStart;\r
+    RtlInitUnicodeString(&TempName, CmpMachineHiveList[i].BaseName);\r
+    RtlAppendStringToString((PSTRING)&RegName, (PSTRING)&TempName);\r
+    \r
+    /* Check if this is a child of the root */\r
+    if (RegName.Buffer[RegName.Length / sizeof(WCHAR) - 1] == '\\')\r
+    {\r
+        /* Then setup the whole name */\r
+        RtlInitUnicodeString(&TempName, CmpMachineHiveList[i].Name);\r
+        RtlAppendStringToString((PSTRING)&RegName, (PSTRING)&TempName);\r
+    }\r
+    \r
+    /* Now Add tge rest if the file name */\r
+    RtlInitUnicodeString(&TempName, CmpMachineHiveList[i].Name);\r
+    FileName.Length = FileStart;\r
+    RtlAppendStringToString((PSTRING)&FileName, (PSTRING)&TempName);\r
+    if (!CmpMachineHiveList[i].CmHive)\r
+    {\r
+        /* We need to allocate a ne whive structure */\r
+        CmpMachineHiveList[i].Allocate = TRUE;\r
+        \r
+        /* Load the hive file */\r
+        DPRINT1("[HiveLoad]: Load from file %wZ\n", &FileName);\r
+        CmpMachineHiveList[i].CmHive2 = (PVOID)0xBAADBEEF;\r
+        goto Later;\r
+        Status = CmpInitHiveFromFile(&FileName,\r
+                                     CmpMachineHiveList[i].HHiveFlags,\r
+                                     &CmHive,\r
+                                     &CmpMachineHiveList[i].Allocate,\r
+                                     0);\r
+        if (!(NT_SUCCESS(Status)) || !(CmHive->FileHandles[HFILE_TYPE_LOG]))\r
+        {\r
+            /* We failed or couldn't get a log file, raise a hard error */\r
+            ErrorParameters = &FileName;\r
+            NtRaiseHardError(STATUS_CANNOT_LOAD_REGISTRY_FILE,\r
+                             1,\r
+                             1,\r
+                             (PULONG_PTR)&ErrorParameters,\r
+                             OptionOk,\r
+                             &ErrorResponse);\r
+        }\r
+        \r
+        /* Set the hive flags and newly allocated hive pointer */\r
+        CmHive->Flags = CmpMachineHiveList[i].CmHiveFlags;\r
+        CmpMachineHiveList[i].CmHive2 = CmHive;\r
+    }\r
+    else\r
+    {\r
+        /* We already have a hive, is it volatile? */\r
+        CmHive = CmpMachineHiveList[i].CmHive;\r
+        if (!(CmHive->Hive.HiveFlags & HIVE_VOLATILE))\r
+        {\r
+            DPRINT1("[HiveLoad]: Open from file %wZ\n", &FileName);\r
+            CmpMachineHiveList[i].CmHive2 = CmHive;\r
+            goto Later;\r
+            \r
+            /* It's now, open the hive file and log */\r
+            Status = CmpOpenHiveFiles(&FileName,\r
+                                      L".LOG",\r
+                                      &PrimaryHandle,\r
+                                      &LogHandle,\r
+                                      &PrimaryDisposition,\r
+                                      &SecondaryDisposition,\r
+                                      TRUE,\r
+                                      TRUE,\r
+                                      FALSE,\r
+                                      &ClusterSize);\r
+            if (!(NT_SUCCESS(Status)) || !(LogHandle))\r
+            {\r
+                /* Couldn't open the hive or its log file, raise a hard error */\r
+                ErrorParameters = &FileName;\r
+                NtRaiseHardError(STATUS_CANNOT_LOAD_REGISTRY_FILE,\r
+                                 1,\r
+                                 1,\r
+                                 (PULONG_PTR)&ErrorParameters,\r
+                                 OptionOk,\r
+                                 &ErrorResponse);\r
+                \r
+                /* And bugcheck for posterity's sake */\r
+                KeBugCheckEx(BAD_SYSTEM_CONFIG_INFO, 9, 0, i, Status);\r
+            }\r
+            \r
+            /* Save the file handles. This should remove our sync hacks */\r
+            CmHive->FileHandles[HFILE_TYPE_LOG] = LogHandle;\r
+            CmHive->FileHandles[HFILE_TYPE_PRIMARY] = PrimaryHandle;\r
+            \r
+            /* Allow lazy flushing since the handles are there -- remove sync hacks */\r
+            ASSERT(CmHive->Hive.HiveFlags & HIVE_NOLAZYFLUSH);\r
+            CmHive->Hive.HiveFlags &= ~HIVE_NOLAZYFLUSH;\r
+            \r
+            /* Get the real size of the hive */\r
+            Length = CmHive->Hive.Storage[Stable].Length + HBLOCK_SIZE;\r
+            \r
+            /* Check if the cluster size doesn't match */\r
+            if (CmHive->Hive.Cluster != ClusterSize) ASSERT(FALSE);\r
+            \r
+            /* Set the file size */\r
+            if (!CmpFileSetSize((PHHIVE)CmHive, HFILE_TYPE_PRIMARY, Length, Length))\r
+            {\r
+                /* This shouldn't fail */\r
+                ASSERT(FALSE);\r
+            }\r
+            \r
+            /* Another thing we don't support is NTLDR-recovery */\r
+            if (CmHive->Hive.BaseBlock->BootRecover) ASSERT(FALSE);\r
+            \r
+            /* Finally, set our allocated hive to the same hive we've had */\r
+            CmpMachineHiveList[i].CmHive2 = CmHive;\r
+            ASSERT(CmpMachineHiveList[i].CmHive == CmpMachineHiveList[i].CmHive2);\r
+        }\r
+    }\r
+    \r
+    /* We're done */\r
+Later:\r
+    CmpMachineHiveList[i].ThreadFinished = TRUE;\r
+    \r
+    /* Check if we're the last worker */\r
+    WorkerCount = InterlockedIncrement(&CmpLoadWorkerIncrement);\r
+    if (WorkerCount == CM_NUMBER_OF_MACHINE_HIVES)\r
+    \r
+    {\r
+        /* Signal the event */\r
+        KeSetEvent(&CmpLoadWorkerEvent, 0, FALSE);\r
+    }\r
+\r
+    /* Kill the thread */\r
+    PsTerminateSystemThread(Status);\r
+}\r
+\r
+VOID\r
+NTAPI\r
+CmpInitializeHiveList(IN USHORT Flag)\r
+{\r
+    WCHAR FileBuffer[MAX_PATH], RegBuffer[MAX_PATH];\r
+    UNICODE_STRING TempName, FileName, RegName;\r
+    HANDLE Thread;\r
+    NTSTATUS Status;\r
+    ULONG FileStart, RegStart, i;\r
+    PSECURITY_DESCRIPTOR SecurityDescriptor;\r
+    PAGED_CODE();\r
+    \r
+    /* Allow writing for now */\r
+    CmpNoWrite = FALSE;\r
+    \r
+    /* Build the file name and registry name strings */\r
+    RtlInitEmptyUnicodeString(&FileName, FileBuffer, MAX_PATH);\r
+    RtlInitEmptyUnicodeString(&RegName, RegBuffer, MAX_PATH);\r
+    \r
+    /* Now build the system root path */\r
+    RtlInitUnicodeString(&TempName, L"\\SystemRoot\\System32\\Config\\");\r
+    RtlAppendStringToString((PSTRING)&FileName, (PSTRING)&TempName);\r
+    FileStart = FileName.Length;\r
+    \r
+    /* And build the registry root path */\r
+    RtlInitUnicodeString(&TempName, L"\\REGISTRY\\");\r
+    RtlAppendStringToString((PSTRING)&RegName, (PSTRING)&TempName);\r
+    RegStart = RegName.Length;\r
+    \r
+    /* Setup the event to synchronize workers */\r
+    KeInitializeEvent(&CmpLoadWorkerEvent, SynchronizationEvent, FALSE);\r
+    \r
+    /* Enter special boot condition */\r
+    CmpSpecialBootCondition = TRUE;\r
+    \r
+    /* Create the SD for the root hives */\r
+    SecurityDescriptor = CmpHiveRootSecurityDescriptor();      \r
+    \r
+    /* Loop every hive we care about */\r
+    for (i = 0; i < CM_NUMBER_OF_MACHINE_HIVES; i++)\r
+    {\r
+        /* Make sure the list is setup */\r
+        ASSERT(CmpMachineHiveList[i].Name != NULL);\r
+        \r
+        /* Create a thread to handle this hive */\r
+        Status = PsCreateSystemThread(&Thread,\r
+                                      THREAD_ALL_ACCESS,\r
+                                      NULL,\r
+                                      0,\r
+                                      NULL,\r
+                                      CmpLoadHiveThread,\r
+                                      (PVOID)i);\r
+        if (NT_SUCCESS(Status))\r
+        {\r
+            /* We don't care about the handle -- the thread self-terminates */\r
+            ZwClose(Thread);\r
+        }\r
+        else\r
+        {\r
+            /* Can't imagine this happening */\r
+            KeBugCheckEx(BAD_SYSTEM_CONFIG_INFO, 9, 3, i, Status);\r
+        }\r
+    }\r
+    \r
+    /* Make sure we've reached the end of the list */\r
+    ASSERT(CmpMachineHiveList[i].Name == NULL);\r
+    \r
+    /* Wait for hive loading to finish */\r
+    KeWaitForSingleObject(&CmpLoadWorkerEvent,\r
+                          Executive,\r
+                          KernelMode,\r
+                          FALSE,\r
+                          NULL);\r
+    \r
+    /* Exit the special boot condition and make sure all workers completed */\r
+    CmpSpecialBootCondition = FALSE;\r
+    ASSERT(CmpLoadWorkerIncrement == CM_NUMBER_OF_MACHINE_HIVES);\r
+    \r
+    /* Loop hives again */\r
+    for (i = 0; i < CM_NUMBER_OF_MACHINE_HIVES; i++)\r
+    {\r
+        /* Make sure the thread ran and finished */\r
+        ASSERT(CmpMachineHiveList[i].ThreadFinished == TRUE);\r
+        ASSERT(CmpMachineHiveList[i].ThreadStarted == TRUE);\r
+        \r
+        /* Check if this was a new hive */\r
+        if (!CmpMachineHiveList[i].CmHive)\r
+        {\r
+            /* Make sure we allocated something */\r
+            ASSERT(CmpMachineHiveList[i].CmHive2 != NULL);\r
+            \r
+            /* Build the base name */\r
+            RegName.Length = RegStart;\r
+            RtlInitUnicodeString(&TempName, CmpMachineHiveList[i].BaseName);\r
+            RtlAppendStringToString((PSTRING)&RegName, (PSTRING)&TempName);\r
+            \r
+            /* Check if this is a child of the root */\r
+            if (RegName.Buffer[RegName.Length / sizeof(WCHAR) - 1] == '\\')\r
+            {\r
+                /* Then setup the whole name */\r
+                RtlInitUnicodeString(&TempName, CmpMachineHiveList[i].Name);\r
+                RtlAppendStringToString((PSTRING)&RegName, (PSTRING)&TempName);\r
+            }\r
+            \r
+            /* Now link the hive to its master */\r
+            DPRINT1("[HiveLoad]: Link %wZ\n", &RegName);\r
+#if 0\r
+            Status = CmpLinkHiveToMaster(&RegName,\r
+                                         NULL,\r
+                                         CmpMachineHiveList[i].CmHive2,\r
+                                         CmpMachineHiveList[i].Allocate,\r
+                                         SecurityDescriptor);\r
+            if (Status != STATUS_SUCCESS)\r
+            {\r
+                /* Linking needs to work */\r
+                KeBugCheckEx(CONFIG_LIST_FAILED, 11, Status, i, (ULONG_PTR)&RegName);\r
+            }\r
+            \r
+            /* Check if we had to allocate a new hive */\r
+                       if (CmpMachineHiveList[i].Allocate)\r
+            {\r
+                /* Sync the new hive */\r
+                               HvSyncHive((PHHIVE)(CmpMachineHiveList[i].CmHive2));\r
+                       }\r
+#endif      \r
+        }\r
+        \r
+        /* Check if we created a new hive */\r
+        if (CmpMachineHiveList[i].CmHive2)\r
+        {\r
+            /* TODO: Add to HiveList key */\r
+        }\r
+    }\r
+    \r
+    /* Get rid of the SD */\r
+    ExFreePool(SecurityDescriptor);\r
+\r
+    /* FIXME: Link SECURITY to SAM */\r
+    \r
+    /* FIXME: Link S-1-5-18 to .Default */\r
+}\r
+\r
 BOOLEAN\r
 NTAPI\r
 CmInitSystem1(VOID)\r
index 7e6dbde..e8c455c 100644 (file)
@@ -492,18 +492,71 @@ NtLoadKey(IN POBJECT_ATTRIBUTES KeyObjectAttributes,
     return NtLoadKey2(KeyObjectAttributes, FileObjectAttributes, 0);
 }
 
+NTSTATUS
+NTAPI
+NtLoadKey2(IN POBJECT_ATTRIBUTES KeyObjectAttributes,
+           IN POBJECT_ATTRIBUTES FileObjectAttributes,
+           IN ULONG Flags)
+{
+    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,
             IN POBJECT_ATTRIBUTES SourceFile,
             IN ULONG Flags,
-            IN HANDLE TrustClassKey,
-            IN HANDLE Event,
-            IN ACCESS_MASK DesiredAccess,
-            OUT PHANDLE RootHandle)
+            IN HANDLE TrustClassKey)
 {
-    UNIMPLEMENTED;
-    return STATUS_NOT_IMPLEMENTED;
+    NTSTATUS Status;
+    KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
+    PKEY_OBJECT 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;
+    }
+    
+    /* Block APCs */
+    KeEnterCriticalRegion();
+    
+    /* Check if we have a trust class */
+    if (TrustClassKey)
+    {
+        /* Reference it */
+        Status = ObReferenceObjectByHandle(TrustClassKey,
+                                           0,
+                                           CmpKeyObjectType,
+                                           PreviousMode,
+                                           (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
index 6048c56..88115e2 100644 (file)
        </directory>
        <directory name="cm">
                <file>ntfunc.c</file>
-               <file>regfile.c</file>
                <file>registry.c</file>
                <file>regobj.c</file>
        </directory>
index 7e0ca01..8332224 100644 (file)
@@ -101,7 +101,7 @@ NtListenPort 2
 NtLoadDriver 1
 NtLoadKey 2
 NtLoadKey2 3
-NtLoadKeyEx 7
+NtLoadKeyEx 4
 NtLockFile 10
 NtLockProductActivationKeys 2
 NtLockRegistryKey 1