- Implement CmpConstructName (builds a full name of the given key).
[reactos.git] / reactos / ntoskrnl / config / cmsysini.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/config/cmsysini.c
5 * PURPOSE: Configuration Manager - System Initialization Code
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7 */
8
9 /* INCLUDES ******************************************************************/
10
11 #include "ntoskrnl.h"
12 #define NDEBUG
13 #include "debug.h"
14
15 POBJECT_TYPE CmpKeyObjectType;
16 PCMHIVE CmiVolatileHive;
17 LIST_ENTRY CmpHiveListHead;
18 ERESOURCE CmpRegistryLock;
19 KGUARDED_MUTEX CmpSelfHealQueueLock;
20 LIST_ENTRY CmpSelfHealQueueListHead;
21 KEVENT CmpLoadWorkerEvent;
22 LONG CmpLoadWorkerIncrement;
23 PEPROCESS CmpSystemProcess;
24 BOOLEAN HvShutdownComplete;
25 PVOID CmpRegistryLockCallerCaller, CmpRegistryLockCaller;
26 BOOLEAN CmpFlushStarveWriters;
27 BOOLEAN CmpFlushOnLockRelease;
28 BOOLEAN CmpSpecialBootCondition;
29 BOOLEAN CmpNoWrite;
30 BOOLEAN CmpForceForceFlush;
31 BOOLEAN CmpWasSetupBoot;
32
33 extern BOOLEAN CmFirstTime;
34
35 /* FUNCTIONS *****************************************************************/
36
37 VOID
38 NTAPI
39 CmpDeleteKeyObject(PVOID DeletedObject)
40 {
41 PCM_KEY_BODY KeyBody = (PCM_KEY_BODY)DeletedObject;
42 PCM_KEY_CONTROL_BLOCK Kcb;
43 REG_KEY_HANDLE_CLOSE_INFORMATION KeyHandleCloseInfo;
44 REG_POST_OPERATION_INFORMATION PostOperationInfo;
45 NTSTATUS Status;
46 PAGED_CODE();
47
48 /* First off, prepare the handle close information callback */
49 PostOperationInfo.Object = KeyBody;
50 KeyHandleCloseInfo.Object = KeyBody;
51 Status = CmiCallRegisteredCallbacks(RegNtPreKeyHandleClose,
52 &KeyHandleCloseInfo);
53 if (!NT_SUCCESS(Status))
54 {
55 /* If we failed, notify the post routine */
56 PostOperationInfo.Status = Status;
57 CmiCallRegisteredCallbacks(RegNtPostKeyHandleClose, &PostOperationInfo);
58 return;
59 }
60
61 /* Acquire hive lock */
62 CmpLockRegistry();
63
64 /* Make sure this is a valid key body */
65 if (KeyBody->Type == TAG('k', 'y', '0', '2'))
66 {
67 /* Get the KCB */
68 Kcb = KeyBody->KeyControlBlock;
69 if (Kcb)
70 {
71 /* Delist the key */
72 DelistKeyBodyFromKCB(KeyBody, FALSE);
73 }
74
75 /* Dereference the KCB */
76 CmpDelayDerefKeyControlBlock(Kcb);
77
78 }
79
80 /* Release the registry lock */
81 CmpUnlockRegistry();
82
83 /* Do the post callback */
84 PostOperationInfo.Status = STATUS_SUCCESS;
85 CmiCallRegisteredCallbacks(RegNtPostKeyHandleClose, &PostOperationInfo);
86 }
87
88 VOID
89 NTAPI
90 CmpCloseKeyObject(IN PEPROCESS Process OPTIONAL,
91 IN PVOID Object,
92 IN ACCESS_MASK GrantedAccess,
93 IN ULONG ProcessHandleCount,
94 IN ULONG SystemHandleCount)
95 {
96 PCM_KEY_BODY KeyBody = (PCM_KEY_BODY)Object;
97 PAGED_CODE();
98
99 /* Don't do anything if we're not the last handle */
100 if (SystemHandleCount > 1) return;
101
102 /* Make sure we're a valid key body */
103 if (KeyBody->Type == TAG('k', 'y', '0', '2'))
104 {
105 /* Don't do anything if we don't have a notify block */
106 if (!KeyBody->NotifyBlock) return;
107
108 /* This shouldn't happen yet */
109 ASSERT(FALSE);
110 }
111 }
112
113 NTSTATUS
114 NTAPI
115 CmpQueryKeyName(IN PVOID ObjectBody,
116 IN BOOLEAN HasName,
117 IN OUT POBJECT_NAME_INFORMATION ObjectNameInfo,
118 IN ULONG Length,
119 OUT PULONG ReturnLength,
120 IN KPROCESSOR_MODE PreviousMode)
121 {
122 PUNICODE_STRING KeyName;
123 NTSTATUS Status = STATUS_SUCCESS;
124 PCM_KEY_BODY KeyBody = (PCM_KEY_BODY)ObjectBody;
125 PCM_KEY_CONTROL_BLOCK Kcb = KeyBody->KeyControlBlock;
126
127 /* Acquire hive lock */
128 CmpLockRegistry();
129
130 /* Lock KCB shared */
131 CmpAcquireKcbLockShared(Kcb);
132
133 /* Check if it's a deleted block */
134 if (Kcb->Delete)
135 {
136 /* Release the locks */
137 CmpReleaseKcbLock(Kcb);
138 CmpUnlockRegistry();
139
140 /* Let the caller know it's deleted */
141 return STATUS_KEY_DELETED;
142 }
143
144 /* Get the name */
145 KeyName = CmpConstructName(Kcb);
146
147 /* Release the locks */
148 CmpReleaseKcbLock(Kcb);
149 CmpUnlockRegistry();
150
151 /* Check if we got the name */
152 if (!KeyName) return STATUS_INSUFFICIENT_RESOURCES;
153
154 /* Set the returned length */
155 *ReturnLength = KeyName->Length + sizeof(OBJECT_NAME_INFORMATION) + sizeof(WCHAR);
156
157 /* Check if it fits into the provided buffer */
158 if ((Length < sizeof(OBJECT_NAME_INFORMATION)) ||
159 (Length < (*ReturnLength - sizeof(OBJECT_NAME_INFORMATION))))
160 {
161 /* Free the buffer allocated by CmpConstructName */
162 ExFreePool(KeyName->Buffer);
163
164 /* Return buffer length failure */
165 return STATUS_INFO_LENGTH_MISMATCH;
166 }
167
168 /* Fill in the result */
169 _SEH_TRY
170 {
171 /* Return data to user */
172 ObjectNameInfo->Name.Buffer = (PWCHAR)(ObjectNameInfo + 1);
173 ObjectNameInfo->Name.MaximumLength = KeyName->Length;
174 ObjectNameInfo->Name.Length = KeyName->Length;
175
176 /* Copy string content*/
177 RtlCopyMemory(ObjectNameInfo->Name.Buffer, KeyName->Buffer, *ReturnLength);
178 }
179 _SEH_HANDLE
180 {
181 /* Get the status */
182 Status = _SEH_GetExceptionCode();
183 }
184 _SEH_END;
185
186 /* Free the buffer allocated by CmpConstructName */
187 ExFreePool(KeyName);
188
189 return Status;
190 }
191
192 NTSTATUS
193 NTAPI
194 CmpInitHiveFromFile(IN PCUNICODE_STRING HiveName,
195 IN ULONG HiveFlags,
196 OUT PCMHIVE *Hive,
197 IN OUT PBOOLEAN New,
198 IN ULONG CheckFlags)
199 {
200 ULONG HiveDisposition, LogDisposition;
201 HANDLE FileHandle = NULL, LogHandle = NULL;
202 NTSTATUS Status;
203 ULONG Operation, FileType;
204 PCMHIVE NewHive;
205 PAGED_CODE();
206
207 /* Assume failure */
208 *Hive = NULL;
209
210 /* Open or create the hive files */
211 Status = CmpOpenHiveFiles(HiveName,
212 L".LOG",
213 &FileHandle,
214 &LogHandle,
215 &HiveDisposition,
216 &LogDisposition,
217 *New,
218 FALSE,
219 TRUE,
220 NULL);
221 if (!NT_SUCCESS(Status)) return Status;
222
223 /* Check if we have a log handle */
224 FileType = (LogHandle) ? HFILE_TYPE_LOG : HFILE_TYPE_PRIMARY;
225
226 /* Check if we created or opened the hive */
227 if (HiveDisposition == FILE_CREATED)
228 {
229 /* Do a create operation */
230 Operation = HINIT_CREATE;
231 *New = TRUE;
232 }
233 else
234 {
235 /* Open it as a file */
236 Operation = HINIT_FILE;
237 *New = FALSE;
238 }
239
240 /* Check if we're sharing hives */
241 if (CmpShareSystemHives)
242 {
243 /* Then force using the primary hive */
244 FileType = HFILE_TYPE_PRIMARY;
245 if (LogHandle)
246 {
247 /* Get rid of the log handle */
248 ZwClose(LogHandle);
249 LogHandle = NULL;
250 }
251 }
252
253 /* Check if we're too late */
254 if (HvShutdownComplete)
255 {
256 /* Fail */
257 ZwClose(FileHandle);
258 if (LogHandle) ZwClose(LogHandle);
259 return STATUS_TOO_LATE;
260 }
261
262 /* Initialize the hive */
263 Status = CmpInitializeHive((PCMHIVE*)&NewHive,
264 Operation,
265 HiveFlags,
266 FileType,
267 NULL,
268 FileHandle,
269 LogHandle,
270 NULL,
271 HiveName,
272 0);
273 if (!NT_SUCCESS(Status))
274 {
275 /* Fail */
276 ZwClose(FileHandle);
277 if (LogHandle) ZwClose(LogHandle);
278 return Status;
279 }
280
281 /* Success, return hive */
282 *Hive = NewHive;
283
284 /* ROS: Init root key cell and prepare the hive */
285 if (Operation == HINIT_CREATE) CmCreateRootNode(&NewHive->Hive, L"");
286
287 /* Duplicate the hive name */
288 NewHive->FileFullPath.Buffer = ExAllocatePoolWithTag(PagedPool,
289 HiveName->Length,
290 TAG_CM);
291 if (NewHive->FileFullPath.Buffer)
292 {
293 /* Copy the string */
294 RtlCopyMemory(NewHive->FileFullPath.Buffer,
295 HiveName->Buffer,
296 HiveName->Length);
297 NewHive->FileFullPath.Length = HiveName->Length;
298 NewHive->FileFullPath.MaximumLength = HiveName->MaximumLength;
299 }
300
301 /* Return success */
302 return STATUS_SUCCESS;
303 }
304
305 NTSTATUS
306 NTAPI
307 CmpSetSystemValues(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
308 {
309 OBJECT_ATTRIBUTES ObjectAttributes;
310 UNICODE_STRING KeyName, ValueName = {0};
311 HANDLE KeyHandle;
312 NTSTATUS Status;
313 ASSERT(LoaderBlock != NULL);
314
315 /* Setup attributes for loader options */
316 RtlInitUnicodeString(&KeyName,
317 L"\\REGISTRY\\MACHINE\\SYSTEM\\CurrentControlSet\\"
318 L"Control");
319 InitializeObjectAttributes(&ObjectAttributes,
320 &KeyName,
321 OBJ_CASE_INSENSITIVE,
322 NULL,
323 NULL);
324 Status = NtOpenKey(&KeyHandle, KEY_WRITE, &ObjectAttributes);
325 if (!NT_SUCCESS(Status)) goto Quickie;
326
327 /* Key opened, now write to the key */
328 RtlInitUnicodeString(&KeyName, L"SystemStartOptions");
329 Status = NtSetValueKey(KeyHandle,
330 &KeyName,
331 0,
332 REG_SZ,
333 CmpLoadOptions.Buffer,
334 CmpLoadOptions.Length);
335 if (!NT_SUCCESS(Status)) goto Quickie;
336
337 /* Setup value name for system boot device */
338 RtlInitUnicodeString(&KeyName, L"SystemBootDevice");
339 RtlCreateUnicodeStringFromAsciiz(&ValueName, LoaderBlock->NtBootPathName);
340 Status = NtSetValueKey(KeyHandle,
341 &KeyName,
342 0,
343 REG_SZ,
344 ValueName.Buffer,
345 ValueName.Length);
346
347 Quickie:
348 /* Free the buffers */
349 RtlFreeUnicodeString(&ValueName);
350
351 /* Close the key and return */
352 NtClose(KeyHandle);
353
354 /* Return the status */
355 return (ExpInTextModeSetup ? STATUS_SUCCESS : Status);
356 }
357
358 NTSTATUS
359 NTAPI
360 CmpCreateControlSet(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
361 {
362 UNICODE_STRING ConfigName = RTL_CONSTANT_STRING(L"Control\\IDConfigDB");
363 UNICODE_STRING SelectName =
364 RTL_CONSTANT_STRING(L"\\Registry\\Machine\\System\\Select");
365 UNICODE_STRING KeyName;
366 OBJECT_ATTRIBUTES ObjectAttributes;
367 CHAR ValueInfoBuffer[128];
368 PKEY_VALUE_FULL_INFORMATION ValueInfo;
369 CHAR Buffer[128];
370 WCHAR UnicodeBuffer[128];
371 HANDLE SelectHandle, KeyHandle, ConfigHandle = NULL, ProfileHandle = NULL;
372 HANDLE ParentHandle = NULL;
373 ULONG ControlSet, HwProfile;
374 ANSI_STRING TempString;
375 NTSTATUS Status;
376 ULONG ResultLength, Disposition;
377 PLOADER_PARAMETER_EXTENSION LoaderExtension;
378 PAGED_CODE();
379
380 /* Open the select key */
381 InitializeObjectAttributes(&ObjectAttributes,
382 &SelectName,
383 OBJ_CASE_INSENSITIVE,
384 NULL,
385 NULL);
386 Status = NtOpenKey(&SelectHandle, KEY_READ, &ObjectAttributes);
387 if (!NT_SUCCESS(Status))
388 {
389 /* ReactOS Hack: Hard-code current to 001 for SetupLdr */
390 if (!LoaderBlock->RegistryBase)
391 {
392 /* Build the ControlSet001 key */
393 RtlInitUnicodeString(&KeyName,
394 L"\\Registry\\Machine\\System\\ControlSet001");
395 InitializeObjectAttributes(&ObjectAttributes,
396 &KeyName,
397 OBJ_CASE_INSENSITIVE,
398 NULL,
399 NULL);
400 Status = NtCreateKey(&KeyHandle,
401 KEY_ALL_ACCESS,
402 &ObjectAttributes,
403 0,
404 NULL,
405 0,
406 &Disposition);
407 if (!NT_SUCCESS(Status)) return Status;
408
409 /* Don't need the handle */
410 ZwClose(KeyHandle);
411
412 /* Use hard-coded setting */
413 ControlSet = 1;
414 goto UseSet;
415 }
416
417 /* Fail for real boots */
418 return Status;
419 }
420
421 /* Open the current value */
422 RtlInitUnicodeString(&KeyName, L"Current");
423 Status = NtQueryValueKey(SelectHandle,
424 &KeyName,
425 KeyValueFullInformation,
426 ValueInfoBuffer,
427 sizeof(ValueInfoBuffer),
428 &ResultLength);
429 NtClose(SelectHandle);
430 if (!NT_SUCCESS(Status)) return Status;
431
432 /* Get the actual value pointer, and get the control set ID */
433 ValueInfo = (PKEY_VALUE_FULL_INFORMATION)ValueInfoBuffer;
434 ControlSet = *(PULONG)((PUCHAR)ValueInfo + ValueInfo->DataOffset);
435
436 /* Create the current control set key */
437 UseSet:
438 RtlInitUnicodeString(&KeyName,
439 L"\\Registry\\Machine\\System\\CurrentControlSet");
440 InitializeObjectAttributes(&ObjectAttributes,
441 &KeyName,
442 OBJ_CASE_INSENSITIVE,
443 NULL,
444 NULL);
445 Status = NtCreateKey(&KeyHandle,
446 KEY_CREATE_LINK,
447 &ObjectAttributes,
448 0,
449 NULL,
450 REG_OPTION_VOLATILE | REG_OPTION_CREATE_LINK,
451 &Disposition);
452 if (!NT_SUCCESS(Status)) return Status;
453
454 /* Sanity check */
455 ASSERT(Disposition == REG_CREATED_NEW_KEY);
456
457 /* Initialize the symbolic link name */
458 sprintf(Buffer,
459 "\\Registry\\Machine\\System\\ControlSet%03ld",
460 ControlSet);
461 RtlInitAnsiString(&TempString, Buffer);
462
463 /* Create a Unicode string out of it */
464 KeyName.MaximumLength = sizeof(UnicodeBuffer);
465 KeyName.Buffer = UnicodeBuffer;
466 Status = RtlAnsiStringToUnicodeString(&KeyName, &TempString, FALSE);
467
468 /* Set the value */
469 Status = NtSetValueKey(KeyHandle,
470 &CmSymbolicLinkValueName,
471 0,
472 REG_LINK,
473 KeyName.Buffer,
474 KeyName.Length);
475 if (!NT_SUCCESS(Status)) return Status;
476
477 /* Get the configuration database key */
478 InitializeObjectAttributes(&ObjectAttributes,
479 &ConfigName,
480 OBJ_CASE_INSENSITIVE,
481 KeyHandle,
482 NULL);
483 Status = NtOpenKey(&ConfigHandle, KEY_READ, &ObjectAttributes);
484 NtClose(KeyHandle);
485
486 /* Check if we don't have one */
487 if (!NT_SUCCESS(Status))
488 {
489 /* Cleanup and exit */
490 ConfigHandle = 0;
491 goto Cleanup;
492 }
493
494 /* Now get the current config */
495 RtlInitUnicodeString(&KeyName, L"CurrentConfig");
496 Status = NtQueryValueKey(ConfigHandle,
497 &KeyName,
498 KeyValueFullInformation,
499 ValueInfoBuffer,
500 sizeof(ValueInfoBuffer),
501 &ResultLength);
502
503 /* Set pointer to buffer */
504 ValueInfo = (PKEY_VALUE_FULL_INFORMATION)ValueInfoBuffer;
505
506 /* Check if we failed or got a non DWORD-value */
507 if (!(NT_SUCCESS(Status)) || (ValueInfo->Type != REG_DWORD)) goto Cleanup;
508
509 /* Get the hadware profile */
510 HwProfile = *(PULONG)((PUCHAR)ValueInfo + ValueInfo->DataOffset);
511
512 /* Open the hardware profile key */
513 RtlInitUnicodeString(&KeyName,
514 L"\\Registry\\Machine\\System\\CurrentControlSet"
515 L"\\Hardware Profiles");
516 InitializeObjectAttributes(&ObjectAttributes,
517 &KeyName,
518 OBJ_CASE_INSENSITIVE,
519 NULL,
520 NULL);
521 Status = NtOpenKey(&ParentHandle, KEY_READ, &ObjectAttributes);
522 if (!NT_SUCCESS(Status))
523 {
524 /* Exit and clean up */
525 ParentHandle = 0;
526 goto Cleanup;
527 }
528
529 /* Build the profile name */
530 sprintf(Buffer, "%04ld", HwProfile);
531 RtlInitAnsiString(&TempString, Buffer);
532
533 /* Convert it to Unicode */
534 KeyName.MaximumLength = sizeof(UnicodeBuffer);
535 KeyName.Buffer = UnicodeBuffer;
536 Status = RtlAnsiStringToUnicodeString(&KeyName,
537 &TempString,
538 FALSE);
539 ASSERT(Status == STATUS_SUCCESS);
540
541 /* Open the associated key */
542 InitializeObjectAttributes(&ObjectAttributes,
543 &KeyName,
544 OBJ_CASE_INSENSITIVE,
545 ParentHandle,
546 NULL);
547 Status = NtOpenKey(&ProfileHandle,
548 KEY_READ | KEY_WRITE,
549 &ObjectAttributes);
550 if (!NT_SUCCESS (Status))
551 {
552 /* Cleanup and exit */
553 ProfileHandle = 0;
554 goto Cleanup;
555 }
556
557 /* Check if we have a loader block extension */
558 LoaderExtension = LoaderBlock->Extension;
559 if (LoaderExtension)
560 {
561 ASSERTMSG("ReactOS doesn't support NTLDR Profiles yet!\n", FALSE);
562 }
563
564 /* Create the current hardware profile key */
565 RtlInitUnicodeString(&KeyName,
566 L"\\Registry\\Machine\\System\\CurrentControlSet\\"
567 L"Hardware Profiles\\Current");
568 InitializeObjectAttributes(&ObjectAttributes,
569 &KeyName,
570 OBJ_CASE_INSENSITIVE,
571 NULL,
572 NULL);
573 Status = NtCreateKey(&KeyHandle,
574 KEY_CREATE_LINK,
575 &ObjectAttributes,
576 0,
577 NULL,
578 REG_OPTION_VOLATILE | REG_OPTION_CREATE_LINK,
579 &Disposition);
580 if (NT_SUCCESS(Status))
581 {
582 /* Sanity check */
583 ASSERT(Disposition == REG_CREATED_NEW_KEY);
584
585 /* Create the profile name */
586 sprintf(Buffer,
587 "\\Registry\\Machine\\System\\CurrentControlSet\\"
588 "Hardware Profiles\\%04ld",
589 HwProfile);
590 RtlInitAnsiString(&TempString, Buffer);
591
592 /* Convert it to Unicode */
593 KeyName.MaximumLength = sizeof(UnicodeBuffer);
594 KeyName.Buffer = UnicodeBuffer;
595 Status = RtlAnsiStringToUnicodeString(&KeyName,
596 &TempString,
597 FALSE);
598 ASSERT(STATUS_SUCCESS == Status);
599
600 /* Set it */
601 Status = NtSetValueKey(KeyHandle,
602 &CmSymbolicLinkValueName,
603 0,
604 REG_LINK,
605 KeyName.Buffer,
606 KeyName.Length);
607 NtClose(KeyHandle);
608 }
609
610 /* Close every opened handle */
611 Cleanup:
612 if (ConfigHandle) NtClose(ConfigHandle);
613 if (ProfileHandle) NtClose(ProfileHandle);
614 if (ParentHandle) NtClose(ParentHandle);
615
616 /* Return success */
617 return STATUS_SUCCESS;
618 }
619
620 NTSTATUS
621 NTAPI
622 CmpLinkHiveToMaster(IN PUNICODE_STRING LinkName,
623 IN HANDLE RootDirectory,
624 IN PCMHIVE RegistryHive,
625 IN BOOLEAN Allocate,
626 IN PSECURITY_DESCRIPTOR SecurityDescriptor)
627 {
628 OBJECT_ATTRIBUTES ObjectAttributes;
629 NTSTATUS Status;
630 CM_PARSE_CONTEXT ParseContext = {0};
631 HANDLE KeyHandle;
632 PCM_KEY_BODY KeyBody;
633 PAGED_CODE();
634
635 /* Setup the object attributes */
636 InitializeObjectAttributes(&ObjectAttributes,
637 LinkName,
638 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
639 RootDirectory,
640 SecurityDescriptor);
641
642 /* Setup the parse context */
643 ParseContext.CreateLink = TRUE;
644 ParseContext.CreateOperation = TRUE;
645 ParseContext.ChildHive.KeyHive = &RegistryHive->Hive;
646
647 /* Check if we have a root keycell or if we need to create it */
648 if (Allocate)
649 {
650 /* Create it */
651 ParseContext.ChildHive.KeyCell = HCELL_NIL;
652 }
653 else
654 {
655 /* We have one */
656 ParseContext.ChildHive.KeyCell = RegistryHive->Hive.BaseBlock->RootCell;
657 }
658
659 /* Create the link node */
660 Status = ObOpenObjectByName(&ObjectAttributes,
661 CmpKeyObjectType,
662 KernelMode,
663 NULL,
664 KEY_READ | KEY_WRITE,
665 (PVOID)&ParseContext,
666 &KeyHandle);
667 if (!NT_SUCCESS(Status)) return Status;
668
669 /* Mark the hive as clean */
670 RegistryHive->Hive.DirtyFlag = FALSE;
671
672 /* ReactOS Hack: Keep alive */
673 Status = ObReferenceObjectByHandle(KeyHandle,
674 0,
675 CmpKeyObjectType,
676 KernelMode,
677 (PVOID*)&KeyBody,
678 NULL);
679 ASSERT(NT_SUCCESS(Status));
680
681 /* Close the extra handle */
682 ZwClose(KeyHandle);
683 return STATUS_SUCCESS;
684 }
685
686 BOOLEAN
687 NTAPI
688 CmpInitializeSystemHive(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
689 {
690 PVOID HiveBase;
691 ANSI_STRING LoadString;
692 PVOID Buffer;
693 ULONG Length;
694 NTSTATUS Status;
695 BOOLEAN Allocate;
696 UNICODE_STRING KeyName;
697 PCMHIVE SystemHive = NULL;
698 UNICODE_STRING HiveName = RTL_CONSTANT_STRING(L"SYSTEM");
699 PSECURITY_DESCRIPTOR SecurityDescriptor;
700 PAGED_CODE();
701
702 /* Setup the ansi string */
703 RtlInitAnsiString(&LoadString, LoaderBlock->LoadOptions);
704
705 /* Allocate the unicode buffer */
706 Length = LoadString.Length * sizeof(WCHAR) + sizeof(UNICODE_NULL);
707 Buffer = ExAllocatePoolWithTag(PagedPool, Length, TAG_CM);
708 if (!Buffer)
709 {
710 /* Fail */
711 KeBugCheckEx(BAD_SYSTEM_CONFIG_INFO, 3, 1, (ULONG_PTR)LoaderBlock, 0);
712 }
713
714 /* Setup the unicode string */
715 RtlInitEmptyUnicodeString(&CmpLoadOptions, Buffer, (USHORT)Length);
716
717 /* Add the load options and null-terminate */
718 RtlAnsiStringToUnicodeString(&CmpLoadOptions, &LoadString, FALSE);
719 CmpLoadOptions.Buffer[LoadString.Length] = UNICODE_NULL;
720 CmpLoadOptions.Length += sizeof(WCHAR);
721
722 /* Get the System Hive base address */
723 HiveBase = LoaderBlock->RegistryBase;
724 if (HiveBase)
725 {
726 /* Import it */
727 ((PHBASE_BLOCK)HiveBase)->Length = LoaderBlock->RegistryLength;
728 Status = CmpInitializeHive((PCMHIVE*)&SystemHive,
729 HINIT_MEMORY,
730 HIVE_NOLAZYFLUSH,
731 HFILE_TYPE_LOG,
732 HiveBase,
733 NULL,
734 NULL,
735 NULL,
736 &HiveName,
737 2);
738 if (!NT_SUCCESS(Status)) return FALSE;
739
740 /* Set the hive filename */
741 RtlCreateUnicodeString(&SystemHive->FileFullPath,
742 L"\\SystemRoot\\System32\\Config\\SYSTEM");
743
744 /* We imported, no need to create a new hive */
745 Allocate = FALSE;
746
747 /* Manually set the hive as volatile, if in Live CD mode */
748 if (CmpShareSystemHives) SystemHive->Hive.HiveFlags = HIVE_VOLATILE;
749 }
750 else
751 {
752 /* Create it */
753 Status = CmpInitializeHive(&SystemHive,
754 HINIT_CREATE,
755 HIVE_NOLAZYFLUSH,
756 HFILE_TYPE_LOG,
757 NULL,
758 NULL,
759 NULL,
760 NULL,
761 &HiveName,
762 0);
763 if (!NT_SUCCESS(Status)) return FALSE;
764
765 /* Set the hive filename */
766 RtlCreateUnicodeString(&SystemHive->FileFullPath,
767 L"\\SystemRoot\\System32\\Config\\SYSTEM");
768
769 /* Tell CmpLinkHiveToMaster to allocate a hive */
770 Allocate = TRUE;
771 }
772
773 /* Save the boot type */
774 if (SystemHive) CmpBootType = SystemHive->Hive.BaseBlock->BootType;
775
776 /* Are we in self-healing mode? */
777 if (!CmSelfHeal)
778 {
779 /* Disable self-healing internally and check if boot type wanted it */
780 CmpSelfHeal = FALSE;
781 if (CmpBootType & 4)
782 {
783 /* We're disabled, so bugcheck */
784 KeBugCheckEx(BAD_SYSTEM_CONFIG_INFO,
785 3,
786 3,
787 (ULONG_PTR)SystemHive,
788 0);
789 }
790 }
791
792 /* Create the default security descriptor */
793 SecurityDescriptor = CmpHiveRootSecurityDescriptor();
794
795 /* Attach it to the system key */
796 RtlInitUnicodeString(&KeyName, L"\\Registry\\Machine\\SYSTEM");
797 Status = CmpLinkHiveToMaster(&KeyName,
798 NULL,
799 (PCMHIVE)SystemHive,
800 Allocate,
801 SecurityDescriptor);
802
803 /* Free the security descriptor */
804 ExFreePool(SecurityDescriptor);
805 if (!NT_SUCCESS(Status)) return FALSE;
806
807 /* Add the hive to the hive list */
808 CmpMachineHiveList[3].CmHive = (PCMHIVE)SystemHive;
809
810 /* Success! */
811 return TRUE;
812 }
813
814 NTSTATUS
815 NTAPI
816 CmpCreateObjectTypes(VOID)
817 {
818 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer;
819 UNICODE_STRING Name;
820 GENERIC_MAPPING CmpKeyMapping = {KEY_READ,
821 KEY_WRITE,
822 KEY_EXECUTE,
823 KEY_ALL_ACCESS};
824 PAGED_CODE();
825
826 /* Initialize the Key object type */
827 RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer));
828 RtlInitUnicodeString(&Name, L"Key");
829 ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer);
830 ObjectTypeInitializer.DefaultPagedPoolCharge = sizeof(CM_KEY_BODY);
831 ObjectTypeInitializer.GenericMapping = CmpKeyMapping;
832 ObjectTypeInitializer.PoolType = PagedPool;
833 ObjectTypeInitializer.ValidAccessMask = KEY_ALL_ACCESS;
834 ObjectTypeInitializer.UseDefaultObject = TRUE;
835 ObjectTypeInitializer.DeleteProcedure = CmpDeleteKeyObject;
836 ObjectTypeInitializer.ParseProcedure = CmpParseKey;
837 ObjectTypeInitializer.SecurityProcedure = CmpSecurityMethod;
838 ObjectTypeInitializer.QueryNameProcedure = CmpQueryKeyName;
839 ObjectTypeInitializer.CloseProcedure = CmpCloseKeyObject;
840 ObjectTypeInitializer.SecurityRequired = TRUE;
841
842 /* Create it */
843 return ObCreateObjectType(&Name, &ObjectTypeInitializer, NULL, &CmpKeyObjectType);
844 }
845
846 BOOLEAN
847 NTAPI
848 CmpCreateRootNode(IN PHHIVE Hive,
849 IN PCWSTR Name,
850 OUT PHCELL_INDEX Index)
851 {
852 UNICODE_STRING KeyName;
853 PCM_KEY_NODE KeyCell;
854 LARGE_INTEGER SystemTime;
855 PAGED_CODE();
856
857 /* Initialize the node name and allocate it */
858 RtlInitUnicodeString(&KeyName, Name);
859 *Index = HvAllocateCell(Hive,
860 FIELD_OFFSET(CM_KEY_NODE, Name) +
861 CmpNameSize(Hive, &KeyName),
862 Stable,
863 HCELL_NIL);
864 if (*Index == HCELL_NIL) return FALSE;
865
866 /* Set the cell index and get the data */
867 Hive->BaseBlock->RootCell = *Index;
868 KeyCell = (PCM_KEY_NODE)HvGetCell(Hive, *Index);
869 if (!KeyCell) return FALSE;
870
871 /* Setup the cell */
872 KeyCell->Signature = (USHORT)CM_KEY_NODE_SIGNATURE;
873 KeyCell->Flags = KEY_HIVE_ENTRY | KEY_NO_DELETE;
874 KeQuerySystemTime(&SystemTime);
875 KeyCell->LastWriteTime = SystemTime;
876 KeyCell->Parent = HCELL_NIL;
877 KeyCell->SubKeyCounts[Stable] = 0;
878 KeyCell->SubKeyCounts[Volatile] = 0;
879 KeyCell->SubKeyLists[Stable] = HCELL_NIL;
880 KeyCell->SubKeyLists[Volatile] = HCELL_NIL;
881 KeyCell->ValueList.Count = 0;
882 KeyCell->ValueList.List = HCELL_NIL;
883 KeyCell->Security = HCELL_NIL;
884 KeyCell->Class = HCELL_NIL;
885 KeyCell->ClassLength = 0;
886 KeyCell->MaxNameLen = 0;
887 KeyCell->MaxClassLen = 0;
888 KeyCell->MaxValueNameLen = 0;
889 KeyCell->MaxValueDataLen = 0;
890
891 /* Copy the name (this will also set the length) */
892 KeyCell->NameLength = CmpCopyName(Hive, (PWCHAR)KeyCell->Name, &KeyName);
893
894 /* Check if the name was compressed */
895 if (KeyCell->NameLength < KeyName.Length)
896 {
897 /* Set the flag */
898 KeyCell->Flags |= KEY_COMP_NAME;
899 }
900
901 /* Return success */
902 HvReleaseCell(Hive, *Index);
903 return TRUE;
904 }
905
906 BOOLEAN
907 NTAPI
908 CmpCreateRegistryRoot(VOID)
909 {
910 UNICODE_STRING KeyName;
911 OBJECT_ATTRIBUTES ObjectAttributes;
912 PCM_KEY_BODY RootKey;
913 HCELL_INDEX RootIndex;
914 NTSTATUS Status;
915 PCM_KEY_NODE KeyCell;
916 PSECURITY_DESCRIPTOR SecurityDescriptor;
917 PCM_KEY_CONTROL_BLOCK Kcb;
918 PAGED_CODE();
919
920 /* Setup the root node */
921 if (!CmpCreateRootNode(&CmiVolatileHive->Hive, L"REGISTRY", &RootIndex))
922 {
923 /* We failed */
924 return FALSE;
925 }
926
927 /* Create '\Registry' key. */
928 RtlInitUnicodeString(&KeyName, L"\\REGISTRY");
929 SecurityDescriptor = CmpHiveRootSecurityDescriptor();
930 InitializeObjectAttributes(&ObjectAttributes,
931 &KeyName,
932 OBJ_CASE_INSENSITIVE,
933 NULL,
934 NULL);
935 Status = ObCreateObject(KernelMode,
936 CmpKeyObjectType,
937 &ObjectAttributes,
938 KernelMode,
939 NULL,
940 sizeof(CM_KEY_BODY),
941 0,
942 0,
943 (PVOID*)&RootKey);
944 ExFreePool(SecurityDescriptor);
945 if (!NT_SUCCESS(Status)) return FALSE;
946
947 /* Sanity check, and get the key cell */
948 ASSERT((&CmiVolatileHive->Hive)->ReleaseCellRoutine == NULL);
949 KeyCell = (PCM_KEY_NODE)HvGetCell(&CmiVolatileHive->Hive, RootIndex);
950 if (!KeyCell) return FALSE;
951
952 /* Create the KCB */
953 RtlInitUnicodeString(&KeyName, L"\\REGISTRY");
954 Kcb = CmpCreateKeyControlBlock(&CmiVolatileHive->Hive,
955 RootIndex,
956 KeyCell,
957 NULL,
958 0,
959 &KeyName);
960 if (!Kcb) return FALSE;
961
962 /* Initialize the object */
963 RootKey->KeyControlBlock = Kcb;
964 RootKey->Type = TAG('k', 'y', '0', '2');
965 RootKey->NotifyBlock = NULL;
966 RootKey->ProcessID = PsGetCurrentProcessId();
967
968 /* Link with KCB */
969 EnlistKeyBodyWithKCB(RootKey, 0);
970
971 /* Insert the key into the namespace */
972 Status = ObInsertObject(RootKey,
973 NULL,
974 KEY_ALL_ACCESS,
975 0,
976 NULL,
977 &CmpRegistryRootHandle);
978 if (!NT_SUCCESS(Status)) return FALSE;
979
980 /* Reference the key again so that we never lose it */
981 Status = ObReferenceObjectByHandle(CmpRegistryRootHandle,
982 KEY_READ,
983 NULL,
984 KernelMode,
985 (PVOID*)&RootKey,
986 NULL);
987 if (!NT_SUCCESS(Status)) return FALSE;
988
989 /* Completely sucessful */
990 return TRUE;
991 }
992
993 NTSTATUS
994 NTAPI
995 CmpGetRegistryPath(IN PWCHAR ConfigPath)
996 {
997 OBJECT_ATTRIBUTES ObjectAttributes;
998 NTSTATUS Status;
999 HANDLE KeyHandle;
1000 PKEY_VALUE_PARTIAL_INFORMATION ValueInfo;
1001 UNICODE_STRING KeyName = RTL_CONSTANT_STRING(L"\\Registry\\Machine\\HARDWARE");
1002 UNICODE_STRING ValueName = RTL_CONSTANT_STRING(L"InstallPath");
1003 ULONG BufferSize, ResultSize;
1004
1005 /* Check if we are booted in setup */
1006 if (ExpInTextModeSetup)
1007 {
1008 /* Setup the object attributes */
1009 InitializeObjectAttributes(&ObjectAttributes,
1010 &KeyName,
1011 OBJ_CASE_INSENSITIVE,
1012 NULL,
1013 NULL);
1014 /* Open the key */
1015 Status = ZwOpenKey(&KeyHandle,
1016 KEY_ALL_ACCESS,
1017 &ObjectAttributes);
1018 if (!NT_SUCCESS(Status)) return Status;
1019
1020 /* Allocate the buffer */
1021 BufferSize = sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 4096;
1022 ValueInfo = ExAllocatePoolWithTag(PagedPool, BufferSize, TAG_CM);
1023 if (!ValueInfo)
1024 {
1025 /* Fail */
1026 ZwClose(KeyHandle);
1027 return STATUS_INSUFFICIENT_RESOURCES;
1028 }
1029
1030 /* Query the value */
1031 Status = ZwQueryValueKey(KeyHandle,
1032 &ValueName,
1033 KeyValuePartialInformation,
1034 ValueInfo,
1035 BufferSize,
1036 &ResultSize);
1037 ZwClose(KeyHandle);
1038 if (!NT_SUCCESS(Status))
1039 {
1040 /* Fail */
1041 ExFreePool(ValueInfo);
1042 return Status;
1043 }
1044
1045 /* Copy the config path and null-terminate it */
1046 RtlCopyMemory(ConfigPath,
1047 ValueInfo->Data,
1048 ValueInfo->DataLength);
1049 ConfigPath[ValueInfo->DataLength / sizeof(WCHAR)] = UNICODE_NULL;
1050 ExFreePool(ValueInfo);
1051 }
1052 else
1053 {
1054 /* Just use default path */
1055 wcscpy(ConfigPath, L"\\SystemRoot");
1056 }
1057
1058 /* Add registry path */
1059 wcscat(ConfigPath, L"\\System32\\Config\\");
1060
1061 /* Done */
1062 return STATUS_SUCCESS;
1063 }
1064
1065 VOID
1066 NTAPI
1067 CmpLoadHiveThread(IN PVOID StartContext)
1068 {
1069 WCHAR FileBuffer[MAX_PATH], RegBuffer[MAX_PATH], ConfigPath[MAX_PATH];
1070 UNICODE_STRING TempName, FileName, RegName;
1071 ULONG FileStart, RegStart, i, ErrorResponse, WorkerCount, Length;
1072 ULONG PrimaryDisposition, SecondaryDisposition, ClusterSize;
1073 PCMHIVE CmHive;
1074 HANDLE PrimaryHandle, LogHandle;
1075 NTSTATUS Status = STATUS_SUCCESS;
1076 PVOID ErrorParameters;
1077 PAGED_CODE();
1078
1079 /* Get the hive index, make sure it makes sense */
1080 i = (ULONG)StartContext;
1081 ASSERT(CmpMachineHiveList[i].Name != NULL);
1082
1083 /* We were started */
1084 CmpMachineHiveList[i].ThreadStarted = TRUE;
1085
1086 /* Build the file name and registry name strings */
1087 RtlInitEmptyUnicodeString(&FileName, FileBuffer, MAX_PATH);
1088 RtlInitEmptyUnicodeString(&RegName, RegBuffer, MAX_PATH);
1089
1090 /* Now build the system root path */
1091 CmpGetRegistryPath(ConfigPath);
1092 RtlInitUnicodeString(&TempName, ConfigPath);
1093 RtlAppendStringToString((PSTRING)&FileName, (PSTRING)&TempName);
1094 FileStart = FileName.Length;
1095
1096 /* And build the registry root path */
1097 RtlInitUnicodeString(&TempName, L"\\REGISTRY\\");
1098 RtlAppendStringToString((PSTRING)&RegName, (PSTRING)&TempName);
1099 RegStart = RegName.Length;
1100
1101 /* Build the base name */
1102 RegName.Length = RegStart;
1103 RtlInitUnicodeString(&TempName, CmpMachineHiveList[i].BaseName);
1104 RtlAppendStringToString((PSTRING)&RegName, (PSTRING)&TempName);
1105
1106 /* Check if this is a child of the root */
1107 if (RegName.Buffer[RegName.Length / sizeof(WCHAR) - 1] == '\\')
1108 {
1109 /* Then setup the whole name */
1110 RtlInitUnicodeString(&TempName, CmpMachineHiveList[i].Name);
1111 RtlAppendStringToString((PSTRING)&RegName, (PSTRING)&TempName);
1112 }
1113
1114 /* Now add the rest of the file name */
1115 RtlInitUnicodeString(&TempName, CmpMachineHiveList[i].Name);
1116 FileName.Length = FileStart;
1117 RtlAppendStringToString((PSTRING)&FileName, (PSTRING)&TempName);
1118 if (!CmpMachineHiveList[i].CmHive)
1119 {
1120 /* We need to allocate a new hive structure */
1121 CmpMachineHiveList[i].Allocate = TRUE;
1122
1123 /* Load the hive file */
1124 Status = CmpInitHiveFromFile(&FileName,
1125 CmpMachineHiveList[i].HHiveFlags,
1126 &CmHive,
1127 &CmpMachineHiveList[i].Allocate,
1128 0);
1129 if (!(NT_SUCCESS(Status)) ||
1130 (!(CmHive->FileHandles[HFILE_TYPE_LOG]) && !(CmpMiniNTBoot))) // HACK
1131 {
1132 /* We failed or couldn't get a log file, raise a hard error */
1133 ErrorParameters = &FileName;
1134 NtRaiseHardError(STATUS_CANNOT_LOAD_REGISTRY_FILE,
1135 1,
1136 1,
1137 (PULONG_PTR)&ErrorParameters,
1138 OptionOk,
1139 &ErrorResponse);
1140 }
1141
1142 /* Set the hive flags and newly allocated hive pointer */
1143 CmHive->Flags = CmpMachineHiveList[i].CmHiveFlags;
1144 CmpMachineHiveList[i].CmHive2 = CmHive;
1145 }
1146 else
1147 {
1148 /* We already have a hive, is it volatile? */
1149 CmHive = CmpMachineHiveList[i].CmHive;
1150 if (!(CmHive->Hive.HiveFlags & HIVE_VOLATILE))
1151 {
1152 /* It's now, open the hive file and log */
1153 Status = CmpOpenHiveFiles(&FileName,
1154 L".LOG",
1155 &PrimaryHandle,
1156 &LogHandle,
1157 &PrimaryDisposition,
1158 &SecondaryDisposition,
1159 TRUE,
1160 TRUE,
1161 FALSE,
1162 &ClusterSize);
1163 if (!(NT_SUCCESS(Status)) || !(LogHandle))
1164 {
1165 /* Couldn't open the hive or its log file, raise a hard error */
1166 ErrorParameters = &FileName;
1167 NtRaiseHardError(STATUS_CANNOT_LOAD_REGISTRY_FILE,
1168 1,
1169 1,
1170 (PULONG_PTR)&ErrorParameters,
1171 OptionOk,
1172 &ErrorResponse);
1173
1174 /* And bugcheck for posterity's sake */
1175 KeBugCheckEx(BAD_SYSTEM_CONFIG_INFO, 9, 0, i, Status);
1176 }
1177
1178 /* Save the file handles. This should remove our sync hacks */
1179 CmHive->FileHandles[HFILE_TYPE_LOG] = LogHandle;
1180 CmHive->FileHandles[HFILE_TYPE_PRIMARY] = PrimaryHandle;
1181
1182 /* Allow lazy flushing since the handles are there -- remove sync hacks */
1183 //ASSERT(CmHive->Hive.HiveFlags & HIVE_NOLAZYFLUSH);
1184 CmHive->Hive.HiveFlags &= ~HIVE_NOLAZYFLUSH;
1185
1186 /* Get the real size of the hive */
1187 Length = CmHive->Hive.Storage[Stable].Length + HBLOCK_SIZE;
1188
1189 /* Check if the cluster size doesn't match */
1190 if (CmHive->Hive.Cluster != ClusterSize) ASSERT(FALSE);
1191
1192 /* Set the file size */
1193 //if (!CmpFileSetSize((PHHIVE)CmHive, HFILE_TYPE_PRIMARY, Length, Length))
1194 {
1195 /* This shouldn't fail */
1196 //ASSERT(FALSE);
1197 }
1198
1199 /* Another thing we don't support is NTLDR-recovery */
1200 if (CmHive->Hive.BaseBlock->BootRecover) ASSERT(FALSE);
1201
1202 /* Finally, set our allocated hive to the same hive we've had */
1203 CmpMachineHiveList[i].CmHive2 = CmHive;
1204 ASSERT(CmpMachineHiveList[i].CmHive == CmpMachineHiveList[i].CmHive2);
1205 }
1206 }
1207
1208 /* We're done */
1209 CmpMachineHiveList[i].ThreadFinished = TRUE;
1210
1211 /* Check if we're the last worker */
1212 WorkerCount = InterlockedIncrement(&CmpLoadWorkerIncrement);
1213 if (WorkerCount == CM_NUMBER_OF_MACHINE_HIVES)
1214 {
1215 /* Signal the event */
1216 KeSetEvent(&CmpLoadWorkerEvent, 0, FALSE);
1217 }
1218
1219 /* Kill the thread */
1220 PsTerminateSystemThread(Status);
1221 }
1222
1223 VOID
1224 NTAPI
1225 CmpInitializeHiveList(IN USHORT Flag)
1226 {
1227 WCHAR FileBuffer[MAX_PATH], RegBuffer[MAX_PATH], ConfigPath[MAX_PATH];
1228 UNICODE_STRING TempName, FileName, RegName;
1229 HANDLE Thread;
1230 NTSTATUS Status;
1231 ULONG FileStart, RegStart, i;
1232 PSECURITY_DESCRIPTOR SecurityDescriptor;
1233 PAGED_CODE();
1234
1235 /* Allow writing for now */
1236 CmpNoWrite = FALSE;
1237
1238 /* Build the file name and registry name strings */
1239 RtlInitEmptyUnicodeString(&FileName, FileBuffer, MAX_PATH);
1240 RtlInitEmptyUnicodeString(&RegName, RegBuffer, MAX_PATH);
1241
1242 /* Now build the system root path */
1243 CmpGetRegistryPath(ConfigPath);
1244 RtlInitUnicodeString(&TempName, ConfigPath);
1245 RtlAppendStringToString((PSTRING)&FileName, (PSTRING)&TempName);
1246 FileStart = FileName.Length;
1247
1248 /* And build the registry root path */
1249 RtlInitUnicodeString(&TempName, L"\\REGISTRY\\");
1250 RtlAppendStringToString((PSTRING)&RegName, (PSTRING)&TempName);
1251 RegStart = RegName.Length;
1252
1253 /* Setup the event to synchronize workers */
1254 KeInitializeEvent(&CmpLoadWorkerEvent, SynchronizationEvent, FALSE);
1255
1256 /* Enter special boot condition */
1257 CmpSpecialBootCondition = TRUE;
1258
1259 /* Create the SD for the root hives */
1260 SecurityDescriptor = CmpHiveRootSecurityDescriptor();
1261
1262 /* Loop every hive we care about */
1263 for (i = 0; i < CM_NUMBER_OF_MACHINE_HIVES; i++)
1264 {
1265 /* Make sure the list is setup */
1266 ASSERT(CmpMachineHiveList[i].Name != NULL);
1267
1268 /* Create a thread to handle this hive */
1269 Status = PsCreateSystemThread(&Thread,
1270 THREAD_ALL_ACCESS,
1271 NULL,
1272 0,
1273 NULL,
1274 CmpLoadHiveThread,
1275 (PVOID)i);
1276 if (NT_SUCCESS(Status))
1277 {
1278 /* We don't care about the handle -- the thread self-terminates */
1279 ZwClose(Thread);
1280 }
1281 else
1282 {
1283 /* Can't imagine this happening */
1284 KeBugCheckEx(BAD_SYSTEM_CONFIG_INFO, 9, 3, i, Status);
1285 }
1286 }
1287
1288 /* Make sure we've reached the end of the list */
1289 ASSERT(CmpMachineHiveList[i].Name == NULL);
1290
1291 /* Wait for hive loading to finish */
1292 KeWaitForSingleObject(&CmpLoadWorkerEvent,
1293 Executive,
1294 KernelMode,
1295 FALSE,
1296 NULL);
1297
1298 /* Exit the special boot condition and make sure all workers completed */
1299 CmpSpecialBootCondition = FALSE;
1300 ASSERT(CmpLoadWorkerIncrement == CM_NUMBER_OF_MACHINE_HIVES);
1301
1302 /* Loop hives again */
1303 for (i = 0; i < CM_NUMBER_OF_MACHINE_HIVES; i++)
1304 {
1305 /* Make sure the thread ran and finished */
1306 ASSERT(CmpMachineHiveList[i].ThreadFinished == TRUE);
1307 ASSERT(CmpMachineHiveList[i].ThreadStarted == TRUE);
1308
1309 /* Check if this was a new hive */
1310 if (!CmpMachineHiveList[i].CmHive)
1311 {
1312 /* Make sure we allocated something */
1313 ASSERT(CmpMachineHiveList[i].CmHive2 != NULL);
1314
1315 /* Build the base name */
1316 RegName.Length = RegStart;
1317 RtlInitUnicodeString(&TempName, CmpMachineHiveList[i].BaseName);
1318 RtlAppendStringToString((PSTRING)&RegName, (PSTRING)&TempName);
1319
1320 /* Check if this is a child of the root */
1321 if (RegName.Buffer[RegName.Length / sizeof(WCHAR) - 1] == '\\')
1322 {
1323 /* Then setup the whole name */
1324 RtlInitUnicodeString(&TempName, CmpMachineHiveList[i].Name);
1325 RtlAppendStringToString((PSTRING)&RegName, (PSTRING)&TempName);
1326 }
1327
1328 /* Now link the hive to its master */
1329 Status = CmpLinkHiveToMaster(&RegName,
1330 NULL,
1331 CmpMachineHiveList[i].CmHive2,
1332 CmpMachineHiveList[i].Allocate,
1333 SecurityDescriptor);
1334 if (Status != STATUS_SUCCESS)
1335 {
1336 /* Linking needs to work */
1337 KeBugCheckEx(CONFIG_LIST_FAILED, 11, Status, i, (ULONG_PTR)&RegName);
1338 }
1339
1340 /* Check if we had to allocate a new hive */
1341 if (CmpMachineHiveList[i].Allocate)
1342 {
1343 /* Sync the new hive */
1344 //HvSyncHive((PHHIVE)(CmpMachineHiveList[i].CmHive2));
1345 }
1346 }
1347
1348 /* Check if we created a new hive */
1349 if (CmpMachineHiveList[i].CmHive2)
1350 {
1351 /* TODO: Add to HiveList key */
1352 }
1353 }
1354
1355 /* Get rid of the SD */
1356 ExFreePool(SecurityDescriptor);
1357
1358 /* FIXME: Link SECURITY to SAM */
1359
1360 /* FIXME: Link S-1-5-18 to .Default */
1361 }
1362
1363 BOOLEAN
1364 NTAPI
1365 CmInitSystem1(VOID)
1366 {
1367 OBJECT_ATTRIBUTES ObjectAttributes;
1368 UNICODE_STRING KeyName;
1369 HANDLE KeyHandle;
1370 NTSTATUS Status;
1371 PCMHIVE HardwareHive;
1372 PSECURITY_DESCRIPTOR SecurityDescriptor;
1373 PAGED_CODE();
1374
1375 /* Check if this is PE-boot */
1376 if (InitIsWinPEMode)
1377 {
1378 /* Set registry to PE mode */
1379 CmpMiniNTBoot = TRUE;
1380 CmpShareSystemHives = TRUE;
1381 }
1382
1383 /* Initialize the hive list and lock */
1384 InitializeListHead(&CmpHiveListHead);
1385 ExInitializePushLock((PVOID)&CmpHiveListHeadLock);
1386 ExInitializePushLock((PVOID)&CmpLoadHiveLock);
1387
1388 /* Initialize registry lock */
1389 ExInitializeResourceLite(&CmpRegistryLock);
1390
1391 /* Initialize the cache */
1392 CmpInitializeCache();
1393
1394 /* Initialize allocation and delayed dereferencing */
1395 CmpInitCmPrivateAlloc();
1396 CmpInitCmPrivateDelayAlloc();
1397 CmpInitDelayDerefKCBEngine();
1398
1399 /* Initialize callbacks */
1400 CmpInitCallback();
1401
1402 /* Initialize self healing */
1403 KeInitializeGuardedMutex(&CmpSelfHealQueueLock);
1404 InitializeListHead(&CmpSelfHealQueueListHead);
1405
1406 /* Save the current process and lock the registry */
1407 CmpSystemProcess = PsGetCurrentProcess();
1408
1409 /* Create the key object types */
1410 Status = CmpCreateObjectTypes();
1411 if (!NT_SUCCESS(Status))
1412 {
1413 /* Bugcheck */
1414 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 1, Status, 0);
1415 }
1416
1417 /* Build the master hive */
1418 Status = CmpInitializeHive((PCMHIVE*)&CmiVolatileHive,
1419 HINIT_CREATE,
1420 HIVE_VOLATILE,
1421 HFILE_TYPE_PRIMARY,
1422 NULL,
1423 NULL,
1424 NULL,
1425 NULL,
1426 NULL,
1427 0);
1428 if (!NT_SUCCESS(Status))
1429 {
1430 /* Bugcheck */
1431 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 2, Status, 0);
1432 }
1433
1434 /* Create the \REGISTRY key node */
1435 if (!CmpCreateRegistryRoot())
1436 {
1437 /* Bugcheck */
1438 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 3, 0, 0);
1439 }
1440
1441 /* Create the default security descriptor */
1442 SecurityDescriptor = CmpHiveRootSecurityDescriptor();
1443
1444 /* Create '\Registry\Machine' key. */
1445 RtlInitUnicodeString(&KeyName, L"\\REGISTRY\\MACHINE");
1446 InitializeObjectAttributes(&ObjectAttributes,
1447 &KeyName,
1448 OBJ_CASE_INSENSITIVE,
1449 NULL,
1450 SecurityDescriptor);
1451 Status = NtCreateKey(&KeyHandle,
1452 KEY_READ | KEY_WRITE,
1453 &ObjectAttributes,
1454 0,
1455 NULL,
1456 0,
1457 NULL);
1458 if (!NT_SUCCESS(Status))
1459 {
1460 /* Bugcheck */
1461 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 5, Status, 0);
1462 }
1463
1464 /* Close the handle */
1465 NtClose(KeyHandle);
1466
1467 /* Create '\Registry\User' key. */
1468 RtlInitUnicodeString(&KeyName, L"\\REGISTRY\\USER");
1469 InitializeObjectAttributes(&ObjectAttributes,
1470 &KeyName,
1471 OBJ_CASE_INSENSITIVE,
1472 NULL,
1473 SecurityDescriptor);
1474 Status = NtCreateKey(&KeyHandle,
1475 KEY_READ | KEY_WRITE,
1476 &ObjectAttributes,
1477 0,
1478 NULL,
1479 0,
1480 NULL);
1481 if (!NT_SUCCESS(Status))
1482 {
1483 /* Bugcheck */
1484 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 6, Status, 0);
1485 }
1486
1487 /* Close the handle */
1488 NtClose(KeyHandle);
1489
1490 /* Initialize the system hive */
1491 if (!CmpInitializeSystemHive(KeLoaderBlock))
1492 {
1493 /* Bugcheck */
1494 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 7, 0, 0);
1495 }
1496
1497 /* Create the 'CurrentControlSet' link. */
1498 Status = CmpCreateControlSet(KeLoaderBlock);
1499 if (!NT_SUCCESS(Status))
1500 {
1501 /* Bugcheck */
1502 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 8, Status, 0);
1503 }
1504
1505 /* Create the hardware hive */
1506 Status = CmpInitializeHive((PCMHIVE*)&HardwareHive,
1507 HINIT_CREATE,
1508 HIVE_VOLATILE,
1509 HFILE_TYPE_PRIMARY,
1510 NULL,
1511 NULL,
1512 NULL,
1513 NULL,
1514 NULL,
1515 0);
1516 if (!NT_SUCCESS(Status))
1517 {
1518 /* Bugcheck */
1519 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 11, Status, 0);
1520 }
1521
1522 /* Add the hive to the hive list */
1523 CmpMachineHiveList[0].CmHive = (PCMHIVE)HardwareHive;
1524
1525 /* Attach it to the machine key */
1526 RtlInitUnicodeString(&KeyName, L"\\Registry\\Machine\\HARDWARE");
1527 Status = CmpLinkHiveToMaster(&KeyName,
1528 NULL,
1529 (PCMHIVE)HardwareHive,
1530 TRUE,
1531 SecurityDescriptor);
1532 if (!NT_SUCCESS(Status))
1533 {
1534 /* Bugcheck */
1535 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 12, Status, 0);
1536 }
1537
1538 /* FIXME: Add to HiveList key */
1539
1540 /* Free the security descriptor */
1541 ExFreePool(SecurityDescriptor);
1542
1543 /* Fill out the Hardware key with the ARC Data from the Loader */
1544 Status = CmpInitializeHardwareConfiguration(KeLoaderBlock);
1545 if (!NT_SUCCESS(Status))
1546 {
1547 /* Bugcheck */
1548 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 13, Status, 0);
1549 }
1550
1551 /* Initialize machine-dependent information into the registry */
1552 Status = CmpInitializeMachineDependentConfiguration(KeLoaderBlock);
1553 if (!NT_SUCCESS(Status))
1554 {
1555 /* Bugcheck */
1556 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 14, Status, 0);
1557 }
1558
1559 /* Initialize volatile registry settings */
1560 Status = CmpSetSystemValues(KeLoaderBlock);
1561 if (!NT_SUCCESS(Status))
1562 {
1563 /* Bugcheck */
1564 KeBugCheckEx(CONFIG_INITIALIZATION_FAILED, 1, 15, Status, 0);
1565 }
1566
1567 /* Free the load options */
1568 ExFreePool(CmpLoadOptions.Buffer);
1569
1570 /* If we got here, all went well */
1571 return TRUE;
1572 }
1573
1574 VOID
1575 NTAPI
1576 CmpLockRegistryExclusive(VOID)
1577 {
1578 /* Enter a critical region and lock the registry */
1579 KeEnterCriticalRegion();
1580 ExAcquireResourceExclusiveLite(&CmpRegistryLock, TRUE);
1581
1582 /* Sanity check */
1583 ASSERT(CmpFlushStarveWriters == 0);
1584 RtlGetCallersAddress(&CmpRegistryLockCaller, &CmpRegistryLockCallerCaller);
1585 }
1586
1587 VOID
1588 NTAPI
1589 CmpLockRegistry(VOID)
1590 {
1591 /* Enter a critical region */
1592 KeEnterCriticalRegion();
1593
1594 /* Check if we have to starve writers */
1595 if (CmpFlushStarveWriters)
1596 {
1597 /* Starve exlusive waiters */
1598 ExAcquireSharedStarveExclusive(&CmpRegistryLock, TRUE);
1599 }
1600 else
1601 {
1602 /* Just grab the lock */
1603 ExAcquireResourceSharedLite(&CmpRegistryLock, TRUE);
1604 }
1605 }
1606
1607 BOOLEAN
1608 NTAPI
1609 CmpTestRegistryLock(VOID)
1610 {
1611 /* Test the lock */
1612 return !ExIsResourceAcquiredSharedLite(&CmpRegistryLock) ? FALSE : TRUE;
1613 }
1614
1615 BOOLEAN
1616 NTAPI
1617 CmpTestRegistryLockExclusive(VOID)
1618 {
1619 /* Test the lock */
1620 return !ExIsResourceAcquiredExclusiveLite(&CmpRegistryLock) ? FALSE : TRUE;
1621 }
1622
1623 VOID
1624 NTAPI
1625 CmpUnlockRegistry(VOID)
1626 {
1627 /* Sanity check */
1628 CMP_ASSERT_REGISTRY_LOCK();
1629
1630 /* Check if we should flush the registry */
1631 if (CmpFlushOnLockRelease)
1632 {
1633 /* The registry should be exclusively locked for this */
1634 CMP_ASSERT_EXCLUSIVE_REGISTRY_LOCK();
1635
1636 /* Flush the registry */
1637 CmpDoFlushAll(TRUE);
1638 CmpFlushOnLockRelease = FALSE;
1639 }
1640
1641 /* Release the lock and leave the critical region */
1642 ExReleaseResourceLite(&CmpRegistryLock);
1643 KeLeaveCriticalRegion();
1644 }
1645
1646 VOID
1647 NTAPI
1648 CmpAcquireTwoKcbLocksExclusiveByKey(IN ULONG ConvKey1,
1649 IN ULONG ConvKey2)
1650 {
1651 ULONG Index1, Index2;
1652
1653 /* Sanity check */
1654 CMP_ASSERT_REGISTRY_LOCK();
1655
1656 /* Get hash indexes */
1657 Index1 = GET_HASH_INDEX(ConvKey1);
1658 Index2 = GET_HASH_INDEX(ConvKey2);
1659
1660 /* See which one is highest */
1661 if (Index1 < Index2)
1662 {
1663 /* Grab them in the proper order */
1664 CmpAcquireKcbLockExclusiveByKey(ConvKey1);
1665 CmpAcquireKcbLockExclusiveByKey(ConvKey2);
1666 }
1667 else
1668 {
1669 /* Grab the second one first, then the first */
1670 CmpAcquireKcbLockExclusiveByKey(ConvKey2);
1671 if (Index1 != Index2) CmpAcquireKcbLockExclusiveByKey(ConvKey1);
1672 }
1673 }
1674
1675 VOID
1676 NTAPI
1677 CmpReleaseTwoKcbLockByKey(IN ULONG ConvKey1,
1678 IN ULONG ConvKey2)
1679 {
1680 ULONG Index1, Index2;
1681
1682 /* Sanity check */
1683 CMP_ASSERT_REGISTRY_LOCK();
1684
1685 /* Get hash indexes */
1686 Index1 = GET_HASH_INDEX(ConvKey1);
1687 Index2 = GET_HASH_INDEX(ConvKey2);
1688 ASSERT((GET_HASH_ENTRY(CmpCacheTable, ConvKey2).Owner == KeGetCurrentThread()) ||
1689 (CmpTestRegistryLockExclusive()));
1690
1691 /* See which one is highest */
1692 if (Index1 < Index2)
1693 {
1694 /* Grab them in the proper order */
1695 ASSERT((GET_HASH_ENTRY(CmpCacheTable, ConvKey1).Owner == KeGetCurrentThread()) ||
1696 (CmpTestRegistryLockExclusive()));
1697 CmpReleaseKcbLockByKey(ConvKey2);
1698 CmpReleaseKcbLockByKey(ConvKey1);
1699 }
1700 else
1701 {
1702 /* Release the first one first, then the second */
1703 if (Index1 != Index2)
1704 {
1705 ASSERT((GET_HASH_ENTRY(CmpCacheTable, ConvKey1).Owner == KeGetCurrentThread()) ||
1706 (CmpTestRegistryLockExclusive()));
1707 CmpReleaseKcbLockByKey(ConvKey1);
1708 }
1709 CmpReleaseKcbLockByKey(ConvKey2);
1710 }
1711 }
1712
1713 VOID
1714 NTAPI
1715 CmShutdownSystem(VOID)
1716 {
1717 /* Kill the workers and flush all hives */
1718 if (!CmFirstTime) CmpShutdownWorkers();
1719 CmpDoFlushAll(TRUE);
1720 }