Fix small typo
[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 PKEY_OBJECT ParentKey;
496 PKEY_OBJECT 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 /* Build the key name */
609 RtlDuplicateUnicodeString(RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE,
610 &RemainingPath,
611 &NewKey->Name);
612
613 /* Reference the new key */
614 ObReferenceObject(NewKey);
615
616 /* Link this key to the parent */
617 CmiAddKeyToList(ParentKey->KeyControlBlock, NewKey);
618 return STATUS_SUCCESS;
619 }
620
621 BOOLEAN
622 NTAPI
623 CmpInitializeSystemHive(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
624 {
625 PVOID HiveBase;
626 ANSI_STRING LoadString;
627 PVOID Buffer;
628 ULONG Length;
629 NTSTATUS Status;
630 BOOLEAN Allocate;
631 UNICODE_STRING KeyName;
632 PCMHIVE SystemHive = NULL;
633 UNICODE_STRING HiveName = RTL_CONSTANT_STRING(L"SYSTEM");
634 PSECURITY_DESCRIPTOR SecurityDescriptor;
635 PAGED_CODE();
636
637 /* Setup the ansi string */
638 RtlInitAnsiString(&LoadString, LoaderBlock->LoadOptions);
639
640 /* Allocate the unicode buffer */
641 Length = LoadString.Length * sizeof(WCHAR) + sizeof(UNICODE_NULL);
642 Buffer = ExAllocatePoolWithTag(PagedPool, Length, TAG_CM);
643 if (!Buffer)
644 {
645 /* Fail */
646 KEBUGCHECKEX(BAD_SYSTEM_CONFIG_INFO, 3, 1, (ULONG_PTR)LoaderBlock, 0);
647 }
648
649 /* Setup the unicode string */
650 RtlInitEmptyUnicodeString(&CmpLoadOptions, Buffer, (USHORT)Length);
651
652 /* Add the load options and null-terminate */
653 RtlAnsiStringToUnicodeString(&CmpLoadOptions, &LoadString, FALSE);
654 CmpLoadOptions.Buffer[LoadString.Length] = UNICODE_NULL;
655 CmpLoadOptions.Length += sizeof(WCHAR);
656
657 /* Get the System Hive base address */
658 HiveBase = LoaderBlock->RegistryBase;
659 if (HiveBase)
660 {
661 /* Import it */
662 ((PHBASE_BLOCK)HiveBase)->Length = LoaderBlock->RegistryLength;
663 Status = CmpInitializeHive((PCMHIVE*)&SystemHive,
664 HINIT_MEMORY,
665 HIVE_NOLAZYFLUSH,
666 HFILE_TYPE_LOG,
667 HiveBase,
668 NULL,
669 NULL,
670 NULL,
671 &HiveName,
672 2);
673 if (!NT_SUCCESS(Status)) return FALSE;
674 CmPrepareHive(&SystemHive->Hive);
675
676 /* Set the hive filename */
677 RtlCreateUnicodeString(&SystemHive->FileFullPath,
678 L"\\SystemRoot\\System32\\Config\\SYSTEM");
679
680 /* We imported, no need to create a new hive */
681 Allocate = FALSE;
682
683 /* Manually set the hive as volatile, if in Live CD mode */
684 if (CmpShareSystemHives) SystemHive->Hive.HiveFlags = HIVE_VOLATILE;
685 }
686 else
687 {
688 /* Create it */
689 Status = CmpInitializeHive(&SystemHive,
690 HINIT_CREATE,
691 HIVE_NOLAZYFLUSH,
692 HFILE_TYPE_LOG,
693 NULL,
694 NULL,
695 NULL,
696 NULL,
697 &HiveName,
698 0);
699 if (!NT_SUCCESS(Status)) return FALSE;
700
701 /* Set the hive filename */
702 RtlCreateUnicodeString(&SystemHive->FileFullPath,
703 L"\\SystemRoot\\System32\\Config\\SYSTEM");
704
705 /* Tell CmpLinkHiveToMaster to allocate a hive */
706 Allocate = TRUE;
707 }
708
709 /* Save the boot type */
710 if (SystemHive) CmpBootType = SystemHive->Hive.BaseBlock->BootType;
711
712 /* Are we in self-healing mode? */
713 if (!CmSelfHeal)
714 {
715 /* Disable self-healing internally and check if boot type wanted it */
716 CmpSelfHeal = FALSE;
717 if (CmpBootType & 4)
718 {
719 /* We're disabled, so bugcheck */
720 KEBUGCHECKEX(BAD_SYSTEM_CONFIG_INFO,
721 3,
722 3,
723 (ULONG_PTR)SystemHive,
724 0);
725 }
726 }
727
728 /* Create the default security descriptor */
729 SecurityDescriptor = CmpHiveRootSecurityDescriptor();
730
731 /* Attach it to the system key */
732 RtlInitUnicodeString(&KeyName, L"\\Registry\\Machine\\SYSTEM");
733 Status = CmpLinkHiveToMaster(&KeyName,
734 NULL,
735 (PCMHIVE)SystemHive,
736 Allocate,
737 SecurityDescriptor);
738
739 /* Free the security descriptor */
740 ExFreePool(SecurityDescriptor);
741 if (!NT_SUCCESS(Status)) return FALSE;
742
743 /* Add the hive to the hive list */
744 CmpMachineHiveList[3].CmHive = (PCMHIVE)SystemHive;
745
746 /* Success! */
747 return TRUE;
748 }
749
750 NTSTATUS
751 NTAPI
752 CmpCreateObjectTypes(VOID)
753 {
754 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer;
755 UNICODE_STRING Name;
756 GENERIC_MAPPING CmpKeyMapping = {KEY_READ,
757 KEY_WRITE,
758 KEY_EXECUTE,
759 KEY_ALL_ACCESS};
760 PAGED_CODE();
761
762 /* Initialize the Key object type */
763 RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer));
764 RtlInitUnicodeString(&Name, L"Key");
765 ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer);
766 ObjectTypeInitializer.DefaultPagedPoolCharge = sizeof(CM_KEY_BODY);
767 ObjectTypeInitializer.GenericMapping = CmpKeyMapping;
768 ObjectTypeInitializer.PoolType = PagedPool;
769 ObjectTypeInitializer.ValidAccessMask = KEY_ALL_ACCESS;
770 ObjectTypeInitializer.UseDefaultObject = TRUE;
771 ObjectTypeInitializer.DeleteProcedure = CmpDeleteKeyObject;
772 ObjectTypeInitializer.ParseProcedure = CmpParseKey;
773 ObjectTypeInitializer.SecurityProcedure = CmpSecurityMethod;
774 ObjectTypeInitializer.QueryNameProcedure = CmpQueryKeyName;
775 //ObjectTypeInitializer.CloseProcedure = CmpCloseKeyObject;
776 ObjectTypeInitializer.SecurityRequired = TRUE;
777
778 /* Create it */
779 return ObCreateObjectType(&Name, &ObjectTypeInitializer, NULL, &CmpKeyObjectType);
780 }
781
782 BOOLEAN
783 NTAPI
784 CmpCreateRootNode(IN PHHIVE Hive,
785 IN PCWSTR Name,
786 OUT PHCELL_INDEX Index)
787 {
788 UNICODE_STRING KeyName;
789 PCM_KEY_NODE KeyCell;
790 LARGE_INTEGER SystemTime;
791 PAGED_CODE();
792
793 /* Initialize the node name and allocate it */
794 RtlInitUnicodeString(&KeyName, Name);
795 *Index = HvAllocateCell(Hive,
796 FIELD_OFFSET(CM_KEY_NODE, Name) +
797 CmpNameSize(Hive, &KeyName),
798 Stable,
799 HCELL_NIL);
800 if (*Index == HCELL_NIL) return FALSE;
801
802 /* Set the cell index and get the data */
803 Hive->BaseBlock->RootCell = *Index;
804 KeyCell = (PCM_KEY_NODE)HvGetCell(Hive, *Index);
805 if (!KeyCell) return FALSE;
806
807 /* Setup the cell */
808 KeyCell->Signature = (USHORT)CM_KEY_NODE_SIGNATURE;
809 KeyCell->Flags = KEY_HIVE_ENTRY | KEY_NO_DELETE;
810 KeQuerySystemTime(&SystemTime);
811 KeyCell->LastWriteTime = SystemTime;
812 KeyCell->Parent = HCELL_NIL;
813 KeyCell->SubKeyCounts[Stable] = 0;
814 KeyCell->SubKeyCounts[Volatile] = 0;
815 KeyCell->SubKeyLists[Stable] = HCELL_NIL;
816 KeyCell->SubKeyLists[Volatile] = HCELL_NIL;
817 KeyCell->ValueList.Count = 0;
818 KeyCell->ValueList.List = HCELL_NIL;
819 KeyCell->Security = HCELL_NIL;
820 KeyCell->Class = HCELL_NIL;
821 KeyCell->ClassLength = 0;
822 KeyCell->MaxNameLen = 0;
823 KeyCell->MaxClassLen = 0;
824 KeyCell->MaxValueNameLen = 0;
825 KeyCell->MaxValueDataLen = 0;
826
827 /* Copy the name (this will also set the length) */
828 KeyCell->NameLength = CmpCopyName(Hive, (PWCHAR)KeyCell->Name, &KeyName);
829
830 /* Check if the name was compressed */
831 if (KeyCell->NameLength < KeyName.Length)
832 {
833 /* Set the flag */
834 KeyCell->Flags |= KEY_COMP_NAME;
835 }
836
837 /* Return success */
838 HvReleaseCell(Hive, *Index);
839 return TRUE;
840 }
841
842 BOOLEAN
843 NTAPI
844 CmpCreateRegistryRoot(VOID)
845 {
846 UNICODE_STRING KeyName;
847 OBJECT_ATTRIBUTES ObjectAttributes;
848 #if 0
849 PCM_KEY_BODY RootKey;
850 #else
851 PKEY_OBJECT RootKey;
852 #endif
853 HCELL_INDEX RootIndex;
854 NTSTATUS Status;
855 PCM_KEY_NODE KeyCell;
856 PSECURITY_DESCRIPTOR SecurityDescriptor;
857 PCM_KEY_CONTROL_BLOCK Kcb;
858 PAGED_CODE();
859
860 /* Setup the root node */
861 if (!CmpCreateRootNode(&CmiVolatileHive->Hive, L"REGISTRY", &RootIndex))
862 {
863 /* We failed */
864 return FALSE;
865 }
866
867 /* Create '\Registry' key. */
868 RtlInitUnicodeString(&KeyName, L"\\Registry");
869 SecurityDescriptor = CmpHiveRootSecurityDescriptor();
870 InitializeObjectAttributes(&ObjectAttributes,
871 &KeyName,
872 OBJ_CASE_INSENSITIVE,
873 NULL,
874 NULL);
875 Status = ObCreateObject(KernelMode,
876 CmpKeyObjectType,
877 &ObjectAttributes,
878 KernelMode,
879 NULL,
880 sizeof(KEY_OBJECT),
881 0,
882 0,
883 (PVOID*)&RootKey);
884 ExFreePool(SecurityDescriptor);
885 if (!NT_SUCCESS(Status)) return FALSE;
886
887 /* Sanity check, and get the key cell */
888 ASSERT((&CmiVolatileHive->Hive)->ReleaseCellRoutine == NULL);
889 KeyCell = (PCM_KEY_NODE)HvGetCell(&CmiVolatileHive->Hive, RootIndex);
890 if (!KeyCell) return FALSE;
891
892 /* Create the KCB */
893 RtlInitUnicodeString(&KeyName, L"Registry");
894 Kcb = CmpCreateKeyControlBlock(&CmiVolatileHive->Hive,
895 RootIndex,
896 KeyCell,
897 NULL,
898 0,
899 &KeyName);
900 if (!Kcb) return FALSE;
901
902 /* Initialize the object */
903 RootKey->Type = TAG('k', 'v', '0', '2');
904 RootKey->KeyControlBlock = Kcb;
905 #if 0
906 RootKey->NotifyBlock = NULL;
907 RootKey->ProcessID = PsGetCurrentProcessId();
908 #else
909 RtlpCreateUnicodeString(&RootKey->Name, L"Registry", NonPagedPool);
910 #endif
911
912 /* Insert the key into the namespace */
913 Status = ObInsertObject(RootKey,
914 NULL,
915 KEY_ALL_ACCESS,
916 0,
917 NULL,
918 &CmpRegistryRootHandle);
919 if (!NT_SUCCESS(Status)) return FALSE;
920
921 /* Reference the key again so that we never lose it */
922 Status = ObReferenceObjectByHandle(CmpRegistryRootHandle,
923 KEY_READ,
924 NULL,
925 KernelMode,
926 (PVOID*)&RootKey,
927 NULL);
928 if (!NT_SUCCESS(Status)) return FALSE;
929
930 /* Completely sucessful */
931 return TRUE;
932 }
933
934 NTSTATUS
935 NTAPI
936 CmpGetRegistryPath(IN PWCHAR ConfigPath)
937 {
938 OBJECT_ATTRIBUTES ObjectAttributes;
939 NTSTATUS Status;
940 HANDLE KeyHandle;
941 PKEY_VALUE_PARTIAL_INFORMATION ValueInfo;
942 UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\HARDWARE");
943 UNICODE_STRING ValueName = RTL_CONSTANT_STRING(L"InstallPath");
944 ULONG BufferSize,ResultSize;
945
946 /* Check if we are booted in setup */
947 if (ExpInTextModeSetup)
948 {
949 /* Setup the object attributes */
950 InitializeObjectAttributes(&ObjectAttributes,
951 &KeyName,
952 OBJ_CASE_INSENSITIVE,
953 NULL,
954 NULL);
955 /* Open the key */
956 Status = ZwOpenKey(&KeyHandle,
957 KEY_ALL_ACCESS,
958 &ObjectAttributes);
959 if (!NT_SUCCESS(Status)) return Status;
960
961 /* Allocate the buffer */
962 BufferSize = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 4096;
963 ValueInfo = ExAllocatePoolWithTag(PagedPool, BufferSize, TAG_CM);
964 if (!ValueInfo)
965 {
966 /* Fail */
967 ZwClose(KeyHandle);
968 return STATUS_INSUFFICIENT_RESOURCES;
969 }
970
971 /* Query the value */
972 Status = ZwQueryValueKey(KeyHandle,
973 &ValueName,
974 KeyValuePartialInformation,
975 ValueInfo,
976 BufferSize,
977 &ResultSize);
978 ZwClose(KeyHandle);
979 if (!NT_SUCCESS(Status))
980 {
981 /* Fail */
982 ExFreePool(ValueInfo);
983 return Status;
984 }
985
986 /* Copy the config path and null-terminate it */
987 RtlCopyMemory(ConfigPath,
988 ValueInfo->Data,
989 ValueInfo->DataLength);
990 ConfigPath[ValueInfo->DataLength / sizeof(WCHAR)] = UNICODE_NULL;
991 ExFreePool(ValueInfo);
992 }
993 else
994 {
995 /* Just use default path */
996 wcscpy(ConfigPath, L"\\SystemRoot");
997 }
998
999 /* Add registry path */
1000 wcscat(ConfigPath, L"\\System32\\Config\\");
1001
1002 /* Done */
1003 return STATUS_SUCCESS;
1004 }
1005
1006 VOID
1007 NTAPI
1008 CmpLoadHiveThread(IN PVOID StartContext)
1009 {
1010 WCHAR FileBuffer[MAX_PATH], RegBuffer[MAX_PATH], ConfigPath[MAX_PATH];
1011 UNICODE_STRING TempName, FileName, RegName;
1012 ULONG FileStart, RegStart, i, ErrorResponse, WorkerCount, Length;
1013 ULONG PrimaryDisposition, SecondaryDisposition, ClusterSize;
1014 PCMHIVE CmHive;
1015 HANDLE PrimaryHandle, LogHandle;
1016 NTSTATUS Status = STATUS_SUCCESS;
1017 PVOID ErrorParameters;
1018 PAGED_CODE();
1019
1020 /* Get the hive index, make sure it makes sense */
1021 i = (ULONG)StartContext;
1022 ASSERT(CmpMachineHiveList[i].Name != NULL);
1023 DPRINT1("[HiveLoad] Parallel Thread: %d\n", i);
1024
1025 /* We were started */
1026 CmpMachineHiveList[i].ThreadStarted = TRUE;
1027
1028 /* Build the file name and registry name strings */
1029 RtlInitEmptyUnicodeString(&FileName, FileBuffer, MAX_PATH);
1030 RtlInitEmptyUnicodeString(&RegName, RegBuffer, MAX_PATH);
1031
1032 /* Now build the system root path */
1033 CmpGetRegistryPath(ConfigPath);
1034 RtlInitUnicodeString(&TempName, ConfigPath);
1035 RtlAppendStringToString((PSTRING)&FileName, (PSTRING)&TempName);
1036 FileStart = FileName.Length;
1037
1038 /* And build the registry root path */
1039 RtlInitUnicodeString(&TempName, L"\\REGISTRY\\");
1040 RtlAppendStringToString((PSTRING)&RegName, (PSTRING)&TempName);
1041 RegStart = RegName.Length;
1042
1043 /* Build the base name */
1044 RegName.Length = RegStart;
1045 RtlInitUnicodeString(&TempName, CmpMachineHiveList[i].BaseName);
1046 RtlAppendStringToString((PSTRING)&RegName, (PSTRING)&TempName);
1047
1048 /* Check if this is a child of the root */
1049 if (RegName.Buffer[RegName.Length / sizeof(WCHAR) - 1] == '\\')
1050 {
1051 /* Then setup the whole name */
1052 RtlInitUnicodeString(&TempName, CmpMachineHiveList[i].Name);
1053 RtlAppendStringToString((PSTRING)&RegName, (PSTRING)&TempName);
1054 }
1055
1056 /* Now Add tge rest if the file name */
1057 RtlInitUnicodeString(&TempName, CmpMachineHiveList[i].Name);
1058 FileName.Length = FileStart;
1059 RtlAppendStringToString((PSTRING)&FileName, (PSTRING)&TempName);
1060 if (!CmpMachineHiveList[i].CmHive)
1061 {
1062 /* We need to allocate a new hive structure */
1063 CmpMachineHiveList[i].Allocate = TRUE;
1064
1065 /* Load the hive file */
1066 DPRINT1("[HiveLoad]: Load from file %wZ\n", &FileName);
1067 Status = CmpInitHiveFromFile(&FileName,
1068 CmpMachineHiveList[i].HHiveFlags,
1069 &CmHive,
1070 &CmpMachineHiveList[i].Allocate,
1071 0);
1072 if (!(NT_SUCCESS(Status)) || !(CmHive->FileHandles[HFILE_TYPE_LOG]))
1073 {
1074 /* We failed or couldn't get a log file, raise a hard error */
1075 ErrorParameters = &FileName;
1076 NtRaiseHardError(STATUS_CANNOT_LOAD_REGISTRY_FILE,
1077 1,
1078 1,
1079 (PULONG_PTR)&ErrorParameters,
1080 OptionOk,
1081 &ErrorResponse);
1082 }
1083
1084 /* Set the hive flags and newly allocated hive pointer */
1085 CmHive->Flags = CmpMachineHiveList[i].CmHiveFlags;
1086 CmpMachineHiveList[i].CmHive2 = CmHive;
1087 }
1088 else
1089 {
1090 CmHive = CmpMachineHiveList[i].CmHive;
1091 /* We already have a hive, is it volatile? */
1092 if (!(CmHive->Hive.HiveFlags & HIVE_VOLATILE))
1093 {
1094 DPRINT1("[HiveLoad]: Open from file %wZ\n", &FileName);
1095
1096 /* It's now, open the hive file and log */
1097 Status = CmpOpenHiveFiles(&FileName,
1098 L".LOG",
1099 &PrimaryHandle,
1100 &LogHandle,
1101 &PrimaryDisposition,
1102 &SecondaryDisposition,
1103 TRUE,
1104 TRUE,
1105 FALSE,
1106 &ClusterSize);
1107 if (!(NT_SUCCESS(Status)) || !(LogHandle))
1108 {
1109 /* Couldn't open the hive or its log file, raise a hard error */
1110 ErrorParameters = &FileName;
1111 NtRaiseHardError(STATUS_CANNOT_LOAD_REGISTRY_FILE,
1112 1,
1113 1,
1114 (PULONG_PTR)&ErrorParameters,
1115 OptionOk,
1116 &ErrorResponse);
1117
1118 /* And bugcheck for posterity's sake */
1119 KeBugCheckEx(BAD_SYSTEM_CONFIG_INFO, 9, 0, i, Status);
1120 }
1121
1122 /* Save the file handles. This should remove our sync hacks */
1123 CmHive->FileHandles[HFILE_TYPE_LOG] = LogHandle;
1124 CmHive->FileHandles[HFILE_TYPE_PRIMARY] = PrimaryHandle;
1125
1126 /* Allow lazy flushing since the handles are there -- remove sync hacks */
1127 //ASSERT(CmHive->Hive.HiveFlags & HIVE_NOLAZYFLUSH);
1128 CmHive->Hive.HiveFlags &= ~HIVE_NOLAZYFLUSH;
1129
1130 /* Get the real size of the hive */
1131 Length = CmHive->Hive.Storage[Stable].Length + HBLOCK_SIZE;
1132
1133 /* Check if the cluster size doesn't match */
1134 if (CmHive->Hive.Cluster != ClusterSize) ASSERT(FALSE);
1135
1136 /* Set the file size */
1137 //if (!CmpFileSetSize((PHHIVE)CmHive, HFILE_TYPE_PRIMARY, Length, Length))
1138 {
1139 /* This shouldn't fail */
1140 //ASSERT(FALSE);
1141 }
1142
1143 /* Another thing we don't support is NTLDR-recovery */
1144 if (CmHive->Hive.BaseBlock->BootRecover) ASSERT(FALSE);
1145
1146 /* Finally, set our allocated hive to the same hive we've had */
1147 CmpMachineHiveList[i].CmHive2 = CmHive;
1148 ASSERT(CmpMachineHiveList[i].CmHive == CmpMachineHiveList[i].CmHive2);
1149 }
1150 }
1151
1152 /* We're done */
1153 CmpMachineHiveList[i].ThreadFinished = TRUE;
1154
1155 /* Check if we're the last worker */
1156 WorkerCount = InterlockedIncrement(&CmpLoadWorkerIncrement);
1157 if (WorkerCount == CM_NUMBER_OF_MACHINE_HIVES)
1158 {
1159 /* Signal the event */
1160 KeSetEvent(&CmpLoadWorkerEvent, 0, FALSE);
1161 }
1162
1163 /* Kill the thread */
1164 PsTerminateSystemThread(Status);
1165 }
1166
1167 VOID
1168 NTAPI
1169 CmpInitializeHiveList(IN USHORT Flag)
1170 {
1171 WCHAR FileBuffer[MAX_PATH], RegBuffer[MAX_PATH], ConfigPath[MAX_PATH];
1172 UNICODE_STRING TempName, FileName, RegName;
1173 HANDLE Thread;
1174 NTSTATUS Status;
1175 ULONG FileStart, RegStart, i;
1176 PSECURITY_DESCRIPTOR SecurityDescriptor;
1177 PAGED_CODE();
1178
1179 /* Allow writing for now */
1180 CmpNoWrite = FALSE;
1181
1182 /* Build the file name and registry name strings */
1183 RtlInitEmptyUnicodeString(&FileName, FileBuffer, MAX_PATH);
1184 RtlInitEmptyUnicodeString(&RegName, RegBuffer, MAX_PATH);
1185
1186 /* Now build the system root path */
1187 CmpGetRegistryPath(ConfigPath);
1188 RtlInitUnicodeString(&TempName, ConfigPath);
1189 RtlAppendStringToString((PSTRING)&FileName, (PSTRING)&TempName);
1190 FileStart = FileName.Length;
1191
1192 /* And build the registry root path */
1193 RtlInitUnicodeString(&TempName, L"\\REGISTRY\\");
1194 RtlAppendStringToString((PSTRING)&RegName, (PSTRING)&TempName);
1195 RegStart = RegName.Length;
1196
1197 /* Setup the event to synchronize workers */
1198 KeInitializeEvent(&CmpLoadWorkerEvent, SynchronizationEvent, FALSE);
1199
1200 /* Enter special boot condition */
1201 CmpSpecialBootCondition = TRUE;
1202
1203 /* Create the SD for the root hives */
1204 SecurityDescriptor = CmpHiveRootSecurityDescriptor();
1205
1206 /* Loop every hive we care about */
1207 for (i = 0; i < CM_NUMBER_OF_MACHINE_HIVES; i++)
1208 {
1209 /* Make sure the list is setup */
1210 ASSERT(CmpMachineHiveList[i].Name != NULL);
1211
1212 /* Create a thread to handle this hive */
1213 Status = PsCreateSystemThread(&Thread,
1214 THREAD_ALL_ACCESS,
1215 NULL,
1216 0,
1217 NULL,
1218 CmpLoadHiveThread,
1219 (PVOID)i);
1220 if (NT_SUCCESS(Status))
1221 {
1222 /* We don't care about the handle -- the thread self-terminates */
1223 ZwClose(Thread);
1224 }
1225 else
1226 {
1227 /* Can't imagine this happening */
1228 KeBugCheckEx(BAD_SYSTEM_CONFIG_INFO, 9, 3, i, Status);
1229 }
1230 }
1231
1232 /* Make sure we've reached the end of the list */
1233 ASSERT(CmpMachineHiveList[i].Name == NULL);
1234
1235 /* Wait for hive loading to finish */
1236 KeWaitForSingleObject(&CmpLoadWorkerEvent,
1237 Executive,
1238 KernelMode,
1239 FALSE,
1240 NULL);
1241
1242 /* Exit the special boot condition and make sure all workers completed */
1243 CmpSpecialBootCondition = FALSE;
1244 ASSERT(CmpLoadWorkerIncrement == CM_NUMBER_OF_MACHINE_HIVES);
1245
1246 /* Loop hives again */
1247 for (i = 0; i < CM_NUMBER_OF_MACHINE_HIVES; i++)
1248 {
1249 /* Make sure the thread ran and finished */
1250 ASSERT(CmpMachineHiveList[i].ThreadFinished == TRUE);
1251 ASSERT(CmpMachineHiveList[i].ThreadStarted == TRUE);
1252
1253 /* Check if this was a new hive */
1254 if (!CmpMachineHiveList[i].CmHive)
1255 {
1256 /* Make sure we allocated something */
1257 ASSERT(CmpMachineHiveList[i].CmHive2 != NULL);
1258
1259 /* Build the base name */
1260 RegName.Length = RegStart;
1261 RtlInitUnicodeString(&TempName, CmpMachineHiveList[i].BaseName);
1262 RtlAppendStringToString((PSTRING)&RegName, (PSTRING)&TempName);
1263
1264 /* Check if this is a child of the root */
1265 if (RegName.Buffer[RegName.Length / sizeof(WCHAR) - 1] == '\\')
1266 {
1267 /* Then setup the whole name */
1268 RtlInitUnicodeString(&TempName, CmpMachineHiveList[i].Name);
1269 RtlAppendStringToString((PSTRING)&RegName, (PSTRING)&TempName);
1270 }
1271
1272 /* Now link the hive to its master */
1273 DPRINT1("[HiveLoad]: Link %wZ\n", &RegName);
1274 Status = CmpLinkHiveToMaster(&RegName,
1275 NULL,
1276 CmpMachineHiveList[i].CmHive2,
1277 CmpMachineHiveList[i].Allocate,
1278 SecurityDescriptor);
1279 if (Status != STATUS_SUCCESS)
1280 {
1281 /* Linking needs to work */
1282 KeBugCheckEx(CONFIG_LIST_FAILED, 11, Status, i, (ULONG_PTR)&RegName);
1283 }
1284
1285 /* Check if we had to allocate a new hive */
1286 if (CmpMachineHiveList[i].Allocate)
1287 {
1288 /* Sync the new hive */
1289 //HvSyncHive((PHHIVE)(CmpMachineHiveList[i].CmHive2));
1290 }
1291 }
1292
1293 /* Check if we created a new hive */
1294 if (CmpMachineHiveList[i].CmHive2)
1295 {
1296 /* TODO: Add to HiveList key */
1297 }
1298 }
1299
1300 /* Get rid of the SD */
1301 ExFreePool(SecurityDescriptor);
1302
1303 /* FIXME: Link SECURITY to SAM */
1304
1305 /* FIXME: Link S-1-5-18 to .Default */
1306 }
1307
1308 BOOLEAN
1309 NTAPI
1310 CmInitSystem1(VOID)
1311 {
1312 OBJECT_ATTRIBUTES ObjectAttributes;
1313 UNICODE_STRING KeyName;
1314 HANDLE KeyHandle;
1315 NTSTATUS Status;
1316 PCMHIVE HardwareHive;
1317 PVOID BaseAddress;
1318 ULONG Length;
1319 PSECURITY_DESCRIPTOR SecurityDescriptor;
1320 PAGED_CODE();
1321
1322 /* Check if this is PE-boot */
1323 if (InitIsWinPEMode)
1324 {
1325 /* Set registry to PE mode */
1326 CmpMiniNTBoot = TRUE;
1327 CmpShareSystemHives = TRUE;
1328 }
1329
1330 /* Initialize the hive list and lock */
1331 InitializeListHead(&CmpHiveListHead);
1332 ExInitializePushLock((PVOID)&CmpHiveListHeadLock);
1333 ExInitializePushLock((PVOID)&CmpLoadHiveLock);
1334
1335 /* Initialize registry lock */
1336 ExInitializeResourceLite(&CmpRegistryLock);
1337
1338 /* Initialize the cache */
1339 CmpInitializeCache();
1340
1341 /* Initialize allocation and delayed dereferencing */
1342 CmpInitCmPrivateAlloc();
1343 CmpInitCmPrivateDelayAlloc();
1344 CmpInitDelayDerefKCBEngine();
1345
1346 /* Initialize callbacks */
1347 CmpInitCallback();
1348
1349 /* Initialize self healing */
1350 KeInitializeGuardedMutex(&CmpSelfHealQueueLock);
1351 InitializeListHead(&CmpSelfHealQueueListHead);
1352
1353 /* Save the current process and lock the registry */
1354 CmpSystemProcess = PsGetCurrentProcess();
1355
1356 /* Create the key object types */
1357 Status = CmpCreateObjectTypes();
1358 if (!NT_SUCCESS(Status))
1359 {
1360 /* Bugcheck */
1361 KEBUGCHECKEX(CONFIG_INITIALIZATION_FAILED, 1, 1, Status, 0);
1362 }
1363
1364 /* Build the master hive */
1365 Status = CmpInitializeHive((PCMHIVE*)&CmiVolatileHive,
1366 HINIT_CREATE,
1367 HIVE_VOLATILE,
1368 HFILE_TYPE_PRIMARY,
1369 NULL,
1370 NULL,
1371 NULL,
1372 NULL,
1373 NULL,
1374 0);
1375 if (!NT_SUCCESS(Status))
1376 {
1377 /* Bugcheck */
1378 KEBUGCHECKEX(CONFIG_INITIALIZATION_FAILED, 1, 2, Status, 0);
1379 }
1380
1381 /* Create the \REGISTRY key node */
1382 if (!CmpCreateRegistryRoot())
1383 {
1384 /* Bugcheck */
1385 KEBUGCHECKEX(CONFIG_INITIALIZATION_FAILED, 1, 3, 0, 0);
1386 }
1387
1388 /* Create the default security descriptor */
1389 SecurityDescriptor = CmpHiveRootSecurityDescriptor();
1390
1391 /* Create '\Registry\Machine' key. */
1392 RtlInitUnicodeString(&KeyName, L"\\REGISTRY\\MACHINE");
1393 InitializeObjectAttributes(&ObjectAttributes,
1394 &KeyName,
1395 OBJ_CASE_INSENSITIVE,
1396 NULL,
1397 SecurityDescriptor);
1398 Status = NtCreateKey(&KeyHandle,
1399 KEY_READ | KEY_WRITE,
1400 &ObjectAttributes,
1401 0,
1402 NULL,
1403 0,
1404 NULL);
1405 if (!NT_SUCCESS(Status))
1406 {
1407 /* Bugcheck */
1408 KEBUGCHECKEX(CONFIG_INITIALIZATION_FAILED, 1, 5, Status, 0);
1409 }
1410
1411 /* Close the handle */
1412 NtClose(KeyHandle);
1413
1414 /* Create '\Registry\User' key. */
1415 RtlInitUnicodeString(&KeyName, L"\\REGISTRY\\USER");
1416 InitializeObjectAttributes(&ObjectAttributes,
1417 &KeyName,
1418 OBJ_CASE_INSENSITIVE,
1419 NULL,
1420 SecurityDescriptor);
1421 Status = NtCreateKey(&KeyHandle,
1422 KEY_READ | KEY_WRITE,
1423 &ObjectAttributes,
1424 0,
1425 NULL,
1426 0,
1427 NULL);
1428 if (!NT_SUCCESS(Status))
1429 {
1430 /* Bugcheck */
1431 KEBUGCHECKEX(CONFIG_INITIALIZATION_FAILED, 1, 6, Status, 0);
1432 }
1433
1434 /* Close the handle */
1435 NtClose(KeyHandle);
1436
1437 /* Initialize the system hive */
1438 if (!CmpInitializeSystemHive(KeLoaderBlock))
1439 {
1440 /* Bugcheck */
1441 KEBUGCHECKEX(CONFIG_INITIALIZATION_FAILED, 1, 7, 0, 0);
1442 }
1443
1444 /* Create the 'CurrentControlSet' link. */
1445 Status = CmpCreateControlSet(KeLoaderBlock);
1446 if (!NT_SUCCESS(Status))
1447 {
1448 /* Bugcheck */
1449 KEBUGCHECKEX(CONFIG_INITIALIZATION_FAILED, 1, 8, Status, 0);
1450 }
1451
1452 /* Import the hardware hive (FIXME: We should create it from scratch) */
1453 BaseAddress = CmpRosGetHardwareHive(&Length);
1454 ((PHBASE_BLOCK)BaseAddress)->Length = Length;
1455 Status = CmpInitializeHive((PCMHIVE*)&HardwareHive,
1456 HINIT_MEMORY, //HINIT_CREATE,
1457 HIVE_VOLATILE | HIVE_NOLAZYFLUSH,
1458 HFILE_TYPE_PRIMARY,
1459 BaseAddress, // NULL,
1460 NULL,
1461 NULL,
1462 NULL,
1463 NULL,
1464 0);
1465 CmPrepareHive(&HardwareHive->Hive);
1466 if (!NT_SUCCESS(Status))
1467 {
1468 /* Bugcheck */
1469 KEBUGCHECKEX(CONFIG_INITIALIZATION_FAILED, 1, 11, Status, 0);
1470 }
1471
1472 /* Add the hive to the hive list */
1473 CmpMachineHiveList[0].CmHive = (PCMHIVE)HardwareHive;
1474
1475 /* Attach it to the machine key */
1476 RtlInitUnicodeString(&KeyName, L"\\Registry\\Machine\\HARDWARE");
1477 Status = CmpLinkHiveToMaster(&KeyName,
1478 NULL,
1479 (PCMHIVE)HardwareHive,
1480 FALSE, // TRUE
1481 SecurityDescriptor);
1482 if (!NT_SUCCESS(Status))
1483 {
1484 /* Bugcheck */
1485 KEBUGCHECKEX(CONFIG_INITIALIZATION_FAILED, 1, 12, Status, 0);
1486 }
1487
1488 /* FIXME: Add to HiveList key */
1489
1490 /* Free the security descriptor */
1491 ExFreePool(SecurityDescriptor);
1492
1493 /* Fill out the Hardware key with the ARC Data from the Loader */
1494 Status = CmpInitializeHardwareConfiguration(KeLoaderBlock);
1495 if (!NT_SUCCESS(Status))
1496 {
1497 /* Bugcheck */
1498 KEBUGCHECKEX(CONFIG_INITIALIZATION_FAILED, 1, 13, Status, 0);
1499 }
1500
1501 /* Initialize machine-dependent information into the registry */
1502 Status = CmpInitializeMachineDependentConfiguration(KeLoaderBlock);
1503 if (!NT_SUCCESS(Status))
1504 {
1505 /* Bugcheck */
1506 KEBUGCHECKEX(CONFIG_INITIALIZATION_FAILED, 1, 14, Status, 0);
1507 }
1508
1509 /* Initialize volatile registry settings */
1510 Status = CmpSetSystemValues(KeLoaderBlock);
1511 if (!NT_SUCCESS(Status))
1512 {
1513 /* Bugcheck */
1514 KEBUGCHECKEX(CONFIG_INITIALIZATION_FAILED, 1, 15, Status, 0);
1515 }
1516
1517 /* Free the load options */
1518 ExFreePool(CmpLoadOptions.Buffer);
1519
1520 /* If we got here, all went well */
1521 return TRUE;
1522 }
1523
1524 VOID
1525 NTAPI
1526 CmpLockRegistryExclusive(VOID)
1527 {
1528 /* Enter a critical region and lock the registry */
1529 KeEnterCriticalRegion();
1530 ExAcquireResourceExclusiveLite(&CmpRegistryLock, TRUE);
1531
1532 /* Sanity check */
1533 ASSERT(CmpFlushStarveWriters == 0);
1534 RtlGetCallersAddress(&CmpRegistryLockCaller, &CmpRegistryLockCallerCaller);
1535 }
1536
1537 VOID
1538 NTAPI
1539 CmpLockRegistry(VOID)
1540 {
1541 /* Enter a critical region */
1542 KeEnterCriticalRegion();
1543
1544 /* Check if we have to starve writers */
1545 if (CmpFlushStarveWriters)
1546 {
1547 /* Starve exlusive waiters */
1548 ExAcquireSharedStarveExclusive(&CmpRegistryLock, TRUE);
1549 }
1550 else
1551 {
1552 /* Just grab the lock */
1553 ExAcquireResourceSharedLite(&CmpRegistryLock, TRUE);
1554 }
1555 }
1556
1557 BOOLEAN
1558 NTAPI
1559 CmpTestRegistryLock(VOID)
1560 {
1561 /* Test the lock */
1562 return !ExIsResourceAcquiredSharedLite(&CmpRegistryLock) ? FALSE : TRUE;
1563 }
1564
1565 BOOLEAN
1566 NTAPI
1567 CmpTestRegistryLockExclusive(VOID)
1568 {
1569 /* Test the lock */
1570 return !ExIsResourceAcquiredExclusiveLite(&CmpRegistryLock) ? FALSE : TRUE;
1571 }
1572
1573 VOID
1574 NTAPI
1575 CmpUnlockRegistry(VOID)
1576 {
1577 /* Sanity check */
1578 CMP_ASSERT_REGISTRY_LOCK();
1579
1580 /* Check if we should flush the registry */
1581 if (CmpFlushOnLockRelease)
1582 {
1583 /* The registry should be exclusively locked for this */
1584 CMP_ASSERT_EXCLUSIVE_REGISTRY_LOCK();
1585
1586 /* Flush the registry */
1587 CmpDoFlushAll(TRUE);
1588 CmpFlushOnLockRelease = FALSE;
1589 }
1590
1591 /* Release the lock and leave the critical region */
1592 ExReleaseResourceLite(&CmpRegistryLock);
1593 KeLeaveCriticalRegion();
1594 }
1595
1596 VOID
1597 NTAPI
1598 CmpAcquireTwoKcbLocksExclusiveByKey(IN ULONG ConvKey1,
1599 IN ULONG ConvKey2)
1600 {
1601 ULONG Index1, Index2;
1602
1603 /* Sanity check */
1604 CMP_ASSERT_REGISTRY_LOCK();
1605
1606 /* Get hash indexes */
1607 Index1 = GET_HASH_INDEX(ConvKey1);
1608 Index2 = GET_HASH_INDEX(ConvKey2);
1609
1610 /* See which one is highest */
1611 if (Index1 < Index2)
1612 {
1613 /* Grab them in the proper order */
1614 CmpAcquireKcbLockExclusiveByKey(ConvKey1);
1615 CmpAcquireKcbLockExclusiveByKey(ConvKey2);
1616 }
1617 else
1618 {
1619 /* Grab the second one first, then the first */
1620 CmpAcquireKcbLockExclusiveByKey(ConvKey2);
1621 if (Index1 != Index2) CmpAcquireKcbLockExclusiveByKey(ConvKey1);
1622 }
1623 }
1624
1625 VOID
1626 NTAPI
1627 CmpReleaseTwoKcbLockByKey(IN ULONG ConvKey1,
1628 IN ULONG ConvKey2)
1629 {
1630 ULONG Index1, Index2;
1631
1632 /* Sanity check */
1633 CMP_ASSERT_REGISTRY_LOCK();
1634
1635 /* Get hash indexes */
1636 Index1 = GET_HASH_INDEX(ConvKey1);
1637 Index2 = GET_HASH_INDEX(ConvKey2);
1638 ASSERT((GET_HASH_ENTRY(CmpCacheTable, ConvKey2).Owner == KeGetCurrentThread()) ||
1639 (CmpTestRegistryLockExclusive()));
1640
1641 /* See which one is highest */
1642 if (Index1 < Index2)
1643 {
1644 /* Grab them in the proper order */
1645 ASSERT((GET_HASH_ENTRY(CmpCacheTable, ConvKey1).Owner == KeGetCurrentThread()) ||
1646 (CmpTestRegistryLockExclusive()));
1647 CmpReleaseKcbLockByKey(ConvKey2);
1648 CmpReleaseKcbLockByKey(ConvKey1);
1649 }
1650 else
1651 {
1652 /* Release the first one first, then the second */
1653 if (Index1 != Index2)
1654 {
1655 ASSERT((GET_HASH_ENTRY(CmpCacheTable, ConvKey1).Owner == KeGetCurrentThread()) ||
1656 (CmpTestRegistryLockExclusive()));
1657 CmpReleaseKcbLockByKey(ConvKey1);
1658 }
1659 CmpReleaseKcbLockByKey(ConvKey2);
1660 }
1661 }
1662
1663 VOID
1664 NTAPI
1665 CmShutdownSystem(VOID)
1666 {
1667 /* Kill the workers and fush all hives */
1668 CmpShutdownWorkers();
1669 CmpDoFlushAll(TRUE);
1670 }