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