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 sucessful */
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
1639 /* Initialize the hive list and lock */
1640 InitializeListHead(&CmpHiveListHead);
1641 ExInitializePushLock(&CmpHiveListHeadLock);
1642 ExInitializePushLock(&CmpLoadHiveLock);
1643
1644 /* Initialize registry lock */
1645 ExInitializeResourceLite(&CmpRegistryLock);
1646
1647 /* Initialize the cache */
1648 CmpInitializeCache();
1649
1650 /* Initialize allocation and delayed dereferencing */
1651 CmpInitCmPrivateAlloc();
1652 CmpInitCmPrivateDelayAlloc();
1653 CmpInitDelayDerefKCBEngine();
1654
1655 /* Initialize callbacks */
1656 CmpInitCallback();
1657
1658 /* Initialize self healing */
1659 KeInitializeGuardedMutex(&CmpSelfHealQueueLock);
1660 InitializeListHead(&CmpSelfHealQueueListHead);
1661
1662 /* Save the current process and lock the registry */
1663 CmpSystemProcess = PsGetCurrentProcess();
1664
1665 /* Create the key object types */
1666 Status = CmpCreateObjectTypes();
1667 if (!NT_SUCCESS(Status))
1668 {
1669 /* Bugcheck */
1670 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 1, Status, 0);
1671 }
1672
1673 /* Build the master hive */
1674 Status = CmpInitializeHive(&CmiVolatileHive,
1675 HINIT_CREATE,
1676 HIVE_VOLATILE,
1677 HFILE_TYPE_PRIMARY,
1678 NULL,
1679 NULL,
1680 NULL,
1681 NULL,
1682 NULL,
1683 NULL,
1684 CM_CHECK_REGISTRY_DONT_PURGE_VOLATILES);
1685 if (!NT_SUCCESS(Status))
1686 {
1687 /* Bugcheck */
1688 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 2, Status, 0);
1689 }
1690
1691 /* Create the \REGISTRY key node */
1692 if (!CmpCreateRegistryRoot())
1693 {
1694 /* Bugcheck */
1695 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 3, 0, 0);
1696 }
1697
1698 /* Create the default security descriptor */
1699 SecurityDescriptor = CmpHiveRootSecurityDescriptor();
1700
1701 /* Create '\Registry\Machine' key */
1702 RtlInitUnicodeString(&KeyName, L"\\REGISTRY\\MACHINE");
1703 InitializeObjectAttributes(&ObjectAttributes,
1704 &KeyName,
1705 OBJ_CASE_INSENSITIVE,
1706 NULL,
1707 SecurityDescriptor);
1708 Status = NtCreateKey(&KeyHandle,
1709 KEY_READ | KEY_WRITE,
1710 &ObjectAttributes,
1711 0,
1712 NULL,
1713 0,
1714 NULL);
1715 if (!NT_SUCCESS(Status))
1716 {
1717 /* Bugcheck */
1718 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 5, Status, 0);
1719 }
1720
1721 /* Close the handle */
1722 NtClose(KeyHandle);
1723
1724 /* Create '\Registry\User' key */
1725 RtlInitUnicodeString(&KeyName, L"\\REGISTRY\\USER");
1726 InitializeObjectAttributes(&ObjectAttributes,
1727 &KeyName,
1728 OBJ_CASE_INSENSITIVE,
1729 NULL,
1730 SecurityDescriptor);
1731 Status = NtCreateKey(&KeyHandle,
1732 KEY_READ | KEY_WRITE,
1733 &ObjectAttributes,
1734 0,
1735 NULL,
1736 0,
1737 NULL);
1738 if (!NT_SUCCESS(Status))
1739 {
1740 /* Bugcheck */
1741 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 6, Status, 0);
1742 }
1743
1744 /* Close the handle */
1745 NtClose(KeyHandle);
1746
1747 /* After this point, do not allow creating keys in the master hive */
1748 CmpNoVolatileCreates = TRUE;
1749
1750 /* Initialize the system hive */
1751 if (!CmpInitializeSystemHive(KeLoaderBlock))
1752 {
1753 /* Bugcheck */
1754 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 7, 0, 0);
1755 }
1756
1757 /* Create the 'CurrentControlSet' link */
1758 Status = CmpCreateControlSet(KeLoaderBlock);
1759 if (!NT_SUCCESS(Status))
1760 {
1761 /* Bugcheck */
1762 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 8, Status, 0);
1763 }
1764
1765 /* Create the hardware hive */
1766 Status = CmpInitializeHive(&HardwareHive,
1767 HINIT_CREATE,
1768 HIVE_VOLATILE,
1769 HFILE_TYPE_PRIMARY,
1770 NULL,
1771 NULL,
1772 NULL,
1773 NULL,
1774 NULL,
1775 NULL,
1776 CM_CHECK_REGISTRY_DONT_PURGE_VOLATILES);
1777 if (!NT_SUCCESS(Status))
1778 {
1779 /* Bugcheck */
1780 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 11, Status, 0);
1781 }
1782
1783 /* Add the hive to the hive list */
1784 CmpMachineHiveList[0].CmHive = HardwareHive;
1785
1786 /* Attach it to the machine key */
1787 RtlInitUnicodeString(&KeyName, L"\\Registry\\Machine\\HARDWARE");
1788 Status = CmpLinkHiveToMaster(&KeyName,
1789 NULL,
1790 HardwareHive,
1791 TRUE,
1792 SecurityDescriptor);
1793 if (!NT_SUCCESS(Status))
1794 {
1795 /* Bugcheck */
1796 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 12, Status, 0);
1797 }
1798
1799 /* Add to HiveList key */
1800 CmpAddToHiveFileList(HardwareHive);
1801
1802 /* Free the security descriptor */
1803 ExFreePoolWithTag(SecurityDescriptor, TAG_CMSD);
1804
1805 /* Fill out the Hardware key with the ARC Data from the Loader */
1806 Status = CmpInitializeHardwareConfiguration(KeLoaderBlock);
1807 if (!NT_SUCCESS(Status))
1808 {
1809 /* Bugcheck */
1810 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 13, Status, 0);
1811 }
1812
1813 /* Initialize machine-dependent information into the registry */
1814 Status = CmpInitializeMachineDependentConfiguration(KeLoaderBlock);
1815 if (!NT_SUCCESS(Status))
1816 {
1817 /* Bugcheck */
1818 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 14, Status, 0);
1819 }
1820
1821 /* Initialize volatile registry settings */
1822 Status = CmpSetSystemValues(KeLoaderBlock);
1823 if (!NT_SUCCESS(Status))
1824 {
1825 /* Bugcheck */
1826 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 15, Status, 0);
1827 }
1828
1829 /* Free the load options */
1830 ExFreePoolWithTag(CmpLoadOptions.Buffer, TAG_CM);
1831
1832 /* If we got here, all went well */
1833 return TRUE;
1834 }
1835
1836 CODE_SEG("INIT")
1837 PUNICODE_STRING*
1838 NTAPI
CmGetSystemDriverList(VOID)1839 CmGetSystemDriverList(VOID)
1840 {
1841 LIST_ENTRY DriverList;
1842 OBJECT_ATTRIBUTES ObjectAttributes;
1843 NTSTATUS Status;
1844 PCM_KEY_BODY KeyBody;
1845 PHHIVE Hive;
1846 HCELL_INDEX RootCell, ControlCell;
1847 HANDLE KeyHandle;
1848 UNICODE_STRING KeyName;
1849 PLIST_ENTRY NextEntry;
1850 ULONG i;
1851 PUNICODE_STRING* ServicePath = NULL;
1852 BOOLEAN Success, AutoSelect;
1853 PBOOT_DRIVER_LIST_ENTRY DriverEntry;
1854 PAGED_CODE();
1855
1856 /* Initialize the driver list */
1857 InitializeListHead(&DriverList);
1858
1859 /* Open the system hive key */
1860 RtlInitUnicodeString(&KeyName, L"\\Registry\\Machine\\System");
1861 InitializeObjectAttributes(&ObjectAttributes,
1862 &KeyName,
1863 OBJ_CASE_INSENSITIVE,
1864 NULL,
1865 NULL);
1866 Status = NtOpenKey(&KeyHandle, KEY_READ, &ObjectAttributes);
1867 if (!NT_SUCCESS(Status)) return NULL;
1868
1869 /* Reference the key object to get the root hive/cell to access directly */
1870 Status = ObReferenceObjectByHandle(KeyHandle,
1871 KEY_QUERY_VALUE,
1872 CmpKeyObjectType,
1873 KernelMode,
1874 (PVOID*)&KeyBody,
1875 NULL);
1876 if (!NT_SUCCESS(Status))
1877 {
1878 /* Fail */
1879 NtClose(KeyHandle);
1880 return NULL;
1881 }
1882
1883 /* Do all this under the registry lock */
1884 CmpLockRegistryExclusive();
1885
1886 /* Get the hive and key cell */
1887 Hive = KeyBody->KeyControlBlock->KeyHive;
1888 RootCell = KeyBody->KeyControlBlock->KeyCell;
1889
1890 /* Open the current control set key */
1891 RtlInitUnicodeString(&KeyName, L"Current");
1892 ControlCell = CmpFindControlSet(Hive, RootCell, &KeyName, &AutoSelect);
1893 if (ControlCell == HCELL_NIL) goto EndPath;
1894
1895 /* Find all system drivers */
1896 Success = CmpFindDrivers(Hive, ControlCell, SystemLoad, NULL, &DriverList);
1897 if (!Success) goto EndPath;
1898
1899 /* Sort by group/tag */
1900 if (!CmpSortDriverList(Hive, ControlCell, &DriverList)) goto EndPath;
1901
1902 /* Remove circular dependencies (cycles) and sort */
1903 if (!CmpResolveDriverDependencies(&DriverList)) goto EndPath;
1904
1905 /* Loop the list to count drivers */
1906 for (i = 0, NextEntry = DriverList.Flink;
1907 NextEntry != &DriverList;
1908 i++, NextEntry = NextEntry->Flink);
1909
1910 /* Allocate the array */
1911 ServicePath = ExAllocatePool(NonPagedPool, (i + 1) * sizeof(PUNICODE_STRING));
1912 if (!ServicePath) KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 2, 1, 0, 0);
1913
1914 /* Loop the driver list */
1915 for (i = 0, NextEntry = DriverList.Flink;
1916 NextEntry != &DriverList;
1917 i++, NextEntry = NextEntry->Flink)
1918 {
1919 /* Get the entry */
1920 DriverEntry = CONTAINING_RECORD(NextEntry, BOOT_DRIVER_LIST_ENTRY, Link);
1921
1922 /* Allocate the path for the caller */
1923 ServicePath[i] = ExAllocatePool(NonPagedPool, sizeof(UNICODE_STRING));
1924 if (!ServicePath[i])
1925 {
1926 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 2, 1, 0, 0);
1927 }
1928
1929 /* Duplicate the registry path */
1930 Status = RtlDuplicateUnicodeString(RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE,
1931 &DriverEntry->RegistryPath,
1932 ServicePath[i]);
1933 if (!NT_SUCCESS(Status))
1934 {
1935 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 2, 1, 0, 0);
1936 }
1937 }
1938
1939 /* Terminate the list */
1940 ServicePath[i] = NULL;
1941
1942 EndPath:
1943 /* Free the driver list if we had one */
1944 if (!IsListEmpty(&DriverList)) CmpFreeDriverList(Hive, &DriverList);
1945
1946 /* Unlock the registry */
1947 CmpUnlockRegistry();
1948
1949 /* Close the key handle and dereference the object, then return the path */
1950 ObDereferenceObject(KeyBody);
1951 NtClose(KeyHandle);
1952 return ServicePath;
1953 }
1954
1955 VOID
1956 NTAPI
CmpLockRegistryExclusive(VOID)1957 CmpLockRegistryExclusive(VOID)
1958 {
1959 /* Enter a critical region and lock the registry */
1960 KeEnterCriticalRegion();
1961 ExAcquireResourceExclusiveLite(&CmpRegistryLock, TRUE);
1962
1963 /* Sanity check */
1964 ASSERT(CmpFlushStarveWriters == 0);
1965 RtlGetCallersAddress(&CmpRegistryLockCaller, &CmpRegistryLockCallerCaller);
1966 }
1967
1968 VOID
1969 NTAPI
CmpLockRegistry(VOID)1970 CmpLockRegistry(VOID)
1971 {
1972 /* Enter a critical region */
1973 KeEnterCriticalRegion();
1974
1975 /* Check if we have to starve writers */
1976 if (CmpFlushStarveWriters)
1977 {
1978 /* Starve exlusive waiters */
1979 ExAcquireSharedStarveExclusive(&CmpRegistryLock, TRUE);
1980 }
1981 else
1982 {
1983 /* Just grab the lock */
1984 ExAcquireResourceSharedLite(&CmpRegistryLock, TRUE);
1985 }
1986 }
1987
1988 BOOLEAN
1989 NTAPI
CmpTestRegistryLock(VOID)1990 CmpTestRegistryLock(VOID)
1991 {
1992 /* Test the lock */
1993 return !ExIsResourceAcquiredSharedLite(&CmpRegistryLock) ? FALSE : TRUE;
1994 }
1995
1996 BOOLEAN
1997 NTAPI
CmpTestRegistryLockExclusive(VOID)1998 CmpTestRegistryLockExclusive(VOID)
1999 {
2000 /* Test the lock */
2001 return !ExIsResourceAcquiredExclusiveLite(&CmpRegistryLock) ? FALSE : TRUE;
2002 }
2003
2004 VOID
2005 NTAPI
CmpLockHiveFlusherExclusive(IN PCMHIVE Hive)2006 CmpLockHiveFlusherExclusive(IN PCMHIVE Hive)
2007 {
2008 /* Lock the flusher. We should already be in a critical section */
2009 CMP_ASSERT_REGISTRY_LOCK_OR_LOADING(Hive);
2010 ASSERT((ExIsResourceAcquiredShared(Hive->FlusherLock) == 0) &&
2011 (ExIsResourceAcquiredExclusiveLite(Hive->FlusherLock) == 0));
2012 ExAcquireResourceExclusiveLite(Hive->FlusherLock, TRUE);
2013 }
2014
2015 VOID
2016 NTAPI
CmpLockHiveFlusherShared(IN PCMHIVE Hive)2017 CmpLockHiveFlusherShared(IN PCMHIVE Hive)
2018 {
2019 /* Lock the flusher. We should already be in a critical section */
2020 CMP_ASSERT_REGISTRY_LOCK_OR_LOADING(Hive);
2021 ASSERT((ExIsResourceAcquiredShared(Hive->FlusherLock) == 0) &&
2022 (ExIsResourceAcquiredExclusiveLite(Hive->FlusherLock) == 0));
2023 ExAcquireResourceSharedLite(Hive->FlusherLock, TRUE);
2024 }
2025
2026 VOID
2027 NTAPI
CmpUnlockHiveFlusher(IN PCMHIVE Hive)2028 CmpUnlockHiveFlusher(IN PCMHIVE Hive)
2029 {
2030 /* Sanity check */
2031 CMP_ASSERT_REGISTRY_LOCK_OR_LOADING(Hive);
2032 CMP_ASSERT_FLUSH_LOCK(Hive);
2033
2034 /* Release the lock */
2035 ExReleaseResourceLite(Hive->FlusherLock);
2036 }
2037
2038 BOOLEAN
2039 NTAPI
CmpTestHiveFlusherLockShared(IN PCMHIVE Hive)2040 CmpTestHiveFlusherLockShared(IN PCMHIVE Hive)
2041 {
2042 /* Test the lock */
2043 return !ExIsResourceAcquiredSharedLite(Hive->FlusherLock) ? FALSE : TRUE;
2044 }
2045
2046 BOOLEAN
2047 NTAPI
CmpTestHiveFlusherLockExclusive(IN PCMHIVE Hive)2048 CmpTestHiveFlusherLockExclusive(IN PCMHIVE Hive)
2049 {
2050 /* Test the lock */
2051 return !ExIsResourceAcquiredExclusiveLite(Hive->FlusherLock) ? FALSE : TRUE;
2052 }
2053
2054 VOID
2055 NTAPI
CmpUnlockRegistry(VOID)2056 CmpUnlockRegistry(VOID)
2057 {
2058 /* Sanity check */
2059 CMP_ASSERT_REGISTRY_LOCK();
2060
2061 /* Check if we should flush the registry */
2062 if (CmpFlushOnLockRelease)
2063 {
2064 /* The registry should be exclusively locked for this */
2065 CMP_ASSERT_EXCLUSIVE_REGISTRY_LOCK();
2066
2067 /* Flush the registry */
2068 CmpDoFlushAll(TRUE);
2069 CmpFlushOnLockRelease = FALSE;
2070 }
2071
2072 /* Release the lock and leave the critical region */
2073 ExReleaseResourceLite(&CmpRegistryLock);
2074 KeLeaveCriticalRegion();
2075 }
2076
2077 VOID
2078 NTAPI
CmpAcquireTwoKcbLocksExclusiveByKey(IN ULONG ConvKey1,IN ULONG ConvKey2)2079 CmpAcquireTwoKcbLocksExclusiveByKey(IN ULONG ConvKey1,
2080 IN ULONG ConvKey2)
2081 {
2082 ULONG Index1, Index2;
2083
2084 /* Sanity check */
2085 CMP_ASSERT_REGISTRY_LOCK();
2086
2087 /* Get hash indexes */
2088 Index1 = GET_HASH_INDEX(ConvKey1);
2089 Index2 = GET_HASH_INDEX(ConvKey2);
2090
2091 /* See which one is highest */
2092 if (Index1 < Index2)
2093 {
2094 /* Grab them in the proper order */
2095 CmpAcquireKcbLockExclusiveByKey(ConvKey1);
2096 CmpAcquireKcbLockExclusiveByKey(ConvKey2);
2097 }
2098 else
2099 {
2100 /* Grab the second one first, then the first */
2101 CmpAcquireKcbLockExclusiveByKey(ConvKey2);
2102 if (Index1 != Index2) CmpAcquireKcbLockExclusiveByKey(ConvKey1);
2103 }
2104 }
2105
2106 VOID
2107 NTAPI
CmpReleaseTwoKcbLockByKey(IN ULONG ConvKey1,IN ULONG ConvKey2)2108 CmpReleaseTwoKcbLockByKey(IN ULONG ConvKey1,
2109 IN ULONG ConvKey2)
2110 {
2111 ULONG Index1, Index2;
2112
2113 /* Sanity check */
2114 CMP_ASSERT_REGISTRY_LOCK();
2115
2116 /* Get hash indexes */
2117 Index1 = GET_HASH_INDEX(ConvKey1);
2118 Index2 = GET_HASH_INDEX(ConvKey2);
2119 ASSERT((GET_HASH_ENTRY(CmpCacheTable, ConvKey2)->Owner == KeGetCurrentThread()) ||
2120 CmpTestRegistryLockExclusive());
2121
2122 /* See which one is highest */
2123 if (Index1 < Index2)
2124 {
2125 /* Grab them in the proper order */
2126 ASSERT((GET_HASH_ENTRY(CmpCacheTable, ConvKey1)->Owner == KeGetCurrentThread()) ||
2127 CmpTestRegistryLockExclusive());
2128 CmpReleaseKcbLockByKey(ConvKey2);
2129 CmpReleaseKcbLockByKey(ConvKey1);
2130 }
2131 else
2132 {
2133 /* Release the first one first, then the second */
2134 if (Index1 != Index2)
2135 {
2136 ASSERT((GET_HASH_ENTRY(CmpCacheTable, ConvKey1)->Owner == KeGetCurrentThread()) ||
2137 CmpTestRegistryLockExclusive());
2138 CmpReleaseKcbLockByKey(ConvKey1);
2139 }
2140 CmpReleaseKcbLockByKey(ConvKey2);
2141 }
2142 }
2143
2144 VOID
2145 NTAPI
CmShutdownSystem(VOID)2146 CmShutdownSystem(VOID)
2147 {
2148 PLIST_ENTRY ListEntry;
2149 PCMHIVE Hive;
2150
2151 /* Kill the workers */
2152 if (!CmFirstTime) CmpShutdownWorkers();
2153
2154 /* Flush all hives */
2155 CmpLockRegistryExclusive();
2156 CmpDoFlushAll(TRUE);
2157
2158 /* Close all hive files */
2159 ListEntry = CmpHiveListHead.Flink;
2160 while (ListEntry != &CmpHiveListHead)
2161 {
2162 Hive = CONTAINING_RECORD(ListEntry, CMHIVE, HiveList);
2163
2164 CmpCloseHiveFiles(Hive);
2165
2166 ListEntry = ListEntry->Flink;
2167 }
2168
2169 /*
2170 * As we flushed all the hives on the disk,
2171 * tell the system we do not want any further
2172 * registry flushing or syncing at this point
2173 * since we are shutting down the registry anyway.
2174 */
2175 HvShutdownComplete = TRUE;
2176
2177 CmpUnlockRegistry();
2178 }
2179
2180 VOID
2181 NTAPI
CmpSetVersionData(VOID)2182 CmpSetVersionData(VOID)
2183 {
2184 NTSTATUS Status;
2185 OBJECT_ATTRIBUTES ObjectAttributes;
2186 UNICODE_STRING KeyName;
2187 UNICODE_STRING ValueName;
2188 UNICODE_STRING ValueData;
2189 ANSI_STRING TempString;
2190 HANDLE SoftwareKeyHandle = NULL;
2191 HANDLE MicrosoftKeyHandle = NULL;
2192 HANDLE WindowsNtKeyHandle = NULL;
2193 HANDLE CurrentVersionKeyHandle = NULL;
2194 WCHAR Buffer[128]; // Buffer large enough to contain a full ULONG in decimal
2195 // representation, and the full 'CurrentType' string.
2196
2197 /*
2198 * Open the 'HKLM\Software\Microsoft\Windows NT\CurrentVersion' key
2199 * (create the intermediate subkeys if needed).
2200 */
2201
2202 RtlInitUnicodeString(&KeyName, L"\\REGISTRY\\MACHINE\\SOFTWARE");
2203 InitializeObjectAttributes(&ObjectAttributes,
2204 &KeyName,
2205 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
2206 NULL,
2207 NULL);
2208 Status = NtCreateKey(&SoftwareKeyHandle,
2209 KEY_CREATE_SUB_KEY,
2210 &ObjectAttributes,
2211 0,
2212 NULL,
2213 0,
2214 NULL);
2215 if (!NT_SUCCESS(Status))
2216 {
2217 DPRINT1("Failed to create key %wZ (Status: %08lx)\n", &KeyName, Status);
2218 return;
2219 }
2220
2221 RtlInitUnicodeString(&KeyName, L"Microsoft");
2222 InitializeObjectAttributes(&ObjectAttributes,
2223 &KeyName,
2224 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
2225 SoftwareKeyHandle,
2226 NULL);
2227 Status = NtCreateKey(&MicrosoftKeyHandle,
2228 KEY_CREATE_SUB_KEY,
2229 &ObjectAttributes,
2230 0,
2231 NULL,
2232 0,
2233 NULL);
2234 if (!NT_SUCCESS(Status))
2235 {
2236 DPRINT1("Failed to create key %wZ (Status: %08lx)\n", &KeyName, Status);
2237 goto Quit;
2238 }
2239
2240 RtlInitUnicodeString(&KeyName, L"Windows NT");
2241 InitializeObjectAttributes(&ObjectAttributes,
2242 &KeyName,
2243 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
2244 MicrosoftKeyHandle,
2245 NULL);
2246 Status = NtCreateKey(&WindowsNtKeyHandle,
2247 KEY_CREATE_SUB_KEY,
2248 &ObjectAttributes,
2249 0,
2250 NULL,
2251 0,
2252 NULL);
2253 if (!NT_SUCCESS(Status))
2254 {
2255 DPRINT1("Failed to create key %wZ (Status: %08lx)\n", &KeyName, Status);
2256 goto Quit;
2257 }
2258
2259 RtlInitUnicodeString(&KeyName, L"CurrentVersion");
2260 InitializeObjectAttributes(&ObjectAttributes,
2261 &KeyName,
2262 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
2263 WindowsNtKeyHandle,
2264 NULL);
2265 Status = NtCreateKey(&CurrentVersionKeyHandle,
2266 KEY_CREATE_SUB_KEY | KEY_SET_VALUE,
2267 &ObjectAttributes,
2268 0,
2269 NULL,
2270 0,
2271 NULL);
2272 if (!NT_SUCCESS(Status))
2273 {
2274 DPRINT1("Failed to create key %wZ (Status: %08lx)\n", &KeyName, Status);
2275 goto Quit;
2276 }
2277
2278 /* Set the 'CurrentVersion' value */
2279 RtlInitUnicodeString(&ValueName, L"CurrentVersion");
2280 NtSetValueKey(CurrentVersionKeyHandle,
2281 &ValueName,
2282 0,
2283 REG_SZ,
2284 CmVersionString.Buffer,
2285 CmVersionString.Length + sizeof(WCHAR));
2286
2287 /* Set the 'CurrentBuildNumber' value */
2288 RtlInitUnicodeString(&ValueName, L"CurrentBuildNumber");
2289 RtlInitEmptyUnicodeString(&ValueData, Buffer, sizeof(Buffer));
2290 RtlIntegerToUnicodeString(NtBuildNumber & 0xFFFF, 10, &ValueData);
2291 NtSetValueKey(CurrentVersionKeyHandle,
2292 &ValueName,
2293 0,
2294 REG_SZ,
2295 ValueData.Buffer,
2296 ValueData.Length + sizeof(WCHAR));
2297
2298 /* Set the 'BuildLab' value */
2299 RtlInitUnicodeString(&ValueName, L"BuildLab");
2300 RtlInitAnsiString(&TempString, NtBuildLab);
2301 Status = RtlAnsiStringToUnicodeString(&ValueData, &TempString, FALSE);
2302 if (NT_SUCCESS(Status))
2303 {
2304 NtSetValueKey(CurrentVersionKeyHandle,
2305 &ValueName,
2306 0,
2307 REG_SZ,
2308 ValueData.Buffer,
2309 ValueData.Length + sizeof(WCHAR));
2310 }
2311
2312 /* Set the 'CurrentType' value */
2313 RtlInitUnicodeString(&ValueName, L"CurrentType");
2314 RtlStringCbPrintfW(Buffer, sizeof(Buffer),
2315 L"%s %s",
2316 #ifdef CONFIG_SMP
2317 L"Multiprocessor"
2318 #else
2319 L"Uniprocessor"
2320 #endif
2321 ,
2322 #if (DBG == 1)
2323 L"Checked"
2324 #else
2325 L"Free"
2326 #endif
2327 );
2328 RtlInitUnicodeString(&ValueData, Buffer);
2329 NtSetValueKey(CurrentVersionKeyHandle,
2330 &ValueName,
2331 0,
2332 REG_SZ,
2333 ValueData.Buffer,
2334 ValueData.Length + sizeof(WCHAR));
2335
2336 /* Set the 'CSDVersion' value */
2337 RtlInitUnicodeString(&ValueName, L"CSDVersion");
2338 if (CmCSDVersionString.Length != 0)
2339 {
2340 NtSetValueKey(CurrentVersionKeyHandle,
2341 &ValueName,
2342 0,
2343 REG_SZ,
2344 CmCSDVersionString.Buffer,
2345 CmCSDVersionString.Length + sizeof(WCHAR));
2346 }
2347 else
2348 {
2349 NtDeleteValueKey(CurrentVersionKeyHandle, &ValueName);
2350 }
2351
2352 /* Set the 'CSDBuildNumber' value */
2353 RtlInitUnicodeString(&ValueName, L"CSDBuildNumber");
2354 if (CmNtSpBuildNumber != 0)
2355 {
2356 RtlInitEmptyUnicodeString(&ValueData, Buffer, sizeof(Buffer));
2357 RtlIntegerToUnicodeString(CmNtSpBuildNumber, 10, &ValueData);
2358 NtSetValueKey(CurrentVersionKeyHandle,
2359 &ValueName,
2360 0,
2361 REG_SZ,
2362 ValueData.Buffer,
2363 ValueData.Length + sizeof(WCHAR));
2364 }
2365 else
2366 {
2367 NtDeleteValueKey(CurrentVersionKeyHandle, &ValueName);
2368 }
2369
2370 /* Set the 'SystemRoot' value */
2371 RtlInitUnicodeString(&ValueName, L"SystemRoot");
2372 NtSetValueKey(CurrentVersionKeyHandle,
2373 &ValueName,
2374 0,
2375 REG_SZ,
2376 NtSystemRoot.Buffer,
2377 NtSystemRoot.Length + sizeof(WCHAR));
2378
2379 Quit:
2380 /* Close the keys */
2381 if (CurrentVersionKeyHandle != NULL)
2382 NtClose(CurrentVersionKeyHandle);
2383
2384 if (WindowsNtKeyHandle != NULL)
2385 NtClose(WindowsNtKeyHandle);
2386
2387 if (MicrosoftKeyHandle != NULL)
2388 NtClose(MicrosoftKeyHandle);
2389
2390 if (SoftwareKeyHandle != NULL)
2391 NtClose(SoftwareKeyHandle);
2392 }
2393
2394 /* EOF */
2395