[NTOS:CONFIG]
[reactos.git] / reactos / 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_ PWSTR LinkKeyName,
44 _In_z_ PWSTR TargetKeyName)
45 {
46 OBJECT_ATTRIBUTES ObjectAttributes;
47 UNICODE_STRING LinkKeyName_U;
48 HANDLE TargetKeyHandle;
49 ULONG Disposition;
50 NTSTATUS Status;
51 PAGED_CODE();
52
53 /* Initialize the object attributes */
54 RtlInitUnicodeString(&LinkKeyName_U, LinkKeyName);
55 InitializeObjectAttributes(&ObjectAttributes,
56 &LinkKeyName_U,
57 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
58 NULL,
59 NULL);
60
61 /* Create the link key */
62 Status = ZwCreateKey(&TargetKeyHandle,
63 KEY_CREATE_LINK,
64 &ObjectAttributes,
65 0,
66 NULL,
67 REG_OPTION_VOLATILE | REG_OPTION_CREATE_LINK,
68 &Disposition);
69 if (!NT_SUCCESS(Status))
70 {
71 DPRINT1("CM: CmpLinkKeyToHive: couldn't create %S Status = 0x%lx\n",
72 LinkKeyName, Status);
73 return FALSE;
74 }
75
76 /* Check if the new key was actually created */
77 if (Disposition != REG_CREATED_NEW_KEY)
78 {
79 DPRINT1("CM: CmpLinkKeyToHive: %S already exists!\n", LinkKeyName);
80 ZwClose(TargetKeyHandle);
81 return FALSE;
82 }
83
84 /* Set the target key name as link target */
85 Status = ZwSetValueKey(TargetKeyHandle,
86 &CmSymbolicLinkValueName,
87 0,
88 REG_LINK,
89 TargetKeyName,
90 (ULONG)wcslen(TargetKeyName) * sizeof(WCHAR));
91
92 /* Close the link key handle */
93 ObCloseHandle(TargetKeyHandle, KernelMode);
94
95 if (!NT_SUCCESS(Status))
96 {
97 DPRINT1("CM: CmpLinkKeyToHive: couldn't create symbolic link for %S\n",
98 TargetKeyName);
99 return FALSE;
100 }
101
102 return TRUE;
103 }
104
105 VOID
106 NTAPI
107 CmpDeleteKeyObject(PVOID DeletedObject)
108 {
109 PCM_KEY_BODY KeyBody = (PCM_KEY_BODY)DeletedObject;
110 PCM_KEY_CONTROL_BLOCK Kcb;
111 REG_KEY_HANDLE_CLOSE_INFORMATION KeyHandleCloseInfo;
112 REG_POST_OPERATION_INFORMATION PostOperationInfo;
113 NTSTATUS Status;
114 PAGED_CODE();
115
116 /* First off, prepare the handle close information callback */
117 PostOperationInfo.Object = KeyBody;
118 KeyHandleCloseInfo.Object = KeyBody;
119 Status = CmiCallRegisteredCallbacks(RegNtPreKeyHandleClose,
120 &KeyHandleCloseInfo);
121 if (!NT_SUCCESS(Status))
122 {
123 /* If we failed, notify the post routine */
124 PostOperationInfo.Status = Status;
125 CmiCallRegisteredCallbacks(RegNtPostKeyHandleClose, &PostOperationInfo);
126 return;
127 }
128
129 /* Acquire hive lock */
130 CmpLockRegistry();
131
132 /* Make sure this is a valid key body */
133 if (KeyBody->Type == CM_KEY_BODY_TYPE)
134 {
135 /* Get the KCB */
136 Kcb = KeyBody->KeyControlBlock;
137 if (Kcb)
138 {
139 /* Delist the key */
140 DelistKeyBodyFromKCB(KeyBody, FALSE);
141
142 /* Dereference the KCB */
143 CmpDelayDerefKeyControlBlock(Kcb);
144 }
145 }
146
147 /* Release the registry lock */
148 CmpUnlockRegistry();
149
150 /* Do the post callback */
151 PostOperationInfo.Status = STATUS_SUCCESS;
152 CmiCallRegisteredCallbacks(RegNtPostKeyHandleClose, &PostOperationInfo);
153 }
154
155 VOID
156 NTAPI
157 CmpCloseKeyObject(IN PEPROCESS Process OPTIONAL,
158 IN PVOID Object,
159 IN ACCESS_MASK GrantedAccess,
160 IN ULONG ProcessHandleCount,
161 IN ULONG SystemHandleCount)
162 {
163 PCM_KEY_BODY KeyBody = (PCM_KEY_BODY)Object;
164 PAGED_CODE();
165
166 /* Don't do anything if we're not the last handle */
167 if (SystemHandleCount > 1) return;
168
169 /* Make sure we're a valid key body */
170 if (KeyBody->Type == CM_KEY_BODY_TYPE)
171 {
172 /* Don't do anything if we don't have a notify block */
173 if (!KeyBody->NotifyBlock) return;
174
175 /* This shouldn't happen yet */
176 ASSERT(FALSE);
177 }
178 }
179
180 NTSTATUS
181 NTAPI
182 CmpQueryKeyName(IN PVOID ObjectBody,
183 IN BOOLEAN HasName,
184 IN OUT POBJECT_NAME_INFORMATION ObjectNameInfo,
185 IN ULONG Length,
186 OUT PULONG ReturnLength,
187 IN KPROCESSOR_MODE PreviousMode)
188 {
189 PUNICODE_STRING KeyName;
190 ULONG BytesToCopy;
191 NTSTATUS Status = STATUS_SUCCESS;
192 PCM_KEY_BODY KeyBody = (PCM_KEY_BODY)ObjectBody;
193 PCM_KEY_CONTROL_BLOCK Kcb = KeyBody->KeyControlBlock;
194
195 /* Acquire hive lock */
196 CmpLockRegistry();
197
198 /* Lock KCB shared */
199 CmpAcquireKcbLockShared(Kcb);
200
201 /* Check if it's a deleted block */
202 if (Kcb->Delete)
203 {
204 /* Release the locks */
205 CmpReleaseKcbLock(Kcb);
206 CmpUnlockRegistry();
207
208 /* Let the caller know it's deleted */
209 return STATUS_KEY_DELETED;
210 }
211
212 /* Get the name */
213 KeyName = CmpConstructName(Kcb);
214
215 /* Release the locks */
216 CmpReleaseKcbLock(Kcb);
217 CmpUnlockRegistry();
218
219 /* Check if we got the name */
220 if (!KeyName) return STATUS_INSUFFICIENT_RESOURCES;
221
222 /* Set the returned length */
223 *ReturnLength = KeyName->Length + sizeof(OBJECT_NAME_INFORMATION) + sizeof(WCHAR);
224
225 /* Calculate amount of bytes to copy into the buffer */
226 BytesToCopy = KeyName->Length + sizeof(WCHAR);
227
228 /* Check if the provided buffer is too small to fit even anything */
229 if ((Length <= sizeof(OBJECT_NAME_INFORMATION)) ||
230 ((Length < (*ReturnLength)) && (BytesToCopy < sizeof(WCHAR))))
231 {
232 /* Free the buffer allocated by CmpConstructName */
233 ExFreePoolWithTag(KeyName, TAG_CM);
234
235 /* Return buffer length failure without writing anything there because nothing fits */
236 return STATUS_INFO_LENGTH_MISMATCH;
237 }
238
239 /* Check if the provided buffer can be partially written */
240 if (Length < (*ReturnLength))
241 {
242 /* Yes, indicate so in the return status */
243 Status = STATUS_INFO_LENGTH_MISMATCH;
244
245 /* Calculate amount of bytes which the provided buffer could handle */
246 BytesToCopy = Length - sizeof(OBJECT_NAME_INFORMATION);
247 }
248
249 /* Remove the null termination character from the size */
250 BytesToCopy -= sizeof(WCHAR);
251
252 /* Fill in the result */
253 _SEH2_TRY
254 {
255 /* Return data to user */
256 ObjectNameInfo->Name.Buffer = (PWCHAR)(ObjectNameInfo + 1);
257 ObjectNameInfo->Name.MaximumLength = KeyName->Length;
258 ObjectNameInfo->Name.Length = KeyName->Length;
259
260 /* Copy string content*/
261 RtlCopyMemory(ObjectNameInfo->Name.Buffer,
262 KeyName->Buffer,
263 BytesToCopy);
264
265 /* Null terminate it */
266 ObjectNameInfo->Name.Buffer[BytesToCopy / sizeof(WCHAR)] = 0;
267 }
268 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
269 {
270 /* Get the status */
271 Status = _SEH2_GetExceptionCode();
272 }
273 _SEH2_END;
274
275 /* Free the buffer allocated by CmpConstructName */
276 ExFreePoolWithTag(KeyName, TAG_CM);
277
278 /* Return status */
279 return Status;
280 }
281
282 NTSTATUS
283 NTAPI
284 CmpInitHiveFromFile(IN PCUNICODE_STRING HiveName,
285 IN ULONG HiveFlags,
286 OUT PCMHIVE *Hive,
287 IN OUT PBOOLEAN New,
288 IN ULONG CheckFlags)
289 {
290 ULONG HiveDisposition, LogDisposition;
291 HANDLE FileHandle = NULL, LogHandle = NULL;
292 NTSTATUS Status;
293 ULONG Operation, FileType;
294 PCMHIVE NewHive;
295 PAGED_CODE();
296
297 /* Assume failure */
298 *Hive = NULL;
299
300 /* Open or create the hive files */
301 Status = CmpOpenHiveFiles(HiveName,
302 L".LOG",
303 &FileHandle,
304 &LogHandle,
305 &HiveDisposition,
306 &LogDisposition,
307 *New,
308 FALSE,
309 TRUE,
310 NULL);
311 if (!NT_SUCCESS(Status)) return Status;
312
313 /* Check if we have a log handle */
314 FileType = (LogHandle) ? HFILE_TYPE_LOG : HFILE_TYPE_PRIMARY;
315
316 /* Check if we created or opened the hive */
317 if (HiveDisposition == FILE_CREATED)
318 {
319 /* Do a create operation */
320 Operation = HINIT_CREATE;
321 *New = TRUE;
322 }
323 else
324 {
325 /* Open it as a file */
326 Operation = HINIT_FILE;
327 *New = FALSE;
328 }
329
330 /* Check if we're sharing hives */
331 if (CmpShareSystemHives)
332 {
333 /* Then force using the primary hive */
334 FileType = HFILE_TYPE_PRIMARY;
335 if (LogHandle)
336 {
337 /* Get rid of the log handle */
338 ZwClose(LogHandle);
339 LogHandle = NULL;
340 }
341 }
342
343 /* Check if we're too late */
344 if (HvShutdownComplete)
345 {
346 /* Fail */
347 ZwClose(FileHandle);
348 if (LogHandle) ZwClose(LogHandle);
349 return STATUS_TOO_LATE;
350 }
351
352 /* Initialize the hive */
353 Status = CmpInitializeHive(&NewHive,
354 Operation,
355 HiveFlags,
356 FileType,
357 NULL,
358 FileHandle,
359 LogHandle,
360 NULL,
361 HiveName,
362 CheckFlags);
363 if (!NT_SUCCESS(Status))
364 {
365 /* Fail */
366 ZwClose(FileHandle);
367 if (LogHandle) ZwClose(LogHandle);
368 return Status;
369 }
370
371 /* Success, return hive */
372 *Hive = NewHive;
373
374 /* Duplicate the hive name */
375 NewHive->FileFullPath.Buffer = ExAllocatePoolWithTag(PagedPool,
376 HiveName->Length,
377 TAG_CM);
378 if (NewHive->FileFullPath.Buffer)
379 {
380 /* Copy the string */
381 RtlCopyMemory(NewHive->FileFullPath.Buffer,
382 HiveName->Buffer,
383 HiveName->Length);
384 NewHive->FileFullPath.Length = HiveName->Length;
385 NewHive->FileFullPath.MaximumLength = HiveName->MaximumLength;
386 }
387
388 /* Return success */
389 return STATUS_SUCCESS;
390 }
391
392 NTSTATUS
393 NTAPI
394 INIT_FUNCTION
395 CmpSetSystemValues(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
396 {
397 OBJECT_ATTRIBUTES ObjectAttributes;
398 UNICODE_STRING KeyName, ValueName = { 0, 0, NULL };
399 HANDLE KeyHandle = NULL;
400 NTSTATUS Status;
401 ASSERT(LoaderBlock != NULL);
402
403 /* Setup attributes for loader options */
404 RtlInitUnicodeString(&KeyName,
405 L"\\REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\"
406 L"Control");
407 InitializeObjectAttributes(&ObjectAttributes,
408 &KeyName,
409 OBJ_CASE_INSENSITIVE,
410 NULL,
411 NULL);
412 Status = NtOpenKey(&KeyHandle, KEY_WRITE, &ObjectAttributes);
413 if (!NT_SUCCESS(Status)) goto Quickie;
414
415 /* Key opened, now write to the key */
416 RtlInitUnicodeString(&KeyName, L"SystemStartOptions");
417 Status = NtSetValueKey(KeyHandle,
418 &KeyName,
419 0,
420 REG_SZ,
421 CmpLoadOptions.Buffer,
422 CmpLoadOptions.Length);
423 if (!NT_SUCCESS(Status)) goto Quickie;
424
425 /* Setup value name for system boot device in ARC format */
426 RtlInitUnicodeString(&KeyName, L"SystemBootDevice");
427 RtlCreateUnicodeStringFromAsciiz(&ValueName, LoaderBlock->ArcBootDeviceName);
428 Status = NtSetValueKey(KeyHandle,
429 &KeyName,
430 0,
431 REG_SZ,
432 ValueName.Buffer,
433 ValueName.Length);
434
435 Quickie:
436 /* Free the buffers */
437 RtlFreeUnicodeString(&ValueName);
438
439 /* Close the key and return */
440 if (KeyHandle) NtClose(KeyHandle);
441
442 /* Return the status */
443 return (ExpInTextModeSetup ? STATUS_SUCCESS : Status);
444 }
445
446 static
447 NTSTATUS
448 INIT_FUNCTION
449 CmpCreateHardwareProfile(HANDLE ControlSetHandle)
450 {
451 OBJECT_ATTRIBUTES ObjectAttributes;
452 UNICODE_STRING KeyName;
453 HANDLE ProfilesHandle = NULL;
454 HANDLE ProfileHandle = NULL;
455 ULONG Disposition;
456 NTSTATUS Status;
457
458 DPRINT("CmpCreateHardwareProfile()\n");
459
460 /* Create the Hardware Profiles key */
461 RtlInitUnicodeString(&KeyName, L"Hardware Profiles");
462 InitializeObjectAttributes(&ObjectAttributes,
463 &KeyName,
464 OBJ_CASE_INSENSITIVE,
465 ControlSetHandle,
466 NULL);
467 Status = NtCreateKey(&ProfilesHandle,
468 KEY_ALL_ACCESS,
469 &ObjectAttributes,
470 0,
471 NULL,
472 0,
473 &Disposition);
474 if (!NT_SUCCESS(Status))
475 {
476 DPRINT1("Creating the Hardware Profile key failed\n");
477 goto done;
478 }
479
480 /* Sanity check */
481 ASSERT(Disposition == REG_CREATED_NEW_KEY);
482
483 /* Create the 0000 key */
484 RtlInitUnicodeString(&KeyName, L"0000");
485 InitializeObjectAttributes(&ObjectAttributes,
486 &KeyName,
487 OBJ_CASE_INSENSITIVE,
488 ProfilesHandle,
489 NULL);
490 Status = NtCreateKey(&ProfileHandle,
491 KEY_ALL_ACCESS,
492 &ObjectAttributes,
493 0,
494 NULL,
495 0,
496 &Disposition);
497 if (!NT_SUCCESS(Status))
498 {
499 DPRINT1("Creating the Hardware Profile\\0000 key failed\n");
500 goto done;
501 }
502
503 /* Sanity check */
504 ASSERT(Disposition == REG_CREATED_NEW_KEY);
505
506 done:
507 if (ProfilesHandle)
508 NtClose(ProfilesHandle);
509
510 if (ProfileHandle)
511 NtClose(ProfileHandle);
512
513 DPRINT1("CmpCreateHardwareProfile() done\n");
514
515 return Status;
516 }
517
518 NTSTATUS
519 NTAPI
520 INIT_FUNCTION
521 CmpCreateControlSet(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
522 {
523 UNICODE_STRING ConfigName = RTL_CONSTANT_STRING(L"Control\\IDConfigDB");
524 UNICODE_STRING SelectName =
525 RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\Select");
526 UNICODE_STRING KeyName;
527 OBJECT_ATTRIBUTES ObjectAttributes;
528 CHAR ValueInfoBuffer[128];
529 PKEY_VALUE_FULL_INFORMATION ValueInfo;
530 CHAR Buffer[128];
531 WCHAR UnicodeBuffer[128];
532 HANDLE SelectHandle, KeyHandle, ConfigHandle = NULL, ProfileHandle = NULL;
533 HANDLE ParentHandle = NULL;
534 ULONG ControlSet, HwProfile;
535 ANSI_STRING TempString;
536 NTSTATUS Status;
537 ULONG ResultLength, Disposition;
538 PLOADER_PARAMETER_EXTENSION LoaderExtension;
539 PAGED_CODE();
540
541 /* Open the select key */
542 InitializeObjectAttributes(&ObjectAttributes,
543 &SelectName,
544 OBJ_CASE_INSENSITIVE,
545 NULL,
546 NULL);
547 Status = NtOpenKey(&SelectHandle, KEY_READ, &ObjectAttributes);
548 if (!NT_SUCCESS(Status))
549 {
550 /* ReactOS Hack: Hard-code current to 001 for SetupLdr */
551 if (!LoaderBlock->RegistryBase)
552 {
553 /* Build the ControlSet001 key */
554 RtlInitUnicodeString(&KeyName,
555 L"\\Registry\\Machine\\System\\ControlSet001");
556 InitializeObjectAttributes(&ObjectAttributes,
557 &KeyName,
558 OBJ_CASE_INSENSITIVE,
559 NULL,
560 NULL);
561 Status = NtCreateKey(&KeyHandle,
562 KEY_ALL_ACCESS,
563 &ObjectAttributes,
564 0,
565 NULL,
566 0,
567 &Disposition);
568 if (!NT_SUCCESS(Status)) return Status;
569
570 /* Create the Hardware Profile keys */
571 Status = CmpCreateHardwareProfile(KeyHandle);
572 if (!NT_SUCCESS(Status))
573 return Status;
574
575 /* Don't need the handle */
576 ZwClose(KeyHandle);
577
578 /* Use hard-coded setting */
579 ControlSet = 1;
580 goto UseSet;
581 }
582
583 /* Fail for real boots */
584 return Status;
585 }
586
587 /* Open the current value */
588 RtlInitUnicodeString(&KeyName, L"Current");
589 Status = NtQueryValueKey(SelectHandle,
590 &KeyName,
591 KeyValueFullInformation,
592 ValueInfoBuffer,
593 sizeof(ValueInfoBuffer),
594 &ResultLength);
595 NtClose(SelectHandle);
596 if (!NT_SUCCESS(Status)) return Status;
597
598 /* Get the actual value pointer, and get the control set ID */
599 ValueInfo = (PKEY_VALUE_FULL_INFORMATION)ValueInfoBuffer;
600 ControlSet = *(PULONG)((PUCHAR)ValueInfo + ValueInfo->DataOffset);
601
602 /* Create the current control set key */
603 UseSet:
604 RtlInitUnicodeString(&KeyName,
605 L"\\Registry\\Machine\\System\\CurrentControlSet");
606 InitializeObjectAttributes(&ObjectAttributes,
607 &KeyName,
608 OBJ_CASE_INSENSITIVE,
609 NULL,
610 NULL);
611 Status = NtCreateKey(&KeyHandle,
612 KEY_CREATE_LINK,
613 &ObjectAttributes,
614 0,
615 NULL,
616 REG_OPTION_VOLATILE | REG_OPTION_CREATE_LINK,
617 &Disposition);
618 if (!NT_SUCCESS(Status)) return Status;
619
620 /* Sanity check */
621 ASSERT(Disposition == REG_CREATED_NEW_KEY);
622
623 /* Initialize the symbolic link name */
624 sprintf(Buffer,
625 "\\Registry\\Machine\\System\\ControlSet%03ld",
626 ControlSet);
627 RtlInitAnsiString(&TempString, Buffer);
628
629 /* Create a Unicode string out of it */
630 KeyName.MaximumLength = sizeof(UnicodeBuffer);
631 KeyName.Buffer = UnicodeBuffer;
632 Status = RtlAnsiStringToUnicodeString(&KeyName, &TempString, FALSE);
633
634 /* Set the value */
635 Status = NtSetValueKey(KeyHandle,
636 &CmSymbolicLinkValueName,
637 0,
638 REG_LINK,
639 KeyName.Buffer,
640 KeyName.Length);
641 if (!NT_SUCCESS(Status)) return Status;
642
643 /* Get the configuration database key */
644 InitializeObjectAttributes(&ObjectAttributes,
645 &ConfigName,
646 OBJ_CASE_INSENSITIVE,
647 KeyHandle,
648 NULL);
649 Status = NtOpenKey(&ConfigHandle, KEY_READ, &ObjectAttributes);
650 NtClose(KeyHandle);
651
652 /* Check if we don't have one */
653 if (!NT_SUCCESS(Status))
654 {
655 /* Cleanup and exit */
656 ConfigHandle = 0;
657 goto Cleanup;
658 }
659
660 /* ReactOS Hack: Hard-code current to 001 for SetupLdr */
661 if (!LoaderBlock->RegistryBase)
662 {
663 HwProfile = 0;
664 }
665 else
666 {
667 /* Now get the current config */
668 RtlInitUnicodeString(&KeyName, L"CurrentConfig");
669 Status = NtQueryValueKey(ConfigHandle,
670 &KeyName,
671 KeyValueFullInformation,
672 ValueInfoBuffer,
673 sizeof(ValueInfoBuffer),
674 &ResultLength);
675
676 /* Set pointer to buffer */
677 ValueInfo = (PKEY_VALUE_FULL_INFORMATION)ValueInfoBuffer;
678
679 /* Check if we failed or got a non DWORD-value */
680 if (!(NT_SUCCESS(Status)) || (ValueInfo->Type != REG_DWORD)) goto Cleanup;
681
682 /* Get the hadware profile */
683 HwProfile = *(PULONG)((PUCHAR)ValueInfo + ValueInfo->DataOffset);
684 }
685
686 /* Open the hardware profile key */
687 RtlInitUnicodeString(&KeyName,
688 L"\\Registry\\Machine\\System\\CurrentControlSet"
689 L"\\Hardware Profiles");
690 InitializeObjectAttributes(&ObjectAttributes,
691 &KeyName,
692 OBJ_CASE_INSENSITIVE,
693 NULL,
694 NULL);
695 Status = NtOpenKey(&ParentHandle, KEY_READ, &ObjectAttributes);
696 if (!NT_SUCCESS(Status))
697 {
698 /* Exit and clean up */
699 ParentHandle = 0;
700 goto Cleanup;
701 }
702
703 /* Build the profile name */
704 sprintf(Buffer, "%04ld", HwProfile);
705 RtlInitAnsiString(&TempString, Buffer);
706
707 /* Convert it to Unicode */
708 KeyName.MaximumLength = sizeof(UnicodeBuffer);
709 KeyName.Buffer = UnicodeBuffer;
710 Status = RtlAnsiStringToUnicodeString(&KeyName,
711 &TempString,
712 FALSE);
713 ASSERT(Status == STATUS_SUCCESS);
714
715 /* Open the associated key */
716 InitializeObjectAttributes(&ObjectAttributes,
717 &KeyName,
718 OBJ_CASE_INSENSITIVE,
719 ParentHandle,
720 NULL);
721 Status = NtOpenKey(&ProfileHandle,
722 KEY_READ | KEY_WRITE,
723 &ObjectAttributes);
724 if (!NT_SUCCESS (Status))
725 {
726 /* Cleanup and exit */
727 ProfileHandle = 0;
728 goto Cleanup;
729 }
730
731 /* Check if we have a loader block extension */
732 LoaderExtension = LoaderBlock->Extension;
733 if (LoaderExtension)
734 {
735 DPRINT("ReactOS doesn't support NTLDR Profiles yet!\n");
736 }
737
738 /* Create the current hardware profile key */
739 RtlInitUnicodeString(&KeyName,
740 L"\\Registry\\Machine\\System\\CurrentControlSet\\"
741 L"Hardware Profiles\\Current");
742 InitializeObjectAttributes(&ObjectAttributes,
743 &KeyName,
744 OBJ_CASE_INSENSITIVE,
745 NULL,
746 NULL);
747 Status = NtCreateKey(&KeyHandle,
748 KEY_CREATE_LINK,
749 &ObjectAttributes,
750 0,
751 NULL,
752 REG_OPTION_VOLATILE | REG_OPTION_CREATE_LINK,
753 &Disposition);
754 if (NT_SUCCESS(Status))
755 {
756 /* Sanity check */
757 ASSERT(Disposition == REG_CREATED_NEW_KEY);
758
759 /* Create the profile name */
760 sprintf(Buffer,
761 "\\Registry\\Machine\\System\\CurrentControlSet\\"
762 "Hardware Profiles\\%04ld",
763 HwProfile);
764 RtlInitAnsiString(&TempString, Buffer);
765
766 /* Convert it to Unicode */
767 KeyName.MaximumLength = sizeof(UnicodeBuffer);
768 KeyName.Buffer = UnicodeBuffer;
769 Status = RtlAnsiStringToUnicodeString(&KeyName,
770 &TempString,
771 FALSE);
772 ASSERT(STATUS_SUCCESS == Status);
773
774 /* Set it */
775 Status = NtSetValueKey(KeyHandle,
776 &CmSymbolicLinkValueName,
777 0,
778 REG_LINK,
779 KeyName.Buffer,
780 KeyName.Length);
781 NtClose(KeyHandle);
782 }
783
784 /* Close every opened handle */
785 Cleanup:
786 if (ConfigHandle) NtClose(ConfigHandle);
787 if (ProfileHandle) NtClose(ProfileHandle);
788 if (ParentHandle) NtClose(ParentHandle);
789
790 DPRINT1("CmpCreateControlSet() done\n");
791
792 /* Return success */
793 return STATUS_SUCCESS;
794 }
795
796 NTSTATUS
797 NTAPI
798 CmpLinkHiveToMaster(IN PUNICODE_STRING LinkName,
799 IN HANDLE RootDirectory,
800 IN PCMHIVE RegistryHive,
801 IN BOOLEAN Allocate,
802 IN PSECURITY_DESCRIPTOR SecurityDescriptor)
803 {
804 OBJECT_ATTRIBUTES ObjectAttributes;
805 NTSTATUS Status;
806 CM_PARSE_CONTEXT ParseContext = {0};
807 HANDLE KeyHandle;
808 PCM_KEY_BODY KeyBody;
809 PAGED_CODE();
810
811 /* Setup the object attributes */
812 InitializeObjectAttributes(&ObjectAttributes,
813 LinkName,
814 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
815 RootDirectory,
816 SecurityDescriptor);
817
818 /* Setup the parse context */
819 ParseContext.CreateLink = TRUE;
820 ParseContext.CreateOperation = TRUE;
821 ParseContext.ChildHive.KeyHive = &RegistryHive->Hive;
822
823 /* Check if we have a root keycell or if we need to create it */
824 if (Allocate)
825 {
826 /* Create it */
827 ParseContext.ChildHive.KeyCell = HCELL_NIL;
828 }
829 else
830 {
831 /* We have one */
832 ParseContext.ChildHive.KeyCell = RegistryHive->Hive.BaseBlock->RootCell;
833 }
834
835 /* Create the link node */
836 Status = ObOpenObjectByName(&ObjectAttributes,
837 CmpKeyObjectType,
838 KernelMode,
839 NULL,
840 KEY_READ | KEY_WRITE,
841 (PVOID)&ParseContext,
842 &KeyHandle);
843 if (!NT_SUCCESS(Status)) return Status;
844
845 /* Mark the hive as clean */
846 RegistryHive->Hive.DirtyFlag = FALSE;
847
848 /* ReactOS Hack: Keep alive */
849 Status = ObReferenceObjectByHandle(KeyHandle,
850 0,
851 CmpKeyObjectType,
852 KernelMode,
853 (PVOID*)&KeyBody,
854 NULL);
855 ASSERT(NT_SUCCESS(Status));
856
857 /* Close the extra handle */
858 ZwClose(KeyHandle);
859 return STATUS_SUCCESS;
860 }
861
862 BOOLEAN
863 NTAPI
864 INIT_FUNCTION
865 CmpInitializeSystemHive(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
866 {
867 PVOID HiveBase;
868 ANSI_STRING LoadString;
869 PVOID Buffer;
870 ULONG Length;
871 NTSTATUS Status;
872 BOOLEAN Allocate;
873 UNICODE_STRING KeyName;
874 PCMHIVE SystemHive = NULL;
875 UNICODE_STRING HiveName = RTL_CONSTANT_STRING(L"SYSTEM");
876 PSECURITY_DESCRIPTOR SecurityDescriptor;
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 RtlAnsiStringToUnicodeString(&CmpLoadOptions, &LoadString, FALSE);
896 CmpLoadOptions.Buffer[LoadString.Length] = UNICODE_NULL;
897 CmpLoadOptions.Length += sizeof(WCHAR);
898
899 /* Get the System Hive base address */
900 HiveBase = LoaderBlock->RegistryBase;
901 if (HiveBase)
902 {
903 /* Import it */
904 Status = CmpInitializeHive(&SystemHive,
905 HINIT_MEMORY,
906 HIVE_NOLAZYFLUSH,
907 HFILE_TYPE_LOG,
908 HiveBase,
909 NULL,
910 NULL,
911 NULL,
912 &HiveName,
913 2);
914 if (!NT_SUCCESS(Status)) return FALSE;
915
916 /* Set the hive filename */
917 RtlCreateUnicodeString(&SystemHive->FileFullPath,
918 L"\\SystemRoot\\System32\\Config\\SYSTEM");
919
920 /* We imported, no need to create a new hive */
921 Allocate = FALSE;
922
923 /* Manually set the hive as volatile, if in Live CD mode */
924 if (CmpShareSystemHives) SystemHive->Hive.HiveFlags = HIVE_VOLATILE;
925 }
926 else
927 {
928 /* Create it */
929 Status = CmpInitializeHive(&SystemHive,
930 HINIT_CREATE,
931 HIVE_NOLAZYFLUSH,
932 HFILE_TYPE_LOG,
933 NULL,
934 NULL,
935 NULL,
936 NULL,
937 &HiveName,
938 0);
939 if (!NT_SUCCESS(Status)) return FALSE;
940
941 /* Set the hive filename */
942 RtlCreateUnicodeString(&SystemHive->FileFullPath,
943 L"\\SystemRoot\\System32\\Config\\SYSTEM");
944
945 /* Tell CmpLinkHiveToMaster to allocate a hive */
946 Allocate = TRUE;
947 }
948
949 /* Save the boot type */
950 CmpBootType = SystemHive->Hive.BaseBlock->BootType;
951
952 /* Are we in self-healing mode? */
953 if (!CmSelfHeal)
954 {
955 /* Disable self-healing internally and check if boot type wanted it */
956 CmpSelfHeal = FALSE;
957 if (CmpBootType & 4)
958 {
959 /* We're disabled, so bugcheck */
960 KeBugCheckEx(BAD_SYSTEM_CONFIG_INFO,
961 3,
962 3,
963 (ULONG_PTR)SystemHive,
964 0);
965 }
966 }
967
968 /* Create the default security descriptor */
969 SecurityDescriptor = CmpHiveRootSecurityDescriptor();
970
971 /* Attach it to the system key */
972 RtlInitUnicodeString(&KeyName, L"\\Registry\\Machine\\SYSTEM");
973 Status = CmpLinkHiveToMaster(&KeyName,
974 NULL,
975 SystemHive,
976 Allocate,
977 SecurityDescriptor);
978
979 /* Free the security descriptor */
980 ExFreePoolWithTag(SecurityDescriptor, TAG_CMSD);
981 if (!NT_SUCCESS(Status)) return FALSE;
982
983 /* Add the hive to the hive list */
984 CmpMachineHiveList[3].CmHive = SystemHive;
985
986 /* Success! */
987 return TRUE;
988 }
989
990 NTSTATUS
991 NTAPI
992 INIT_FUNCTION
993 CmpCreateObjectTypes(VOID)
994 {
995 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer;
996 UNICODE_STRING Name;
997 GENERIC_MAPPING CmpKeyMapping = {KEY_READ,
998 KEY_WRITE,
999 KEY_EXECUTE,
1000 KEY_ALL_ACCESS};
1001 PAGED_CODE();
1002
1003 /* Initialize the Key object type */
1004 RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer));
1005 RtlInitUnicodeString(&Name, L"Key");
1006 ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer);
1007 ObjectTypeInitializer.DefaultPagedPoolCharge = sizeof(CM_KEY_BODY);
1008 ObjectTypeInitializer.GenericMapping = CmpKeyMapping;
1009 ObjectTypeInitializer.PoolType = PagedPool;
1010 ObjectTypeInitializer.ValidAccessMask = KEY_ALL_ACCESS;
1011 ObjectTypeInitializer.UseDefaultObject = TRUE;
1012 ObjectTypeInitializer.DeleteProcedure = CmpDeleteKeyObject;
1013 ObjectTypeInitializer.ParseProcedure = CmpParseKey;
1014 ObjectTypeInitializer.SecurityProcedure = CmpSecurityMethod;
1015 ObjectTypeInitializer.QueryNameProcedure = CmpQueryKeyName;
1016 ObjectTypeInitializer.CloseProcedure = CmpCloseKeyObject;
1017 ObjectTypeInitializer.SecurityRequired = TRUE;
1018 ObjectTypeInitializer.InvalidAttributes = OBJ_EXCLUSIVE | OBJ_PERMANENT;
1019
1020 /* Create it */
1021 return ObCreateObjectType(&Name, &ObjectTypeInitializer, NULL, &CmpKeyObjectType);
1022 }
1023
1024 BOOLEAN
1025 NTAPI
1026 INIT_FUNCTION
1027 CmpCreateRootNode(IN PHHIVE Hive,
1028 IN PCWSTR Name,
1029 OUT PHCELL_INDEX Index)
1030 {
1031 UNICODE_STRING KeyName;
1032 PCM_KEY_NODE KeyCell;
1033 LARGE_INTEGER SystemTime;
1034 PAGED_CODE();
1035
1036 /* Initialize the node name and allocate it */
1037 RtlInitUnicodeString(&KeyName, Name);
1038 *Index = HvAllocateCell(Hive,
1039 FIELD_OFFSET(CM_KEY_NODE, Name) +
1040 CmpNameSize(Hive, &KeyName),
1041 Stable,
1042 HCELL_NIL);
1043 if (*Index == HCELL_NIL) return FALSE;
1044
1045 /* Set the cell index and get the data */
1046 Hive->BaseBlock->RootCell = *Index;
1047 KeyCell = (PCM_KEY_NODE)HvGetCell(Hive, *Index);
1048 if (!KeyCell) return FALSE;
1049
1050 /* Setup the cell */
1051 KeyCell->Signature = (USHORT)CM_KEY_NODE_SIGNATURE;
1052 KeyCell->Flags = KEY_HIVE_ENTRY | KEY_NO_DELETE;
1053 KeQuerySystemTime(&SystemTime);
1054 KeyCell->LastWriteTime = SystemTime;
1055 KeyCell->Parent = HCELL_NIL;
1056 KeyCell->SubKeyCounts[Stable] = 0;
1057 KeyCell->SubKeyCounts[Volatile] = 0;
1058 KeyCell->SubKeyLists[Stable] = HCELL_NIL;
1059 KeyCell->SubKeyLists[Volatile] = HCELL_NIL;
1060 KeyCell->ValueList.Count = 0;
1061 KeyCell->ValueList.List = HCELL_NIL;
1062 KeyCell->Security = HCELL_NIL;
1063 KeyCell->Class = HCELL_NIL;
1064 KeyCell->ClassLength = 0;
1065 KeyCell->MaxNameLen = 0;
1066 KeyCell->MaxClassLen = 0;
1067 KeyCell->MaxValueNameLen = 0;
1068 KeyCell->MaxValueDataLen = 0;
1069
1070 /* Copy the name (this will also set the length) */
1071 KeyCell->NameLength = CmpCopyName(Hive, (PWCHAR)KeyCell->Name, &KeyName);
1072
1073 /* Check if the name was compressed */
1074 if (KeyCell->NameLength < KeyName.Length)
1075 {
1076 /* Set the flag */
1077 KeyCell->Flags |= KEY_COMP_NAME;
1078 }
1079
1080 /* Return success */
1081 HvReleaseCell(Hive, *Index);
1082 return TRUE;
1083 }
1084
1085 BOOLEAN
1086 NTAPI
1087 INIT_FUNCTION
1088 CmpCreateRegistryRoot(VOID)
1089 {
1090 UNICODE_STRING KeyName;
1091 OBJECT_ATTRIBUTES ObjectAttributes;
1092 PCM_KEY_BODY RootKey;
1093 HCELL_INDEX RootIndex;
1094 NTSTATUS Status;
1095 PCM_KEY_NODE KeyCell;
1096 PSECURITY_DESCRIPTOR SecurityDescriptor;
1097 PCM_KEY_CONTROL_BLOCK Kcb;
1098 PAGED_CODE();
1099
1100 /* Setup the root node */
1101 if (!CmpCreateRootNode(&CmiVolatileHive->Hive, L"REGISTRY", &RootIndex))
1102 {
1103 /* We failed */
1104 return FALSE;
1105 }
1106
1107 /* Create '\Registry' key. */
1108 RtlInitUnicodeString(&KeyName, L"\\REGISTRY");
1109 SecurityDescriptor = CmpHiveRootSecurityDescriptor();
1110 InitializeObjectAttributes(&ObjectAttributes,
1111 &KeyName,
1112 OBJ_CASE_INSENSITIVE,
1113 NULL,
1114 SecurityDescriptor);
1115 Status = ObCreateObject(KernelMode,
1116 CmpKeyObjectType,
1117 &ObjectAttributes,
1118 KernelMode,
1119 NULL,
1120 sizeof(CM_KEY_BODY),
1121 0,
1122 0,
1123 (PVOID*)&RootKey);
1124 ExFreePoolWithTag(SecurityDescriptor, TAG_CMSD);
1125 if (!NT_SUCCESS(Status)) return FALSE;
1126
1127 /* Sanity check, and get the key cell */
1128 ASSERT((&CmiVolatileHive->Hive)->ReleaseCellRoutine == NULL);
1129 KeyCell = (PCM_KEY_NODE)HvGetCell(&CmiVolatileHive->Hive, RootIndex);
1130 if (!KeyCell) return FALSE;
1131
1132 /* Create the KCB */
1133 RtlInitUnicodeString(&KeyName, L"\\REGISTRY");
1134 Kcb = CmpCreateKeyControlBlock(&CmiVolatileHive->Hive,
1135 RootIndex,
1136 KeyCell,
1137 NULL,
1138 0,
1139 &KeyName);
1140 if (!Kcb)
1141 {
1142 ObDereferenceObject(RootKey);
1143 return FALSE;
1144 }
1145
1146 /* Initialize the object */
1147 RootKey->KeyControlBlock = Kcb;
1148 RootKey->Type = CM_KEY_BODY_TYPE;
1149 RootKey->NotifyBlock = NULL;
1150 RootKey->ProcessID = PsGetCurrentProcessId();
1151
1152 /* Link with KCB */
1153 EnlistKeyBodyWithKCB(RootKey, 0);
1154
1155 /* Insert the key into the namespace */
1156 Status = ObInsertObject(RootKey,
1157 NULL,
1158 KEY_ALL_ACCESS,
1159 0,
1160 NULL,
1161 &CmpRegistryRootHandle);
1162 if (!NT_SUCCESS(Status))
1163 {
1164 ObDereferenceObject(RootKey);
1165 return FALSE;
1166 }
1167
1168 /* Reference the key again so that we never lose it */
1169 Status = ObReferenceObjectByHandle(CmpRegistryRootHandle,
1170 KEY_READ,
1171 NULL,
1172 KernelMode,
1173 (PVOID*)&RootKey,
1174 NULL);
1175 if (!NT_SUCCESS(Status))
1176 {
1177 ObDereferenceObject(RootKey);
1178 return FALSE;
1179 }
1180
1181 /* Completely sucessful */
1182 return TRUE;
1183 }
1184
1185 NTSTATUS
1186 NTAPI
1187 CmpGetRegistryPath(IN PWCHAR ConfigPath)
1188 {
1189 OBJECT_ATTRIBUTES ObjectAttributes;
1190 NTSTATUS Status;
1191 HANDLE KeyHandle;
1192 PKEY_VALUE_PARTIAL_INFORMATION ValueInfo;
1193 UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\HARDWARE");
1194 UNICODE_STRING ValueName = RTL_CONSTANT_STRING(L"InstallPath");
1195 ULONG BufferSize, ResultSize;
1196
1197 /* Check if we are booted in setup */
1198 if (ExpInTextModeSetup)
1199 {
1200 /* Setup the object attributes */
1201 InitializeObjectAttributes(&ObjectAttributes,
1202 &KeyName,
1203 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
1204 NULL,
1205 NULL);
1206 /* Open the key */
1207 Status = ZwOpenKey(&KeyHandle,
1208 KEY_ALL_ACCESS,
1209 &ObjectAttributes);
1210 if (!NT_SUCCESS(Status)) return Status;
1211
1212 /* Allocate the buffer */
1213 BufferSize = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 4096;
1214 ValueInfo = ExAllocatePoolWithTag(PagedPool, BufferSize, TAG_CM);
1215 if (!ValueInfo)
1216 {
1217 /* Fail */
1218 ZwClose(KeyHandle);
1219 return STATUS_INSUFFICIENT_RESOURCES;
1220 }
1221
1222 /* Query the value */
1223 Status = ZwQueryValueKey(KeyHandle,
1224 &ValueName,
1225 KeyValuePartialInformation,
1226 ValueInfo,
1227 BufferSize,
1228 &ResultSize);
1229 ZwClose(KeyHandle);
1230 if (!NT_SUCCESS(Status))
1231 {
1232 /* Fail */
1233 ExFreePoolWithTag(ValueInfo, TAG_CM);
1234 return Status;
1235 }
1236
1237 /* Copy the config path and null-terminate it */
1238 RtlCopyMemory(ConfigPath,
1239 ValueInfo->Data,
1240 ValueInfo->DataLength);
1241 ConfigPath[ValueInfo->DataLength / sizeof(WCHAR)] = UNICODE_NULL;
1242 ExFreePoolWithTag(ValueInfo, TAG_CM);
1243 }
1244 else
1245 {
1246 /* Just use default path */
1247 wcscpy(ConfigPath, L"\\SystemRoot");
1248 }
1249
1250 /* Add registry path */
1251 wcscat(ConfigPath, L"\\System32\\Config\\");
1252
1253 /* Done */
1254 return STATUS_SUCCESS;
1255 }
1256
1257 VOID
1258 NTAPI
1259 CmpLoadHiveThread(IN PVOID StartContext)
1260 {
1261 WCHAR FileBuffer[MAX_PATH], RegBuffer[MAX_PATH], ConfigPath[MAX_PATH];
1262 UNICODE_STRING TempName, FileName, RegName;
1263 ULONG i, ErrorResponse, WorkerCount, Length;
1264 USHORT FileStart;
1265 //ULONG RegStart;
1266 ULONG PrimaryDisposition, SecondaryDisposition, ClusterSize;
1267 PCMHIVE CmHive;
1268 HANDLE PrimaryHandle = NULL, LogHandle = NULL;
1269 NTSTATUS Status = STATUS_SUCCESS;
1270 PVOID ErrorParameters;
1271 PAGED_CODE();
1272
1273 /* Get the hive index, make sure it makes sense */
1274 i = PtrToUlong(StartContext);
1275 ASSERT(CmpMachineHiveList[i].Name != NULL);
1276
1277 /* We were started */
1278 CmpMachineHiveList[i].ThreadStarted = TRUE;
1279
1280 /* Build the file name and registry name strings */
1281 RtlInitEmptyUnicodeString(&FileName, FileBuffer, MAX_PATH);
1282 RtlInitEmptyUnicodeString(&RegName, RegBuffer, MAX_PATH);
1283
1284 /* Now build the system root path */
1285 CmpGetRegistryPath(ConfigPath);
1286 RtlInitUnicodeString(&TempName, ConfigPath);
1287 RtlAppendStringToString((PSTRING)&FileName, (PSTRING)&TempName);
1288 FileStart = FileName.Length;
1289
1290 /* And build the registry root path */
1291 RtlInitUnicodeString(&TempName, L"\\REGISTRY\\");
1292 RtlAppendStringToString((PSTRING)&RegName, (PSTRING)&TempName);
1293 //RegStart = RegName.Length;
1294
1295 /* Build the base name */
1296 RtlInitUnicodeString(&TempName, CmpMachineHiveList[i].BaseName);
1297 RtlAppendStringToString((PSTRING)&RegName, (PSTRING)&TempName);
1298
1299 /* Check if this is a child of the root */
1300 if (RegName.Buffer[RegName.Length / sizeof(WCHAR) - 1] == '\\')
1301 {
1302 /* Then setup the whole name */
1303 RtlInitUnicodeString(&TempName, CmpMachineHiveList[i].Name);
1304 RtlAppendStringToString((PSTRING)&RegName, (PSTRING)&TempName);
1305 }
1306
1307 /* Now add the rest of the file name */
1308 RtlInitUnicodeString(&TempName, CmpMachineHiveList[i].Name);
1309 FileName.Length = FileStart;
1310 RtlAppendStringToString((PSTRING)&FileName, (PSTRING)&TempName);
1311 if (!CmpMachineHiveList[i].CmHive)
1312 {
1313 /* We need to allocate a new hive structure */
1314 CmpMachineHiveList[i].Allocate = TRUE;
1315
1316 /* Load the hive file */
1317 Status = CmpInitHiveFromFile(&FileName,
1318 CmpMachineHiveList[i].HHiveFlags,
1319 &CmHive,
1320 &CmpMachineHiveList[i].Allocate,
1321 0);
1322 if (!(NT_SUCCESS(Status)) ||
1323 (!(CmHive->FileHandles[HFILE_TYPE_LOG]) && !(CmpMiniNTBoot))) // HACK
1324 {
1325 /* We failed or couldn't get a log file, raise a hard error */
1326 ErrorParameters = &FileName;
1327 NtRaiseHardError(STATUS_CANNOT_LOAD_REGISTRY_FILE,
1328 1,
1329 1,
1330 (PULONG_PTR)&ErrorParameters,
1331 OptionOk,
1332 &ErrorResponse);
1333 }
1334
1335 /* Set the hive flags and newly allocated hive pointer */
1336 CmHive->Flags = CmpMachineHiveList[i].CmHiveFlags;
1337 CmpMachineHiveList[i].CmHive2 = CmHive;
1338 }
1339 else
1340 {
1341 /* We already have a hive, is it volatile? */
1342 CmHive = CmpMachineHiveList[i].CmHive;
1343 if (!(CmHive->Hive.HiveFlags & HIVE_VOLATILE))
1344 {
1345 /* It's now, open the hive file and log */
1346 Status = CmpOpenHiveFiles(&FileName,
1347 L".LOG",
1348 &PrimaryHandle,
1349 &LogHandle,
1350 &PrimaryDisposition,
1351 &SecondaryDisposition,
1352 TRUE,
1353 TRUE,
1354 FALSE,
1355 &ClusterSize);
1356 if (!(NT_SUCCESS(Status)) || !(LogHandle))
1357 {
1358 /* Couldn't open the hive or its log file, raise a hard error */
1359 ErrorParameters = &FileName;
1360 NtRaiseHardError(STATUS_CANNOT_LOAD_REGISTRY_FILE,
1361 1,
1362 1,
1363 (PULONG_PTR)&ErrorParameters,
1364 OptionOk,
1365 &ErrorResponse);
1366
1367 /* And bugcheck for posterity's sake */
1368 KeBugCheckEx(BAD_SYSTEM_CONFIG_INFO, 9, 0, i, Status);
1369 }
1370
1371 /* Save the file handles. This should remove our sync hacks */
1372 CmHive->FileHandles[HFILE_TYPE_LOG] = LogHandle;
1373 CmHive->FileHandles[HFILE_TYPE_PRIMARY] = PrimaryHandle;
1374
1375 /* Allow lazy flushing since the handles are there -- remove sync hacks */
1376 //ASSERT(CmHive->Hive.HiveFlags & HIVE_NOLAZYFLUSH);
1377 CmHive->Hive.HiveFlags &= ~HIVE_NOLAZYFLUSH;
1378
1379 /* Get the real size of the hive */
1380 Length = CmHive->Hive.Storage[Stable].Length + HBLOCK_SIZE;
1381
1382 /* Check if the cluster size doesn't match */
1383 if (CmHive->Hive.Cluster != ClusterSize) ASSERT(FALSE);
1384
1385 /* Set the file size */
1386 DPRINT("FIXME: Should set file size: %lx\n", Length);
1387 //if (!CmpFileSetSize((PHHIVE)CmHive, HFILE_TYPE_PRIMARY, Length, Length))
1388 {
1389 /* This shouldn't fail */
1390 //ASSERT(FALSE);
1391 }
1392
1393 /* Another thing we don't support is NTLDR-recovery */
1394 if (CmHive->Hive.BaseBlock->BootRecover) ASSERT(FALSE);
1395
1396 /* Finally, set our allocated hive to the same hive we've had */
1397 CmpMachineHiveList[i].CmHive2 = CmHive;
1398 ASSERT(CmpMachineHiveList[i].CmHive == CmpMachineHiveList[i].CmHive2);
1399 }
1400 }
1401
1402 /* We're done */
1403 CmpMachineHiveList[i].ThreadFinished = TRUE;
1404
1405 /* Check if we're the last worker */
1406 WorkerCount = InterlockedIncrement(&CmpLoadWorkerIncrement);
1407 if (WorkerCount == CM_NUMBER_OF_MACHINE_HIVES)
1408 {
1409 /* Signal the event */
1410 KeSetEvent(&CmpLoadWorkerEvent, 0, FALSE);
1411 }
1412
1413 /* Kill the thread */
1414 PsTerminateSystemThread(Status);
1415 }
1416
1417 VOID
1418 NTAPI
1419 CmpInitializeHiveList(IN USHORT Flag)
1420 {
1421 WCHAR FileBuffer[MAX_PATH], RegBuffer[MAX_PATH], ConfigPath[MAX_PATH];
1422 UNICODE_STRING TempName, FileName, RegName;
1423 HANDLE Thread;
1424 NTSTATUS Status;
1425 ULONG i;
1426 USHORT RegStart;
1427 PSECURITY_DESCRIPTOR SecurityDescriptor;
1428 PAGED_CODE();
1429
1430 /* Allow writing for now */
1431 CmpNoWrite = FALSE;
1432
1433 /* Build the file name and registry name strings */
1434 RtlInitEmptyUnicodeString(&FileName, FileBuffer, MAX_PATH);
1435 RtlInitEmptyUnicodeString(&RegName, RegBuffer, MAX_PATH);
1436
1437 /* Now build the system root path */
1438 CmpGetRegistryPath(ConfigPath);
1439 RtlInitUnicodeString(&TempName, ConfigPath);
1440 RtlAppendStringToString((PSTRING)&FileName, (PSTRING)&TempName);
1441
1442 /* And build the registry root path */
1443 RtlInitUnicodeString(&TempName, L"\\REGISTRY\\");
1444 RtlAppendStringToString((PSTRING)&RegName, (PSTRING)&TempName);
1445 RegStart = RegName.Length;
1446
1447 /* Setup the event to synchronize workers */
1448 KeInitializeEvent(&CmpLoadWorkerEvent, SynchronizationEvent, FALSE);
1449
1450 /* Enter special boot condition */
1451 CmpSpecialBootCondition = TRUE;
1452
1453 /* Create the SD for the root hives */
1454 SecurityDescriptor = CmpHiveRootSecurityDescriptor();
1455
1456 /* Loop every hive we care about */
1457 for (i = 0; i < CM_NUMBER_OF_MACHINE_HIVES; i++)
1458 {
1459 /* Make sure the list is setup */
1460 ASSERT(CmpMachineHiveList[i].Name != NULL);
1461
1462 /* Create a thread to handle this hive */
1463 Status = PsCreateSystemThread(&Thread,
1464 THREAD_ALL_ACCESS,
1465 NULL,
1466 0,
1467 NULL,
1468 CmpLoadHiveThread,
1469 UlongToPtr(i));
1470 if (NT_SUCCESS(Status))
1471 {
1472 /* We don't care about the handle -- the thread self-terminates */
1473 ZwClose(Thread);
1474 }
1475 else
1476 {
1477 /* Can't imagine this happening */
1478 KeBugCheckEx(BAD_SYSTEM_CONFIG_INFO, 9, 3, i, Status);
1479 }
1480 }
1481
1482 /* Make sure we've reached the end of the list */
1483 ASSERT(CmpMachineHiveList[i].Name == NULL);
1484
1485 /* Wait for hive loading to finish */
1486 KeWaitForSingleObject(&CmpLoadWorkerEvent,
1487 Executive,
1488 KernelMode,
1489 FALSE,
1490 NULL);
1491
1492 /* Exit the special boot condition and make sure all workers completed */
1493 CmpSpecialBootCondition = FALSE;
1494 ASSERT(CmpLoadWorkerIncrement == CM_NUMBER_OF_MACHINE_HIVES);
1495
1496 /* Loop hives again */
1497 for (i = 0; i < CM_NUMBER_OF_MACHINE_HIVES; i++)
1498 {
1499 /* Make sure the thread ran and finished */
1500 ASSERT(CmpMachineHiveList[i].ThreadFinished == TRUE);
1501 ASSERT(CmpMachineHiveList[i].ThreadStarted == TRUE);
1502
1503 /* Check if this was a new hive */
1504 if (!CmpMachineHiveList[i].CmHive)
1505 {
1506 /* Make sure we allocated something */
1507 ASSERT(CmpMachineHiveList[i].CmHive2 != NULL);
1508
1509 /* Build the base name */
1510 RegName.Length = RegStart;
1511 RtlInitUnicodeString(&TempName, CmpMachineHiveList[i].BaseName);
1512 RtlAppendStringToString((PSTRING)&RegName, (PSTRING)&TempName);
1513
1514 /* Check if this is a child of the root */
1515 if (RegName.Buffer[RegName.Length / sizeof(WCHAR) - 1] == '\\')
1516 {
1517 /* Then setup the whole name */
1518 RtlInitUnicodeString(&TempName, CmpMachineHiveList[i].Name);
1519 RtlAppendStringToString((PSTRING)&RegName, (PSTRING)&TempName);
1520 }
1521
1522 /* Now link the hive to its master */
1523 Status = CmpLinkHiveToMaster(&RegName,
1524 NULL,
1525 CmpMachineHiveList[i].CmHive2,
1526 CmpMachineHiveList[i].Allocate,
1527 SecurityDescriptor);
1528 if (Status != STATUS_SUCCESS)
1529 {
1530 /* Linking needs to work */
1531 KeBugCheckEx(CONFIG_LIST_FAILED, 11, Status, i, (ULONG_PTR)&RegName);
1532 }
1533
1534 /* Check if we had to allocate a new hive */
1535 if (CmpMachineHiveList[i].Allocate)
1536 {
1537 /* Sync the new hive */
1538 //HvSyncHive((PHHIVE)(CmpMachineHiveList[i].CmHive2));
1539 }
1540 }
1541
1542 /* Check if we created a new hive */
1543 if (CmpMachineHiveList[i].CmHive2)
1544 {
1545 /* Add to HiveList key */
1546 CmpAddToHiveFileList(CmpMachineHiveList[i].CmHive2);
1547 }
1548 }
1549
1550 /* Get rid of the SD */
1551 ExFreePoolWithTag(SecurityDescriptor, TAG_CMSD);
1552
1553 /* Link SECURITY to SAM */
1554 CmpLinkKeyToHive(L"\\Registry\\Machine\\Security\\SAM",
1555 L"\\Registry\\Machine\\SAM\\SAM");
1556
1557 /* Link S-1-5-18 to .Default */
1558 CmpNoVolatileCreates = FALSE;
1559 CmpLinkKeyToHive(L"\\Registry\\User\\S-1-5-18",
1560 L"\\Registry\\User\\.Default");
1561 CmpNoVolatileCreates = TRUE;
1562 }
1563
1564 BOOLEAN
1565 NTAPI
1566 INIT_FUNCTION
1567 CmInitSystem1(VOID)
1568 {
1569 OBJECT_ATTRIBUTES ObjectAttributes;
1570 UNICODE_STRING KeyName;
1571 HANDLE KeyHandle;
1572 NTSTATUS Status;
1573 PCMHIVE HardwareHive;
1574 PSECURITY_DESCRIPTOR SecurityDescriptor;
1575 PAGED_CODE();
1576
1577 /* Check if this is PE-boot */
1578 if (InitIsWinPEMode)
1579 {
1580 /* Set registry to PE mode */
1581 CmpMiniNTBoot = TRUE;
1582 CmpShareSystemHives = TRUE;
1583 }
1584
1585 /* Initialize the hive list and lock */
1586 InitializeListHead(&CmpHiveListHead);
1587 ExInitializePushLock(&CmpHiveListHeadLock);
1588 ExInitializePushLock(&CmpLoadHiveLock);
1589
1590 /* Initialize registry lock */
1591 ExInitializeResourceLite(&CmpRegistryLock);
1592
1593 /* Initialize the cache */
1594 CmpInitializeCache();
1595
1596 /* Initialize allocation and delayed dereferencing */
1597 CmpInitCmPrivateAlloc();
1598 CmpInitCmPrivateDelayAlloc();
1599 CmpInitDelayDerefKCBEngine();
1600
1601 /* Initialize callbacks */
1602 CmpInitCallback();
1603
1604 /* Initialize self healing */
1605 KeInitializeGuardedMutex(&CmpSelfHealQueueLock);
1606 InitializeListHead(&CmpSelfHealQueueListHead);
1607
1608 /* Save the current process and lock the registry */
1609 CmpSystemProcess = PsGetCurrentProcess();
1610
1611 /* Create the key object types */
1612 Status = CmpCreateObjectTypes();
1613 if (!NT_SUCCESS(Status))
1614 {
1615 /* Bugcheck */
1616 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 1, Status, 0);
1617 }
1618
1619 /* Build the master hive */
1620 Status = CmpInitializeHive(&CmiVolatileHive,
1621 HINIT_CREATE,
1622 HIVE_VOLATILE,
1623 HFILE_TYPE_PRIMARY,
1624 NULL,
1625 NULL,
1626 NULL,
1627 NULL,
1628 NULL,
1629 0);
1630 if (!NT_SUCCESS(Status))
1631 {
1632 /* Bugcheck */
1633 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 2, Status, 0);
1634 }
1635
1636 /* Create the \REGISTRY key node */
1637 if (!CmpCreateRegistryRoot())
1638 {
1639 /* Bugcheck */
1640 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 3, 0, 0);
1641 }
1642
1643 /* Create the default security descriptor */
1644 SecurityDescriptor = CmpHiveRootSecurityDescriptor();
1645
1646 /* Create '\Registry\Machine' key. */
1647 RtlInitUnicodeString(&KeyName, L"\\REGISTRY\\MACHINE");
1648 InitializeObjectAttributes(&ObjectAttributes,
1649 &KeyName,
1650 OBJ_CASE_INSENSITIVE,
1651 NULL,
1652 SecurityDescriptor);
1653 Status = NtCreateKey(&KeyHandle,
1654 KEY_READ | KEY_WRITE,
1655 &ObjectAttributes,
1656 0,
1657 NULL,
1658 0,
1659 NULL);
1660 if (!NT_SUCCESS(Status))
1661 {
1662 /* Bugcheck */
1663 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 5, Status, 0);
1664 }
1665
1666 /* Close the handle */
1667 NtClose(KeyHandle);
1668
1669 /* Create '\Registry\User' key. */
1670 RtlInitUnicodeString(&KeyName, L"\\REGISTRY\\USER");
1671 InitializeObjectAttributes(&ObjectAttributes,
1672 &KeyName,
1673 OBJ_CASE_INSENSITIVE,
1674 NULL,
1675 SecurityDescriptor);
1676 Status = NtCreateKey(&KeyHandle,
1677 KEY_READ | KEY_WRITE,
1678 &ObjectAttributes,
1679 0,
1680 NULL,
1681 0,
1682 NULL);
1683 if (!NT_SUCCESS(Status))
1684 {
1685 /* Bugcheck */
1686 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 6, Status, 0);
1687 }
1688
1689 /* Close the handle */
1690 NtClose(KeyHandle);
1691
1692 /* After this point, do not allow creating keys in the master hive */
1693 CmpNoVolatileCreates = TRUE;
1694
1695 /* Initialize the system hive */
1696 if (!CmpInitializeSystemHive(KeLoaderBlock))
1697 {
1698 /* Bugcheck */
1699 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 7, 0, 0);
1700 }
1701
1702 /* Create the 'CurrentControlSet' link. */
1703 Status = CmpCreateControlSet(KeLoaderBlock);
1704 if (!NT_SUCCESS(Status))
1705 {
1706 /* Bugcheck */
1707 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 8, Status, 0);
1708 }
1709
1710 /* Create the hardware hive */
1711 Status = CmpInitializeHive(&HardwareHive,
1712 HINIT_CREATE,
1713 HIVE_VOLATILE,
1714 HFILE_TYPE_PRIMARY,
1715 NULL,
1716 NULL,
1717 NULL,
1718 NULL,
1719 NULL,
1720 0);
1721 if (!NT_SUCCESS(Status))
1722 {
1723 /* Bugcheck */
1724 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 11, Status, 0);
1725 }
1726
1727 /* Add the hive to the hive list */
1728 CmpMachineHiveList[0].CmHive = HardwareHive;
1729
1730 /* Attach it to the machine key */
1731 RtlInitUnicodeString(&KeyName, L"\\Registry\\Machine\\HARDWARE");
1732 Status = CmpLinkHiveToMaster(&KeyName,
1733 NULL,
1734 HardwareHive,
1735 TRUE,
1736 SecurityDescriptor);
1737 if (!NT_SUCCESS(Status))
1738 {
1739 /* Bugcheck */
1740 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 12, Status, 0);
1741 }
1742
1743 /* Add to HiveList key */
1744 CmpAddToHiveFileList(HardwareHive);
1745
1746 /* Free the security descriptor */
1747 ExFreePoolWithTag(SecurityDescriptor, TAG_CMSD);
1748
1749 /* Fill out the Hardware key with the ARC Data from the Loader */
1750 Status = CmpInitializeHardwareConfiguration(KeLoaderBlock);
1751 if (!NT_SUCCESS(Status))
1752 {
1753 /* Bugcheck */
1754 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 13, Status, 0);
1755 }
1756
1757 /* Initialize machine-dependent information into the registry */
1758 Status = CmpInitializeMachineDependentConfiguration(KeLoaderBlock);
1759 if (!NT_SUCCESS(Status))
1760 {
1761 /* Bugcheck */
1762 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 14, Status, 0);
1763 }
1764
1765 /* Initialize volatile registry settings */
1766 Status = CmpSetSystemValues(KeLoaderBlock);
1767 if (!NT_SUCCESS(Status))
1768 {
1769 /* Bugcheck */
1770 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 15, Status, 0);
1771 }
1772
1773 /* Free the load options */
1774 ExFreePoolWithTag(CmpLoadOptions.Buffer, TAG_CM);
1775
1776 /* If we got here, all went well */
1777 return TRUE;
1778 }
1779
1780 VOID
1781 NTAPI
1782 INIT_FUNCTION
1783 CmpFreeDriverList(IN PHHIVE Hive,
1784 IN PLIST_ENTRY DriverList)
1785 {
1786 PLIST_ENTRY NextEntry, OldEntry;
1787 PBOOT_DRIVER_NODE DriverNode;
1788 PAGED_CODE();
1789
1790 /* Parse the current list */
1791 NextEntry = DriverList->Flink;
1792 while (NextEntry != DriverList)
1793 {
1794 /* Get the driver node */
1795 DriverNode = CONTAINING_RECORD(NextEntry, BOOT_DRIVER_NODE, ListEntry.Link);
1796
1797 /* Get the next entry now, since we're going to free it later */
1798 OldEntry = NextEntry;
1799 NextEntry = NextEntry->Flink;
1800
1801 /* Was there a name? */
1802 if (DriverNode->Name.Buffer)
1803 {
1804 /* Free it */
1805 CmpFree(DriverNode->Name.Buffer, DriverNode->Name.Length);
1806 }
1807
1808 /* Was there a registry path? */
1809 if (DriverNode->ListEntry.RegistryPath.Buffer)
1810 {
1811 /* Free it */
1812 CmpFree(DriverNode->ListEntry.RegistryPath.Buffer,
1813 DriverNode->ListEntry.RegistryPath.MaximumLength);
1814 }
1815
1816 /* Was there a file path? */
1817 if (DriverNode->ListEntry.FilePath.Buffer)
1818 {
1819 /* Free it */
1820 CmpFree(DriverNode->ListEntry.FilePath.Buffer,
1821 DriverNode->ListEntry.FilePath.MaximumLength);
1822 }
1823
1824 /* Now free the node, and move on */
1825 CmpFree(OldEntry, sizeof(BOOT_DRIVER_NODE));
1826 }
1827 }
1828
1829 PUNICODE_STRING*
1830 NTAPI
1831 INIT_FUNCTION
1832 CmGetSystemDriverList(VOID)
1833 {
1834 LIST_ENTRY DriverList;
1835 OBJECT_ATTRIBUTES ObjectAttributes;
1836 NTSTATUS Status;
1837 PCM_KEY_BODY KeyBody;
1838 PHHIVE Hive;
1839 HCELL_INDEX RootCell, ControlCell;
1840 HANDLE KeyHandle;
1841 UNICODE_STRING KeyName;
1842 PLIST_ENTRY NextEntry;
1843 ULONG i;
1844 PUNICODE_STRING* ServicePath = NULL;
1845 BOOLEAN Success, AutoSelect;
1846 PBOOT_DRIVER_LIST_ENTRY DriverEntry;
1847 PAGED_CODE();
1848
1849 /* Initialize the driver list */
1850 InitializeListHead(&DriverList);
1851
1852 /* Open the system hive key */
1853 RtlInitUnicodeString(&KeyName, L"\\Registry\\Machine\\System");
1854 InitializeObjectAttributes(&ObjectAttributes,
1855 &KeyName,
1856 OBJ_CASE_INSENSITIVE,
1857 NULL,
1858 NULL);
1859 Status = NtOpenKey(&KeyHandle, KEY_READ, &ObjectAttributes);
1860 if (!NT_SUCCESS(Status)) return NULL;
1861
1862 /* Reference the key object to get the root hive/cell to access directly */
1863 Status = ObReferenceObjectByHandle(KeyHandle,
1864 KEY_QUERY_VALUE,
1865 CmpKeyObjectType,
1866 KernelMode,
1867 (PVOID*)&KeyBody,
1868 NULL);
1869 if (!NT_SUCCESS(Status))
1870 {
1871 /* Fail */
1872 NtClose(KeyHandle);
1873 return NULL;
1874 }
1875
1876 /* Do all this under the registry lock */
1877 CmpLockRegistryExclusive();
1878
1879 /* Get the hive and key cell */
1880 Hive = KeyBody->KeyControlBlock->KeyHive;
1881 RootCell = KeyBody->KeyControlBlock->KeyCell;
1882
1883 /* Open the current control set key */
1884 RtlInitUnicodeString(&KeyName, L"Current");
1885 ControlCell = CmpFindControlSet(Hive, RootCell, &KeyName, &AutoSelect);
1886 if (ControlCell == HCELL_NIL) goto EndPath;
1887
1888 /* Find all system drivers */
1889 Success = CmpFindDrivers(Hive, ControlCell, SystemLoad, NULL, &DriverList);
1890 if (!Success) goto EndPath;
1891
1892 /* Sort by group/tag */
1893 if (!CmpSortDriverList(Hive, ControlCell, &DriverList)) goto EndPath;
1894
1895 /* Remove circular dependencies (cycles) and sort */
1896 if (!CmpResolveDriverDependencies(&DriverList)) goto EndPath;
1897
1898 /* Loop the list to count drivers */
1899 for (i = 0, NextEntry = DriverList.Flink;
1900 NextEntry != &DriverList;
1901 i++, NextEntry = NextEntry->Flink);
1902
1903 /* Allocate the array */
1904 ServicePath = ExAllocatePool(NonPagedPool, (i + 1) * sizeof(PUNICODE_STRING));
1905 if (!ServicePath) KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 2, 1, 0, 0);
1906
1907 /* Loop the driver list */
1908 for (i = 0, NextEntry = DriverList.Flink;
1909 NextEntry != &DriverList;
1910 i++, NextEntry = NextEntry->Flink)
1911 {
1912 /* Get the entry */
1913 DriverEntry = CONTAINING_RECORD(NextEntry, BOOT_DRIVER_LIST_ENTRY, Link);
1914
1915 /* Allocate the path for the caller and duplicate the registry path */
1916 ServicePath[i] = ExAllocatePool(NonPagedPool, sizeof(UNICODE_STRING));
1917 RtlDuplicateUnicodeString(RTL_DUPLICATE_UNICODE_STRING_NULL_TERMINATE,
1918 &DriverEntry->RegistryPath,
1919 ServicePath[i]);
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 representation,
2175 // 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
2295 swprintf(Buffer, 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 */