1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: BSD - See COPYING.ARM in the top level directory
4 * PURPOSE: Configuration Manager - System Initialization Code
5 * PROGRAMMERS: ReactOS Portable Systems Group
6 * 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 PVOID CmpRegistryLockCallerCaller, CmpRegistryLockCaller;
25 BOOLEAN CmpFlushOnLockRelease;
26 BOOLEAN CmpSpecialBootCondition;
27
28 /* Disable registry hive writes, until the IO subsystem is initialized
29 * and disk access is enabled (when the SM signals so after AUTOCHK) */
30 BOOLEAN CmpNoWrite = TRUE;
31
32 BOOLEAN CmpWasSetupBoot;
33 BOOLEAN CmpProfileLoaded;
34 BOOLEAN CmpNoVolatileCreates;
35 ULONG CmpTraceLevel = 0;
36 BOOLEAN HvShutdownComplete = FALSE;
37
38 extern LONG CmpFlushStarveWriters;
39 extern BOOLEAN CmFirstTime;
40
41 /* FUNCTIONS ******************************************************************/
42
43 BOOLEAN
44 NTAPI
CmpLinkKeyToHive(_In_z_ PCWSTR LinkKeyName,_In_z_ PCWSTR TargetKeyName)45 CmpLinkKeyToHive(
46 _In_z_ PCWSTR LinkKeyName,
47 _In_z_ PCWSTR TargetKeyName)
48 {
49 NTSTATUS Status;
50 OBJECT_ATTRIBUTES ObjectAttributes;
51 UNICODE_STRING KeyName;
52 HANDLE LinkKeyHandle;
53 ULONG Disposition;
54
55 PAGED_CODE();
56
57 /* Initialize the object attributes */
58 RtlInitUnicodeString(&KeyName, LinkKeyName);
59 InitializeObjectAttributes(&ObjectAttributes,
60 &KeyName,
61 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
62 NULL,
63 NULL);
64
65 /* Create the link key */
66 Status = ZwCreateKey(&LinkKeyHandle,
67 KEY_CREATE_LINK,
68 &ObjectAttributes,
69 0,
70 NULL,
71 REG_OPTION_VOLATILE | REG_OPTION_CREATE_LINK,
72 &Disposition);
73 if (!NT_SUCCESS(Status))
74 {
75 DPRINT1("CM: CmpLinkKeyToHive: couldn't create %S, Status = 0x%lx\n",
76 LinkKeyName, Status);
77 return FALSE;
78 }
79
80 /* Check if the new key was actually created */
81 if (Disposition != REG_CREATED_NEW_KEY)
82 {
83 DPRINT1("CM: CmpLinkKeyToHive: %S already exists!\n", LinkKeyName);
84 ZwClose(LinkKeyHandle);
85 return FALSE;
86 }
87
88 /* Set the target key name as link target */
89 RtlInitUnicodeString(&KeyName, TargetKeyName);
90 Status = ZwSetValueKey(LinkKeyHandle,
91 &CmSymbolicLinkValueName,
92 0,
93 REG_LINK,
94 KeyName.Buffer,
95 KeyName.Length);
96
97 /* Close the link key handle */
98 ObCloseHandle(LinkKeyHandle, KernelMode);
99
100 if (!NT_SUCCESS(Status))
101 {
102 DPRINT1("CM: CmpLinkKeyToHive: couldn't create symbolic link for %S, Status = 0x%lx\n",
103 TargetKeyName, Status);
104 return FALSE;
105 }
106
107 return TRUE;
108 }
109
110 VOID
111 NTAPI
CmpDeleteKeyObject(PVOID DeletedObject)112 CmpDeleteKeyObject(PVOID DeletedObject)
113 {
114 PCM_KEY_BODY KeyBody = (PCM_KEY_BODY)DeletedObject;
115 PCM_KEY_CONTROL_BLOCK Kcb;
116 REG_KEY_HANDLE_CLOSE_INFORMATION KeyHandleCloseInfo;
117 REG_POST_OPERATION_INFORMATION PostOperationInfo;
118 NTSTATUS Status;
119 PAGED_CODE();
120
121 /* First off, prepare the handle close information callback */
122 PostOperationInfo.Object = KeyBody;
123 KeyHandleCloseInfo.Object = KeyBody;
124 Status = CmiCallRegisteredCallbacks(RegNtPreKeyHandleClose,
125 &KeyHandleCloseInfo);
126 if (!NT_SUCCESS(Status))
127 {
128 /* If we failed, notify the post routine */
129 PostOperationInfo.Status = Status;
130 CmiCallRegisteredCallbacks(RegNtPostKeyHandleClose, &PostOperationInfo);
131 return;
132 }
133
134 /* Acquire hive lock */
135 CmpLockRegistry();
136
137 /* Make sure this is a valid key body */
138 if (KeyBody->Type == CM_KEY_BODY_TYPE)
139 {
140 /* Get the KCB */
141 Kcb = KeyBody->KeyControlBlock;
142 if (Kcb)
143 {
144 /* Delist the key */
145 DelistKeyBodyFromKCB(KeyBody, KeyBody->KcbLocked);
146
147 /* Dereference the KCB */
148 CmpDelayDerefKeyControlBlock(Kcb);
149 }
150 }
151
152 /* Release the registry lock */
153 CmpUnlockRegistry();
154
155 /* Do the post callback */
156 PostOperationInfo.Status = STATUS_SUCCESS;
157 CmiCallRegisteredCallbacks(RegNtPostKeyHandleClose, &PostOperationInfo);
158 }
159
160 VOID
161 NTAPI
CmpCloseKeyObject(IN PEPROCESS Process OPTIONAL,IN PVOID Object,IN ACCESS_MASK GrantedAccess,IN ULONG ProcessHandleCount,IN ULONG SystemHandleCount)162 CmpCloseKeyObject(IN PEPROCESS Process OPTIONAL,
163 IN PVOID Object,
164 IN ACCESS_MASK GrantedAccess,
165 IN ULONG ProcessHandleCount,
166 IN ULONG SystemHandleCount)
167 {
168 PCM_KEY_BODY KeyBody = (PCM_KEY_BODY)Object;
169 PAGED_CODE();
170
171 /* Don't do anything if we're not the last handle */
172 if (SystemHandleCount > 1) return;
173
174 /* Make sure we're a valid key body */
175 if (KeyBody->Type == CM_KEY_BODY_TYPE)
176 {
177 /* Don't do anything if we don't have a notify block */
178 if (!KeyBody->NotifyBlock) return;
179
180 /* This shouldn't happen yet */
181 ASSERT(FALSE);
182 }
183 }
184
185 NTSTATUS
186 NTAPI
CmpQueryKeyName(IN PVOID ObjectBody,IN BOOLEAN HasName,IN OUT POBJECT_NAME_INFORMATION ObjectNameInfo,IN ULONG Length,OUT PULONG ReturnLength,IN KPROCESSOR_MODE PreviousMode)187 CmpQueryKeyName(IN PVOID ObjectBody,
188 IN BOOLEAN HasName,
189 IN OUT POBJECT_NAME_INFORMATION ObjectNameInfo,
190 IN ULONG Length,
191 OUT PULONG ReturnLength,
192 IN KPROCESSOR_MODE PreviousMode)
193 {
194 PUNICODE_STRING KeyName;
195 ULONG BytesToCopy;
196 NTSTATUS Status = STATUS_SUCCESS;
197 PCM_KEY_BODY KeyBody = (PCM_KEY_BODY)ObjectBody;
198 PCM_KEY_CONTROL_BLOCK Kcb = KeyBody->KeyControlBlock;
199
200 /* Acquire hive lock */
201 CmpLockRegistry();
202
203 /* Lock KCB shared */
204 CmpAcquireKcbLockShared(Kcb);
205
206 /* Check if it's a deleted block */
207 if (Kcb->Delete)
208 {
209 /* Release the locks */
210 CmpReleaseKcbLock(Kcb);
211 CmpUnlockRegistry();
212
213 /* Let the caller know it's deleted */
214 return STATUS_KEY_DELETED;
215 }
216
217 /* Get the name */
218 KeyName = CmpConstructName(Kcb);
219
220 /* Release the locks */
221 CmpReleaseKcbLock(Kcb);
222 CmpUnlockRegistry();
223
224 /* Check if we got the name */
225 if (!KeyName) return STATUS_INSUFFICIENT_RESOURCES;
226
227 /* Set the returned length */
228 *ReturnLength = KeyName->Length + sizeof(OBJECT_NAME_INFORMATION) + sizeof(WCHAR);
229
230 /* Calculate amount of bytes to copy into the buffer */
231 BytesToCopy = KeyName->Length + sizeof(WCHAR);
232
233 /* Check if the provided buffer is too small to fit even anything */
234 if ((Length <= sizeof(OBJECT_NAME_INFORMATION)) ||
235 ((Length < *ReturnLength) && (BytesToCopy < sizeof(WCHAR))))
236 {
237 /* Free the buffer allocated by CmpConstructName */
238 ExFreePoolWithTag(KeyName, TAG_CM);
239
240 /* Return buffer length failure without writing anything there because nothing fits */
241 return STATUS_INFO_LENGTH_MISMATCH;
242 }
243
244 /* Check if the provided buffer can be partially written */
245 if (Length < *ReturnLength)
246 {
247 /* Yes, indicate so in the return status */
248 Status = STATUS_INFO_LENGTH_MISMATCH;
249
250 /* Calculate amount of bytes which the provided buffer could handle */
251 BytesToCopy = Length - sizeof(OBJECT_NAME_INFORMATION);
252 }
253
254 /* Remove the null termination character from the size */
255 BytesToCopy -= sizeof(WCHAR);
256
257 /* Fill in the result */
258 _SEH2_TRY
259 {
260 /* Return data to user */
261 ObjectNameInfo->Name.Buffer = (PWCHAR)(ObjectNameInfo + 1);
262 ObjectNameInfo->Name.MaximumLength = KeyName->Length;
263 ObjectNameInfo->Name.Length = KeyName->Length;
264
265 /* Copy string content*/
266 RtlCopyMemory(ObjectNameInfo->Name.Buffer,
267 KeyName->Buffer,
268 BytesToCopy);
269
270 /* Null terminate it */
271 ObjectNameInfo->Name.Buffer[BytesToCopy / sizeof(WCHAR)] = UNICODE_NULL;
272 }
273 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
274 {
275 /* Get the status */
276 Status = _SEH2_GetExceptionCode();
277 }
278 _SEH2_END;
279
280 /* Free the buffer allocated by CmpConstructName */
281 ExFreePoolWithTag(KeyName, TAG_CM);
282
283 /* Return status */
284 return Status;
285 }
286
287 NTSTATUS
288 NTAPI
CmpInitHiveFromFile(IN PCUNICODE_STRING HiveName,IN ULONG HiveFlags,OUT PCMHIVE * Hive,IN OUT PBOOLEAN New,IN ULONG CheckFlags)289 CmpInitHiveFromFile(IN PCUNICODE_STRING HiveName,
290 IN ULONG HiveFlags,
291 OUT PCMHIVE *Hive,
292 IN OUT PBOOLEAN New,
293 IN ULONG CheckFlags)
294 {
295 ULONG HiveDisposition, LogDisposition;
296 HANDLE FileHandle = NULL, LogHandle = NULL;
297 NTSTATUS Status;
298 ULONG Operation, FileType;
299 PCMHIVE NewHive;
300 PAGED_CODE();
301
302 /* Assume failure */
303 *Hive = NULL;
304
305 /* Open or create the hive files */
306 Status = CmpOpenHiveFiles(HiveName,
307 L".LOG",
308 &FileHandle,
309 &LogHandle,
310 &HiveDisposition,
311 &LogDisposition,
312 *New,
313 FALSE,
314 TRUE,
315 NULL);
316 if (!NT_SUCCESS(Status)) return Status;
317
318 /* Check if we have a log handle */
319 FileType = (LogHandle) ? HFILE_TYPE_LOG : HFILE_TYPE_PRIMARY;
320
321 /* Check if we created or opened the hive */
322 if (HiveDisposition == FILE_CREATED)
323 {
324 /* Do a create operation */
325 Operation = HINIT_CREATE;
326 *New = TRUE;
327 }
328 else
329 {
330 /* Open it as a file */
331 Operation = HINIT_FILE;
332 *New = FALSE;
333 }
334
335 /* Check if the system hives are opened in shared mode */
336 if (CmpShareSystemHives)
337 {
338 /* Then force using the primary hive */
339 FileType = HFILE_TYPE_PRIMARY;
340 if (LogHandle)
341 {
342 /* Get rid of the log handle */
343 ZwClose(LogHandle);
344 LogHandle = NULL;
345 }
346 }
347
348 /* Check if we're too late */
349 if (HvShutdownComplete)
350 {
351 /* Fail */
352 ZwClose(FileHandle);
353 if (LogHandle) ZwClose(LogHandle);
354 return STATUS_TOO_LATE;
355 }
356
357 /* Initialize the hive */
358 Status = CmpInitializeHive(&NewHive,
359 Operation,
360 HiveFlags,
361 FileType,
362 NULL,
363 FileHandle,
364 LogHandle,
365 NULL,
366 NULL,
367 HiveName,
368 CheckFlags);
369 if (!NT_SUCCESS(Status))
370 {
371 /* Fail */
372 ZwClose(FileHandle);
373 if (LogHandle) ZwClose(LogHandle);
374 return Status;
375 }
376
377 /* Success, return hive */
378 *Hive = NewHive;
379
380 /* Duplicate the hive name */
381 NewHive->FileFullPath.Buffer = ExAllocatePoolWithTag(PagedPool,
382 HiveName->Length,
383 TAG_CM);
384 if (NewHive->FileFullPath.Buffer)
385 {
386 /* Copy the string */
387 RtlCopyMemory(NewHive->FileFullPath.Buffer,
388 HiveName->Buffer,
389 HiveName->Length);
390 NewHive->FileFullPath.Length = HiveName->Length;
391 NewHive->FileFullPath.MaximumLength = HiveName->Length;
392 }
393
394 /* Return success */
395 return STATUS_SUCCESS;
396 }
397
398 CODE_SEG("INIT")
399 NTSTATUS
400 NTAPI
CmpSetSystemValues(IN PLOADER_PARAMETER_BLOCK LoaderBlock)401 CmpSetSystemValues(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
402 {
403 NTSTATUS Status;
404 OBJECT_ATTRIBUTES ObjectAttributes;
405 HANDLE KeyHandle;
406 UNICODE_STRING KeyName, ValueName = { 0, 0, NULL };
407
408 ASSERT(LoaderBlock != NULL);
409
410 /* Setup attributes for loader options */
411 RtlInitUnicodeString(&KeyName,
412 L"\\REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\"
413 L"Control");
414 InitializeObjectAttributes(&ObjectAttributes,
415 &KeyName,
416 OBJ_CASE_INSENSITIVE,
417 NULL,
418 NULL);
419 Status = NtOpenKey(&KeyHandle, KEY_WRITE, &ObjectAttributes);
420 if (!NT_SUCCESS(Status))
421 return Status;
422
423 /* Setup the value for the system start options */
424 RtlInitUnicodeString(&KeyName, L"SystemStartOptions");
425 Status = NtSetValueKey(KeyHandle,
426 &KeyName,
427 0,
428 REG_SZ,
429 CmpLoadOptions.Buffer,
430 CmpLoadOptions.Length);
431 if (!NT_SUCCESS(Status))
432 goto Quit;
433
434 /* Setup the value for the system boot device in ARC format */
435 RtlInitUnicodeString(&KeyName, L"SystemBootDevice");
436 RtlCreateUnicodeStringFromAsciiz(&ValueName, LoaderBlock->ArcBootDeviceName);
437 Status = NtSetValueKey(KeyHandle,
438 &KeyName,
439 0,
440 REG_SZ,
441 ValueName.Buffer,
442 ValueName.Length);
443
444 /* Free the temporary string */
445 RtlFreeUnicodeString(&ValueName);
446
447 Quit:
448 /* Close the key and return */
449 NtClose(KeyHandle);
450 return Status;
451 }
452
453 static
454 CODE_SEG("INIT")
455 NTSTATUS
CmpCreateHardwareProfile(HANDLE ControlSetHandle)456 CmpCreateHardwareProfile(HANDLE ControlSetHandle)
457 {
458 OBJECT_ATTRIBUTES ObjectAttributes;
459 UNICODE_STRING KeyName;
460 HANDLE ProfilesHandle = NULL;
461 HANDLE ProfileHandle = NULL;
462 ULONG Disposition;
463 NTSTATUS Status;
464
465 DPRINT("CmpCreateHardwareProfile()\n");
466
467 /* Create the Hardware Profiles key */
468 RtlInitUnicodeString(&KeyName, L"Hardware Profiles");
469 InitializeObjectAttributes(&ObjectAttributes,
470 &KeyName,
471 OBJ_CASE_INSENSITIVE,
472 ControlSetHandle,
473 NULL);
474 Status = NtCreateKey(&ProfilesHandle,
475 KEY_ALL_ACCESS,
476 &ObjectAttributes,
477 0,
478 NULL,
479 0,
480 &Disposition);
481 if (!NT_SUCCESS(Status))
482 {
483 DPRINT1("Creating the Hardware Profile key failed\n");
484 goto done;
485 }
486
487 /* Sanity check */
488 ASSERT(Disposition == REG_CREATED_NEW_KEY);
489
490 /* Create the 0000 key */
491 RtlInitUnicodeString(&KeyName, L"0000");
492 InitializeObjectAttributes(&ObjectAttributes,
493 &KeyName,
494 OBJ_CASE_INSENSITIVE,
495 ProfilesHandle,
496 NULL);
497 Status = NtCreateKey(&ProfileHandle,
498 KEY_ALL_ACCESS,
499 &ObjectAttributes,
500 0,
501 NULL,
502 0,
503 &Disposition);
504 if (!NT_SUCCESS(Status))
505 {
506 DPRINT1("Creating the Hardware Profile\\0000 key failed\n");
507 goto done;
508 }
509
510 /* Sanity check */
511 ASSERT(Disposition == REG_CREATED_NEW_KEY);
512
513 done:
514 if (ProfilesHandle)
515 NtClose(ProfilesHandle);
516
517 if (ProfileHandle)
518 NtClose(ProfileHandle);
519
520 DPRINT("CmpCreateHardwareProfile() done\n");
521
522 return Status;
523 }
524
525 CODE_SEG("INIT")
526 NTSTATUS
527 NTAPI
CmpCreateControlSet(IN PLOADER_PARAMETER_BLOCK LoaderBlock)528 CmpCreateControlSet(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
529 {
530 UNICODE_STRING ConfigName = RTL_CONSTANT_STRING(L"Control\\IDConfigDB");
531 UNICODE_STRING SelectName =
532 RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\Select");
533 UNICODE_STRING KeyName;
534 OBJECT_ATTRIBUTES ObjectAttributes;
535 CHAR ValueInfoBuffer[128];
536 PKEY_VALUE_FULL_INFORMATION ValueInfo;
537 WCHAR UnicodeBuffer[128];
538 HANDLE SelectHandle = NULL;
539 HANDLE KeyHandle = NULL;
540 HANDLE ConfigHandle = NULL;
541 HANDLE ProfileHandle = NULL;
542 HANDLE ParentHandle = NULL;
543 ULONG ControlSet, HwProfile;
544 NTSTATUS Status;
545 ULONG ResultLength, Disposition;
546 PLOADER_PARAMETER_EXTENSION LoaderExtension;
547 PAGED_CODE();
548
549 /* ReactOS Hack: Hard-code current to 001 for SetupLdr */
550 if (LoaderBlock->RegistryBase == NULL)
551 {
552 /* Build the ControlSet001 key */
553 RtlInitUnicodeString(&KeyName,
554 L"\\Registry\\Machine\\System\\ControlSet001");
555 InitializeObjectAttributes(&ObjectAttributes,
556 &KeyName,
557 OBJ_CASE_INSENSITIVE,
558 NULL,
559 NULL);
560 Status = NtCreateKey(&KeyHandle,
561 KEY_ALL_ACCESS,
562 &ObjectAttributes,
563 0,
564 NULL,
565 0,
566 &Disposition);
567 if (!NT_SUCCESS(Status))
568 {
569 DPRINT1("Failed to create ControlSet001 key: 0x%lx\n", Status);
570 goto Cleanup;
571 }
572
573 /* Create the Hardware Profile keys */
574 Status = CmpCreateHardwareProfile(KeyHandle);
575 if (!NT_SUCCESS(Status))
576 {
577 DPRINT1("Failed to create Hardware profile keys: 0x%lx\n", Status);
578 goto Cleanup;
579 }
580
581 /* Use hard-coded setting */
582 ControlSet = 1;
583 }
584 else
585 {
586 /* Open the select key */
587 InitializeObjectAttributes(&ObjectAttributes,
588 &SelectName,
589 OBJ_CASE_INSENSITIVE,
590 NULL,
591 NULL);
592 Status = NtOpenKey(&SelectHandle, KEY_READ, &ObjectAttributes);
593 if (!NT_SUCCESS(Status))
594 {
595 DPRINT1("Failed to open select key: 0x%lx\n", Status);
596 goto Cleanup;
597 }
598
599 /* Open the current value */
600 RtlInitUnicodeString(&KeyName, L"Current");
601 Status = NtQueryValueKey(SelectHandle,
602 &KeyName,
603 KeyValueFullInformation,
604 ValueInfoBuffer,
605 sizeof(ValueInfoBuffer),
606 &ResultLength);
607 if (!NT_SUCCESS(Status))
608 {
609 DPRINT1("Failed to open the Current value: 0x%lx\n", Status);
610 goto Cleanup;
611 }
612
613 /* Get the actual value pointer, and get the control set ID */
614 ValueInfo = (PKEY_VALUE_FULL_INFORMATION)ValueInfoBuffer;
615 ControlSet = *(PULONG)((PUCHAR)ValueInfo + ValueInfo->DataOffset);
616 }
617
618 /* Create the current control set key */
619 RtlInitUnicodeString(&KeyName,
620 L"\\Registry\\Machine\\System\\CurrentControlSet");
621 InitializeObjectAttributes(&ObjectAttributes,
622 &KeyName,
623 OBJ_CASE_INSENSITIVE,
624 NULL,
625 NULL);
626 Status = NtCreateKey(&KeyHandle,
627 KEY_CREATE_LINK,
628 &ObjectAttributes,
629 0,
630 NULL,
631 REG_OPTION_VOLATILE | REG_OPTION_CREATE_LINK,
632 &Disposition);
633 if (!NT_SUCCESS(Status))
634 goto Cleanup;
635
636 /* Sanity check */
637 ASSERT(Disposition == REG_CREATED_NEW_KEY);
638
639 /* Initialize the target link name */
640 Status = RtlStringCbPrintfW(UnicodeBuffer, sizeof(UnicodeBuffer),
641 L"\\Registry\\Machine\\System\\ControlSet%03ld",
642 ControlSet);
643 if (!NT_SUCCESS(Status))
644 goto Cleanup;
645
646 RtlInitUnicodeString(&KeyName, UnicodeBuffer);
647
648 /* Set the value */
649 Status = NtSetValueKey(KeyHandle,
650 &CmSymbolicLinkValueName,
651 0,
652 REG_LINK,
653 KeyName.Buffer,
654 KeyName.Length);
655 if (!NT_SUCCESS(Status))
656 goto Cleanup;
657
658 /* Get the configuration database key */
659 InitializeObjectAttributes(&ObjectAttributes,
660 &ConfigName,
661 OBJ_CASE_INSENSITIVE,
662 KeyHandle,
663 NULL);
664 Status = NtOpenKey(&ConfigHandle, KEY_READ, &ObjectAttributes);
665
666 /* Check if we don't have one */
667 if (!NT_SUCCESS(Status))
668 {
669 /* Cleanup and exit */
670 Status = STATUS_SUCCESS;
671 goto Cleanup;
672 }
673
674 /* ReactOS Hack: Hard-code current to 001 for SetupLdr */
675 if (LoaderBlock->RegistryBase == NULL)
676 {
677 HwProfile = 0;
678 }
679 else
680 {
681 /* Now get the current config */
682 RtlInitUnicodeString(&KeyName, L"CurrentConfig");
683 Status = NtQueryValueKey(ConfigHandle,
684 &KeyName,
685 KeyValueFullInformation,
686 ValueInfoBuffer,
687 sizeof(ValueInfoBuffer),
688 &ResultLength);
689
690 /* Set pointer to buffer */
691 ValueInfo = (PKEY_VALUE_FULL_INFORMATION)ValueInfoBuffer;
692
693 /* Check if we failed or got a non DWORD-value */
694 if (!NT_SUCCESS(Status) || (ValueInfo->Type != REG_DWORD))
695 {
696 Status = STATUS_SUCCESS;
697 goto Cleanup;
698 }
699
700 /* Get the hadware profile */
701 HwProfile = *(PULONG)((PUCHAR)ValueInfo + ValueInfo->DataOffset);
702 }
703
704 /* Open the hardware profile key */
705 RtlInitUnicodeString(&KeyName,
706 L"\\Registry\\Machine\\System\\CurrentControlSet"
707 L"\\Hardware Profiles");
708 InitializeObjectAttributes(&ObjectAttributes,
709 &KeyName,
710 OBJ_CASE_INSENSITIVE,
711 NULL,
712 NULL);
713 Status = NtOpenKey(&ParentHandle, KEY_READ, &ObjectAttributes);
714 if (!NT_SUCCESS(Status))
715 {
716 /* Exit and clean up */
717 Status = STATUS_SUCCESS;
718 goto Cleanup;
719 }
720
721 /* Build the profile name */
722 RtlStringCbPrintfW(UnicodeBuffer, sizeof(UnicodeBuffer),
723 L"%04ld", HwProfile);
724 RtlInitUnicodeString(&KeyName, UnicodeBuffer);
725
726 /* Open the associated key */
727 InitializeObjectAttributes(&ObjectAttributes,
728 &KeyName,
729 OBJ_CASE_INSENSITIVE,
730 ParentHandle,
731 NULL);
732 Status = NtOpenKey(&ProfileHandle,
733 KEY_READ | KEY_WRITE,
734 &ObjectAttributes);
735 if (!NT_SUCCESS(Status))
736 {
737 /* Cleanup and exit */
738 Status = STATUS_SUCCESS;
739 goto Cleanup;
740 }
741
742 /* Check if we have a loader block extension */
743 LoaderExtension = LoaderBlock->Extension;
744 if (LoaderExtension)
745 {
746 DPRINT("ReactOS doesn't support NTLDR Profiles yet!\n");
747 }
748
749 /* Create the current hardware profile key */
750 RtlInitUnicodeString(&KeyName,
751 L"\\Registry\\Machine\\System\\CurrentControlSet\\"
752 L"Hardware Profiles\\Current");
753 InitializeObjectAttributes(&ObjectAttributes,
754 &KeyName,
755 OBJ_CASE_INSENSITIVE,
756 NULL,
757 NULL);
758 Status = NtCreateKey(&KeyHandle,
759 KEY_CREATE_LINK,
760 &ObjectAttributes,
761 0,
762 NULL,
763 REG_OPTION_VOLATILE | REG_OPTION_CREATE_LINK,
764 &Disposition);
765 if (NT_SUCCESS(Status))
766 {
767 /* Sanity check */
768 ASSERT(Disposition == REG_CREATED_NEW_KEY);
769
770 /* Create the profile name */
771 RtlStringCbPrintfW(UnicodeBuffer, sizeof(UnicodeBuffer),
772 L"\\Registry\\Machine\\System\\CurrentControlSet\\"
773 L"Hardware Profiles\\%04ld",
774 HwProfile);
775 RtlInitUnicodeString(&KeyName, UnicodeBuffer);
776
777 /* Set it */
778 Status = NtSetValueKey(KeyHandle,
779 &CmSymbolicLinkValueName,
780 0,
781 REG_LINK,
782 KeyName.Buffer,
783 KeyName.Length);
784 }
785
786 Status = STATUS_SUCCESS;
787
788 Cleanup:
789 /* Close every opened handle */
790 if (SelectHandle) NtClose(SelectHandle);
791 if (KeyHandle) NtClose(KeyHandle);
792 if (ConfigHandle) NtClose(ConfigHandle);
793 if (ProfileHandle) NtClose(ProfileHandle);
794 if (ParentHandle) NtClose(ParentHandle);
795
796 DPRINT("CmpCreateControlSet() done\n");
797 return Status;
798 }
799
800 NTSTATUS
801 NTAPI
CmpLinkHiveToMaster(IN PUNICODE_STRING LinkName,IN HANDLE RootDirectory,IN PCMHIVE RegistryHive,IN BOOLEAN Allocate,IN PSECURITY_DESCRIPTOR SecurityDescriptor)802 CmpLinkHiveToMaster(IN PUNICODE_STRING LinkName,
803 IN HANDLE RootDirectory,
804 IN PCMHIVE RegistryHive,
805 IN BOOLEAN Allocate,
806 IN PSECURITY_DESCRIPTOR SecurityDescriptor)
807 {
808 OBJECT_ATTRIBUTES ObjectAttributes;
809 NTSTATUS Status;
810 CM_PARSE_CONTEXT ParseContext = {0};
811 HANDLE KeyHandle;
812 PCM_KEY_BODY KeyBody;
813 PAGED_CODE();
814
815 /* Setup the object attributes */
816 InitializeObjectAttributes(&ObjectAttributes,
817 LinkName,
818 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
819 RootDirectory,
820 SecurityDescriptor);
821
822 /* Setup the parse context */
823 ParseContext.CreateLink = TRUE;
824 ParseContext.CreateOperation = TRUE;
825 ParseContext.ChildHive.KeyHive = &RegistryHive->Hive;
826
827 /* Check if we have a root keycell or if we need to create it */
828 if (Allocate)
829 {
830 /* Create it */
831 ParseContext.ChildHive.KeyCell = HCELL_NIL;
832 }
833 else
834 {
835 /* We have one */
836 ParseContext.ChildHive.KeyCell = RegistryHive->Hive.BaseBlock->RootCell;
837 }
838
839 /* Create the link node */
840 Status = ObOpenObjectByName(&ObjectAttributes,
841 CmpKeyObjectType,
842 KernelMode,
843 NULL,
844 KEY_READ | KEY_WRITE,
845 (PVOID)&ParseContext,
846 &KeyHandle);
847 if (!NT_SUCCESS(Status)) return Status;
848
849 /* Mark the hive as clean */
850 RegistryHive->Hive.DirtyFlag = FALSE;
851
852 /* ReactOS Hack: Keep alive */
853 Status = ObReferenceObjectByHandle(KeyHandle,
854 0,
855 CmpKeyObjectType,
856 KernelMode,
857 (PVOID*)&KeyBody,
858 NULL);
859 ASSERT(NT_SUCCESS(Status));
860
861 /* Close the extra handle */
862 ZwClose(KeyHandle);
863 return STATUS_SUCCESS;
864 }
865
866 CODE_SEG("INIT")
867 BOOLEAN
868 NTAPI
CmpInitializeSystemHive(IN PLOADER_PARAMETER_BLOCK LoaderBlock)869 CmpInitializeSystemHive(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
870 {
871 static const UNICODE_STRING HiveName = RTL_CONSTANT_STRING(L"SYSTEM");
872 PVOID HiveBase;
873 ANSI_STRING LoadString;
874 PVOID Buffer;
875 ULONG Length;
876 NTSTATUS Status;
877 UNICODE_STRING KeyName;
878 PCMHIVE SystemHive = NULL;
879 PSECURITY_DESCRIPTOR SecurityDescriptor;
880
881 PAGED_CODE();
882
883 /* Setup the ansi string */
884 RtlInitAnsiString(&LoadString, LoaderBlock->LoadOptions);
885
886 /* Allocate the unicode buffer */
887 Length = LoadString.Length * sizeof(WCHAR) + sizeof(UNICODE_NULL);
888 Buffer = ExAllocatePoolWithTag(PagedPool, Length, TAG_CM);
889 if (!Buffer)
890 {
891 /* Fail */
892 KeBugCheckEx(BAD_SYSTEM_CONFIG_INFO, 3, 1, (ULONG_PTR)LoaderBlock, 0);
893 }
894
895 /* Setup the unicode string */
896 RtlInitEmptyUnicodeString(&CmpLoadOptions, Buffer, (USHORT)Length);
897
898 /* Add the load options and null-terminate */
899 Status = RtlAnsiStringToUnicodeString(&CmpLoadOptions, &LoadString, FALSE);
900 if (!NT_SUCCESS(Status))
901 {
902 return FALSE;
903 }
904
905 CmpLoadOptions.Buffer[LoadString.Length] = UNICODE_NULL;
906 CmpLoadOptions.Length += sizeof(WCHAR);
907
908 /* Get the System Hive base address */
909 HiveBase = LoaderBlock->RegistryBase;
910
911 Status = CmpInitializeHive(&SystemHive,
912 HiveBase ? HINIT_MEMORY : HINIT_CREATE,
913 HIVE_NOLAZYFLUSH,
914 HFILE_TYPE_ALTERNATE,
915 HiveBase,
916 NULL,
917 NULL,
918 NULL,
919 NULL,
920 &HiveName,
921 HiveBase ? CM_CHECK_REGISTRY_PURGE_VOLATILES : CM_CHECK_REGISTRY_DONT_PURGE_VOLATILES);
922 if (!NT_SUCCESS(Status))
923 {
924 return FALSE;
925 }
926
927 /* Set the hive filename */
928 if (!RtlCreateUnicodeString(&SystemHive->FileFullPath, L"\\SystemRoot\\System32\\Config\\SYSTEM"))
929 return FALSE;
930
931 /* Load the system hive as volatile, if opened in shared mode */
932 if (HiveBase && CmpShareSystemHives)
933 SystemHive->Hive.HiveFlags = HIVE_VOLATILE;
934
935 /* Save the boot type */
936 CmpBootType = SystemHive->Hive.BaseBlock->BootType;
937
938 /* Are we in self-healing mode? */
939 if (!CmSelfHeal)
940 {
941 /* Disable self-healing internally and check if boot type wanted it */
942 CmpSelfHeal = FALSE;
943 if (CmpBootType & HBOOT_TYPE_SELF_HEAL)
944 {
945 /* We're disabled, so bugcheck */
946 KeBugCheckEx(BAD_SYSTEM_CONFIG_INFO,
947 3,
948 3,
949 (ULONG_PTR)SystemHive,
950 0);
951 }
952 }
953
954 /* Create the default security descriptor */
955 SecurityDescriptor = CmpHiveRootSecurityDescriptor();
956
957 /* Attach it to the system key */
958 /* Let CmpLinkHiveToMaster allocate a new hive if we got none from the LoaderBlock. */
959 RtlInitUnicodeString(&KeyName, L"\\Registry\\Machine\\SYSTEM");
960 Status = CmpLinkHiveToMaster(&KeyName,
961 NULL,
962 SystemHive,
963 !HiveBase,
964 SecurityDescriptor);
965
966 /* Free the security descriptor */
967 ExFreePoolWithTag(SecurityDescriptor, TAG_CMSD);
968 if (!NT_SUCCESS(Status)) return FALSE;
969
970 /* Add the hive to the hive list */
971 CmpMachineHiveList[3].CmHive = SystemHive;
972
973 /* Success! */
974 return TRUE;
975 }
976
977 CODE_SEG("INIT")
978 NTSTATUS
979 NTAPI
CmpCreateObjectTypes(VOID)980 CmpCreateObjectTypes(VOID)
981 {
982 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer;
983 UNICODE_STRING Name;
984 GENERIC_MAPPING CmpKeyMapping = {KEY_READ,
985 KEY_WRITE,
986 KEY_EXECUTE,
987 KEY_ALL_ACCESS};
988 PAGED_CODE();
989
990 /* Initialize the Key object type */
991 RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer));
992 RtlInitUnicodeString(&Name, L"Key");
993 ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer);
994 ObjectTypeInitializer.DefaultPagedPoolCharge = sizeof(CM_KEY_BODY);
995 ObjectTypeInitializer.GenericMapping = CmpKeyMapping;
996 ObjectTypeInitializer.PoolType = PagedPool;
997 ObjectTypeInitializer.ValidAccessMask = KEY_ALL_ACCESS;
998 ObjectTypeInitializer.UseDefaultObject = TRUE;
999 ObjectTypeInitializer.DeleteProcedure = CmpDeleteKeyObject;
1000 ObjectTypeInitializer.ParseProcedure = CmpParseKey;
1001 ObjectTypeInitializer.SecurityProcedure = CmpSecurityMethod;
1002 ObjectTypeInitializer.QueryNameProcedure = CmpQueryKeyName;
1003 ObjectTypeInitializer.CloseProcedure = CmpCloseKeyObject;
1004 ObjectTypeInitializer.SecurityRequired = TRUE;
1005 ObjectTypeInitializer.InvalidAttributes = OBJ_EXCLUSIVE | OBJ_PERMANENT;
1006
1007 /* Create it */
1008 return ObCreateObjectType(&Name, &ObjectTypeInitializer, NULL, &CmpKeyObjectType);
1009 }
1010
1011 CODE_SEG("INIT")
1012 BOOLEAN
1013 NTAPI
CmpCreateRootNode(IN PHHIVE Hive,IN PCWSTR Name,OUT PHCELL_INDEX Index)1014 CmpCreateRootNode(IN PHHIVE Hive,
1015 IN PCWSTR Name,
1016 OUT PHCELL_INDEX Index)
1017 {
1018 UNICODE_STRING KeyName;
1019 PCM_KEY_NODE KeyCell;
1020 PAGED_CODE();
1021
1022 /* Initialize the node name and allocate it */
1023 RtlInitUnicodeString(&KeyName, Name);
1024 *Index = HvAllocateCell(Hive,
1025 FIELD_OFFSET(CM_KEY_NODE, Name) +
1026 CmpNameSize(Hive, &KeyName),
1027 Stable,
1028 HCELL_NIL);
1029 if (*Index == HCELL_NIL) return FALSE;
1030
1031 /* Set the cell index and get the data */
1032 Hive->BaseBlock->RootCell = *Index;
1033 KeyCell = (PCM_KEY_NODE)HvGetCell(Hive, *Index);
1034 if (!KeyCell) return FALSE;
1035
1036 /* Setup the cell */
1037 KeyCell->Signature = CM_KEY_NODE_SIGNATURE;
1038 KeyCell->Flags = KEY_HIVE_ENTRY | KEY_NO_DELETE;
1039 KeQuerySystemTime(&KeyCell->LastWriteTime);
1040 KeyCell->Parent = HCELL_NIL;
1041 KeyCell->SubKeyCounts[Stable] = 0;
1042 KeyCell->SubKeyCounts[Volatile] = 0;
1043 KeyCell->SubKeyLists[Stable] = HCELL_NIL;
1044 KeyCell->SubKeyLists[Volatile] = HCELL_NIL;
1045 KeyCell->ValueList.Count = 0;
1046 KeyCell->ValueList.List = HCELL_NIL;
1047 KeyCell->Security = HCELL_NIL;
1048 KeyCell->Class = HCELL_NIL;
1049 KeyCell->ClassLength = 0;
1050 KeyCell->MaxNameLen = 0;
1051 KeyCell->MaxClassLen = 0;
1052 KeyCell->MaxValueNameLen = 0;
1053 KeyCell->MaxValueDataLen = 0;
1054
1055 /* Copy the name (this will also set the length) */
1056 KeyCell->NameLength = CmpCopyName(Hive, KeyCell->Name, &KeyName);
1057
1058 /* Check if the name was compressed and set the flag if so */
1059 if (KeyCell->NameLength < KeyName.Length)
1060 KeyCell->Flags |= KEY_COMP_NAME;
1061
1062 /* Return success */
1063 HvReleaseCell(Hive, *Index);
1064 return TRUE;
1065 }
1066
1067 CODE_SEG("INIT")
1068 BOOLEAN
1069 NTAPI
CmpCreateRegistryRoot(VOID)1070 CmpCreateRegistryRoot(VOID)
1071 {
1072 UNICODE_STRING KeyName;
1073 OBJECT_ATTRIBUTES ObjectAttributes;
1074 PCM_KEY_BODY RootKey;
1075 HCELL_INDEX RootIndex;
1076 NTSTATUS Status;
1077 PCM_KEY_NODE KeyCell;
1078 PSECURITY_DESCRIPTOR SecurityDescriptor;
1079 PCM_KEY_CONTROL_BLOCK Kcb;
1080 PAGED_CODE();
1081
1082 /* Setup the root node */
1083 if (!CmpCreateRootNode(&CmiVolatileHive->Hive, L"REGISTRY", &RootIndex))
1084 {
1085 /* We failed */
1086 return FALSE;
1087 }
1088
1089 /* Create '\Registry' key. */
1090 RtlInitUnicodeString(&KeyName, L"\\REGISTRY");
1091 SecurityDescriptor = CmpHiveRootSecurityDescriptor();
1092 InitializeObjectAttributes(&ObjectAttributes,
1093 &KeyName,
1094 OBJ_CASE_INSENSITIVE,
1095 NULL,
1096 SecurityDescriptor);
1097 Status = ObCreateObject(KernelMode,
1098 CmpKeyObjectType,
1099 &ObjectAttributes,
1100 KernelMode,
1101 NULL,
1102 sizeof(CM_KEY_BODY),
1103 0,
1104 0,
1105 (PVOID*)&RootKey);
1106 ExFreePoolWithTag(SecurityDescriptor, TAG_CMSD);
1107 if (!NT_SUCCESS(Status)) return FALSE;
1108
1109 /* Sanity check, and get the key cell */
1110 ASSERT((&CmiVolatileHive->Hive)->ReleaseCellRoutine == NULL);
1111 KeyCell = (PCM_KEY_NODE)HvGetCell(&CmiVolatileHive->Hive, RootIndex);
1112 if (!KeyCell)
1113 {
1114 ObDereferenceObject(RootKey);
1115 return FALSE;
1116 }
1117
1118 /* Create the KCB */
1119 RtlInitUnicodeString(&KeyName, L"\\REGISTRY");
1120 Kcb = CmpCreateKeyControlBlock(&CmiVolatileHive->Hive,
1121 RootIndex,
1122 KeyCell,
1123 NULL,
1124 0,
1125 &KeyName);
1126 if (!Kcb)
1127 {
1128 ObDereferenceObject(RootKey);
1129 return FALSE;
1130 }
1131
1132 /* Initialize the object */
1133 RootKey->KeyControlBlock = Kcb;
1134 RootKey->Type = CM_KEY_BODY_TYPE;
1135 RootKey->NotifyBlock = NULL;
1136 RootKey->ProcessID = PsGetCurrentProcessId();
1137 RootKey->KcbLocked = FALSE;
1138
1139 /* Link with KCB */
1140 EnlistKeyBodyWithKCB(RootKey, 0);
1141
1142 /* Insert the key into the namespace */
1143 Status = ObInsertObject(RootKey,
1144 NULL,
1145 KEY_ALL_ACCESS,
1146 0,
1147 NULL,
1148 &CmpRegistryRootHandle);
1149 if (!NT_SUCCESS(Status))
1150 {
1151 return FALSE;
1152 }
1153
1154 /* Reference the key again so that we never lose it */
1155 Status = ObReferenceObjectByHandle(CmpRegistryRootHandle,
1156 KEY_READ,
1157 NULL,
1158 KernelMode,
1159 (PVOID*)&RootKey,
1160 NULL);
1161 if (!NT_SUCCESS(Status))
1162 {
1163 ObDereferenceObject(RootKey);
1164 return FALSE;
1165 }
1166
1167 /* Completely successful */
1168 return TRUE;
1169 }
1170
1171 static PCWSTR
CmpGetRegistryPath(VOID)1172 CmpGetRegistryPath(VOID)
1173 {
1174 PCWSTR ConfigPath;
1175
1176 /* Check if we are booted in setup */
1177 if (!ExpInTextModeSetup)
1178 {
1179 ConfigPath = L"\\SystemRoot\\System32\\Config\\";
1180 }
1181 else
1182 {
1183 ConfigPath = L"\\SystemRoot\\";
1184 }
1185
1186 DPRINT1("CmpGetRegistryPath: ConfigPath = '%S'\n", ConfigPath);
1187
1188 return ConfigPath;
1189 }
1190
1191 /**
1192 * @brief
1193 * Checks if the primary and alternate backing hive are
1194 * the same, by determining the time stamp of both hives.
1195 *
1196 * @param[in] FileName
1197 * A pointer to a string containing the file name of the
1198 * primary hive.
1199 *
1200 * @param[in] CmMainmHive
1201 * A pointer to a CM hive descriptor associated with the
1202 * primary hive.
1203 *
1204 * @param[in] AlternateHandle
1205 * A handle to a file that represents the alternate hive.
1206 *
1207 * @param[in] Diverged
1208 * A pointer to a boolean value, if both hives are the same
1209 * it returns TRUE. Otherwise it returns FALSE.
1210 */
1211 static
1212 VOID
CmpHasAlternateHiveDiverged(_In_ PCUNICODE_STRING FileName,_In_ PCMHIVE CmMainmHive,_In_ HANDLE AlternateHandle,_Out_ PBOOLEAN Diverged)1213 CmpHasAlternateHiveDiverged(
1214 _In_ PCUNICODE_STRING FileName,
1215 _In_ PCMHIVE CmMainmHive,
1216 _In_ HANDLE AlternateHandle,
1217 _Out_ PBOOLEAN Diverged)
1218 {
1219 PHHIVE Hive, AlternateHive;
1220 NTSTATUS Status;
1221 PCMHIVE CmiAlternateHive;
1222
1223 /* Assume it has not diverged */
1224 *Diverged = FALSE;
1225
1226 /* Initialize the SYSTEM alternate hive */
1227 Status = CmpInitializeHive(&CmiAlternateHive,
1228 HINIT_FILE,
1229 0,
1230 HFILE_TYPE_PRIMARY,
1231 NULL,
1232 AlternateHandle,
1233 NULL,
1234 NULL,
1235 NULL,
1236 FileName,
1237 CM_CHECK_REGISTRY_DONT_PURGE_VOLATILES);
1238 if (!NT_SUCCESS(Status))
1239 {
1240 /* Assume it has diverged... */
1241 DPRINT1("Failed to initialize the alternate hive to check for diversion (Status 0x%lx)\n", Status);
1242 *Diverged = TRUE;
1243 return;
1244 }
1245
1246 /*
1247 * Check the timestamp of both hives. If they do not match they
1248 * have diverged, the kernel has to synchronize the both hives.
1249 */
1250 Hive = &CmMainmHive->Hive;
1251 AlternateHive = &CmiAlternateHive->Hive;
1252 if (AlternateHive->BaseBlock->TimeStamp.QuadPart !=
1253 Hive->BaseBlock->TimeStamp.QuadPart)
1254 {
1255 *Diverged = TRUE;
1256 }
1257
1258 CmpDestroyHive(CmiAlternateHive);
1259 }
1260
_Function_class_(KSTART_ROUTINE)1261 _Function_class_(KSTART_ROUTINE)
1262 VOID
1263 NTAPI
1264 CmpLoadHiveThread(IN PVOID StartContext)
1265 {
1266 WCHAR FileBuffer[64], RegBuffer[64];
1267 PCWSTR ConfigPath;
1268 UNICODE_STRING TempName, FileName, RegName;
1269 ULONG i, ErrorResponse, WorkerCount, Length;
1270 USHORT FileStart;
1271 ULONG PrimaryDisposition, SecondaryDisposition, ClusterSize;
1272 PCMHIVE CmHive;
1273 HANDLE PrimaryHandle = NULL, AlternateHandle = NULL;
1274 NTSTATUS Status = STATUS_SUCCESS;
1275 PVOID ErrorParameters;
1276 BOOLEAN HasDiverged;
1277 PAGED_CODE();
1278
1279 /* Get the hive index, make sure it makes sense */
1280 i = PtrToUlong(StartContext);
1281 ASSERT(CmpMachineHiveList[i].Name != NULL);
1282
1283 /* We were started */
1284 CmpMachineHiveList[i].ThreadStarted = TRUE;
1285
1286 /* Build the file name and registry name strings */
1287 RtlInitEmptyUnicodeString(&FileName, FileBuffer, sizeof(FileBuffer));
1288 RtlInitEmptyUnicodeString(&RegName, RegBuffer, sizeof(RegBuffer));
1289
1290 /* Now build the system root path */
1291 ConfigPath = CmpGetRegistryPath();
1292 RtlInitUnicodeString(&TempName, ConfigPath);
1293 RtlAppendUnicodeStringToString(&FileName, &TempName);
1294 FileStart = FileName.Length;
1295
1296 /* And build the registry root path */
1297 RtlInitUnicodeString(&TempName, L"\\REGISTRY\\");
1298 RtlAppendUnicodeStringToString(&RegName, &TempName);
1299
1300 /* Build the base name */
1301 RtlInitUnicodeString(&TempName, CmpMachineHiveList[i].BaseName);
1302 RtlAppendUnicodeStringToString(&RegName, &TempName);
1303
1304 /* Check if this is a child of the root */
1305 if (RegName.Buffer[RegName.Length / sizeof(WCHAR) - 1] == OBJ_NAME_PATH_SEPARATOR)
1306 {
1307 /* Then setup the whole name */
1308 RtlInitUnicodeString(&TempName, CmpMachineHiveList[i].Name);
1309 RtlAppendUnicodeStringToString(&RegName, &TempName);
1310 }
1311
1312 /* Now add the rest of the file name */
1313 RtlInitUnicodeString(&TempName, CmpMachineHiveList[i].Name);
1314 FileName.Length = FileStart;
1315 RtlAppendUnicodeStringToString(&FileName, &TempName);
1316 if (!CmpMachineHiveList[i].CmHive)
1317 {
1318 /* We need to allocate a new hive structure */
1319 CmpMachineHiveList[i].Allocate = TRUE;
1320
1321 /* Load the hive file */
1322 Status = CmpInitHiveFromFile(&FileName,
1323 CmpMachineHiveList[i].HHiveFlags,
1324 &CmHive,
1325 &CmpMachineHiveList[i].Allocate,
1326 CM_CHECK_REGISTRY_PURGE_VOLATILES);
1327 if (!NT_SUCCESS(Status) ||
1328 (!CmpShareSystemHives && !CmHive->FileHandles[HFILE_TYPE_LOG]))
1329 {
1330 /*
1331 * We failed, or could not get a log file (unless
1332 * the hive is shared), raise a hard error.
1333 */
1334 ErrorParameters = &FileName;
1335 NtRaiseHardError(STATUS_CANNOT_LOAD_REGISTRY_FILE,
1336 1,
1337 1,
1338 (PULONG_PTR)&ErrorParameters,
1339 OptionOk,
1340 &ErrorResponse);
1341 }
1342
1343 /* Set the hive flags and newly allocated hive pointer */
1344 CmHive->Flags = CmpMachineHiveList[i].CmHiveFlags;
1345 CmpMachineHiveList[i].CmHive2 = CmHive;
1346 }
1347 else
1348 {
1349 /* We already have a hive, is it volatile? */
1350 CmHive = CmpMachineHiveList[i].CmHive;
1351 if (!(CmHive->Hive.HiveFlags & HIVE_VOLATILE))
1352 {
1353 /* It's now, open the hive file and log */
1354 Status = CmpOpenHiveFiles(&FileName,
1355 L".ALT",
1356 &PrimaryHandle,
1357 &AlternateHandle,
1358 &PrimaryDisposition,
1359 &SecondaryDisposition,
1360 TRUE,
1361 TRUE,
1362 FALSE,
1363 &ClusterSize);
1364 if (!NT_SUCCESS(Status) || !AlternateHandle)
1365 {
1366 /* Couldn't open the hive or its alternate file, raise a hard error */
1367 ErrorParameters = &FileName;
1368 NtRaiseHardError(STATUS_CANNOT_LOAD_REGISTRY_FILE,
1369 1,
1370 1,
1371 (PULONG_PTR)&ErrorParameters,
1372 OptionOk,
1373 &ErrorResponse);
1374
1375 /* And bugcheck for posterity's sake */
1376 KeBugCheckEx(BAD_SYSTEM_CONFIG_INFO, 9, 0, i, Status);
1377 }
1378
1379 /* Save the file handles. This should remove our sync hacks */
1380 /*
1381 * FIXME: Any hive that relies on the alternate hive for recovery purposes
1382 * will only get an alternate hive. As a result, the LOG file would never
1383 * get synced each time a write is done to the hive. In the future it would
1384 * be best to adapt the code so that a primary hive can use a LOG and ALT
1385 * hives at the same time.
1386 */
1387 CmHive->FileHandles[HFILE_TYPE_ALTERNATE] = AlternateHandle;
1388 CmHive->FileHandles[HFILE_TYPE_PRIMARY] = PrimaryHandle;
1389
1390 /* Allow lazy flushing since the handles are there -- remove sync hacks */
1391 //ASSERT(CmHive->Hive.HiveFlags & HIVE_NOLAZYFLUSH);
1392 CmHive->Hive.HiveFlags &= ~HIVE_NOLAZYFLUSH;
1393
1394 /* Get the real size of the hive */
1395 Length = CmHive->Hive.Storage[Stable].Length + HBLOCK_SIZE;
1396
1397 /* Check if the cluster size doesn't match */
1398 if (CmHive->Hive.Cluster != ClusterSize)
1399 {
1400 DPRINT1("FIXME: Support for CmHive->Hive.Cluster (%lu) != ClusterSize (%lu) is unimplemented!\n",
1401 CmHive->Hive.Cluster, ClusterSize);
1402 }
1403
1404 /* Set the file size */
1405 DPRINT("FIXME: Should set file size: %lu\n", Length);
1406 //if (!CmpFileSetSize((PHHIVE)CmHive, HFILE_TYPE_PRIMARY, Length, Length))
1407 //{
1408 /* This shouldn't fail */
1409 //ASSERT(FALSE);
1410 //}
1411
1412 /* FreeLdr has recovered the hive with a log, we must do a flush */
1413 if (CmHive->Hive.BaseBlock->BootRecover == HBOOT_BOOT_RECOVERED_BY_HIVE_LOG)
1414 {
1415 DPRINT1("FreeLdr recovered the hive (hive 0x%p)\n", CmHive);
1416 RtlSetAllBits(&CmHive->Hive.DirtyVector);
1417 CmHive->Hive.DirtyCount = CmHive->Hive.DirtyVector.SizeOfBitMap;
1418 HvSyncHive((PHHIVE)CmHive);
1419 }
1420 else
1421 {
1422 /*
1423 * Check whether the both primary and alternate hives are the same,
1424 * or that the primary or alternate were created for the first time.
1425 * Do a write against the alternate hive in these cases.
1426 */
1427 CmpHasAlternateHiveDiverged(&FileName,
1428 CmHive,
1429 AlternateHandle,
1430 &HasDiverged);
1431 if (HasDiverged ||
1432 PrimaryDisposition == FILE_CREATED ||
1433 SecondaryDisposition == FILE_CREATED)
1434 {
1435 if (!HvWriteAlternateHive((PHHIVE)CmHive))
1436 {
1437 DPRINT1("Failed to write to alternate hive\n");
1438 goto Exit;
1439 }
1440 }
1441 }
1442
1443 /* Finally, set our allocated hive to the same hive we've had */
1444 CmpMachineHiveList[i].CmHive2 = CmHive;
1445 ASSERT(CmpMachineHiveList[i].CmHive == CmpMachineHiveList[i].CmHive2);
1446 }
1447 }
1448
1449 Exit:
1450 /* We're done */
1451 CmpMachineHiveList[i].ThreadFinished = TRUE;
1452
1453 /* Check if we're the last worker */
1454 WorkerCount = InterlockedIncrement(&CmpLoadWorkerIncrement);
1455 if (WorkerCount == CM_NUMBER_OF_MACHINE_HIVES)
1456 {
1457 /* Signal the event */
1458 KeSetEvent(&CmpLoadWorkerEvent, 0, FALSE);
1459 }
1460
1461 /* Kill the thread */
1462 PsTerminateSystemThread(Status);
1463 }
1464
1465 VOID
1466 NTAPI
CmpInitializeHiveList(VOID)1467 CmpInitializeHiveList(VOID)
1468 {
1469 WCHAR FileBuffer[64], RegBuffer[64];
1470 PCWSTR ConfigPath;
1471 UNICODE_STRING TempName, FileName, RegName;
1472 HANDLE Thread;
1473 NTSTATUS Status;
1474 ULONG i;
1475 USHORT RegStart;
1476 PSECURITY_DESCRIPTOR SecurityDescriptor;
1477
1478 PAGED_CODE();
1479
1480 /* Reenable hive writes now */
1481 CmpNoWrite = FALSE;
1482
1483 /* Build the file name and registry name strings */
1484 RtlInitEmptyUnicodeString(&FileName, FileBuffer, sizeof(FileBuffer));
1485 RtlInitEmptyUnicodeString(&RegName, RegBuffer, sizeof(RegBuffer));
1486
1487 /* Now build the system root path */
1488 ConfigPath = CmpGetRegistryPath();
1489 RtlInitUnicodeString(&TempName, ConfigPath);
1490 RtlAppendUnicodeStringToString(&FileName, &TempName);
1491
1492 /* And build the registry root path */
1493 RtlInitUnicodeString(&TempName, L"\\REGISTRY\\");
1494 RtlAppendUnicodeStringToString(&RegName, &TempName);
1495 RegStart = RegName.Length;
1496
1497 /* Setup the event to synchronize workers */
1498 KeInitializeEvent(&CmpLoadWorkerEvent, SynchronizationEvent, FALSE);
1499
1500 /* Enter special boot condition */
1501 CmpSpecialBootCondition = TRUE;
1502
1503 /* Create the SD for the root hives */
1504 SecurityDescriptor = CmpHiveRootSecurityDescriptor();
1505
1506 /* Loop every hive we care about */
1507 for (i = 0; i < CM_NUMBER_OF_MACHINE_HIVES; i++)
1508 {
1509 /* Make sure the list is set up */
1510 ASSERT(CmpMachineHiveList[i].Name != NULL);
1511
1512 /* Load this root hive as volatile, if opened in shared mode */
1513 if (CmpShareSystemHives)
1514 CmpMachineHiveList[i].HHiveFlags |= HIVE_VOLATILE;
1515
1516 /* Create a thread to handle this hive */
1517 Status = PsCreateSystemThread(&Thread,
1518 THREAD_ALL_ACCESS,
1519 NULL,
1520 0,
1521 NULL,
1522 CmpLoadHiveThread,
1523 UlongToPtr(i));
1524 if (NT_SUCCESS(Status))
1525 {
1526 /* We don't care about the handle -- the thread self-terminates */
1527 ZwClose(Thread);
1528 }
1529 else
1530 {
1531 /* Can't imagine this happening */
1532 KeBugCheckEx(BAD_SYSTEM_CONFIG_INFO, 9, 3, i, Status);
1533 }
1534 }
1535
1536 /* Make sure we've reached the end of the list */
1537 ASSERT(CmpMachineHiveList[i].Name == NULL);
1538
1539 /* Wait for hive loading to finish */
1540 KeWaitForSingleObject(&CmpLoadWorkerEvent,
1541 Executive,
1542 KernelMode,
1543 FALSE,
1544 NULL);
1545
1546 /* Exit the special boot condition and make sure all workers completed */
1547 CmpSpecialBootCondition = FALSE;
1548 ASSERT(CmpLoadWorkerIncrement == CM_NUMBER_OF_MACHINE_HIVES);
1549
1550 /* Loop hives again */
1551 for (i = 0; i < CM_NUMBER_OF_MACHINE_HIVES; i++)
1552 {
1553 /* Make sure the thread ran and finished */
1554 ASSERT(CmpMachineHiveList[i].ThreadFinished == TRUE);
1555 ASSERT(CmpMachineHiveList[i].ThreadStarted == TRUE);
1556
1557 /* Check if this was a new hive */
1558 if (!CmpMachineHiveList[i].CmHive)
1559 {
1560 /* Make sure we allocated something */
1561 ASSERT(CmpMachineHiveList[i].CmHive2 != NULL);
1562
1563 /* Build the base name */
1564 RegName.Length = RegStart;
1565 RtlInitUnicodeString(&TempName, CmpMachineHiveList[i].BaseName);
1566 RtlAppendUnicodeStringToString(&RegName, &TempName);
1567
1568 /* Check if this is a child of the root */
1569 if (RegName.Buffer[RegName.Length / sizeof(WCHAR) - 1] == OBJ_NAME_PATH_SEPARATOR)
1570 {
1571 /* Then setup the whole name */
1572 RtlInitUnicodeString(&TempName, CmpMachineHiveList[i].Name);
1573 RtlAppendUnicodeStringToString(&RegName, &TempName);
1574 }
1575
1576 /* Now link the hive to its master */
1577 Status = CmpLinkHiveToMaster(&RegName,
1578 NULL,
1579 CmpMachineHiveList[i].CmHive2,
1580 CmpMachineHiveList[i].Allocate,
1581 SecurityDescriptor);
1582 if (Status != STATUS_SUCCESS)
1583 {
1584 /* Linking needs to work */
1585 KeBugCheckEx(CONFIG_LIST_FAILED, 11, Status, i, (ULONG_PTR)&RegName);
1586 }
1587
1588 /* Check if we had to allocate a new hive */
1589 if (CmpMachineHiveList[i].Allocate)
1590 {
1591 /* Sync the new hive */
1592 //HvSyncHive((PHHIVE)(CmpMachineHiveList[i].CmHive2));
1593 }
1594 }
1595
1596 /* Check if we created a new hive */
1597 if (CmpMachineHiveList[i].CmHive2)
1598 {
1599 /* Add to HiveList key */
1600 CmpAddToHiveFileList(CmpMachineHiveList[i].CmHive2);
1601 }
1602 }
1603
1604 /* Get rid of the SD */
1605 ExFreePoolWithTag(SecurityDescriptor, TAG_CMSD);
1606
1607 /* Link SECURITY to SAM */
1608 CmpLinkKeyToHive(L"\\Registry\\Machine\\Security\\SAM",
1609 L"\\Registry\\Machine\\SAM\\SAM");
1610
1611 /* Link S-1-5-18 to .Default */
1612 CmpNoVolatileCreates = FALSE;
1613 CmpLinkKeyToHive(L"\\Registry\\User\\S-1-5-18",
1614 L"\\Registry\\User\\.Default");
1615 CmpNoVolatileCreates = TRUE;
1616 }
1617
1618 CODE_SEG("INIT")
1619 BOOLEAN
1620 NTAPI
CmInitSystem1(VOID)1621 CmInitSystem1(VOID)
1622 {
1623 OBJECT_ATTRIBUTES ObjectAttributes;
1624 UNICODE_STRING KeyName;
1625 HANDLE KeyHandle;
1626 NTSTATUS Status;
1627 PCMHIVE HardwareHive;
1628 PSECURITY_DESCRIPTOR SecurityDescriptor;
1629 PAGED_CODE();
1630
1631 /* Check if this is PE-boot */
1632 if (InitIsWinPEMode)
1633 {
1634 /* Set the registry in PE mode and load the system hives in shared mode */
1635 CmpMiniNTBoot = TRUE;
1636 CmpShareSystemHives = TRUE;
1637 }
1638 /* If we are in volatile boot mode, ALL hives without exception
1639 * (system hives and others) will be loaded in shared mode */
1640 if (CmpVolatileBoot)
1641 CmpShareSystemHives = TRUE;
1642
1643 /* Initialize the hive list and lock */
1644 InitializeListHead(&CmpHiveListHead);
1645 ExInitializePushLock(&CmpHiveListHeadLock);
1646 ExInitializePushLock(&CmpLoadHiveLock);
1647
1648 /* Initialize registry lock */
1649 ExInitializeResourceLite(&CmpRegistryLock);
1650
1651 /* Initialize the cache */
1652 CmpInitializeCache();
1653
1654 /* Initialize allocation and delayed dereferencing */
1655 CmpInitCmPrivateAlloc();
1656 CmpInitCmPrivateDelayAlloc();
1657 CmpInitDelayDerefKCBEngine();
1658
1659 /* Initialize callbacks */
1660 CmpInitCallback();
1661
1662 /* Initialize self healing */
1663 KeInitializeGuardedMutex(&CmpSelfHealQueueLock);
1664 InitializeListHead(&CmpSelfHealQueueListHead);
1665
1666 /* Save the current process and lock the registry */
1667 CmpSystemProcess = PsGetCurrentProcess();
1668
1669 /* Create the key object types */
1670 Status = CmpCreateObjectTypes();
1671 if (!NT_SUCCESS(Status))
1672 {
1673 /* Bugcheck */
1674 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 1, Status, 0);
1675 }
1676
1677 /* Build the master hive */
1678 Status = CmpInitializeHive(&CmiVolatileHive,
1679 HINIT_CREATE,
1680 HIVE_VOLATILE,
1681 HFILE_TYPE_PRIMARY,
1682 NULL,
1683 NULL,
1684 NULL,
1685 NULL,
1686 NULL,
1687 NULL,
1688 CM_CHECK_REGISTRY_DONT_PURGE_VOLATILES);
1689 if (!NT_SUCCESS(Status))
1690 {
1691 /* Bugcheck */
1692 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 2, Status, 0);
1693 }
1694
1695 /* Create the \REGISTRY key node */
1696 if (!CmpCreateRegistryRoot())
1697 {
1698 /* Bugcheck */
1699 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 3, 0, 0);
1700 }
1701
1702 /* Create the default security descriptor */
1703 SecurityDescriptor = CmpHiveRootSecurityDescriptor();
1704
1705 /* Create '\Registry\Machine' key */
1706 RtlInitUnicodeString(&KeyName, L"\\REGISTRY\\MACHINE");
1707 InitializeObjectAttributes(&ObjectAttributes,
1708 &KeyName,
1709 OBJ_CASE_INSENSITIVE,
1710 NULL,
1711 SecurityDescriptor);
1712 Status = NtCreateKey(&KeyHandle,
1713 KEY_READ | KEY_WRITE,
1714 &ObjectAttributes,
1715 0,
1716 NULL,
1717 0,
1718 NULL);
1719 if (!NT_SUCCESS(Status))
1720 {
1721 /* Bugcheck */
1722 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 5, Status, 0);
1723 }
1724
1725 /* Close the handle */
1726 NtClose(KeyHandle);
1727
1728 /* Create '\Registry\User' key */
1729 RtlInitUnicodeString(&KeyName, L"\\REGISTRY\\USER");
1730 InitializeObjectAttributes(&ObjectAttributes,
1731 &KeyName,
1732 OBJ_CASE_INSENSITIVE,
1733 NULL,
1734 SecurityDescriptor);
1735 Status = NtCreateKey(&KeyHandle,
1736 KEY_READ | KEY_WRITE,
1737 &ObjectAttributes,
1738 0,
1739 NULL,
1740 0,
1741 NULL);
1742 if (!NT_SUCCESS(Status))
1743 {
1744 /* Bugcheck */
1745 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 6, Status, 0);
1746 }
1747
1748 /* Close the handle */
1749 NtClose(KeyHandle);
1750
1751 /* After this point, do not allow creating keys in the master hive */
1752 CmpNoVolatileCreates = TRUE;
1753
1754 /* Initialize the system hive */
1755 if (!CmpInitializeSystemHive(KeLoaderBlock))
1756 {
1757 /* Bugcheck */
1758 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 7, 0, 0);
1759 }
1760
1761 /* Create the 'CurrentControlSet' link */
1762 Status = CmpCreateControlSet(KeLoaderBlock);
1763 if (!NT_SUCCESS(Status))
1764 {
1765 /* Bugcheck */
1766 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 8, Status, 0);
1767 }
1768
1769 /* Create the hardware hive */
1770 Status = CmpInitializeHive(&HardwareHive,
1771 HINIT_CREATE,
1772 HIVE_VOLATILE,
1773 HFILE_TYPE_PRIMARY,
1774 NULL,
1775 NULL,
1776 NULL,
1777 NULL,
1778 NULL,
1779 NULL,
1780 CM_CHECK_REGISTRY_DONT_PURGE_VOLATILES);
1781 if (!NT_SUCCESS(Status))
1782 {
1783 /* Bugcheck */
1784 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 11, Status, 0);
1785 }
1786
1787 /* Add the hive to the hive list */
1788 CmpMachineHiveList[0].CmHive = HardwareHive;
1789
1790 /* Attach it to the machine key */
1791 RtlInitUnicodeString(&KeyName, L"\\Registry\\Machine\\HARDWARE");
1792 Status = CmpLinkHiveToMaster(&KeyName,
1793 NULL,
1794 HardwareHive,
1795 TRUE,
1796 SecurityDescriptor);
1797 if (!NT_SUCCESS(Status))
1798 {
1799 /* Bugcheck */
1800 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 12, Status, 0);
1801 }
1802
1803 /* Add to HiveList key */
1804 CmpAddToHiveFileList(HardwareHive);
1805
1806 /* Free the security descriptor */
1807 ExFreePoolWithTag(SecurityDescriptor, TAG_CMSD);
1808
1809 /* Fill out the Hardware key with the ARC Data from the Loader */
1810 Status = CmpInitializeHardwareConfiguration(KeLoaderBlock);
1811 if (!NT_SUCCESS(Status))
1812 {
1813 /* Bugcheck */
1814 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 13, Status, 0);
1815 }
1816
1817 /* Initialize machine-dependent information into the registry */
1818 Status = CmpInitializeMachineDependentConfiguration(KeLoaderBlock);
1819 if (!NT_SUCCESS(Status))
1820 {
1821 /* Bugcheck */
1822 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 14, Status, 0);
1823 }
1824
1825 /* Initialize volatile registry settings */
1826 Status = CmpSetSystemValues(KeLoaderBlock);
1827 if (!NT_SUCCESS(Status))
1828 {
1829 /* Bugcheck */
1830 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 15, Status, 0);
1831 }
1832
1833 /* Free the load options */
1834 ExFreePoolWithTag(CmpLoadOptions.Buffer, TAG_CM);
1835
1836 /* If we got here, all went well */
1837 return TRUE;
1838 }
1839
1840 CODE_SEG("INIT")
1841 PUNICODE_STRING*
1842 NTAPI
CmGetSystemDriverList(VOID)1843 CmGetSystemDriverList(VOID)
1844 {
1845 LIST_ENTRY DriverList;
1846 OBJECT_ATTRIBUTES ObjectAttributes;
1847 NTSTATUS Status;
1848 PCM_KEY_BODY KeyBody;
1849 PHHIVE Hive;
1850 HCELL_INDEX RootCell, ControlCell;
1851 HANDLE KeyHandle;
1852 UNICODE_STRING KeyName;
1853 PLIST_ENTRY NextEntry;
1854 ULONG i;
1855 PUNICODE_STRING* ServicePath = NULL;
1856 BOOLEAN Success, AutoSelect;
1857 PBOOT_DRIVER_LIST_ENTRY DriverEntry;
1858 PAGED_CODE();
1859
1860 /* Initialize the driver list */
1861 InitializeListHead(&DriverList);
1862
1863 /* Open the system hive key */
1864 RtlInitUnicodeString(&KeyName, L"\\Registry\\Machine\\System");
1865 InitializeObjectAttributes(&ObjectAttributes,
1866 &KeyName,
1867 OBJ_CASE_INSENSITIVE,
1868 NULL,
1869 NULL);
1870 Status = NtOpenKey(&KeyHandle, KEY_READ, &ObjectAttributes);
1871 if (!NT_SUCCESS(Status)) return NULL;
1872
1873 /* Reference the key object to get the root hive/cell to access directly */
1874 Status = ObReferenceObjectByHandle(KeyHandle,
1875 KEY_QUERY_VALUE,
1876 CmpKeyObjectType,
1877 KernelMode,
1878 (PVOID*)&KeyBody,
1879 NULL);
1880 if (!NT_SUCCESS(Status))
1881 {
1882 /* Fail */
1883 NtClose(KeyHandle);
1884 return NULL;
1885 }
1886
1887 /* Do all this under the registry lock */
1888 CmpLockRegistryExclusive();
1889
1890 /* Get the hive and key cell */
1891 Hive = KeyBody->KeyControlBlock->KeyHive;
1892 RootCell = KeyBody->KeyControlBlock->KeyCell;
1893
1894 /* Open the current control set key */
1895 RtlInitUnicodeString(&KeyName, L"Current");
1896 ControlCell = CmpFindControlSet(Hive, RootCell, &KeyName, &AutoSelect);
1897 if (ControlCell == HCELL_NIL) goto EndPath;
1898
1899 /* Find all system drivers */
1900 Success = CmpFindDrivers(Hive, ControlCell, SystemLoad, NULL, &DriverList);
1901 if (!Success) goto EndPath;
1902
1903 /* Sort by group/tag */
1904 if (!CmpSortDriverList(Hive, ControlCell, &DriverList)) goto EndPath;
1905
1906 /* Remove circular dependencies (cycles) and sort */
1907 if (!CmpResolveDriverDependencies(&DriverList)) goto EndPath;
1908
1909 /* Loop the list to count drivers */
1910 for (i = 0, NextEntry = DriverList.Flink;
1911 NextEntry != &DriverList;
1912 i++, NextEntry = NextEntry->Flink);
1913
1914 /* Allocate the array */
1915 ServicePath = ExAllocatePool(NonPagedPool, (i + 1) * sizeof(PUNICODE_STRING));
1916 if (!ServicePath) KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 2, 1, 0, 0);
1917
1918 /* Loop the driver list */
1919 for (i = 0, NextEntry = DriverList.Flink;
1920 NextEntry != &DriverList;
1921 i++, NextEntry = NextEntry->Flink)
1922 {
1923 /* Get the entry */
1924 DriverEntry = CONTAINING_RECORD(NextEntry, BOOT_DRIVER_LIST_ENTRY, Link);
1925
1926 /* Allocate the path for the caller */
1927 ServicePath[i] = ExAllocatePool(NonPagedPool, sizeof(UNICODE_STRING));
1928 if (!ServicePath[i])
1929 {
1930 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 2, 1, 0, 0);
1931 }
1932
1933 /* Duplicate the registry path */
1934 Status = RtlDuplicateUnicodeString(RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE,
1935 &DriverEntry->RegistryPath,
1936 ServicePath[i]);
1937 if (!NT_SUCCESS(Status))
1938 {
1939 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 2, 1, 0, 0);
1940 }
1941 }
1942
1943 /* Terminate the list */
1944 ServicePath[i] = NULL;
1945
1946 EndPath:
1947 /* Free the driver list if we had one */
1948 if (!IsListEmpty(&DriverList)) CmpFreeDriverList(Hive, &DriverList);
1949
1950 /* Unlock the registry */
1951 CmpUnlockRegistry();
1952
1953 /* Close the key handle and dereference the object, then return the path */
1954 ObDereferenceObject(KeyBody);
1955 NtClose(KeyHandle);
1956 return ServicePath;
1957 }
1958
1959 VOID
1960 NTAPI
CmpLockRegistryExclusive(VOID)1961 CmpLockRegistryExclusive(VOID)
1962 {
1963 /* Enter a critical region and lock the registry */
1964 KeEnterCriticalRegion();
1965 ExAcquireResourceExclusiveLite(&CmpRegistryLock, TRUE);
1966
1967 /* Sanity check */
1968 ASSERT(CmpFlushStarveWriters == 0);
1969 RtlGetCallersAddress(&CmpRegistryLockCaller, &CmpRegistryLockCallerCaller);
1970 }
1971
1972 VOID
1973 NTAPI
CmpLockRegistry(VOID)1974 CmpLockRegistry(VOID)
1975 {
1976 /* Enter a critical region */
1977 KeEnterCriticalRegion();
1978
1979 /* Check if we have to starve writers */
1980 if (CmpFlushStarveWriters)
1981 {
1982 /* Starve exlusive waiters */
1983 ExAcquireSharedStarveExclusive(&CmpRegistryLock, TRUE);
1984 }
1985 else
1986 {
1987 /* Just grab the lock */
1988 ExAcquireResourceSharedLite(&CmpRegistryLock, TRUE);
1989 }
1990 }
1991
1992 BOOLEAN
1993 NTAPI
CmpTestRegistryLock(VOID)1994 CmpTestRegistryLock(VOID)
1995 {
1996 /* Test the lock */
1997 return !ExIsResourceAcquiredSharedLite(&CmpRegistryLock) ? FALSE : TRUE;
1998 }
1999
2000 BOOLEAN
2001 NTAPI
CmpTestRegistryLockExclusive(VOID)2002 CmpTestRegistryLockExclusive(VOID)
2003 {
2004 /* Test the lock */
2005 return !ExIsResourceAcquiredExclusiveLite(&CmpRegistryLock) ? FALSE : TRUE;
2006 }
2007
2008 VOID
2009 NTAPI
CmpLockHiveFlusherExclusive(IN PCMHIVE Hive)2010 CmpLockHiveFlusherExclusive(IN PCMHIVE Hive)
2011 {
2012 /* Lock the flusher. We should already be in a critical section */
2013 CMP_ASSERT_REGISTRY_LOCK_OR_LOADING(Hive);
2014 ASSERT((ExIsResourceAcquiredShared(Hive->FlusherLock) == 0) &&
2015 (ExIsResourceAcquiredExclusiveLite(Hive->FlusherLock) == 0));
2016 ExAcquireResourceExclusiveLite(Hive->FlusherLock, TRUE);
2017 }
2018
2019 VOID
2020 NTAPI
CmpLockHiveFlusherShared(IN PCMHIVE Hive)2021 CmpLockHiveFlusherShared(IN PCMHIVE Hive)
2022 {
2023 /* Lock the flusher. We should already be in a critical section */
2024 CMP_ASSERT_REGISTRY_LOCK_OR_LOADING(Hive);
2025 ASSERT((ExIsResourceAcquiredShared(Hive->FlusherLock) == 0) &&
2026 (ExIsResourceAcquiredExclusiveLite(Hive->FlusherLock) == 0));
2027 ExAcquireResourceSharedLite(Hive->FlusherLock, TRUE);
2028 }
2029
2030 VOID
2031 NTAPI
CmpUnlockHiveFlusher(IN PCMHIVE Hive)2032 CmpUnlockHiveFlusher(IN PCMHIVE Hive)
2033 {
2034 /* Sanity check */
2035 CMP_ASSERT_REGISTRY_LOCK_OR_LOADING(Hive);
2036 CMP_ASSERT_FLUSH_LOCK(Hive);
2037
2038 /* Release the lock */
2039 ExReleaseResourceLite(Hive->FlusherLock);
2040 }
2041
2042 BOOLEAN
2043 NTAPI
CmpTestHiveFlusherLockShared(IN PCMHIVE Hive)2044 CmpTestHiveFlusherLockShared(IN PCMHIVE Hive)
2045 {
2046 /* Test the lock */
2047 return !ExIsResourceAcquiredSharedLite(Hive->FlusherLock) ? FALSE : TRUE;
2048 }
2049
2050 BOOLEAN
2051 NTAPI
CmpTestHiveFlusherLockExclusive(IN PCMHIVE Hive)2052 CmpTestHiveFlusherLockExclusive(IN PCMHIVE Hive)
2053 {
2054 /* Test the lock */
2055 return !ExIsResourceAcquiredExclusiveLite(Hive->FlusherLock) ? FALSE : TRUE;
2056 }
2057
2058 VOID
2059 NTAPI
CmpUnlockRegistry(VOID)2060 CmpUnlockRegistry(VOID)
2061 {
2062 /* Sanity check */
2063 CMP_ASSERT_REGISTRY_LOCK();
2064
2065 /* Check if we should flush the registry */
2066 if (CmpFlushOnLockRelease)
2067 {
2068 /* The registry should be exclusively locked for this */
2069 CMP_ASSERT_EXCLUSIVE_REGISTRY_LOCK();
2070
2071 /* Flush the registry */
2072 CmpDoFlushAll(TRUE);
2073 CmpFlushOnLockRelease = FALSE;
2074 }
2075
2076 /* Release the lock and leave the critical region */
2077 ExReleaseResourceLite(&CmpRegistryLock);
2078 KeLeaveCriticalRegion();
2079 }
2080
2081 VOID
2082 NTAPI
CmpAcquireTwoKcbLocksExclusiveByKey(IN ULONG ConvKey1,IN ULONG ConvKey2)2083 CmpAcquireTwoKcbLocksExclusiveByKey(IN ULONG ConvKey1,
2084 IN ULONG ConvKey2)
2085 {
2086 ULONG Index1, Index2;
2087
2088 /* Sanity check */
2089 CMP_ASSERT_REGISTRY_LOCK();
2090
2091 /* Get hash indexes */
2092 Index1 = GET_HASH_INDEX(ConvKey1);
2093 Index2 = GET_HASH_INDEX(ConvKey2);
2094
2095 /* See which one is highest */
2096 if (Index1 < Index2)
2097 {
2098 /* Grab them in the proper order */
2099 CmpAcquireKcbLockExclusiveByKey(ConvKey1);
2100 CmpAcquireKcbLockExclusiveByKey(ConvKey2);
2101 }
2102 else
2103 {
2104 /* Grab the second one first, then the first */
2105 CmpAcquireKcbLockExclusiveByKey(ConvKey2);
2106 if (Index1 != Index2) CmpAcquireKcbLockExclusiveByKey(ConvKey1);
2107 }
2108 }
2109
2110 VOID
2111 NTAPI
CmpReleaseTwoKcbLockByKey(IN ULONG ConvKey1,IN ULONG ConvKey2)2112 CmpReleaseTwoKcbLockByKey(IN ULONG ConvKey1,
2113 IN ULONG ConvKey2)
2114 {
2115 ULONG Index1, Index2;
2116
2117 /* Sanity check */
2118 CMP_ASSERT_REGISTRY_LOCK();
2119
2120 /* Get hash indexes */
2121 Index1 = GET_HASH_INDEX(ConvKey1);
2122 Index2 = GET_HASH_INDEX(ConvKey2);
2123 ASSERT((GET_HASH_ENTRY(CmpCacheTable, ConvKey2)->Owner == KeGetCurrentThread()) ||
2124 CmpTestRegistryLockExclusive());
2125
2126 /* See which one is highest */
2127 if (Index1 < Index2)
2128 {
2129 /* Grab them in the proper order */
2130 ASSERT((GET_HASH_ENTRY(CmpCacheTable, ConvKey1)->Owner == KeGetCurrentThread()) ||
2131 CmpTestRegistryLockExclusive());
2132 CmpReleaseKcbLockByKey(ConvKey2);
2133 CmpReleaseKcbLockByKey(ConvKey1);
2134 }
2135 else
2136 {
2137 /* Release the first one first, then the second */
2138 if (Index1 != Index2)
2139 {
2140 ASSERT((GET_HASH_ENTRY(CmpCacheTable, ConvKey1)->Owner == KeGetCurrentThread()) ||
2141 CmpTestRegistryLockExclusive());
2142 CmpReleaseKcbLockByKey(ConvKey1);
2143 }
2144 CmpReleaseKcbLockByKey(ConvKey2);
2145 }
2146 }
2147
2148 VOID
2149 NTAPI
CmShutdownSystem(VOID)2150 CmShutdownSystem(VOID)
2151 {
2152 PLIST_ENTRY ListEntry;
2153 PCMHIVE Hive;
2154
2155 /* Kill the workers */
2156 if (!CmFirstTime) CmpShutdownWorkers();
2157
2158 /* Flush all hives */
2159 CmpLockRegistryExclusive();
2160 CmpDoFlushAll(TRUE);
2161
2162 /* Close all hive files */
2163 ListEntry = CmpHiveListHead.Flink;
2164 while (ListEntry != &CmpHiveListHead)
2165 {
2166 Hive = CONTAINING_RECORD(ListEntry, CMHIVE, HiveList);
2167
2168 CmpCloseHiveFiles(Hive);
2169
2170 ListEntry = ListEntry->Flink;
2171 }
2172
2173 /*
2174 * As we flushed all the hives on the disk,
2175 * tell the system we do not want any further
2176 * registry flushing or syncing at this point
2177 * since we are shutting down the registry anyway.
2178 */
2179 HvShutdownComplete = TRUE;
2180
2181 CmpUnlockRegistry();
2182 }
2183
2184 VOID
2185 NTAPI
CmpSetVersionData(VOID)2186 CmpSetVersionData(VOID)
2187 {
2188 NTSTATUS Status;
2189 OBJECT_ATTRIBUTES ObjectAttributes;
2190 UNICODE_STRING KeyName;
2191 UNICODE_STRING ValueName;
2192 UNICODE_STRING ValueData;
2193 ANSI_STRING TempString;
2194 HANDLE SoftwareKeyHandle = NULL;
2195 HANDLE MicrosoftKeyHandle = NULL;
2196 HANDLE WindowsNtKeyHandle = NULL;
2197 HANDLE CurrentVersionKeyHandle = NULL;
2198 WCHAR Buffer[128]; // Buffer large enough to contain a full ULONG in decimal
2199 // representation, and the full 'CurrentType' string.
2200
2201 /*
2202 * Open the 'HKLM\Software\Microsoft\Windows NT\CurrentVersion' key
2203 * (create the intermediate subkeys if needed).
2204 */
2205
2206 RtlInitUnicodeString(&KeyName, L"\\REGISTRY\\MACHINE\\SOFTWARE");
2207 InitializeObjectAttributes(&ObjectAttributes,
2208 &KeyName,
2209 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
2210 NULL,
2211 NULL);
2212 Status = NtCreateKey(&SoftwareKeyHandle,
2213 KEY_CREATE_SUB_KEY,
2214 &ObjectAttributes,
2215 0,
2216 NULL,
2217 0,
2218 NULL);
2219 if (!NT_SUCCESS(Status))
2220 {
2221 DPRINT1("Failed to create key %wZ (Status: %08lx)\n", &KeyName, Status);
2222 return;
2223 }
2224
2225 RtlInitUnicodeString(&KeyName, L"Microsoft");
2226 InitializeObjectAttributes(&ObjectAttributes,
2227 &KeyName,
2228 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
2229 SoftwareKeyHandle,
2230 NULL);
2231 Status = NtCreateKey(&MicrosoftKeyHandle,
2232 KEY_CREATE_SUB_KEY,
2233 &ObjectAttributes,
2234 0,
2235 NULL,
2236 0,
2237 NULL);
2238 if (!NT_SUCCESS(Status))
2239 {
2240 DPRINT1("Failed to create key %wZ (Status: %08lx)\n", &KeyName, Status);
2241 goto Quit;
2242 }
2243
2244 RtlInitUnicodeString(&KeyName, L"Windows NT");
2245 InitializeObjectAttributes(&ObjectAttributes,
2246 &KeyName,
2247 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
2248 MicrosoftKeyHandle,
2249 NULL);
2250 Status = NtCreateKey(&WindowsNtKeyHandle,
2251 KEY_CREATE_SUB_KEY,
2252 &ObjectAttributes,
2253 0,
2254 NULL,
2255 0,
2256 NULL);
2257 if (!NT_SUCCESS(Status))
2258 {
2259 DPRINT1("Failed to create key %wZ (Status: %08lx)\n", &KeyName, Status);
2260 goto Quit;
2261 }
2262
2263 RtlInitUnicodeString(&KeyName, L"CurrentVersion");
2264 InitializeObjectAttributes(&ObjectAttributes,
2265 &KeyName,
2266 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
2267 WindowsNtKeyHandle,
2268 NULL);
2269 Status = NtCreateKey(&CurrentVersionKeyHandle,
2270 KEY_CREATE_SUB_KEY | KEY_SET_VALUE,
2271 &ObjectAttributes,
2272 0,
2273 NULL,
2274 0,
2275 NULL);
2276 if (!NT_SUCCESS(Status))
2277 {
2278 DPRINT1("Failed to create key %wZ (Status: %08lx)\n", &KeyName, Status);
2279 goto Quit;
2280 }
2281
2282 /* Set the 'CurrentVersion' value */
2283 RtlInitUnicodeString(&ValueName, L"CurrentVersion");
2284 NtSetValueKey(CurrentVersionKeyHandle,
2285 &ValueName,
2286 0,
2287 REG_SZ,
2288 CmVersionString.Buffer,
2289 CmVersionString.Length + sizeof(WCHAR));
2290
2291 /* Set the 'CurrentBuildNumber' value */
2292 RtlInitUnicodeString(&ValueName, L"CurrentBuildNumber");
2293 RtlInitEmptyUnicodeString(&ValueData, Buffer, sizeof(Buffer));
2294 RtlIntegerToUnicodeString(NtBuildNumber & 0xFFFF, 10, &ValueData);
2295 NtSetValueKey(CurrentVersionKeyHandle,
2296 &ValueName,
2297 0,
2298 REG_SZ,
2299 ValueData.Buffer,
2300 ValueData.Length + sizeof(WCHAR));
2301
2302 /* Set the 'BuildLab' value */
2303 RtlInitUnicodeString(&ValueName, L"BuildLab");
2304 RtlInitAnsiString(&TempString, NtBuildLab);
2305 Status = RtlAnsiStringToUnicodeString(&ValueData, &TempString, FALSE);
2306 if (NT_SUCCESS(Status))
2307 {
2308 NtSetValueKey(CurrentVersionKeyHandle,
2309 &ValueName,
2310 0,
2311 REG_SZ,
2312 ValueData.Buffer,
2313 ValueData.Length + sizeof(WCHAR));
2314 }
2315
2316 /* Set the 'CurrentType' value */
2317 RtlInitUnicodeString(&ValueName, L"CurrentType");
2318 RtlStringCbPrintfW(Buffer, sizeof(Buffer),
2319 L"%s %s",
2320 #ifdef CONFIG_SMP
2321 L"Multiprocessor"
2322 #else
2323 L"Uniprocessor"
2324 #endif
2325 ,
2326 #if (DBG == 1)
2327 L"Checked"
2328 #else
2329 L"Free"
2330 #endif
2331 );
2332 RtlInitUnicodeString(&ValueData, Buffer);
2333 NtSetValueKey(CurrentVersionKeyHandle,
2334 &ValueName,
2335 0,
2336 REG_SZ,
2337 ValueData.Buffer,
2338 ValueData.Length + sizeof(WCHAR));
2339
2340 /* Set the 'CSDVersion' value */
2341 RtlInitUnicodeString(&ValueName, L"CSDVersion");
2342 if (CmCSDVersionString.Length != 0)
2343 {
2344 NtSetValueKey(CurrentVersionKeyHandle,
2345 &ValueName,
2346 0,
2347 REG_SZ,
2348 CmCSDVersionString.Buffer,
2349 CmCSDVersionString.Length + sizeof(WCHAR));
2350 }
2351 else
2352 {
2353 NtDeleteValueKey(CurrentVersionKeyHandle, &ValueName);
2354 }
2355
2356 /* Set the 'CSDBuildNumber' value */
2357 RtlInitUnicodeString(&ValueName, L"CSDBuildNumber");
2358 if (CmNtSpBuildNumber != 0)
2359 {
2360 RtlInitEmptyUnicodeString(&ValueData, Buffer, sizeof(Buffer));
2361 RtlIntegerToUnicodeString(CmNtSpBuildNumber, 10, &ValueData);
2362 NtSetValueKey(CurrentVersionKeyHandle,
2363 &ValueName,
2364 0,
2365 REG_SZ,
2366 ValueData.Buffer,
2367 ValueData.Length + sizeof(WCHAR));
2368 }
2369 else
2370 {
2371 NtDeleteValueKey(CurrentVersionKeyHandle, &ValueName);
2372 }
2373
2374 /* Set the 'SystemRoot' value */
2375 RtlInitUnicodeString(&ValueName, L"SystemRoot");
2376 NtSetValueKey(CurrentVersionKeyHandle,
2377 &ValueName,
2378 0,
2379 REG_SZ,
2380 NtSystemRoot.Buffer,
2381 NtSystemRoot.Length + sizeof(WCHAR));
2382
2383 Quit:
2384 /* Close the keys */
2385 if (CurrentVersionKeyHandle != NULL)
2386 NtClose(CurrentVersionKeyHandle);
2387
2388 if (WindowsNtKeyHandle != NULL)
2389 NtClose(WindowsNtKeyHandle);
2390
2391 if (MicrosoftKeyHandle != NULL)
2392 NtClose(MicrosoftKeyHandle);
2393
2394 if (SoftwareKeyHandle != NULL)
2395 NtClose(SoftwareKeyHandle);
2396 }
2397
2398 /* EOF */
2399