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