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