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