b95610552a31ab93bed3b8c626bdd051e34442e3
[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 PAGED_CODE();
876
877 /* Setup the ansi string */
878 RtlInitAnsiString(&LoadString, LoaderBlock->LoadOptions);
879
880 /* Allocate the unicode buffer */
881 Length = LoadString.Length * sizeof(WCHAR) + sizeof(UNICODE_NULL);
882 Buffer = ExAllocatePoolWithTag(PagedPool, Length, TAG_CM);
883 if (!Buffer)
884 {
885 /* Fail */
886 KeBugCheckEx(BAD_SYSTEM_CONFIG_INFO, 3, 1, (ULONG_PTR)LoaderBlock, 0);
887 }
888
889 /* Setup the unicode string */
890 RtlInitEmptyUnicodeString(&CmpLoadOptions, Buffer, (USHORT)Length);
891
892 /* Add the load options and null-terminate */
893 Status = RtlAnsiStringToUnicodeString(&CmpLoadOptions, &LoadString, FALSE);
894 if (!NT_SUCCESS(Status))
895 {
896 return FALSE;
897 }
898
899 CmpLoadOptions.Buffer[LoadString.Length] = UNICODE_NULL;
900 CmpLoadOptions.Length += sizeof(WCHAR);
901
902 /* Get the System Hive base address */
903 HiveBase = LoaderBlock->RegistryBase;
904
905 Status = CmpInitializeHive(&SystemHive,
906 HiveBase ? HINIT_MEMORY : HINIT_CREATE,
907 HIVE_NOLAZYFLUSH,
908 HFILE_TYPE_LOG,
909 HiveBase,
910 NULL,
911 NULL,
912 NULL,
913 &HiveName,
914 HiveBase ? 2 : 0);
915 if (!NT_SUCCESS(Status))
916 {
917 return FALSE;
918 }
919
920 /* Set the hive filename */
921 Status = RtlCreateUnicodeString(&SystemHive->FileFullPath, L"\\SystemRoot\\System32\\Config\\SYSTEM");
922 if (!NT_SUCCESS(Status))
923 {
924 return FALSE;
925 }
926
927 /* Manually set the hive as volatile, if in Live CD mode */
928 if (HiveBase && CmpShareSystemHives)
929 {
930 SystemHive->Hive.HiveFlags = HIVE_VOLATILE;
931 }
932
933 /* Save the boot type */
934 CmpBootType = SystemHive->Hive.BaseBlock->BootType;
935
936 /* Are we in self-healing mode? */
937 if (!CmSelfHeal)
938 {
939 /* Disable self-healing internally and check if boot type wanted it */
940 CmpSelfHeal = FALSE;
941 if (CmpBootType & 4)
942 {
943 /* We're disabled, so bugcheck */
944 KeBugCheckEx(BAD_SYSTEM_CONFIG_INFO,
945 3,
946 3,
947 (ULONG_PTR)SystemHive,
948 0);
949 }
950 }
951
952 /* Create the default security descriptor */
953 SecurityDescriptor = CmpHiveRootSecurityDescriptor();
954
955 /* Attach it to the system key */
956 /* Let CmpLinkHiveToMaster allocate a new hive if we got none from the LoaderBlock. */
957 RtlInitUnicodeString(&KeyName, L"\\Registry\\Machine\\SYSTEM");
958 Status = CmpLinkHiveToMaster(&KeyName,
959 NULL,
960 SystemHive,
961 !HiveBase,
962 SecurityDescriptor);
963
964 /* Free the security descriptor */
965 ExFreePoolWithTag(SecurityDescriptor, TAG_CMSD);
966 if (!NT_SUCCESS(Status)) return FALSE;
967
968 /* Add the hive to the hive list */
969 CmpMachineHiveList[3].CmHive = SystemHive;
970
971 /* Success! */
972 return TRUE;
973 }
974
975 NTSTATUS
976 NTAPI
977 INIT_FUNCTION
978 CmpCreateObjectTypes(VOID)
979 {
980 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer;
981 UNICODE_STRING Name;
982 GENERIC_MAPPING CmpKeyMapping = {KEY_READ,
983 KEY_WRITE,
984 KEY_EXECUTE,
985 KEY_ALL_ACCESS};
986 PAGED_CODE();
987
988 /* Initialize the Key object type */
989 RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer));
990 RtlInitUnicodeString(&Name, L"Key");
991 ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer);
992 ObjectTypeInitializer.DefaultPagedPoolCharge = sizeof(CM_KEY_BODY);
993 ObjectTypeInitializer.GenericMapping = CmpKeyMapping;
994 ObjectTypeInitializer.PoolType = PagedPool;
995 ObjectTypeInitializer.ValidAccessMask = KEY_ALL_ACCESS;
996 ObjectTypeInitializer.UseDefaultObject = TRUE;
997 ObjectTypeInitializer.DeleteProcedure = CmpDeleteKeyObject;
998 ObjectTypeInitializer.ParseProcedure = CmpParseKey;
999 ObjectTypeInitializer.SecurityProcedure = CmpSecurityMethod;
1000 ObjectTypeInitializer.QueryNameProcedure = CmpQueryKeyName;
1001 ObjectTypeInitializer.CloseProcedure = CmpCloseKeyObject;
1002 ObjectTypeInitializer.SecurityRequired = TRUE;
1003 ObjectTypeInitializer.InvalidAttributes = OBJ_EXCLUSIVE | OBJ_PERMANENT;
1004
1005 /* Create it */
1006 return ObCreateObjectType(&Name, &ObjectTypeInitializer, NULL, &CmpKeyObjectType);
1007 }
1008
1009 BOOLEAN
1010 NTAPI
1011 INIT_FUNCTION
1012 CmpCreateRootNode(IN PHHIVE Hive,
1013 IN PCWSTR Name,
1014 OUT PHCELL_INDEX Index)
1015 {
1016 UNICODE_STRING KeyName;
1017 PCM_KEY_NODE KeyCell;
1018 PAGED_CODE();
1019
1020 /* Initialize the node name and allocate it */
1021 RtlInitUnicodeString(&KeyName, Name);
1022 *Index = HvAllocateCell(Hive,
1023 FIELD_OFFSET(CM_KEY_NODE, Name) +
1024 CmpNameSize(Hive, &KeyName),
1025 Stable,
1026 HCELL_NIL);
1027 if (*Index == HCELL_NIL) return FALSE;
1028
1029 /* Set the cell index and get the data */
1030 Hive->BaseBlock->RootCell = *Index;
1031 KeyCell = (PCM_KEY_NODE)HvGetCell(Hive, *Index);
1032 if (!KeyCell) return FALSE;
1033
1034 /* Setup the cell */
1035 KeyCell->Signature = CM_KEY_NODE_SIGNATURE;
1036 KeyCell->Flags = KEY_HIVE_ENTRY | KEY_NO_DELETE;
1037 KeQuerySystemTime(&KeyCell->LastWriteTime);
1038 KeyCell->Parent = HCELL_NIL;
1039 KeyCell->SubKeyCounts[Stable] = 0;
1040 KeyCell->SubKeyCounts[Volatile] = 0;
1041 KeyCell->SubKeyLists[Stable] = HCELL_NIL;
1042 KeyCell->SubKeyLists[Volatile] = HCELL_NIL;
1043 KeyCell->ValueList.Count = 0;
1044 KeyCell->ValueList.List = HCELL_NIL;
1045 KeyCell->Security = HCELL_NIL;
1046 KeyCell->Class = HCELL_NIL;
1047 KeyCell->ClassLength = 0;
1048 KeyCell->MaxNameLen = 0;
1049 KeyCell->MaxClassLen = 0;
1050 KeyCell->MaxValueNameLen = 0;
1051 KeyCell->MaxValueDataLen = 0;
1052
1053 /* Copy the name (this will also set the length) */
1054 KeyCell->NameLength = CmpCopyName(Hive, KeyCell->Name, &KeyName);
1055
1056 /* Check if the name was compressed and set the flag if so */
1057 if (KeyCell->NameLength < KeyName.Length)
1058 KeyCell->Flags |= KEY_COMP_NAME;
1059
1060 /* Return success */
1061 HvReleaseCell(Hive, *Index);
1062 return TRUE;
1063 }
1064
1065 BOOLEAN
1066 NTAPI
1067 INIT_FUNCTION
1068 CmpCreateRegistryRoot(VOID)
1069 {
1070 UNICODE_STRING KeyName;
1071 OBJECT_ATTRIBUTES ObjectAttributes;
1072 PCM_KEY_BODY RootKey;
1073 HCELL_INDEX RootIndex;
1074 NTSTATUS Status;
1075 PCM_KEY_NODE KeyCell;
1076 PSECURITY_DESCRIPTOR SecurityDescriptor;
1077 PCM_KEY_CONTROL_BLOCK Kcb;
1078 PAGED_CODE();
1079
1080 /* Setup the root node */
1081 if (!CmpCreateRootNode(&CmiVolatileHive->Hive, L"REGISTRY", &RootIndex))
1082 {
1083 /* We failed */
1084 return FALSE;
1085 }
1086
1087 /* Create '\Registry' key. */
1088 RtlInitUnicodeString(&KeyName, L"\\REGISTRY");
1089 SecurityDescriptor = CmpHiveRootSecurityDescriptor();
1090 InitializeObjectAttributes(&ObjectAttributes,
1091 &KeyName,
1092 OBJ_CASE_INSENSITIVE,
1093 NULL,
1094 SecurityDescriptor);
1095 Status = ObCreateObject(KernelMode,
1096 CmpKeyObjectType,
1097 &ObjectAttributes,
1098 KernelMode,
1099 NULL,
1100 sizeof(CM_KEY_BODY),
1101 0,
1102 0,
1103 (PVOID*)&RootKey);
1104 ExFreePoolWithTag(SecurityDescriptor, TAG_CMSD);
1105 if (!NT_SUCCESS(Status)) return FALSE;
1106
1107 /* Sanity check, and get the key cell */
1108 ASSERT((&CmiVolatileHive->Hive)->ReleaseCellRoutine == NULL);
1109 KeyCell = (PCM_KEY_NODE)HvGetCell(&CmiVolatileHive->Hive, RootIndex);
1110 if (!KeyCell) return FALSE;
1111
1112 /* Create the KCB */
1113 RtlInitUnicodeString(&KeyName, L"\\REGISTRY");
1114 Kcb = CmpCreateKeyControlBlock(&CmiVolatileHive->Hive,
1115 RootIndex,
1116 KeyCell,
1117 NULL,
1118 0,
1119 &KeyName);
1120 if (!Kcb)
1121 {
1122 ObDereferenceObject(RootKey);
1123 return FALSE;
1124 }
1125
1126 /* Initialize the object */
1127 RootKey->KeyControlBlock = Kcb;
1128 RootKey->Type = CM_KEY_BODY_TYPE;
1129 RootKey->NotifyBlock = NULL;
1130 RootKey->ProcessID = PsGetCurrentProcessId();
1131
1132 /* Link with KCB */
1133 EnlistKeyBodyWithKCB(RootKey, 0);
1134
1135 /* Insert the key into the namespace */
1136 Status = ObInsertObject(RootKey,
1137 NULL,
1138 KEY_ALL_ACCESS,
1139 0,
1140 NULL,
1141 &CmpRegistryRootHandle);
1142 if (!NT_SUCCESS(Status))
1143 {
1144 ObDereferenceObject(RootKey);
1145 return FALSE;
1146 }
1147
1148 /* Reference the key again so that we never lose it */
1149 Status = ObReferenceObjectByHandle(CmpRegistryRootHandle,
1150 KEY_READ,
1151 NULL,
1152 KernelMode,
1153 (PVOID*)&RootKey,
1154 NULL);
1155 if (!NT_SUCCESS(Status))
1156 {
1157 ObDereferenceObject(RootKey);
1158 return FALSE;
1159 }
1160
1161 /* Completely sucessful */
1162 return TRUE;
1163 }
1164
1165 NTSTATUS
1166 NTAPI
1167 CmpGetRegistryPath(OUT PWCHAR ConfigPath)
1168 {
1169 OBJECT_ATTRIBUTES ObjectAttributes;
1170 NTSTATUS Status;
1171 HANDLE KeyHandle;
1172 PKEY_VALUE_PARTIAL_INFORMATION ValueInfo;
1173 UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\HARDWARE");
1174 UNICODE_STRING ValueName = RTL_CONSTANT_STRING(L"InstallPath");
1175 ULONG BufferSize, ResultSize;
1176
1177 /* Check if we are booted in setup */
1178 if (ExpInTextModeSetup)
1179 {
1180 DPRINT1("CmpGetRegistryPath TextMode setup HACK!!\n");
1181
1182 /* Setup the object attributes */
1183 InitializeObjectAttributes(&ObjectAttributes,
1184 &KeyName,
1185 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
1186 NULL,
1187 NULL);
1188 /* Open the key */
1189 Status = ZwOpenKey(&KeyHandle,
1190 KEY_ALL_ACCESS,
1191 &ObjectAttributes);
1192 if (!NT_SUCCESS(Status)) return Status;
1193
1194 /* Allocate the buffer */
1195 BufferSize = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 4096;
1196 ValueInfo = ExAllocatePoolWithTag(PagedPool, BufferSize, TAG_CM);
1197 if (!ValueInfo)
1198 {
1199 /* Fail */
1200 ZwClose(KeyHandle);
1201 return STATUS_INSUFFICIENT_RESOURCES;
1202 }
1203
1204 /* Query the value */
1205 Status = ZwQueryValueKey(KeyHandle,
1206 &ValueName,
1207 KeyValuePartialInformation,
1208 ValueInfo,
1209 BufferSize,
1210 &ResultSize);
1211 ZwClose(KeyHandle);
1212 if (!NT_SUCCESS(Status))
1213 {
1214 /* Fail */
1215 ExFreePoolWithTag(ValueInfo, TAG_CM);
1216 return Status;
1217 }
1218
1219 /* Copy the config path and null-terminate it */
1220 RtlCopyMemory(ConfigPath,
1221 ValueInfo->Data,
1222 ValueInfo->DataLength);
1223 ConfigPath[ValueInfo->DataLength / sizeof(WCHAR)] = UNICODE_NULL;
1224 ExFreePoolWithTag(ValueInfo, TAG_CM);
1225 }
1226 else
1227 {
1228 /* Just use default path */
1229 wcscpy(ConfigPath, L"\\SystemRoot");
1230 }
1231
1232 /* Add registry path */
1233 wcscat(ConfigPath, L"\\System32\\Config\\");
1234
1235 DPRINT1("CmpGetRegistryPath: ConfigPath = '%S'\n", ConfigPath);
1236
1237 /* Done */
1238 return STATUS_SUCCESS;
1239 }
1240
1241 _Function_class_(KSTART_ROUTINE)
1242 VOID
1243 NTAPI
1244 CmpLoadHiveThread(IN PVOID StartContext)
1245 {
1246 WCHAR FileBuffer[MAX_PATH], RegBuffer[MAX_PATH], ConfigPath[MAX_PATH];
1247 UNICODE_STRING TempName, FileName, RegName;
1248 ULONG i, ErrorResponse, WorkerCount, Length;
1249 USHORT FileStart;
1250 ULONG PrimaryDisposition, SecondaryDisposition, ClusterSize;
1251 PCMHIVE CmHive;
1252 HANDLE PrimaryHandle = NULL, LogHandle = NULL;
1253 NTSTATUS Status = STATUS_SUCCESS;
1254 PVOID ErrorParameters;
1255 PAGED_CODE();
1256
1257 /* Get the hive index, make sure it makes sense */
1258 i = PtrToUlong(StartContext);
1259 ASSERT(CmpMachineHiveList[i].Name != NULL);
1260
1261 /* We were started */
1262 CmpMachineHiveList[i].ThreadStarted = TRUE;
1263
1264 /* Build the file name and registry name strings */
1265 RtlInitEmptyUnicodeString(&FileName, FileBuffer, sizeof(FileBuffer));
1266 RtlInitEmptyUnicodeString(&RegName, RegBuffer, sizeof(RegBuffer));
1267
1268 /* Now build the system root path */
1269 CmpGetRegistryPath(ConfigPath);
1270 RtlInitUnicodeString(&TempName, ConfigPath);
1271 RtlAppendUnicodeStringToString(&FileName, &TempName);
1272 FileStart = FileName.Length;
1273
1274 /* And build the registry root path */
1275 RtlInitUnicodeString(&TempName, L"\\REGISTRY\\");
1276 RtlAppendUnicodeStringToString(&RegName, &TempName);
1277
1278 /* Build the base name */
1279 RtlInitUnicodeString(&TempName, CmpMachineHiveList[i].BaseName);
1280 RtlAppendUnicodeStringToString(&RegName, &TempName);
1281
1282 /* Check if this is a child of the root */
1283 if (RegName.Buffer[RegName.Length / sizeof(WCHAR) - 1] == OBJ_NAME_PATH_SEPARATOR)
1284 {
1285 /* Then setup the whole name */
1286 RtlInitUnicodeString(&TempName, CmpMachineHiveList[i].Name);
1287 RtlAppendUnicodeStringToString(&RegName, &TempName);
1288 }
1289
1290 /* Now add the rest of the file name */
1291 RtlInitUnicodeString(&TempName, CmpMachineHiveList[i].Name);
1292 FileName.Length = FileStart;
1293 RtlAppendUnicodeStringToString(&FileName, &TempName);
1294 if (!CmpMachineHiveList[i].CmHive)
1295 {
1296 /* We need to allocate a new hive structure */
1297 CmpMachineHiveList[i].Allocate = TRUE;
1298
1299 /* Load the hive file */
1300 Status = CmpInitHiveFromFile(&FileName,
1301 CmpMachineHiveList[i].HHiveFlags,
1302 &CmHive,
1303 &CmpMachineHiveList[i].Allocate,
1304 0);
1305 if (!(NT_SUCCESS(Status)) ||
1306 (!(CmpShareSystemHives) && !(CmHive->FileHandles[HFILE_TYPE_LOG])))
1307 {
1308 /*
1309 * We failed, or could not get a log file (unless
1310 * the hive is shared), raise a hard error.
1311 */
1312 ErrorParameters = &FileName;
1313 NtRaiseHardError(STATUS_CANNOT_LOAD_REGISTRY_FILE,
1314 1,
1315 1,
1316 (PULONG_PTR)&ErrorParameters,
1317 OptionOk,
1318 &ErrorResponse);
1319 }
1320
1321 /* Set the hive flags and newly allocated hive pointer */
1322 CmHive->Flags = CmpMachineHiveList[i].CmHiveFlags;
1323 CmpMachineHiveList[i].CmHive2 = CmHive;
1324 }
1325 else
1326 {
1327 /* We already have a hive, is it volatile? */
1328 CmHive = CmpMachineHiveList[i].CmHive;
1329 if (!(CmHive->Hive.HiveFlags & HIVE_VOLATILE))
1330 {
1331 /* It's now, open the hive file and log */
1332 Status = CmpOpenHiveFiles(&FileName,
1333 L".LOG",
1334 &PrimaryHandle,
1335 &LogHandle,
1336 &PrimaryDisposition,
1337 &SecondaryDisposition,
1338 TRUE,
1339 TRUE,
1340 FALSE,
1341 &ClusterSize);
1342 if (!(NT_SUCCESS(Status)) || !(LogHandle))
1343 {
1344 /* Couldn't open the hive or its log file, raise a hard error */
1345 ErrorParameters = &FileName;
1346 NtRaiseHardError(STATUS_CANNOT_LOAD_REGISTRY_FILE,
1347 1,
1348 1,
1349 (PULONG_PTR)&ErrorParameters,
1350 OptionOk,
1351 &ErrorResponse);
1352
1353 /* And bugcheck for posterity's sake */
1354 KeBugCheckEx(BAD_SYSTEM_CONFIG_INFO, 9, 0, i, Status);
1355 }
1356
1357 /* Save the file handles. This should remove our sync hacks */
1358 CmHive->FileHandles[HFILE_TYPE_LOG] = LogHandle;
1359 CmHive->FileHandles[HFILE_TYPE_PRIMARY] = PrimaryHandle;
1360
1361 /* Allow lazy flushing since the handles are there -- remove sync hacks */
1362 //ASSERT(CmHive->Hive.HiveFlags & HIVE_NOLAZYFLUSH);
1363 CmHive->Hive.HiveFlags &= ~HIVE_NOLAZYFLUSH;
1364
1365 /* Get the real size of the hive */
1366 Length = CmHive->Hive.Storage[Stable].Length + HBLOCK_SIZE;
1367
1368 /* Check if the cluster size doesn't match */
1369 if (CmHive->Hive.Cluster != ClusterSize) ASSERT(FALSE);
1370
1371 /* Set the file size */
1372 DPRINT("FIXME: Should set file size: %lx\n", Length);
1373 //if (!CmpFileSetSize((PHHIVE)CmHive, HFILE_TYPE_PRIMARY, Length, Length))
1374 {
1375 /* This shouldn't fail */
1376 //ASSERT(FALSE);
1377 }
1378
1379 /* Another thing we don't support is NTLDR-recovery */
1380 if (CmHive->Hive.BaseBlock->BootRecover) ASSERT(FALSE);
1381
1382 /* Finally, set our allocated hive to the same hive we've had */
1383 CmpMachineHiveList[i].CmHive2 = CmHive;
1384 ASSERT(CmpMachineHiveList[i].CmHive == CmpMachineHiveList[i].CmHive2);
1385 }
1386 }
1387
1388 /* We're done */
1389 CmpMachineHiveList[i].ThreadFinished = TRUE;
1390
1391 /* Check if we're the last worker */
1392 WorkerCount = InterlockedIncrement(&CmpLoadWorkerIncrement);
1393 if (WorkerCount == CM_NUMBER_OF_MACHINE_HIVES)
1394 {
1395 /* Signal the event */
1396 KeSetEvent(&CmpLoadWorkerEvent, 0, FALSE);
1397 }
1398
1399 /* Kill the thread */
1400 PsTerminateSystemThread(Status);
1401 }
1402
1403 VOID
1404 NTAPI
1405 CmpInitializeHiveList(IN USHORT Flag)
1406 {
1407 WCHAR FileBuffer[MAX_PATH], RegBuffer[MAX_PATH], ConfigPath[MAX_PATH];
1408 UNICODE_STRING TempName, FileName, RegName;
1409 HANDLE Thread;
1410 NTSTATUS Status;
1411 ULONG i;
1412 USHORT RegStart;
1413 PSECURITY_DESCRIPTOR SecurityDescriptor;
1414 PAGED_CODE();
1415
1416 /* Allow writing for now */
1417 CmpNoWrite = FALSE;
1418
1419 /* Build the file name and registry name strings */
1420 RtlInitEmptyUnicodeString(&FileName, FileBuffer, sizeof(FileBuffer));
1421 RtlInitEmptyUnicodeString(&RegName, RegBuffer, sizeof(RegBuffer));
1422
1423 /* Now build the system root path */
1424 CmpGetRegistryPath(ConfigPath);
1425 RtlInitUnicodeString(&TempName, ConfigPath);
1426 RtlAppendUnicodeStringToString(&FileName, &TempName);
1427
1428 /* And build the registry root path */
1429 RtlInitUnicodeString(&TempName, L"\\REGISTRY\\");
1430 RtlAppendUnicodeStringToString(&RegName, &TempName);
1431 RegStart = RegName.Length;
1432
1433 /* Setup the event to synchronize workers */
1434 KeInitializeEvent(&CmpLoadWorkerEvent, SynchronizationEvent, FALSE);
1435
1436 /* Enter special boot condition */
1437 CmpSpecialBootCondition = TRUE;
1438
1439 /* Create the SD for the root hives */
1440 SecurityDescriptor = CmpHiveRootSecurityDescriptor();
1441
1442 /* Loop every hive we care about */
1443 for (i = 0; i < CM_NUMBER_OF_MACHINE_HIVES; i++)
1444 {
1445 /* Make sure the list is set up */
1446 ASSERT(CmpMachineHiveList[i].Name != NULL);
1447
1448 /* Load the hive as volatile, if in LiveCD mode */
1449 if (CmpShareSystemHives)
1450 CmpMachineHiveList[i].HHiveFlags |= HIVE_VOLATILE;
1451
1452 /* Create a thread to handle this hive */
1453 Status = PsCreateSystemThread(&Thread,
1454 THREAD_ALL_ACCESS,
1455 NULL,
1456 0,
1457 NULL,
1458 CmpLoadHiveThread,
1459 UlongToPtr(i));
1460 if (NT_SUCCESS(Status))
1461 {
1462 /* We don't care about the handle -- the thread self-terminates */
1463 ZwClose(Thread);
1464 }
1465 else
1466 {
1467 /* Can't imagine this happening */
1468 KeBugCheckEx(BAD_SYSTEM_CONFIG_INFO, 9, 3, i, Status);
1469 }
1470 }
1471
1472 /* Make sure we've reached the end of the list */
1473 ASSERT(CmpMachineHiveList[i].Name == NULL);
1474
1475 /* Wait for hive loading to finish */
1476 KeWaitForSingleObject(&CmpLoadWorkerEvent,
1477 Executive,
1478 KernelMode,
1479 FALSE,
1480 NULL);
1481
1482 /* Exit the special boot condition and make sure all workers completed */
1483 CmpSpecialBootCondition = FALSE;
1484 ASSERT(CmpLoadWorkerIncrement == CM_NUMBER_OF_MACHINE_HIVES);
1485
1486 /* Loop hives again */
1487 for (i = 0; i < CM_NUMBER_OF_MACHINE_HIVES; i++)
1488 {
1489 /* Make sure the thread ran and finished */
1490 ASSERT(CmpMachineHiveList[i].ThreadFinished == TRUE);
1491 ASSERT(CmpMachineHiveList[i].ThreadStarted == TRUE);
1492
1493 /* Check if this was a new hive */
1494 if (!CmpMachineHiveList[i].CmHive)
1495 {
1496 /* Make sure we allocated something */
1497 ASSERT(CmpMachineHiveList[i].CmHive2 != NULL);
1498
1499 /* Build the base name */
1500 RegName.Length = RegStart;
1501 RtlInitUnicodeString(&TempName, CmpMachineHiveList[i].BaseName);
1502 RtlAppendUnicodeStringToString(&RegName, &TempName);
1503
1504 /* Check if this is a child of the root */
1505 if (RegName.Buffer[RegName.Length / sizeof(WCHAR) - 1] == OBJ_NAME_PATH_SEPARATOR)
1506 {
1507 /* Then setup the whole name */
1508 RtlInitUnicodeString(&TempName, CmpMachineHiveList[i].Name);
1509 RtlAppendUnicodeStringToString(&RegName, &TempName);
1510 }
1511
1512 /* Now link the hive to its master */
1513 Status = CmpLinkHiveToMaster(&RegName,
1514 NULL,
1515 CmpMachineHiveList[i].CmHive2,
1516 CmpMachineHiveList[i].Allocate,
1517 SecurityDescriptor);
1518 if (Status != STATUS_SUCCESS)
1519 {
1520 /* Linking needs to work */
1521 KeBugCheckEx(CONFIG_LIST_FAILED, 11, Status, i, (ULONG_PTR)&RegName);
1522 }
1523
1524 /* Check if we had to allocate a new hive */
1525 if (CmpMachineHiveList[i].Allocate)
1526 {
1527 /* Sync the new hive */
1528 //HvSyncHive((PHHIVE)(CmpMachineHiveList[i].CmHive2));
1529 }
1530 }
1531
1532 /* Check if we created a new hive */
1533 if (CmpMachineHiveList[i].CmHive2)
1534 {
1535 /* Add to HiveList key */
1536 CmpAddToHiveFileList(CmpMachineHiveList[i].CmHive2);
1537 }
1538 }
1539
1540 /* Get rid of the SD */
1541 ExFreePoolWithTag(SecurityDescriptor, TAG_CMSD);
1542
1543 /* Link SECURITY to SAM */
1544 CmpLinkKeyToHive(L"\\Registry\\Machine\\Security\\SAM",
1545 L"\\Registry\\Machine\\SAM\\SAM");
1546
1547 /* Link S-1-5-18 to .Default */
1548 CmpNoVolatileCreates = FALSE;
1549 CmpLinkKeyToHive(L"\\Registry\\User\\S-1-5-18",
1550 L"\\Registry\\User\\.Default");
1551 CmpNoVolatileCreates = TRUE;
1552 }
1553
1554 BOOLEAN
1555 NTAPI
1556 INIT_FUNCTION
1557 CmInitSystem1(VOID)
1558 {
1559 OBJECT_ATTRIBUTES ObjectAttributes;
1560 UNICODE_STRING KeyName;
1561 HANDLE KeyHandle;
1562 NTSTATUS Status;
1563 PCMHIVE HardwareHive;
1564 PSECURITY_DESCRIPTOR SecurityDescriptor;
1565 PAGED_CODE();
1566
1567 /* Check if this is PE-boot */
1568 if (InitIsWinPEMode)
1569 {
1570 /* Set registry to PE mode */
1571 CmpMiniNTBoot = TRUE;
1572 CmpShareSystemHives = TRUE;
1573 }
1574
1575 /* Initialize the hive list and lock */
1576 InitializeListHead(&CmpHiveListHead);
1577 ExInitializePushLock(&CmpHiveListHeadLock);
1578 ExInitializePushLock(&CmpLoadHiveLock);
1579
1580 /* Initialize registry lock */
1581 ExInitializeResourceLite(&CmpRegistryLock);
1582
1583 /* Initialize the cache */
1584 CmpInitializeCache();
1585
1586 /* Initialize allocation and delayed dereferencing */
1587 CmpInitCmPrivateAlloc();
1588 CmpInitCmPrivateDelayAlloc();
1589 CmpInitDelayDerefKCBEngine();
1590
1591 /* Initialize callbacks */
1592 CmpInitCallback();
1593
1594 /* Initialize self healing */
1595 KeInitializeGuardedMutex(&CmpSelfHealQueueLock);
1596 InitializeListHead(&CmpSelfHealQueueListHead);
1597
1598 /* Save the current process and lock the registry */
1599 CmpSystemProcess = PsGetCurrentProcess();
1600
1601 /* Create the key object types */
1602 Status = CmpCreateObjectTypes();
1603 if (!NT_SUCCESS(Status))
1604 {
1605 /* Bugcheck */
1606 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 1, Status, 0);
1607 }
1608
1609 /* Build the master hive */
1610 Status = CmpInitializeHive(&CmiVolatileHive,
1611 HINIT_CREATE,
1612 HIVE_VOLATILE,
1613 HFILE_TYPE_PRIMARY,
1614 NULL,
1615 NULL,
1616 NULL,
1617 NULL,
1618 NULL,
1619 0);
1620 if (!NT_SUCCESS(Status))
1621 {
1622 /* Bugcheck */
1623 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 2, Status, 0);
1624 }
1625
1626 /* Create the \REGISTRY key node */
1627 if (!CmpCreateRegistryRoot())
1628 {
1629 /* Bugcheck */
1630 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 3, 0, 0);
1631 }
1632
1633 /* Create the default security descriptor */
1634 SecurityDescriptor = CmpHiveRootSecurityDescriptor();
1635
1636 /* Create '\Registry\Machine' key */
1637 RtlInitUnicodeString(&KeyName, L"\\REGISTRY\\MACHINE");
1638 InitializeObjectAttributes(&ObjectAttributes,
1639 &KeyName,
1640 OBJ_CASE_INSENSITIVE,
1641 NULL,
1642 SecurityDescriptor);
1643 Status = NtCreateKey(&KeyHandle,
1644 KEY_READ | KEY_WRITE,
1645 &ObjectAttributes,
1646 0,
1647 NULL,
1648 0,
1649 NULL);
1650 if (!NT_SUCCESS(Status))
1651 {
1652 /* Bugcheck */
1653 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 5, Status, 0);
1654 }
1655
1656 /* Close the handle */
1657 NtClose(KeyHandle);
1658
1659 /* Create '\Registry\User' key */
1660 RtlInitUnicodeString(&KeyName, L"\\REGISTRY\\USER");
1661 InitializeObjectAttributes(&ObjectAttributes,
1662 &KeyName,
1663 OBJ_CASE_INSENSITIVE,
1664 NULL,
1665 SecurityDescriptor);
1666 Status = NtCreateKey(&KeyHandle,
1667 KEY_READ | KEY_WRITE,
1668 &ObjectAttributes,
1669 0,
1670 NULL,
1671 0,
1672 NULL);
1673 if (!NT_SUCCESS(Status))
1674 {
1675 /* Bugcheck */
1676 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 6, Status, 0);
1677 }
1678
1679 /* Close the handle */
1680 NtClose(KeyHandle);
1681
1682 /* After this point, do not allow creating keys in the master hive */
1683 CmpNoVolatileCreates = TRUE;
1684
1685 /* Initialize the system hive */
1686 if (!CmpInitializeSystemHive(KeLoaderBlock))
1687 {
1688 /* Bugcheck */
1689 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 7, 0, 0);
1690 }
1691
1692 /* Create the 'CurrentControlSet' link */
1693 Status = CmpCreateControlSet(KeLoaderBlock);
1694 if (!NT_SUCCESS(Status))
1695 {
1696 /* Bugcheck */
1697 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 8, Status, 0);
1698 }
1699
1700 /* Create the hardware hive */
1701 Status = CmpInitializeHive(&HardwareHive,
1702 HINIT_CREATE,
1703 HIVE_VOLATILE,
1704 HFILE_TYPE_PRIMARY,
1705 NULL,
1706 NULL,
1707 NULL,
1708 NULL,
1709 NULL,
1710 0);
1711 if (!NT_SUCCESS(Status))
1712 {
1713 /* Bugcheck */
1714 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 11, Status, 0);
1715 }
1716
1717 /* Add the hive to the hive list */
1718 CmpMachineHiveList[0].CmHive = HardwareHive;
1719
1720 /* Attach it to the machine key */
1721 RtlInitUnicodeString(&KeyName, L"\\Registry\\Machine\\HARDWARE");
1722 Status = CmpLinkHiveToMaster(&KeyName,
1723 NULL,
1724 HardwareHive,
1725 TRUE,
1726 SecurityDescriptor);
1727 if (!NT_SUCCESS(Status))
1728 {
1729 /* Bugcheck */
1730 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 12, Status, 0);
1731 }
1732
1733 /* Add to HiveList key */
1734 CmpAddToHiveFileList(HardwareHive);
1735
1736 /* Free the security descriptor */
1737 ExFreePoolWithTag(SecurityDescriptor, TAG_CMSD);
1738
1739 /* Fill out the Hardware key with the ARC Data from the Loader */
1740 Status = CmpInitializeHardwareConfiguration(KeLoaderBlock);
1741 if (!NT_SUCCESS(Status))
1742 {
1743 /* Bugcheck */
1744 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 13, Status, 0);
1745 }
1746
1747 /* Initialize machine-dependent information into the registry */
1748 Status = CmpInitializeMachineDependentConfiguration(KeLoaderBlock);
1749 if (!NT_SUCCESS(Status))
1750 {
1751 /* Bugcheck */
1752 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 14, Status, 0);
1753 }
1754
1755 /* Initialize volatile registry settings */
1756 Status = CmpSetSystemValues(KeLoaderBlock);
1757 if (!NT_SUCCESS(Status))
1758 {
1759 /* Bugcheck */
1760 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 15, Status, 0);
1761 }
1762
1763 /* Free the load options */
1764 ExFreePoolWithTag(CmpLoadOptions.Buffer, TAG_CM);
1765
1766 /* If we got here, all went well */
1767 return TRUE;
1768 }
1769
1770 VOID
1771 NTAPI
1772 INIT_FUNCTION
1773 CmpFreeDriverList(IN PHHIVE Hive,
1774 IN PLIST_ENTRY DriverList)
1775 {
1776 PLIST_ENTRY NextEntry, OldEntry;
1777 PBOOT_DRIVER_NODE DriverNode;
1778 PAGED_CODE();
1779
1780 /* Parse the current list */
1781 NextEntry = DriverList->Flink;
1782 while (NextEntry != DriverList)
1783 {
1784 /* Get the driver node */
1785 DriverNode = CONTAINING_RECORD(NextEntry, BOOT_DRIVER_NODE, ListEntry.Link);
1786
1787 /* Get the next entry now, since we're going to free it later */
1788 OldEntry = NextEntry;
1789 NextEntry = NextEntry->Flink;
1790
1791 /* Was there a name? */
1792 if (DriverNode->Name.Buffer)
1793 {
1794 /* Free it */
1795 CmpFree(DriverNode->Name.Buffer, DriverNode->Name.Length);
1796 }
1797
1798 /* Was there a registry path? */
1799 if (DriverNode->ListEntry.RegistryPath.Buffer)
1800 {
1801 /* Free it */
1802 CmpFree(DriverNode->ListEntry.RegistryPath.Buffer,
1803 DriverNode->ListEntry.RegistryPath.MaximumLength);
1804 }
1805
1806 /* Was there a file path? */
1807 if (DriverNode->ListEntry.FilePath.Buffer)
1808 {
1809 /* Free it */
1810 CmpFree(DriverNode->ListEntry.FilePath.Buffer,
1811 DriverNode->ListEntry.FilePath.MaximumLength);
1812 }
1813
1814 /* Now free the node, and move on */
1815 CmpFree(OldEntry, sizeof(BOOT_DRIVER_NODE));
1816 }
1817 }
1818
1819 PUNICODE_STRING*
1820 NTAPI
1821 INIT_FUNCTION
1822 CmGetSystemDriverList(VOID)
1823 {
1824 LIST_ENTRY DriverList;
1825 OBJECT_ATTRIBUTES ObjectAttributes;
1826 NTSTATUS Status;
1827 PCM_KEY_BODY KeyBody;
1828 PHHIVE Hive;
1829 HCELL_INDEX RootCell, ControlCell;
1830 HANDLE KeyHandle;
1831 UNICODE_STRING KeyName;
1832 PLIST_ENTRY NextEntry;
1833 ULONG i;
1834 PUNICODE_STRING* ServicePath = NULL;
1835 BOOLEAN Success, AutoSelect;
1836 PBOOT_DRIVER_LIST_ENTRY DriverEntry;
1837 PAGED_CODE();
1838
1839 /* Initialize the driver list */
1840 InitializeListHead(&DriverList);
1841
1842 /* Open the system hive key */
1843 RtlInitUnicodeString(&KeyName, L"\\Registry\\Machine\\System");
1844 InitializeObjectAttributes(&ObjectAttributes,
1845 &KeyName,
1846 OBJ_CASE_INSENSITIVE,
1847 NULL,
1848 NULL);
1849 Status = NtOpenKey(&KeyHandle, KEY_READ, &ObjectAttributes);
1850 if (!NT_SUCCESS(Status)) return NULL;
1851
1852 /* Reference the key object to get the root hive/cell to access directly */
1853 Status = ObReferenceObjectByHandle(KeyHandle,
1854 KEY_QUERY_VALUE,
1855 CmpKeyObjectType,
1856 KernelMode,
1857 (PVOID*)&KeyBody,
1858 NULL);
1859 if (!NT_SUCCESS(Status))
1860 {
1861 /* Fail */
1862 NtClose(KeyHandle);
1863 return NULL;
1864 }
1865
1866 /* Do all this under the registry lock */
1867 CmpLockRegistryExclusive();
1868
1869 /* Get the hive and key cell */
1870 Hive = KeyBody->KeyControlBlock->KeyHive;
1871 RootCell = KeyBody->KeyControlBlock->KeyCell;
1872
1873 /* Open the current control set key */
1874 RtlInitUnicodeString(&KeyName, L"Current");
1875 ControlCell = CmpFindControlSet(Hive, RootCell, &KeyName, &AutoSelect);
1876 if (ControlCell == HCELL_NIL) goto EndPath;
1877
1878 /* Find all system drivers */
1879 Success = CmpFindDrivers(Hive, ControlCell, SystemLoad, NULL, &DriverList);
1880 if (!Success) goto EndPath;
1881
1882 /* Sort by group/tag */
1883 if (!CmpSortDriverList(Hive, ControlCell, &DriverList)) goto EndPath;
1884
1885 /* Remove circular dependencies (cycles) and sort */
1886 if (!CmpResolveDriverDependencies(&DriverList)) goto EndPath;
1887
1888 /* Loop the list to count drivers */
1889 for (i = 0, NextEntry = DriverList.Flink;
1890 NextEntry != &DriverList;
1891 i++, NextEntry = NextEntry->Flink);
1892
1893 /* Allocate the array */
1894 ServicePath = ExAllocatePool(NonPagedPool, (i + 1) * sizeof(PUNICODE_STRING));
1895 if (!ServicePath) KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 2, 1, 0, 0);
1896
1897 /* Loop the driver list */
1898 for (i = 0, NextEntry = DriverList.Flink;
1899 NextEntry != &DriverList;
1900 i++, NextEntry = NextEntry->Flink)
1901 {
1902 /* Get the entry */
1903 DriverEntry = CONTAINING_RECORD(NextEntry, BOOT_DRIVER_LIST_ENTRY, Link);
1904
1905 /* Allocate the path for the caller */
1906 ServicePath[i] = ExAllocatePool(NonPagedPool, sizeof(UNICODE_STRING));
1907 if (!ServicePath[i])
1908 {
1909 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 2, 1, 0, 0);
1910 }
1911
1912 /* Duplicate the registry path */
1913 Status = RtlDuplicateUnicodeString(RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE,
1914 &DriverEntry->RegistryPath,
1915 ServicePath[i]);
1916 if (!NT_SUCCESS(Status))
1917 {
1918 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 2, 1, 0, 0);
1919 }
1920 }
1921
1922 /* Terminate the list */
1923 ServicePath[i] = NULL;
1924
1925 EndPath:
1926 /* Free the driver list if we had one */
1927 if (!IsListEmpty(&DriverList)) CmpFreeDriverList(Hive, &DriverList);
1928
1929 /* Unlock the registry */
1930 CmpUnlockRegistry();
1931
1932 /* Close the key handle and dereference the object, then return the path */
1933 ObDereferenceObject(KeyBody);
1934 NtClose(KeyHandle);
1935 return ServicePath;
1936 }
1937
1938 VOID
1939 NTAPI
1940 CmpLockRegistryExclusive(VOID)
1941 {
1942 /* Enter a critical region and lock the registry */
1943 KeEnterCriticalRegion();
1944 ExAcquireResourceExclusiveLite(&CmpRegistryLock, TRUE);
1945
1946 /* Sanity check */
1947 ASSERT(CmpFlushStarveWriters == 0);
1948 RtlGetCallersAddress(&CmpRegistryLockCaller, &CmpRegistryLockCallerCaller);
1949 }
1950
1951 VOID
1952 NTAPI
1953 CmpLockRegistry(VOID)
1954 {
1955 /* Enter a critical region */
1956 KeEnterCriticalRegion();
1957
1958 /* Check if we have to starve writers */
1959 if (CmpFlushStarveWriters)
1960 {
1961 /* Starve exlusive waiters */
1962 ExAcquireSharedStarveExclusive(&CmpRegistryLock, TRUE);
1963 }
1964 else
1965 {
1966 /* Just grab the lock */
1967 ExAcquireResourceSharedLite(&CmpRegistryLock, TRUE);
1968 }
1969 }
1970
1971 BOOLEAN
1972 NTAPI
1973 CmpTestRegistryLock(VOID)
1974 {
1975 /* Test the lock */
1976 return !ExIsResourceAcquiredSharedLite(&CmpRegistryLock) ? FALSE : TRUE;
1977 }
1978
1979 BOOLEAN
1980 NTAPI
1981 CmpTestRegistryLockExclusive(VOID)
1982 {
1983 /* Test the lock */
1984 return !ExIsResourceAcquiredExclusiveLite(&CmpRegistryLock) ? FALSE : TRUE;
1985 }
1986
1987 VOID
1988 NTAPI
1989 CmpLockHiveFlusherExclusive(IN PCMHIVE Hive)
1990 {
1991 /* Lock the flusher. We should already be in a critical section */
1992 CMP_ASSERT_REGISTRY_LOCK_OR_LOADING(Hive);
1993 ASSERT((ExIsResourceAcquiredShared(Hive->FlusherLock) == 0) &&
1994 (ExIsResourceAcquiredExclusiveLite(Hive->FlusherLock) == 0));
1995 ExAcquireResourceExclusiveLite(Hive->FlusherLock, TRUE);
1996 }
1997
1998 VOID
1999 NTAPI
2000 CmpLockHiveFlusherShared(IN PCMHIVE Hive)
2001 {
2002 /* Lock the flusher. We should already be in a critical section */
2003 CMP_ASSERT_REGISTRY_LOCK_OR_LOADING(Hive);
2004 ASSERT((ExIsResourceAcquiredShared(Hive->FlusherLock) == 0) &&
2005 (ExIsResourceAcquiredExclusiveLite(Hive->FlusherLock) == 0));
2006 ExAcquireResourceSharedLite(Hive->FlusherLock, TRUE);
2007 }
2008
2009 VOID
2010 NTAPI
2011 CmpUnlockHiveFlusher(IN PCMHIVE Hive)
2012 {
2013 /* Sanity check */
2014 CMP_ASSERT_REGISTRY_LOCK_OR_LOADING(Hive);
2015 CMP_ASSERT_FLUSH_LOCK(Hive);
2016
2017 /* Release the lock */
2018 ExReleaseResourceLite(Hive->FlusherLock);
2019 }
2020
2021 BOOLEAN
2022 NTAPI
2023 CmpTestHiveFlusherLockShared(IN PCMHIVE Hive)
2024 {
2025 /* Test the lock */
2026 return !ExIsResourceAcquiredSharedLite(Hive->FlusherLock) ? FALSE : TRUE;
2027 }
2028
2029 BOOLEAN
2030 NTAPI
2031 CmpTestHiveFlusherLockExclusive(IN PCMHIVE Hive)
2032 {
2033 /* Test the lock */
2034 return !ExIsResourceAcquiredExclusiveLite(Hive->FlusherLock) ? FALSE : TRUE;
2035 }
2036
2037 VOID
2038 NTAPI
2039 CmpUnlockRegistry(VOID)
2040 {
2041 /* Sanity check */
2042 CMP_ASSERT_REGISTRY_LOCK();
2043
2044 /* Check if we should flush the registry */
2045 if (CmpFlushOnLockRelease)
2046 {
2047 /* The registry should be exclusively locked for this */
2048 CMP_ASSERT_EXCLUSIVE_REGISTRY_LOCK();
2049
2050 /* Flush the registry */
2051 CmpDoFlushAll(TRUE);
2052 CmpFlushOnLockRelease = FALSE;
2053 }
2054 else
2055 {
2056 /* Lazy flush the registry */
2057 CmpLazyFlush();
2058 }
2059
2060 /* Release the lock and leave the critical region */
2061 ExReleaseResourceLite(&CmpRegistryLock);
2062 KeLeaveCriticalRegion();
2063 }
2064
2065 VOID
2066 NTAPI
2067 CmpAcquireTwoKcbLocksExclusiveByKey(IN ULONG ConvKey1,
2068 IN ULONG ConvKey2)
2069 {
2070 ULONG Index1, Index2;
2071
2072 /* Sanity check */
2073 CMP_ASSERT_REGISTRY_LOCK();
2074
2075 /* Get hash indexes */
2076 Index1 = GET_HASH_INDEX(ConvKey1);
2077 Index2 = GET_HASH_INDEX(ConvKey2);
2078
2079 /* See which one is highest */
2080 if (Index1 < Index2)
2081 {
2082 /* Grab them in the proper order */
2083 CmpAcquireKcbLockExclusiveByKey(ConvKey1);
2084 CmpAcquireKcbLockExclusiveByKey(ConvKey2);
2085 }
2086 else
2087 {
2088 /* Grab the second one first, then the first */
2089 CmpAcquireKcbLockExclusiveByKey(ConvKey2);
2090 if (Index1 != Index2) CmpAcquireKcbLockExclusiveByKey(ConvKey1);
2091 }
2092 }
2093
2094 VOID
2095 NTAPI
2096 CmpReleaseTwoKcbLockByKey(IN ULONG ConvKey1,
2097 IN ULONG ConvKey2)
2098 {
2099 ULONG Index1, Index2;
2100
2101 /* Sanity check */
2102 CMP_ASSERT_REGISTRY_LOCK();
2103
2104 /* Get hash indexes */
2105 Index1 = GET_HASH_INDEX(ConvKey1);
2106 Index2 = GET_HASH_INDEX(ConvKey2);
2107 ASSERT((GET_HASH_ENTRY(CmpCacheTable, ConvKey2)->Owner == KeGetCurrentThread()) ||
2108 (CmpTestRegistryLockExclusive()));
2109
2110 /* See which one is highest */
2111 if (Index1 < Index2)
2112 {
2113 /* Grab them in the proper order */
2114 ASSERT((GET_HASH_ENTRY(CmpCacheTable, ConvKey1)->Owner == KeGetCurrentThread()) ||
2115 (CmpTestRegistryLockExclusive()));
2116 CmpReleaseKcbLockByKey(ConvKey2);
2117 CmpReleaseKcbLockByKey(ConvKey1);
2118 }
2119 else
2120 {
2121 /* Release the first one first, then the second */
2122 if (Index1 != Index2)
2123 {
2124 ASSERT((GET_HASH_ENTRY(CmpCacheTable, ConvKey1)->Owner == KeGetCurrentThread()) ||
2125 (CmpTestRegistryLockExclusive()));
2126 CmpReleaseKcbLockByKey(ConvKey1);
2127 }
2128 CmpReleaseKcbLockByKey(ConvKey2);
2129 }
2130 }
2131
2132 VOID
2133 NTAPI
2134 CmShutdownSystem(VOID)
2135 {
2136 PLIST_ENTRY ListEntry;
2137 PCMHIVE Hive;
2138
2139 /* Kill the workers */
2140 if (!CmFirstTime) CmpShutdownWorkers();
2141
2142 /* Flush all hives */
2143 CmpLockRegistryExclusive();
2144 CmpDoFlushAll(TRUE);
2145
2146 /* Close all hive files */
2147 ListEntry = CmpHiveListHead.Flink;
2148 while (ListEntry != &CmpHiveListHead)
2149 {
2150 Hive = CONTAINING_RECORD(ListEntry, CMHIVE, HiveList);
2151
2152 CmpCloseHiveFiles(Hive);
2153
2154 ListEntry = ListEntry->Flink;
2155 }
2156
2157 CmpUnlockRegistry();
2158 }
2159
2160 VOID
2161 NTAPI
2162 CmpSetVersionData(VOID)
2163 {
2164 NTSTATUS Status;
2165 OBJECT_ATTRIBUTES ObjectAttributes;
2166 UNICODE_STRING KeyName;
2167 UNICODE_STRING ValueName;
2168 UNICODE_STRING ValueData;
2169 ANSI_STRING TempString;
2170 HANDLE SoftwareKeyHandle = NULL;
2171 HANDLE MicrosoftKeyHandle = NULL;
2172 HANDLE WindowsNtKeyHandle = NULL;
2173 HANDLE CurrentVersionKeyHandle = NULL;
2174 WCHAR Buffer[128]; // Buffer large enough to contain a full ULONG in decimal
2175 // representation, and the full 'CurrentType' string.
2176
2177 /*
2178 * Open the 'HKLM\Software\Microsoft\Windows NT\CurrentVersion' key
2179 * (create the intermediate subkeys if needed).
2180 */
2181
2182 RtlInitUnicodeString(&KeyName, L"\\REGISTRY\\MACHINE\\SOFTWARE");
2183 InitializeObjectAttributes(&ObjectAttributes,
2184 &KeyName,
2185 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
2186 NULL,
2187 NULL);
2188 Status = NtCreateKey(&SoftwareKeyHandle,
2189 KEY_CREATE_SUB_KEY,
2190 &ObjectAttributes,
2191 0,
2192 NULL,
2193 0,
2194 NULL);
2195 if (!NT_SUCCESS(Status))
2196 {
2197 DPRINT1("Failed to create key %wZ (Status: %08lx)\n", &KeyName, Status);
2198 return;
2199 }
2200
2201 RtlInitUnicodeString(&KeyName, L"Microsoft");
2202 InitializeObjectAttributes(&ObjectAttributes,
2203 &KeyName,
2204 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
2205 SoftwareKeyHandle,
2206 NULL);
2207 Status = NtCreateKey(&MicrosoftKeyHandle,
2208 KEY_CREATE_SUB_KEY,
2209 &ObjectAttributes,
2210 0,
2211 NULL,
2212 0,
2213 NULL);
2214 if (!NT_SUCCESS(Status))
2215 {
2216 DPRINT1("Failed to create key %wZ (Status: %08lx)\n", &KeyName, Status);
2217 goto Quit;
2218 }
2219
2220 RtlInitUnicodeString(&KeyName, L"Windows NT");
2221 InitializeObjectAttributes(&ObjectAttributes,
2222 &KeyName,
2223 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
2224 MicrosoftKeyHandle,
2225 NULL);
2226 Status = NtCreateKey(&WindowsNtKeyHandle,
2227 KEY_CREATE_SUB_KEY,
2228 &ObjectAttributes,
2229 0,
2230 NULL,
2231 0,
2232 NULL);
2233 if (!NT_SUCCESS(Status))
2234 {
2235 DPRINT1("Failed to create key %wZ (Status: %08lx)\n", &KeyName, Status);
2236 goto Quit;
2237 }
2238
2239 RtlInitUnicodeString(&KeyName, L"CurrentVersion");
2240 InitializeObjectAttributes(&ObjectAttributes,
2241 &KeyName,
2242 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
2243 WindowsNtKeyHandle,
2244 NULL);
2245 Status = NtCreateKey(&CurrentVersionKeyHandle,
2246 KEY_CREATE_SUB_KEY | KEY_SET_VALUE,
2247 &ObjectAttributes,
2248 0,
2249 NULL,
2250 0,
2251 NULL);
2252 if (!NT_SUCCESS(Status))
2253 {
2254 DPRINT1("Failed to create key %wZ (Status: %08lx)\n", &KeyName, Status);
2255 goto Quit;
2256 }
2257
2258 /* Set the 'CurrentVersion' value */
2259 RtlInitUnicodeString(&ValueName, L"CurrentVersion");
2260 NtSetValueKey(CurrentVersionKeyHandle,
2261 &ValueName,
2262 0,
2263 REG_SZ,
2264 CmVersionString.Buffer,
2265 CmVersionString.Length + sizeof(WCHAR));
2266
2267 /* Set the 'CurrentBuildNumber' value */
2268 RtlInitUnicodeString(&ValueName, L"CurrentBuildNumber");
2269 RtlInitEmptyUnicodeString(&ValueData, Buffer, sizeof(Buffer));
2270 RtlIntegerToUnicodeString(NtBuildNumber & 0xFFFF, 10, &ValueData);
2271 NtSetValueKey(CurrentVersionKeyHandle,
2272 &ValueName,
2273 0,
2274 REG_SZ,
2275 ValueData.Buffer,
2276 ValueData.Length + sizeof(WCHAR));
2277
2278 /* Set the 'BuildLab' value */
2279 RtlInitUnicodeString(&ValueName, L"BuildLab");
2280 RtlInitAnsiString(&TempString, NtBuildLab);
2281 Status = RtlAnsiStringToUnicodeString(&ValueData, &TempString, FALSE);
2282 if (NT_SUCCESS(Status))
2283 {
2284 NtSetValueKey(CurrentVersionKeyHandle,
2285 &ValueName,
2286 0,
2287 REG_SZ,
2288 ValueData.Buffer,
2289 ValueData.Length + sizeof(WCHAR));
2290 }
2291
2292 /* Set the 'CurrentType' value */
2293 RtlInitUnicodeString(&ValueName, L"CurrentType");
2294 RtlStringCbPrintfW(Buffer, sizeof(Buffer),
2295 L"%s %s",
2296 #ifdef CONFIG_SMP
2297 L"Multiprocessor"
2298 #else
2299 L"Uniprocessor"
2300 #endif
2301 ,
2302 #if (DBG == 1)
2303 L"Checked"
2304 #else
2305 L"Free"
2306 #endif
2307 );
2308 RtlInitUnicodeString(&ValueData, Buffer);
2309 NtSetValueKey(CurrentVersionKeyHandle,
2310 &ValueName,
2311 0,
2312 REG_SZ,
2313 ValueData.Buffer,
2314 ValueData.Length + sizeof(WCHAR));
2315
2316 /* Set the 'CSDVersion' value */
2317 RtlInitUnicodeString(&ValueName, L"CSDVersion");
2318 if (CmCSDVersionString.Length != 0)
2319 {
2320 NtSetValueKey(CurrentVersionKeyHandle,
2321 &ValueName,
2322 0,
2323 REG_SZ,
2324 CmCSDVersionString.Buffer,
2325 CmCSDVersionString.Length + sizeof(WCHAR));
2326 }
2327 else
2328 {
2329 NtDeleteValueKey(CurrentVersionKeyHandle, &ValueName);
2330 }
2331
2332 /* Set the 'CSDBuildNumber' value */
2333 RtlInitUnicodeString(&ValueName, L"CSDBuildNumber");
2334 if (CmNtSpBuildNumber != 0)
2335 {
2336 RtlInitEmptyUnicodeString(&ValueData, Buffer, sizeof(Buffer));
2337 RtlIntegerToUnicodeString(CmNtSpBuildNumber, 10, &ValueData);
2338 NtSetValueKey(CurrentVersionKeyHandle,
2339 &ValueName,
2340 0,
2341 REG_SZ,
2342 ValueData.Buffer,
2343 ValueData.Length + sizeof(WCHAR));
2344 }
2345 else
2346 {
2347 NtDeleteValueKey(CurrentVersionKeyHandle, &ValueName);
2348 }
2349
2350 /* Set the 'SystemRoot' value */
2351 RtlInitUnicodeString(&ValueName, L"SystemRoot");
2352 NtSetValueKey(CurrentVersionKeyHandle,
2353 &ValueName,
2354 0,
2355 REG_SZ,
2356 NtSystemRoot.Buffer,
2357 NtSystemRoot.Length + sizeof(WCHAR));
2358
2359 Quit:
2360 /* Close the keys */
2361 if (CurrentVersionKeyHandle != NULL)
2362 NtClose(CurrentVersionKeyHandle);
2363
2364 if (WindowsNtKeyHandle != NULL)
2365 NtClose(WindowsNtKeyHandle);
2366
2367 if (MicrosoftKeyHandle != NULL)
2368 NtClose(MicrosoftKeyHandle);
2369
2370 if (SoftwareKeyHandle != NULL)
2371 NtClose(SoftwareKeyHandle);
2372 }
2373
2374 /* EOF */