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