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