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