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