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