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