- Replace KEY_OBJECT by real CM_KEY_BODY NT type.
[reactos.git] / reactos / ntoskrnl / config / cmsysini.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/config/cmsysini.c
5 * PURPOSE: Configuration Manager - System Initialization Code
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7 */
8
9 /* INCLUDES ******************************************************************/
10
11 #include "ntoskrnl.h"
12 #include "cm.h"
13 #define NDEBUG
14 #include "debug.h"
15
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 CmpFlushStarveWriters;
28 BOOLEAN CmpFlushOnLockRelease;
29 BOOLEAN CmpSpecialBootCondition;
30 BOOLEAN CmpNoWrite;
31 BOOLEAN CmpForceForceFlush;
32 BOOLEAN CmpWasSetupBoot;
33
34 /* FUNCTIONS *****************************************************************/
35
36 PVOID
37 NTAPI
38 CmpRosGetHardwareHive(OUT PULONG Length)
39 {
40 PLIST_ENTRY ListHead, NextEntry;
41 PMEMORY_ALLOCATION_DESCRIPTOR MdBlock = NULL;
42
43 /* Loop the memory descriptors */
44 ListHead = &KeLoaderBlock->MemoryDescriptorListHead;
45 NextEntry = ListHead->Flink;
46 while (NextEntry != ListHead)
47 {
48 /* Get the current block */
49 MdBlock = CONTAINING_RECORD(NextEntry,
50 MEMORY_ALLOCATION_DESCRIPTOR,
51 ListEntry);
52
53 /* Check if this is an registry block */
54 if (MdBlock->MemoryType == LoaderRegistryData)
55 {
56 /* Check if it's not the SYSTEM hive that we already initialized */
57 if ((MdBlock->BasePage) !=
58 (((ULONG_PTR)KeLoaderBlock->RegistryBase &~ KSEG0_BASE) >> PAGE_SHIFT))
59 {
60 /* Hardware hive break out */
61 break;
62 }
63 }
64
65 /* Go to the next block */
66 NextEntry = MdBlock->ListEntry.Flink;
67 }
68
69 /* We need a hardware hive */
70 ASSERT(MdBlock);
71 *Length = MdBlock->PageCount << PAGE_SHIFT;
72 return (PVOID)((MdBlock->BasePage << PAGE_SHIFT) | KSEG0_BASE);
73 }
74
75 NTSTATUS
76 NTAPI
77 CmpInitHiveFromFile(IN PCUNICODE_STRING HiveName,
78 IN ULONG HiveFlags,
79 OUT PCMHIVE *Hive,
80 IN OUT PBOOLEAN New,
81 IN ULONG CheckFlags)
82 {
83 ULONG HiveDisposition, LogDisposition;
84 HANDLE FileHandle = NULL, LogHandle = NULL;
85 NTSTATUS Status;
86 ULONG Operation, FileType;
87 PCMHIVE NewHive;
88 PAGED_CODE();
89
90 /* Assume failure */
91 *Hive = NULL;
92
93 /* Open or create the hive files */
94 Status = CmpOpenHiveFiles(HiveName,
95 L".LOG",
96 &FileHandle,
97 &LogHandle,
98 &HiveDisposition,
99 &LogDisposition,
100 *New,
101 FALSE,
102 TRUE,
103 NULL);
104 if (!NT_SUCCESS(Status)) return Status;
105
106 /* Check if we have a log handle */
107 FileType = (LogHandle) ? HFILE_TYPE_LOG : HFILE_TYPE_PRIMARY;
108
109 /* Check if we created or opened the hive */
110 if (HiveDisposition == FILE_CREATED)
111 {
112 /* Do a create operation */
113 Operation = HINIT_CREATE;
114 *New = TRUE;
115 }
116 else
117 {
118 /* Open it as a file */
119 Operation = HINIT_FILE;
120 *New = FALSE;
121 }
122
123 /* Check if we're sharing hives */
124 if (CmpShareSystemHives)
125 {
126 /* Then force using the primary hive */
127 FileType = HFILE_TYPE_PRIMARY;
128 if (LogHandle)
129 {
130 /* Get rid of the log handle */
131 ZwClose(LogHandle);
132 LogHandle = NULL;
133 }
134 }
135
136 /* Check if we're too late */
137 if (HvShutdownComplete)
138 {
139 /* Fail */
140 ZwClose(FileHandle);
141 if (LogHandle) ZwClose(LogHandle);
142 return STATUS_TOO_LATE;
143 }
144
145 /* Initialize the hive */
146 Status = CmpInitializeHive((PCMHIVE*)&NewHive,
147 Operation,
148 HiveFlags,
149 FileType,
150 NULL,
151 FileHandle,
152 LogHandle,
153 NULL,
154 HiveName,
155 0);
156 if (!NT_SUCCESS(Status))
157 {
158 /* Fail */
159 ZwClose(FileHandle);
160 if (LogHandle) ZwClose(LogHandle);
161 return Status;
162 }
163
164 /* Success, return hive */
165 *Hive = NewHive;
166
167 /* ROS: Init root key cell and prepare the hive */
168 if (Operation == HINIT_CREATE) CmCreateRootNode(&NewHive->Hive, L"");
169 CmPrepareHive(&NewHive->Hive);
170
171 /* Duplicate the hive name */
172 NewHive->FileFullPath.Buffer = ExAllocatePoolWithTag(PagedPool,
173 HiveName->Length,
174 TAG_CM);
175 if (NewHive->FileFullPath.Buffer)
176 {
177 /* Copy the string */
178 RtlCopyMemory(NewHive->FileFullPath.Buffer,
179 HiveName->Buffer,
180 HiveName->Length);
181 NewHive->FileFullPath.Length = HiveName->Length;
182 NewHive->FileFullPath.MaximumLength = HiveName->MaximumLength;
183 }
184
185 /* Return success */
186 return STATUS_SUCCESS;
187 }
188
189 NTSTATUS
190 NTAPI
191 CmpSetSystemValues(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
192 {
193 OBJECT_ATTRIBUTES ObjectAttributes;
194 UNICODE_STRING KeyName, ValueName = {0};
195 HANDLE KeyHandle;
196 NTSTATUS Status;
197 ASSERT(LoaderBlock != NULL);
198
199 /* Setup attributes for loader options */
200 RtlInitUnicodeString(&KeyName,
201 L"\\REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\"
202 L"Control");
203 InitializeObjectAttributes(&ObjectAttributes,
204 &KeyName,
205 OBJ_CASE_INSENSITIVE,
206 NULL,
207 NULL);
208 Status = NtOpenKey(&KeyHandle, KEY_WRITE, &ObjectAttributes);
209 if (!NT_SUCCESS(Status)) goto Quickie;
210
211 /* Key opened, now write to the key */
212 RtlInitUnicodeString(&KeyName, L"SystemStartOptions");
213 Status = NtSetValueKey(KeyHandle,
214 &KeyName,
215 0,
216 REG_SZ,
217 CmpLoadOptions.Buffer,
218 CmpLoadOptions.Length);
219 if (!NT_SUCCESS(Status)) goto Quickie;
220
221 /* Setup value name for system boot device */
222 RtlInitUnicodeString(&KeyName, L"SystemBootDevice");
223 RtlCreateUnicodeStringFromAsciiz(&ValueName, LoaderBlock->NtBootPathName);
224 Status = NtSetValueKey(KeyHandle,
225 &KeyName,
226 0,
227 REG_SZ,
228 ValueName.Buffer,
229 ValueName.Length);
230
231 Quickie:
232 /* Free the buffers */
233 RtlFreeUnicodeString(&ValueName);
234
235 /* Close the key and return */
236 NtClose(KeyHandle);
237
238 /* Return the status */
239 return (ExpInTextModeSetup ? STATUS_SUCCESS : Status);
240 }
241
242 NTSTATUS
243 NTAPI
244 CmpCreateControlSet(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
245 {
246 UNICODE_STRING ConfigName = RTL_CONSTANT_STRING(L"Control\\IDConfigDB");
247 UNICODE_STRING SelectName =
248 RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\Select");
249 UNICODE_STRING KeyName;
250 OBJECT_ATTRIBUTES ObjectAttributes;
251 CHAR ValueInfoBuffer[128];
252 PKEY_VALUE_FULL_INFORMATION ValueInfo;
253 CHAR Buffer[128];
254 WCHAR UnicodeBuffer[128];
255 HANDLE SelectHandle, KeyHandle, ConfigHandle = NULL, ProfileHandle = NULL;
256 HANDLE ParentHandle = NULL;
257 ULONG ControlSet, HwProfile;
258 ANSI_STRING TempString;
259 NTSTATUS Status;
260 ULONG ResultLength, Disposition;
261 PLOADER_PARAMETER_EXTENSION LoaderExtension;
262 PAGED_CODE();
263
264 /* Open the select key */
265 InitializeObjectAttributes(&ObjectAttributes,
266 &SelectName,
267 OBJ_CASE_INSENSITIVE,
268 NULL,
269 NULL);
270 Status = NtOpenKey(&SelectHandle, KEY_READ, &ObjectAttributes);
271 if (!NT_SUCCESS(Status))
272 {
273 /* ReactOS Hack: Hard-code current to 001 for SetupLdr */
274 if (!LoaderBlock->RegistryBase)
275 {
276 /* Use hard-coded setting */
277 ControlSet = 1;
278 goto UseSet;
279 }
280
281 /* Fail for real boots */
282 return Status;
283 }
284
285 /* Open the current value */
286 RtlInitUnicodeString(&KeyName, L"Current");
287 Status = NtQueryValueKey(SelectHandle,
288 &KeyName,
289 KeyValueFullInformation,
290 ValueInfoBuffer,
291 sizeof(ValueInfoBuffer),
292 &ResultLength);
293 NtClose(SelectHandle);
294 if (!NT_SUCCESS(Status)) return Status;
295
296 /* Get the actual value pointer, and get the control set ID */
297 ValueInfo = (PKEY_VALUE_FULL_INFORMATION)ValueInfoBuffer;
298 ControlSet = *(PULONG)((PUCHAR)ValueInfo + ValueInfo->DataOffset);
299
300 /* Create the current control set key */
301 UseSet:
302 RtlInitUnicodeString(&KeyName,
303 L"\\Registry\\Machine\\System\\CurrentControlSet");
304 InitializeObjectAttributes(&ObjectAttributes,
305 &KeyName,
306 OBJ_CASE_INSENSITIVE,
307 NULL,
308 NULL);
309
310 Status = NtCreateKey(&KeyHandle,
311 KEY_CREATE_LINK,
312 &ObjectAttributes,
313 0,
314 NULL,
315 REG_OPTION_VOLATILE | REG_OPTION_CREATE_LINK,
316 &Disposition);
317 if (!NT_SUCCESS(Status)) return Status;
318
319 /* Sanity check */
320 ASSERT(Disposition == REG_CREATED_NEW_KEY);
321
322 /* Initialize the symbolic link name */
323 sprintf(Buffer,
324 "\\Registry\\Machine\\System\\ControlSet%03ld",
325 ControlSet);
326 RtlInitAnsiString(&TempString, Buffer);
327
328 /* Create a Unicode string out of it */
329 KeyName.MaximumLength = sizeof(UnicodeBuffer);
330 KeyName.Buffer = UnicodeBuffer;
331 Status = RtlAnsiStringToUnicodeString(&KeyName, &TempString, FALSE);
332
333 /* Set the value */
334 Status = NtSetValueKey(KeyHandle,
335 &CmSymbolicLinkValueName,
336 0,
337 REG_LINK,
338 KeyName.Buffer,
339 KeyName.Length);
340 if (!NT_SUCCESS(Status)) return Status;
341
342 /* Get the configuration database key */
343 InitializeObjectAttributes(&ObjectAttributes,
344 &ConfigName,
345 OBJ_CASE_INSENSITIVE,
346 KeyHandle,
347 NULL);
348 Status = NtOpenKey(&ConfigHandle, KEY_READ, &ObjectAttributes);
349 NtClose(KeyHandle);
350
351 /* Check if we don't have one */
352 if (!NT_SUCCESS(Status))
353 {
354 /* Cleanup and exit */
355 ConfigHandle = 0;
356 goto Cleanup;
357 }
358
359 /* Now get the current config */
360 RtlInitUnicodeString(&KeyName, L"CurrentConfig");
361 Status = NtQueryValueKey(ConfigHandle,
362 &KeyName,
363 KeyValueFullInformation,
364 ValueInfoBuffer,
365 sizeof(ValueInfoBuffer),
366 &ResultLength);
367
368 /* Set pointer to buffer */
369 ValueInfo = (PKEY_VALUE_FULL_INFORMATION)ValueInfoBuffer;
370
371 /* Check if we failed or got a non DWORD-value */
372 if (!(NT_SUCCESS(Status)) || (ValueInfo->Type != REG_DWORD)) goto Cleanup;
373
374 /* Get the hadware profile */
375 HwProfile = *(PULONG)((PUCHAR)ValueInfo + ValueInfo->DataOffset);
376
377 /* Open the hardware profile key */
378 RtlInitUnicodeString(&KeyName,
379 L"\\Registry\\Machine\\System\\CurrentControlSet"
380 L"\\Hardware Profiles");
381 InitializeObjectAttributes(&ObjectAttributes,
382 &KeyName,
383 OBJ_CASE_INSENSITIVE,
384 NULL,
385 NULL);
386 Status = NtOpenKey(&ParentHandle, KEY_READ, &ObjectAttributes);
387 if (!NT_SUCCESS(Status))
388 {
389 /* Exit and clean up */
390 ParentHandle = 0;
391 goto Cleanup;
392 }
393
394 /* Build the profile name */
395 sprintf(Buffer, "%04ld", HwProfile);
396 RtlInitAnsiString(&TempString, Buffer);
397
398 /* Convert it to Unicode */
399 KeyName.MaximumLength = sizeof(UnicodeBuffer);
400 KeyName.Buffer = UnicodeBuffer;
401 Status = RtlAnsiStringToUnicodeString(&KeyName,
402 &TempString,
403 FALSE);
404 ASSERT(Status == STATUS_SUCCESS);
405
406 /* Open the associated key */
407 InitializeObjectAttributes(&ObjectAttributes,
408 &KeyName,
409 OBJ_CASE_INSENSITIVE,
410 ParentHandle,
411 NULL);
412 Status = NtOpenKey(&ProfileHandle,
413 KEY_READ | KEY_WRITE,
414 &ObjectAttributes);
415 if (!NT_SUCCESS (Status))
416 {
417 /* Cleanup and exit */
418 ProfileHandle = 0;
419 goto Cleanup;
420 }
421
422 /* Check if we have a loader block extension */
423 LoaderExtension = LoaderBlock->Extension;
424 if (LoaderExtension)
425 {
426 ASSERTMSG("ReactOS doesn't support NTLDR Profiles yet!\n", FALSE);
427 }
428
429 /* Create the current hardware profile key */
430 RtlInitUnicodeString(&KeyName,
431 L"\\Registry\\Machine\\System\\CurrentControlSet\\"
432 L"Hardware Profiles\\Current");
433 InitializeObjectAttributes(&ObjectAttributes,
434 &KeyName,
435 OBJ_CASE_INSENSITIVE,
436 NULL,
437 NULL);
438 Status = NtCreateKey(&KeyHandle,
439 KEY_CREATE_LINK,
440 &ObjectAttributes,
441 0,
442 NULL,
443 REG_OPTION_VOLATILE | REG_OPTION_CREATE_LINK,
444 &Disposition);
445 if (NT_SUCCESS(Status))
446 {
447 /* Sanity check */
448 ASSERT(Disposition == REG_CREATED_NEW_KEY);
449
450 /* Create the profile name */
451 sprintf(Buffer,
452 "\\Registry\\Machine\\System\\CurrentControlSet\\"
453 "Hardware Profiles\\%04ld",
454 HwProfile);
455 RtlInitAnsiString(&TempString, Buffer);
456
457 /* Convert it to Unicode */
458 KeyName.MaximumLength = sizeof(UnicodeBuffer);
459 KeyName.Buffer = UnicodeBuffer;
460 Status = RtlAnsiStringToUnicodeString(&KeyName,
461 &TempString,
462 FALSE);
463 ASSERT(STATUS_SUCCESS == Status);
464
465 /* Set it */
466 Status = NtSetValueKey(KeyHandle,
467 &CmSymbolicLinkValueName,
468 0,
469 REG_LINK,
470 KeyName.Buffer,
471 KeyName.Length);
472 NtClose(KeyHandle);
473 }
474
475 /* Close every opened handle */
476 Cleanup:
477 if (ConfigHandle) NtClose(ConfigHandle);
478 if (ProfileHandle) NtClose(ProfileHandle);
479 if (ParentHandle) NtClose(ParentHandle);
480
481 /* Return success */
482 return STATUS_SUCCESS;
483 }
484
485 NTSTATUS
486 NTAPI
487 CmpLinkHiveToMaster(IN PUNICODE_STRING LinkName,
488 IN HANDLE RootDirectory,
489 IN PCMHIVE RegistryHive,
490 IN BOOLEAN Allocate,
491 IN PSECURITY_DESCRIPTOR SecurityDescriptor)
492 {
493 OBJECT_ATTRIBUTES ObjectAttributes;
494 UNICODE_STRING RemainingPath;
495 PCM_KEY_BODY ParentKey;
496 PCM_KEY_BODY NewKey;
497 NTSTATUS Status;
498 UNICODE_STRING ObjectName;
499 OBJECT_CREATE_INFORMATION ObjectCreateInfo;
500 CM_PARSE_CONTEXT ParseContext = {0};
501 HANDLE KeyHandle;
502 PAGED_CODE();
503
504 /* Setup the object attributes */
505 InitializeObjectAttributes(&ObjectAttributes,
506 LinkName,
507 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
508 RootDirectory,
509 SecurityDescriptor);
510
511 /* Setup the parse context */
512 ParseContext.CreateLink = TRUE;
513 ParseContext.CreateOperation = TRUE;
514 ParseContext.ChildHive.KeyHive = &RegistryHive->Hive;
515
516 /* Check if we have a root keycell or if we need to create it */
517 if (Allocate)
518 {
519 /* Create it */
520 ParseContext.ChildHive.KeyCell = HCELL_NIL;
521 }
522 else
523 {
524 /* We have one */
525 ParseContext.ChildHive.KeyCell = RegistryHive->Hive.BaseBlock->RootCell;
526 }
527
528 /* Create the link node */
529 Status = ObOpenObjectByName(&ObjectAttributes,
530 CmpKeyObjectType,
531 KernelMode,
532 NULL,
533 KEY_READ | KEY_WRITE,
534 (PVOID)&ParseContext,
535 &KeyHandle);
536
537 /* Capture all the info */
538 Status = ObpCaptureObjectAttributes(&ObjectAttributes,
539 KernelMode,
540 FALSE,
541 &ObjectCreateInfo,
542 &ObjectName);
543 if (!NT_SUCCESS(Status)) return Status;
544
545 /* Do the parse */
546 Status = CmFindObject(&ObjectCreateInfo,
547 &ObjectName,
548 (PVOID*)&ParentKey,
549 &RemainingPath,
550 CmpKeyObjectType,
551 NULL,
552 NULL);
553
554 /* Let go of captured attributes and name */
555 ObpReleaseCapturedAttributes(&ObjectCreateInfo);
556 if (ObjectName.Buffer) ObpFreeObjectNameBuffer(&ObjectName);
557
558 /* Get out of here if we failed */
559 if (!NT_SUCCESS(Status)) return Status;
560
561 /* Scan for no name */
562 if (!(RemainingPath.Length) || (RemainingPath.Buffer[0] == UNICODE_NULL))
563 {
564 /* Fail */
565 ObDereferenceObject(ParentKey);
566 return STATUS_OBJECT_NAME_NOT_FOUND;
567 }
568
569 /* Scan for leading backslash */
570 while ((RemainingPath.Length) &&
571 (*RemainingPath.Buffer == OBJ_NAME_PATH_SEPARATOR))
572 {
573 /* Ignore it */
574 RemainingPath.Length -= sizeof(WCHAR);
575 RemainingPath.MaximumLength -= sizeof(WCHAR);
576 RemainingPath.Buffer++;
577 }
578
579 /* Create the link node */
580 Status = CmpCreateLinkNode(ParentKey->KeyControlBlock->KeyHive,
581 ParentKey->KeyControlBlock->KeyCell,
582 NULL,
583 RemainingPath,
584 KernelMode,
585 0,
586 &ParseContext,
587 ParentKey->KeyControlBlock,
588 (PVOID*)&NewKey);
589 if (!NT_SUCCESS(Status))
590 {
591 /* Failed */
592 DPRINT1("CmpLinkHiveToMaster failed: %lx\n", Status);
593 ObDereferenceObject(ParentKey);
594 return Status;
595 }
596
597 /* Free the create information */
598 ObpFreeAndReleaseCapturedAttributes(OBJECT_TO_OBJECT_HEADER(NewKey)->ObjectCreateInfo);
599 OBJECT_TO_OBJECT_HEADER(NewKey)->ObjectCreateInfo = NULL;
600
601 /* Mark the hive as clean */
602 RegistryHive->Hive.DirtyFlag = FALSE;
603
604 /* Update KCB information */
605 NewKey->KeyControlBlock->KeyCell = RegistryHive->Hive.BaseBlock->RootCell;
606 NewKey->KeyControlBlock->KeyHive = &RegistryHive->Hive;
607
608 /* Reference the new key */
609 ObReferenceObject(NewKey);
610
611 /* Link this key to the parent */
612 InsertTailList(&ParentKey->KeyControlBlock->KeyBodyListHead, &NewKey->KeyBodyList);
613 return STATUS_SUCCESS;
614 }
615
616 BOOLEAN
617 NTAPI
618 CmpInitializeSystemHive(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
619 {
620 PVOID HiveBase;
621 ANSI_STRING LoadString;
622 PVOID Buffer;
623 ULONG Length;
624 NTSTATUS Status;
625 BOOLEAN Allocate;
626 UNICODE_STRING KeyName;
627 PCMHIVE SystemHive = NULL;
628 UNICODE_STRING HiveName = RTL_CONSTANT_STRING(L"SYSTEM");
629 PSECURITY_DESCRIPTOR SecurityDescriptor;
630 PAGED_CODE();
631
632 /* Setup the ansi string */
633 RtlInitAnsiString(&LoadString, LoaderBlock->LoadOptions);
634
635 /* Allocate the unicode buffer */
636 Length = LoadString.Length * sizeof(WCHAR) + sizeof(UNICODE_NULL);
637 Buffer = ExAllocatePoolWithTag(PagedPool, Length, TAG_CM);
638 if (!Buffer)
639 {
640 /* Fail */
641 KEBUGCHECKEX(BAD_SYSTEM_CONFIG_INFO, 3, 1, (ULONG_PTR)LoaderBlock, 0);
642 }
643
644 /* Setup the unicode string */
645 RtlInitEmptyUnicodeString(&CmpLoadOptions, Buffer, (USHORT)Length);
646
647 /* Add the load options and null-terminate */
648 RtlAnsiStringToUnicodeString(&CmpLoadOptions, &LoadString, FALSE);
649 CmpLoadOptions.Buffer[LoadString.Length] = UNICODE_NULL;
650 CmpLoadOptions.Length += sizeof(WCHAR);
651
652 /* Get the System Hive base address */
653 HiveBase = LoaderBlock->RegistryBase;
654 if (HiveBase)
655 {
656 /* Import it */
657 ((PHBASE_BLOCK)HiveBase)->Length = LoaderBlock->RegistryLength;
658 Status = CmpInitializeHive((PCMHIVE*)&SystemHive,
659 HINIT_MEMORY,
660 HIVE_NOLAZYFLUSH,
661 HFILE_TYPE_LOG,
662 HiveBase,
663 NULL,
664 NULL,
665 NULL,
666 &HiveName,
667 2);
668 if (!NT_SUCCESS(Status)) return FALSE;
669 CmPrepareHive(&SystemHive->Hive);
670
671 /* Set the hive filename */
672 RtlCreateUnicodeString(&SystemHive->FileFullPath,
673 L"\\SystemRoot\\System32\\Config\\SYSTEM");
674
675 /* We imported, no need to create a new hive */
676 Allocate = FALSE;
677
678 /* Manually set the hive as volatile, if in Live CD mode */
679 if (CmpShareSystemHives) SystemHive->Hive.HiveFlags = HIVE_VOLATILE;
680 }
681 else
682 {
683 /* Create it */
684 Status = CmpInitializeHive(&SystemHive,
685 HINIT_CREATE,
686 HIVE_NOLAZYFLUSH,
687 HFILE_TYPE_LOG,
688 NULL,
689 NULL,
690 NULL,
691 NULL,
692 &HiveName,
693 0);
694 if (!NT_SUCCESS(Status)) return FALSE;
695
696 /* Set the hive filename */
697 RtlCreateUnicodeString(&SystemHive->FileFullPath,
698 L"\\SystemRoot\\System32\\Config\\SYSTEM");
699
700 /* Tell CmpLinkHiveToMaster to allocate a hive */
701 Allocate = TRUE;
702 }
703
704 /* Save the boot type */
705 if (SystemHive) CmpBootType = SystemHive->Hive.BaseBlock->BootType;
706
707 /* Are we in self-healing mode? */
708 if (!CmSelfHeal)
709 {
710 /* Disable self-healing internally and check if boot type wanted it */
711 CmpSelfHeal = FALSE;
712 if (CmpBootType & 4)
713 {
714 /* We're disabled, so bugcheck */
715 KEBUGCHECKEX(BAD_SYSTEM_CONFIG_INFO,
716 3,
717 3,
718 (ULONG_PTR)SystemHive,
719 0);
720 }
721 }
722
723 /* Create the default security descriptor */
724 SecurityDescriptor = CmpHiveRootSecurityDescriptor();
725
726 /* Attach it to the system key */
727 RtlInitUnicodeString(&KeyName, L"\\Registry\\Machine\\SYSTEM");
728 Status = CmpLinkHiveToMaster(&KeyName,
729 NULL,
730 (PCMHIVE)SystemHive,
731 Allocate,
732 SecurityDescriptor);
733
734 /* Free the security descriptor */
735 ExFreePool(SecurityDescriptor);
736 if (!NT_SUCCESS(Status)) return FALSE;
737
738 /* Add the hive to the hive list */
739 CmpMachineHiveList[3].CmHive = (PCMHIVE)SystemHive;
740
741 /* Success! */
742 return TRUE;
743 }
744
745 NTSTATUS
746 NTAPI
747 CmpCreateObjectTypes(VOID)
748 {
749 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer;
750 UNICODE_STRING Name;
751 GENERIC_MAPPING CmpKeyMapping = {KEY_READ,
752 KEY_WRITE,
753 KEY_EXECUTE,
754 KEY_ALL_ACCESS};
755 PAGED_CODE();
756
757 /* Initialize the Key object type */
758 RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer));
759 RtlInitUnicodeString(&Name, L"Key");
760 ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer);
761 ObjectTypeInitializer.DefaultPagedPoolCharge = sizeof(CM_KEY_BODY);
762 ObjectTypeInitializer.GenericMapping = CmpKeyMapping;
763 ObjectTypeInitializer.PoolType = PagedPool;
764 ObjectTypeInitializer.ValidAccessMask = KEY_ALL_ACCESS;
765 ObjectTypeInitializer.UseDefaultObject = TRUE;
766 ObjectTypeInitializer.DeleteProcedure = CmpDeleteKeyObject;
767 ObjectTypeInitializer.ParseProcedure = CmpParseKey;
768 ObjectTypeInitializer.SecurityProcedure = CmpSecurityMethod;
769 ObjectTypeInitializer.QueryNameProcedure = CmpQueryKeyName;
770 //ObjectTypeInitializer.CloseProcedure = CmpCloseKeyObject;
771 ObjectTypeInitializer.SecurityRequired = TRUE;
772
773 /* Create it */
774 return ObCreateObjectType(&Name, &ObjectTypeInitializer, NULL, &CmpKeyObjectType);
775 }
776
777 BOOLEAN
778 NTAPI
779 CmpCreateRootNode(IN PHHIVE Hive,
780 IN PCWSTR Name,
781 OUT PHCELL_INDEX Index)
782 {
783 UNICODE_STRING KeyName;
784 PCM_KEY_NODE KeyCell;
785 LARGE_INTEGER SystemTime;
786 PAGED_CODE();
787
788 /* Initialize the node name and allocate it */
789 RtlInitUnicodeString(&KeyName, Name);
790 *Index = HvAllocateCell(Hive,
791 FIELD_OFFSET(CM_KEY_NODE, Name) +
792 CmpNameSize(Hive, &KeyName),
793 Stable,
794 HCELL_NIL);
795 if (*Index == HCELL_NIL) return FALSE;
796
797 /* Set the cell index and get the data */
798 Hive->BaseBlock->RootCell = *Index;
799 KeyCell = (PCM_KEY_NODE)HvGetCell(Hive, *Index);
800 if (!KeyCell) return FALSE;
801
802 /* Setup the cell */
803 KeyCell->Signature = (USHORT)CM_KEY_NODE_SIGNATURE;
804 KeyCell->Flags = KEY_HIVE_ENTRY | KEY_NO_DELETE;
805 KeQuerySystemTime(&SystemTime);
806 KeyCell->LastWriteTime = SystemTime;
807 KeyCell->Parent = HCELL_NIL;
808 KeyCell->SubKeyCounts[Stable] = 0;
809 KeyCell->SubKeyCounts[Volatile] = 0;
810 KeyCell->SubKeyLists[Stable] = HCELL_NIL;
811 KeyCell->SubKeyLists[Volatile] = HCELL_NIL;
812 KeyCell->ValueList.Count = 0;
813 KeyCell->ValueList.List = HCELL_NIL;
814 KeyCell->Security = HCELL_NIL;
815 KeyCell->Class = HCELL_NIL;
816 KeyCell->ClassLength = 0;
817 KeyCell->MaxNameLen = 0;
818 KeyCell->MaxClassLen = 0;
819 KeyCell->MaxValueNameLen = 0;
820 KeyCell->MaxValueDataLen = 0;
821
822 /* Copy the name (this will also set the length) */
823 KeyCell->NameLength = CmpCopyName(Hive, (PWCHAR)KeyCell->Name, &KeyName);
824
825 /* Check if the name was compressed */
826 if (KeyCell->NameLength < KeyName.Length)
827 {
828 /* Set the flag */
829 KeyCell->Flags |= KEY_COMP_NAME;
830 }
831
832 /* Return success */
833 HvReleaseCell(Hive, *Index);
834 return TRUE;
835 }
836
837 BOOLEAN
838 NTAPI
839 CmpCreateRegistryRoot(VOID)
840 {
841 UNICODE_STRING KeyName;
842 OBJECT_ATTRIBUTES ObjectAttributes;
843 PCM_KEY_BODY RootKey;
844 HCELL_INDEX RootIndex;
845 NTSTATUS Status;
846 PCM_KEY_NODE KeyCell;
847 PSECURITY_DESCRIPTOR SecurityDescriptor;
848 PCM_KEY_CONTROL_BLOCK Kcb;
849 PAGED_CODE();
850
851 /* Setup the root node */
852 if (!CmpCreateRootNode(&CmiVolatileHive->Hive, L"REGISTRY", &RootIndex))
853 {
854 /* We failed */
855 return FALSE;
856 }
857
858 /* Create '\Registry' key. */
859 RtlInitUnicodeString(&KeyName, L"\\Registry");
860 SecurityDescriptor = CmpHiveRootSecurityDescriptor();
861 InitializeObjectAttributes(&ObjectAttributes,
862 &KeyName,
863 OBJ_CASE_INSENSITIVE,
864 NULL,
865 NULL);
866 Status = ObCreateObject(KernelMode,
867 CmpKeyObjectType,
868 &ObjectAttributes,
869 KernelMode,
870 NULL,
871 sizeof(CM_KEY_BODY),
872 0,
873 0,
874 (PVOID*)&RootKey);
875 ExFreePool(SecurityDescriptor);
876 if (!NT_SUCCESS(Status)) return FALSE;
877
878 /* Sanity check, and get the key cell */
879 ASSERT((&CmiVolatileHive->Hive)->ReleaseCellRoutine == NULL);
880 KeyCell = (PCM_KEY_NODE)HvGetCell(&CmiVolatileHive->Hive, RootIndex);
881 if (!KeyCell) return FALSE;
882
883 /* Create the KCB */
884 RtlInitUnicodeString(&KeyName, L"Registry");
885 Kcb = CmpCreateKeyControlBlock(&CmiVolatileHive->Hive,
886 RootIndex,
887 KeyCell,
888 NULL,
889 0,
890 &KeyName);
891 if (!Kcb) return FALSE;
892
893 /* Initialize the object */
894 RootKey->KeyControlBlock = Kcb;
895 RootKey->Type = TAG('k', 'v', '0', '2');
896 RootKey->NotifyBlock = NULL;
897 RootKey->ProcessID = PsGetCurrentProcessId();
898
899 /* Insert the key into the namespace */
900 Status = ObInsertObject(RootKey,
901 NULL,
902 KEY_ALL_ACCESS,
903 0,
904 NULL,
905 &CmpRegistryRootHandle);
906 if (!NT_SUCCESS(Status)) return FALSE;
907
908 /* Reference the key again so that we never lose it */
909 Status = ObReferenceObjectByHandle(CmpRegistryRootHandle,
910 KEY_READ,
911 NULL,
912 KernelMode,
913 (PVOID*)&RootKey,
914 NULL);
915 if (!NT_SUCCESS(Status)) return FALSE;
916
917 /* Completely sucessful */
918 return TRUE;
919 }
920
921 NTSTATUS
922 NTAPI
923 CmpGetRegistryPath(IN PWCHAR ConfigPath)
924 {
925 OBJECT_ATTRIBUTES ObjectAttributes;
926 NTSTATUS Status;
927 HANDLE KeyHandle;
928 PKEY_VALUE_PARTIAL_INFORMATION ValueInfo;
929 UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\HARDWARE");
930 UNICODE_STRING ValueName = RTL_CONSTANT_STRING(L"InstallPath");
931 ULONG BufferSize,ResultSize;
932
933 /* Check if we are booted in setup */
934 if (ExpInTextModeSetup)
935 {
936 /* Setup the object attributes */
937 InitializeObjectAttributes(&ObjectAttributes,
938 &KeyName,
939 OBJ_CASE_INSENSITIVE,
940 NULL,
941 NULL);
942 /* Open the key */
943 Status = ZwOpenKey(&KeyHandle,
944 KEY_ALL_ACCESS,
945 &ObjectAttributes);
946 if (!NT_SUCCESS(Status)) return Status;
947
948 /* Allocate the buffer */
949 BufferSize = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 4096;
950 ValueInfo = ExAllocatePoolWithTag(PagedPool, BufferSize, TAG_CM);
951 if (!ValueInfo)
952 {
953 /* Fail */
954 ZwClose(KeyHandle);
955 return STATUS_INSUFFICIENT_RESOURCES;
956 }
957
958 /* Query the value */
959 Status = ZwQueryValueKey(KeyHandle,
960 &ValueName,
961 KeyValuePartialInformation,
962 ValueInfo,
963 BufferSize,
964 &ResultSize);
965 ZwClose(KeyHandle);
966 if (!NT_SUCCESS(Status))
967 {
968 /* Fail */
969 ExFreePool(ValueInfo);
970 return Status;
971 }
972
973 /* Copy the config path and null-terminate it */
974 RtlCopyMemory(ConfigPath,
975 ValueInfo->Data,
976 ValueInfo->DataLength);
977 ConfigPath[ValueInfo->DataLength / sizeof(WCHAR)] = UNICODE_NULL;
978 ExFreePool(ValueInfo);
979 }
980 else
981 {
982 /* Just use default path */
983 wcscpy(ConfigPath, L"\\SystemRoot");
984 }
985
986 /* Add registry path */
987 wcscat(ConfigPath, L"\\System32\\Config\\");
988
989 /* Done */
990 return STATUS_SUCCESS;
991 }
992
993 VOID
994 NTAPI
995 CmpLoadHiveThread(IN PVOID StartContext)
996 {
997 WCHAR FileBuffer[MAX_PATH], RegBuffer[MAX_PATH], ConfigPath[MAX_PATH];
998 UNICODE_STRING TempName, FileName, RegName;
999 ULONG FileStart, RegStart, i, ErrorResponse, WorkerCount, Length;
1000 ULONG PrimaryDisposition, SecondaryDisposition, ClusterSize;
1001 PCMHIVE CmHive;
1002 HANDLE PrimaryHandle, LogHandle;
1003 NTSTATUS Status = STATUS_SUCCESS;
1004 PVOID ErrorParameters;
1005 PAGED_CODE();
1006
1007 /* Get the hive index, make sure it makes sense */
1008 i = (ULONG)StartContext;
1009 ASSERT(CmpMachineHiveList[i].Name != NULL);
1010 DPRINT1("[HiveLoad] Parallel Thread: %d\n", i);
1011
1012 /* We were started */
1013 CmpMachineHiveList[i].ThreadStarted = TRUE;
1014
1015 /* Build the file name and registry name strings */
1016 RtlInitEmptyUnicodeString(&FileName, FileBuffer, MAX_PATH);
1017 RtlInitEmptyUnicodeString(&RegName, RegBuffer, MAX_PATH);
1018
1019 /* Now build the system root path */
1020 CmpGetRegistryPath(ConfigPath);
1021 RtlInitUnicodeString(&TempName, ConfigPath);
1022 RtlAppendStringToString((PSTRING)&FileName, (PSTRING)&TempName);
1023 FileStart = FileName.Length;
1024
1025 /* And build the registry root path */
1026 RtlInitUnicodeString(&TempName, L"\\REGISTRY\\");
1027 RtlAppendStringToString((PSTRING)&RegName, (PSTRING)&TempName);
1028 RegStart = RegName.Length;
1029
1030 /* Build the base name */
1031 RegName.Length = RegStart;
1032 RtlInitUnicodeString(&TempName, CmpMachineHiveList[i].BaseName);
1033 RtlAppendStringToString((PSTRING)&RegName, (PSTRING)&TempName);
1034
1035 /* Check if this is a child of the root */
1036 if (RegName.Buffer[RegName.Length / sizeof(WCHAR) - 1] == '\\')
1037 {
1038 /* Then setup the whole name */
1039 RtlInitUnicodeString(&TempName, CmpMachineHiveList[i].Name);
1040 RtlAppendStringToString((PSTRING)&RegName, (PSTRING)&TempName);
1041 }
1042
1043 /* Now Add tge rest if the file name */
1044 RtlInitUnicodeString(&TempName, CmpMachineHiveList[i].Name);
1045 FileName.Length = FileStart;
1046 RtlAppendStringToString((PSTRING)&FileName, (PSTRING)&TempName);
1047 if (!CmpMachineHiveList[i].CmHive)
1048 {
1049 /* We need to allocate a new hive structure */
1050 CmpMachineHiveList[i].Allocate = TRUE;
1051
1052 /* Load the hive file */
1053 DPRINT1("[HiveLoad]: Load from file %wZ\n", &FileName);
1054 Status = CmpInitHiveFromFile(&FileName,
1055 CmpMachineHiveList[i].HHiveFlags,
1056 &CmHive,
1057 &CmpMachineHiveList[i].Allocate,
1058 0);
1059 if (!(NT_SUCCESS(Status)) || !(CmHive->FileHandles[HFILE_TYPE_LOG]))
1060 {
1061 /* We failed or couldn't get a log file, raise a hard error */
1062 ErrorParameters = &FileName;
1063 NtRaiseHardError(STATUS_CANNOT_LOAD_REGISTRY_FILE,
1064 1,
1065 1,
1066 (PULONG_PTR)&ErrorParameters,
1067 OptionOk,
1068 &ErrorResponse);
1069 }
1070
1071 /* Set the hive flags and newly allocated hive pointer */
1072 CmHive->Flags = CmpMachineHiveList[i].CmHiveFlags;
1073 CmpMachineHiveList[i].CmHive2 = CmHive;
1074 }
1075 else
1076 {
1077 CmHive = CmpMachineHiveList[i].CmHive;
1078 /* We already have a hive, is it volatile? */
1079 if (!(CmHive->Hive.HiveFlags & HIVE_VOLATILE))
1080 {
1081 DPRINT1("[HiveLoad]: Open from file %wZ\n", &FileName);
1082
1083 /* It's now, open the hive file and log */
1084 Status = CmpOpenHiveFiles(&FileName,
1085 L".LOG",
1086 &PrimaryHandle,
1087 &LogHandle,
1088 &PrimaryDisposition,
1089 &SecondaryDisposition,
1090 TRUE,
1091 TRUE,
1092 FALSE,
1093 &ClusterSize);
1094 if (!(NT_SUCCESS(Status)) || !(LogHandle))
1095 {
1096 /* Couldn't open the hive or its log file, raise a hard error */
1097 ErrorParameters = &FileName;
1098 NtRaiseHardError(STATUS_CANNOT_LOAD_REGISTRY_FILE,
1099 1,
1100 1,
1101 (PULONG_PTR)&ErrorParameters,
1102 OptionOk,
1103 &ErrorResponse);
1104
1105 /* And bugcheck for posterity's sake */
1106 KeBugCheckEx(BAD_SYSTEM_CONFIG_INFO, 9, 0, i, Status);
1107 }
1108
1109 /* Save the file handles. This should remove our sync hacks */
1110 CmHive->FileHandles[HFILE_TYPE_LOG] = LogHandle;
1111 CmHive->FileHandles[HFILE_TYPE_PRIMARY] = PrimaryHandle;
1112
1113 /* Allow lazy flushing since the handles are there -- remove sync hacks */
1114 //ASSERT(CmHive->Hive.HiveFlags & HIVE_NOLAZYFLUSH);
1115 CmHive->Hive.HiveFlags &= ~HIVE_NOLAZYFLUSH;
1116
1117 /* Get the real size of the hive */
1118 Length = CmHive->Hive.Storage[Stable].Length + HBLOCK_SIZE;
1119
1120 /* Check if the cluster size doesn't match */
1121 if (CmHive->Hive.Cluster != ClusterSize) ASSERT(FALSE);
1122
1123 /* Set the file size */
1124 //if (!CmpFileSetSize((PHHIVE)CmHive, HFILE_TYPE_PRIMARY, Length, Length))
1125 {
1126 /* This shouldn't fail */
1127 //ASSERT(FALSE);
1128 }
1129
1130 /* Another thing we don't support is NTLDR-recovery */
1131 if (CmHive->Hive.BaseBlock->BootRecover) ASSERT(FALSE);
1132
1133 /* Finally, set our allocated hive to the same hive we've had */
1134 CmpMachineHiveList[i].CmHive2 = CmHive;
1135 ASSERT(CmpMachineHiveList[i].CmHive == CmpMachineHiveList[i].CmHive2);
1136 }
1137 }
1138
1139 /* We're done */
1140 CmpMachineHiveList[i].ThreadFinished = TRUE;
1141
1142 /* Check if we're the last worker */
1143 WorkerCount = InterlockedIncrement(&CmpLoadWorkerIncrement);
1144 if (WorkerCount == CM_NUMBER_OF_MACHINE_HIVES)
1145 {
1146 /* Signal the event */
1147 KeSetEvent(&CmpLoadWorkerEvent, 0, FALSE);
1148 }
1149
1150 /* Kill the thread */
1151 PsTerminateSystemThread(Status);
1152 }
1153
1154 VOID
1155 NTAPI
1156 CmpInitializeHiveList(IN USHORT Flag)
1157 {
1158 WCHAR FileBuffer[MAX_PATH], RegBuffer[MAX_PATH], ConfigPath[MAX_PATH];
1159 UNICODE_STRING TempName, FileName, RegName;
1160 HANDLE Thread;
1161 NTSTATUS Status;
1162 ULONG FileStart, RegStart, i;
1163 PSECURITY_DESCRIPTOR SecurityDescriptor;
1164 PAGED_CODE();
1165
1166 /* Allow writing for now */
1167 CmpNoWrite = FALSE;
1168
1169 /* Build the file name and registry name strings */
1170 RtlInitEmptyUnicodeString(&FileName, FileBuffer, MAX_PATH);
1171 RtlInitEmptyUnicodeString(&RegName, RegBuffer, MAX_PATH);
1172
1173 /* Now build the system root path */
1174 CmpGetRegistryPath(ConfigPath);
1175 RtlInitUnicodeString(&TempName, ConfigPath);
1176 RtlAppendStringToString((PSTRING)&FileName, (PSTRING)&TempName);
1177 FileStart = FileName.Length;
1178
1179 /* And build the registry root path */
1180 RtlInitUnicodeString(&TempName, L"\\REGISTRY\\");
1181 RtlAppendStringToString((PSTRING)&RegName, (PSTRING)&TempName);
1182 RegStart = RegName.Length;
1183
1184 /* Setup the event to synchronize workers */
1185 KeInitializeEvent(&CmpLoadWorkerEvent, SynchronizationEvent, FALSE);
1186
1187 /* Enter special boot condition */
1188 CmpSpecialBootCondition = TRUE;
1189
1190 /* Create the SD for the root hives */
1191 SecurityDescriptor = CmpHiveRootSecurityDescriptor();
1192
1193 /* Loop every hive we care about */
1194 for (i = 0; i < CM_NUMBER_OF_MACHINE_HIVES; i++)
1195 {
1196 /* Make sure the list is setup */
1197 ASSERT(CmpMachineHiveList[i].Name != NULL);
1198
1199 /* Create a thread to handle this hive */
1200 Status = PsCreateSystemThread(&Thread,
1201 THREAD_ALL_ACCESS,
1202 NULL,
1203 0,
1204 NULL,
1205 CmpLoadHiveThread,
1206 (PVOID)i);
1207 if (NT_SUCCESS(Status))
1208 {
1209 /* We don't care about the handle -- the thread self-terminates */
1210 ZwClose(Thread);
1211 }
1212 else
1213 {
1214 /* Can't imagine this happening */
1215 KeBugCheckEx(BAD_SYSTEM_CONFIG_INFO, 9, 3, i, Status);
1216 }
1217 }
1218
1219 /* Make sure we've reached the end of the list */
1220 ASSERT(CmpMachineHiveList[i].Name == NULL);
1221
1222 /* Wait for hive loading to finish */
1223 KeWaitForSingleObject(&CmpLoadWorkerEvent,
1224 Executive,
1225 KernelMode,
1226 FALSE,
1227 NULL);
1228
1229 /* Exit the special boot condition and make sure all workers completed */
1230 CmpSpecialBootCondition = FALSE;
1231 ASSERT(CmpLoadWorkerIncrement == CM_NUMBER_OF_MACHINE_HIVES);
1232
1233 /* Loop hives again */
1234 for (i = 0; i < CM_NUMBER_OF_MACHINE_HIVES; i++)
1235 {
1236 /* Make sure the thread ran and finished */
1237 ASSERT(CmpMachineHiveList[i].ThreadFinished == TRUE);
1238 ASSERT(CmpMachineHiveList[i].ThreadStarted == TRUE);
1239
1240 /* Check if this was a new hive */
1241 if (!CmpMachineHiveList[i].CmHive)
1242 {
1243 /* Make sure we allocated something */
1244 ASSERT(CmpMachineHiveList[i].CmHive2 != NULL);
1245
1246 /* Build the base name */
1247 RegName.Length = RegStart;
1248 RtlInitUnicodeString(&TempName, CmpMachineHiveList[i].BaseName);
1249 RtlAppendStringToString((PSTRING)&RegName, (PSTRING)&TempName);
1250
1251 /* Check if this is a child of the root */
1252 if (RegName.Buffer[RegName.Length / sizeof(WCHAR) - 1] == '\\')
1253 {
1254 /* Then setup the whole name */
1255 RtlInitUnicodeString(&TempName, CmpMachineHiveList[i].Name);
1256 RtlAppendStringToString((PSTRING)&RegName, (PSTRING)&TempName);
1257 }
1258
1259 /* Now link the hive to its master */
1260 DPRINT1("[HiveLoad]: Link %wZ\n", &RegName);
1261 Status = CmpLinkHiveToMaster(&RegName,
1262 NULL,
1263 CmpMachineHiveList[i].CmHive2,
1264 CmpMachineHiveList[i].Allocate,
1265 SecurityDescriptor);
1266 if (Status != STATUS_SUCCESS)
1267 {
1268 /* Linking needs to work */
1269 KeBugCheckEx(CONFIG_LIST_FAILED, 11, Status, i, (ULONG_PTR)&RegName);
1270 }
1271
1272 /* Check if we had to allocate a new hive */
1273 if (CmpMachineHiveList[i].Allocate)
1274 {
1275 /* Sync the new hive */
1276 //HvSyncHive((PHHIVE)(CmpMachineHiveList[i].CmHive2));
1277 }
1278 }
1279
1280 /* Check if we created a new hive */
1281 if (CmpMachineHiveList[i].CmHive2)
1282 {
1283 /* TODO: Add to HiveList key */
1284 }
1285 }
1286
1287 /* Get rid of the SD */
1288 ExFreePool(SecurityDescriptor);
1289
1290 /* FIXME: Link SECURITY to SAM */
1291
1292 /* FIXME: Link S-1-5-18 to .Default */
1293 }
1294
1295 BOOLEAN
1296 NTAPI
1297 CmInitSystem1(VOID)
1298 {
1299 OBJECT_ATTRIBUTES ObjectAttributes;
1300 UNICODE_STRING KeyName;
1301 HANDLE KeyHandle;
1302 NTSTATUS Status;
1303 PCMHIVE HardwareHive;
1304 PVOID BaseAddress;
1305 ULONG Length;
1306 PSECURITY_DESCRIPTOR SecurityDescriptor;
1307 PAGED_CODE();
1308
1309 /* Check if this is PE-boot */
1310 if (InitIsWinPEMode)
1311 {
1312 /* Set registry to PE mode */
1313 CmpMiniNTBoot = TRUE;
1314 CmpShareSystemHives = TRUE;
1315 }
1316
1317 /* Initialize the hive list and lock */
1318 InitializeListHead(&CmpHiveListHead);
1319 ExInitializePushLock((PVOID)&CmpHiveListHeadLock);
1320 ExInitializePushLock((PVOID)&CmpLoadHiveLock);
1321
1322 /* Initialize registry lock */
1323 ExInitializeResourceLite(&CmpRegistryLock);
1324
1325 /* Initialize the cache */
1326 CmpInitializeCache();
1327
1328 /* Initialize allocation and delayed dereferencing */
1329 CmpInitCmPrivateAlloc();
1330 CmpInitCmPrivateDelayAlloc();
1331 CmpInitDelayDerefKCBEngine();
1332
1333 /* Initialize callbacks */
1334 CmpInitCallback();
1335
1336 /* Initialize self healing */
1337 KeInitializeGuardedMutex(&CmpSelfHealQueueLock);
1338 InitializeListHead(&CmpSelfHealQueueListHead);
1339
1340 /* Save the current process and lock the registry */
1341 CmpSystemProcess = PsGetCurrentProcess();
1342
1343 /* Create the key object types */
1344 Status = CmpCreateObjectTypes();
1345 if (!NT_SUCCESS(Status))
1346 {
1347 /* Bugcheck */
1348 KEBUGCHECKEX(CONFIG_INITIALIZATION_FAILED, 1, 1, Status, 0);
1349 }
1350
1351 /* Build the master hive */
1352 Status = CmpInitializeHive((PCMHIVE*)&CmiVolatileHive,
1353 HINIT_CREATE,
1354 HIVE_VOLATILE,
1355 HFILE_TYPE_PRIMARY,
1356 NULL,
1357 NULL,
1358 NULL,
1359 NULL,
1360 NULL,
1361 0);
1362 if (!NT_SUCCESS(Status))
1363 {
1364 /* Bugcheck */
1365 KEBUGCHECKEX(CONFIG_INITIALIZATION_FAILED, 1, 2, Status, 0);
1366 }
1367
1368 /* Create the \REGISTRY key node */
1369 if (!CmpCreateRegistryRoot())
1370 {
1371 /* Bugcheck */
1372 KEBUGCHECKEX(CONFIG_INITIALIZATION_FAILED, 1, 3, 0, 0);
1373 }
1374
1375 /* Create the default security descriptor */
1376 SecurityDescriptor = CmpHiveRootSecurityDescriptor();
1377
1378 /* Create '\Registry\Machine' key. */
1379 RtlInitUnicodeString(&KeyName, L"\\REGISTRY\\MACHINE");
1380 InitializeObjectAttributes(&ObjectAttributes,
1381 &KeyName,
1382 OBJ_CASE_INSENSITIVE,
1383 NULL,
1384 SecurityDescriptor);
1385 Status = NtCreateKey(&KeyHandle,
1386 KEY_READ | KEY_WRITE,
1387 &ObjectAttributes,
1388 0,
1389 NULL,
1390 0,
1391 NULL);
1392 if (!NT_SUCCESS(Status))
1393 {
1394 /* Bugcheck */
1395 KEBUGCHECKEX(CONFIG_INITIALIZATION_FAILED, 1, 5, Status, 0);
1396 }
1397
1398 /* Close the handle */
1399 NtClose(KeyHandle);
1400
1401 /* Create '\Registry\User' key. */
1402 RtlInitUnicodeString(&KeyName, L"\\REGISTRY\\USER");
1403 InitializeObjectAttributes(&ObjectAttributes,
1404 &KeyName,
1405 OBJ_CASE_INSENSITIVE,
1406 NULL,
1407 SecurityDescriptor);
1408 Status = NtCreateKey(&KeyHandle,
1409 KEY_READ | KEY_WRITE,
1410 &ObjectAttributes,
1411 0,
1412 NULL,
1413 0,
1414 NULL);
1415 if (!NT_SUCCESS(Status))
1416 {
1417 /* Bugcheck */
1418 KEBUGCHECKEX(CONFIG_INITIALIZATION_FAILED, 1, 6, Status, 0);
1419 }
1420
1421 /* Close the handle */
1422 NtClose(KeyHandle);
1423
1424 /* Initialize the system hive */
1425 if (!CmpInitializeSystemHive(KeLoaderBlock))
1426 {
1427 /* Bugcheck */
1428 KEBUGCHECKEX(CONFIG_INITIALIZATION_FAILED, 1, 7, 0, 0);
1429 }
1430
1431 /* Create the 'CurrentControlSet' link. */
1432 Status = CmpCreateControlSet(KeLoaderBlock);
1433 if (!NT_SUCCESS(Status))
1434 {
1435 /* Bugcheck */
1436 KEBUGCHECKEX(CONFIG_INITIALIZATION_FAILED, 1, 8, Status, 0);
1437 }
1438
1439 /* Import the hardware hive (FIXME: We should create it from scratch) */
1440 BaseAddress = CmpRosGetHardwareHive(&Length);
1441 ((PHBASE_BLOCK)BaseAddress)->Length = Length;
1442 Status = CmpInitializeHive((PCMHIVE*)&HardwareHive,
1443 HINIT_MEMORY, //HINIT_CREATE,
1444 HIVE_VOLATILE | HIVE_NOLAZYFLUSH,
1445 HFILE_TYPE_PRIMARY,
1446 BaseAddress, // NULL,
1447 NULL,
1448 NULL,
1449 NULL,
1450 NULL,
1451 0);
1452 CmPrepareHive(&HardwareHive->Hive);
1453 if (!NT_SUCCESS(Status))
1454 {
1455 /* Bugcheck */
1456 KEBUGCHECKEX(CONFIG_INITIALIZATION_FAILED, 1, 11, Status, 0);
1457 }
1458
1459 /* Add the hive to the hive list */
1460 CmpMachineHiveList[0].CmHive = (PCMHIVE)HardwareHive;
1461
1462 /* Attach it to the machine key */
1463 RtlInitUnicodeString(&KeyName, L"\\Registry\\Machine\\HARDWARE");
1464 Status = CmpLinkHiveToMaster(&KeyName,
1465 NULL,
1466 (PCMHIVE)HardwareHive,
1467 FALSE, // TRUE
1468 SecurityDescriptor);
1469 if (!NT_SUCCESS(Status))
1470 {
1471 /* Bugcheck */
1472 KEBUGCHECKEX(CONFIG_INITIALIZATION_FAILED, 1, 12, Status, 0);
1473 }
1474
1475 /* FIXME: Add to HiveList key */
1476
1477 /* Free the security descriptor */
1478 ExFreePool(SecurityDescriptor);
1479
1480 /* Fill out the Hardware key with the ARC Data from the Loader */
1481 Status = CmpInitializeHardwareConfiguration(KeLoaderBlock);
1482 if (!NT_SUCCESS(Status))
1483 {
1484 /* Bugcheck */
1485 KEBUGCHECKEX(CONFIG_INITIALIZATION_FAILED, 1, 13, Status, 0);
1486 }
1487
1488 /* Initialize machine-dependent information into the registry */
1489 Status = CmpInitializeMachineDependentConfiguration(KeLoaderBlock);
1490 if (!NT_SUCCESS(Status))
1491 {
1492 /* Bugcheck */
1493 KEBUGCHECKEX(CONFIG_INITIALIZATION_FAILED, 1, 14, Status, 0);
1494 }
1495
1496 /* Initialize volatile registry settings */
1497 Status = CmpSetSystemValues(KeLoaderBlock);
1498 if (!NT_SUCCESS(Status))
1499 {
1500 /* Bugcheck */
1501 KEBUGCHECKEX(CONFIG_INITIALIZATION_FAILED, 1, 15, Status, 0);
1502 }
1503
1504 /* Free the load options */
1505 ExFreePool(CmpLoadOptions.Buffer);
1506
1507 /* If we got here, all went well */
1508 return TRUE;
1509 }
1510
1511 VOID
1512 NTAPI
1513 CmpLockRegistryExclusive(VOID)
1514 {
1515 /* Enter a critical region and lock the registry */
1516 KeEnterCriticalRegion();
1517 ExAcquireResourceExclusiveLite(&CmpRegistryLock, TRUE);
1518
1519 /* Sanity check */
1520 ASSERT(CmpFlushStarveWriters == 0);
1521 RtlGetCallersAddress(&CmpRegistryLockCaller, &CmpRegistryLockCallerCaller);
1522 }
1523
1524 VOID
1525 NTAPI
1526 CmpLockRegistry(VOID)
1527 {
1528 /* Enter a critical region */
1529 KeEnterCriticalRegion();
1530
1531 /* Check if we have to starve writers */
1532 if (CmpFlushStarveWriters)
1533 {
1534 /* Starve exlusive waiters */
1535 ExAcquireSharedStarveExclusive(&CmpRegistryLock, TRUE);
1536 }
1537 else
1538 {
1539 /* Just grab the lock */
1540 ExAcquireResourceSharedLite(&CmpRegistryLock, TRUE);
1541 }
1542 }
1543
1544 BOOLEAN
1545 NTAPI
1546 CmpTestRegistryLock(VOID)
1547 {
1548 /* Test the lock */
1549 return !ExIsResourceAcquiredSharedLite(&CmpRegistryLock) ? FALSE : TRUE;
1550 }
1551
1552 BOOLEAN
1553 NTAPI
1554 CmpTestRegistryLockExclusive(VOID)
1555 {
1556 /* Test the lock */
1557 return !ExIsResourceAcquiredExclusiveLite(&CmpRegistryLock) ? FALSE : TRUE;
1558 }
1559
1560 VOID
1561 NTAPI
1562 CmpUnlockRegistry(VOID)
1563 {
1564 /* Sanity check */
1565 CMP_ASSERT_REGISTRY_LOCK();
1566
1567 /* Check if we should flush the registry */
1568 if (CmpFlushOnLockRelease)
1569 {
1570 /* The registry should be exclusively locked for this */
1571 CMP_ASSERT_EXCLUSIVE_REGISTRY_LOCK();
1572
1573 /* Flush the registry */
1574 CmpDoFlushAll(TRUE);
1575 CmpFlushOnLockRelease = FALSE;
1576 }
1577
1578 /* Release the lock and leave the critical region */
1579 ExReleaseResourceLite(&CmpRegistryLock);
1580 KeLeaveCriticalRegion();
1581 }
1582
1583 VOID
1584 NTAPI
1585 CmpAcquireTwoKcbLocksExclusiveByKey(IN ULONG ConvKey1,
1586 IN ULONG ConvKey2)
1587 {
1588 ULONG Index1, Index2;
1589
1590 /* Sanity check */
1591 CMP_ASSERT_REGISTRY_LOCK();
1592
1593 /* Get hash indexes */
1594 Index1 = GET_HASH_INDEX(ConvKey1);
1595 Index2 = GET_HASH_INDEX(ConvKey2);
1596
1597 /* See which one is highest */
1598 if (Index1 < Index2)
1599 {
1600 /* Grab them in the proper order */
1601 CmpAcquireKcbLockExclusiveByKey(ConvKey1);
1602 CmpAcquireKcbLockExclusiveByKey(ConvKey2);
1603 }
1604 else
1605 {
1606 /* Grab the second one first, then the first */
1607 CmpAcquireKcbLockExclusiveByKey(ConvKey2);
1608 if (Index1 != Index2) CmpAcquireKcbLockExclusiveByKey(ConvKey1);
1609 }
1610 }
1611
1612 VOID
1613 NTAPI
1614 CmpReleaseTwoKcbLockByKey(IN ULONG ConvKey1,
1615 IN ULONG ConvKey2)
1616 {
1617 ULONG Index1, Index2;
1618
1619 /* Sanity check */
1620 CMP_ASSERT_REGISTRY_LOCK();
1621
1622 /* Get hash indexes */
1623 Index1 = GET_HASH_INDEX(ConvKey1);
1624 Index2 = GET_HASH_INDEX(ConvKey2);
1625 ASSERT((GET_HASH_ENTRY(CmpCacheTable, ConvKey2).Owner == KeGetCurrentThread()) ||
1626 (CmpTestRegistryLockExclusive()));
1627
1628 /* See which one is highest */
1629 if (Index1 < Index2)
1630 {
1631 /* Grab them in the proper order */
1632 ASSERT((GET_HASH_ENTRY(CmpCacheTable, ConvKey1).Owner == KeGetCurrentThread()) ||
1633 (CmpTestRegistryLockExclusive()));
1634 CmpReleaseKcbLockByKey(ConvKey2);
1635 CmpReleaseKcbLockByKey(ConvKey1);
1636 }
1637 else
1638 {
1639 /* Release the first one first, then the second */
1640 if (Index1 != Index2)
1641 {
1642 ASSERT((GET_HASH_ENTRY(CmpCacheTable, ConvKey1).Owner == KeGetCurrentThread()) ||
1643 (CmpTestRegistryLockExclusive()));
1644 CmpReleaseKcbLockByKey(ConvKey1);
1645 }
1646 CmpReleaseKcbLockByKey(ConvKey2);
1647 }
1648 }
1649
1650 VOID
1651 NTAPI
1652 CmShutdownSystem(VOID)
1653 {
1654 /* Kill the workers and fush all hives */
1655 CmpShutdownWorkers();
1656 CmpDoFlushAll(TRUE);
1657 }