2 * PROJECT: ReactOS Kernel
3 * LICENSE: BSD - See COPYING.ARM in the top level directory
4 * FILE: ntoskrnl/config/cmsysini.c
5 * PURPOSE: Configuration Manager - System Initialization Code
6 * PROGRAMMERS: ReactOS Portable Systems Group
7 * Alex Ionescu (alex.ionescu@reactos.org)
10 /* INCLUDES *******************************************************************/
16 POBJECT_TYPE CmpKeyObjectType
;
17 PCMHIVE CmiVolatileHive
;
18 LIST_ENTRY CmpHiveListHead
;
19 ERESOURCE CmpRegistryLock
;
20 KGUARDED_MUTEX CmpSelfHealQueueLock
;
21 LIST_ENTRY CmpSelfHealQueueListHead
;
22 KEVENT CmpLoadWorkerEvent
;
23 LONG CmpLoadWorkerIncrement
;
24 PEPROCESS CmpSystemProcess
;
25 BOOLEAN HvShutdownComplete
;
26 PVOID CmpRegistryLockCallerCaller
, CmpRegistryLockCaller
;
27 BOOLEAN CmpFlushOnLockRelease
;
28 BOOLEAN CmpSpecialBootCondition
;
30 BOOLEAN CmpWasSetupBoot
;
31 BOOLEAN CmpProfileLoaded
;
32 BOOLEAN CmpNoVolatileCreates
;
33 ULONG CmpTraceLevel
= 0;
35 extern LONG CmpFlushStarveWriters
;
36 extern BOOLEAN CmFirstTime
;
38 /* FUNCTIONS ******************************************************************/
43 _In_z_ PCWSTR LinkKeyName
,
44 _In_z_ PCWSTR TargetKeyName
)
47 OBJECT_ATTRIBUTES ObjectAttributes
;
48 UNICODE_STRING KeyName
;
54 /* Initialize the object attributes */
55 RtlInitUnicodeString(&KeyName
, LinkKeyName
);
56 InitializeObjectAttributes(&ObjectAttributes
,
58 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
62 /* Create the link key */
63 Status
= ZwCreateKey(&LinkKeyHandle
,
68 REG_OPTION_VOLATILE
| REG_OPTION_CREATE_LINK
,
70 if (!NT_SUCCESS(Status
))
72 DPRINT1("CM: CmpLinkKeyToHive: couldn't create %S, Status = 0x%lx\n",
77 /* Check if the new key was actually created */
78 if (Disposition
!= REG_CREATED_NEW_KEY
)
80 DPRINT1("CM: CmpLinkKeyToHive: %S already exists!\n", LinkKeyName
);
81 ZwClose(LinkKeyHandle
);
85 /* Set the target key name as link target */
86 RtlInitUnicodeString(&KeyName
, TargetKeyName
);
87 Status
= ZwSetValueKey(LinkKeyHandle
,
88 &CmSymbolicLinkValueName
,
94 /* Close the link key handle */
95 ObCloseHandle(LinkKeyHandle
, KernelMode
);
97 if (!NT_SUCCESS(Status
))
99 DPRINT1("CM: CmpLinkKeyToHive: couldn't create symbolic link for %S, Status = 0x%lx\n",
100 TargetKeyName
, Status
);
109 CmpDeleteKeyObject(PVOID DeletedObject
)
111 PCM_KEY_BODY KeyBody
= (PCM_KEY_BODY
)DeletedObject
;
112 PCM_KEY_CONTROL_BLOCK Kcb
;
113 REG_KEY_HANDLE_CLOSE_INFORMATION KeyHandleCloseInfo
;
114 REG_POST_OPERATION_INFORMATION PostOperationInfo
;
118 /* First off, prepare the handle close information callback */
119 PostOperationInfo
.Object
= KeyBody
;
120 KeyHandleCloseInfo
.Object
= KeyBody
;
121 Status
= CmiCallRegisteredCallbacks(RegNtPreKeyHandleClose
,
122 &KeyHandleCloseInfo
);
123 if (!NT_SUCCESS(Status
))
125 /* If we failed, notify the post routine */
126 PostOperationInfo
.Status
= Status
;
127 CmiCallRegisteredCallbacks(RegNtPostKeyHandleClose
, &PostOperationInfo
);
131 /* Acquire hive lock */
134 /* Make sure this is a valid key body */
135 if (KeyBody
->Type
== CM_KEY_BODY_TYPE
)
138 Kcb
= KeyBody
->KeyControlBlock
;
142 DelistKeyBodyFromKCB(KeyBody
, FALSE
);
144 /* Dereference the KCB */
145 CmpDelayDerefKeyControlBlock(Kcb
);
149 /* Release the registry lock */
152 /* Do the post callback */
153 PostOperationInfo
.Status
= STATUS_SUCCESS
;
154 CmiCallRegisteredCallbacks(RegNtPostKeyHandleClose
, &PostOperationInfo
);
159 CmpCloseKeyObject(IN PEPROCESS Process OPTIONAL
,
161 IN ACCESS_MASK GrantedAccess
,
162 IN ULONG ProcessHandleCount
,
163 IN ULONG SystemHandleCount
)
165 PCM_KEY_BODY KeyBody
= (PCM_KEY_BODY
)Object
;
168 /* Don't do anything if we're not the last handle */
169 if (SystemHandleCount
> 1) return;
171 /* Make sure we're a valid key body */
172 if (KeyBody
->Type
== CM_KEY_BODY_TYPE
)
174 /* Don't do anything if we don't have a notify block */
175 if (!KeyBody
->NotifyBlock
) return;
177 /* This shouldn't happen yet */
184 CmpQueryKeyName(IN PVOID ObjectBody
,
186 IN OUT POBJECT_NAME_INFORMATION ObjectNameInfo
,
188 OUT PULONG ReturnLength
,
189 IN KPROCESSOR_MODE PreviousMode
)
191 PUNICODE_STRING KeyName
;
193 NTSTATUS Status
= STATUS_SUCCESS
;
194 PCM_KEY_BODY KeyBody
= (PCM_KEY_BODY
)ObjectBody
;
195 PCM_KEY_CONTROL_BLOCK Kcb
= KeyBody
->KeyControlBlock
;
197 /* Acquire hive lock */
200 /* Lock KCB shared */
201 CmpAcquireKcbLockShared(Kcb
);
203 /* Check if it's a deleted block */
206 /* Release the locks */
207 CmpReleaseKcbLock(Kcb
);
210 /* Let the caller know it's deleted */
211 return STATUS_KEY_DELETED
;
215 KeyName
= CmpConstructName(Kcb
);
217 /* Release the locks */
218 CmpReleaseKcbLock(Kcb
);
221 /* Check if we got the name */
222 if (!KeyName
) return STATUS_INSUFFICIENT_RESOURCES
;
224 /* Set the returned length */
225 *ReturnLength
= KeyName
->Length
+ sizeof(OBJECT_NAME_INFORMATION
) + sizeof(WCHAR
);
227 /* Calculate amount of bytes to copy into the buffer */
228 BytesToCopy
= KeyName
->Length
+ sizeof(WCHAR
);
230 /* Check if the provided buffer is too small to fit even anything */
231 if ((Length
<= sizeof(OBJECT_NAME_INFORMATION
)) ||
232 ((Length
< (*ReturnLength
)) && (BytesToCopy
< sizeof(WCHAR
))))
234 /* Free the buffer allocated by CmpConstructName */
235 ExFreePoolWithTag(KeyName
, TAG_CM
);
237 /* Return buffer length failure without writing anything there because nothing fits */
238 return STATUS_INFO_LENGTH_MISMATCH
;
241 /* Check if the provided buffer can be partially written */
242 if (Length
< (*ReturnLength
))
244 /* Yes, indicate so in the return status */
245 Status
= STATUS_INFO_LENGTH_MISMATCH
;
247 /* Calculate amount of bytes which the provided buffer could handle */
248 BytesToCopy
= Length
- sizeof(OBJECT_NAME_INFORMATION
);
251 /* Remove the null termination character from the size */
252 BytesToCopy
-= sizeof(WCHAR
);
254 /* Fill in the result */
257 /* Return data to user */
258 ObjectNameInfo
->Name
.Buffer
= (PWCHAR
)(ObjectNameInfo
+ 1);
259 ObjectNameInfo
->Name
.MaximumLength
= KeyName
->Length
;
260 ObjectNameInfo
->Name
.Length
= KeyName
->Length
;
262 /* Copy string content*/
263 RtlCopyMemory(ObjectNameInfo
->Name
.Buffer
,
267 /* Null terminate it */
268 ObjectNameInfo
->Name
.Buffer
[BytesToCopy
/ sizeof(WCHAR
)] = UNICODE_NULL
;
270 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
273 Status
= _SEH2_GetExceptionCode();
277 /* Free the buffer allocated by CmpConstructName */
278 ExFreePoolWithTag(KeyName
, TAG_CM
);
286 CmpInitHiveFromFile(IN PCUNICODE_STRING HiveName
,
292 ULONG HiveDisposition
, LogDisposition
;
293 HANDLE FileHandle
= NULL
, LogHandle
= NULL
;
295 ULONG Operation
, FileType
;
302 /* Open or create the hive files */
303 Status
= CmpOpenHiveFiles(HiveName
,
313 if (!NT_SUCCESS(Status
)) return Status
;
315 /* Check if we have a log handle */
316 FileType
= (LogHandle
) ? HFILE_TYPE_LOG
: HFILE_TYPE_PRIMARY
;
318 /* Check if we created or opened the hive */
319 if (HiveDisposition
== FILE_CREATED
)
321 /* Do a create operation */
322 Operation
= HINIT_CREATE
;
327 /* Open it as a file */
328 Operation
= HINIT_FILE
;
332 /* Check if we're sharing hives */
333 if (CmpShareSystemHives
)
335 /* Then force using the primary hive */
336 FileType
= HFILE_TYPE_PRIMARY
;
339 /* Get rid of the log handle */
345 /* Check if we're too late */
346 if (HvShutdownComplete
)
350 if (LogHandle
) ZwClose(LogHandle
);
351 return STATUS_TOO_LATE
;
354 /* Initialize the hive */
355 Status
= CmpInitializeHive(&NewHive
,
365 if (!NT_SUCCESS(Status
))
369 if (LogHandle
) ZwClose(LogHandle
);
373 /* Success, return hive */
376 /* Duplicate the hive name */
377 NewHive
->FileFullPath
.Buffer
= ExAllocatePoolWithTag(PagedPool
,
380 if (NewHive
->FileFullPath
.Buffer
)
382 /* Copy the string */
383 RtlCopyMemory(NewHive
->FileFullPath
.Buffer
,
386 NewHive
->FileFullPath
.Length
= HiveName
->Length
;
387 NewHive
->FileFullPath
.MaximumLength
= HiveName
->Length
;
391 return STATUS_SUCCESS
;
397 CmpSetSystemValues(IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
399 OBJECT_ATTRIBUTES ObjectAttributes
;
400 UNICODE_STRING KeyName
, ValueName
= { 0, 0, NULL
};
401 HANDLE KeyHandle
= NULL
;
403 ASSERT(LoaderBlock
!= NULL
);
405 /* Setup attributes for loader options */
406 RtlInitUnicodeString(&KeyName
,
407 L
"\\REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\"
409 InitializeObjectAttributes(&ObjectAttributes
,
411 OBJ_CASE_INSENSITIVE
,
414 Status
= NtOpenKey(&KeyHandle
, KEY_WRITE
, &ObjectAttributes
);
415 if (!NT_SUCCESS(Status
)) goto Quickie
;
417 /* Key opened, now write to the key */
418 RtlInitUnicodeString(&KeyName
, L
"SystemStartOptions");
419 Status
= NtSetValueKey(KeyHandle
,
423 CmpLoadOptions
.Buffer
,
424 CmpLoadOptions
.Length
);
425 if (!NT_SUCCESS(Status
)) goto Quickie
;
427 /* Setup value name for system boot device in ARC format */
428 RtlInitUnicodeString(&KeyName
, L
"SystemBootDevice");
429 RtlCreateUnicodeStringFromAsciiz(&ValueName
, LoaderBlock
->ArcBootDeviceName
);
430 Status
= NtSetValueKey(KeyHandle
,
438 /* Free the buffers */
439 RtlFreeUnicodeString(&ValueName
);
441 /* Close the key and return */
442 if (KeyHandle
) NtClose(KeyHandle
);
444 /* Return the status */
445 return (ExpInTextModeSetup
? STATUS_SUCCESS
: Status
);
451 CmpCreateHardwareProfile(HANDLE ControlSetHandle
)
453 OBJECT_ATTRIBUTES ObjectAttributes
;
454 UNICODE_STRING KeyName
;
455 HANDLE ProfilesHandle
= NULL
;
456 HANDLE ProfileHandle
= NULL
;
460 DPRINT("CmpCreateHardwareProfile()\n");
462 /* Create the Hardware Profiles key */
463 RtlInitUnicodeString(&KeyName
, L
"Hardware Profiles");
464 InitializeObjectAttributes(&ObjectAttributes
,
466 OBJ_CASE_INSENSITIVE
,
469 Status
= NtCreateKey(&ProfilesHandle
,
476 if (!NT_SUCCESS(Status
))
478 DPRINT1("Creating the Hardware Profile key failed\n");
483 ASSERT(Disposition
== REG_CREATED_NEW_KEY
);
485 /* Create the 0000 key */
486 RtlInitUnicodeString(&KeyName
, L
"0000");
487 InitializeObjectAttributes(&ObjectAttributes
,
489 OBJ_CASE_INSENSITIVE
,
492 Status
= NtCreateKey(&ProfileHandle
,
499 if (!NT_SUCCESS(Status
))
501 DPRINT1("Creating the Hardware Profile\\0000 key failed\n");
506 ASSERT(Disposition
== REG_CREATED_NEW_KEY
);
510 NtClose(ProfilesHandle
);
513 NtClose(ProfileHandle
);
515 DPRINT("CmpCreateHardwareProfile() done\n");
523 CmpCreateControlSet(IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
525 UNICODE_STRING ConfigName
= RTL_CONSTANT_STRING(L
"Control\\IDConfigDB");
526 UNICODE_STRING SelectName
=
527 RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\System\\Select");
528 UNICODE_STRING KeyName
;
529 OBJECT_ATTRIBUTES ObjectAttributes
;
530 CHAR ValueInfoBuffer
[128];
531 PKEY_VALUE_FULL_INFORMATION ValueInfo
;
532 WCHAR UnicodeBuffer
[128];
533 HANDLE SelectHandle
= NULL
;
534 HANDLE KeyHandle
= NULL
;
535 HANDLE ConfigHandle
= NULL
;
536 HANDLE ProfileHandle
= NULL
;
537 HANDLE ParentHandle
= NULL
;
538 ULONG ControlSet
, HwProfile
;
540 ULONG ResultLength
, Disposition
;
541 PLOADER_PARAMETER_EXTENSION LoaderExtension
;
544 /* ReactOS Hack: Hard-code current to 001 for SetupLdr */
545 if (LoaderBlock
->RegistryBase
== NULL
)
547 /* Build the ControlSet001 key */
548 RtlInitUnicodeString(&KeyName
,
549 L
"\\Registry\\Machine\\System\\ControlSet001");
550 InitializeObjectAttributes(&ObjectAttributes
,
552 OBJ_CASE_INSENSITIVE
,
555 Status
= NtCreateKey(&KeyHandle
,
562 if (!NT_SUCCESS(Status
))
564 DPRINT1("Failed to create ControlSet001 key: 0x%lx\n", Status
);
568 /* Create the Hardware Profile keys */
569 Status
= CmpCreateHardwareProfile(KeyHandle
);
570 if (!NT_SUCCESS(Status
))
572 DPRINT1("Failed to create Hardware profile keys: 0x%lx\n", Status
);
576 /* Use hard-coded setting */
581 /* Open the select key */
582 InitializeObjectAttributes(&ObjectAttributes
,
584 OBJ_CASE_INSENSITIVE
,
587 Status
= NtOpenKey(&SelectHandle
, KEY_READ
, &ObjectAttributes
);
588 if (!NT_SUCCESS(Status
))
590 DPRINT1("Failed to open select key: 0x%lx\n", Status
);
594 /* Open the current value */
595 RtlInitUnicodeString(&KeyName
, L
"Current");
596 Status
= NtQueryValueKey(SelectHandle
,
598 KeyValueFullInformation
,
600 sizeof(ValueInfoBuffer
),
602 if (!NT_SUCCESS(Status
))
604 DPRINT1("Failed to open the Current value: 0x%lx\n", Status
);
608 /* Get the actual value pointer, and get the control set ID */
609 ValueInfo
= (PKEY_VALUE_FULL_INFORMATION
)ValueInfoBuffer
;
610 ControlSet
= *(PULONG
)((PUCHAR
)ValueInfo
+ ValueInfo
->DataOffset
);
613 /* Create the current control set key */
614 RtlInitUnicodeString(&KeyName
,
615 L
"\\Registry\\Machine\\System\\CurrentControlSet");
616 InitializeObjectAttributes(&ObjectAttributes
,
618 OBJ_CASE_INSENSITIVE
,
621 Status
= NtCreateKey(&KeyHandle
,
626 REG_OPTION_VOLATILE
| REG_OPTION_CREATE_LINK
,
628 if (!NT_SUCCESS(Status
))
632 ASSERT(Disposition
== REG_CREATED_NEW_KEY
);
634 /* Initialize the target link name */
635 Status
= RtlStringCbPrintfW(UnicodeBuffer
, sizeof(UnicodeBuffer
),
636 L
"\\Registry\\Machine\\System\\ControlSet%03ld",
638 if (!NT_SUCCESS(Status
))
641 RtlInitUnicodeString(&KeyName
, UnicodeBuffer
);
644 Status
= NtSetValueKey(KeyHandle
,
645 &CmSymbolicLinkValueName
,
650 if (!NT_SUCCESS(Status
))
653 /* Get the configuration database key */
654 InitializeObjectAttributes(&ObjectAttributes
,
656 OBJ_CASE_INSENSITIVE
,
659 Status
= NtOpenKey(&ConfigHandle
, KEY_READ
, &ObjectAttributes
);
661 /* Check if we don't have one */
662 if (!NT_SUCCESS(Status
))
664 /* Cleanup and exit */
665 Status
= STATUS_SUCCESS
;
669 /* ReactOS Hack: Hard-code current to 001 for SetupLdr */
670 if (LoaderBlock
->RegistryBase
== NULL
)
676 /* Now get the current config */
677 RtlInitUnicodeString(&KeyName
, L
"CurrentConfig");
678 Status
= NtQueryValueKey(ConfigHandle
,
680 KeyValueFullInformation
,
682 sizeof(ValueInfoBuffer
),
685 /* Set pointer to buffer */
686 ValueInfo
= (PKEY_VALUE_FULL_INFORMATION
)ValueInfoBuffer
;
688 /* Check if we failed or got a non DWORD-value */
689 if (!(NT_SUCCESS(Status
)) || (ValueInfo
->Type
!= REG_DWORD
))
691 Status
= STATUS_SUCCESS
;
695 /* Get the hadware profile */
696 HwProfile
= *(PULONG
)((PUCHAR
)ValueInfo
+ ValueInfo
->DataOffset
);
699 /* Open the hardware profile key */
700 RtlInitUnicodeString(&KeyName
,
701 L
"\\Registry\\Machine\\System\\CurrentControlSet"
702 L
"\\Hardware Profiles");
703 InitializeObjectAttributes(&ObjectAttributes
,
705 OBJ_CASE_INSENSITIVE
,
708 Status
= NtOpenKey(&ParentHandle
, KEY_READ
, &ObjectAttributes
);
709 if (!NT_SUCCESS(Status
))
711 /* Exit and clean up */
712 Status
= STATUS_SUCCESS
;
716 /* Build the profile name */
717 RtlStringCbPrintfW(UnicodeBuffer
, sizeof(UnicodeBuffer
),
718 L
"%04ld", HwProfile
);
719 RtlInitUnicodeString(&KeyName
, UnicodeBuffer
);
721 /* Open the associated key */
722 InitializeObjectAttributes(&ObjectAttributes
,
724 OBJ_CASE_INSENSITIVE
,
727 Status
= NtOpenKey(&ProfileHandle
,
728 KEY_READ
| KEY_WRITE
,
730 if (!NT_SUCCESS (Status
))
732 /* Cleanup and exit */
733 Status
= STATUS_SUCCESS
;
737 /* Check if we have a loader block extension */
738 LoaderExtension
= LoaderBlock
->Extension
;
741 DPRINT("ReactOS doesn't support NTLDR Profiles yet!\n");
744 /* Create the current hardware profile key */
745 RtlInitUnicodeString(&KeyName
,
746 L
"\\Registry\\Machine\\System\\CurrentControlSet\\"
747 L
"Hardware Profiles\\Current");
748 InitializeObjectAttributes(&ObjectAttributes
,
750 OBJ_CASE_INSENSITIVE
,
753 Status
= NtCreateKey(&KeyHandle
,
758 REG_OPTION_VOLATILE
| REG_OPTION_CREATE_LINK
,
760 if (NT_SUCCESS(Status
))
763 ASSERT(Disposition
== REG_CREATED_NEW_KEY
);
765 /* Create the profile name */
766 RtlStringCbPrintfW(UnicodeBuffer
, sizeof(UnicodeBuffer
),
767 L
"\\Registry\\Machine\\System\\CurrentControlSet\\"
768 L
"Hardware Profiles\\%04ld",
770 RtlInitUnicodeString(&KeyName
, UnicodeBuffer
);
773 Status
= NtSetValueKey(KeyHandle
,
774 &CmSymbolicLinkValueName
,
781 Status
= STATUS_SUCCESS
;
784 /* Close every opened handle */
785 if (SelectHandle
) NtClose(SelectHandle
);
786 if (KeyHandle
) NtClose(KeyHandle
);
787 if (ConfigHandle
) NtClose(ConfigHandle
);
788 if (ProfileHandle
) NtClose(ProfileHandle
);
789 if (ParentHandle
) NtClose(ParentHandle
);
791 DPRINT("CmpCreateControlSet() done\n");
797 CmpLinkHiveToMaster(IN PUNICODE_STRING LinkName
,
798 IN HANDLE RootDirectory
,
799 IN PCMHIVE RegistryHive
,
801 IN PSECURITY_DESCRIPTOR SecurityDescriptor
)
803 OBJECT_ATTRIBUTES ObjectAttributes
;
805 CM_PARSE_CONTEXT ParseContext
= {0};
807 PCM_KEY_BODY KeyBody
;
810 /* Setup the object attributes */
811 InitializeObjectAttributes(&ObjectAttributes
,
813 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
817 /* Setup the parse context */
818 ParseContext
.CreateLink
= TRUE
;
819 ParseContext
.CreateOperation
= TRUE
;
820 ParseContext
.ChildHive
.KeyHive
= &RegistryHive
->Hive
;
822 /* Check if we have a root keycell or if we need to create it */
826 ParseContext
.ChildHive
.KeyCell
= HCELL_NIL
;
831 ParseContext
.ChildHive
.KeyCell
= RegistryHive
->Hive
.BaseBlock
->RootCell
;
834 /* Create the link node */
835 Status
= ObOpenObjectByName(&ObjectAttributes
,
839 KEY_READ
| KEY_WRITE
,
840 (PVOID
)&ParseContext
,
842 if (!NT_SUCCESS(Status
)) return Status
;
844 /* Mark the hive as clean */
845 RegistryHive
->Hive
.DirtyFlag
= FALSE
;
847 /* ReactOS Hack: Keep alive */
848 Status
= ObReferenceObjectByHandle(KeyHandle
,
854 ASSERT(NT_SUCCESS(Status
));
856 /* Close the extra handle */
858 return STATUS_SUCCESS
;
864 CmpInitializeSystemHive(IN PLOADER_PARAMETER_BLOCK LoaderBlock
)
866 static const UNICODE_STRING HiveName
= RTL_CONSTANT_STRING(L
"SYSTEM");
868 ANSI_STRING LoadString
;
872 UNICODE_STRING KeyName
;
873 PCMHIVE SystemHive
= NULL
;
874 PSECURITY_DESCRIPTOR SecurityDescriptor
;
879 /* Setup the ansi string */
880 RtlInitAnsiString(&LoadString
, LoaderBlock
->LoadOptions
);
882 /* Allocate the unicode buffer */
883 Length
= LoadString
.Length
* sizeof(WCHAR
) + sizeof(UNICODE_NULL
);
884 Buffer
= ExAllocatePoolWithTag(PagedPool
, Length
, TAG_CM
);
888 KeBugCheckEx(BAD_SYSTEM_CONFIG_INFO
, 3, 1, (ULONG_PTR
)LoaderBlock
, 0);
891 /* Setup the unicode string */
892 RtlInitEmptyUnicodeString(&CmpLoadOptions
, Buffer
, (USHORT
)Length
);
894 /* Add the load options and null-terminate */
895 Status
= RtlAnsiStringToUnicodeString(&CmpLoadOptions
, &LoadString
, FALSE
);
896 if (!NT_SUCCESS(Status
))
901 CmpLoadOptions
.Buffer
[LoadString
.Length
] = UNICODE_NULL
;
902 CmpLoadOptions
.Length
+= sizeof(WCHAR
);
904 /* Get the System Hive base address */
905 HiveBase
= LoaderBlock
->RegistryBase
;
907 Status
= CmpInitializeHive(&SystemHive
,
908 HiveBase
? HINIT_MEMORY
: HINIT_CREATE
,
917 if (!NT_SUCCESS(Status
))
922 /* Set the hive filename */
923 Success
= RtlCreateUnicodeString(&SystemHive
->FileFullPath
,
924 L
"\\SystemRoot\\System32\\Config\\SYSTEM");
930 /* Manually set the hive as volatile, if in Live CD mode */
931 if (HiveBase
&& CmpShareSystemHives
)
933 SystemHive
->Hive
.HiveFlags
= HIVE_VOLATILE
;
936 /* Save the boot type */
937 CmpBootType
= SystemHive
->Hive
.BaseBlock
->BootType
;
939 /* Are we in self-healing mode? */
942 /* Disable self-healing internally and check if boot type wanted it */
946 /* We're disabled, so bugcheck */
947 KeBugCheckEx(BAD_SYSTEM_CONFIG_INFO
,
950 (ULONG_PTR
)SystemHive
,
955 /* Create the default security descriptor */
956 SecurityDescriptor
= CmpHiveRootSecurityDescriptor();
958 /* Attach it to the system key */
959 /* Let CmpLinkHiveToMaster allocate a new hive if we got none from the LoaderBlock. */
960 RtlInitUnicodeString(&KeyName
, L
"\\Registry\\Machine\\SYSTEM");
961 Status
= CmpLinkHiveToMaster(&KeyName
,
967 /* Free the security descriptor */
968 ExFreePoolWithTag(SecurityDescriptor
, TAG_CMSD
);
969 if (!NT_SUCCESS(Status
)) return FALSE
;
971 /* Add the hive to the hive list */
972 CmpMachineHiveList
[3].CmHive
= SystemHive
;
981 CmpCreateObjectTypes(VOID
)
983 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer
;
985 GENERIC_MAPPING CmpKeyMapping
= {KEY_READ
,
991 /* Initialize the Key object type */
992 RtlZeroMemory(&ObjectTypeInitializer
, sizeof(ObjectTypeInitializer
));
993 RtlInitUnicodeString(&Name
, L
"Key");
994 ObjectTypeInitializer
.Length
= sizeof(ObjectTypeInitializer
);
995 ObjectTypeInitializer
.DefaultPagedPoolCharge
= sizeof(CM_KEY_BODY
);
996 ObjectTypeInitializer
.GenericMapping
= CmpKeyMapping
;
997 ObjectTypeInitializer
.PoolType
= PagedPool
;
998 ObjectTypeInitializer
.ValidAccessMask
= KEY_ALL_ACCESS
;
999 ObjectTypeInitializer
.UseDefaultObject
= TRUE
;
1000 ObjectTypeInitializer
.DeleteProcedure
= CmpDeleteKeyObject
;
1001 ObjectTypeInitializer
.ParseProcedure
= CmpParseKey
;
1002 ObjectTypeInitializer
.SecurityProcedure
= CmpSecurityMethod
;
1003 ObjectTypeInitializer
.QueryNameProcedure
= CmpQueryKeyName
;
1004 ObjectTypeInitializer
.CloseProcedure
= CmpCloseKeyObject
;
1005 ObjectTypeInitializer
.SecurityRequired
= TRUE
;
1006 ObjectTypeInitializer
.InvalidAttributes
= OBJ_EXCLUSIVE
| OBJ_PERMANENT
;
1009 return ObCreateObjectType(&Name
, &ObjectTypeInitializer
, NULL
, &CmpKeyObjectType
);
1015 CmpCreateRootNode(IN PHHIVE Hive
,
1017 OUT PHCELL_INDEX Index
)
1019 UNICODE_STRING KeyName
;
1020 PCM_KEY_NODE KeyCell
;
1023 /* Initialize the node name and allocate it */
1024 RtlInitUnicodeString(&KeyName
, Name
);
1025 *Index
= HvAllocateCell(Hive
,
1026 FIELD_OFFSET(CM_KEY_NODE
, Name
) +
1027 CmpNameSize(Hive
, &KeyName
),
1030 if (*Index
== HCELL_NIL
) return FALSE
;
1032 /* Set the cell index and get the data */
1033 Hive
->BaseBlock
->RootCell
= *Index
;
1034 KeyCell
= (PCM_KEY_NODE
)HvGetCell(Hive
, *Index
);
1035 if (!KeyCell
) return FALSE
;
1037 /* Setup the cell */
1038 KeyCell
->Signature
= CM_KEY_NODE_SIGNATURE
;
1039 KeyCell
->Flags
= KEY_HIVE_ENTRY
| KEY_NO_DELETE
;
1040 KeQuerySystemTime(&KeyCell
->LastWriteTime
);
1041 KeyCell
->Parent
= HCELL_NIL
;
1042 KeyCell
->SubKeyCounts
[Stable
] = 0;
1043 KeyCell
->SubKeyCounts
[Volatile
] = 0;
1044 KeyCell
->SubKeyLists
[Stable
] = HCELL_NIL
;
1045 KeyCell
->SubKeyLists
[Volatile
] = HCELL_NIL
;
1046 KeyCell
->ValueList
.Count
= 0;
1047 KeyCell
->ValueList
.List
= HCELL_NIL
;
1048 KeyCell
->Security
= HCELL_NIL
;
1049 KeyCell
->Class
= HCELL_NIL
;
1050 KeyCell
->ClassLength
= 0;
1051 KeyCell
->MaxNameLen
= 0;
1052 KeyCell
->MaxClassLen
= 0;
1053 KeyCell
->MaxValueNameLen
= 0;
1054 KeyCell
->MaxValueDataLen
= 0;
1056 /* Copy the name (this will also set the length) */
1057 KeyCell
->NameLength
= CmpCopyName(Hive
, KeyCell
->Name
, &KeyName
);
1059 /* Check if the name was compressed and set the flag if so */
1060 if (KeyCell
->NameLength
< KeyName
.Length
)
1061 KeyCell
->Flags
|= KEY_COMP_NAME
;
1063 /* Return success */
1064 HvReleaseCell(Hive
, *Index
);
1071 CmpCreateRegistryRoot(VOID
)
1073 UNICODE_STRING KeyName
;
1074 OBJECT_ATTRIBUTES ObjectAttributes
;
1075 PCM_KEY_BODY RootKey
;
1076 HCELL_INDEX RootIndex
;
1078 PCM_KEY_NODE KeyCell
;
1079 PSECURITY_DESCRIPTOR SecurityDescriptor
;
1080 PCM_KEY_CONTROL_BLOCK Kcb
;
1083 /* Setup the root node */
1084 if (!CmpCreateRootNode(&CmiVolatileHive
->Hive
, L
"REGISTRY", &RootIndex
))
1090 /* Create '\Registry' key. */
1091 RtlInitUnicodeString(&KeyName
, L
"\\REGISTRY");
1092 SecurityDescriptor
= CmpHiveRootSecurityDescriptor();
1093 InitializeObjectAttributes(&ObjectAttributes
,
1095 OBJ_CASE_INSENSITIVE
,
1097 SecurityDescriptor
);
1098 Status
= ObCreateObject(KernelMode
,
1103 sizeof(CM_KEY_BODY
),
1107 ExFreePoolWithTag(SecurityDescriptor
, TAG_CMSD
);
1108 if (!NT_SUCCESS(Status
)) return FALSE
;
1110 /* Sanity check, and get the key cell */
1111 ASSERT((&CmiVolatileHive
->Hive
)->ReleaseCellRoutine
== NULL
);
1112 KeyCell
= (PCM_KEY_NODE
)HvGetCell(&CmiVolatileHive
->Hive
, RootIndex
);
1113 if (!KeyCell
) return FALSE
;
1115 /* Create the KCB */
1116 RtlInitUnicodeString(&KeyName
, L
"\\REGISTRY");
1117 Kcb
= CmpCreateKeyControlBlock(&CmiVolatileHive
->Hive
,
1125 ObDereferenceObject(RootKey
);
1129 /* Initialize the object */
1130 RootKey
->KeyControlBlock
= Kcb
;
1131 RootKey
->Type
= CM_KEY_BODY_TYPE
;
1132 RootKey
->NotifyBlock
= NULL
;
1133 RootKey
->ProcessID
= PsGetCurrentProcessId();
1136 EnlistKeyBodyWithKCB(RootKey
, 0);
1138 /* Insert the key into the namespace */
1139 Status
= ObInsertObject(RootKey
,
1144 &CmpRegistryRootHandle
);
1145 if (!NT_SUCCESS(Status
))
1147 ObDereferenceObject(RootKey
);
1151 /* Reference the key again so that we never lose it */
1152 Status
= ObReferenceObjectByHandle(CmpRegistryRootHandle
,
1158 if (!NT_SUCCESS(Status
))
1160 ObDereferenceObject(RootKey
);
1164 /* Completely sucessful */
1170 CmpGetRegistryPath(OUT PWCHAR ConfigPath
)
1172 OBJECT_ATTRIBUTES ObjectAttributes
;
1175 PKEY_VALUE_PARTIAL_INFORMATION ValueInfo
;
1176 UNICODE_STRING KeyName
= RTL_CONSTANT_STRING(L
"\\Registry\\Machine\\HARDWARE");
1177 UNICODE_STRING ValueName
= RTL_CONSTANT_STRING(L
"InstallPath");
1178 ULONG BufferSize
, ResultSize
;
1180 /* Check if we are booted in setup */
1181 if (ExpInTextModeSetup
)
1183 DPRINT1("CmpGetRegistryPath TextMode setup HACK!!\n");
1185 /* Setup the object attributes */
1186 InitializeObjectAttributes(&ObjectAttributes
,
1188 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
1192 Status
= ZwOpenKey(&KeyHandle
,
1195 if (!NT_SUCCESS(Status
)) return Status
;
1197 /* Allocate the buffer */
1198 BufferSize
= sizeof(KEY_VALUE_PARTIAL_INFORMATION
) + 4096;
1199 ValueInfo
= ExAllocatePoolWithTag(PagedPool
, BufferSize
, TAG_CM
);
1204 return STATUS_INSUFFICIENT_RESOURCES
;
1207 /* Query the value */
1208 Status
= ZwQueryValueKey(KeyHandle
,
1210 KeyValuePartialInformation
,
1215 if (!NT_SUCCESS(Status
))
1218 ExFreePoolWithTag(ValueInfo
, TAG_CM
);
1222 /* Copy the config path and null-terminate it */
1223 RtlCopyMemory(ConfigPath
,
1225 ValueInfo
->DataLength
);
1226 ConfigPath
[ValueInfo
->DataLength
/ sizeof(WCHAR
)] = UNICODE_NULL
;
1227 ExFreePoolWithTag(ValueInfo
, TAG_CM
);
1231 /* Just use default path */
1232 wcscpy(ConfigPath
, L
"\\SystemRoot");
1235 /* Add registry path */
1236 wcscat(ConfigPath
, L
"\\System32\\Config\\");
1238 DPRINT1("CmpGetRegistryPath: ConfigPath = '%S'\n", ConfigPath
);
1241 return STATUS_SUCCESS
;
1244 _Function_class_(KSTART_ROUTINE
)
1247 CmpLoadHiveThread(IN PVOID StartContext
)
1249 WCHAR FileBuffer
[MAX_PATH
], RegBuffer
[MAX_PATH
], ConfigPath
[MAX_PATH
];
1250 UNICODE_STRING TempName
, FileName
, RegName
;
1251 ULONG i
, ErrorResponse
, WorkerCount
, Length
;
1253 ULONG PrimaryDisposition
, SecondaryDisposition
, ClusterSize
;
1255 HANDLE PrimaryHandle
= NULL
, LogHandle
= NULL
;
1256 NTSTATUS Status
= STATUS_SUCCESS
;
1257 PVOID ErrorParameters
;
1260 /* Get the hive index, make sure it makes sense */
1261 i
= PtrToUlong(StartContext
);
1262 ASSERT(CmpMachineHiveList
[i
].Name
!= NULL
);
1264 /* We were started */
1265 CmpMachineHiveList
[i
].ThreadStarted
= TRUE
;
1267 /* Build the file name and registry name strings */
1268 RtlInitEmptyUnicodeString(&FileName
, FileBuffer
, sizeof(FileBuffer
));
1269 RtlInitEmptyUnicodeString(&RegName
, RegBuffer
, sizeof(RegBuffer
));
1271 /* Now build the system root path */
1272 CmpGetRegistryPath(ConfigPath
);
1273 RtlInitUnicodeString(&TempName
, ConfigPath
);
1274 RtlAppendUnicodeStringToString(&FileName
, &TempName
);
1275 FileStart
= FileName
.Length
;
1277 /* And build the registry root path */
1278 RtlInitUnicodeString(&TempName
, L
"\\REGISTRY\\");
1279 RtlAppendUnicodeStringToString(&RegName
, &TempName
);
1281 /* Build the base name */
1282 RtlInitUnicodeString(&TempName
, CmpMachineHiveList
[i
].BaseName
);
1283 RtlAppendUnicodeStringToString(&RegName
, &TempName
);
1285 /* Check if this is a child of the root */
1286 if (RegName
.Buffer
[RegName
.Length
/ sizeof(WCHAR
) - 1] == OBJ_NAME_PATH_SEPARATOR
)
1288 /* Then setup the whole name */
1289 RtlInitUnicodeString(&TempName
, CmpMachineHiveList
[i
].Name
);
1290 RtlAppendUnicodeStringToString(&RegName
, &TempName
);
1293 /* Now add the rest of the file name */
1294 RtlInitUnicodeString(&TempName
, CmpMachineHiveList
[i
].Name
);
1295 FileName
.Length
= FileStart
;
1296 RtlAppendUnicodeStringToString(&FileName
, &TempName
);
1297 if (!CmpMachineHiveList
[i
].CmHive
)
1299 /* We need to allocate a new hive structure */
1300 CmpMachineHiveList
[i
].Allocate
= TRUE
;
1302 /* Load the hive file */
1303 Status
= CmpInitHiveFromFile(&FileName
,
1304 CmpMachineHiveList
[i
].HHiveFlags
,
1306 &CmpMachineHiveList
[i
].Allocate
,
1308 if (!(NT_SUCCESS(Status
)) ||
1309 (!(CmpShareSystemHives
) && !(CmHive
->FileHandles
[HFILE_TYPE_LOG
])))
1312 * We failed, or could not get a log file (unless
1313 * the hive is shared), raise a hard error.
1315 ErrorParameters
= &FileName
;
1316 NtRaiseHardError(STATUS_CANNOT_LOAD_REGISTRY_FILE
,
1319 (PULONG_PTR
)&ErrorParameters
,
1324 /* Set the hive flags and newly allocated hive pointer */
1325 CmHive
->Flags
= CmpMachineHiveList
[i
].CmHiveFlags
;
1326 CmpMachineHiveList
[i
].CmHive2
= CmHive
;
1330 /* We already have a hive, is it volatile? */
1331 CmHive
= CmpMachineHiveList
[i
].CmHive
;
1332 if (!(CmHive
->Hive
.HiveFlags
& HIVE_VOLATILE
))
1334 /* It's now, open the hive file and log */
1335 Status
= CmpOpenHiveFiles(&FileName
,
1339 &PrimaryDisposition
,
1340 &SecondaryDisposition
,
1345 if (!(NT_SUCCESS(Status
)) || !(LogHandle
))
1347 /* Couldn't open the hive or its log file, raise a hard error */
1348 ErrorParameters
= &FileName
;
1349 NtRaiseHardError(STATUS_CANNOT_LOAD_REGISTRY_FILE
,
1352 (PULONG_PTR
)&ErrorParameters
,
1356 /* And bugcheck for posterity's sake */
1357 KeBugCheckEx(BAD_SYSTEM_CONFIG_INFO
, 9, 0, i
, Status
);
1360 /* Save the file handles. This should remove our sync hacks */
1361 CmHive
->FileHandles
[HFILE_TYPE_LOG
] = LogHandle
;
1362 CmHive
->FileHandles
[HFILE_TYPE_PRIMARY
] = PrimaryHandle
;
1364 /* Allow lazy flushing since the handles are there -- remove sync hacks */
1365 //ASSERT(CmHive->Hive.HiveFlags & HIVE_NOLAZYFLUSH);
1366 CmHive
->Hive
.HiveFlags
&= ~HIVE_NOLAZYFLUSH
;
1368 /* Get the real size of the hive */
1369 Length
= CmHive
->Hive
.Storage
[Stable
].Length
+ HBLOCK_SIZE
;
1371 /* Check if the cluster size doesn't match */
1372 if (CmHive
->Hive
.Cluster
!= ClusterSize
)
1374 DPRINT1("FIXME: Support for CmHive->Hive.Cluster (%lu) != ClusterSize (%lu) is unimplemented!\n",
1375 CmHive
->Hive
.Cluster
, ClusterSize
);
1378 /* Set the file size */
1379 DPRINT("FIXME: Should set file size: %lu\n", Length
);
1380 //if (!CmpFileSetSize((PHHIVE)CmHive, HFILE_TYPE_PRIMARY, Length, Length))
1382 /* This shouldn't fail */
1386 /* Another thing we don't support is NTLDR-recovery */
1387 if (CmHive
->Hive
.BaseBlock
->BootRecover
) ASSERT(FALSE
);
1389 /* Finally, set our allocated hive to the same hive we've had */
1390 CmpMachineHiveList
[i
].CmHive2
= CmHive
;
1391 ASSERT(CmpMachineHiveList
[i
].CmHive
== CmpMachineHiveList
[i
].CmHive2
);
1396 CmpMachineHiveList
[i
].ThreadFinished
= TRUE
;
1398 /* Check if we're the last worker */
1399 WorkerCount
= InterlockedIncrement(&CmpLoadWorkerIncrement
);
1400 if (WorkerCount
== CM_NUMBER_OF_MACHINE_HIVES
)
1402 /* Signal the event */
1403 KeSetEvent(&CmpLoadWorkerEvent
, 0, FALSE
);
1406 /* Kill the thread */
1407 PsTerminateSystemThread(Status
);
1412 CmpInitializeHiveList(IN USHORT Flag
)
1414 WCHAR FileBuffer
[MAX_PATH
], RegBuffer
[MAX_PATH
], ConfigPath
[MAX_PATH
];
1415 UNICODE_STRING TempName
, FileName
, RegName
;
1420 PSECURITY_DESCRIPTOR SecurityDescriptor
;
1423 /* Allow writing for now */
1426 /* Build the file name and registry name strings */
1427 RtlInitEmptyUnicodeString(&FileName
, FileBuffer
, sizeof(FileBuffer
));
1428 RtlInitEmptyUnicodeString(&RegName
, RegBuffer
, sizeof(RegBuffer
));
1430 /* Now build the system root path */
1431 CmpGetRegistryPath(ConfigPath
);
1432 RtlInitUnicodeString(&TempName
, ConfigPath
);
1433 RtlAppendUnicodeStringToString(&FileName
, &TempName
);
1435 /* And build the registry root path */
1436 RtlInitUnicodeString(&TempName
, L
"\\REGISTRY\\");
1437 RtlAppendUnicodeStringToString(&RegName
, &TempName
);
1438 RegStart
= RegName
.Length
;
1440 /* Setup the event to synchronize workers */
1441 KeInitializeEvent(&CmpLoadWorkerEvent
, SynchronizationEvent
, FALSE
);
1443 /* Enter special boot condition */
1444 CmpSpecialBootCondition
= TRUE
;
1446 /* Create the SD for the root hives */
1447 SecurityDescriptor
= CmpHiveRootSecurityDescriptor();
1449 /* Loop every hive we care about */
1450 for (i
= 0; i
< CM_NUMBER_OF_MACHINE_HIVES
; i
++)
1452 /* Make sure the list is set up */
1453 ASSERT(CmpMachineHiveList
[i
].Name
!= NULL
);
1455 /* Load the hive as volatile, if in LiveCD mode */
1456 if (CmpShareSystemHives
)
1457 CmpMachineHiveList
[i
].HHiveFlags
|= HIVE_VOLATILE
;
1459 /* Create a thread to handle this hive */
1460 Status
= PsCreateSystemThread(&Thread
,
1467 if (NT_SUCCESS(Status
))
1469 /* We don't care about the handle -- the thread self-terminates */
1474 /* Can't imagine this happening */
1475 KeBugCheckEx(BAD_SYSTEM_CONFIG_INFO
, 9, 3, i
, Status
);
1479 /* Make sure we've reached the end of the list */
1480 ASSERT(CmpMachineHiveList
[i
].Name
== NULL
);
1482 /* Wait for hive loading to finish */
1483 KeWaitForSingleObject(&CmpLoadWorkerEvent
,
1489 /* Exit the special boot condition and make sure all workers completed */
1490 CmpSpecialBootCondition
= FALSE
;
1491 ASSERT(CmpLoadWorkerIncrement
== CM_NUMBER_OF_MACHINE_HIVES
);
1493 /* Loop hives again */
1494 for (i
= 0; i
< CM_NUMBER_OF_MACHINE_HIVES
; i
++)
1496 /* Make sure the thread ran and finished */
1497 ASSERT(CmpMachineHiveList
[i
].ThreadFinished
== TRUE
);
1498 ASSERT(CmpMachineHiveList
[i
].ThreadStarted
== TRUE
);
1500 /* Check if this was a new hive */
1501 if (!CmpMachineHiveList
[i
].CmHive
)
1503 /* Make sure we allocated something */
1504 ASSERT(CmpMachineHiveList
[i
].CmHive2
!= NULL
);
1506 /* Build the base name */
1507 RegName
.Length
= RegStart
;
1508 RtlInitUnicodeString(&TempName
, CmpMachineHiveList
[i
].BaseName
);
1509 RtlAppendUnicodeStringToString(&RegName
, &TempName
);
1511 /* Check if this is a child of the root */
1512 if (RegName
.Buffer
[RegName
.Length
/ sizeof(WCHAR
) - 1] == OBJ_NAME_PATH_SEPARATOR
)
1514 /* Then setup the whole name */
1515 RtlInitUnicodeString(&TempName
, CmpMachineHiveList
[i
].Name
);
1516 RtlAppendUnicodeStringToString(&RegName
, &TempName
);
1519 /* Now link the hive to its master */
1520 Status
= CmpLinkHiveToMaster(&RegName
,
1522 CmpMachineHiveList
[i
].CmHive2
,
1523 CmpMachineHiveList
[i
].Allocate
,
1524 SecurityDescriptor
);
1525 if (Status
!= STATUS_SUCCESS
)
1527 /* Linking needs to work */
1528 KeBugCheckEx(CONFIG_LIST_FAILED
, 11, Status
, i
, (ULONG_PTR
)&RegName
);
1531 /* Check if we had to allocate a new hive */
1532 if (CmpMachineHiveList
[i
].Allocate
)
1534 /* Sync the new hive */
1535 //HvSyncHive((PHHIVE)(CmpMachineHiveList[i].CmHive2));
1539 /* Check if we created a new hive */
1540 if (CmpMachineHiveList
[i
].CmHive2
)
1542 /* Add to HiveList key */
1543 CmpAddToHiveFileList(CmpMachineHiveList
[i
].CmHive2
);
1547 /* Get rid of the SD */
1548 ExFreePoolWithTag(SecurityDescriptor
, TAG_CMSD
);
1550 /* Link SECURITY to SAM */
1551 CmpLinkKeyToHive(L
"\\Registry\\Machine\\Security\\SAM",
1552 L
"\\Registry\\Machine\\SAM\\SAM");
1554 /* Link S-1-5-18 to .Default */
1555 CmpNoVolatileCreates
= FALSE
;
1556 CmpLinkKeyToHive(L
"\\Registry\\User\\S-1-5-18",
1557 L
"\\Registry\\User\\.Default");
1558 CmpNoVolatileCreates
= TRUE
;
1566 OBJECT_ATTRIBUTES ObjectAttributes
;
1567 UNICODE_STRING KeyName
;
1570 PCMHIVE HardwareHive
;
1571 PSECURITY_DESCRIPTOR SecurityDescriptor
;
1574 /* Check if this is PE-boot */
1575 if (InitIsWinPEMode
)
1577 /* Set registry to PE mode */
1578 CmpMiniNTBoot
= TRUE
;
1579 CmpShareSystemHives
= TRUE
;
1582 /* Initialize the hive list and lock */
1583 InitializeListHead(&CmpHiveListHead
);
1584 ExInitializePushLock(&CmpHiveListHeadLock
);
1585 ExInitializePushLock(&CmpLoadHiveLock
);
1587 /* Initialize registry lock */
1588 ExInitializeResourceLite(&CmpRegistryLock
);
1590 /* Initialize the cache */
1591 CmpInitializeCache();
1593 /* Initialize allocation and delayed dereferencing */
1594 CmpInitCmPrivateAlloc();
1595 CmpInitCmPrivateDelayAlloc();
1596 CmpInitDelayDerefKCBEngine();
1598 /* Initialize callbacks */
1601 /* Initialize self healing */
1602 KeInitializeGuardedMutex(&CmpSelfHealQueueLock
);
1603 InitializeListHead(&CmpSelfHealQueueListHead
);
1605 /* Save the current process and lock the registry */
1606 CmpSystemProcess
= PsGetCurrentProcess();
1608 /* Create the key object types */
1609 Status
= CmpCreateObjectTypes();
1610 if (!NT_SUCCESS(Status
))
1613 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED
, 1, 1, Status
, 0);
1616 /* Build the master hive */
1617 Status
= CmpInitializeHive(&CmiVolatileHive
,
1627 if (!NT_SUCCESS(Status
))
1630 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED
, 1, 2, Status
, 0);
1633 /* Create the \REGISTRY key node */
1634 if (!CmpCreateRegistryRoot())
1637 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED
, 1, 3, 0, 0);
1640 /* Create the default security descriptor */
1641 SecurityDescriptor
= CmpHiveRootSecurityDescriptor();
1643 /* Create '\Registry\Machine' key */
1644 RtlInitUnicodeString(&KeyName
, L
"\\REGISTRY\\MACHINE");
1645 InitializeObjectAttributes(&ObjectAttributes
,
1647 OBJ_CASE_INSENSITIVE
,
1649 SecurityDescriptor
);
1650 Status
= NtCreateKey(&KeyHandle
,
1651 KEY_READ
| KEY_WRITE
,
1657 if (!NT_SUCCESS(Status
))
1660 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED
, 1, 5, Status
, 0);
1663 /* Close the handle */
1666 /* Create '\Registry\User' key */
1667 RtlInitUnicodeString(&KeyName
, L
"\\REGISTRY\\USER");
1668 InitializeObjectAttributes(&ObjectAttributes
,
1670 OBJ_CASE_INSENSITIVE
,
1672 SecurityDescriptor
);
1673 Status
= NtCreateKey(&KeyHandle
,
1674 KEY_READ
| KEY_WRITE
,
1680 if (!NT_SUCCESS(Status
))
1683 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED
, 1, 6, Status
, 0);
1686 /* Close the handle */
1689 /* After this point, do not allow creating keys in the master hive */
1690 CmpNoVolatileCreates
= TRUE
;
1692 /* Initialize the system hive */
1693 if (!CmpInitializeSystemHive(KeLoaderBlock
))
1696 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED
, 1, 7, 0, 0);
1699 /* Create the 'CurrentControlSet' link */
1700 Status
= CmpCreateControlSet(KeLoaderBlock
);
1701 if (!NT_SUCCESS(Status
))
1704 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED
, 1, 8, Status
, 0);
1707 /* Create the hardware hive */
1708 Status
= CmpInitializeHive(&HardwareHive
,
1718 if (!NT_SUCCESS(Status
))
1721 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED
, 1, 11, Status
, 0);
1724 /* Add the hive to the hive list */
1725 CmpMachineHiveList
[0].CmHive
= HardwareHive
;
1727 /* Attach it to the machine key */
1728 RtlInitUnicodeString(&KeyName
, L
"\\Registry\\Machine\\HARDWARE");
1729 Status
= CmpLinkHiveToMaster(&KeyName
,
1733 SecurityDescriptor
);
1734 if (!NT_SUCCESS(Status
))
1737 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED
, 1, 12, Status
, 0);
1740 /* Add to HiveList key */
1741 CmpAddToHiveFileList(HardwareHive
);
1743 /* Free the security descriptor */
1744 ExFreePoolWithTag(SecurityDescriptor
, TAG_CMSD
);
1746 /* Fill out the Hardware key with the ARC Data from the Loader */
1747 Status
= CmpInitializeHardwareConfiguration(KeLoaderBlock
);
1748 if (!NT_SUCCESS(Status
))
1751 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED
, 1, 13, Status
, 0);
1754 /* Initialize machine-dependent information into the registry */
1755 Status
= CmpInitializeMachineDependentConfiguration(KeLoaderBlock
);
1756 if (!NT_SUCCESS(Status
))
1759 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED
, 1, 14, Status
, 0);
1762 /* Initialize volatile registry settings */
1763 Status
= CmpSetSystemValues(KeLoaderBlock
);
1764 if (!NT_SUCCESS(Status
))
1767 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED
, 1, 15, Status
, 0);
1770 /* Free the load options */
1771 ExFreePoolWithTag(CmpLoadOptions
.Buffer
, TAG_CM
);
1773 /* If we got here, all went well */
1780 CmpFreeDriverList(IN PHHIVE Hive
,
1781 IN PLIST_ENTRY DriverList
)
1783 PLIST_ENTRY NextEntry
, OldEntry
;
1784 PBOOT_DRIVER_NODE DriverNode
;
1787 /* Parse the current list */
1788 NextEntry
= DriverList
->Flink
;
1789 while (NextEntry
!= DriverList
)
1791 /* Get the driver node */
1792 DriverNode
= CONTAINING_RECORD(NextEntry
, BOOT_DRIVER_NODE
, ListEntry
.Link
);
1794 /* Get the next entry now, since we're going to free it later */
1795 OldEntry
= NextEntry
;
1796 NextEntry
= NextEntry
->Flink
;
1798 /* Was there a name? */
1799 if (DriverNode
->Name
.Buffer
)
1802 CmpFree(DriverNode
->Name
.Buffer
, DriverNode
->Name
.Length
);
1805 /* Was there a registry path? */
1806 if (DriverNode
->ListEntry
.RegistryPath
.Buffer
)
1809 CmpFree(DriverNode
->ListEntry
.RegistryPath
.Buffer
,
1810 DriverNode
->ListEntry
.RegistryPath
.MaximumLength
);
1813 /* Was there a file path? */
1814 if (DriverNode
->ListEntry
.FilePath
.Buffer
)
1817 CmpFree(DriverNode
->ListEntry
.FilePath
.Buffer
,
1818 DriverNode
->ListEntry
.FilePath
.MaximumLength
);
1821 /* Now free the node, and move on */
1822 CmpFree(OldEntry
, sizeof(BOOT_DRIVER_NODE
));
1829 CmGetSystemDriverList(VOID
)
1831 LIST_ENTRY DriverList
;
1832 OBJECT_ATTRIBUTES ObjectAttributes
;
1834 PCM_KEY_BODY KeyBody
;
1836 HCELL_INDEX RootCell
, ControlCell
;
1838 UNICODE_STRING KeyName
;
1839 PLIST_ENTRY NextEntry
;
1841 PUNICODE_STRING
* ServicePath
= NULL
;
1842 BOOLEAN Success
, AutoSelect
;
1843 PBOOT_DRIVER_LIST_ENTRY DriverEntry
;
1846 /* Initialize the driver list */
1847 InitializeListHead(&DriverList
);
1849 /* Open the system hive key */
1850 RtlInitUnicodeString(&KeyName
, L
"\\Registry\\Machine\\System");
1851 InitializeObjectAttributes(&ObjectAttributes
,
1853 OBJ_CASE_INSENSITIVE
,
1856 Status
= NtOpenKey(&KeyHandle
, KEY_READ
, &ObjectAttributes
);
1857 if (!NT_SUCCESS(Status
)) return NULL
;
1859 /* Reference the key object to get the root hive/cell to access directly */
1860 Status
= ObReferenceObjectByHandle(KeyHandle
,
1866 if (!NT_SUCCESS(Status
))
1873 /* Do all this under the registry lock */
1874 CmpLockRegistryExclusive();
1876 /* Get the hive and key cell */
1877 Hive
= KeyBody
->KeyControlBlock
->KeyHive
;
1878 RootCell
= KeyBody
->KeyControlBlock
->KeyCell
;
1880 /* Open the current control set key */
1881 RtlInitUnicodeString(&KeyName
, L
"Current");
1882 ControlCell
= CmpFindControlSet(Hive
, RootCell
, &KeyName
, &AutoSelect
);
1883 if (ControlCell
== HCELL_NIL
) goto EndPath
;
1885 /* Find all system drivers */
1886 Success
= CmpFindDrivers(Hive
, ControlCell
, SystemLoad
, NULL
, &DriverList
);
1887 if (!Success
) goto EndPath
;
1889 /* Sort by group/tag */
1890 if (!CmpSortDriverList(Hive
, ControlCell
, &DriverList
)) goto EndPath
;
1892 /* Remove circular dependencies (cycles) and sort */
1893 if (!CmpResolveDriverDependencies(&DriverList
)) goto EndPath
;
1895 /* Loop the list to count drivers */
1896 for (i
= 0, NextEntry
= DriverList
.Flink
;
1897 NextEntry
!= &DriverList
;
1898 i
++, NextEntry
= NextEntry
->Flink
);
1900 /* Allocate the array */
1901 ServicePath
= ExAllocatePool(NonPagedPool
, (i
+ 1) * sizeof(PUNICODE_STRING
));
1902 if (!ServicePath
) KeBugCheckEx(CONFIG_INITIALIZATION_FAILED
, 2, 1, 0, 0);
1904 /* Loop the driver list */
1905 for (i
= 0, NextEntry
= DriverList
.Flink
;
1906 NextEntry
!= &DriverList
;
1907 i
++, NextEntry
= NextEntry
->Flink
)
1910 DriverEntry
= CONTAINING_RECORD(NextEntry
, BOOT_DRIVER_LIST_ENTRY
, Link
);
1912 /* Allocate the path for the caller */
1913 ServicePath
[i
] = ExAllocatePool(NonPagedPool
, sizeof(UNICODE_STRING
));
1914 if (!ServicePath
[i
])
1916 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED
, 2, 1, 0, 0);
1919 /* Duplicate the registry path */
1920 Status
= RtlDuplicateUnicodeString(RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE
,
1921 &DriverEntry
->RegistryPath
,
1923 if (!NT_SUCCESS(Status
))
1925 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED
, 2, 1, 0, 0);
1929 /* Terminate the list */
1930 ServicePath
[i
] = NULL
;
1933 /* Free the driver list if we had one */
1934 if (!IsListEmpty(&DriverList
)) CmpFreeDriverList(Hive
, &DriverList
);
1936 /* Unlock the registry */
1937 CmpUnlockRegistry();
1939 /* Close the key handle and dereference the object, then return the path */
1940 ObDereferenceObject(KeyBody
);
1947 CmpLockRegistryExclusive(VOID
)
1949 /* Enter a critical region and lock the registry */
1950 KeEnterCriticalRegion();
1951 ExAcquireResourceExclusiveLite(&CmpRegistryLock
, TRUE
);
1954 ASSERT(CmpFlushStarveWriters
== 0);
1955 RtlGetCallersAddress(&CmpRegistryLockCaller
, &CmpRegistryLockCallerCaller
);
1960 CmpLockRegistry(VOID
)
1962 /* Enter a critical region */
1963 KeEnterCriticalRegion();
1965 /* Check if we have to starve writers */
1966 if (CmpFlushStarveWriters
)
1968 /* Starve exlusive waiters */
1969 ExAcquireSharedStarveExclusive(&CmpRegistryLock
, TRUE
);
1973 /* Just grab the lock */
1974 ExAcquireResourceSharedLite(&CmpRegistryLock
, TRUE
);
1980 CmpTestRegistryLock(VOID
)
1983 return !ExIsResourceAcquiredSharedLite(&CmpRegistryLock
) ? FALSE
: TRUE
;
1988 CmpTestRegistryLockExclusive(VOID
)
1991 return !ExIsResourceAcquiredExclusiveLite(&CmpRegistryLock
) ? FALSE
: TRUE
;
1996 CmpLockHiveFlusherExclusive(IN PCMHIVE Hive
)
1998 /* Lock the flusher. We should already be in a critical section */
1999 CMP_ASSERT_REGISTRY_LOCK_OR_LOADING(Hive
);
2000 ASSERT((ExIsResourceAcquiredShared(Hive
->FlusherLock
) == 0) &&
2001 (ExIsResourceAcquiredExclusiveLite(Hive
->FlusherLock
) == 0));
2002 ExAcquireResourceExclusiveLite(Hive
->FlusherLock
, TRUE
);
2007 CmpLockHiveFlusherShared(IN PCMHIVE Hive
)
2009 /* Lock the flusher. We should already be in a critical section */
2010 CMP_ASSERT_REGISTRY_LOCK_OR_LOADING(Hive
);
2011 ASSERT((ExIsResourceAcquiredShared(Hive
->FlusherLock
) == 0) &&
2012 (ExIsResourceAcquiredExclusiveLite(Hive
->FlusherLock
) == 0));
2013 ExAcquireResourceSharedLite(Hive
->FlusherLock
, TRUE
);
2018 CmpUnlockHiveFlusher(IN PCMHIVE Hive
)
2021 CMP_ASSERT_REGISTRY_LOCK_OR_LOADING(Hive
);
2022 CMP_ASSERT_FLUSH_LOCK(Hive
);
2024 /* Release the lock */
2025 ExReleaseResourceLite(Hive
->FlusherLock
);
2030 CmpTestHiveFlusherLockShared(IN PCMHIVE Hive
)
2033 return !ExIsResourceAcquiredSharedLite(Hive
->FlusherLock
) ? FALSE
: TRUE
;
2038 CmpTestHiveFlusherLockExclusive(IN PCMHIVE Hive
)
2041 return !ExIsResourceAcquiredExclusiveLite(Hive
->FlusherLock
) ? FALSE
: TRUE
;
2046 CmpUnlockRegistry(VOID
)
2049 CMP_ASSERT_REGISTRY_LOCK();
2051 /* Check if we should flush the registry */
2052 if (CmpFlushOnLockRelease
)
2054 /* The registry should be exclusively locked for this */
2055 CMP_ASSERT_EXCLUSIVE_REGISTRY_LOCK();
2057 /* Flush the registry */
2058 CmpDoFlushAll(TRUE
);
2059 CmpFlushOnLockRelease
= FALSE
;
2063 /* Lazy flush the registry */
2067 /* Release the lock and leave the critical region */
2068 ExReleaseResourceLite(&CmpRegistryLock
);
2069 KeLeaveCriticalRegion();
2074 CmpAcquireTwoKcbLocksExclusiveByKey(IN ULONG ConvKey1
,
2077 ULONG Index1
, Index2
;
2080 CMP_ASSERT_REGISTRY_LOCK();
2082 /* Get hash indexes */
2083 Index1
= GET_HASH_INDEX(ConvKey1
);
2084 Index2
= GET_HASH_INDEX(ConvKey2
);
2086 /* See which one is highest */
2087 if (Index1
< Index2
)
2089 /* Grab them in the proper order */
2090 CmpAcquireKcbLockExclusiveByKey(ConvKey1
);
2091 CmpAcquireKcbLockExclusiveByKey(ConvKey2
);
2095 /* Grab the second one first, then the first */
2096 CmpAcquireKcbLockExclusiveByKey(ConvKey2
);
2097 if (Index1
!= Index2
) CmpAcquireKcbLockExclusiveByKey(ConvKey1
);
2103 CmpReleaseTwoKcbLockByKey(IN ULONG ConvKey1
,
2106 ULONG Index1
, Index2
;
2109 CMP_ASSERT_REGISTRY_LOCK();
2111 /* Get hash indexes */
2112 Index1
= GET_HASH_INDEX(ConvKey1
);
2113 Index2
= GET_HASH_INDEX(ConvKey2
);
2114 ASSERT((GET_HASH_ENTRY(CmpCacheTable
, ConvKey2
)->Owner
== KeGetCurrentThread()) ||
2115 (CmpTestRegistryLockExclusive()));
2117 /* See which one is highest */
2118 if (Index1
< Index2
)
2120 /* Grab them in the proper order */
2121 ASSERT((GET_HASH_ENTRY(CmpCacheTable
, ConvKey1
)->Owner
== KeGetCurrentThread()) ||
2122 (CmpTestRegistryLockExclusive()));
2123 CmpReleaseKcbLockByKey(ConvKey2
);
2124 CmpReleaseKcbLockByKey(ConvKey1
);
2128 /* Release the first one first, then the second */
2129 if (Index1
!= Index2
)
2131 ASSERT((GET_HASH_ENTRY(CmpCacheTable
, ConvKey1
)->Owner
== KeGetCurrentThread()) ||
2132 (CmpTestRegistryLockExclusive()));
2133 CmpReleaseKcbLockByKey(ConvKey1
);
2135 CmpReleaseKcbLockByKey(ConvKey2
);
2141 CmShutdownSystem(VOID
)
2143 PLIST_ENTRY ListEntry
;
2146 /* Kill the workers */
2147 if (!CmFirstTime
) CmpShutdownWorkers();
2149 /* Flush all hives */
2150 CmpLockRegistryExclusive();
2151 CmpDoFlushAll(TRUE
);
2153 /* Close all hive files */
2154 ListEntry
= CmpHiveListHead
.Flink
;
2155 while (ListEntry
!= &CmpHiveListHead
)
2157 Hive
= CONTAINING_RECORD(ListEntry
, CMHIVE
, HiveList
);
2159 CmpCloseHiveFiles(Hive
);
2161 ListEntry
= ListEntry
->Flink
;
2164 CmpUnlockRegistry();
2169 CmpSetVersionData(VOID
)
2172 OBJECT_ATTRIBUTES ObjectAttributes
;
2173 UNICODE_STRING KeyName
;
2174 UNICODE_STRING ValueName
;
2175 UNICODE_STRING ValueData
;
2176 ANSI_STRING TempString
;
2177 HANDLE SoftwareKeyHandle
= NULL
;
2178 HANDLE MicrosoftKeyHandle
= NULL
;
2179 HANDLE WindowsNtKeyHandle
= NULL
;
2180 HANDLE CurrentVersionKeyHandle
= NULL
;
2181 WCHAR Buffer
[128]; // Buffer large enough to contain a full ULONG in decimal
2182 // representation, and the full 'CurrentType' string.
2185 * Open the 'HKLM\Software\Microsoft\Windows NT\CurrentVersion' key
2186 * (create the intermediate subkeys if needed).
2189 RtlInitUnicodeString(&KeyName
, L
"\\REGISTRY\\MACHINE\\SOFTWARE");
2190 InitializeObjectAttributes(&ObjectAttributes
,
2192 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
2195 Status
= NtCreateKey(&SoftwareKeyHandle
,
2202 if (!NT_SUCCESS(Status
))
2204 DPRINT1("Failed to create key %wZ (Status: %08lx)\n", &KeyName
, Status
);
2208 RtlInitUnicodeString(&KeyName
, L
"Microsoft");
2209 InitializeObjectAttributes(&ObjectAttributes
,
2211 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
2214 Status
= NtCreateKey(&MicrosoftKeyHandle
,
2221 if (!NT_SUCCESS(Status
))
2223 DPRINT1("Failed to create key %wZ (Status: %08lx)\n", &KeyName
, Status
);
2227 RtlInitUnicodeString(&KeyName
, L
"Windows NT");
2228 InitializeObjectAttributes(&ObjectAttributes
,
2230 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
2233 Status
= NtCreateKey(&WindowsNtKeyHandle
,
2240 if (!NT_SUCCESS(Status
))
2242 DPRINT1("Failed to create key %wZ (Status: %08lx)\n", &KeyName
, Status
);
2246 RtlInitUnicodeString(&KeyName
, L
"CurrentVersion");
2247 InitializeObjectAttributes(&ObjectAttributes
,
2249 OBJ_CASE_INSENSITIVE
| OBJ_KERNEL_HANDLE
,
2252 Status
= NtCreateKey(&CurrentVersionKeyHandle
,
2253 KEY_CREATE_SUB_KEY
| KEY_SET_VALUE
,
2259 if (!NT_SUCCESS(Status
))
2261 DPRINT1("Failed to create key %wZ (Status: %08lx)\n", &KeyName
, Status
);
2265 /* Set the 'CurrentVersion' value */
2266 RtlInitUnicodeString(&ValueName
, L
"CurrentVersion");
2267 NtSetValueKey(CurrentVersionKeyHandle
,
2271 CmVersionString
.Buffer
,
2272 CmVersionString
.Length
+ sizeof(WCHAR
));
2274 /* Set the 'CurrentBuildNumber' value */
2275 RtlInitUnicodeString(&ValueName
, L
"CurrentBuildNumber");
2276 RtlInitEmptyUnicodeString(&ValueData
, Buffer
, sizeof(Buffer
));
2277 RtlIntegerToUnicodeString(NtBuildNumber
& 0xFFFF, 10, &ValueData
);
2278 NtSetValueKey(CurrentVersionKeyHandle
,
2283 ValueData
.Length
+ sizeof(WCHAR
));
2285 /* Set the 'BuildLab' value */
2286 RtlInitUnicodeString(&ValueName
, L
"BuildLab");
2287 RtlInitAnsiString(&TempString
, NtBuildLab
);
2288 Status
= RtlAnsiStringToUnicodeString(&ValueData
, &TempString
, FALSE
);
2289 if (NT_SUCCESS(Status
))
2291 NtSetValueKey(CurrentVersionKeyHandle
,
2296 ValueData
.Length
+ sizeof(WCHAR
));
2299 /* Set the 'CurrentType' value */
2300 RtlInitUnicodeString(&ValueName
, L
"CurrentType");
2301 RtlStringCbPrintfW(Buffer
, sizeof(Buffer
),
2315 RtlInitUnicodeString(&ValueData
, Buffer
);
2316 NtSetValueKey(CurrentVersionKeyHandle
,
2321 ValueData
.Length
+ sizeof(WCHAR
));
2323 /* Set the 'CSDVersion' value */
2324 RtlInitUnicodeString(&ValueName
, L
"CSDVersion");
2325 if (CmCSDVersionString
.Length
!= 0)
2327 NtSetValueKey(CurrentVersionKeyHandle
,
2331 CmCSDVersionString
.Buffer
,
2332 CmCSDVersionString
.Length
+ sizeof(WCHAR
));
2336 NtDeleteValueKey(CurrentVersionKeyHandle
, &ValueName
);
2339 /* Set the 'CSDBuildNumber' value */
2340 RtlInitUnicodeString(&ValueName
, L
"CSDBuildNumber");
2341 if (CmNtSpBuildNumber
!= 0)
2343 RtlInitEmptyUnicodeString(&ValueData
, Buffer
, sizeof(Buffer
));
2344 RtlIntegerToUnicodeString(CmNtSpBuildNumber
, 10, &ValueData
);
2345 NtSetValueKey(CurrentVersionKeyHandle
,
2350 ValueData
.Length
+ sizeof(WCHAR
));
2354 NtDeleteValueKey(CurrentVersionKeyHandle
, &ValueName
);
2357 /* Set the 'SystemRoot' value */
2358 RtlInitUnicodeString(&ValueName
, L
"SystemRoot");
2359 NtSetValueKey(CurrentVersionKeyHandle
,
2363 NtSystemRoot
.Buffer
,
2364 NtSystemRoot
.Length
+ sizeof(WCHAR
));
2367 /* Close the keys */
2368 if (CurrentVersionKeyHandle
!= NULL
)
2369 NtClose(CurrentVersionKeyHandle
);
2371 if (WindowsNtKeyHandle
!= NULL
)
2372 NtClose(WindowsNtKeyHandle
);
2374 if (MicrosoftKeyHandle
!= NULL
)
2375 NtClose(MicrosoftKeyHandle
);
2377 if (SoftwareKeyHandle
!= NULL
)
2378 NtClose(SoftwareKeyHandle
);